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 */
cachefiles_preset_object_xattr(struct cachefiles_object * object,struct file * file)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 */
cachefiles_set_object_xattr(struct cachefiles_object * object)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 */
cachefiles_check_auxdata(struct cachefiles_object * object,struct file * file)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 */
cachefiles_remove_object_xattr(struct cachefiles_cache * cache,struct cachefiles_object * object,struct dentry * dentry)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 */
cachefiles_prepare_to_write(struct fscache_cookie * cookie)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 */
cachefiles_set_volume_xattr(struct cachefiles_volume * volume)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 */
cachefiles_check_volume_xattr(struct cachefiles_volume * volume)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