]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blame - fs/aufs/xattr.c
Revert "UBUNTU: SAUCE: aufs -- Convert to use xattr handlers"
[mirror_ubuntu-zesty-kernel.git] / fs / aufs / xattr.c
CommitLineData
5b88fdd9
SF
1/*
2 * Copyright (C) 2014-2016 Junjiro R. Okajima
3 *
4 * This program, aufs is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18/*
19 * handling xattr functions
20 */
21
22#include <linux/xattr.h>
23#include "aufs.h"
24
25static int au_xattr_ignore(int err, char *name, unsigned int ignore_flags)
26{
27 if (!ignore_flags)
28 goto out;
29 switch (err) {
30 case -ENOMEM:
31 case -EDQUOT:
32 goto out;
33 }
34
35 if ((ignore_flags & AuBrAttr_ICEX) == AuBrAttr_ICEX) {
36 err = 0;
37 goto out;
38 }
39
40#define cmp(brattr, prefix) do { \
41 if (!strncmp(name, XATTR_##prefix##_PREFIX, \
42 XATTR_##prefix##_PREFIX_LEN)) { \
43 if (ignore_flags & AuBrAttr_ICEX_##brattr) \
44 err = 0; \
45 goto out; \
46 } \
47 } while (0)
48
49 cmp(SEC, SECURITY);
50 cmp(SYS, SYSTEM);
51 cmp(TR, TRUSTED);
52 cmp(USR, USER);
53#undef cmp
54
55 if (ignore_flags & AuBrAttr_ICEX_OTH)
56 err = 0;
57
58out:
59 return err;
60}
61
62static const int au_xattr_out_of_list = AuBrAttr_ICEX_OTH << 1;
63
64static int au_do_cpup_xattr(struct dentry *h_dst, struct dentry *h_src,
65 char *name, char **buf, unsigned int ignore_flags,
66 unsigned int verbose)
67{
68 int err;
69 ssize_t ssz;
70 struct inode *h_idst;
71
72 ssz = vfs_getxattr_alloc(h_src, name, buf, 0, GFP_NOFS);
73 err = ssz;
74 if (unlikely(err <= 0)) {
75 if (err == -ENODATA
76 || (err == -EOPNOTSUPP
77 && ((ignore_flags & au_xattr_out_of_list)
78 || (au_test_nfs_noacl(d_inode(h_src))
79 && (!strcmp(name, XATTR_NAME_POSIX_ACL_ACCESS)
80 || !strcmp(name,
81 XATTR_NAME_POSIX_ACL_DEFAULT))))
82 ))
83 err = 0;
84 if (err && (verbose || au_debug_test()))
85 pr_err("%s, err %d\n", name, err);
86 goto out;
87 }
88
89 /* unlock it temporary */
90 h_idst = d_inode(h_dst);
91 inode_unlock(h_idst);
92 err = vfsub_setxattr(h_dst, name, *buf, ssz, /*flags*/0);
93 inode_lock_nested(h_idst, AuLsc_I_CHILD2);
94 if (unlikely(err)) {
95 if (verbose || au_debug_test())
96 pr_err("%s, err %d\n", name, err);
97 err = au_xattr_ignore(err, name, ignore_flags);
98 }
99
100out:
101 return err;
102}
103
104int au_cpup_xattr(struct dentry *h_dst, struct dentry *h_src, int ignore_flags,
105 unsigned int verbose)
106{
107 int err, unlocked, acl_access, acl_default;
108 ssize_t ssz;
109 struct inode *h_isrc, *h_idst;
110 char *value, *p, *o, *e;
111
112 /* try stopping to update the source inode while we are referencing */
113 /* there should not be the parent-child relationship between them */
114 h_isrc = d_inode(h_src);
115 h_idst = d_inode(h_dst);
116 inode_unlock(h_idst);
117 inode_lock_nested(h_isrc, AuLsc_I_CHILD);
118 inode_lock_nested(h_idst, AuLsc_I_CHILD2);
119 unlocked = 0;
120
121 /* some filesystems don't list POSIX ACL, for example tmpfs */
122 ssz = vfs_listxattr(h_src, NULL, 0);
123 err = ssz;
124 if (unlikely(err < 0)) {
125 AuTraceErr(err);
126 if (err == -ENODATA
127 || err == -EOPNOTSUPP)
128 err = 0; /* ignore */
129 goto out;
130 }
131
132 err = 0;
133 p = NULL;
134 o = NULL;
135 if (ssz) {
136 err = -ENOMEM;
137 p = kmalloc(ssz, GFP_NOFS);
138 o = p;
139 if (unlikely(!p))
140 goto out;
141 err = vfs_listxattr(h_src, p, ssz);
142 }
143 inode_unlock(h_isrc);
144 unlocked = 1;
145 AuDbg("err %d, ssz %zd\n", err, ssz);
146 if (unlikely(err < 0))
147 goto out_free;
148
149 err = 0;
150 e = p + ssz;
151 value = NULL;
152 acl_access = 0;
153 acl_default = 0;
154 while (!err && p < e) {
155 acl_access |= !strncmp(p, XATTR_NAME_POSIX_ACL_ACCESS,
156 sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1);
157 acl_default |= !strncmp(p, XATTR_NAME_POSIX_ACL_DEFAULT,
158 sizeof(XATTR_NAME_POSIX_ACL_DEFAULT)
159 - 1);
160 err = au_do_cpup_xattr(h_dst, h_src, p, &value, ignore_flags,
161 verbose);
162 p += strlen(p) + 1;
163 }
164 AuTraceErr(err);
165 ignore_flags |= au_xattr_out_of_list;
166 if (!err && !acl_access) {
167 err = au_do_cpup_xattr(h_dst, h_src,
168 XATTR_NAME_POSIX_ACL_ACCESS, &value,
169 ignore_flags, verbose);
170 AuTraceErr(err);
171 }
172 if (!err && !acl_default) {
173 err = au_do_cpup_xattr(h_dst, h_src,
174 XATTR_NAME_POSIX_ACL_DEFAULT, &value,
175 ignore_flags, verbose);
176 AuTraceErr(err);
177 }
178
179 if (value)
180 au_delayed_kfree(value);
181
182out_free:
183 if (o)
184 au_delayed_kfree(o);
185out:
186 if (!unlocked)
187 inode_unlock(h_isrc);
188 AuTraceErr(err);
189 return err;
190}
191
192/* ---------------------------------------------------------------------- */
193
194enum {
195 AU_XATTR_LIST,
196 AU_XATTR_GET
197};
198
199struct au_lgxattr {
200 int type;
201 union {
202 struct {
203 char *list;
204 size_t size;
205 } list;
206 struct {
207 const char *name;
208 void *value;
209 size_t size;
210 } get;
211 } u;
212};
213
214static ssize_t au_lgxattr(struct dentry *dentry, struct au_lgxattr *arg)
215{
216 ssize_t err;
217 struct path h_path;
218 struct super_block *sb;
219
220 sb = dentry->d_sb;
221 err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM);
222 if (unlikely(err))
223 goto out;
224 err = au_h_path_getattr(dentry, /*force*/1, &h_path);
225 if (unlikely(err))
226 goto out_si;
227 if (unlikely(!h_path.dentry))
228 /* illegally overlapped or something */
229 goto out_di; /* pretending success */
230
231 /* always topmost entry only */
232 switch (arg->type) {
233 case AU_XATTR_LIST:
234 err = vfs_listxattr(h_path.dentry,
235 arg->u.list.list, arg->u.list.size);
236 break;
237 case AU_XATTR_GET:
238 AuDebugOn(d_is_negative(h_path.dentry));
239 err = vfs_getxattr(h_path.dentry,
240 arg->u.get.name, arg->u.get.value,
241 arg->u.get.size);
242 break;
243 }
244
245out_di:
246 di_read_unlock(dentry, AuLock_IR);
247out_si:
248 si_read_unlock(sb);
249out:
250 AuTraceErr(err);
251 return err;
252}
253
254ssize_t aufs_listxattr(struct dentry *dentry, char *list, size_t size)
255{
256 struct au_lgxattr arg = {
257 .type = AU_XATTR_LIST,
258 .u.list = {
259 .list = list,
260 .size = size
261 },
262 };
263
264 return au_lgxattr(dentry, &arg);
265}
266
b7ca57c6
SF
267ssize_t aufs_getxattr(struct dentry *dentry, struct inode *inode __maybe_unused,
268 const char *name, void *value, size_t size)
5b88fdd9
SF
269{
270 struct au_lgxattr arg = {
271 .type = AU_XATTR_GET,
272 .u.get = {
273 .name = name,
274 .value = value,
275 .size = size
276 },
277 };
278
279 return au_lgxattr(dentry, &arg);
280}
281
b7ca57c6
SF
282int aufs_setxattr(struct dentry *dentry, struct inode *inode, const char *name,
283 const void *value, size_t size, int flags)
5b88fdd9
SF
284{
285 struct au_srxattr arg = {
286 .type = AU_XATTR_SET,
287 .u.set = {
288 .name = name,
289 .value = value,
290 .size = size,
291 .flags = flags
292 },
293 };
294
295 return au_srxattr(dentry, inode, &arg);
296}
297
b7ca57c6 298int aufs_removexattr(struct dentry *dentry, const char *name)
5b88fdd9
SF
299{
300 struct au_srxattr arg = {
301 .type = AU_XATTR_REMOVE,
302 .u.remove = {
303 .name = name
304 },
305 };
306
307 return au_srxattr(dentry, d_inode(dentry), &arg);
308}
309
b7ca57c6
SF
310/* ---------------------------------------------------------------------- */
311
312#if 0
313static size_t au_xattr_list(struct dentry *dentry, char *list, size_t list_size,
314 const char *name, size_t name_len, int type)
5b88fdd9 315{
b7ca57c6 316 return aufs_listxattr(dentry, list, list_size);
5b88fdd9
SF
317}
318
b7ca57c6
SF
319static int au_xattr_get(struct dentry *dentry, const char *name, void *buffer,
320 size_t size, int type)
5b88fdd9 321{
b7ca57c6
SF
322 return aufs_getxattr(dentry, name, buffer, size);
323}
324
325static int au_xattr_set(struct dentry *dentry, const char *name,
326 const void *value, size_t size, int flags, int type)
327{
328 return aufs_setxattr(dentry, name, value, size, flags);
5b88fdd9
SF
329}
330
331static const struct xattr_handler au_xattr_handler = {
b7ca57c6
SF
332 /* no prefix, no flags */
333 .list = au_xattr_list,
334 .get = au_xattr_get,
335 .set = au_xattr_set
336 /* why no remove? */
5b88fdd9
SF
337};
338
339static const struct xattr_handler *au_xattr_handlers[] = {
b7ca57c6 340 &au_xattr_handler
5b88fdd9
SF
341};
342
343void au_xattr_init(struct super_block *sb)
344{
b7ca57c6 345 /* sb->s_xattr = au_xattr_handlers; */
5b88fdd9 346}
b7ca57c6 347#endif