Merge tag 'memcpy-v5.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees...
[linux-2.6-microblaze.git] / fs / cachefiles / xattr.c
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
20 struct 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
28 static const char cachefiles_xattr_cache[] =
29         XATTR_USER_PREFIX "CacheFiles.cache";
30
31 struct 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  */
39 int 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(&init_user_ns, 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  */
94 int 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(&init_user_ns, 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  */
145 int 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(&init_user_ns, 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  */
173 void 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  */
191 bool 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, len);
207
208         ret = cachefiles_inject_write_error();
209         if (ret == 0)
210                 ret = vfs_setxattr(&init_user_ns, 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  */
233 int 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(&init_user_ns, 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 }