diff options
Diffstat (limited to 'fs/xfs/xfs_attr.c')
-rw-r--r-- | fs/xfs/xfs_attr.c | 718 |
1 files changed, 160 insertions, 558 deletions
diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c index df151a859186..f7cdc28aff41 100644 --- a/fs/xfs/xfs_attr.c +++ b/fs/xfs/xfs_attr.c | |||
@@ -16,8 +16,6 @@ | |||
16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <linux/capability.h> | ||
20 | |||
21 | #include "xfs.h" | 19 | #include "xfs.h" |
22 | #include "xfs_fs.h" | 20 | #include "xfs_fs.h" |
23 | #include "xfs_types.h" | 21 | #include "xfs_types.h" |
@@ -57,11 +55,6 @@ | |||
57 | * Provide the external interfaces to manage attribute lists. | 55 | * Provide the external interfaces to manage attribute lists. |
58 | */ | 56 | */ |
59 | 57 | ||
60 | #define ATTR_SYSCOUNT 2 | ||
61 | static struct attrnames posix_acl_access; | ||
62 | static struct attrnames posix_acl_default; | ||
63 | static struct attrnames *attr_system_names[ATTR_SYSCOUNT]; | ||
64 | |||
65 | /*======================================================================== | 58 | /*======================================================================== |
66 | * Function prototypes for the kernel. | 59 | * Function prototypes for the kernel. |
67 | *========================================================================*/ | 60 | *========================================================================*/ |
@@ -116,6 +109,17 @@ xfs_attr_name_to_xname( | |||
116 | return 0; | 109 | return 0; |
117 | } | 110 | } |
118 | 111 | ||
112 | STATIC int | ||
113 | xfs_inode_hasattr( | ||
114 | struct xfs_inode *ip) | ||
115 | { | ||
116 | if (!XFS_IFORK_Q(ip) || | ||
117 | (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && | ||
118 | ip->i_d.di_anextents == 0)) | ||
119 | return 0; | ||
120 | return 1; | ||
121 | } | ||
122 | |||
119 | /*======================================================================== | 123 | /*======================================================================== |
120 | * Overall external interface routines. | 124 | * Overall external interface routines. |
121 | *========================================================================*/ | 125 | *========================================================================*/ |
@@ -127,10 +131,8 @@ xfs_attr_fetch(xfs_inode_t *ip, struct xfs_name *name, | |||
127 | xfs_da_args_t args; | 131 | xfs_da_args_t args; |
128 | int error; | 132 | int error; |
129 | 133 | ||
130 | if ((XFS_IFORK_Q(ip) == 0) || | 134 | if (!xfs_inode_hasattr(ip)) |
131 | (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && | 135 | return ENOATTR; |
132 | ip->i_d.di_anextents == 0)) | ||
133 | return(ENOATTR); | ||
134 | 136 | ||
135 | /* | 137 | /* |
136 | * Fill in the arg structure for this request. | 138 | * Fill in the arg structure for this request. |
@@ -148,11 +150,7 @@ xfs_attr_fetch(xfs_inode_t *ip, struct xfs_name *name, | |||
148 | /* | 150 | /* |
149 | * Decide on what work routines to call based on the inode size. | 151 | * Decide on what work routines to call based on the inode size. |
150 | */ | 152 | */ |
151 | if (XFS_IFORK_Q(ip) == 0 || | 153 | if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { |
152 | (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && | ||
153 | ip->i_d.di_anextents == 0)) { | ||
154 | error = XFS_ERROR(ENOATTR); | ||
155 | } else if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { | ||
156 | error = xfs_attr_shortform_getvalue(&args); | 154 | error = xfs_attr_shortform_getvalue(&args); |
157 | } else if (xfs_bmap_one_block(ip, XFS_ATTR_FORK)) { | 155 | } else if (xfs_bmap_one_block(ip, XFS_ATTR_FORK)) { |
158 | error = xfs_attr_leaf_get(&args); | 156 | error = xfs_attr_leaf_get(&args); |
@@ -196,6 +194,46 @@ xfs_attr_get( | |||
196 | return(error); | 194 | return(error); |
197 | } | 195 | } |
198 | 196 | ||
197 | /* | ||
198 | * Calculate how many blocks we need for the new attribute, | ||
199 | */ | ||
200 | int | ||
201 | xfs_attr_calc_size( | ||
202 | struct xfs_inode *ip, | ||
203 | int namelen, | ||
204 | int valuelen, | ||
205 | int *local) | ||
206 | { | ||
207 | struct xfs_mount *mp = ip->i_mount; | ||
208 | int size; | ||
209 | int nblks; | ||
210 | |||
211 | /* | ||
212 | * Determine space new attribute will use, and if it would be | ||
213 | * "local" or "remote" (note: local != inline). | ||
214 | */ | ||
215 | size = xfs_attr_leaf_newentsize(namelen, valuelen, | ||
216 | mp->m_sb.sb_blocksize, local); | ||
217 | |||
218 | nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK); | ||
219 | if (*local) { | ||
220 | if (size > (mp->m_sb.sb_blocksize >> 1)) { | ||
221 | /* Double split possible */ | ||
222 | nblks *= 2; | ||
223 | } | ||
224 | } else { | ||
225 | /* | ||
226 | * Out of line attribute, cannot double split, but | ||
227 | * make room for the attribute value itself. | ||
228 | */ | ||
229 | uint dblocks = XFS_B_TO_FSB(mp, valuelen); | ||
230 | nblks += dblocks; | ||
231 | nblks += XFS_NEXTENTADD_SPACE_RES(mp, dblocks, XFS_ATTR_FORK); | ||
232 | } | ||
233 | |||
234 | return nblks; | ||
235 | } | ||
236 | |||
199 | STATIC int | 237 | STATIC int |
200 | xfs_attr_set_int(xfs_inode_t *dp, struct xfs_name *name, | 238 | xfs_attr_set_int(xfs_inode_t *dp, struct xfs_name *name, |
201 | char *value, int valuelen, int flags) | 239 | char *value, int valuelen, int flags) |
@@ -204,10 +242,9 @@ xfs_attr_set_int(xfs_inode_t *dp, struct xfs_name *name, | |||
204 | xfs_fsblock_t firstblock; | 242 | xfs_fsblock_t firstblock; |
205 | xfs_bmap_free_t flist; | 243 | xfs_bmap_free_t flist; |
206 | int error, err2, committed; | 244 | int error, err2, committed; |
207 | int local, size; | ||
208 | uint nblks; | ||
209 | xfs_mount_t *mp = dp->i_mount; | 245 | xfs_mount_t *mp = dp->i_mount; |
210 | int rsvd = (flags & ATTR_ROOT) != 0; | 246 | int rsvd = (flags & ATTR_ROOT) != 0; |
247 | int local; | ||
211 | 248 | ||
212 | /* | 249 | /* |
213 | * Attach the dquots to the inode. | 250 | * Attach the dquots to the inode. |
@@ -241,33 +278,10 @@ xfs_attr_set_int(xfs_inode_t *dp, struct xfs_name *name, | |||
241 | args.firstblock = &firstblock; | 278 | args.firstblock = &firstblock; |
242 | args.flist = &flist; | 279 | args.flist = &flist; |
243 | args.whichfork = XFS_ATTR_FORK; | 280 | args.whichfork = XFS_ATTR_FORK; |
244 | args.addname = 1; | 281 | args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT; |
245 | args.oknoent = 1; | ||
246 | |||
247 | /* | ||
248 | * Determine space new attribute will use, and if it would be | ||
249 | * "local" or "remote" (note: local != inline). | ||
250 | */ | ||
251 | size = xfs_attr_leaf_newentsize(name->len, valuelen, | ||
252 | mp->m_sb.sb_blocksize, &local); | ||
253 | |||
254 | nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK); | ||
255 | if (local) { | ||
256 | if (size > (mp->m_sb.sb_blocksize >> 1)) { | ||
257 | /* Double split possible */ | ||
258 | nblks <<= 1; | ||
259 | } | ||
260 | } else { | ||
261 | uint dblocks = XFS_B_TO_FSB(mp, valuelen); | ||
262 | /* Out of line attribute, cannot double split, but make | ||
263 | * room for the attribute value itself. | ||
264 | */ | ||
265 | nblks += dblocks; | ||
266 | nblks += XFS_NEXTENTADD_SPACE_RES(mp, dblocks, XFS_ATTR_FORK); | ||
267 | } | ||
268 | 282 | ||
269 | /* Size is now blocks for attribute data */ | 283 | /* Size is now blocks for attribute data */ |
270 | args.total = nblks; | 284 | args.total = xfs_attr_calc_size(dp, name->len, valuelen, &local); |
271 | 285 | ||
272 | /* | 286 | /* |
273 | * Start our first transaction of the day. | 287 | * Start our first transaction of the day. |
@@ -289,18 +303,17 @@ xfs_attr_set_int(xfs_inode_t *dp, struct xfs_name *name, | |||
289 | if (rsvd) | 303 | if (rsvd) |
290 | args.trans->t_flags |= XFS_TRANS_RESERVE; | 304 | args.trans->t_flags |= XFS_TRANS_RESERVE; |
291 | 305 | ||
292 | if ((error = xfs_trans_reserve(args.trans, (uint) nblks, | 306 | if ((error = xfs_trans_reserve(args.trans, args.total, |
293 | XFS_ATTRSET_LOG_RES(mp, nblks), | 307 | XFS_ATTRSET_LOG_RES(mp, args.total), 0, |
294 | 0, XFS_TRANS_PERM_LOG_RES, | 308 | XFS_TRANS_PERM_LOG_RES, XFS_ATTRSET_LOG_COUNT))) { |
295 | XFS_ATTRSET_LOG_COUNT))) { | ||
296 | xfs_trans_cancel(args.trans, 0); | 309 | xfs_trans_cancel(args.trans, 0); |
297 | return(error); | 310 | return(error); |
298 | } | 311 | } |
299 | xfs_ilock(dp, XFS_ILOCK_EXCL); | 312 | xfs_ilock(dp, XFS_ILOCK_EXCL); |
300 | 313 | ||
301 | error = XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, args.trans, dp, nblks, 0, | 314 | error = XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, args.trans, dp, args.total, 0, |
302 | rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES : | 315 | rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES : |
303 | XFS_QMOPT_RES_REGBLKS); | 316 | XFS_QMOPT_RES_REGBLKS); |
304 | if (error) { | 317 | if (error) { |
305 | xfs_iunlock(dp, XFS_ILOCK_EXCL); | 318 | xfs_iunlock(dp, XFS_ILOCK_EXCL); |
306 | xfs_trans_cancel(args.trans, XFS_TRANS_RELEASE_LOG_RES); | 319 | xfs_trans_cancel(args.trans, XFS_TRANS_RELEASE_LOG_RES); |
@@ -387,7 +400,9 @@ xfs_attr_set_int(xfs_inode_t *dp, struct xfs_name *name, | |||
387 | * Commit the leaf transformation. We'll need another (linked) | 400 | * Commit the leaf transformation. We'll need another (linked) |
388 | * transaction to add the new attribute to the leaf. | 401 | * transaction to add the new attribute to the leaf. |
389 | */ | 402 | */ |
390 | if ((error = xfs_attr_rolltrans(&args.trans, dp))) | 403 | |
404 | error = xfs_trans_roll(&args.trans, dp); | ||
405 | if (error) | ||
391 | goto out; | 406 | goto out; |
392 | 407 | ||
393 | } | 408 | } |
@@ -529,9 +544,7 @@ xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags) | |||
529 | /* | 544 | /* |
530 | * Decide on what work routines to call based on the inode size. | 545 | * Decide on what work routines to call based on the inode size. |
531 | */ | 546 | */ |
532 | if (XFS_IFORK_Q(dp) == 0 || | 547 | if (!xfs_inode_hasattr(dp)) { |
533 | (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && | ||
534 | dp->i_d.di_anextents == 0)) { | ||
535 | error = XFS_ERROR(ENOATTR); | 548 | error = XFS_ERROR(ENOATTR); |
536 | goto out; | 549 | goto out; |
537 | } | 550 | } |
@@ -601,29 +614,33 @@ xfs_attr_remove( | |||
601 | return error; | 614 | return error; |
602 | 615 | ||
603 | xfs_ilock(dp, XFS_ILOCK_SHARED); | 616 | xfs_ilock(dp, XFS_ILOCK_SHARED); |
604 | if (XFS_IFORK_Q(dp) == 0 || | 617 | if (!xfs_inode_hasattr(dp)) { |
605 | (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && | ||
606 | dp->i_d.di_anextents == 0)) { | ||
607 | xfs_iunlock(dp, XFS_ILOCK_SHARED); | 618 | xfs_iunlock(dp, XFS_ILOCK_SHARED); |
608 | return(XFS_ERROR(ENOATTR)); | 619 | return XFS_ERROR(ENOATTR); |
609 | } | 620 | } |
610 | xfs_iunlock(dp, XFS_ILOCK_SHARED); | 621 | xfs_iunlock(dp, XFS_ILOCK_SHARED); |
611 | 622 | ||
612 | return xfs_attr_remove_int(dp, &xname, flags); | 623 | return xfs_attr_remove_int(dp, &xname, flags); |
613 | } | 624 | } |
614 | 625 | ||
615 | STATIC int | 626 | int |
616 | xfs_attr_list_int(xfs_attr_list_context_t *context) | 627 | xfs_attr_list_int(xfs_attr_list_context_t *context) |
617 | { | 628 | { |
618 | int error; | 629 | int error; |
619 | xfs_inode_t *dp = context->dp; | 630 | xfs_inode_t *dp = context->dp; |
620 | 631 | ||
632 | XFS_STATS_INC(xs_attr_list); | ||
633 | |||
634 | if (XFS_FORCED_SHUTDOWN(dp->i_mount)) | ||
635 | return EIO; | ||
636 | |||
637 | xfs_ilock(dp, XFS_ILOCK_SHARED); | ||
638 | xfs_attr_trace_l_c("syscall start", context); | ||
639 | |||
621 | /* | 640 | /* |
622 | * Decide on what work routines to call based on the inode size. | 641 | * Decide on what work routines to call based on the inode size. |
623 | */ | 642 | */ |
624 | if (XFS_IFORK_Q(dp) == 0 || | 643 | if (!xfs_inode_hasattr(dp)) { |
625 | (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && | ||
626 | dp->i_d.di_anextents == 0)) { | ||
627 | error = 0; | 644 | error = 0; |
628 | } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { | 645 | } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { |
629 | error = xfs_attr_shortform_list(context); | 646 | error = xfs_attr_shortform_list(context); |
@@ -632,6 +649,10 @@ xfs_attr_list_int(xfs_attr_list_context_t *context) | |||
632 | } else { | 649 | } else { |
633 | error = xfs_attr_node_list(context); | 650 | error = xfs_attr_node_list(context); |
634 | } | 651 | } |
652 | |||
653 | xfs_iunlock(dp, XFS_ILOCK_SHARED); | ||
654 | xfs_attr_trace_l_c("syscall end", context); | ||
655 | |||
635 | return error; | 656 | return error; |
636 | } | 657 | } |
637 | 658 | ||
@@ -648,74 +669,50 @@ xfs_attr_list_int(xfs_attr_list_context_t *context) | |||
648 | */ | 669 | */ |
649 | /*ARGSUSED*/ | 670 | /*ARGSUSED*/ |
650 | STATIC int | 671 | STATIC int |
651 | xfs_attr_put_listent(xfs_attr_list_context_t *context, attrnames_t *namesp, | 672 | xfs_attr_put_listent(xfs_attr_list_context_t *context, int flags, |
652 | char *name, int namelen, | 673 | char *name, int namelen, |
653 | int valuelen, char *value) | 674 | int valuelen, char *value) |
654 | { | 675 | { |
676 | struct attrlist *alist = (struct attrlist *)context->alist; | ||
655 | attrlist_ent_t *aep; | 677 | attrlist_ent_t *aep; |
656 | int arraytop; | 678 | int arraytop; |
657 | 679 | ||
658 | ASSERT(!(context->flags & ATTR_KERNOVAL)); | 680 | ASSERT(!(context->flags & ATTR_KERNOVAL)); |
659 | ASSERT(context->count >= 0); | 681 | ASSERT(context->count >= 0); |
660 | ASSERT(context->count < (ATTR_MAX_VALUELEN/8)); | 682 | ASSERT(context->count < (ATTR_MAX_VALUELEN/8)); |
661 | ASSERT(context->firstu >= sizeof(*context->alist)); | 683 | ASSERT(context->firstu >= sizeof(*alist)); |
662 | ASSERT(context->firstu <= context->bufsize); | 684 | ASSERT(context->firstu <= context->bufsize); |
663 | 685 | ||
664 | arraytop = sizeof(*context->alist) + | 686 | /* |
665 | context->count * sizeof(context->alist->al_offset[0]); | 687 | * Only list entries in the right namespace. |
688 | */ | ||
689 | if (((context->flags & ATTR_SECURE) == 0) != | ||
690 | ((flags & XFS_ATTR_SECURE) == 0)) | ||
691 | return 0; | ||
692 | if (((context->flags & ATTR_ROOT) == 0) != | ||
693 | ((flags & XFS_ATTR_ROOT) == 0)) | ||
694 | return 0; | ||
695 | |||
696 | arraytop = sizeof(*alist) + | ||
697 | context->count * sizeof(alist->al_offset[0]); | ||
666 | context->firstu -= ATTR_ENTSIZE(namelen); | 698 | context->firstu -= ATTR_ENTSIZE(namelen); |
667 | if (context->firstu < arraytop) { | 699 | if (context->firstu < arraytop) { |
668 | xfs_attr_trace_l_c("buffer full", context); | 700 | xfs_attr_trace_l_c("buffer full", context); |
669 | context->alist->al_more = 1; | 701 | alist->al_more = 1; |
670 | context->seen_enough = 1; | 702 | context->seen_enough = 1; |
671 | return 1; | 703 | return 1; |
672 | } | 704 | } |
673 | 705 | ||
674 | aep = (attrlist_ent_t *)&(((char *)context->alist)[ context->firstu ]); | 706 | aep = (attrlist_ent_t *)&context->alist[context->firstu]; |
675 | aep->a_valuelen = valuelen; | 707 | aep->a_valuelen = valuelen; |
676 | memcpy(aep->a_name, name, namelen); | 708 | memcpy(aep->a_name, name, namelen); |
677 | aep->a_name[ namelen ] = 0; | 709 | aep->a_name[namelen] = 0; |
678 | context->alist->al_offset[ context->count++ ] = context->firstu; | 710 | alist->al_offset[context->count++] = context->firstu; |
679 | context->alist->al_count = context->count; | 711 | alist->al_count = context->count; |
680 | xfs_attr_trace_l_c("add", context); | 712 | xfs_attr_trace_l_c("add", context); |
681 | return 0; | 713 | return 0; |
682 | } | 714 | } |
683 | 715 | ||
684 | STATIC int | ||
685 | xfs_attr_kern_list(xfs_attr_list_context_t *context, attrnames_t *namesp, | ||
686 | char *name, int namelen, | ||
687 | int valuelen, char *value) | ||
688 | { | ||
689 | char *offset; | ||
690 | int arraytop; | ||
691 | |||
692 | ASSERT(context->count >= 0); | ||
693 | |||
694 | arraytop = context->count + namesp->attr_namelen + namelen + 1; | ||
695 | if (arraytop > context->firstu) { | ||
696 | context->count = -1; /* insufficient space */ | ||
697 | return 1; | ||
698 | } | ||
699 | offset = (char *)context->alist + context->count; | ||
700 | strncpy(offset, namesp->attr_name, namesp->attr_namelen); | ||
701 | offset += namesp->attr_namelen; | ||
702 | strncpy(offset, name, namelen); /* real name */ | ||
703 | offset += namelen; | ||
704 | *offset = '\0'; | ||
705 | context->count += namesp->attr_namelen + namelen + 1; | ||
706 | return 0; | ||
707 | } | ||
708 | |||
709 | /*ARGSUSED*/ | ||
710 | STATIC int | ||
711 | xfs_attr_kern_list_sizes(xfs_attr_list_context_t *context, attrnames_t *namesp, | ||
712 | char *name, int namelen, | ||
713 | int valuelen, char *value) | ||
714 | { | ||
715 | context->count += namesp->attr_namelen + namelen + 1; | ||
716 | return 0; | ||
717 | } | ||
718 | |||
719 | /* | 716 | /* |
720 | * Generate a list of extended attribute names and optionally | 717 | * Generate a list of extended attribute names and optionally |
721 | * also value lengths. Positive return value follows the XFS | 718 | * also value lengths. Positive return value follows the XFS |
@@ -732,10 +729,9 @@ xfs_attr_list( | |||
732 | attrlist_cursor_kern_t *cursor) | 729 | attrlist_cursor_kern_t *cursor) |
733 | { | 730 | { |
734 | xfs_attr_list_context_t context; | 731 | xfs_attr_list_context_t context; |
732 | struct attrlist *alist; | ||
735 | int error; | 733 | int error; |
736 | 734 | ||
737 | XFS_STATS_INC(xs_attr_list); | ||
738 | |||
739 | /* | 735 | /* |
740 | * Validate the cursor. | 736 | * Validate the cursor. |
741 | */ | 737 | */ |
@@ -756,52 +752,23 @@ xfs_attr_list( | |||
756 | /* | 752 | /* |
757 | * Initialize the output buffer. | 753 | * Initialize the output buffer. |
758 | */ | 754 | */ |
755 | memset(&context, 0, sizeof(context)); | ||
759 | context.dp = dp; | 756 | context.dp = dp; |
760 | context.cursor = cursor; | 757 | context.cursor = cursor; |
761 | context.count = 0; | ||
762 | context.dupcnt = 0; | ||
763 | context.resynch = 1; | 758 | context.resynch = 1; |
764 | context.flags = flags; | 759 | context.flags = flags; |
765 | context.seen_enough = 0; | 760 | context.alist = buffer; |
766 | context.alist = (attrlist_t *)buffer; | 761 | context.bufsize = (bufsize & ~(sizeof(int)-1)); /* align */ |
767 | context.put_value = 0; | 762 | context.firstu = context.bufsize; |
768 | 763 | context.put_listent = xfs_attr_put_listent; | |
769 | if (flags & ATTR_KERNAMELS) { | ||
770 | context.bufsize = bufsize; | ||
771 | context.firstu = context.bufsize; | ||
772 | if (flags & ATTR_KERNOVAL) | ||
773 | context.put_listent = xfs_attr_kern_list_sizes; | ||
774 | else | ||
775 | context.put_listent = xfs_attr_kern_list; | ||
776 | } else { | ||
777 | context.bufsize = (bufsize & ~(sizeof(int)-1)); /* align */ | ||
778 | context.firstu = context.bufsize; | ||
779 | context.alist->al_count = 0; | ||
780 | context.alist->al_more = 0; | ||
781 | context.alist->al_offset[0] = context.bufsize; | ||
782 | context.put_listent = xfs_attr_put_listent; | ||
783 | } | ||
784 | |||
785 | if (XFS_FORCED_SHUTDOWN(dp->i_mount)) | ||
786 | return EIO; | ||
787 | 764 | ||
788 | xfs_ilock(dp, XFS_ILOCK_SHARED); | 765 | alist = (struct attrlist *)context.alist; |
789 | xfs_attr_trace_l_c("syscall start", &context); | 766 | alist->al_count = 0; |
767 | alist->al_more = 0; | ||
768 | alist->al_offset[0] = context.bufsize; | ||
790 | 769 | ||
791 | error = xfs_attr_list_int(&context); | 770 | error = xfs_attr_list_int(&context); |
792 | 771 | ASSERT(error >= 0); | |
793 | xfs_iunlock(dp, XFS_ILOCK_SHARED); | ||
794 | xfs_attr_trace_l_c("syscall end", &context); | ||
795 | |||
796 | if (context.flags & (ATTR_KERNOVAL|ATTR_KERNAMELS)) { | ||
797 | /* must return negated buffer size or the error */ | ||
798 | if (context.count < 0) | ||
799 | error = XFS_ERROR(ERANGE); | ||
800 | else | ||
801 | error = -context.count; | ||
802 | } else | ||
803 | ASSERT(error >= 0); | ||
804 | |||
805 | return error; | 772 | return error; |
806 | } | 773 | } |
807 | 774 | ||
@@ -816,12 +783,10 @@ xfs_attr_inactive(xfs_inode_t *dp) | |||
816 | ASSERT(! XFS_NOT_DQATTACHED(mp, dp)); | 783 | ASSERT(! XFS_NOT_DQATTACHED(mp, dp)); |
817 | 784 | ||
818 | xfs_ilock(dp, XFS_ILOCK_SHARED); | 785 | xfs_ilock(dp, XFS_ILOCK_SHARED); |
819 | if ((XFS_IFORK_Q(dp) == 0) || | 786 | if (!xfs_inode_hasattr(dp) || |
820 | (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) || | 787 | dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { |
821 | (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && | ||
822 | dp->i_d.di_anextents == 0)) { | ||
823 | xfs_iunlock(dp, XFS_ILOCK_SHARED); | 788 | xfs_iunlock(dp, XFS_ILOCK_SHARED); |
824 | return(0); | 789 | return 0; |
825 | } | 790 | } |
826 | xfs_iunlock(dp, XFS_ILOCK_SHARED); | 791 | xfs_iunlock(dp, XFS_ILOCK_SHARED); |
827 | 792 | ||
@@ -854,10 +819,8 @@ xfs_attr_inactive(xfs_inode_t *dp) | |||
854 | /* | 819 | /* |
855 | * Decide on what work routines to call based on the inode size. | 820 | * Decide on what work routines to call based on the inode size. |
856 | */ | 821 | */ |
857 | if ((XFS_IFORK_Q(dp) == 0) || | 822 | if (!xfs_inode_hasattr(dp) || |
858 | (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) || | 823 | dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { |
859 | (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && | ||
860 | dp->i_d.di_anextents == 0)) { | ||
861 | error = 0; | 824 | error = 0; |
862 | goto out; | 825 | goto out; |
863 | } | 826 | } |
@@ -974,7 +937,7 @@ xfs_attr_leaf_addname(xfs_da_args_t *args) | |||
974 | xfs_da_brelse(args->trans, bp); | 937 | xfs_da_brelse(args->trans, bp); |
975 | return(retval); | 938 | return(retval); |
976 | } | 939 | } |
977 | args->rename = 1; /* an atomic rename */ | 940 | args->op_flags |= XFS_DA_OP_RENAME; /* an atomic rename */ |
978 | args->blkno2 = args->blkno; /* set 2nd entry info*/ | 941 | args->blkno2 = args->blkno; /* set 2nd entry info*/ |
979 | args->index2 = args->index; | 942 | args->index2 = args->index; |
980 | args->rmtblkno2 = args->rmtblkno; | 943 | args->rmtblkno2 = args->rmtblkno; |
@@ -1019,7 +982,8 @@ xfs_attr_leaf_addname(xfs_da_args_t *args) | |||
1019 | * Commit the current trans (including the inode) and start | 982 | * Commit the current trans (including the inode) and start |
1020 | * a new one. | 983 | * a new one. |
1021 | */ | 984 | */ |
1022 | if ((error = xfs_attr_rolltrans(&args->trans, dp))) | 985 | error = xfs_trans_roll(&args->trans, dp); |
986 | if (error) | ||
1023 | return (error); | 987 | return (error); |
1024 | 988 | ||
1025 | /* | 989 | /* |
@@ -1033,7 +997,8 @@ xfs_attr_leaf_addname(xfs_da_args_t *args) | |||
1033 | * Commit the transaction that added the attr name so that | 997 | * Commit the transaction that added the attr name so that |
1034 | * later routines can manage their own transactions. | 998 | * later routines can manage their own transactions. |
1035 | */ | 999 | */ |
1036 | if ((error = xfs_attr_rolltrans(&args->trans, dp))) | 1000 | error = xfs_trans_roll(&args->trans, dp); |
1001 | if (error) | ||
1037 | return (error); | 1002 | return (error); |
1038 | 1003 | ||
1039 | /* | 1004 | /* |
@@ -1054,7 +1019,7 @@ xfs_attr_leaf_addname(xfs_da_args_t *args) | |||
1054 | * so that one disappears and one appears atomically. Then we | 1019 | * so that one disappears and one appears atomically. Then we |
1055 | * must remove the "old" attribute/value pair. | 1020 | * must remove the "old" attribute/value pair. |
1056 | */ | 1021 | */ |
1057 | if (args->rename) { | 1022 | if (args->op_flags & XFS_DA_OP_RENAME) { |
1058 | /* | 1023 | /* |
1059 | * In a separate transaction, set the incomplete flag on the | 1024 | * In a separate transaction, set the incomplete flag on the |
1060 | * "old" attr and clear the incomplete flag on the "new" attr. | 1025 | * "old" attr and clear the incomplete flag on the "new" attr. |
@@ -1122,7 +1087,7 @@ xfs_attr_leaf_addname(xfs_da_args_t *args) | |||
1122 | /* | 1087 | /* |
1123 | * Commit the remove and start the next trans in series. | 1088 | * Commit the remove and start the next trans in series. |
1124 | */ | 1089 | */ |
1125 | error = xfs_attr_rolltrans(&args->trans, dp); | 1090 | error = xfs_trans_roll(&args->trans, dp); |
1126 | 1091 | ||
1127 | } else if (args->rmtblkno > 0) { | 1092 | } else if (args->rmtblkno > 0) { |
1128 | /* | 1093 | /* |
@@ -1307,7 +1272,7 @@ restart: | |||
1307 | } else if (retval == EEXIST) { | 1272 | } else if (retval == EEXIST) { |
1308 | if (args->flags & ATTR_CREATE) | 1273 | if (args->flags & ATTR_CREATE) |
1309 | goto out; | 1274 | goto out; |
1310 | args->rename = 1; /* atomic rename op */ | 1275 | args->op_flags |= XFS_DA_OP_RENAME; /* atomic rename op */ |
1311 | args->blkno2 = args->blkno; /* set 2nd entry info*/ | 1276 | args->blkno2 = args->blkno; /* set 2nd entry info*/ |
1312 | args->index2 = args->index; | 1277 | args->index2 = args->index; |
1313 | args->rmtblkno2 = args->rmtblkno; | 1278 | args->rmtblkno2 = args->rmtblkno; |
@@ -1353,7 +1318,8 @@ restart: | |||
1353 | * Commit the node conversion and start the next | 1318 | * Commit the node conversion and start the next |
1354 | * trans in the chain. | 1319 | * trans in the chain. |
1355 | */ | 1320 | */ |
1356 | if ((error = xfs_attr_rolltrans(&args->trans, dp))) | 1321 | error = xfs_trans_roll(&args->trans, dp); |
1322 | if (error) | ||
1357 | goto out; | 1323 | goto out; |
1358 | 1324 | ||
1359 | goto restart; | 1325 | goto restart; |
@@ -1404,7 +1370,8 @@ restart: | |||
1404 | * Commit the leaf addition or btree split and start the next | 1370 | * Commit the leaf addition or btree split and start the next |
1405 | * trans in the chain. | 1371 | * trans in the chain. |
1406 | */ | 1372 | */ |
1407 | if ((error = xfs_attr_rolltrans(&args->trans, dp))) | 1373 | error = xfs_trans_roll(&args->trans, dp); |
1374 | if (error) | ||
1408 | goto out; | 1375 | goto out; |
1409 | 1376 | ||
1410 | /* | 1377 | /* |
@@ -1425,7 +1392,7 @@ restart: | |||
1425 | * so that one disappears and one appears atomically. Then we | 1392 | * so that one disappears and one appears atomically. Then we |
1426 | * must remove the "old" attribute/value pair. | 1393 | * must remove the "old" attribute/value pair. |
1427 | */ | 1394 | */ |
1428 | if (args->rename) { | 1395 | if (args->op_flags & XFS_DA_OP_RENAME) { |
1429 | /* | 1396 | /* |
1430 | * In a separate transaction, set the incomplete flag on the | 1397 | * In a separate transaction, set the incomplete flag on the |
1431 | * "old" attr and clear the incomplete flag on the "new" attr. | 1398 | * "old" attr and clear the incomplete flag on the "new" attr. |
@@ -1504,7 +1471,8 @@ restart: | |||
1504 | /* | 1471 | /* |
1505 | * Commit and start the next trans in the chain. | 1472 | * Commit and start the next trans in the chain. |
1506 | */ | 1473 | */ |
1507 | if ((error = xfs_attr_rolltrans(&args->trans, dp))) | 1474 | error = xfs_trans_roll(&args->trans, dp); |
1475 | if (error) | ||
1508 | goto out; | 1476 | goto out; |
1509 | 1477 | ||
1510 | } else if (args->rmtblkno > 0) { | 1478 | } else if (args->rmtblkno > 0) { |
@@ -1636,7 +1604,8 @@ xfs_attr_node_removename(xfs_da_args_t *args) | |||
1636 | /* | 1604 | /* |
1637 | * Commit the Btree join operation and start a new trans. | 1605 | * Commit the Btree join operation and start a new trans. |
1638 | */ | 1606 | */ |
1639 | if ((error = xfs_attr_rolltrans(&args->trans, dp))) | 1607 | error = xfs_trans_roll(&args->trans, dp); |
1608 | if (error) | ||
1640 | goto out; | 1609 | goto out; |
1641 | } | 1610 | } |
1642 | 1611 | ||
@@ -2137,7 +2106,8 @@ xfs_attr_rmtval_set(xfs_da_args_t *args) | |||
2137 | /* | 2106 | /* |
2138 | * Start the next trans in the chain. | 2107 | * Start the next trans in the chain. |
2139 | */ | 2108 | */ |
2140 | if ((error = xfs_attr_rolltrans(&args->trans, dp))) | 2109 | error = xfs_trans_roll(&args->trans, dp); |
2110 | if (error) | ||
2141 | return (error); | 2111 | return (error); |
2142 | } | 2112 | } |
2143 | 2113 | ||
@@ -2287,7 +2257,8 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args) | |||
2287 | /* | 2257 | /* |
2288 | * Close out trans and start the next one in the chain. | 2258 | * Close out trans and start the next one in the chain. |
2289 | */ | 2259 | */ |
2290 | if ((error = xfs_attr_rolltrans(&args->trans, args->dp))) | 2260 | error = xfs_trans_roll(&args->trans, args->dp); |
2261 | if (error) | ||
2291 | return (error); | 2262 | return (error); |
2292 | } | 2263 | } |
2293 | return(0); | 2264 | return(0); |
@@ -2300,23 +2271,7 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args) | |||
2300 | void | 2271 | void |
2301 | xfs_attr_trace_l_c(char *where, struct xfs_attr_list_context *context) | 2272 | xfs_attr_trace_l_c(char *where, struct xfs_attr_list_context *context) |
2302 | { | 2273 | { |
2303 | xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_C, where, | 2274 | xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_C, where, context, |
2304 | (__psunsigned_t)context->dp, | ||
2305 | (__psunsigned_t)context->cursor->hashval, | ||
2306 | (__psunsigned_t)context->cursor->blkno, | ||
2307 | (__psunsigned_t)context->cursor->offset, | ||
2308 | (__psunsigned_t)context->alist, | ||
2309 | (__psunsigned_t)context->bufsize, | ||
2310 | (__psunsigned_t)context->count, | ||
2311 | (__psunsigned_t)context->firstu, | ||
2312 | (__psunsigned_t) | ||
2313 | ((context->count > 0) && | ||
2314 | !(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL))) | ||
2315 | ? (ATTR_ENTRY(context->alist, | ||
2316 | context->count-1)->a_valuelen) | ||
2317 | : 0, | ||
2318 | (__psunsigned_t)context->dupcnt, | ||
2319 | (__psunsigned_t)context->flags, | ||
2320 | (__psunsigned_t)NULL, | 2275 | (__psunsigned_t)NULL, |
2321 | (__psunsigned_t)NULL, | 2276 | (__psunsigned_t)NULL, |
2322 | (__psunsigned_t)NULL); | 2277 | (__psunsigned_t)NULL); |
@@ -2329,23 +2284,7 @@ void | |||
2329 | xfs_attr_trace_l_cn(char *where, struct xfs_attr_list_context *context, | 2284 | xfs_attr_trace_l_cn(char *where, struct xfs_attr_list_context *context, |
2330 | struct xfs_da_intnode *node) | 2285 | struct xfs_da_intnode *node) |
2331 | { | 2286 | { |
2332 | xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CN, where, | 2287 | xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CN, where, context, |
2333 | (__psunsigned_t)context->dp, | ||
2334 | (__psunsigned_t)context->cursor->hashval, | ||
2335 | (__psunsigned_t)context->cursor->blkno, | ||
2336 | (__psunsigned_t)context->cursor->offset, | ||
2337 | (__psunsigned_t)context->alist, | ||
2338 | (__psunsigned_t)context->bufsize, | ||
2339 | (__psunsigned_t)context->count, | ||
2340 | (__psunsigned_t)context->firstu, | ||
2341 | (__psunsigned_t) | ||
2342 | ((context->count > 0) && | ||
2343 | !(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL))) | ||
2344 | ? (ATTR_ENTRY(context->alist, | ||
2345 | context->count-1)->a_valuelen) | ||
2346 | : 0, | ||
2347 | (__psunsigned_t)context->dupcnt, | ||
2348 | (__psunsigned_t)context->flags, | ||
2349 | (__psunsigned_t)be16_to_cpu(node->hdr.count), | 2288 | (__psunsigned_t)be16_to_cpu(node->hdr.count), |
2350 | (__psunsigned_t)be32_to_cpu(node->btree[0].hashval), | 2289 | (__psunsigned_t)be32_to_cpu(node->btree[0].hashval), |
2351 | (__psunsigned_t)be32_to_cpu(node->btree[ | 2290 | (__psunsigned_t)be32_to_cpu(node->btree[ |
@@ -2359,23 +2298,7 @@ void | |||
2359 | xfs_attr_trace_l_cb(char *where, struct xfs_attr_list_context *context, | 2298 | xfs_attr_trace_l_cb(char *where, struct xfs_attr_list_context *context, |
2360 | struct xfs_da_node_entry *btree) | 2299 | struct xfs_da_node_entry *btree) |
2361 | { | 2300 | { |
2362 | xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CB, where, | 2301 | xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CB, where, context, |
2363 | (__psunsigned_t)context->dp, | ||
2364 | (__psunsigned_t)context->cursor->hashval, | ||
2365 | (__psunsigned_t)context->cursor->blkno, | ||
2366 | (__psunsigned_t)context->cursor->offset, | ||
2367 | (__psunsigned_t)context->alist, | ||
2368 | (__psunsigned_t)context->bufsize, | ||
2369 | (__psunsigned_t)context->count, | ||
2370 | (__psunsigned_t)context->firstu, | ||
2371 | (__psunsigned_t) | ||
2372 | ((context->count > 0) && | ||
2373 | !(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL))) | ||
2374 | ? (ATTR_ENTRY(context->alist, | ||
2375 | context->count-1)->a_valuelen) | ||
2376 | : 0, | ||
2377 | (__psunsigned_t)context->dupcnt, | ||
2378 | (__psunsigned_t)context->flags, | ||
2379 | (__psunsigned_t)be32_to_cpu(btree->hashval), | 2302 | (__psunsigned_t)be32_to_cpu(btree->hashval), |
2380 | (__psunsigned_t)be32_to_cpu(btree->before), | 2303 | (__psunsigned_t)be32_to_cpu(btree->before), |
2381 | (__psunsigned_t)NULL); | 2304 | (__psunsigned_t)NULL); |
@@ -2388,23 +2311,7 @@ void | |||
2388 | xfs_attr_trace_l_cl(char *where, struct xfs_attr_list_context *context, | 2311 | xfs_attr_trace_l_cl(char *where, struct xfs_attr_list_context *context, |
2389 | struct xfs_attr_leafblock *leaf) | 2312 | struct xfs_attr_leafblock *leaf) |
2390 | { | 2313 | { |
2391 | xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CL, where, | 2314 | xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CL, where, context, |
2392 | (__psunsigned_t)context->dp, | ||
2393 | (__psunsigned_t)context->cursor->hashval, | ||
2394 | (__psunsigned_t)context->cursor->blkno, | ||
2395 | (__psunsigned_t)context->cursor->offset, | ||
2396 | (__psunsigned_t)context->alist, | ||
2397 | (__psunsigned_t)context->bufsize, | ||
2398 | (__psunsigned_t)context->count, | ||
2399 | (__psunsigned_t)context->firstu, | ||
2400 | (__psunsigned_t) | ||
2401 | ((context->count > 0) && | ||
2402 | !(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL))) | ||
2403 | ? (ATTR_ENTRY(context->alist, | ||
2404 | context->count-1)->a_valuelen) | ||
2405 | : 0, | ||
2406 | (__psunsigned_t)context->dupcnt, | ||
2407 | (__psunsigned_t)context->flags, | ||
2408 | (__psunsigned_t)be16_to_cpu(leaf->hdr.count), | 2315 | (__psunsigned_t)be16_to_cpu(leaf->hdr.count), |
2409 | (__psunsigned_t)be32_to_cpu(leaf->entries[0].hashval), | 2316 | (__psunsigned_t)be32_to_cpu(leaf->entries[0].hashval), |
2410 | (__psunsigned_t)be32_to_cpu(leaf->entries[ | 2317 | (__psunsigned_t)be32_to_cpu(leaf->entries[ |
@@ -2417,329 +2324,24 @@ xfs_attr_trace_l_cl(char *where, struct xfs_attr_list_context *context, | |||
2417 | */ | 2324 | */ |
2418 | void | 2325 | void |
2419 | xfs_attr_trace_enter(int type, char *where, | 2326 | xfs_attr_trace_enter(int type, char *where, |
2420 | __psunsigned_t a2, __psunsigned_t a3, | 2327 | struct xfs_attr_list_context *context, |
2421 | __psunsigned_t a4, __psunsigned_t a5, | 2328 | __psunsigned_t a13, __psunsigned_t a14, |
2422 | __psunsigned_t a6, __psunsigned_t a7, | 2329 | __psunsigned_t a15) |
2423 | __psunsigned_t a8, __psunsigned_t a9, | ||
2424 | __psunsigned_t a10, __psunsigned_t a11, | ||
2425 | __psunsigned_t a12, __psunsigned_t a13, | ||
2426 | __psunsigned_t a14, __psunsigned_t a15) | ||
2427 | { | 2330 | { |
2428 | ASSERT(xfs_attr_trace_buf); | 2331 | ASSERT(xfs_attr_trace_buf); |
2429 | ktrace_enter(xfs_attr_trace_buf, (void *)((__psunsigned_t)type), | 2332 | ktrace_enter(xfs_attr_trace_buf, (void *)((__psunsigned_t)type), |
2430 | (void *)where, | 2333 | (void *)((__psunsigned_t)where), |
2431 | (void *)a2, (void *)a3, (void *)a4, | 2334 | (void *)((__psunsigned_t)context->dp), |
2432 | (void *)a5, (void *)a6, (void *)a7, | 2335 | (void *)((__psunsigned_t)context->cursor->hashval), |
2433 | (void *)a8, (void *)a9, (void *)a10, | 2336 | (void *)((__psunsigned_t)context->cursor->blkno), |
2434 | (void *)a11, (void *)a12, (void *)a13, | 2337 | (void *)((__psunsigned_t)context->cursor->offset), |
2435 | (void *)a14, (void *)a15); | 2338 | (void *)((__psunsigned_t)context->alist), |
2339 | (void *)((__psunsigned_t)context->bufsize), | ||
2340 | (void *)((__psunsigned_t)context->count), | ||
2341 | (void *)((__psunsigned_t)context->firstu), | ||
2342 | NULL, | ||
2343 | (void *)((__psunsigned_t)context->dupcnt), | ||
2344 | (void *)((__psunsigned_t)context->flags), | ||
2345 | (void *)a13, (void *)a14, (void *)a15); | ||
2436 | } | 2346 | } |
2437 | #endif /* XFS_ATTR_TRACE */ | 2347 | #endif /* XFS_ATTR_TRACE */ |
2438 | |||
2439 | |||
2440 | /*======================================================================== | ||
2441 | * System (pseudo) namespace attribute interface routines. | ||
2442 | *========================================================================*/ | ||
2443 | |||
2444 | STATIC int | ||
2445 | posix_acl_access_set( | ||
2446 | bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags) | ||
2447 | { | ||
2448 | return xfs_acl_vset(vp, data, size, _ACL_TYPE_ACCESS); | ||
2449 | } | ||
2450 | |||
2451 | STATIC int | ||
2452 | posix_acl_access_remove( | ||
2453 | bhv_vnode_t *vp, char *name, int xflags) | ||
2454 | { | ||
2455 | return xfs_acl_vremove(vp, _ACL_TYPE_ACCESS); | ||
2456 | } | ||
2457 | |||
2458 | STATIC int | ||
2459 | posix_acl_access_get( | ||
2460 | bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags) | ||
2461 | { | ||
2462 | return xfs_acl_vget(vp, data, size, _ACL_TYPE_ACCESS); | ||
2463 | } | ||
2464 | |||
2465 | STATIC int | ||
2466 | posix_acl_access_exists( | ||
2467 | bhv_vnode_t *vp) | ||
2468 | { | ||
2469 | return xfs_acl_vhasacl_access(vp); | ||
2470 | } | ||
2471 | |||
2472 | STATIC int | ||
2473 | posix_acl_default_set( | ||
2474 | bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags) | ||
2475 | { | ||
2476 | return xfs_acl_vset(vp, data, size, _ACL_TYPE_DEFAULT); | ||
2477 | } | ||
2478 | |||
2479 | STATIC int | ||
2480 | posix_acl_default_get( | ||
2481 | bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags) | ||
2482 | { | ||
2483 | return xfs_acl_vget(vp, data, size, _ACL_TYPE_DEFAULT); | ||
2484 | } | ||
2485 | |||
2486 | STATIC int | ||
2487 | posix_acl_default_remove( | ||
2488 | bhv_vnode_t *vp, char *name, int xflags) | ||
2489 | { | ||
2490 | return xfs_acl_vremove(vp, _ACL_TYPE_DEFAULT); | ||
2491 | } | ||
2492 | |||
2493 | STATIC int | ||
2494 | posix_acl_default_exists( | ||
2495 | bhv_vnode_t *vp) | ||
2496 | { | ||
2497 | return xfs_acl_vhasacl_default(vp); | ||
2498 | } | ||
2499 | |||
2500 | static struct attrnames posix_acl_access = { | ||
2501 | .attr_name = "posix_acl_access", | ||
2502 | .attr_namelen = sizeof("posix_acl_access") - 1, | ||
2503 | .attr_get = posix_acl_access_get, | ||
2504 | .attr_set = posix_acl_access_set, | ||
2505 | .attr_remove = posix_acl_access_remove, | ||
2506 | .attr_exists = posix_acl_access_exists, | ||
2507 | }; | ||
2508 | |||
2509 | static struct attrnames posix_acl_default = { | ||
2510 | .attr_name = "posix_acl_default", | ||
2511 | .attr_namelen = sizeof("posix_acl_default") - 1, | ||
2512 | .attr_get = posix_acl_default_get, | ||
2513 | .attr_set = posix_acl_default_set, | ||
2514 | .attr_remove = posix_acl_default_remove, | ||
2515 | .attr_exists = posix_acl_default_exists, | ||
2516 | }; | ||
2517 | |||
2518 | static struct attrnames *attr_system_names[] = | ||
2519 | { &posix_acl_access, &posix_acl_default }; | ||
2520 | |||
2521 | |||
2522 | /*======================================================================== | ||
2523 | * Namespace-prefix-style attribute name interface routines. | ||
2524 | *========================================================================*/ | ||
2525 | |||
2526 | STATIC int | ||
2527 | attr_generic_set( | ||
2528 | bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags) | ||
2529 | { | ||
2530 | return -xfs_attr_set(xfs_vtoi(vp), name, data, size, xflags); | ||
2531 | } | ||
2532 | |||
2533 | STATIC int | ||
2534 | attr_generic_get( | ||
2535 | bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags) | ||
2536 | { | ||
2537 | int error, asize = size; | ||
2538 | |||
2539 | error = xfs_attr_get(xfs_vtoi(vp), name, data, &asize, xflags); | ||
2540 | if (!error) | ||
2541 | return asize; | ||
2542 | return -error; | ||
2543 | } | ||
2544 | |||
2545 | STATIC int | ||
2546 | attr_generic_remove( | ||
2547 | bhv_vnode_t *vp, char *name, int xflags) | ||
2548 | { | ||
2549 | return -xfs_attr_remove(xfs_vtoi(vp), name, xflags); | ||
2550 | } | ||
2551 | |||
2552 | STATIC int | ||
2553 | attr_generic_listadd( | ||
2554 | attrnames_t *prefix, | ||
2555 | attrnames_t *namesp, | ||
2556 | void *data, | ||
2557 | size_t size, | ||
2558 | ssize_t *result) | ||
2559 | { | ||
2560 | char *p = data + *result; | ||
2561 | |||
2562 | *result += prefix->attr_namelen; | ||
2563 | *result += namesp->attr_namelen + 1; | ||
2564 | if (!size) | ||
2565 | return 0; | ||
2566 | if (*result > size) | ||
2567 | return -ERANGE; | ||
2568 | strcpy(p, prefix->attr_name); | ||
2569 | p += prefix->attr_namelen; | ||
2570 | strcpy(p, namesp->attr_name); | ||
2571 | p += namesp->attr_namelen + 1; | ||
2572 | return 0; | ||
2573 | } | ||
2574 | |||
2575 | STATIC int | ||
2576 | attr_system_list( | ||
2577 | bhv_vnode_t *vp, | ||
2578 | void *data, | ||
2579 | size_t size, | ||
2580 | ssize_t *result) | ||
2581 | { | ||
2582 | attrnames_t *namesp; | ||
2583 | int i, error = 0; | ||
2584 | |||
2585 | for (i = 0; i < ATTR_SYSCOUNT; i++) { | ||
2586 | namesp = attr_system_names[i]; | ||
2587 | if (!namesp->attr_exists || !namesp->attr_exists(vp)) | ||
2588 | continue; | ||
2589 | error = attr_generic_listadd(&attr_system, namesp, | ||
2590 | data, size, result); | ||
2591 | if (error) | ||
2592 | break; | ||
2593 | } | ||
2594 | return error; | ||
2595 | } | ||
2596 | |||
2597 | int | ||
2598 | attr_generic_list( | ||
2599 | bhv_vnode_t *vp, void *data, size_t size, int xflags, ssize_t *result) | ||
2600 | { | ||
2601 | attrlist_cursor_kern_t cursor = { 0 }; | ||
2602 | int error; | ||
2603 | |||
2604 | error = xfs_attr_list(xfs_vtoi(vp), data, size, xflags, &cursor); | ||
2605 | if (error > 0) | ||
2606 | return -error; | ||
2607 | *result = -error; | ||
2608 | return attr_system_list(vp, data, size, result); | ||
2609 | } | ||
2610 | |||
2611 | attrnames_t * | ||
2612 | attr_lookup_namespace( | ||
2613 | char *name, | ||
2614 | struct attrnames **names, | ||
2615 | int nnames) | ||
2616 | { | ||
2617 | int i; | ||
2618 | |||
2619 | for (i = 0; i < nnames; i++) | ||
2620 | if (!strncmp(name, names[i]->attr_name, names[i]->attr_namelen)) | ||
2621 | return names[i]; | ||
2622 | return NULL; | ||
2623 | } | ||
2624 | |||
2625 | /* | ||
2626 | * Some checks to prevent people abusing EAs to get over quota: | ||
2627 | * - Don't allow modifying user EAs on devices/symlinks; | ||
2628 | * - Don't allow modifying user EAs if sticky bit set; | ||
2629 | */ | ||
2630 | STATIC int | ||
2631 | attr_user_capable( | ||
2632 | bhv_vnode_t *vp, | ||
2633 | cred_t *cred) | ||
2634 | { | ||
2635 | struct inode *inode = vn_to_inode(vp); | ||
2636 | |||
2637 | if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) | ||
2638 | return -EPERM; | ||
2639 | if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode) && | ||
2640 | !capable(CAP_SYS_ADMIN)) | ||
2641 | return -EPERM; | ||
2642 | if (S_ISDIR(inode->i_mode) && (inode->i_mode & S_ISVTX) && | ||
2643 | (current_fsuid(cred) != inode->i_uid) && !capable(CAP_FOWNER)) | ||
2644 | return -EPERM; | ||
2645 | return 0; | ||
2646 | } | ||
2647 | |||
2648 | STATIC int | ||
2649 | attr_trusted_capable( | ||
2650 | bhv_vnode_t *vp, | ||
2651 | cred_t *cred) | ||
2652 | { | ||
2653 | struct inode *inode = vn_to_inode(vp); | ||
2654 | |||
2655 | if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) | ||
2656 | return -EPERM; | ||
2657 | if (!capable(CAP_SYS_ADMIN)) | ||
2658 | return -EPERM; | ||
2659 | return 0; | ||
2660 | } | ||
2661 | |||
2662 | STATIC int | ||
2663 | attr_system_set( | ||
2664 | bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags) | ||
2665 | { | ||
2666 | attrnames_t *namesp; | ||
2667 | int error; | ||
2668 | |||
2669 | if (xflags & ATTR_CREATE) | ||
2670 | return -EINVAL; | ||
2671 | |||
2672 | namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT); | ||
2673 | if (!namesp) | ||
2674 | return -EOPNOTSUPP; | ||
2675 | error = namesp->attr_set(vp, name, data, size, xflags); | ||
2676 | if (!error) | ||
2677 | error = vn_revalidate(vp); | ||
2678 | return error; | ||
2679 | } | ||
2680 | |||
2681 | STATIC int | ||
2682 | attr_system_get( | ||
2683 | bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags) | ||
2684 | { | ||
2685 | attrnames_t *namesp; | ||
2686 | |||
2687 | namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT); | ||
2688 | if (!namesp) | ||
2689 | return -EOPNOTSUPP; | ||
2690 | return namesp->attr_get(vp, name, data, size, xflags); | ||
2691 | } | ||
2692 | |||
2693 | STATIC int | ||
2694 | attr_system_remove( | ||
2695 | bhv_vnode_t *vp, char *name, int xflags) | ||
2696 | { | ||
2697 | attrnames_t *namesp; | ||
2698 | |||
2699 | namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT); | ||
2700 | if (!namesp) | ||
2701 | return -EOPNOTSUPP; | ||
2702 | return namesp->attr_remove(vp, name, xflags); | ||
2703 | } | ||
2704 | |||
2705 | struct attrnames attr_system = { | ||
2706 | .attr_name = "system.", | ||
2707 | .attr_namelen = sizeof("system.") - 1, | ||
2708 | .attr_flag = ATTR_SYSTEM, | ||
2709 | .attr_get = attr_system_get, | ||
2710 | .attr_set = attr_system_set, | ||
2711 | .attr_remove = attr_system_remove, | ||
2712 | .attr_capable = (attrcapable_t)fs_noerr, | ||
2713 | }; | ||
2714 | |||
2715 | struct attrnames attr_trusted = { | ||
2716 | .attr_name = "trusted.", | ||
2717 | .attr_namelen = sizeof("trusted.") - 1, | ||
2718 | .attr_flag = ATTR_ROOT, | ||
2719 | .attr_get = attr_generic_get, | ||
2720 | .attr_set = attr_generic_set, | ||
2721 | .attr_remove = attr_generic_remove, | ||
2722 | .attr_capable = attr_trusted_capable, | ||
2723 | }; | ||
2724 | |||
2725 | struct attrnames attr_secure = { | ||
2726 | .attr_name = "security.", | ||
2727 | .attr_namelen = sizeof("security.") - 1, | ||
2728 | .attr_flag = ATTR_SECURE, | ||
2729 | .attr_get = attr_generic_get, | ||
2730 | .attr_set = attr_generic_set, | ||
2731 | .attr_remove = attr_generic_remove, | ||
2732 | .attr_capable = (attrcapable_t)fs_noerr, | ||
2733 | }; | ||
2734 | |||
2735 | struct attrnames attr_user = { | ||
2736 | .attr_name = "user.", | ||
2737 | .attr_namelen = sizeof("user.") - 1, | ||
2738 | .attr_get = attr_generic_get, | ||
2739 | .attr_set = attr_generic_set, | ||
2740 | .attr_remove = attr_generic_remove, | ||
2741 | .attr_capable = attr_user_capable, | ||
2742 | }; | ||
2743 | |||
2744 | struct attrnames *attr_namespaces[] = | ||
2745 | { &attr_system, &attr_trusted, &attr_secure, &attr_user }; | ||