X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=fs%2Fxfs%2Fxfs_attr.c;h=7ce44a7b88a246de3effe15bd9ab8f0aa680b095;hb=0f1145cc18e970ebe37da114fc34c297f135e062;hp=1a210104327547b77768e6fd6cd58f7618bac090;hpb=f6c2d1fa6310a71b1c2e05fc6d9ff9b91489fa0e;p=safe%2Fjmp%2Flinux-2.6 diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c index 1a21010..7ce44a7 100644 --- a/fs/xfs/xfs_attr.c +++ b/fs/xfs/xfs_attr.c @@ -57,9 +57,9 @@ */ #define ATTR_SYSCOUNT 2 -STATIC struct attrnames posix_acl_access; -STATIC struct attrnames posix_acl_default; -STATIC struct attrnames *attr_system_names[ATTR_SYSCOUNT]; +static struct attrnames posix_acl_access; +static struct attrnames posix_acl_default; +static struct attrnames *attr_system_names[ATTR_SYSCOUNT]; /*======================================================================== * Function prototypes for the kernel. @@ -91,7 +91,6 @@ STATIC int xfs_attr_refillstate(xfs_da_state_t *state); /* * Routines to manipulate out-of-line attribute values. */ -STATIC int xfs_attr_rmtval_get(xfs_da_args_t *args); STATIC int xfs_attr_rmtval_set(xfs_da_args_t *args); STATIC int xfs_attr_rmtval_remove(xfs_da_args_t *args); @@ -180,7 +179,7 @@ xfs_attr_get(bhv_desc_t *bdp, const char *name, char *value, int *valuelenp, return(error); } -STATIC int +int xfs_attr_set_int(xfs_inode_t *dp, const char *name, int namelen, char *value, int valuelen, int flags) { @@ -200,18 +199,14 @@ xfs_attr_set_int(xfs_inode_t *dp, const char *name, int namelen, return (error); /* - * Determine space new attribute will use, and if it would be - * "local" or "remote" (note: local != inline). - */ - size = xfs_attr_leaf_newentsize(namelen, valuelen, - mp->m_sb.sb_blocksize, &local); - - /* * If the inode doesn't have an attribute fork, add one. * (inode must not be locked when we call this routine) */ if (XFS_IFORK_Q(dp) == 0) { - if ((error = xfs_bmap_add_attrfork(dp, size, rsvd))) + int sf_size = sizeof(xfs_attr_sf_hdr_t) + + XFS_ATTR_SF_ENTSIZE_BYNAME(namelen, valuelen); + + if ((error = xfs_bmap_add_attrfork(dp, sf_size, rsvd))) return(error); } @@ -232,6 +227,13 @@ xfs_attr_set_int(xfs_inode_t *dp, const char *name, int namelen, args.addname = 1; args.oknoent = 1; + /* + * Determine space new attribute will use, and if it would be + * "local" or "remote" (note: local != inline). + */ + size = xfs_attr_leaf_newentsize(namelen, valuelen, + mp->m_sb.sb_blocksize, &local); + nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK); if (local) { if (size > (mp->m_sb.sb_blocksize >> 1)) { @@ -326,8 +328,7 @@ xfs_attr_set_int(xfs_inode_t *dp, const char *name, int namelen, xfs_trans_set_sync(args.trans); } err2 = xfs_trans_commit(args.trans, - XFS_TRANS_RELEASE_LOG_RES, - NULL); + XFS_TRANS_RELEASE_LOG_RES); xfs_iunlock(dp, XFS_ILOCK_EXCL); /* @@ -347,7 +348,7 @@ xfs_attr_set_int(xfs_inode_t *dp, const char *name, int namelen, error = xfs_attr_shortform_to_leaf(&args); if (!error) { error = xfs_bmap_finish(&args.trans, args.flist, - *args.firstblock, &committed); + &committed); } if (error) { ASSERT(committed); @@ -395,8 +396,7 @@ xfs_attr_set_int(xfs_inode_t *dp, const char *name, int namelen, * Commit the last in the sequence of transactions. */ xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE); - error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES, - NULL); + error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES); xfs_iunlock(dp, XFS_ILOCK_EXCL); /* @@ -440,7 +440,7 @@ xfs_attr_set(bhv_desc_t *bdp, const char *name, char *value, int valuelen, int f * Generic handler routine to remove a name from an attribute list. * Transitions attribute list from Btree to shortform as necessary. */ -STATIC int +int xfs_attr_remove_int(xfs_inode_t *dp, const char *name, int namelen, int flags) { xfs_da_args_t args; @@ -542,8 +542,7 @@ xfs_attr_remove_int(xfs_inode_t *dp, const char *name, int namelen, int flags) * Commit the last in the sequence of transactions. */ xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE); - error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES, - NULL); + error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES); xfs_iunlock(dp, XFS_ILOCK_EXCL); /* @@ -591,6 +590,110 @@ xfs_attr_remove(bhv_desc_t *bdp, const char *name, int flags, struct cred *cred) return xfs_attr_remove_int(dp, name, namelen, flags); } +int /* error */ +xfs_attr_list_int(xfs_attr_list_context_t *context) +{ + int error; + xfs_inode_t *dp = context->dp; + + /* + * Decide on what work routines to call based on the inode size. + */ + if (XFS_IFORK_Q(dp) == 0 || + (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && + dp->i_d.di_anextents == 0)) { + error = 0; + } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { + error = xfs_attr_shortform_list(context); + } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { + error = xfs_attr_leaf_list(context); + } else { + error = xfs_attr_node_list(context); + } + return error; +} + +#define ATTR_ENTBASESIZE /* minimum bytes used by an attr */ \ + (((struct attrlist_ent *) 0)->a_name - (char *) 0) +#define ATTR_ENTSIZE(namelen) /* actual bytes used by an attr */ \ + ((ATTR_ENTBASESIZE + (namelen) + 1 + sizeof(u_int32_t)-1) \ + & ~(sizeof(u_int32_t)-1)) + +/* + * Format an attribute and copy it out to the user's buffer. + * Take care to check values and protect against them changing later, + * we may be reading them directly out of a user buffer. + */ +/*ARGSUSED*/ +STATIC int +xfs_attr_put_listent(xfs_attr_list_context_t *context, attrnames_t *namesp, + char *name, int namelen, + int valuelen, char *value) +{ + attrlist_ent_t *aep; + int arraytop; + + ASSERT(!(context->flags & ATTR_KERNOVAL)); + ASSERT(context->count >= 0); + ASSERT(context->count < (ATTR_MAX_VALUELEN/8)); + ASSERT(context->firstu >= sizeof(*context->alist)); + ASSERT(context->firstu <= context->bufsize); + + arraytop = sizeof(*context->alist) + + context->count * sizeof(context->alist->al_offset[0]); + context->firstu -= ATTR_ENTSIZE(namelen); + if (context->firstu < arraytop) { + xfs_attr_trace_l_c("buffer full", context); + context->alist->al_more = 1; + context->seen_enough = 1; + return 1; + } + + aep = (attrlist_ent_t *)&(((char *)context->alist)[ context->firstu ]); + aep->a_valuelen = valuelen; + memcpy(aep->a_name, name, namelen); + aep->a_name[ namelen ] = 0; + context->alist->al_offset[ context->count++ ] = context->firstu; + context->alist->al_count = context->count; + xfs_attr_trace_l_c("add", context); + return 0; +} + +STATIC int +xfs_attr_kern_list(xfs_attr_list_context_t *context, attrnames_t *namesp, + char *name, int namelen, + int valuelen, char *value) +{ + char *offset; + int arraytop; + + ASSERT(context->count >= 0); + + arraytop = context->count + namesp->attr_namelen + namelen + 1; + if (arraytop > context->firstu) { + context->count = -1; /* insufficient space */ + return 1; + } + offset = (char *)context->alist + context->count; + strncpy(offset, namesp->attr_name, namesp->attr_namelen); + offset += namesp->attr_namelen; + strncpy(offset, name, namelen); /* real name */ + offset += namelen; + *offset = '\0'; + context->count += namesp->attr_namelen + namelen + 1; + return 0; +} + +/*ARGSUSED*/ +STATIC int +xfs_attr_kern_list_sizes(xfs_attr_list_context_t *context, attrnames_t *namesp, + char *name, int namelen, + int valuelen, char *value) +{ + context->count += namesp->attr_namelen + namelen + 1; + return 0; +} + /* * Generate a list of extended attribute names and optionally * 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, return(XFS_ERROR(EINVAL)); if ((cursor->initted == 0) && (cursor->hashval || cursor->blkno || cursor->offset)) - return(XFS_ERROR(EINVAL)); + return XFS_ERROR(EINVAL); /* * Check for a properly aligned buffer. */ if (((long)buffer) & (sizeof(int)-1)) - return(XFS_ERROR(EFAULT)); + return XFS_ERROR(EFAULT); if (flags & ATTR_KERNOVAL) bufsize = 0; @@ -634,53 +737,47 @@ xfs_attr_list(bhv_desc_t *bdp, char *buffer, int bufsize, int flags, context.dupcnt = 0; context.resynch = 1; context.flags = flags; - if (!(flags & ATTR_KERNAMELS)) { + context.seen_enough = 0; + context.alist = (attrlist_t *)buffer; + context.put_value = 0; + + if (flags & ATTR_KERNAMELS) { + context.bufsize = bufsize; + context.firstu = context.bufsize; + if (flags & ATTR_KERNOVAL) + context.put_listent = xfs_attr_kern_list_sizes; + else + context.put_listent = xfs_attr_kern_list; + } else { context.bufsize = (bufsize & ~(sizeof(int)-1)); /* align */ context.firstu = context.bufsize; - context.alist = (attrlist_t *)buffer; context.alist->al_count = 0; context.alist->al_more = 0; context.alist->al_offset[0] = context.bufsize; - } - else { - context.bufsize = bufsize; - context.firstu = context.bufsize; - context.alist = (attrlist_t *)buffer; + context.put_listent = xfs_attr_put_listent; } if (XFS_FORCED_SHUTDOWN(dp->i_mount)) - return (EIO); + return EIO; xfs_ilock(dp, XFS_ILOCK_SHARED); - /* - * Decide on what work routines to call based on the inode size. - */ xfs_attr_trace_l_c("syscall start", &context); - if (XFS_IFORK_Q(dp) == 0 || - (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && - dp->i_d.di_anextents == 0)) { - error = 0; - } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { - error = xfs_attr_shortform_list(&context); - } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { - error = xfs_attr_leaf_list(&context); - } else { - error = xfs_attr_node_list(&context); - } + + error = xfs_attr_list_int(&context); + xfs_iunlock(dp, XFS_ILOCK_SHARED); xfs_attr_trace_l_c("syscall end", &context); - if (!(context.flags & (ATTR_KERNOVAL|ATTR_KERNAMELS))) { - ASSERT(error >= 0); - } - else { /* must return negated buffer size or the error */ + if (context.flags & (ATTR_KERNOVAL|ATTR_KERNAMELS)) { + /* must return negated buffer size or the error */ if (context.count < 0) error = XFS_ERROR(ERANGE); else error = -context.count; - } + } else + ASSERT(error >= 0); - return(error); + return error; } int /* error */ @@ -759,8 +856,7 @@ xfs_attr_inactive(xfs_inode_t *dp) * Commit the last in the sequence of transactions. */ xfs_trans_log_inode(trans, dp, XFS_ILOG_CORE); - error = xfs_trans_commit(trans, XFS_TRANS_RELEASE_LOG_RES, - NULL); + error = xfs_trans_commit(trans, XFS_TRANS_RELEASE_LOG_RES); xfs_iunlock(dp, XFS_ILOCK_EXCL); return(error); @@ -876,7 +972,7 @@ xfs_attr_leaf_addname(xfs_da_args_t *args) error = xfs_attr_leaf_to_node(args); if (!error) { error = xfs_bmap_finish(&args->trans, args->flist, - *args->firstblock, &committed); + &committed); } if (error) { ASSERT(committed); @@ -977,7 +1073,6 @@ xfs_attr_leaf_addname(xfs_da_args_t *args) if (!error) { error = xfs_bmap_finish(&args->trans, args->flist, - *args->firstblock, &committed); } if (error) { @@ -1055,7 +1150,7 @@ xfs_attr_leaf_removename(xfs_da_args_t *args) /* bp is gone due to xfs_da_shrink_inode */ if (!error) { error = xfs_bmap_finish(&args->trans, args->flist, - *args->firstblock, &committed); + &committed); } if (error) { ASSERT(committed); @@ -1122,19 +1217,19 @@ xfs_attr_leaf_list(xfs_attr_list_context_t *context) context->cursor->blkno = 0; error = xfs_da_read_buf(NULL, context->dp, 0, -1, &bp, XFS_ATTR_FORK); if (error) - return(error); + return XFS_ERROR(error); ASSERT(bp != NULL); leaf = bp->data; if (unlikely(be16_to_cpu(leaf->hdr.info.magic) != XFS_ATTR_LEAF_MAGIC)) { XFS_CORRUPTION_ERROR("xfs_attr_leaf_list", XFS_ERRLEVEL_LOW, context->dp->i_mount, leaf); xfs_da_brelse(NULL, bp); - return(XFS_ERROR(EFSCORRUPTED)); + return XFS_ERROR(EFSCORRUPTED); } - (void)xfs_attr_leaf_list_int(bp, context); + error = xfs_attr_leaf_list_int(bp, context); xfs_da_brelse(NULL, bp); - return(0); + return XFS_ERROR(error); } @@ -1210,7 +1305,6 @@ restart: if (!error) { error = xfs_bmap_finish(&args->trans, args->flist, - *args->firstblock, &committed); } if (error) { @@ -1250,7 +1344,7 @@ restart: error = xfs_da_split(state); if (!error) { error = xfs_bmap_finish(&args->trans, args->flist, - *args->firstblock, &committed); + &committed); } if (error) { ASSERT(committed); @@ -1362,7 +1456,6 @@ restart: if (!error) { error = xfs_bmap_finish(&args->trans, args->flist, - *args->firstblock, &committed); } if (error) { @@ -1497,7 +1590,7 @@ xfs_attr_node_removename(xfs_da_args_t *args) error = xfs_da_join(state); if (!error) { error = xfs_bmap_finish(&args->trans, args->flist, - *args->firstblock, &committed); + &committed); } if (error) { ASSERT(committed); @@ -1549,7 +1642,6 @@ xfs_attr_node_removename(xfs_da_args_t *args) if (!error) { error = xfs_bmap_finish(&args->trans, args->flist, - *args->firstblock, &committed); } if (error) { @@ -1858,8 +1950,12 @@ xfs_attr_node_list(xfs_attr_list_context_t *context) return(XFS_ERROR(EFSCORRUPTED)); } error = xfs_attr_leaf_list_int(bp, context); - if (error || !leaf->hdr.info.forw) - break; /* not really an error, buffer full or EOF */ + if (error) { + xfs_da_brelse(NULL, bp); + return error; + } + if (context->seen_enough || leaf->hdr.info.forw == 0) + break; cursor->blkno = be32_to_cpu(leaf->hdr.info.forw); xfs_da_brelse(NULL, bp); error = xfs_da_read_buf(NULL, context->dp, cursor->blkno, -1, @@ -1886,7 +1982,7 @@ xfs_attr_node_list(xfs_attr_list_context_t *context) * Read the value associated with an attribute from the out-of-line buffer * that we stored it in. */ -STATIC int +int xfs_attr_rmtval_get(xfs_da_args_t *args) { xfs_bmbt_irec_t map[ATTR_RMTVALUE_MAPSIZE]; @@ -1989,7 +2085,7 @@ xfs_attr_rmtval_set(xfs_da_args_t *args) args->flist, NULL); if (!error) { error = xfs_bmap_finish(&args->trans, args->flist, - *args->firstblock, &committed); + &committed); } if (error) { ASSERT(committed); @@ -2145,7 +2241,7 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args) NULL, &done); if (!error) { error = xfs_bmap_finish(&args->trans, args->flist, - *args->firstblock, &committed); + &committed); } if (error) { ASSERT(committed); @@ -2376,7 +2472,7 @@ posix_acl_default_exists( return xfs_acl_vhasacl_default(vp); } -STATIC struct attrnames posix_acl_access = { +static struct attrnames posix_acl_access = { .attr_name = "posix_acl_access", .attr_namelen = sizeof("posix_acl_access") - 1, .attr_get = posix_acl_access_get, @@ -2385,7 +2481,7 @@ STATIC struct attrnames posix_acl_access = { .attr_exists = posix_acl_access_exists, }; -STATIC struct attrnames posix_acl_default = { +static struct attrnames posix_acl_default = { .attr_name = "posix_acl_default", .attr_namelen = sizeof("posix_acl_default") - 1, .attr_get = posix_acl_default_get, @@ -2394,7 +2490,7 @@ STATIC struct attrnames posix_acl_default = { .attr_exists = posix_acl_default_exists, }; -STATIC struct attrnames *attr_system_names[] = +static struct attrnames *attr_system_names[] = { &posix_acl_access, &posix_acl_default };