]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - libxfs/xfs_attr.c
xfs: use ->t_dfops for attr set/remove operations
[thirdparty/xfsprogs-dev.git] / libxfs / xfs_attr.c
CommitLineData
37b3b4d6 1// SPDX-License-Identifier: GPL-2.0
57c9fccb 2/*
5e656dbb 3 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
da23017d 4 * All Rights Reserved.
57c9fccb 5 */
9c799827 6#include "libxfs_priv.h"
b626fb59
DC
7#include "xfs_fs.h"
8#include "xfs_shared.h"
9#include "xfs_format.h"
10#include "xfs_log_format.h"
11#include "xfs_trans_resv.h"
12#include "xfs_bit.h"
13#include "xfs_mount.h"
f944d3d0 14#include "xfs_defer.h"
b626fb59
DC
15#include "xfs_da_format.h"
16#include "xfs_da_btree.h"
17#include "xfs_attr_sf.h"
18#include "xfs_inode.h"
19#include "xfs_alloc.h"
20#include "xfs_trans.h"
21#include "xfs_bmap.h"
22#include "xfs_bmap_btree.h"
23#include "xfs_attr_leaf.h"
24#include "xfs_attr_remote.h"
25#include "xfs_trans_space.h"
26#include "xfs_trace.h"
57c9fccb
NS
27
28/*
29 * xfs_attr.c
30 *
31 * Provide the external interfaces to manage attribute lists.
32 */
33
34/*========================================================================
35 * Function prototypes for the kernel.
36 *========================================================================*/
37
38/*
39 * Internal routines when attribute list fits inside the inode.
40 */
41STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
42
43/*
44 * Internal routines when attribute list is one block.
45 */
46STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
47STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
48STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
57c9fccb
NS
49
50/*
51 * Internal routines when attribute list is more than one block.
52 */
53STATIC int xfs_attr_node_get(xfs_da_args_t *args);
54STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
55STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
57c9fccb
NS
56STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
57STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
58
57c9fccb 59
5e656dbb 60STATIC int
ff105f75
DC
61xfs_attr_args_init(
62 struct xfs_da_args *args,
63 struct xfs_inode *dp,
64 const unsigned char *name,
65 int flags)
5e656dbb 66{
ff105f75
DC
67
68 if (!name)
12b53197 69 return -EINVAL;
ff105f75
DC
70
71 memset(args, 0, sizeof(*args));
72 args->geo = dp->i_mount->m_attr_geo;
73 args->whichfork = XFS_ATTR_FORK;
74 args->dp = dp;
75 args->flags = flags;
76 args->name = name;
77 args->namelen = strlen((const char *)name);
78 if (args->namelen >= MAXNAMELEN)
12b53197 79 return -EFAULT; /* match IRIX behaviour */
5e656dbb 80
ff105f75 81 args->hashval = xfs_da_hashname(args->name, args->namelen);
5e656dbb
BN
82 return 0;
83}
84
78d6585c 85int
5e656dbb
BN
86xfs_inode_hasattr(
87 struct xfs_inode *ip)
88{
89 if (!XFS_IFORK_Q(ip) ||
90 (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
91 ip->i_d.di_anextents == 0))
92 return 0;
93 return 1;
94}
95
57c9fccb
NS
96/*========================================================================
97 * Overall external interface routines.
98 *========================================================================*/
99
baebed82 100/* Retrieve an extended attribute and its value. Must have ilock. */
b2d5ffd5
DW
101int
102xfs_attr_get_ilocked(
103 struct xfs_inode *ip,
104 struct xfs_da_args *args)
105{
baebed82
CH
106 ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
107
b2d5ffd5
DW
108 if (!xfs_inode_hasattr(ip))
109 return -ENOATTR;
110 else if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL)
111 return xfs_attr_shortform_getvalue(args);
112 else if (xfs_bmap_one_block(ip, XFS_ATTR_FORK))
113 return xfs_attr_leaf_get(args);
114 else
115 return xfs_attr_node_get(args);
116}
117
118/* Retrieve an extended attribute by name, and its value. */
ff105f75
DC
119int
120xfs_attr_get(
56b2de80 121 struct xfs_inode *ip,
ff105f75 122 const unsigned char *name,
56b2de80
DC
123 unsigned char *value,
124 int *valuelenp,
125 int flags)
5e656dbb 126{
ff105f75
DC
127 struct xfs_da_args args;
128 uint lock_mode;
129 int error;
130
79896434 131 XFS_STATS_INC(ip->i_mount, xs_attr_get);
ff105f75
DC
132
133 if (XFS_FORCED_SHUTDOWN(ip->i_mount))
12b53197 134 return -EIO;
5e656dbb 135
ff105f75
DC
136 error = xfs_attr_args_init(&args, ip, name, flags);
137 if (error)
138 return error;
139
5e656dbb
BN
140 args.value = value;
141 args.valuelen = *valuelenp;
cd9f2a5d
ES
142 /* Entirely possible to look up a name which doesn't exist */
143 args.op_flags = XFS_DA_OP_OKNOENT;
5e656dbb 144
ff105f75 145 lock_mode = xfs_ilock_attr_map_shared(ip);
b2d5ffd5 146 error = xfs_attr_get_ilocked(ip, &args);
ff105f75 147 xfs_iunlock(ip, lock_mode);
5e656dbb 148
5e656dbb 149 *valuelenp = args.valuelen;
12b53197 150 return error == -EEXIST ? 0 : error;
5e656dbb
BN
151}
152
153/*
154 * Calculate how many blocks we need for the new attribute,
155 */
56b2de80 156STATIC int
5e656dbb 157xfs_attr_calc_size(
ff105f75 158 struct xfs_da_args *args,
5e656dbb
BN
159 int *local)
160{
ff105f75 161 struct xfs_mount *mp = args->dp->i_mount;
5e656dbb
BN
162 int size;
163 int nblks;
164
165 /*
166 * Determine space new attribute will use, and if it would be
167 * "local" or "remote" (note: local != inline).
168 */
ff105f75 169 size = xfs_attr_leaf_newentsize(args, local);
5e656dbb
BN
170 nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK);
171 if (*local) {
ff105f75 172 if (size > (args->geo->blksize / 2)) {
5e656dbb
BN
173 /* Double split possible */
174 nblks *= 2;
175 }
176 } else {
177 /*
178 * Out of line attribute, cannot double split, but
179 * make room for the attribute value itself.
180 */
ff105f75 181 uint dblocks = xfs_attr3_rmt_blocks(mp, args->valuelen);
5e656dbb
BN
182 nblks += dblocks;
183 nblks += XFS_NEXTENTADD_SPACE_RES(mp, dblocks, XFS_ATTR_FORK);
184 }
185
186 return nblks;
187}
188
ff105f75
DC
189int
190xfs_attr_set(
191 struct xfs_inode *dp,
192 const unsigned char *name,
193 unsigned char *value,
194 int valuelen,
195 int flags)
57c9fccb 196{
48ea6cb9 197 struct xfs_mount *mp = dp->i_mount;
3fbc4d7d 198 struct xfs_buf *leaf_bp = NULL;
ff105f75 199 struct xfs_da_args args;
f33cea1a 200 struct xfs_defer_ops dfops;
48ea6cb9 201 struct xfs_trans_res tres;
ff105f75 202 xfs_fsblock_t firstblock;
48ea6cb9 203 int rsvd = (flags & ATTR_ROOT) != 0;
0b66d459 204 int error, err2, local;
ff105f75 205
79896434 206 XFS_STATS_INC(mp, xs_attr_set);
ff105f75
DC
207
208 if (XFS_FORCED_SHUTDOWN(dp->i_mount))
12b53197 209 return -EIO;
ff105f75
DC
210
211 error = xfs_attr_args_init(&args, dp, name, flags);
212 if (error)
213 return error;
214
215 args.value = value;
216 args.valuelen = valuelen;
217 args.firstblock = &firstblock;
f33cea1a 218 args.dfops = &dfops;
ff105f75
DC
219 args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
220 args.total = xfs_attr_calc_size(&args, &local);
57c9fccb 221
43cf369d 222 error = xfs_qm_dqattach(dp);
56b2de80
DC
223 if (error)
224 return error;
ca86e759 225
57c9fccb
NS
226 /*
227 * If the inode doesn't have an attribute fork, add one.
228 * (inode must not be locked when we call this routine)
229 */
230 if (XFS_IFORK_Q(dp) == 0) {
5e656dbb 231 int sf_size = sizeof(xfs_attr_sf_hdr_t) +
ff105f75 232 XFS_ATTR_SF_ENTSIZE_BYNAME(args.namelen, valuelen);
5e656dbb 233
ff105f75
DC
234 error = xfs_bmap_add_attrfork(dp, sf_size, rsvd);
235 if (error)
236 return error;
57c9fccb
NS
237 }
238
9074815c
CH
239 tres.tr_logres = M_RES(mp)->tr_attrsetm.tr_logres +
240 M_RES(mp)->tr_attrsetrt.tr_logres * args.total;
241 tres.tr_logcount = XFS_ATTRSET_LOG_COUNT;
242 tres.tr_logflags = XFS_TRANS_PERM_LOG_RES;
57c9fccb
NS
243
244 /*
245 * Root fork attributes can use reserved data blocks for this
246 * operation if necessary
247 */
9074815c
CH
248 error = xfs_trans_alloc(mp, &tres, args.total, 0,
249 rsvd ? XFS_TRANS_RESERVE : 0, &args.trans);
250 if (error)
ff105f75 251 return error;
e599d8b9
BF
252 xfs_defer_init(&dfops, &firstblock);
253 args.trans->t_dfops = &dfops;
57c9fccb 254
9074815c 255 xfs_ilock(dp, XFS_ILOCK_EXCL);
56b2de80 256 error = xfs_trans_reserve_quota_nblks(args.trans, dp, args.total, 0,
5e656dbb
BN
257 rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES :
258 XFS_QMOPT_RES_REGBLKS);
57c9fccb
NS
259 if (error) {
260 xfs_iunlock(dp, XFS_ILOCK_EXCL);
3d7434fe 261 xfs_trans_cancel(args.trans);
ff105f75 262 return error;
57c9fccb
NS
263 }
264
a2ceac1f 265 xfs_trans_ijoin(args.trans, dp, 0);
57c9fccb
NS
266
267 /*
5e656dbb 268 * If the attribute list is non-existent or a shortform list,
57c9fccb
NS
269 * upgrade it to a single-leaf-block attribute list.
270 */
ff105f75
DC
271 if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
272 (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
273 dp->i_d.di_anextents == 0)) {
57c9fccb
NS
274
275 /*
276 * Build initial attribute list (if required).
277 */
278 if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
ca86e759 279 xfs_attr_shortform_create(&args);
57c9fccb
NS
280
281 /*
282 * Try to add the attr to the attribute list in
283 * the inode.
284 */
285 error = xfs_attr_shortform_addname(&args);
12b53197 286 if (error != -ENOSPC) {
57c9fccb
NS
287 /*
288 * Commit the shortform mods, and we're done.
289 * NOTE: this is also the error path (EEXIST, etc).
290 */
291 ASSERT(args.trans != NULL);
292
293 /*
294 * If this is a synchronous mount, make sure that
295 * the transaction goes to disk before returning
296 * to the user.
297 */
ff105f75 298 if (mp->m_flags & XFS_MOUNT_WSYNC)
57c9fccb 299 xfs_trans_set_sync(args.trans);
56b2de80
DC
300
301 if (!error && (flags & ATTR_KERNOTIME) == 0) {
302 xfs_trans_ichgtime(args.trans, dp,
303 XFS_ICHGTIME_CHG);
304 }
de5a3f46 305 err2 = xfs_trans_commit(args.trans);
57c9fccb
NS
306 xfs_iunlock(dp, XFS_ILOCK_EXCL);
307
ff105f75 308 return error ? error : err2;
57c9fccb
NS
309 }
310
311 /*
312 * It won't fit in the shortform, transform to a leaf block.
313 * GROT: another possible req'mt for a double-split btree op.
314 */
3fbc4d7d 315 error = xfs_attr_shortform_to_leaf(&args, &leaf_bp);
5c33baee
CH
316 if (error)
317 goto out_defer_cancel;
3fbc4d7d
DW
318 /*
319 * Prevent the leaf buffer from being unlocked so that a
320 * concurrent AIL push cannot grab the half-baked leaf
321 * buffer and run into problems with the write verifier.
322 */
323 xfs_trans_bhold(args.trans, leaf_bp);
e599d8b9
BF
324 xfs_defer_bjoin(&dfops, leaf_bp);
325 xfs_defer_ijoin(&dfops, dp);
326 error = xfs_defer_finish(&args.trans, &dfops);
5c33baee
CH
327 if (error)
328 goto out_defer_cancel;
57c9fccb 329
57c9fccb
NS
330 /*
331 * Commit the leaf transformation. We'll need another (linked)
3fbc4d7d
DW
332 * transaction to add the new attribute to the leaf, which
333 * means that we have to hold & join the leaf buffer here too.
57c9fccb 334 */
d67406c9 335 error = xfs_trans_roll_inode(&args.trans, dp);
5e656dbb 336 if (error)
57c9fccb 337 goto out;
3fbc4d7d
DW
338 xfs_trans_bjoin(args.trans, leaf_bp);
339 leaf_bp = NULL;
57c9fccb
NS
340 }
341
ff105f75 342 if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
57c9fccb 343 error = xfs_attr_leaf_addname(&args);
ff105f75 344 else
57c9fccb 345 error = xfs_attr_node_addname(&args);
ff105f75 346 if (error)
57c9fccb 347 goto out;
57c9fccb
NS
348
349 /*
350 * If this is a synchronous mount, make sure that the
351 * transaction goes to disk before returning to the user.
352 */
ff105f75 353 if (mp->m_flags & XFS_MOUNT_WSYNC)
57c9fccb 354 xfs_trans_set_sync(args.trans);
57c9fccb 355
56b2de80
DC
356 if ((flags & ATTR_KERNOTIME) == 0)
357 xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
358
57c9fccb
NS
359 /*
360 * Commit the last in the sequence of transactions.
361 */
362 xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE);
de5a3f46 363 error = xfs_trans_commit(args.trans);
57c9fccb
NS
364 xfs_iunlock(dp, XFS_ILOCK_EXCL);
365
ff105f75 366 return error;
57c9fccb 367
5c33baee
CH
368out_defer_cancel:
369 xfs_defer_cancel(&dfops);
57c9fccb 370out:
3fbc4d7d
DW
371 if (leaf_bp)
372 xfs_trans_brelse(args.trans, leaf_bp);
3d7434fe
CH
373 if (args.trans)
374 xfs_trans_cancel(args.trans);
57c9fccb 375 xfs_iunlock(dp, XFS_ILOCK_EXCL);
ff105f75 376 return error;
57c9fccb
NS
377}
378
ff105f75
DC
379/*
380 * Generic handler routine to remove a name from an attribute list.
381 * Transitions attribute list from Btree to shortform as necessary.
382 */
5e656dbb 383int
ff105f75
DC
384xfs_attr_remove(
385 struct xfs_inode *dp,
386 const unsigned char *name,
387 int flags)
5e656dbb 388{
ff105f75
DC
389 struct xfs_mount *mp = dp->i_mount;
390 struct xfs_da_args args;
f33cea1a 391 struct xfs_defer_ops dfops;
ff105f75
DC
392 xfs_fsblock_t firstblock;
393 int error;
5e656dbb 394
79896434 395 XFS_STATS_INC(mp, xs_attr_remove);
5e656dbb
BN
396
397 if (XFS_FORCED_SHUTDOWN(dp->i_mount))
12b53197 398 return -EIO;
ff105f75 399
ff105f75 400 error = xfs_attr_args_init(&args, dp, name, flags);
5e656dbb
BN
401 if (error)
402 return error;
403
57c9fccb 404 args.firstblock = &firstblock;
f33cea1a 405 args.dfops = &dfops;
57c9fccb 406
a2ceac1f
DC
407 /*
408 * we have no control over the attribute names that userspace passes us
409 * to remove, so we have to allow the name lookup prior to attribute
410 * removal to fail.
411 */
412 args.op_flags = XFS_DA_OP_OKNOENT;
413
43cf369d 414 error = xfs_qm_dqattach(dp);
56b2de80
DC
415 if (error)
416 return error;
57c9fccb 417
57c9fccb
NS
418 /*
419 * Root fork attributes can use reserved data blocks for this
420 * operation if necessary
421 */
9074815c
CH
422 error = xfs_trans_alloc(mp, &M_RES(mp)->tr_attrrm,
423 XFS_ATTRRM_SPACE_RES(mp), 0,
424 (flags & ATTR_ROOT) ? XFS_TRANS_RESERVE : 0,
425 &args.trans);
426 if (error)
ff105f75 427 return error;
e599d8b9
BF
428 xfs_defer_init(&dfops, &firstblock);
429 args.trans->t_dfops = &dfops;
57c9fccb
NS
430
431 xfs_ilock(dp, XFS_ILOCK_EXCL);
432 /*
433 * No need to make quota reservations here. We expect to release some
434 * blocks not allocate in the common case.
435 */
a2ceac1f 436 xfs_trans_ijoin(args.trans, dp, 0);
57c9fccb 437
5e656dbb 438 if (!xfs_inode_hasattr(dp)) {
12b53197 439 error = -ENOATTR;
ff105f75 440 } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
57c9fccb
NS
441 ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
442 error = xfs_attr_shortform_remove(&args);
57c9fccb
NS
443 } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
444 error = xfs_attr_leaf_removename(&args);
445 } else {
446 error = xfs_attr_node_removename(&args);
447 }
ff105f75
DC
448
449 if (error)
57c9fccb 450 goto out;
57c9fccb
NS
451
452 /*
453 * If this is a synchronous mount, make sure that the
454 * transaction goes to disk before returning to the user.
455 */
ff105f75 456 if (mp->m_flags & XFS_MOUNT_WSYNC)
57c9fccb 457 xfs_trans_set_sync(args.trans);
57c9fccb 458
56b2de80
DC
459 if ((flags & ATTR_KERNOTIME) == 0)
460 xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
461
57c9fccb
NS
462 /*
463 * Commit the last in the sequence of transactions.
464 */
465 xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE);
de5a3f46 466 error = xfs_trans_commit(args.trans);
57c9fccb
NS
467 xfs_iunlock(dp, XFS_ILOCK_EXCL);
468
ff105f75 469 return error;
57c9fccb
NS
470
471out:
3d7434fe
CH
472 if (args.trans)
473 xfs_trans_cancel(args.trans);
ff105f75
DC
474 xfs_iunlock(dp, XFS_ILOCK_EXCL);
475 return error;
5e656dbb
BN
476}
477
57c9fccb
NS
478/*========================================================================
479 * External routines when attribute list is inside the inode
480 *========================================================================*/
481
482/*
483 * Add a name to the shortform attribute list structure
484 * This is the external routine.
485 */
486STATIC int
487xfs_attr_shortform_addname(xfs_da_args_t *args)
488{
ca86e759 489 int newsize, forkoff, retval;
57c9fccb 490
a2ceac1f
DC
491 trace_xfs_attr_sf_addname(args);
492
57c9fccb 493 retval = xfs_attr_shortform_lookup(args);
12b53197 494 if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
af43ca9f 495 return retval;
12b53197 496 } else if (retval == -EEXIST) {
57c9fccb 497 if (args->flags & ATTR_CREATE)
af43ca9f 498 return retval;
57c9fccb 499 retval = xfs_attr_shortform_remove(args);
dee7606b
DW
500 if (retval)
501 return retval;
502 /*
503 * Since we have removed the old attr, clear ATTR_REPLACE so
504 * that the leaf format add routine won't trip over the attr
505 * not being around.
506 */
507 args->flags &= ~ATTR_REPLACE;
57c9fccb
NS
508 }
509
ca86e759
NS
510 if (args->namelen >= XFS_ATTR_SF_ENTSIZE_MAX ||
511 args->valuelen >= XFS_ATTR_SF_ENTSIZE_MAX)
12b53197 512 return -ENOSPC;
ca86e759 513
57c9fccb
NS
514 newsize = XFS_ATTR_SF_TOTSIZE(args->dp);
515 newsize += XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);
ca86e759
NS
516
517 forkoff = xfs_attr_shortform_bytesfit(args->dp, newsize);
518 if (!forkoff)
12b53197 519 return -ENOSPC;
ca86e759
NS
520
521 xfs_attr_shortform_add(args, forkoff);
af43ca9f 522 return 0;
57c9fccb
NS
523}
524
525
526/*========================================================================
527 * External routines when attribute list is one block
528 *========================================================================*/
529
530/*
531 * Add a name to the leaf attribute list structure
532 *
533 * This leaf block cannot have a "remote" value, we only call this routine
534 * if bmap_one_block() says there is only one block (ie: no remote blks).
535 */
5e656dbb 536STATIC int
57c9fccb
NS
537xfs_attr_leaf_addname(xfs_da_args_t *args)
538{
539 xfs_inode_t *dp;
a2ceac1f 540 struct xfs_buf *bp;
0b66d459 541 int retval, error, forkoff;
57c9fccb 542
a2ceac1f
DC
543 trace_xfs_attr_leaf_addname(args);
544
57c9fccb
NS
545 /*
546 * Read the (only) block in the attribute list in.
547 */
548 dp = args->dp;
549 args->blkno = 0;
a24374f4 550 error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
57c9fccb 551 if (error)
a2ceac1f 552 return error;
57c9fccb
NS
553
554 /*
555 * Look up the given attribute in the leaf block. Figure out if
556 * the given flags produce an error or call for an atomic rename.
557 */
a24374f4 558 retval = xfs_attr3_leaf_lookup_int(bp, args);
12b53197 559 if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
a2ceac1f 560 xfs_trans_brelse(args->trans, bp);
a24374f4 561 return retval;
12b53197 562 } else if (retval == -EEXIST) {
57c9fccb 563 if (args->flags & ATTR_CREATE) { /* pure create op */
a2ceac1f 564 xfs_trans_brelse(args->trans, bp);
a24374f4 565 return retval;
57c9fccb 566 }
a2ceac1f
DC
567
568 trace_xfs_attr_leaf_replace(args);
569
ff105f75 570 /* save the attribute state for later removal*/
5e656dbb 571 args->op_flags |= XFS_DA_OP_RENAME; /* an atomic rename */
57c9fccb
NS
572 args->blkno2 = args->blkno; /* set 2nd entry info*/
573 args->index2 = args->index;
574 args->rmtblkno2 = args->rmtblkno;
575 args->rmtblkcnt2 = args->rmtblkcnt;
ff105f75
DC
576 args->rmtvaluelen2 = args->rmtvaluelen;
577
578 /*
579 * clear the remote attr state now that it is saved so that the
580 * values reflect the state of the attribute we are about to
581 * add, not the attribute we just found and will remove later.
582 */
583 args->rmtblkno = 0;
584 args->rmtblkcnt = 0;
585 args->rmtvaluelen = 0;
57c9fccb
NS
586 }
587
588 /*
589 * Add the attribute to the leaf block, transitioning to a Btree
590 * if required.
591 */
a24374f4 592 retval = xfs_attr3_leaf_add(bp, args);
12b53197 593 if (retval == -ENOSPC) {
57c9fccb
NS
594 /*
595 * Promote the attribute list to the Btree format, then
596 * Commit that transaction so that the node_addname() call
597 * can manage its own transactions.
598 */
f33cea1a 599 xfs_defer_init(args->dfops, args->firstblock);
a24374f4 600 error = xfs_attr3_leaf_to_node(args);
5c33baee
CH
601 if (error)
602 goto out_defer_cancel;
603 xfs_defer_ijoin(args->dfops, dp);
604 error = xfs_defer_finish(&args->trans, args->dfops);
605 if (error)
606 goto out_defer_cancel;
57c9fccb 607
57c9fccb
NS
608 /*
609 * Commit the current trans (including the inode) and start
610 * a new one.
611 */
d67406c9 612 error = xfs_trans_roll_inode(&args->trans, dp);
5e656dbb 613 if (error)
af43ca9f 614 return error;
57c9fccb
NS
615
616 /*
617 * Fob the whole rest of the problem off on the Btree code.
618 */
619 error = xfs_attr_node_addname(args);
af43ca9f 620 return error;
57c9fccb
NS
621 }
622
623 /*
624 * Commit the transaction that added the attr name so that
625 * later routines can manage their own transactions.
626 */
d67406c9 627 error = xfs_trans_roll_inode(&args->trans, dp);
5e656dbb 628 if (error)
af43ca9f 629 return error;
57c9fccb
NS
630
631 /*
632 * If there was an out-of-line value, allocate the blocks we
633 * identified for its storage and copy the value. This is done
634 * after we create the attribute so that we don't overflow the
635 * maximum size of a transaction and/or hit a deadlock.
636 */
637 if (args->rmtblkno > 0) {
638 error = xfs_attr_rmtval_set(args);
639 if (error)
af43ca9f 640 return error;
57c9fccb
NS
641 }
642
643 /*
644 * If this is an atomic rename operation, we must "flip" the
645 * incomplete flags on the "new" and "old" attribute/value pairs
646 * so that one disappears and one appears atomically. Then we
647 * must remove the "old" attribute/value pair.
648 */
5e656dbb 649 if (args->op_flags & XFS_DA_OP_RENAME) {
57c9fccb
NS
650 /*
651 * In a separate transaction, set the incomplete flag on the
652 * "old" attr and clear the incomplete flag on the "new" attr.
653 */
a24374f4 654 error = xfs_attr3_leaf_flipflags(args);
57c9fccb 655 if (error)
af43ca9f 656 return error;
57c9fccb
NS
657
658 /*
659 * Dismantle the "old" attribute/value pair by removing
660 * a "remote" value (if it exists).
661 */
662 args->index = args->index2;
663 args->blkno = args->blkno2;
664 args->rmtblkno = args->rmtblkno2;
665 args->rmtblkcnt = args->rmtblkcnt2;
ff105f75 666 args->rmtvaluelen = args->rmtvaluelen2;
57c9fccb
NS
667 if (args->rmtblkno) {
668 error = xfs_attr_rmtval_remove(args);
669 if (error)
af43ca9f 670 return error;
57c9fccb
NS
671 }
672
673 /*
674 * Read in the block containing the "old" attr, then
675 * remove the "old" attr from that block (neat, huh!)
676 */
a24374f4 677 error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
a2ceac1f 678 -1, &bp);
57c9fccb 679 if (error)
a2ceac1f
DC
680 return error;
681
a24374f4 682 xfs_attr3_leaf_remove(bp, args);
57c9fccb
NS
683
684 /*
685 * If the result is small enough, shrink it all into the inode.
686 */
ca86e759 687 if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
f33cea1a 688 xfs_defer_init(args->dfops, args->firstblock);
a24374f4 689 error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
57c9fccb 690 /* bp is gone due to xfs_da_shrink_inode */
5c33baee
CH
691 if (error)
692 goto out_defer_cancel;
693 xfs_defer_ijoin(args->dfops, dp);
694 error = xfs_defer_finish(&args->trans, args->dfops);
695 if (error)
696 goto out_defer_cancel;
a2ceac1f 697 }
57c9fccb
NS
698
699 /*
700 * Commit the remove and start the next trans in series.
701 */
d67406c9 702 error = xfs_trans_roll_inode(&args->trans, dp);
57c9fccb
NS
703
704 } else if (args->rmtblkno > 0) {
705 /*
706 * Added a "remote" value, just clear the incomplete flag.
707 */
a24374f4 708 error = xfs_attr3_leaf_clearflag(args);
57c9fccb 709 }
a24374f4 710 return error;
5c33baee
CH
711out_defer_cancel:
712 xfs_defer_cancel(args->dfops);
5c33baee 713 return error;
57c9fccb
NS
714}
715
716/*
717 * Remove a name from the leaf attribute list structure
718 *
719 * This leaf block cannot have a "remote" value, we only call this routine
720 * if bmap_one_block() says there is only one block (ie: no remote blks).
721 */
722STATIC int
723xfs_attr_leaf_removename(xfs_da_args_t *args)
724{
725 xfs_inode_t *dp;
a2ceac1f 726 struct xfs_buf *bp;
0b66d459 727 int error, forkoff;
57c9fccb 728
a2ceac1f
DC
729 trace_xfs_attr_leaf_removename(args);
730
57c9fccb
NS
731 /*
732 * Remove the attribute.
733 */
734 dp = args->dp;
735 args->blkno = 0;
a24374f4 736 error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
a2ceac1f
DC
737 if (error)
738 return error;
57c9fccb 739
a24374f4 740 error = xfs_attr3_leaf_lookup_int(bp, args);
12b53197 741 if (error == -ENOATTR) {
a2ceac1f 742 xfs_trans_brelse(args->trans, bp);
78d6585c 743 return error;
57c9fccb
NS
744 }
745
a24374f4 746 xfs_attr3_leaf_remove(bp, args);
57c9fccb
NS
747
748 /*
749 * If the result is small enough, shrink it all into the inode.
750 */
ca86e759 751 if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
f33cea1a 752 xfs_defer_init(args->dfops, args->firstblock);
a24374f4 753 error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
57c9fccb 754 /* bp is gone due to xfs_da_shrink_inode */
5c33baee
CH
755 if (error)
756 goto out_defer_cancel;
757 xfs_defer_ijoin(args->dfops, dp);
758 error = xfs_defer_finish(&args->trans, args->dfops);
759 if (error)
760 goto out_defer_cancel;
a2ceac1f 761 }
a24374f4 762 return 0;
5c33baee
CH
763out_defer_cancel:
764 xfs_defer_cancel(args->dfops);
5c33baee 765 return error;
57c9fccb
NS
766}
767
5e656dbb
BN
768/*
769 * Look up a name in a leaf attribute list structure.
770 *
771 * This leaf block cannot have a "remote" value, we only call this routine
772 * if bmap_one_block() says there is only one block (ie: no remote blks).
773 */
774STATIC int
775xfs_attr_leaf_get(xfs_da_args_t *args)
776{
a2ceac1f 777 struct xfs_buf *bp;
5e656dbb
BN
778 int error;
779
a2ceac1f
DC
780 trace_xfs_attr_leaf_get(args);
781
5e656dbb 782 args->blkno = 0;
a24374f4 783 error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
5e656dbb 784 if (error)
a2ceac1f 785 return error;
5e656dbb 786
a24374f4 787 error = xfs_attr3_leaf_lookup_int(bp, args);
12b53197 788 if (error != -EEXIST) {
a2ceac1f 789 xfs_trans_brelse(args->trans, bp);
a24374f4 790 return error;
5e656dbb 791 }
a24374f4 792 error = xfs_attr3_leaf_getvalue(bp, args);
a2ceac1f 793 xfs_trans_brelse(args->trans, bp);
5e656dbb
BN
794 if (!error && (args->rmtblkno > 0) && !(args->flags & ATTR_KERNOVAL)) {
795 error = xfs_attr_rmtval_get(args);
796 }
a24374f4 797 return error;
5e656dbb
BN
798}
799
57c9fccb 800/*========================================================================
ff105f75 801 * External routines when attribute list size > geo->blksize
57c9fccb
NS
802 *========================================================================*/
803
804/*
805 * Add a name to a Btree-format attribute list.
806 *
807 * This will involve walking down the Btree, and may involve splitting
808 * leaf nodes and even splitting intermediate nodes up to and including
809 * the root node (a special case of an intermediate node).
810 *
811 * "Remote" attribute values confuse the issue and atomic rename operations
812 * add a whole extra layer of confusion on top of that.
813 */
814STATIC int
815xfs_attr_node_addname(xfs_da_args_t *args)
816{
817 xfs_da_state_t *state;
818 xfs_da_state_blk_t *blk;
819 xfs_inode_t *dp;
820 xfs_mount_t *mp;
0b66d459 821 int retval, error;
57c9fccb 822
a2ceac1f
DC
823 trace_xfs_attr_node_addname(args);
824
57c9fccb
NS
825 /*
826 * Fill in bucket of arguments/results/context to carry around.
827 */
828 dp = args->dp;
829 mp = dp->i_mount;
830restart:
831 state = xfs_da_state_alloc();
832 state->args = args;
833 state->mp = mp;
57c9fccb
NS
834
835 /*
836 * Search to see if name already exists, and get back a pointer
837 * to where it should go.
838 */
88b32f06 839 error = xfs_da3_node_lookup_int(state, &retval);
57c9fccb
NS
840 if (error)
841 goto out;
842 blk = &state->path.blk[ state->path.active-1 ];
843 ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
12b53197 844 if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
57c9fccb 845 goto out;
12b53197 846 } else if (retval == -EEXIST) {
57c9fccb
NS
847 if (args->flags & ATTR_CREATE)
848 goto out;
a2ceac1f
DC
849
850 trace_xfs_attr_node_replace(args);
851
ff105f75 852 /* save the attribute state for later removal*/
5e656dbb 853 args->op_flags |= XFS_DA_OP_RENAME; /* atomic rename op */
57c9fccb
NS
854 args->blkno2 = args->blkno; /* set 2nd entry info*/
855 args->index2 = args->index;
856 args->rmtblkno2 = args->rmtblkno;
857 args->rmtblkcnt2 = args->rmtblkcnt;
ff105f75
DC
858 args->rmtvaluelen2 = args->rmtvaluelen;
859
860 /*
861 * clear the remote attr state now that it is saved so that the
862 * values reflect the state of the attribute we are about to
863 * add, not the attribute we just found and will remove later.
864 */
57c9fccb
NS
865 args->rmtblkno = 0;
866 args->rmtblkcnt = 0;
ff105f75 867 args->rmtvaluelen = 0;
57c9fccb
NS
868 }
869
a24374f4 870 retval = xfs_attr3_leaf_add(blk->bp, state->args);
12b53197 871 if (retval == -ENOSPC) {
57c9fccb
NS
872 if (state->path.active == 1) {
873 /*
874 * Its really a single leaf node, but it had
875 * out-of-line values so it looked like it *might*
876 * have been a b-tree.
877 */
878 xfs_da_state_free(state);
504dbe46 879 state = NULL;
f33cea1a 880 xfs_defer_init(args->dfops, args->firstblock);
a24374f4 881 error = xfs_attr3_leaf_to_node(args);
5c33baee
CH
882 if (error)
883 goto out_defer_cancel;
884 xfs_defer_ijoin(args->dfops, dp);
885 error = xfs_defer_finish(&args->trans, args->dfops);
886 if (error)
887 goto out_defer_cancel;
57c9fccb 888
57c9fccb
NS
889 /*
890 * Commit the node conversion and start the next
891 * trans in the chain.
892 */
d67406c9 893 error = xfs_trans_roll_inode(&args->trans, dp);
5e656dbb 894 if (error)
57c9fccb
NS
895 goto out;
896
897 goto restart;
898 }
899
900 /*
901 * Split as many Btree elements as required.
902 * This code tracks the new and old attr's location
903 * in the index/blkno/rmtblkno/rmtblkcnt fields and
904 * in the index2/blkno2/rmtblkno2/rmtblkcnt2 fields.
905 */
f33cea1a 906 xfs_defer_init(args->dfops, args->firstblock);
88b32f06 907 error = xfs_da3_split(state);
5c33baee
CH
908 if (error)
909 goto out_defer_cancel;
910 xfs_defer_ijoin(args->dfops, dp);
911 error = xfs_defer_finish(&args->trans, args->dfops);
912 if (error)
913 goto out_defer_cancel;
57c9fccb
NS
914 } else {
915 /*
916 * Addition succeeded, update Btree hashvals.
917 */
88b32f06 918 xfs_da3_fixhashpath(state, &state->path);
57c9fccb
NS
919 }
920
921 /*
922 * Kill the state structure, we're done with it and need to
923 * allow the buffers to come back later.
924 */
925 xfs_da_state_free(state);
926 state = NULL;
927
928 /*
929 * Commit the leaf addition or btree split and start the next
930 * trans in the chain.
931 */
d67406c9 932 error = xfs_trans_roll_inode(&args->trans, dp);
5e656dbb 933 if (error)
57c9fccb
NS
934 goto out;
935
936 /*
937 * If there was an out-of-line value, allocate the blocks we
938 * identified for its storage and copy the value. This is done
939 * after we create the attribute so that we don't overflow the
940 * maximum size of a transaction and/or hit a deadlock.
941 */
942 if (args->rmtblkno > 0) {
943 error = xfs_attr_rmtval_set(args);
944 if (error)
af43ca9f 945 return error;
57c9fccb
NS
946 }
947
948 /*
949 * If this is an atomic rename operation, we must "flip" the
950 * incomplete flags on the "new" and "old" attribute/value pairs
951 * so that one disappears and one appears atomically. Then we
952 * must remove the "old" attribute/value pair.
953 */
5e656dbb 954 if (args->op_flags & XFS_DA_OP_RENAME) {
57c9fccb
NS
955 /*
956 * In a separate transaction, set the incomplete flag on the
957 * "old" attr and clear the incomplete flag on the "new" attr.
958 */
a24374f4 959 error = xfs_attr3_leaf_flipflags(args);
57c9fccb
NS
960 if (error)
961 goto out;
962
963 /*
964 * Dismantle the "old" attribute/value pair by removing
965 * a "remote" value (if it exists).
966 */
967 args->index = args->index2;
968 args->blkno = args->blkno2;
969 args->rmtblkno = args->rmtblkno2;
970 args->rmtblkcnt = args->rmtblkcnt2;
ff105f75 971 args->rmtvaluelen = args->rmtvaluelen2;
57c9fccb
NS
972 if (args->rmtblkno) {
973 error = xfs_attr_rmtval_remove(args);
974 if (error)
af43ca9f 975 return error;
57c9fccb
NS
976 }
977
978 /*
979 * Re-find the "old" attribute entry after any split ops.
980 * The INCOMPLETE flag means that we will find the "old"
981 * attr, not the "new" one.
982 */
983 args->flags |= XFS_ATTR_INCOMPLETE;
984 state = xfs_da_state_alloc();
985 state->args = args;
986 state->mp = mp;
57c9fccb 987 state->inleaf = 0;
88b32f06 988 error = xfs_da3_node_lookup_int(state, &retval);
57c9fccb
NS
989 if (error)
990 goto out;
991
992 /*
993 * Remove the name and update the hashvals in the tree.
994 */
995 blk = &state->path.blk[ state->path.active-1 ];
996 ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
a24374f4 997 error = xfs_attr3_leaf_remove(blk->bp, args);
88b32f06 998 xfs_da3_fixhashpath(state, &state->path);
57c9fccb
NS
999
1000 /*
1001 * Check to see if the tree needs to be collapsed.
1002 */
1003 if (retval && (state->path.active > 1)) {
f33cea1a 1004 xfs_defer_init(args->dfops, args->firstblock);
88b32f06 1005 error = xfs_da3_join(state);
5c33baee
CH
1006 if (error)
1007 goto out_defer_cancel;
1008 xfs_defer_ijoin(args->dfops, dp);
1009 error = xfs_defer_finish(&args->trans, args->dfops);
1010 if (error)
1011 goto out_defer_cancel;
57c9fccb
NS
1012 }
1013
1014 /*
1015 * Commit and start the next trans in the chain.
1016 */
d67406c9 1017 error = xfs_trans_roll_inode(&args->trans, dp);
5e656dbb 1018 if (error)
57c9fccb
NS
1019 goto out;
1020
1021 } else if (args->rmtblkno > 0) {
1022 /*
1023 * Added a "remote" value, just clear the incomplete flag.
1024 */
a24374f4 1025 error = xfs_attr3_leaf_clearflag(args);
57c9fccb
NS
1026 if (error)
1027 goto out;
1028 }
1029 retval = error = 0;
1030
1031out:
1032 if (state)
1033 xfs_da_state_free(state);
1034 if (error)
af43ca9f
DC
1035 return error;
1036 return retval;
5c33baee
CH
1037out_defer_cancel:
1038 xfs_defer_cancel(args->dfops);
5c33baee 1039 goto out;
57c9fccb
NS
1040}
1041
1042/*
1043 * Remove a name from a B-tree attribute list.
1044 *
1045 * This will involve walking down the Btree, and may involve joining
1046 * leaf nodes and even joining intermediate nodes up to and including
1047 * the root node (a special case of an intermediate node).
1048 */
1049STATIC int
1050xfs_attr_node_removename(xfs_da_args_t *args)
1051{
1052 xfs_da_state_t *state;
1053 xfs_da_state_blk_t *blk;
1054 xfs_inode_t *dp;
a2ceac1f 1055 struct xfs_buf *bp;
0b66d459 1056 int retval, error, forkoff;
57c9fccb 1057
a2ceac1f
DC
1058 trace_xfs_attr_node_removename(args);
1059
57c9fccb
NS
1060 /*
1061 * Tie a string around our finger to remind us where we are.
1062 */
1063 dp = args->dp;
1064 state = xfs_da_state_alloc();
1065 state->args = args;
1066 state->mp = dp->i_mount;
57c9fccb
NS
1067
1068 /*
1069 * Search to see if name exists, and get back a pointer to it.
1070 */
88b32f06 1071 error = xfs_da3_node_lookup_int(state, &retval);
12b53197 1072 if (error || (retval != -EEXIST)) {
57c9fccb
NS
1073 if (error == 0)
1074 error = retval;
1075 goto out;
1076 }
1077
1078 /*
1079 * If there is an out-of-line value, de-allocate the blocks.
1080 * This is done before we remove the attribute so that we don't
1081 * overflow the maximum size of a transaction and/or hit a deadlock.
1082 */
1083 blk = &state->path.blk[ state->path.active-1 ];
1084 ASSERT(blk->bp != NULL);
1085 ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
1086 if (args->rmtblkno > 0) {
1087 /*
1088 * Fill in disk block numbers in the state structure
1089 * so that we can get the buffers back after we commit
1090 * several transactions in the following calls.
1091 */
1092 error = xfs_attr_fillstate(state);
1093 if (error)
1094 goto out;
1095
1096 /*
1097 * Mark the attribute as INCOMPLETE, then bunmapi() the
1098 * remote value.
1099 */
a24374f4 1100 error = xfs_attr3_leaf_setflag(args);
57c9fccb
NS
1101 if (error)
1102 goto out;
1103 error = xfs_attr_rmtval_remove(args);
1104 if (error)
1105 goto out;
1106
1107 /*
1108 * Refill the state structure with buffers, the prior calls
1109 * released our buffers.
1110 */
1111 error = xfs_attr_refillstate(state);
1112 if (error)
1113 goto out;
1114 }
1115
1116 /*
1117 * Remove the name and update the hashvals in the tree.
1118 */
1119 blk = &state->path.blk[ state->path.active-1 ];
1120 ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
a24374f4 1121 retval = xfs_attr3_leaf_remove(blk->bp, args);
88b32f06 1122 xfs_da3_fixhashpath(state, &state->path);
57c9fccb
NS
1123
1124 /*
1125 * Check to see if the tree needs to be collapsed.
1126 */
1127 if (retval && (state->path.active > 1)) {
f33cea1a 1128 xfs_defer_init(args->dfops, args->firstblock);
88b32f06 1129 error = xfs_da3_join(state);
5c33baee
CH
1130 if (error)
1131 goto out_defer_cancel;
1132 xfs_defer_ijoin(args->dfops, dp);
1133 error = xfs_defer_finish(&args->trans, args->dfops);
1134 if (error)
1135 goto out_defer_cancel;
57c9fccb
NS
1136 /*
1137 * Commit the Btree join operation and start a new trans.
1138 */
d67406c9 1139 error = xfs_trans_roll_inode(&args->trans, dp);
5e656dbb 1140 if (error)
57c9fccb
NS
1141 goto out;
1142 }
1143
1144 /*
1145 * If the result is small enough, push it all into the inode.
1146 */
1147 if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
1148 /*
1149 * Have to get rid of the copy of this dabuf in the state.
1150 */
1151 ASSERT(state->path.active == 1);
1152 ASSERT(state->path.blk[0].bp);
57c9fccb
NS
1153 state->path.blk[0].bp = NULL;
1154
a24374f4 1155 error = xfs_attr3_leaf_read(args->trans, args->dp, 0, -1, &bp);
57c9fccb
NS
1156 if (error)
1157 goto out;
57c9fccb 1158
ca86e759 1159 if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
f33cea1a 1160 xfs_defer_init(args->dfops, args->firstblock);
a24374f4 1161 error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
57c9fccb 1162 /* bp is gone due to xfs_da_shrink_inode */
5c33baee
CH
1163 if (error)
1164 goto out_defer_cancel;
1165 xfs_defer_ijoin(args->dfops, dp);
1166 error = xfs_defer_finish(&args->trans, args->dfops);
1167 if (error)
1168 goto out_defer_cancel;
57c9fccb 1169 } else
a2ceac1f 1170 xfs_trans_brelse(args->trans, bp);
57c9fccb
NS
1171 }
1172 error = 0;
1173
1174out:
1175 xfs_da_state_free(state);
af43ca9f 1176 return error;
5c33baee
CH
1177out_defer_cancel:
1178 xfs_defer_cancel(args->dfops);
5c33baee 1179 goto out;
57c9fccb
NS
1180}
1181
1182/*
1183 * Fill in the disk block numbers in the state structure for the buffers
1184 * that are attached to the state structure.
1185 * This is done so that we can quickly reattach ourselves to those buffers
5e656dbb 1186 * after some set of transaction commits have released these buffers.
57c9fccb
NS
1187 */
1188STATIC int
1189xfs_attr_fillstate(xfs_da_state_t *state)
1190{
1191 xfs_da_state_path_t *path;
1192 xfs_da_state_blk_t *blk;
1193 int level;
1194
a2ceac1f
DC
1195 trace_xfs_attr_fillstate(state->args);
1196
57c9fccb
NS
1197 /*
1198 * Roll down the "path" in the state structure, storing the on-disk
1199 * block number for those buffers in the "path".
1200 */
1201 path = &state->path;
1202 ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
1203 for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
1204 if (blk->bp) {
a2ceac1f 1205 blk->disk_blkno = XFS_BUF_ADDR(blk->bp);
57c9fccb
NS
1206 blk->bp = NULL;
1207 } else {
1208 blk->disk_blkno = 0;
1209 }
1210 }
1211
1212 /*
1213 * Roll down the "altpath" in the state structure, storing the on-disk
1214 * block number for those buffers in the "altpath".
1215 */
1216 path = &state->altpath;
1217 ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
1218 for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
1219 if (blk->bp) {
a2ceac1f 1220 blk->disk_blkno = XFS_BUF_ADDR(blk->bp);
57c9fccb
NS
1221 blk->bp = NULL;
1222 } else {
1223 blk->disk_blkno = 0;
1224 }
1225 }
1226
af43ca9f 1227 return 0;
57c9fccb
NS
1228}
1229
1230/*
1231 * Reattach the buffers to the state structure based on the disk block
1232 * numbers stored in the state structure.
5e656dbb 1233 * This is done after some set of transaction commits have released those
57c9fccb
NS
1234 * buffers from our grip.
1235 */
1236STATIC int
1237xfs_attr_refillstate(xfs_da_state_t *state)
1238{
1239 xfs_da_state_path_t *path;
1240 xfs_da_state_blk_t *blk;
1241 int level, error;
1242
a2ceac1f
DC
1243 trace_xfs_attr_refillstate(state->args);
1244
57c9fccb
NS
1245 /*
1246 * Roll down the "path" in the state structure, storing the on-disk
1247 * block number for those buffers in the "path".
1248 */
1249 path = &state->path;
1250 ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
1251 for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
1252 if (blk->disk_blkno) {
88b32f06 1253 error = xfs_da3_node_read(state->args->trans,
57c9fccb
NS
1254 state->args->dp,
1255 blk->blkno, blk->disk_blkno,
1256 &blk->bp, XFS_ATTR_FORK);
1257 if (error)
af43ca9f 1258 return error;
57c9fccb
NS
1259 } else {
1260 blk->bp = NULL;
1261 }
1262 }
1263
1264 /*
1265 * Roll down the "altpath" in the state structure, storing the on-disk
1266 * block number for those buffers in the "altpath".
1267 */
1268 path = &state->altpath;
1269 ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
1270 for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
1271 if (blk->disk_blkno) {
88b32f06 1272 error = xfs_da3_node_read(state->args->trans,
57c9fccb
NS
1273 state->args->dp,
1274 blk->blkno, blk->disk_blkno,
1275 &blk->bp, XFS_ATTR_FORK);
1276 if (error)
af43ca9f 1277 return error;
57c9fccb
NS
1278 } else {
1279 blk->bp = NULL;
1280 }
1281 }
1282
af43ca9f 1283 return 0;
57c9fccb
NS
1284}
1285
5e656dbb
BN
1286/*
1287 * Look up a filename in a node attribute list.
1288 *
1289 * This routine gets called for any attribute fork that has more than one
1290 * block, ie: both true Btree attr lists and for single-leaf-blocks with
1291 * "remote" values taking up more blocks.
1292 */
1293STATIC int
1294xfs_attr_node_get(xfs_da_args_t *args)
1295{
1296 xfs_da_state_t *state;
1297 xfs_da_state_blk_t *blk;
1298 int error, retval;
1299 int i;
1300
a2ceac1f
DC
1301 trace_xfs_attr_node_get(args);
1302
5e656dbb
BN
1303 state = xfs_da_state_alloc();
1304 state->args = args;
1305 state->mp = args->dp->i_mount;
5e656dbb
BN
1306
1307 /*
1308 * Search to see if name exists, and get back a pointer to it.
1309 */
88b32f06 1310 error = xfs_da3_node_lookup_int(state, &retval);
5e656dbb
BN
1311 if (error) {
1312 retval = error;
12b53197 1313 } else if (retval == -EEXIST) {
5e656dbb
BN
1314 blk = &state->path.blk[ state->path.active-1 ];
1315 ASSERT(blk->bp != NULL);
1316 ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
1317
1318 /*
1319 * Get the value, local or "remote"
1320 */
a24374f4 1321 retval = xfs_attr3_leaf_getvalue(blk->bp, args);
5e656dbb
BN
1322 if (!retval && (args->rmtblkno > 0)
1323 && !(args->flags & ATTR_KERNOVAL)) {
1324 retval = xfs_attr_rmtval_get(args);
1325 }
1326 }
1327
1328 /*
1329 * If not in a transaction, we have to release all the buffers.
1330 */
1331 for (i = 0; i < state->path.active; i++) {
a2ceac1f 1332 xfs_trans_brelse(args->trans, state->path.blk[i].bp);
5e656dbb
BN
1333 state->path.blk[i].bp = NULL;
1334 }
1335
1336 xfs_da_state_free(state);
af43ca9f 1337 return retval;
5e656dbb 1338}