brintos

brintos / linux-shallow public Read only

0
0
Text · 8.1 KiB · 7c6f260 Raw
298 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/* CacheFiles extended attribute management3 *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 119 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 file38 */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 = mnt_want_write_file(file);69		if (ret == 0) {70			ret = vfs_setxattr(&nop_mnt_idmap, dentry,71					   cachefiles_xattr_cache, buf,72					   sizeof(struct cachefiles_xattr) + len, 0);73			mnt_drop_write_file(file);74		}75	}76	if (ret < 0) {77		trace_cachefiles_vfs_error(object, file_inode(file), ret,78					   cachefiles_trace_setxattr_error);79		trace_cachefiles_coherency(object, file_inode(file)->i_ino,80					   buf->content,81					   cachefiles_coherency_set_fail);82		if (ret != -ENOMEM)83			cachefiles_io_error_obj(84				object,85				"Failed to set xattr with error %d", ret);86	} else {87		trace_cachefiles_coherency(object, file_inode(file)->i_ino,88					   buf->content,89					   cachefiles_coherency_set_ok);90	}91 92	kfree(buf);93	_leave(" = %d", ret);94	return ret;95}96 97/*98 * check the consistency between the backing cache and the FS-Cache cookie99 */100int cachefiles_check_auxdata(struct cachefiles_object *object, struct file *file)101{102	struct cachefiles_xattr *buf;103	struct dentry *dentry = file->f_path.dentry;104	unsigned int len = object->cookie->aux_len, tlen;105	const void *p = fscache_get_aux(object->cookie);106	enum cachefiles_coherency_trace why;107	ssize_t xlen;108	int ret = -ESTALE;109 110	tlen = sizeof(struct cachefiles_xattr) + len;111	buf = kmalloc(tlen, GFP_KERNEL);112	if (!buf)113		return -ENOMEM;114 115	xlen = cachefiles_inject_read_error();116	if (xlen == 0)117		xlen = vfs_getxattr(&nop_mnt_idmap, dentry, cachefiles_xattr_cache, buf, tlen);118	if (xlen != tlen) {119		if (xlen < 0) {120			ret = xlen;121			trace_cachefiles_vfs_error(object, file_inode(file), xlen,122						   cachefiles_trace_getxattr_error);123		}124		if (xlen == -EIO)125			cachefiles_io_error_obj(126				object,127				"Failed to read aux with error %zd", xlen);128		why = cachefiles_coherency_check_xattr;129	} else if (buf->type != CACHEFILES_COOKIE_TYPE_DATA) {130		why = cachefiles_coherency_check_type;131	} else if (memcmp(buf->data, p, len) != 0) {132		why = cachefiles_coherency_check_aux;133	} else if (be64_to_cpu(buf->object_size) != object->cookie->object_size) {134		why = cachefiles_coherency_check_objsize;135	} else if (buf->content == CACHEFILES_CONTENT_DIRTY) {136		// TODO: Begin conflict resolution137		pr_warn("Dirty object in cache\n");138		why = cachefiles_coherency_check_dirty;139	} else {140		why = cachefiles_coherency_check_ok;141		ret = 0;142	}143 144	trace_cachefiles_coherency(object, file_inode(file)->i_ino,145				   buf->content, why);146	kfree(buf);147	return ret;148}149 150/*151 * remove the object's xattr to mark it stale152 */153int cachefiles_remove_object_xattr(struct cachefiles_cache *cache,154				   struct cachefiles_object *object,155				   struct dentry *dentry)156{157	int ret;158 159	ret = cachefiles_inject_remove_error();160	if (ret == 0) {161		ret = mnt_want_write(cache->mnt);162		if (ret == 0) {163			ret = vfs_removexattr(&nop_mnt_idmap, dentry,164					      cachefiles_xattr_cache);165			mnt_drop_write(cache->mnt);166		}167	}168	if (ret < 0) {169		trace_cachefiles_vfs_error(object, d_inode(dentry), ret,170					   cachefiles_trace_remxattr_error);171		if (ret == -ENOENT || ret == -ENODATA)172			ret = 0;173		else if (ret != -ENOMEM)174			cachefiles_io_error(cache,175					    "Can't remove xattr from %lu"176					    " (error %d)",177					    d_backing_inode(dentry)->i_ino, -ret);178	}179 180	_leave(" = %d", ret);181	return ret;182}183 184/*185 * Stick a marker on the cache object to indicate that it's dirty.186 */187void cachefiles_prepare_to_write(struct fscache_cookie *cookie)188{189	const struct cred *saved_cred;190	struct cachefiles_object *object = cookie->cache_priv;191	struct cachefiles_cache *cache = object->volume->cache;192 193	_enter("c=%08x", object->cookie->debug_id);194 195	if (!test_bit(CACHEFILES_OBJECT_USING_TMPFILE, &object->flags)) {196		cachefiles_begin_secure(cache, &saved_cred);197		cachefiles_set_object_xattr(object);198		cachefiles_end_secure(cache, saved_cred);199	}200}201 202/*203 * Set the state xattr on a volume directory.204 */205bool cachefiles_set_volume_xattr(struct cachefiles_volume *volume)206{207	struct cachefiles_vol_xattr *buf;208	unsigned int len = volume->vcookie->coherency_len;209	const void *p = volume->vcookie->coherency;210	struct dentry *dentry = volume->dentry;211	int ret;212 213	_enter("%x,#%d", volume->vcookie->debug_id, len);214 215	len += sizeof(*buf);216	buf = kmalloc(len, GFP_KERNEL);217	if (!buf)218		return false;219	buf->reserved = cpu_to_be32(0);220	memcpy(buf->data, p, volume->vcookie->coherency_len);221 222	ret = cachefiles_inject_write_error();223	if (ret == 0) {224		ret = mnt_want_write(volume->cache->mnt);225		if (ret == 0) {226			ret = vfs_setxattr(&nop_mnt_idmap, dentry,227					   cachefiles_xattr_cache,228					   buf, len, 0);229			mnt_drop_write(volume->cache->mnt);230		}231	}232	if (ret < 0) {233		trace_cachefiles_vfs_error(NULL, d_inode(dentry), ret,234					   cachefiles_trace_setxattr_error);235		trace_cachefiles_vol_coherency(volume, d_inode(dentry)->i_ino,236					       cachefiles_coherency_vol_set_fail);237		if (ret != -ENOMEM)238			cachefiles_io_error(239				volume->cache, "Failed to set xattr with error %d", ret);240	} else {241		trace_cachefiles_vol_coherency(volume, d_inode(dentry)->i_ino,242					       cachefiles_coherency_vol_set_ok);243	}244 245	kfree(buf);246	_leave(" = %d", ret);247	return ret == 0;248}249 250/*251 * Check the consistency between the backing cache and the volume cookie.252 */253int cachefiles_check_volume_xattr(struct cachefiles_volume *volume)254{255	struct cachefiles_vol_xattr *buf;256	struct dentry *dentry = volume->dentry;257	unsigned int len = volume->vcookie->coherency_len;258	const void *p = volume->vcookie->coherency;259	enum cachefiles_coherency_trace why;260	ssize_t xlen;261	int ret = -ESTALE;262 263	_enter("");264 265	len += sizeof(*buf);266	buf = kmalloc(len, GFP_KERNEL);267	if (!buf)268		return -ENOMEM;269 270	xlen = cachefiles_inject_read_error();271	if (xlen == 0)272		xlen = vfs_getxattr(&nop_mnt_idmap, dentry, cachefiles_xattr_cache, buf, len);273	if (xlen != len) {274		if (xlen < 0) {275			ret = xlen;276			trace_cachefiles_vfs_error(NULL, d_inode(dentry), xlen,277						   cachefiles_trace_getxattr_error);278			if (xlen == -EIO)279				cachefiles_io_error(280					volume->cache,281					"Failed to read xattr with error %zd", xlen);282		}283		why = cachefiles_coherency_vol_check_xattr;284	} else if (buf->reserved != cpu_to_be32(0)) {285		why = cachefiles_coherency_vol_check_resv;286	} else if (memcmp(buf->data, p, len - sizeof(*buf)) != 0) {287		why = cachefiles_coherency_vol_check_cmp;288	} else {289		why = cachefiles_coherency_vol_check_ok;290		ret = 0;291	}292 293	trace_cachefiles_vol_coherency(volume, d_inode(dentry)->i_ino, why);294	kfree(buf);295	_leave(" = %d", ret);296	return ret;297}298