Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

fuse: Use generic xattr ops

In preparation for posix acl support, rework fuse to use xattr handlers and
the generic setxattr/getxattr/listxattr callbacks. Split the xattr code
out into it's own file, and promote symbols to module-global scope as
needed.

Functionally these changes have no impact, as fuse still uses a single
handler for all xattrs which uses the old callbacks.

Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>

authored by

Seth Forshee and committed by
Miklos Szeredi
703c7362 cb3ae6d2

+221 -176
+1 -1
fs/fuse/Makefile
··· 5 5 obj-$(CONFIG_FUSE_FS) += fuse.o 6 6 obj-$(CONFIG_CUSE) += cuse.o 7 7 8 - fuse-objs := dev.o dir.o file.o inode.o control.o 8 + fuse-objs := dev.o dir.o file.o inode.o control.o xattr.o
+11 -175
fs/fuse/dir.c
··· 13 13 #include <linux/sched.h> 14 14 #include <linux/namei.h> 15 15 #include <linux/slab.h> 16 + #include <linux/xattr.h> 16 17 17 18 static bool fuse_use_readdirplus(struct inode *dir, struct dir_context *ctx) 18 19 { ··· 635 634 return create_new_entry(fc, &args, dir, entry, S_IFLNK); 636 635 } 637 636 638 - static inline void fuse_update_ctime(struct inode *inode) 637 + void fuse_update_ctime(struct inode *inode) 639 638 { 640 639 if (!IS_NOCMTIME(inode)) { 641 640 inode->i_ctime = current_fs_time(inode->i_sb); ··· 1725 1724 return fuse_update_attributes(inode, stat, NULL, NULL); 1726 1725 } 1727 1726 1728 - static int fuse_setxattr(struct dentry *unused, struct inode *inode, 1729 - const char *name, const void *value, 1730 - size_t size, int flags) 1731 - { 1732 - struct fuse_conn *fc = get_fuse_conn(inode); 1733 - FUSE_ARGS(args); 1734 - struct fuse_setxattr_in inarg; 1735 - int err; 1736 - 1737 - if (fc->no_setxattr) 1738 - return -EOPNOTSUPP; 1739 - 1740 - memset(&inarg, 0, sizeof(inarg)); 1741 - inarg.size = size; 1742 - inarg.flags = flags; 1743 - args.in.h.opcode = FUSE_SETXATTR; 1744 - args.in.h.nodeid = get_node_id(inode); 1745 - args.in.numargs = 3; 1746 - args.in.args[0].size = sizeof(inarg); 1747 - args.in.args[0].value = &inarg; 1748 - args.in.args[1].size = strlen(name) + 1; 1749 - args.in.args[1].value = name; 1750 - args.in.args[2].size = size; 1751 - args.in.args[2].value = value; 1752 - err = fuse_simple_request(fc, &args); 1753 - if (err == -ENOSYS) { 1754 - fc->no_setxattr = 1; 1755 - err = -EOPNOTSUPP; 1756 - } 1757 - if (!err) { 1758 - fuse_invalidate_attr(inode); 1759 - fuse_update_ctime(inode); 1760 - } 1761 - return err; 1762 - } 1763 - 1764 - static ssize_t fuse_getxattr(struct dentry *entry, struct inode *inode, 1765 - const char *name, void *value, size_t size) 1766 - { 1767 - struct fuse_conn *fc = get_fuse_conn(inode); 1768 - FUSE_ARGS(args); 1769 - struct fuse_getxattr_in inarg; 1770 - struct fuse_getxattr_out outarg; 1771 - ssize_t ret; 1772 - 1773 - if (fc->no_getxattr) 1774 - return -EOPNOTSUPP; 1775 - 1776 - memset(&inarg, 0, sizeof(inarg)); 1777 - inarg.size = size; 1778 - args.in.h.opcode = FUSE_GETXATTR; 1779 - args.in.h.nodeid = get_node_id(inode); 1780 - args.in.numargs = 2; 1781 - args.in.args[0].size = sizeof(inarg); 1782 - args.in.args[0].value = &inarg; 1783 - args.in.args[1].size = strlen(name) + 1; 1784 - args.in.args[1].value = name; 1785 - /* This is really two different operations rolled into one */ 1786 - args.out.numargs = 1; 1787 - if (size) { 1788 - args.out.argvar = 1; 1789 - args.out.args[0].size = size; 1790 - args.out.args[0].value = value; 1791 - } else { 1792 - args.out.args[0].size = sizeof(outarg); 1793 - args.out.args[0].value = &outarg; 1794 - } 1795 - ret = fuse_simple_request(fc, &args); 1796 - if (!ret && !size) 1797 - ret = outarg.size; 1798 - if (ret == -ENOSYS) { 1799 - fc->no_getxattr = 1; 1800 - ret = -EOPNOTSUPP; 1801 - } 1802 - return ret; 1803 - } 1804 - 1805 - static int fuse_verify_xattr_list(char *list, size_t size) 1806 - { 1807 - size_t origsize = size; 1808 - 1809 - while (size) { 1810 - size_t thislen = strnlen(list, size); 1811 - 1812 - if (!thislen || thislen == size) 1813 - return -EIO; 1814 - 1815 - size -= thislen + 1; 1816 - list += thislen + 1; 1817 - } 1818 - 1819 - return origsize; 1820 - } 1821 - 1822 - static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size) 1823 - { 1824 - struct inode *inode = d_inode(entry); 1825 - struct fuse_conn *fc = get_fuse_conn(inode); 1826 - FUSE_ARGS(args); 1827 - struct fuse_getxattr_in inarg; 1828 - struct fuse_getxattr_out outarg; 1829 - ssize_t ret; 1830 - 1831 - if (!fuse_allow_current_process(fc)) 1832 - return -EACCES; 1833 - 1834 - if (fc->no_listxattr) 1835 - return -EOPNOTSUPP; 1836 - 1837 - memset(&inarg, 0, sizeof(inarg)); 1838 - inarg.size = size; 1839 - args.in.h.opcode = FUSE_LISTXATTR; 1840 - args.in.h.nodeid = get_node_id(inode); 1841 - args.in.numargs = 1; 1842 - args.in.args[0].size = sizeof(inarg); 1843 - args.in.args[0].value = &inarg; 1844 - /* This is really two different operations rolled into one */ 1845 - args.out.numargs = 1; 1846 - if (size) { 1847 - args.out.argvar = 1; 1848 - args.out.args[0].size = size; 1849 - args.out.args[0].value = list; 1850 - } else { 1851 - args.out.args[0].size = sizeof(outarg); 1852 - args.out.args[0].value = &outarg; 1853 - } 1854 - ret = fuse_simple_request(fc, &args); 1855 - if (!ret && !size) 1856 - ret = outarg.size; 1857 - if (ret > 0 && size) 1858 - ret = fuse_verify_xattr_list(list, ret); 1859 - if (ret == -ENOSYS) { 1860 - fc->no_listxattr = 1; 1861 - ret = -EOPNOTSUPP; 1862 - } 1863 - return ret; 1864 - } 1865 - 1866 - static int fuse_removexattr(struct dentry *entry, const char *name) 1867 - { 1868 - struct inode *inode = d_inode(entry); 1869 - struct fuse_conn *fc = get_fuse_conn(inode); 1870 - FUSE_ARGS(args); 1871 - int err; 1872 - 1873 - if (fc->no_removexattr) 1874 - return -EOPNOTSUPP; 1875 - 1876 - args.in.h.opcode = FUSE_REMOVEXATTR; 1877 - args.in.h.nodeid = get_node_id(inode); 1878 - args.in.numargs = 1; 1879 - args.in.args[0].size = strlen(name) + 1; 1880 - args.in.args[0].value = name; 1881 - err = fuse_simple_request(fc, &args); 1882 - if (err == -ENOSYS) { 1883 - fc->no_removexattr = 1; 1884 - err = -EOPNOTSUPP; 1885 - } 1886 - if (!err) { 1887 - fuse_invalidate_attr(inode); 1888 - fuse_update_ctime(inode); 1889 - } 1890 - return err; 1891 - } 1892 - 1893 1727 static const struct inode_operations fuse_dir_inode_operations = { 1894 1728 .lookup = fuse_lookup, 1895 1729 .mkdir = fuse_mkdir, ··· 1739 1903 .mknod = fuse_mknod, 1740 1904 .permission = fuse_permission, 1741 1905 .getattr = fuse_getattr, 1742 - .setxattr = fuse_setxattr, 1743 - .getxattr = fuse_getxattr, 1906 + .setxattr = generic_setxattr, 1907 + .getxattr = generic_getxattr, 1744 1908 .listxattr = fuse_listxattr, 1745 - .removexattr = fuse_removexattr, 1909 + .removexattr = generic_removexattr, 1746 1910 }; 1747 1911 1748 1912 static const struct file_operations fuse_dir_operations = { ··· 1760 1924 .setattr = fuse_setattr, 1761 1925 .permission = fuse_permission, 1762 1926 .getattr = fuse_getattr, 1763 - .setxattr = fuse_setxattr, 1764 - .getxattr = fuse_getxattr, 1927 + .setxattr = generic_setxattr, 1928 + .getxattr = generic_getxattr, 1765 1929 .listxattr = fuse_listxattr, 1766 - .removexattr = fuse_removexattr, 1930 + .removexattr = generic_removexattr, 1767 1931 }; 1768 1932 1769 1933 static const struct inode_operations fuse_symlink_inode_operations = { ··· 1771 1935 .get_link = fuse_get_link, 1772 1936 .readlink = generic_readlink, 1773 1937 .getattr = fuse_getattr, 1774 - .setxattr = fuse_setxattr, 1775 - .getxattr = fuse_getxattr, 1938 + .setxattr = generic_setxattr, 1939 + .getxattr = generic_getxattr, 1776 1940 .listxattr = fuse_listxattr, 1777 - .removexattr = fuse_removexattr, 1941 + .removexattr = generic_removexattr, 1778 1942 }; 1779 1943 1780 1944 void fuse_init_common(struct inode *inode)
+5
fs/fuse/fuse_i.h
··· 902 902 903 903 u64 fuse_lock_owner_id(struct fuse_conn *fc, fl_owner_t id); 904 904 905 + void fuse_update_ctime(struct inode *inode); 906 + 905 907 int fuse_update_attributes(struct inode *inode, struct kstat *stat, 906 908 struct file *file, bool *refreshed); 907 909 ··· 967 965 968 966 void fuse_unlock_inode(struct inode *inode); 969 967 void fuse_lock_inode(struct inode *inode); 968 + 969 + ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size); 970 + extern const struct xattr_handler *fuse_xattr_handlers[]; 970 971 971 972 #endif /* _FS_FUSE_I_H */
+1
fs/fuse/inode.c
··· 1071 1071 } 1072 1072 sb->s_magic = FUSE_SUPER_MAGIC; 1073 1073 sb->s_op = &fuse_super_operations; 1074 + sb->s_xattr = fuse_xattr_handlers; 1074 1075 sb->s_maxbytes = MAX_LFS_FILESIZE; 1075 1076 sb->s_time_gran = 1; 1076 1077 sb->s_export_op = &fuse_export_operations;
+203
fs/fuse/xattr.c
··· 1 + /* 2 + * FUSE: Filesystem in Userspace 3 + * Copyright (C) 2001-2016 Miklos Szeredi <miklos@szeredi.hu> 4 + * 5 + * This program can be distributed under the terms of the GNU GPL. 6 + * See the file COPYING. 7 + */ 8 + 9 + #include "fuse_i.h" 10 + 11 + #include <linux/xattr.h> 12 + 13 + static int fuse_setxattr(struct inode *inode, const char *name, 14 + const void *value, size_t size, int flags) 15 + { 16 + struct fuse_conn *fc = get_fuse_conn(inode); 17 + FUSE_ARGS(args); 18 + struct fuse_setxattr_in inarg; 19 + int err; 20 + 21 + if (fc->no_setxattr) 22 + return -EOPNOTSUPP; 23 + 24 + memset(&inarg, 0, sizeof(inarg)); 25 + inarg.size = size; 26 + inarg.flags = flags; 27 + args.in.h.opcode = FUSE_SETXATTR; 28 + args.in.h.nodeid = get_node_id(inode); 29 + args.in.numargs = 3; 30 + args.in.args[0].size = sizeof(inarg); 31 + args.in.args[0].value = &inarg; 32 + args.in.args[1].size = strlen(name) + 1; 33 + args.in.args[1].value = name; 34 + args.in.args[2].size = size; 35 + args.in.args[2].value = value; 36 + err = fuse_simple_request(fc, &args); 37 + if (err == -ENOSYS) { 38 + fc->no_setxattr = 1; 39 + err = -EOPNOTSUPP; 40 + } 41 + if (!err) { 42 + fuse_invalidate_attr(inode); 43 + fuse_update_ctime(inode); 44 + } 45 + return err; 46 + } 47 + 48 + static ssize_t fuse_getxattr(struct inode *inode, const char *name, 49 + void *value, size_t size) 50 + { 51 + struct fuse_conn *fc = get_fuse_conn(inode); 52 + FUSE_ARGS(args); 53 + struct fuse_getxattr_in inarg; 54 + struct fuse_getxattr_out outarg; 55 + ssize_t ret; 56 + 57 + if (fc->no_getxattr) 58 + return -EOPNOTSUPP; 59 + 60 + memset(&inarg, 0, sizeof(inarg)); 61 + inarg.size = size; 62 + args.in.h.opcode = FUSE_GETXATTR; 63 + args.in.h.nodeid = get_node_id(inode); 64 + args.in.numargs = 2; 65 + args.in.args[0].size = sizeof(inarg); 66 + args.in.args[0].value = &inarg; 67 + args.in.args[1].size = strlen(name) + 1; 68 + args.in.args[1].value = name; 69 + /* This is really two different operations rolled into one */ 70 + args.out.numargs = 1; 71 + if (size) { 72 + args.out.argvar = 1; 73 + args.out.args[0].size = size; 74 + args.out.args[0].value = value; 75 + } else { 76 + args.out.args[0].size = sizeof(outarg); 77 + args.out.args[0].value = &outarg; 78 + } 79 + ret = fuse_simple_request(fc, &args); 80 + if (!ret && !size) 81 + ret = outarg.size; 82 + if (ret == -ENOSYS) { 83 + fc->no_getxattr = 1; 84 + ret = -EOPNOTSUPP; 85 + } 86 + return ret; 87 + } 88 + 89 + static int fuse_verify_xattr_list(char *list, size_t size) 90 + { 91 + size_t origsize = size; 92 + 93 + while (size) { 94 + size_t thislen = strnlen(list, size); 95 + 96 + if (!thislen || thislen == size) 97 + return -EIO; 98 + 99 + size -= thislen + 1; 100 + list += thislen + 1; 101 + } 102 + 103 + return origsize; 104 + } 105 + 106 + ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size) 107 + { 108 + struct inode *inode = d_inode(entry); 109 + struct fuse_conn *fc = get_fuse_conn(inode); 110 + FUSE_ARGS(args); 111 + struct fuse_getxattr_in inarg; 112 + struct fuse_getxattr_out outarg; 113 + ssize_t ret; 114 + 115 + if (!fuse_allow_current_process(fc)) 116 + return -EACCES; 117 + 118 + if (fc->no_listxattr) 119 + return -EOPNOTSUPP; 120 + 121 + memset(&inarg, 0, sizeof(inarg)); 122 + inarg.size = size; 123 + args.in.h.opcode = FUSE_LISTXATTR; 124 + args.in.h.nodeid = get_node_id(inode); 125 + args.in.numargs = 1; 126 + args.in.args[0].size = sizeof(inarg); 127 + args.in.args[0].value = &inarg; 128 + /* This is really two different operations rolled into one */ 129 + args.out.numargs = 1; 130 + if (size) { 131 + args.out.argvar = 1; 132 + args.out.args[0].size = size; 133 + args.out.args[0].value = list; 134 + } else { 135 + args.out.args[0].size = sizeof(outarg); 136 + args.out.args[0].value = &outarg; 137 + } 138 + ret = fuse_simple_request(fc, &args); 139 + if (!ret && !size) 140 + ret = outarg.size; 141 + if (ret > 0 && size) 142 + ret = fuse_verify_xattr_list(list, ret); 143 + if (ret == -ENOSYS) { 144 + fc->no_listxattr = 1; 145 + ret = -EOPNOTSUPP; 146 + } 147 + return ret; 148 + } 149 + 150 + static int fuse_removexattr(struct inode *inode, const char *name) 151 + { 152 + struct fuse_conn *fc = get_fuse_conn(inode); 153 + FUSE_ARGS(args); 154 + int err; 155 + 156 + if (fc->no_removexattr) 157 + return -EOPNOTSUPP; 158 + 159 + args.in.h.opcode = FUSE_REMOVEXATTR; 160 + args.in.h.nodeid = get_node_id(inode); 161 + args.in.numargs = 1; 162 + args.in.args[0].size = strlen(name) + 1; 163 + args.in.args[0].value = name; 164 + err = fuse_simple_request(fc, &args); 165 + if (err == -ENOSYS) { 166 + fc->no_removexattr = 1; 167 + err = -EOPNOTSUPP; 168 + } 169 + if (!err) { 170 + fuse_invalidate_attr(inode); 171 + fuse_update_ctime(inode); 172 + } 173 + return err; 174 + } 175 + 176 + static int fuse_xattr_get(const struct xattr_handler *handler, 177 + struct dentry *dentry, struct inode *inode, 178 + const char *name, void *value, size_t size) 179 + { 180 + return fuse_getxattr(inode, name, value, size); 181 + } 182 + 183 + static int fuse_xattr_set(const struct xattr_handler *handler, 184 + struct dentry *dentry, struct inode *inode, 185 + const char *name, const void *value, size_t size, 186 + int flags) 187 + { 188 + if (!value) 189 + return fuse_removexattr(inode, name); 190 + 191 + return fuse_setxattr(inode, name, value, size, flags); 192 + } 193 + 194 + static const struct xattr_handler fuse_xattr_handler = { 195 + .prefix = "", 196 + .get = fuse_xattr_get, 197 + .set = fuse_xattr_set, 198 + }; 199 + 200 + const struct xattr_handler *fuse_xattr_handlers[] = { 201 + &fuse_xattr_handler, 202 + NULL 203 + };