]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/nfs/nfs3acl.c
[PATCH] x86/x86_64: mark rodata section read-only: make some datastructures const
[linux-2.6-omap-h63xx.git] / fs / nfs / nfs3acl.c
index 393ba79fc14fbe718fc5a2892b134f82d9a8993b..6a5bbc0ae941aa690e1f73137cbce4af38902092 100644 (file)
@@ -2,7 +2,7 @@
 #include <linux/nfs.h>
 #include <linux/nfs3.h>
 #include <linux/nfs_fs.h>
-#include <linux/xattr_acl.h>
+#include <linux/posix_acl_xattr.h>
 #include <linux/nfsacl.h>
 
 #define NFSDBG_FACILITY        NFSDBG_PROC
@@ -53,9 +53,9 @@ ssize_t nfs3_getxattr(struct dentry *dentry, const char *name,
        struct posix_acl *acl;
        int type, error = 0;
 
-       if (strcmp(name, XATTR_NAME_ACL_ACCESS) == 0)
+       if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0)
                type = ACL_TYPE_ACCESS;
-       else if (strcmp(name, XATTR_NAME_ACL_DEFAULT) == 0)
+       else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0)
                type = ACL_TYPE_DEFAULT;
        else
                return -EOPNOTSUPP;
@@ -82,9 +82,9 @@ int nfs3_setxattr(struct dentry *dentry, const char *name,
        struct posix_acl *acl;
        int type, error;
 
-       if (strcmp(name, XATTR_NAME_ACL_ACCESS) == 0)
+       if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0)
                type = ACL_TYPE_ACCESS;
-       else if (strcmp(name, XATTR_NAME_ACL_DEFAULT) == 0)
+       else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0)
                type = ACL_TYPE_DEFAULT;
        else
                return -EOPNOTSUPP;
@@ -103,9 +103,9 @@ int nfs3_removexattr(struct dentry *dentry, const char *name)
        struct inode *inode = dentry->d_inode;
        int type;
 
-       if (strcmp(name, XATTR_NAME_ACL_ACCESS) == 0)
+       if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0)
                type = ACL_TYPE_ACCESS;
-       else if (strcmp(name, XATTR_NAME_ACL_DEFAULT) == 0)
+       else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0)
                type = ACL_TYPE_DEFAULT;
        else
                return -EOPNOTSUPP;
@@ -113,6 +113,70 @@ int nfs3_removexattr(struct dentry *dentry, const char *name)
        return nfs3_proc_setacl(inode, type, NULL);
 }
 
+static void __nfs3_forget_cached_acls(struct nfs_inode *nfsi)
+{
+       if (!IS_ERR(nfsi->acl_access)) {
+               posix_acl_release(nfsi->acl_access);
+               nfsi->acl_access = ERR_PTR(-EAGAIN);
+       }
+       if (!IS_ERR(nfsi->acl_default)) {
+               posix_acl_release(nfsi->acl_default);
+               nfsi->acl_default = ERR_PTR(-EAGAIN);
+       }
+}
+
+void nfs3_forget_cached_acls(struct inode *inode)
+{
+       dprintk("NFS: nfs3_forget_cached_acls(%s/%ld)\n", inode->i_sb->s_id,
+               inode->i_ino);
+       spin_lock(&inode->i_lock);
+       __nfs3_forget_cached_acls(NFS_I(inode));
+       spin_unlock(&inode->i_lock);
+}
+
+static struct posix_acl *nfs3_get_cached_acl(struct inode *inode, int type)
+{
+       struct nfs_inode *nfsi = NFS_I(inode);
+       struct posix_acl *acl = ERR_PTR(-EINVAL);
+
+       spin_lock(&inode->i_lock);
+       switch(type) {
+               case ACL_TYPE_ACCESS:
+                       acl = nfsi->acl_access;
+                       break;
+
+               case ACL_TYPE_DEFAULT:
+                       acl = nfsi->acl_default;
+                       break;
+
+               default:
+                       goto out;
+       }
+       if (IS_ERR(acl))
+               acl = ERR_PTR(-EAGAIN);
+       else
+               acl = posix_acl_dup(acl);
+out:
+       spin_unlock(&inode->i_lock);
+       dprintk("NFS: nfs3_get_cached_acl(%s/%ld, %d) = %p\n", inode->i_sb->s_id,
+               inode->i_ino, type, acl);
+       return acl;
+}
+
+static void nfs3_cache_acls(struct inode *inode, struct posix_acl *acl,
+                   struct posix_acl *dfacl)
+{
+       struct nfs_inode *nfsi = NFS_I(inode);
+
+       dprintk("nfs3_cache_acls(%s/%ld, %p, %p)\n", inode->i_sb->s_id,
+               inode->i_ino, acl, dfacl);
+       spin_lock(&inode->i_lock);
+       __nfs3_forget_cached_acls(NFS_I(inode));
+       nfsi->acl_access = posix_acl_dup(acl);
+       nfsi->acl_default = posix_acl_dup(dfacl);
+       spin_unlock(&inode->i_lock);
+}
+
 struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type)
 {
        struct nfs_server *server = NFS_SERVER(inode);
@@ -126,26 +190,32 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type)
        struct nfs3_getaclres res = {
                .fattr =        &fattr,
        };
-       struct posix_acl *acl = NULL;
+       struct posix_acl *acl;
        int status, count;
 
        if (!nfs_server_capable(inode, NFS_CAP_ACLS))
                return ERR_PTR(-EOPNOTSUPP);
 
-       switch (type) {
-               case ACL_TYPE_ACCESS:
-                       args.mask = NFS_ACLCNT|NFS_ACL;
-                       break;
-
-               case ACL_TYPE_DEFAULT:
-                       if (!S_ISDIR(inode->i_mode))
-                               return NULL;
-                       args.mask = NFS_DFACLCNT|NFS_DFACL;
-                       break;
-
-               default:
-                       return ERR_PTR(-EINVAL);
-       }
+       status = nfs_revalidate_inode(server, inode);
+       if (status < 0)
+               return ERR_PTR(status);
+       acl = nfs3_get_cached_acl(inode, type);
+       if (acl != ERR_PTR(-EAGAIN))
+               return acl;
+       acl = NULL;
+
+       /*
+        * Only get the access acl when explicitly requested: We don't
+        * need it for access decisions, and only some applications use
+        * it. Applications which request the access acl first are not
+        * penalized from this optimization.
+        */
+       if (type == ACL_TYPE_ACCESS)
+               args.mask |= NFS_ACLCNT|NFS_ACL;
+       if (S_ISDIR(inode->i_mode))
+               args.mask |= NFS_DFACLCNT|NFS_DFACL;
+       if (args.mask == 0)
+               return NULL;
 
        dprintk("NFS call getacl\n");
        status = rpc_call(server->client_acl, ACLPROC3_GETACL,
@@ -180,6 +250,7 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type)
                        res.acl_access = NULL;
                }
        }
+       nfs3_cache_acls(inode, res.acl_access, res.acl_default);
 
        switch(type) {
                case ACL_TYPE_ACCESS:
@@ -237,7 +308,9 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
        nfs_begin_data_update(inode);
        status = rpc_call(server->client_acl, ACLPROC3_SETACL,
                          &args, &fattr, 0);
-       NFS_FLAGS(inode) |= NFS_INO_INVALID_ACCESS;
+       spin_lock(&inode->i_lock);
+       NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ACCESS;
+       spin_unlock(&inode->i_lock);
        nfs_end_data_update(inode);
        dprintk("NFS reply setacl: %d\n", status);
 
@@ -301,3 +374,32 @@ int nfs3_proc_setacl(struct inode *inode, int type, struct posix_acl *acl)
 fail:
        return PTR_ERR(alloc);
 }
+
+int nfs3_proc_set_default_acl(struct inode *dir, struct inode *inode,
+               mode_t mode)
+{
+       struct posix_acl *dfacl, *acl;
+       int error = 0;
+
+       dfacl = nfs3_proc_getacl(dir, ACL_TYPE_DEFAULT);
+       if (IS_ERR(dfacl)) {
+               error = PTR_ERR(dfacl);
+               return (error == -EOPNOTSUPP) ? 0 : error;
+       }
+       if (!dfacl)
+               return 0;
+       acl = posix_acl_clone(dfacl, GFP_KERNEL);
+       error = -ENOMEM;
+       if (!acl)
+               goto out_release_dfacl;
+       error = posix_acl_create_masq(acl, &mode);
+       if (error < 0)
+               goto out_release_acl;
+       error = nfs3_proc_setacls(inode, acl, S_ISDIR(inode->i_mode) ?
+                                                     dfacl : NULL);
+out_release_acl:
+       posix_acl_release(acl);
+out_release_dfacl:
+       posix_acl_release(dfacl);
+       return error;
+}