fs/9p: Implement POSIX ACL permission checking function
Aneesh Kumar K.V [Mon, 27 Sep 2010 18:57:39 +0000 (23:57 +0530)]
The ACL value is fetched as a part of inode initialization
from the server and the permission checking function use the
cached value of the ACL

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/Kconfig
fs/9p/Makefile
fs/9p/acl.c [new file with mode: 0644]
fs/9p/acl.h [new file with mode: 0644]
fs/9p/vfs_inode.c
fs/9p/vfs_super.c
fs/9p/xattr.c
fs/9p/xattr.h

index 7952337..7e05114 100644 (file)
@@ -17,3 +17,16 @@ config 9P_FSCACHE
          Choose Y here to enable persistent, read-only local
          caching support for 9p clients using FS-Cache
 
+
+config 9P_FS_POSIX_ACL
+       bool "9P POSIX Access Control Lists"
+       depends on 9P_FS
+       select FS_POSIX_ACL
+       help
+         POSIX Access Control Lists (ACLs) support permissions for users and
+         groups beyond the owner/group/world scheme.
+
+         To learn more about Access Control Lists, visit the POSIX ACLs for
+         Linux website <http://acl.bestbits.at/>.
+
+         If you don't know what Access Control Lists are, say N
index 91fba02..f8ba37e 100644 (file)
@@ -13,3 +13,4 @@ obj-$(CONFIG_9P_FS) := 9p.o
        xattr_user.o
 
 9p-$(CONFIG_9P_FSCACHE) += cache.o
+9p-$(CONFIG_9P_FS_POSIX_ACL) += acl.o
diff --git a/fs/9p/acl.c b/fs/9p/acl.c
new file mode 100644 (file)
index 0000000..a8c0136
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * 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 <net/9p/9p.h>
+#include <net/9p/client.h>
+#include <linux/slab.h>
+#include <linux/posix_acl_xattr.h>
+#include "xattr.h"
+#include "acl.h"
+
+static struct posix_acl *__v9fs_get_acl(struct p9_fid *fid, char *name)
+{
+       ssize_t size;
+       void *value = NULL;
+       struct posix_acl *acl = NULL;;
+
+       size = v9fs_fid_xattr_get(fid, name, NULL, 0);
+       if (size > 0) {
+               value = kzalloc(size, GFP_NOFS);
+               if (!value)
+                       return ERR_PTR(-ENOMEM);
+               size = v9fs_fid_xattr_get(fid, name, value, size);
+               if (size > 0) {
+                       acl = posix_acl_from_xattr(value, size);
+                       if (IS_ERR(acl))
+                               goto err_out;
+               }
+       } else if (size == -ENODATA || size == 0 ||
+                  size == -ENOSYS || size == -EOPNOTSUPP) {
+               acl = NULL;
+       } else
+               acl = ERR_PTR(-EIO);
+
+err_out:
+       kfree(value);
+       return acl;
+}
+
+int v9fs_get_acl(struct inode *inode, struct p9_fid *fid)
+{
+       int retval = 0;
+       struct posix_acl *pacl, *dacl;
+
+       /* get the default/access acl values and cache them */
+       dacl = __v9fs_get_acl(fid, POSIX_ACL_XATTR_DEFAULT);
+       pacl = __v9fs_get_acl(fid, POSIX_ACL_XATTR_ACCESS);
+
+       if (!IS_ERR(dacl) && !IS_ERR(pacl)) {
+               set_cached_acl(inode, ACL_TYPE_DEFAULT, dacl);
+               set_cached_acl(inode, ACL_TYPE_ACCESS, pacl);
+               posix_acl_release(dacl);
+               posix_acl_release(pacl);
+       } else
+               retval = -EIO;
+
+       return retval;
+}
+
+static struct posix_acl *v9fs_get_cached_acl(struct inode *inode, int type)
+{
+       struct posix_acl *acl;
+       /*
+        * 9p Always cache the acl value when
+        * instantiating the inode (v9fs_inode_from_fid)
+        */
+       acl = get_cached_acl(inode, type);
+       BUG_ON(acl == ACL_NOT_CACHED);
+       return acl;
+}
+
+int v9fs_check_acl(struct inode *inode, int mask)
+{
+       struct posix_acl *acl = v9fs_get_cached_acl(inode, ACL_TYPE_ACCESS);
+
+       if (IS_ERR(acl))
+               return PTR_ERR(acl);
+       if (acl) {
+               int error = posix_acl_permission(inode, acl, mask);
+               posix_acl_release(acl);
+               return error;
+       }
+       return -EAGAIN;
+}
diff --git a/fs/9p/acl.h b/fs/9p/acl.h
new file mode 100644 (file)
index 0000000..b1414f7
--- /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_ACL_H
+#define FS_9P_ACL_H
+
+#ifdef CONFIG_9P_FS_POSIX_ACL
+extern int v9fs_get_acl(struct inode *, struct p9_fid *);
+extern int v9fs_check_acl(struct inode *inode, int mask);
+#else
+#define v9fs_check_acl NULL
+static inline int v9fs_get_acl(struct inode *inode, struct p9_fid *fid)
+{
+       return 0;
+}
+#endif
+#endif /* FS_9P_XATTR_H */
index c3d200d..1249b83 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/xattr.h>
+#include <linux/posix_acl.h>
 #include <net/9p/9p.h>
 #include <net/9p/client.h>
 
@@ -44,6 +45,7 @@
 #include "fid.h"
 #include "cache.h"
 #include "xattr.h"
+#include "acl.h"
 
 static const struct inode_operations v9fs_dir_inode_operations;
 static const struct inode_operations v9fs_dir_inode_operations_dotu;
@@ -500,6 +502,11 @@ v9fs_inode_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid,
        v9fs_vcookie_set_qid(ret, &st->qid);
        v9fs_cache_inode_get_cookie(ret);
 #endif
+       err = v9fs_get_acl(ret, fid);
+       if (err) {
+               iput(ret);
+               goto error;
+       }
        kfree(st);
        return ret;
 error:
@@ -1959,7 +1966,7 @@ static const struct inode_operations v9fs_dir_inode_operations_dotl = {
        .getxattr = generic_getxattr,
        .removexattr = generic_removexattr,
        .listxattr = v9fs_listxattr,
-
+       .check_acl = v9fs_check_acl,
 };
 
 static const struct inode_operations v9fs_dir_inode_operations = {
@@ -1986,6 +1993,7 @@ static const struct inode_operations v9fs_file_inode_operations_dotl = {
        .getxattr = generic_getxattr,
        .removexattr = generic_removexattr,
        .listxattr = v9fs_listxattr,
+       .check_acl = v9fs_check_acl,
 };
 
 static const struct inode_operations v9fs_symlink_inode_operations = {
index 1d12ba0..14da577 100644 (file)
@@ -46,6 +46,7 @@
 #include "v9fs_vfs.h"
 #include "fid.h"
 #include "xattr.h"
+#include "acl.h"
 
 static const struct super_operations v9fs_super_ops, v9fs_super_ops_dotl;
 
@@ -88,6 +89,10 @@ v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses,
        sb->s_flags = flags | MS_ACTIVE | MS_SYNCHRONOUS | MS_DIRSYNC |
            MS_NOATIME;
 
+#ifdef CONFIG_9P_FS_POSIX_ACL
+       sb->s_flags |= MS_POSIXACL;
+#endif
+
        save_mount_options(sb, data);
 }
 
@@ -149,7 +154,6 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
                goto release_sb;
        }
        sb->s_root = root;
-
        if (v9fs_proto_dotl(v9ses)) {
                struct p9_stat_dotl *st = NULL;
                st = p9_client_getattr_dotl(fid, P9_STATS_BASIC);
@@ -174,6 +178,9 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
                p9stat_free(st);
                kfree(st);
        }
+       retval = v9fs_get_acl(inode, fid);
+       if (retval)
+               goto release_sb;
 
        v9fs_fid_add(root, fid);
 
index f88e5c2..67ac6cf 100644 (file)
 #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 v9fs_fid_xattr_get(struct p9_fid *fid, 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);
+       struct p9_fid *attr_fid;
 
        attr_fid = p9_client_xattrwalk(fid, name, &attr_size);
        if (IS_ERR(attr_fid)) {
@@ -88,6 +71,31 @@ error:
 
 }
 
+
+/*
+ * 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)
+{
+       struct p9_fid *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);
+
+       return v9fs_fid_xattr_get(fid, name, buffer, buffer_size);
+}
+
 /*
  * v9fs_xattr_set()
  *
index 9ddf672..ec908c6 100644 (file)
 #define FS_9P_XATTR_H
 
 #include <linux/xattr.h>
+#include <net/9p/9p.h>
+#include <net/9p/client.h>
 
 extern const struct xattr_handler *v9fs_xattr_handlers[];
 extern struct xattr_handler v9fs_xattr_user_handler;
 
+extern ssize_t v9fs_fid_xattr_get(struct p9_fid *, const char *,
+                                 void *, size_t);
 extern ssize_t v9fs_xattr_get(struct dentry *, const char *,
                              void *, size_t);
 extern int v9fs_xattr_set(struct dentry *, const char *,