Skip to content

Commit ad017f6

Browse files
committed
xfs: pass along transaction context when reading xattr block buffers
Teach the extended attribute reading functions to pass along a transaction context if one was supplied. The extended attribute scrub code will use transactions to lock buffers and avoid deadlocking with itself in the case of loops; since it will already have the inode locked, also create xattr get/list helpers that don't take locks. Signed-off-by: Darrick J. Wong <[email protected]> Reviewed-by: Brian Foster <[email protected]>
1 parent acb9553 commit ad017f6

File tree

4 files changed

+57
-36
lines changed

4 files changed

+57
-36
lines changed

fs/xfs/libxfs/xfs_attr.c

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,23 @@ xfs_inode_hasattr(
114114
* Overall external interface routines.
115115
*========================================================================*/
116116

117+
/* Retrieve an extended attribute and its value. Must have iolock. */
118+
int
119+
xfs_attr_get_ilocked(
120+
struct xfs_inode *ip,
121+
struct xfs_da_args *args)
122+
{
123+
if (!xfs_inode_hasattr(ip))
124+
return -ENOATTR;
125+
else if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL)
126+
return xfs_attr_shortform_getvalue(args);
127+
else if (xfs_bmap_one_block(ip, XFS_ATTR_FORK))
128+
return xfs_attr_leaf_get(args);
129+
else
130+
return xfs_attr_node_get(args);
131+
}
132+
133+
/* Retrieve an extended attribute by name, and its value. */
117134
int
118135
xfs_attr_get(
119136
struct xfs_inode *ip,
@@ -141,14 +158,7 @@ xfs_attr_get(
141158
args.op_flags = XFS_DA_OP_OKNOENT;
142159

143160
lock_mode = xfs_ilock_attr_map_shared(ip);
144-
if (!xfs_inode_hasattr(ip))
145-
error = -ENOATTR;
146-
else if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL)
147-
error = xfs_attr_shortform_getvalue(&args);
148-
else if (xfs_bmap_one_block(ip, XFS_ATTR_FORK))
149-
error = xfs_attr_leaf_get(&args);
150-
else
151-
error = xfs_attr_node_get(&args);
161+
error = xfs_attr_get_ilocked(ip, &args);
152162
xfs_iunlock(ip, lock_mode);
153163

154164
*valuelenp = args.valuelen;

fs/xfs/libxfs/xfs_attr_remote.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,8 @@ xfs_attr_rmtval_get(
386386
(map[i].br_startblock != HOLESTARTBLOCK));
387387
dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock);
388388
dblkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount);
389-
error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp,
389+
error = xfs_trans_read_buf(mp, args->trans,
390+
mp->m_ddev_targp,
390391
dblkno, dblkcnt, 0, &bp,
391392
&xfs_attr3_rmt_buf_ops);
392393
if (error)
@@ -395,7 +396,7 @@ xfs_attr_rmtval_get(
395396
error = xfs_attr_rmtval_copyout(mp, bp, args->dp->i_ino,
396397
&offset, &valuelen,
397398
&dst);
398-
xfs_buf_relse(bp);
399+
xfs_trans_brelse(args->trans, bp);
399400
if (error)
400401
return error;
401402

fs/xfs/xfs_attr.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ typedef void (*put_listent_func_t)(struct xfs_attr_list_context *, int,
117117
unsigned char *, int, int);
118118

119119
typedef struct xfs_attr_list_context {
120+
struct xfs_trans *tp;
120121
struct xfs_inode *dp; /* inode */
121122
struct attrlist_cursor_kern *cursor; /* position in list */
122123
char *alist; /* output buffer */
@@ -140,8 +141,10 @@ typedef struct xfs_attr_list_context {
140141
* Overall external interface routines.
141142
*/
142143
int xfs_attr_inactive(struct xfs_inode *dp);
144+
int xfs_attr_list_int_ilocked(struct xfs_attr_list_context *);
143145
int xfs_attr_list_int(struct xfs_attr_list_context *);
144146
int xfs_inode_hasattr(struct xfs_inode *ip);
147+
int xfs_attr_get_ilocked(struct xfs_inode *ip, struct xfs_da_args *args);
145148
int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
146149
unsigned char *value, int *valuelenp, int flags);
147150
int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,

fs/xfs/xfs_attr_list.c

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ xfs_attr_node_list(xfs_attr_list_context_t *context)
230230
*/
231231
bp = NULL;
232232
if (cursor->blkno > 0) {
233-
error = xfs_da3_node_read(NULL, dp, cursor->blkno, -1,
233+
error = xfs_da3_node_read(context->tp, dp, cursor->blkno, -1,
234234
&bp, XFS_ATTR_FORK);
235235
if ((error != 0) && (error != -EFSCORRUPTED))
236236
return error;
@@ -242,7 +242,7 @@ xfs_attr_node_list(xfs_attr_list_context_t *context)
242242
case XFS_DA_NODE_MAGIC:
243243
case XFS_DA3_NODE_MAGIC:
244244
trace_xfs_attr_list_wrong_blk(context);
245-
xfs_trans_brelse(NULL, bp);
245+
xfs_trans_brelse(context->tp, bp);
246246
bp = NULL;
247247
break;
248248
case XFS_ATTR_LEAF_MAGIC:
@@ -254,18 +254,18 @@ xfs_attr_node_list(xfs_attr_list_context_t *context)
254254
if (cursor->hashval > be32_to_cpu(
255255
entries[leafhdr.count - 1].hashval)) {
256256
trace_xfs_attr_list_wrong_blk(context);
257-
xfs_trans_brelse(NULL, bp);
257+
xfs_trans_brelse(context->tp, bp);
258258
bp = NULL;
259259
} else if (cursor->hashval <= be32_to_cpu(
260260
entries[0].hashval)) {
261261
trace_xfs_attr_list_wrong_blk(context);
262-
xfs_trans_brelse(NULL, bp);
262+
xfs_trans_brelse(context->tp, bp);
263263
bp = NULL;
264264
}
265265
break;
266266
default:
267267
trace_xfs_attr_list_wrong_blk(context);
268-
xfs_trans_brelse(NULL, bp);
268+
xfs_trans_brelse(context->tp, bp);
269269
bp = NULL;
270270
}
271271
}
@@ -281,7 +281,7 @@ xfs_attr_node_list(xfs_attr_list_context_t *context)
281281
for (;;) {
282282
uint16_t magic;
283283

284-
error = xfs_da3_node_read(NULL, dp,
284+
error = xfs_da3_node_read(context->tp, dp,
285285
cursor->blkno, -1, &bp,
286286
XFS_ATTR_FORK);
287287
if (error)
@@ -297,7 +297,7 @@ xfs_attr_node_list(xfs_attr_list_context_t *context)
297297
XFS_ERRLEVEL_LOW,
298298
context->dp->i_mount,
299299
node);
300-
xfs_trans_brelse(NULL, bp);
300+
xfs_trans_brelse(context->tp, bp);
301301
return -EFSCORRUPTED;
302302
}
303303

@@ -313,10 +313,10 @@ xfs_attr_node_list(xfs_attr_list_context_t *context)
313313
}
314314
}
315315
if (i == nodehdr.count) {
316-
xfs_trans_brelse(NULL, bp);
316+
xfs_trans_brelse(context->tp, bp);
317317
return 0;
318318
}
319-
xfs_trans_brelse(NULL, bp);
319+
xfs_trans_brelse(context->tp, bp);
320320
}
321321
}
322322
ASSERT(bp != NULL);
@@ -333,12 +333,12 @@ xfs_attr_node_list(xfs_attr_list_context_t *context)
333333
if (context->seen_enough || leafhdr.forw == 0)
334334
break;
335335
cursor->blkno = leafhdr.forw;
336-
xfs_trans_brelse(NULL, bp);
337-
error = xfs_attr3_leaf_read(NULL, dp, cursor->blkno, -1, &bp);
336+
xfs_trans_brelse(context->tp, bp);
337+
error = xfs_attr3_leaf_read(context->tp, dp, cursor->blkno, -1, &bp);
338338
if (error)
339339
return error;
340340
}
341-
xfs_trans_brelse(NULL, bp);
341+
xfs_trans_brelse(context->tp, bp);
342342
return 0;
343343
}
344344

@@ -448,15 +448,33 @@ xfs_attr_leaf_list(xfs_attr_list_context_t *context)
448448
trace_xfs_attr_leaf_list(context);
449449

450450
context->cursor->blkno = 0;
451-
error = xfs_attr3_leaf_read(NULL, context->dp, 0, -1, &bp);
451+
error = xfs_attr3_leaf_read(context->tp, context->dp, 0, -1, &bp);
452452
if (error)
453453
return error;
454454

455455
xfs_attr3_leaf_list_int(bp, context);
456-
xfs_trans_brelse(NULL, bp);
456+
xfs_trans_brelse(context->tp, bp);
457457
return 0;
458458
}
459459

460+
int
461+
xfs_attr_list_int_ilocked(
462+
struct xfs_attr_list_context *context)
463+
{
464+
struct xfs_inode *dp = context->dp;
465+
466+
/*
467+
* Decide on what work routines to call based on the inode size.
468+
*/
469+
if (!xfs_inode_hasattr(dp))
470+
return 0;
471+
else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL)
472+
return xfs_attr_shortform_list(context);
473+
else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
474+
return xfs_attr_leaf_list(context);
475+
return xfs_attr_node_list(context);
476+
}
477+
460478
int
461479
xfs_attr_list_int(
462480
xfs_attr_list_context_t *context)
@@ -470,19 +488,8 @@ xfs_attr_list_int(
470488
if (XFS_FORCED_SHUTDOWN(dp->i_mount))
471489
return -EIO;
472490

473-
/*
474-
* Decide on what work routines to call based on the inode size.
475-
*/
476491
lock_mode = xfs_ilock_attr_map_shared(dp);
477-
if (!xfs_inode_hasattr(dp)) {
478-
error = 0;
479-
} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
480-
error = xfs_attr_shortform_list(context);
481-
} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
482-
error = xfs_attr_leaf_list(context);
483-
} else {
484-
error = xfs_attr_node_list(context);
485-
}
492+
error = xfs_attr_list_int_ilocked(context);
486493
xfs_iunlock(dp, lock_mode);
487494
return error;
488495
}

0 commit comments

Comments
 (0)