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

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

fuse: 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>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent eda72afb
Loading
Loading
Loading
Loading
+67 −27
Original line number Diff line number Diff line
@@ -369,8 +369,9 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
 * If the filesystem doesn't support this, then fall back to separate
 * 'mknod' + 'open' requests.
 */
static int fuse_create_open(struct inode *dir, struct dentry *entry,
			    umode_t mode, struct nameidata *nd)
static struct file *fuse_create_open(struct inode *dir, struct dentry *entry,
				     struct opendata *od, unsigned flags,
				     umode_t mode)
{
	int err;
	struct inode *inode;
@@ -382,14 +383,11 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
	struct fuse_entry_out outentry;
	struct fuse_file *ff;
	struct file *file;
	int flags = nd->intent.open.flags;

	if (fc->no_create)
		return -ENOSYS;

	forget = fuse_alloc_forget();
	err = -ENOMEM;
	if (!forget)
		return -ENOMEM;
		goto out_err;

	req = fuse_get_req(fc);
	err = PTR_ERR(req);
@@ -428,11 +426,8 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
	req->out.args[1].value = &outopen;
	fuse_request_send(fc, req);
	err = req->out.h.error;
	if (err) {
		if (err == -ENOSYS)
			fc->no_create = 1;
	if (err)
		goto out_free_ff;
	}

	err = -EIO;
	if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid))
@@ -448,20 +443,21 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
		flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
		fuse_sync_release(ff, flags);
		fuse_queue_forget(fc, forget, outentry.nodeid, 1);
		return -ENOMEM;
		err = -ENOMEM;
		goto out_err;
	}
	kfree(forget);
	d_instantiate(entry, inode);
	fuse_change_entry_timeout(entry, &outentry);
	fuse_invalidate_attr(dir);
	file = lookup_instantiate_filp(nd, entry, generic_file_open);
	file = finish_open(od, entry, generic_file_open);
	if (IS_ERR(file)) {
		fuse_sync_release(ff, flags);
		return PTR_ERR(file);
	}
	} else {
		file->private_data = fuse_file_get(ff);
		fuse_finish_open(inode, file);
	return 0;
	}
	return file;

out_free_ff:
	fuse_file_free(ff);
@@ -469,7 +465,56 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
	fuse_put_request(fc, req);
out_put_forget_req:
	kfree(forget);
	return err;
out_err:
	return ERR_PTR(err);
}

static int fuse_mknod(struct inode *, struct dentry *, umode_t, dev_t);
static struct file *fuse_atomic_open(struct inode *dir, struct dentry *entry,
				     struct opendata *od, unsigned flags,
				     umode_t mode, bool *created)
{
	int err;
	struct fuse_conn *fc = get_fuse_conn(dir);
	struct file *file;
	struct dentry *res = NULL;

	if (d_unhashed(entry)) {
		res = fuse_lookup(dir, entry, NULL);
		if (IS_ERR(res))
			return ERR_CAST(res);

		if (res)
			entry = res;
	}

	if (!(flags & O_CREAT) || entry->d_inode)
		goto no_open;

	/* Only creates */
	*created = true;

	if (fc->no_create)
		goto mknod;

	file = fuse_create_open(dir, entry, od, flags, mode);
	if (PTR_ERR(file) == -ENOSYS) {
		fc->no_create = 1;
		goto mknod;
	}
out_dput:
	dput(res);
	return file;

mknod:
	err = fuse_mknod(dir, entry, mode, 0);
	if (err) {
		file = ERR_PTR(err);
		goto out_dput;
	}
no_open:
	finish_no_open(od, res);
	return NULL;
}

/*
@@ -573,12 +618,6 @@ static int fuse_mknod(struct inode *dir, struct dentry *entry, umode_t mode,
static int fuse_create(struct inode *dir, struct dentry *entry, umode_t mode,
		       struct nameidata *nd)
{
	if (nd) {
		int err = fuse_create_open(dir, entry, mode, nd);
		if (err != -ENOSYS)
			return err;
		/* Fall back on mknod */
	}
	return fuse_mknod(dir, entry, mode, 0);
}

@@ -1646,6 +1685,7 @@ static const struct inode_operations fuse_dir_inode_operations = {
	.link		= fuse_link,
	.setattr	= fuse_setattr,
	.create		= fuse_create,
	.atomic_open	= fuse_atomic_open,
	.mknod		= fuse_mknod,
	.permission	= fuse_permission,
	.getattr	= fuse_getattr,