xref: /openbmc/linux/fs/cachefiles/xattr.c (revision a06c488d)
1 /* CacheFiles extended attribute management
2  *
3  * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4  * Written by David Howells (dhowells@redhat.com)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public Licence
8  * as published by the Free Software Foundation; either version
9  * 2 of the Licence, or (at your option) any later version.
10  */
11 
12 #include <linux/module.h>
13 #include <linux/sched.h>
14 #include <linux/file.h>
15 #include <linux/fs.h>
16 #include <linux/fsnotify.h>
17 #include <linux/quotaops.h>
18 #include <linux/xattr.h>
19 #include <linux/slab.h>
20 #include "internal.h"
21 
22 static const char cachefiles_xattr_cache[] =
23 	XATTR_USER_PREFIX "CacheFiles.cache";
24 
25 /*
26  * check the type label on an object
27  * - done using xattrs
28  */
29 int cachefiles_check_object_type(struct cachefiles_object *object)
30 {
31 	struct dentry *dentry = object->dentry;
32 	char type[3], xtype[3];
33 	int ret;
34 
35 	ASSERT(dentry);
36 	ASSERT(d_backing_inode(dentry));
37 
38 	if (!object->fscache.cookie)
39 		strcpy(type, "C3");
40 	else
41 		snprintf(type, 3, "%02x", object->fscache.cookie->def->type);
42 
43 	_enter("%p{%s}", object, type);
44 
45 	/* attempt to install a type label directly */
46 	ret = vfs_setxattr(dentry, cachefiles_xattr_cache, type, 2,
47 			   XATTR_CREATE);
48 	if (ret == 0) {
49 		_debug("SET"); /* we succeeded */
50 		goto error;
51 	}
52 
53 	if (ret != -EEXIST) {
54 		pr_err("Can't set xattr on %pd [%lu] (err %d)\n",
55 		       dentry, d_backing_inode(dentry)->i_ino,
56 		       -ret);
57 		goto error;
58 	}
59 
60 	/* read the current type label */
61 	ret = vfs_getxattr(dentry, cachefiles_xattr_cache, xtype, 3);
62 	if (ret < 0) {
63 		if (ret == -ERANGE)
64 			goto bad_type_length;
65 
66 		pr_err("Can't read xattr on %pd [%lu] (err %d)\n",
67 		       dentry, d_backing_inode(dentry)->i_ino,
68 		       -ret);
69 		goto error;
70 	}
71 
72 	/* check the type is what we're expecting */
73 	if (ret != 2)
74 		goto bad_type_length;
75 
76 	if (xtype[0] != type[0] || xtype[1] != type[1])
77 		goto bad_type;
78 
79 	ret = 0;
80 
81 error:
82 	_leave(" = %d", ret);
83 	return ret;
84 
85 bad_type_length:
86 	pr_err("Cache object %lu type xattr length incorrect\n",
87 	       d_backing_inode(dentry)->i_ino);
88 	ret = -EIO;
89 	goto error;
90 
91 bad_type:
92 	xtype[2] = 0;
93 	pr_err("Cache object %pd [%lu] type %s not %s\n",
94 	       dentry, d_backing_inode(dentry)->i_ino,
95 	       xtype, type);
96 	ret = -EIO;
97 	goto error;
98 }
99 
100 /*
101  * set the state xattr on a cache file
102  */
103 int cachefiles_set_object_xattr(struct cachefiles_object *object,
104 				struct cachefiles_xattr *auxdata)
105 {
106 	struct dentry *dentry = object->dentry;
107 	int ret;
108 
109 	ASSERT(dentry);
110 
111 	_enter("%p,#%d", object, auxdata->len);
112 
113 	/* attempt to install the cache metadata directly */
114 	_debug("SET #%u", auxdata->len);
115 
116 	ret = vfs_setxattr(dentry, cachefiles_xattr_cache,
117 			   &auxdata->type, auxdata->len,
118 			   XATTR_CREATE);
119 	if (ret < 0 && ret != -ENOMEM)
120 		cachefiles_io_error_obj(
121 			object,
122 			"Failed to set xattr with error %d", ret);
123 
124 	_leave(" = %d", ret);
125 	return ret;
126 }
127 
128 /*
129  * update the state xattr on a cache file
130  */
131 int cachefiles_update_object_xattr(struct cachefiles_object *object,
132 				   struct cachefiles_xattr *auxdata)
133 {
134 	struct dentry *dentry = object->dentry;
135 	int ret;
136 
137 	ASSERT(dentry);
138 
139 	_enter("%p,#%d", object, auxdata->len);
140 
141 	/* attempt to install the cache metadata directly */
142 	_debug("SET #%u", auxdata->len);
143 
144 	ret = vfs_setxattr(dentry, cachefiles_xattr_cache,
145 			   &auxdata->type, auxdata->len,
146 			   XATTR_REPLACE);
147 	if (ret < 0 && ret != -ENOMEM)
148 		cachefiles_io_error_obj(
149 			object,
150 			"Failed to update xattr with error %d", ret);
151 
152 	_leave(" = %d", ret);
153 	return ret;
154 }
155 
156 /*
157  * check the consistency between the backing cache and the FS-Cache cookie
158  */
159 int cachefiles_check_auxdata(struct cachefiles_object *object)
160 {
161 	struct cachefiles_xattr *auxbuf;
162 	enum fscache_checkaux validity;
163 	struct dentry *dentry = object->dentry;
164 	ssize_t xlen;
165 	int ret;
166 
167 	ASSERT(dentry);
168 	ASSERT(d_backing_inode(dentry));
169 	ASSERT(object->fscache.cookie->def->check_aux);
170 
171 	auxbuf = kmalloc(sizeof(struct cachefiles_xattr) + 512, GFP_KERNEL);
172 	if (!auxbuf)
173 		return -ENOMEM;
174 
175 	xlen = vfs_getxattr(dentry, cachefiles_xattr_cache,
176 			    &auxbuf->type, 512 + 1);
177 	ret = -ESTALE;
178 	if (xlen < 1 ||
179 	    auxbuf->type != object->fscache.cookie->def->type)
180 		goto error;
181 
182 	xlen--;
183 	validity = fscache_check_aux(&object->fscache, &auxbuf->data, xlen);
184 	if (validity != FSCACHE_CHECKAUX_OKAY)
185 		goto error;
186 
187 	ret = 0;
188 error:
189 	kfree(auxbuf);
190 	return ret;
191 }
192 
193 /*
194  * check the state xattr on a cache file
195  * - return -ESTALE if the object should be deleted
196  */
197 int cachefiles_check_object_xattr(struct cachefiles_object *object,
198 				  struct cachefiles_xattr *auxdata)
199 {
200 	struct cachefiles_xattr *auxbuf;
201 	struct dentry *dentry = object->dentry;
202 	int ret;
203 
204 	_enter("%p,#%d", object, auxdata->len);
205 
206 	ASSERT(dentry);
207 	ASSERT(d_backing_inode(dentry));
208 
209 	auxbuf = kmalloc(sizeof(struct cachefiles_xattr) + 512, cachefiles_gfp);
210 	if (!auxbuf) {
211 		_leave(" = -ENOMEM");
212 		return -ENOMEM;
213 	}
214 
215 	/* read the current type label */
216 	ret = vfs_getxattr(dentry, cachefiles_xattr_cache,
217 			   &auxbuf->type, 512 + 1);
218 	if (ret < 0) {
219 		if (ret == -ENODATA)
220 			goto stale; /* no attribute - power went off
221 				     * mid-cull? */
222 
223 		if (ret == -ERANGE)
224 			goto bad_type_length;
225 
226 		cachefiles_io_error_obj(object,
227 					"Can't read xattr on %lu (err %d)",
228 					d_backing_inode(dentry)->i_ino, -ret);
229 		goto error;
230 	}
231 
232 	/* check the on-disk object */
233 	if (ret < 1)
234 		goto bad_type_length;
235 
236 	if (auxbuf->type != auxdata->type)
237 		goto stale;
238 
239 	auxbuf->len = ret;
240 
241 	/* consult the netfs */
242 	if (object->fscache.cookie->def->check_aux) {
243 		enum fscache_checkaux result;
244 		unsigned int dlen;
245 
246 		dlen = auxbuf->len - 1;
247 
248 		_debug("checkaux %s #%u",
249 		       object->fscache.cookie->def->name, dlen);
250 
251 		result = fscache_check_aux(&object->fscache,
252 					   &auxbuf->data, dlen);
253 
254 		switch (result) {
255 			/* entry okay as is */
256 		case FSCACHE_CHECKAUX_OKAY:
257 			goto okay;
258 
259 			/* entry requires update */
260 		case FSCACHE_CHECKAUX_NEEDS_UPDATE:
261 			break;
262 
263 			/* entry requires deletion */
264 		case FSCACHE_CHECKAUX_OBSOLETE:
265 			goto stale;
266 
267 		default:
268 			BUG();
269 		}
270 
271 		/* update the current label */
272 		ret = vfs_setxattr(dentry, cachefiles_xattr_cache,
273 				   &auxdata->type, auxdata->len,
274 				   XATTR_REPLACE);
275 		if (ret < 0) {
276 			cachefiles_io_error_obj(object,
277 						"Can't update xattr on %lu"
278 						" (error %d)",
279 						d_backing_inode(dentry)->i_ino, -ret);
280 			goto error;
281 		}
282 	}
283 
284 okay:
285 	ret = 0;
286 
287 error:
288 	kfree(auxbuf);
289 	_leave(" = %d", ret);
290 	return ret;
291 
292 bad_type_length:
293 	pr_err("Cache object %lu xattr length incorrect\n",
294 	       d_backing_inode(dentry)->i_ino);
295 	ret = -EIO;
296 	goto error;
297 
298 stale:
299 	ret = -ESTALE;
300 	goto error;
301 }
302 
303 /*
304  * remove the object's xattr to mark it stale
305  */
306 int cachefiles_remove_object_xattr(struct cachefiles_cache *cache,
307 				   struct dentry *dentry)
308 {
309 	int ret;
310 
311 	ret = vfs_removexattr(dentry, cachefiles_xattr_cache);
312 	if (ret < 0) {
313 		if (ret == -ENOENT || ret == -ENODATA)
314 			ret = 0;
315 		else if (ret != -ENOMEM)
316 			cachefiles_io_error(cache,
317 					    "Can't remove xattr from %lu"
318 					    " (error %d)",
319 					    d_backing_inode(dentry)->i_ino, -ret);
320 	}
321 
322 	_leave(" = %d", ret);
323 	return ret;
324 }
325