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

Commit e43ae79c authored by Miklos Szeredi's avatar Miklos Szeredi Committed by Al Viro
Browse files

9p: implement i_op->atomic_open()



Add an ->atomic_open implementation which replaces the atomic open+create
operation implemented via ->create.  No functionality is changed.

Signed-off-by: default avatarMiklos Szeredi <mszeredi@suse.cz>
CC: Eric Van Hensbergen <ericvh@gmail.com>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 2d83bde9
Loading
Loading
Loading
Loading
+102 −67
Original line number Diff line number Diff line
@@ -712,11 +712,14 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
}

/**
 * v9fs_vfs_create - VFS hook to create files
 * v9fs_vfs_create - VFS hook to create a regular file
 *
 * open(.., O_CREAT) is handled in v9fs_vfs_atomic_open().  This is only called
 * for mknod(2).
 *
 * @dir: directory inode that is being created
 * @dentry:  dentry that is being deleted
 * @mode: create permissions
 * @nd: path information
 *
 */

@@ -724,76 +727,19 @@ static int
v9fs_vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
		struct nameidata *nd)
{
	int err;
	u32 perm;
	int flags;
	struct file *filp;
	struct v9fs_inode *v9inode;
	struct v9fs_session_info *v9ses;
	struct p9_fid *fid, *inode_fid;

	err = 0;
	fid = NULL;
	v9ses = v9fs_inode2v9ses(dir);
	perm = unixmode2p9mode(v9ses, mode);
	if (nd)
		flags = nd->intent.open.flags;
	else
		flags = O_RDWR;
	struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir);
	u32 perm = unixmode2p9mode(v9ses, mode);
	struct p9_fid *fid;

	fid = v9fs_create(v9ses, dir, dentry, NULL, perm,
				v9fs_uflags2omode(flags,
						v9fs_proto_dotu(v9ses)));
	if (IS_ERR(fid)) {
		err = PTR_ERR(fid);
		fid = NULL;
		goto error;
	}
	/* P9_OEXCL? */
	fid = v9fs_create(v9ses, dir, dentry, NULL, perm, P9_ORDWR);
	if (IS_ERR(fid))
		return PTR_ERR(fid);

	v9fs_invalidate_inode_attr(dir);
	/* if we are opening a file, assign the open fid to the file */
	if (nd) {
		v9inode = V9FS_I(dentry->d_inode);
		mutex_lock(&v9inode->v_mutex);
		if (v9ses->cache && !v9inode->writeback_fid &&
		    ((flags & O_ACCMODE) != O_RDONLY)) {
			/*
			 * clone a fid and add it to writeback_fid
			 * we do it during open time instead of
			 * page dirty time via write_begin/page_mkwrite
			 * because we want write after unlink usecase
			 * to work.
			 */
			inode_fid = v9fs_writeback_fid(dentry);
			if (IS_ERR(inode_fid)) {
				err = PTR_ERR(inode_fid);
				mutex_unlock(&v9inode->v_mutex);
				goto error;
			}
			v9inode->writeback_fid = (void *) inode_fid;
		}
		mutex_unlock(&v9inode->v_mutex);
		filp = lookup_instantiate_filp(nd, dentry, generic_file_open);
		if (IS_ERR(filp)) {
			err = PTR_ERR(filp);
			goto error;
		}

		filp->private_data = fid;
#ifdef CONFIG_9P_FSCACHE
		if (v9ses->cache)
			v9fs_cache_inode_set_cookie(dentry->d_inode, filp);
#endif
	} else
	p9_client_clunk(fid);

	return 0;

error:
	if (fid)
		p9_client_clunk(fid);

	return err;
}

/**
@@ -910,6 +856,93 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
	return ERR_PTR(result);
}

static struct file *
v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry,
		     struct opendata *od, unsigned flags, umode_t mode,
		     bool *created)
{
	int err;
	u32 perm;
	struct file *filp;
	struct v9fs_inode *v9inode;
	struct v9fs_session_info *v9ses;
	struct p9_fid *fid, *inode_fid;
	struct dentry *res = NULL;

	if (d_unhashed(dentry)) {
		res = v9fs_vfs_lookup(dir, dentry, NULL);
		if (IS_ERR(res))
			return ERR_CAST(res);

		if (res)
			dentry = res;
	}

	/* Only creates */
	if (!(flags & O_CREAT) || dentry->d_inode) {
		finish_no_open(od, res);
		return NULL;
	}

	err = 0;
	fid = NULL;
	v9ses = v9fs_inode2v9ses(dir);
	perm = unixmode2p9mode(v9ses, mode);
	fid = v9fs_create(v9ses, dir, dentry, NULL, perm,
				v9fs_uflags2omode(flags,
						v9fs_proto_dotu(v9ses)));
	if (IS_ERR(fid)) {
		err = PTR_ERR(fid);
		fid = NULL;
		goto error;
	}

	v9fs_invalidate_inode_attr(dir);
	v9inode = V9FS_I(dentry->d_inode);
	mutex_lock(&v9inode->v_mutex);
	if (v9ses->cache && !v9inode->writeback_fid &&
	    ((flags & O_ACCMODE) != O_RDONLY)) {
		/*
		 * clone a fid and add it to writeback_fid
		 * we do it during open time instead of
		 * page dirty time via write_begin/page_mkwrite
		 * because we want write after unlink usecase
		 * to work.
		 */
		inode_fid = v9fs_writeback_fid(dentry);
		if (IS_ERR(inode_fid)) {
			err = PTR_ERR(inode_fid);
			mutex_unlock(&v9inode->v_mutex);
			goto error;
		}
		v9inode->writeback_fid = (void *) inode_fid;
	}
	mutex_unlock(&v9inode->v_mutex);
	filp = finish_open(od, dentry, generic_file_open);
	if (IS_ERR(filp)) {
		err = PTR_ERR(filp);
		goto error;
	}

	filp->private_data = fid;
#ifdef CONFIG_9P_FSCACHE
	if (v9ses->cache)
		v9fs_cache_inode_set_cookie(dentry->d_inode, filp);
#endif

	*created = true;
out:
	dput(res);
	return filp;

error:
	if (fid)
		p9_client_clunk(fid);

	filp = ERR_PTR(err);
	goto out;
}

/**
 * v9fs_vfs_unlink - VFS unlink hook to delete an inode
 * @i:  inode that is being unlinked
@@ -1488,6 +1521,7 @@ int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode)
static const struct inode_operations v9fs_dir_inode_operations_dotu = {
	.create = v9fs_vfs_create,
	.lookup = v9fs_vfs_lookup,
	.atomic_open = v9fs_vfs_atomic_open,
	.symlink = v9fs_vfs_symlink,
	.link = v9fs_vfs_link,
	.unlink = v9fs_vfs_unlink,
@@ -1502,6 +1536,7 @@ static const struct inode_operations v9fs_dir_inode_operations_dotu = {
static const struct inode_operations v9fs_dir_inode_operations = {
	.create = v9fs_vfs_create,
	.lookup = v9fs_vfs_lookup,
	.atomic_open = v9fs_vfs_atomic_open,
	.unlink = v9fs_vfs_unlink,
	.mkdir = v9fs_vfs_mkdir,
	.rmdir = v9fs_vfs_rmdir,
+35 −17
Original line number Diff line number Diff line
@@ -230,17 +230,23 @@ int v9fs_open_to_dotl_flags(int flags)
 * @dir: directory inode that is being created
 * @dentry:  dentry that is being deleted
 * @mode: create permissions
 * @nd: path information
 *
 */

static int
v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
		struct nameidata *nd)
{
	return v9fs_vfs_mknod_dotl(dir, dentry, omode, 0);
}

static struct file *
v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry,
			  struct opendata *od, unsigned flags, umode_t omode,
			  bool *created)
{
	int err = 0;
	gid_t gid;
	int flags;
	umode_t mode;
	char *name = NULL;
	struct file *filp;
@@ -251,19 +257,25 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
	struct p9_fid *dfid, *ofid, *inode_fid;
	struct v9fs_session_info *v9ses;
	struct posix_acl *pacl = NULL, *dacl = NULL;
	struct dentry *res = NULL;

	v9ses = v9fs_inode2v9ses(dir);
	if (nd)
		flags = nd->intent.open.flags;
	else {
		/*
		 * create call without LOOKUP_OPEN is due
		 * to mknod of regular files. So use mknod
		 * operation.
		 */
		return v9fs_vfs_mknod_dotl(dir, dentry, omode, 0);
	if (d_unhashed(dentry)) {
		res = v9fs_vfs_lookup(dir, dentry, NULL);
		if (IS_ERR(res))
			return ERR_CAST(res);

		if (res)
			dentry = res;
	}

	/* Only creates */
	if (!(flags & O_CREAT) || dentry->d_inode) {
		finish_no_open(od, res);
		return NULL;
	}

	v9ses = v9fs_inode2v9ses(dir);

	name = (char *) dentry->d_name.name;
	p9_debug(P9_DEBUG_VFS, "name:%s flags:0x%x mode:0x%hx\n",
		 name, flags, omode);
@@ -272,7 +284,7 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
	if (IS_ERR(dfid)) {
		err = PTR_ERR(dfid);
		p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
		return err;
		goto err_return;
	}

	/* clone a fid to use for creation */
@@ -280,7 +292,7 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
	if (IS_ERR(ofid)) {
		err = PTR_ERR(ofid);
		p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
		return err;
		goto err_return;
	}

	gid = v9fs_get_fsgid_for_create(dir);
@@ -345,7 +357,7 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
	}
	mutex_unlock(&v9inode->v_mutex);
	/* Since we are opening a file, assign the open fid to the file */
	filp = lookup_instantiate_filp(nd, dentry, generic_file_open);
	filp = finish_open(od, dentry, generic_file_open);
	if (IS_ERR(filp)) {
		err = PTR_ERR(filp);
		goto err_clunk_old_fid;
@@ -355,7 +367,10 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
	if (v9ses->cache)
		v9fs_cache_inode_set_cookie(inode, filp);
#endif
	return 0;
	*created = true;
out:
	dput(res);
	return filp;

error:
	if (fid)
@@ -364,7 +379,9 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
	if (ofid)
		p9_client_clunk(ofid);
	v9fs_set_create_acl(NULL, &dacl, &pacl);
	return err;
err_return:
	filp = ERR_PTR(err);
	goto out;
}

/**
@@ -982,6 +999,7 @@ int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode)

const struct inode_operations v9fs_dir_inode_operations_dotl = {
	.create = v9fs_vfs_create_dotl,
	.atomic_open = v9fs_vfs_atomic_open_dotl,
	.lookup = v9fs_vfs_lookup,
	.link = v9fs_vfs_link_dotl,
	.symlink = v9fs_vfs_symlink_dotl,