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