Skip to contentSkip to conversation

use generic_*xattr routines

PATCH In review Christoph Hellwig 2 participants 11 messages Apr 30, 2008 – May 30, 2008 XFS filesystem

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 use generic_*xattr routines

Use the generic set, get and removexattr methods and supply the s_xattr array with fine-grained handlers. All XFS/Linux highlevel attr handling is rewritten from scratch and placed into fs/xfs/linux-2.6/xfs_xattr.c so that it's separated from the generic low-level code.

The code size reduction is not as big as I had hoped, but it's still a worthwile cleanup.

I didn't managed to get rid of struct attrnames yet, as it's still used to hack the Linux string prefixes into the output inside the lowest level xattr code. I have some plans to clean that bit up aswell, but that will have to wait for a while.

fs/xfs/Makefile +1 -0
Index: linux-2.6-xfs/fs/xfs/Makefile
===================================================================
@@ -97,6 +97,7 @@ xfs-y				+= $(addprefix $(XFS_LINUX)/, \
 				   xfs_lrw.o \
 				   xfs_super.o \
 				   xfs_vnode.o \
+				   xfs_xattr.o \
 				   xfs_ksyms.o) 
 
 # Objects in support/
fs/xfs/linux-2.6/xfs_iops.c +10 -102

143 lines not on this page · raw message

fs/xfs/linux-2.6/xfs_xattr.c new file +266 -0

266 lines not on this page · raw message

fs/xfs/xfs_attr.c +0 -272

281 lines not on this page · raw message

fs/xfs/xfs_attr.h +0 -17
Index: linux-2.6-xfs/fs/xfs/xfs_attr.h
===================================================================
@@ -38,30 +38,14 @@
 struct cred;
 struct xfs_attr_list_context;
 
-typedef int (*attrset_t)(bhv_vnode_t *, char *, void *, size_t, int);
-typedef int (*attrget_t)(bhv_vnode_t *, char *, void *, size_t, int);
-typedef int (*attrremove_t)(bhv_vnode_t *, char *, int);
-typedef int (*attrexists_t)(bhv_vnode_t *);
-
 typedef struct attrnames {
 	char *		attr_name;
 	unsigned int	attr_namelen;
-	unsigned int	attr_flag;
-	attrget_t	attr_get;
-	attrset_t	attr_set;
-	attrremove_t	attr_remove;
-	attrexists_t	attr_exists;
 } attrnames_t;
 
-#define ATTR_NAMECOUNT	4
 extern struct attrnames attr_user;
 extern struct attrnames attr_secure;
-extern struct attrnames attr_system;
 extern struct attrnames attr_trusted;
-extern struct attrnames *attr_namespaces[ATTR_NAMECOUNT];
-
-extern attrnames_t *attr_lookup_namespace(char *, attrnames_t **, int);
-extern int attr_generic_list(bhv_vnode_t *, void *, size_t, int, ssize_t *);
 
 #define ATTR_DONTFOLLOW	0x0001	/* -- unused, from IRIX -- */
 #define ATTR_ROOT	0x0002	/* use attrs in root (trusted) namespace */
@@ -69,7 +53,6 @@ extern int attr_generic_list(bhv_vnode_t
 #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 ATTR_SYSTEM	0x0100	/* use attrs in system (pseudo) namespace */
 
 #define ATTR_KERNACCESS	0x0400	/* [kernel] iaccess, inode held io-locked */
 #define ATTR_KERNOTIME	0x1000	/* [kernel] don't update inode timestamps */
fs/xfs/linux-2.6/xfs_iops.h +1 -0
Index: linux-2.6-xfs/fs/xfs/linux-2.6/xfs_iops.h
===================================================================
@@ -26,6 +26,7 @@ extern const struct file_operations xfs_
 extern const struct file_operations xfs_dir_file_operations;
 extern const struct file_operations xfs_invis_file_operations;
 
+extern ssize_t xfs_vn_listxattr(struct dentry *, char *data, size_t size);
 
 struct xfs_inode;
 extern void xfs_ichgtime(struct xfs_inode *, int);
fs/xfs/linux-2.6/xfs_super.c +1 -0
Index: linux-2.6-xfs/fs/xfs/linux-2.6/xfs_super.c
===================================================================
@@ -1328,6 +1328,7 @@ xfs_fs_fill_super(
 		goto fail_vfsop;
 
 	sb_min_blocksize(sb, BBSIZE);
+	sb->s_xattr = xfs_xattr_handlers;
 	sb->s_export_op = &xfs_export_operations;
 	sb->s_qcop = &xfs_quotactl_operations;
 	sb->s_op = &xfs_super_operations;
fs/xfs/linux-2.6/xfs_super.h +1 -0
Index: linux-2.6-xfs/fs/xfs/linux-2.6/xfs_super.h
===================================================================
@@ -84,6 +84,7 @@ extern void xfs_blkdev_put(struct block_
 extern void xfs_blkdev_issue_flush(struct xfs_buftarg *);
 
 extern const struct export_operations xfs_export_operations;
+extern struct xattr_handler *xfs_xattr_handlers[];
 
 #define XFS_M(sb)		((struct xfs_mount *)((sb)->s_fs_info))
 
#1 lore raw
Quoted 5 lines · Christoph Hellwig

Use the generic set, get and removexattr methods and supply the s_xattr array with fine-grained handlers. All XFS/Linux highlevel attr handling is rewritten from scratch and placed into fs/xfs/linux-2.6/xfs_xattr.c so that it's separated from the generic low-level code.

Quoted 7 lines

The code size reduction is not as big as I had hoped, but it's still a worthwile cleanup.

I didn't managed to get rid of struct attrnames yet, as it's still used to hack the Linux string prefixes into the output inside the lowest level xattr code. I have some plans to clean that bit up aswell, but that will have to wait for a while.

Updated on top of the case-insensitive filename changes:

fs/xfs/Makefile +1 -0
Index: linux-2.6-xfs/fs/xfs/Makefile
===================================================================
@@ -97,6 +97,7 @@ xfs-y				+= $(addprefix $(XFS_LINUX)/, \
 				   xfs_lrw.o \
 				   xfs_super.o \
 				   xfs_vnode.o \
+				   xfs_xattr.o \
 				   xfs_ksyms.o) 
 
 # Objects in support/
fs/xfs/linux-2.6/xfs_iops.c +13 -105

156 lines not on this page · raw message

fs/xfs/linux-2.6/xfs_xattr.c new file +266 -0

266 lines not on this page · raw message

fs/xfs/xfs_attr.c +0 -272

281 lines not on this page · raw message

fs/xfs/xfs_attr.h +0 -17
Index: linux-2.6-xfs/fs/xfs/xfs_attr.h
===================================================================
@@ -38,30 +38,14 @@
 struct cred;
 struct xfs_attr_list_context;
 
-typedef int (*attrset_t)(bhv_vnode_t *, char *, void *, size_t, int);
-typedef int (*attrget_t)(bhv_vnode_t *, char *, void *, size_t, int);
-typedef int (*attrremove_t)(bhv_vnode_t *, char *, int);
-typedef int (*attrexists_t)(bhv_vnode_t *);
-
 typedef struct attrnames {
 	char *		attr_name;
 	unsigned int	attr_namelen;
-	unsigned int	attr_flag;
-	attrget_t	attr_get;
-	attrset_t	attr_set;
-	attrremove_t	attr_remove;
-	attrexists_t	attr_exists;
 } attrnames_t;
 
-#define ATTR_NAMECOUNT	4
 extern struct attrnames attr_user;
 extern struct attrnames attr_secure;
-extern struct attrnames attr_system;
 extern struct attrnames attr_trusted;
-extern struct attrnames *attr_namespaces[ATTR_NAMECOUNT];
-
-extern attrnames_t *attr_lookup_namespace(char *, attrnames_t **, int);
-extern int attr_generic_list(bhv_vnode_t *, void *, size_t, int, ssize_t *);
 
 #define ATTR_DONTFOLLOW	0x0001	/* -- unused, from IRIX -- */
 #define ATTR_ROOT	0x0002	/* use attrs in root (trusted) namespace */
@@ -69,7 +53,6 @@ extern int attr_generic_list(bhv_vnode_t
 #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 ATTR_SYSTEM	0x0100	/* use attrs in system (pseudo) namespace */
 
 #define ATTR_KERNACCESS	0x0400	/* [kernel] iaccess, inode held io-locked */
 #define ATTR_KERNOTIME	0x1000	/* [kernel] don't update inode timestamps */
fs/xfs/linux-2.6/xfs_iops.h +1 -0
Index: linux-2.6-xfs/fs/xfs/linux-2.6/xfs_iops.h
===================================================================
@@ -27,6 +27,7 @@ extern const struct file_operations xfs_
 extern const struct file_operations xfs_dir_file_operations;
 extern const struct file_operations xfs_invis_file_operations;
 
+extern ssize_t xfs_vn_listxattr(struct dentry *, char *data, size_t size);
 
 struct xfs_inode;
 extern void xfs_ichgtime(struct xfs_inode *, int);
fs/xfs/linux-2.6/xfs_super.c +1 -0
Index: linux-2.6-xfs/fs/xfs/linux-2.6/xfs_super.c
===================================================================
@@ -1767,6 +1767,7 @@ xfs_fs_fill_super(
 		goto out_free_mp;
 
 	sb_min_blocksize(sb, BBSIZE);
+	sb->s_xattr = xfs_xattr_handlers;
 	sb->s_export_op = &xfs_export_operations;
 	sb->s_qcop = &xfs_quotactl_operations;
 	sb->s_op = &xfs_super_operations;
fs/xfs/linux-2.6/xfs_super.h +1 -0
Index: linux-2.6-xfs/fs/xfs/linux-2.6/xfs_super.h
===================================================================
@@ -81,6 +81,7 @@ extern void xfs_flush_device(struct xfs_
 extern void xfs_blkdev_issue_flush(struct xfs_buftarg *);
 
 extern const struct export_operations xfs_export_operations;
+extern struct xattr_handler *xfs_xattr_handlers[];
 
 #define XFS_M(sb)		((struct xfs_mount *)((sb)->s_fs_info))
 
#2 lore raw

Looking at this now and will reply tomorrow.

--Tim

Quoted 835 lines · Christoph Hellwig
Quoted 5 lines · Christoph Hellwig

Use the generic set, get and removexattr methods and supply the s_xattr array with fine-grained handlers. All XFS/Linux highlevel attr handling is rewritten from scratch and placed into fs/xfs/linux-2.6/xfs_xattr.c so that it's separated from the generic low-level code.

Quoted 7 lines

The code size reduction is not as big as I had hoped, but it's still a worthwile cleanup.

I didn't managed to get rid of struct attrnames yet, as it's still used to hack the Linux string prefixes into the output inside the lowest level xattr code. I have some plans to clean that bit up aswell, but that will have to wait for a while.

Updated on top of the case-insensitive filename changes:

Index: linux-2.6-xfs/fs/xfs/Makefile
===================================================================

fs/xfs/Makefile +1 -0
@@ -97,6 +97,7 @@ xfs-y				+= $(addprefix $(XFS_LINUX)/, \
 				   xfs_lrw.o \
 				   xfs_super.o \
 				   xfs_vnode.o \
+				   xfs_xattr.o \
 				   xfs_ksyms.o) 
 
 # Objects in support/

Index: linux-2.6-xfs/fs/xfs/linux-2.6/xfs_iops.c
===================================================================

fs/xfs/linux-2.6/xfs_iops.c +13 -105
@@ -282,7 +282,7 @@ xfs_vn_mknod(
 	struct xfs_inode *ip = NULL;
 	xfs_acl_t	*default_acl = NULL;
 	struct xfs_name	name;
-	attrexists_t	test_default_acl = _ACL_DEFAULT_EXISTS;
+	int (*test_default_acl)(struct inode *) = _ACL_DEFAULT_EXISTS;
 	int		error;
 
 	/*
@@ -771,98 +771,6 @@ xfs_vn_truncate(
 	WARN_ON(error);
 }
 
-STATIC int
-xfs_vn_setxattr(
-	struct dentry	*dentry,
-	const char	*name,
-	const void	*data,
-	size_t		size,
-	int		flags)
-{
-	bhv_vnode_t	*vp = vn_from_inode(dentry->d_inode);
-	char		*attr = (char *)name;
-	attrnames_t	*namesp;
-	int		xflags = 0;
-
-	namesp = attr_lookup_namespace(attr, attr_namespaces, ATTR_NAMECOUNT);
-	if (!namesp)
-		return -EOPNOTSUPP;
-	attr += namesp->attr_namelen;
-
-	/* Convert Linux syscall to XFS internal ATTR flags */
-	if (flags & XATTR_CREATE)
-		xflags |= ATTR_CREATE;
-	if (flags & XATTR_REPLACE)
-		xflags |= ATTR_REPLACE;
-	xflags |= namesp->attr_flag;
-	return namesp->attr_set(vp, attr, (void *)data, size, xflags);
-}
-
-STATIC ssize_t
-xfs_vn_getxattr(
-	struct dentry	*dentry,
-	const char	*name,
-	void		*data,
-	size_t		size)
-{
-	bhv_vnode_t	*vp = vn_from_inode(dentry->d_inode);
-	char		*attr = (char *)name;
-	attrnames_t	*namesp;
-	int		xflags = 0;
-
-	namesp = attr_lookup_namespace(attr, attr_namespaces, ATTR_NAMECOUNT);
-	if (!namesp)
-		return -EOPNOTSUPP;
-	attr += namesp->attr_namelen;
-
-	/* Convert Linux syscall to XFS internal ATTR flags */
-	if (!size) {
-		xflags |= ATTR_KERNOVAL;
-		data = NULL;
-	}
-	xflags |= namesp->attr_flag;
-	return namesp->attr_get(vp, attr, (void *)data, size, xflags);
-}
-
-STATIC ssize_t
-xfs_vn_listxattr(
-	struct dentry		*dentry,
-	char			*data,
-	size_t			size)
-{
-	bhv_vnode_t		*vp = vn_from_inode(dentry->d_inode);
-	int			error, xflags = ATTR_KERNAMELS;
-	ssize_t			result;
-
-	if (!size)
-		xflags |= ATTR_KERNOVAL;
-	xflags |= capable(CAP_SYS_ADMIN) ? ATTR_KERNFULLS : ATTR_KERNORMALS;
-
-	error = attr_generic_list(vp, data, size, xflags, &result);
-	if (error < 0)
-		return error;
-	return result;
-}
-
-STATIC int
-xfs_vn_removexattr(
-	struct dentry	*dentry,
-	const char	*name)
-{
-	bhv_vnode_t	*vp = vn_from_inode(dentry->d_inode);
-	char		*attr = (char *)name;
-	attrnames_t	*namesp;
-	int		xflags = 0;
-
-	namesp = attr_lookup_namespace(attr, attr_namespaces, ATTR_NAMECOUNT);
-	if (!namesp)
-		return -EOPNOTSUPP;
-	attr += namesp->attr_namelen;
-
-	xflags |= namesp->attr_flag;
-	return namesp->attr_remove(vp, attr, xflags);
-}
-
 STATIC long
 xfs_vn_fallocate(
 	struct inode	*inode,
@@ -910,10 +818,10 @@ const struct inode_operations xfs_inode_
 	.truncate		= xfs_vn_truncate,
 	.getattr		= xfs_vn_getattr,
 	.setattr		= xfs_vn_setattr,
-	.setxattr		= xfs_vn_setxattr,
-	.getxattr		= xfs_vn_getxattr,
+	.setxattr		= generic_setxattr,
+	.getxattr		= generic_getxattr,
+	.removexattr		= generic_removexattr,
 	.listxattr		= xfs_vn_listxattr,
-	.removexattr		= xfs_vn_removexattr,
 	.fallocate		= xfs_vn_fallocate,
 };
 
@@ -930,10 +838,10 @@ const struct inode_operations xfs_dir_in
 	.permission		= xfs_vn_permission,
 	.getattr		= xfs_vn_getattr,
 	.setattr		= xfs_vn_setattr,
-	.setxattr		= xfs_vn_setxattr,
-	.getxattr		= xfs_vn_getxattr,
+	.setxattr		= generic_setxattr,
+	.getxattr		= generic_getxattr,
+	.removexattr		= generic_removexattr,
 	.listxattr		= xfs_vn_listxattr,
-	.removexattr		= xfs_vn_removexattr,
 };
 
 const struct inode_operations xfs_dir_ci_inode_operations = {
@@ -949,10 +857,10 @@ const struct inode_operations xfs_dir_ci
 	.permission		= xfs_vn_permission,
 	.getattr		= xfs_vn_getattr,
 	.setattr		= xfs_vn_setattr,
-	.setxattr		= xfs_vn_setxattr,
-	.getxattr		= xfs_vn_getxattr,
+	.setxattr		= generic_setxattr,
+	.getxattr		= generic_getxattr,
+	.removexattr		= generic_removexattr,
 	.listxattr		= xfs_vn_listxattr,
-	.removexattr		= xfs_vn_removexattr,
 };
 
 const struct inode_operations xfs_symlink_inode_operations = {
@@ -962,8 +870,8 @@ const struct inode_operations xfs_symlin
 	.permission		= xfs_vn_permission,
 	.getattr		= xfs_vn_getattr,
 	.setattr		= xfs_vn_setattr,
-	.setxattr		= xfs_vn_setxattr,
-	.getxattr		= xfs_vn_getxattr,
+	.setxattr		= generic_setxattr,
+	.getxattr		= generic_getxattr,
+	.removexattr		= generic_removexattr,
 	.listxattr		= xfs_vn_listxattr,
-	.removexattr		= xfs_vn_removexattr,
 };

Index: linux-2.6-xfs/fs/xfs/linux-2.6/xfs_xattr.c
===================================================================

fs/xfs/linux-2.6/xfs_xattr.c new file +266 -0
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2008 Christoph Hellwig.
+ *	Released under GPL v2.
+ */
+
+#include "xfs.h"
+#include "xfs_attr.h"
+#include "xfs_acl.h"
+#include "xfs_vnodeops.h"
+
+#include <linux/posix_acl_xattr.h>
+#include <linux/xattr.h>
+
+
+/*
+ * ACL handling.  Should eventually be moved into xfs_acl.c
+ */
+
+static int
+xfs_decode_acl(const char *name)
+{
+	if (strcmp(name, "posix_acl_access") == 0)
+		return _ACL_TYPE_ACCESS;
+	else if (strcmp(name, "posix_acl_default") == 0)
+		return _ACL_TYPE_DEFAULT;
+	return -EINVAL;
+}
+
+static int
+xfs_xattr_system_get(struct inode *inode, const char *name,
+		void *buffer, size_t size)
+{
+	int acl;
+
+	acl = xfs_decode_acl(name);
+	if (acl < 0)
+		return acl;
+
+	return xfs_acl_vget(inode, buffer, size, acl);
+}
+
+static int
+xfs_xattr_system_set(struct inode *inode, const char *name,
+		const void *value, size_t size, int flags)
+{
+	int error, acl;
+
+	acl = xfs_decode_acl(name);
+	if (acl < 0)
+		return acl;
+	if (flags & XATTR_CREATE)
+		return -EINVAL;
+
+	if (!value)
+		return xfs_acl_vremove(inode, acl);
+
+	error = xfs_acl_vset(inode, (void *)value, size, acl);
+	if (!error)
+		vn_revalidate(inode);
+	return error;
+}
+
+static struct xattr_handler xfs_xattr_system_handler = {
+	.prefix	= XATTR_SYSTEM_PREFIX,
+	.get	= xfs_xattr_system_get,
+	.set	= xfs_xattr_system_set,
+};
+
+
+/*
+ * Real xattr handling.  The only difference between the namespaces is
+ * a flag passed to the low-level attr code.
+ */
+
+static int
+__xfs_xattr_get(struct inode *inode, const char *name,
+		void *value, size_t size, int xflags)
+{
+	struct xfs_inode *ip = XFS_I(inode);
+	int error, asize = size;
+
+	if (strcmp(name, "") == 0)
+		return -EINVAL;
+
+	/* Convert Linux syscall to XFS internal ATTR flags */
+	if (!size) {
+		xflags |= ATTR_KERNOVAL;
+		value = NULL;
+	}
+
+	error = -xfs_attr_get(ip, name, value, &asize, xflags);
+	if (error)
+		return error;
+	return asize;
+}
+
+static int
+__xfs_xattr_set(struct inode *inode, const char *name, const void *value,
+		size_t size, int flags, int xflags)
+{
+	struct xfs_inode *ip = XFS_I(inode);
+
+	if (strcmp(name, "") == 0)
+		return -EINVAL;
+
+	/* Convert Linux syscall to XFS internal ATTR flags */
+	if (flags & XATTR_CREATE)
+		xflags |= ATTR_CREATE;
+	if (flags & XATTR_REPLACE)
+		xflags |= ATTR_REPLACE;
+
+	if (!value)
+		return -xfs_attr_remove(ip, name, xflags);
+	return -xfs_attr_set(ip, name, (void *)value, size, xflags);
+}
+
+static int
+xfs_xattr_user_get(struct inode *inode, const char *name,
+		void *value, size_t size)
+{
+	return __xfs_xattr_get(inode, name, value, size, 0);
+}
+
+static int
+xfs_xattr_user_set(struct inode *inode, const char *name,
+		const void *value, size_t size, int flags)
+{
+	return __xfs_xattr_set(inode, name, value, size, flags, 0);
+}
+
+struct attrnames attr_user = {
+	.attr_name	= "user.",
+	.attr_namelen	= sizeof("user.") - 1,
+};
+
+static struct xattr_handler xfs_xattr_user_handler = {
+	.prefix	= XATTR_USER_PREFIX,
+	.get	= xfs_xattr_user_get,
+	.set	= xfs_xattr_user_set,
+};
+
+
+static int
+xfs_xattr_trusted_get(struct inode *inode, const char *name,
+		void *value, size_t size)
+{
+	return __xfs_xattr_get(inode, name, value, size, ATTR_ROOT);
+}
+
+static int
+xfs_xattr_trusted_set(struct inode *inode, const char *name,
+		const void *value, size_t size, int flags)
+{
+	return __xfs_xattr_set(inode, name, value, size, flags, ATTR_ROOT);
+}
+
+struct attrnames attr_trusted = {
+	.attr_name	= "trusted.",
+	.attr_namelen	= sizeof("trusted.") - 1,
+};
+
+static struct xattr_handler xfs_xattr_trusted_handler = {
+	.prefix	= XATTR_TRUSTED_PREFIX,
+	.get	= xfs_xattr_trusted_get,
+	.set	= xfs_xattr_trusted_set,
+};
+
+
+static int
+xfs_xattr_secure_get(struct inode *inode, const char *name,
+		void *value, size_t size)
+{
+	return __xfs_xattr_get(inode, name, value, size, ATTR_SECURE);
+}
+
+static int
+xfs_xattr_secure_set(struct inode *inode, const char *name,
+		const void *value, size_t size, int flags)
+{
+	return __xfs_xattr_set(inode, name, value, size, flags, ATTR_SECURE);
+}
+
+struct attrnames attr_secure = {
+	.attr_name	= "security.",
+	.attr_namelen	= sizeof("security.") - 1,
+};
+
+static struct xattr_handler xfs_xattr_security_handler = {
+	.prefix	= XATTR_SECURITY_PREFIX,
+	.get	= xfs_xattr_secure_get,
+	.set	= xfs_xattr_secure_set,
+};
+
+
+struct xattr_handler *xfs_xattr_handlers[] = {
+	&xfs_xattr_user_handler,
+	&xfs_xattr_trusted_handler,
+	&xfs_xattr_security_handler,
+	&xfs_xattr_system_handler,
+	NULL
+};
+
+static int
+list_one_attr(const char *name, const size_t len, void *data,
+		size_t size, ssize_t *result)
+{
+	char *p = data + *result;
+
+	*result += len;
+	if (!size)
+		return 0;
+	if (*result > size)
+		return -ERANGE;
+
+	strcpy(p, name);
+	p += len;
+	return 0;
+}
+
+ssize_t
+xfs_vn_listxattr(struct dentry *dentry, char *data, size_t size)
+{
+	struct inode		*inode = dentry->d_inode;
+	struct xfs_inode	*ip = XFS_I(inode);
+	attrlist_cursor_kern_t	cursor = { 0 };
+	int			error, xflags;
+	ssize_t			result;
+
+	xflags = ATTR_KERNAMELS;
+	if (!size)
+		xflags |= ATTR_KERNOVAL;
+
+	if (capable(CAP_SYS_ADMIN))
+		xflags |= ATTR_KERNFULLS;
+	else
+		xflags |= ATTR_KERNORMALS;
+
+
+	/*
+	 * First read the regular on-disk attributes.
+	 */
+	result = -xfs_attr_list(ip, data, size, xflags, &cursor);
+	if (result < 0)
+		return result;
+
+	/*
+	 * Then add the two synthetic ACL attributes.
+	 */
+	if (xfs_acl_vhasacl_access(inode)) {
+		error = list_one_attr(POSIX_ACL_XATTR_ACCESS,
+				strlen(POSIX_ACL_XATTR_ACCESS) + 1,
+				data, size, &result);
+		if (error)
+			return error;
+	}
+
+	if (xfs_acl_vhasacl_default(inode)) {
+		error = list_one_attr(POSIX_ACL_XATTR_DEFAULT,
+				strlen(POSIX_ACL_XATTR_DEFAULT) + 1,
+				data, size, &result);
+		if (error)
+			return error;
+	}
+
+	return result;
+}

Index: linux-2.6-xfs/fs/xfs/xfs_attr.c
===================================================================

fs/xfs/xfs_attr.c +0 -272
@@ -57,11 +57,6 @@
  * Provide the external interfaces to manage attribute lists.
  */
 
-#define ATTR_SYSCOUNT	2
-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.
  *========================================================================*/
@@ -2378,270 +2373,3 @@ xfs_attr_trace_enter(int type, char *whe
 		(void *)a13, (void *)a14, (void *)a15);
 }
 #endif	/* XFS_ATTR_TRACE */
-
-
-/*========================================================================
- * System (pseudo) namespace attribute interface routines.
- *========================================================================*/
-
-STATIC int
-posix_acl_access_set(
-	bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
-{
-	return xfs_acl_vset(vp, data, size, _ACL_TYPE_ACCESS);
-}
-
-STATIC int
-posix_acl_access_remove(
-	bhv_vnode_t *vp, char *name, int xflags)
-{
-	return xfs_acl_vremove(vp, _ACL_TYPE_ACCESS);
-}
-
-STATIC int
-posix_acl_access_get(
-	bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
-{
-	return xfs_acl_vget(vp, data, size, _ACL_TYPE_ACCESS);
-}
-
-STATIC int
-posix_acl_access_exists(
-	bhv_vnode_t *vp)
-{
-	return xfs_acl_vhasacl_access(vp);
-}
-
-STATIC int
-posix_acl_default_set(
-	bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
-{
-	return xfs_acl_vset(vp, data, size, _ACL_TYPE_DEFAULT);
-}
-
-STATIC int
-posix_acl_default_get(
-	bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
-{
-	return xfs_acl_vget(vp, data, size, _ACL_TYPE_DEFAULT);
-}
-
-STATIC int
-posix_acl_default_remove(
-	bhv_vnode_t *vp, char *name, int xflags)
-{
-	return xfs_acl_vremove(vp, _ACL_TYPE_DEFAULT);
-}
-
-STATIC int
-posix_acl_default_exists(
-	bhv_vnode_t *vp)
-{
-	return xfs_acl_vhasacl_default(vp);
-}
-
-static struct attrnames posix_acl_access = {
-	.attr_name	= "posix_acl_access",
-	.attr_namelen	= sizeof("posix_acl_access") - 1,
-	.attr_get	= posix_acl_access_get,
-	.attr_set	= posix_acl_access_set,
-	.attr_remove	= posix_acl_access_remove,
-	.attr_exists	= posix_acl_access_exists,
-};
-
-static struct attrnames posix_acl_default = {
-	.attr_name	= "posix_acl_default",
-	.attr_namelen	= sizeof("posix_acl_default") - 1,
-	.attr_get	= posix_acl_default_get,
-	.attr_set	= posix_acl_default_set,
-	.attr_remove	= posix_acl_default_remove,
-	.attr_exists	= posix_acl_default_exists,
-};
-
-static struct attrnames *attr_system_names[] =
-	{ &posix_acl_access, &posix_acl_default };
-
-
-/*========================================================================
- * Namespace-prefix-style attribute name interface routines.
- *========================================================================*/
-
-STATIC int
-attr_generic_set(
-	bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
-{
-	return -xfs_attr_set(xfs_vtoi(vp), name, data, size, xflags);
-}
-
-STATIC int
-attr_generic_get(
-	bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
-{
-	int	error, asize = size;
-
-	error = xfs_attr_get(xfs_vtoi(vp), name, data, &asize, xflags);
-	if (!error)
-		return asize;
-	return -error;
-}
-
-STATIC int
-attr_generic_remove(
-	bhv_vnode_t *vp, char *name, int xflags)
-{
-	return -xfs_attr_remove(xfs_vtoi(vp), name, xflags);
-}
-
-STATIC int
-attr_generic_listadd(
-	attrnames_t		*prefix,
-	attrnames_t		*namesp,
-	void			*data,
-	size_t			size,
-	ssize_t			*result)
-{
-	char			*p = data + *result;
-
-	*result += prefix->attr_namelen;
-	*result += namesp->attr_namelen + 1;
-	if (!size)
-		return 0;
-	if (*result > size)
-		return -ERANGE;
-	strcpy(p, prefix->attr_name);
-	p += prefix->attr_namelen;
-	strcpy(p, namesp->attr_name);
-	p += namesp->attr_namelen + 1;
-	return 0;
-}
-
-STATIC int
-attr_system_list(
-	bhv_vnode_t		*vp,
-	void			*data,
-	size_t			size,
-	ssize_t			*result)
-{
-	attrnames_t		*namesp;
-	int			i, error = 0;
-
-	for (i = 0; i < ATTR_SYSCOUNT; i++) {
-		namesp = attr_system_names[i];
-		if (!namesp->attr_exists || !namesp->attr_exists(vp))
-			continue;
-		error = attr_generic_listadd(&attr_system, namesp,
-						data, size, result);
-		if (error)
-			break;
-	}
-	return error;
-}
-
-int
-attr_generic_list(
-	bhv_vnode_t *vp, void *data, size_t size, int xflags, ssize_t *result)
-{
-	attrlist_cursor_kern_t	cursor = { 0 };
-	int			error;
-
-	error = xfs_attr_list(xfs_vtoi(vp), data, size, xflags, &cursor);
-	if (error > 0)
-		return -error;
-	*result = -error;
-	return attr_system_list(vp, data, size, result);
-}
-
-attrnames_t *
-attr_lookup_namespace(
-	char			*name,
-	struct attrnames	**names,
-	int			nnames)
-{
-	int			i;
-
-	for (i = 0; i < nnames; i++)
-		if (!strncmp(name, names[i]->attr_name, names[i]->attr_namelen))
-			return names[i];
-	return NULL;
-}
-
-STATIC int
-attr_system_set(
-	bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
-{
-	attrnames_t	*namesp;
-	int		error;
-
-	if (xflags & ATTR_CREATE)
-		return -EINVAL;
-
-	namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT);
-	if (!namesp)
-		return -EOPNOTSUPP;
-	error = namesp->attr_set(vp, name, data, size, xflags);
-	if (!error)
-		error = vn_revalidate(vp);
-	return error;
-}
-
-STATIC int
-attr_system_get(
-	bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
-{
-	attrnames_t	*namesp;
-
-	namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT);
-	if (!namesp)
-		return -EOPNOTSUPP;
-	return namesp->attr_get(vp, name, data, size, xflags);
-}
-
-STATIC int
-attr_system_remove(
-	bhv_vnode_t *vp, char *name, int xflags)
-{
-	attrnames_t	*namesp;
-
-	namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT);
-	if (!namesp)
-		return -EOPNOTSUPP;
-	return namesp->attr_remove(vp, name, xflags);
-}
-
-struct attrnames attr_system = {
-	.attr_name	= "system.",
-	.attr_namelen	= sizeof("system.") - 1,
-	.attr_flag	= ATTR_SYSTEM,
-	.attr_get	= attr_system_get,
-	.attr_set	= attr_system_set,
-	.attr_remove	= attr_system_remove,
-};
-
-struct attrnames attr_trusted = {
-	.attr_name	= "trusted.",
-	.attr_namelen	= sizeof("trusted.") - 1,
-	.attr_flag	= ATTR_ROOT,
-	.attr_get	= attr_generic_get,
-	.attr_set	= attr_generic_set,
-	.attr_remove	= attr_generic_remove,
-};
-
-struct attrnames attr_secure = {
-	.attr_name	= "security.",
-	.attr_namelen	= sizeof("security.") - 1,
-	.attr_flag	= ATTR_SECURE,
-	.attr_get	= attr_generic_get,
-	.attr_set	= attr_generic_set,
-	.attr_remove	= attr_generic_remove,
-};
-
-struct attrnames attr_user = {
-	.attr_name	= "user.",
-	.attr_namelen	= sizeof("user.") - 1,
-	.attr_get	= attr_generic_get,
-	.attr_set	= attr_generic_set,
-	.attr_remove	= attr_generic_remove,
-};
-
-struct attrnames *attr_namespaces[] =
-	{ &attr_system, &attr_trusted, &attr_secure, &attr_user };

Index: linux-2.6-xfs/fs/xfs/xfs_attr.h
===================================================================

fs/xfs/xfs_attr.h +0 -17
@@ -38,30 +38,14 @@
 struct cred;
 struct xfs_attr_list_context;
 
-typedef int (*attrset_t)(bhv_vnode_t *, char *, void *, size_t, int);
-typedef int (*attrget_t)(bhv_vnode_t *, char *, void *, size_t, int);
-typedef int (*attrremove_t)(bhv_vnode_t *, char *, int);
-typedef int (*attrexists_t)(bhv_vnode_t *);
-
 typedef struct attrnames {
 	char *		attr_name;
 	unsigned int	attr_namelen;
-	unsigned int	attr_flag;
-	attrget_t	attr_get;
-	attrset_t	attr_set;
-	attrremove_t	attr_remove;
-	attrexists_t	attr_exists;
 } attrnames_t;
 
-#define ATTR_NAMECOUNT	4
 extern struct attrnames attr_user;
 extern struct attrnames attr_secure;
-extern struct attrnames attr_system;
 extern struct attrnames attr_trusted;
-extern struct attrnames *attr_namespaces[ATTR_NAMECOUNT];
-
-extern attrnames_t *attr_lookup_namespace(char *, attrnames_t **, int);
-extern int attr_generic_list(bhv_vnode_t *, void *, size_t, int, ssize_t *);
 
 #define ATTR_DONTFOLLOW	0x0001	/* -- unused, from IRIX -- */
 #define ATTR_ROOT	0x0002	/* use attrs in root (trusted) namespace */
@@ -69,7 +53,6 @@ extern int attr_generic_list(bhv_vnode_t
 #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 ATTR_SYSTEM	0x0100	/* use attrs in system (pseudo) namespace */
 
 #define ATTR_KERNACCESS	0x0400	/* [kernel] iaccess, inode held io-locked */
 #define ATTR_KERNOTIME	0x1000	/* [kernel] don't update inode timestamps */

Index: linux-2.6-xfs/fs/xfs/linux-2.6/xfs_iops.h
===================================================================

fs/xfs/linux-2.6/xfs_iops.h +1 -0
@@ -27,6 +27,7 @@ extern const struct file_operations xfs_
 extern const struct file_operations xfs_dir_file_operations;
 extern const struct file_operations xfs_invis_file_operations;
 
+extern ssize_t xfs_vn_listxattr(struct dentry *, char *data, size_t size);
 
 struct xfs_inode;
 extern void xfs_ichgtime(struct xfs_inode *, int);

Index: linux-2.6-xfs/fs/xfs/linux-2.6/xfs_super.c
===================================================================

fs/xfs/linux-2.6/xfs_super.c +1 -0
@@ -1767,6 +1767,7 @@ xfs_fs_fill_super(
 		goto out_free_mp;
 
 	sb_min_blocksize(sb, BBSIZE);
+	sb->s_xattr = xfs_xattr_handlers;
 	sb->s_export_op = &xfs_export_operations;
 	sb->s_qcop = &xfs_quotactl_operations;
 	sb->s_op = &xfs_super_operations;

Index: linux-2.6-xfs/fs/xfs/linux-2.6/xfs_super.h
===================================================================

fs/xfs/linux-2.6/xfs_super.h +1 -0
@@ -81,6 +81,7 @@ extern void xfs_flush_device(struct xfs_
 extern void xfs_blkdev_issue_flush(struct xfs_buftarg *);
 
 extern const struct export_operations xfs_export_operations;
+extern struct xattr_handler *xfs_xattr_handlers[];
 
 #define XFS_M(sb)		((struct xfs_mount *)((sb)->s_fs_info))
 
#3 lore raw
In reply to Christoph Hellwig

Hi Christoph,

Looks reasonable to me.

In list_one_attr(), which looks based on attr_generic_listadd(), it does a final:

fs/xfs/linux-2.6/xfs_xattr.c line 216

Quoted 1 line
fs/xfs/linux-2.6/xfs_xattr.c new file +1 -0
+	p += len;

which seems useless.

An aside, I noticed in passing (which was in existing code), how we call vn_revalidate
in xfs_xattr_system_set(). I presume this is because we call xfs_acl_setmode() in xfs_acl_vset() when we want to sync the mode bits to the ACL.
If this is the case, then I think it would have been clearer to put vn_revalidate() in the vicinity of xfs_acl_setmode(). Or is there some other reason?

I'll test it out.

Thanks,
Tim.

Quoted 9 lines · Christoph Hellwig
Quoted 8 lines · Christoph Hellwig

Use the generic set, get and removexattr methods and supply the s_xattr array with fine-grained handlers. All XFS/Linux highlevel attr handling is rewritten from scratch and placed into fs/xfs/linux-2.6/xfs_xattr.c so that it's separated from the generic low-level code.

The code size reduction is not as big as I had hoped, but it's still a worthwile cleanup.

Quoted 8 lines
Quoted 4 lines

I didn't managed to get rid of struct attrnames yet, as it's still used to hack the Linux string prefixes into the output inside the lowest level xattr code. I have some plans to clean that bit up aswell, but that will have to wait for a while.

Updated on top of the case-insensitive filename changes:

Just my notes (for my reference)...

fs/xfs/Makefile xfs-y += $(addprefix $(XFS_LINUX)/, \ · line 102

Quoted 13 lines

Index: linux-2.6-xfs/fs/xfs/Makefile
===================================================================

fs/xfs/Makefile +1 -0
@@ -97,6 +97,7 @@ xfs-y				+= $(addprefix $(XFS_LINUX)/, \
 				   xfs_lrw.o \
 				   xfs_super.o \
 				   xfs_vnode.o \
+				   xfs_xattr.o \
 				   xfs_ksyms.o) 
 

Okay adding in a linux-2.6/xfs_xattr.c
(slightly different name than xfs_attr.c)

Quoted 15 lines
fs/xfs/Makefile +0 -0
 # Objects in support/

Index: linux-2.6-xfs/fs/xfs/linux-2.6/xfs_iops.c
===================================================================

fs/xfs/linux-2.6/xfs_iops.c +1 -1
@@ -282,7 +282,7 @@ xfs_vn_mknod(
 	struct xfs_inode *ip = NULL;
 	xfs_acl_t	*default_acl = NULL;
 	struct xfs_name	name;
-	attrexists_t	test_default_acl = _ACL_DEFAULT_EXISTS;
+	int (*test_default_acl)(struct inode *) = _ACL_DEFAULT_EXISTS;
 	int		error;
 
 	/*

fs/xfs/linux-2.6/xfs_iops.c xfs_vn_truncate( · line 773

Quoted 3 lines
fs/xfs/linux-2.6/xfs_iops.c +0 -0
@@ -771,98 +771,6 @@ xfs_vn_truncate(
 	WARN_ON(error);
 }
 

So you are removing xfs_vn_setxattr, xfs_vn_getxattr, and xfs_vn_removexattr and calling generic_xattr and retaining the code in xattr_handler's.

You leave xfs_vn_listxattr alone. Just like ext3 does its own. Ok.

Quoted 176 lines
fs/xfs/linux-2.6/xfs_iops.c +12 -104
-STATIC int
-xfs_vn_setxattr(
-	struct dentry	*dentry,
-	const char	*name,
-	const void	*data,
-	size_t		size,
-	int		flags)
-{
-	bhv_vnode_t	*vp = vn_from_inode(dentry->d_inode);
-	char		*attr = (char *)name;
-	attrnames_t	*namesp;
-	int		xflags = 0;
-
-	namesp = attr_lookup_namespace(attr, attr_namespaces, ATTR_NAMECOUNT);
-	if (!namesp)
-		return -EOPNOTSUPP;
-	attr += namesp->attr_namelen;
-
-	/* Convert Linux syscall to XFS internal ATTR flags */
-	if (flags & XATTR_CREATE)
-		xflags |= ATTR_CREATE;
-	if (flags & XATTR_REPLACE)
-		xflags |= ATTR_REPLACE;
-	xflags |= namesp->attr_flag;
-	return namesp->attr_set(vp, attr, (void *)data, size, xflags);
-}
-
-STATIC ssize_t
-xfs_vn_getxattr(
-	struct dentry	*dentry,
-	const char	*name,
-	void		*data,
-	size_t		size)
-{
-	bhv_vnode_t	*vp = vn_from_inode(dentry->d_inode);
-	char		*attr = (char *)name;
-	attrnames_t	*namesp;
-	int		xflags = 0;
-
-	namesp = attr_lookup_namespace(attr, attr_namespaces, ATTR_NAMECOUNT);
-	if (!namesp)
-		return -EOPNOTSUPP;
-	attr += namesp->attr_namelen;
-
-	/* Convert Linux syscall to XFS internal ATTR flags */
-	if (!size) {
-		xflags |= ATTR_KERNOVAL;
-		data = NULL;
-	}
-	xflags |= namesp->attr_flag;
-	return namesp->attr_get(vp, attr, (void *)data, size, xflags);
-}
-
-STATIC ssize_t
-xfs_vn_listxattr(
-	struct dentry		*dentry,
-	char			*data,
-	size_t			size)
-{
-	bhv_vnode_t		*vp = vn_from_inode(dentry->d_inode);
-	int			error, xflags = ATTR_KERNAMELS;
-	ssize_t			result;
-
-	if (!size)
-		xflags |= ATTR_KERNOVAL;
-	xflags |= capable(CAP_SYS_ADMIN) ? ATTR_KERNFULLS : ATTR_KERNORMALS;
-
-	error = attr_generic_list(vp, data, size, xflags, &result);
-	if (error < 0)
-		return error;
-	return result;
-}
-
-STATIC int
-xfs_vn_removexattr(
-	struct dentry	*dentry,
-	const char	*name)
-{
-	bhv_vnode_t	*vp = vn_from_inode(dentry->d_inode);
-	char		*attr = (char *)name;
-	attrnames_t	*namesp;
-	int		xflags = 0;
-
-	namesp = attr_lookup_namespace(attr, attr_namespaces, ATTR_NAMECOUNT);
-	if (!namesp)
-		return -EOPNOTSUPP;
-	attr += namesp->attr_namelen;
-
-	xflags |= namesp->attr_flag;
-	return namesp->attr_remove(vp, attr, xflags);
-}
-
 STATIC long
 xfs_vn_fallocate(
 	struct inode	*inode,
@@ -910,10 +818,10 @@ const struct inode_operations xfs_inode_
 	.truncate		= xfs_vn_truncate,
 	.getattr		= xfs_vn_getattr,
 	.setattr		= xfs_vn_setattr,
-	.setxattr		= xfs_vn_setxattr,
-	.getxattr		= xfs_vn_getxattr,
+	.setxattr		= generic_setxattr,
+	.getxattr		= generic_getxattr,
+	.removexattr		= generic_removexattr,
 	.listxattr		= xfs_vn_listxattr,
-	.removexattr		= xfs_vn_removexattr,
 	.fallocate		= xfs_vn_fallocate,
 };
 
@@ -930,10 +838,10 @@ const struct inode_operations xfs_dir_in
 	.permission		= xfs_vn_permission,
 	.getattr		= xfs_vn_getattr,
 	.setattr		= xfs_vn_setattr,
-	.setxattr		= xfs_vn_setxattr,
-	.getxattr		= xfs_vn_getxattr,
+	.setxattr		= generic_setxattr,
+	.getxattr		= generic_getxattr,
+	.removexattr		= generic_removexattr,
 	.listxattr		= xfs_vn_listxattr,
-	.removexattr		= xfs_vn_removexattr,
 };
 
 const struct inode_operations xfs_dir_ci_inode_operations = {
@@ -949,10 +857,10 @@ const struct inode_operations xfs_dir_ci
 	.permission		= xfs_vn_permission,
 	.getattr		= xfs_vn_getattr,
 	.setattr		= xfs_vn_setattr,
-	.setxattr		= xfs_vn_setxattr,
-	.getxattr		= xfs_vn_getxattr,
+	.setxattr		= generic_setxattr,
+	.getxattr		= generic_getxattr,
+	.removexattr		= generic_removexattr,
 	.listxattr		= xfs_vn_listxattr,
-	.removexattr		= xfs_vn_removexattr,
 };
 
 const struct inode_operations xfs_symlink_inode_operations = {
@@ -962,8 +870,8 @@ const struct inode_operations xfs_symlin
 	.permission		= xfs_vn_permission,
 	.getattr		= xfs_vn_getattr,
 	.setattr		= xfs_vn_setattr,
-	.setxattr		= xfs_vn_setxattr,
-	.getxattr		= xfs_vn_getxattr,
+	.setxattr		= generic_setxattr,
+	.getxattr		= generic_getxattr,
+	.removexattr		= generic_removexattr,
 	.listxattr		= xfs_vn_listxattr,
-	.removexattr		= xfs_vn_removexattr,
 };

Index: linux-2.6-xfs/fs/xfs/linux-2.6/xfs_xattr.c
===================================================================

fs/xfs/linux-2.6/xfs_xattr.c new file +18 -0
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2008 Christoph Hellwig.
+ *	Released under GPL v2.
+ */
+
+#include "xfs.h"
+#include "xfs_attr.h"
+#include "xfs_acl.h"
+#include "xfs_vnodeops.h"
+
+#include <linux/posix_acl_xattr.h>
+#include <linux/xattr.h>
+
+
+/*
+ * ACL handling.  Should eventually be moved into xfs_acl.c
+ */
+

fs/xfs/linux-2.6/xfs_xattr.c line 28

Quoted 10 lines
fs/xfs/linux-2.6/xfs_xattr.c new file +10 -0
+static int
+xfs_decode_acl(const char *name)
+{
+	if (strcmp(name, "posix_acl_access") == 0)
+		return _ACL_TYPE_ACCESS;
+	else if (strcmp(name, "posix_acl_default") == 0)
+		return _ACL_TYPE_DEFAULT;
+	return -EINVAL;
+}
+

Fine.

fs/xfs/linux-2.6/xfs_xattr.c line 41

Quoted 13 lines
fs/xfs/linux-2.6/xfs_xattr.c new file +13 -0
+static int
+xfs_xattr_system_get(struct inode *inode, const char *name,
+		void *buffer, size_t size)
+{
+	int acl;
+
+	acl = xfs_decode_acl(name);
+	if (acl < 0)
+		return acl;
+
+	return xfs_acl_vget(inode, buffer, size, acl);
+}
+

Fine.
Seems a little funny as we are calling it a system EA but then directly calling the acl code.
i.e. acknowledging, I guess, that we only have Posix ACLs as system EAs.
Almost could call it xfs_xattr_acl_get().
It saves on one liner wrappers I guess.

Quoted 11 lines
fs/xfs/linux-2.6/xfs_xattr.c new file +11 -0
+static int
+xfs_xattr_system_set(struct inode *inode, const char *name,
+		const void *value, size_t size, int flags)
+{
+	int error, acl;
+
+	acl = xfs_decode_acl(name);
+	if (acl < 0)
+		return acl;
+	if (flags & XATTR_CREATE)
+		return -EINVAL;

fs/xfs/linux-2.6/xfs_xattr.c line 62

Quoted 10 lines
fs/xfs/linux-2.6/xfs_xattr.c new file +10 -0
+
+	if (!value)
+		return xfs_acl_vremove(inode, acl);
+
+	error = xfs_acl_vset(inode, (void *)value, size, acl);
+	if (!error)
+		vn_revalidate(inode);
+	return error;
+}
+

Why the vn_revalidate?
b/c we did that in xfs_attr.c/attr_system_set().
It updates the linux inode fields based on the xfs inode fields. I wonder why.
Because we can modify an ACL which can cause mode changes? in the call to xfs_acl_setmode(vp, xfs_acl, &basicperms) I wonder why we do it at this point though as it doesn't look so obvious.

Quoted 24 lines
fs/xfs/linux-2.6/xfs_xattr.c new file +24 -0
+static struct xattr_handler xfs_xattr_system_handler = {
+	.prefix	= XATTR_SYSTEM_PREFIX,
+	.get	= xfs_xattr_system_get,
+	.set	= xfs_xattr_system_set,
+};
+
+
+/*
+ * Real xattr handling.  The only difference between the namespaces is
+ * a flag passed to the low-level attr code.
+ */
+
+static int
+__xfs_xattr_get(struct inode *inode, const char *name,
+		void *value, size_t size, int xflags)
+{
+	struct xfs_inode *ip = XFS_I(inode);
+	int error, asize = size;
+
+	if (strcmp(name, "") == 0)
+		return -EINVAL;
+
+	/* Convert Linux syscall to XFS internal ATTR flags */
+	if (!size) {

fs/xfs/linux-2.6/xfs_xattr.c line 96

Quoted 10 lines
fs/xfs/linux-2.6/xfs_xattr.c new file +10 -0
+		xflags |= ATTR_KERNOVAL;
+		value = NULL;
+	}
+
+	error = -xfs_attr_get(ip, name, value, &asize, xflags);
+	if (error)
+		return error;
+	return asize;
+}
+

Ok.

Quoted 10 lines
fs/xfs/linux-2.6/xfs_xattr.c new file +10 -0
+static int
+__xfs_xattr_set(struct inode *inode, const char *name, const void *value,
+		size_t size, int flags, int xflags)
+{
+	struct xfs_inode *ip = XFS_I(inode);
+
+	if (strcmp(name, "") == 0)
+		return -EINVAL;
+
+	/* Convert Linux syscall to XFS internal ATTR flags */

fs/xfs/linux-2.6/xfs_xattr.c line 116

Quoted 10 lines
fs/xfs/linux-2.6/xfs_xattr.c new file +10 -0
+	if (flags & XATTR_CREATE)
+		xflags |= ATTR_CREATE;
+	if (flags & XATTR_REPLACE)
+		xflags |= ATTR_REPLACE;
+
+	if (!value)
+		return -xfs_attr_remove(ip, name, xflags);
+	return -xfs_attr_set(ip, name, (void *)value, size, xflags);
+}
+

Ok.

Quoted 15 lines
fs/xfs/linux-2.6/xfs_xattr.c new file +15 -0
+static int
+xfs_xattr_user_get(struct inode *inode, const char *name,
+		void *value, size_t size)
+{
+	return __xfs_xattr_get(inode, name, value, size, 0);
+}
+
+static int
+xfs_xattr_user_set(struct inode *inode, const char *name,
+		const void *value, size_t size, int flags)
+{
+	return __xfs_xattr_set(inode, name, value, size, flags, 0);
+}
+
+struct attrnames attr_user = {

fs/xfs/linux-2.6/xfs_xattr.c line 141

Quoted 10 lines
fs/xfs/linux-2.6/xfs_xattr.c new file +10 -0
+	.attr_name	= "user.",
+	.attr_namelen	= sizeof("user.") - 1,
+};
+
+static struct xattr_handler xfs_xattr_user_handler = {
+	.prefix	= XATTR_USER_PREFIX,
+	.get	= xfs_xattr_user_get,
+	.set	= xfs_xattr_user_set,
+};
+

Ok.

Quoted 16 lines
fs/xfs/linux-2.6/xfs_xattr.c new file +16 -0
+
+static int
+xfs_xattr_trusted_get(struct inode *inode, const char *name,
+		void *value, size_t size)
+{
+	return __xfs_xattr_get(inode, name, value, size, ATTR_ROOT);
+}
+
+static int
+xfs_xattr_trusted_set(struct inode *inode, const char *name,
+		const void *value, size_t size, int flags)
+{
+	return __xfs_xattr_set(inode, name, value, size, flags, ATTR_ROOT);
+}
+
+struct attrnames attr_trusted = {

fs/xfs/linux-2.6/xfs_xattr.c line 167

Quoted 10 lines
fs/xfs/linux-2.6/xfs_xattr.c new file +10 -0
+	.attr_name	= "trusted.",
+	.attr_namelen	= sizeof("trusted.") - 1,
+};
+
+static struct xattr_handler xfs_xattr_trusted_handler = {
+	.prefix	= XATTR_TRUSTED_PREFIX,
+	.get	= xfs_xattr_trusted_get,
+	.set	= xfs_xattr_trusted_set,
+};
+

Ok.

Quoted 16 lines
fs/xfs/linux-2.6/xfs_xattr.c new file +16 -0
+
+static int
+xfs_xattr_secure_get(struct inode *inode, const char *name,
+		void *value, size_t size)
+{
+	return __xfs_xattr_get(inode, name, value, size, ATTR_SECURE);
+}
+
+static int
+xfs_xattr_secure_set(struct inode *inode, const char *name,
+		const void *value, size_t size, int flags)
+{
+	return __xfs_xattr_set(inode, name, value, size, flags, ATTR_SECURE);
+}
+
+struct attrnames attr_secure = {

fs/xfs/linux-2.6/xfs_xattr.c line 193

Quoted 10 lines
fs/xfs/linux-2.6/xfs_xattr.c new file +10 -0
+	.attr_name	= "security.",
+	.attr_namelen	= sizeof("security.") - 1,
+};
+
+static struct xattr_handler xfs_xattr_security_handler = {
+	.prefix	= XATTR_SECURITY_PREFIX,
+	.get	= xfs_xattr_secure_get,
+	.set	= xfs_xattr_secure_set,
+};
+

Ok.

fs/xfs/linux-2.6/xfs_xattr.c line 202

Quoted 9 lines
fs/xfs/linux-2.6/xfs_xattr.c new file +9 -0
+
+struct xattr_handler *xfs_xattr_handlers[] = {
+	&xfs_xattr_user_handler,
+	&xfs_xattr_trusted_handler,
+	&xfs_xattr_security_handler,
+	&xfs_xattr_system_handler,
+	NULL
+};
+

So List code is done separately. Hmmmm...

Oh, okay, ATTR_KERNAMELS (for attr_vn_listxattr) uses concatenated string arrays
whereas for not ATTR_KERNAMELS, such as is used in xfs_attrlist_by_handle is uses list data in the form:
<u32: valuelen> <char: name-array> <pad-to-4-byte-boundary>

Quoted 4 lines
fs/xfs/linux-2.6/xfs_xattr.c new file +4 -0
+static int
+list_one_attr(const char *name, const size_t len, void *data,
+		size_t size, ssize_t *result)
+{

fs/xfs/linux-2.6/xfs_xattr.c line 216

Quoted 10 lines
fs/xfs/linux-2.6/xfs_xattr.c new file +10 -0
+	char *p = data + *result;
+
+	*result += len;
+	if (!size)
+		return 0;
+	if (*result > size)
+		return -ERANGE;
+
+	strcpy(p, name);
+	p += len;

Q: Why increment p?

Ok, this code looks like it is coming from attr_generic_listadd().

fs/xfs/linux-2.6/xfs_xattr.c line 219

Quoted 3 lines
fs/xfs/linux-2.6/xfs_xattr.c new file +3 -0
+	return 0;
+}
+

Previously, in attr_generic_list it did:
-> xfs_attr_list
-> attr_system_list

So you've expanded out attr_system_list into xfs_vn_listxattr().

Quoted 37 lines
fs/xfs/linux-2.6/xfs_xattr.c new file +37 -0
+ssize_t
+xfs_vn_listxattr(struct dentry *dentry, char *data, size_t size)
+{
+	struct inode		*inode = dentry->d_inode;
+	struct xfs_inode	*ip = XFS_I(inode);
+	attrlist_cursor_kern_t	cursor = { 0 };
+	int			error, xflags;
+	ssize_t			result;
+
+	xflags = ATTR_KERNAMELS;
+	if (!size)
+		xflags |= ATTR_KERNOVAL;
+
+	if (capable(CAP_SYS_ADMIN))
+		xflags |= ATTR_KERNFULLS;
+	else
+		xflags |= ATTR_KERNORMALS;
+
+
+	/*
+	 * First read the regular on-disk attributes.
+	 */
+	result = -xfs_attr_list(ip, data, size, xflags, &cursor);
+	if (result < 0)
+		return result;
+
+	/*
+	 * Then add the two synthetic ACL attributes.
+	 */
+	if (xfs_acl_vhasacl_access(inode)) {
+		error = list_one_attr(POSIX_ACL_XATTR_ACCESS,
+				strlen(POSIX_ACL_XATTR_ACCESS) + 1,
+				data, size, &result);
+		if (error)
+			return error;
+	}
+

fs/xfs/linux-2.6/xfs_xattr.c line 266

Quoted 10 lines
fs/xfs/linux-2.6/xfs_xattr.c new file +10 -0
+	if (xfs_acl_vhasacl_default(inode)) {
+		error = list_one_attr(POSIX_ACL_XATTR_DEFAULT,
+				strlen(POSIX_ACL_XATTR_DEFAULT) + 1,
+				data, size, &result);
+		if (error)
+			return error;
+	}
+
+	return result;
+}

Looks reasonable.

Quoted 367 lines

Index: linux-2.6-xfs/fs/xfs/xfs_attr.c
===================================================================

fs/xfs/xfs_attr.c +0 -272
@@ -57,11 +57,6 @@
  * Provide the external interfaces to manage attribute lists.
  */
 
-#define ATTR_SYSCOUNT	2
-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.
  *========================================================================*/
@@ -2378,270 +2373,3 @@ xfs_attr_trace_enter(int type, char *whe
 		(void *)a13, (void *)a14, (void *)a15);
 }
 #endif	/* XFS_ATTR_TRACE */
-
-
-/*========================================================================
- * System (pseudo) namespace attribute interface routines.
- *========================================================================*/
-
-STATIC int
-posix_acl_access_set(
-	bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
-{
-	return xfs_acl_vset(vp, data, size, _ACL_TYPE_ACCESS);
-}
-
-STATIC int
-posix_acl_access_remove(
-	bhv_vnode_t *vp, char *name, int xflags)
-{
-	return xfs_acl_vremove(vp, _ACL_TYPE_ACCESS);
-}
-
-STATIC int
-posix_acl_access_get(
-	bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
-{
-	return xfs_acl_vget(vp, data, size, _ACL_TYPE_ACCESS);
-}
-
-STATIC int
-posix_acl_access_exists(
-	bhv_vnode_t *vp)
-{
-	return xfs_acl_vhasacl_access(vp);
-}
-
-STATIC int
-posix_acl_default_set(
-	bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
-{
-	return xfs_acl_vset(vp, data, size, _ACL_TYPE_DEFAULT);
-}
-
-STATIC int
-posix_acl_default_get(
-	bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
-{
-	return xfs_acl_vget(vp, data, size, _ACL_TYPE_DEFAULT);
-}
-
-STATIC int
-posix_acl_default_remove(
-	bhv_vnode_t *vp, char *name, int xflags)
-{
-	return xfs_acl_vremove(vp, _ACL_TYPE_DEFAULT);
-}
-
-STATIC int
-posix_acl_default_exists(
-	bhv_vnode_t *vp)
-{
-	return xfs_acl_vhasacl_default(vp);
-}
-
-static struct attrnames posix_acl_access = {
-	.attr_name	= "posix_acl_access",
-	.attr_namelen	= sizeof("posix_acl_access") - 1,
-	.attr_get	= posix_acl_access_get,
-	.attr_set	= posix_acl_access_set,
-	.attr_remove	= posix_acl_access_remove,
-	.attr_exists	= posix_acl_access_exists,
-};
-
-static struct attrnames posix_acl_default = {
-	.attr_name	= "posix_acl_default",
-	.attr_namelen	= sizeof("posix_acl_default") - 1,
-	.attr_get	= posix_acl_default_get,
-	.attr_set	= posix_acl_default_set,
-	.attr_remove	= posix_acl_default_remove,
-	.attr_exists	= posix_acl_default_exists,
-};
-
-static struct attrnames *attr_system_names[] =
-	{ &posix_acl_access, &posix_acl_default };
-
-
-/*========================================================================
- * Namespace-prefix-style attribute name interface routines.
- *========================================================================*/
-
-STATIC int
-attr_generic_set(
-	bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
-{
-	return -xfs_attr_set(xfs_vtoi(vp), name, data, size, xflags);
-}
-
-STATIC int
-attr_generic_get(
-	bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
-{
-	int	error, asize = size;
-
-	error = xfs_attr_get(xfs_vtoi(vp), name, data, &asize, xflags);
-	if (!error)
-		return asize;
-	return -error;
-}
-
-STATIC int
-attr_generic_remove(
-	bhv_vnode_t *vp, char *name, int xflags)
-{
-	return -xfs_attr_remove(xfs_vtoi(vp), name, xflags);
-}
-
-STATIC int
-attr_generic_listadd(
-	attrnames_t		*prefix,
-	attrnames_t		*namesp,
-	void			*data,
-	size_t			size,
-	ssize_t			*result)
-{
-	char			*p = data + *result;
-
-	*result += prefix->attr_namelen;
-	*result += namesp->attr_namelen + 1;
-	if (!size)
-		return 0;
-	if (*result > size)
-		return -ERANGE;
-	strcpy(p, prefix->attr_name);
-	p += prefix->attr_namelen;
-	strcpy(p, namesp->attr_name);
-	p += namesp->attr_namelen + 1;
-	return 0;
-}
-
-STATIC int
-attr_system_list(
-	bhv_vnode_t		*vp,
-	void			*data,
-	size_t			size,
-	ssize_t			*result)
-{
-	attrnames_t		*namesp;
-	int			i, error = 0;
-
-	for (i = 0; i < ATTR_SYSCOUNT; i++) {
-		namesp = attr_system_names[i];
-		if (!namesp->attr_exists || !namesp->attr_exists(vp))
-			continue;
-		error = attr_generic_listadd(&attr_system, namesp,
-						data, size, result);
-		if (error)
-			break;
-	}
-	return error;
-}
-
-int
-attr_generic_list(
-	bhv_vnode_t *vp, void *data, size_t size, int xflags, ssize_t *result)
-{
-	attrlist_cursor_kern_t	cursor = { 0 };
-	int			error;
-
-	error = xfs_attr_list(xfs_vtoi(vp), data, size, xflags, &cursor);
-	if (error > 0)
-		return -error;
-	*result = -error;
-	return attr_system_list(vp, data, size, result);
-}
-
-attrnames_t *
-attr_lookup_namespace(
-	char			*name,
-	struct attrnames	**names,
-	int			nnames)
-{
-	int			i;
-
-	for (i = 0; i < nnames; i++)
-		if (!strncmp(name, names[i]->attr_name, names[i]->attr_namelen))
-			return names[i];
-	return NULL;
-}
-
-STATIC int
-attr_system_set(
-	bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
-{
-	attrnames_t	*namesp;
-	int		error;
-
-	if (xflags & ATTR_CREATE)
-		return -EINVAL;
-
-	namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT);
-	if (!namesp)
-		return -EOPNOTSUPP;
-	error = namesp->attr_set(vp, name, data, size, xflags);
-	if (!error)
-		error = vn_revalidate(vp);
-	return error;
-}
-
-STATIC int
-attr_system_get(
-	bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
-{
-	attrnames_t	*namesp;
-
-	namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT);
-	if (!namesp)
-		return -EOPNOTSUPP;
-	return namesp->attr_get(vp, name, data, size, xflags);
-}
-
-STATIC int
-attr_system_remove(
-	bhv_vnode_t *vp, char *name, int xflags)
-{
-	attrnames_t	*namesp;
-
-	namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT);
-	if (!namesp)
-		return -EOPNOTSUPP;
-	return namesp->attr_remove(vp, name, xflags);
-}
-
-struct attrnames attr_system = {
-	.attr_name	= "system.",
-	.attr_namelen	= sizeof("system.") - 1,
-	.attr_flag	= ATTR_SYSTEM,
-	.attr_get	= attr_system_get,
-	.attr_set	= attr_system_set,
-	.attr_remove	= attr_system_remove,
-};
-
-struct attrnames attr_trusted = {
-	.attr_name	= "trusted.",
-	.attr_namelen	= sizeof("trusted.") - 1,
-	.attr_flag	= ATTR_ROOT,
-	.attr_get	= attr_generic_get,
-	.attr_set	= attr_generic_set,
-	.attr_remove	= attr_generic_remove,
-};
-
-struct attrnames attr_secure = {
-	.attr_name	= "security.",
-	.attr_namelen	= sizeof("security.") - 1,
-	.attr_flag	= ATTR_SECURE,
-	.attr_get	= attr_generic_get,
-	.attr_set	= attr_generic_set,
-	.attr_remove	= attr_generic_remove,
-};
-
-struct attrnames attr_user = {
-	.attr_name	= "user.",
-	.attr_namelen	= sizeof("user.") - 1,
-	.attr_get	= attr_generic_get,
-	.attr_set	= attr_generic_set,
-	.attr_remove	= attr_generic_remove,
-};
-
-struct attrnames *attr_namespaces[] =
-	{ &attr_system, &attr_trusted, &attr_secure, &attr_user };

Index: linux-2.6-xfs/fs/xfs/xfs_attr.h
===================================================================

fs/xfs/xfs_attr.h +0 -17
@@ -38,30 +38,14 @@
 struct cred;
 struct xfs_attr_list_context;
 
-typedef int (*attrset_t)(bhv_vnode_t *, char *, void *, size_t, int);
-typedef int (*attrget_t)(bhv_vnode_t *, char *, void *, size_t, int);
-typedef int (*attrremove_t)(bhv_vnode_t *, char *, int);
-typedef int (*attrexists_t)(bhv_vnode_t *);
-
 typedef struct attrnames {
 	char *		attr_name;
 	unsigned int	attr_namelen;
-	unsigned int	attr_flag;
-	attrget_t	attr_get;
-	attrset_t	attr_set;
-	attrremove_t	attr_remove;
-	attrexists_t	attr_exists;
 } attrnames_t;
 
-#define ATTR_NAMECOUNT	4
 extern struct attrnames attr_user;
 extern struct attrnames attr_secure;
-extern struct attrnames attr_system;
 extern struct attrnames attr_trusted;
-extern struct attrnames *attr_namespaces[ATTR_NAMECOUNT];
-
-extern attrnames_t *attr_lookup_namespace(char *, attrnames_t **, int);
-extern int attr_generic_list(bhv_vnode_t *, void *, size_t, int, ssize_t *);
 
 #define ATTR_DONTFOLLOW	0x0001	/* -- unused, from IRIX -- */
 #define ATTR_ROOT	0x0002	/* use attrs in root (trusted) namespace */
@@ -69,7 +53,6 @@ extern int attr_generic_list(bhv_vnode_t
 #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 ATTR_SYSTEM	0x0100	/* use attrs in system (pseudo) namespace */
 
 #define ATTR_KERNACCESS	0x0400	/* [kernel] iaccess, inode held io-locked */
 #define ATTR_KERNOTIME	0x1000	/* [kernel] don't update inode timestamps */

Index: linux-2.6-xfs/fs/xfs/linux-2.6/xfs_iops.h
===================================================================

fs/xfs/linux-2.6/xfs_iops.h +1 -0
@@ -27,6 +27,7 @@ extern const struct file_operations xfs_
 extern const struct file_operations xfs_dir_file_operations;
 extern const struct file_operations xfs_invis_file_operations;
 
+extern ssize_t xfs_vn_listxattr(struct dentry *, char *data, size_t size);
 
 struct xfs_inode;
 extern void xfs_ichgtime(struct xfs_inode *, int);

Index: linux-2.6-xfs/fs/xfs/linux-2.6/xfs_super.c
===================================================================

fs/xfs/linux-2.6/xfs_super.c +1 -0
@@ -1767,6 +1767,7 @@ xfs_fs_fill_super(
 		goto out_free_mp;
 
 	sb_min_blocksize(sb, BBSIZE);
+	sb->s_xattr = xfs_xattr_handlers;
 	sb->s_export_op = &xfs_export_operations;
 	sb->s_qcop = &xfs_quotactl_operations;
 	sb->s_op = &xfs_super_operations;

Index: linux-2.6-xfs/fs/xfs/linux-2.6/xfs_super.h
===================================================================

fs/xfs/linux-2.6/xfs_super.h +1 -0
@@ -81,6 +81,7 @@ extern void xfs_flush_device(struct xfs_
 extern void xfs_blkdev_issue_flush(struct xfs_buftarg *);
 
 extern const struct export_operations xfs_export_operations;
+extern struct xattr_handler *xfs_xattr_handlers[];
 
 #define XFS_M(sb)		((struct xfs_mount *)((sb)->s_fs_info))
 
#4 lore raw
Quoted 8 lines · Timothy Shimmin

Hi Christoph,

Looks reasonable to me.

In list_one_attr(), which looks based on attr_generic_listadd(), it does a final:

fs/xfs/linux-2.6/xfs_xattr.c line 216

Quoted 1 line
fs/xfs/linux-2.6/xfs_xattr.c new file +1 -0
+	p += len;

which seems useless.

Yeah, feel free to remove it when you commit the patch. Alternatively I'll send an incremental patch once commited.

Quoted 8 lines

An aside, I noticed in passing (which was in existing code), how we call vn_revalidate
in xfs_xattr_system_set(). I presume this is because we call xfs_acl_setmode() in xfs_acl_vset() when we want to sync the mode bits to the ACL.
If this is the case, then I think it would have been clearer to put vn_revalidate() in the vicinity of xfs_acl_setmode(). Or is there some other reason?

No real reason, I was just keeping what was there before. But getting rid of vn_revalidate complete is on my todo list. The timestamp updates in there are already not nessecary anymore, and the i_mode/i_uid/i_gid and i_flags updates can be done much better in the caller that change the values in the dinode.

Quoted 5 lines

fs/xfs/Makefile xfs-y += $(addprefix $(XFS_LINUX)/, \ · line 101

Quoted 3 lines
fs/xfs/Makefile +1 -0
+				   xfs_xattr.o \
 				   xfs_ksyms.o) 

Okay adding in a linux-2.6/xfs_xattr.c
(slightly different name than xfs_attr.c)

Yeah. For one xfs_attr.c is already taken in fs/xfs and second the xattr name makes it pretty clear these are the Linux xattr routines and not the lowlevel XFS attr code

Quoted 5 lines

So you are removing xfs_vn_setxattr, xfs_vn_getxattr, and xfs_vn_removexattr and calling generic_xattr and retaining the code in xattr_handler's.

You leave xfs_vn_listxattr alone. Just like ext3 does its own. Ok.

Yes, the generic listxattr doesn't buy us anything as we just traverse the attr btree and list all of them in their natural order. No point in traversing it N times for N different attribute handlers.

Quoted 24 lines

fs/xfs/linux-2.6/xfs_xattr.c line 28

Quoted 10 lines
fs/xfs/linux-2.6/xfs_xattr.c new file +10 -0
+static int
+xfs_decode_acl(const char *name)
+{
+	if (strcmp(name, "posix_acl_access") == 0)
+		return _ACL_TYPE_ACCESS;
+	else if (strcmp(name, "posix_acl_default") == 0)
+		return _ACL_TYPE_DEFAULT;
+	return -EINVAL;
+}
+

Fine.

Quoted 12 lines
fs/xfs/linux-2.6/xfs_xattr.c new file +12 -0
+static int
+xfs_xattr_system_get(struct inode *inode, const char *name,
+		void *buffer, size_t size)
+{
+	int acl;
+
+	acl = xfs_decode_acl(name);
+	if (acl < 0)
+		return acl;
+
+	return xfs_acl_vget(inode, buffer, size, acl);
+}
Quoted 8 lines
Quoted 1 line

+

Fine.
Seems a little funny as we are calling it a system EA but then directly calling the acl code.
i.e. acknowledging, I guess, that we only have Posix ACLs as system EAs.
Almost could call it xfs_xattr_acl_get().
It saves on one liner wrappers I guess.

Probably worth adding a comment that we only have acls for now. The reason I did this is to avoid doing multiple memcpys on the xattr name for decoding it. It will probably need some revisiting if/when we support other system xattrs.

Quoted 8 lines

Why the vn_revalidate?
b/c we did that in xfs_attr.c/attr_system_set().
It updates the linux inode fields based on the xfs inode fields. I wonder why.
Because we can modify an ACL which can cause mode changes? in the call to xfs_acl_setmode(vp, xfs_acl, &basicperms) I wonder why we do it at this point though as it doesn't look so obvious.

Yeah, se the comment above. vn_revalidate will go away pretty soon at which point this is sorted out.

Quoted 11 lines

fs/xfs/linux-2.6/xfs_xattr.c line 202

Quoted 8 lines
fs/xfs/linux-2.6/xfs_xattr.c new file +8 -0
+struct xattr_handler *xfs_xattr_handlers[] = {
+	&xfs_xattr_user_handler,
+	&xfs_xattr_trusted_handler,
+	&xfs_xattr_security_handler,
+	&xfs_xattr_system_handler,
+	NULL
+};
+

So List code is done separately. Hmmmm...

Quoted 5 lines

Oh, okay, ATTR_KERNAMELS (for attr_vn_listxattr) uses concatenated string arrays
whereas for not ATTR_KERNAMELS, such as is used in xfs_attrlist_by_handle is uses list data in the form:
<u32: valuelen> <char: name-array> <pad-to-4-byte-boundary>

Yes, this is quite unfortunate. My plan is to refactor the low-level attr code so that is passes down a formatter ala filldir for directory reading. This should clean up the attr listing code a lot and also gets rid of the levtover struct attrnames bits. But that a different patch which still needs to be written.

Quoted 5 lines

Previously, in attr_generic_list it did:
-> xfs_attr_list
-> attr_system_list

So you've expanded out attr_system_list into xfs_vn_listxattr().

Yes. And loop-unrolled it while we're at it because the loop over the system attrs didn't make much sense.

#5 lore raw
Quoted 5 lines · Christoph Hellwig
Quoted 4 lines · Timothy Shimmin

Hi Christoph,

Looks reasonable to me.

Quoted 8 lines
Quoted 4 lines

In list_one_attr(), which looks based on attr_generic_listadd(), it does a final:

fs/xfs/linux-2.6/xfs_xattr.c line 216

Quoted 1 line
fs/xfs/linux-2.6/xfs_xattr.c new file +1 -0
+	p += len;

which seems useless.

Yeah, feel free to remove it when you commit the patch. Alternatively I'll send an incremental patch once commited.

Yep, I'll remove it before checkin.

Quoted 9 lines
Quoted 8 lines

An aside, I noticed in passing (which was in existing code), how we call vn_revalidate
in xfs_xattr_system_set(). I presume this is because we call xfs_acl_setmode() in xfs_acl_vset() when we want to sync the mode bits to the ACL.
If this is the case, then I think it would have been clearer to put vn_revalidate() in the vicinity of xfs_acl_setmode(). Or is there some other reason?

Quoted 6 lines

No real reason, I was just keeping what was there before. But getting rid of vn_revalidate complete is on my todo list. The timestamp updates in there are already not nessecary anymore, and the i_mode/i_uid/i_gid and i_flags updates can be done much better in the caller that change the values in the dinode.

Okay, good to know.

Quoted 10 lines
Quoted 5 lines

So you are removing xfs_vn_setxattr, xfs_vn_getxattr, and xfs_vn_removexattr and calling generic_xattr and retaining the code in xattr_handler's.

You leave xfs_vn_listxattr alone. Just like ext3 does its own. Ok.

Yes, the generic listxattr doesn't buy us anything as we just traverse the attr btree and list all of them in their natural order. No point in traversing it N times for N different attribute handlers.

Good point (I didn't really look).

Quoted 21 lines
Quoted 12 lines
Quoted 12 lines
fs/xfs/linux-2.6/xfs_xattr.c new file +12 -0
+static int
+xfs_xattr_system_get(struct inode *inode, const char *name,
+		void *buffer, size_t size)
+{
+	int acl;
+
+	acl = xfs_decode_acl(name);
+	if (acl < 0)
+		return acl;
+
+	return xfs_acl_vget(inode, buffer, size, acl);
+}
Quoted 8 lines
Quoted 1 line

+

Fine.
Seems a little funny as we are calling it a system EA but then directly calling the acl code.
i.e. acknowledging, I guess, that we only have Posix ACLs as system EAs.
Almost could call it xfs_xattr_acl_get().
It saves on one liner wrappers I guess.

Quoted 4 lines

Probably worth adding a comment that we only have acls for now. The reason I did this is to avoid doing multiple memcpys on the xattr name for decoding it. It will probably need some revisiting if/when we support other system xattrs.

Okay, I'll add a comment.

Quoted 20 lines

Yeah, se the comment above. vn_revalidate will go away pretty soon at which point this is sorted out.

Quoted 10 lines

fs/xfs/linux-2.6/xfs_xattr.c line 202

Quoted 8 lines
fs/xfs/linux-2.6/xfs_xattr.c new file +8 -0
+struct xattr_handler *xfs_xattr_handlers[] = {
+	&xfs_xattr_user_handler,
+	&xfs_xattr_trusted_handler,
+	&xfs_xattr_security_handler,
+	&xfs_xattr_system_handler,
+	NULL
+};
+

So List code is done separately. Hmmmm...

Quoted 5 lines

Oh, okay, ATTR_KERNAMELS (for attr_vn_listxattr) uses concatenated string arrays
whereas for not ATTR_KERNAMELS, such as is used in xfs_attrlist_by_handle is uses list data in the form:
<u32: valuelen> <char: name-array> <pad-to-4-byte-boundary>

Quoted 6 lines

Yes, this is quite unfortunate. My plan is to refactor the low-level attr code so that is passes down a formatter ala filldir for directory reading. This should clean up the attr listing code a lot and also gets rid of the levtover struct attrnames bits. But that a different patch which still needs to be written.

I guess this is done to some extent by the put_listent() callback. Though, the context structure is probably a bit overused in different ways.
The callback was also used for searching (for parent-ptr code) as well as for list formatting.
I presume we are preserving the valuelen list format to keep the API for xfs_attrlist_by_handle used by xfsdump and probably for dmf.

Thanks,
--Tim

#6 lore raw
Quoted 7 lines · Timothy Shimmin

I guess this is done to some extent by the put_listent() callback. Though, the context structure is probably a bit overused in different ways.
The callback was also used for searching (for parent-ptr code) as well as for list formatting.
I presume we are preserving the valuelen list format to keep the API for xfs_attrlist_by_handle used by xfsdump and probably for dmf.

Yes, the idea is to change the put_listen callback for work more like filldir. Thas is:

- the callback is supplied by the xfs_attr_list caller, not set based on options
- there will be an opaque object supplied to xfs_attr_list that is to be used by put_listent so that we don't have to pass down implementation-specific arguments directly.

I'd also like to move the attrlist_cursor_kern_t into this callback opaque context because it doesn't make sense for the normal xattr API, but I'll have to see if that's actually feasible.

#7 lore raw
Quoted 9 lines · Christoph Hellwig
Quoted 7 lines · Timothy Shimmin

I guess this is done to some extent by the put_listent() callback. Though, the context structure is probably a bit overused in different ways.
The callback was also used for searching (for parent-ptr code) as well as for list formatting.
I presume we are preserving the valuelen list format to keep the API for xfs_attrlist_by_handle used by xfsdump and probably for dmf.

Quoted 5 lines

Yes, the idea is to change the put_listen callback for work more like filldir. Thas is:

- the callback is supplied by the xfs_attr_list caller, not set based on options

Oh, okay. For example, instead of setting the flags to ATTR_KERNOVAL such as in xfs_vn_listxattr when size is 0, one could just set the callback to xfs_attr_kern_list_sizes and pass it in etc...

Quoted 4 lines

- there will be an opaque object supplied to xfs_attr_list that is to be used by put_listent so that we don't have to pass down implementation-specific arguments directly.

Ok.
So instead of overloading fields in xfs_attr_list_context_t, you'll pass down a void* argument or some such for callback specific data.

Quoted 3 lines

I'd also like to move the attrlist_cursor_kern_t into this callback opaque context because it doesn't make sense for the normal xattr API, but I'll have to see if that's actually feasible.

BTW, the cursor stuff is a bit flawed. Like the dir1 code (I believe), if from userspace you use the cursor and modifications happen to the EAs (add or removal) between calls,
we can end up repeating elements in the list or miss some. We don't preserve the position and we can compact the data etc.

--Tim

xfs_attr_list(

        xfs_inode_t     *dp,
        char            *buffer,
        int             bufsize,
        int             flags,
        attrlist_cursor_kern_t *cursor)
{       
        xfs_attr_list_context_t context;
...
        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->al_count = 0;
                context.alist->al_more = 0;
                context.alist->al_offset[0] = context.bufsize;
                context.put_listent = xfs_attr_put_listent;
        }

ssize_t
xfs_vn_listxattr(struct dentry *dentry, char *data, size_t size)

{
        struct inode            *inode = dentry->d_inode;
        struct xfs_inode        *ip = XFS_I(inode);
        attrlist_cursor_kern_t  cursor = { 0 };
        int                     error, xflags;
        ssize_t                 result;

        xflags = ATTR_KERNAMELS;
        if (!size)
                xflags |= ATTR_KERNOVAL;

        if (capable(CAP_SYS_ADMIN))
                xflags |= ATTR_KERNFULLS;
        else
                xflags |= ATTR_KERNORMALS;


        /*
         * First read the regular on-disk attributes.
         */
        result = -xfs_attr_list(ip, data, size, xflags, &cursor);
#8 lore raw
Quoted 6 lines · Timothy Shimmin
Quoted 2 lines

- the callback is supplied by the xfs_attr_list caller, not set based on options

Oh, okay. For example, instead of setting the flags to ATTR_KERNOVAL such as in xfs_vn_listxattr when size is 0, one could just set the callback to xfs_attr_kern_list_sizes and pass it in etc...

Yes. I have an initial patch that goes directly to xfs_attr_list_int from xfs_xattr.c and kills most of the ATTR_KERN flags. It's a quite nice cleanup already. Next step will be to convert dmapi to use it's own callback aswell. This will be an even bigger cleanup as put_listent gets the xattr value aswell and we can kill the additional xfs_attr_get calls, making this code simpler and more efficient.

Quoted 8 lines
Quoted 4 lines

- there will be an opaque object supplied to xfs_attr_list that is to be used by put_listent so that we don't have to pass down implementation-specific arguments directly.

Ok.
So instead of overloading fields in xfs_attr_list_context_t, you'll pass down a void* argument or some such for callback specific data.

I've started looking at this and after some investigattion I think we should just pass the xfs_inode directly to all the functions and then a void parameter, yes. We'll need to find a solution for the seen_enough paramter, but I think this could be handled similar to filldir. There's also some functions directly touching the attr cursor which seems solveable, too.

Quoted 9 lines
Quoted 3 lines

I'd also like to move the attrlist_cursor_kern_t into this callback opaque context because it doesn't make sense for the normal xattr API, but I'll have to see if that's actually feasible.

BTW, the cursor stuff is a bit flawed. Like the dir1 code (I believe), if from userspace you use the cursor and modifications happen to the EAs (add or removal) between calls,
we can end up repeating elements in the list or miss some. We don't preserve the position and we can compact the data etc.

Yes, I think this whole cursor is a rather bad idea. But given that it's used by xfsdump we can't easily get rid of it.

#9 lore raw
Quoted 7 lines · Christoph Hellwig
Quoted 5 lines · Timothy Shimmin
Quoted 2 lines

- the callback is supplied by the xfs_attr_list caller, not set based on options

Oh, okay. For example, instead of setting the flags to ATTR_KERNOVAL such as in xfs_vn_listxattr when size is 0, one could just set the callback to xfs_attr_kern_list_sizes and pass it in etc...

Quoted 7 lines

Yes. I have an initial patch that goes directly to xfs_attr_list_int from xfs_xattr.c and kills most of the ATTR_KERN flags. It's a quite nice cleanup already. Next step will be to convert dmapi to use it's own callback aswell. This will be an even bigger cleanup as put_listent gets the xattr value aswell and we can kill the additional xfs_attr_get calls, making this code simpler and more efficient.

Sorry, what xfs_attr_get call are you referring to?

Quoted 8 lines
Quoted 7 lines
Quoted 4 lines

- there will be an opaque object supplied to xfs_attr_list that is to be used by put_listent so that we don't have to pass down implementation-specific arguments directly.

Ok.
So instead of overloading fields in xfs_attr_list_context_t, you'll pass down a void* argument or some such for callback specific data.

Quoted 7 lines

I've started looking at this and after some investigation I think we should just pass the xfs_inode directly to all the functions and then a void parameter, yes. We'll need to find a solution for the seen_enough paramter, but I think this could be handled similar to filldir. There's also some functions directly touching the attr cursor which seems solveable, too.

I'll await the patch :)
The seen_enough param was added for search type callbacks so the callback could terminate the list walk early.
Oh okay, I also used it to stop when we fill the buffer.

Quoted 11 lines
Quoted 8 lines
Quoted 3 lines

I'd also like to move the attrlist_cursor_kern_t into this callback opaque context because it doesn't make sense for the normal xattr API, but I'll have to see if that's actually feasible.

BTW, the cursor stuff is a bit flawed. Like the dir1 code (I believe), if from userspace you use the cursor and modifications happen to the EAs (add or removal) between calls,
we can end up repeating elements in the list or miss some. We don't preserve the position and we can compact the data etc.

Yes, I think this whole cursor is a rather bad idea. But given that it's used by xfsdump we can't easily get rid of it.

Not if we are to remain compatible with old xfsdump programs (assuming we changed the latest one).
Yep.

--Tim

#10 lore raw
Quoted 8 lines · Timothy Shimmin
Quoted 7 lines

Yes. I have an initial patch that goes directly to xfs_attr_list_int from xfs_xattr.c and kills most of the ATTR_KERN flags. It's a quite nice cleanup already. Next step will be to convert dmapi to use it's own callback aswell. This will be an even bigger cleanup as put_listent gets the xattr value aswell and we can kill the additional xfs_attr_get calls, making this code simpler and more efficient.

Sorry, what xfs_attr_get call are you referring to?

xfs_dm_getall_dmattr currently does an xfs_attr_list and then performs and xfs_attr_get for each attribute it cares about. But rewriting this to use put_listent we not only get rid of the temporary buffer but also the need to calls xfs_attr_get because put_listent already gets the attribute value passed. It also fixes the race mentioned in the comment and with a properly written put_listent helper can copy the attributes directly to userspace without any kernel buffer at all.

That would also fix the direct userspace pointer dereference currently lingering in that code :)

Quoted 11 lines
Quoted 7 lines

I've started looking at this and after some investigation I think we should just pass the xfs_inode directly to all the functions and then a void parameter, yes. We'll need to find a solution for the seen_enough paramter, but I think this could be handled similar to filldir. There's also some functions directly touching the attr cursor which seems solveable, too.

I'll await the patch :)
The seen_enough param was added for search type callbacks so the callback could terminate the list walk early.
Oh okay, I also used it to stop when we fill the buffer.

Yes. May idea is to break out of the loop as soon as put_listent returns a non-zero value just like filldir. We can then decided to play with positivie / begative values to allow for a sucessfull early exit, or just like filldir have the actual errno inside the private context structure. I suspect the first variant will be cleaner.