aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2014-04-28 16:43:44 +0200
committerAlex Shi <alex.shi@linaro.org>2015-04-20 13:45:25 +0800
commite03ae8b69bb899c5cdd0c594fa58a85cd180df1b (patch)
treee08a444b90bd7d0af8a0d0a2b2d7a37d53530ef8
parent6b1c8b7974158eabc822d1a01f528f95793219ae (diff)
fuse: add renameat2 support
Support RENAME_EXCHANGE and RENAME_NOREPLACE flags on the userspace ABI. Signed-off-by: Miklos Szeredi <mszeredi@suse.cz> (cherry picked from commit 1560c974dcd40a8d3f193283acd7cc6aee13dc13) Signed-off-by: Alex Shi <alex.shi@linaro.org> Conflicts: fs/fuse/dir.c include/uapi/linux/fuse.h
-rw-r--r--fs/fuse/dir.c24
-rw-r--r--fs/fuse/fuse_i.h3
-rw-r--r--include/uapi/linux/fuse.h10
3 files changed, 29 insertions, 8 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 6d5e45c0db77..33dec83eccfb 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -753,23 +753,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;
@@ -783,12 +786,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);
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 1e6ad6d43051..7cc58c976780 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -544,6 +544,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;
diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h
index 60bb2f9f7b74..b77cf381a44b 100644
--- a/include/uapi/linux/fuse.h
+++ b/include/uapi/linux/fuse.h
@@ -93,6 +93,9 @@
*
* 7.22
* - add FUSE_ASYNC_DIO
+ *
+ * 7.23
+ * - add FUSE_RENAME2 request
*/
#ifndef _LINUX_FUSE_H
@@ -343,6 +346,7 @@ enum fuse_opcode {
FUSE_BATCH_FORGET = 42,
FUSE_FALLOCATE = 43,
FUSE_READDIRPLUS = 44,
+ FUSE_RENAME2 = 45,
/* CUSE specific operations */
CUSE_INIT = 4096,
@@ -421,6 +425,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;
};