diff options
Diffstat (limited to 'fs/xfs/xfs_attr.c')
-rw-r--r-- | fs/xfs/xfs_attr.c | 181 |
1 files changed, 141 insertions, 40 deletions
diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c index 1a2101043275..9ada7bdbae52 100644 --- a/fs/xfs/xfs_attr.c +++ b/fs/xfs/xfs_attr.c | |||
@@ -91,7 +91,6 @@ STATIC int xfs_attr_refillstate(xfs_da_state_t *state); | |||
91 | /* | 91 | /* |
92 | * Routines to manipulate out-of-line attribute values. | 92 | * Routines to manipulate out-of-line attribute values. |
93 | */ | 93 | */ |
94 | STATIC int xfs_attr_rmtval_get(xfs_da_args_t *args); | ||
95 | STATIC int xfs_attr_rmtval_set(xfs_da_args_t *args); | 94 | STATIC int xfs_attr_rmtval_set(xfs_da_args_t *args); |
96 | STATIC int xfs_attr_rmtval_remove(xfs_da_args_t *args); | 95 | STATIC int xfs_attr_rmtval_remove(xfs_da_args_t *args); |
97 | 96 | ||
@@ -180,7 +179,7 @@ xfs_attr_get(bhv_desc_t *bdp, const char *name, char *value, int *valuelenp, | |||
180 | return(error); | 179 | return(error); |
181 | } | 180 | } |
182 | 181 | ||
183 | STATIC int | 182 | int |
184 | xfs_attr_set_int(xfs_inode_t *dp, const char *name, int namelen, | 183 | xfs_attr_set_int(xfs_inode_t *dp, const char *name, int namelen, |
185 | char *value, int valuelen, int flags) | 184 | char *value, int valuelen, int flags) |
186 | { | 185 | { |
@@ -440,7 +439,7 @@ xfs_attr_set(bhv_desc_t *bdp, const char *name, char *value, int valuelen, int f | |||
440 | * Generic handler routine to remove a name from an attribute list. | 439 | * Generic handler routine to remove a name from an attribute list. |
441 | * Transitions attribute list from Btree to shortform as necessary. | 440 | * Transitions attribute list from Btree to shortform as necessary. |
442 | */ | 441 | */ |
443 | STATIC int | 442 | int |
444 | xfs_attr_remove_int(xfs_inode_t *dp, const char *name, int namelen, int flags) | 443 | xfs_attr_remove_int(xfs_inode_t *dp, const char *name, int namelen, int flags) |
445 | { | 444 | { |
446 | xfs_da_args_t args; | 445 | xfs_da_args_t args; |
@@ -591,6 +590,110 @@ xfs_attr_remove(bhv_desc_t *bdp, const char *name, int flags, struct cred *cred) | |||
591 | return xfs_attr_remove_int(dp, name, namelen, flags); | 590 | return xfs_attr_remove_int(dp, name, namelen, flags); |
592 | } | 591 | } |
593 | 592 | ||
593 | int /* error */ | ||
594 | xfs_attr_list_int(xfs_attr_list_context_t *context) | ||
595 | { | ||
596 | int error; | ||
597 | xfs_inode_t *dp = context->dp; | ||
598 | |||
599 | /* | ||
600 | * Decide on what work routines to call based on the inode size. | ||
601 | */ | ||
602 | if (XFS_IFORK_Q(dp) == 0 || | ||
603 | (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && | ||
604 | dp->i_d.di_anextents == 0)) { | ||
605 | error = 0; | ||
606 | } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { | ||
607 | error = xfs_attr_shortform_list(context); | ||
608 | } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { | ||
609 | error = xfs_attr_leaf_list(context); | ||
610 | } else { | ||
611 | error = xfs_attr_node_list(context); | ||
612 | } | ||
613 | return error; | ||
614 | } | ||
615 | |||
616 | #define ATTR_ENTBASESIZE /* minimum bytes used by an attr */ \ | ||
617 | (((struct attrlist_ent *) 0)->a_name - (char *) 0) | ||
618 | #define ATTR_ENTSIZE(namelen) /* actual bytes used by an attr */ \ | ||
619 | ((ATTR_ENTBASESIZE + (namelen) + 1 + sizeof(u_int32_t)-1) \ | ||
620 | & ~(sizeof(u_int32_t)-1)) | ||
621 | |||
622 | /* | ||
623 | * Format an attribute and copy it out to the user's buffer. | ||
624 | * Take care to check values and protect against them changing later, | ||
625 | * we may be reading them directly out of a user buffer. | ||
626 | */ | ||
627 | /*ARGSUSED*/ | ||
628 | STATIC int | ||
629 | xfs_attr_put_listent(xfs_attr_list_context_t *context, attrnames_t *namesp, | ||
630 | char *name, int namelen, | ||
631 | int valuelen, char *value) | ||
632 | { | ||
633 | attrlist_ent_t *aep; | ||
634 | int arraytop; | ||
635 | |||
636 | ASSERT(!(context->flags & ATTR_KERNOVAL)); | ||
637 | ASSERT(context->count >= 0); | ||
638 | ASSERT(context->count < (ATTR_MAX_VALUELEN/8)); | ||
639 | ASSERT(context->firstu >= sizeof(*context->alist)); | ||
640 | ASSERT(context->firstu <= context->bufsize); | ||
641 | |||
642 | arraytop = sizeof(*context->alist) + | ||
643 | context->count * sizeof(context->alist->al_offset[0]); | ||
644 | context->firstu -= ATTR_ENTSIZE(namelen); | ||
645 | if (context->firstu < arraytop) { | ||
646 | xfs_attr_trace_l_c("buffer full", context); | ||
647 | context->alist->al_more = 1; | ||
648 | context->seen_enough = 1; | ||
649 | return 1; | ||
650 | } | ||
651 | |||
652 | aep = (attrlist_ent_t *)&(((char *)context->alist)[ context->firstu ]); | ||
653 | aep->a_valuelen = valuelen; | ||
654 | memcpy(aep->a_name, name, namelen); | ||
655 | aep->a_name[ namelen ] = 0; | ||
656 | context->alist->al_offset[ context->count++ ] = context->firstu; | ||
657 | context->alist->al_count = context->count; | ||
658 | xfs_attr_trace_l_c("add", context); | ||
659 | return 0; | ||
660 | } | ||
661 | |||
662 | STATIC int | ||
663 | xfs_attr_kern_list(xfs_attr_list_context_t *context, attrnames_t *namesp, | ||
664 | char *name, int namelen, | ||
665 | int valuelen, char *value) | ||
666 | { | ||
667 | char *offset; | ||
668 | int arraytop; | ||
669 | |||
670 | ASSERT(context->count >= 0); | ||
671 | |||
672 | arraytop = context->count + namesp->attr_namelen + namelen + 1; | ||
673 | if (arraytop > context->firstu) { | ||
674 | context->count = -1; /* insufficient space */ | ||
675 | return 1; | ||
676 | } | ||
677 | offset = (char *)context->alist + context->count; | ||
678 | strncpy(offset, namesp->attr_name, namesp->attr_namelen); | ||
679 | offset += namesp->attr_namelen; | ||
680 | strncpy(offset, name, namelen); /* real name */ | ||
681 | offset += namelen; | ||
682 | *offset = '\0'; | ||
683 | context->count += namesp->attr_namelen + namelen + 1; | ||
684 | return 0; | ||
685 | } | ||
686 | |||
687 | /*ARGSUSED*/ | ||
688 | STATIC int | ||
689 | xfs_attr_kern_list_sizes(xfs_attr_list_context_t *context, attrnames_t *namesp, | ||
690 | char *name, int namelen, | ||
691 | int valuelen, char *value) | ||
692 | { | ||
693 | context->count += namesp->attr_namelen + namelen + 1; | ||
694 | return 0; | ||
695 | } | ||
696 | |||
594 | /* | 697 | /* |
595 | * Generate a list of extended attribute names and optionally | 698 | * Generate a list of extended attribute names and optionally |
596 | * also value lengths. Positive return value follows the XFS | 699 | * also value lengths. Positive return value follows the XFS |
@@ -615,13 +718,13 @@ xfs_attr_list(bhv_desc_t *bdp, char *buffer, int bufsize, int flags, | |||
615 | return(XFS_ERROR(EINVAL)); | 718 | return(XFS_ERROR(EINVAL)); |
616 | if ((cursor->initted == 0) && | 719 | if ((cursor->initted == 0) && |
617 | (cursor->hashval || cursor->blkno || cursor->offset)) | 720 | (cursor->hashval || cursor->blkno || cursor->offset)) |
618 | return(XFS_ERROR(EINVAL)); | 721 | return XFS_ERROR(EINVAL); |
619 | 722 | ||
620 | /* | 723 | /* |
621 | * Check for a properly aligned buffer. | 724 | * Check for a properly aligned buffer. |
622 | */ | 725 | */ |
623 | if (((long)buffer) & (sizeof(int)-1)) | 726 | if (((long)buffer) & (sizeof(int)-1)) |
624 | return(XFS_ERROR(EFAULT)); | 727 | return XFS_ERROR(EFAULT); |
625 | if (flags & ATTR_KERNOVAL) | 728 | if (flags & ATTR_KERNOVAL) |
626 | bufsize = 0; | 729 | bufsize = 0; |
627 | 730 | ||
@@ -634,53 +737,47 @@ xfs_attr_list(bhv_desc_t *bdp, char *buffer, int bufsize, int flags, | |||
634 | context.dupcnt = 0; | 737 | context.dupcnt = 0; |
635 | context.resynch = 1; | 738 | context.resynch = 1; |
636 | context.flags = flags; | 739 | context.flags = flags; |
637 | if (!(flags & ATTR_KERNAMELS)) { | 740 | context.seen_enough = 0; |
741 | context.alist = (attrlist_t *)buffer; | ||
742 | context.put_value = 0; | ||
743 | |||
744 | if (flags & ATTR_KERNAMELS) { | ||
745 | context.bufsize = bufsize; | ||
746 | context.firstu = context.bufsize; | ||
747 | if (flags & ATTR_KERNOVAL) | ||
748 | context.put_listent = xfs_attr_kern_list_sizes; | ||
749 | else | ||
750 | context.put_listent = xfs_attr_kern_list; | ||
751 | } else { | ||
638 | context.bufsize = (bufsize & ~(sizeof(int)-1)); /* align */ | 752 | context.bufsize = (bufsize & ~(sizeof(int)-1)); /* align */ |
639 | context.firstu = context.bufsize; | 753 | context.firstu = context.bufsize; |
640 | context.alist = (attrlist_t *)buffer; | ||
641 | context.alist->al_count = 0; | 754 | context.alist->al_count = 0; |
642 | context.alist->al_more = 0; | 755 | context.alist->al_more = 0; |
643 | context.alist->al_offset[0] = context.bufsize; | 756 | context.alist->al_offset[0] = context.bufsize; |
644 | } | 757 | context.put_listent = xfs_attr_put_listent; |
645 | else { | ||
646 | context.bufsize = bufsize; | ||
647 | context.firstu = context.bufsize; | ||
648 | context.alist = (attrlist_t *)buffer; | ||
649 | } | 758 | } |
650 | 759 | ||
651 | if (XFS_FORCED_SHUTDOWN(dp->i_mount)) | 760 | if (XFS_FORCED_SHUTDOWN(dp->i_mount)) |
652 | return (EIO); | 761 | return EIO; |
653 | 762 | ||
654 | xfs_ilock(dp, XFS_ILOCK_SHARED); | 763 | xfs_ilock(dp, XFS_ILOCK_SHARED); |
655 | /* | ||
656 | * Decide on what work routines to call based on the inode size. | ||
657 | */ | ||
658 | xfs_attr_trace_l_c("syscall start", &context); | 764 | xfs_attr_trace_l_c("syscall start", &context); |
659 | if (XFS_IFORK_Q(dp) == 0 || | 765 | |
660 | (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && | 766 | error = xfs_attr_list_int(&context); |
661 | dp->i_d.di_anextents == 0)) { | 767 | |
662 | error = 0; | ||
663 | } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { | ||
664 | error = xfs_attr_shortform_list(&context); | ||
665 | } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { | ||
666 | error = xfs_attr_leaf_list(&context); | ||
667 | } else { | ||
668 | error = xfs_attr_node_list(&context); | ||
669 | } | ||
670 | xfs_iunlock(dp, XFS_ILOCK_SHARED); | 768 | xfs_iunlock(dp, XFS_ILOCK_SHARED); |
671 | xfs_attr_trace_l_c("syscall end", &context); | 769 | xfs_attr_trace_l_c("syscall end", &context); |
672 | 770 | ||
673 | if (!(context.flags & (ATTR_KERNOVAL|ATTR_KERNAMELS))) { | 771 | if (context.flags & (ATTR_KERNOVAL|ATTR_KERNAMELS)) { |
674 | ASSERT(error >= 0); | 772 | /* must return negated buffer size or the error */ |
675 | } | ||
676 | else { /* must return negated buffer size or the error */ | ||
677 | if (context.count < 0) | 773 | if (context.count < 0) |
678 | error = XFS_ERROR(ERANGE); | 774 | error = XFS_ERROR(ERANGE); |
679 | else | 775 | else |
680 | error = -context.count; | 776 | error = -context.count; |
681 | } | 777 | } else |
778 | ASSERT(error >= 0); | ||
682 | 779 | ||
683 | return(error); | 780 | return error; |
684 | } | 781 | } |
685 | 782 | ||
686 | int /* error */ | 783 | int /* error */ |
@@ -1122,19 +1219,19 @@ xfs_attr_leaf_list(xfs_attr_list_context_t *context) | |||
1122 | context->cursor->blkno = 0; | 1219 | context->cursor->blkno = 0; |
1123 | error = xfs_da_read_buf(NULL, context->dp, 0, -1, &bp, XFS_ATTR_FORK); | 1220 | error = xfs_da_read_buf(NULL, context->dp, 0, -1, &bp, XFS_ATTR_FORK); |
1124 | if (error) | 1221 | if (error) |
1125 | return(error); | 1222 | return XFS_ERROR(error); |
1126 | ASSERT(bp != NULL); | 1223 | ASSERT(bp != NULL); |
1127 | leaf = bp->data; | 1224 | leaf = bp->data; |
1128 | if (unlikely(be16_to_cpu(leaf->hdr.info.magic) != XFS_ATTR_LEAF_MAGIC)) { | 1225 | if (unlikely(be16_to_cpu(leaf->hdr.info.magic) != XFS_ATTR_LEAF_MAGIC)) { |
1129 | XFS_CORRUPTION_ERROR("xfs_attr_leaf_list", XFS_ERRLEVEL_LOW, | 1226 | XFS_CORRUPTION_ERROR("xfs_attr_leaf_list", XFS_ERRLEVEL_LOW, |
1130 | context->dp->i_mount, leaf); | 1227 | context->dp->i_mount, leaf); |
1131 | xfs_da_brelse(NULL, bp); | 1228 | xfs_da_brelse(NULL, bp); |
1132 | return(XFS_ERROR(EFSCORRUPTED)); | 1229 | return XFS_ERROR(EFSCORRUPTED); |
1133 | } | 1230 | } |
1134 | 1231 | ||
1135 | (void)xfs_attr_leaf_list_int(bp, context); | 1232 | error = xfs_attr_leaf_list_int(bp, context); |
1136 | xfs_da_brelse(NULL, bp); | 1233 | xfs_da_brelse(NULL, bp); |
1137 | return(0); | 1234 | return XFS_ERROR(error); |
1138 | } | 1235 | } |
1139 | 1236 | ||
1140 | 1237 | ||
@@ -1858,8 +1955,12 @@ xfs_attr_node_list(xfs_attr_list_context_t *context) | |||
1858 | return(XFS_ERROR(EFSCORRUPTED)); | 1955 | return(XFS_ERROR(EFSCORRUPTED)); |
1859 | } | 1956 | } |
1860 | error = xfs_attr_leaf_list_int(bp, context); | 1957 | error = xfs_attr_leaf_list_int(bp, context); |
1861 | if (error || !leaf->hdr.info.forw) | 1958 | if (error) { |
1862 | break; /* not really an error, buffer full or EOF */ | 1959 | xfs_da_brelse(NULL, bp); |
1960 | return error; | ||
1961 | } | ||
1962 | if (context->seen_enough || leaf->hdr.info.forw == 0) | ||
1963 | break; | ||
1863 | cursor->blkno = be32_to_cpu(leaf->hdr.info.forw); | 1964 | cursor->blkno = be32_to_cpu(leaf->hdr.info.forw); |
1864 | xfs_da_brelse(NULL, bp); | 1965 | xfs_da_brelse(NULL, bp); |
1865 | error = xfs_da_read_buf(NULL, context->dp, cursor->blkno, -1, | 1966 | error = xfs_da_read_buf(NULL, context->dp, cursor->blkno, -1, |
@@ -1886,7 +1987,7 @@ xfs_attr_node_list(xfs_attr_list_context_t *context) | |||
1886 | * Read the value associated with an attribute from the out-of-line buffer | 1987 | * Read the value associated with an attribute from the out-of-line buffer |
1887 | * that we stored it in. | 1988 | * that we stored it in. |
1888 | */ | 1989 | */ |
1889 | STATIC int | 1990 | int |
1890 | xfs_attr_rmtval_get(xfs_da_args_t *args) | 1991 | xfs_attr_rmtval_get(xfs_da_args_t *args) |
1891 | { | 1992 | { |
1892 | xfs_bmbt_irec_t map[ATTR_RMTVALUE_MAPSIZE]; | 1993 | xfs_bmbt_irec_t map[ATTR_RMTVALUE_MAPSIZE]; |