Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 19690ddb authored by Miklos Szeredi's avatar Miklos Szeredi
Browse files

fuse: make fuse_permission() RCU aware



Only bail out of fuse_permission() on IPERM_FLAG_RCU when blocking is
actually necessary.

CC: Nick Piggin <npiggin@gmail.com>
Signed-off-by: default avatarMiklos Szeredi <mszeredi@suse.cz>
parent 357ccf2b
Loading
Loading
Loading
Loading
+22 −8
Original line number Diff line number Diff line
@@ -970,6 +970,14 @@ static int fuse_access(struct inode *inode, int mask)
	return err;
}

static int fuse_perm_getattr(struct inode *inode, int flags)
{
	if (flags & IPERM_FLAG_RCU)
		return -ECHILD;

	return fuse_do_getattr(inode, NULL, NULL);
}

/*
 * Check permission.  The two basic access models of FUSE are:
 *
@@ -989,9 +997,6 @@ static int fuse_permission(struct inode *inode, int mask, unsigned int flags)
	bool refreshed = false;
	int err = 0;

	if (flags & IPERM_FLAG_RCU)
		return -ECHILD;

	if (!fuse_allow_task(fc, current))
		return -EACCES;

@@ -1000,10 +1005,16 @@ static int fuse_permission(struct inode *inode, int mask, unsigned int flags)
	 */
	if ((fc->flags & FUSE_DEFAULT_PERMISSIONS) ||
	    ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))) {
		err = fuse_update_attributes(inode, NULL, NULL, &refreshed);
		struct fuse_inode *fi = get_fuse_inode(inode);

		if (fi->i_time < get_jiffies_64()) {
			refreshed = true;

			err = fuse_perm_getattr(inode, flags);
			if (err)
				return err;
		}
	}

	if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
		err = generic_permission(inode, mask, flags, NULL);
@@ -1012,7 +1023,7 @@ static int fuse_permission(struct inode *inode, int mask, unsigned int flags)
		   attributes.  This is also needed, because the root
		   node will at first have no permissions */
		if (err == -EACCES && !refreshed) {
			err = fuse_do_getattr(inode, NULL, NULL);
			err = fuse_perm_getattr(inode, flags);
			if (!err)
				err = generic_permission(inode, mask,
							flags, NULL);
@@ -1023,13 +1034,16 @@ static int fuse_permission(struct inode *inode, int mask, unsigned int flags)
		   noticed immediately, only after the attribute
		   timeout has expired */
	} else if (mask & (MAY_ACCESS | MAY_CHDIR)) {
		if (flags & IPERM_FLAG_RCU)
			return -ECHILD;

		err = fuse_access(inode, mask);
	} else if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) {
		if (!(inode->i_mode & S_IXUGO)) {
			if (refreshed)
				return -EACCES;

			err = fuse_do_getattr(inode, NULL, NULL);
			err = fuse_perm_getattr(inode, flags);
			if (!err && !(inode->i_mode & S_IXUGO))
				return -EACCES;
		}