aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_attr.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_attr.c')
-rw-r--r--fs/xfs/xfs_attr.c181
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 */
94STATIC int xfs_attr_rmtval_get(xfs_da_args_t *args);
95STATIC int xfs_attr_rmtval_set(xfs_da_args_t *args); 94STATIC int xfs_attr_rmtval_set(xfs_da_args_t *args);
96STATIC int xfs_attr_rmtval_remove(xfs_da_args_t *args); 95STATIC 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
183STATIC int 182int
184xfs_attr_set_int(xfs_inode_t *dp, const char *name, int namelen, 183xfs_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 */
443STATIC int 442int
444xfs_attr_remove_int(xfs_inode_t *dp, const char *name, int namelen, int flags) 443xfs_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
593int /* error */
594xfs_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*/
628STATIC int
629xfs_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
662STATIC int
663xfs_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*/
688STATIC int
689xfs_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
686int /* error */ 783int /* 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 */
1889STATIC int 1990int
1890xfs_attr_rmtval_get(xfs_da_args_t *args) 1991xfs_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];