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