aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/fuse/dir.c183
-rw-r--r--fs/fuse/fuse_i.h12
-rw-r--r--include/linux/fuse.h18
3 files changed, 213 insertions, 0 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 0950455914dd..f127625543b4 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -744,6 +744,177 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
744 return d_splice_alias(inode, entry); 744 return d_splice_alias(inode, entry);
745} 745}
746 746
747static int fuse_setxattr(struct dentry *entry, const char *name,
748 const void *value, size_t size, int flags)
749{
750 struct inode *inode = entry->d_inode;
751 struct fuse_conn *fc = get_fuse_conn(inode);
752 struct fuse_req *req;
753 struct fuse_setxattr_in inarg;
754 int err;
755
756 if (size > FUSE_XATTR_SIZE_MAX)
757 return -E2BIG;
758
759 if (fc->no_setxattr)
760 return -EOPNOTSUPP;
761
762 req = fuse_get_request(fc);
763 if (!req)
764 return -ERESTARTNOINTR;
765
766 memset(&inarg, 0, sizeof(inarg));
767 inarg.size = size;
768 inarg.flags = flags;
769 req->in.h.opcode = FUSE_SETXATTR;
770 req->in.h.nodeid = get_node_id(inode);
771 req->inode = inode;
772 req->in.numargs = 3;
773 req->in.args[0].size = sizeof(inarg);
774 req->in.args[0].value = &inarg;
775 req->in.args[1].size = strlen(name) + 1;
776 req->in.args[1].value = name;
777 req->in.args[2].size = size;
778 req->in.args[2].value = value;
779 request_send(fc, req);
780 err = req->out.h.error;
781 fuse_put_request(fc, req);
782 if (err == -ENOSYS) {
783 fc->no_setxattr = 1;
784 err = -EOPNOTSUPP;
785 }
786 return err;
787}
788
789static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
790 void *value, size_t size)
791{
792 struct inode *inode = entry->d_inode;
793 struct fuse_conn *fc = get_fuse_conn(inode);
794 struct fuse_req *req;
795 struct fuse_getxattr_in inarg;
796 struct fuse_getxattr_out outarg;
797 ssize_t ret;
798
799 if (fc->no_getxattr)
800 return -EOPNOTSUPP;
801
802 req = fuse_get_request(fc);
803 if (!req)
804 return -ERESTARTNOINTR;
805
806 memset(&inarg, 0, sizeof(inarg));
807 inarg.size = size;
808 req->in.h.opcode = FUSE_GETXATTR;
809 req->in.h.nodeid = get_node_id(inode);
810 req->inode = inode;
811 req->in.numargs = 2;
812 req->in.args[0].size = sizeof(inarg);
813 req->in.args[0].value = &inarg;
814 req->in.args[1].size = strlen(name) + 1;
815 req->in.args[1].value = name;
816 /* This is really two different operations rolled into one */
817 req->out.numargs = 1;
818 if (size) {
819 req->out.argvar = 1;
820 req->out.args[0].size = size;
821 req->out.args[0].value = value;
822 } else {
823 req->out.args[0].size = sizeof(outarg);
824 req->out.args[0].value = &outarg;
825 }
826 request_send(fc, req);
827 ret = req->out.h.error;
828 if (!ret)
829 ret = size ? req->out.args[0].size : outarg.size;
830 else {
831 if (ret == -ENOSYS) {
832 fc->no_getxattr = 1;
833 ret = -EOPNOTSUPP;
834 }
835 }
836 fuse_put_request(fc, req);
837 return ret;
838}
839
840static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
841{
842 struct inode *inode = entry->d_inode;
843 struct fuse_conn *fc = get_fuse_conn(inode);
844 struct fuse_req *req;
845 struct fuse_getxattr_in inarg;
846 struct fuse_getxattr_out outarg;
847 ssize_t ret;
848
849 if (fc->no_listxattr)
850 return -EOPNOTSUPP;
851
852 req = fuse_get_request(fc);
853 if (!req)
854 return -ERESTARTNOINTR;
855
856 memset(&inarg, 0, sizeof(inarg));
857 inarg.size = size;
858 req->in.h.opcode = FUSE_LISTXATTR;
859 req->in.h.nodeid = get_node_id(inode);
860 req->inode = inode;
861 req->in.numargs = 1;
862 req->in.args[0].size = sizeof(inarg);
863 req->in.args[0].value = &inarg;
864 /* This is really two different operations rolled into one */
865 req->out.numargs = 1;
866 if (size) {
867 req->out.argvar = 1;
868 req->out.args[0].size = size;
869 req->out.args[0].value = list;
870 } else {
871 req->out.args[0].size = sizeof(outarg);
872 req->out.args[0].value = &outarg;
873 }
874 request_send(fc, req);
875 ret = req->out.h.error;
876 if (!ret)
877 ret = size ? req->out.args[0].size : outarg.size;
878 else {
879 if (ret == -ENOSYS) {
880 fc->no_listxattr = 1;
881 ret = -EOPNOTSUPP;
882 }
883 }
884 fuse_put_request(fc, req);
885 return ret;
886}
887
888static int fuse_removexattr(struct dentry *entry, const char *name)
889{
890 struct inode *inode = entry->d_inode;
891 struct fuse_conn *fc = get_fuse_conn(inode);
892 struct fuse_req *req;
893 int err;
894
895 if (fc->no_removexattr)
896 return -EOPNOTSUPP;
897
898 req = fuse_get_request(fc);
899 if (!req)
900 return -ERESTARTNOINTR;
901
902 req->in.h.opcode = FUSE_REMOVEXATTR;
903 req->in.h.nodeid = get_node_id(inode);
904 req->inode = inode;
905 req->in.numargs = 1;
906 req->in.args[0].size = strlen(name) + 1;
907 req->in.args[0].value = name;
908 request_send(fc, req);
909 err = req->out.h.error;
910 fuse_put_request(fc, req);
911 if (err == -ENOSYS) {
912 fc->no_removexattr = 1;
913 err = -EOPNOTSUPP;
914 }
915 return err;
916}
917
747static struct inode_operations fuse_dir_inode_operations = { 918static struct inode_operations fuse_dir_inode_operations = {
748 .lookup = fuse_lookup, 919 .lookup = fuse_lookup,
749 .mkdir = fuse_mkdir, 920 .mkdir = fuse_mkdir,
@@ -757,6 +928,10 @@ static struct inode_operations fuse_dir_inode_operations = {
757 .mknod = fuse_mknod, 928 .mknod = fuse_mknod,
758 .permission = fuse_permission, 929 .permission = fuse_permission,
759 .getattr = fuse_getattr, 930 .getattr = fuse_getattr,
931 .setxattr = fuse_setxattr,
932 .getxattr = fuse_getxattr,
933 .listxattr = fuse_listxattr,
934 .removexattr = fuse_removexattr,
760}; 935};
761 936
762static struct file_operations fuse_dir_operations = { 937static struct file_operations fuse_dir_operations = {
@@ -771,6 +946,10 @@ static struct inode_operations fuse_common_inode_operations = {
771 .setattr = fuse_setattr, 946 .setattr = fuse_setattr,
772 .permission = fuse_permission, 947 .permission = fuse_permission,
773 .getattr = fuse_getattr, 948 .getattr = fuse_getattr,
949 .setxattr = fuse_setxattr,
950 .getxattr = fuse_getxattr,
951 .listxattr = fuse_listxattr,
952 .removexattr = fuse_removexattr,
774}; 953};
775 954
776static struct inode_operations fuse_symlink_inode_operations = { 955static struct inode_operations fuse_symlink_inode_operations = {
@@ -779,6 +958,10 @@ static struct inode_operations fuse_symlink_inode_operations = {
779 .put_link = fuse_put_link, 958 .put_link = fuse_put_link,
780 .readlink = generic_readlink, 959 .readlink = generic_readlink,
781 .getattr = fuse_getattr, 960 .getattr = fuse_getattr,
961 .setxattr = fuse_setxattr,
962 .getxattr = fuse_getxattr,
963 .listxattr = fuse_listxattr,
964 .removexattr = fuse_removexattr,
782}; 965};
783 966
784void fuse_init_common(struct inode *inode) 967void fuse_init_common(struct inode *inode)
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index c8e6c87496e0..86183c562104 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -245,6 +245,18 @@ struct fuse_conn {
245 /** Is flush not implemented by fs? */ 245 /** Is flush not implemented by fs? */
246 unsigned no_flush : 1; 246 unsigned no_flush : 1;
247 247
248 /** Is setxattr not implemented by fs? */
249 unsigned no_setxattr : 1;
250
251 /** Is getxattr not implemented by fs? */
252 unsigned no_getxattr : 1;
253
254 /** Is listxattr not implemented by fs? */
255 unsigned no_listxattr : 1;
256
257 /** Is removexattr not implemented by fs? */
258 unsigned no_removexattr : 1;
259
248 /** Backing dev info */ 260 /** Backing dev info */
249 struct backing_dev_info bdi; 261 struct backing_dev_info bdi;
250}; 262};
diff --git a/include/linux/fuse.h b/include/linux/fuse.h
index 61f34636ffbc..bf564edf9905 100644
--- a/include/linux/fuse.h
+++ b/include/linux/fuse.h
@@ -80,6 +80,10 @@ enum fuse_opcode {
80 FUSE_STATFS = 17, 80 FUSE_STATFS = 17,
81 FUSE_RELEASE = 18, 81 FUSE_RELEASE = 18,
82 FUSE_FSYNC = 20, 82 FUSE_FSYNC = 20,
83 FUSE_SETXATTR = 21,
84 FUSE_GETXATTR = 22,
85 FUSE_LISTXATTR = 23,
86 FUSE_REMOVEXATTR = 24,
83 FUSE_FLUSH = 25, 87 FUSE_FLUSH = 25,
84 FUSE_INIT = 26 88 FUSE_INIT = 26
85}; 89};
@@ -89,6 +93,7 @@ enum fuse_opcode {
89 93
90#define FUSE_NAME_MAX 1024 94#define FUSE_NAME_MAX 1024
91#define FUSE_SYMLINK_MAX 4096 95#define FUSE_SYMLINK_MAX 4096
96#define FUSE_XATTR_SIZE_MAX 4096
92 97
93struct fuse_entry_out { 98struct fuse_entry_out {
94 __u64 nodeid; /* Inode ID */ 99 __u64 nodeid; /* Inode ID */
@@ -183,6 +188,19 @@ struct fuse_fsync_in {
183 __u32 fsync_flags; 188 __u32 fsync_flags;
184}; 189};
185 190
191struct fuse_setxattr_in {
192 __u32 size;
193 __u32 flags;
194};
195
196struct fuse_getxattr_in {
197 __u32 size;
198};
199
200struct fuse_getxattr_out {
201 __u32 size;
202};
203
186struct fuse_init_in_out { 204struct fuse_init_in_out {
187 __u32 major; 205 __u32 major;
188 __u32 minor; 206 __u32 minor;