From 6446f7277dea09bb8bcae745f4eab5f84d68a6bb Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 2 Aug 2011 21:32:13 -0400 Subject: [PATCH] --- yaml --- r: 262430 b: refs/heads/master c: 3567866bf26190d1e734c975c907eb06e923ba23 h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/fs/namei.c | 17 ++++++----------- trunk/include/linux/posix_acl.h | 18 +++++++++--------- 3 files changed, 16 insertions(+), 21 deletions(-) diff --git a/[refs] b/[refs] index 91becabdc53d..d7f144fab919 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 951c0d660a7c35286e401ca6d6ef38c9d49643c7 +refs/heads/master: 3567866bf26190d1e734c975c907eb06e923ba23 diff --git a/trunk/fs/namei.c b/trunk/fs/namei.c index 445fd5da11fa..3d607bd80e09 100644 --- a/trunk/fs/namei.c +++ b/trunk/fs/namei.c @@ -179,19 +179,14 @@ static int check_acl(struct inode *inode, int mask) #ifdef CONFIG_FS_POSIX_ACL struct posix_acl *acl; - /* - * Under RCU walk, we cannot even do a "get_cached_acl()", - * because that involves locking and getting a refcount on - * a cached ACL. - * - * So the only case we handle during RCU walking is the - * case of a cached "no ACL at all", which needs no locks - * or refcounts. - */ if (mask & MAY_NOT_BLOCK) { - if (negative_cached_acl(inode, ACL_TYPE_ACCESS)) + acl = get_cached_acl_rcu(inode, ACL_TYPE_ACCESS); + if (!acl) return -EAGAIN; - return -ECHILD; + /* no ->get_acl() calls in RCU mode... */ + if (acl == ACL_NOT_CACHED) + return -ECHILD; + return posix_acl_permission(inode, acl, mask); } acl = get_cached_acl(inode, ACL_TYPE_ACCESS); diff --git a/trunk/include/linux/posix_acl.h b/trunk/include/linux/posix_acl.h index a9c2fb29be96..b7681102a4b9 100644 --- a/trunk/include/linux/posix_acl.h +++ b/trunk/include/linux/posix_acl.h @@ -9,6 +9,7 @@ #define __LINUX_POSIX_ACL_H #include +#include #define ACL_UNDEFINED_ID (-1) @@ -38,7 +39,10 @@ struct posix_acl_entry { }; struct posix_acl { - atomic_t a_refcount; + union { + atomic_t a_refcount; + struct rcu_head a_rcu; + }; unsigned int a_count; struct posix_acl_entry a_entries[0]; }; @@ -65,7 +69,7 @@ static inline void posix_acl_release(struct posix_acl *acl) { if (acl && atomic_dec_and_test(&acl->a_refcount)) - kfree(acl); + kfree_rcu(acl, a_rcu); } @@ -110,13 +114,9 @@ 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) +static inline struct posix_acl *get_cached_acl_rcu(struct inode *inode, int type) { - struct posix_acl **p = acl_by_type(inode, type); - struct posix_acl *acl = ACCESS_ONCE(*p); - if (acl) - return 0; - return 1; + return rcu_dereference(*acl_by_type(inode, type)); } static inline void set_cached_acl(struct inode *inode, @@ -127,7 +127,7 @@ static inline void set_cached_acl(struct inode *inode, struct posix_acl *old; spin_lock(&inode->i_lock); old = *p; - *p = posix_dup_acl(acl); + rcu_assign_pointer(*p, posix_acl_dup(acl)); spin_unlock(&inode->i_lock); if (old != ACL_NOT_CACHED) posix_acl_release(old);