summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Piggin <npiggin@kernel.dk>2011-01-07 06:49:59 (GMT)
committerNick Piggin <npiggin@kernel.dk>2011-01-07 06:50:29 (GMT)
commit1e1743ebe35ec7e3c1fa732408358fbc614cbbe5 (patch)
tree9654cd50bb29a4c5ccc498b9b08cc385288bc854
parentb74c79e99389cd79b31fcc08f82c24e492e63c7e (diff)
downloadlinux-1e1743ebe35ec7e3c1fa732408358fbc614cbbe5.tar.xz
fs: provide simple rcu-walk generic_check_acl implementation
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>
-rw-r--r--fs/generic_acl.c22
-rw-r--r--include/linux/posix_acl.h19
2 files changed, 31 insertions, 10 deletions
diff --git a/fs/generic_acl.c b/fs/generic_acl.c
index 6280042..06c48a8 100644
--- a/fs/generic_acl.c
+++ b/fs/generic_acl.c
@@ -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;
}
diff --git a/include/linux/posix_acl.h b/include/linux/posix_acl.h
index 6760816..d68283a 100644
--- a/include/linux/posix_acl.h
+++ b/include/linux/posix_acl.h
@@ -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)