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
22static 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 */
29int 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
81error:
82	_leave(" = %d", ret);
83	return ret;
84
85bad_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
91bad_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 */
103int 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 */
131int 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 */
159int 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;
188error:
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 */
197int 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
284okay:
285	ret = 0;
286
287error:
288	kfree(auxbuf);
289	_leave(" = %d", ret);
290	return ret;
291
292bad_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
298stale:
299	ret = -ESTALE;
300	goto error;
301}
302
303/*
304 * remove the object's xattr to mark it stale
305 */
306int 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