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