xref: /openbmc/linux/fs/afs/xattr.c (revision b10494af4989d2d20679d0e3b7d1a45c2f8f8f1a)
1d3e3b7eaSDavid Howells /* Extended attribute handling for AFS.  We use xattrs to get and set metadata
2d3e3b7eaSDavid Howells  * instead of providing pioctl().
3d3e3b7eaSDavid Howells  *
4d3e3b7eaSDavid Howells  * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
5d3e3b7eaSDavid Howells  * Written by David Howells (dhowells@redhat.com)
6d3e3b7eaSDavid Howells  *
7d3e3b7eaSDavid Howells  * This program is free software; you can redistribute it and/or
8d3e3b7eaSDavid Howells  * modify it under the terms of the GNU General Public Licence
9d3e3b7eaSDavid Howells  * as published by the Free Software Foundation; either version
10d3e3b7eaSDavid Howells  * 2 of the Licence, or (at your option) any later version.
11d3e3b7eaSDavid Howells  */
12d3e3b7eaSDavid Howells 
13d3e3b7eaSDavid Howells #include <linux/slab.h>
14d3e3b7eaSDavid Howells #include <linux/fs.h>
15d3e3b7eaSDavid Howells #include <linux/xattr.h>
16d3e3b7eaSDavid Howells #include "internal.h"
17d3e3b7eaSDavid Howells 
18d3e3b7eaSDavid Howells static const char afs_xattr_list[] =
19260f082bSDavid Howells 	"afs.acl\0"
20d3e3b7eaSDavid Howells 	"afs.cell\0"
21d3e3b7eaSDavid Howells 	"afs.fid\0"
22d3e3b7eaSDavid Howells 	"afs.volume";
23d3e3b7eaSDavid Howells 
24d3e3b7eaSDavid Howells /*
25d3e3b7eaSDavid Howells  * Retrieve a list of the supported xattrs.
26d3e3b7eaSDavid Howells  */
27d3e3b7eaSDavid Howells ssize_t afs_listxattr(struct dentry *dentry, char *buffer, size_t size)
28d3e3b7eaSDavid Howells {
29d3e3b7eaSDavid Howells 	if (size == 0)
30d3e3b7eaSDavid Howells 		return sizeof(afs_xattr_list);
31d3e3b7eaSDavid Howells 	if (size < sizeof(afs_xattr_list))
32d3e3b7eaSDavid Howells 		return -ERANGE;
33d3e3b7eaSDavid Howells 	memcpy(buffer, afs_xattr_list, sizeof(afs_xattr_list));
34d3e3b7eaSDavid Howells 	return sizeof(afs_xattr_list);
35d3e3b7eaSDavid Howells }
36d3e3b7eaSDavid Howells 
37d3e3b7eaSDavid Howells /*
38260f082bSDavid Howells  * Get a file's ACL.
39260f082bSDavid Howells  */
40260f082bSDavid Howells static int afs_xattr_get_acl(const struct xattr_handler *handler,
41260f082bSDavid Howells 			     struct dentry *dentry,
42260f082bSDavid Howells 			     struct inode *inode, const char *name,
43260f082bSDavid Howells 			     void *buffer, size_t size)
44260f082bSDavid Howells {
45260f082bSDavid Howells 	struct afs_fs_cursor fc;
46260f082bSDavid Howells 	struct afs_vnode *vnode = AFS_FS_I(inode);
47260f082bSDavid Howells 	struct afs_acl *acl = NULL;
48260f082bSDavid Howells 	struct key *key;
49260f082bSDavid Howells 	int ret;
50260f082bSDavid Howells 
51260f082bSDavid Howells 	key = afs_request_key(vnode->volume->cell);
52260f082bSDavid Howells 	if (IS_ERR(key))
53260f082bSDavid Howells 		return PTR_ERR(key);
54260f082bSDavid Howells 
55260f082bSDavid Howells 	ret = -ERESTARTSYS;
56260f082bSDavid Howells 	if (afs_begin_vnode_operation(&fc, vnode, key)) {
57260f082bSDavid Howells 		while (afs_select_fileserver(&fc)) {
58260f082bSDavid Howells 			fc.cb_break = afs_calc_vnode_cb_break(vnode);
59260f082bSDavid Howells 			acl = afs_fs_fetch_acl(&fc);
60260f082bSDavid Howells 		}
61260f082bSDavid Howells 
62260f082bSDavid Howells 		afs_check_for_remote_deletion(&fc, fc.vnode);
63260f082bSDavid Howells 		afs_vnode_commit_status(&fc, vnode, fc.cb_break);
64260f082bSDavid Howells 		ret = afs_end_vnode_operation(&fc);
65260f082bSDavid Howells 	}
66260f082bSDavid Howells 
67260f082bSDavid Howells 	if (ret == 0) {
68260f082bSDavid Howells 		ret = acl->size;
69260f082bSDavid Howells 		if (size > 0) {
70260f082bSDavid Howells 			ret = -ERANGE;
71260f082bSDavid Howells 			if (acl->size > size)
72260f082bSDavid Howells 				return -ERANGE;
73260f082bSDavid Howells 			memcpy(buffer, acl->data, acl->size);
74260f082bSDavid Howells 			ret = acl->size;
75260f082bSDavid Howells 		}
76260f082bSDavid Howells 		kfree(acl);
77260f082bSDavid Howells 	}
78260f082bSDavid Howells 
79260f082bSDavid Howells 	key_put(key);
80260f082bSDavid Howells 	return ret;
81260f082bSDavid Howells }
82260f082bSDavid Howells 
83*b10494afSJoe Gorse /*
84*b10494afSJoe Gorse  * Set a file's AFS3 ACL.
85*b10494afSJoe Gorse  */
86*b10494afSJoe Gorse static int afs_xattr_set_acl(const struct xattr_handler *handler,
87*b10494afSJoe Gorse                              struct dentry *dentry,
88*b10494afSJoe Gorse                              struct inode *inode, const char *name,
89*b10494afSJoe Gorse                              const void *buffer, size_t size, int flags)
90*b10494afSJoe Gorse {
91*b10494afSJoe Gorse 	struct afs_fs_cursor fc;
92*b10494afSJoe Gorse 	struct afs_vnode *vnode = AFS_FS_I(inode);
93*b10494afSJoe Gorse 	struct afs_acl *acl = NULL;
94*b10494afSJoe Gorse 	struct key *key;
95*b10494afSJoe Gorse 	int ret;
96*b10494afSJoe Gorse 
97*b10494afSJoe Gorse 	if (flags == XATTR_CREATE)
98*b10494afSJoe Gorse 		return -EINVAL;
99*b10494afSJoe Gorse 
100*b10494afSJoe Gorse 	key = afs_request_key(vnode->volume->cell);
101*b10494afSJoe Gorse 	if (IS_ERR(key))
102*b10494afSJoe Gorse 		return PTR_ERR(key);
103*b10494afSJoe Gorse 
104*b10494afSJoe Gorse 	acl = kmalloc(sizeof(*acl) + size, GFP_KERNEL);
105*b10494afSJoe Gorse 	if (!acl) {
106*b10494afSJoe Gorse 		key_put(key);
107*b10494afSJoe Gorse 		return -ENOMEM;
108*b10494afSJoe Gorse 	}
109*b10494afSJoe Gorse 
110*b10494afSJoe Gorse 	acl->size = size;
111*b10494afSJoe Gorse 	memcpy(acl->data, buffer, size);
112*b10494afSJoe Gorse 
113*b10494afSJoe Gorse 	ret = -ERESTARTSYS;
114*b10494afSJoe Gorse 	if (afs_begin_vnode_operation(&fc, vnode, key)) {
115*b10494afSJoe Gorse 		while (afs_select_fileserver(&fc)) {
116*b10494afSJoe Gorse 			fc.cb_break = afs_calc_vnode_cb_break(vnode);
117*b10494afSJoe Gorse 			afs_fs_store_acl(&fc, acl);
118*b10494afSJoe Gorse 		}
119*b10494afSJoe Gorse 
120*b10494afSJoe Gorse 		afs_check_for_remote_deletion(&fc, fc.vnode);
121*b10494afSJoe Gorse 		afs_vnode_commit_status(&fc, vnode, fc.cb_break);
122*b10494afSJoe Gorse 		ret = afs_end_vnode_operation(&fc);
123*b10494afSJoe Gorse 	}
124*b10494afSJoe Gorse 
125*b10494afSJoe Gorse 	kfree(acl);
126*b10494afSJoe Gorse 	key_put(key);
127*b10494afSJoe Gorse 	return ret;
128*b10494afSJoe Gorse }
129*b10494afSJoe Gorse 
130260f082bSDavid Howells static const struct xattr_handler afs_xattr_afs_acl_handler = {
131260f082bSDavid Howells 	.name   = "afs.acl",
132260f082bSDavid Howells 	.get    = afs_xattr_get_acl,
133*b10494afSJoe Gorse 	.set    = afs_xattr_set_acl,
134260f082bSDavid Howells };
135260f082bSDavid Howells 
136260f082bSDavid Howells /*
137d3e3b7eaSDavid Howells  * Get the name of the cell on which a file resides.
138d3e3b7eaSDavid Howells  */
139d3e3b7eaSDavid Howells static int afs_xattr_get_cell(const struct xattr_handler *handler,
140d3e3b7eaSDavid Howells 			      struct dentry *dentry,
141d3e3b7eaSDavid Howells 			      struct inode *inode, const char *name,
142d3e3b7eaSDavid Howells 			      void *buffer, size_t size)
143d3e3b7eaSDavid Howells {
144d3e3b7eaSDavid Howells 	struct afs_vnode *vnode = AFS_FS_I(inode);
145d3e3b7eaSDavid Howells 	struct afs_cell *cell = vnode->volume->cell;
146d3e3b7eaSDavid Howells 	size_t namelen;
147d3e3b7eaSDavid Howells 
148989782dcSDavid Howells 	namelen = cell->name_len;
149d3e3b7eaSDavid Howells 	if (size == 0)
150d3e3b7eaSDavid Howells 		return namelen;
151d3e3b7eaSDavid Howells 	if (namelen > size)
152d3e3b7eaSDavid Howells 		return -ERANGE;
153c73aa410SDavid Howells 	memcpy(buffer, cell->name, namelen);
154d3e3b7eaSDavid Howells 	return namelen;
155d3e3b7eaSDavid Howells }
156d3e3b7eaSDavid Howells 
157d3e3b7eaSDavid Howells static const struct xattr_handler afs_xattr_afs_cell_handler = {
158d3e3b7eaSDavid Howells 	.name	= "afs.cell",
159d3e3b7eaSDavid Howells 	.get	= afs_xattr_get_cell,
160d3e3b7eaSDavid Howells };
161d3e3b7eaSDavid Howells 
162d3e3b7eaSDavid Howells /*
163d3e3b7eaSDavid Howells  * Get the volume ID, vnode ID and vnode uniquifier of a file as a sequence of
164d3e3b7eaSDavid Howells  * hex numbers separated by colons.
165d3e3b7eaSDavid Howells  */
166d3e3b7eaSDavid Howells static int afs_xattr_get_fid(const struct xattr_handler *handler,
167d3e3b7eaSDavid Howells 			     struct dentry *dentry,
168d3e3b7eaSDavid Howells 			     struct inode *inode, const char *name,
169d3e3b7eaSDavid Howells 			     void *buffer, size_t size)
170d3e3b7eaSDavid Howells {
171d3e3b7eaSDavid Howells 	struct afs_vnode *vnode = AFS_FS_I(inode);
172a2f611a3SDavid Howells 	char text[16 + 1 + 24 + 1 + 8 + 1];
173d3e3b7eaSDavid Howells 	size_t len;
174d3e3b7eaSDavid Howells 
175a2f611a3SDavid Howells 	/* The volume ID is 64-bit, the vnode ID is 96-bit and the
176a2f611a3SDavid Howells 	 * uniquifier is 32-bit.
177a2f611a3SDavid Howells 	 */
178a2f611a3SDavid Howells 	len = sprintf(text, "%llx:", vnode->fid.vid);
179a2f611a3SDavid Howells 	if (vnode->fid.vnode_hi)
180a2f611a3SDavid Howells 		len += sprintf(text + len, "%x%016llx",
181a2f611a3SDavid Howells 			       vnode->fid.vnode_hi, vnode->fid.vnode);
182a2f611a3SDavid Howells 	else
183a2f611a3SDavid Howells 		len += sprintf(text + len, "%llx", vnode->fid.vnode);
184a2f611a3SDavid Howells 	len += sprintf(text + len, ":%x", vnode->fid.unique);
185a2f611a3SDavid Howells 
186d3e3b7eaSDavid Howells 	if (size == 0)
187d3e3b7eaSDavid Howells 		return len;
188d3e3b7eaSDavid Howells 	if (len > size)
189d3e3b7eaSDavid Howells 		return -ERANGE;
190d3e3b7eaSDavid Howells 	memcpy(buffer, text, len);
191d3e3b7eaSDavid Howells 	return len;
192d3e3b7eaSDavid Howells }
193d3e3b7eaSDavid Howells 
194d3e3b7eaSDavid Howells static const struct xattr_handler afs_xattr_afs_fid_handler = {
195d3e3b7eaSDavid Howells 	.name	= "afs.fid",
196d3e3b7eaSDavid Howells 	.get	= afs_xattr_get_fid,
197d3e3b7eaSDavid Howells };
198d3e3b7eaSDavid Howells 
199d3e3b7eaSDavid Howells /*
200d3e3b7eaSDavid Howells  * Get the name of the volume on which a file resides.
201d3e3b7eaSDavid Howells  */
202d3e3b7eaSDavid Howells static int afs_xattr_get_volume(const struct xattr_handler *handler,
203d3e3b7eaSDavid Howells 			      struct dentry *dentry,
204d3e3b7eaSDavid Howells 			      struct inode *inode, const char *name,
205d3e3b7eaSDavid Howells 			      void *buffer, size_t size)
206d3e3b7eaSDavid Howells {
207d3e3b7eaSDavid Howells 	struct afs_vnode *vnode = AFS_FS_I(inode);
208d2ddc776SDavid Howells 	const char *volname = vnode->volume->name;
209d3e3b7eaSDavid Howells 	size_t namelen;
210d3e3b7eaSDavid Howells 
211d3e3b7eaSDavid Howells 	namelen = strlen(volname);
212d3e3b7eaSDavid Howells 	if (size == 0)
213d3e3b7eaSDavid Howells 		return namelen;
214d3e3b7eaSDavid Howells 	if (namelen > size)
215d3e3b7eaSDavid Howells 		return -ERANGE;
216c73aa410SDavid Howells 	memcpy(buffer, volname, namelen);
217d3e3b7eaSDavid Howells 	return namelen;
218d3e3b7eaSDavid Howells }
219d3e3b7eaSDavid Howells 
220d3e3b7eaSDavid Howells static const struct xattr_handler afs_xattr_afs_volume_handler = {
221d3e3b7eaSDavid Howells 	.name	= "afs.volume",
222d3e3b7eaSDavid Howells 	.get	= afs_xattr_get_volume,
223d3e3b7eaSDavid Howells };
224d3e3b7eaSDavid Howells 
225d3e3b7eaSDavid Howells const struct xattr_handler *afs_xattr_handlers[] = {
226260f082bSDavid Howells 	&afs_xattr_afs_acl_handler,
227d3e3b7eaSDavid Howells 	&afs_xattr_afs_cell_handler,
228d3e3b7eaSDavid Howells 	&afs_xattr_afs_fid_handler,
229d3e3b7eaSDavid Howells 	&afs_xattr_afs_volume_handler,
230d3e3b7eaSDavid Howells 	NULL
231d3e3b7eaSDavid Howells };
232