Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/fs/afs/xattr.c
26278 views
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 ([email protected])
7
*/
8
9
#include <linux/slab.h>
10
#include <linux/fs.h>
11
#include <linux/xattr.h>
12
#include "internal.h"
13
14
/*
15
* Deal with the result of a successful fetch ACL operation.
16
*/
17
static void afs_acl_success(struct afs_operation *op)
18
{
19
afs_vnode_commit_status(op, &op->file[0]);
20
}
21
22
static void afs_acl_put(struct afs_operation *op)
23
{
24
kfree(op->acl);
25
}
26
27
static const struct afs_operation_ops afs_fetch_acl_operation = {
28
.issue_afs_rpc = afs_fs_fetch_acl,
29
.success = afs_acl_success,
30
.put = afs_acl_put,
31
};
32
33
/*
34
* Get a file's ACL.
35
*/
36
static int afs_xattr_get_acl(const struct xattr_handler *handler,
37
struct dentry *dentry,
38
struct inode *inode, const char *name,
39
void *buffer, size_t size)
40
{
41
struct afs_operation *op;
42
struct afs_vnode *vnode = AFS_FS_I(inode);
43
struct afs_acl *acl = NULL;
44
int ret;
45
46
op = afs_alloc_operation(NULL, vnode->volume);
47
if (IS_ERR(op))
48
return -ENOMEM;
49
50
afs_op_set_vnode(op, 0, vnode);
51
op->ops = &afs_fetch_acl_operation;
52
53
afs_begin_vnode_operation(op);
54
afs_wait_for_operation(op);
55
acl = op->acl;
56
op->acl = NULL;
57
ret = afs_put_operation(op);
58
59
if (ret == 0) {
60
ret = acl->size;
61
if (size > 0) {
62
if (acl->size <= size)
63
memcpy(buffer, acl->data, acl->size);
64
else
65
ret = -ERANGE;
66
}
67
}
68
69
kfree(acl);
70
return ret;
71
}
72
73
static bool afs_make_acl(struct afs_operation *op,
74
const void *buffer, size_t size)
75
{
76
struct afs_acl *acl;
77
78
acl = kmalloc(struct_size(acl, data, size), GFP_KERNEL);
79
if (!acl) {
80
afs_op_nomem(op);
81
return false;
82
}
83
84
acl->size = size;
85
memcpy(acl->data, buffer, size);
86
op->acl = acl;
87
return true;
88
}
89
90
static const struct afs_operation_ops afs_store_acl_operation = {
91
.issue_afs_rpc = afs_fs_store_acl,
92
.success = afs_acl_success,
93
.put = afs_acl_put,
94
};
95
96
/*
97
* Set a file's AFS3 ACL.
98
*/
99
static int afs_xattr_set_acl(const struct xattr_handler *handler,
100
struct mnt_idmap *idmap,
101
struct dentry *dentry,
102
struct inode *inode, const char *name,
103
const void *buffer, size_t size, int flags)
104
{
105
struct afs_operation *op;
106
struct afs_vnode *vnode = AFS_FS_I(inode);
107
108
if (flags == XATTR_CREATE)
109
return -EINVAL;
110
111
op = afs_alloc_operation(NULL, vnode->volume);
112
if (IS_ERR(op))
113
return -ENOMEM;
114
115
afs_op_set_vnode(op, 0, vnode);
116
if (!afs_make_acl(op, buffer, size))
117
return afs_put_operation(op);
118
119
op->ops = &afs_store_acl_operation;
120
return afs_do_sync_operation(op);
121
}
122
123
static const struct xattr_handler afs_xattr_afs_acl_handler = {
124
.name = "afs.acl",
125
.get = afs_xattr_get_acl,
126
.set = afs_xattr_set_acl,
127
};
128
129
static const struct afs_operation_ops yfs_fetch_opaque_acl_operation = {
130
.issue_yfs_rpc = yfs_fs_fetch_opaque_acl,
131
.success = afs_acl_success,
132
/* Don't free op->yacl in .put here */
133
};
134
135
/*
136
* Get a file's YFS ACL.
137
*/
138
static int afs_xattr_get_yfs(const struct xattr_handler *handler,
139
struct dentry *dentry,
140
struct inode *inode, const char *name,
141
void *buffer, size_t size)
142
{
143
struct afs_operation *op;
144
struct afs_vnode *vnode = AFS_FS_I(inode);
145
struct yfs_acl *yacl = NULL;
146
char buf[16], *data;
147
int which = 0, dsize, ret = -ENOMEM;
148
149
if (strcmp(name, "acl") == 0)
150
which = 0;
151
else if (strcmp(name, "acl_inherited") == 0)
152
which = 1;
153
else if (strcmp(name, "acl_num_cleaned") == 0)
154
which = 2;
155
else if (strcmp(name, "vol_acl") == 0)
156
which = 3;
157
else
158
return -EOPNOTSUPP;
159
160
yacl = kzalloc(sizeof(struct yfs_acl), GFP_KERNEL);
161
if (!yacl)
162
goto error;
163
164
if (which == 0)
165
yacl->flags |= YFS_ACL_WANT_ACL;
166
else if (which == 3)
167
yacl->flags |= YFS_ACL_WANT_VOL_ACL;
168
169
op = afs_alloc_operation(NULL, vnode->volume);
170
if (IS_ERR(op))
171
goto error_yacl;
172
173
afs_op_set_vnode(op, 0, vnode);
174
op->yacl = yacl;
175
op->ops = &yfs_fetch_opaque_acl_operation;
176
177
afs_begin_vnode_operation(op);
178
afs_wait_for_operation(op);
179
ret = afs_put_operation(op);
180
181
if (ret == 0) {
182
switch (which) {
183
case 0:
184
data = yacl->acl->data;
185
dsize = yacl->acl->size;
186
break;
187
case 1:
188
data = buf;
189
dsize = scnprintf(buf, sizeof(buf), "%u", yacl->inherit_flag);
190
break;
191
case 2:
192
data = buf;
193
dsize = scnprintf(buf, sizeof(buf), "%u", yacl->num_cleaned);
194
break;
195
case 3:
196
data = yacl->vol_acl->data;
197
dsize = yacl->vol_acl->size;
198
break;
199
default:
200
ret = -EOPNOTSUPP;
201
goto error_yacl;
202
}
203
204
ret = dsize;
205
if (size > 0) {
206
if (dsize <= size)
207
memcpy(buffer, data, dsize);
208
else
209
ret = -ERANGE;
210
}
211
} else if (ret == -ENOTSUPP) {
212
ret = -ENODATA;
213
}
214
215
error_yacl:
216
yfs_free_opaque_acl(yacl);
217
error:
218
return ret;
219
}
220
221
static const struct afs_operation_ops yfs_store_opaque_acl2_operation = {
222
.issue_yfs_rpc = yfs_fs_store_opaque_acl2,
223
.success = afs_acl_success,
224
.put = afs_acl_put,
225
};
226
227
/*
228
* Set a file's YFS ACL.
229
*/
230
static int afs_xattr_set_yfs(const struct xattr_handler *handler,
231
struct mnt_idmap *idmap,
232
struct dentry *dentry,
233
struct inode *inode, const char *name,
234
const void *buffer, size_t size, int flags)
235
{
236
struct afs_operation *op;
237
struct afs_vnode *vnode = AFS_FS_I(inode);
238
int ret;
239
240
if (flags == XATTR_CREATE ||
241
strcmp(name, "acl") != 0)
242
return -EINVAL;
243
244
op = afs_alloc_operation(NULL, vnode->volume);
245
if (IS_ERR(op))
246
return -ENOMEM;
247
248
afs_op_set_vnode(op, 0, vnode);
249
if (!afs_make_acl(op, buffer, size))
250
return afs_put_operation(op);
251
252
op->ops = &yfs_store_opaque_acl2_operation;
253
ret = afs_do_sync_operation(op);
254
if (ret == -ENOTSUPP)
255
ret = -ENODATA;
256
return ret;
257
}
258
259
static const struct xattr_handler afs_xattr_yfs_handler = {
260
.prefix = "afs.yfs.",
261
.get = afs_xattr_get_yfs,
262
.set = afs_xattr_set_yfs,
263
};
264
265
/*
266
* Get the name of the cell on which a file resides.
267
*/
268
static int afs_xattr_get_cell(const struct xattr_handler *handler,
269
struct dentry *dentry,
270
struct inode *inode, const char *name,
271
void *buffer, size_t size)
272
{
273
struct afs_vnode *vnode = AFS_FS_I(inode);
274
struct afs_cell *cell = vnode->volume->cell;
275
size_t namelen;
276
277
namelen = cell->name_len;
278
if (size == 0)
279
return namelen;
280
if (namelen > size)
281
return -ERANGE;
282
memcpy(buffer, cell->name, namelen);
283
return namelen;
284
}
285
286
static const struct xattr_handler afs_xattr_afs_cell_handler = {
287
.name = "afs.cell",
288
.get = afs_xattr_get_cell,
289
};
290
291
/*
292
* Get the volume ID, vnode ID and vnode uniquifier of a file as a sequence of
293
* hex numbers separated by colons.
294
*/
295
static int afs_xattr_get_fid(const struct xattr_handler *handler,
296
struct dentry *dentry,
297
struct inode *inode, const char *name,
298
void *buffer, size_t size)
299
{
300
struct afs_vnode *vnode = AFS_FS_I(inode);
301
char text[16 + 1 + 24 + 1 + 8 + 1];
302
size_t len;
303
304
/* The volume ID is 64-bit, the vnode ID is 96-bit and the
305
* uniquifier is 32-bit.
306
*/
307
len = scnprintf(text, sizeof(text), "%llx:", vnode->fid.vid);
308
if (vnode->fid.vnode_hi)
309
len += scnprintf(text + len, sizeof(text) - len, "%x%016llx",
310
vnode->fid.vnode_hi, vnode->fid.vnode);
311
else
312
len += scnprintf(text + len, sizeof(text) - len, "%llx",
313
vnode->fid.vnode);
314
len += scnprintf(text + len, sizeof(text) - len, ":%x",
315
vnode->fid.unique);
316
317
if (size == 0)
318
return len;
319
if (len > size)
320
return -ERANGE;
321
memcpy(buffer, text, len);
322
return len;
323
}
324
325
static const struct xattr_handler afs_xattr_afs_fid_handler = {
326
.name = "afs.fid",
327
.get = afs_xattr_get_fid,
328
};
329
330
/*
331
* Get the name of the volume on which a file resides.
332
*/
333
static int afs_xattr_get_volume(const struct xattr_handler *handler,
334
struct dentry *dentry,
335
struct inode *inode, const char *name,
336
void *buffer, size_t size)
337
{
338
struct afs_vnode *vnode = AFS_FS_I(inode);
339
const char *volname = vnode->volume->name;
340
size_t namelen;
341
342
namelen = strlen(volname);
343
if (size == 0)
344
return namelen;
345
if (namelen > size)
346
return -ERANGE;
347
memcpy(buffer, volname, namelen);
348
return namelen;
349
}
350
351
static const struct xattr_handler afs_xattr_afs_volume_handler = {
352
.name = "afs.volume",
353
.get = afs_xattr_get_volume,
354
};
355
356
const struct xattr_handler * const afs_xattr_handlers[] = {
357
&afs_xattr_afs_acl_handler,
358
&afs_xattr_afs_cell_handler,
359
&afs_xattr_afs_fid_handler,
360
&afs_xattr_afs_volume_handler,
361
&afs_xattr_yfs_handler, /* afs.yfs. prefix */
362
NULL
363
};
364
365