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

Merge remote-tracking branch 'fuse/xattr' into work.xattr

Al Viro 41fefa36 6c6ef9f2

+221 -157
+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 -156
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 ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size) 1806 - { 1807 - struct inode *inode = d_inode(entry); 1808 - struct fuse_conn *fc = get_fuse_conn(inode); 1809 - FUSE_ARGS(args); 1810 - struct fuse_getxattr_in inarg; 1811 - struct fuse_getxattr_out outarg; 1812 - ssize_t ret; 1813 - 1814 - if (!fuse_allow_current_process(fc)) 1815 - return -EACCES; 1816 - 1817 - if (fc->no_listxattr) 1818 - return -EOPNOTSUPP; 1819 - 1820 - memset(&inarg, 0, sizeof(inarg)); 1821 - inarg.size = size; 1822 - args.in.h.opcode = FUSE_LISTXATTR; 1823 - args.in.h.nodeid = get_node_id(inode); 1824 - args.in.numargs = 1; 1825 - args.in.args[0].size = sizeof(inarg); 1826 - args.in.args[0].value = &inarg; 1827 - /* This is really two different operations rolled into one */ 1828 - args.out.numargs = 1; 1829 - if (size) { 1830 - args.out.argvar = 1; 1831 - args.out.args[0].size = size; 1832 - args.out.args[0].value = list; 1833 - } else { 1834 - args.out.args[0].size = sizeof(outarg); 1835 - args.out.args[0].value = &outarg; 1836 - } 1837 - ret = fuse_simple_request(fc, &args); 1838 - if (!ret && !size) 1839 - ret = outarg.size; 1840 - if (ret == -ENOSYS) { 1841 - fc->no_listxattr = 1; 1842 - ret = -EOPNOTSUPP; 1843 - } 1844 - return ret; 1845 - } 1846 - 1847 - static int fuse_removexattr(struct dentry *entry, const char *name) 1848 - { 1849 - struct inode *inode = d_inode(entry); 1850 - struct fuse_conn *fc = get_fuse_conn(inode); 1851 - FUSE_ARGS(args); 1852 - int err; 1853 - 1854 - if (fc->no_removexattr) 1855 - return -EOPNOTSUPP; 1856 - 1857 - args.in.h.opcode = FUSE_REMOVEXATTR; 1858 - args.in.h.nodeid = get_node_id(inode); 1859 - args.in.numargs = 1; 1860 - args.in.args[0].size = strlen(name) + 1; 1861 - args.in.args[0].value = name; 1862 - err = fuse_simple_request(fc, &args); 1863 - if (err == -ENOSYS) { 1864 - fc->no_removexattr = 1; 1865 - err = -EOPNOTSUPP; 1866 - } 1867 - if (!err) { 1868 - fuse_invalidate_attr(inode); 1869 - fuse_update_ctime(inode); 1870 - } 1871 - return err; 1872 - } 1873 - 1874 1727 static const struct inode_operations fuse_dir_inode_operations = { 1875 1728 .lookup = fuse_lookup, 1876 1729 .mkdir = fuse_mkdir, ··· 1739 1884 .mknod = fuse_mknod, 1740 1885 .permission = fuse_permission, 1741 1886 .getattr = fuse_getattr, 1742 - .setxattr = fuse_setxattr, 1743 - .getxattr = fuse_getxattr, 1887 + .setxattr = generic_setxattr, 1888 + .getxattr = generic_getxattr, 1744 1889 .listxattr = fuse_listxattr, 1745 - .removexattr = fuse_removexattr, 1890 + .removexattr = generic_removexattr, 1746 1891 }; 1747 1892 1748 1893 static const struct file_operations fuse_dir_operations = { ··· 1760 1905 .setattr = fuse_setattr, 1761 1906 .permission = fuse_permission, 1762 1907 .getattr = fuse_getattr, 1763 - .setxattr = fuse_setxattr, 1764 - .getxattr = fuse_getxattr, 1908 + .setxattr = generic_setxattr, 1909 + .getxattr = generic_getxattr, 1765 1910 .listxattr = fuse_listxattr, 1766 - .removexattr = fuse_removexattr, 1911 + .removexattr = generic_removexattr, 1767 1912 }; 1768 1913 1769 1914 static const struct inode_operations fuse_symlink_inode_operations = { ··· 1771 1916 .get_link = fuse_get_link, 1772 1917 .readlink = generic_readlink, 1773 1918 .getattr = fuse_getattr, 1774 - .setxattr = fuse_setxattr, 1775 - .getxattr = fuse_getxattr, 1919 + .setxattr = generic_setxattr, 1920 + .getxattr = generic_getxattr, 1776 1921 .listxattr = fuse_listxattr, 1777 - .removexattr = fuse_removexattr, 1922 + .removexattr = generic_removexattr, 1778 1923 }; 1779 1924 1780 1925 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 + };