diff options
author | Andreas Gruenbacher <agruenba@redhat.com> | 2016-09-29 17:48:44 +0200 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2016-10-07 20:10:44 -0400 |
commit | 6c6ef9f26e598fb977f60935e109cd5b266c941a (patch) | |
tree | ee583d1c81a7f2e3380cc71108f033ff961649eb /fs | |
parent | bf3ee71363c0b44acb62f375aea470262ac4210a (diff) |
xattr: Stop calling {get,set,remove}xattr inode operations
All filesystems that support xattrs by now do so via xattr handlers.
They all define sb->s_xattr, and their getxattr, setxattr, and
removexattr inode operations use the generic inode operations. On
filesystems that don't support xattrs, the xattr inode operations are
all NULL, and sb->s_xattr is also NULL.
This means that we can remove the getxattr, setxattr, and removexattr
inode operations and directly call the generic handlers, or better,
inline expand those handlers into fs/xattr.c.
Filesystems that do not support xattrs on some inodes should clear the
IOP_XATTR i_opflags flag in those inodes. (Right now, some filesystems
have checks to disable xattrs on some inodes in the ->list, ->get, and
->set xattr handler operations instead.) The IOP_XATTR flag is
automatically cleared in inodes of filesystems that don't have xattr
support.
In orangefs, symlinks do have a setxattr iop but no getxattr iop. Add a
check for symlinks to orangefs_inode_getxattr to preserve the current,
weird behavior; that check may not be necessary though.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/orangefs/xattr.c | 3 | ||||
-rw-r--r-- | fs/xattr.c | 52 |
2 files changed, 37 insertions, 18 deletions
diff --git a/fs/orangefs/xattr.c b/fs/orangefs/xattr.c index 2a9f07f06d10..74a81b1daaac 100644 --- a/fs/orangefs/xattr.c +++ b/fs/orangefs/xattr.c @@ -73,6 +73,9 @@ ssize_t orangefs_inode_getxattr(struct inode *inode, const char *name, "%s: name %s, buffer_size %zd\n", __func__, name, size); + if (S_ISLNK(inode->i_mode)) + return -EOPNOTSUPP; + if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN) { gossip_err("Invalid key length (%d)\n", (int)strlen(name)); diff --git a/fs/xattr.c b/fs/xattr.c index e1ccf2be88ac..2432442656a2 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -36,12 +36,9 @@ strcmp_prefix(const char *a, const char *a_prefix) /* * In order to implement different sets of xattr operations for each xattr - * prefix with the generic xattr API, a filesystem should create a - * null-terminated array of struct xattr_handler (one for each prefix) and - * hang a pointer to it off of the s_xattr field of the superblock. - * - * The generic_fooxattr() functions will use this list to dispatch xattr - * operations to the correct xattr_handler. + * prefix, a filesystem should create a null-terminated array of struct + * xattr_handler (one for each prefix) and hang a pointer to it off of the + * s_xattr field of the superblock. */ #define for_each_xattr_handler(handlers, handler) \ if (handlers) \ @@ -140,9 +137,16 @@ int __vfs_setxattr(struct dentry *dentry, struct inode *inode, const char *name, const void *value, size_t size, int flags) { - if (!inode->i_op->setxattr) + const struct xattr_handler *handler; + + handler = xattr_resolve_name(inode, &name); + if (IS_ERR(handler)) + return PTR_ERR(handler); + if (!handler->set) return -EOPNOTSUPP; - return inode->i_op->setxattr(dentry, inode, name, value, size, flags); + if (size == 0) + value = ""; /* empty EA, do not remove */ + return handler->set(handler, dentry, inode, name, value, size, flags); } EXPORT_SYMBOL(__vfs_setxattr); @@ -172,7 +176,7 @@ int __vfs_setxattr_noperm(struct dentry *dentry, const char *name, if (issec) inode->i_flags &= ~S_NOSEC; - if (inode->i_op->setxattr) { + if (inode->i_opflags & IOP_XATTR) { error = __vfs_setxattr(dentry, inode, name, value, size, flags); if (!error) { fsnotify_xattr(dentry); @@ -257,6 +261,7 @@ ssize_t vfs_getxattr_alloc(struct dentry *dentry, const char *name, char **xattr_value, size_t xattr_size, gfp_t flags) { + const struct xattr_handler *handler; struct inode *inode = dentry->d_inode; char *value = *xattr_value; int error; @@ -265,10 +270,12 @@ vfs_getxattr_alloc(struct dentry *dentry, const char *name, char **xattr_value, if (error) return error; - if (!inode->i_op->getxattr) + handler = xattr_resolve_name(inode, &name); + if (IS_ERR(handler)) + return PTR_ERR(handler); + if (!handler->get) return -EOPNOTSUPP; - - error = inode->i_op->getxattr(dentry, inode, name, NULL, 0); + error = handler->get(handler, dentry, inode, name, NULL, 0); if (error < 0) return error; @@ -279,7 +286,7 @@ vfs_getxattr_alloc(struct dentry *dentry, const char *name, char **xattr_value, memset(value, 0, error + 1); } - error = inode->i_op->getxattr(dentry, inode, name, value, error); + error = handler->get(handler, dentry, inode, name, value, error); *xattr_value = value; return error; } @@ -288,9 +295,14 @@ ssize_t __vfs_getxattr(struct dentry *dentry, struct inode *inode, const char *name, void *value, size_t size) { - if (!inode->i_op->getxattr) + const struct xattr_handler *handler; + + handler = xattr_resolve_name(inode, &name); + if (IS_ERR(handler)) + return PTR_ERR(handler); + if (!handler->get) return -EOPNOTSUPP; - return inode->i_op->getxattr(dentry, inode, name, value, size); + return handler->get(handler, dentry, inode, name, value, size); } EXPORT_SYMBOL(__vfs_getxattr); @@ -349,11 +361,15 @@ EXPORT_SYMBOL_GPL(vfs_listxattr); int __vfs_removexattr(struct dentry *dentry, const char *name) { - struct inode *inode = dentry->d_inode; + struct inode *inode = d_inode(dentry); + const struct xattr_handler *handler; - if (!inode->i_op->removexattr) + handler = xattr_resolve_name(inode, &name); + if (IS_ERR(handler)) + return PTR_ERR(handler); + if (!handler->set) return -EOPNOTSUPP; - return inode->i_op->removexattr(dentry, name); + return handler->set(handler, dentry, inode, name, NULL, 0, XATTR_REPLACE); } EXPORT_SYMBOL(__vfs_removexattr); |