Linux Audio

Check our new training course

Loading...
v6.8
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/* CacheFiles extended attribute management
  3 *
  4 * Copyright (C) 2021 Red Hat, Inc. All Rights Reserved.
  5 * Written by David Howells (dhowells@redhat.com)
 
 
 
 
 
  6 */
  7
  8#include <linux/module.h>
  9#include <linux/sched.h>
 10#include <linux/file.h>
 11#include <linux/fs.h>
 12#include <linux/fsnotify.h>
 13#include <linux/quotaops.h>
 14#include <linux/xattr.h>
 15#include <linux/slab.h>
 16#include "internal.h"
 17
 18#define CACHEFILES_COOKIE_TYPE_DATA 1
 19
 20struct cachefiles_xattr {
 21	__be64	object_size;	/* Actual size of the object */
 22	__be64	zero_point;	/* Size after which server has no data not written by us */
 23	__u8	type;		/* Type of object */
 24	__u8	content;	/* Content presence (enum cachefiles_content) */
 25	__u8	data[];		/* netfs coherency data */
 26} __packed;
 27
 28static const char cachefiles_xattr_cache[] =
 29	XATTR_USER_PREFIX "CacheFiles.cache";
 30
 31struct cachefiles_vol_xattr {
 32	__be32	reserved;	/* Reserved, should be 0 */
 33	__u8	data[];		/* netfs volume coherency data */
 34} __packed;
 35
 36/*
 37 * set the state xattr on a cache file
 
 38 */
 39int cachefiles_set_object_xattr(struct cachefiles_object *object)
 40{
 41	struct cachefiles_xattr *buf;
 42	struct dentry *dentry;
 43	struct file *file = object->file;
 44	unsigned int len = object->cookie->aux_len;
 45	int ret;
 46
 47	if (!file)
 48		return -ESTALE;
 49	dentry = file->f_path.dentry;
 50
 51	_enter("%x,#%d", object->debug_id, len);
 
 
 
 
 
 
 
 
 
 
 
 
 
 52
 53	buf = kmalloc(sizeof(struct cachefiles_xattr) + len, GFP_KERNEL);
 54	if (!buf)
 55		return -ENOMEM;
 
 
 
 
 56
 57	buf->object_size	= cpu_to_be64(object->cookie->object_size);
 58	buf->zero_point		= 0;
 59	buf->type		= CACHEFILES_COOKIE_TYPE_DATA;
 60	buf->content		= object->content_info;
 61	if (test_bit(FSCACHE_COOKIE_LOCAL_WRITE, &object->cookie->flags))
 62		buf->content	= CACHEFILES_CONTENT_DIRTY;
 63	if (len > 0)
 64		memcpy(buf->data, fscache_get_aux(object->cookie), len);
 65
 66	ret = cachefiles_inject_write_error();
 67	if (ret == 0)
 68		ret = vfs_setxattr(&nop_mnt_idmap, dentry, cachefiles_xattr_cache,
 69				   buf, sizeof(struct cachefiles_xattr) + len, 0);
 70	if (ret < 0) {
 71		trace_cachefiles_vfs_error(object, file_inode(file), ret,
 72					   cachefiles_trace_setxattr_error);
 73		trace_cachefiles_coherency(object, file_inode(file)->i_ino,
 74					   buf->content,
 75					   cachefiles_coherency_set_fail);
 76		if (ret != -ENOMEM)
 77			cachefiles_io_error_obj(
 78				object,
 79				"Failed to set xattr with error %d", ret);
 80	} else {
 81		trace_cachefiles_coherency(object, file_inode(file)->i_ino,
 82					   buf->content,
 83					   cachefiles_coherency_set_ok);
 84	}
 85
 86	kfree(buf);
 
 
 
 
 
 
 
 
 
 87	_leave(" = %d", ret);
 88	return ret;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 89}
 90
 91/*
 92 * check the consistency between the backing cache and the FS-Cache cookie
 93 */
 94int cachefiles_check_auxdata(struct cachefiles_object *object, struct file *file)
 
 95{
 96	struct cachefiles_xattr *buf;
 97	struct dentry *dentry = file->f_path.dentry;
 98	unsigned int len = object->cookie->aux_len, tlen;
 99	const void *p = fscache_get_aux(object->cookie);
100	enum cachefiles_coherency_trace why;
101	ssize_t xlen;
102	int ret = -ESTALE;
103
104	tlen = sizeof(struct cachefiles_xattr) + len;
105	buf = kmalloc(tlen, GFP_KERNEL);
106	if (!buf)
107		return -ENOMEM;
108
109	xlen = cachefiles_inject_read_error();
110	if (xlen == 0)
111		xlen = vfs_getxattr(&nop_mnt_idmap, dentry, cachefiles_xattr_cache, buf, tlen);
112	if (xlen != tlen) {
113		if (xlen < 0)
114			trace_cachefiles_vfs_error(object, file_inode(file), xlen,
115						   cachefiles_trace_getxattr_error);
116		if (xlen == -EIO)
117			cachefiles_io_error_obj(
118				object,
119				"Failed to read aux with error %zd", xlen);
120		why = cachefiles_coherency_check_xattr;
121	} else if (buf->type != CACHEFILES_COOKIE_TYPE_DATA) {
122		why = cachefiles_coherency_check_type;
123	} else if (memcmp(buf->data, p, len) != 0) {
124		why = cachefiles_coherency_check_aux;
125	} else if (be64_to_cpu(buf->object_size) != object->cookie->object_size) {
126		why = cachefiles_coherency_check_objsize;
127	} else if (buf->content == CACHEFILES_CONTENT_DIRTY) {
128		// TODO: Begin conflict resolution
129		pr_warn("Dirty object in cache\n");
130		why = cachefiles_coherency_check_dirty;
131	} else {
132		why = cachefiles_coherency_check_ok;
133		ret = 0;
134	}
135
136	trace_cachefiles_coherency(object, file_inode(file)->i_ino,
137				   buf->content, why);
138	kfree(buf);
139	return ret;
140}
141
142/*
143 * remove the object's xattr to mark it stale
144 */
145int cachefiles_remove_object_xattr(struct cachefiles_cache *cache,
146				   struct cachefiles_object *object,
147				   struct dentry *dentry)
148{
 
149	int ret;
150
151	ret = cachefiles_inject_remove_error();
152	if (ret == 0)
153		ret = vfs_removexattr(&nop_mnt_idmap, dentry, cachefiles_xattr_cache);
154	if (ret < 0) {
155		trace_cachefiles_vfs_error(object, d_inode(dentry), ret,
156					   cachefiles_trace_remxattr_error);
157		if (ret == -ENOENT || ret == -ENODATA)
158			ret = 0;
159		else if (ret != -ENOMEM)
160			cachefiles_io_error(cache,
161					    "Can't remove xattr from %lu"
162					    " (error %d)",
163					    d_backing_inode(dentry)->i_ino, -ret);
164	}
165
166	_leave(" = %d", ret);
167	return ret;
168}
169
170/*
171 * Stick a marker on the cache object to indicate that it's dirty.
172 */
173void cachefiles_prepare_to_write(struct fscache_cookie *cookie)
174{
175	const struct cred *saved_cred;
176	struct cachefiles_object *object = cookie->cache_priv;
177	struct cachefiles_cache *cache = object->volume->cache;
178
179	_enter("c=%08x", object->cookie->debug_id);
180
181	if (!test_bit(CACHEFILES_OBJECT_USING_TMPFILE, &object->flags)) {
182		cachefiles_begin_secure(cache, &saved_cred);
183		cachefiles_set_object_xattr(object);
184		cachefiles_end_secure(cache, saved_cred);
185	}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
186}
187
188/*
189 * Set the state xattr on a volume directory.
 
190 */
191bool cachefiles_set_volume_xattr(struct cachefiles_volume *volume)
 
192{
193	struct cachefiles_vol_xattr *buf;
194	unsigned int len = volume->vcookie->coherency_len;
195	const void *p = volume->vcookie->coherency;
196	struct dentry *dentry = volume->dentry;
197	int ret;
198
199	_enter("%x,#%d", volume->vcookie->debug_id, len);
200
201	len += sizeof(*buf);
202	buf = kmalloc(len, GFP_KERNEL);
203	if (!buf)
204		return false;
205	buf->reserved = cpu_to_be32(0);
206	memcpy(buf->data, p, volume->vcookie->coherency_len);
207
208	ret = cachefiles_inject_write_error();
209	if (ret == 0)
210		ret = vfs_setxattr(&nop_mnt_idmap, dentry, cachefiles_xattr_cache,
211				   buf, len, 0);
 
212	if (ret < 0) {
213		trace_cachefiles_vfs_error(NULL, d_inode(dentry), ret,
214					   cachefiles_trace_setxattr_error);
215		trace_cachefiles_vol_coherency(volume, d_inode(dentry)->i_ino,
216					       cachefiles_coherency_vol_set_fail);
217		if (ret != -ENOMEM)
218			cachefiles_io_error(
219				volume->cache, "Failed to set xattr with error %d", ret);
220	} else {
221		trace_cachefiles_vol_coherency(volume, d_inode(dentry)->i_ino,
222					       cachefiles_coherency_vol_set_ok);
 
223	}
224
225	kfree(buf);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226	_leave(" = %d", ret);
227	return ret == 0;
 
 
 
 
 
 
 
 
 
 
228}
229
230/*
231 * Check the consistency between the backing cache and the volume cookie.
232 */
233int cachefiles_check_volume_xattr(struct cachefiles_volume *volume)
 
234{
235	struct cachefiles_vol_xattr *buf;
236	struct dentry *dentry = volume->dentry;
237	unsigned int len = volume->vcookie->coherency_len;
238	const void *p = volume->vcookie->coherency;
239	enum cachefiles_coherency_trace why;
240	ssize_t xlen;
241	int ret = -ESTALE;
242
243	_enter("");
244
245	len += sizeof(*buf);
246	buf = kmalloc(len, GFP_KERNEL);
247	if (!buf)
248		return -ENOMEM;
249
250	xlen = cachefiles_inject_read_error();
251	if (xlen == 0)
252		xlen = vfs_getxattr(&nop_mnt_idmap, dentry, cachefiles_xattr_cache, buf, len);
253	if (xlen != len) {
254		if (xlen < 0) {
255			trace_cachefiles_vfs_error(NULL, d_inode(dentry), xlen,
256						   cachefiles_trace_getxattr_error);
257			if (xlen == -EIO)
258				cachefiles_io_error(
259					volume->cache,
260					"Failed to read xattr with error %zd", xlen);
261		}
262		why = cachefiles_coherency_vol_check_xattr;
263	} else if (buf->reserved != cpu_to_be32(0)) {
264		why = cachefiles_coherency_vol_check_resv;
265	} else if (memcmp(buf->data, p, len - sizeof(*buf)) != 0) {
266		why = cachefiles_coherency_vol_check_cmp;
267	} else {
268		why = cachefiles_coherency_vol_check_ok;
269		ret = 0;
270	}
271
272	trace_cachefiles_vol_coherency(volume, d_inode(dentry)->i_ino, why);
273	kfree(buf);
274	_leave(" = %d", ret);
275	return ret;
276}
v3.15
 
  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(dentry->d_inode);
 
 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		kerror("Can't set xattr on %*.*s [%lu] (err %d)",
 55		       dentry->d_name.len, dentry->d_name.len,
 56		       dentry->d_name.name, dentry->d_inode->i_ino,
 57		       -ret);
 58		goto error;
 59	}
 60
 61	/* read the current type label */
 62	ret = vfs_getxattr(dentry, cachefiles_xattr_cache, xtype, 3);
 
 
 
 
 
 
 
 
 
 
 
 63	if (ret < 0) {
 64		if (ret == -ERANGE)
 65			goto bad_type_length;
 66
 67		kerror("Can't read xattr on %*.*s [%lu] (err %d)",
 68		       dentry->d_name.len, dentry->d_name.len,
 69		       dentry->d_name.name, dentry->d_inode->i_ino,
 70		       -ret);
 71		goto error;
 
 
 
 
 
 72	}
 73
 74	/* check the type is what we're expecting */
 75	if (ret != 2)
 76		goto bad_type_length;
 77
 78	if (xtype[0] != type[0] || xtype[1] != type[1])
 79		goto bad_type;
 80
 81	ret = 0;
 82
 83error:
 84	_leave(" = %d", ret);
 85	return ret;
 86
 87bad_type_length:
 88	kerror("Cache object %lu type xattr length incorrect",
 89	       dentry->d_inode->i_ino);
 90	ret = -EIO;
 91	goto error;
 92
 93bad_type:
 94	xtype[2] = 0;
 95	kerror("Cache object %*.*s [%lu] type %s not %s",
 96	       dentry->d_name.len, dentry->d_name.len,
 97	       dentry->d_name.name, dentry->d_inode->i_ino,
 98	       xtype, type);
 99	ret = -EIO;
100	goto error;
101}
102
103/*
104 * set the state xattr on a cache file
105 */
106int cachefiles_set_object_xattr(struct cachefiles_object *object,
107				struct cachefiles_xattr *auxdata)
108{
109	struct dentry *dentry = object->dentry;
110	int ret;
 
 
 
 
 
111
112	ASSERT(dentry);
 
 
 
113
114	_enter("%p,#%d", object, auxdata->len);
115
116	/* attempt to install the cache metadata directly */
117	_debug("SET #%u", auxdata->len);
118
119	ret = vfs_setxattr(dentry, cachefiles_xattr_cache,
120			   &auxdata->type, auxdata->len,
121			   XATTR_CREATE);
122	if (ret < 0 && ret != -ENOMEM)
123		cachefiles_io_error_obj(
124			object,
125			"Failed to set xattr with error %d", ret);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
127	_leave(" = %d", ret);
 
 
128	return ret;
129}
130
131/*
132 * update the state xattr on a cache file
133 */
134int cachefiles_update_object_xattr(struct cachefiles_object *object,
135				   struct cachefiles_xattr *auxdata)
 
136{
137	struct dentry *dentry = object->dentry;
138	int ret;
139
140	ASSERT(dentry);
141
142	_enter("%p,#%d", object, auxdata->len);
143
144	/* attempt to install the cache metadata directly */
145	_debug("SET #%u", auxdata->len);
146
147	ret = vfs_setxattr(dentry, cachefiles_xattr_cache,
148			   &auxdata->type, auxdata->len,
149			   XATTR_REPLACE);
150	if (ret < 0 && ret != -ENOMEM)
151		cachefiles_io_error_obj(
152			object,
153			"Failed to update xattr with error %d", ret);
154
155	_leave(" = %d", ret);
156	return ret;
157}
158
159/*
160 * check the consistency between the backing cache and the FS-Cache cookie
161 */
162int cachefiles_check_auxdata(struct cachefiles_object *object)
163{
164	struct cachefiles_xattr *auxbuf;
165	enum fscache_checkaux validity;
166	struct dentry *dentry = object->dentry;
167	ssize_t xlen;
168	int ret;
169
170	ASSERT(dentry);
171	ASSERT(dentry->d_inode);
172	ASSERT(object->fscache.cookie->def->check_aux);
173
174	auxbuf = kmalloc(sizeof(struct cachefiles_xattr) + 512, GFP_KERNEL);
175	if (!auxbuf)
176		return -ENOMEM;
177
178	xlen = vfs_getxattr(dentry, cachefiles_xattr_cache,
179			    &auxbuf->type, 512 + 1);
180	ret = -ESTALE;
181	if (xlen < 1 ||
182	    auxbuf->type != object->fscache.cookie->def->type)
183		goto error;
184
185	xlen--;
186	validity = fscache_check_aux(&object->fscache, &auxbuf->data, xlen);
187	if (validity != FSCACHE_CHECKAUX_OKAY)
188		goto error;
189
190	ret = 0;
191error:
192	kfree(auxbuf);
193	return ret;
194}
195
196/*
197 * check the state xattr on a cache file
198 * - return -ESTALE if the object should be deleted
199 */
200int cachefiles_check_object_xattr(struct cachefiles_object *object,
201				  struct cachefiles_xattr *auxdata)
202{
203	struct cachefiles_xattr *auxbuf;
204	struct dentry *dentry = object->dentry;
 
 
205	int ret;
206
207	_enter("%p,#%d", object, auxdata->len);
208
209	ASSERT(dentry);
210	ASSERT(dentry->d_inode);
211
212	auxbuf = kmalloc(sizeof(struct cachefiles_xattr) + 512, cachefiles_gfp);
213	if (!auxbuf) {
214		_leave(" = -ENOMEM");
215		return -ENOMEM;
216	}
217
218	/* read the current type label */
219	ret = vfs_getxattr(dentry, cachefiles_xattr_cache,
220			   &auxbuf->type, 512 + 1);
221	if (ret < 0) {
222		if (ret == -ENODATA)
223			goto stale; /* no attribute - power went off
224				     * mid-cull? */
225
226		if (ret == -ERANGE)
227			goto bad_type_length;
228
229		cachefiles_io_error_obj(object,
230					"Can't read xattr on %lu (err %d)",
231					dentry->d_inode->i_ino, -ret);
232		goto error;
233	}
234
235	/* check the on-disk object */
236	if (ret < 1)
237		goto bad_type_length;
238
239	if (auxbuf->type != auxdata->type)
240		goto stale;
241
242	auxbuf->len = ret;
243
244	/* consult the netfs */
245	if (object->fscache.cookie->def->check_aux) {
246		enum fscache_checkaux result;
247		unsigned int dlen;
248
249		dlen = auxbuf->len - 1;
250
251		_debug("checkaux %s #%u",
252		       object->fscache.cookie->def->name, dlen);
253
254		result = fscache_check_aux(&object->fscache,
255					   &auxbuf->data, dlen);
256
257		switch (result) {
258			/* entry okay as is */
259		case FSCACHE_CHECKAUX_OKAY:
260			goto okay;
261
262			/* entry requires update */
263		case FSCACHE_CHECKAUX_NEEDS_UPDATE:
264			break;
265
266			/* entry requires deletion */
267		case FSCACHE_CHECKAUX_OBSOLETE:
268			goto stale;
269
270		default:
271			BUG();
272		}
273
274		/* update the current label */
275		ret = vfs_setxattr(dentry, cachefiles_xattr_cache,
276				   &auxdata->type, auxdata->len,
277				   XATTR_REPLACE);
278		if (ret < 0) {
279			cachefiles_io_error_obj(object,
280						"Can't update xattr on %lu"
281						" (error %d)",
282						dentry->d_inode->i_ino, -ret);
283			goto error;
284		}
285	}
286
287okay:
288	ret = 0;
289
290error:
291	kfree(auxbuf);
292	_leave(" = %d", ret);
293	return ret;
294
295bad_type_length:
296	kerror("Cache object %lu xattr length incorrect",
297	       dentry->d_inode->i_ino);
298	ret = -EIO;
299	goto error;
300
301stale:
302	ret = -ESTALE;
303	goto error;
304}
305
306/*
307 * remove the object's xattr to mark it stale
308 */
309int cachefiles_remove_object_xattr(struct cachefiles_cache *cache,
310				   struct dentry *dentry)
311{
312	int ret;
 
 
 
 
 
 
 
 
 
 
 
 
 
313
314	ret = vfs_removexattr(dentry, cachefiles_xattr_cache);
315	if (ret < 0) {
316		if (ret == -ENOENT || ret == -ENODATA)
317			ret = 0;
318		else if (ret != -ENOMEM)
319			cachefiles_io_error(cache,
320					    "Can't remove xattr from %lu"
321					    " (error %d)",
322					    dentry->d_inode->i_ino, -ret);
 
 
 
 
 
 
 
 
 
 
 
323	}
324
 
 
325	_leave(" = %d", ret);
326	return ret;
327}