]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blob - fs/afs/xattr.c
Merge branch 'for-v5.6' of git://git.kernel.org:/pub/scm/linux/kernel/git/jmorris...
[mirror_ubuntu-jammy-kernel.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 };