linux/fs/cachefiles/xattr.c
<<
>>
Prefs
   1/* CacheFiles extended attribute management
   2 *
   3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
   4 * Written by David Howells (dhowells@redhat.com)
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public Licence
   8 * as published by the Free Software Foundation; either version
   9 * 2 of the Licence, or (at your option) any later version.
  10 */
  11
  12#include <linux/module.h>
  13#include <linux/sched.h>
  14#include <linux/file.h>
  15#include <linux/fs.h>
  16#include <linux/fsnotify.h>
  17#include <linux/quotaops.h>
  18#include <linux/xattr.h>
  19#include <linux/slab.h>
  20#include "internal.h"
  21
  22static const char cachefiles_xattr_cache[] =
  23        XATTR_USER_PREFIX "CacheFiles.cache";
  24
  25/*
  26 * check the type label on an object
  27 * - done using xattrs
  28 */
  29int cachefiles_check_object_type(struct cachefiles_object *object)
  30{
  31        struct dentry *dentry = object->dentry;
  32        char type[3], xtype[3];
  33        int ret;
  34
  35        ASSERT(dentry);
  36        ASSERT(d_backing_inode(dentry));
  37
  38        if (!object->fscache.cookie)
  39                strcpy(type, "C3");
  40        else
  41                snprintf(type, 3, "%02x", object->fscache.cookie->def->type);
  42
  43        _enter("%p{%s}", object, type);
  44
  45        /* attempt to install a type label directly */
  46        ret = vfs_setxattr(dentry, cachefiles_xattr_cache, type, 2,
  47                           XATTR_CREATE);
  48        if (ret == 0) {
  49                _debug("SET"); /* we succeeded */
  50                goto error;
  51        }
  52
  53        if (ret != -EEXIST) {
  54                pr_err("Can't set xattr on %pd [%lu] (err %d)\n",
  55                       dentry, d_backing_inode(dentry)->i_ino,
  56                       -ret);
  57                goto error;
  58        }
  59
  60        /* read the current type label */
  61        ret = vfs_getxattr(dentry, cachefiles_xattr_cache, xtype, 3);
  62        if (ret < 0) {
  63                if (ret == -ERANGE)
  64                        goto bad_type_length;
  65
  66                pr_err("Can't read xattr on %pd [%lu] (err %d)\n",
  67                       dentry, d_backing_inode(dentry)->i_ino,
  68                       -ret);
  69                goto error;
  70        }
  71
  72        /* check the type is what we're expecting */
  73        if (ret != 2)
  74                goto bad_type_length;
  75
  76        if (xtype[0] != type[0] || xtype[1] != type[1])
  77                goto bad_type;
  78
  79        ret = 0;
  80
  81error:
  82        _leave(" = %d", ret);
  83        return ret;
  84
  85bad_type_length:
  86        pr_err("Cache object %lu type xattr length incorrect\n",
  87               d_backing_inode(dentry)->i_ino);
  88        ret = -EIO;
  89        goto error;
  90
  91bad_type:
  92        xtype[2] = 0;
  93        pr_err("Cache object %pd [%lu] type %s not %s\n",
  94               dentry, d_backing_inode(dentry)->i_ino,
  95               xtype, type);
  96        ret = -EIO;
  97        goto error;
  98}
  99
 100/*
 101 * set the state xattr on a cache file
 102 */
 103int cachefiles_set_object_xattr(struct cachefiles_object *object,
 104                                struct cachefiles_xattr *auxdata)
 105{
 106        struct dentry *dentry = object->dentry;
 107        int ret;
 108
 109        ASSERT(dentry);
 110
 111        _enter("%p,#%d", object, auxdata->len);
 112
 113        /* attempt to install the cache metadata directly */
 114        _debug("SET #%u", auxdata->len);
 115
 116        ret = vfs_setxattr(dentry, cachefiles_xattr_cache,
 117                           &auxdata->type, auxdata->len,
 118                           XATTR_CREATE);
 119        if (ret < 0 && ret != -ENOMEM)
 120                cachefiles_io_error_obj(
 121                        object,
 122                        "Failed to set xattr with error %d", ret);
 123
 124        _leave(" = %d", ret);
 125        return ret;
 126}
 127
 128/*
 129 * update the state xattr on a cache file
 130 */
 131int cachefiles_update_object_xattr(struct cachefiles_object *object,
 132                                   struct cachefiles_xattr *auxdata)
 133{
 134        struct dentry *dentry = object->dentry;
 135        int ret;
 136
 137        ASSERT(dentry);
 138
 139        _enter("%p,#%d", object, auxdata->len);
 140
 141        /* attempt to install the cache metadata directly */
 142        _debug("SET #%u", auxdata->len);
 143
 144        ret = vfs_setxattr(dentry, cachefiles_xattr_cache,
 145                           &auxdata->type, auxdata->len,
 146                           XATTR_REPLACE);
 147        if (ret < 0 && ret != -ENOMEM)
 148                cachefiles_io_error_obj(
 149                        object,
 150                        "Failed to update xattr with error %d", ret);
 151
 152        _leave(" = %d", ret);
 153        return ret;
 154}
 155
 156/*
 157 * check the consistency between the backing cache and the FS-Cache cookie
 158 */
 159int cachefiles_check_auxdata(struct cachefiles_object *object)
 160{
 161        struct cachefiles_xattr *auxbuf;
 162        enum fscache_checkaux validity;
 163        struct dentry *dentry = object->dentry;
 164        ssize_t xlen;
 165        int ret;
 166
 167        ASSERT(dentry);
 168        ASSERT(d_backing_inode(dentry));
 169        ASSERT(object->fscache.cookie->def->check_aux);
 170
 171        auxbuf = kmalloc(sizeof(struct cachefiles_xattr) + 512, GFP_KERNEL);
 172        if (!auxbuf)
 173                return -ENOMEM;
 174
 175        xlen = vfs_getxattr(dentry, cachefiles_xattr_cache,
 176                            &auxbuf->type, 512 + 1);
 177        ret = -ESTALE;
 178        if (xlen < 1 ||
 179            auxbuf->type != object->fscache.cookie->def->type)
 180                goto error;
 181
 182        xlen--;
 183        validity = fscache_check_aux(&object->fscache, &auxbuf->data, xlen);
 184        if (validity != FSCACHE_CHECKAUX_OKAY)
 185                goto error;
 186
 187        ret = 0;
 188error:
 189        kfree(auxbuf);
 190        return ret;
 191}
 192
 193/*
 194 * check the state xattr on a cache file
 195 * - return -ESTALE if the object should be deleted
 196 */
 197int cachefiles_check_object_xattr(struct cachefiles_object *object,
 198                                  struct cachefiles_xattr *auxdata)
 199{
 200        struct cachefiles_xattr *auxbuf;
 201        struct dentry *dentry = object->dentry;
 202        int ret;
 203
 204        _enter("%p,#%d", object, auxdata->len);
 205
 206        ASSERT(dentry);
 207        ASSERT(d_backing_inode(dentry));
 208
 209        auxbuf = kmalloc(sizeof(struct cachefiles_xattr) + 512, cachefiles_gfp);
 210        if (!auxbuf) {
 211                _leave(" = -ENOMEM");
 212                return -ENOMEM;
 213        }
 214
 215        /* read the current type label */
 216        ret = vfs_getxattr(dentry, cachefiles_xattr_cache,
 217                           &auxbuf->type, 512 + 1);
 218        if (ret < 0) {
 219                if (ret == -ENODATA)
 220                        goto stale; /* no attribute - power went off
 221                                     * mid-cull? */
 222
 223                if (ret == -ERANGE)
 224                        goto bad_type_length;
 225
 226                cachefiles_io_error_obj(object,
 227                                        "Can't read xattr on %lu (err %d)",
 228                                        d_backing_inode(dentry)->i_ino, -ret);
 229                goto error;
 230        }
 231
 232        /* check the on-disk object */
 233        if (ret < 1)
 234                goto bad_type_length;
 235
 236        if (auxbuf->type != auxdata->type)
 237                goto stale;
 238
 239        auxbuf->len = ret;
 240
 241        /* consult the netfs */
 242        if (object->fscache.cookie->def->check_aux) {
 243                enum fscache_checkaux result;
 244                unsigned int dlen;
 245
 246                dlen = auxbuf->len - 1;
 247
 248                _debug("checkaux %s #%u",
 249                       object->fscache.cookie->def->name, dlen);
 250
 251                result = fscache_check_aux(&object->fscache,
 252                                           &auxbuf->data, dlen);
 253
 254                switch (result) {
 255                        /* entry okay as is */
 256                case FSCACHE_CHECKAUX_OKAY:
 257                        goto okay;
 258
 259                        /* entry requires update */
 260                case FSCACHE_CHECKAUX_NEEDS_UPDATE:
 261                        break;
 262
 263                        /* entry requires deletion */
 264                case FSCACHE_CHECKAUX_OBSOLETE:
 265                        goto stale;
 266
 267                default:
 268                        BUG();
 269                }
 270
 271                /* update the current label */
 272                ret = vfs_setxattr(dentry, cachefiles_xattr_cache,
 273                                   &auxdata->type, auxdata->len,
 274                                   XATTR_REPLACE);
 275                if (ret < 0) {
 276                        cachefiles_io_error_obj(object,
 277                                                "Can't update xattr on %lu"
 278                                                " (error %d)",
 279                                                d_backing_inode(dentry)->i_ino, -ret);
 280                        goto error;
 281                }
 282        }
 283
 284okay:
 285        ret = 0;
 286
 287error:
 288        kfree(auxbuf);
 289        _leave(" = %d", ret);
 290        return ret;
 291
 292bad_type_length:
 293        pr_err("Cache object %lu xattr length incorrect\n",
 294               d_backing_inode(dentry)->i_ino);
 295        ret = -EIO;
 296        goto error;
 297
 298stale:
 299        ret = -ESTALE;
 300        goto error;
 301}
 302
 303/*
 304 * remove the object's xattr to mark it stale
 305 */
 306int cachefiles_remove_object_xattr(struct cachefiles_cache *cache,
 307                                   struct dentry *dentry)
 308{
 309        int ret;
 310
 311        ret = vfs_removexattr(dentry, cachefiles_xattr_cache);
 312        if (ret < 0) {
 313                if (ret == -ENOENT || ret == -ENODATA)
 314                        ret = 0;
 315                else if (ret != -ENOMEM)
 316                        cachefiles_io_error(cache,
 317                                            "Can't remove xattr from %lu"
 318                                            " (error %d)",
 319                                            d_backing_inode(dentry)->i_ino, -ret);
 320        }
 321
 322        _leave(" = %d", ret);
 323        return ret;
 324}
 325