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}
v4.6
 
  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}