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(dentry->d_inode);
  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                kerror("Can't set xattr on %*.*s [%lu] (err %d)",
  55                       dentry->d_name.len, dentry->d_name.len,
  56                       dentry->d_name.name, dentry->d_inode->i_ino,
  57                       -ret);
  58                goto error;
  59        }
  60
  61        /* read the current type label */
  62        ret = vfs_getxattr(dentry, cachefiles_xattr_cache, xtype, 3);
  63        if (ret < 0) {
  64                if (ret == -ERANGE)
  65                        goto bad_type_length;
  66
  67                kerror("Can't read xattr on %*.*s [%lu] (err %d)",
  68                       dentry->d_name.len, dentry->d_name.len,
  69                       dentry->d_name.name, dentry->d_inode->i_ino,
  70                       -ret);
  71                goto error;
  72        }
  73
  74        /* check the type is what we're expecting */
  75        if (ret != 2)
  76                goto bad_type_length;
  77
  78        if (xtype[0] != type[0] || xtype[1] != type[1])
  79                goto bad_type;
  80
  81        ret = 0;
  82
  83error:
  84        _leave(" = %d", ret);
  85        return ret;
  86
  87bad_type_length:
  88        kerror("Cache object %lu type xattr length incorrect",
  89               dentry->d_inode->i_ino);
  90        ret = -EIO;
  91        goto error;
  92
  93bad_type:
  94        xtype[2] = 0;
  95        kerror("Cache object %*.*s [%lu] type %s not %s",
  96               dentry->d_name.len, dentry->d_name.len,
  97               dentry->d_name.name, dentry->d_inode->i_ino,
  98               xtype, type);
  99        ret = -EIO;
 100        goto error;
 101}
 102
 103/*
 104 * set the state xattr on a cache file
 105 */
 106int cachefiles_set_object_xattr(struct cachefiles_object *object,
 107                                struct cachefiles_xattr *auxdata)
 108{
 109        struct dentry *dentry = object->dentry;
 110        int ret;
 111
 112        ASSERT(object->fscache.cookie);
 113        ASSERT(dentry);
 114
 115        _enter("%p,#%d", object, auxdata->len);
 116
 117        /* attempt to install the cache metadata directly */
 118        _debug("SET %s #%u", object->fscache.cookie->def->name, auxdata->len);
 119
 120        ret = vfs_setxattr(dentry, cachefiles_xattr_cache,
 121                           &auxdata->type, auxdata->len,
 122                           XATTR_CREATE);
 123        if (ret < 0 && ret != -ENOMEM)
 124                cachefiles_io_error_obj(
 125                        object,
 126                        "Failed to set xattr with error %d", ret);
 127
 128        _leave(" = %d", ret);
 129        return ret;
 130}
 131
 132/*
 133 * update the state xattr on a cache file
 134 */
 135int cachefiles_update_object_xattr(struct cachefiles_object *object,
 136                                   struct cachefiles_xattr *auxdata)
 137{
 138        struct dentry *dentry = object->dentry;
 139        int ret;
 140
 141        ASSERT(object->fscache.cookie);
 142        ASSERT(dentry);
 143
 144        _enter("%p,#%d", object, auxdata->len);
 145
 146        /* attempt to install the cache metadata directly */
 147        _debug("SET %s #%u", object->fscache.cookie->def->name, auxdata->len);
 148
 149        ret = vfs_setxattr(dentry, cachefiles_xattr_cache,
 150                           &auxdata->type, auxdata->len,
 151                           XATTR_REPLACE);
 152        if (ret < 0 && ret != -ENOMEM)
 153                cachefiles_io_error_obj(
 154                        object,
 155                        "Failed to update xattr with error %d", ret);
 156
 157        _leave(" = %d", ret);
 158        return ret;
 159}
 160
 161/*
 162 * check the state xattr on a cache file
 163 * - return -ESTALE if the object should be deleted
 164 */
 165int cachefiles_check_object_xattr(struct cachefiles_object *object,
 166                                  struct cachefiles_xattr *auxdata)
 167{
 168        struct cachefiles_xattr *auxbuf;
 169        struct dentry *dentry = object->dentry;
 170        int ret;
 171
 172        _enter("%p,#%d", object, auxdata->len);
 173
 174        ASSERT(dentry);
 175        ASSERT(dentry->d_inode);
 176
 177        auxbuf = kmalloc(sizeof(struct cachefiles_xattr) + 512, GFP_KERNEL);
 178        if (!auxbuf) {
 179                _leave(" = -ENOMEM");
 180                return -ENOMEM;
 181        }
 182
 183        /* read the current type label */
 184        ret = vfs_getxattr(dentry, cachefiles_xattr_cache,
 185                           &auxbuf->type, 512 + 1);
 186        if (ret < 0) {
 187                if (ret == -ENODATA)
 188                        goto stale; /* no attribute - power went off
 189                                     * mid-cull? */
 190
 191                if (ret == -ERANGE)
 192                        goto bad_type_length;
 193
 194                cachefiles_io_error_obj(object,
 195                                        "Can't read xattr on %lu (err %d)",
 196                                        dentry->d_inode->i_ino, -ret);
 197                goto error;
 198        }
 199
 200        /* check the on-disk object */
 201        if (ret < 1)
 202                goto bad_type_length;
 203
 204        if (auxbuf->type != auxdata->type)
 205                goto stale;
 206
 207        auxbuf->len = ret;
 208
 209        /* consult the netfs */
 210        if (object->fscache.cookie->def->check_aux) {
 211                enum fscache_checkaux result;
 212                unsigned int dlen;
 213
 214                dlen = auxbuf->len - 1;
 215
 216                _debug("checkaux %s #%u",
 217                       object->fscache.cookie->def->name, dlen);
 218
 219                result = fscache_check_aux(&object->fscache,
 220                                           &auxbuf->data, dlen);
 221
 222                switch (result) {
 223                        /* entry okay as is */
 224                case FSCACHE_CHECKAUX_OKAY:
 225                        goto okay;
 226
 227                        /* entry requires update */
 228                case FSCACHE_CHECKAUX_NEEDS_UPDATE:
 229                        break;
 230
 231                        /* entry requires deletion */
 232                case FSCACHE_CHECKAUX_OBSOLETE:
 233                        goto stale;
 234
 235                default:
 236                        BUG();
 237                }
 238
 239                /* update the current label */
 240                ret = vfs_setxattr(dentry, cachefiles_xattr_cache,
 241                                   &auxdata->type, auxdata->len,
 242                                   XATTR_REPLACE);
 243                if (ret < 0) {
 244                        cachefiles_io_error_obj(object,
 245                                                "Can't update xattr on %lu"
 246                                                " (error %d)",
 247                                                dentry->d_inode->i_ino, -ret);
 248                        goto error;
 249                }
 250        }
 251
 252okay:
 253        ret = 0;
 254
 255error:
 256        kfree(auxbuf);
 257        _leave(" = %d", ret);
 258        return ret;
 259
 260bad_type_length:
 261        kerror("Cache object %lu xattr length incorrect",
 262               dentry->d_inode->i_ino);
 263        ret = -EIO;
 264        goto error;
 265
 266stale:
 267        ret = -ESTALE;
 268        goto error;
 269}
 270
 271/*
 272 * remove the object's xattr to mark it stale
 273 */
 274int cachefiles_remove_object_xattr(struct cachefiles_cache *cache,
 275                                   struct dentry *dentry)
 276{
 277        int ret;
 278
 279        ret = vfs_removexattr(dentry, cachefiles_xattr_cache);
 280        if (ret < 0) {
 281                if (ret == -ENOENT || ret == -ENODATA)
 282                        ret = 0;
 283                else if (ret != -ENOMEM)
 284                        cachefiles_io_error(cache,
 285                                            "Can't remove xattr from %lu"
 286                                            " (error %d)",
 287                                            dentry->d_inode->i_ino, -ret);
 288        }
 289
 290        _leave(" = %d", ret);
 291        return ret;
 292}
 293