]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - libxfs/xfs_attr.c
Support for updated inline extended attributes format (attr2).
[thirdparty/xfsprogs-dev.git] / libxfs / xfs_attr.c
1 /*
2 * Copyright (c) 2005 Silicon Graphics, Inc. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like. Any license provided herein, whether implied or
15 * otherwise, applies only to this software file. Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write the Free Software Foundation, Inc., 59
21 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
22 *
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
25 *
26 * http://www.sgi.com
27 *
28 * For further information regarding this notice, see:
29 *
30 * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
31 */
32
33 #include <xfs.h>
34
35 /*
36 * xfs_attr.c
37 *
38 * Provide the external interfaces to manage attribute lists.
39 */
40
41 /*========================================================================
42 * Function prototypes for the kernel.
43 *========================================================================*/
44
45 /*
46 * Internal routines when attribute list fits inside the inode.
47 */
48 STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
49
50 /*
51 * Internal routines when attribute list is one block.
52 */
53 STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
54 STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
55 STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
56 STATIC int xfs_attr_leaf_list(xfs_attr_list_context_t *context);
57
58 /*
59 * Internal routines when attribute list is more than one block.
60 */
61 STATIC int xfs_attr_node_get(xfs_da_args_t *args);
62 STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
63 STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
64 STATIC int xfs_attr_node_list(xfs_attr_list_context_t *context);
65 STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
66 STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
67
68 /*
69 * Routines to manipulate out-of-line attribute values.
70 */
71 STATIC int xfs_attr_rmtval_get(xfs_da_args_t *args);
72 STATIC int xfs_attr_rmtval_set(xfs_da_args_t *args);
73 STATIC int xfs_attr_rmtval_remove(xfs_da_args_t *args);
74
75 #define ATTR_RMTVALUE_MAPSIZE 1 /* # of map entries at once */
76
77 /*========================================================================
78 * Overall external interface routines.
79 *========================================================================*/
80
81 int
82 xfs_attr_set_int(xfs_inode_t *dp, char *name, int namelen,
83 char *value, int valuelen, int flags)
84 {
85 xfs_da_args_t args;
86 xfs_fsblock_t firstblock;
87 xfs_bmap_free_t flist;
88 int error, err2, committed;
89 int local, size;
90 uint nblks;
91 xfs_mount_t *mp = dp->i_mount;
92 int rsvd = (flags & ATTR_ROOT) != 0;
93
94 /*
95 * Attach the dquots to the inode.
96 */
97 if ((error = XFS_QM_DQATTACH(mp, dp, 0)))
98 return (error);
99
100 /*
101 * Determine space new attribute will use, and if it would be
102 * "local" or "remote" (note: local != inline).
103 */
104 size = xfs_attr_leaf_newentsize(namelen, valuelen,
105 mp->m_sb.sb_blocksize, &local);
106
107 /*
108 * If the inode doesn't have an attribute fork, add one.
109 * (inode must not be locked when we call this routine)
110 */
111 if (XFS_IFORK_Q(dp) == 0) {
112 if ((error = xfs_bmap_add_attrfork(dp, size, rsvd)))
113 return(error);
114 }
115
116 /*
117 * Fill in the arg structure for this request.
118 */
119 memset((char *)&args, 0, sizeof(args));
120 args.name = name;
121 args.namelen = namelen;
122 args.value = value;
123 args.valuelen = valuelen;
124 args.flags = flags;
125 args.hashval = xfs_da_hashname(args.name, args.namelen);
126 args.dp = dp;
127 args.firstblock = &firstblock;
128 args.flist = &flist;
129 args.whichfork = XFS_ATTR_FORK;
130 args.addname = 1;
131 args.oknoent = 1;
132
133 nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK);
134 if (local) {
135 if (size > (mp->m_sb.sb_blocksize >> 1)) {
136 /* Double split possible */
137 nblks <<= 1;
138 }
139 } else {
140 uint dblocks = XFS_B_TO_FSB(mp, valuelen);
141 /* Out of line attribute, cannot double split, but make
142 * room for the attribute value itself.
143 */
144 nblks += dblocks;
145 nblks += XFS_NEXTENTADD_SPACE_RES(mp, dblocks, XFS_ATTR_FORK);
146 }
147
148 /* Size is now blocks for attribute data */
149 args.total = nblks;
150
151 /*
152 * Start our first transaction of the day.
153 *
154 * All future transactions during this code must be "chained" off
155 * this one via the trans_dup() call. All transactions will contain
156 * the inode, and the inode will always be marked with trans_ihold().
157 * Since the inode will be locked in all transactions, we must log
158 * the inode in every transaction to let it float upward through
159 * the log.
160 */
161 args.trans = xfs_trans_alloc(mp, XFS_TRANS_ATTR_SET);
162
163 /*
164 * Root fork attributes can use reserved data blocks for this
165 * operation if necessary
166 */
167
168 if (rsvd)
169 args.trans->t_flags |= XFS_TRANS_RESERVE;
170
171 if ((error = xfs_trans_reserve(args.trans, (uint) nblks,
172 XFS_ATTRSET_LOG_RES(mp, nblks),
173 0, XFS_TRANS_PERM_LOG_RES,
174 XFS_ATTRSET_LOG_COUNT))) {
175 xfs_trans_cancel(args.trans, 0);
176 return(error);
177 }
178 xfs_ilock(dp, XFS_ILOCK_EXCL);
179
180 error = XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, args.trans, dp, nblks, 0,
181 rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES :
182 XFS_QMOPT_RES_REGBLKS);
183 if (error) {
184 xfs_iunlock(dp, XFS_ILOCK_EXCL);
185 xfs_trans_cancel(args.trans, XFS_TRANS_RELEASE_LOG_RES);
186 return (error);
187 }
188
189 xfs_trans_ijoin(args.trans, dp, XFS_ILOCK_EXCL);
190 xfs_trans_ihold(args.trans, dp);
191
192 /*
193 * If the attribute list is non-existant or a shortform list,
194 * upgrade it to a single-leaf-block attribute list.
195 */
196 if ((dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) ||
197 ((dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) &&
198 (dp->i_d.di_anextents == 0))) {
199
200 /*
201 * Build initial attribute list (if required).
202 */
203 if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
204 xfs_attr_shortform_create(&args);
205
206 /*
207 * Try to add the attr to the attribute list in
208 * the inode.
209 */
210 error = xfs_attr_shortform_addname(&args);
211 if (error != ENOSPC) {
212 /*
213 * Commit the shortform mods, and we're done.
214 * NOTE: this is also the error path (EEXIST, etc).
215 */
216 ASSERT(args.trans != NULL);
217
218 /*
219 * If this is a synchronous mount, make sure that
220 * the transaction goes to disk before returning
221 * to the user.
222 */
223 if (mp->m_flags & XFS_MOUNT_WSYNC) {
224 xfs_trans_set_sync(args.trans);
225 }
226 err2 = xfs_trans_commit(args.trans,
227 XFS_TRANS_RELEASE_LOG_RES,
228 NULL);
229 xfs_iunlock(dp, XFS_ILOCK_EXCL);
230
231 /*
232 * Hit the inode change time.
233 */
234 if (!error && (flags & ATTR_KERNOTIME) == 0) {
235 xfs_ichgtime(dp, XFS_ICHGTIME_CHG);
236 }
237 return(error == 0 ? err2 : error);
238 }
239
240 /*
241 * It won't fit in the shortform, transform to a leaf block.
242 * GROT: another possible req'mt for a double-split btree op.
243 */
244 XFS_BMAP_INIT(args.flist, args.firstblock);
245 error = xfs_attr_shortform_to_leaf(&args);
246 if (!error) {
247 error = xfs_bmap_finish(&args.trans, args.flist,
248 *args.firstblock, &committed);
249 }
250 if (error) {
251 ASSERT(committed);
252 args.trans = NULL;
253 xfs_bmap_cancel(&flist);
254 goto out;
255 }
256
257 /*
258 * bmap_finish() may have committed the last trans and started
259 * a new one. We need the inode to be in all transactions.
260 */
261 if (committed) {
262 xfs_trans_ijoin(args.trans, dp, XFS_ILOCK_EXCL);
263 xfs_trans_ihold(args.trans, dp);
264 }
265
266 /*
267 * Commit the leaf transformation. We'll need another (linked)
268 * transaction to add the new attribute to the leaf.
269 */
270 if ((error = xfs_attr_rolltrans(&args.trans, dp)))
271 goto out;
272
273 }
274
275 if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
276 error = xfs_attr_leaf_addname(&args);
277 } else {
278 error = xfs_attr_node_addname(&args);
279 }
280 if (error) {
281 goto out;
282 }
283
284 /*
285 * If this is a synchronous mount, make sure that the
286 * transaction goes to disk before returning to the user.
287 */
288 if (mp->m_flags & XFS_MOUNT_WSYNC) {
289 xfs_trans_set_sync(args.trans);
290 }
291
292 /*
293 * Commit the last in the sequence of transactions.
294 */
295 xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE);
296 error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES,
297 NULL);
298 xfs_iunlock(dp, XFS_ILOCK_EXCL);
299
300 /*
301 * Hit the inode change time.
302 */
303 if (!error && (flags & ATTR_KERNOTIME) == 0) {
304 xfs_ichgtime(dp, XFS_ICHGTIME_CHG);
305 }
306
307 return(error);
308
309 out:
310 if (args.trans)
311 xfs_trans_cancel(args.trans,
312 XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
313 xfs_iunlock(dp, XFS_ILOCK_EXCL);
314 return(error);
315 }
316
317 STATIC int
318 xfs_attr_remove_int(xfs_inode_t *dp, char *name, int namelen, int flags)
319 {
320 xfs_da_args_t args;
321 xfs_fsblock_t firstblock;
322 xfs_bmap_free_t flist;
323 int error;
324 xfs_mount_t *mp = dp->i_mount;
325
326 /*
327 * Fill in the arg structure for this request.
328 */
329 memset((char *)&args, 0, sizeof(args));
330 args.name = name;
331 args.namelen = namelen;
332 args.flags = flags;
333 args.hashval = xfs_da_hashname(args.name, args.namelen);
334 args.dp = dp;
335 args.firstblock = &firstblock;
336 args.flist = &flist;
337 args.total = 0;
338 args.whichfork = XFS_ATTR_FORK;
339
340 /*
341 * Attach the dquots to the inode.
342 */
343 if ((error = XFS_QM_DQATTACH(mp, dp, 0)))
344 return (error);
345
346 /*
347 * Start our first transaction of the day.
348 *
349 * All future transactions during this code must be "chained" off
350 * this one via the trans_dup() call. All transactions will contain
351 * the inode, and the inode will always be marked with trans_ihold().
352 * Since the inode will be locked in all transactions, we must log
353 * the inode in every transaction to let it float upward through
354 * the log.
355 */
356 args.trans = xfs_trans_alloc(mp, XFS_TRANS_ATTR_RM);
357
358 /*
359 * Root fork attributes can use reserved data blocks for this
360 * operation if necessary
361 */
362
363 if (flags & ATTR_ROOT)
364 args.trans->t_flags |= XFS_TRANS_RESERVE;
365
366 if ((error = xfs_trans_reserve(args.trans,
367 XFS_ATTRRM_SPACE_RES(mp),
368 XFS_ATTRRM_LOG_RES(mp),
369 0, XFS_TRANS_PERM_LOG_RES,
370 XFS_ATTRRM_LOG_COUNT))) {
371 xfs_trans_cancel(args.trans, 0);
372 return(error);
373 }
374
375 xfs_ilock(dp, XFS_ILOCK_EXCL);
376 /*
377 * No need to make quota reservations here. We expect to release some
378 * blocks not allocate in the common case.
379 */
380 xfs_trans_ijoin(args.trans, dp, XFS_ILOCK_EXCL);
381 xfs_trans_ihold(args.trans, dp);
382
383 /*
384 * Decide on what work routines to call based on the inode size.
385 */
386 if (XFS_IFORK_Q(dp) == 0 ||
387 (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
388 dp->i_d.di_anextents == 0)) {
389 error = XFS_ERROR(ENOATTR);
390 goto out;
391 }
392 if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
393 ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
394 error = xfs_attr_shortform_remove(&args);
395 if (error) {
396 goto out;
397 }
398 } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
399 error = xfs_attr_leaf_removename(&args);
400 } else {
401 error = xfs_attr_node_removename(&args);
402 }
403 if (error) {
404 goto out;
405 }
406
407 /*
408 * If this is a synchronous mount, make sure that the
409 * transaction goes to disk before returning to the user.
410 */
411 if (mp->m_flags & XFS_MOUNT_WSYNC) {
412 xfs_trans_set_sync(args.trans);
413 }
414
415 /*
416 * Commit the last in the sequence of transactions.
417 */
418 xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE);
419 error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES,
420 NULL);
421 xfs_iunlock(dp, XFS_ILOCK_EXCL);
422
423 /*
424 * Hit the inode change time.
425 */
426 if (!error && (flags & ATTR_KERNOTIME) == 0) {
427 xfs_ichgtime(dp, XFS_ICHGTIME_CHG);
428 }
429
430 return(error);
431
432 out:
433 if (args.trans)
434 xfs_trans_cancel(args.trans,
435 XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
436 xfs_iunlock(dp, XFS_ILOCK_EXCL);
437 return(error);
438 }
439
440
441 /*========================================================================
442 * External routines when attribute list is inside the inode
443 *========================================================================*/
444
445 /*
446 * Add a name to the shortform attribute list structure
447 * This is the external routine.
448 */
449 STATIC int
450 xfs_attr_shortform_addname(xfs_da_args_t *args)
451 {
452 int newsize, forkoff, retval;
453
454 retval = xfs_attr_shortform_lookup(args);
455 if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) {
456 return(retval);
457 } else if (retval == EEXIST) {
458 if (args->flags & ATTR_CREATE)
459 return(retval);
460 retval = xfs_attr_shortform_remove(args);
461 ASSERT(retval == 0);
462 }
463
464 if (args->namelen >= XFS_ATTR_SF_ENTSIZE_MAX ||
465 args->valuelen >= XFS_ATTR_SF_ENTSIZE_MAX)
466 return(XFS_ERROR(ENOSPC));
467
468 newsize = XFS_ATTR_SF_TOTSIZE(args->dp);
469 newsize += XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);
470
471 forkoff = xfs_attr_shortform_bytesfit(args->dp, newsize);
472 if (!forkoff)
473 return(XFS_ERROR(ENOSPC));
474
475 xfs_attr_shortform_add(args, forkoff);
476 return(0);
477 }
478
479
480 /*========================================================================
481 * External routines when attribute list is one block
482 *========================================================================*/
483
484 /*
485 * Add a name to the leaf attribute list structure
486 *
487 * This leaf block cannot have a "remote" value, we only call this routine
488 * if bmap_one_block() says there is only one block (ie: no remote blks).
489 */
490 int
491 xfs_attr_leaf_addname(xfs_da_args_t *args)
492 {
493 xfs_inode_t *dp;
494 xfs_dabuf_t *bp;
495 int retval, error, committed, forkoff;
496
497 /*
498 * Read the (only) block in the attribute list in.
499 */
500 dp = args->dp;
501 args->blkno = 0;
502 error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp,
503 XFS_ATTR_FORK);
504 if (error)
505 return(error);
506 ASSERT(bp != NULL);
507
508 /*
509 * Look up the given attribute in the leaf block. Figure out if
510 * the given flags produce an error or call for an atomic rename.
511 */
512 retval = xfs_attr_leaf_lookup_int(bp, args);
513 if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) {
514 xfs_da_brelse(args->trans, bp);
515 return(retval);
516 } else if (retval == EEXIST) {
517 if (args->flags & ATTR_CREATE) { /* pure create op */
518 xfs_da_brelse(args->trans, bp);
519 return(retval);
520 }
521 args->rename = 1; /* an atomic rename */
522 args->blkno2 = args->blkno; /* set 2nd entry info*/
523 args->index2 = args->index;
524 args->rmtblkno2 = args->rmtblkno;
525 args->rmtblkcnt2 = args->rmtblkcnt;
526 }
527
528 /*
529 * Add the attribute to the leaf block, transitioning to a Btree
530 * if required.
531 */
532 retval = xfs_attr_leaf_add(bp, args);
533 xfs_da_buf_done(bp);
534 if (retval == ENOSPC) {
535 /*
536 * Promote the attribute list to the Btree format, then
537 * Commit that transaction so that the node_addname() call
538 * can manage its own transactions.
539 */
540 XFS_BMAP_INIT(args->flist, args->firstblock);
541 error = xfs_attr_leaf_to_node(args);
542 if (!error) {
543 error = xfs_bmap_finish(&args->trans, args->flist,
544 *args->firstblock, &committed);
545 }
546 if (error) {
547 ASSERT(committed);
548 args->trans = NULL;
549 xfs_bmap_cancel(args->flist);
550 return(error);
551 }
552
553 /*
554 * bmap_finish() may have committed the last trans and started
555 * a new one. We need the inode to be in all transactions.
556 */
557 if (committed) {
558 xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
559 xfs_trans_ihold(args->trans, dp);
560 }
561
562 /*
563 * Commit the current trans (including the inode) and start
564 * a new one.
565 */
566 if ((error = xfs_attr_rolltrans(&args->trans, dp)))
567 return (error);
568
569 /*
570 * Fob the whole rest of the problem off on the Btree code.
571 */
572 error = xfs_attr_node_addname(args);
573 return(error);
574 }
575
576 /*
577 * Commit the transaction that added the attr name so that
578 * later routines can manage their own transactions.
579 */
580 if ((error = xfs_attr_rolltrans(&args->trans, dp)))
581 return (error);
582
583 /*
584 * If there was an out-of-line value, allocate the blocks we
585 * identified for its storage and copy the value. This is done
586 * after we create the attribute so that we don't overflow the
587 * maximum size of a transaction and/or hit a deadlock.
588 */
589 if (args->rmtblkno > 0) {
590 error = xfs_attr_rmtval_set(args);
591 if (error)
592 return(error);
593 }
594
595 /*
596 * If this is an atomic rename operation, we must "flip" the
597 * incomplete flags on the "new" and "old" attribute/value pairs
598 * so that one disappears and one appears atomically. Then we
599 * must remove the "old" attribute/value pair.
600 */
601 if (args->rename) {
602 /*
603 * In a separate transaction, set the incomplete flag on the
604 * "old" attr and clear the incomplete flag on the "new" attr.
605 */
606 error = xfs_attr_leaf_flipflags(args);
607 if (error)
608 return(error);
609
610 /*
611 * Dismantle the "old" attribute/value pair by removing
612 * a "remote" value (if it exists).
613 */
614 args->index = args->index2;
615 args->blkno = args->blkno2;
616 args->rmtblkno = args->rmtblkno2;
617 args->rmtblkcnt = args->rmtblkcnt2;
618 if (args->rmtblkno) {
619 error = xfs_attr_rmtval_remove(args);
620 if (error)
621 return(error);
622 }
623
624 /*
625 * Read in the block containing the "old" attr, then
626 * remove the "old" attr from that block (neat, huh!)
627 */
628 error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1,
629 &bp, XFS_ATTR_FORK);
630 if (error)
631 return(error);
632 ASSERT(bp != NULL);
633 (void)xfs_attr_leaf_remove(bp, args);
634
635 /*
636 * If the result is small enough, shrink it all into the inode.
637 */
638 if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
639 XFS_BMAP_INIT(args->flist, args->firstblock);
640 error = xfs_attr_leaf_to_shortform(bp, args, forkoff);
641 /* bp is gone due to xfs_da_shrink_inode */
642 if (!error) {
643 error = xfs_bmap_finish(&args->trans,
644 args->flist,
645 *args->firstblock,
646 &committed);
647 }
648 if (error) {
649 ASSERT(committed);
650 args->trans = NULL;
651 xfs_bmap_cancel(args->flist);
652 return(error);
653 }
654
655 /*
656 * bmap_finish() may have committed the last trans
657 * and started a new one. We need the inode to be
658 * in all transactions.
659 */
660 if (committed) {
661 xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
662 xfs_trans_ihold(args->trans, dp);
663 }
664 } else
665 xfs_da_buf_done(bp);
666
667 /*
668 * Commit the remove and start the next trans in series.
669 */
670 error = xfs_attr_rolltrans(&args->trans, dp);
671
672 } else if (args->rmtblkno > 0) {
673 /*
674 * Added a "remote" value, just clear the incomplete flag.
675 */
676 error = xfs_attr_leaf_clearflag(args);
677 }
678 return(error);
679 }
680
681 /*
682 * Remove a name from the leaf attribute list structure
683 *
684 * This leaf block cannot have a "remote" value, we only call this routine
685 * if bmap_one_block() says there is only one block (ie: no remote blks).
686 */
687 STATIC int
688 xfs_attr_leaf_removename(xfs_da_args_t *args)
689 {
690 xfs_inode_t *dp;
691 xfs_dabuf_t *bp;
692 int error, committed, forkoff;
693
694 /*
695 * Remove the attribute.
696 */
697 dp = args->dp;
698 args->blkno = 0;
699 error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp,
700 XFS_ATTR_FORK);
701 if (error) {
702 return(error);
703 }
704
705 ASSERT(bp != NULL);
706 error = xfs_attr_leaf_lookup_int(bp, args);
707 if (error == ENOATTR) {
708 xfs_da_brelse(args->trans, bp);
709 return(error);
710 }
711
712 (void)xfs_attr_leaf_remove(bp, args);
713
714 /*
715 * If the result is small enough, shrink it all into the inode.
716 */
717 if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
718 XFS_BMAP_INIT(args->flist, args->firstblock);
719 error = xfs_attr_leaf_to_shortform(bp, args, forkoff);
720 /* bp is gone due to xfs_da_shrink_inode */
721 if (!error) {
722 error = xfs_bmap_finish(&args->trans, args->flist,
723 *args->firstblock, &committed);
724 }
725 if (error) {
726 ASSERT(committed);
727 args->trans = NULL;
728 xfs_bmap_cancel(args->flist);
729 return(error);
730 }
731
732 /*
733 * bmap_finish() may have committed the last trans and started
734 * a new one. We need the inode to be in all transactions.
735 */
736 if (committed) {
737 xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
738 xfs_trans_ihold(args->trans, dp);
739 }
740 } else
741 xfs_da_buf_done(bp);
742 return(0);
743 }
744
745 /*========================================================================
746 * External routines when attribute list size > XFS_LBSIZE(mp).
747 *========================================================================*/
748
749 /*
750 * Add a name to a Btree-format attribute list.
751 *
752 * This will involve walking down the Btree, and may involve splitting
753 * leaf nodes and even splitting intermediate nodes up to and including
754 * the root node (a special case of an intermediate node).
755 *
756 * "Remote" attribute values confuse the issue and atomic rename operations
757 * add a whole extra layer of confusion on top of that.
758 */
759 STATIC int
760 xfs_attr_node_addname(xfs_da_args_t *args)
761 {
762 xfs_da_state_t *state;
763 xfs_da_state_blk_t *blk;
764 xfs_inode_t *dp;
765 xfs_mount_t *mp;
766 int committed, retval, error;
767
768 /*
769 * Fill in bucket of arguments/results/context to carry around.
770 */
771 dp = args->dp;
772 mp = dp->i_mount;
773 restart:
774 state = xfs_da_state_alloc();
775 state->args = args;
776 state->mp = mp;
777 state->blocksize = state->mp->m_sb.sb_blocksize;
778 state->node_ents = state->mp->m_attr_node_ents;
779
780 /*
781 * Search to see if name already exists, and get back a pointer
782 * to where it should go.
783 */
784 error = xfs_da_node_lookup_int(state, &retval);
785 if (error)
786 goto out;
787 blk = &state->path.blk[ state->path.active-1 ];
788 ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
789 if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) {
790 goto out;
791 } else if (retval == EEXIST) {
792 if (args->flags & ATTR_CREATE)
793 goto out;
794 args->rename = 1; /* atomic rename op */
795 args->blkno2 = args->blkno; /* set 2nd entry info*/
796 args->index2 = args->index;
797 args->rmtblkno2 = args->rmtblkno;
798 args->rmtblkcnt2 = args->rmtblkcnt;
799 args->rmtblkno = 0;
800 args->rmtblkcnt = 0;
801 }
802
803 retval = xfs_attr_leaf_add(blk->bp, state->args);
804 if (retval == ENOSPC) {
805 if (state->path.active == 1) {
806 /*
807 * Its really a single leaf node, but it had
808 * out-of-line values so it looked like it *might*
809 * have been a b-tree.
810 */
811 xfs_da_state_free(state);
812 XFS_BMAP_INIT(args->flist, args->firstblock);
813 error = xfs_attr_leaf_to_node(args);
814 if (!error) {
815 error = xfs_bmap_finish(&args->trans,
816 args->flist,
817 *args->firstblock,
818 &committed);
819 }
820 if (error) {
821 ASSERT(committed);
822 args->trans = NULL;
823 xfs_bmap_cancel(args->flist);
824 goto out;
825 }
826
827 /*
828 * bmap_finish() may have committed the last trans
829 * and started a new one. We need the inode to be
830 * in all transactions.
831 */
832 if (committed) {
833 xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
834 xfs_trans_ihold(args->trans, dp);
835 }
836
837 /*
838 * Commit the node conversion and start the next
839 * trans in the chain.
840 */
841 if ((error = xfs_attr_rolltrans(&args->trans, dp)))
842 goto out;
843
844 goto restart;
845 }
846
847 /*
848 * Split as many Btree elements as required.
849 * This code tracks the new and old attr's location
850 * in the index/blkno/rmtblkno/rmtblkcnt fields and
851 * in the index2/blkno2/rmtblkno2/rmtblkcnt2 fields.
852 */
853 XFS_BMAP_INIT(args->flist, args->firstblock);
854 error = xfs_da_split(state);
855 if (!error) {
856 error = xfs_bmap_finish(&args->trans, args->flist,
857 *args->firstblock, &committed);
858 }
859 if (error) {
860 ASSERT(committed);
861 args->trans = NULL;
862 xfs_bmap_cancel(args->flist);
863 goto out;
864 }
865
866 /*
867 * bmap_finish() may have committed the last trans and started
868 * a new one. We need the inode to be in all transactions.
869 */
870 if (committed) {
871 xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
872 xfs_trans_ihold(args->trans, dp);
873 }
874 } else {
875 /*
876 * Addition succeeded, update Btree hashvals.
877 */
878 xfs_da_fixhashpath(state, &state->path);
879 }
880
881 /*
882 * Kill the state structure, we're done with it and need to
883 * allow the buffers to come back later.
884 */
885 xfs_da_state_free(state);
886 state = NULL;
887
888 /*
889 * Commit the leaf addition or btree split and start the next
890 * trans in the chain.
891 */
892 if ((error = xfs_attr_rolltrans(&args->trans, dp)))
893 goto out;
894
895 /*
896 * If there was an out-of-line value, allocate the blocks we
897 * identified for its storage and copy the value. This is done
898 * after we create the attribute so that we don't overflow the
899 * maximum size of a transaction and/or hit a deadlock.
900 */
901 if (args->rmtblkno > 0) {
902 error = xfs_attr_rmtval_set(args);
903 if (error)
904 return(error);
905 }
906
907 /*
908 * If this is an atomic rename operation, we must "flip" the
909 * incomplete flags on the "new" and "old" attribute/value pairs
910 * so that one disappears and one appears atomically. Then we
911 * must remove the "old" attribute/value pair.
912 */
913 if (args->rename) {
914 /*
915 * In a separate transaction, set the incomplete flag on the
916 * "old" attr and clear the incomplete flag on the "new" attr.
917 */
918 error = xfs_attr_leaf_flipflags(args);
919 if (error)
920 goto out;
921
922 /*
923 * Dismantle the "old" attribute/value pair by removing
924 * a "remote" value (if it exists).
925 */
926 args->index = args->index2;
927 args->blkno = args->blkno2;
928 args->rmtblkno = args->rmtblkno2;
929 args->rmtblkcnt = args->rmtblkcnt2;
930 if (args->rmtblkno) {
931 error = xfs_attr_rmtval_remove(args);
932 if (error)
933 return(error);
934 }
935
936 /*
937 * Re-find the "old" attribute entry after any split ops.
938 * The INCOMPLETE flag means that we will find the "old"
939 * attr, not the "new" one.
940 */
941 args->flags |= XFS_ATTR_INCOMPLETE;
942 state = xfs_da_state_alloc();
943 state->args = args;
944 state->mp = mp;
945 state->blocksize = state->mp->m_sb.sb_blocksize;
946 state->node_ents = state->mp->m_attr_node_ents;
947 state->inleaf = 0;
948 error = xfs_da_node_lookup_int(state, &retval);
949 if (error)
950 goto out;
951
952 /*
953 * Remove the name and update the hashvals in the tree.
954 */
955 blk = &state->path.blk[ state->path.active-1 ];
956 ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
957 error = xfs_attr_leaf_remove(blk->bp, args);
958 xfs_da_fixhashpath(state, &state->path);
959
960 /*
961 * Check to see if the tree needs to be collapsed.
962 */
963 if (retval && (state->path.active > 1)) {
964 XFS_BMAP_INIT(args->flist, args->firstblock);
965 error = xfs_da_join(state);
966 if (!error) {
967 error = xfs_bmap_finish(&args->trans,
968 args->flist,
969 *args->firstblock,
970 &committed);
971 }
972 if (error) {
973 ASSERT(committed);
974 args->trans = NULL;
975 xfs_bmap_cancel(args->flist);
976 goto out;
977 }
978
979 /*
980 * bmap_finish() may have committed the last trans
981 * and started a new one. We need the inode to be
982 * in all transactions.
983 */
984 if (committed) {
985 xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
986 xfs_trans_ihold(args->trans, dp);
987 }
988 }
989
990 /*
991 * Commit and start the next trans in the chain.
992 */
993 if ((error = xfs_attr_rolltrans(&args->trans, dp)))
994 goto out;
995
996 } else if (args->rmtblkno > 0) {
997 /*
998 * Added a "remote" value, just clear the incomplete flag.
999 */
1000 error = xfs_attr_leaf_clearflag(args);
1001 if (error)
1002 goto out;
1003 }
1004 retval = error = 0;
1005
1006 out:
1007 if (state)
1008 xfs_da_state_free(state);
1009 if (error)
1010 return(error);
1011 return(retval);
1012 }
1013
1014 /*
1015 * Remove a name from a B-tree attribute list.
1016 *
1017 * This will involve walking down the Btree, and may involve joining
1018 * leaf nodes and even joining intermediate nodes up to and including
1019 * the root node (a special case of an intermediate node).
1020 */
1021 STATIC int
1022 xfs_attr_node_removename(xfs_da_args_t *args)
1023 {
1024 xfs_da_state_t *state;
1025 xfs_da_state_blk_t *blk;
1026 xfs_inode_t *dp;
1027 xfs_dabuf_t *bp;
1028 int retval, error, committed, forkoff;
1029
1030 /*
1031 * Tie a string around our finger to remind us where we are.
1032 */
1033 dp = args->dp;
1034 state = xfs_da_state_alloc();
1035 state->args = args;
1036 state->mp = dp->i_mount;
1037 state->blocksize = state->mp->m_sb.sb_blocksize;
1038 state->node_ents = state->mp->m_attr_node_ents;
1039
1040 /*
1041 * Search to see if name exists, and get back a pointer to it.
1042 */
1043 error = xfs_da_node_lookup_int(state, &retval);
1044 if (error || (retval != EEXIST)) {
1045 if (error == 0)
1046 error = retval;
1047 goto out;
1048 }
1049
1050 /*
1051 * If there is an out-of-line value, de-allocate the blocks.
1052 * This is done before we remove the attribute so that we don't
1053 * overflow the maximum size of a transaction and/or hit a deadlock.
1054 */
1055 blk = &state->path.blk[ state->path.active-1 ];
1056 ASSERT(blk->bp != NULL);
1057 ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
1058 if (args->rmtblkno > 0) {
1059 /*
1060 * Fill in disk block numbers in the state structure
1061 * so that we can get the buffers back after we commit
1062 * several transactions in the following calls.
1063 */
1064 error = xfs_attr_fillstate(state);
1065 if (error)
1066 goto out;
1067
1068 /*
1069 * Mark the attribute as INCOMPLETE, then bunmapi() the
1070 * remote value.
1071 */
1072 error = xfs_attr_leaf_setflag(args);
1073 if (error)
1074 goto out;
1075 error = xfs_attr_rmtval_remove(args);
1076 if (error)
1077 goto out;
1078
1079 /*
1080 * Refill the state structure with buffers, the prior calls
1081 * released our buffers.
1082 */
1083 error = xfs_attr_refillstate(state);
1084 if (error)
1085 goto out;
1086 }
1087
1088 /*
1089 * Remove the name and update the hashvals in the tree.
1090 */
1091 blk = &state->path.blk[ state->path.active-1 ];
1092 ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
1093 retval = xfs_attr_leaf_remove(blk->bp, args);
1094 xfs_da_fixhashpath(state, &state->path);
1095
1096 /*
1097 * Check to see if the tree needs to be collapsed.
1098 */
1099 if (retval && (state->path.active > 1)) {
1100 XFS_BMAP_INIT(args->flist, args->firstblock);
1101 error = xfs_da_join(state);
1102 if (!error) {
1103 error = xfs_bmap_finish(&args->trans, args->flist,
1104 *args->firstblock, &committed);
1105 }
1106 if (error) {
1107 ASSERT(committed);
1108 args->trans = NULL;
1109 xfs_bmap_cancel(args->flist);
1110 goto out;
1111 }
1112
1113 /*
1114 * bmap_finish() may have committed the last trans and started
1115 * a new one. We need the inode to be in all transactions.
1116 */
1117 if (committed) {
1118 xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
1119 xfs_trans_ihold(args->trans, dp);
1120 }
1121
1122 /*
1123 * Commit the Btree join operation and start a new trans.
1124 */
1125 if ((error = xfs_attr_rolltrans(&args->trans, dp)))
1126 goto out;
1127 }
1128
1129 /*
1130 * If the result is small enough, push it all into the inode.
1131 */
1132 if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
1133 /*
1134 * Have to get rid of the copy of this dabuf in the state.
1135 */
1136 ASSERT(state->path.active == 1);
1137 ASSERT(state->path.blk[0].bp);
1138 xfs_da_buf_done(state->path.blk[0].bp);
1139 state->path.blk[0].bp = NULL;
1140
1141 error = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp,
1142 XFS_ATTR_FORK);
1143 if (error)
1144 goto out;
1145 ASSERT(INT_GET(((xfs_attr_leafblock_t *)
1146 bp->data)->hdr.info.magic, ARCH_CONVERT)
1147 == XFS_ATTR_LEAF_MAGIC);
1148
1149 if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
1150 XFS_BMAP_INIT(args->flist, args->firstblock);
1151 error = xfs_attr_leaf_to_shortform(bp, args, forkoff);
1152 /* bp is gone due to xfs_da_shrink_inode */
1153 if (!error) {
1154 error = xfs_bmap_finish(&args->trans,
1155 args->flist,
1156 *args->firstblock,
1157 &committed);
1158 }
1159 if (error) {
1160 ASSERT(committed);
1161 args->trans = NULL;
1162 xfs_bmap_cancel(args->flist);
1163 goto out;
1164 }
1165
1166 /*
1167 * bmap_finish() may have committed the last trans
1168 * and started a new one. We need the inode to be
1169 * in all transactions.
1170 */
1171 if (committed) {
1172 xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
1173 xfs_trans_ihold(args->trans, dp);
1174 }
1175 } else
1176 xfs_da_brelse(args->trans, bp);
1177 }
1178 error = 0;
1179
1180 out:
1181 xfs_da_state_free(state);
1182 return(error);
1183 }
1184
1185 /*
1186 * Fill in the disk block numbers in the state structure for the buffers
1187 * that are attached to the state structure.
1188 * This is done so that we can quickly reattach ourselves to those buffers
1189 * after some set of transaction commit's has released these buffers.
1190 */
1191 STATIC int
1192 xfs_attr_fillstate(xfs_da_state_t *state)
1193 {
1194 xfs_da_state_path_t *path;
1195 xfs_da_state_blk_t *blk;
1196 int level;
1197
1198 /*
1199 * Roll down the "path" in the state structure, storing the on-disk
1200 * block number for those buffers in the "path".
1201 */
1202 path = &state->path;
1203 ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
1204 for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
1205 if (blk->bp) {
1206 blk->disk_blkno = xfs_da_blkno(blk->bp);
1207 xfs_da_buf_done(blk->bp);
1208 blk->bp = NULL;
1209 } else {
1210 blk->disk_blkno = 0;
1211 }
1212 }
1213
1214 /*
1215 * Roll down the "altpath" in the state structure, storing the on-disk
1216 * block number for those buffers in the "altpath".
1217 */
1218 path = &state->altpath;
1219 ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
1220 for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
1221 if (blk->bp) {
1222 blk->disk_blkno = xfs_da_blkno(blk->bp);
1223 xfs_da_buf_done(blk->bp);
1224 blk->bp = NULL;
1225 } else {
1226 blk->disk_blkno = 0;
1227 }
1228 }
1229
1230 return(0);
1231 }
1232
1233 /*
1234 * Reattach the buffers to the state structure based on the disk block
1235 * numbers stored in the state structure.
1236 * This is done after some set of transaction commit's has released those
1237 * buffers from our grip.
1238 */
1239 STATIC int
1240 xfs_attr_refillstate(xfs_da_state_t *state)
1241 {
1242 xfs_da_state_path_t *path;
1243 xfs_da_state_blk_t *blk;
1244 int level, error;
1245
1246 /*
1247 * Roll down the "path" in the state structure, storing the on-disk
1248 * block number for those buffers in the "path".
1249 */
1250 path = &state->path;
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) {
1254 error = xfs_da_read_buf(state->args->trans,
1255 state->args->dp,
1256 blk->blkno, blk->disk_blkno,
1257 &blk->bp, XFS_ATTR_FORK);
1258 if (error)
1259 return(error);
1260 } else {
1261 blk->bp = NULL;
1262 }
1263 }
1264
1265 /*
1266 * Roll down the "altpath" in the state structure, storing the on-disk
1267 * block number for those buffers in the "altpath".
1268 */
1269 path = &state->altpath;
1270 ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
1271 for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
1272 if (blk->disk_blkno) {
1273 error = xfs_da_read_buf(state->args->trans,
1274 state->args->dp,
1275 blk->blkno, blk->disk_blkno,
1276 &blk->bp, XFS_ATTR_FORK);
1277 if (error)
1278 return(error);
1279 } else {
1280 blk->bp = NULL;
1281 }
1282 }
1283
1284 return(0);
1285 }
1286
1287 /*
1288 * Write the value associated with an attribute into the out-of-line buffer
1289 * that we have defined for it.
1290 */
1291 STATIC int
1292 xfs_attr_rmtval_set(xfs_da_args_t *args)
1293 {
1294 xfs_mount_t *mp;
1295 xfs_fileoff_t lfileoff;
1296 xfs_inode_t *dp;
1297 xfs_bmbt_irec_t map;
1298 xfs_daddr_t dblkno;
1299 xfs_caddr_t src;
1300 xfs_buf_t *bp;
1301 xfs_dablk_t lblkno;
1302 int blkcnt, valuelen, nmap, error, tmp, committed;
1303
1304 dp = args->dp;
1305 mp = dp->i_mount;
1306 src = args->value;
1307
1308 /*
1309 * Find a "hole" in the attribute address space large enough for
1310 * us to drop the new attribute's value into.
1311 */
1312 blkcnt = XFS_B_TO_FSB(mp, args->valuelen);
1313 lfileoff = 0;
1314 error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff,
1315 XFS_ATTR_FORK);
1316 if (error) {
1317 return(error);
1318 }
1319 args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff;
1320 args->rmtblkcnt = blkcnt;
1321
1322 /*
1323 * Roll through the "value", allocating blocks on disk as required.
1324 */
1325 while (blkcnt > 0) {
1326 /*
1327 * Allocate a single extent, up to the size of the value.
1328 */
1329 XFS_BMAP_INIT(args->flist, args->firstblock);
1330 nmap = 1;
1331 error = xfs_bmapi(args->trans, dp, (xfs_fileoff_t)lblkno,
1332 blkcnt,
1333 XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA |
1334 XFS_BMAPI_WRITE,
1335 args->firstblock, args->total, &map, &nmap,
1336 args->flist);
1337 if (!error) {
1338 error = xfs_bmap_finish(&args->trans, args->flist,
1339 *args->firstblock, &committed);
1340 }
1341 if (error) {
1342 ASSERT(committed);
1343 args->trans = NULL;
1344 xfs_bmap_cancel(args->flist);
1345 return(error);
1346 }
1347
1348 /*
1349 * bmap_finish() may have committed the last trans and started
1350 * a new one. We need the inode to be in all transactions.
1351 */
1352 if (committed) {
1353 xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);
1354 xfs_trans_ihold(args->trans, dp);
1355 }
1356
1357 ASSERT(nmap == 1);
1358 ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
1359 (map.br_startblock != HOLESTARTBLOCK));
1360 lblkno += map.br_blockcount;
1361 blkcnt -= map.br_blockcount;
1362
1363 /*
1364 * Start the next trans in the chain.
1365 */
1366 if ((error = xfs_attr_rolltrans(&args->trans, dp)))
1367 return (error);
1368 }
1369
1370 /*
1371 * Roll through the "value", copying the attribute value to the
1372 * already-allocated blocks. Blocks are written synchronously
1373 * so that we can know they are all on disk before we turn off
1374 * the INCOMPLETE flag.
1375 */
1376 lblkno = args->rmtblkno;
1377 valuelen = args->valuelen;
1378 while (valuelen > 0) {
1379 /*
1380 * Try to remember where we decided to put the value.
1381 */
1382 XFS_BMAP_INIT(args->flist, args->firstblock);
1383 nmap = 1;
1384 error = xfs_bmapi(NULL, dp, (xfs_fileoff_t)lblkno,
1385 args->rmtblkcnt,
1386 XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
1387 args->firstblock, 0, &map, &nmap, NULL);
1388 if (error) {
1389 return(error);
1390 }
1391 ASSERT(nmap == 1);
1392 ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
1393 (map.br_startblock != HOLESTARTBLOCK));
1394
1395 dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
1396 blkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
1397
1398 bp = xfs_buf_get_flags(mp->m_ddev_targp, dblkno,
1399 blkcnt, XFS_BUF_LOCK);
1400 ASSERT(bp);
1401 ASSERT(!XFS_BUF_GETERROR(bp));
1402
1403 tmp = (valuelen < XFS_BUF_SIZE(bp)) ? valuelen :
1404 XFS_BUF_SIZE(bp);
1405 xfs_biomove(bp, 0, tmp, src, XFS_B_WRITE);
1406 if (tmp < XFS_BUF_SIZE(bp))
1407 xfs_biozero(bp, tmp, XFS_BUF_SIZE(bp) - tmp);
1408 if ((error = xfs_bwrite(mp, bp))) {/* GROT: NOTE: synchronous write */
1409 return (error);
1410 }
1411 src += tmp;
1412 valuelen -= tmp;
1413
1414 lblkno += map.br_blockcount;
1415 }
1416 ASSERT(valuelen == 0);
1417 return(0);
1418 }
1419
1420 /*
1421 * Remove the value associated with an attribute by deleting the
1422 * out-of-line buffer that it is stored on.
1423 */
1424 STATIC int
1425 xfs_attr_rmtval_remove(xfs_da_args_t *args)
1426 {
1427 xfs_mount_t *mp;
1428 xfs_bmbt_irec_t map;
1429 xfs_buf_t *bp;
1430 xfs_daddr_t dblkno;
1431 xfs_dablk_t lblkno;
1432 int valuelen, blkcnt, nmap, error, done, committed;
1433
1434 mp = args->dp->i_mount;
1435
1436 /*
1437 * Roll through the "value", invalidating the attribute value's
1438 * blocks.
1439 */
1440 lblkno = args->rmtblkno;
1441 valuelen = args->rmtblkcnt;
1442 while (valuelen > 0) {
1443 /*
1444 * Try to remember where we decided to put the value.
1445 */
1446 XFS_BMAP_INIT(args->flist, args->firstblock);
1447 nmap = 1;
1448 error = xfs_bmapi(NULL, args->dp, (xfs_fileoff_t)lblkno,
1449 args->rmtblkcnt,
1450 XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
1451 args->firstblock, 0, &map, &nmap,
1452 args->flist);
1453 if (error) {
1454 return(error);
1455 }
1456 ASSERT(nmap == 1);
1457 ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
1458 (map.br_startblock != HOLESTARTBLOCK));
1459
1460 dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
1461 blkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
1462
1463 /*
1464 * If the "remote" value is in the cache, remove it.
1465 */
1466 bp = xfs_incore(mp->m_ddev_targp, dblkno, blkcnt,
1467 XFS_INCORE_TRYLOCK);
1468 if (bp) {
1469 XFS_BUF_STALE(bp);
1470 XFS_BUF_UNDELAYWRITE(bp);
1471 xfs_buf_relse(bp);
1472 bp = NULL;
1473 }
1474
1475 valuelen -= map.br_blockcount;
1476
1477 lblkno += map.br_blockcount;
1478 }
1479
1480 /*
1481 * Keep de-allocating extents until the remote-value region is gone.
1482 */
1483 lblkno = args->rmtblkno;
1484 blkcnt = args->rmtblkcnt;
1485 done = 0;
1486 while (!done) {
1487 XFS_BMAP_INIT(args->flist, args->firstblock);
1488 error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt,
1489 XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
1490 1, args->firstblock, args->flist, &done);
1491 if (!error) {
1492 error = xfs_bmap_finish(&args->trans, args->flist,
1493 *args->firstblock, &committed);
1494 }
1495 if (error) {
1496 ASSERT(committed);
1497 args->trans = NULL;
1498 xfs_bmap_cancel(args->flist);
1499 return(error);
1500 }
1501
1502 /*
1503 * bmap_finish() may have committed the last trans and started
1504 * a new one. We need the inode to be in all transactions.
1505 */
1506 if (committed) {
1507 xfs_trans_ijoin(args->trans, args->dp, XFS_ILOCK_EXCL);
1508 xfs_trans_ihold(args->trans, args->dp);
1509 }
1510
1511 /*
1512 * Close out trans and start the next one in the chain.
1513 */
1514 if ((error = xfs_attr_rolltrans(&args->trans, args->dp)))
1515 return (error);
1516 }
1517 return(0);
1518 }