diff mbox series

[27/29] xfs: clean up the attr flag confusion

Message ID 20200114081051.297488-28-hch@lst.de (mailing list archive)
State Superseded
Headers show
Series [01/29] xfs: remove the ATTR_INCOMPLETE flag | expand

Commit Message

Christoph Hellwig Jan. 14, 2020, 8:10 a.m. UTC
The ATTR_* flags have a long IRIX history, where they a userspace
interface, the on-disk format and an internal interface.  We've split
out the on-disk interface to the XFS_ATTR_* values, but despite (or
because?) of that the flag have still been a mess.  Switch the
internal interface to pass the on-disk XFS_ATTR_* flags for the
namespace and the Linux XATTR_* flags for the actual flags instead.
The ATTR_* values that are actually used are move to xfs_fs.h with a
new XFS_IOC_* prefix to not conflict with the userspace version that
has the same name and must have the same value.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 fs/xfs/libxfs/xfs_attr.c      | 16 ++++++-------
 fs/xfs/libxfs/xfs_attr.h      | 22 +-----------------
 fs/xfs/libxfs/xfs_attr_leaf.c | 14 +++++------
 fs/xfs/libxfs/xfs_da_format.h | 12 ----------
 fs/xfs/libxfs/xfs_fs.h        | 29 ++++++++++++-----------
 fs/xfs/libxfs/xfs_types.h     |  3 ++-
 fs/xfs/scrub/attr.c           |  5 +---
 fs/xfs/xfs_acl.c              |  5 ++--
 fs/xfs/xfs_ioctl.c            | 44 ++++++++++++++++++++++++++---------
 fs/xfs/xfs_iops.c             |  3 +--
 fs/xfs/xfs_linux.h            |  1 +
 fs/xfs/xfs_trace.h            | 35 +++++++++++++++++-----------
 fs/xfs/xfs_xattr.c            | 18 +++++---------
 13 files changed, 100 insertions(+), 107 deletions(-)

Comments

Darrick J. Wong Jan. 21, 2020, 7:44 p.m. UTC | #1
Clean up?  This whole XATTR_/ATTR_/XFS_ATTR_/XFS_IOC_ATTR_ quadrality is
/still/ confusing to me.

On Tue, Jan 14, 2020 at 09:10:49AM +0100, Christoph Hellwig wrote:
> The ATTR_* flags have a long IRIX history, where they a userspace
> interface, the on-disk format and an internal interface.  We've split
> out the on-disk interface to the XFS_ATTR_* values, but despite (or
> because?) of that the flag have still been a mess.  Switch the
> internal interface to pass the on-disk XFS_ATTR_* flags for the
> namespace and the Linux XATTR_* flags for the actual flags instead.
> The ATTR_* values that are actually used are move to xfs_fs.h with a
> new XFS_IOC_* prefix to not conflict with the userspace version that
> has the same name and must have the same value.
> 
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> ---
>  fs/xfs/libxfs/xfs_attr.c      | 16 ++++++-------
>  fs/xfs/libxfs/xfs_attr.h      | 22 +-----------------
>  fs/xfs/libxfs/xfs_attr_leaf.c | 14 +++++------
>  fs/xfs/libxfs/xfs_da_format.h | 12 ----------
>  fs/xfs/libxfs/xfs_fs.h        | 29 ++++++++++++-----------
>  fs/xfs/libxfs/xfs_types.h     |  3 ++-
>  fs/xfs/scrub/attr.c           |  5 +---
>  fs/xfs/xfs_acl.c              |  5 ++--
>  fs/xfs/xfs_ioctl.c            | 44 ++++++++++++++++++++++++++---------
>  fs/xfs/xfs_iops.c             |  3 +--
>  fs/xfs/xfs_linux.h            |  1 +
>  fs/xfs/xfs_trace.h            | 35 +++++++++++++++++-----------
>  fs/xfs/xfs_xattr.c            | 18 +++++---------
>  13 files changed, 100 insertions(+), 107 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 3b29cdeecb64..2b9c0aa5af4a 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -291,7 +291,7 @@ xfs_attr_set(
>  	struct xfs_inode	*dp = args->dp;
>  	struct xfs_mount	*mp = dp->i_mount;
>  	struct xfs_trans_res	tres;
> -	int			rsvd = (args->flags & ATTR_ROOT) != 0;
> +	int			rsvd = (args->attr_namespace & XFS_ATTR_ROOT);

bool?

>  	int			error, local;
>  	unsigned int		total;
>  
> @@ -419,10 +419,10 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
>  	trace_xfs_attr_sf_addname(args);
>  
>  	retval = xfs_attr_shortform_lookup(args);
> -	if ((args->flags & ATTR_REPLACE) && retval == -ENOATTR)
> +	if ((args->attr_flags & XATTR_REPLACE) && retval == -ENOATTR)
>  		return retval;
>  	if (retval == -EEXIST) {
> -		if (args->flags & ATTR_CREATE)
> +		if (args->attr_flags & XATTR_CREATE)
>  			return retval;
>  		retval = xfs_attr_shortform_remove(args);
>  		if (retval)
> @@ -432,7 +432,7 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
>  		 * that the leaf format add routine won't trip over the attr
>  		 * not being around.
>  		 */
> -		args->flags &= ~ATTR_REPLACE;
> +		args->attr_flags &= ~XATTR_REPLACE;
>  	}
>  
>  	if (args->namelen >= XFS_ATTR_SF_ENTSIZE_MAX ||
> @@ -485,10 +485,10 @@ xfs_attr_leaf_addname(
>  	 * the given flags produce an error or call for an atomic rename.
>  	 */
>  	retval = xfs_attr3_leaf_lookup_int(bp, args);
> -	if ((args->flags & ATTR_REPLACE) && retval == -ENOATTR)
> +	if ((args->attr_flags & XATTR_REPLACE) && retval == -ENOATTR)
>  		goto out_brelse;
>  	if (retval == -EEXIST) {
> -		if (args->flags & ATTR_CREATE)	/* pure create op */
> +		if (args->attr_flags & XATTR_CREATE)	/* pure create op */
>  			goto out_brelse;
>  
>  		trace_xfs_attr_leaf_replace(args);
> @@ -759,10 +759,10 @@ xfs_attr_node_addname(
>  		goto out;
>  	blk = &state->path.blk[ state->path.active-1 ];
>  	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
> -	if ((args->flags & ATTR_REPLACE) && retval == -ENOATTR)
> +	if ((args->attr_flags & XATTR_REPLACE) && retval == -ENOATTR)
>  		goto out;
>  	if (retval == -EEXIST) {
> -		if (args->flags & ATTR_CREATE)
> +		if (args->attr_flags & XATTR_CREATE)
>  			goto out;
>  
>  		trace_xfs_attr_node_replace(args);
> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> index 8d42f5782ff7..2a379338d71b 100644
> --- a/fs/xfs/libxfs/xfs_attr.h
> +++ b/fs/xfs/libxfs/xfs_attr.h
> @@ -21,26 +21,6 @@ struct xfs_attr_list_context;
>   * as possible so as to fit into the literal area of the inode.
>   */
>  
> -/*========================================================================
> - * External interfaces
> - *========================================================================*/
> -
> -
> -#define ATTR_DONTFOLLOW	0x0001	/* -- ignored, from IRIX -- */
> -#define ATTR_ROOT	0x0002	/* use attrs in root (trusted) namespace */
> -#define ATTR_TRUST	0x0004	/* -- unused, from IRIX -- */
> -#define ATTR_SECURE	0x0008	/* use attrs in security namespace */
> -#define ATTR_CREATE	0x0010	/* pure create: fail if attr already exists */
> -#define ATTR_REPLACE	0x0020	/* pure set: fail if attr does not exist */
> -
> -#define XFS_ATTR_FLAGS \
> -	{ ATTR_DONTFOLLOW, 	"DONTFOLLOW" }, \
> -	{ ATTR_ROOT,		"ROOT" }, \
> -	{ ATTR_TRUST,		"TRUST" }, \
> -	{ ATTR_SECURE,		"SECURE" }, \
> -	{ ATTR_CREATE,		"CREATE" }, \
> -	{ ATTR_REPLACE,		"REPLACE" }
> -
>  /*
>   * The maximum size (into the kernel or returned from the kernel) of an
>   * attribute value or the buffer used for an attr_list() call.  Larger
> @@ -87,7 +67,7 @@ struct xfs_attr_list_context {
>  	int			dupcnt;		/* count dup hashvals seen */
>  	int			bufsize;	/* total buffer size */
>  	int			firstu;		/* first used byte in buffer */
> -	int			flags;		/* from VOP call */
> +	unsigned int		attr_namespace;

What flags go with this attr_namespace field?  XFS_ATTR_{ROOT,SECURE}?

(Note: While I /think/ all the code changes work correctly, I'm mostly
going to complain about things in the hunks that change the header
files.)

>  	int			resynch;	/* T/F: resynch with cursor */
>  	put_listent_func_t	put_listent;	/* list output fmt function */
>  	int			index;		/* index into output buffer */
> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
> index 8852754153ba..9081ba7af90a 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
> @@ -456,8 +456,7 @@ xfs_attr_match(
>  		return false;
>  	if (memcmp(args->name, name, namelen) != 0)
>  		return false;
> -	if (XFS_ATTR_NSP_ARGS_TO_ONDISK(args->flags) !=
> -	    XFS_ATTR_NSP_ONDISK(flags))
> +	if (args->attr_namespace != (flags & XFS_ATTR_NSP_ONDISK_MASK))
>  		return false;
>  	return true;
>  }
> @@ -697,7 +696,7 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
>  
>  	sfe->namelen = args->namelen;
>  	sfe->valuelen = args->valuelen;
> -	sfe->flags = XFS_ATTR_NSP_ARGS_TO_ONDISK(args->flags);
> +	sfe->flags = args->attr_namespace;
>  	memcpy(sfe->nameval, args->name, args->namelen);
>  	memcpy(&sfe->nameval[args->namelen], args->value, args->valuelen);
>  	sf->hdr.count++;
> @@ -906,7 +905,7 @@ xfs_attr_shortform_to_leaf(
>  		nargs.valuelen = sfe->valuelen;
>  		nargs.hashval = xfs_da_hashname(sfe->nameval,
>  						sfe->namelen);
> -		nargs.flags = XFS_ATTR_NSP_ONDISK_TO_ARGS(sfe->flags);
> +		nargs.attr_namespace = sfe->flags & XFS_ATTR_NSP_ONDISK_MASK;
>  		error = xfs_attr3_leaf_lookup_int(bp, &nargs); /* set a->index */
>  		ASSERT(error == -ENOATTR);
>  		error = xfs_attr3_leaf_add(bp, &nargs);
> @@ -1112,7 +1111,7 @@ xfs_attr3_leaf_to_shortform(
>  		nargs.value = &name_loc->nameval[nargs.namelen];
>  		nargs.valuelen = be16_to_cpu(name_loc->valuelen);
>  		nargs.hashval = be32_to_cpu(entry->hashval);
> -		nargs.flags = XFS_ATTR_NSP_ONDISK_TO_ARGS(entry->flags);
> +		nargs.attr_namespace = entry->flags & XFS_ATTR_NSP_ONDISK_MASK;
>  		xfs_attr_shortform_add(&nargs, forkoff);
>  	}
>  	error = 0;
> @@ -1437,8 +1436,9 @@ xfs_attr3_leaf_add_work(
>  	entry->nameidx = cpu_to_be16(ichdr->freemap[mapindex].base +
>  				     ichdr->freemap[mapindex].size);
>  	entry->hashval = cpu_to_be32(args->hashval);
> -	entry->flags = tmp ? XFS_ATTR_LOCAL : 0;
> -	entry->flags |= XFS_ATTR_NSP_ARGS_TO_ONDISK(args->flags);
> +	entry->flags = args->attr_namespace;
> +	if (tmp)
> +		entry->flags |= XFS_ATTR_LOCAL;
>  	if (args->op_flags & XFS_DA_OP_RENAME) {
>  		entry->flags |= XFS_ATTR_INCOMPLETE;
>  		if ((args->blkno2 == args->blkno) &&
> diff --git a/fs/xfs/libxfs/xfs_da_format.h b/fs/xfs/libxfs/xfs_da_format.h
> index 05615d1f4113..239b114932b8 100644
> --- a/fs/xfs/libxfs/xfs_da_format.h
> +++ b/fs/xfs/libxfs/xfs_da_format.h
> @@ -692,19 +692,7 @@ struct xfs_attr3_leafblock {
>  #define XFS_ATTR_ROOT		(1 << XFS_ATTR_ROOT_BIT)
>  #define XFS_ATTR_SECURE		(1 << XFS_ATTR_SECURE_BIT)
>  #define XFS_ATTR_INCOMPLETE	(1 << XFS_ATTR_INCOMPLETE_BIT)
> -
> -/*
> - * Conversion macros for converting namespace bits from argument flags
> - * to ondisk flags.
> - */
> -#define XFS_ATTR_NSP_ARGS_MASK		(ATTR_ROOT | ATTR_SECURE)
>  #define XFS_ATTR_NSP_ONDISK_MASK	(XFS_ATTR_ROOT | XFS_ATTR_SECURE)
> -#define XFS_ATTR_NSP_ONDISK(flags)	((flags) & XFS_ATTR_NSP_ONDISK_MASK)
> -#define XFS_ATTR_NSP_ARGS(flags)	((flags) & XFS_ATTR_NSP_ARGS_MASK)
> -#define XFS_ATTR_NSP_ARGS_TO_ONDISK(x)	(((x) & ATTR_ROOT ? XFS_ATTR_ROOT : 0) |\
> -					 ((x) & ATTR_SECURE ? XFS_ATTR_SECURE : 0))
> -#define XFS_ATTR_NSP_ONDISK_TO_ARGS(x)	(((x) & XFS_ATTR_ROOT ? ATTR_ROOT : 0) |\
> -					 ((x) & XFS_ATTR_SECURE ? ATTR_SECURE : 0))
>  
>  /*
>   * Alignment for namelist and valuelist entries (since they are mixed
> diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
> index 2c2b6e2b58f4..e79af058b1b3 100644
> --- a/fs/xfs/libxfs/xfs_fs.h
> +++ b/fs/xfs/libxfs/xfs_fs.h
> @@ -568,17 +568,27 @@ typedef struct xfs_fsop_setdm_handlereq {
>  	struct fsdmidata		__user *data;	/* DMAPI data	*/
>  } xfs_fsop_setdm_handlereq_t;
>  
> +/*
> + * Flags for the attr ioctl interface.
> + * NOTE: Must match the values declared in libattr without the XFS_IOC_ prefix.
> + */
> +#define XFS_IOC_ATTR_ROOT	0x0002	/* use attrs in root namespace */
> +#define XFS_IOC_ATTR_SECURE	0x0008	/* use attrs in security namespace */
> +#define XFS_IOC_ATTR_CREATE	0x0010	/* fail if attr already exists */
> +#define XFS_IOC_ATTR_REPLACE	0x0020	/* fail if attr does not exist */

I think it's worth nothing that these flags are supposed to be passed in
via am_flags in the attrmulti structure.

(Assuming I even got that right...)

>  typedef struct xfs_attrlist_cursor {
>  	__u32		opaque[4];
>  } xfs_attrlist_cursor_t;
>  
>  /*
> - * Define how lists of attribute names are returned to the user from
> - * the attr_list() call.  A large, 32bit aligned, buffer is passed in
> - * along with its size.  We put an array of offsets at the top that each
> - * reference an attrlist_ent_t and pack the attrlist_ent_t's at the bottom.
> + * Define how lists of attribute names are returned to userspace from the
> + * XFS_IOC_ATTRLIST_BY_HANDLE ioctl.  struct xfs_attrlist is the header at the
> + * beginning of the returned buffer, and a each entry in al_offset contains the
> + * relative offset of an xfs_attrlist_ent containing the actual entry.
>   *
> - * NOTE: struct xfs_attrlist must match struct attrlist defined in libattr.
> + * NOTE: struct xfs_attrlist must match struct attrlist defined in libattr, and
> + * struct xfs_attrlist_ent must match struct attrlist_ent defined in libattr.
>   */
>  struct xfs_attrlist {
>  	__s32	al_count;	/* number of entries in attrlist */
> @@ -586,13 +596,6 @@ struct xfs_attrlist {
>  	__s32	al_offset[1];	/* byte offsets of attrs [var-sized] */
>  };
>  
> -/*
> - * Show the interesting info about one attribute.  This is what the
> - * al_offset[i] entry points to.
> - *
> - * NOTE: struct xfs_attrlist_ent must match struct attrlist_ent defined in
> - * libattr.
> - */
>  struct xfs_attrlist_ent {	/* data from attr_list() */
>  	__u32	a_valuelen;	/* number bytes in value of attr */
>  	char	a_name[1];	/* attr name (NULL terminated) */
> @@ -603,7 +606,7 @@ typedef struct xfs_fsop_attrlist_handlereq {
>  	struct xfs_attrlist_cursor	pos; /* opaque cookie, list offset */
>  	__u32				flags;	/* which namespace to use */
>  	__u32				buflen;	/* length of buffer supplied */
> -	void				__user *buffer;	/* returned names */
> +	struct xfs_attrlist __user	*buffer;/* returned names */
>  } xfs_fsop_attrlist_handlereq_t;
>  
>  typedef struct xfs_attr_multiop {
> diff --git a/fs/xfs/libxfs/xfs_types.h b/fs/xfs/libxfs/xfs_types.h
> index 1594325d7742..1bf84488d34c 100644
> --- a/fs/xfs/libxfs/xfs_types.h
> +++ b/fs/xfs/libxfs/xfs_types.h
> @@ -194,7 +194,8 @@ typedef struct xfs_da_args {
>  	uint8_t		filetype;	/* filetype of inode for directories */
>  	void		*value;		/* set of bytes (maybe contain NULLs) */
>  	int		valuelen;	/* length of value */
> -	int		flags;		/* argument flags (eg: ATTR_NOCREATE) */
> +	unsigned int	attr_namespace;
> +	unsigned int	attr_flags;

Please add comments to both of these fields explaining which flags go
with which field.

AFAICT, xfs_da_args.attr_namespace holds the two ondisk namespace flags?
Which are XFS_ATTR_{ROOT,SECURE}?  And ... I think the next patch makes
it so that people can pass XFS_ATTR_INCOMPLETE for lookups, too?

vs. xfs_da_args.attr_flags, which contains the XATTR_{CREATE,REPLACE}
flags, which are the attr operation flags that we got from userspace?

And what goes in xfs_attr_list_context.attr_namespace?  Same values as
xfs_da_args.attr_namespace?

>  	xfs_dahash_t	hashval;	/* hash value of name */
>  	xfs_ino_t	inumber;	/* input/output inode number */
>  	struct xfs_inode *dp;		/* directory inode to manipulate */
> diff --git a/fs/xfs/scrub/attr.c b/fs/xfs/scrub/attr.c
> index 9e336d797616..d84237af5455 100644
> --- a/fs/xfs/scrub/attr.c
> +++ b/fs/xfs/scrub/attr.c
> @@ -148,10 +148,7 @@ xchk_xattr_listent(
>  	}
>  
>  	args.op_flags = XFS_DA_OP_NOTIME;
> -	if (flags & XFS_ATTR_ROOT)
> -		args.flags |= ATTR_ROOT;
> -	else if (flags & XFS_ATTR_SECURE)
> -		args.flags |= ATTR_SECURE;
> +	args.attr_namespace = flags & XFS_ATTR_NSP_ONDISK_MASK;
>  	args.geo = context->dp->i_mount->m_attr_geo;
>  	args.whichfork = XFS_ATTR_FORK;
>  	args.dp = context->dp;
> diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
> index c993ffd9b767..dd54e3b8adb2 100644
> --- a/fs/xfs/xfs_acl.c
> +++ b/fs/xfs/xfs_acl.c
> @@ -14,6 +14,7 @@
>  #include "xfs_trace.h"
>  #include "xfs_error.h"
>  #include "xfs_acl.h"
> +#include "xfs_da_format.h"
>  
>  #include <linux/posix_acl_xattr.h>
>  
> @@ -125,7 +126,7 @@ xfs_get_acl(struct inode *inode, int type)
>  	struct posix_acl	*acl = NULL;
>  	struct xfs_da_args	args = {
>  		.dp		= ip,
> -		.flags		= ATTR_ROOT,
> +		.attr_namespace	= XFS_ATTR_ROOT,
>  		.valuelen	= XFS_ACL_MAX_SIZE(mp),
>  	};
>  	int			error;
> @@ -166,7 +167,7 @@ __xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
>  	struct xfs_inode	*ip = XFS_I(inode);
>  	struct xfs_da_args	args = {
>  		.dp		= ip,
> -		.flags		= ATTR_ROOT,
> +		.attr_namespace	= XFS_ATTR_ROOT,
>  	};
>  	int			error;
>  
> diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
> index 7a1ff66b4786..063dc0d83453 100644
> --- a/fs/xfs/xfs_ioctl.c
> +++ b/fs/xfs/xfs_ioctl.c
> @@ -293,6 +293,30 @@ xfs_readlink_by_handle(
>  	return error;
>  }
>  
> +static unsigned int
> +xfs_attr_namespace(
> +	u32			ioc_flags)
> +{
> +	unsigned int		namespace = 0;
> +
> +	if (ioc_flags & XFS_IOC_ATTR_ROOT)
> +		namespace |= XFS_ATTR_ROOT;
> +	if (ioc_flags & XFS_IOC_ATTR_SECURE)
> +		namespace |= XFS_ATTR_SECURE;

Seeing as these are mutually exclusive options, I'm a little surprised
there isn't more checking that both of these flags aren't set at the
same time.

(Or I've been reading this series too long and missed that it does...)

--D

> +	return namespace;
> +}
> +
> +static unsigned int
> +xfs_attr_flags(
> +	u32			ioc_flags)
> +{
> +	if (ioc_flags & XFS_IOC_ATTR_CREATE)
> +		return XATTR_CREATE;
> +	if (ioc_flags & XFS_IOC_ATTR_REPLACE)
> +		return XATTR_REPLACE;
> +	return 0;
> +}
> +
>  #define	ATTR_ENTSIZE(namelen)		/* actual bytes used by an attr */ \
>  	((offsetof(struct xfs_attrlist_ent, a_name) + \
>  	 (namelen) + 1 + sizeof(uint32_t) - 1) \
> @@ -324,11 +348,7 @@ xfs_ioc_attr_put_listent(
>  	/*
>  	 * Only list entries in the right namespace.
>  	 */
> -	if (((context->flags & ATTR_SECURE) == 0) !=
> -	    ((flags & XFS_ATTR_SECURE) == 0))
> -		return;
> -	if (((context->flags & ATTR_ROOT) == 0) !=
> -	    ((flags & XFS_ATTR_ROOT) == 0))
> +	if (context->attr_namespace != (flags & XFS_ATTR_NSP_ONDISK_MASK))
>  		return;
>  
>  	arraytop = sizeof(*alist) +
> @@ -371,7 +391,7 @@ xfs_ioc_attr_list(
>  	/*
>  	 * Reject flags, only allow namespaces.
>  	 */
> -	if (flags & ~(ATTR_ROOT | ATTR_SECURE))
> +	if (flags & ~(XFS_IOC_ATTR_ROOT | XFS_IOC_ATTR_SECURE))
>  		return -EINVAL;
>  
>  	/*
> @@ -396,7 +416,7 @@ xfs_ioc_attr_list(
>  	context.dp = dp;
>  	context.cursor = &cursor;
>  	context.resynch = 1;
> -	context.flags = flags;
> +	context.attr_namespace = xfs_attr_namespace(flags);
>  	context.buffer = buffer;
>  	context.bufsize = (bufsize & ~(sizeof(int)-1));  /* align */
>  	context.firstu = context.bufsize;
> @@ -453,7 +473,8 @@ xfs_attrmulti_attr_get(
>  {
>  	struct xfs_da_args	args = {
>  		.dp		= XFS_I(inode),
> -		.flags		= flags,
> +		.attr_namespace	= xfs_attr_namespace(flags),
> +		.attr_flags	= xfs_attr_flags(flags),
>  		.name		= name,
>  		.namelen	= strlen(name),
>  		.valuelen	= *len,
> @@ -490,7 +511,8 @@ xfs_attrmulti_attr_set(
>  {
>  	struct xfs_da_args	args = {
>  		.dp		= XFS_I(inode),
> -		.flags		= flags,
> +		.attr_namespace	= xfs_attr_namespace(flags),
> +		.attr_flags	= xfs_attr_flags(flags),
>  		.name		= name,
>  		.namelen	= strlen(name),
>  	};
> @@ -509,7 +531,7 @@ xfs_attrmulti_attr_set(
>  	}
>  
>  	error = xfs_attr_set(&args);
> -	if (!error && (flags & ATTR_ROOT))
> +	if (!error && (flags & XFS_IOC_ATTR_ROOT))
>  		xfs_forget_acl(inode, name);
>  	kfree(args.value);
>  	return error;
> @@ -528,7 +550,7 @@ xfs_ioc_attrmulti_one(
>  	unsigned char		*name;
>  	int			error;
>  
> -	if ((flags & ATTR_ROOT) && (flags & ATTR_SECURE))
> +	if ((flags & XFS_IOC_ATTR_ROOT) && (flags & XFS_IOC_ATTR_SECURE))
>  		return -EINVAL;
>  
>  	name = strndup_user(uname, MAXNAMELEN);
> diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
> index 94cd4254656c..8b1a3e7d83e6 100644
> --- a/fs/xfs/xfs_iops.c
> +++ b/fs/xfs/xfs_iops.c
> @@ -22,7 +22,6 @@
>  #include "xfs_iomap.h"
>  #include "xfs_error.h"
>  
> -#include <linux/xattr.h>
>  #include <linux/posix_acl.h>
>  #include <linux/security.h>
>  #include <linux/iversion.h>
> @@ -52,7 +51,7 @@ xfs_initxattrs(
>  	for (xattr = xattr_array; xattr->name != NULL; xattr++) {
>  		struct xfs_da_args	args = {
>  			.dp		= ip,
> -			.flags		= ATTR_SECURE,
> +			.attr_namespace	= XFS_ATTR_SECURE,
>  			.name		= xattr->name,
>  			.namelen	= strlen(xattr->name),
>  			.value		= xattr->value,
> diff --git a/fs/xfs/xfs_linux.h b/fs/xfs/xfs_linux.h
> index 8738bb03f253..8c0070a797de 100644
> --- a/fs/xfs/xfs_linux.h
> +++ b/fs/xfs/xfs_linux.h
> @@ -60,6 +60,7 @@ typedef __u32			xfs_nlink_t;
>  #include <linux/list_sort.h>
>  #include <linux/ratelimit.h>
>  #include <linux/rhashtable.h>
> +#include <linux/xattr.h>
>  
>  #include <asm/page.h>
>  #include <asm/div64.h>
> diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
> index 8358a92987f9..a064b1523fa5 100644
> --- a/fs/xfs/xfs_trace.h
> +++ b/fs/xfs/xfs_trace.h
> @@ -36,6 +36,10 @@ struct xfs_owner_info;
>  struct xfs_trans_res;
>  struct xfs_inobt_rec_incore;
>  
> +#define XFS_ATTR_NSP_FLAGS \
> +	{ XFS_ATTR_ROOT,	"ROOT" }, \
> +	{ XFS_ATTR_SECURE,	"SECURE" }
> +
>  DECLARE_EVENT_CLASS(xfs_attr_list_class,
>  	TP_PROTO(struct xfs_attr_list_context *ctx),
>  	TP_ARGS(ctx),
> @@ -50,7 +54,7 @@ DECLARE_EVENT_CLASS(xfs_attr_list_class,
>  		__field(int, count)
>  		__field(int, firstu)
>  		__field(int, dupcnt)
> -		__field(int, flags)
> +		__field(int, attr_namespace)
>  	),
>  	TP_fast_assign(
>  		__entry->dev = VFS_I(ctx->dp)->i_sb->s_dev;
> @@ -62,10 +66,10 @@ DECLARE_EVENT_CLASS(xfs_attr_list_class,
>  		__entry->bufsize = ctx->bufsize;
>  		__entry->count = ctx->count;
>  		__entry->firstu = ctx->firstu;
> -		__entry->flags = ctx->flags;
> +		__entry->attr_namespace = ctx->attr_namespace;
>  	),
>  	TP_printk("dev %d:%d ino 0x%llx cursor h/b/o 0x%x/0x%x/%u dupcnt %u "
> -		  "buffer %p size %u count %u firstu %u flags %d %s",
> +		  "buffer %p size %u count %u firstu %u namespace %d %s",
>  		  MAJOR(__entry->dev), MINOR(__entry->dev),
>  		   __entry->ino,
>  		   __entry->hashval,
> @@ -76,8 +80,9 @@ DECLARE_EVENT_CLASS(xfs_attr_list_class,
>  		   __entry->bufsize,
>  		   __entry->count,
>  		   __entry->firstu,
> -		   __entry->flags,
> -		   __print_flags(__entry->flags, "|", XFS_ATTR_FLAGS)
> +		   __entry->attr_namespace,
> +		   __print_flags(__entry->attr_namespace, "|",
> +				 XFS_ATTR_NSP_FLAGS)
>  	)
>  )
>  
> @@ -174,7 +179,7 @@ TRACE_EVENT(xfs_attr_list_node_descend,
>  		__field(int, count)
>  		__field(int, firstu)
>  		__field(int, dupcnt)
> -		__field(int, flags)
> +		__field(int, attr_namespace)
>  		__field(u32, bt_hashval)
>  		__field(u32, bt_before)
>  	),
> @@ -188,12 +193,12 @@ TRACE_EVENT(xfs_attr_list_node_descend,
>  		__entry->bufsize = ctx->bufsize;
>  		__entry->count = ctx->count;
>  		__entry->firstu = ctx->firstu;
> -		__entry->flags = ctx->flags;
> +		__entry->attr_namespace = ctx->attr_namespace;
>  		__entry->bt_hashval = be32_to_cpu(btree->hashval);
>  		__entry->bt_before = be32_to_cpu(btree->before);
>  	),
>  	TP_printk("dev %d:%d ino 0x%llx cursor h/b/o 0x%x/0x%x/%u dupcnt %u "
> -		  "buffer %p size %u count %u firstu %u flags %d %s "
> +		  "buffer %p size %u count %u firstu %u namespae %d %s "
>  		  "node hashval %u, node before %u",
>  		  MAJOR(__entry->dev), MINOR(__entry->dev),
>  		   __entry->ino,
> @@ -205,8 +210,9 @@ TRACE_EVENT(xfs_attr_list_node_descend,
>  		   __entry->bufsize,
>  		   __entry->count,
>  		   __entry->firstu,
> -		   __entry->flags,
> -		   __print_flags(__entry->flags, "|", XFS_ATTR_FLAGS),
> +		   __entry->attr_namespace,
> +		   __print_flags(__entry->attr_namespace, "|",
> +				 XFS_ATTR_NSP_FLAGS),
>  		   __entry->bt_hashval,
>  		   __entry->bt_before)
>  );
> @@ -1701,7 +1707,7 @@ DECLARE_EVENT_CLASS(xfs_attr_class,
>  		__field(int, namelen)
>  		__field(int, valuelen)
>  		__field(xfs_dahash_t, hashval)
> -		__field(int, flags)
> +		__field(int, attr_namespace)
>  		__field(int, op_flags)
>  	),
>  	TP_fast_assign(
> @@ -1712,11 +1718,11 @@ DECLARE_EVENT_CLASS(xfs_attr_class,
>  		__entry->namelen = args->namelen;
>  		__entry->valuelen = args->valuelen;
>  		__entry->hashval = args->hashval;
> -		__entry->flags = args->flags;
> +		__entry->attr_namespace = args->attr_namespace;
>  		__entry->op_flags = args->op_flags;
>  	),
>  	TP_printk("dev %d:%d ino 0x%llx name %.*s namelen %d valuelen %d "
> -		  "hashval 0x%x flags %s op_flags %s",
> +		  "hashval 0x%x namespace %s op_flags %s",
>  		  MAJOR(__entry->dev), MINOR(__entry->dev),
>  		  __entry->ino,
>  		  __entry->namelen,
> @@ -1724,7 +1730,8 @@ DECLARE_EVENT_CLASS(xfs_attr_class,
>  		  __entry->namelen,
>  		  __entry->valuelen,
>  		  __entry->hashval,
> -		  __print_flags(__entry->flags, "|", XFS_ATTR_FLAGS),
> +		  __print_flags(__entry->attr_namespace, "|",
> +				XFS_ATTR_NSP_FLAGS),
>  		  __print_flags(__entry->op_flags, "|", XFS_DA_OP_FLAGS))
>  )
>  
> diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
> index 863e9fdec162..1d2c8615b335 100644
> --- a/fs/xfs/xfs_xattr.c
> +++ b/fs/xfs/xfs_xattr.c
> @@ -14,7 +14,6 @@
>  #include "xfs_acl.h"
>  
>  #include <linux/posix_acl_xattr.h>
> -#include <linux/xattr.h>
>  
>  
>  static int
> @@ -23,7 +22,7 @@ xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
>  {
>  	struct xfs_da_args	args = {
>  		.dp		= XFS_I(inode),
> -		.flags		= handler->flags,
> +		.attr_namespace	= handler->flags,
>  		.name		= name,
>  		.namelen	= strlen(name),
>  		.value		= value,
> @@ -44,7 +43,8 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
>  {
>  	struct xfs_da_args	args = {
>  		.dp		= XFS_I(inode),
> -		.flags		= handler->flags,
> +		.attr_namespace	= handler->flags,
> +		.attr_flags	= flags,
>  		.name		= name,
>  		.namelen	= strlen(name),
>  		.value		= (unsigned char *)value,
> @@ -52,14 +52,8 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
>  	};
>  	int			error;
>  
> -	/* Convert Linux syscall to XFS internal ATTR flags */
> -	if (flags & XATTR_CREATE)
> -		args.flags |= ATTR_CREATE;
> -	if (flags & XATTR_REPLACE)
> -		args.flags |= ATTR_REPLACE;
> -
>  	error = xfs_attr_set(&args);
> -	if (!error && (flags & ATTR_ROOT))
> +	if (!error && (handler->flags & XFS_ATTR_ROOT))
>  		xfs_forget_acl(inode, name);
>  	return error;
>  }
> @@ -73,14 +67,14 @@ static const struct xattr_handler xfs_xattr_user_handler = {
>  
>  static const struct xattr_handler xfs_xattr_trusted_handler = {
>  	.prefix	= XATTR_TRUSTED_PREFIX,
> -	.flags	= ATTR_ROOT,
> +	.flags	= XFS_ATTR_ROOT,
>  	.get	= xfs_xattr_get,
>  	.set	= xfs_xattr_set,
>  };
>  
>  static const struct xattr_handler xfs_xattr_security_handler = {
>  	.prefix	= XATTR_SECURITY_PREFIX,
> -	.flags	= ATTR_SECURE,
> +	.flags	= XFS_ATTR_SECURE,
>  	.get	= xfs_xattr_get,
>  	.set	= xfs_xattr_set,
>  };
> -- 
> 2.24.1
>
Christoph Hellwig Jan. 24, 2020, 11:24 p.m. UTC | #2
On Tue, Jan 21, 2020 at 11:44:40AM -0800, Darrick J. Wong wrote:
> Clean up?  This whole XATTR_/ATTR_/XFS_ATTR_/XFS_IOC_ATTR_ quadrality is
> /still/ confusing to me.

> >  	struct xfs_mount	*mp = dp->i_mount;
> >  	struct xfs_trans_res	tres;
> > -	int			rsvd = (args->flags & ATTR_ROOT) != 0;
> > +	int			rsvd = (args->attr_namespace & XFS_ATTR_ROOT);
> 
> bool?

Ok.

> > @@ -87,7 +67,7 @@ struct xfs_attr_list_context {
> >  	int			dupcnt;		/* count dup hashvals seen */
> >  	int			bufsize;	/* total buffer size */
> >  	int			firstu;		/* first used byte in buffer */
> > -	int			flags;		/* from VOP call */
> > +	unsigned int		attr_namespace;
> 
> What flags go with this attr_namespace field?  XFS_ATTR_{ROOT,SECURE}?

Yes.. I'll add a comment.

> > +/*
> > + * Flags for the attr ioctl interface.
> > + * NOTE: Must match the values declared in libattr without the XFS_IOC_ prefix.
> > + */
> > +#define XFS_IOC_ATTR_ROOT	0x0002	/* use attrs in root namespace */
> > +#define XFS_IOC_ATTR_SECURE	0x0008	/* use attrs in security namespace */
> > +#define XFS_IOC_ATTR_CREATE	0x0010	/* fail if attr already exists */
> > +#define XFS_IOC_ATTR_REPLACE	0x0020	/* fail if attr does not exist */
> 
> I think it's worth nothing that these flags are supposed to be passed in
> via am_flags in the attrmulti structure.

Done.

> > +++ b/fs/xfs/libxfs/xfs_types.h
> > @@ -194,7 +194,8 @@ typedef struct xfs_da_args {
> >  	uint8_t		filetype;	/* filetype of inode for directories */
> >  	void		*value;		/* set of bytes (maybe contain NULLs) */
> >  	int		valuelen;	/* length of value */
> > -	int		flags;		/* argument flags (eg: ATTR_NOCREATE) */
> > +	unsigned int	attr_namespace;
> > +	unsigned int	attr_flags;
> 
> Please add comments to both of these fields explaining which flags go
> with which field.

Ok.

> AFAICT, xfs_da_args.attr_namespace holds the two ondisk namespace flags?

Yes.

> Which are XFS_ATTR_{ROOT,SECURE}?

Yes.

> And ... I think the next patch makes
> it so that people can pass XFS_ATTR_INCOMPLETE for lookups, too?

Yes.  Internal lookups at least.

> 
> vs. xfs_da_args.attr_flags, which contains the XATTR_{CREATE,REPLACE}
> flags, which are the attr operation flags that we got from userspace?

Yes.

> And what goes in xfs_attr_list_context.attr_namespace?  Same values as
> xfs_da_args.attr_namespace?

Yes.

> > +static unsigned int
> > +xfs_attr_namespace(
> > +	u32			ioc_flags)
> > +{
> > +	unsigned int		namespace = 0;
> > +
> > +	if (ioc_flags & XFS_IOC_ATTR_ROOT)
> > +		namespace |= XFS_ATTR_ROOT;
> > +	if (ioc_flags & XFS_IOC_ATTR_SECURE)
> > +		namespace |= XFS_ATTR_SECURE;
> 
> Seeing as these are mutually exclusive options, I'm a little surprised
> there isn't more checking that both of these flags aren't set at the
> same time.
> 
> (Or I've been reading this series too long and missed that it does...)

XFS never rejected the combination.  It just won't find anything in that
case.  Let me see if I could throw in another patch to add more checks
there.
Christoph Hellwig Jan. 25, 2020, 11:10 p.m. UTC | #3
On Fri, Jan 24, 2020 at 03:24:13PM -0800, Christoph Hellwig wrote:
> > > +	u32			ioc_flags)
> > > +{
> > > +	unsigned int		namespace = 0;
> > > +
> > > +	if (ioc_flags & XFS_IOC_ATTR_ROOT)
> > > +		namespace |= XFS_ATTR_ROOT;
> > > +	if (ioc_flags & XFS_IOC_ATTR_SECURE)
> > > +		namespace |= XFS_ATTR_SECURE;
> > 
> > Seeing as these are mutually exclusive options, I'm a little surprised
> > there isn't more checking that both of these flags aren't set at the
> > same time.
> > 
> > (Or I've been reading this series too long and missed that it does...)
> 
> XFS never rejected the combination.  It just won't find anything in that
> case.  Let me see if I could throw in another patch to add more checks
> there.

So for the get/set ioctl this was all fixed by

"xfs: reject invalid flags combinations in XFS_IOC_ATTRMULTI_BY_HANDLE"

for listattr it is rather harmless, but I can throw in a patch to
explicitly reject it.
Darrick J. Wong Jan. 26, 2020, 10:24 p.m. UTC | #4
On Sat, Jan 25, 2020 at 03:10:47PM -0800, Christoph Hellwig wrote:
> On Fri, Jan 24, 2020 at 03:24:13PM -0800, Christoph Hellwig wrote:
> > > > +	u32			ioc_flags)
> > > > +{
> > > > +	unsigned int		namespace = 0;
> > > > +
> > > > +	if (ioc_flags & XFS_IOC_ATTR_ROOT)
> > > > +		namespace |= XFS_ATTR_ROOT;
> > > > +	if (ioc_flags & XFS_IOC_ATTR_SECURE)
> > > > +		namespace |= XFS_ATTR_SECURE;
> > > 
> > > Seeing as these are mutually exclusive options, I'm a little surprised
> > > there isn't more checking that both of these flags aren't set at the
> > > same time.
> > > 
> > > (Or I've been reading this series too long and missed that it does...)
> > 
> > XFS never rejected the combination.  It just won't find anything in that
> > case.  Let me see if I could throw in another patch to add more checks
> > there.
> 
> So for the get/set ioctl this was all fixed by
> 
> "xfs: reject invalid flags combinations in XFS_IOC_ATTRMULTI_BY_HANDLE"
> 
> for listattr it is rather harmless, but I can throw in a patch to
> explicitly reject it.

I think that's a good idea.

--D
diff mbox series

Patch

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 3b29cdeecb64..2b9c0aa5af4a 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -291,7 +291,7 @@  xfs_attr_set(
 	struct xfs_inode	*dp = args->dp;
 	struct xfs_mount	*mp = dp->i_mount;
 	struct xfs_trans_res	tres;
-	int			rsvd = (args->flags & ATTR_ROOT) != 0;
+	int			rsvd = (args->attr_namespace & XFS_ATTR_ROOT);
 	int			error, local;
 	unsigned int		total;
 
@@ -419,10 +419,10 @@  xfs_attr_shortform_addname(xfs_da_args_t *args)
 	trace_xfs_attr_sf_addname(args);
 
 	retval = xfs_attr_shortform_lookup(args);
-	if ((args->flags & ATTR_REPLACE) && retval == -ENOATTR)
+	if ((args->attr_flags & XATTR_REPLACE) && retval == -ENOATTR)
 		return retval;
 	if (retval == -EEXIST) {
-		if (args->flags & ATTR_CREATE)
+		if (args->attr_flags & XATTR_CREATE)
 			return retval;
 		retval = xfs_attr_shortform_remove(args);
 		if (retval)
@@ -432,7 +432,7 @@  xfs_attr_shortform_addname(xfs_da_args_t *args)
 		 * that the leaf format add routine won't trip over the attr
 		 * not being around.
 		 */
-		args->flags &= ~ATTR_REPLACE;
+		args->attr_flags &= ~XATTR_REPLACE;
 	}
 
 	if (args->namelen >= XFS_ATTR_SF_ENTSIZE_MAX ||
@@ -485,10 +485,10 @@  xfs_attr_leaf_addname(
 	 * the given flags produce an error or call for an atomic rename.
 	 */
 	retval = xfs_attr3_leaf_lookup_int(bp, args);
-	if ((args->flags & ATTR_REPLACE) && retval == -ENOATTR)
+	if ((args->attr_flags & XATTR_REPLACE) && retval == -ENOATTR)
 		goto out_brelse;
 	if (retval == -EEXIST) {
-		if (args->flags & ATTR_CREATE)	/* pure create op */
+		if (args->attr_flags & XATTR_CREATE)	/* pure create op */
 			goto out_brelse;
 
 		trace_xfs_attr_leaf_replace(args);
@@ -759,10 +759,10 @@  xfs_attr_node_addname(
 		goto out;
 	blk = &state->path.blk[ state->path.active-1 ];
 	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
-	if ((args->flags & ATTR_REPLACE) && retval == -ENOATTR)
+	if ((args->attr_flags & XATTR_REPLACE) && retval == -ENOATTR)
 		goto out;
 	if (retval == -EEXIST) {
-		if (args->flags & ATTR_CREATE)
+		if (args->attr_flags & XATTR_CREATE)
 			goto out;
 
 		trace_xfs_attr_node_replace(args);
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index 8d42f5782ff7..2a379338d71b 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -21,26 +21,6 @@  struct xfs_attr_list_context;
  * as possible so as to fit into the literal area of the inode.
  */
 
-/*========================================================================
- * External interfaces
- *========================================================================*/
-
-
-#define ATTR_DONTFOLLOW	0x0001	/* -- ignored, from IRIX -- */
-#define ATTR_ROOT	0x0002	/* use attrs in root (trusted) namespace */
-#define ATTR_TRUST	0x0004	/* -- unused, from IRIX -- */
-#define ATTR_SECURE	0x0008	/* use attrs in security namespace */
-#define ATTR_CREATE	0x0010	/* pure create: fail if attr already exists */
-#define ATTR_REPLACE	0x0020	/* pure set: fail if attr does not exist */
-
-#define XFS_ATTR_FLAGS \
-	{ ATTR_DONTFOLLOW, 	"DONTFOLLOW" }, \
-	{ ATTR_ROOT,		"ROOT" }, \
-	{ ATTR_TRUST,		"TRUST" }, \
-	{ ATTR_SECURE,		"SECURE" }, \
-	{ ATTR_CREATE,		"CREATE" }, \
-	{ ATTR_REPLACE,		"REPLACE" }
-
 /*
  * The maximum size (into the kernel or returned from the kernel) of an
  * attribute value or the buffer used for an attr_list() call.  Larger
@@ -87,7 +67,7 @@  struct xfs_attr_list_context {
 	int			dupcnt;		/* count dup hashvals seen */
 	int			bufsize;	/* total buffer size */
 	int			firstu;		/* first used byte in buffer */
-	int			flags;		/* from VOP call */
+	unsigned int		attr_namespace;
 	int			resynch;	/* T/F: resynch with cursor */
 	put_listent_func_t	put_listent;	/* list output fmt function */
 	int			index;		/* index into output buffer */
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
index 8852754153ba..9081ba7af90a 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -456,8 +456,7 @@  xfs_attr_match(
 		return false;
 	if (memcmp(args->name, name, namelen) != 0)
 		return false;
-	if (XFS_ATTR_NSP_ARGS_TO_ONDISK(args->flags) !=
-	    XFS_ATTR_NSP_ONDISK(flags))
+	if (args->attr_namespace != (flags & XFS_ATTR_NSP_ONDISK_MASK))
 		return false;
 	return true;
 }
@@ -697,7 +696,7 @@  xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
 
 	sfe->namelen = args->namelen;
 	sfe->valuelen = args->valuelen;
-	sfe->flags = XFS_ATTR_NSP_ARGS_TO_ONDISK(args->flags);
+	sfe->flags = args->attr_namespace;
 	memcpy(sfe->nameval, args->name, args->namelen);
 	memcpy(&sfe->nameval[args->namelen], args->value, args->valuelen);
 	sf->hdr.count++;
@@ -906,7 +905,7 @@  xfs_attr_shortform_to_leaf(
 		nargs.valuelen = sfe->valuelen;
 		nargs.hashval = xfs_da_hashname(sfe->nameval,
 						sfe->namelen);
-		nargs.flags = XFS_ATTR_NSP_ONDISK_TO_ARGS(sfe->flags);
+		nargs.attr_namespace = sfe->flags & XFS_ATTR_NSP_ONDISK_MASK;
 		error = xfs_attr3_leaf_lookup_int(bp, &nargs); /* set a->index */
 		ASSERT(error == -ENOATTR);
 		error = xfs_attr3_leaf_add(bp, &nargs);
@@ -1112,7 +1111,7 @@  xfs_attr3_leaf_to_shortform(
 		nargs.value = &name_loc->nameval[nargs.namelen];
 		nargs.valuelen = be16_to_cpu(name_loc->valuelen);
 		nargs.hashval = be32_to_cpu(entry->hashval);
-		nargs.flags = XFS_ATTR_NSP_ONDISK_TO_ARGS(entry->flags);
+		nargs.attr_namespace = entry->flags & XFS_ATTR_NSP_ONDISK_MASK;
 		xfs_attr_shortform_add(&nargs, forkoff);
 	}
 	error = 0;
@@ -1437,8 +1436,9 @@  xfs_attr3_leaf_add_work(
 	entry->nameidx = cpu_to_be16(ichdr->freemap[mapindex].base +
 				     ichdr->freemap[mapindex].size);
 	entry->hashval = cpu_to_be32(args->hashval);
-	entry->flags = tmp ? XFS_ATTR_LOCAL : 0;
-	entry->flags |= XFS_ATTR_NSP_ARGS_TO_ONDISK(args->flags);
+	entry->flags = args->attr_namespace;
+	if (tmp)
+		entry->flags |= XFS_ATTR_LOCAL;
 	if (args->op_flags & XFS_DA_OP_RENAME) {
 		entry->flags |= XFS_ATTR_INCOMPLETE;
 		if ((args->blkno2 == args->blkno) &&
diff --git a/fs/xfs/libxfs/xfs_da_format.h b/fs/xfs/libxfs/xfs_da_format.h
index 05615d1f4113..239b114932b8 100644
--- a/fs/xfs/libxfs/xfs_da_format.h
+++ b/fs/xfs/libxfs/xfs_da_format.h
@@ -692,19 +692,7 @@  struct xfs_attr3_leafblock {
 #define XFS_ATTR_ROOT		(1 << XFS_ATTR_ROOT_BIT)
 #define XFS_ATTR_SECURE		(1 << XFS_ATTR_SECURE_BIT)
 #define XFS_ATTR_INCOMPLETE	(1 << XFS_ATTR_INCOMPLETE_BIT)
-
-/*
- * Conversion macros for converting namespace bits from argument flags
- * to ondisk flags.
- */
-#define XFS_ATTR_NSP_ARGS_MASK		(ATTR_ROOT | ATTR_SECURE)
 #define XFS_ATTR_NSP_ONDISK_MASK	(XFS_ATTR_ROOT | XFS_ATTR_SECURE)
-#define XFS_ATTR_NSP_ONDISK(flags)	((flags) & XFS_ATTR_NSP_ONDISK_MASK)
-#define XFS_ATTR_NSP_ARGS(flags)	((flags) & XFS_ATTR_NSP_ARGS_MASK)
-#define XFS_ATTR_NSP_ARGS_TO_ONDISK(x)	(((x) & ATTR_ROOT ? XFS_ATTR_ROOT : 0) |\
-					 ((x) & ATTR_SECURE ? XFS_ATTR_SECURE : 0))
-#define XFS_ATTR_NSP_ONDISK_TO_ARGS(x)	(((x) & XFS_ATTR_ROOT ? ATTR_ROOT : 0) |\
-					 ((x) & XFS_ATTR_SECURE ? ATTR_SECURE : 0))
 
 /*
  * Alignment for namelist and valuelist entries (since they are mixed
diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
index 2c2b6e2b58f4..e79af058b1b3 100644
--- a/fs/xfs/libxfs/xfs_fs.h
+++ b/fs/xfs/libxfs/xfs_fs.h
@@ -568,17 +568,27 @@  typedef struct xfs_fsop_setdm_handlereq {
 	struct fsdmidata		__user *data;	/* DMAPI data	*/
 } xfs_fsop_setdm_handlereq_t;
 
+/*
+ * Flags for the attr ioctl interface.
+ * NOTE: Must match the values declared in libattr without the XFS_IOC_ prefix.
+ */
+#define XFS_IOC_ATTR_ROOT	0x0002	/* use attrs in root namespace */
+#define XFS_IOC_ATTR_SECURE	0x0008	/* use attrs in security namespace */
+#define XFS_IOC_ATTR_CREATE	0x0010	/* fail if attr already exists */
+#define XFS_IOC_ATTR_REPLACE	0x0020	/* fail if attr does not exist */
+
 typedef struct xfs_attrlist_cursor {
 	__u32		opaque[4];
 } xfs_attrlist_cursor_t;
 
 /*
- * Define how lists of attribute names are returned to the user from
- * the attr_list() call.  A large, 32bit aligned, buffer is passed in
- * along with its size.  We put an array of offsets at the top that each
- * reference an attrlist_ent_t and pack the attrlist_ent_t's at the bottom.
+ * Define how lists of attribute names are returned to userspace from the
+ * XFS_IOC_ATTRLIST_BY_HANDLE ioctl.  struct xfs_attrlist is the header at the
+ * beginning of the returned buffer, and a each entry in al_offset contains the
+ * relative offset of an xfs_attrlist_ent containing the actual entry.
  *
- * NOTE: struct xfs_attrlist must match struct attrlist defined in libattr.
+ * NOTE: struct xfs_attrlist must match struct attrlist defined in libattr, and
+ * struct xfs_attrlist_ent must match struct attrlist_ent defined in libattr.
  */
 struct xfs_attrlist {
 	__s32	al_count;	/* number of entries in attrlist */
@@ -586,13 +596,6 @@  struct xfs_attrlist {
 	__s32	al_offset[1];	/* byte offsets of attrs [var-sized] */
 };
 
-/*
- * Show the interesting info about one attribute.  This is what the
- * al_offset[i] entry points to.
- *
- * NOTE: struct xfs_attrlist_ent must match struct attrlist_ent defined in
- * libattr.
- */
 struct xfs_attrlist_ent {	/* data from attr_list() */
 	__u32	a_valuelen;	/* number bytes in value of attr */
 	char	a_name[1];	/* attr name (NULL terminated) */
@@ -603,7 +606,7 @@  typedef struct xfs_fsop_attrlist_handlereq {
 	struct xfs_attrlist_cursor	pos; /* opaque cookie, list offset */
 	__u32				flags;	/* which namespace to use */
 	__u32				buflen;	/* length of buffer supplied */
-	void				__user *buffer;	/* returned names */
+	struct xfs_attrlist __user	*buffer;/* returned names */
 } xfs_fsop_attrlist_handlereq_t;
 
 typedef struct xfs_attr_multiop {
diff --git a/fs/xfs/libxfs/xfs_types.h b/fs/xfs/libxfs/xfs_types.h
index 1594325d7742..1bf84488d34c 100644
--- a/fs/xfs/libxfs/xfs_types.h
+++ b/fs/xfs/libxfs/xfs_types.h
@@ -194,7 +194,8 @@  typedef struct xfs_da_args {
 	uint8_t		filetype;	/* filetype of inode for directories */
 	void		*value;		/* set of bytes (maybe contain NULLs) */
 	int		valuelen;	/* length of value */
-	int		flags;		/* argument flags (eg: ATTR_NOCREATE) */
+	unsigned int	attr_namespace;
+	unsigned int	attr_flags;
 	xfs_dahash_t	hashval;	/* hash value of name */
 	xfs_ino_t	inumber;	/* input/output inode number */
 	struct xfs_inode *dp;		/* directory inode to manipulate */
diff --git a/fs/xfs/scrub/attr.c b/fs/xfs/scrub/attr.c
index 9e336d797616..d84237af5455 100644
--- a/fs/xfs/scrub/attr.c
+++ b/fs/xfs/scrub/attr.c
@@ -148,10 +148,7 @@  xchk_xattr_listent(
 	}
 
 	args.op_flags = XFS_DA_OP_NOTIME;
-	if (flags & XFS_ATTR_ROOT)
-		args.flags |= ATTR_ROOT;
-	else if (flags & XFS_ATTR_SECURE)
-		args.flags |= ATTR_SECURE;
+	args.attr_namespace = flags & XFS_ATTR_NSP_ONDISK_MASK;
 	args.geo = context->dp->i_mount->m_attr_geo;
 	args.whichfork = XFS_ATTR_FORK;
 	args.dp = context->dp;
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
index c993ffd9b767..dd54e3b8adb2 100644
--- a/fs/xfs/xfs_acl.c
+++ b/fs/xfs/xfs_acl.c
@@ -14,6 +14,7 @@ 
 #include "xfs_trace.h"
 #include "xfs_error.h"
 #include "xfs_acl.h"
+#include "xfs_da_format.h"
 
 #include <linux/posix_acl_xattr.h>
 
@@ -125,7 +126,7 @@  xfs_get_acl(struct inode *inode, int type)
 	struct posix_acl	*acl = NULL;
 	struct xfs_da_args	args = {
 		.dp		= ip,
-		.flags		= ATTR_ROOT,
+		.attr_namespace	= XFS_ATTR_ROOT,
 		.valuelen	= XFS_ACL_MAX_SIZE(mp),
 	};
 	int			error;
@@ -166,7 +167,7 @@  __xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 	struct xfs_inode	*ip = XFS_I(inode);
 	struct xfs_da_args	args = {
 		.dp		= ip,
-		.flags		= ATTR_ROOT,
+		.attr_namespace	= XFS_ATTR_ROOT,
 	};
 	int			error;
 
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 7a1ff66b4786..063dc0d83453 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -293,6 +293,30 @@  xfs_readlink_by_handle(
 	return error;
 }
 
+static unsigned int
+xfs_attr_namespace(
+	u32			ioc_flags)
+{
+	unsigned int		namespace = 0;
+
+	if (ioc_flags & XFS_IOC_ATTR_ROOT)
+		namespace |= XFS_ATTR_ROOT;
+	if (ioc_flags & XFS_IOC_ATTR_SECURE)
+		namespace |= XFS_ATTR_SECURE;
+	return namespace;
+}
+
+static unsigned int
+xfs_attr_flags(
+	u32			ioc_flags)
+{
+	if (ioc_flags & XFS_IOC_ATTR_CREATE)
+		return XATTR_CREATE;
+	if (ioc_flags & XFS_IOC_ATTR_REPLACE)
+		return XATTR_REPLACE;
+	return 0;
+}
+
 #define	ATTR_ENTSIZE(namelen)		/* actual bytes used by an attr */ \
 	((offsetof(struct xfs_attrlist_ent, a_name) + \
 	 (namelen) + 1 + sizeof(uint32_t) - 1) \
@@ -324,11 +348,7 @@  xfs_ioc_attr_put_listent(
 	/*
 	 * Only list entries in the right namespace.
 	 */
-	if (((context->flags & ATTR_SECURE) == 0) !=
-	    ((flags & XFS_ATTR_SECURE) == 0))
-		return;
-	if (((context->flags & ATTR_ROOT) == 0) !=
-	    ((flags & XFS_ATTR_ROOT) == 0))
+	if (context->attr_namespace != (flags & XFS_ATTR_NSP_ONDISK_MASK))
 		return;
 
 	arraytop = sizeof(*alist) +
@@ -371,7 +391,7 @@  xfs_ioc_attr_list(
 	/*
 	 * Reject flags, only allow namespaces.
 	 */
-	if (flags & ~(ATTR_ROOT | ATTR_SECURE))
+	if (flags & ~(XFS_IOC_ATTR_ROOT | XFS_IOC_ATTR_SECURE))
 		return -EINVAL;
 
 	/*
@@ -396,7 +416,7 @@  xfs_ioc_attr_list(
 	context.dp = dp;
 	context.cursor = &cursor;
 	context.resynch = 1;
-	context.flags = flags;
+	context.attr_namespace = xfs_attr_namespace(flags);
 	context.buffer = buffer;
 	context.bufsize = (bufsize & ~(sizeof(int)-1));  /* align */
 	context.firstu = context.bufsize;
@@ -453,7 +473,8 @@  xfs_attrmulti_attr_get(
 {
 	struct xfs_da_args	args = {
 		.dp		= XFS_I(inode),
-		.flags		= flags,
+		.attr_namespace	= xfs_attr_namespace(flags),
+		.attr_flags	= xfs_attr_flags(flags),
 		.name		= name,
 		.namelen	= strlen(name),
 		.valuelen	= *len,
@@ -490,7 +511,8 @@  xfs_attrmulti_attr_set(
 {
 	struct xfs_da_args	args = {
 		.dp		= XFS_I(inode),
-		.flags		= flags,
+		.attr_namespace	= xfs_attr_namespace(flags),
+		.attr_flags	= xfs_attr_flags(flags),
 		.name		= name,
 		.namelen	= strlen(name),
 	};
@@ -509,7 +531,7 @@  xfs_attrmulti_attr_set(
 	}
 
 	error = xfs_attr_set(&args);
-	if (!error && (flags & ATTR_ROOT))
+	if (!error && (flags & XFS_IOC_ATTR_ROOT))
 		xfs_forget_acl(inode, name);
 	kfree(args.value);
 	return error;
@@ -528,7 +550,7 @@  xfs_ioc_attrmulti_one(
 	unsigned char		*name;
 	int			error;
 
-	if ((flags & ATTR_ROOT) && (flags & ATTR_SECURE))
+	if ((flags & XFS_IOC_ATTR_ROOT) && (flags & XFS_IOC_ATTR_SECURE))
 		return -EINVAL;
 
 	name = strndup_user(uname, MAXNAMELEN);
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index 94cd4254656c..8b1a3e7d83e6 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -22,7 +22,6 @@ 
 #include "xfs_iomap.h"
 #include "xfs_error.h"
 
-#include <linux/xattr.h>
 #include <linux/posix_acl.h>
 #include <linux/security.h>
 #include <linux/iversion.h>
@@ -52,7 +51,7 @@  xfs_initxattrs(
 	for (xattr = xattr_array; xattr->name != NULL; xattr++) {
 		struct xfs_da_args	args = {
 			.dp		= ip,
-			.flags		= ATTR_SECURE,
+			.attr_namespace	= XFS_ATTR_SECURE,
 			.name		= xattr->name,
 			.namelen	= strlen(xattr->name),
 			.value		= xattr->value,
diff --git a/fs/xfs/xfs_linux.h b/fs/xfs/xfs_linux.h
index 8738bb03f253..8c0070a797de 100644
--- a/fs/xfs/xfs_linux.h
+++ b/fs/xfs/xfs_linux.h
@@ -60,6 +60,7 @@  typedef __u32			xfs_nlink_t;
 #include <linux/list_sort.h>
 #include <linux/ratelimit.h>
 #include <linux/rhashtable.h>
+#include <linux/xattr.h>
 
 #include <asm/page.h>
 #include <asm/div64.h>
diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
index 8358a92987f9..a064b1523fa5 100644
--- a/fs/xfs/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
@@ -36,6 +36,10 @@  struct xfs_owner_info;
 struct xfs_trans_res;
 struct xfs_inobt_rec_incore;
 
+#define XFS_ATTR_NSP_FLAGS \
+	{ XFS_ATTR_ROOT,	"ROOT" }, \
+	{ XFS_ATTR_SECURE,	"SECURE" }
+
 DECLARE_EVENT_CLASS(xfs_attr_list_class,
 	TP_PROTO(struct xfs_attr_list_context *ctx),
 	TP_ARGS(ctx),
@@ -50,7 +54,7 @@  DECLARE_EVENT_CLASS(xfs_attr_list_class,
 		__field(int, count)
 		__field(int, firstu)
 		__field(int, dupcnt)
-		__field(int, flags)
+		__field(int, attr_namespace)
 	),
 	TP_fast_assign(
 		__entry->dev = VFS_I(ctx->dp)->i_sb->s_dev;
@@ -62,10 +66,10 @@  DECLARE_EVENT_CLASS(xfs_attr_list_class,
 		__entry->bufsize = ctx->bufsize;
 		__entry->count = ctx->count;
 		__entry->firstu = ctx->firstu;
-		__entry->flags = ctx->flags;
+		__entry->attr_namespace = ctx->attr_namespace;
 	),
 	TP_printk("dev %d:%d ino 0x%llx cursor h/b/o 0x%x/0x%x/%u dupcnt %u "
-		  "buffer %p size %u count %u firstu %u flags %d %s",
+		  "buffer %p size %u count %u firstu %u namespace %d %s",
 		  MAJOR(__entry->dev), MINOR(__entry->dev),
 		   __entry->ino,
 		   __entry->hashval,
@@ -76,8 +80,9 @@  DECLARE_EVENT_CLASS(xfs_attr_list_class,
 		   __entry->bufsize,
 		   __entry->count,
 		   __entry->firstu,
-		   __entry->flags,
-		   __print_flags(__entry->flags, "|", XFS_ATTR_FLAGS)
+		   __entry->attr_namespace,
+		   __print_flags(__entry->attr_namespace, "|",
+				 XFS_ATTR_NSP_FLAGS)
 	)
 )
 
@@ -174,7 +179,7 @@  TRACE_EVENT(xfs_attr_list_node_descend,
 		__field(int, count)
 		__field(int, firstu)
 		__field(int, dupcnt)
-		__field(int, flags)
+		__field(int, attr_namespace)
 		__field(u32, bt_hashval)
 		__field(u32, bt_before)
 	),
@@ -188,12 +193,12 @@  TRACE_EVENT(xfs_attr_list_node_descend,
 		__entry->bufsize = ctx->bufsize;
 		__entry->count = ctx->count;
 		__entry->firstu = ctx->firstu;
-		__entry->flags = ctx->flags;
+		__entry->attr_namespace = ctx->attr_namespace;
 		__entry->bt_hashval = be32_to_cpu(btree->hashval);
 		__entry->bt_before = be32_to_cpu(btree->before);
 	),
 	TP_printk("dev %d:%d ino 0x%llx cursor h/b/o 0x%x/0x%x/%u dupcnt %u "
-		  "buffer %p size %u count %u firstu %u flags %d %s "
+		  "buffer %p size %u count %u firstu %u namespae %d %s "
 		  "node hashval %u, node before %u",
 		  MAJOR(__entry->dev), MINOR(__entry->dev),
 		   __entry->ino,
@@ -205,8 +210,9 @@  TRACE_EVENT(xfs_attr_list_node_descend,
 		   __entry->bufsize,
 		   __entry->count,
 		   __entry->firstu,
-		   __entry->flags,
-		   __print_flags(__entry->flags, "|", XFS_ATTR_FLAGS),
+		   __entry->attr_namespace,
+		   __print_flags(__entry->attr_namespace, "|",
+				 XFS_ATTR_NSP_FLAGS),
 		   __entry->bt_hashval,
 		   __entry->bt_before)
 );
@@ -1701,7 +1707,7 @@  DECLARE_EVENT_CLASS(xfs_attr_class,
 		__field(int, namelen)
 		__field(int, valuelen)
 		__field(xfs_dahash_t, hashval)
-		__field(int, flags)
+		__field(int, attr_namespace)
 		__field(int, op_flags)
 	),
 	TP_fast_assign(
@@ -1712,11 +1718,11 @@  DECLARE_EVENT_CLASS(xfs_attr_class,
 		__entry->namelen = args->namelen;
 		__entry->valuelen = args->valuelen;
 		__entry->hashval = args->hashval;
-		__entry->flags = args->flags;
+		__entry->attr_namespace = args->attr_namespace;
 		__entry->op_flags = args->op_flags;
 	),
 	TP_printk("dev %d:%d ino 0x%llx name %.*s namelen %d valuelen %d "
-		  "hashval 0x%x flags %s op_flags %s",
+		  "hashval 0x%x namespace %s op_flags %s",
 		  MAJOR(__entry->dev), MINOR(__entry->dev),
 		  __entry->ino,
 		  __entry->namelen,
@@ -1724,7 +1730,8 @@  DECLARE_EVENT_CLASS(xfs_attr_class,
 		  __entry->namelen,
 		  __entry->valuelen,
 		  __entry->hashval,
-		  __print_flags(__entry->flags, "|", XFS_ATTR_FLAGS),
+		  __print_flags(__entry->attr_namespace, "|",
+				XFS_ATTR_NSP_FLAGS),
 		  __print_flags(__entry->op_flags, "|", XFS_DA_OP_FLAGS))
 )
 
diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
index 863e9fdec162..1d2c8615b335 100644
--- a/fs/xfs/xfs_xattr.c
+++ b/fs/xfs/xfs_xattr.c
@@ -14,7 +14,6 @@ 
 #include "xfs_acl.h"
 
 #include <linux/posix_acl_xattr.h>
-#include <linux/xattr.h>
 
 
 static int
@@ -23,7 +22,7 @@  xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
 {
 	struct xfs_da_args	args = {
 		.dp		= XFS_I(inode),
-		.flags		= handler->flags,
+		.attr_namespace	= handler->flags,
 		.name		= name,
 		.namelen	= strlen(name),
 		.value		= value,
@@ -44,7 +43,8 @@  xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
 {
 	struct xfs_da_args	args = {
 		.dp		= XFS_I(inode),
-		.flags		= handler->flags,
+		.attr_namespace	= handler->flags,
+		.attr_flags	= flags,
 		.name		= name,
 		.namelen	= strlen(name),
 		.value		= (unsigned char *)value,
@@ -52,14 +52,8 @@  xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
 	};
 	int			error;
 
-	/* Convert Linux syscall to XFS internal ATTR flags */
-	if (flags & XATTR_CREATE)
-		args.flags |= ATTR_CREATE;
-	if (flags & XATTR_REPLACE)
-		args.flags |= ATTR_REPLACE;
-
 	error = xfs_attr_set(&args);
-	if (!error && (flags & ATTR_ROOT))
+	if (!error && (handler->flags & XFS_ATTR_ROOT))
 		xfs_forget_acl(inode, name);
 	return error;
 }
@@ -73,14 +67,14 @@  static const struct xattr_handler xfs_xattr_user_handler = {
 
 static const struct xattr_handler xfs_xattr_trusted_handler = {
 	.prefix	= XATTR_TRUSTED_PREFIX,
-	.flags	= ATTR_ROOT,
+	.flags	= XFS_ATTR_ROOT,
 	.get	= xfs_xattr_get,
 	.set	= xfs_xattr_set,
 };
 
 static const struct xattr_handler xfs_xattr_security_handler = {
 	.prefix	= XATTR_SECURITY_PREFIX,
-	.flags	= ATTR_SECURE,
+	.flags	= XFS_ATTR_SECURE,
 	.get	= xfs_xattr_get,
 	.set	= xfs_xattr_set,
 };