tangled
alpha
login
or
join now
tjh.dev
/
kernel
1
fork
atom
Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1
fork
atom
overview
issues
pulls
pipelines
Merge remote-tracking branch 'fuse/xattr' into work.xattr
Al Viro
9 years ago
41fefa36
6c6ef9f2
+221
-157
5 changed files
expand all
collapse all
unified
split
fs
fuse
Makefile
dir.c
fuse_i.h
inode.c
xattr.c
+1
-1
fs/fuse/Makefile
reviewed
···
5
5
obj-$(CONFIG_FUSE_FS) += fuse.o
6
6
obj-$(CONFIG_CUSE) += cuse.o
7
7
8
8
-
fuse-objs := dev.o dir.o file.o inode.o control.o
8
8
+
fuse-objs := dev.o dir.o file.o inode.o control.o xattr.o
+11
-156
fs/fuse/dir.c
reviewed
···
13
13
#include <linux/sched.h>
14
14
#include <linux/namei.h>
15
15
#include <linux/slab.h>
16
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
638
-
static inline void fuse_update_ctime(struct inode *inode)
637
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
1728
-
static int fuse_setxattr(struct dentry *unused, struct inode *inode,
1729
1729
-
const char *name, const void *value,
1730
1730
-
size_t size, int flags)
1731
1731
-
{
1732
1732
-
struct fuse_conn *fc = get_fuse_conn(inode);
1733
1733
-
FUSE_ARGS(args);
1734
1734
-
struct fuse_setxattr_in inarg;
1735
1735
-
int err;
1736
1736
-
1737
1737
-
if (fc->no_setxattr)
1738
1738
-
return -EOPNOTSUPP;
1739
1739
-
1740
1740
-
memset(&inarg, 0, sizeof(inarg));
1741
1741
-
inarg.size = size;
1742
1742
-
inarg.flags = flags;
1743
1743
-
args.in.h.opcode = FUSE_SETXATTR;
1744
1744
-
args.in.h.nodeid = get_node_id(inode);
1745
1745
-
args.in.numargs = 3;
1746
1746
-
args.in.args[0].size = sizeof(inarg);
1747
1747
-
args.in.args[0].value = &inarg;
1748
1748
-
args.in.args[1].size = strlen(name) + 1;
1749
1749
-
args.in.args[1].value = name;
1750
1750
-
args.in.args[2].size = size;
1751
1751
-
args.in.args[2].value = value;
1752
1752
-
err = fuse_simple_request(fc, &args);
1753
1753
-
if (err == -ENOSYS) {
1754
1754
-
fc->no_setxattr = 1;
1755
1755
-
err = -EOPNOTSUPP;
1756
1756
-
}
1757
1757
-
if (!err) {
1758
1758
-
fuse_invalidate_attr(inode);
1759
1759
-
fuse_update_ctime(inode);
1760
1760
-
}
1761
1761
-
return err;
1762
1762
-
}
1763
1763
-
1764
1764
-
static ssize_t fuse_getxattr(struct dentry *entry, struct inode *inode,
1765
1765
-
const char *name, void *value, size_t size)
1766
1766
-
{
1767
1767
-
struct fuse_conn *fc = get_fuse_conn(inode);
1768
1768
-
FUSE_ARGS(args);
1769
1769
-
struct fuse_getxattr_in inarg;
1770
1770
-
struct fuse_getxattr_out outarg;
1771
1771
-
ssize_t ret;
1772
1772
-
1773
1773
-
if (fc->no_getxattr)
1774
1774
-
return -EOPNOTSUPP;
1775
1775
-
1776
1776
-
memset(&inarg, 0, sizeof(inarg));
1777
1777
-
inarg.size = size;
1778
1778
-
args.in.h.opcode = FUSE_GETXATTR;
1779
1779
-
args.in.h.nodeid = get_node_id(inode);
1780
1780
-
args.in.numargs = 2;
1781
1781
-
args.in.args[0].size = sizeof(inarg);
1782
1782
-
args.in.args[0].value = &inarg;
1783
1783
-
args.in.args[1].size = strlen(name) + 1;
1784
1784
-
args.in.args[1].value = name;
1785
1785
-
/* This is really two different operations rolled into one */
1786
1786
-
args.out.numargs = 1;
1787
1787
-
if (size) {
1788
1788
-
args.out.argvar = 1;
1789
1789
-
args.out.args[0].size = size;
1790
1790
-
args.out.args[0].value = value;
1791
1791
-
} else {
1792
1792
-
args.out.args[0].size = sizeof(outarg);
1793
1793
-
args.out.args[0].value = &outarg;
1794
1794
-
}
1795
1795
-
ret = fuse_simple_request(fc, &args);
1796
1796
-
if (!ret && !size)
1797
1797
-
ret = outarg.size;
1798
1798
-
if (ret == -ENOSYS) {
1799
1799
-
fc->no_getxattr = 1;
1800
1800
-
ret = -EOPNOTSUPP;
1801
1801
-
}
1802
1802
-
return ret;
1803
1803
-
}
1804
1804
-
1805
1805
-
static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
1806
1806
-
{
1807
1807
-
struct inode *inode = d_inode(entry);
1808
1808
-
struct fuse_conn *fc = get_fuse_conn(inode);
1809
1809
-
FUSE_ARGS(args);
1810
1810
-
struct fuse_getxattr_in inarg;
1811
1811
-
struct fuse_getxattr_out outarg;
1812
1812
-
ssize_t ret;
1813
1813
-
1814
1814
-
if (!fuse_allow_current_process(fc))
1815
1815
-
return -EACCES;
1816
1816
-
1817
1817
-
if (fc->no_listxattr)
1818
1818
-
return -EOPNOTSUPP;
1819
1819
-
1820
1820
-
memset(&inarg, 0, sizeof(inarg));
1821
1821
-
inarg.size = size;
1822
1822
-
args.in.h.opcode = FUSE_LISTXATTR;
1823
1823
-
args.in.h.nodeid = get_node_id(inode);
1824
1824
-
args.in.numargs = 1;
1825
1825
-
args.in.args[0].size = sizeof(inarg);
1826
1826
-
args.in.args[0].value = &inarg;
1827
1827
-
/* This is really two different operations rolled into one */
1828
1828
-
args.out.numargs = 1;
1829
1829
-
if (size) {
1830
1830
-
args.out.argvar = 1;
1831
1831
-
args.out.args[0].size = size;
1832
1832
-
args.out.args[0].value = list;
1833
1833
-
} else {
1834
1834
-
args.out.args[0].size = sizeof(outarg);
1835
1835
-
args.out.args[0].value = &outarg;
1836
1836
-
}
1837
1837
-
ret = fuse_simple_request(fc, &args);
1838
1838
-
if (!ret && !size)
1839
1839
-
ret = outarg.size;
1840
1840
-
if (ret == -ENOSYS) {
1841
1841
-
fc->no_listxattr = 1;
1842
1842
-
ret = -EOPNOTSUPP;
1843
1843
-
}
1844
1844
-
return ret;
1845
1845
-
}
1846
1846
-
1847
1847
-
static int fuse_removexattr(struct dentry *entry, const char *name)
1848
1848
-
{
1849
1849
-
struct inode *inode = d_inode(entry);
1850
1850
-
struct fuse_conn *fc = get_fuse_conn(inode);
1851
1851
-
FUSE_ARGS(args);
1852
1852
-
int err;
1853
1853
-
1854
1854
-
if (fc->no_removexattr)
1855
1855
-
return -EOPNOTSUPP;
1856
1856
-
1857
1857
-
args.in.h.opcode = FUSE_REMOVEXATTR;
1858
1858
-
args.in.h.nodeid = get_node_id(inode);
1859
1859
-
args.in.numargs = 1;
1860
1860
-
args.in.args[0].size = strlen(name) + 1;
1861
1861
-
args.in.args[0].value = name;
1862
1862
-
err = fuse_simple_request(fc, &args);
1863
1863
-
if (err == -ENOSYS) {
1864
1864
-
fc->no_removexattr = 1;
1865
1865
-
err = -EOPNOTSUPP;
1866
1866
-
}
1867
1867
-
if (!err) {
1868
1868
-
fuse_invalidate_attr(inode);
1869
1869
-
fuse_update_ctime(inode);
1870
1870
-
}
1871
1871
-
return err;
1872
1872
-
}
1873
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
1742
-
.setxattr = fuse_setxattr,
1743
1743
-
.getxattr = fuse_getxattr,
1887
1887
+
.setxattr = generic_setxattr,
1888
1888
+
.getxattr = generic_getxattr,
1744
1889
.listxattr = fuse_listxattr,
1745
1745
-
.removexattr = fuse_removexattr,
1890
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
1763
-
.setxattr = fuse_setxattr,
1764
1764
-
.getxattr = fuse_getxattr,
1908
1908
+
.setxattr = generic_setxattr,
1909
1909
+
.getxattr = generic_getxattr,
1765
1910
.listxattr = fuse_listxattr,
1766
1766
-
.removexattr = fuse_removexattr,
1911
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
1774
-
.setxattr = fuse_setxattr,
1775
1775
-
.getxattr = fuse_getxattr,
1919
1919
+
.setxattr = generic_setxattr,
1920
1920
+
.getxattr = generic_getxattr,
1776
1921
.listxattr = fuse_listxattr,
1777
1777
-
.removexattr = fuse_removexattr,
1922
1922
+
.removexattr = generic_removexattr,
1778
1923
};
1779
1924
1780
1925
void fuse_init_common(struct inode *inode)
+5
fs/fuse/fuse_i.h
reviewed
···
902
902
903
903
u64 fuse_lock_owner_id(struct fuse_conn *fc, fl_owner_t id);
904
904
905
905
+
void fuse_update_ctime(struct inode *inode);
906
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
968
+
969
969
+
ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size);
970
970
+
extern const struct xattr_handler *fuse_xattr_handlers[];
970
971
971
972
#endif /* _FS_FUSE_I_H */
+1
fs/fuse/inode.c
reviewed
···
1071
1071
}
1072
1072
sb->s_magic = FUSE_SUPER_MAGIC;
1073
1073
sb->s_op = &fuse_super_operations;
1074
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
reviewed
···
1
1
+
/*
2
2
+
* FUSE: Filesystem in Userspace
3
3
+
* Copyright (C) 2001-2016 Miklos Szeredi <miklos@szeredi.hu>
4
4
+
*
5
5
+
* This program can be distributed under the terms of the GNU GPL.
6
6
+
* See the file COPYING.
7
7
+
*/
8
8
+
9
9
+
#include "fuse_i.h"
10
10
+
11
11
+
#include <linux/xattr.h>
12
12
+
13
13
+
static int fuse_setxattr(struct inode *inode, const char *name,
14
14
+
const void *value, size_t size, int flags)
15
15
+
{
16
16
+
struct fuse_conn *fc = get_fuse_conn(inode);
17
17
+
FUSE_ARGS(args);
18
18
+
struct fuse_setxattr_in inarg;
19
19
+
int err;
20
20
+
21
21
+
if (fc->no_setxattr)
22
22
+
return -EOPNOTSUPP;
23
23
+
24
24
+
memset(&inarg, 0, sizeof(inarg));
25
25
+
inarg.size = size;
26
26
+
inarg.flags = flags;
27
27
+
args.in.h.opcode = FUSE_SETXATTR;
28
28
+
args.in.h.nodeid = get_node_id(inode);
29
29
+
args.in.numargs = 3;
30
30
+
args.in.args[0].size = sizeof(inarg);
31
31
+
args.in.args[0].value = &inarg;
32
32
+
args.in.args[1].size = strlen(name) + 1;
33
33
+
args.in.args[1].value = name;
34
34
+
args.in.args[2].size = size;
35
35
+
args.in.args[2].value = value;
36
36
+
err = fuse_simple_request(fc, &args);
37
37
+
if (err == -ENOSYS) {
38
38
+
fc->no_setxattr = 1;
39
39
+
err = -EOPNOTSUPP;
40
40
+
}
41
41
+
if (!err) {
42
42
+
fuse_invalidate_attr(inode);
43
43
+
fuse_update_ctime(inode);
44
44
+
}
45
45
+
return err;
46
46
+
}
47
47
+
48
48
+
static ssize_t fuse_getxattr(struct inode *inode, const char *name,
49
49
+
void *value, size_t size)
50
50
+
{
51
51
+
struct fuse_conn *fc = get_fuse_conn(inode);
52
52
+
FUSE_ARGS(args);
53
53
+
struct fuse_getxattr_in inarg;
54
54
+
struct fuse_getxattr_out outarg;
55
55
+
ssize_t ret;
56
56
+
57
57
+
if (fc->no_getxattr)
58
58
+
return -EOPNOTSUPP;
59
59
+
60
60
+
memset(&inarg, 0, sizeof(inarg));
61
61
+
inarg.size = size;
62
62
+
args.in.h.opcode = FUSE_GETXATTR;
63
63
+
args.in.h.nodeid = get_node_id(inode);
64
64
+
args.in.numargs = 2;
65
65
+
args.in.args[0].size = sizeof(inarg);
66
66
+
args.in.args[0].value = &inarg;
67
67
+
args.in.args[1].size = strlen(name) + 1;
68
68
+
args.in.args[1].value = name;
69
69
+
/* This is really two different operations rolled into one */
70
70
+
args.out.numargs = 1;
71
71
+
if (size) {
72
72
+
args.out.argvar = 1;
73
73
+
args.out.args[0].size = size;
74
74
+
args.out.args[0].value = value;
75
75
+
} else {
76
76
+
args.out.args[0].size = sizeof(outarg);
77
77
+
args.out.args[0].value = &outarg;
78
78
+
}
79
79
+
ret = fuse_simple_request(fc, &args);
80
80
+
if (!ret && !size)
81
81
+
ret = outarg.size;
82
82
+
if (ret == -ENOSYS) {
83
83
+
fc->no_getxattr = 1;
84
84
+
ret = -EOPNOTSUPP;
85
85
+
}
86
86
+
return ret;
87
87
+
}
88
88
+
89
89
+
static int fuse_verify_xattr_list(char *list, size_t size)
90
90
+
{
91
91
+
size_t origsize = size;
92
92
+
93
93
+
while (size) {
94
94
+
size_t thislen = strnlen(list, size);
95
95
+
96
96
+
if (!thislen || thislen == size)
97
97
+
return -EIO;
98
98
+
99
99
+
size -= thislen + 1;
100
100
+
list += thislen + 1;
101
101
+
}
102
102
+
103
103
+
return origsize;
104
104
+
}
105
105
+
106
106
+
ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
107
107
+
{
108
108
+
struct inode *inode = d_inode(entry);
109
109
+
struct fuse_conn *fc = get_fuse_conn(inode);
110
110
+
FUSE_ARGS(args);
111
111
+
struct fuse_getxattr_in inarg;
112
112
+
struct fuse_getxattr_out outarg;
113
113
+
ssize_t ret;
114
114
+
115
115
+
if (!fuse_allow_current_process(fc))
116
116
+
return -EACCES;
117
117
+
118
118
+
if (fc->no_listxattr)
119
119
+
return -EOPNOTSUPP;
120
120
+
121
121
+
memset(&inarg, 0, sizeof(inarg));
122
122
+
inarg.size = size;
123
123
+
args.in.h.opcode = FUSE_LISTXATTR;
124
124
+
args.in.h.nodeid = get_node_id(inode);
125
125
+
args.in.numargs = 1;
126
126
+
args.in.args[0].size = sizeof(inarg);
127
127
+
args.in.args[0].value = &inarg;
128
128
+
/* This is really two different operations rolled into one */
129
129
+
args.out.numargs = 1;
130
130
+
if (size) {
131
131
+
args.out.argvar = 1;
132
132
+
args.out.args[0].size = size;
133
133
+
args.out.args[0].value = list;
134
134
+
} else {
135
135
+
args.out.args[0].size = sizeof(outarg);
136
136
+
args.out.args[0].value = &outarg;
137
137
+
}
138
138
+
ret = fuse_simple_request(fc, &args);
139
139
+
if (!ret && !size)
140
140
+
ret = outarg.size;
141
141
+
if (ret > 0 && size)
142
142
+
ret = fuse_verify_xattr_list(list, ret);
143
143
+
if (ret == -ENOSYS) {
144
144
+
fc->no_listxattr = 1;
145
145
+
ret = -EOPNOTSUPP;
146
146
+
}
147
147
+
return ret;
148
148
+
}
149
149
+
150
150
+
static int fuse_removexattr(struct inode *inode, const char *name)
151
151
+
{
152
152
+
struct fuse_conn *fc = get_fuse_conn(inode);
153
153
+
FUSE_ARGS(args);
154
154
+
int err;
155
155
+
156
156
+
if (fc->no_removexattr)
157
157
+
return -EOPNOTSUPP;
158
158
+
159
159
+
args.in.h.opcode = FUSE_REMOVEXATTR;
160
160
+
args.in.h.nodeid = get_node_id(inode);
161
161
+
args.in.numargs = 1;
162
162
+
args.in.args[0].size = strlen(name) + 1;
163
163
+
args.in.args[0].value = name;
164
164
+
err = fuse_simple_request(fc, &args);
165
165
+
if (err == -ENOSYS) {
166
166
+
fc->no_removexattr = 1;
167
167
+
err = -EOPNOTSUPP;
168
168
+
}
169
169
+
if (!err) {
170
170
+
fuse_invalidate_attr(inode);
171
171
+
fuse_update_ctime(inode);
172
172
+
}
173
173
+
return err;
174
174
+
}
175
175
+
176
176
+
static int fuse_xattr_get(const struct xattr_handler *handler,
177
177
+
struct dentry *dentry, struct inode *inode,
178
178
+
const char *name, void *value, size_t size)
179
179
+
{
180
180
+
return fuse_getxattr(inode, name, value, size);
181
181
+
}
182
182
+
183
183
+
static int fuse_xattr_set(const struct xattr_handler *handler,
184
184
+
struct dentry *dentry, struct inode *inode,
185
185
+
const char *name, const void *value, size_t size,
186
186
+
int flags)
187
187
+
{
188
188
+
if (!value)
189
189
+
return fuse_removexattr(inode, name);
190
190
+
191
191
+
return fuse_setxattr(inode, name, value, size, flags);
192
192
+
}
193
193
+
194
194
+
static const struct xattr_handler fuse_xattr_handler = {
195
195
+
.prefix = "",
196
196
+
.get = fuse_xattr_get,
197
197
+
.set = fuse_xattr_set,
198
198
+
};
199
199
+
200
200
+
const struct xattr_handler *fuse_xattr_handlers[] = {
201
201
+
&fuse_xattr_handler,
202
202
+
NULL
203
203
+
};