1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include "xfs.h"
19#include "xfs_fs.h"
20#include "xfs_format.h"
21#include "xfs_bit.h"
22#include "xfs_log.h"
23#include "xfs_trans.h"
24#include "xfs_trans_priv.h"
25#include "xfs_sb.h"
26#include "xfs_ag.h"
27#include "xfs_mount.h"
28#include "xfs_da_btree.h"
29#include "xfs_bmap_btree.h"
30#include "xfs_attr_sf.h"
31#include "xfs_dinode.h"
32#include "xfs_inode.h"
33#include "xfs_alloc.h"
34#include "xfs_inode_item.h"
35#include "xfs_bmap.h"
36#include "xfs_bmap_util.h"
37#include "xfs_attr.h"
38#include "xfs_attr_leaf.h"
39#include "xfs_attr_remote.h"
40#include "xfs_error.h"
41#include "xfs_quota.h"
42#include "xfs_trans_space.h"
43#include "xfs_trace.h"
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
59
60
61
62
63STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
64STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
65STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
66
67
68
69
70STATIC int xfs_attr_node_get(xfs_da_args_t *args);
71STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
72STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
73STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
74STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
75
76
77STATIC int
78xfs_attr_name_to_xname(
79 struct xfs_name *xname,
80 const unsigned char *aname)
81{
82 if (!aname)
83 return EINVAL;
84 xname->name = aname;
85 xname->len = strlen((char *)aname);
86 if (xname->len >= MAXNAMELEN)
87 return EFAULT;
88
89 return 0;
90}
91
92int
93xfs_inode_hasattr(
94 struct xfs_inode *ip)
95{
96 if (!XFS_IFORK_Q(ip) ||
97 (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
98 ip->i_d.di_anextents == 0))
99 return 0;
100 return 1;
101}
102
103
104
105
106
107STATIC int
108xfs_attr_get_int(
109 struct xfs_inode *ip,
110 struct xfs_name *name,
111 unsigned char *value,
112 int *valuelenp,
113 int flags)
114{
115 xfs_da_args_t args;
116 int error;
117
118 if (!xfs_inode_hasattr(ip))
119 return ENOATTR;
120
121
122
123
124 memset((char *)&args, 0, sizeof(args));
125 args.name = name->name;
126 args.namelen = name->len;
127 args.value = value;
128 args.valuelen = *valuelenp;
129 args.flags = flags;
130 args.hashval = xfs_da_hashname(args.name, args.namelen);
131 args.dp = ip;
132 args.whichfork = XFS_ATTR_FORK;
133
134
135
136
137 if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
138 error = xfs_attr_shortform_getvalue(&args);
139 } else if (xfs_bmap_one_block(ip, XFS_ATTR_FORK)) {
140 error = xfs_attr_leaf_get(&args);
141 } else {
142 error = xfs_attr_node_get(&args);
143 }
144
145
146
147
148 *valuelenp = args.valuelen;
149
150 if (error == EEXIST)
151 error = 0;
152 return(error);
153}
154
155int
156xfs_attr_get(
157 xfs_inode_t *ip,
158 const unsigned char *name,
159 unsigned char *value,
160 int *valuelenp,
161 int flags)
162{
163 int error;
164 struct xfs_name xname;
165
166 XFS_STATS_INC(xs_attr_get);
167
168 if (XFS_FORCED_SHUTDOWN(ip->i_mount))
169 return(EIO);
170
171 error = xfs_attr_name_to_xname(&xname, name);
172 if (error)
173 return error;
174
175 xfs_ilock(ip, XFS_ILOCK_SHARED);
176 error = xfs_attr_get_int(ip, &xname, value, valuelenp, flags);
177 xfs_iunlock(ip, XFS_ILOCK_SHARED);
178 return(error);
179}
180
181
182
183
184STATIC int
185xfs_attr_calc_size(
186 struct xfs_inode *ip,
187 int namelen,
188 int valuelen,
189 int *local)
190{
191 struct xfs_mount *mp = ip->i_mount;
192 int size;
193 int nblks;
194
195
196
197
198
199 size = xfs_attr_leaf_newentsize(namelen, valuelen,
200 mp->m_sb.sb_blocksize, local);
201
202 nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK);
203 if (*local) {
204 if (size > (mp->m_sb.sb_blocksize >> 1)) {
205
206 nblks *= 2;
207 }
208 } else {
209
210
211
212
213 uint dblocks = XFS_B_TO_FSB(mp, valuelen);
214 nblks += dblocks;
215 nblks += XFS_NEXTENTADD_SPACE_RES(mp, dblocks, XFS_ATTR_FORK);
216 }
217
218 return nblks;
219}
220
221STATIC int
222xfs_attr_set_int(
223 struct xfs_inode *dp,
224 struct xfs_name *name,
225 unsigned char *value,
226 int valuelen,
227 int flags)
228{
229 xfs_da_args_t args;
230 xfs_fsblock_t firstblock;
231 xfs_bmap_free_t flist;
232 int error, err2, committed;
233 struct xfs_mount *mp = dp->i_mount;
234 struct xfs_trans_res tres;
235 int rsvd = (flags & ATTR_ROOT) != 0;
236 int local;
237
238
239
240
241 error = xfs_qm_dqattach(dp, 0);
242 if (error)
243 return error;
244
245
246
247
248
249 if (XFS_IFORK_Q(dp) == 0) {
250 int sf_size = sizeof(xfs_attr_sf_hdr_t) +
251 XFS_ATTR_SF_ENTSIZE_BYNAME(name->len, valuelen);
252
253 if ((error = xfs_bmap_add_attrfork(dp, sf_size, rsvd)))
254 return(error);
255 }
256
257
258
259
260 memset((char *)&args, 0, sizeof(args));
261 args.name = name->name;
262 args.namelen = name->len;
263 args.value = value;
264 args.valuelen = valuelen;
265 args.flags = flags;
266 args.hashval = xfs_da_hashname(args.name, args.namelen);
267 args.dp = dp;
268 args.firstblock = &firstblock;
269 args.flist = &flist;
270 args.whichfork = XFS_ATTR_FORK;
271 args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
272
273
274 args.total = xfs_attr_calc_size(dp, name->len, valuelen, &local);
275
276
277
278
279
280
281
282
283
284
285
286 args.trans = xfs_trans_alloc(mp, XFS_TRANS_ATTR_SET);
287
288
289
290
291
292
293 if (rsvd)
294 args.trans->t_flags |= XFS_TRANS_RESERVE;
295
296 tres.tr_logres = M_RES(mp)->tr_attrsetm.tr_logres +
297 M_RES(mp)->tr_attrsetrt.tr_logres * args.total;
298 tres.tr_logcount = XFS_ATTRSET_LOG_COUNT;
299 tres.tr_logflags = XFS_TRANS_PERM_LOG_RES;
300 error = xfs_trans_reserve(args.trans, &tres, args.total, 0);
301 if (error) {
302 xfs_trans_cancel(args.trans, 0);
303 return(error);
304 }
305 xfs_ilock(dp, XFS_ILOCK_EXCL);
306
307 error = xfs_trans_reserve_quota_nblks(args.trans, dp, args.total, 0,
308 rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES :
309 XFS_QMOPT_RES_REGBLKS);
310 if (error) {
311 xfs_iunlock(dp, XFS_ILOCK_EXCL);
312 xfs_trans_cancel(args.trans, XFS_TRANS_RELEASE_LOG_RES);
313 return (error);
314 }
315
316 xfs_trans_ijoin(args.trans, dp, 0);
317
318
319
320
321
322 if ((dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) ||
323 ((dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) &&
324 (dp->i_d.di_anextents == 0))) {
325
326
327
328
329 if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
330 xfs_attr_shortform_create(&args);
331
332
333
334
335
336 error = xfs_attr_shortform_addname(&args);
337 if (error != ENOSPC) {
338
339
340
341
342 ASSERT(args.trans != NULL);
343
344
345
346
347
348
349 if (mp->m_flags & XFS_MOUNT_WSYNC) {
350 xfs_trans_set_sync(args.trans);
351 }
352
353 if (!error && (flags & ATTR_KERNOTIME) == 0) {
354 xfs_trans_ichgtime(args.trans, dp,
355 XFS_ICHGTIME_CHG);
356 }
357 err2 = xfs_trans_commit(args.trans,
358 XFS_TRANS_RELEASE_LOG_RES);
359 xfs_iunlock(dp, XFS_ILOCK_EXCL);
360
361 return(error == 0 ? err2 : error);
362 }
363
364
365
366
367
368 xfs_bmap_init(args.flist, args.firstblock);
369 error = xfs_attr_shortform_to_leaf(&args);
370 if (!error) {
371 error = xfs_bmap_finish(&args.trans, args.flist,
372 &committed);
373 }
374 if (error) {
375 ASSERT(committed);
376 args.trans = NULL;
377 xfs_bmap_cancel(&flist);
378 goto out;
379 }
380
381
382
383
384
385 if (committed)
386 xfs_trans_ijoin(args.trans, dp, 0);
387
388
389
390
391
392
393 error = xfs_trans_roll(&args.trans, dp);
394 if (error)
395 goto out;
396
397 }
398
399 if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
400 error = xfs_attr_leaf_addname(&args);
401 } else {
402 error = xfs_attr_node_addname(&args);
403 }
404 if (error) {
405 goto out;
406 }
407
408
409
410
411
412 if (mp->m_flags & XFS_MOUNT_WSYNC) {
413 xfs_trans_set_sync(args.trans);
414 }
415
416 if ((flags & ATTR_KERNOTIME) == 0)
417 xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
418
419
420
421
422 xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE);
423 error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES);
424 xfs_iunlock(dp, XFS_ILOCK_EXCL);
425
426 return(error);
427
428out:
429 if (args.trans)
430 xfs_trans_cancel(args.trans,
431 XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
432 xfs_iunlock(dp, XFS_ILOCK_EXCL);
433 return(error);
434}
435
436int
437xfs_attr_set(
438 xfs_inode_t *dp,
439 const unsigned char *name,
440 unsigned char *value,
441 int valuelen,
442 int flags)
443{
444 int error;
445 struct xfs_name xname;
446
447 XFS_STATS_INC(xs_attr_set);
448
449 if (XFS_FORCED_SHUTDOWN(dp->i_mount))
450 return (EIO);
451
452 error = xfs_attr_name_to_xname(&xname, name);
453 if (error)
454 return error;
455
456 return xfs_attr_set_int(dp, &xname, value, valuelen, flags);
457}
458
459
460
461
462
463STATIC int
464xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags)
465{
466 xfs_da_args_t args;
467 xfs_fsblock_t firstblock;
468 xfs_bmap_free_t flist;
469 int error;
470 xfs_mount_t *mp = dp->i_mount;
471
472
473
474
475 memset((char *)&args, 0, sizeof(args));
476 args.name = name->name;
477 args.namelen = name->len;
478 args.flags = flags;
479 args.hashval = xfs_da_hashname(args.name, args.namelen);
480 args.dp = dp;
481 args.firstblock = &firstblock;
482 args.flist = &flist;
483 args.total = 0;
484 args.whichfork = XFS_ATTR_FORK;
485
486
487
488
489
490
491 args.op_flags = XFS_DA_OP_OKNOENT;
492
493
494
495
496 error = xfs_qm_dqattach(dp, 0);
497 if (error)
498 return error;
499
500
501
502
503
504
505
506
507
508
509
510 args.trans = xfs_trans_alloc(mp, XFS_TRANS_ATTR_RM);
511
512
513
514
515
516
517 if (flags & ATTR_ROOT)
518 args.trans->t_flags |= XFS_TRANS_RESERVE;
519
520 error = xfs_trans_reserve(args.trans, &M_RES(mp)->tr_attrrm,
521 XFS_ATTRRM_SPACE_RES(mp), 0);
522 if (error) {
523 xfs_trans_cancel(args.trans, 0);
524 return(error);
525 }
526
527 xfs_ilock(dp, XFS_ILOCK_EXCL);
528
529
530
531
532 xfs_trans_ijoin(args.trans, dp, 0);
533
534
535
536
537 if (!xfs_inode_hasattr(dp)) {
538 error = XFS_ERROR(ENOATTR);
539 goto out;
540 }
541 if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
542 ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
543 error = xfs_attr_shortform_remove(&args);
544 if (error) {
545 goto out;
546 }
547 } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
548 error = xfs_attr_leaf_removename(&args);
549 } else {
550 error = xfs_attr_node_removename(&args);
551 }
552 if (error) {
553 goto out;
554 }
555
556
557
558
559
560 if (mp->m_flags & XFS_MOUNT_WSYNC) {
561 xfs_trans_set_sync(args.trans);
562 }
563
564 if ((flags & ATTR_KERNOTIME) == 0)
565 xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
566
567
568
569
570 xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE);
571 error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES);
572 xfs_iunlock(dp, XFS_ILOCK_EXCL);
573
574 return(error);
575
576out:
577 if (args.trans)
578 xfs_trans_cancel(args.trans,
579 XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
580 xfs_iunlock(dp, XFS_ILOCK_EXCL);
581 return(error);
582}
583
584int
585xfs_attr_remove(
586 xfs_inode_t *dp,
587 const unsigned char *name,
588 int flags)
589{
590 int error;
591 struct xfs_name xname;
592
593 XFS_STATS_INC(xs_attr_remove);
594
595 if (XFS_FORCED_SHUTDOWN(dp->i_mount))
596 return (EIO);
597
598 error = xfs_attr_name_to_xname(&xname, name);
599 if (error)
600 return error;
601
602 xfs_ilock(dp, XFS_ILOCK_SHARED);
603 if (!xfs_inode_hasattr(dp)) {
604 xfs_iunlock(dp, XFS_ILOCK_SHARED);
605 return XFS_ERROR(ENOATTR);
606 }
607 xfs_iunlock(dp, XFS_ILOCK_SHARED);
608
609 return xfs_attr_remove_int(dp, &xname, flags);
610}
611
612
613
614
615
616
617
618
619
620
621STATIC int
622xfs_attr_shortform_addname(xfs_da_args_t *args)
623{
624 int newsize, forkoff, retval;
625
626 trace_xfs_attr_sf_addname(args);
627
628 retval = xfs_attr_shortform_lookup(args);
629 if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) {
630 return(retval);
631 } else if (retval == EEXIST) {
632 if (args->flags & ATTR_CREATE)
633 return(retval);
634 retval = xfs_attr_shortform_remove(args);
635 ASSERT(retval == 0);
636 }
637
638 if (args->namelen >= XFS_ATTR_SF_ENTSIZE_MAX ||
639 args->valuelen >= XFS_ATTR_SF_ENTSIZE_MAX)
640 return(XFS_ERROR(ENOSPC));
641
642 newsize = XFS_ATTR_SF_TOTSIZE(args->dp);
643 newsize += XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);
644
645 forkoff = xfs_attr_shortform_bytesfit(args->dp, newsize);
646 if (!forkoff)
647 return(XFS_ERROR(ENOSPC));
648
649 xfs_attr_shortform_add(args, forkoff);
650 return(0);
651}
652
653
654
655
656
657
658
659
660
661
662
663
664STATIC int
665xfs_attr_leaf_addname(xfs_da_args_t *args)
666{
667 xfs_inode_t *dp;
668 struct xfs_buf *bp;
669 int retval, error, committed, forkoff;
670
671 trace_xfs_attr_leaf_addname(args);
672
673
674
675
676 dp = args->dp;
677 args->blkno = 0;
678 error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
679 if (error)
680 return error;
681
682
683
684
685
686 retval = xfs_attr3_leaf_lookup_int(bp, args);
687 if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) {
688 xfs_trans_brelse(args->trans, bp);
689 return retval;
690 } else if (retval == EEXIST) {
691 if (args->flags & ATTR_CREATE) {
692 xfs_trans_brelse(args->trans, bp);
693 return retval;
694 }
695
696 trace_xfs_attr_leaf_replace(args);
697
698 args->op_flags |= XFS_DA_OP_RENAME;
699 args->blkno2 = args->blkno;
700 args->index2 = args->index;
701 args->rmtblkno2 = args->rmtblkno;
702 args->rmtblkcnt2 = args->rmtblkcnt;
703 }
704
705
706
707
708
709 retval = xfs_attr3_leaf_add(bp, args);
710 if (retval == ENOSPC) {
711
712
713
714
715
716 xfs_bmap_init(args->flist, args->firstblock);
717 error = xfs_attr3_leaf_to_node(args);
718 if (!error) {
719 error = xfs_bmap_finish(&args->trans, args->flist,
720 &committed);
721 }
722 if (error) {
723 ASSERT(committed);
724 args->trans = NULL;
725 xfs_bmap_cancel(args->flist);
726 return(error);
727 }
728
729
730
731
732
733 if (committed)
734 xfs_trans_ijoin(args->trans, dp, 0);
735
736
737
738
739
740 error = xfs_trans_roll(&args->trans, dp);
741 if (error)
742 return (error);
743
744
745
746
747 error = xfs_attr_node_addname(args);
748 return(error);
749 }
750
751
752
753
754
755 error = xfs_trans_roll(&args->trans, dp);
756 if (error)
757 return (error);
758
759
760
761
762
763
764
765 if (args->rmtblkno > 0) {
766 error = xfs_attr_rmtval_set(args);
767 if (error)
768 return(error);
769 }
770
771
772
773
774
775
776
777 if (args->op_flags & XFS_DA_OP_RENAME) {
778
779
780
781
782 error = xfs_attr3_leaf_flipflags(args);
783 if (error)
784 return(error);
785
786
787
788
789
790 args->index = args->index2;
791 args->blkno = args->blkno2;
792 args->rmtblkno = args->rmtblkno2;
793 args->rmtblkcnt = args->rmtblkcnt2;
794 if (args->rmtblkno) {
795 error = xfs_attr_rmtval_remove(args);
796 if (error)
797 return(error);
798 }
799
800
801
802
803
804 error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
805 -1, &bp);
806 if (error)
807 return error;
808
809 xfs_attr3_leaf_remove(bp, args);
810
811
812
813
814 if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
815 xfs_bmap_init(args->flist, args->firstblock);
816 error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
817
818 if (!error) {
819 error = xfs_bmap_finish(&args->trans,
820 args->flist,
821 &committed);
822 }
823 if (error) {
824 ASSERT(committed);
825 args->trans = NULL;
826 xfs_bmap_cancel(args->flist);
827 return(error);
828 }
829
830
831
832
833
834
835 if (committed)
836 xfs_trans_ijoin(args->trans, dp, 0);
837 }
838
839
840
841
842 error = xfs_trans_roll(&args->trans, dp);
843
844 } else if (args->rmtblkno > 0) {
845
846
847
848 error = xfs_attr3_leaf_clearflag(args);
849 }
850 return error;
851}
852
853
854
855
856
857
858
859STATIC int
860xfs_attr_leaf_removename(xfs_da_args_t *args)
861{
862 xfs_inode_t *dp;
863 struct xfs_buf *bp;
864 int error, committed, forkoff;
865
866 trace_xfs_attr_leaf_removename(args);
867
868
869
870
871 dp = args->dp;
872 args->blkno = 0;
873 error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
874 if (error)
875 return error;
876
877 error = xfs_attr3_leaf_lookup_int(bp, args);
878 if (error == ENOATTR) {
879 xfs_trans_brelse(args->trans, bp);
880 return error;
881 }
882
883 xfs_attr3_leaf_remove(bp, args);
884
885
886
887
888 if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
889 xfs_bmap_init(args->flist, args->firstblock);
890 error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
891
892 if (!error) {
893 error = xfs_bmap_finish(&args->trans, args->flist,
894 &committed);
895 }
896 if (error) {
897 ASSERT(committed);
898 args->trans = NULL;
899 xfs_bmap_cancel(args->flist);
900 return error;
901 }
902
903
904
905
906
907 if (committed)
908 xfs_trans_ijoin(args->trans, dp, 0);
909 }
910 return 0;
911}
912
913
914
915
916
917
918
919STATIC int
920xfs_attr_leaf_get(xfs_da_args_t *args)
921{
922 struct xfs_buf *bp;
923 int error;
924
925 trace_xfs_attr_leaf_get(args);
926
927 args->blkno = 0;
928 error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
929 if (error)
930 return error;
931
932 error = xfs_attr3_leaf_lookup_int(bp, args);
933 if (error != EEXIST) {
934 xfs_trans_brelse(args->trans, bp);
935 return error;
936 }
937 error = xfs_attr3_leaf_getvalue(bp, args);
938 xfs_trans_brelse(args->trans, bp);
939 if (!error && (args->rmtblkno > 0) && !(args->flags & ATTR_KERNOVAL)) {
940 error = xfs_attr_rmtval_get(args);
941 }
942 return error;
943}
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959STATIC int
960xfs_attr_node_addname(xfs_da_args_t *args)
961{
962 xfs_da_state_t *state;
963 xfs_da_state_blk_t *blk;
964 xfs_inode_t *dp;
965 xfs_mount_t *mp;
966 int committed, retval, error;
967
968 trace_xfs_attr_node_addname(args);
969
970
971
972
973 dp = args->dp;
974 mp = dp->i_mount;
975restart:
976 state = xfs_da_state_alloc();
977 state->args = args;
978 state->mp = mp;
979 state->blocksize = state->mp->m_sb.sb_blocksize;
980 state->node_ents = state->mp->m_attr_node_ents;
981
982
983
984
985
986 error = xfs_da3_node_lookup_int(state, &retval);
987 if (error)
988 goto out;
989 blk = &state->path.blk[ state->path.active-1 ];
990 ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
991 if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) {
992 goto out;
993 } else if (retval == EEXIST) {
994 if (args->flags & ATTR_CREATE)
995 goto out;
996
997 trace_xfs_attr_node_replace(args);
998
999 args->op_flags |= XFS_DA_OP_RENAME;
1000 args->blkno2 = args->blkno;
1001 args->index2 = args->index;
1002 args->rmtblkno2 = args->rmtblkno;
1003 args->rmtblkcnt2 = args->rmtblkcnt;
1004 args->rmtblkno = 0;
1005 args->rmtblkcnt = 0;
1006 }
1007
1008 retval = xfs_attr3_leaf_add(blk->bp, state->args);
1009 if (retval == ENOSPC) {
1010 if (state->path.active == 1) {
1011
1012
1013
1014
1015
1016 xfs_da_state_free(state);
1017 state = NULL;
1018 xfs_bmap_init(args->flist, args->firstblock);
1019 error = xfs_attr3_leaf_to_node(args);
1020 if (!error) {
1021 error = xfs_bmap_finish(&args->trans,
1022 args->flist,
1023 &committed);
1024 }
1025 if (error) {
1026 ASSERT(committed);
1027 args->trans = NULL;
1028 xfs_bmap_cancel(args->flist);
1029 goto out;
1030 }
1031
1032
1033
1034
1035
1036
1037 if (committed)
1038 xfs_trans_ijoin(args->trans, dp, 0);
1039
1040
1041
1042
1043
1044 error = xfs_trans_roll(&args->trans, dp);
1045 if (error)
1046 goto out;
1047
1048 goto restart;
1049 }
1050
1051
1052
1053
1054
1055
1056
1057 xfs_bmap_init(args->flist, args->firstblock);
1058 error = xfs_da3_split(state);
1059 if (!error) {
1060 error = xfs_bmap_finish(&args->trans, args->flist,
1061 &committed);
1062 }
1063 if (error) {
1064 ASSERT(committed);
1065 args->trans = NULL;
1066 xfs_bmap_cancel(args->flist);
1067 goto out;
1068 }
1069
1070
1071
1072
1073
1074 if (committed)
1075 xfs_trans_ijoin(args->trans, dp, 0);
1076 } else {
1077
1078
1079
1080 xfs_da3_fixhashpath(state, &state->path);
1081 }
1082
1083
1084
1085
1086
1087 xfs_da_state_free(state);
1088 state = NULL;
1089
1090
1091
1092
1093
1094 error = xfs_trans_roll(&args->trans, dp);
1095 if (error)
1096 goto out;
1097
1098
1099
1100
1101
1102
1103
1104 if (args->rmtblkno > 0) {
1105 error = xfs_attr_rmtval_set(args);
1106 if (error)
1107 return(error);
1108 }
1109
1110
1111
1112
1113
1114
1115
1116 if (args->op_flags & XFS_DA_OP_RENAME) {
1117
1118
1119
1120
1121 error = xfs_attr3_leaf_flipflags(args);
1122 if (error)
1123 goto out;
1124
1125
1126
1127
1128
1129 args->index = args->index2;
1130 args->blkno = args->blkno2;
1131 args->rmtblkno = args->rmtblkno2;
1132 args->rmtblkcnt = args->rmtblkcnt2;
1133 if (args->rmtblkno) {
1134 error = xfs_attr_rmtval_remove(args);
1135 if (error)
1136 return(error);
1137 }
1138
1139
1140
1141
1142
1143
1144 args->flags |= XFS_ATTR_INCOMPLETE;
1145 state = xfs_da_state_alloc();
1146 state->args = args;
1147 state->mp = mp;
1148 state->blocksize = state->mp->m_sb.sb_blocksize;
1149 state->node_ents = state->mp->m_attr_node_ents;
1150 state->inleaf = 0;
1151 error = xfs_da3_node_lookup_int(state, &retval);
1152 if (error)
1153 goto out;
1154
1155
1156
1157
1158 blk = &state->path.blk[ state->path.active-1 ];
1159 ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
1160 error = xfs_attr3_leaf_remove(blk->bp, args);
1161 xfs_da3_fixhashpath(state, &state->path);
1162
1163
1164
1165
1166 if (retval && (state->path.active > 1)) {
1167 xfs_bmap_init(args->flist, args->firstblock);
1168 error = xfs_da3_join(state);
1169 if (!error) {
1170 error = xfs_bmap_finish(&args->trans,
1171 args->flist,
1172 &committed);
1173 }
1174 if (error) {
1175 ASSERT(committed);
1176 args->trans = NULL;
1177 xfs_bmap_cancel(args->flist);
1178 goto out;
1179 }
1180
1181
1182
1183
1184
1185
1186 if (committed)
1187 xfs_trans_ijoin(args->trans, dp, 0);
1188 }
1189
1190
1191
1192
1193 error = xfs_trans_roll(&args->trans, dp);
1194 if (error)
1195 goto out;
1196
1197 } else if (args->rmtblkno > 0) {
1198
1199
1200
1201 error = xfs_attr3_leaf_clearflag(args);
1202 if (error)
1203 goto out;
1204 }
1205 retval = error = 0;
1206
1207out:
1208 if (state)
1209 xfs_da_state_free(state);
1210 if (error)
1211 return(error);
1212 return(retval);
1213}
1214
1215
1216
1217
1218
1219
1220
1221
1222STATIC int
1223xfs_attr_node_removename(xfs_da_args_t *args)
1224{
1225 xfs_da_state_t *state;
1226 xfs_da_state_blk_t *blk;
1227 xfs_inode_t *dp;
1228 struct xfs_buf *bp;
1229 int retval, error, committed, forkoff;
1230
1231 trace_xfs_attr_node_removename(args);
1232
1233
1234
1235
1236 dp = args->dp;
1237 state = xfs_da_state_alloc();
1238 state->args = args;
1239 state->mp = dp->i_mount;
1240 state->blocksize = state->mp->m_sb.sb_blocksize;
1241 state->node_ents = state->mp->m_attr_node_ents;
1242
1243
1244
1245
1246 error = xfs_da3_node_lookup_int(state, &retval);
1247 if (error || (retval != EEXIST)) {
1248 if (error == 0)
1249 error = retval;
1250 goto out;
1251 }
1252
1253
1254
1255
1256
1257
1258 blk = &state->path.blk[ state->path.active-1 ];
1259 ASSERT(blk->bp != NULL);
1260 ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
1261 if (args->rmtblkno > 0) {
1262
1263
1264
1265
1266
1267 error = xfs_attr_fillstate(state);
1268 if (error)
1269 goto out;
1270
1271
1272
1273
1274
1275 error = xfs_attr3_leaf_setflag(args);
1276 if (error)
1277 goto out;
1278 error = xfs_attr_rmtval_remove(args);
1279 if (error)
1280 goto out;
1281
1282
1283
1284
1285
1286 error = xfs_attr_refillstate(state);
1287 if (error)
1288 goto out;
1289 }
1290
1291
1292
1293
1294 blk = &state->path.blk[ state->path.active-1 ];
1295 ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
1296 retval = xfs_attr3_leaf_remove(blk->bp, args);
1297 xfs_da3_fixhashpath(state, &state->path);
1298
1299
1300
1301
1302 if (retval && (state->path.active > 1)) {
1303 xfs_bmap_init(args->flist, args->firstblock);
1304 error = xfs_da3_join(state);
1305 if (!error) {
1306 error = xfs_bmap_finish(&args->trans, args->flist,
1307 &committed);
1308 }
1309 if (error) {
1310 ASSERT(committed);
1311 args->trans = NULL;
1312 xfs_bmap_cancel(args->flist);
1313 goto out;
1314 }
1315
1316
1317
1318
1319
1320 if (committed)
1321 xfs_trans_ijoin(args->trans, dp, 0);
1322
1323
1324
1325
1326 error = xfs_trans_roll(&args->trans, dp);
1327 if (error)
1328 goto out;
1329 }
1330
1331
1332
1333
1334 if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
1335
1336
1337
1338 ASSERT(state->path.active == 1);
1339 ASSERT(state->path.blk[0].bp);
1340 state->path.blk[0].bp = NULL;
1341
1342 error = xfs_attr3_leaf_read(args->trans, args->dp, 0, -1, &bp);
1343 if (error)
1344 goto out;
1345
1346 if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
1347 xfs_bmap_init(args->flist, args->firstblock);
1348 error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
1349
1350 if (!error) {
1351 error = xfs_bmap_finish(&args->trans,
1352 args->flist,
1353 &committed);
1354 }
1355 if (error) {
1356 ASSERT(committed);
1357 args->trans = NULL;
1358 xfs_bmap_cancel(args->flist);
1359 goto out;
1360 }
1361
1362
1363
1364
1365
1366
1367 if (committed)
1368 xfs_trans_ijoin(args->trans, dp, 0);
1369 } else
1370 xfs_trans_brelse(args->trans, bp);
1371 }
1372 error = 0;
1373
1374out:
1375 xfs_da_state_free(state);
1376 return(error);
1377}
1378
1379
1380
1381
1382
1383
1384
1385STATIC int
1386xfs_attr_fillstate(xfs_da_state_t *state)
1387{
1388 xfs_da_state_path_t *path;
1389 xfs_da_state_blk_t *blk;
1390 int level;
1391
1392 trace_xfs_attr_fillstate(state->args);
1393
1394
1395
1396
1397
1398 path = &state->path;
1399 ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
1400 for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
1401 if (blk->bp) {
1402 blk->disk_blkno = XFS_BUF_ADDR(blk->bp);
1403 blk->bp = NULL;
1404 } else {
1405 blk->disk_blkno = 0;
1406 }
1407 }
1408
1409
1410
1411
1412
1413 path = &state->altpath;
1414 ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
1415 for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
1416 if (blk->bp) {
1417 blk->disk_blkno = XFS_BUF_ADDR(blk->bp);
1418 blk->bp = NULL;
1419 } else {
1420 blk->disk_blkno = 0;
1421 }
1422 }
1423
1424 return(0);
1425}
1426
1427
1428
1429
1430
1431
1432
1433STATIC int
1434xfs_attr_refillstate(xfs_da_state_t *state)
1435{
1436 xfs_da_state_path_t *path;
1437 xfs_da_state_blk_t *blk;
1438 int level, error;
1439
1440 trace_xfs_attr_refillstate(state->args);
1441
1442
1443
1444
1445
1446 path = &state->path;
1447 ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
1448 for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
1449 if (blk->disk_blkno) {
1450 error = xfs_da3_node_read(state->args->trans,
1451 state->args->dp,
1452 blk->blkno, blk->disk_blkno,
1453 &blk->bp, XFS_ATTR_FORK);
1454 if (error)
1455 return(error);
1456 } else {
1457 blk->bp = NULL;
1458 }
1459 }
1460
1461
1462
1463
1464
1465 path = &state->altpath;
1466 ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
1467 for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
1468 if (blk->disk_blkno) {
1469 error = xfs_da3_node_read(state->args->trans,
1470 state->args->dp,
1471 blk->blkno, blk->disk_blkno,
1472 &blk->bp, XFS_ATTR_FORK);
1473 if (error)
1474 return(error);
1475 } else {
1476 blk->bp = NULL;
1477 }
1478 }
1479
1480 return(0);
1481}
1482
1483
1484
1485
1486
1487
1488
1489
1490STATIC int
1491xfs_attr_node_get(xfs_da_args_t *args)
1492{
1493 xfs_da_state_t *state;
1494 xfs_da_state_blk_t *blk;
1495 int error, retval;
1496 int i;
1497
1498 trace_xfs_attr_node_get(args);
1499
1500 state = xfs_da_state_alloc();
1501 state->args = args;
1502 state->mp = args->dp->i_mount;
1503 state->blocksize = state->mp->m_sb.sb_blocksize;
1504 state->node_ents = state->mp->m_attr_node_ents;
1505
1506
1507
1508
1509 error = xfs_da3_node_lookup_int(state, &retval);
1510 if (error) {
1511 retval = error;
1512 } else if (retval == EEXIST) {
1513 blk = &state->path.blk[ state->path.active-1 ];
1514 ASSERT(blk->bp != NULL);
1515 ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
1516
1517
1518
1519
1520 retval = xfs_attr3_leaf_getvalue(blk->bp, args);
1521 if (!retval && (args->rmtblkno > 0)
1522 && !(args->flags & ATTR_KERNOVAL)) {
1523 retval = xfs_attr_rmtval_get(args);
1524 }
1525 }
1526
1527
1528
1529
1530 for (i = 0; i < state->path.active; i++) {
1531 xfs_trans_brelse(args->trans, state->path.blk[i].bp);
1532 state->path.blk[i].bp = NULL;
1533 }
1534
1535 xfs_da_state_free(state);
1536 return(retval);
1537}
1538