fs/9p: Add support user. xattr
authorAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Mon, 31 May 2010 07:52:56 +0000 (13:22 +0530)
committerEric Van Hensbergen <ericvh@gmail.com>
Mon, 2 Aug 2010 19:28:35 +0000 (14:28 -0500)
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Venkateswararao Jujjuri <jvrao@linux.vnet.ibm.com>
Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com>
fs/9p/Makefile
fs/9p/vfs_inode.c
fs/9p/vfs_super.c
fs/9p/xattr.c [new file with mode: 0644]
fs/9p/xattr.h [new file with mode: 0644]
fs/9p/xattr_user.c [new file with mode: 0644]

index 1a940ec..91fba02 100644 (file)
@@ -8,6 +8,8 @@ obj-$(CONFIG_9P_FS) := 9p.o
        vfs_dir.o \
        vfs_dentry.o \
        v9fs.o \
-       fid.o
+       fid.o  \
+       xattr.o \
+       xattr_user.o
 
 9p-$(CONFIG_9P_FSCACHE) += cache.o
index 2ac2459..39352ef 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/idr.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/xattr.h>
 #include <net/9p/9p.h>
 #include <net/9p/client.h>
 
@@ -42,6 +43,7 @@
 #include "v9fs_vfs.h"
 #include "fid.h"
 #include "cache.h"
+#include "xattr.h"
 
 static const struct inode_operations v9fs_dir_inode_operations;
 static const struct inode_operations v9fs_dir_inode_operations_dotu;
@@ -1931,6 +1933,11 @@ static const struct inode_operations v9fs_dir_inode_operations_dotl = {
        .rename = v9fs_vfs_rename,
        .getattr = v9fs_vfs_getattr_dotl,
        .setattr = v9fs_vfs_setattr_dotl,
+       .setxattr = generic_setxattr,
+       .getxattr = generic_getxattr,
+       .removexattr = generic_removexattr,
+       .listxattr = v9fs_listxattr,
+
 };
 
 static const struct inode_operations v9fs_dir_inode_operations = {
@@ -1953,6 +1960,10 @@ static const struct inode_operations v9fs_file_inode_operations = {
 static const struct inode_operations v9fs_file_inode_operations_dotl = {
        .getattr = v9fs_vfs_getattr_dotl,
        .setattr = v9fs_vfs_setattr_dotl,
+       .setxattr = generic_setxattr,
+       .getxattr = generic_getxattr,
+       .removexattr = generic_removexattr,
+       .listxattr = v9fs_listxattr,
 };
 
 static const struct inode_operations v9fs_symlink_inode_operations = {
@@ -1969,4 +1980,8 @@ static const struct inode_operations v9fs_symlink_inode_operations_dotl = {
        .put_link = v9fs_vfs_put_link,
        .getattr = v9fs_vfs_getattr_dotl,
        .setattr = v9fs_vfs_setattr_dotl,
+       .setxattr = generic_setxattr,
+       .getxattr = generic_getxattr,
+       .removexattr = generic_removexattr,
+       .listxattr = v9fs_listxattr,
 };
index 3623f69..0a2e203 100644 (file)
@@ -45,6 +45,7 @@
 #include "v9fs.h"
 #include "v9fs_vfs.h"
 #include "fid.h"
+#include "xattr.h"
 
 static const struct super_operations v9fs_super_ops, v9fs_super_ops_dotl;
 
@@ -77,9 +78,10 @@ v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses,
        sb->s_blocksize_bits = fls(v9ses->maxdata - 1);
        sb->s_blocksize = 1 << sb->s_blocksize_bits;
        sb->s_magic = V9FS_MAGIC;
-       if (v9fs_proto_dotl(v9ses))
+       if (v9fs_proto_dotl(v9ses)) {
                sb->s_op = &v9fs_super_ops_dotl;
-       else
+               sb->s_xattr = v9fs_xattr_handlers;
+       } else
                sb->s_op = &v9fs_super_ops;
        sb->s_bdi = &v9ses->bdi;
 
diff --git a/fs/9p/xattr.c b/fs/9p/xattr.c
new file mode 100644 (file)
index 0000000..c434424
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Copyright IBM Corporation, 2010
+ * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <net/9p/9p.h>
+#include <net/9p/client.h>
+
+#include "fid.h"
+#include "xattr.h"
+
+/*
+ * v9fs_xattr_get()
+ *
+ * Copy an extended attribute into the buffer
+ * provided, or compute the buffer size required.
+ * Buffer is NULL to compute the size of the buffer required.
+ *
+ * Returns a negative error number on failure, or the number of bytes
+ * used / required on success.
+ */
+ssize_t v9fs_xattr_get(struct dentry *dentry, const char *name,
+                      void *buffer, size_t buffer_size)
+{
+       ssize_t retval;
+       int msize, read_count;
+       u64 offset = 0, attr_size;
+       struct p9_fid *fid, *attr_fid;
+
+       P9_DPRINTK(P9_DEBUG_VFS, "%s: name = %s value_len = %zu\n",
+               __func__, name, buffer_size);
+
+       fid = v9fs_fid_lookup(dentry);
+       if (IS_ERR(fid))
+               return PTR_ERR(fid);
+
+       attr_fid = p9_client_xattrwalk(fid, name, &attr_size);
+       if (IS_ERR(attr_fid)) {
+               retval = PTR_ERR(attr_fid);
+               P9_DPRINTK(P9_DEBUG_VFS,
+                       "p9_client_attrwalk failed %zd\n", retval);
+               attr_fid = NULL;
+               goto error;
+       }
+       if (!buffer_size) {
+               /* request to get the attr_size */
+               retval = attr_size;
+               goto error;
+       }
+       if (attr_size > buffer_size) {
+               retval = -ERANGE;
+               goto error;
+       }
+       msize = attr_fid->clnt->msize;
+       while (attr_size) {
+               if (attr_size > (msize - P9_IOHDRSZ))
+                       read_count = msize - P9_IOHDRSZ;
+               else
+                       read_count = attr_size;
+               read_count = p9_client_read(attr_fid, ((char *)buffer)+offset,
+                                       0, offset, read_count);
+               if (read_count < 0) {
+                       /* error in xattr read */
+                       retval = read_count;
+                       goto error;
+               }
+               offset += read_count;
+               attr_size -= read_count;
+       }
+       /* Total read xattr bytes */
+       retval = offset;
+error:
+       if (attr_fid)
+               p9_client_clunk(attr_fid);
+       return retval;
+
+}
+
+/*
+ * v9fs_xattr_set()
+ *
+ * Create, replace or remove an extended attribute for this inode. Buffer
+ * is NULL to remove an existing extended attribute, and non-NULL to
+ * either replace an existing extended attribute, or create a new extended
+ * attribute. The flags XATTR_REPLACE and XATTR_CREATE
+ * specify that an extended attribute must exist and must not exist
+ * previous to the call, respectively.
+ *
+ * Returns 0, or a negative error number on failure.
+ */
+int v9fs_xattr_set(struct dentry *dentry, const char *name,
+                  const void *value, size_t value_len, int flags)
+{
+       u64 offset = 0;
+       int retval, msize, write_count;
+       struct p9_fid *fid = NULL;
+
+       P9_DPRINTK(P9_DEBUG_VFS, "%s: name = %s value_len = %zu flags = %d\n",
+               __func__, name, value_len, flags);
+
+       fid = v9fs_fid_clone(dentry);
+       if (IS_ERR(fid)) {
+               retval = PTR_ERR(fid);
+               fid = NULL;
+               goto error;
+       }
+       /*
+        * On success fid points to xattr
+        */
+       retval = p9_client_xattrcreate(fid, name, value_len, flags);
+       if (retval < 0) {
+               P9_DPRINTK(P9_DEBUG_VFS,
+                       "p9_client_xattrcreate failed %d\n", retval);
+               goto error;
+       }
+       msize = fid->clnt->msize;;
+       while (value_len) {
+               if (value_len > (msize - P9_IOHDRSZ))
+                       write_count = msize - P9_IOHDRSZ;
+               else
+                       write_count = value_len;
+               write_count = p9_client_write(fid, ((char *)value)+offset,
+                                       0, offset, write_count);
+               if (write_count < 0) {
+                       /* error in xattr write */
+                       retval = write_count;
+                       goto error;
+               }
+               offset += write_count;
+               value_len -= write_count;
+       }
+       /* Total read xattr bytes */
+       retval = offset;
+error:
+       if (fid)
+               retval = p9_client_clunk(fid);
+       return retval;
+}
+
+ssize_t v9fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
+{
+       return v9fs_xattr_get(dentry, NULL, buffer, buffer_size);
+}
+
+const struct xattr_handler *v9fs_xattr_handlers[] = {
+       &v9fs_xattr_user_handler,
+       NULL
+};
diff --git a/fs/9p/xattr.h b/fs/9p/xattr.h
new file mode 100644 (file)
index 0000000..9ddf672
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright IBM Corporation, 2010
+ * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+#ifndef FS_9P_XATTR_H
+#define FS_9P_XATTR_H
+
+#include <linux/xattr.h>
+
+extern const struct xattr_handler *v9fs_xattr_handlers[];
+extern struct xattr_handler v9fs_xattr_user_handler;
+
+extern ssize_t v9fs_xattr_get(struct dentry *, const char *,
+                             void *, size_t);
+extern int v9fs_xattr_set(struct dentry *, const char *,
+                         const void *, size_t, int);
+extern ssize_t v9fs_listxattr(struct dentry *, char *, size_t);
+#endif /* FS_9P_XATTR_H */
diff --git a/fs/9p/xattr_user.c b/fs/9p/xattr_user.c
new file mode 100644 (file)
index 0000000..d0b701b
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright IBM Corporation, 2010
+ * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include "xattr.h"
+
+static int v9fs_xattr_user_get(struct dentry *dentry, const char *name,
+                       void *buffer, size_t size, int type)
+{
+       int retval;
+       char *full_name;
+       size_t name_len;
+       size_t prefix_len = XATTR_USER_PREFIX_LEN;
+
+       if (name == NULL)
+               return -EINVAL;
+
+       if (strcmp(name, "") == 0)
+               return -EINVAL;
+
+       name_len = strlen(name);
+       full_name = kmalloc(prefix_len + name_len + 1 , GFP_KERNEL);
+       if (!full_name)
+               return -ENOMEM;
+       memcpy(full_name, XATTR_USER_PREFIX, prefix_len);
+       memcpy(full_name+prefix_len, name, name_len);
+       full_name[prefix_len + name_len] = '\0';
+
+       retval = v9fs_xattr_get(dentry, full_name, buffer, size);
+       kfree(full_name);
+       return retval;
+}
+
+static int v9fs_xattr_user_set(struct dentry *dentry, const char *name,
+                       const void *value, size_t size, int flags, int type)
+{
+       int retval;
+       char *full_name;
+       size_t name_len;
+       size_t prefix_len = XATTR_USER_PREFIX_LEN;
+
+       if (name == NULL)
+               return -EINVAL;
+
+       if (strcmp(name, "") == 0)
+               return -EINVAL;
+
+       name_len = strlen(name);
+       full_name = kmalloc(prefix_len + name_len + 1 , GFP_KERNEL);
+       if (!full_name)
+               return -ENOMEM;
+       memcpy(full_name, XATTR_USER_PREFIX, prefix_len);
+       memcpy(full_name + prefix_len, name, name_len);
+       full_name[prefix_len + name_len] = '\0';
+
+       retval = v9fs_xattr_set(dentry, full_name, value, size, flags);
+       kfree(full_name);
+       return retval;
+}
+
+struct xattr_handler v9fs_xattr_user_handler = {
+       .prefix = XATTR_USER_PREFIX,
+       .get    = v9fs_xattr_user_get,
+       .set    = v9fs_xattr_user_set,
+};