aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNick Piggin <npiggin@kernel.dk>2011-01-07 01:49:58 -0500
committerNick Piggin <npiggin@kernel.dk>2011-01-07 01:50:29 -0500
commitb74c79e99389cd79b31fcc08f82c24e492e63c7e (patch)
tree763c6b412517306670bc625e90035f2d16bb739f
parent34286d6662308d82aed891852d04c7c3a2649b16 (diff)
fs: provide rcu-walk aware permission i_ops
Signed-off-by: Nick Piggin <npiggin@kernel.dk>
-rw-r--r--Documentation/filesystems/Locking6
-rw-r--r--Documentation/filesystems/path-lookup.txt44
-rw-r--r--Documentation/filesystems/porting5
-rw-r--r--Documentation/filesystems/vfs.txt10
-rw-r--r--drivers/staging/smbfs/file.c5
-rw-r--r--fs/9p/acl.c5
-rw-r--r--fs/9p/acl.h2
-rw-r--r--fs/afs/internal.h2
-rw-r--r--fs/afs/security.c7
-rw-r--r--fs/bad_inode.c5
-rw-r--r--fs/btrfs/acl.c6
-rw-r--r--fs/btrfs/ctree.h2
-rw-r--r--fs/btrfs/inode.c7
-rw-r--r--fs/ceph/inode.c11
-rw-r--r--fs/ceph/super.h2
-rw-r--r--fs/cifs/cifsfs.c7
-rw-r--r--fs/coda/dir.c5
-rw-r--r--fs/coda/pioctl.c6
-rw-r--r--fs/ecryptfs/inode.c4
-rw-r--r--fs/ext2/acl.c8
-rw-r--r--fs/ext2/acl.h2
-rw-r--r--fs/ext3/acl.c8
-rw-r--r--fs/ext3/acl.h2
-rw-r--r--fs/ext4/acl.c8
-rw-r--r--fs/ext4/acl.h2
-rw-r--r--fs/fuse/dir.c10
-rw-r--r--fs/generic_acl.c8
-rw-r--r--fs/gfs2/acl.c5
-rw-r--r--fs/gfs2/acl.h2
-rw-r--r--fs/gfs2/file.c2
-rw-r--r--fs/gfs2/inode.c4
-rw-r--r--fs/gfs2/inode.h2
-rw-r--r--fs/gfs2/ops_inode.c18
-rw-r--r--fs/hostfs/hostfs_kern.c7
-rw-r--r--fs/hpfs/namei.c2
-rw-r--r--fs/jffs2/acl.c5
-rw-r--r--fs/jffs2/acl.h2
-rw-r--r--fs/jfs/acl.c8
-rw-r--r--fs/jfs/jfs_acl.h2
-rw-r--r--fs/logfs/dir.c6
-rw-r--r--fs/namei.c75
-rw-r--r--fs/nfs/dir.c7
-rw-r--r--fs/nilfs2/inode.c10
-rw-r--r--fs/nilfs2/nilfs.h2
-rw-r--r--fs/ocfs2/acl.c8
-rw-r--r--fs/ocfs2/acl.h2
-rw-r--r--fs/ocfs2/file.c7
-rw-r--r--fs/ocfs2/file.h2
-rw-r--r--fs/proc/base.c6
-rw-r--r--fs/proc/proc_sysctl.c5
-rw-r--r--fs/reiserfs/xattr.c14
-rw-r--r--fs/sysfs/inode.c11
-rw-r--r--fs/sysfs/sysfs.h2
-rw-r--r--fs/xfs/linux-2.6/xfs_acl.c8
-rw-r--r--fs/xfs/xfs_acl.h2
-rw-r--r--include/linux/coda_linux.h2
-rw-r--r--include/linux/fs.h10
-rw-r--r--include/linux/generic_acl.h2
-rw-r--r--include/linux/nfs_fs.h2
-rw-r--r--include/linux/reiserfs_xattr.h2
60 files changed, 287 insertions, 146 deletions
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index e90ffe61eb65..977d8919cc69 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -47,8 +47,8 @@ ata *);
47 void * (*follow_link) (struct dentry *, struct nameidata *); 47 void * (*follow_link) (struct dentry *, struct nameidata *);
48 void (*put_link) (struct dentry *, struct nameidata *, void *); 48 void (*put_link) (struct dentry *, struct nameidata *, void *);
49 void (*truncate) (struct inode *); 49 void (*truncate) (struct inode *);
50 int (*permission) (struct inode *, int, struct nameidata *); 50 int (*permission) (struct inode *, int, unsigned int);
51 int (*check_acl)(struct inode *, int); 51 int (*check_acl)(struct inode *, int, unsigned int);
52 int (*setattr) (struct dentry *, struct iattr *); 52 int (*setattr) (struct dentry *, struct iattr *);
53 int (*getattr) (struct vfsmount *, struct dentry *, struct kstat *); 53 int (*getattr) (struct vfsmount *, struct dentry *, struct kstat *);
54 int (*setxattr) (struct dentry *, const char *,const void *,size_t,int); 54 int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
@@ -76,7 +76,7 @@ follow_link: no
76put_link: no 76put_link: no
77truncate: yes (see below) 77truncate: yes (see below)
78setattr: yes 78setattr: yes
79permission: no 79permission: no (may not block if called in rcu-walk mode)
80check_acl: no 80check_acl: no
81getattr: no 81getattr: no
82setxattr: yes 82setxattr: yes
diff --git a/Documentation/filesystems/path-lookup.txt b/Documentation/filesystems/path-lookup.txt
index 8789d1810bed..eb59c8b44be9 100644
--- a/Documentation/filesystems/path-lookup.txt
+++ b/Documentation/filesystems/path-lookup.txt
@@ -316,11 +316,9 @@ The detailed design for rcu-walk is like this:
316 316
317The cases where rcu-walk cannot continue are: 317The cases where rcu-walk cannot continue are:
318* NULL dentry (ie. any uncached path element) 318* NULL dentry (ie. any uncached path element)
319* parent with d_inode->i_op->permission or ACLs
320* Following links 319* Following links
321 320
322In future patches, permission checks become rcu-walk aware. It may be possible 321It may be possible eventually to make following links rcu-walk aware.
323eventually to make following links rcu-walk aware.
324 322
325Uncached path elements will always require dropping to ref-walk mode, at the 323Uncached path elements will always require dropping to ref-walk mode, at the
326very least because i_mutex needs to be grabbed, and objects allocated. 324very least because i_mutex needs to be grabbed, and objects allocated.
@@ -336,9 +334,49 @@ or stored into. The result is massive improvements in performance and
336scalability of path resolution. 334scalability of path resolution.
337 335
338 336
337Interesting statistics
338======================
339
340The following table gives rcu lookup statistics for a few simple workloads
341(2s12c24t Westmere, debian non-graphical system). Ungraceful are attempts to
342drop rcu that fail due to d_seq failure and requiring the entire path lookup
343again. Other cases are successful rcu-drops that are required before the final
344element, nodentry for missing dentry, revalidate for filesystem revalidate
345routine requiring rcu drop, permission for permission check requiring drop,
346and link for symlink traversal requiring drop.
347
348 rcu-lookups restart nodentry link revalidate permission
349bootup 47121 0 4624 1010 10283 7852
350dbench 25386793 0 6778659(26.7%) 55 549 1156
351kbuild 2696672 10 64442(2.3%) 108764(4.0%) 1 1590
352git diff 39605 0 28 2 0 106
353vfstest 24185492 4945 708725(2.9%) 1076136(4.4%) 0 2651
354
355What this shows is that failed rcu-walk lookups, ie. ones that are restarted
356entirely with ref-walk, are quite rare. Even the "vfstest" case which
357specifically has concurrent renames/mkdir/rmdir/ creat/unlink/etc to excercise
358such races is not showing a huge amount of restarts.
359
360Dropping from rcu-walk to ref-walk mean that we have encountered a dentry where
361the reference count needs to be taken for some reason. This is either because
362we have reached the target of the path walk, or because we have encountered a
363condition that can't be resolved in rcu-walk mode. Ideally, we drop rcu-walk
364only when we have reached the target dentry, so the other statistics show where
365this does not happen.
366
367Note that a graceful drop from rcu-walk mode due to something such as the
368dentry not existing (which can be common) is not necessarily a failure of
369rcu-walk scheme, because some elements of the path may have been walked in
370rcu-walk mode. The further we get from common path elements (such as cwd or
371root), the less contended the dentry is likely to be. The closer we are to
372common path elements, the more likely they will exist in dentry cache.
373
374
339Papers and other documentation on dcache locking 375Papers and other documentation on dcache locking
340================================================ 376================================================
341 377
3421. Scaling dcache with RCU (http://linuxjournal.com/article.php?sid=7124). 3781. Scaling dcache with RCU (http://linuxjournal.com/article.php?sid=7124).
343 379
3442. http://lse.sourceforge.net/locking/dcache/dcache.html 3802. http://lse.sourceforge.net/locking/dcache/dcache.html
381
382
diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting
index cd9756a2709d..07a32b42cf9c 100644
--- a/Documentation/filesystems/porting
+++ b/Documentation/filesystems/porting
@@ -380,3 +380,8 @@ the filesystem provides it), which requires dropping out of rcu-walk mode. This
380may now be called in rcu-walk mode (nd->flags & LOOKUP_RCU). -ECHILD should be 380may now be called in rcu-walk mode (nd->flags & LOOKUP_RCU). -ECHILD should be
381returned if the filesystem cannot handle rcu-walk. See 381returned if the filesystem cannot handle rcu-walk. See
382Documentation/filesystems/vfs.txt for more details. 382Documentation/filesystems/vfs.txt for more details.
383
384 permission and check_acl are inode permission checks that are called
385on many or all directory inodes on the way down a path walk (to check for
386exec permission). These must now be rcu-walk aware (flags & IPERM_RCU). See
387Documentation/filesystems/vfs.txt for more details.
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index c936b4912383..fbb324e2bd43 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -325,7 +325,8 @@ struct inode_operations {
325 void * (*follow_link) (struct dentry *, struct nameidata *); 325 void * (*follow_link) (struct dentry *, struct nameidata *);
326 void (*put_link) (struct dentry *, struct nameidata *, void *); 326 void (*put_link) (struct dentry *, struct nameidata *, void *);
327 void (*truncate) (struct inode *); 327 void (*truncate) (struct inode *);
328 int (*permission) (struct inode *, int, struct nameidata *); 328 int (*permission) (struct inode *, int, unsigned int);
329 int (*check_acl)(struct inode *, int, unsigned int);
329 int (*setattr) (struct dentry *, struct iattr *); 330 int (*setattr) (struct dentry *, struct iattr *);
330 int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *); 331 int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
331 int (*setxattr) (struct dentry *, const char *,const void *,size_t,int); 332 int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
@@ -414,6 +415,13 @@ otherwise noted.
414 permission: called by the VFS to check for access rights on a POSIX-like 415 permission: called by the VFS to check for access rights on a POSIX-like
415 filesystem. 416 filesystem.
416 417
418 May be called in rcu-walk mode (flags & IPERM_RCU). If in rcu-walk
419 mode, the filesystem must check the permission without blocking or
420 storing to the inode.
421
422 If a situation is encountered that rcu-walk cannot handle, return
423 -ECHILD and it will be called again in ref-walk mode.
424
417 setattr: called by the VFS to set attributes for a file. This method 425 setattr: called by the VFS to set attributes for a file. This method
418 is called by chmod(2) and related system calls. 426 is called by chmod(2) and related system calls.
419 427
diff --git a/drivers/staging/smbfs/file.c b/drivers/staging/smbfs/file.c
index 5dcd19c60eb9..31372e7b12de 100644
--- a/drivers/staging/smbfs/file.c
+++ b/drivers/staging/smbfs/file.c
@@ -407,11 +407,14 @@ smb_file_release(struct inode *inode, struct file * file)
407 * privileges, so we need our own check for this. 407 * privileges, so we need our own check for this.
408 */ 408 */
409static int 409static int
410smb_file_permission(struct inode *inode, int mask) 410smb_file_permission(struct inode *inode, int mask, unsigned int flags)
411{ 411{
412 int mode = inode->i_mode; 412 int mode = inode->i_mode;
413 int error = 0; 413 int error = 0;
414 414
415 if (flags & IPERM_FLAG_RCU)
416 return -ECHILD;
417
415 VERBOSE("mode=%x, mask=%x\n", mode, mask); 418 VERBOSE("mode=%x, mask=%x\n", mode, mask);
416 419
417 /* Look at user permissions */ 420 /* Look at user permissions */
diff --git a/fs/9p/acl.c b/fs/9p/acl.c
index 12d602351dbe..6e58c4ca1e6e 100644
--- a/fs/9p/acl.c
+++ b/fs/9p/acl.c
@@ -91,11 +91,14 @@ static struct posix_acl *v9fs_get_cached_acl(struct inode *inode, int type)
91 return acl; 91 return acl;
92} 92}
93 93
94int v9fs_check_acl(struct inode *inode, int mask) 94int v9fs_check_acl(struct inode *inode, int mask, unsigned int flags)
95{ 95{
96 struct posix_acl *acl; 96 struct posix_acl *acl;
97 struct v9fs_session_info *v9ses; 97 struct v9fs_session_info *v9ses;
98 98
99 if (flags & IPERM_FLAG_RCU)
100 return -ECHILD;
101
99 v9ses = v9fs_inode2v9ses(inode); 102 v9ses = v9fs_inode2v9ses(inode);
100 if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) { 103 if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) {
101 /* 104 /*
diff --git a/fs/9p/acl.h b/fs/9p/acl.h
index 59e18c2e8c7e..7ef3ac9f6d95 100644
--- a/fs/9p/acl.h
+++ b/fs/9p/acl.h
@@ -16,7 +16,7 @@
16 16
17#ifdef CONFIG_9P_FS_POSIX_ACL 17#ifdef CONFIG_9P_FS_POSIX_ACL
18extern int v9fs_get_acl(struct inode *, struct p9_fid *); 18extern int v9fs_get_acl(struct inode *, struct p9_fid *);
19extern int v9fs_check_acl(struct inode *inode, int mask); 19extern int v9fs_check_acl(struct inode *inode, int mask, unsigned int flags);
20extern int v9fs_acl_chmod(struct dentry *); 20extern int v9fs_acl_chmod(struct dentry *);
21extern int v9fs_set_create_acl(struct dentry *, 21extern int v9fs_set_create_acl(struct dentry *,
22 struct posix_acl *, struct posix_acl *); 22 struct posix_acl *, struct posix_acl *);
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index cca8eef736fc..6d4bc1c8ff60 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -624,7 +624,7 @@ extern void afs_clear_permits(struct afs_vnode *);
624extern void afs_cache_permit(struct afs_vnode *, struct key *, long); 624extern void afs_cache_permit(struct afs_vnode *, struct key *, long);
625extern void afs_zap_permits(struct rcu_head *); 625extern void afs_zap_permits(struct rcu_head *);
626extern struct key *afs_request_key(struct afs_cell *); 626extern struct key *afs_request_key(struct afs_cell *);
627extern int afs_permission(struct inode *, int); 627extern int afs_permission(struct inode *, int, unsigned int);
628 628
629/* 629/*
630 * server.c 630 * server.c
diff --git a/fs/afs/security.c b/fs/afs/security.c
index bb4ed144d0e4..f44b9d355377 100644
--- a/fs/afs/security.c
+++ b/fs/afs/security.c
@@ -285,13 +285,16 @@ static int afs_check_permit(struct afs_vnode *vnode, struct key *key,
285 * - AFS ACLs are attached to directories only, and a file is controlled by its 285 * - AFS ACLs are attached to directories only, and a file is controlled by its
286 * parent directory's ACL 286 * parent directory's ACL
287 */ 287 */
288int afs_permission(struct inode *inode, int mask) 288int afs_permission(struct inode *inode, int mask, unsigned int flags)
289{ 289{
290 struct afs_vnode *vnode = AFS_FS_I(inode); 290 struct afs_vnode *vnode = AFS_FS_I(inode);
291 afs_access_t uninitialized_var(access); 291 afs_access_t uninitialized_var(access);
292 struct key *key; 292 struct key *key;
293 int ret; 293 int ret;
294 294
295 if (flags & IPERM_FLAG_RCU)
296 return -ECHILD;
297
295 _enter("{{%x:%u},%lx},%x,", 298 _enter("{{%x:%u},%lx},%x,",
296 vnode->fid.vid, vnode->fid.vnode, vnode->flags, mask); 299 vnode->fid.vid, vnode->fid.vnode, vnode->flags, mask);
297 300
@@ -347,7 +350,7 @@ int afs_permission(struct inode *inode, int mask)
347 } 350 }
348 351
349 key_put(key); 352 key_put(key);
350 ret = generic_permission(inode, mask, NULL); 353 ret = generic_permission(inode, mask, flags, NULL);
351 _leave(" = %d", ret); 354 _leave(" = %d", ret);
352 return ret; 355 return ret;
353 356
diff --git a/fs/bad_inode.c b/fs/bad_inode.c
index f024d8aaddef..9ad2369d9e35 100644
--- a/fs/bad_inode.c
+++ b/fs/bad_inode.c
@@ -229,8 +229,11 @@ static int bad_inode_readlink(struct dentry *dentry, char __user *buffer,
229 return -EIO; 229 return -EIO;
230} 230}
231 231
232static int bad_inode_permission(struct inode *inode, int mask) 232static int bad_inode_permission(struct inode *inode, int mask, unsigned int flags)
233{ 233{
234 if (flags & IPERM_FLAG_RCU)
235 return -ECHILD;
236
234 return -EIO; 237 return -EIO;
235} 238}
236 239
diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c
index 2222d161c7b6..cb518a4b917c 100644
--- a/fs/btrfs/acl.c
+++ b/fs/btrfs/acl.c
@@ -185,13 +185,15 @@ static int btrfs_xattr_acl_set(struct dentry *dentry, const char *name,
185 return ret; 185 return ret;
186} 186}
187 187
188int btrfs_check_acl(struct inode *inode, int mask) 188int btrfs_check_acl(struct inode *inode, int mask, unsigned int flags)
189{ 189{
190 struct posix_acl *acl; 190 struct posix_acl *acl;
191 int error = -EAGAIN; 191 int error = -EAGAIN;
192 192
193 acl = btrfs_get_acl(inode, ACL_TYPE_ACCESS); 193 if (flags & IPERM_FLAG_RCU)
194 return -ECHILD;
194 195
196 acl = btrfs_get_acl(inode, ACL_TYPE_ACCESS);
195 if (IS_ERR(acl)) 197 if (IS_ERR(acl))
196 return PTR_ERR(acl); 198 return PTR_ERR(acl);
197 if (acl) { 199 if (acl) {
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index af52f6d7a4d8..a142d204b526 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -2544,7 +2544,7 @@ int btrfs_sync_fs(struct super_block *sb, int wait);
2544 2544
2545/* acl.c */ 2545/* acl.c */
2546#ifdef CONFIG_BTRFS_FS_POSIX_ACL 2546#ifdef CONFIG_BTRFS_FS_POSIX_ACL
2547int btrfs_check_acl(struct inode *inode, int mask); 2547int btrfs_check_acl(struct inode *inode, int mask, unsigned int flags);
2548#else 2548#else
2549#define btrfs_check_acl NULL 2549#define btrfs_check_acl NULL
2550#endif 2550#endif
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 63e4546b478a..5cf0db0081f9 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -7211,11 +7211,14 @@ static int btrfs_set_page_dirty(struct page *page)
7211 return __set_page_dirty_nobuffers(page); 7211 return __set_page_dirty_nobuffers(page);
7212} 7212}
7213 7213
7214static int btrfs_permission(struct inode *inode, int mask) 7214static int btrfs_permission(struct inode *inode, int mask, unsigned int flags)
7215{ 7215{
7216 if (flags & IPERM_FLAG_RCU)
7217 return -ECHILD;
7218
7216 if ((BTRFS_I(inode)->flags & BTRFS_INODE_READONLY) && (mask & MAY_WRITE)) 7219 if ((BTRFS_I(inode)->flags & BTRFS_INODE_READONLY) && (mask & MAY_WRITE))
7217 return -EACCES; 7220 return -EACCES;
7218 return generic_permission(inode, mask, btrfs_check_acl); 7221 return generic_permission(inode, mask, flags, btrfs_check_acl);
7219} 7222}
7220 7223
7221static const struct inode_operations btrfs_dir_inode_operations = { 7224static const struct inode_operations btrfs_dir_inode_operations = {
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
index 47f8c8baf3b5..e61de4f7b99d 100644
--- a/fs/ceph/inode.c
+++ b/fs/ceph/inode.c
@@ -1781,12 +1781,17 @@ int ceph_do_getattr(struct inode *inode, int mask)
1781 * Check inode permissions. We verify we have a valid value for 1781 * Check inode permissions. We verify we have a valid value for
1782 * the AUTH cap, then call the generic handler. 1782 * the AUTH cap, then call the generic handler.
1783 */ 1783 */
1784int ceph_permission(struct inode *inode, int mask) 1784int ceph_permission(struct inode *inode, int mask, unsigned int flags)
1785{ 1785{
1786 int err = ceph_do_getattr(inode, CEPH_CAP_AUTH_SHARED); 1786 int err;
1787
1788 if (flags & IPERM_FLAG_RCU)
1789 return -ECHILD;
1790
1791 err = ceph_do_getattr(inode, CEPH_CAP_AUTH_SHARED);
1787 1792
1788 if (!err) 1793 if (!err)
1789 err = generic_permission(inode, mask, NULL); 1794 err = generic_permission(inode, mask, flags, NULL);
1790 return err; 1795 return err;
1791} 1796}
1792 1797
diff --git a/fs/ceph/super.h b/fs/ceph/super.h
index 7f01728a4657..4553d8829edb 100644
--- a/fs/ceph/super.h
+++ b/fs/ceph/super.h
@@ -665,7 +665,7 @@ extern void ceph_queue_invalidate(struct inode *inode);
665extern void ceph_queue_writeback(struct inode *inode); 665extern void ceph_queue_writeback(struct inode *inode);
666 666
667extern int ceph_do_getattr(struct inode *inode, int mask); 667extern int ceph_do_getattr(struct inode *inode, int mask);
668extern int ceph_permission(struct inode *inode, int mask); 668extern int ceph_permission(struct inode *inode, int mask, unsigned int flags);
669extern int ceph_setattr(struct dentry *dentry, struct iattr *attr); 669extern int ceph_setattr(struct dentry *dentry, struct iattr *attr);
670extern int ceph_getattr(struct vfsmount *mnt, struct dentry *dentry, 670extern int ceph_getattr(struct vfsmount *mnt, struct dentry *dentry,
671 struct kstat *stat); 671 struct kstat *stat);
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 223717dcc401..8e21e0fe65d5 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -283,10 +283,13 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
283 return 0; 283 return 0;
284} 284}
285 285
286static int cifs_permission(struct inode *inode, int mask) 286static int cifs_permission(struct inode *inode, int mask, unsigned int flags)
287{ 287{
288 struct cifs_sb_info *cifs_sb; 288 struct cifs_sb_info *cifs_sb;
289 289
290 if (flags & IPERM_FLAG_RCU)
291 return -ECHILD;
292
290 cifs_sb = CIFS_SB(inode->i_sb); 293 cifs_sb = CIFS_SB(inode->i_sb);
291 294
292 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) { 295 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) {
@@ -298,7 +301,7 @@ static int cifs_permission(struct inode *inode, int mask)
298 on the client (above and beyond ACL on servers) for 301 on the client (above and beyond ACL on servers) for
299 servers which do not support setting and viewing mode bits, 302 servers which do not support setting and viewing mode bits,
300 so allowing client to check permissions is useful */ 303 so allowing client to check permissions is useful */
301 return generic_permission(inode, mask, NULL); 304 return generic_permission(inode, mask, flags, NULL);
302} 305}
303 306
304static struct kmem_cache *cifs_inode_cachep; 307static struct kmem_cache *cifs_inode_cachep;
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index 619a8303766e..29badd91360f 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -135,10 +135,13 @@ exit:
135} 135}
136 136
137 137
138int coda_permission(struct inode *inode, int mask) 138int coda_permission(struct inode *inode, int mask, unsigned int flags)
139{ 139{
140 int error; 140 int error;
141 141
142 if (flags & IPERM_FLAG_RCU)
143 return -ECHILD;
144
142 mask &= MAY_READ | MAY_WRITE | MAY_EXEC; 145 mask &= MAY_READ | MAY_WRITE | MAY_EXEC;
143 146
144 if (!mask) 147 if (!mask)
diff --git a/fs/coda/pioctl.c b/fs/coda/pioctl.c
index 2fd89b5c5c7b..741f0bd03918 100644
--- a/fs/coda/pioctl.c
+++ b/fs/coda/pioctl.c
@@ -24,7 +24,7 @@
24#include <linux/coda_psdev.h> 24#include <linux/coda_psdev.h>
25 25
26/* pioctl ops */ 26/* pioctl ops */
27static int coda_ioctl_permission(struct inode *inode, int mask); 27static int coda_ioctl_permission(struct inode *inode, int mask, unsigned int flags);
28static long coda_pioctl(struct file *filp, unsigned int cmd, 28static long coda_pioctl(struct file *filp, unsigned int cmd,
29 unsigned long user_data); 29 unsigned long user_data);
30 30
@@ -41,8 +41,10 @@ const struct file_operations coda_ioctl_operations = {
41}; 41};
42 42
43/* the coda pioctl inode ops */ 43/* the coda pioctl inode ops */
44static int coda_ioctl_permission(struct inode *inode, int mask) 44static int coda_ioctl_permission(struct inode *inode, int mask, unsigned int flags)
45{ 45{
46 if (flags & IPERM_FLAG_RCU)
47 return -ECHILD;
46 return (mask & MAY_EXEC) ? -EACCES : 0; 48 return (mask & MAY_EXEC) ? -EACCES : 0;
47} 49}
48 50
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index f91b35db4c6e..337352a94751 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -980,8 +980,10 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length)
980} 980}
981 981
982static int 982static int
983ecryptfs_permission(struct inode *inode, int mask) 983ecryptfs_permission(struct inode *inode, int mask, unsigned int flags)
984{ 984{
985 if (flags & IPERM_FLAG_RCU)
986 return -ECHILD;
985 return inode_permission(ecryptfs_inode_to_lower(inode), mask); 987 return inode_permission(ecryptfs_inode_to_lower(inode), mask);
986} 988}
987 989
diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c
index 2bcc0431bada..dd9bb3f0c8d7 100644
--- a/fs/ext2/acl.c
+++ b/fs/ext2/acl.c
@@ -232,10 +232,14 @@ ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
232} 232}
233 233
234int 234int
235ext2_check_acl(struct inode *inode, int mask) 235ext2_check_acl(struct inode *inode, int mask, unsigned int flags)
236{ 236{
237 struct posix_acl *acl = ext2_get_acl(inode, ACL_TYPE_ACCESS); 237 struct posix_acl *acl;
238
239 if (flags & IPERM_FLAG_RCU)
240 return -ECHILD;
238 241
242 acl = ext2_get_acl(inode, ACL_TYPE_ACCESS);
239 if (IS_ERR(acl)) 243 if (IS_ERR(acl))
240 return PTR_ERR(acl); 244 return PTR_ERR(acl);
241 if (acl) { 245 if (acl) {
diff --git a/fs/ext2/acl.h b/fs/ext2/acl.h
index 3ff6cbb9ac44..c939b7b12099 100644
--- a/fs/ext2/acl.h
+++ b/fs/ext2/acl.h
@@ -54,7 +54,7 @@ static inline int ext2_acl_count(size_t size)
54#ifdef CONFIG_EXT2_FS_POSIX_ACL 54#ifdef CONFIG_EXT2_FS_POSIX_ACL
55 55
56/* acl.c */ 56/* acl.c */
57extern int ext2_check_acl (struct inode *, int); 57extern int ext2_check_acl (struct inode *, int, unsigned int);
58extern int ext2_acl_chmod (struct inode *); 58extern int ext2_acl_chmod (struct inode *);
59extern int ext2_init_acl (struct inode *, struct inode *); 59extern int ext2_init_acl (struct inode *, struct inode *);
60 60
diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c
index 8a11fe212183..9e49da8302d3 100644
--- a/fs/ext3/acl.c
+++ b/fs/ext3/acl.c
@@ -240,10 +240,14 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type,
240} 240}
241 241
242int 242int
243ext3_check_acl(struct inode *inode, int mask) 243ext3_check_acl(struct inode *inode, int mask, unsigned int flags)
244{ 244{
245 struct posix_acl *acl = ext3_get_acl(inode, ACL_TYPE_ACCESS); 245 struct posix_acl *acl;
246
247 if (flags & IPERM_FLAG_RCU)
248 return -ECHILD;
246 249
250 acl = ext3_get_acl(inode, ACL_TYPE_ACCESS);
247 if (IS_ERR(acl)) 251 if (IS_ERR(acl))
248 return PTR_ERR(acl); 252 return PTR_ERR(acl);
249 if (acl) { 253 if (acl) {
diff --git a/fs/ext3/acl.h b/fs/ext3/acl.h
index 597334626de9..5faf8048e906 100644
--- a/fs/ext3/acl.h
+++ b/fs/ext3/acl.h
@@ -54,7 +54,7 @@ static inline int ext3_acl_count(size_t size)
54#ifdef CONFIG_EXT3_FS_POSIX_ACL 54#ifdef CONFIG_EXT3_FS_POSIX_ACL
55 55
56/* acl.c */ 56/* acl.c */
57extern int ext3_check_acl (struct inode *, int); 57extern int ext3_check_acl (struct inode *, int, unsigned int);
58extern int ext3_acl_chmod (struct inode *); 58extern int ext3_acl_chmod (struct inode *);
59extern int ext3_init_acl (handle_t *, struct inode *, struct inode *); 59extern int ext3_init_acl (handle_t *, struct inode *, struct inode *);
60 60
diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c
index 5e2ed4504ead..373dcaeedba9 100644
--- a/fs/ext4/acl.c
+++ b/fs/ext4/acl.c
@@ -238,10 +238,14 @@ ext4_set_acl(handle_t *handle, struct inode *inode, int type,
238} 238}
239 239
240int 240int
241ext4_check_acl(struct inode *inode, int mask) 241ext4_check_acl(struct inode *inode, int mask, unsigned int flags)
242{ 242{
243 struct posix_acl *acl = ext4_get_acl(inode, ACL_TYPE_ACCESS); 243 struct posix_acl *acl;
244
245 if (flags & IPERM_FLAG_RCU)
246 return -ECHILD;
244 247
248 acl = ext4_get_acl(inode, ACL_TYPE_ACCESS);
245 if (IS_ERR(acl)) 249 if (IS_ERR(acl))
246 return PTR_ERR(acl); 250 return PTR_ERR(acl);
247 if (acl) { 251 if (acl) {
diff --git a/fs/ext4/acl.h b/fs/ext4/acl.h
index 9d843d5deac4..dec821168fd4 100644
--- a/fs/ext4/acl.h
+++ b/fs/ext4/acl.h
@@ -54,7 +54,7 @@ static inline int ext4_acl_count(size_t size)
54#ifdef CONFIG_EXT4_FS_POSIX_ACL 54#ifdef CONFIG_EXT4_FS_POSIX_ACL
55 55
56/* acl.c */ 56/* acl.c */
57extern int ext4_check_acl(struct inode *, int); 57extern int ext4_check_acl(struct inode *, int, unsigned int);
58extern int ext4_acl_chmod(struct inode *); 58extern int ext4_acl_chmod(struct inode *);
59extern int ext4_init_acl(handle_t *, struct inode *, struct inode *); 59extern int ext4_init_acl(handle_t *, struct inode *, struct inode *);
60 60
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 07f4b5e675fc..f738599fd8cd 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -985,12 +985,15 @@ static int fuse_access(struct inode *inode, int mask)
985 * access request is sent. Execute permission is still checked 985 * access request is sent. Execute permission is still checked
986 * locally based on file mode. 986 * locally based on file mode.
987 */ 987 */
988static int fuse_permission(struct inode *inode, int mask) 988static int fuse_permission(struct inode *inode, int mask, unsigned int flags)
989{ 989{
990 struct fuse_conn *fc = get_fuse_conn(inode); 990 struct fuse_conn *fc = get_fuse_conn(inode);
991 bool refreshed = false; 991 bool refreshed = false;
992 int err = 0; 992 int err = 0;
993 993
994 if (flags & IPERM_FLAG_RCU)
995 return -ECHILD;
996
994 if (!fuse_allow_task(fc, current)) 997 if (!fuse_allow_task(fc, current))
995 return -EACCES; 998 return -EACCES;
996 999
@@ -1005,7 +1008,7 @@ static int fuse_permission(struct inode *inode, int mask)
1005 } 1008 }
1006 1009
1007 if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { 1010 if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
1008 err = generic_permission(inode, mask, NULL); 1011 err = generic_permission(inode, mask, flags, NULL);
1009 1012
1010 /* If permission is denied, try to refresh file 1013 /* If permission is denied, try to refresh file
1011 attributes. This is also needed, because the root 1014 attributes. This is also needed, because the root
@@ -1013,7 +1016,8 @@ static int fuse_permission(struct inode *inode, int mask)
1013 if (err == -EACCES && !refreshed) { 1016 if (err == -EACCES && !refreshed) {
1014 err = fuse_do_getattr(inode, NULL, NULL); 1017 err = fuse_do_getattr(inode, NULL, NULL);
1015 if (!err) 1018 if (!err)
1016 err = generic_permission(inode, mask, NULL); 1019 err = generic_permission(inode, mask,
1020 flags, NULL);
1017 } 1021 }
1018 1022
1019 /* Note: the opposite of the above test does not 1023 /* Note: the opposite of the above test does not
diff --git a/fs/generic_acl.c b/fs/generic_acl.c
index 6bc9e3a5a693..628004282130 100644
--- a/fs/generic_acl.c
+++ b/fs/generic_acl.c
@@ -190,10 +190,14 @@ generic_acl_chmod(struct inode *inode)
190} 190}
191 191
192int 192int
193generic_check_acl(struct inode *inode, int mask) 193generic_check_acl(struct inode *inode, int mask, unsigned int flags)
194{ 194{
195 struct posix_acl *acl = get_cached_acl(inode, ACL_TYPE_ACCESS); 195 struct posix_acl *acl;
196
197 if (flags & IPERM_FLAG_RCU)
198 return -ECHILD;
196 199
200 acl = get_cached_acl(inode, ACL_TYPE_ACCESS);
197 if (acl) { 201 if (acl) {
198 int error = posix_acl_permission(inode, acl, mask); 202 int error = posix_acl_permission(inode, acl, mask);
199 posix_acl_release(acl); 203 posix_acl_release(acl);
diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c
index 48171f4c943d..7118f1a780a9 100644
--- a/fs/gfs2/acl.c
+++ b/fs/gfs2/acl.c
@@ -75,11 +75,14 @@ static struct posix_acl *gfs2_acl_get(struct gfs2_inode *ip, int type)
75 * Returns: errno 75 * Returns: errno
76 */ 76 */
77 77
78int gfs2_check_acl(struct inode *inode, int mask) 78int gfs2_check_acl(struct inode *inode, int mask, unsigned int flags)
79{ 79{
80 struct posix_acl *acl; 80 struct posix_acl *acl;
81 int error; 81 int error;
82 82
83 if (flags & IPERM_FLAG_RCU)
84 return -ECHILD;
85
83 acl = gfs2_acl_get(GFS2_I(inode), ACL_TYPE_ACCESS); 86 acl = gfs2_acl_get(GFS2_I(inode), ACL_TYPE_ACCESS);
84 if (IS_ERR(acl)) 87 if (IS_ERR(acl))
85 return PTR_ERR(acl); 88 return PTR_ERR(acl);
diff --git a/fs/gfs2/acl.h b/fs/gfs2/acl.h
index b522b0cb39ea..a93907c8159b 100644
--- a/fs/gfs2/acl.h
+++ b/fs/gfs2/acl.h
@@ -16,7 +16,7 @@
16#define GFS2_POSIX_ACL_DEFAULT "posix_acl_default" 16#define GFS2_POSIX_ACL_DEFAULT "posix_acl_default"
17#define GFS2_ACL_MAX_ENTRIES 25 17#define GFS2_ACL_MAX_ENTRIES 25
18 18
19extern int gfs2_check_acl(struct inode *inode, int mask); 19extern int gfs2_check_acl(struct inode *inode, int mask, unsigned int);
20extern int gfs2_acl_create(struct gfs2_inode *dip, struct inode *inode); 20extern int gfs2_acl_create(struct gfs2_inode *dip, struct inode *inode);
21extern int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr); 21extern int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr);
22extern const struct xattr_handler gfs2_xattr_system_handler; 22extern const struct xattr_handler gfs2_xattr_system_handler;
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
index aa996471ec5c..fca6689e12e6 100644
--- a/fs/gfs2/file.c
+++ b/fs/gfs2/file.c
@@ -241,7 +241,7 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask)
241 !capable(CAP_LINUX_IMMUTABLE)) 241 !capable(CAP_LINUX_IMMUTABLE))
242 goto out; 242 goto out;
243 if (!IS_IMMUTABLE(inode)) { 243 if (!IS_IMMUTABLE(inode)) {
244 error = gfs2_permission(inode, MAY_WRITE); 244 error = gfs2_permission(inode, MAY_WRITE, 0);
245 if (error) 245 if (error)
246 goto out; 246 goto out;
247 } 247 }
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index e1213f7f9217..6163be9686be 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -509,7 +509,7 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
509 } 509 }
510 510
511 if (!is_root) { 511 if (!is_root) {
512 error = gfs2_permission(dir, MAY_EXEC); 512 error = gfs2_permission(dir, MAY_EXEC, 0);
513 if (error) 513 if (error)
514 goto out; 514 goto out;
515 } 515 }
@@ -539,7 +539,7 @@ static int create_ok(struct gfs2_inode *dip, const struct qstr *name,
539{ 539{
540 int error; 540 int error;
541 541
542 error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC); 542 error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC, 0);
543 if (error) 543 if (error)
544 return error; 544 return error;
545 545
diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h
index d8499fadcc53..732a183efdb3 100644
--- a/fs/gfs2/inode.h
+++ b/fs/gfs2/inode.h
@@ -113,7 +113,7 @@ extern struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
113extern struct inode *gfs2_createi(struct gfs2_holder *ghs, 113extern struct inode *gfs2_createi(struct gfs2_holder *ghs,
114 const struct qstr *name, 114 const struct qstr *name,
115 unsigned int mode, dev_t dev); 115 unsigned int mode, dev_t dev);
116extern int gfs2_permission(struct inode *inode, int mask); 116extern int gfs2_permission(struct inode *inode, int mask, unsigned int flags);
117extern int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr); 117extern int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr);
118extern struct inode *gfs2_lookup_simple(struct inode *dip, const char *name); 118extern struct inode *gfs2_lookup_simple(struct inode *dip, const char *name);
119extern void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf); 119extern void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf);
diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c
index f28f89796f4d..5c63a06fcd7c 100644
--- a/fs/gfs2/ops_inode.c
+++ b/fs/gfs2/ops_inode.c
@@ -166,7 +166,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
166 if (error) 166 if (error)
167 goto out_child; 167 goto out_child;
168 168
169 error = gfs2_permission(dir, MAY_WRITE | MAY_EXEC); 169 error = gfs2_permission(dir, MAY_WRITE | MAY_EXEC, 0);
170 if (error) 170 if (error)
171 goto out_gunlock; 171 goto out_gunlock;
172 172
@@ -289,7 +289,7 @@ static int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name,
289 if (IS_APPEND(&dip->i_inode)) 289 if (IS_APPEND(&dip->i_inode))
290 return -EPERM; 290 return -EPERM;
291 291
292 error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC); 292 error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC, 0);
293 if (error) 293 if (error)
294 return error; 294 return error;
295 295
@@ -822,7 +822,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
822 } 822 }
823 } 823 }
824 } else { 824 } else {
825 error = gfs2_permission(ndir, MAY_WRITE | MAY_EXEC); 825 error = gfs2_permission(ndir, MAY_WRITE | MAY_EXEC, 0);
826 if (error) 826 if (error)
827 goto out_gunlock; 827 goto out_gunlock;
828 828
@@ -857,7 +857,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
857 /* Check out the dir to be renamed */ 857 /* Check out the dir to be renamed */
858 858
859 if (dir_rename) { 859 if (dir_rename) {
860 error = gfs2_permission(odentry->d_inode, MAY_WRITE); 860 error = gfs2_permission(odentry->d_inode, MAY_WRITE, 0);
861 if (error) 861 if (error)
862 goto out_gunlock; 862 goto out_gunlock;
863 } 863 }
@@ -1041,13 +1041,17 @@ static void gfs2_put_link(struct dentry *dentry, struct nameidata *nd, void *p)
1041 * Returns: errno 1041 * Returns: errno
1042 */ 1042 */
1043 1043
1044int gfs2_permission(struct inode *inode, int mask) 1044int gfs2_permission(struct inode *inode, int mask, unsigned int flags)
1045{ 1045{
1046 struct gfs2_inode *ip = GFS2_I(inode); 1046 struct gfs2_inode *ip;
1047 struct gfs2_holder i_gh; 1047 struct gfs2_holder i_gh;
1048 int error; 1048 int error;
1049 int unlock = 0; 1049 int unlock = 0;
1050 1050
1051 if (flags & IPERM_FLAG_RCU)
1052 return -ECHILD;
1053
1054 ip = GFS2_I(inode);
1051 if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) { 1055 if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) {
1052 error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); 1056 error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
1053 if (error) 1057 if (error)
@@ -1058,7 +1062,7 @@ int gfs2_permission(struct inode *inode, int mask)
1058 if ((mask & MAY_WRITE) && IS_IMMUTABLE(inode)) 1062 if ((mask & MAY_WRITE) && IS_IMMUTABLE(inode))
1059 error = -EACCES; 1063 error = -EACCES;
1060 else 1064 else
1061 error = generic_permission(inode, mask, gfs2_check_acl); 1065 error = generic_permission(inode, mask, flags, gfs2_check_acl);
1062 if (unlock) 1066 if (unlock)
1063 gfs2_glock_dq_uninit(&i_gh); 1067 gfs2_glock_dq_uninit(&i_gh);
1064 1068
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index 0bc81cf256b8..d3244d949a4e 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -749,11 +749,14 @@ int hostfs_rename(struct inode *from_ino, struct dentry *from,
749 return err; 749 return err;
750} 750}
751 751
752int hostfs_permission(struct inode *ino, int desired) 752int hostfs_permission(struct inode *ino, int desired, unsigned int flags)
753{ 753{
754 char *name; 754 char *name;
755 int r = 0, w = 0, x = 0, err; 755 int r = 0, w = 0, x = 0, err;
756 756
757 if (flags & IPERM_FLAG_RCU)
758 return -ECHILD;
759
757 if (desired & MAY_READ) r = 1; 760 if (desired & MAY_READ) r = 1;
758 if (desired & MAY_WRITE) w = 1; 761 if (desired & MAY_WRITE) w = 1;
759 if (desired & MAY_EXEC) x = 1; 762 if (desired & MAY_EXEC) x = 1;
@@ -768,7 +771,7 @@ int hostfs_permission(struct inode *ino, int desired)
768 err = access_file(name, r, w, x); 771 err = access_file(name, r, w, x);
769 __putname(name); 772 __putname(name);
770 if (!err) 773 if (!err)
771 err = generic_permission(ino, desired, NULL); 774 err = generic_permission(ino, desired, flags, NULL);
772 return err; 775 return err;
773} 776}
774 777
diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c
index 11c2b4080f65..f4ad9e31ddc4 100644
--- a/fs/hpfs/namei.c
+++ b/fs/hpfs/namei.c
@@ -419,7 +419,7 @@ again:
419 unlock_kernel(); 419 unlock_kernel();
420 return -ENOSPC; 420 return -ENOSPC;
421 } 421 }
422 if (generic_permission(inode, MAY_WRITE, NULL) || 422 if (generic_permission(inode, MAY_WRITE, 0, NULL) ||
423 !S_ISREG(inode->i_mode) || 423 !S_ISREG(inode->i_mode) ||
424 get_write_access(inode)) { 424 get_write_access(inode)) {
425 d_rehash(dentry); 425 d_rehash(dentry);
diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c
index 54a92fd02bbd..95b79672150a 100644
--- a/fs/jffs2/acl.c
+++ b/fs/jffs2/acl.c
@@ -259,11 +259,14 @@ static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
259 return rc; 259 return rc;
260} 260}
261 261
262int jffs2_check_acl(struct inode *inode, int mask) 262int jffs2_check_acl(struct inode *inode, int mask, unsigned int flags)
263{ 263{
264 struct posix_acl *acl; 264 struct posix_acl *acl;
265 int rc; 265 int rc;
266 266
267 if (flags & IPERM_FLAG_RCU)
268 return -ECHILD;
269
267 acl = jffs2_get_acl(inode, ACL_TYPE_ACCESS); 270 acl = jffs2_get_acl(inode, ACL_TYPE_ACCESS);
268 if (IS_ERR(acl)) 271 if (IS_ERR(acl))
269 return PTR_ERR(acl); 272 return PTR_ERR(acl);
diff --git a/fs/jffs2/acl.h b/fs/jffs2/acl.h
index 5e42de8d9541..3119f59253d3 100644
--- a/fs/jffs2/acl.h
+++ b/fs/jffs2/acl.h
@@ -26,7 +26,7 @@ struct jffs2_acl_header {
26 26
27#ifdef CONFIG_JFFS2_FS_POSIX_ACL 27#ifdef CONFIG_JFFS2_FS_POSIX_ACL
28 28
29extern int jffs2_check_acl(struct inode *, int); 29extern int jffs2_check_acl(struct inode *, int, unsigned int);
30extern int jffs2_acl_chmod(struct inode *); 30extern int jffs2_acl_chmod(struct inode *);
31extern int jffs2_init_acl_pre(struct inode *, struct inode *, int *); 31extern int jffs2_init_acl_pre(struct inode *, struct inode *, int *);
32extern int jffs2_init_acl_post(struct inode *); 32extern int jffs2_init_acl_post(struct inode *);
diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c
index 1057a4998e4e..e5de9422fa32 100644
--- a/fs/jfs/acl.c
+++ b/fs/jfs/acl.c
@@ -114,10 +114,14 @@ out:
114 return rc; 114 return rc;
115} 115}
116 116
117int jfs_check_acl(struct inode *inode, int mask) 117int jfs_check_acl(struct inode *inode, int mask, unsigned int flags)
118{ 118{
119 struct posix_acl *acl = jfs_get_acl(inode, ACL_TYPE_ACCESS); 119 struct posix_acl *acl;
120
121 if (flags & IPERM_FLAG_RCU)
122 return -ECHILD;
120 123
124 acl = jfs_get_acl(inode, ACL_TYPE_ACCESS);
121 if (IS_ERR(acl)) 125 if (IS_ERR(acl))
122 return PTR_ERR(acl); 126 return PTR_ERR(acl);
123 if (acl) { 127 if (acl) {
diff --git a/fs/jfs/jfs_acl.h b/fs/jfs/jfs_acl.h
index 54e07559878d..f9285c4900fa 100644
--- a/fs/jfs/jfs_acl.h
+++ b/fs/jfs/jfs_acl.h
@@ -20,7 +20,7 @@
20 20
21#ifdef CONFIG_JFS_POSIX_ACL 21#ifdef CONFIG_JFS_POSIX_ACL
22 22
23int jfs_check_acl(struct inode *, int); 23int jfs_check_acl(struct inode *, int, unsigned int flags);
24int jfs_init_acl(tid_t, struct inode *, struct inode *); 24int jfs_init_acl(tid_t, struct inode *, struct inode *);
25int jfs_acl_chmod(struct inode *inode); 25int jfs_acl_chmod(struct inode *inode);
26 26
diff --git a/fs/logfs/dir.c b/fs/logfs/dir.c
index 409dfd65e9a1..f9ddf0c388c8 100644
--- a/fs/logfs/dir.c
+++ b/fs/logfs/dir.c
@@ -555,9 +555,11 @@ static int logfs_symlink(struct inode *dir, struct dentry *dentry,
555 return __logfs_create(dir, dentry, inode, target, destlen); 555 return __logfs_create(dir, dentry, inode, target, destlen);
556} 556}
557 557
558static int logfs_permission(struct inode *inode, int mask) 558static int logfs_permission(struct inode *inode, int mask, unsigned int flags)
559{ 559{
560 return generic_permission(inode, mask, NULL); 560 if (flags & IPERM_FLAG_RCU)
561 return -ECHILD;
562 return generic_permission(inode, mask, flags, NULL);
561} 563}
562 564
563static int logfs_link(struct dentry *old_dentry, struct inode *dir, 565static int logfs_link(struct dentry *old_dentry, struct inode *dir,
diff --git a/fs/namei.c b/fs/namei.c
index 6e275363e89d..4e957bf744ae 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -169,8 +169,8 @@ EXPORT_SYMBOL(putname);
169/* 169/*
170 * This does basic POSIX ACL permission checking 170 * This does basic POSIX ACL permission checking
171 */ 171 */
172static inline int __acl_permission_check(struct inode *inode, int mask, 172static int acl_permission_check(struct inode *inode, int mask, unsigned int flags,
173 int (*check_acl)(struct inode *inode, int mask), int rcu) 173 int (*check_acl)(struct inode *inode, int mask, unsigned int flags))
174{ 174{
175 umode_t mode = inode->i_mode; 175 umode_t mode = inode->i_mode;
176 176
@@ -180,13 +180,9 @@ static inline int __acl_permission_check(struct inode *inode, int mask,
180 mode >>= 6; 180 mode >>= 6;
181 else { 181 else {
182 if (IS_POSIXACL(inode) && (mode & S_IRWXG) && check_acl) { 182 if (IS_POSIXACL(inode) && (mode & S_IRWXG) && check_acl) {
183 if (rcu) { 183 int error = check_acl(inode, mask, flags);
184 return -ECHILD; 184 if (error != -EAGAIN)
185 } else { 185 return error;
186 int error = check_acl(inode, mask);
187 if (error != -EAGAIN)
188 return error;
189 }
190 } 186 }
191 187
192 if (in_group_p(inode->i_gid)) 188 if (in_group_p(inode->i_gid))
@@ -201,32 +197,31 @@ static inline int __acl_permission_check(struct inode *inode, int mask,
201 return -EACCES; 197 return -EACCES;
202} 198}
203 199
204static inline int acl_permission_check(struct inode *inode, int mask,
205 int (*check_acl)(struct inode *inode, int mask))
206{
207 return __acl_permission_check(inode, mask, check_acl, 0);
208}
209
210/** 200/**
211 * generic_permission - check for access rights on a Posix-like filesystem 201 * generic_permission - check for access rights on a Posix-like filesystem
212 * @inode: inode to check access rights for 202 * @inode: inode to check access rights for
213 * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC) 203 * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
214 * @check_acl: optional callback to check for Posix ACLs 204 * @check_acl: optional callback to check for Posix ACLs
205 * @flags IPERM_FLAG_ flags.
215 * 206 *
216 * Used to check for read/write/execute permissions on a file. 207 * Used to check for read/write/execute permissions on a file.
217 * We use "fsuid" for this, letting us set arbitrary permissions 208 * We use "fsuid" for this, letting us set arbitrary permissions
218 * for filesystem access without changing the "normal" uids which 209 * for filesystem access without changing the "normal" uids which
219 * are used for other things.. 210 * are used for other things.
211 *
212 * generic_permission is rcu-walk aware. It returns -ECHILD in case an rcu-walk
213 * request cannot be satisfied (eg. requires blocking or too much complexity).
214 * It would then be called again in ref-walk mode.
220 */ 215 */
221int generic_permission(struct inode *inode, int mask, 216int generic_permission(struct inode *inode, int mask, unsigned int flags,
222 int (*check_acl)(struct inode *inode, int mask)) 217 int (*check_acl)(struct inode *inode, int mask, unsigned int flags))
223{ 218{
224 int ret; 219 int ret;
225 220
226 /* 221 /*
227 * Do the basic POSIX ACL permission checks. 222 * Do the basic POSIX ACL permission checks.
228 */ 223 */
229 ret = acl_permission_check(inode, mask, check_acl); 224 ret = acl_permission_check(inode, mask, flags, check_acl);
230 if (ret != -EACCES) 225 if (ret != -EACCES)
231 return ret; 226 return ret;
232 227
@@ -281,9 +276,10 @@ int inode_permission(struct inode *inode, int mask)
281 } 276 }
282 277
283 if (inode->i_op->permission) 278 if (inode->i_op->permission)
284 retval = inode->i_op->permission(inode, mask); 279 retval = inode->i_op->permission(inode, mask, 0);
285 else 280 else
286 retval = generic_permission(inode, mask, inode->i_op->check_acl); 281 retval = generic_permission(inode, mask, 0,
282 inode->i_op->check_acl);
287 283
288 if (retval) 284 if (retval)
289 return retval; 285 return retval;
@@ -668,22 +664,19 @@ force_reval_path(struct path *path, struct nameidata *nd)
668 * short-cut DAC fails, then call ->permission() to do more 664 * short-cut DAC fails, then call ->permission() to do more
669 * complete permission check. 665 * complete permission check.
670 */ 666 */
671static inline int __exec_permission(struct inode *inode, int rcu) 667static inline int exec_permission(struct inode *inode, unsigned int flags)
672{ 668{
673 int ret; 669 int ret;
674 670
675 if (inode->i_op->permission) { 671 if (inode->i_op->permission) {
676 if (rcu) 672 ret = inode->i_op->permission(inode, MAY_EXEC, flags);
677 return -ECHILD; 673 } else {
678 ret = inode->i_op->permission(inode, MAY_EXEC); 674 ret = acl_permission_check(inode, MAY_EXEC, flags,
679 if (!ret) 675 inode->i_op->check_acl);
680 goto ok;
681 return ret;
682 } 676 }
683 ret = __acl_permission_check(inode, MAY_EXEC, inode->i_op->check_acl, rcu); 677 if (likely(!ret))
684 if (!ret)
685 goto ok; 678 goto ok;
686 if (rcu && ret == -ECHILD) 679 if (ret == -ECHILD)
687 return ret; 680 return ret;
688 681
689 if (capable(CAP_DAC_OVERRIDE) || capable(CAP_DAC_READ_SEARCH)) 682 if (capable(CAP_DAC_OVERRIDE) || capable(CAP_DAC_READ_SEARCH))
@@ -691,17 +684,7 @@ static inline int __exec_permission(struct inode *inode, int rcu)
691 684
692 return ret; 685 return ret;
693ok: 686ok:
694 return security_inode_exec_permission(inode, rcu); 687 return security_inode_exec_permission(inode, flags);
695}
696
697static int exec_permission(struct inode *inode)
698{
699 return __exec_permission(inode, 0);
700}
701
702static int exec_permission_rcu(struct inode *inode)
703{
704 return __exec_permission(inode, 1);
705} 688}
706 689
707static __always_inline void set_root(struct nameidata *nd) 690static __always_inline void set_root(struct nameidata *nd)
@@ -1165,7 +1148,7 @@ static int link_path_walk(const char *name, struct nameidata *nd)
1165 1148
1166 nd->flags |= LOOKUP_CONTINUE; 1149 nd->flags |= LOOKUP_CONTINUE;
1167 if (nd->flags & LOOKUP_RCU) { 1150 if (nd->flags & LOOKUP_RCU) {
1168 err = exec_permission_rcu(nd->inode); 1151 err = exec_permission(nd->inode, IPERM_FLAG_RCU);
1169 if (err == -ECHILD) { 1152 if (err == -ECHILD) {
1170 if (nameidata_drop_rcu(nd)) 1153 if (nameidata_drop_rcu(nd))
1171 return -ECHILD; 1154 return -ECHILD;
@@ -1173,7 +1156,7 @@ static int link_path_walk(const char *name, struct nameidata *nd)
1173 } 1156 }
1174 } else { 1157 } else {
1175exec_again: 1158exec_again:
1176 err = exec_permission(nd->inode); 1159 err = exec_permission(nd->inode, 0);
1177 } 1160 }
1178 if (err) 1161 if (err)
1179 break; 1162 break;
@@ -1620,7 +1603,7 @@ static struct dentry *__lookup_hash(struct qstr *name,
1620 struct dentry *dentry; 1603 struct dentry *dentry;
1621 int err; 1604 int err;
1622 1605
1623 err = exec_permission(inode); 1606 err = exec_permission(inode, 0);
1624 if (err) 1607 if (err)
1625 return ERR_PTR(err); 1608 return ERR_PTR(err);
1626 1609
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 58beace14b19..d33da530097a 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -2189,11 +2189,14 @@ int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags)
2189 return nfs_do_access(inode, cred, nfs_open_permission_mask(openflags)); 2189 return nfs_do_access(inode, cred, nfs_open_permission_mask(openflags));
2190} 2190}
2191 2191
2192int nfs_permission(struct inode *inode, int mask) 2192int nfs_permission(struct inode *inode, int mask, unsigned int flags)
2193{ 2193{
2194 struct rpc_cred *cred; 2194 struct rpc_cred *cred;
2195 int res = 0; 2195 int res = 0;
2196 2196
2197 if (flags & IPERM_FLAG_RCU)
2198 return -ECHILD;
2199
2197 nfs_inc_stats(inode, NFSIOS_VFSACCESS); 2200 nfs_inc_stats(inode, NFSIOS_VFSACCESS);
2198 2201
2199 if ((mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0) 2202 if ((mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0)
@@ -2241,7 +2244,7 @@ out:
2241out_notsup: 2244out_notsup:
2242 res = nfs_revalidate_inode(NFS_SERVER(inode), inode); 2245 res = nfs_revalidate_inode(NFS_SERVER(inode), inode);
2243 if (res == 0) 2246 if (res == 0)
2244 res = generic_permission(inode, mask, NULL); 2247 res = generic_permission(inode, mask, flags, NULL);
2245 goto out; 2248 goto out;
2246} 2249}
2247 2250
diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c
index 71d4bc8464e0..77b48c8fab17 100644
--- a/fs/nilfs2/inode.c
+++ b/fs/nilfs2/inode.c
@@ -785,15 +785,19 @@ out_err:
785 return err; 785 return err;
786} 786}
787 787
788int nilfs_permission(struct inode *inode, int mask) 788int nilfs_permission(struct inode *inode, int mask, unsigned int flags)
789{ 789{
790 struct nilfs_root *root = NILFS_I(inode)->i_root; 790 struct nilfs_root *root;
791
792 if (flags & IPERM_FLAG_RCU)
793 return -ECHILD;
791 794
795 root = NILFS_I(inode)->i_root;
792 if ((mask & MAY_WRITE) && root && 796 if ((mask & MAY_WRITE) && root &&
793 root->cno != NILFS_CPTREE_CURRENT_CNO) 797 root->cno != NILFS_CPTREE_CURRENT_CNO)
794 return -EROFS; /* snapshot is not writable */ 798 return -EROFS; /* snapshot is not writable */
795 799
796 return generic_permission(inode, mask, NULL); 800 return generic_permission(inode, mask, flags, NULL);
797} 801}
798 802
799int nilfs_load_inode_block(struct nilfs_sb_info *sbi, struct inode *inode, 803int nilfs_load_inode_block(struct nilfs_sb_info *sbi, struct inode *inode,
diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h
index f7560da5a567..0ca98823db59 100644
--- a/fs/nilfs2/nilfs.h
+++ b/fs/nilfs2/nilfs.h
@@ -256,7 +256,7 @@ extern void nilfs_update_inode(struct inode *, struct buffer_head *);
256extern void nilfs_truncate(struct inode *); 256extern void nilfs_truncate(struct inode *);
257extern void nilfs_evict_inode(struct inode *); 257extern void nilfs_evict_inode(struct inode *);
258extern int nilfs_setattr(struct dentry *, struct iattr *); 258extern int nilfs_setattr(struct dentry *, struct iattr *);
259int nilfs_permission(struct inode *inode, int mask); 259int nilfs_permission(struct inode *inode, int mask, unsigned int flags);
260extern int nilfs_load_inode_block(struct nilfs_sb_info *, struct inode *, 260extern int nilfs_load_inode_block(struct nilfs_sb_info *, struct inode *,
261 struct buffer_head **); 261 struct buffer_head **);
262extern int nilfs_inode_dirty(struct inode *); 262extern int nilfs_inode_dirty(struct inode *);
diff --git a/fs/ocfs2/acl.c b/fs/ocfs2/acl.c
index 391915093fe1..704f6b1742f3 100644
--- a/fs/ocfs2/acl.c
+++ b/fs/ocfs2/acl.c
@@ -291,13 +291,17 @@ static int ocfs2_set_acl(handle_t *handle,
291 return ret; 291 return ret;
292} 292}
293 293
294int ocfs2_check_acl(struct inode *inode, int mask) 294int ocfs2_check_acl(struct inode *inode, int mask, unsigned int flags)
295{ 295{
296 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 296 struct ocfs2_super *osb;
297 struct buffer_head *di_bh = NULL; 297 struct buffer_head *di_bh = NULL;
298 struct posix_acl *acl; 298 struct posix_acl *acl;
299 int ret = -EAGAIN; 299 int ret = -EAGAIN;
300 300
301 if (flags & IPERM_FLAG_RCU)
302 return -ECHILD;
303
304 osb = OCFS2_SB(inode->i_sb);
301 if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) 305 if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
302 return ret; 306 return ret;
303 307
diff --git a/fs/ocfs2/acl.h b/fs/ocfs2/acl.h
index 5c5d31f05853..4fe7c9cf4bfb 100644
--- a/fs/ocfs2/acl.h
+++ b/fs/ocfs2/acl.h
@@ -26,7 +26,7 @@ struct ocfs2_acl_entry {
26 __le32 e_id; 26 __le32 e_id;
27}; 27};
28 28
29extern int ocfs2_check_acl(struct inode *, int); 29extern int ocfs2_check_acl(struct inode *, int, unsigned int);
30extern int ocfs2_acl_chmod(struct inode *); 30extern int ocfs2_acl_chmod(struct inode *);
31extern int ocfs2_init_acl(handle_t *, struct inode *, struct inode *, 31extern int ocfs2_init_acl(handle_t *, struct inode *, struct inode *,
32 struct buffer_head *, struct buffer_head *, 32 struct buffer_head *, struct buffer_head *,
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index f6cba566429d..bdadbae09094 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -1307,10 +1307,13 @@ bail:
1307 return err; 1307 return err;
1308} 1308}
1309 1309
1310int ocfs2_permission(struct inode *inode, int mask) 1310int ocfs2_permission(struct inode *inode, int mask, unsigned int flags)
1311{ 1311{
1312 int ret; 1312 int ret;
1313 1313
1314 if (flags & IPERM_FLAG_RCU)
1315 return -ECHILD;
1316
1314 mlog_entry_void(); 1317 mlog_entry_void();
1315 1318
1316 ret = ocfs2_inode_lock(inode, NULL, 0); 1319 ret = ocfs2_inode_lock(inode, NULL, 0);
@@ -1320,7 +1323,7 @@ int ocfs2_permission(struct inode *inode, int mask)
1320 goto out; 1323 goto out;
1321 } 1324 }
1322 1325
1323 ret = generic_permission(inode, mask, ocfs2_check_acl); 1326 ret = generic_permission(inode, mask, flags, ocfs2_check_acl);
1324 1327
1325 ocfs2_inode_unlock(inode, 0); 1328 ocfs2_inode_unlock(inode, 0);
1326out: 1329out:
diff --git a/fs/ocfs2/file.h b/fs/ocfs2/file.h
index 97bf761c9e7c..f5afbbef6703 100644
--- a/fs/ocfs2/file.h
+++ b/fs/ocfs2/file.h
@@ -61,7 +61,7 @@ int ocfs2_zero_extend(struct inode *inode, struct buffer_head *di_bh,
61int ocfs2_setattr(struct dentry *dentry, struct iattr *attr); 61int ocfs2_setattr(struct dentry *dentry, struct iattr *attr);
62int ocfs2_getattr(struct vfsmount *mnt, struct dentry *dentry, 62int ocfs2_getattr(struct vfsmount *mnt, struct dentry *dentry,
63 struct kstat *stat); 63 struct kstat *stat);
64int ocfs2_permission(struct inode *inode, int mask); 64int ocfs2_permission(struct inode *inode, int mask, unsigned int flags);
65 65
66int ocfs2_should_update_atime(struct inode *inode, 66int ocfs2_should_update_atime(struct inode *inode,
67 struct vfsmount *vfsmnt); 67 struct vfsmount *vfsmnt);
diff --git a/fs/proc/base.c b/fs/proc/base.c
index dc5b2fcadc3b..b953d41d9abf 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -2114,11 +2114,13 @@ static const struct file_operations proc_fd_operations = {
2114 * /proc/pid/fd needs a special permission handler so that a process can still 2114 * /proc/pid/fd needs a special permission handler so that a process can still
2115 * access /proc/self/fd after it has executed a setuid(). 2115 * access /proc/self/fd after it has executed a setuid().
2116 */ 2116 */
2117static int proc_fd_permission(struct inode *inode, int mask) 2117static int proc_fd_permission(struct inode *inode, int mask, unsigned int flags)
2118{ 2118{
2119 int rv; 2119 int rv;
2120 2120
2121 rv = generic_permission(inode, mask, NULL); 2121 if (flags & IPERM_FLAG_RCU)
2122 return -ECHILD;
2123 rv = generic_permission(inode, mask, flags, NULL);
2122 if (rv == 0) 2124 if (rv == 0)
2123 return 0; 2125 return 0;
2124 if (task_pid(current) == proc_pid(inode)) 2126 if (task_pid(current) == proc_pid(inode))
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index c9097f43b425..09a1f92a34ef 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -295,7 +295,7 @@ out:
295 return ret; 295 return ret;
296} 296}
297 297
298static int proc_sys_permission(struct inode *inode, int mask) 298static int proc_sys_permission(struct inode *inode, int mask,unsigned int flags)
299{ 299{
300 /* 300 /*
301 * sysctl entries that are not writeable, 301 * sysctl entries that are not writeable,
@@ -305,6 +305,9 @@ static int proc_sys_permission(struct inode *inode, int mask)
305 struct ctl_table *table; 305 struct ctl_table *table;
306 int error; 306 int error;
307 307
308 if (flags & IPERM_FLAG_RCU)
309 return -ECHILD;
310
308 /* Executable files are not allowed under /proc/sys/ */ 311 /* Executable files are not allowed under /proc/sys/ */
309 if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) 312 if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))
310 return -EACCES; 313 return -EACCES;
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c
index 9ea22a56cdf1..3cfb2e933644 100644
--- a/fs/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -870,11 +870,14 @@ out:
870 return err; 870 return err;
871} 871}
872 872
873static int reiserfs_check_acl(struct inode *inode, int mask) 873static int reiserfs_check_acl(struct inode *inode, int mask, unsigned int flags)
874{ 874{
875 struct posix_acl *acl; 875 struct posix_acl *acl;
876 int error = -EAGAIN; /* do regular unix permission checks by default */ 876 int error = -EAGAIN; /* do regular unix permission checks by default */
877 877
878 if (flags & IPERM_FLAG_RCU)
879 return -ECHILD;
880
878 acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS); 881 acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS);
879 882
880 if (acl) { 883 if (acl) {
@@ -951,8 +954,10 @@ static int xattr_mount_check(struct super_block *s)
951 return 0; 954 return 0;
952} 955}
953 956
954int reiserfs_permission(struct inode *inode, int mask) 957int reiserfs_permission(struct inode *inode, int mask, unsigned int flags)
955{ 958{
959 if (flags & IPERM_FLAG_RCU)
960 return -ECHILD;
956 /* 961 /*
957 * We don't do permission checks on the internal objects. 962 * We don't do permission checks on the internal objects.
958 * Permissions are determined by the "owning" object. 963 * Permissions are determined by the "owning" object.
@@ -965,9 +970,10 @@ int reiserfs_permission(struct inode *inode, int mask)
965 * Stat data v1 doesn't support ACLs. 970 * Stat data v1 doesn't support ACLs.
966 */ 971 */
967 if (get_inode_sd_version(inode) != STAT_DATA_V1) 972 if (get_inode_sd_version(inode) != STAT_DATA_V1)
968 return generic_permission(inode, mask, reiserfs_check_acl); 973 return generic_permission(inode, mask, flags,
974 reiserfs_check_acl);
969#endif 975#endif
970 return generic_permission(inode, mask, NULL); 976 return generic_permission(inode, mask, flags, NULL);
971} 977}
972 978
973static int xattr_hide_revalidate(struct dentry *dentry, struct nameidata *nd) 979static int xattr_hide_revalidate(struct dentry *dentry, struct nameidata *nd)
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index cffb1fd8ba33..30ac27345586 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -348,13 +348,18 @@ int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const void *ns, const cha
348 return -ENOENT; 348 return -ENOENT;
349} 349}
350 350
351int sysfs_permission(struct inode *inode, int mask) 351int sysfs_permission(struct inode *inode, int mask, unsigned int flags)
352{ 352{
353 struct sysfs_dirent *sd = inode->i_private; 353 struct sysfs_dirent *sd;
354
355 if (flags & IPERM_FLAG_RCU)
356 return -ECHILD;
357
358 sd = inode->i_private;
354 359
355 mutex_lock(&sysfs_mutex); 360 mutex_lock(&sysfs_mutex);
356 sysfs_refresh_inode(sd, inode); 361 sysfs_refresh_inode(sd, inode);
357 mutex_unlock(&sysfs_mutex); 362 mutex_unlock(&sysfs_mutex);
358 363
359 return generic_permission(inode, mask, NULL); 364 return generic_permission(inode, mask, flags, NULL);
360} 365}
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index d9be60a2e956..ffaaa816bfba 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -200,7 +200,7 @@ static inline void __sysfs_put(struct sysfs_dirent *sd)
200struct inode *sysfs_get_inode(struct super_block *sb, struct sysfs_dirent *sd); 200struct inode *sysfs_get_inode(struct super_block *sb, struct sysfs_dirent *sd);
201void sysfs_evict_inode(struct inode *inode); 201void sysfs_evict_inode(struct inode *inode);
202int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr *iattr); 202int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr *iattr);
203int sysfs_permission(struct inode *inode, int mask); 203int sysfs_permission(struct inode *inode, int mask, unsigned int flags);
204int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); 204int sysfs_setattr(struct dentry *dentry, struct iattr *iattr);
205int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); 205int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat);
206int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, 206int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value,
diff --git a/fs/xfs/linux-2.6/xfs_acl.c b/fs/xfs/linux-2.6/xfs_acl.c
index b2771862fd3d..4b11eaf6a580 100644
--- a/fs/xfs/linux-2.6/xfs_acl.c
+++ b/fs/xfs/linux-2.6/xfs_acl.c
@@ -219,12 +219,16 @@ xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
219} 219}
220 220
221int 221int
222xfs_check_acl(struct inode *inode, int mask) 222xfs_check_acl(struct inode *inode, int mask, unsigned int flags)
223{ 223{
224 struct xfs_inode *ip = XFS_I(inode); 224 struct xfs_inode *ip;
225 struct posix_acl *acl; 225 struct posix_acl *acl;
226 int error = -EAGAIN; 226 int error = -EAGAIN;
227 227
228 if (flags & IPERM_FLAG_RCU)
229 return -ECHILD;
230
231 ip = XFS_I(inode);
228 trace_xfs_check_acl(ip); 232 trace_xfs_check_acl(ip);
229 233
230 /* 234 /*
diff --git a/fs/xfs/xfs_acl.h b/fs/xfs/xfs_acl.h
index 0135e2a669d7..11dd72070cbb 100644
--- a/fs/xfs/xfs_acl.h
+++ b/fs/xfs/xfs_acl.h
@@ -42,7 +42,7 @@ struct xfs_acl {
42#define SGI_ACL_DEFAULT_SIZE (sizeof(SGI_ACL_DEFAULT)-1) 42#define SGI_ACL_DEFAULT_SIZE (sizeof(SGI_ACL_DEFAULT)-1)
43 43
44#ifdef CONFIG_XFS_POSIX_ACL 44#ifdef CONFIG_XFS_POSIX_ACL
45extern int xfs_check_acl(struct inode *inode, int mask); 45extern int xfs_check_acl(struct inode *inode, int mask, unsigned int flags);
46extern struct posix_acl *xfs_get_acl(struct inode *inode, int type); 46extern struct posix_acl *xfs_get_acl(struct inode *inode, int type);
47extern int xfs_inherit_acl(struct inode *inode, struct posix_acl *default_acl); 47extern int xfs_inherit_acl(struct inode *inode, struct posix_acl *default_acl);
48extern int xfs_acl_chmod(struct inode *inode); 48extern int xfs_acl_chmod(struct inode *inode);
diff --git a/include/linux/coda_linux.h b/include/linux/coda_linux.h
index 2e914d0771b9..4ccc59c1ea82 100644
--- a/include/linux/coda_linux.h
+++ b/include/linux/coda_linux.h
@@ -37,7 +37,7 @@ extern const struct file_operations coda_ioctl_operations;
37/* operations shared over more than one file */ 37/* operations shared over more than one file */
38int coda_open(struct inode *i, struct file *f); 38int coda_open(struct inode *i, struct file *f);
39int coda_release(struct inode *i, struct file *f); 39int coda_release(struct inode *i, struct file *f);
40int coda_permission(struct inode *inode, int mask); 40int coda_permission(struct inode *inode, int mask, unsigned int flags);
41int coda_revalidate_inode(struct dentry *); 41int coda_revalidate_inode(struct dentry *);
42int coda_getattr(struct vfsmount *, struct dentry *, struct kstat *); 42int coda_getattr(struct vfsmount *, struct dentry *, struct kstat *);
43int coda_setattr(struct dentry *, struct iattr *); 43int coda_setattr(struct dentry *, struct iattr *);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index a04aa96acb71..d5a4d42f655b 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1550,11 +1550,13 @@ struct file_operations {
1550 int (*setlease)(struct file *, long, struct file_lock **); 1550 int (*setlease)(struct file *, long, struct file_lock **);
1551}; 1551};
1552 1552
1553#define IPERM_FLAG_RCU 0x0001
1554
1553struct inode_operations { 1555struct inode_operations {
1554 struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *); 1556 struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *);
1555 void * (*follow_link) (struct dentry *, struct nameidata *); 1557 void * (*follow_link) (struct dentry *, struct nameidata *);
1556 int (*permission) (struct inode *, int); 1558 int (*permission) (struct inode *, int, unsigned int);
1557 int (*check_acl)(struct inode *, int); 1559 int (*check_acl)(struct inode *, int, unsigned int);
1558 1560
1559 int (*readlink) (struct dentry *, char __user *,int); 1561 int (*readlink) (struct dentry *, char __user *,int);
1560 void (*put_link) (struct dentry *, struct nameidata *, void *); 1562 void (*put_link) (struct dentry *, struct nameidata *, void *);
@@ -2165,8 +2167,8 @@ extern sector_t bmap(struct inode *, sector_t);
2165#endif 2167#endif
2166extern int notify_change(struct dentry *, struct iattr *); 2168extern int notify_change(struct dentry *, struct iattr *);
2167extern int inode_permission(struct inode *, int); 2169extern int inode_permission(struct inode *, int);
2168extern int generic_permission(struct inode *, int, 2170extern int generic_permission(struct inode *, int, unsigned int,
2169 int (*check_acl)(struct inode *, int)); 2171 int (*check_acl)(struct inode *, int, unsigned int));
2170 2172
2171static inline bool execute_ok(struct inode *inode) 2173static inline bool execute_ok(struct inode *inode)
2172{ 2174{
diff --git a/include/linux/generic_acl.h b/include/linux/generic_acl.h
index 574bea4013b6..0437e377b555 100644
--- a/include/linux/generic_acl.h
+++ b/include/linux/generic_acl.h
@@ -10,6 +10,6 @@ extern const struct xattr_handler generic_acl_default_handler;
10 10
11int generic_acl_init(struct inode *, struct inode *); 11int generic_acl_init(struct inode *, struct inode *);
12int generic_acl_chmod(struct inode *); 12int generic_acl_chmod(struct inode *);
13int generic_check_acl(struct inode *inode, int mask); 13int generic_check_acl(struct inode *inode, int mask, unsigned int flags);
14 14
15#endif /* LINUX_GENERIC_ACL_H */ 15#endif /* LINUX_GENERIC_ACL_H */
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 29d504d5d1c3..0779bb8f95be 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -351,7 +351,7 @@ extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
351extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr); 351extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr);
352extern int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr); 352extern int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr);
353extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *); 353extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
354extern int nfs_permission(struct inode *, int); 354extern int nfs_permission(struct inode *, int, unsigned int);
355extern int nfs_open(struct inode *, struct file *); 355extern int nfs_open(struct inode *, struct file *);
356extern int nfs_release(struct inode *, struct file *); 356extern int nfs_release(struct inode *, struct file *);
357extern int nfs_attribute_timeout(struct inode *inode); 357extern int nfs_attribute_timeout(struct inode *inode);
diff --git a/include/linux/reiserfs_xattr.h b/include/linux/reiserfs_xattr.h
index b2cf2089769b..3b94c91f20a6 100644
--- a/include/linux/reiserfs_xattr.h
+++ b/include/linux/reiserfs_xattr.h
@@ -41,7 +41,7 @@ int reiserfs_xattr_init(struct super_block *sb, int mount_flags);
41int reiserfs_lookup_privroot(struct super_block *sb); 41int reiserfs_lookup_privroot(struct super_block *sb);
42int reiserfs_delete_xattrs(struct inode *inode); 42int reiserfs_delete_xattrs(struct inode *inode);
43int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs); 43int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs);
44int reiserfs_permission(struct inode *inode, int mask); 44int reiserfs_permission(struct inode *inode, int mask, unsigned int flags);
45 45
46#ifdef CONFIG_REISERFS_FS_XATTR 46#ifdef CONFIG_REISERFS_FS_XATTR
47#define has_xattr_dir(inode) (REISERFS_I(inode)->i_flags & i_has_xattr_dir) 47#define has_xattr_dir(inode) (REISERFS_I(inode)->i_flags & i_has_xattr_dir)