fs: provide simple rcu-walk generic_check_acl implementation
authorNick Piggin <npiggin@kernel.dk>
Fri, 7 Jan 2011 06:49:59 +0000 (17:49 +1100)
committerNick Piggin <npiggin@kernel.dk>
Fri, 7 Jan 2011 06:50:29 +0000 (17:50 +1100)
This simple implementation just checks for no ACLs on the inode, and
if so, then the rcu-walk may proceed, otherwise fail it.

This could easily be extended to put acls under RCU and check them
under seqlock, if need be. But this implementation is enough to show
the rcu-walk aware permissions code for path lookups is working, and
will handle cases where there are no ACLs or ACLs in just the final
element.

This patch implicity converts tmpfs to rcu-aware permission check.
Subsequent patches onvert ext*, xfs, and, btrfs. Each of these uses
acl/permission code in a different way, so convert them all to provide
templates and proof of concept.

Signed-off-by: Nick Piggin <npiggin@kernel.dk>
fs/generic_acl.c
include/linux/posix_acl.h

index 628004282130029d3d9b7bf06707a48161abe599..06c48a89183293b86e25d87329cb2d6aa6e3b775 100644 (file)
@@ -192,16 +192,18 @@ generic_acl_chmod(struct inode *inode)
 int
 generic_check_acl(struct inode *inode, int mask, unsigned int flags)
 {
-       struct posix_acl *acl;
-
-       if (flags & IPERM_FLAG_RCU)
-               return -ECHILD;
-
-       acl = get_cached_acl(inode, ACL_TYPE_ACCESS);
-       if (acl) {
-               int error = posix_acl_permission(inode, acl, mask);
-               posix_acl_release(acl);
-               return error;
+       if (flags & IPERM_FLAG_RCU) {
+               if (!negative_cached_acl(inode, ACL_TYPE_ACCESS))
+                       return -ECHILD;
+       } else {
+               struct posix_acl *acl;
+
+               acl = get_cached_acl(inode, ACL_TYPE_ACCESS);
+               if (acl) {
+                       int error = posix_acl_permission(inode, acl, mask);
+                       posix_acl_release(acl);
+                       return error;
+               }
        }
        return -EAGAIN;
 }
index 67608161df6b574eb5e382678d58e9683e30a6a6..d68283a898bb8df089a5f04e29160eaea1c315b3 100644 (file)
@@ -108,6 +108,25 @@ static inline struct posix_acl *get_cached_acl(struct inode *inode, int type)
        return acl;
 }
 
+static inline int negative_cached_acl(struct inode *inode, int type)
+{
+       struct posix_acl **p, *acl;
+       switch (type) {
+       case ACL_TYPE_ACCESS:
+               p = &inode->i_acl;
+               break;
+       case ACL_TYPE_DEFAULT:
+               p = &inode->i_default_acl;
+               break;
+       default:
+               BUG();
+       }
+       acl = ACCESS_ONCE(*p);
+       if (acl)
+               return 0;
+       return 1;
+}
+
 static inline void set_cached_acl(struct inode *inode,
                                  int type,
                                  struct posix_acl *acl)