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