aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2014-04-28 10:43:44 -0400
committerMiklos Szeredi <mszeredi@suse.cz>2014-04-28 10:43:44 -0400
commit1560c974dcd40a8d3f193283acd7cc6aee13dc13 (patch)
tree844409c63c329b8fdee462ead3ff87aac3201405
parent4ace1f85a7cdab5453c2e12029ff978dd4cd6155 (diff)
fuse: add renameat2 support
Support RENAME_EXCHANGE and RENAME_NOREPLACE flags on the userspace ABI. Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
-rw-r--r--fs/fuse/dir.c55
-rw-r--r--fs/fuse/fuse_i.h3
-rw-r--r--include/uapi/linux/fuse.h8
3 files changed, 58 insertions, 8 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 843dcf1222eb..42198359fa1b 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -752,23 +752,26 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry)
752 return err; 752 return err;
753} 753}
754 754
755static int fuse_rename(struct inode *olddir, struct dentry *oldent, 755static int fuse_rename_common(struct inode *olddir, struct dentry *oldent,
756 struct inode *newdir, struct dentry *newent) 756 struct inode *newdir, struct dentry *newent,
757 unsigned int flags, int opcode, size_t argsize)
757{ 758{
758 int err; 759 int err;
759 struct fuse_rename_in inarg; 760 struct fuse_rename2_in inarg;
760 struct fuse_conn *fc = get_fuse_conn(olddir); 761 struct fuse_conn *fc = get_fuse_conn(olddir);
761 struct fuse_req *req = fuse_get_req_nopages(fc); 762 struct fuse_req *req;
762 763
764 req = fuse_get_req_nopages(fc);
763 if (IS_ERR(req)) 765 if (IS_ERR(req))
764 return PTR_ERR(req); 766 return PTR_ERR(req);
765 767
766 memset(&inarg, 0, sizeof(inarg)); 768 memset(&inarg, 0, argsize);
767 inarg.newdir = get_node_id(newdir); 769 inarg.newdir = get_node_id(newdir);
768 req->in.h.opcode = FUSE_RENAME; 770 inarg.flags = flags;
771 req->in.h.opcode = opcode;
769 req->in.h.nodeid = get_node_id(olddir); 772 req->in.h.nodeid = get_node_id(olddir);
770 req->in.numargs = 3; 773 req->in.numargs = 3;
771 req->in.args[0].size = sizeof(inarg); 774 req->in.args[0].size = argsize;
772 req->in.args[0].value = &inarg; 775 req->in.args[0].value = &inarg;
773 req->in.args[1].size = oldent->d_name.len + 1; 776 req->in.args[1].size = oldent->d_name.len + 1;
774 req->in.args[1].value = oldent->d_name.name; 777 req->in.args[1].value = oldent->d_name.name;
@@ -782,12 +785,17 @@ static int fuse_rename(struct inode *olddir, struct dentry *oldent,
782 fuse_invalidate_attr(oldent->d_inode); 785 fuse_invalidate_attr(oldent->d_inode);
783 fuse_update_ctime(oldent->d_inode); 786 fuse_update_ctime(oldent->d_inode);
784 787
788 if (flags & RENAME_EXCHANGE) {
789 fuse_invalidate_attr(newent->d_inode);
790 fuse_update_ctime(newent->d_inode);
791 }
792
785 fuse_invalidate_attr(olddir); 793 fuse_invalidate_attr(olddir);
786 if (olddir != newdir) 794 if (olddir != newdir)
787 fuse_invalidate_attr(newdir); 795 fuse_invalidate_attr(newdir);
788 796
789 /* newent will end up negative */ 797 /* newent will end up negative */
790 if (newent->d_inode) { 798 if (!(flags & RENAME_EXCHANGE) && newent->d_inode) {
791 fuse_invalidate_attr(newent->d_inode); 799 fuse_invalidate_attr(newent->d_inode);
792 fuse_invalidate_entry_cache(newent); 800 fuse_invalidate_entry_cache(newent);
793 fuse_update_ctime(newent->d_inode); 801 fuse_update_ctime(newent->d_inode);
@@ -806,6 +814,36 @@ static int fuse_rename(struct inode *olddir, struct dentry *oldent,
806 return err; 814 return err;
807} 815}
808 816
817static int fuse_rename(struct inode *olddir, struct dentry *oldent,
818 struct inode *newdir, struct dentry *newent)
819{
820 return fuse_rename_common(olddir, oldent, newdir, newent, 0,
821 FUSE_RENAME, sizeof(struct fuse_rename_in));
822}
823
824static int fuse_rename2(struct inode *olddir, struct dentry *oldent,
825 struct inode *newdir, struct dentry *newent,
826 unsigned int flags)
827{
828 struct fuse_conn *fc = get_fuse_conn(olddir);
829 int err;
830
831 if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
832 return -EINVAL;
833
834 if (fc->no_rename2 || fc->minor < 23)
835 return -EINVAL;
836
837 err = fuse_rename_common(olddir, oldent, newdir, newent, flags,
838 FUSE_RENAME2, sizeof(struct fuse_rename2_in));
839 if (err == -ENOSYS) {
840 fc->no_rename2 = 1;
841 err = -EINVAL;
842 }
843 return err;
844
845}
846
809static int fuse_link(struct dentry *entry, struct inode *newdir, 847static int fuse_link(struct dentry *entry, struct inode *newdir,
810 struct dentry *newent) 848 struct dentry *newent)
811{ 849{
@@ -1980,6 +2018,7 @@ static const struct inode_operations fuse_dir_inode_operations = {
1980 .unlink = fuse_unlink, 2018 .unlink = fuse_unlink,
1981 .rmdir = fuse_rmdir, 2019 .rmdir = fuse_rmdir,
1982 .rename = fuse_rename, 2020 .rename = fuse_rename,
2021 .rename2 = fuse_rename2,
1983 .link = fuse_link, 2022 .link = fuse_link,
1984 .setattr = fuse_setattr, 2023 .setattr = fuse_setattr,
1985 .create = fuse_create, 2024 .create = fuse_create,
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 40677e33504f..7aa5c75e0de1 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -542,6 +542,9 @@ struct fuse_conn {
542 /** Is fallocate not implemented by fs? */ 542 /** Is fallocate not implemented by fs? */
543 unsigned no_fallocate:1; 543 unsigned no_fallocate:1;
544 544
545 /** Is rename with flags implemented by fs? */
546 unsigned no_rename2:1;
547
545 /** Use enhanced/automatic page cache invalidation. */ 548 /** Use enhanced/automatic page cache invalidation. */
546 unsigned auto_inval_data:1; 549 unsigned auto_inval_data:1;
547 550
diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h
index e86a21acef75..40b5ca8a1b1f 100644
--- a/include/uapi/linux/fuse.h
+++ b/include/uapi/linux/fuse.h
@@ -100,6 +100,7 @@
100 * - add reserved space to fuse_init_out 100 * - add reserved space to fuse_init_out
101 * - add FATTR_CTIME 101 * - add FATTR_CTIME
102 * - add ctime and ctimensec to fuse_setattr_in 102 * - add ctime and ctimensec to fuse_setattr_in
103 * - add FUSE_RENAME2 request
103 */ 104 */
104 105
105#ifndef _LINUX_FUSE_H 106#ifndef _LINUX_FUSE_H
@@ -353,6 +354,7 @@ enum fuse_opcode {
353 FUSE_BATCH_FORGET = 42, 354 FUSE_BATCH_FORGET = 42,
354 FUSE_FALLOCATE = 43, 355 FUSE_FALLOCATE = 43,
355 FUSE_READDIRPLUS = 44, 356 FUSE_READDIRPLUS = 44,
357 FUSE_RENAME2 = 45,
356 358
357 /* CUSE specific operations */ 359 /* CUSE specific operations */
358 CUSE_INIT = 4096, 360 CUSE_INIT = 4096,
@@ -431,6 +433,12 @@ struct fuse_rename_in {
431 uint64_t newdir; 433 uint64_t newdir;
432}; 434};
433 435
436struct fuse_rename2_in {
437 uint64_t newdir;
438 uint32_t flags;
439 uint32_t padding;
440};
441
434struct fuse_link_in { 442struct fuse_link_in {
435 uint64_t oldnodeid; 443 uint64_t oldnodeid;
436}; 444};