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

Commit 1560c974 authored by Miklos Szeredi's avatar Miklos Szeredi
Browse files

fuse: add renameat2 support



Support RENAME_EXCHANGE and RENAME_NOREPLACE flags on the userspace ABI.

Signed-off-by: default avatarMiklos Szeredi <mszeredi@suse.cz>
parent 4ace1f85
Loading
Loading
Loading
Loading
+47 −8
Original line number Diff line number Diff line
@@ -752,23 +752,26 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry)
	return err;
}

static int fuse_rename(struct inode *olddir, struct dentry *oldent,
		       struct inode *newdir, struct dentry *newent)
static int fuse_rename_common(struct inode *olddir, struct dentry *oldent,
			      struct inode *newdir, struct dentry *newent,
			      unsigned int flags, int opcode, size_t argsize)
{
	int err;
	struct fuse_rename_in inarg;
	struct fuse_rename2_in inarg;
	struct fuse_conn *fc = get_fuse_conn(olddir);
	struct fuse_req *req = fuse_get_req_nopages(fc);
	struct fuse_req *req;

	req = fuse_get_req_nopages(fc);
	if (IS_ERR(req))
		return PTR_ERR(req);

	memset(&inarg, 0, sizeof(inarg));
	memset(&inarg, 0, argsize);
	inarg.newdir = get_node_id(newdir);
	req->in.h.opcode = FUSE_RENAME;
	inarg.flags = flags;
	req->in.h.opcode = opcode;
	req->in.h.nodeid = get_node_id(olddir);
	req->in.numargs = 3;
	req->in.args[0].size = sizeof(inarg);
	req->in.args[0].size = argsize;
	req->in.args[0].value = &inarg;
	req->in.args[1].size = oldent->d_name.len + 1;
	req->in.args[1].value = oldent->d_name.name;
@@ -782,12 +785,17 @@ static int fuse_rename(struct inode *olddir, struct dentry *oldent,
		fuse_invalidate_attr(oldent->d_inode);
		fuse_update_ctime(oldent->d_inode);

		if (flags & RENAME_EXCHANGE) {
			fuse_invalidate_attr(newent->d_inode);
			fuse_update_ctime(newent->d_inode);
		}

		fuse_invalidate_attr(olddir);
		if (olddir != newdir)
			fuse_invalidate_attr(newdir);

		/* newent will end up negative */
		if (newent->d_inode) {
		if (!(flags & RENAME_EXCHANGE) && newent->d_inode) {
			fuse_invalidate_attr(newent->d_inode);
			fuse_invalidate_entry_cache(newent);
			fuse_update_ctime(newent->d_inode);
@@ -806,6 +814,36 @@ static int fuse_rename(struct inode *olddir, struct dentry *oldent,
	return err;
}

static int fuse_rename(struct inode *olddir, struct dentry *oldent,
		       struct inode *newdir, struct dentry *newent)
{
	return fuse_rename_common(olddir, oldent, newdir, newent, 0,
				  FUSE_RENAME, sizeof(struct fuse_rename_in));
}

static int fuse_rename2(struct inode *olddir, struct dentry *oldent,
			struct inode *newdir, struct dentry *newent,
			unsigned int flags)
{
	struct fuse_conn *fc = get_fuse_conn(olddir);
	int err;

	if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
		return -EINVAL;

	if (fc->no_rename2 || fc->minor < 23)
		return -EINVAL;

	err = fuse_rename_common(olddir, oldent, newdir, newent, flags,
				 FUSE_RENAME2, sizeof(struct fuse_rename2_in));
	if (err == -ENOSYS) {
		fc->no_rename2 = 1;
		err = -EINVAL;
	}
	return err;

}

static int fuse_link(struct dentry *entry, struct inode *newdir,
		     struct dentry *newent)
{
@@ -1980,6 +2018,7 @@ static const struct inode_operations fuse_dir_inode_operations = {
	.unlink		= fuse_unlink,
	.rmdir		= fuse_rmdir,
	.rename		= fuse_rename,
	.rename2	= fuse_rename2,
	.link		= fuse_link,
	.setattr	= fuse_setattr,
	.create		= fuse_create,
+3 −0
Original line number Diff line number Diff line
@@ -542,6 +542,9 @@ struct fuse_conn {
	/** Is fallocate not implemented by fs? */
	unsigned no_fallocate:1;

	/** Is rename with flags implemented by fs? */
	unsigned no_rename2:1;

	/** Use enhanced/automatic page cache invalidation. */
	unsigned auto_inval_data:1;

+8 −0
Original line number Diff line number Diff line
@@ -100,6 +100,7 @@
 *  - add reserved space to fuse_init_out
 *  - add FATTR_CTIME
 *  - add ctime and ctimensec to fuse_setattr_in
 *  - add FUSE_RENAME2 request
 */

#ifndef _LINUX_FUSE_H
@@ -353,6 +354,7 @@ enum fuse_opcode {
	FUSE_BATCH_FORGET  = 42,
	FUSE_FALLOCATE     = 43,
	FUSE_READDIRPLUS   = 44,
	FUSE_RENAME2       = 45,

	/* CUSE specific operations */
	CUSE_INIT          = 4096,
@@ -431,6 +433,12 @@ struct fuse_rename_in {
	uint64_t	newdir;
};

struct fuse_rename2_in {
	uint64_t	newdir;
	uint32_t	flags;
	uint32_t	padding;
};

struct fuse_link_in {
	uint64_t	oldnodeid;
};