diff options
Diffstat (limited to 'fs/xfs/xfs_attr.c')
-rw-r--r-- | fs/xfs/xfs_attr.c | 608 |
1 files changed, 92 insertions, 516 deletions
diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c index df151a859186..78de80e3caa2 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); |
@@ -241,8 +239,7 @@ xfs_attr_set_int(xfs_inode_t *dp, struct xfs_name *name, | |||
241 | args.firstblock = &firstblock; | 239 | args.firstblock = &firstblock; |
242 | args.flist = &flist; | 240 | args.flist = &flist; |
243 | args.whichfork = XFS_ATTR_FORK; | 241 | args.whichfork = XFS_ATTR_FORK; |
244 | args.addname = 1; | 242 | args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT; |
245 | args.oknoent = 1; | ||
246 | 243 | ||
247 | /* | 244 | /* |
248 | * Determine space new attribute will use, and if it would be | 245 | * Determine space new attribute will use, and if it would be |
@@ -529,9 +526,7 @@ xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags) | |||
529 | /* | 526 | /* |
530 | * Decide on what work routines to call based on the inode size. | 527 | * Decide on what work routines to call based on the inode size. |
531 | */ | 528 | */ |
532 | if (XFS_IFORK_Q(dp) == 0 || | 529 | 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); | 530 | error = XFS_ERROR(ENOATTR); |
536 | goto out; | 531 | goto out; |
537 | } | 532 | } |
@@ -601,29 +596,33 @@ xfs_attr_remove( | |||
601 | return error; | 596 | return error; |
602 | 597 | ||
603 | xfs_ilock(dp, XFS_ILOCK_SHARED); | 598 | xfs_ilock(dp, XFS_ILOCK_SHARED); |
604 | if (XFS_IFORK_Q(dp) == 0 || | 599 | 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); | 600 | xfs_iunlock(dp, XFS_ILOCK_SHARED); |
608 | return(XFS_ERROR(ENOATTR)); | 601 | return XFS_ERROR(ENOATTR); |
609 | } | 602 | } |
610 | xfs_iunlock(dp, XFS_ILOCK_SHARED); | 603 | xfs_iunlock(dp, XFS_ILOCK_SHARED); |
611 | 604 | ||
612 | return xfs_attr_remove_int(dp, &xname, flags); | 605 | return xfs_attr_remove_int(dp, &xname, flags); |
613 | } | 606 | } |
614 | 607 | ||
615 | STATIC int | 608 | int |
616 | xfs_attr_list_int(xfs_attr_list_context_t *context) | 609 | xfs_attr_list_int(xfs_attr_list_context_t *context) |
617 | { | 610 | { |
618 | int error; | 611 | int error; |
619 | xfs_inode_t *dp = context->dp; | 612 | xfs_inode_t *dp = context->dp; |
620 | 613 | ||
614 | XFS_STATS_INC(xs_attr_list); | ||
615 | |||
616 | if (XFS_FORCED_SHUTDOWN(dp->i_mount)) | ||
617 | return EIO; | ||
618 | |||
619 | xfs_ilock(dp, XFS_ILOCK_SHARED); | ||
620 | xfs_attr_trace_l_c("syscall start", context); | ||
621 | |||
621 | /* | 622 | /* |
622 | * Decide on what work routines to call based on the inode size. | 623 | * Decide on what work routines to call based on the inode size. |
623 | */ | 624 | */ |
624 | if (XFS_IFORK_Q(dp) == 0 || | 625 | 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; | 626 | error = 0; |
628 | } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { | 627 | } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { |
629 | error = xfs_attr_shortform_list(context); | 628 | error = xfs_attr_shortform_list(context); |
@@ -632,6 +631,10 @@ xfs_attr_list_int(xfs_attr_list_context_t *context) | |||
632 | } else { | 631 | } else { |
633 | error = xfs_attr_node_list(context); | 632 | error = xfs_attr_node_list(context); |
634 | } | 633 | } |
634 | |||
635 | xfs_iunlock(dp, XFS_ILOCK_SHARED); | ||
636 | xfs_attr_trace_l_c("syscall end", context); | ||
637 | |||
635 | return error; | 638 | return error; |
636 | } | 639 | } |
637 | 640 | ||
@@ -648,74 +651,50 @@ xfs_attr_list_int(xfs_attr_list_context_t *context) | |||
648 | */ | 651 | */ |
649 | /*ARGSUSED*/ | 652 | /*ARGSUSED*/ |
650 | STATIC int | 653 | STATIC int |
651 | xfs_attr_put_listent(xfs_attr_list_context_t *context, attrnames_t *namesp, | 654 | xfs_attr_put_listent(xfs_attr_list_context_t *context, int flags, |
652 | char *name, int namelen, | 655 | char *name, int namelen, |
653 | int valuelen, char *value) | 656 | int valuelen, char *value) |
654 | { | 657 | { |
658 | struct attrlist *alist = (struct attrlist *)context->alist; | ||
655 | attrlist_ent_t *aep; | 659 | attrlist_ent_t *aep; |
656 | int arraytop; | 660 | int arraytop; |
657 | 661 | ||
658 | ASSERT(!(context->flags & ATTR_KERNOVAL)); | 662 | ASSERT(!(context->flags & ATTR_KERNOVAL)); |
659 | ASSERT(context->count >= 0); | 663 | ASSERT(context->count >= 0); |
660 | ASSERT(context->count < (ATTR_MAX_VALUELEN/8)); | 664 | ASSERT(context->count < (ATTR_MAX_VALUELEN/8)); |
661 | ASSERT(context->firstu >= sizeof(*context->alist)); | 665 | ASSERT(context->firstu >= sizeof(*alist)); |
662 | ASSERT(context->firstu <= context->bufsize); | 666 | ASSERT(context->firstu <= context->bufsize); |
663 | 667 | ||
664 | arraytop = sizeof(*context->alist) + | 668 | /* |
665 | context->count * sizeof(context->alist->al_offset[0]); | 669 | * Only list entries in the right namespace. |
670 | */ | ||
671 | if (((context->flags & ATTR_SECURE) == 0) != | ||
672 | ((flags & XFS_ATTR_SECURE) == 0)) | ||
673 | return 0; | ||
674 | if (((context->flags & ATTR_ROOT) == 0) != | ||
675 | ((flags & XFS_ATTR_ROOT) == 0)) | ||
676 | return 0; | ||
677 | |||
678 | arraytop = sizeof(*alist) + | ||
679 | context->count * sizeof(alist->al_offset[0]); | ||
666 | context->firstu -= ATTR_ENTSIZE(namelen); | 680 | context->firstu -= ATTR_ENTSIZE(namelen); |
667 | if (context->firstu < arraytop) { | 681 | if (context->firstu < arraytop) { |
668 | xfs_attr_trace_l_c("buffer full", context); | 682 | xfs_attr_trace_l_c("buffer full", context); |
669 | context->alist->al_more = 1; | 683 | alist->al_more = 1; |
670 | context->seen_enough = 1; | 684 | context->seen_enough = 1; |
671 | return 1; | 685 | return 1; |
672 | } | 686 | } |
673 | 687 | ||
674 | aep = (attrlist_ent_t *)&(((char *)context->alist)[ context->firstu ]); | 688 | aep = (attrlist_ent_t *)&context->alist[context->firstu]; |
675 | aep->a_valuelen = valuelen; | 689 | aep->a_valuelen = valuelen; |
676 | memcpy(aep->a_name, name, namelen); | 690 | memcpy(aep->a_name, name, namelen); |
677 | aep->a_name[ namelen ] = 0; | 691 | aep->a_name[namelen] = 0; |
678 | context->alist->al_offset[ context->count++ ] = context->firstu; | 692 | alist->al_offset[context->count++] = context->firstu; |
679 | context->alist->al_count = context->count; | 693 | alist->al_count = context->count; |
680 | xfs_attr_trace_l_c("add", context); | 694 | xfs_attr_trace_l_c("add", context); |
681 | return 0; | 695 | return 0; |
682 | } | 696 | } |
683 | 697 | ||
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 | /* | 698 | /* |
720 | * Generate a list of extended attribute names and optionally | 699 | * Generate a list of extended attribute names and optionally |
721 | * also value lengths. Positive return value follows the XFS | 700 | * also value lengths. Positive return value follows the XFS |
@@ -732,10 +711,9 @@ xfs_attr_list( | |||
732 | attrlist_cursor_kern_t *cursor) | 711 | attrlist_cursor_kern_t *cursor) |
733 | { | 712 | { |
734 | xfs_attr_list_context_t context; | 713 | xfs_attr_list_context_t context; |
714 | struct attrlist *alist; | ||
735 | int error; | 715 | int error; |
736 | 716 | ||
737 | XFS_STATS_INC(xs_attr_list); | ||
738 | |||
739 | /* | 717 | /* |
740 | * Validate the cursor. | 718 | * Validate the cursor. |
741 | */ | 719 | */ |
@@ -756,52 +734,23 @@ xfs_attr_list( | |||
756 | /* | 734 | /* |
757 | * Initialize the output buffer. | 735 | * Initialize the output buffer. |
758 | */ | 736 | */ |
737 | memset(&context, 0, sizeof(context)); | ||
759 | context.dp = dp; | 738 | context.dp = dp; |
760 | context.cursor = cursor; | 739 | context.cursor = cursor; |
761 | context.count = 0; | ||
762 | context.dupcnt = 0; | ||
763 | context.resynch = 1; | 740 | context.resynch = 1; |
764 | context.flags = flags; | 741 | context.flags = flags; |
765 | context.seen_enough = 0; | 742 | context.alist = buffer; |
766 | context.alist = (attrlist_t *)buffer; | 743 | context.bufsize = (bufsize & ~(sizeof(int)-1)); /* align */ |
767 | context.put_value = 0; | 744 | context.firstu = context.bufsize; |
768 | 745 | 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 | 746 | ||
785 | if (XFS_FORCED_SHUTDOWN(dp->i_mount)) | 747 | alist = (struct attrlist *)context.alist; |
786 | return EIO; | 748 | alist->al_count = 0; |
787 | 749 | alist->al_more = 0; | |
788 | xfs_ilock(dp, XFS_ILOCK_SHARED); | 750 | alist->al_offset[0] = context.bufsize; |
789 | xfs_attr_trace_l_c("syscall start", &context); | ||
790 | 751 | ||
791 | error = xfs_attr_list_int(&context); | 752 | error = xfs_attr_list_int(&context); |
792 | 753 | 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; | 754 | return error; |
806 | } | 755 | } |
807 | 756 | ||
@@ -816,12 +765,10 @@ xfs_attr_inactive(xfs_inode_t *dp) | |||
816 | ASSERT(! XFS_NOT_DQATTACHED(mp, dp)); | 765 | ASSERT(! XFS_NOT_DQATTACHED(mp, dp)); |
817 | 766 | ||
818 | xfs_ilock(dp, XFS_ILOCK_SHARED); | 767 | xfs_ilock(dp, XFS_ILOCK_SHARED); |
819 | if ((XFS_IFORK_Q(dp) == 0) || | 768 | if (!xfs_inode_hasattr(dp) || |
820 | (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) || | 769 | 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); | 770 | xfs_iunlock(dp, XFS_ILOCK_SHARED); |
824 | return(0); | 771 | return 0; |
825 | } | 772 | } |
826 | xfs_iunlock(dp, XFS_ILOCK_SHARED); | 773 | xfs_iunlock(dp, XFS_ILOCK_SHARED); |
827 | 774 | ||
@@ -854,10 +801,8 @@ xfs_attr_inactive(xfs_inode_t *dp) | |||
854 | /* | 801 | /* |
855 | * Decide on what work routines to call based on the inode size. | 802 | * Decide on what work routines to call based on the inode size. |
856 | */ | 803 | */ |
857 | if ((XFS_IFORK_Q(dp) == 0) || | 804 | if (!xfs_inode_hasattr(dp) || |
858 | (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) || | 805 | 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; | 806 | error = 0; |
862 | goto out; | 807 | goto out; |
863 | } | 808 | } |
@@ -974,7 +919,7 @@ xfs_attr_leaf_addname(xfs_da_args_t *args) | |||
974 | xfs_da_brelse(args->trans, bp); | 919 | xfs_da_brelse(args->trans, bp); |
975 | return(retval); | 920 | return(retval); |
976 | } | 921 | } |
977 | args->rename = 1; /* an atomic rename */ | 922 | args->op_flags |= XFS_DA_OP_RENAME; /* an atomic rename */ |
978 | args->blkno2 = args->blkno; /* set 2nd entry info*/ | 923 | args->blkno2 = args->blkno; /* set 2nd entry info*/ |
979 | args->index2 = args->index; | 924 | args->index2 = args->index; |
980 | args->rmtblkno2 = args->rmtblkno; | 925 | args->rmtblkno2 = args->rmtblkno; |
@@ -1054,7 +999,7 @@ xfs_attr_leaf_addname(xfs_da_args_t *args) | |||
1054 | * so that one disappears and one appears atomically. Then we | 999 | * so that one disappears and one appears atomically. Then we |
1055 | * must remove the "old" attribute/value pair. | 1000 | * must remove the "old" attribute/value pair. |
1056 | */ | 1001 | */ |
1057 | if (args->rename) { | 1002 | if (args->op_flags & XFS_DA_OP_RENAME) { |
1058 | /* | 1003 | /* |
1059 | * In a separate transaction, set the incomplete flag on the | 1004 | * In a separate transaction, set the incomplete flag on the |
1060 | * "old" attr and clear the incomplete flag on the "new" attr. | 1005 | * "old" attr and clear the incomplete flag on the "new" attr. |
@@ -1307,7 +1252,7 @@ restart: | |||
1307 | } else if (retval == EEXIST) { | 1252 | } else if (retval == EEXIST) { |
1308 | if (args->flags & ATTR_CREATE) | 1253 | if (args->flags & ATTR_CREATE) |
1309 | goto out; | 1254 | goto out; |
1310 | args->rename = 1; /* atomic rename op */ | 1255 | args->op_flags |= XFS_DA_OP_RENAME; /* atomic rename op */ |
1311 | args->blkno2 = args->blkno; /* set 2nd entry info*/ | 1256 | args->blkno2 = args->blkno; /* set 2nd entry info*/ |
1312 | args->index2 = args->index; | 1257 | args->index2 = args->index; |
1313 | args->rmtblkno2 = args->rmtblkno; | 1258 | args->rmtblkno2 = args->rmtblkno; |
@@ -1425,7 +1370,7 @@ restart: | |||
1425 | * so that one disappears and one appears atomically. Then we | 1370 | * so that one disappears and one appears atomically. Then we |
1426 | * must remove the "old" attribute/value pair. | 1371 | * must remove the "old" attribute/value pair. |
1427 | */ | 1372 | */ |
1428 | if (args->rename) { | 1373 | if (args->op_flags & XFS_DA_OP_RENAME) { |
1429 | /* | 1374 | /* |
1430 | * In a separate transaction, set the incomplete flag on the | 1375 | * In a separate transaction, set the incomplete flag on the |
1431 | * "old" attr and clear the incomplete flag on the "new" attr. | 1376 | * "old" attr and clear the incomplete flag on the "new" attr. |
@@ -2300,23 +2245,7 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args) | |||
2300 | void | 2245 | void |
2301 | xfs_attr_trace_l_c(char *where, struct xfs_attr_list_context *context) | 2246 | xfs_attr_trace_l_c(char *where, struct xfs_attr_list_context *context) |
2302 | { | 2247 | { |
2303 | xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_C, where, | 2248 | 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, | 2249 | (__psunsigned_t)NULL, |
2321 | (__psunsigned_t)NULL, | 2250 | (__psunsigned_t)NULL, |
2322 | (__psunsigned_t)NULL); | 2251 | (__psunsigned_t)NULL); |
@@ -2329,23 +2258,7 @@ void | |||
2329 | xfs_attr_trace_l_cn(char *where, struct xfs_attr_list_context *context, | 2258 | xfs_attr_trace_l_cn(char *where, struct xfs_attr_list_context *context, |
2330 | struct xfs_da_intnode *node) | 2259 | struct xfs_da_intnode *node) |
2331 | { | 2260 | { |
2332 | xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CN, where, | 2261 | 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), | 2262 | (__psunsigned_t)be16_to_cpu(node->hdr.count), |
2350 | (__psunsigned_t)be32_to_cpu(node->btree[0].hashval), | 2263 | (__psunsigned_t)be32_to_cpu(node->btree[0].hashval), |
2351 | (__psunsigned_t)be32_to_cpu(node->btree[ | 2264 | (__psunsigned_t)be32_to_cpu(node->btree[ |
@@ -2359,23 +2272,7 @@ void | |||
2359 | xfs_attr_trace_l_cb(char *where, struct xfs_attr_list_context *context, | 2272 | xfs_attr_trace_l_cb(char *where, struct xfs_attr_list_context *context, |
2360 | struct xfs_da_node_entry *btree) | 2273 | struct xfs_da_node_entry *btree) |
2361 | { | 2274 | { |
2362 | xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CB, where, | 2275 | 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), | 2276 | (__psunsigned_t)be32_to_cpu(btree->hashval), |
2380 | (__psunsigned_t)be32_to_cpu(btree->before), | 2277 | (__psunsigned_t)be32_to_cpu(btree->before), |
2381 | (__psunsigned_t)NULL); | 2278 | (__psunsigned_t)NULL); |
@@ -2388,23 +2285,7 @@ void | |||
2388 | xfs_attr_trace_l_cl(char *where, struct xfs_attr_list_context *context, | 2285 | xfs_attr_trace_l_cl(char *where, struct xfs_attr_list_context *context, |
2389 | struct xfs_attr_leafblock *leaf) | 2286 | struct xfs_attr_leafblock *leaf) |
2390 | { | 2287 | { |
2391 | xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CL, where, | 2288 | 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), | 2289 | (__psunsigned_t)be16_to_cpu(leaf->hdr.count), |
2409 | (__psunsigned_t)be32_to_cpu(leaf->entries[0].hashval), | 2290 | (__psunsigned_t)be32_to_cpu(leaf->entries[0].hashval), |
2410 | (__psunsigned_t)be32_to_cpu(leaf->entries[ | 2291 | (__psunsigned_t)be32_to_cpu(leaf->entries[ |
@@ -2417,329 +2298,24 @@ xfs_attr_trace_l_cl(char *where, struct xfs_attr_list_context *context, | |||
2417 | */ | 2298 | */ |
2418 | void | 2299 | void |
2419 | xfs_attr_trace_enter(int type, char *where, | 2300 | xfs_attr_trace_enter(int type, char *where, |
2420 | __psunsigned_t a2, __psunsigned_t a3, | 2301 | struct xfs_attr_list_context *context, |
2421 | __psunsigned_t a4, __psunsigned_t a5, | 2302 | __psunsigned_t a13, __psunsigned_t a14, |
2422 | __psunsigned_t a6, __psunsigned_t a7, | 2303 | __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 | { | 2304 | { |
2428 | ASSERT(xfs_attr_trace_buf); | 2305 | ASSERT(xfs_attr_trace_buf); |
2429 | ktrace_enter(xfs_attr_trace_buf, (void *)((__psunsigned_t)type), | 2306 | ktrace_enter(xfs_attr_trace_buf, (void *)((__psunsigned_t)type), |
2430 | (void *)where, | 2307 | (void *)((__psunsigned_t)where), |
2431 | (void *)a2, (void *)a3, (void *)a4, | 2308 | (void *)((__psunsigned_t)context->dp), |
2432 | (void *)a5, (void *)a6, (void *)a7, | 2309 | (void *)((__psunsigned_t)context->cursor->hashval), |
2433 | (void *)a8, (void *)a9, (void *)a10, | 2310 | (void *)((__psunsigned_t)context->cursor->blkno), |
2434 | (void *)a11, (void *)a12, (void *)a13, | 2311 | (void *)((__psunsigned_t)context->cursor->offset), |
2435 | (void *)a14, (void *)a15); | 2312 | (void *)((__psunsigned_t)context->alist), |
2313 | (void *)((__psunsigned_t)context->bufsize), | ||
2314 | (void *)((__psunsigned_t)context->count), | ||
2315 | (void *)((__psunsigned_t)context->firstu), | ||
2316 | NULL, | ||
2317 | (void *)((__psunsigned_t)context->dupcnt), | ||
2318 | (void *)((__psunsigned_t)context->flags), | ||
2319 | (void *)a13, (void *)a14, (void *)a15); | ||
2436 | } | 2320 | } |
2437 | #endif /* XFS_ATTR_TRACE */ | 2321 | #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 }; | ||