xref: /linux/fs/cachefiles/xattr.c (revision 12d5fc96ebbb3b948861805b32a4c3a96105ccd9)
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 <linux/unaligned.h>
17 #include "internal.h"
18 
19 #define CACHEFILES_COOKIE_TYPE_DATA 1
20 
21 struct cachefiles_xattr {
22 	__be64	object_size;	/* Actual size of the object */
23 	__be64	zero_point;	/* Size after which server has no data not written by us */
24 	__u8	type;		/* Type of object */
25 	__u8	content;	/* Content presence (enum cachefiles_content) */
26 	__u8	data[];		/* netfs coherency data */
27 } __packed;
28 
29 static const char cachefiles_xattr_cache[] =
30 	XATTR_USER_PREFIX "CacheFiles.cache";
31 
32 struct cachefiles_vol_xattr {
33 	__be32	reserved;	/* Reserved, should be 0 */
34 	__u8	data[];		/* netfs volume coherency data */
35 } __packed;
36 
37 /*
38  * Preset the state xattr on a cache file to allocate space for it.
39  */
40 int cachefiles_preset_object_xattr(struct cachefiles_object *object, struct file *file)
41 {
42 	struct cachefiles_xattr *buf;
43 	struct dentry *dentry = file->f_path.dentry;
44 	unsigned int len = object->cookie->aux_len;
45 	int ret;
46 
47 	buf = kzalloc(sizeof(struct cachefiles_xattr) + min(len, sizeof(__be64)), GFP_KERNEL);
48 	if (!buf)
49 		return -ENOMEM;
50 
51 	buf->type		= CACHEFILES_COOKIE_TYPE_DATA;
52 	buf->content		= CACHEFILES_CONTENT_DIRTY;
53 
54 	ret = cachefiles_inject_write_error();
55 	if (ret == 0) {
56 		ret = mnt_want_write_file(file);
57 		if (ret == 0) {
58 			ret = vfs_setxattr(&nop_mnt_idmap, dentry,
59 					   cachefiles_xattr_cache, buf,
60 					   sizeof(struct cachefiles_xattr) + len, 0);
61 			mnt_drop_write_file(file);
62 		}
63 	}
64 	if (ret < 0) {
65 		trace_cachefiles_vfs_error(object, file_inode(file), ret,
66 					   cachefiles_trace_setxattr_error);
67 		trace_cachefiles_coherency(object, file_inode(file)->i_ino,
68 					   object->object_size,
69 					   buf->data, buf->content,
70 					   cachefiles_coherency_set_fail);
71 		switch (ret) {
72 		case -ENOMEM:
73 		case -ENOSPC:
74 			break;
75 		default:
76 			cachefiles_io_error_obj(
77 				object,
78 				"Failed to set xattr with error %d", ret);
79 			break;
80 		}
81 	}
82 
83 	kfree(buf);
84 	_leave(" = %d", ret);
85 	return ret;
86 }
87 
88 /*
89  * set the state xattr on a cache file
90  */
91 int cachefiles_set_object_xattr(struct cachefiles_object *object)
92 {
93 	struct cachefiles_xattr *buf;
94 	struct dentry *dentry;
95 	struct file *file = object->file;
96 	unsigned int len = object->cookie->aux_len;
97 	uoff_t object_size = object->cookie->object_size;
98 	int ret;
99 
100 	if (!file)
101 		return -ESTALE;
102 	dentry = file->f_path.dentry;
103 
104 	_enter("%x,#%d", object->debug_id, len);
105 
106 	buf = kmalloc(sizeof(struct cachefiles_xattr) + max(len, sizeof(__be64)), GFP_KERNEL);
107 	if (!buf)
108 		return -ENOMEM;
109 
110 	buf->object_size	= cpu_to_be64(object_size);
111 	buf->zero_point		= 0;
112 	buf->type		= CACHEFILES_COOKIE_TYPE_DATA;
113 	buf->content		= object->content_info;
114 	if (test_bit(FSCACHE_COOKIE_LOCAL_WRITE, &object->cookie->flags))
115 		buf->content	= CACHEFILES_CONTENT_DIRTY;
116 	put_unaligned_be64(0, (__be64 *)buf->data);
117 	if (len > 0)
118 		memcpy(buf->data, fscache_get_aux(object->cookie), len);
119 
120 	ret = cachefiles_inject_write_error();
121 	if (ret == 0) {
122 		ret = mnt_want_write_file(file);
123 		if (ret == 0) {
124 			ret = vfs_setxattr(&nop_mnt_idmap, dentry,
125 					   cachefiles_xattr_cache, buf,
126 					   sizeof(struct cachefiles_xattr) + len, 0);
127 			mnt_drop_write_file(file);
128 		}
129 	}
130 	if (ret < 0) {
131 		trace_cachefiles_vfs_error(object, file_inode(file), ret,
132 					   cachefiles_trace_setxattr_error);
133 		trace_cachefiles_coherency(object, file_inode(file)->i_ino,
134 					   object_size, buf->data, buf->content,
135 					   cachefiles_coherency_set_fail);
136 		switch (ret) {
137 		case -ENOMEM:
138 			break;
139 		case -ENOSPC:
140 		default:
141 			cachefiles_io_error_obj(
142 				object,
143 				"Failed to set xattr with error %d", ret);
144 			break;
145 		}
146 	} else {
147 		trace_cachefiles_coherency(object, file_inode(file)->i_ino,
148 					   object_size, buf->data, buf->content,
149 					   cachefiles_coherency_set_ok);
150 	}
151 
152 	kfree(buf);
153 	_leave(" = %d", ret);
154 	return ret;
155 }
156 
157 /*
158  * check the consistency between the backing cache and the FS-Cache cookie
159  */
160 int cachefiles_check_auxdata(struct cachefiles_object *object, struct file *file)
161 {
162 	struct cachefiles_xattr *buf;
163 	struct dentry *dentry = file->f_path.dentry;
164 	struct inode *inode = file_inode(file);
165 	unsigned int len = object->cookie->aux_len, tlen;
166 	const void *p = fscache_get_aux(object->cookie);
167 	enum cachefiles_coherency_trace why;
168 	ssize_t xlen;
169 	uoff_t obj_size;
170 	int ret = -ESTALE;
171 
172 	tlen = sizeof(struct cachefiles_xattr) + len;
173 	buf = kmalloc(sizeof(struct cachefiles_xattr) + max(len, sizeof(__be64)), GFP_KERNEL);
174 	if (!buf)
175 		return -ENOMEM;
176 	put_unaligned_be64(0, (__be64 *)buf->data);
177 
178 	xlen = cachefiles_inject_read_error();
179 	if (xlen == 0)
180 		xlen = vfs_getxattr(&nop_mnt_idmap, dentry, cachefiles_xattr_cache, buf, tlen);
181 	if (xlen != tlen) {
182 		if (xlen < 0) {
183 			ret = xlen;
184 			trace_cachefiles_vfs_error(object, inode, xlen,
185 						   cachefiles_trace_getxattr_error);
186 		}
187 		if (xlen == -EIO)
188 			cachefiles_io_error_obj(
189 				object,
190 				"Failed to read aux with error %zd", xlen);
191 		obj_size = 0;
192 		why = cachefiles_coherency_check_xattr;
193 		goto out;
194 	}
195 
196 	obj_size = be64_to_cpu(buf->object_size);
197 	if (buf->type != CACHEFILES_COOKIE_TYPE_DATA) {
198 		why = cachefiles_coherency_check_type;
199 	} else if (memcmp(buf->data, p, len) != 0) {
200 		why = cachefiles_coherency_check_aux;
201 	} else if (obj_size != object->cookie->object_size) {
202 		why = cachefiles_coherency_check_objsize;
203 	} else if (buf->content == CACHEFILES_CONTENT_DIRTY) {
204 		// TODO: Begin conflict resolution
205 		pr_warn("Dirty object in cache\n");
206 		why = cachefiles_coherency_check_dirty;
207 	} else {
208 		object->content_info = buf->content;
209 		object->object_size = obj_size;
210 		atomic64_set(&object->read_limit, i_size_read(inode));
211 		why = cachefiles_coherency_check_ok;
212 		ret = 0;
213 	}
214 
215 out:
216 	trace_cachefiles_coherency(object, inode->i_ino, obj_size,
217 				   buf->data, buf->content, why);
218 	kfree(buf);
219 	return ret;
220 }
221 
222 /*
223  * remove the object's xattr to mark it stale
224  */
225 int cachefiles_remove_object_xattr(struct cachefiles_cache *cache,
226 				   struct cachefiles_object *object,
227 				   struct dentry *dentry)
228 {
229 	int ret;
230 
231 	trace_cachefiles_coherency(object, d_inode(dentry)->i_ino, 0, NULL, 0,
232 				   cachefiles_coherency_remove);
233 
234 	ret = cachefiles_inject_remove_error();
235 	if (ret == 0) {
236 		ret = mnt_want_write(cache->mnt);
237 		if (ret == 0) {
238 			ret = vfs_removexattr(&nop_mnt_idmap, dentry,
239 					      cachefiles_xattr_cache);
240 			mnt_drop_write(cache->mnt);
241 		}
242 	}
243 	if (ret < 0) {
244 		trace_cachefiles_vfs_error(object, d_inode(dentry), ret,
245 					   cachefiles_trace_remxattr_error);
246 		if (ret == -ENOENT || ret == -ENODATA)
247 			ret = 0;
248 		else if (ret != -ENOMEM)
249 			cachefiles_io_error(cache,
250 					    "Can't remove xattr from %llu"
251 					    " (error %d)",
252 					    d_backing_inode(dentry)->i_ino, -ret);
253 	}
254 
255 	_leave(" = %d", ret);
256 	return ret;
257 }
258 
259 /*
260  * Stick a marker on the cache object to indicate that it's dirty.
261  */
262 void cachefiles_prepare_to_write(struct fscache_cookie *cookie)
263 {
264 	const struct cred *saved_cred;
265 	struct cachefiles_object *object = cookie->cache_priv;
266 	struct cachefiles_cache *cache = object->volume->cache;
267 
268 	_enter("c=%08x", object->cookie->debug_id);
269 
270 	if (!test_bit(CACHEFILES_OBJECT_USING_TMPFILE, &object->flags)) {
271 		cachefiles_begin_secure(cache, &saved_cred);
272 		cachefiles_set_object_xattr(object);
273 		cachefiles_end_secure(cache, saved_cred);
274 	}
275 }
276 
277 /*
278  * Set the state xattr on a volume directory.
279  */
280 bool cachefiles_set_volume_xattr(struct cachefiles_volume *volume)
281 {
282 	struct cachefiles_vol_xattr *buf;
283 	unsigned int len = volume->vcookie->coherency_len;
284 	const void *p = volume->vcookie->coherency;
285 	struct dentry *dentry = volume->dentry;
286 	int ret;
287 
288 	_enter("%x,#%d", volume->vcookie->debug_id, len);
289 
290 	len += sizeof(*buf);
291 	buf = kmalloc(len, GFP_KERNEL);
292 	if (!buf)
293 		return false;
294 	buf->reserved = cpu_to_be32(0);
295 	memcpy(buf->data, p, volume->vcookie->coherency_len);
296 
297 	ret = cachefiles_inject_write_error();
298 	if (ret == 0) {
299 		ret = mnt_want_write(volume->cache->mnt);
300 		if (ret == 0) {
301 			ret = vfs_setxattr(&nop_mnt_idmap, dentry,
302 					   cachefiles_xattr_cache,
303 					   buf, len, 0);
304 			mnt_drop_write(volume->cache->mnt);
305 		}
306 	}
307 	if (ret < 0) {
308 		trace_cachefiles_vfs_error(NULL, d_inode(dentry), ret,
309 					   cachefiles_trace_setxattr_error);
310 		trace_cachefiles_vol_coherency(volume, d_inode(dentry)->i_ino,
311 					       cachefiles_coherency_vol_set_fail);
312 		if (ret != -ENOMEM)
313 			cachefiles_io_error(
314 				volume->cache, "Failed to set xattr with error %d", ret);
315 	} else {
316 		trace_cachefiles_vol_coherency(volume, d_inode(dentry)->i_ino,
317 					       cachefiles_coherency_vol_set_ok);
318 	}
319 
320 	kfree(buf);
321 	_leave(" = %d", ret);
322 	return ret == 0;
323 }
324 
325 /*
326  * Check the consistency between the backing cache and the volume cookie.
327  */
328 int cachefiles_check_volume_xattr(struct cachefiles_volume *volume)
329 {
330 	struct cachefiles_vol_xattr *buf;
331 	struct dentry *dentry = volume->dentry;
332 	unsigned int len = volume->vcookie->coherency_len;
333 	const void *p = volume->vcookie->coherency;
334 	enum cachefiles_coherency_trace why;
335 	ssize_t xlen;
336 	int ret = -ESTALE;
337 
338 	_enter("");
339 
340 	len += sizeof(*buf);
341 	buf = kmalloc(len, GFP_KERNEL);
342 	if (!buf)
343 		return -ENOMEM;
344 
345 	xlen = cachefiles_inject_read_error();
346 	if (xlen == 0)
347 		xlen = vfs_getxattr(&nop_mnt_idmap, dentry, cachefiles_xattr_cache, buf, len);
348 	if (xlen != len) {
349 		if (xlen < 0) {
350 			ret = xlen;
351 			trace_cachefiles_vfs_error(NULL, d_inode(dentry), xlen,
352 						   cachefiles_trace_getxattr_error);
353 			if (xlen == -EIO)
354 				cachefiles_io_error(
355 					volume->cache,
356 					"Failed to read xattr with error %zd", xlen);
357 		}
358 		why = cachefiles_coherency_vol_check_xattr;
359 	} else if (buf->reserved != cpu_to_be32(0)) {
360 		why = cachefiles_coherency_vol_check_resv;
361 	} else if (memcmp(buf->data, p, len - sizeof(*buf)) != 0) {
362 		why = cachefiles_coherency_vol_check_cmp;
363 	} else {
364 		why = cachefiles_coherency_vol_check_ok;
365 		ret = 0;
366 	}
367 
368 	trace_cachefiles_vol_coherency(volume, d_inode(dentry)->i_ino, why);
369 	kfree(buf);
370 	_leave(" = %d", ret);
371 	return ret;
372 }
373