Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / fs / afs / xattr.c
1 /* Extended attribute handling for AFS.  We use xattrs to get and set metadata
2  * instead of providing pioctl().
3  *
4  * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
5  * Written by David Howells (dhowells@redhat.com)
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public Licence
9  * as published by the Free Software Foundation; either version
10  * 2 of the Licence, or (at your option) any later version.
11  */
12
13 #include <linux/slab.h>
14 #include <linux/fs.h>
15 #include <linux/xattr.h>
16 #include "internal.h"
17
18 static const char afs_xattr_list[] =
19         "afs.acl\0"
20         "afs.cell\0"
21         "afs.fid\0"
22         "afs.volume\0"
23         "afs.yfs.acl\0"
24         "afs.yfs.acl_inherited\0"
25         "afs.yfs.acl_num_cleaned\0"
26         "afs.yfs.vol_acl";
27
28 /*
29  * Retrieve a list of the supported xattrs.
30  */
31 ssize_t afs_listxattr(struct dentry *dentry, char *buffer, size_t size)
32 {
33         if (size == 0)
34                 return sizeof(afs_xattr_list);
35         if (size < sizeof(afs_xattr_list))
36                 return -ERANGE;
37         memcpy(buffer, afs_xattr_list, sizeof(afs_xattr_list));
38         return sizeof(afs_xattr_list);
39 }
40
41 /*
42  * Get a file's ACL.
43  */
44 static int afs_xattr_get_acl(const struct xattr_handler *handler,
45                              struct dentry *dentry,
46                              struct inode *inode, const char *name,
47                              void *buffer, size_t size)
48 {
49         struct afs_fs_cursor fc;
50         struct afs_status_cb *scb;
51         struct afs_vnode *vnode = AFS_FS_I(inode);
52         struct afs_acl *acl = NULL;
53         struct key *key;
54         int ret = -ENOMEM;
55
56         scb = kzalloc(sizeof(struct afs_status_cb), GFP_NOFS);
57         if (!scb)
58                 goto error;
59
60         key = afs_request_key(vnode->volume->cell);
61         if (IS_ERR(key)) {
62                 ret = PTR_ERR(key);
63                 goto error_scb;
64         }
65
66         ret = -ERESTARTSYS;
67         if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
68                 afs_dataversion_t data_version = vnode->status.data_version;
69
70                 while (afs_select_fileserver(&fc)) {
71                         fc.cb_break = afs_calc_vnode_cb_break(vnode);
72                         acl = afs_fs_fetch_acl(&fc, scb);
73                 }
74
75                 afs_check_for_remote_deletion(&fc, fc.vnode);
76                 afs_vnode_commit_status(&fc, vnode, fc.cb_break,
77                                         &data_version, scb);
78                 ret = afs_end_vnode_operation(&fc);
79         }
80
81         if (ret == 0) {
82                 ret = acl->size;
83                 if (size > 0) {
84                         if (acl->size <= size)
85                                 memcpy(buffer, acl->data, acl->size);
86                         else
87                                 ret = -ERANGE;
88                 }
89                 kfree(acl);
90         }
91
92         key_put(key);
93 error_scb:
94         kfree(scb);
95 error:
96         return ret;
97 }
98
99 /*
100  * Set a file's AFS3 ACL.
101  */
102 static int afs_xattr_set_acl(const struct xattr_handler *handler,
103                              struct dentry *dentry,
104                              struct inode *inode, const char *name,
105                              const void *buffer, size_t size, int flags)
106 {
107         struct afs_fs_cursor fc;
108         struct afs_status_cb *scb;
109         struct afs_vnode *vnode = AFS_FS_I(inode);
110         struct afs_acl *acl = NULL;
111         struct key *key;
112         int ret = -ENOMEM;
113
114         if (flags == XATTR_CREATE)
115                 return -EINVAL;
116
117         scb = kzalloc(sizeof(struct afs_status_cb), GFP_NOFS);
118         if (!scb)
119                 goto error;
120
121         acl = kmalloc(sizeof(*acl) + size, GFP_KERNEL);
122         if (!acl)
123                 goto error_scb;
124
125         key = afs_request_key(vnode->volume->cell);
126         if (IS_ERR(key)) {
127                 ret = PTR_ERR(key);
128                 goto error_acl;
129         }
130
131         acl->size = size;
132         memcpy(acl->data, buffer, size);
133
134         ret = -ERESTARTSYS;
135         if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
136                 afs_dataversion_t data_version = vnode->status.data_version;
137
138                 while (afs_select_fileserver(&fc)) {
139                         fc.cb_break = afs_calc_vnode_cb_break(vnode);
140                         afs_fs_store_acl(&fc, acl, scb);
141                 }
142
143                 afs_check_for_remote_deletion(&fc, fc.vnode);
144                 afs_vnode_commit_status(&fc, vnode, fc.cb_break,
145                                         &data_version, scb);
146                 ret = afs_end_vnode_operation(&fc);
147         }
148
149         key_put(key);
150 error_acl:
151         kfree(acl);
152 error_scb:
153         kfree(scb);
154 error:
155         return ret;
156 }
157
158 static const struct xattr_handler afs_xattr_afs_acl_handler = {
159         .name   = "afs.acl",
160         .get    = afs_xattr_get_acl,
161         .set    = afs_xattr_set_acl,
162 };
163
164 /*
165  * Get a file's YFS ACL.
166  */
167 static int afs_xattr_get_yfs(const struct xattr_handler *handler,
168                              struct dentry *dentry,
169                              struct inode *inode, const char *name,
170                              void *buffer, size_t size)
171 {
172         struct afs_fs_cursor fc;
173         struct afs_status_cb *scb;
174         struct afs_vnode *vnode = AFS_FS_I(inode);
175         struct yfs_acl *yacl = NULL;
176         struct key *key;
177         char buf[16], *data;
178         int which = 0, dsize, ret = -ENOMEM;
179
180         if (strcmp(name, "acl") == 0)
181                 which = 0;
182         else if (strcmp(name, "acl_inherited") == 0)
183                 which = 1;
184         else if (strcmp(name, "acl_num_cleaned") == 0)
185                 which = 2;
186         else if (strcmp(name, "vol_acl") == 0)
187                 which = 3;
188         else
189                 return -EOPNOTSUPP;
190
191         yacl = kzalloc(sizeof(struct yfs_acl), GFP_KERNEL);
192         if (!yacl)
193                 goto error;
194
195         if (which == 0)
196                 yacl->flags |= YFS_ACL_WANT_ACL;
197         else if (which == 3)
198                 yacl->flags |= YFS_ACL_WANT_VOL_ACL;
199
200         scb = kzalloc(sizeof(struct afs_status_cb), GFP_NOFS);
201         if (!scb)
202                 goto error_yacl;
203
204         key = afs_request_key(vnode->volume->cell);
205         if (IS_ERR(key)) {
206                 ret = PTR_ERR(key);
207                 goto error_scb;
208         }
209
210         ret = -ERESTARTSYS;
211         if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
212                 afs_dataversion_t data_version = vnode->status.data_version;
213
214                 while (afs_select_fileserver(&fc)) {
215                         fc.cb_break = afs_calc_vnode_cb_break(vnode);
216                         yfs_fs_fetch_opaque_acl(&fc, yacl, scb);
217                 }
218
219                 afs_check_for_remote_deletion(&fc, fc.vnode);
220                 afs_vnode_commit_status(&fc, vnode, fc.cb_break,
221                                         &data_version, scb);
222                 ret = afs_end_vnode_operation(&fc);
223         }
224
225         if (ret < 0)
226                 goto error_key;
227
228         switch (which) {
229         case 0:
230                 data = yacl->acl->data;
231                 dsize = yacl->acl->size;
232                 break;
233         case 1:
234                 data = buf;
235                 dsize = snprintf(buf, sizeof(buf), "%u", yacl->inherit_flag);
236                 break;
237         case 2:
238                 data = buf;
239                 dsize = snprintf(buf, sizeof(buf), "%u", yacl->num_cleaned);
240                 break;
241         case 3:
242                 data = yacl->vol_acl->data;
243                 dsize = yacl->vol_acl->size;
244                 break;
245         default:
246                 ret = -EOPNOTSUPP;
247                 goto error_key;
248         }
249
250         ret = dsize;
251         if (size > 0) {
252                 if (dsize > size) {
253                         ret = -ERANGE;
254                         goto error_key;
255                 }
256                 memcpy(buffer, data, dsize);
257         }
258
259 error_key:
260         key_put(key);
261 error_scb:
262         kfree(scb);
263 error_yacl:
264         yfs_free_opaque_acl(yacl);
265 error:
266         return ret;
267 }
268
269 /*
270  * Set a file's YFS ACL.
271  */
272 static int afs_xattr_set_yfs(const struct xattr_handler *handler,
273                              struct dentry *dentry,
274                              struct inode *inode, const char *name,
275                              const void *buffer, size_t size, int flags)
276 {
277         struct afs_fs_cursor fc;
278         struct afs_status_cb *scb;
279         struct afs_vnode *vnode = AFS_FS_I(inode);
280         struct afs_acl *acl = NULL;
281         struct key *key;
282         int ret = -ENOMEM;
283
284         if (flags == XATTR_CREATE ||
285             strcmp(name, "acl") != 0)
286                 return -EINVAL;
287
288         scb = kzalloc(sizeof(struct afs_status_cb), GFP_NOFS);
289         if (!scb)
290                 goto error;
291
292         acl = kmalloc(sizeof(*acl) + size, GFP_KERNEL);
293         if (!acl)
294                 goto error_scb;
295
296         acl->size = size;
297         memcpy(acl->data, buffer, size);
298
299         key = afs_request_key(vnode->volume->cell);
300         if (IS_ERR(key)) {
301                 ret = PTR_ERR(key);
302                 goto error_acl;
303         }
304
305         ret = -ERESTARTSYS;
306         if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
307                 afs_dataversion_t data_version = vnode->status.data_version;
308
309                 while (afs_select_fileserver(&fc)) {
310                         fc.cb_break = afs_calc_vnode_cb_break(vnode);
311                         yfs_fs_store_opaque_acl2(&fc, acl, scb);
312                 }
313
314                 afs_check_for_remote_deletion(&fc, fc.vnode);
315                 afs_vnode_commit_status(&fc, vnode, fc.cb_break,
316                                         &data_version, scb);
317                 ret = afs_end_vnode_operation(&fc);
318         }
319
320 error_acl:
321         kfree(acl);
322         key_put(key);
323 error_scb:
324         kfree(scb);
325 error:
326         return ret;
327 }
328
329 static const struct xattr_handler afs_xattr_yfs_handler = {
330         .prefix = "afs.yfs.",
331         .get    = afs_xattr_get_yfs,
332         .set    = afs_xattr_set_yfs,
333 };
334
335 /*
336  * Get the name of the cell on which a file resides.
337  */
338 static int afs_xattr_get_cell(const struct xattr_handler *handler,
339                               struct dentry *dentry,
340                               struct inode *inode, const char *name,
341                               void *buffer, size_t size)
342 {
343         struct afs_vnode *vnode = AFS_FS_I(inode);
344         struct afs_cell *cell = vnode->volume->cell;
345         size_t namelen;
346
347         namelen = cell->name_len;
348         if (size == 0)
349                 return namelen;
350         if (namelen > size)
351                 return -ERANGE;
352         memcpy(buffer, cell->name, namelen);
353         return namelen;
354 }
355
356 static const struct xattr_handler afs_xattr_afs_cell_handler = {
357         .name   = "afs.cell",
358         .get    = afs_xattr_get_cell,
359 };
360
361 /*
362  * Get the volume ID, vnode ID and vnode uniquifier of a file as a sequence of
363  * hex numbers separated by colons.
364  */
365 static int afs_xattr_get_fid(const struct xattr_handler *handler,
366                              struct dentry *dentry,
367                              struct inode *inode, const char *name,
368                              void *buffer, size_t size)
369 {
370         struct afs_vnode *vnode = AFS_FS_I(inode);
371         char text[16 + 1 + 24 + 1 + 8 + 1];
372         size_t len;
373
374         /* The volume ID is 64-bit, the vnode ID is 96-bit and the
375          * uniquifier is 32-bit.
376          */
377         len = sprintf(text, "%llx:", vnode->fid.vid);
378         if (vnode->fid.vnode_hi)
379                 len += sprintf(text + len, "%x%016llx",
380                                vnode->fid.vnode_hi, vnode->fid.vnode);
381         else
382                 len += sprintf(text + len, "%llx", vnode->fid.vnode);
383         len += sprintf(text + len, ":%x", vnode->fid.unique);
384
385         if (size == 0)
386                 return len;
387         if (len > size)
388                 return -ERANGE;
389         memcpy(buffer, text, len);
390         return len;
391 }
392
393 static const struct xattr_handler afs_xattr_afs_fid_handler = {
394         .name   = "afs.fid",
395         .get    = afs_xattr_get_fid,
396 };
397
398 /*
399  * Get the name of the volume on which a file resides.
400  */
401 static int afs_xattr_get_volume(const struct xattr_handler *handler,
402                               struct dentry *dentry,
403                               struct inode *inode, const char *name,
404                               void *buffer, size_t size)
405 {
406         struct afs_vnode *vnode = AFS_FS_I(inode);
407         const char *volname = vnode->volume->name;
408         size_t namelen;
409
410         namelen = strlen(volname);
411         if (size == 0)
412                 return namelen;
413         if (namelen > size)
414                 return -ERANGE;
415         memcpy(buffer, volname, namelen);
416         return namelen;
417 }
418
419 static const struct xattr_handler afs_xattr_afs_volume_handler = {
420         .name   = "afs.volume",
421         .get    = afs_xattr_get_volume,
422 };
423
424 const struct xattr_handler *afs_xattr_handlers[] = {
425         &afs_xattr_afs_acl_handler,
426         &afs_xattr_afs_cell_handler,
427         &afs_xattr_afs_fid_handler,
428         &afs_xattr_afs_volume_handler,
429         &afs_xattr_yfs_handler,         /* afs.yfs. prefix */
430         NULL
431 };