~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/cachefiles/xattr.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 = 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 cookie
 99  */
100 int 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 resolution
137                 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 stale
152  */
153 int 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  */
187 void 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  */
205 bool 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  */
253 int 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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php