Merge branch 'xfs-attr-cleanup' into for-next

Conflicts:
	fs/xfs/xfs_attr.c
This commit is contained in:
Dave Chinner 2014-05-15 09:39:28 +10:00
commit 2d6dcc6d7e

View file

@ -77,17 +77,26 @@ STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
STATIC int STATIC int
xfs_attr_name_to_xname( xfs_attr_args_init(
struct xfs_name *xname, struct xfs_da_args *args,
const unsigned char *aname) struct xfs_inode *dp,
const unsigned char *name,
int flags)
{ {
if (!aname)
if (!name)
return EINVAL; return EINVAL;
xname->name = aname;
xname->len = strlen((char *)aname); memset(args, 0, sizeof(*args));
if (xname->len >= MAXNAMELEN) args->whichfork = XFS_ATTR_FORK;
args->dp = dp;
args->flags = flags;
args->name = name;
args->namelen = strlen((const char *)name);
if (args->namelen >= MAXNAMELEN)
return EFAULT; /* match IRIX behaviour */ return EFAULT; /* match IRIX behaviour */
args->hashval = xfs_da_hashname(args->name, args->namelen);
return 0; return 0;
} }
@ -106,79 +115,46 @@ xfs_inode_hasattr(
* Overall external interface routines. * Overall external interface routines.
*========================================================================*/ *========================================================================*/
STATIC int int
xfs_attr_get_int( xfs_attr_get(
struct xfs_inode *ip, struct xfs_inode *ip,
struct xfs_name *name, const unsigned char *name,
unsigned char *value, unsigned char *value,
int *valuelenp, int *valuelenp,
int flags) int flags)
{ {
xfs_da_args_t args; struct xfs_da_args args;
int error; uint lock_mode;
int error;
if (!xfs_inode_hasattr(ip))
return ENOATTR;
/*
* Fill in the arg structure for this request.
*/
memset((char *)&args, 0, sizeof(args));
args.name = name->name;
args.namelen = name->len;
args.value = value;
args.valuelen = *valuelenp;
args.flags = flags;
args.hashval = xfs_da_hashname(args.name, args.namelen);
args.dp = ip;
args.whichfork = XFS_ATTR_FORK;
/*
* Decide on what work routines to call based on the inode size.
*/
if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
error = xfs_attr_shortform_getvalue(&args);
} else if (xfs_bmap_one_block(ip, XFS_ATTR_FORK)) {
error = xfs_attr_leaf_get(&args);
} else {
error = xfs_attr_node_get(&args);
}
/*
* Return the number of bytes in the value to the caller.
*/
*valuelenp = args.valuelen;
if (error == EEXIST)
error = 0;
return(error);
}
int
xfs_attr_get(
xfs_inode_t *ip,
const unsigned char *name,
unsigned char *value,
int *valuelenp,
int flags)
{
int error;
struct xfs_name xname;
uint lock_mode;
XFS_STATS_INC(xs_attr_get); XFS_STATS_INC(xs_attr_get);
if (XFS_FORCED_SHUTDOWN(ip->i_mount)) if (XFS_FORCED_SHUTDOWN(ip->i_mount))
return(EIO); return EIO;
error = xfs_attr_name_to_xname(&xname, name); if (!xfs_inode_hasattr(ip))
return ENOATTR;
error = xfs_attr_args_init(&args, ip, name, flags);
if (error) if (error)
return error; return error;
args.value = value;
args.valuelen = *valuelenp;
lock_mode = xfs_ilock_attr_map_shared(ip); lock_mode = xfs_ilock_attr_map_shared(ip);
error = xfs_attr_get_int(ip, &xname, value, valuelenp, flags); if (!xfs_inode_hasattr(ip))
error = ENOATTR;
else if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL)
error = xfs_attr_shortform_getvalue(&args);
else if (xfs_bmap_one_block(ip, XFS_ATTR_FORK))
error = xfs_attr_leaf_get(&args);
else
error = xfs_attr_node_get(&args);
xfs_iunlock(ip, lock_mode); xfs_iunlock(ip, lock_mode);
return(error);
*valuelenp = args.valuelen;
return error == EEXIST ? 0 : error;
} }
/* /*
@ -186,12 +162,10 @@ xfs_attr_get(
*/ */
STATIC int STATIC int
xfs_attr_calc_size( xfs_attr_calc_size(
struct xfs_inode *ip, struct xfs_da_args *args,
int namelen,
int valuelen,
int *local) int *local)
{ {
struct xfs_mount *mp = ip->i_mount; struct xfs_mount *mp = args->dp->i_mount;
int size; int size;
int nblks; int nblks;
@ -199,7 +173,7 @@ xfs_attr_calc_size(
* Determine space new attribute will use, and if it would be * Determine space new attribute will use, and if it would be
* "local" or "remote" (note: local != inline). * "local" or "remote" (note: local != inline).
*/ */
size = xfs_attr_leaf_newentsize(namelen, valuelen, size = xfs_attr_leaf_newentsize(args->namelen, args->valuelen,
mp->m_sb.sb_blocksize, local); mp->m_sb.sb_blocksize, local);
nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK); nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK);
@ -213,7 +187,7 @@ xfs_attr_calc_size(
* Out of line attribute, cannot double split, but * Out of line attribute, cannot double split, but
* make room for the attribute value itself. * make room for the attribute value itself.
*/ */
uint dblocks = xfs_attr3_rmt_blocks(mp, valuelen); uint dblocks = xfs_attr3_rmt_blocks(mp, args->valuelen);
nblks += dblocks; nblks += dblocks;
nblks += XFS_NEXTENTADD_SPACE_RES(mp, dblocks, XFS_ATTR_FORK); nblks += XFS_NEXTENTADD_SPACE_RES(mp, dblocks, XFS_ATTR_FORK);
} }
@ -221,26 +195,38 @@ xfs_attr_calc_size(
return nblks; return nblks;
} }
STATIC int int
xfs_attr_set_int( xfs_attr_set(
struct xfs_inode *dp, struct xfs_inode *dp,
struct xfs_name *name, const unsigned char *name,
unsigned char *value, unsigned char *value,
int valuelen, int valuelen,
int flags) int flags)
{ {
xfs_da_args_t args;
xfs_fsblock_t firstblock;
xfs_bmap_free_t flist;
int error, err2, committed;
struct xfs_mount *mp = dp->i_mount; struct xfs_mount *mp = dp->i_mount;
struct xfs_da_args args;
struct xfs_bmap_free flist;
struct xfs_trans_res tres; struct xfs_trans_res tres;
xfs_fsblock_t firstblock;
int rsvd = (flags & ATTR_ROOT) != 0; int rsvd = (flags & ATTR_ROOT) != 0;
int local; int error, err2, committed, local;
XFS_STATS_INC(xs_attr_set);
if (XFS_FORCED_SHUTDOWN(dp->i_mount))
return EIO;
error = xfs_attr_args_init(&args, dp, name, flags);
if (error)
return error;
args.value = value;
args.valuelen = valuelen;
args.firstblock = &firstblock;
args.flist = &flist;
args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
args.total = xfs_attr_calc_size(&args, &local);
/*
* Attach the dquots to the inode.
*/
error = xfs_qm_dqattach(dp, 0); error = xfs_qm_dqattach(dp, 0);
if (error) if (error)
return error; return error;
@ -251,31 +237,13 @@ xfs_attr_set_int(
*/ */
if (XFS_IFORK_Q(dp) == 0) { if (XFS_IFORK_Q(dp) == 0) {
int sf_size = sizeof(xfs_attr_sf_hdr_t) + int sf_size = sizeof(xfs_attr_sf_hdr_t) +
XFS_ATTR_SF_ENTSIZE_BYNAME(name->len, valuelen); XFS_ATTR_SF_ENTSIZE_BYNAME(args.namelen, valuelen);
if ((error = xfs_bmap_add_attrfork(dp, sf_size, rsvd))) error = xfs_bmap_add_attrfork(dp, sf_size, rsvd);
return(error); if (error)
return error;
} }
/*
* Fill in the arg structure for this request.
*/
memset((char *)&args, 0, sizeof(args));
args.name = name->name;
args.namelen = name->len;
args.value = value;
args.valuelen = valuelen;
args.flags = flags;
args.hashval = xfs_da_hashname(args.name, args.namelen);
args.dp = dp;
args.firstblock = &firstblock;
args.flist = &flist;
args.whichfork = XFS_ATTR_FORK;
args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
/* Size is now blocks for attribute data */
args.total = xfs_attr_calc_size(dp, name->len, valuelen, &local);
/* /*
* Start our first transaction of the day. * Start our first transaction of the day.
* *
@ -303,7 +271,7 @@ xfs_attr_set_int(
error = xfs_trans_reserve(args.trans, &tres, args.total, 0); error = xfs_trans_reserve(args.trans, &tres, args.total, 0);
if (error) { if (error) {
xfs_trans_cancel(args.trans, 0); xfs_trans_cancel(args.trans, 0);
return(error); return error;
} }
xfs_ilock(dp, XFS_ILOCK_EXCL); xfs_ilock(dp, XFS_ILOCK_EXCL);
@ -313,7 +281,7 @@ xfs_attr_set_int(
if (error) { if (error) {
xfs_iunlock(dp, XFS_ILOCK_EXCL); xfs_iunlock(dp, XFS_ILOCK_EXCL);
xfs_trans_cancel(args.trans, XFS_TRANS_RELEASE_LOG_RES); xfs_trans_cancel(args.trans, XFS_TRANS_RELEASE_LOG_RES);
return (error); return error;
} }
xfs_trans_ijoin(args.trans, dp, 0); xfs_trans_ijoin(args.trans, dp, 0);
@ -322,9 +290,9 @@ xfs_attr_set_int(
* If the attribute list is non-existent or a shortform list, * If the attribute list is non-existent or a shortform list,
* upgrade it to a single-leaf-block attribute list. * upgrade it to a single-leaf-block attribute list.
*/ */
if ((dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) || if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
((dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) && (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
(dp->i_d.di_anextents == 0))) { dp->i_d.di_anextents == 0)) {
/* /*
* Build initial attribute list (if required). * Build initial attribute list (if required).
@ -349,9 +317,8 @@ xfs_attr_set_int(
* the transaction goes to disk before returning * the transaction goes to disk before returning
* to the user. * to the user.
*/ */
if (mp->m_flags & XFS_MOUNT_WSYNC) { if (mp->m_flags & XFS_MOUNT_WSYNC)
xfs_trans_set_sync(args.trans); xfs_trans_set_sync(args.trans);
}
if (!error && (flags & ATTR_KERNOTIME) == 0) { if (!error && (flags & ATTR_KERNOTIME) == 0) {
xfs_trans_ichgtime(args.trans, dp, xfs_trans_ichgtime(args.trans, dp,
@ -361,7 +328,7 @@ xfs_attr_set_int(
XFS_TRANS_RELEASE_LOG_RES); XFS_TRANS_RELEASE_LOG_RES);
xfs_iunlock(dp, XFS_ILOCK_EXCL); xfs_iunlock(dp, XFS_ILOCK_EXCL);
return(error == 0 ? err2 : error); return error ? error : err2;
} }
/* /*
@ -399,22 +366,19 @@ xfs_attr_set_int(
} }
if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
error = xfs_attr_leaf_addname(&args); error = xfs_attr_leaf_addname(&args);
} else { else
error = xfs_attr_node_addname(&args); error = xfs_attr_node_addname(&args);
} if (error)
if (error) {
goto out; goto out;
}
/* /*
* If this is a synchronous mount, make sure that the * If this is a synchronous mount, make sure that the
* transaction goes to disk before returning to the user. * transaction goes to disk before returning to the user.
*/ */
if (mp->m_flags & XFS_MOUNT_WSYNC) { if (mp->m_flags & XFS_MOUNT_WSYNC)
xfs_trans_set_sync(args.trans); xfs_trans_set_sync(args.trans);
}
if ((flags & ATTR_KERNOTIME) == 0) if ((flags & ATTR_KERNOTIME) == 0)
xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG); xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
@ -426,65 +390,47 @@ xfs_attr_set_int(
error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES); error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES);
xfs_iunlock(dp, XFS_ILOCK_EXCL); xfs_iunlock(dp, XFS_ILOCK_EXCL);
return(error); return error;
out: out:
if (args.trans) if (args.trans) {
xfs_trans_cancel(args.trans, xfs_trans_cancel(args.trans,
XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
}
xfs_iunlock(dp, XFS_ILOCK_EXCL); xfs_iunlock(dp, XFS_ILOCK_EXCL);
return(error); return error;
}
int
xfs_attr_set(
xfs_inode_t *dp,
const unsigned char *name,
unsigned char *value,
int valuelen,
int flags)
{
int error;
struct xfs_name xname;
XFS_STATS_INC(xs_attr_set);
if (XFS_FORCED_SHUTDOWN(dp->i_mount))
return (EIO);
error = xfs_attr_name_to_xname(&xname, name);
if (error)
return error;
return xfs_attr_set_int(dp, &xname, value, valuelen, flags);
} }
/* /*
* Generic handler routine to remove a name from an attribute list. * Generic handler routine to remove a name from an attribute list.
* Transitions attribute list from Btree to shortform as necessary. * Transitions attribute list from Btree to shortform as necessary.
*/ */
STATIC int int
xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags) xfs_attr_remove(
struct xfs_inode *dp,
const unsigned char *name,
int flags)
{ {
xfs_da_args_t args; struct xfs_mount *mp = dp->i_mount;
xfs_fsblock_t firstblock; struct xfs_da_args args;
xfs_bmap_free_t flist; struct xfs_bmap_free flist;
int error; xfs_fsblock_t firstblock;
xfs_mount_t *mp = dp->i_mount; int error;
XFS_STATS_INC(xs_attr_remove);
if (XFS_FORCED_SHUTDOWN(dp->i_mount))
return EIO;
if (!xfs_inode_hasattr(dp))
return ENOATTR;
error = xfs_attr_args_init(&args, dp, name, flags);
if (error)
return error;
/*
* Fill in the arg structure for this request.
*/
memset((char *)&args, 0, sizeof(args));
args.name = name->name;
args.namelen = name->len;
args.flags = flags;
args.hashval = xfs_da_hashname(args.name, args.namelen);
args.dp = dp;
args.firstblock = &firstblock; args.firstblock = &firstblock;
args.flist = &flist; args.flist = &flist;
args.total = 0;
args.whichfork = XFS_ATTR_FORK;
/* /*
* we have no control over the attribute names that userspace passes us * we have no control over the attribute names that userspace passes us
@ -493,9 +439,6 @@ xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags)
*/ */
args.op_flags = XFS_DA_OP_OKNOENT; args.op_flags = XFS_DA_OP_OKNOENT;
/*
* Attach the dquots to the inode.
*/
error = xfs_qm_dqattach(dp, 0); error = xfs_qm_dqattach(dp, 0);
if (error) if (error)
return error; return error;
@ -524,7 +467,7 @@ xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags)
XFS_ATTRRM_SPACE_RES(mp), 0); XFS_ATTRRM_SPACE_RES(mp), 0);
if (error) { if (error) {
xfs_trans_cancel(args.trans, 0); xfs_trans_cancel(args.trans, 0);
return(error); return error;
} }
xfs_ilock(dp, XFS_ILOCK_EXCL); xfs_ilock(dp, XFS_ILOCK_EXCL);
@ -534,35 +477,26 @@ xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags)
*/ */
xfs_trans_ijoin(args.trans, dp, 0); xfs_trans_ijoin(args.trans, dp, 0);
/*
* Decide on what work routines to call based on the inode size.
*/
if (!xfs_inode_hasattr(dp)) { if (!xfs_inode_hasattr(dp)) {
error = XFS_ERROR(ENOATTR); error = XFS_ERROR(ENOATTR);
goto out; } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
}
if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
ASSERT(dp->i_afp->if_flags & XFS_IFINLINE); ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
error = xfs_attr_shortform_remove(&args); error = xfs_attr_shortform_remove(&args);
if (error) {
goto out;
}
} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
error = xfs_attr_leaf_removename(&args); error = xfs_attr_leaf_removename(&args);
} else { } else {
error = xfs_attr_node_removename(&args); error = xfs_attr_node_removename(&args);
} }
if (error) {
if (error)
goto out; goto out;
}
/* /*
* If this is a synchronous mount, make sure that the * If this is a synchronous mount, make sure that the
* transaction goes to disk before returning to the user. * transaction goes to disk before returning to the user.
*/ */
if (mp->m_flags & XFS_MOUNT_WSYNC) { if (mp->m_flags & XFS_MOUNT_WSYNC)
xfs_trans_set_sync(args.trans); xfs_trans_set_sync(args.trans);
}
if ((flags & ATTR_KERNOTIME) == 0) if ((flags & ATTR_KERNOTIME) == 0)
xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG); xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
@ -574,45 +508,17 @@ xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags)
error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES); error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES);
xfs_iunlock(dp, XFS_ILOCK_EXCL); xfs_iunlock(dp, XFS_ILOCK_EXCL);
return(error); return error;
out: out:
if (args.trans) if (args.trans) {
xfs_trans_cancel(args.trans, xfs_trans_cancel(args.trans,
XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
xfs_iunlock(dp, XFS_ILOCK_EXCL);
return(error);
}
int
xfs_attr_remove(
xfs_inode_t *dp,
const unsigned char *name,
int flags)
{
int error;
struct xfs_name xname;
XFS_STATS_INC(xs_attr_remove);
if (XFS_FORCED_SHUTDOWN(dp->i_mount))
return (EIO);
error = xfs_attr_name_to_xname(&xname, name);
if (error)
return error;
xfs_ilock(dp, XFS_ILOCK_SHARED);
if (!xfs_inode_hasattr(dp)) {
xfs_iunlock(dp, XFS_ILOCK_SHARED);
return XFS_ERROR(ENOATTR);
} }
xfs_iunlock(dp, XFS_ILOCK_SHARED); xfs_iunlock(dp, XFS_ILOCK_EXCL);
return error;
return xfs_attr_remove_int(dp, &xname, flags);
} }
/*======================================================================== /*========================================================================
* External routines when attribute list is inside the inode * External routines when attribute list is inside the inode
*========================================================================*/ *========================================================================*/