linux/fs/cachefiles/interface.c
<<
>>
Prefs
   1/* FS-Cache interface to CacheFiles
   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/slab.h>
  13#include <linux/mount.h>
  14#include <linux/buffer_head.h>
  15#include "internal.h"
  16
  17#define list_to_page(head) (list_entry((head)->prev, struct page, lru))
  18
  19struct cachefiles_lookup_data {
  20        struct cachefiles_xattr *auxdata;       /* auxiliary data */
  21        char                    *key;           /* key path */
  22};
  23
  24static int cachefiles_attr_changed(struct fscache_object *_object);
  25
  26/*
  27 * allocate an object record for a cookie lookup and prepare the lookup data
  28 */
  29static struct fscache_object *cachefiles_alloc_object(
  30        struct fscache_cache *_cache,
  31        struct fscache_cookie *cookie)
  32{
  33        struct cachefiles_lookup_data *lookup_data;
  34        struct cachefiles_object *object;
  35        struct cachefiles_cache *cache;
  36        struct cachefiles_xattr *auxdata;
  37        unsigned keylen, auxlen;
  38        void *buffer;
  39        char *key;
  40
  41        cache = container_of(_cache, struct cachefiles_cache, cache);
  42
  43        _enter("{%s},%p,", cache->cache.identifier, cookie);
  44
  45        lookup_data = kmalloc(sizeof(*lookup_data), GFP_KERNEL);
  46        if (!lookup_data)
  47                goto nomem_lookup_data;
  48
  49        /* create a new object record and a temporary leaf image */
  50        object = kmem_cache_alloc(cachefiles_object_jar, GFP_KERNEL);
  51        if (!object)
  52                goto nomem_object;
  53
  54        ASSERTCMP(object->backer, ==, NULL);
  55
  56        BUG_ON(test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags));
  57        atomic_set(&object->usage, 1);
  58
  59        fscache_object_init(&object->fscache, cookie, &cache->cache);
  60
  61        object->type = cookie->def->type;
  62
  63        /* get hold of the raw key
  64         * - stick the length on the front and leave space on the back for the
  65         *   encoder
  66         */
  67        buffer = kmalloc((2 + 512) + 3, GFP_KERNEL);
  68        if (!buffer)
  69                goto nomem_buffer;
  70
  71        keylen = cookie->def->get_key(cookie->netfs_data, buffer + 2, 512);
  72        ASSERTCMP(keylen, <, 512);
  73
  74        *(uint16_t *)buffer = keylen;
  75        ((char *)buffer)[keylen + 2] = 0;
  76        ((char *)buffer)[keylen + 3] = 0;
  77        ((char *)buffer)[keylen + 4] = 0;
  78
  79        /* turn the raw key into something that can work with as a filename */
  80        key = cachefiles_cook_key(buffer, keylen + 2, object->type);
  81        if (!key)
  82                goto nomem_key;
  83
  84        /* get hold of the auxiliary data and prepend the object type */
  85        auxdata = buffer;
  86        auxlen = 0;
  87        if (cookie->def->get_aux) {
  88                auxlen = cookie->def->get_aux(cookie->netfs_data,
  89                                              auxdata->data, 511);
  90                ASSERTCMP(auxlen, <, 511);
  91        }
  92
  93        auxdata->len = auxlen + 1;
  94        auxdata->type = cookie->def->type;
  95
  96        lookup_data->auxdata = auxdata;
  97        lookup_data->key = key;
  98        object->lookup_data = lookup_data;
  99
 100        _leave(" = %p [%p]", &object->fscache, lookup_data);
 101        return &object->fscache;
 102
 103nomem_key:
 104        kfree(buffer);
 105nomem_buffer:
 106        BUG_ON(test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags));
 107        kmem_cache_free(cachefiles_object_jar, object);
 108        fscache_object_destroyed(&cache->cache);
 109nomem_object:
 110        kfree(lookup_data);
 111nomem_lookup_data:
 112        _leave(" = -ENOMEM");
 113        return ERR_PTR(-ENOMEM);
 114}
 115
 116/*
 117 * attempt to look up the nominated node in this cache
 118 * - return -ETIMEDOUT to be scheduled again
 119 */
 120static int cachefiles_lookup_object(struct fscache_object *_object)
 121{
 122        struct cachefiles_lookup_data *lookup_data;
 123        struct cachefiles_object *parent, *object;
 124        struct cachefiles_cache *cache;
 125        const struct cred *saved_cred;
 126        int ret;
 127
 128        _enter("{OBJ%x}", _object->debug_id);
 129
 130        cache = container_of(_object->cache, struct cachefiles_cache, cache);
 131        parent = container_of(_object->parent,
 132                              struct cachefiles_object, fscache);
 133        object = container_of(_object, struct cachefiles_object, fscache);
 134        lookup_data = object->lookup_data;
 135
 136        ASSERTCMP(lookup_data, !=, NULL);
 137
 138        /* look up the key, creating any missing bits */
 139        cachefiles_begin_secure(cache, &saved_cred);
 140        ret = cachefiles_walk_to_object(parent, object,
 141                                        lookup_data->key,
 142                                        lookup_data->auxdata);
 143        cachefiles_end_secure(cache, saved_cred);
 144
 145        /* polish off by setting the attributes of non-index files */
 146        if (ret == 0 &&
 147            object->fscache.cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX)
 148                cachefiles_attr_changed(&object->fscache);
 149
 150        if (ret < 0 && ret != -ETIMEDOUT) {
 151                if (ret != -ENOBUFS)
 152                        printk(KERN_WARNING
 153                               "CacheFiles: Lookup failed error %d\n", ret);
 154                fscache_object_lookup_error(&object->fscache);
 155        }
 156
 157        _leave(" [%d]", ret);
 158        return ret;
 159}
 160
 161/*
 162 * indication of lookup completion
 163 */
 164static void cachefiles_lookup_complete(struct fscache_object *_object)
 165{
 166        struct cachefiles_object *object;
 167
 168        object = container_of(_object, struct cachefiles_object, fscache);
 169
 170        _enter("{OBJ%x,%p}", object->fscache.debug_id, object->lookup_data);
 171
 172        if (object->lookup_data) {
 173                kfree(object->lookup_data->key);
 174                kfree(object->lookup_data->auxdata);
 175                kfree(object->lookup_data);
 176                object->lookup_data = NULL;
 177        }
 178}
 179
 180/*
 181 * increment the usage count on an inode object (may fail if unmounting)
 182 */
 183static
 184struct fscache_object *cachefiles_grab_object(struct fscache_object *_object)
 185{
 186        struct cachefiles_object *object =
 187                container_of(_object, struct cachefiles_object, fscache);
 188
 189        _enter("{OBJ%x,%d}", _object->debug_id, atomic_read(&object->usage));
 190
 191#ifdef CACHEFILES_DEBUG_SLAB
 192        ASSERT((atomic_read(&object->usage) & 0xffff0000) != 0x6b6b0000);
 193#endif
 194
 195        atomic_inc(&object->usage);
 196        return &object->fscache;
 197}
 198
 199/*
 200 * update the auxilliary data for an object object on disk
 201 */
 202static void cachefiles_update_object(struct fscache_object *_object)
 203{
 204        struct cachefiles_object *object;
 205        struct cachefiles_xattr *auxdata;
 206        struct cachefiles_cache *cache;
 207        struct fscache_cookie *cookie;
 208        const struct cred *saved_cred;
 209        unsigned auxlen;
 210
 211        _enter("{OBJ%x}", _object->debug_id);
 212
 213        object = container_of(_object, struct cachefiles_object, fscache);
 214        cache = container_of(object->fscache.cache, struct cachefiles_cache,
 215                             cache);
 216        cookie = object->fscache.cookie;
 217
 218        if (!cookie->def->get_aux) {
 219                _leave(" [no aux]");
 220                return;
 221        }
 222
 223        auxdata = kmalloc(2 + 512 + 3, GFP_KERNEL);
 224        if (!auxdata) {
 225                _leave(" [nomem]");
 226                return;
 227        }
 228
 229        auxlen = cookie->def->get_aux(cookie->netfs_data, auxdata->data, 511);
 230        ASSERTCMP(auxlen, <, 511);
 231
 232        auxdata->len = auxlen + 1;
 233        auxdata->type = cookie->def->type;
 234
 235        cachefiles_begin_secure(cache, &saved_cred);
 236        cachefiles_update_object_xattr(object, auxdata);
 237        cachefiles_end_secure(cache, saved_cred);
 238        kfree(auxdata);
 239        _leave("");
 240}
 241
 242/*
 243 * discard the resources pinned by an object and effect retirement if
 244 * requested
 245 */
 246static void cachefiles_drop_object(struct fscache_object *_object)
 247{
 248        struct cachefiles_object *object;
 249        struct cachefiles_cache *cache;
 250        const struct cred *saved_cred;
 251
 252        ASSERT(_object);
 253
 254        object = container_of(_object, struct cachefiles_object, fscache);
 255
 256        _enter("{OBJ%x,%d}",
 257               object->fscache.debug_id, atomic_read(&object->usage));
 258
 259        cache = container_of(object->fscache.cache,
 260                             struct cachefiles_cache, cache);
 261
 262#ifdef CACHEFILES_DEBUG_SLAB
 263        ASSERT((atomic_read(&object->usage) & 0xffff0000) != 0x6b6b0000);
 264#endif
 265
 266        /* delete retired objects */
 267        if (object->fscache.state == FSCACHE_OBJECT_RECYCLING &&
 268            _object != cache->cache.fsdef
 269            ) {
 270                _debug("- retire object OBJ%x", object->fscache.debug_id);
 271                cachefiles_begin_secure(cache, &saved_cred);
 272                cachefiles_delete_object(cache, object);
 273                cachefiles_end_secure(cache, saved_cred);
 274        }
 275
 276        /* close the filesystem stuff attached to the object */
 277        if (object->backer != object->dentry)
 278                dput(object->backer);
 279        object->backer = NULL;
 280
 281        /* note that the object is now inactive */
 282        if (test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags)) {
 283                write_lock(&cache->active_lock);
 284                if (!test_and_clear_bit(CACHEFILES_OBJECT_ACTIVE,
 285                                        &object->flags))
 286                        BUG();
 287                rb_erase(&object->active_node, &cache->active_nodes);
 288                wake_up_bit(&object->flags, CACHEFILES_OBJECT_ACTIVE);
 289                write_unlock(&cache->active_lock);
 290        }
 291
 292        dput(object->dentry);
 293        object->dentry = NULL;
 294
 295        _leave("");
 296}
 297
 298/*
 299 * dispose of a reference to an object
 300 */
 301static void cachefiles_put_object(struct fscache_object *_object)
 302{
 303        struct cachefiles_object *object;
 304        struct fscache_cache *cache;
 305
 306        ASSERT(_object);
 307
 308        object = container_of(_object, struct cachefiles_object, fscache);
 309
 310        _enter("{OBJ%x,%d}",
 311               object->fscache.debug_id, atomic_read(&object->usage));
 312
 313#ifdef CACHEFILES_DEBUG_SLAB
 314        ASSERT((atomic_read(&object->usage) & 0xffff0000) != 0x6b6b0000);
 315#endif
 316
 317        ASSERTIFCMP(object->fscache.parent,
 318                    object->fscache.parent->n_children, >, 0);
 319
 320        if (atomic_dec_and_test(&object->usage)) {
 321                _debug("- kill object OBJ%x", object->fscache.debug_id);
 322
 323                ASSERT(!test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags));
 324                ASSERTCMP(object->fscache.parent, ==, NULL);
 325                ASSERTCMP(object->backer, ==, NULL);
 326                ASSERTCMP(object->dentry, ==, NULL);
 327                ASSERTCMP(object->fscache.n_ops, ==, 0);
 328                ASSERTCMP(object->fscache.n_children, ==, 0);
 329
 330                if (object->lookup_data) {
 331                        kfree(object->lookup_data->key);
 332                        kfree(object->lookup_data->auxdata);
 333                        kfree(object->lookup_data);
 334                        object->lookup_data = NULL;
 335                }
 336
 337                cache = object->fscache.cache;
 338                fscache_object_destroy(&object->fscache);
 339                kmem_cache_free(cachefiles_object_jar, object);
 340                fscache_object_destroyed(cache);
 341        }
 342
 343        _leave("");
 344}
 345
 346/*
 347 * sync a cache
 348 */
 349static void cachefiles_sync_cache(struct fscache_cache *_cache)
 350{
 351        struct cachefiles_cache *cache;
 352        const struct cred *saved_cred;
 353        int ret;
 354
 355        _enter("%p", _cache);
 356
 357        cache = container_of(_cache, struct cachefiles_cache, cache);
 358
 359        /* make sure all pages pinned by operations on behalf of the netfs are
 360         * written to disc */
 361        cachefiles_begin_secure(cache, &saved_cred);
 362        down_read(&cache->mnt->mnt_sb->s_umount);
 363        ret = sync_filesystem(cache->mnt->mnt_sb);
 364        up_read(&cache->mnt->mnt_sb->s_umount);
 365        cachefiles_end_secure(cache, saved_cred);
 366
 367        if (ret == -EIO)
 368                cachefiles_io_error(cache,
 369                                    "Attempt to sync backing fs superblock"
 370                                    " returned error %d",
 371                                    ret);
 372}
 373
 374/*
 375 * notification the attributes on an object have changed
 376 * - called with reads/writes excluded by FS-Cache
 377 */
 378static int cachefiles_attr_changed(struct fscache_object *_object)
 379{
 380        struct cachefiles_object *object;
 381        struct cachefiles_cache *cache;
 382        const struct cred *saved_cred;
 383        struct iattr newattrs;
 384        uint64_t ni_size;
 385        loff_t oi_size;
 386        int ret;
 387
 388        _object->cookie->def->get_attr(_object->cookie->netfs_data, &ni_size);
 389
 390        _enter("{OBJ%x},[%llu]",
 391               _object->debug_id, (unsigned long long) ni_size);
 392
 393        object = container_of(_object, struct cachefiles_object, fscache);
 394        cache = container_of(object->fscache.cache,
 395                             struct cachefiles_cache, cache);
 396
 397        if (ni_size == object->i_size)
 398                return 0;
 399
 400        if (!object->backer)
 401                return -ENOBUFS;
 402
 403        ASSERT(S_ISREG(object->backer->d_inode->i_mode));
 404
 405        fscache_set_store_limit(&object->fscache, ni_size);
 406
 407        oi_size = i_size_read(object->backer->d_inode);
 408        if (oi_size == ni_size)
 409                return 0;
 410
 411        cachefiles_begin_secure(cache, &saved_cred);
 412        mutex_lock(&object->backer->d_inode->i_mutex);
 413
 414        /* if there's an extension to a partial page at the end of the backing
 415         * file, we need to discard the partial page so that we pick up new
 416         * data after it */
 417        if (oi_size & ~PAGE_MASK && ni_size > oi_size) {
 418                _debug("discard tail %llx", oi_size);
 419                newattrs.ia_valid = ATTR_SIZE;
 420                newattrs.ia_size = oi_size & PAGE_MASK;
 421                ret = notify_change(object->backer, &newattrs);
 422                if (ret < 0)
 423                        goto truncate_failed;
 424        }
 425
 426        newattrs.ia_valid = ATTR_SIZE;
 427        newattrs.ia_size = ni_size;
 428        ret = notify_change(object->backer, &newattrs);
 429
 430truncate_failed:
 431        mutex_unlock(&object->backer->d_inode->i_mutex);
 432        cachefiles_end_secure(cache, saved_cred);
 433
 434        if (ret == -EIO) {
 435                fscache_set_store_limit(&object->fscache, 0);
 436                cachefiles_io_error_obj(object, "Size set failed");
 437                ret = -ENOBUFS;
 438        }
 439
 440        _leave(" = %d", ret);
 441        return ret;
 442}
 443
 444/*
 445 * dissociate a cache from all the pages it was backing
 446 */
 447static void cachefiles_dissociate_pages(struct fscache_cache *cache)
 448{
 449        _enter("");
 450}
 451
 452const struct fscache_cache_ops cachefiles_cache_ops = {
 453        .name                   = "cachefiles",
 454        .alloc_object           = cachefiles_alloc_object,
 455        .lookup_object          = cachefiles_lookup_object,
 456        .lookup_complete        = cachefiles_lookup_complete,
 457        .grab_object            = cachefiles_grab_object,
 458        .update_object          = cachefiles_update_object,
 459        .drop_object            = cachefiles_drop_object,
 460        .put_object             = cachefiles_put_object,
 461        .sync_cache             = cachefiles_sync_cache,
 462        .attr_changed           = cachefiles_attr_changed,
 463        .read_or_alloc_page     = cachefiles_read_or_alloc_page,
 464        .read_or_alloc_pages    = cachefiles_read_or_alloc_pages,
 465        .allocate_page          = cachefiles_allocate_page,
 466        .allocate_pages         = cachefiles_allocate_pages,
 467        .write_page             = cachefiles_write_page,
 468        .uncache_page           = cachefiles_uncache_page,
 469        .dissociate_pages       = cachefiles_dissociate_pages,
 470};
 471