diff options
| author | Jiri Kosina <jkosina@suse.cz> | 2011-09-15 15:08:05 +0200 | 
|---|---|---|
| committer | Jiri Kosina <jkosina@suse.cz> | 2011-09-15 15:08:18 +0200 | 
| commit | e060c38434b2caa78efe7cedaff4191040b65a15 (patch) | |
| tree | 407361230bf6733f63d8e788e4b5e6566ee04818 /fs/namei.c | |
| parent | 10e4ac572eeffe5317019bd7330b6058a400dfc2 (diff) | |
| parent | cc39c6a9bbdebfcf1a7dee64d83bf302bc38d941 (diff) | |
| download | olio-linux-3.10-e060c38434b2caa78efe7cedaff4191040b65a15.tar.xz olio-linux-3.10-e060c38434b2caa78efe7cedaff4191040b65a15.zip  | |
Merge branch 'master' into for-next
Fast-forward merge with Linus to be able to merge patches
based on more recent version of the tree.
Diffstat (limited to 'fs/namei.c')
| -rw-r--r-- | fs/namei.c | 118 | 
1 files changed, 88 insertions, 30 deletions
diff --git a/fs/namei.c b/fs/namei.c index f8c69d37379..f4788365ea2 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -179,19 +179,14 @@ static int check_acl(struct inode *inode, int mask)  #ifdef CONFIG_FS_POSIX_ACL  	struct posix_acl *acl; -	/* -	 * Under RCU walk, we cannot even do a "get_cached_acl()", -	 * because that involves locking and getting a refcount on -	 * a cached ACL. -	 * -	 * So the only case we handle during RCU walking is the -	 * case of a cached "no ACL at all", which needs no locks -	 * or refcounts. -	 */  	if (mask & MAY_NOT_BLOCK) { -	        if (negative_cached_acl(inode, ACL_TYPE_ACCESS)) +		acl = get_cached_acl_rcu(inode, ACL_TYPE_ACCESS); +	        if (!acl)  	                return -EAGAIN; -	        return -ECHILD; +		/* no ->get_acl() calls in RCU mode... */ +		if (acl == ACL_NOT_CACHED) +			return -ECHILD; +	        return posix_acl_permission(inode, acl, mask & ~MAY_NOT_BLOCK);  	}  	acl = get_cached_acl(inode, ACL_TYPE_ACCESS); @@ -313,6 +308,26 @@ int generic_permission(struct inode *inode, int mask)  	return -EACCES;  } +/* + * We _really_ want to just do "generic_permission()" without + * even looking at the inode->i_op values. So we keep a cache + * flag in inode->i_opflags, that says "this has not special + * permission function, use the fast case". + */ +static inline int do_inode_permission(struct inode *inode, int mask) +{ +	if (unlikely(!(inode->i_opflags & IOP_FASTPERM))) { +		if (likely(inode->i_op->permission)) +			return inode->i_op->permission(inode, mask); + +		/* This gets set once for the inode lifetime */ +		spin_lock(&inode->i_lock); +		inode->i_opflags |= IOP_FASTPERM; +		spin_unlock(&inode->i_lock); +	} +	return generic_permission(inode, mask); +} +  /**   * inode_permission  -  check for access rights to a given inode   * @inode:	inode to check permission on @@ -327,7 +342,7 @@ int inode_permission(struct inode *inode, int mask)  {  	int retval; -	if (mask & MAY_WRITE) { +	if (unlikely(mask & MAY_WRITE)) {  		umode_t mode = inode->i_mode;  		/* @@ -344,11 +359,7 @@ int inode_permission(struct inode *inode, int mask)  			return -EACCES;  	} -	if (inode->i_op->permission) -		retval = inode->i_op->permission(inode, mask); -	else -		retval = generic_permission(inode, mask); - +	retval = do_inode_permission(inode, mask);  	if (retval)  		return retval; @@ -716,17 +727,20 @@ static int follow_automount(struct path *path, unsigned flags,  	if ((flags & LOOKUP_NO_AUTOMOUNT) && !(flags & LOOKUP_PARENT))  		return -EISDIR; /* we actually want to stop here */ -	/* We want to mount if someone is trying to open/create a file of any -	 * type under the mountpoint, wants to traverse through the mountpoint -	 * or wants to open the mounted directory. +	/* We don't want to mount if someone's just doing a stat - +	 * unless they're stat'ing a directory and appended a '/' to +	 * the name.  	 * -	 * We don't want to mount if someone's just doing a stat and they've -	 * set AT_SYMLINK_NOFOLLOW - unless they're stat'ing a directory and -	 * appended a '/' to the name. +	 * We do, however, want to mount if someone wants to open or +	 * create a file of any type under the mountpoint, wants to +	 * traverse through the mountpoint or wants to open the +	 * mounted directory.  Also, autofs may mark negative dentries +	 * as being automount points.  These will need the attentions +	 * of the daemon to instantiate them before they can be used.  	 */ -	if (!(flags & LOOKUP_FOLLOW) && -	    !(flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY | -		       LOOKUP_OPEN | LOOKUP_CREATE))) +	if (!(flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY | +		     LOOKUP_OPEN | LOOKUP_CREATE)) && +	    path->dentry->d_inode)  		return -EISDIR;  	current->total_link_count++; @@ -1244,6 +1258,26 @@ static void terminate_walk(struct nameidata *nd)  	}  } +/* + * Do we need to follow links? We _really_ want to be able + * to do this check without having to look at inode->i_op, + * so we keep a cache of "no, this doesn't need follow_link" + * for the common case. + */ +static inline int should_follow_link(struct inode *inode, int follow) +{ +	if (unlikely(!(inode->i_opflags & IOP_NOFOLLOW))) { +		if (likely(inode->i_op->follow_link)) +			return follow; + +		/* This gets set once for the inode lifetime */ +		spin_lock(&inode->i_lock); +		inode->i_opflags |= IOP_NOFOLLOW; +		spin_unlock(&inode->i_lock); +	} +	return 0; +} +  static inline int walk_component(struct nameidata *nd, struct path *path,  		struct qstr *name, int type, int follow)  { @@ -1266,7 +1300,7 @@ static inline int walk_component(struct nameidata *nd, struct path *path,  		terminate_walk(nd);  		return -ENOENT;  	} -	if (unlikely(inode->i_op->follow_link) && follow) { +	if (should_follow_link(inode, follow)) {  		if (nd->flags & LOOKUP_RCU) {  			if (unlikely(unlazy_walk(nd, path->dentry))) {  				terminate_walk(nd); @@ -1319,6 +1353,26 @@ static inline int nested_symlink(struct path *path, struct nameidata *nd)  }  /* + * We really don't want to look at inode->i_op->lookup + * when we don't have to. So we keep a cache bit in + * the inode ->i_opflags field that says "yes, we can + * do lookup on this inode". + */ +static inline int can_lookup(struct inode *inode) +{ +	if (likely(inode->i_opflags & IOP_LOOKUP)) +		return 1; +	if (likely(!inode->i_op->lookup)) +		return 0; + +	/* We do this once for the lifetime of the inode */ +	spin_lock(&inode->i_lock); +	inode->i_opflags |= IOP_LOOKUP; +	spin_unlock(&inode->i_lock); +	return 1; +} + +/*   * Name resolution.   * This is the basic name resolution function, turning a pathname into   * the final dentry. We expect 'base' to be positive and a directory. @@ -1397,10 +1451,10 @@ static int link_path_walk(const char *name, struct nameidata *nd)  			if (err)  				return err;  		} +		if (can_lookup(nd->inode)) +			continue;  		err = -ENOTDIR;  -		if (!nd->inode->i_op->lookup) -			break; -		continue; +		break;  		/* here ends the main loop */  last_component: @@ -2562,6 +2616,7 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry)  	if (!dir->i_op->rmdir)  		return -EPERM; +	dget(dentry);  	mutex_lock(&dentry->d_inode->i_mutex);  	error = -EBUSY; @@ -2582,6 +2637,7 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry)  out:  	mutex_unlock(&dentry->d_inode->i_mutex); +	dput(dentry);  	if (!error)  		d_delete(dentry);  	return error; @@ -2971,6 +3027,7 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,  	if (error)  		return error; +	dget(new_dentry);  	if (target)  		mutex_lock(&target->i_mutex); @@ -2991,6 +3048,7 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,  out:  	if (target)  		mutex_unlock(&target->i_mutex); +	dput(new_dentry);  	if (!error)  		if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE))  			d_move(old_dentry,new_dentry);  |