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

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
...@@ -752,23 +752,26 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry) ...@@ -752,23 +752,26 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry)
return err; return err;
} }
static int fuse_rename(struct inode *olddir, struct dentry *oldent, static int fuse_rename_common(struct inode *olddir, struct dentry *oldent,
struct inode *newdir, struct dentry *newent) struct inode *newdir, struct dentry *newent,
unsigned int flags, int opcode, size_t argsize)
{ {
int err; int err;
struct fuse_rename_in inarg; struct fuse_rename2_in inarg;
struct fuse_conn *fc = get_fuse_conn(olddir); 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)) if (IS_ERR(req))
return PTR_ERR(req); return PTR_ERR(req);
memset(&inarg, 0, sizeof(inarg)); memset(&inarg, 0, argsize);
inarg.newdir = get_node_id(newdir); 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.h.nodeid = get_node_id(olddir);
req->in.numargs = 3; 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[0].value = &inarg;
req->in.args[1].size = oldent->d_name.len + 1; req->in.args[1].size = oldent->d_name.len + 1;
req->in.args[1].value = oldent->d_name.name; req->in.args[1].value = oldent->d_name.name;
...@@ -782,12 +785,17 @@ static int fuse_rename(struct inode *olddir, struct dentry *oldent, ...@@ -782,12 +785,17 @@ static int fuse_rename(struct inode *olddir, struct dentry *oldent,
fuse_invalidate_attr(oldent->d_inode); fuse_invalidate_attr(oldent->d_inode);
fuse_update_ctime(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); fuse_invalidate_attr(olddir);
if (olddir != newdir) if (olddir != newdir)
fuse_invalidate_attr(newdir); fuse_invalidate_attr(newdir);
/* newent will end up negative */ /* newent will end up negative */
if (newent->d_inode) { if (!(flags & RENAME_EXCHANGE) && newent->d_inode) {
fuse_invalidate_attr(newent->d_inode); fuse_invalidate_attr(newent->d_inode);
fuse_invalidate_entry_cache(newent); fuse_invalidate_entry_cache(newent);
fuse_update_ctime(newent->d_inode); fuse_update_ctime(newent->d_inode);
...@@ -806,6 +814,36 @@ static int fuse_rename(struct inode *olddir, struct dentry *oldent, ...@@ -806,6 +814,36 @@ static int fuse_rename(struct inode *olddir, struct dentry *oldent,
return err; 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, static int fuse_link(struct dentry *entry, struct inode *newdir,
struct dentry *newent) struct dentry *newent)
{ {
...@@ -1980,6 +2018,7 @@ static const struct inode_operations fuse_dir_inode_operations = { ...@@ -1980,6 +2018,7 @@ static const struct inode_operations fuse_dir_inode_operations = {
.unlink = fuse_unlink, .unlink = fuse_unlink,
.rmdir = fuse_rmdir, .rmdir = fuse_rmdir,
.rename = fuse_rename, .rename = fuse_rename,
.rename2 = fuse_rename2,
.link = fuse_link, .link = fuse_link,
.setattr = fuse_setattr, .setattr = fuse_setattr,
.create = fuse_create, .create = fuse_create,
......
...@@ -542,6 +542,9 @@ struct fuse_conn { ...@@ -542,6 +542,9 @@ struct fuse_conn {
/** Is fallocate not implemented by fs? */ /** Is fallocate not implemented by fs? */
unsigned no_fallocate:1; unsigned no_fallocate:1;
/** Is rename with flags implemented by fs? */
unsigned no_rename2:1;
/** Use enhanced/automatic page cache invalidation. */ /** Use enhanced/automatic page cache invalidation. */
unsigned auto_inval_data:1; unsigned auto_inval_data:1;
......
...@@ -100,6 +100,7 @@ ...@@ -100,6 +100,7 @@
* - add reserved space to fuse_init_out * - add reserved space to fuse_init_out
* - add FATTR_CTIME * - add FATTR_CTIME
* - add ctime and ctimensec to fuse_setattr_in * - add ctime and ctimensec to fuse_setattr_in
* - add FUSE_RENAME2 request
*/ */
#ifndef _LINUX_FUSE_H #ifndef _LINUX_FUSE_H
...@@ -353,6 +354,7 @@ enum fuse_opcode { ...@@ -353,6 +354,7 @@ enum fuse_opcode {
FUSE_BATCH_FORGET = 42, FUSE_BATCH_FORGET = 42,
FUSE_FALLOCATE = 43, FUSE_FALLOCATE = 43,
FUSE_READDIRPLUS = 44, FUSE_READDIRPLUS = 44,
FUSE_RENAME2 = 45,
/* CUSE specific operations */ /* CUSE specific operations */
CUSE_INIT = 4096, CUSE_INIT = 4096,
...@@ -431,6 +433,12 @@ struct fuse_rename_in { ...@@ -431,6 +433,12 @@ struct fuse_rename_in {
uint64_t newdir; uint64_t newdir;
}; };
struct fuse_rename2_in {
uint64_t newdir;
uint32_t flags;
uint32_t padding;
};
struct fuse_link_in { struct fuse_link_in {
uint64_t oldnodeid; uint64_t oldnodeid;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment