···4747 void * (*follow_link) (struct dentry *, struct nameidata *);4848 void (*put_link) (struct dentry *, struct nameidata *, void *);4949 void (*truncate) (struct inode *);5050- int (*permission) (struct inode *, int, struct nameidata *);5151- int (*check_acl)(struct inode *, int);5050+ int (*permission) (struct inode *, int, unsigned int);5151+ int (*check_acl)(struct inode *, int, unsigned int);5252 int (*setattr) (struct dentry *, struct iattr *);5353 int (*getattr) (struct vfsmount *, struct dentry *, struct kstat *);5454 int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);···7676put_link: no7777truncate: yes (see below)7878setattr: yes7979-permission: no7979+permission: no (may not block if called in rcu-walk mode)8080check_acl: no8181getattr: no8282setxattr: yes
+41-3
Documentation/filesystems/path-lookup.txt
···316316317317The cases where rcu-walk cannot continue are:318318* NULL dentry (ie. any uncached path element)319319-* parent with d_inode->i_op->permission or ACLs320319* Following links321320322322-In future patches, permission checks become rcu-walk aware. It may be possible323323-eventually to make following links rcu-walk aware.321321+It may be possible eventually to make following links rcu-walk aware.324322325323Uncached path elements will always require dropping to ref-walk mode, at the326324very least because i_mutex needs to be grabbed, and objects allocated.···334336scalability of path resolution.335337336338339339+Interesting statistics340340+======================341341+342342+The following table gives rcu lookup statistics for a few simple workloads343343+(2s12c24t Westmere, debian non-graphical system). Ungraceful are attempts to344344+drop rcu that fail due to d_seq failure and requiring the entire path lookup345345+again. Other cases are successful rcu-drops that are required before the final346346+element, nodentry for missing dentry, revalidate for filesystem revalidate347347+routine requiring rcu drop, permission for permission check requiring drop,348348+and link for symlink traversal requiring drop.349349+350350+ rcu-lookups restart nodentry link revalidate permission351351+bootup 47121 0 4624 1010 10283 7852352352+dbench 25386793 0 6778659(26.7%) 55 549 1156353353+kbuild 2696672 10 64442(2.3%) 108764(4.0%) 1 1590354354+git diff 39605 0 28 2 0 106355355+vfstest 24185492 4945 708725(2.9%) 1076136(4.4%) 0 2651356356+357357+What this shows is that failed rcu-walk lookups, ie. ones that are restarted358358+entirely with ref-walk, are quite rare. Even the "vfstest" case which359359+specifically has concurrent renames/mkdir/rmdir/ creat/unlink/etc to excercise360360+such races is not showing a huge amount of restarts.361361+362362+Dropping from rcu-walk to ref-walk mean that we have encountered a dentry where363363+the reference count needs to be taken for some reason. This is either because364364+we have reached the target of the path walk, or because we have encountered a365365+condition that can't be resolved in rcu-walk mode. Ideally, we drop rcu-walk366366+only when we have reached the target dentry, so the other statistics show where367367+this does not happen.368368+369369+Note that a graceful drop from rcu-walk mode due to something such as the370370+dentry not existing (which can be common) is not necessarily a failure of371371+rcu-walk scheme, because some elements of the path may have been walked in372372+rcu-walk mode. The further we get from common path elements (such as cwd or373373+root), the less contended the dentry is likely to be. The closer we are to374374+common path elements, the more likely they will exist in dentry cache.375375+376376+337377Papers and other documentation on dcache locking338378================================================3393793403801. Scaling dcache with RCU (http://linuxjournal.com/article.php?sid=7124).3413813423822. http://lse.sourceforge.net/locking/dcache/dcache.html383383+384384+
+5
Documentation/filesystems/porting
···380380may now be called in rcu-walk mode (nd->flags & LOOKUP_RCU). -ECHILD should be381381returned if the filesystem cannot handle rcu-walk. See382382Documentation/filesystems/vfs.txt for more details.383383+384384+ permission and check_acl are inode permission checks that are called385385+on many or all directory inodes on the way down a path walk (to check for386386+exec permission). These must now be rcu-walk aware (flags & IPERM_RCU). See387387+Documentation/filesystems/vfs.txt for more details.
+9-1
Documentation/filesystems/vfs.txt
···325325 void * (*follow_link) (struct dentry *, struct nameidata *);326326 void (*put_link) (struct dentry *, struct nameidata *, void *);327327 void (*truncate) (struct inode *);328328- int (*permission) (struct inode *, int, struct nameidata *);328328+ int (*permission) (struct inode *, int, unsigned int);329329+ int (*check_acl)(struct inode *, int, unsigned int);329330 int (*setattr) (struct dentry *, struct iattr *);330331 int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);331332 int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);···414413415414 permission: called by the VFS to check for access rights on a POSIX-like416415 filesystem.416416+417417+ May be called in rcu-walk mode (flags & IPERM_RCU). If in rcu-walk418418+ mode, the filesystem must check the permission without blocking or419419+ storing to the inode.420420+421421+ If a situation is encountered that rcu-walk cannot handle, return422422+ -ECHILD and it will be called again in ref-walk mode.417423418424 setattr: called by the VFS to set attributes for a file. This method419425 is called by chmod(2) and related system calls.
+4-1
drivers/staging/smbfs/file.c
···407407 * privileges, so we need our own check for this.408408 */409409static int410410-smb_file_permission(struct inode *inode, int mask)410410+smb_file_permission(struct inode *inode, int mask, unsigned int flags)411411{412412 int mode = inode->i_mode;413413 int error = 0;414414+415415+ if (flags & IPERM_FLAG_RCU)416416+ return -ECHILD;414417415418 VERBOSE("mode=%x, mask=%x\n", mode, mask);416419
+4-1
fs/9p/acl.c
···9191 return acl;9292}93939494-int v9fs_check_acl(struct inode *inode, int mask)9494+int v9fs_check_acl(struct inode *inode, int mask, unsigned int flags)9595{9696 struct posix_acl *acl;9797 struct v9fs_session_info *v9ses;9898+9999+ if (flags & IPERM_FLAG_RCU)100100+ return -ECHILD;9810199102 v9ses = v9fs_inode2v9ses(inode);100103 if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) {
+1-1
fs/9p/acl.h
···16161717#ifdef CONFIG_9P_FS_POSIX_ACL1818extern int v9fs_get_acl(struct inode *, struct p9_fid *);1919-extern int v9fs_check_acl(struct inode *inode, int mask);1919+extern int v9fs_check_acl(struct inode *inode, int mask, unsigned int flags);2020extern int v9fs_acl_chmod(struct dentry *);2121extern int v9fs_set_create_acl(struct dentry *,2222 struct posix_acl *, struct posix_acl *);
···285285 * - AFS ACLs are attached to directories only, and a file is controlled by its286286 * parent directory's ACL287287 */288288-int afs_permission(struct inode *inode, int mask)288288+int afs_permission(struct inode *inode, int mask, unsigned int flags)289289{290290 struct afs_vnode *vnode = AFS_FS_I(inode);291291 afs_access_t uninitialized_var(access);292292 struct key *key;293293 int ret;294294+295295+ if (flags & IPERM_FLAG_RCU)296296+ return -ECHILD;294297295298 _enter("{{%x:%u},%lx},%x,",296299 vnode->fid.vid, vnode->fid.vnode, vnode->flags, mask);···350347 }351348352349 key_put(key);353353- ret = generic_permission(inode, mask, NULL);350350+ ret = generic_permission(inode, mask, flags, NULL);354351 _leave(" = %d", ret);355352 return ret;356353
+4-1
fs/bad_inode.c
···229229 return -EIO;230230}231231232232-static int bad_inode_permission(struct inode *inode, int mask)232232+static int bad_inode_permission(struct inode *inode, int mask, unsigned int flags)233233{234234+ if (flags & IPERM_FLAG_RCU)235235+ return -ECHILD;236236+234237 return -EIO;235238}236239
+4-2
fs/btrfs/acl.c
···185185 return ret;186186}187187188188-int btrfs_check_acl(struct inode *inode, int mask)188188+int btrfs_check_acl(struct inode *inode, int mask, unsigned int flags)189189{190190 struct posix_acl *acl;191191 int error = -EAGAIN;192192193193- acl = btrfs_get_acl(inode, ACL_TYPE_ACCESS);193193+ if (flags & IPERM_FLAG_RCU)194194+ return -ECHILD;194195196196+ acl = btrfs_get_acl(inode, ACL_TYPE_ACCESS);195197 if (IS_ERR(acl))196198 return PTR_ERR(acl);197199 if (acl) {
+1-1
fs/btrfs/ctree.h
···2544254425452545/* acl.c */25462546#ifdef CONFIG_BTRFS_FS_POSIX_ACL25472547-int btrfs_check_acl(struct inode *inode, int mask);25472547+int btrfs_check_acl(struct inode *inode, int mask, unsigned int flags);25482548#else25492549#define btrfs_check_acl NULL25502550#endif
+5-2
fs/btrfs/inode.c
···72117211 return __set_page_dirty_nobuffers(page);72127212}7213721372147214-static int btrfs_permission(struct inode *inode, int mask)72147214+static int btrfs_permission(struct inode *inode, int mask, unsigned int flags)72157215{72167216+ if (flags & IPERM_FLAG_RCU)72177217+ return -ECHILD;72187218+72167219 if ((BTRFS_I(inode)->flags & BTRFS_INODE_READONLY) && (mask & MAY_WRITE))72177220 return -EACCES;72187218- return generic_permission(inode, mask, btrfs_check_acl);72217221+ return generic_permission(inode, mask, flags, btrfs_check_acl);72197222}7220722372217224static const struct inode_operations btrfs_dir_inode_operations = {
+8-3
fs/ceph/inode.c
···17811781 * Check inode permissions. We verify we have a valid value for17821782 * the AUTH cap, then call the generic handler.17831783 */17841784-int ceph_permission(struct inode *inode, int mask)17841784+int ceph_permission(struct inode *inode, int mask, unsigned int flags)17851785{17861786- int err = ceph_do_getattr(inode, CEPH_CAP_AUTH_SHARED);17861786+ int err;17871787+17881788+ if (flags & IPERM_FLAG_RCU)17891789+ return -ECHILD;17901790+17911791+ err = ceph_do_getattr(inode, CEPH_CAP_AUTH_SHARED);1787179217881793 if (!err)17891789- err = generic_permission(inode, mask, NULL);17941794+ err = generic_permission(inode, mask, flags, NULL);17901795 return err;17911796}17921797
+1-1
fs/ceph/super.h
···665665extern void ceph_queue_writeback(struct inode *inode);666666667667extern int ceph_do_getattr(struct inode *inode, int mask);668668-extern int ceph_permission(struct inode *inode, int mask);668668+extern int ceph_permission(struct inode *inode, int mask, unsigned int flags);669669extern int ceph_setattr(struct dentry *dentry, struct iattr *attr);670670extern int ceph_getattr(struct vfsmount *mnt, struct dentry *dentry,671671 struct kstat *stat);
+5-2
fs/cifs/cifsfs.c
···283283 return 0;284284}285285286286-static int cifs_permission(struct inode *inode, int mask)286286+static int cifs_permission(struct inode *inode, int mask, unsigned int flags)287287{288288 struct cifs_sb_info *cifs_sb;289289+290290+ if (flags & IPERM_FLAG_RCU)291291+ return -ECHILD;289292290293 cifs_sb = CIFS_SB(inode->i_sb);291294···301298 on the client (above and beyond ACL on servers) for302299 servers which do not support setting and viewing mode bits,303300 so allowing client to check permissions is useful */304304- return generic_permission(inode, mask, NULL);301301+ return generic_permission(inode, mask, flags, NULL);305302}306303307304static struct kmem_cache *cifs_inode_cachep;
+4-1
fs/coda/dir.c
···135135}136136137137138138-int coda_permission(struct inode *inode, int mask)138138+int coda_permission(struct inode *inode, int mask, unsigned int flags)139139{140140 int error;141141+142142+ if (flags & IPERM_FLAG_RCU)143143+ return -ECHILD;141144142145 mask &= MAY_READ | MAY_WRITE | MAY_EXEC;143146
+4-2
fs/coda/pioctl.c
···2424#include <linux/coda_psdev.h>25252626/* pioctl ops */2727-static int coda_ioctl_permission(struct inode *inode, int mask);2727+static int coda_ioctl_permission(struct inode *inode, int mask, unsigned int flags);2828static long coda_pioctl(struct file *filp, unsigned int cmd,2929 unsigned long user_data);3030···4141};42424343/* the coda pioctl inode ops */4444-static int coda_ioctl_permission(struct inode *inode, int mask)4444+static int coda_ioctl_permission(struct inode *inode, int mask, unsigned int flags)4545{4646+ if (flags & IPERM_FLAG_RCU)4747+ return -ECHILD;4648 return (mask & MAY_EXEC) ? -EACCES : 0;4749}4850
+3-1
fs/ecryptfs/inode.c
···980980}981981982982static int983983-ecryptfs_permission(struct inode *inode, int mask)983983+ecryptfs_permission(struct inode *inode, int mask, unsigned int flags)984984{985985+ if (flags & IPERM_FLAG_RCU)986986+ return -ECHILD;985987 return inode_permission(ecryptfs_inode_to_lower(inode), mask);986988}987989
+6-2
fs/ext2/acl.c
···232232}233233234234int235235-ext2_check_acl(struct inode *inode, int mask)235235+ext2_check_acl(struct inode *inode, int mask, unsigned int flags)236236{237237- struct posix_acl *acl = ext2_get_acl(inode, ACL_TYPE_ACCESS);237237+ struct posix_acl *acl;238238239239+ if (flags & IPERM_FLAG_RCU)240240+ return -ECHILD;241241+242242+ acl = ext2_get_acl(inode, ACL_TYPE_ACCESS);239243 if (IS_ERR(acl))240244 return PTR_ERR(acl);241245 if (acl) {
+1-1
fs/ext2/acl.h
···5454#ifdef CONFIG_EXT2_FS_POSIX_ACL55555656/* acl.c */5757-extern int ext2_check_acl (struct inode *, int);5757+extern int ext2_check_acl (struct inode *, int, unsigned int);5858extern int ext2_acl_chmod (struct inode *);5959extern int ext2_init_acl (struct inode *, struct inode *);6060
+6-2
fs/ext3/acl.c
···240240}241241242242int243243-ext3_check_acl(struct inode *inode, int mask)243243+ext3_check_acl(struct inode *inode, int mask, unsigned int flags)244244{245245- struct posix_acl *acl = ext3_get_acl(inode, ACL_TYPE_ACCESS);245245+ struct posix_acl *acl;246246247247+ if (flags & IPERM_FLAG_RCU)248248+ return -ECHILD;249249+250250+ acl = ext3_get_acl(inode, ACL_TYPE_ACCESS);247251 if (IS_ERR(acl))248252 return PTR_ERR(acl);249253 if (acl) {
+1-1
fs/ext3/acl.h
···5454#ifdef CONFIG_EXT3_FS_POSIX_ACL55555656/* acl.c */5757-extern int ext3_check_acl (struct inode *, int);5757+extern int ext3_check_acl (struct inode *, int, unsigned int);5858extern int ext3_acl_chmod (struct inode *);5959extern int ext3_init_acl (handle_t *, struct inode *, struct inode *);6060
+6-2
fs/ext4/acl.c
···238238}239239240240int241241-ext4_check_acl(struct inode *inode, int mask)241241+ext4_check_acl(struct inode *inode, int mask, unsigned int flags)242242{243243- struct posix_acl *acl = ext4_get_acl(inode, ACL_TYPE_ACCESS);243243+ struct posix_acl *acl;244244245245+ if (flags & IPERM_FLAG_RCU)246246+ return -ECHILD;247247+248248+ acl = ext4_get_acl(inode, ACL_TYPE_ACCESS);245249 if (IS_ERR(acl))246250 return PTR_ERR(acl);247251 if (acl) {
+1-1
fs/ext4/acl.h
···5454#ifdef CONFIG_EXT4_FS_POSIX_ACL55555656/* acl.c */5757-extern int ext4_check_acl(struct inode *, int);5757+extern int ext4_check_acl(struct inode *, int, unsigned int);5858extern int ext4_acl_chmod(struct inode *);5959extern int ext4_init_acl(handle_t *, struct inode *, struct inode *);6060
+7-3
fs/fuse/dir.c
···985985 * access request is sent. Execute permission is still checked986986 * locally based on file mode.987987 */988988-static int fuse_permission(struct inode *inode, int mask)988988+static int fuse_permission(struct inode *inode, int mask, unsigned int flags)989989{990990 struct fuse_conn *fc = get_fuse_conn(inode);991991 bool refreshed = false;992992 int err = 0;993993+994994+ if (flags & IPERM_FLAG_RCU)995995+ return -ECHILD;993996994997 if (!fuse_allow_task(fc, current))995998 return -EACCES;···10081005 }1009100610101007 if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {10111011- err = generic_permission(inode, mask, NULL);10081008+ err = generic_permission(inode, mask, flags, NULL);1012100910131010 /* If permission is denied, try to refresh file10141011 attributes. This is also needed, because the root···10161013 if (err == -EACCES && !refreshed) {10171014 err = fuse_do_getattr(inode, NULL, NULL);10181015 if (!err)10191019- err = generic_permission(inode, mask, NULL);10161016+ err = generic_permission(inode, mask,10171017+ flags, NULL);10201018 }1021101910221020 /* Note: the opposite of the above test does not
+6-2
fs/generic_acl.c
···190190}191191192192int193193-generic_check_acl(struct inode *inode, int mask)193193+generic_check_acl(struct inode *inode, int mask, unsigned int flags)194194{195195- struct posix_acl *acl = get_cached_acl(inode, ACL_TYPE_ACCESS);195195+ struct posix_acl *acl;196196197197+ if (flags & IPERM_FLAG_RCU)198198+ return -ECHILD;199199+200200+ acl = get_cached_acl(inode, ACL_TYPE_ACCESS);197201 if (acl) {198202 int error = posix_acl_permission(inode, acl, mask);199203 posix_acl_release(acl);
+4-1
fs/gfs2/acl.c
···7575 * Returns: errno7676 */77777878-int gfs2_check_acl(struct inode *inode, int mask)7878+int gfs2_check_acl(struct inode *inode, int mask, unsigned int flags)7979{8080 struct posix_acl *acl;8181 int error;8282+8383+ if (flags & IPERM_FLAG_RCU)8484+ return -ECHILD;82858386 acl = gfs2_acl_get(GFS2_I(inode), ACL_TYPE_ACCESS);8487 if (IS_ERR(acl))
+1-1
fs/gfs2/acl.h
···1616#define GFS2_POSIX_ACL_DEFAULT "posix_acl_default"1717#define GFS2_ACL_MAX_ENTRIES 2518181919-extern int gfs2_check_acl(struct inode *inode, int mask);1919+extern int gfs2_check_acl(struct inode *inode, int mask, unsigned int);2020extern int gfs2_acl_create(struct gfs2_inode *dip, struct inode *inode);2121extern int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr);2222extern const struct xattr_handler gfs2_xattr_system_handler;
···555555 return __logfs_create(dir, dentry, inode, target, destlen);556556}557557558558-static int logfs_permission(struct inode *inode, int mask)558558+static int logfs_permission(struct inode *inode, int mask, unsigned int flags)559559{560560- return generic_permission(inode, mask, NULL);560560+ if (flags & IPERM_FLAG_RCU)561561+ return -ECHILD;562562+ return generic_permission(inode, mask, flags, NULL);561563}562564563565static int logfs_link(struct dentry *old_dentry, struct inode *dir,
+29-46
fs/namei.c
···169169/*170170 * This does basic POSIX ACL permission checking171171 */172172-static inline int __acl_permission_check(struct inode *inode, int mask,173173- int (*check_acl)(struct inode *inode, int mask), int rcu)172172+static int acl_permission_check(struct inode *inode, int mask, unsigned int flags,173173+ int (*check_acl)(struct inode *inode, int mask, unsigned int flags))174174{175175 umode_t mode = inode->i_mode;176176···180180 mode >>= 6;181181 else {182182 if (IS_POSIXACL(inode) && (mode & S_IRWXG) && check_acl) {183183- if (rcu) {184184- return -ECHILD;185185- } else {186186- int error = check_acl(inode, mask);187187- if (error != -EAGAIN)188188- return error;189189- }183183+ int error = check_acl(inode, mask, flags);184184+ if (error != -EAGAIN)185185+ return error;190186 }191187192188 if (in_group_p(inode->i_gid))···197201 return -EACCES;198202}199203200200-static inline int acl_permission_check(struct inode *inode, int mask,201201- int (*check_acl)(struct inode *inode, int mask))202202-{203203- return __acl_permission_check(inode, mask, check_acl, 0);204204-}205205-206204/**207207- * generic_permission - check for access rights on a Posix-like filesystem205205+ * generic_permission - check for access rights on a Posix-like filesystem208206 * @inode: inode to check access rights for209207 * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)210208 * @check_acl: optional callback to check for Posix ACLs209209+ * @flags IPERM_FLAG_ flags.211210 *212211 * Used to check for read/write/execute permissions on a file.213212 * We use "fsuid" for this, letting us set arbitrary permissions214213 * for filesystem access without changing the "normal" uids which215215- * are used for other things..214214+ * are used for other things.215215+ *216216+ * generic_permission is rcu-walk aware. It returns -ECHILD in case an rcu-walk217217+ * request cannot be satisfied (eg. requires blocking or too much complexity).218218+ * It would then be called again in ref-walk mode.216219 */217217-int generic_permission(struct inode *inode, int mask,218218- int (*check_acl)(struct inode *inode, int mask))220220+int generic_permission(struct inode *inode, int mask, unsigned int flags,221221+ int (*check_acl)(struct inode *inode, int mask, unsigned int flags))219222{220223 int ret;221224222225 /*223226 * Do the basic POSIX ACL permission checks.224227 */225225- ret = acl_permission_check(inode, mask, check_acl);228228+ ret = acl_permission_check(inode, mask, flags, check_acl);226229 if (ret != -EACCES)227230 return ret;228231···276281 }277282278283 if (inode->i_op->permission)279279- retval = inode->i_op->permission(inode, mask);284284+ retval = inode->i_op->permission(inode, mask, 0);280285 else281281- retval = generic_permission(inode, mask, inode->i_op->check_acl);286286+ retval = generic_permission(inode, mask, 0,287287+ inode->i_op->check_acl);282288283289 if (retval)284290 return retval;···664668 * short-cut DAC fails, then call ->permission() to do more665669 * complete permission check.666670 */667667-static inline int __exec_permission(struct inode *inode, int rcu)671671+static inline int exec_permission(struct inode *inode, unsigned int flags)668672{669673 int ret;670674671675 if (inode->i_op->permission) {672672- if (rcu)673673- return -ECHILD;674674- ret = inode->i_op->permission(inode, MAY_EXEC);675675- if (!ret)676676- goto ok;677677- return ret;676676+ ret = inode->i_op->permission(inode, MAY_EXEC, flags);677677+ } else {678678+ ret = acl_permission_check(inode, MAY_EXEC, flags,679679+ inode->i_op->check_acl);678680 }679679- ret = __acl_permission_check(inode, MAY_EXEC, inode->i_op->check_acl, rcu);680680- if (!ret)681681+ if (likely(!ret))681682 goto ok;682682- if (rcu && ret == -ECHILD)683683+ if (ret == -ECHILD)683684 return ret;684685685686 if (capable(CAP_DAC_OVERRIDE) || capable(CAP_DAC_READ_SEARCH))···684691685692 return ret;686693ok:687687- return security_inode_exec_permission(inode, rcu);688688-}689689-690690-static int exec_permission(struct inode *inode)691691-{692692- return __exec_permission(inode, 0);693693-}694694-695695-static int exec_permission_rcu(struct inode *inode)696696-{697697- return __exec_permission(inode, 1);694694+ return security_inode_exec_permission(inode, flags);698695}699696700697static __always_inline void set_root(struct nameidata *nd)···1148116511491166 nd->flags |= LOOKUP_CONTINUE;11501167 if (nd->flags & LOOKUP_RCU) {11511151- err = exec_permission_rcu(nd->inode);11681168+ err = exec_permission(nd->inode, IPERM_FLAG_RCU);11521169 if (err == -ECHILD) {11531170 if (nameidata_drop_rcu(nd))11541171 return -ECHILD;···11561173 }11571174 } else {11581175exec_again:11591159- err = exec_permission(nd->inode);11761176+ err = exec_permission(nd->inode, 0);11601177 }11611178 if (err)11621179 break;···16031620 struct dentry *dentry;16041621 int err;1605162216061606- err = exec_permission(inode);16231623+ err = exec_permission(inode, 0);16071624 if (err)16081625 return ERR_PTR(err);16091626
+5-2
fs/nfs/dir.c
···21892189 return nfs_do_access(inode, cred, nfs_open_permission_mask(openflags));21902190}2191219121922192-int nfs_permission(struct inode *inode, int mask)21922192+int nfs_permission(struct inode *inode, int mask, unsigned int flags)21932193{21942194 struct rpc_cred *cred;21952195 int res = 0;21962196+21972197+ if (flags & IPERM_FLAG_RCU)21982198+ return -ECHILD;2196219921972200 nfs_inc_stats(inode, NFSIOS_VFSACCESS);21982201···22442241out_notsup:22452242 res = nfs_revalidate_inode(NFS_SERVER(inode), inode);22462243 if (res == 0)22472247- res = generic_permission(inode, mask, NULL);22442244+ res = generic_permission(inode, mask, flags, NULL);22482245 goto out;22492246}22502247
+7-3
fs/nilfs2/inode.c
···785785 return err;786786}787787788788-int nilfs_permission(struct inode *inode, int mask)788788+int nilfs_permission(struct inode *inode, int mask, unsigned int flags)789789{790790- struct nilfs_root *root = NILFS_I(inode)->i_root;790790+ struct nilfs_root *root;791791792792+ if (flags & IPERM_FLAG_RCU)793793+ return -ECHILD;794794+795795+ root = NILFS_I(inode)->i_root;792796 if ((mask & MAY_WRITE) && root &&793797 root->cno != NILFS_CPTREE_CURRENT_CNO)794798 return -EROFS; /* snapshot is not writable */795799796796- return generic_permission(inode, mask, NULL);800800+ return generic_permission(inode, mask, flags, NULL);797801}798802799803int nilfs_load_inode_block(struct nilfs_sb_info *sbi, struct inode *inode,
+1-1
fs/nilfs2/nilfs.h
···256256extern void nilfs_truncate(struct inode *);257257extern void nilfs_evict_inode(struct inode *);258258extern int nilfs_setattr(struct dentry *, struct iattr *);259259-int nilfs_permission(struct inode *inode, int mask);259259+int nilfs_permission(struct inode *inode, int mask, unsigned int flags);260260extern int nilfs_load_inode_block(struct nilfs_sb_info *, struct inode *,261261 struct buffer_head **);262262extern int nilfs_inode_dirty(struct inode *);
+6-2
fs/ocfs2/acl.c
···291291 return ret;292292}293293294294-int ocfs2_check_acl(struct inode *inode, int mask)294294+int ocfs2_check_acl(struct inode *inode, int mask, unsigned int flags)295295{296296- struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);296296+ struct ocfs2_super *osb;297297 struct buffer_head *di_bh = NULL;298298 struct posix_acl *acl;299299 int ret = -EAGAIN;300300301301+ if (flags & IPERM_FLAG_RCU)302302+ return -ECHILD;303303+304304+ osb = OCFS2_SB(inode->i_sb);301305 if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))302306 return ret;303307
+1-1
fs/ocfs2/acl.h
···2626 __le32 e_id;2727};28282929-extern int ocfs2_check_acl(struct inode *, int);2929+extern int ocfs2_check_acl(struct inode *, int, unsigned int);3030extern int ocfs2_acl_chmod(struct inode *);3131extern int ocfs2_init_acl(handle_t *, struct inode *, struct inode *,3232 struct buffer_head *, struct buffer_head *,
···21142114 * /proc/pid/fd needs a special permission handler so that a process can still21152115 * access /proc/self/fd after it has executed a setuid().21162116 */21172117-static int proc_fd_permission(struct inode *inode, int mask)21172117+static int proc_fd_permission(struct inode *inode, int mask, unsigned int flags)21182118{21192119 int rv;2120212021212121- rv = generic_permission(inode, mask, NULL);21212121+ if (flags & IPERM_FLAG_RCU)21222122+ return -ECHILD;21232123+ rv = generic_permission(inode, mask, flags, NULL);21222124 if (rv == 0)21232125 return 0;21242126 if (task_pid(current) == proc_pid(inode))
+4-1
fs/proc/proc_sysctl.c
···295295 return ret;296296}297297298298-static int proc_sys_permission(struct inode *inode, int mask)298298+static int proc_sys_permission(struct inode *inode, int mask,unsigned int flags)299299{300300 /*301301 * sysctl entries that are not writeable,···304304 struct ctl_table_header *head;305305 struct ctl_table *table;306306 int error;307307+308308+ if (flags & IPERM_FLAG_RCU)309309+ return -ECHILD;307310308311 /* Executable files are not allowed under /proc/sys/ */309312 if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))
+10-4
fs/reiserfs/xattr.c
···870870 return err;871871}872872873873-static int reiserfs_check_acl(struct inode *inode, int mask)873873+static int reiserfs_check_acl(struct inode *inode, int mask, unsigned int flags)874874{875875 struct posix_acl *acl;876876 int error = -EAGAIN; /* do regular unix permission checks by default */877877+878878+ if (flags & IPERM_FLAG_RCU)879879+ return -ECHILD;877880878881 acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS);879882···954951 return 0;955952}956953957957-int reiserfs_permission(struct inode *inode, int mask)954954+int reiserfs_permission(struct inode *inode, int mask, unsigned int flags)958955{956956+ if (flags & IPERM_FLAG_RCU)957957+ return -ECHILD;959958 /*960959 * We don't do permission checks on the internal objects.961960 * Permissions are determined by the "owning" object.···970965 * Stat data v1 doesn't support ACLs.971966 */972967 if (get_inode_sd_version(inode) != STAT_DATA_V1)973973- return generic_permission(inode, mask, reiserfs_check_acl);968968+ return generic_permission(inode, mask, flags,969969+ reiserfs_check_acl);974970#endif975975- return generic_permission(inode, mask, NULL);971971+ return generic_permission(inode, mask, flags, NULL);976972}977973978974static int xattr_hide_revalidate(struct dentry *dentry, struct nameidata *nd)
···219219}220220221221int222222-xfs_check_acl(struct inode *inode, int mask)222222+xfs_check_acl(struct inode *inode, int mask, unsigned int flags)223223{224224- struct xfs_inode *ip = XFS_I(inode);224224+ struct xfs_inode *ip;225225 struct posix_acl *acl;226226 int error = -EAGAIN;227227228228+ if (flags & IPERM_FLAG_RCU)229229+ return -ECHILD;230230+231231+ ip = XFS_I(inode);228232 trace_xfs_check_acl(ip);229233230234 /*
+1-1
fs/xfs/xfs_acl.h
···4242#define SGI_ACL_DEFAULT_SIZE (sizeof(SGI_ACL_DEFAULT)-1)43434444#ifdef CONFIG_XFS_POSIX_ACL4545-extern int xfs_check_acl(struct inode *inode, int mask);4545+extern int xfs_check_acl(struct inode *inode, int mask, unsigned int flags);4646extern struct posix_acl *xfs_get_acl(struct inode *inode, int type);4747extern int xfs_inherit_acl(struct inode *inode, struct posix_acl *default_acl);4848extern int xfs_acl_chmod(struct inode *inode);
+1-1
include/linux/coda_linux.h
···3737/* operations shared over more than one file */3838int coda_open(struct inode *i, struct file *f);3939int coda_release(struct inode *i, struct file *f);4040-int coda_permission(struct inode *inode, int mask);4040+int coda_permission(struct inode *inode, int mask, unsigned int flags);4141int coda_revalidate_inode(struct dentry *);4242int coda_getattr(struct vfsmount *, struct dentry *, struct kstat *);4343int coda_setattr(struct dentry *, struct iattr *);
+6-4
include/linux/fs.h
···15501550 int (*setlease)(struct file *, long, struct file_lock **);15511551};1552155215531553+#define IPERM_FLAG_RCU 0x000115541554+15531555struct inode_operations {15541556 struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *);15551557 void * (*follow_link) (struct dentry *, struct nameidata *);15561556- int (*permission) (struct inode *, int);15571557- int (*check_acl)(struct inode *, int);15581558+ int (*permission) (struct inode *, int, unsigned int);15591559+ int (*check_acl)(struct inode *, int, unsigned int);1558156015591561 int (*readlink) (struct dentry *, char __user *,int);15601562 void (*put_link) (struct dentry *, struct nameidata *, void *);···21672165#endif21682166extern int notify_change(struct dentry *, struct iattr *);21692167extern int inode_permission(struct inode *, int);21702170-extern int generic_permission(struct inode *, int,21712171- int (*check_acl)(struct inode *, int));21682168+extern int generic_permission(struct inode *, int, unsigned int,21692169+ int (*check_acl)(struct inode *, int, unsigned int));2172217021732171static inline bool execute_ok(struct inode *inode)21742172{
+1-1
include/linux/generic_acl.h
···10101111int generic_acl_init(struct inode *, struct inode *);1212int generic_acl_chmod(struct inode *);1313-int generic_check_acl(struct inode *inode, int mask);1313+int generic_check_acl(struct inode *inode, int mask, unsigned int flags);14141515#endif /* LINUX_GENERIC_ACL_H */
+1-1
include/linux/nfs_fs.h
···351351extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr);352352extern int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr);353353extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);354354-extern int nfs_permission(struct inode *, int);354354+extern int nfs_permission(struct inode *, int, unsigned int);355355extern int nfs_open(struct inode *, struct file *);356356extern int nfs_release(struct inode *, struct file *);357357extern int nfs_attribute_timeout(struct inode *inode);