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