diff options
-rw-r--r-- | fs/9p/acl.c | 2 | ||||
-rw-r--r-- | fs/btrfs/acl.c | 3 | ||||
-rw-r--r-- | fs/ceph/acl.c | 2 | ||||
-rw-r--r-- | fs/ext2/acl.c | 3 | ||||
-rw-r--r-- | fs/ext4/acl.c | 3 | ||||
-rw-r--r-- | fs/f2fs/acl.c | 3 | ||||
-rw-r--r-- | fs/hfsplus/posix_acl.c | 3 | ||||
-rw-r--r-- | fs/inode.c | 4 | ||||
-rw-r--r-- | fs/jffs2/acl.c | 2 | ||||
-rw-r--r-- | fs/jfs/acl.c | 2 | ||||
-rw-r--r-- | fs/namei.c | 2 | ||||
-rw-r--r-- | fs/nfs/nfs3acl.c | 43 | ||||
-rw-r--r-- | fs/ocfs2/dlmglue.c | 3 | ||||
-rw-r--r-- | fs/posix_acl.c | 103 | ||||
-rw-r--r-- | fs/reiserfs/xattr_acl.c | 6 | ||||
-rw-r--r-- | fs/xfs/xfs_acl.c | 20 | ||||
-rw-r--r-- | include/linux/fs.h | 12 |
17 files changed, 138 insertions, 78 deletions
diff --git a/fs/9p/acl.c b/fs/9p/acl.c index 9da967f38387..2d94e94b6b59 100644 --- a/fs/9p/acl.c +++ b/fs/9p/acl.c | |||
@@ -93,7 +93,7 @@ static struct posix_acl *v9fs_get_cached_acl(struct inode *inode, int type) | |||
93 | * instantiating the inode (v9fs_inode_from_fid) | 93 | * instantiating the inode (v9fs_inode_from_fid) |
94 | */ | 94 | */ |
95 | acl = get_cached_acl(inode, type); | 95 | acl = get_cached_acl(inode, type); |
96 | BUG_ON(acl == ACL_NOT_CACHED); | 96 | BUG_ON(is_uncached_acl(acl)); |
97 | return acl; | 97 | return acl; |
98 | } | 98 | } |
99 | 99 | ||
diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c index 6d263bb1621c..67a607709d4f 100644 --- a/fs/btrfs/acl.c +++ b/fs/btrfs/acl.c | |||
@@ -63,9 +63,6 @@ struct posix_acl *btrfs_get_acl(struct inode *inode, int type) | |||
63 | } | 63 | } |
64 | kfree(value); | 64 | kfree(value); |
65 | 65 | ||
66 | if (!IS_ERR(acl)) | ||
67 | set_cached_acl(inode, type, acl); | ||
68 | |||
69 | return acl; | 66 | return acl; |
70 | } | 67 | } |
71 | 68 | ||
diff --git a/fs/ceph/acl.c b/fs/ceph/acl.c index f19708487e2f..5457f216e2e5 100644 --- a/fs/ceph/acl.c +++ b/fs/ceph/acl.c | |||
@@ -37,6 +37,8 @@ static inline void ceph_set_cached_acl(struct inode *inode, | |||
37 | spin_lock(&ci->i_ceph_lock); | 37 | spin_lock(&ci->i_ceph_lock); |
38 | if (__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 0)) | 38 | if (__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 0)) |
39 | set_cached_acl(inode, type, acl); | 39 | set_cached_acl(inode, type, acl); |
40 | else | ||
41 | forget_cached_acl(inode, type); | ||
40 | spin_unlock(&ci->i_ceph_lock); | 42 | spin_unlock(&ci->i_ceph_lock); |
41 | } | 43 | } |
42 | 44 | ||
diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c index 27695e6f4e46..42f1d1814083 100644 --- a/fs/ext2/acl.c +++ b/fs/ext2/acl.c | |||
@@ -172,9 +172,6 @@ ext2_get_acl(struct inode *inode, int type) | |||
172 | acl = ERR_PTR(retval); | 172 | acl = ERR_PTR(retval); |
173 | kfree(value); | 173 | kfree(value); |
174 | 174 | ||
175 | if (!IS_ERR(acl)) | ||
176 | set_cached_acl(inode, type, acl); | ||
177 | |||
178 | return acl; | 175 | return acl; |
179 | } | 176 | } |
180 | 177 | ||
diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c index 69b1e73026a5..c6601a476c02 100644 --- a/fs/ext4/acl.c +++ b/fs/ext4/acl.c | |||
@@ -172,9 +172,6 @@ ext4_get_acl(struct inode *inode, int type) | |||
172 | acl = ERR_PTR(retval); | 172 | acl = ERR_PTR(retval); |
173 | kfree(value); | 173 | kfree(value); |
174 | 174 | ||
175 | if (!IS_ERR(acl)) | ||
176 | set_cached_acl(inode, type, acl); | ||
177 | |||
178 | return acl; | 175 | return acl; |
179 | } | 176 | } |
180 | 177 | ||
diff --git a/fs/f2fs/acl.c b/fs/f2fs/acl.c index c8f25f7241f0..6f1fdda977b3 100644 --- a/fs/f2fs/acl.c +++ b/fs/f2fs/acl.c | |||
@@ -190,9 +190,6 @@ static struct posix_acl *__f2fs_get_acl(struct inode *inode, int type, | |||
190 | acl = ERR_PTR(retval); | 190 | acl = ERR_PTR(retval); |
191 | kfree(value); | 191 | kfree(value); |
192 | 192 | ||
193 | if (!IS_ERR(acl)) | ||
194 | set_cached_acl(inode, type, acl); | ||
195 | |||
196 | return acl; | 193 | return acl; |
197 | } | 194 | } |
198 | 195 | ||
diff --git a/fs/hfsplus/posix_acl.c b/fs/hfsplus/posix_acl.c index afb33eda6d7d..ab7ea2506b4d 100644 --- a/fs/hfsplus/posix_acl.c +++ b/fs/hfsplus/posix_acl.c | |||
@@ -48,9 +48,6 @@ struct posix_acl *hfsplus_get_posix_acl(struct inode *inode, int type) | |||
48 | 48 | ||
49 | hfsplus_destroy_attr_entry((hfsplus_attr_entry *)value); | 49 | hfsplus_destroy_attr_entry((hfsplus_attr_entry *)value); |
50 | 50 | ||
51 | if (!IS_ERR(acl)) | ||
52 | set_cached_acl(inode, type, acl); | ||
53 | |||
54 | return acl; | 51 | return acl; |
55 | } | 52 | } |
56 | 53 | ||
diff --git a/fs/inode.c b/fs/inode.c index 69b8b526c194..4202aac99464 100644 --- a/fs/inode.c +++ b/fs/inode.c | |||
@@ -238,9 +238,9 @@ void __destroy_inode(struct inode *inode) | |||
238 | } | 238 | } |
239 | 239 | ||
240 | #ifdef CONFIG_FS_POSIX_ACL | 240 | #ifdef CONFIG_FS_POSIX_ACL |
241 | if (inode->i_acl && inode->i_acl != ACL_NOT_CACHED) | 241 | if (inode->i_acl && !is_uncached_acl(inode->i_acl)) |
242 | posix_acl_release(inode->i_acl); | 242 | posix_acl_release(inode->i_acl); |
243 | if (inode->i_default_acl && inode->i_default_acl != ACL_NOT_CACHED) | 243 | if (inode->i_default_acl && !is_uncached_acl(inode->i_default_acl)) |
244 | posix_acl_release(inode->i_default_acl); | 244 | posix_acl_release(inode->i_default_acl); |
245 | #endif | 245 | #endif |
246 | this_cpu_dec(nr_inodes); | 246 | this_cpu_dec(nr_inodes); |
diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c index 2f7a3c090489..bc2693d56298 100644 --- a/fs/jffs2/acl.c +++ b/fs/jffs2/acl.c | |||
@@ -203,8 +203,6 @@ struct posix_acl *jffs2_get_acl(struct inode *inode, int type) | |||
203 | acl = ERR_PTR(rc); | 203 | acl = ERR_PTR(rc); |
204 | } | 204 | } |
205 | kfree(value); | 205 | kfree(value); |
206 | if (!IS_ERR(acl)) | ||
207 | set_cached_acl(inode, type, acl); | ||
208 | return acl; | 206 | return acl; |
209 | } | 207 | } |
210 | 208 | ||
diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c index ab4882801b24..21fa92ba2c19 100644 --- a/fs/jfs/acl.c +++ b/fs/jfs/acl.c | |||
@@ -63,8 +63,6 @@ struct posix_acl *jfs_get_acl(struct inode *inode, int type) | |||
63 | acl = posix_acl_from_xattr(&init_user_ns, value, size); | 63 | acl = posix_acl_from_xattr(&init_user_ns, value, size); |
64 | } | 64 | } |
65 | kfree(value); | 65 | kfree(value); |
66 | if (!IS_ERR(acl)) | ||
67 | set_cached_acl(inode, type, acl); | ||
68 | return acl; | 66 | return acl; |
69 | } | 67 | } |
70 | 68 | ||
diff --git a/fs/namei.c b/fs/namei.c index 794f81dce766..3498d53de26f 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -265,7 +265,7 @@ static int check_acl(struct inode *inode, int mask) | |||
265 | if (!acl) | 265 | if (!acl) |
266 | return -EAGAIN; | 266 | return -EAGAIN; |
267 | /* no ->get_acl() calls in RCU mode... */ | 267 | /* no ->get_acl() calls in RCU mode... */ |
268 | if (acl == ACL_NOT_CACHED) | 268 | if (is_uncached_acl(acl)) |
269 | return -ECHILD; | 269 | return -ECHILD; |
270 | return posix_acl_permission(inode, acl, mask & ~MAY_NOT_BLOCK); | 270 | return posix_acl_permission(inode, acl, mask & ~MAY_NOT_BLOCK); |
271 | } | 271 | } |
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c index 17c0fa1eccfa..720d92f5abfb 100644 --- a/fs/nfs/nfs3acl.c +++ b/fs/nfs/nfs3acl.c | |||
@@ -11,6 +11,38 @@ | |||
11 | 11 | ||
12 | #define NFSDBG_FACILITY NFSDBG_PROC | 12 | #define NFSDBG_FACILITY NFSDBG_PROC |
13 | 13 | ||
14 | /* | ||
15 | * nfs3_prepare_get_acl, nfs3_complete_get_acl, nfs3_abort_get_acl: Helpers for | ||
16 | * caching get_acl results in a race-free way. See fs/posix_acl.c:get_acl() | ||
17 | * for explanations. | ||
18 | */ | ||
19 | static void nfs3_prepare_get_acl(struct posix_acl **p) | ||
20 | { | ||
21 | struct posix_acl *sentinel = uncached_acl_sentinel(current); | ||
22 | |||
23 | if (cmpxchg(p, ACL_NOT_CACHED, sentinel) != ACL_NOT_CACHED) { | ||
24 | /* Not the first reader or sentinel already in place. */ | ||
25 | } | ||
26 | } | ||
27 | |||
28 | static void nfs3_complete_get_acl(struct posix_acl **p, struct posix_acl *acl) | ||
29 | { | ||
30 | struct posix_acl *sentinel = uncached_acl_sentinel(current); | ||
31 | |||
32 | /* Only cache the ACL if our sentinel is still in place. */ | ||
33 | posix_acl_dup(acl); | ||
34 | if (cmpxchg(p, sentinel, acl) != sentinel) | ||
35 | posix_acl_release(acl); | ||
36 | } | ||
37 | |||
38 | static void nfs3_abort_get_acl(struct posix_acl **p) | ||
39 | { | ||
40 | struct posix_acl *sentinel = uncached_acl_sentinel(current); | ||
41 | |||
42 | /* Remove our sentinel upon failure. */ | ||
43 | cmpxchg(p, sentinel, ACL_NOT_CACHED); | ||
44 | } | ||
45 | |||
14 | struct posix_acl *nfs3_get_acl(struct inode *inode, int type) | 46 | struct posix_acl *nfs3_get_acl(struct inode *inode, int type) |
15 | { | 47 | { |
16 | struct nfs_server *server = NFS_SERVER(inode); | 48 | struct nfs_server *server = NFS_SERVER(inode); |
@@ -55,6 +87,11 @@ struct posix_acl *nfs3_get_acl(struct inode *inode, int type) | |||
55 | if (res.fattr == NULL) | 87 | if (res.fattr == NULL) |
56 | return ERR_PTR(-ENOMEM); | 88 | return ERR_PTR(-ENOMEM); |
57 | 89 | ||
90 | if (args.mask & NFS_ACL) | ||
91 | nfs3_prepare_get_acl(&inode->i_acl); | ||
92 | if (args.mask & NFS_DFACL) | ||
93 | nfs3_prepare_get_acl(&inode->i_default_acl); | ||
94 | |||
58 | status = rpc_call_sync(server->client_acl, &msg, 0); | 95 | status = rpc_call_sync(server->client_acl, &msg, 0); |
59 | dprintk("NFS reply getacl: %d\n", status); | 96 | dprintk("NFS reply getacl: %d\n", status); |
60 | 97 | ||
@@ -89,12 +126,12 @@ struct posix_acl *nfs3_get_acl(struct inode *inode, int type) | |||
89 | } | 126 | } |
90 | 127 | ||
91 | if (res.mask & NFS_ACL) | 128 | if (res.mask & NFS_ACL) |
92 | set_cached_acl(inode, ACL_TYPE_ACCESS, res.acl_access); | 129 | nfs3_complete_get_acl(&inode->i_acl, res.acl_access); |
93 | else | 130 | else |
94 | forget_cached_acl(inode, ACL_TYPE_ACCESS); | 131 | forget_cached_acl(inode, ACL_TYPE_ACCESS); |
95 | 132 | ||
96 | if (res.mask & NFS_DFACL) | 133 | if (res.mask & NFS_DFACL) |
97 | set_cached_acl(inode, ACL_TYPE_DEFAULT, res.acl_default); | 134 | nfs3_complete_get_acl(&inode->i_default_acl, res.acl_default); |
98 | else | 135 | else |
99 | forget_cached_acl(inode, ACL_TYPE_DEFAULT); | 136 | forget_cached_acl(inode, ACL_TYPE_DEFAULT); |
100 | 137 | ||
@@ -108,6 +145,8 @@ struct posix_acl *nfs3_get_acl(struct inode *inode, int type) | |||
108 | } | 145 | } |
109 | 146 | ||
110 | getout: | 147 | getout: |
148 | nfs3_abort_get_acl(&inode->i_acl); | ||
149 | nfs3_abort_get_acl(&inode->i_default_acl); | ||
111 | posix_acl_release(res.acl_access); | 150 | posix_acl_release(res.acl_access); |
112 | posix_acl_release(res.acl_default); | 151 | posix_acl_release(res.acl_default); |
113 | nfs_free_fattr(res.fattr); | 152 | nfs_free_fattr(res.fattr); |
diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c index 474e57f834e6..1eaa9100c889 100644 --- a/fs/ocfs2/dlmglue.c +++ b/fs/ocfs2/dlmglue.c | |||
@@ -54,6 +54,7 @@ | |||
54 | #include "uptodate.h" | 54 | #include "uptodate.h" |
55 | #include "quota.h" | 55 | #include "quota.h" |
56 | #include "refcounttree.h" | 56 | #include "refcounttree.h" |
57 | #include "acl.h" | ||
57 | 58 | ||
58 | #include "buffer_head_io.h" | 59 | #include "buffer_head_io.h" |
59 | 60 | ||
@@ -3623,6 +3624,8 @@ static int ocfs2_data_convert_worker(struct ocfs2_lock_res *lockres, | |||
3623 | filemap_fdatawait(mapping); | 3624 | filemap_fdatawait(mapping); |
3624 | } | 3625 | } |
3625 | 3626 | ||
3627 | forget_all_cached_acls(inode); | ||
3628 | |||
3626 | out: | 3629 | out: |
3627 | return UNBLOCK_CONTINUE; | 3630 | return UNBLOCK_CONTINUE; |
3628 | } | 3631 | } |
diff --git a/fs/posix_acl.c b/fs/posix_acl.c index 711dd5170376..bc6736d60786 100644 --- a/fs/posix_acl.c +++ b/fs/posix_acl.c | |||
@@ -37,14 +37,18 @@ EXPORT_SYMBOL(acl_by_type); | |||
37 | struct posix_acl *get_cached_acl(struct inode *inode, int type) | 37 | struct posix_acl *get_cached_acl(struct inode *inode, int type) |
38 | { | 38 | { |
39 | struct posix_acl **p = acl_by_type(inode, type); | 39 | struct posix_acl **p = acl_by_type(inode, type); |
40 | struct posix_acl *acl = ACCESS_ONCE(*p); | 40 | struct posix_acl *acl; |
41 | if (acl) { | 41 | |
42 | spin_lock(&inode->i_lock); | 42 | for (;;) { |
43 | acl = *p; | 43 | rcu_read_lock(); |
44 | if (acl != ACL_NOT_CACHED) | 44 | acl = rcu_dereference(*p); |
45 | acl = posix_acl_dup(acl); | 45 | if (!acl || is_uncached_acl(acl) || |
46 | spin_unlock(&inode->i_lock); | 46 | atomic_inc_not_zero(&acl->a_refcount)) |
47 | break; | ||
48 | rcu_read_unlock(); | ||
49 | cpu_relax(); | ||
47 | } | 50 | } |
51 | rcu_read_unlock(); | ||
48 | return acl; | 52 | return acl; |
49 | } | 53 | } |
50 | EXPORT_SYMBOL(get_cached_acl); | 54 | EXPORT_SYMBOL(get_cached_acl); |
@@ -59,58 +63,72 @@ void set_cached_acl(struct inode *inode, int type, struct posix_acl *acl) | |||
59 | { | 63 | { |
60 | struct posix_acl **p = acl_by_type(inode, type); | 64 | struct posix_acl **p = acl_by_type(inode, type); |
61 | struct posix_acl *old; | 65 | struct posix_acl *old; |
62 | spin_lock(&inode->i_lock); | 66 | |
63 | old = *p; | 67 | old = xchg(p, posix_acl_dup(acl)); |
64 | rcu_assign_pointer(*p, posix_acl_dup(acl)); | 68 | if (!is_uncached_acl(old)) |
65 | spin_unlock(&inode->i_lock); | ||
66 | if (old != ACL_NOT_CACHED) | ||
67 | posix_acl_release(old); | 69 | posix_acl_release(old); |
68 | } | 70 | } |
69 | EXPORT_SYMBOL(set_cached_acl); | 71 | EXPORT_SYMBOL(set_cached_acl); |
70 | 72 | ||
71 | void forget_cached_acl(struct inode *inode, int type) | 73 | static void __forget_cached_acl(struct posix_acl **p) |
72 | { | 74 | { |
73 | struct posix_acl **p = acl_by_type(inode, type); | ||
74 | struct posix_acl *old; | 75 | struct posix_acl *old; |
75 | spin_lock(&inode->i_lock); | 76 | |
76 | old = *p; | 77 | old = xchg(p, ACL_NOT_CACHED); |
77 | *p = ACL_NOT_CACHED; | 78 | if (!is_uncached_acl(old)) |
78 | spin_unlock(&inode->i_lock); | ||
79 | if (old != ACL_NOT_CACHED) | ||
80 | posix_acl_release(old); | 79 | posix_acl_release(old); |
81 | } | 80 | } |
81 | |||
82 | void forget_cached_acl(struct inode *inode, int type) | ||
83 | { | ||
84 | __forget_cached_acl(acl_by_type(inode, type)); | ||
85 | } | ||
82 | EXPORT_SYMBOL(forget_cached_acl); | 86 | EXPORT_SYMBOL(forget_cached_acl); |
83 | 87 | ||
84 | void forget_all_cached_acls(struct inode *inode) | 88 | void forget_all_cached_acls(struct inode *inode) |
85 | { | 89 | { |
86 | struct posix_acl *old_access, *old_default; | 90 | __forget_cached_acl(&inode->i_acl); |
87 | spin_lock(&inode->i_lock); | 91 | __forget_cached_acl(&inode->i_default_acl); |
88 | old_access = inode->i_acl; | ||
89 | old_default = inode->i_default_acl; | ||
90 | inode->i_acl = inode->i_default_acl = ACL_NOT_CACHED; | ||
91 | spin_unlock(&inode->i_lock); | ||
92 | if (old_access != ACL_NOT_CACHED) | ||
93 | posix_acl_release(old_access); | ||
94 | if (old_default != ACL_NOT_CACHED) | ||
95 | posix_acl_release(old_default); | ||
96 | } | 92 | } |
97 | EXPORT_SYMBOL(forget_all_cached_acls); | 93 | EXPORT_SYMBOL(forget_all_cached_acls); |
98 | 94 | ||
99 | struct posix_acl *get_acl(struct inode *inode, int type) | 95 | struct posix_acl *get_acl(struct inode *inode, int type) |
100 | { | 96 | { |
97 | void *sentinel; | ||
98 | struct posix_acl **p; | ||
101 | struct posix_acl *acl; | 99 | struct posix_acl *acl; |
102 | 100 | ||
101 | /* | ||
102 | * The sentinel is used to detect when another operation like | ||
103 | * set_cached_acl() or forget_cached_acl() races with get_acl(). | ||
104 | * It is guaranteed that is_uncached_acl(sentinel) is true. | ||
105 | */ | ||
106 | |||
103 | acl = get_cached_acl(inode, type); | 107 | acl = get_cached_acl(inode, type); |
104 | if (acl != ACL_NOT_CACHED) | 108 | if (!is_uncached_acl(acl)) |
105 | return acl; | 109 | return acl; |
106 | 110 | ||
107 | if (!IS_POSIXACL(inode)) | 111 | if (!IS_POSIXACL(inode)) |
108 | return NULL; | 112 | return NULL; |
109 | 113 | ||
114 | sentinel = uncached_acl_sentinel(current); | ||
115 | p = acl_by_type(inode, type); | ||
116 | |||
110 | /* | 117 | /* |
111 | * A filesystem can force a ACL callback by just never filling the | 118 | * If the ACL isn't being read yet, set our sentinel. Otherwise, the |
112 | * ACL cache. But normally you'd fill the cache either at inode | 119 | * current value of the ACL will not be ACL_NOT_CACHED and so our own |
113 | * instantiation time, or on the first ->get_acl call. | 120 | * sentinel will not be set; another task will update the cache. We |
121 | * could wait for that other task to complete its job, but it's easier | ||
122 | * to just call ->get_acl to fetch the ACL ourself. (This is going to | ||
123 | * be an unlikely race.) | ||
124 | */ | ||
125 | if (cmpxchg(p, ACL_NOT_CACHED, sentinel) != ACL_NOT_CACHED) | ||
126 | /* fall through */ ; | ||
127 | |||
128 | /* | ||
129 | * Normally, the ACL returned by ->get_acl will be cached. | ||
130 | * A filesystem can prevent that by calling | ||
131 | * forget_cached_acl(inode, type) in ->get_acl. | ||
114 | * | 132 | * |
115 | * If the filesystem doesn't have a get_acl() function at all, we'll | 133 | * If the filesystem doesn't have a get_acl() function at all, we'll |
116 | * just create the negative cache entry. | 134 | * just create the negative cache entry. |
@@ -119,7 +137,24 @@ struct posix_acl *get_acl(struct inode *inode, int type) | |||
119 | set_cached_acl(inode, type, NULL); | 137 | set_cached_acl(inode, type, NULL); |
120 | return NULL; | 138 | return NULL; |
121 | } | 139 | } |
122 | return inode->i_op->get_acl(inode, type); | 140 | acl = inode->i_op->get_acl(inode, type); |
141 | |||
142 | if (IS_ERR(acl)) { | ||
143 | /* | ||
144 | * Remove our sentinel so that we don't block future attempts | ||
145 | * to cache the ACL. | ||
146 | */ | ||
147 | cmpxchg(p, sentinel, ACL_NOT_CACHED); | ||
148 | return acl; | ||
149 | } | ||
150 | |||
151 | /* | ||
152 | * Cache the result, but only if our sentinel is still in place. | ||
153 | */ | ||
154 | posix_acl_dup(acl); | ||
155 | if (unlikely(cmpxchg(p, sentinel, acl) != sentinel)) | ||
156 | posix_acl_release(acl); | ||
157 | return acl; | ||
123 | } | 158 | } |
124 | EXPORT_SYMBOL(get_acl); | 159 | EXPORT_SYMBOL(get_acl); |
125 | 160 | ||
diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c index ec74bbedc873..dbed42f755e0 100644 --- a/fs/reiserfs/xattr_acl.c +++ b/fs/reiserfs/xattr_acl.c | |||
@@ -197,10 +197,8 @@ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type) | |||
197 | 197 | ||
198 | size = reiserfs_xattr_get(inode, name, NULL, 0); | 198 | size = reiserfs_xattr_get(inode, name, NULL, 0); |
199 | if (size < 0) { | 199 | if (size < 0) { |
200 | if (size == -ENODATA || size == -ENOSYS) { | 200 | if (size == -ENODATA || size == -ENOSYS) |
201 | set_cached_acl(inode, type, NULL); | ||
202 | return NULL; | 201 | return NULL; |
203 | } | ||
204 | return ERR_PTR(size); | 202 | return ERR_PTR(size); |
205 | } | 203 | } |
206 | 204 | ||
@@ -220,8 +218,6 @@ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type) | |||
220 | } else { | 218 | } else { |
221 | acl = reiserfs_posix_acl_from_disk(value, retval); | 219 | acl = reiserfs_posix_acl_from_disk(value, retval); |
222 | } | 220 | } |
223 | if (!IS_ERR(acl)) | ||
224 | set_cached_acl(inode, type, acl); | ||
225 | 221 | ||
226 | kfree(value); | 222 | kfree(value); |
227 | return acl; | 223 | return acl; |
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c index 2d5df1f23bbc..b6e527b8eccb 100644 --- a/fs/xfs/xfs_acl.c +++ b/fs/xfs/xfs_acl.c | |||
@@ -158,22 +158,14 @@ xfs_get_acl(struct inode *inode, int type) | |||
158 | if (error) { | 158 | if (error) { |
159 | /* | 159 | /* |
160 | * If the attribute doesn't exist make sure we have a negative | 160 | * If the attribute doesn't exist make sure we have a negative |
161 | * cache entry, for any other error assume it is transient and | 161 | * cache entry, for any other error assume it is transient. |
162 | * leave the cache entry as ACL_NOT_CACHED. | ||
163 | */ | 162 | */ |
164 | if (error == -ENOATTR) | 163 | if (error != -ENOATTR) |
165 | goto out_update_cache; | 164 | acl = ERR_PTR(error); |
166 | acl = ERR_PTR(error); | 165 | } else { |
167 | goto out; | 166 | acl = xfs_acl_from_disk(xfs_acl, len, |
167 | XFS_ACL_MAX_ENTRIES(ip->i_mount)); | ||
168 | } | 168 | } |
169 | |||
170 | acl = xfs_acl_from_disk(xfs_acl, len, XFS_ACL_MAX_ENTRIES(ip->i_mount)); | ||
171 | if (IS_ERR(acl)) | ||
172 | goto out; | ||
173 | |||
174 | out_update_cache: | ||
175 | set_cached_acl(inode, type, acl); | ||
176 | out: | ||
177 | kmem_free(xfs_acl); | 169 | kmem_free(xfs_acl); |
178 | return acl; | 170 | return acl; |
179 | } | 171 | } |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 14a97194b34b..329ed372d708 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -577,6 +577,18 @@ static inline void mapping_allow_writable(struct address_space *mapping) | |||
577 | struct posix_acl; | 577 | struct posix_acl; |
578 | #define ACL_NOT_CACHED ((void *)(-1)) | 578 | #define ACL_NOT_CACHED ((void *)(-1)) |
579 | 579 | ||
580 | static inline struct posix_acl * | ||
581 | uncached_acl_sentinel(struct task_struct *task) | ||
582 | { | ||
583 | return (void *)task + 1; | ||
584 | } | ||
585 | |||
586 | static inline bool | ||
587 | is_uncached_acl(struct posix_acl *acl) | ||
588 | { | ||
589 | return (long)acl & 1; | ||
590 | } | ||
591 | |||
580 | #define IOP_FASTPERM 0x0001 | 592 | #define IOP_FASTPERM 0x0001 |
581 | #define IOP_LOOKUP 0x0002 | 593 | #define IOP_LOOKUP 0x0002 |
582 | #define IOP_NOFOLLOW 0x0004 | 594 | #define IOP_NOFOLLOW 0x0004 |