Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* CacheFiles extended attribute management
0003  *
0004  * Copyright (C) 2021 Red Hat, Inc. All Rights Reserved.
0005  * Written by David Howells (dhowells@redhat.com)
0006  */
0007 
0008 #include <linux/module.h>
0009 #include <linux/sched.h>
0010 #include <linux/file.h>
0011 #include <linux/fs.h>
0012 #include <linux/fsnotify.h>
0013 #include <linux/quotaops.h>
0014 #include <linux/xattr.h>
0015 #include <linux/slab.h>
0016 #include "internal.h"
0017 
0018 #define CACHEFILES_COOKIE_TYPE_DATA 1
0019 
0020 struct cachefiles_xattr {
0021     __be64  object_size;    /* Actual size of the object */
0022     __be64  zero_point; /* Size after which server has no data not written by us */
0023     __u8    type;       /* Type of object */
0024     __u8    content;    /* Content presence (enum cachefiles_content) */
0025     __u8    data[];     /* netfs coherency data */
0026 } __packed;
0027 
0028 static const char cachefiles_xattr_cache[] =
0029     XATTR_USER_PREFIX "CacheFiles.cache";
0030 
0031 struct cachefiles_vol_xattr {
0032     __be32  reserved;   /* Reserved, should be 0 */
0033     __u8    data[];     /* netfs volume coherency data */
0034 } __packed;
0035 
0036 /*
0037  * set the state xattr on a cache file
0038  */
0039 int cachefiles_set_object_xattr(struct cachefiles_object *object)
0040 {
0041     struct cachefiles_xattr *buf;
0042     struct dentry *dentry;
0043     struct file *file = object->file;
0044     unsigned int len = object->cookie->aux_len;
0045     int ret;
0046 
0047     if (!file)
0048         return -ESTALE;
0049     dentry = file->f_path.dentry;
0050 
0051     _enter("%x,#%d", object->debug_id, len);
0052 
0053     buf = kmalloc(sizeof(struct cachefiles_xattr) + len, GFP_KERNEL);
0054     if (!buf)
0055         return -ENOMEM;
0056 
0057     buf->object_size    = cpu_to_be64(object->cookie->object_size);
0058     buf->zero_point     = 0;
0059     buf->type       = CACHEFILES_COOKIE_TYPE_DATA;
0060     buf->content        = object->content_info;
0061     if (test_bit(FSCACHE_COOKIE_LOCAL_WRITE, &object->cookie->flags))
0062         buf->content    = CACHEFILES_CONTENT_DIRTY;
0063     if (len > 0)
0064         memcpy(buf->data, fscache_get_aux(object->cookie), len);
0065 
0066     ret = cachefiles_inject_write_error();
0067     if (ret == 0)
0068         ret = vfs_setxattr(&init_user_ns, dentry, cachefiles_xattr_cache,
0069                    buf, sizeof(struct cachefiles_xattr) + len, 0);
0070     if (ret < 0) {
0071         trace_cachefiles_vfs_error(object, file_inode(file), ret,
0072                        cachefiles_trace_setxattr_error);
0073         trace_cachefiles_coherency(object, file_inode(file)->i_ino,
0074                        buf->content,
0075                        cachefiles_coherency_set_fail);
0076         if (ret != -ENOMEM)
0077             cachefiles_io_error_obj(
0078                 object,
0079                 "Failed to set xattr with error %d", ret);
0080     } else {
0081         trace_cachefiles_coherency(object, file_inode(file)->i_ino,
0082                        buf->content,
0083                        cachefiles_coherency_set_ok);
0084     }
0085 
0086     kfree(buf);
0087     _leave(" = %d", ret);
0088     return ret;
0089 }
0090 
0091 /*
0092  * check the consistency between the backing cache and the FS-Cache cookie
0093  */
0094 int cachefiles_check_auxdata(struct cachefiles_object *object, struct file *file)
0095 {
0096     struct cachefiles_xattr *buf;
0097     struct dentry *dentry = file->f_path.dentry;
0098     unsigned int len = object->cookie->aux_len, tlen;
0099     const void *p = fscache_get_aux(object->cookie);
0100     enum cachefiles_coherency_trace why;
0101     ssize_t xlen;
0102     int ret = -ESTALE;
0103 
0104     tlen = sizeof(struct cachefiles_xattr) + len;
0105     buf = kmalloc(tlen, GFP_KERNEL);
0106     if (!buf)
0107         return -ENOMEM;
0108 
0109     xlen = cachefiles_inject_read_error();
0110     if (xlen == 0)
0111         xlen = vfs_getxattr(&init_user_ns, dentry, cachefiles_xattr_cache, buf, tlen);
0112     if (xlen != tlen) {
0113         if (xlen < 0)
0114             trace_cachefiles_vfs_error(object, file_inode(file), xlen,
0115                            cachefiles_trace_getxattr_error);
0116         if (xlen == -EIO)
0117             cachefiles_io_error_obj(
0118                 object,
0119                 "Failed to read aux with error %zd", xlen);
0120         why = cachefiles_coherency_check_xattr;
0121     } else if (buf->type != CACHEFILES_COOKIE_TYPE_DATA) {
0122         why = cachefiles_coherency_check_type;
0123     } else if (memcmp(buf->data, p, len) != 0) {
0124         why = cachefiles_coherency_check_aux;
0125     } else if (be64_to_cpu(buf->object_size) != object->cookie->object_size) {
0126         why = cachefiles_coherency_check_objsize;
0127     } else if (buf->content == CACHEFILES_CONTENT_DIRTY) {
0128         // TODO: Begin conflict resolution
0129         pr_warn("Dirty object in cache\n");
0130         why = cachefiles_coherency_check_dirty;
0131     } else {
0132         why = cachefiles_coherency_check_ok;
0133         ret = 0;
0134     }
0135 
0136     trace_cachefiles_coherency(object, file_inode(file)->i_ino,
0137                    buf->content, why);
0138     kfree(buf);
0139     return ret;
0140 }
0141 
0142 /*
0143  * remove the object's xattr to mark it stale
0144  */
0145 int cachefiles_remove_object_xattr(struct cachefiles_cache *cache,
0146                    struct cachefiles_object *object,
0147                    struct dentry *dentry)
0148 {
0149     int ret;
0150 
0151     ret = cachefiles_inject_remove_error();
0152     if (ret == 0)
0153         ret = vfs_removexattr(&init_user_ns, dentry, cachefiles_xattr_cache);
0154     if (ret < 0) {
0155         trace_cachefiles_vfs_error(object, d_inode(dentry), ret,
0156                        cachefiles_trace_remxattr_error);
0157         if (ret == -ENOENT || ret == -ENODATA)
0158             ret = 0;
0159         else if (ret != -ENOMEM)
0160             cachefiles_io_error(cache,
0161                         "Can't remove xattr from %lu"
0162                         " (error %d)",
0163                         d_backing_inode(dentry)->i_ino, -ret);
0164     }
0165 
0166     _leave(" = %d", ret);
0167     return ret;
0168 }
0169 
0170 /*
0171  * Stick a marker on the cache object to indicate that it's dirty.
0172  */
0173 void cachefiles_prepare_to_write(struct fscache_cookie *cookie)
0174 {
0175     const struct cred *saved_cred;
0176     struct cachefiles_object *object = cookie->cache_priv;
0177     struct cachefiles_cache *cache = object->volume->cache;
0178 
0179     _enter("c=%08x", object->cookie->debug_id);
0180 
0181     if (!test_bit(CACHEFILES_OBJECT_USING_TMPFILE, &object->flags)) {
0182         cachefiles_begin_secure(cache, &saved_cred);
0183         cachefiles_set_object_xattr(object);
0184         cachefiles_end_secure(cache, saved_cred);
0185     }
0186 }
0187 
0188 /*
0189  * Set the state xattr on a volume directory.
0190  */
0191 bool cachefiles_set_volume_xattr(struct cachefiles_volume *volume)
0192 {
0193     struct cachefiles_vol_xattr *buf;
0194     unsigned int len = volume->vcookie->coherency_len;
0195     const void *p = volume->vcookie->coherency;
0196     struct dentry *dentry = volume->dentry;
0197     int ret;
0198 
0199     _enter("%x,#%d", volume->vcookie->debug_id, len);
0200 
0201     len += sizeof(*buf);
0202     buf = kmalloc(len, GFP_KERNEL);
0203     if (!buf)
0204         return false;
0205     buf->reserved = cpu_to_be32(0);
0206     memcpy(buf->data, p, volume->vcookie->coherency_len);
0207 
0208     ret = cachefiles_inject_write_error();
0209     if (ret == 0)
0210         ret = vfs_setxattr(&init_user_ns, dentry, cachefiles_xattr_cache,
0211                    buf, len, 0);
0212     if (ret < 0) {
0213         trace_cachefiles_vfs_error(NULL, d_inode(dentry), ret,
0214                        cachefiles_trace_setxattr_error);
0215         trace_cachefiles_vol_coherency(volume, d_inode(dentry)->i_ino,
0216                            cachefiles_coherency_vol_set_fail);
0217         if (ret != -ENOMEM)
0218             cachefiles_io_error(
0219                 volume->cache, "Failed to set xattr with error %d", ret);
0220     } else {
0221         trace_cachefiles_vol_coherency(volume, d_inode(dentry)->i_ino,
0222                            cachefiles_coherency_vol_set_ok);
0223     }
0224 
0225     kfree(buf);
0226     _leave(" = %d", ret);
0227     return ret == 0;
0228 }
0229 
0230 /*
0231  * Check the consistency between the backing cache and the volume cookie.
0232  */
0233 int cachefiles_check_volume_xattr(struct cachefiles_volume *volume)
0234 {
0235     struct cachefiles_vol_xattr *buf;
0236     struct dentry *dentry = volume->dentry;
0237     unsigned int len = volume->vcookie->coherency_len;
0238     const void *p = volume->vcookie->coherency;
0239     enum cachefiles_coherency_trace why;
0240     ssize_t xlen;
0241     int ret = -ESTALE;
0242 
0243     _enter("");
0244 
0245     len += sizeof(*buf);
0246     buf = kmalloc(len, GFP_KERNEL);
0247     if (!buf)
0248         return -ENOMEM;
0249 
0250     xlen = cachefiles_inject_read_error();
0251     if (xlen == 0)
0252         xlen = vfs_getxattr(&init_user_ns, dentry, cachefiles_xattr_cache, buf, len);
0253     if (xlen != len) {
0254         if (xlen < 0) {
0255             trace_cachefiles_vfs_error(NULL, d_inode(dentry), xlen,
0256                            cachefiles_trace_getxattr_error);
0257             if (xlen == -EIO)
0258                 cachefiles_io_error(
0259                     volume->cache,
0260                     "Failed to read xattr with error %zd", xlen);
0261         }
0262         why = cachefiles_coherency_vol_check_xattr;
0263     } else if (buf->reserved != cpu_to_be32(0)) {
0264         why = cachefiles_coherency_vol_check_resv;
0265     } else if (memcmp(buf->data, p, len - sizeof(*buf)) != 0) {
0266         why = cachefiles_coherency_vol_check_cmp;
0267     } else {
0268         why = cachefiles_coherency_vol_check_ok;
0269         ret = 0;
0270     }
0271 
0272     trace_cachefiles_vol_coherency(volume, d_inode(dentry)->i_ino, why);
0273     kfree(buf);
0274     _leave(" = %d", ret);
0275     return ret;
0276 }