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