From: Vyacheslav Dubeyko <slava@xxxxxxxxxxx> Subject: [RFC][PATCH 09/15] nilfs2: implement listxattr and getxattr functionality This patch adds functionality listxattr and getxattr operations. Signed-off-by: Vyacheslav Dubeyko <slava@xxxxxxxxxxx> CC: Ryusuke Konishi <konishi.ryusuke@xxxxxxxxxxxxx> --- fs/nilfs2/xafile.c | 167 ++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/nilfs2/xafile.h | 20 +++++++ fs/nilfs2/xattr.c | 64 ++++++++++++++++++++ fs/nilfs2/xattr.h | 44 ++++++++++++++ 4 files changed, 295 insertions(+) create mode 100644 fs/nilfs2/xattr.c create mode 100644 fs/nilfs2/xattr.h diff --git a/fs/nilfs2/xafile.c b/fs/nilfs2/xafile.c index 6511da7..e89e95b 100644 --- a/fs/nilfs2/xafile.c +++ b/fs/nilfs2/xafile.c @@ -220,6 +220,19 @@ struct nilfs_xattr_search { (!IS_SEARCH_KEY_EMPTY(data) && \ IS_SEARCH_RESULT_EMPTY(data)) +/* Map of xattr handlers */ +static const struct xattr_handler *nilfs_xattr_handler_map[] = { + [NILFS_USER_XATTR_ID] = &nilfs_xattr_user_handler, +#ifdef CONFIG_NILFS2_FS_POSIX_ACL + [NILFS_POSIX_ACL_ACCESS_XATTR_ID] = &nilfs_xattr_acl_access_handler, + [NILFS_POSIX_ACL_DEFAULT_XATTR_ID] = &nilfs_xattr_acl_default_handler, +#endif + [NILFS_TRUSTED_XATTR_ID] = &nilfs_xattr_trusted_handler, +#ifdef CONFIG_NILFS2_FS_SECURITY + [NILFS_SECURITY_XATTR_ID] = &nilfs_xattr_security_handler, +#endif +}; + /* * NILFS_XAFILE_I - convert inode info into xafile inode info */ @@ -230,6 +243,19 @@ struct nilfs_xafile_info *NILFS_XAFILE_I(struct inode *xafile) } /* + * nilfs_xattr_handler - get xattr handler by name index + */ +static inline +const struct xattr_handler *nilfs_xattr_handler(int name_index) +{ + const struct xattr_handler *handler = NULL; + + if (name_index > 0 && name_index < ARRAY_SIZE(nilfs_xattr_handler_map)) + handler = nilfs_xattr_handler_map[name_index]; + return handler; +} + +/* * nilfs_xafile_get_node - get xafile node * @xafile: xafile inode * @node_id: node number @@ -1300,3 +1326,144 @@ void nilfs_xafile_abort_new_node(struct inode *inode, nilfs_xafile_abort_node_creation(xafile, &data->node.req); nilfs_xafile_abort_node_change(data); } + +/* + * nilfs_xattr_list_entries - list inode's xattrs from one xanode + * @dentry: dentry object + * @bh: xanode's buffer + * @buf: buffer for getting xattrs' list [out] + * @size: buffer size + */ +static +int nilfs_xattr_list_entries(struct dentry *dentry, struct buffer_head *bh, + char *buf, size_t buf_size) +{ + union nilfs_xanode_header *hdr = NILFS_XANODE_HDR(BH_DATA(bh)); + union nilfs_xattr_key *key; + size_t rest = buf_size; + + key = NILFS_XANODE_FIRST_NOT_INDEX_KEY(hdr); + + for (; !IS_END_KEY(key); key = NEXT_KEY(key, 1)) { + u8 name_index = NILFS_XANODE_NAME_HASH(key)->name_index; + const struct nilfs_xanode_entry *entry = + NILFS_XANODE_ENTRY(key, BH_DATA(bh)); + const struct xattr_handler *handler = + nilfs_xattr_handler(name_index); + __u8 name_len = NILFS_XANODE_NAME_HASH(key)->name_len; + + if (handler) { + size_t size = handler->list(dentry, buf, rest, + entry->name, name_len, + handler->flags); + if (buf) { + if (size > rest) + return -ERANGE; + buf += size; + } + rest -= size; + } + } + + return buf_size - rest; +} + +/* + * nilfs_xafile_listxattr - list all inode's xattrs + * @dentry: dentry object + * @buffer: buffer for getting xattrs' list [out] + * @size: buffer size + */ +ssize_t nilfs_xafile_listxattr(struct dentry *dentry, char *buffer, size_t size) +{ + ssize_t ret = 0, err = 0; + struct inode *inode = dentry->d_inode; + struct the_nilfs *nilfs = inode->i_sb->s_fs_info; + struct buffer_head *bh = NULL; + __u64 node = NILFS_I(inode)->i_xattr; + + if (!nilfs_has_xafile(nilfs)) + return -EOPNOTSUPP; + + if (node == NILFS_INVALID_XANODE) + return 0; + + err = nilfs_xafile_get_checked_node(inode, node, &bh); + if (unlikely(err)) + goto failed_xafile_listxattr; + + err = nilfs_xattr_list_entries(dentry, bh, buffer, size); + if (unlikely(err < 0)) + goto cleanup_after_failure; + else + ret += err; + + brelse(bh); + return ret; + +cleanup_after_failure: + brelse(bh); + +failed_xafile_listxattr: + return err; +} + +/* + * nilfs_xafile_getxattr - get xattr + * @inode: inode pointer + * @name: xattr's name + * @value: buffer for xattr's value [out] + * @size: buffer size + */ +ssize_t nilfs_xafile_getxattr(struct inode *inode, + int name_index, const char *name, + void *value, size_t size) +{ + ssize_t ret, err; + struct the_nilfs *nilfs = inode->i_sb->s_fs_info; + struct nilfs_xattr_search data; + + if (!nilfs_has_xafile(nilfs)) + return -EOPNOTSUPP; + + if (NILFS_I(inode)->i_xattr == NILFS_INVALID_XANODE) + return -ENODATA; + + err = nilfs_xattr_search_init(inode, name_index, (char *)name, &data); + if (unlikely(err)) + return err; + + err = nilfs_xafile_find_node(inode, &data); + if (unlikely(err)) { + ret = err; + goto failed_xafile_getxattr; + } + + if (!data.result.found) { + ret = -ENODATA; + goto cleanup_after_failure; + } + + ret = NILFS_XANODE_ENTRY_SIZE(data.result.key) - + NILFS_XANODE_NAME_HASH(data.result.key)->name_len; + + if (value) { + char *xattr_value; + + if (ret > size) { + ret = -ERANGE; + goto cleanup_after_failure; + } + + xattr_value = NILFS_XATTR_VALUE(data.result.entry, + data.result.key); + memcpy(value, xattr_value, ret); + } + +cleanup_after_failure: + brelse(NODE_BH(&data.node)); + +failed_xafile_getxattr: + nilfs_xattr_search_release(&data); + return ret; +} diff --git a/fs/nilfs2/xafile.h b/fs/nilfs2/xafile.h index 846ea3a..50c4735 100644 --- a/fs/nilfs2/xafile.h +++ b/fs/nilfs2/xafile.h @@ -29,6 +29,20 @@ /* Magic number of xafile node */ #define NILFS_XANODE_MAGIC 0x5841 /* XA */ +/* Name indexes */ +#define NILFS_USER_XATTR_ID 1 +#define NILFS_POSIX_ACL_ACCESS_XATTR_ID 2 +#define NILFS_POSIX_ACL_DEFAULT_XATTR_ID 3 +#define NILFS_TRUSTED_XATTR_ID 4 +#define NILFS_SECURITY_XATTR_ID 5 +#define NILFS_SYSTEM_XATTR_ID 6 +#define NILFS_RICHACL_XATTR_ID 7 +#define NILFS_XATTR_MAX_ID 255 + +#define IS_NAME_ID_VALID(name_index) \ + (name_index < NILFS_USER_XATTR_ID || \ + name_index > NILFS_RICHACL_XATTR_ID) + /* Xanode types */ #define NILFS_UNKNOWN_XANODE_TYPE 0 /* Temporary, numbers from 1 till 6 are simply reserved */ @@ -417,6 +431,12 @@ NILFS_XANODE_LAST_ENTRY(union nilfs_xanode_header *hdr) #define NILFS_XATTR_VALUE(entry, key) \ ((char *)(entry) + NILFS_XANODE_NAME_HASH(key)->name_len) +extern const struct xattr_handler nilfs_xattr_user_handler; +extern const struct xattr_handler nilfs_xattr_trusted_handler; +extern const struct xattr_handler nilfs_xattr_acl_access_handler; +extern const struct xattr_handler nilfs_xattr_acl_default_handler; +extern const struct xattr_handler nilfs_xattr_security_handler; + /* Xafile API */ ssize_t nilfs_xafile_listxattr(struct dentry *dentry, char *buf, size_t size); ssize_t nilfs_xafile_getxattr(struct inode *inode, diff --git a/fs/nilfs2/xattr.c b/fs/nilfs2/xattr.c new file mode 100644 index 0000000..7be523a --- /dev/null +++ b/fs/nilfs2/xattr.c @@ -0,0 +1,64 @@ +/* + * xattr.c - NILFS extended attributes support implementation. + * + * Copyright (C) 2005-2013 Nippon Telegraph and Telephone Corporation. + * Copyright (C) 2013 Vyacheslav Dubeyko <slava@xxxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Written by Vyacheslav Dubeyko <slava@xxxxxxxxxxx> + */ + +#include "nilfs.h" +#include "xafile.h" +#include "xattr.h" + +const struct xattr_handler *nilfs_xattr_handlers[] = { + &nilfs_xattr_user_handler, + &nilfs_xattr_trusted_handler, +#ifdef CONFIG_NILFS2_FS_POSIX_ACL + &nilfs_xattr_acl_access_handler, + &nilfs_xattr_acl_default_handler, +#endif +#ifdef CONFIG_NILFS2_FS_SECURITY + &nilfs_xattr_security_handler, +#endif + NULL +}; + +ssize_t nilfs_listxattr(struct dentry *dentry, char *buffer, size_t size) +{ + ssize_t ret; + struct inode *inode = dentry->d_inode; + + down_read(&NILFS_I(inode)->xattr_sem); + ret = nilfs_xafile_listxattr(dentry, buffer, size); + up_read(&NILFS_I(inode)->xattr_sem); + + return ret; +} + +ssize_t __nilfs_getxattr(struct inode *inode, + int name_index, const char *name, + void *value, size_t size) +{ + ssize_t ret; + + down_read(&NILFS_I(inode)->xattr_sem); + ret = nilfs_xafile_getxattr(inode, name_index, name, value, size); + up_read(&NILFS_I(inode)->xattr_sem); + + return ret; +} diff --git a/fs/nilfs2/xattr.h b/fs/nilfs2/xattr.h new file mode 100644 index 0000000..0736086 --- /dev/null +++ b/fs/nilfs2/xattr.h @@ -0,0 +1,44 @@ +/* + * xattr.h - NILFS extended attributes declarations. + * + * Copyright (C) 2005-2013 Nippon Telegraph and Telephone Corporation. + * Copyright (C) 2013 Vyacheslav Dubeyko <slava@xxxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Written by Vyacheslav Dubeyko <slava@xxxxxxxxxxx> + */ + +#ifndef _NILFS_XATTR_H +#define _NILFS_XATTR_H + +#include <linux/xattr.h> + +extern const struct xattr_handler *nilfs_xattr_handlers[]; + +ssize_t __nilfs_getxattr(struct inode *inode, + int name_index, const char *name, + void *value, size_t size); + +static inline ssize_t nilfs_getxattr(struct dentry *dentry, + int name_index, const char *name, + void *value, size_t size) +{ + return __nilfs_getxattr(dentry->d_inode, name_index, name, value, size); +} + +ssize_t nilfs_listxattr(struct dentry *dentry, char *buffer, size_t size); + +#endif /* _NILFS_XATTR_H */ -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html