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
  16struct cachefiles_lookup_data {
  17        struct cachefiles_xattr *auxdata;       /* auxiliary data */
  18        char                    *key;           /* key path */
  19};
  20
  21static int cachefiles_attr_changed(struct fscache_object *_object);
  22
  23/*
  24 * allocate an object record for a cookie lookup and prepare the lookup data
  25 */
  26static struct fscache_object *cachefiles_alloc_object(
  27        struct fscache_cache *_cache,
  28        struct fscache_cookie *cookie)
  29{
  30        struct cachefiles_lookup_data *lookup_data;
  31        struct cachefiles_object *object;
  32        struct cachefiles_cache *cache;
  33        struct cachefiles_xattr *auxdata;
  34        unsigned keylen, auxlen;
  35        void *buffer, *p;
  36        char *key;
  37
  38        cache = container_of(_cache, struct cachefiles_cache, cache);
  39
  40        _enter("{%s},%p,", cache->cache.identifier, cookie);
  41
  42        lookup_data = kmalloc(sizeof(*lookup_data), cachefiles_gfp);
  43        if (!lookup_data)
  44                goto nomem_lookup_data;
  45
  46        /* create a new object record and a temporary leaf image */
  47        object = kmem_cache_alloc(cachefiles_object_jar, cachefiles_gfp);
  48        if (!object)
  49                goto nomem_object;
  50
  51        ASSERTCMP(object->backer, ==, NULL);
  52
  53        BUG_ON(test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags));
  54        atomic_set(&object->usage, 1);
  55
  56        fscache_object_init(&object->fscache, cookie, &cache->cache);
  57
  58        object->type = cookie->def->type;
  59
  60        /* get hold of the raw key
  61         * - stick the length on the front and leave space on the back for the
  62         *   encoder
  63         */
  64        buffer = kmalloc((2 + 512) + 3, cachefiles_gfp);
  65        if (!buffer)
  66                goto nomem_buffer;
  67
  68        keylen = cookie->key_len;
  69        if (keylen <= sizeof(cookie->inline_key))
  70                p = cookie->inline_key;
  71        else
  72                p = cookie->key;
  73        memcpy(buffer + 2, p, keylen);
  74
  75        *(uint16_t *)buffer = keylen;
  76        ((char *)buffer)[keylen + 2] = 0;
  77        ((char *)buffer)[keylen + 3] = 0;
  78        ((char *)buffer)[keylen + 4] = 0;
  79
  80        /* turn the raw key into something that can work with as a filename */
  81        key = cachefiles_cook_key(buffer, keylen + 2, object->type);
  82        if (!key)
  83                goto nomem_key;
  84
  85        /* get hold of the auxiliary data and prepend the object type */
  86        auxdata = buffer;
  87        auxlen = cookie->aux_len;
  88        if (auxlen) {
  89                if (auxlen <= sizeof(cookie->inline_aux))
  90                        p = cookie->inline_aux;
  91                else
  92                        p = cookie->aux;
  93                memcpy(auxdata->data, p, auxlen);
  94        }
  95
  96        auxdata->len = auxlen + 1;
  97        auxdata->type = cookie->type;
  98
  99        lookup_data->auxdata = auxdata;
 100        lookup_data->key = key;
 101        object->lookup_data = lookup_data;
 102
 103        _leave(" = %p [%p]", &object->fscache, lookup_data);
 104        return &object->fscache;
 105
 106nomem_key:
 107        kfree(buffer);
 108nomem_buffer:
 109        BUG_ON(test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags));
 110        kmem_cache_free(cachefiles_object_jar, object);
 111        fscache_object_destroyed(&cache->cache);
 112nomem_object:
 113        kfree(lookup_data);
 114nomem_lookup_data:
 115        _leave(" = -ENOMEM");
 116        return ERR_PTR(-ENOMEM);
 117}
 118
 119/*
 120 * attempt to look up the nominated node in this cache
 121 * - return -ETIMEDOUT to be scheduled again
 122 */
 123static int cachefiles_lookup_object(struct fscache_object *_object)
 124{
 125        struct cachefiles_lookup_data *lookup_data;
 126        struct cachefiles_object *parent, *object;
 127        struct cachefiles_cache *cache;
 128        const struct cred *saved_cred;
 129        int ret;
 130
 131        _enter("{OBJ%x}", _object->debug_id);
 132
 133        cache = container_of(_object->cache, struct cachefiles_cache, cache);
 134        parent = container_of(_object->parent,
 135                              struct cachefiles_object, fscache);
 136        object = container_of(_object, struct cachefiles_object, fscache);
 137        lookup_data = object->lookup_data;
 138
 139        ASSERTCMP(lookup_data, !=, NULL);
 140
 141        /* look up the key, creating any missing bits */
 142        cachefiles_begin_secure(cache, &saved_cred);
 143        ret = cachefiles_walk_to_object(parent, object,
 144                                        lookup_data->key,
 145                                        lookup_data->auxdata);
 146        cachefiles_end_secure(cache, saved_cred);
 147
 148        /* polish off by setting the attributes of non-index files */
 149        if (ret == 0 &&
 150            object->fscache.cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX)
 151                cachefiles_attr_changed(&object->fscache);
 152
 153        if (ret < 0 && ret != -ETIMEDOUT) {
 154                if (ret != -ENOBUFS)
 155                        pr_warn("Lookup failed error %d\n", ret);
 156                fscache_object_lookup_error(&object->fscache);
 157        }
 158
 159        _leave(" [%d]", ret);
 160        return ret;
 161}
 162
 163/*
 164 * indication of lookup completion
 165 */
 166static void cachefiles_lookup_complete(struct fscache_object *_object)
 167{
 168        struct cachefiles_object *object;
 169
 170        object = container_of(_object, struct cachefiles_object, fscache);
 171
 172        _enter("{OBJ%x,%p}", object->fscache.debug_id, object->lookup_data);
 173
 174        if (object->lookup_data) {
 175                kfree(object->lookup_data->key);
 176                kfree(object->lookup_data->auxdata);
 177                kfree(object->lookup_data);
 178                object->lookup_data = NULL;
 179        }
 180}
 181
 182/*
 183 * increment the usage count on an inode object (may fail if unmounting)
 184 */
 185static
 186struct fscache_object *cachefiles_grab_object(struct fscache_object *_object,
 187                                              enum fscache_obj_ref_trace why)
 188{
 189        struct cachefiles_object *object =
 190                container_of(_object, struct cachefiles_object, fscache);
 191        int u;
 192
 193        _enter("{OBJ%x,%d}", _object->debug_id, atomic_read(&object->usage));
 194
 195#ifdef CACHEFILES_DEBUG_SLAB
 196        ASSERT((atomic_read(&object->usage) & 0xffff0000) != 0x6b6b0000);
 197#endif
 198
 199        u = atomic_inc_return(&object->usage);
 200        trace_cachefiles_ref(object, _object->cookie,
 201                             (enum cachefiles_obj_ref_trace)why, u);
 202        return &object->fscache;
 203}
 204
 205/*
 206 * update the auxiliary data for an object object on disk
 207 */
 208static void cachefiles_update_object(struct fscache_object *_object)
 209{
 210        struct cachefiles_object *object;
 211        struct cachefiles_xattr *auxdata;
 212        struct cachefiles_cache *cache;
 213        struct fscache_cookie *cookie;
 214        const struct cred *saved_cred;
 215        const void *aux;
 216        unsigned auxlen;
 217
 218        _enter("{OBJ%x}", _object->debug_id);
 219
 220        object = container_of(_object, struct cachefiles_object, fscache);
 221        cache = container_of(object->fscache.cache, struct cachefiles_cache,
 222                             cache);
 223
 224        if (!fscache_use_cookie(_object)) {
 225                _leave(" [relinq]");
 226                return;
 227        }
 228
 229        cookie = object->fscache.cookie;
 230        auxlen = cookie->aux_len;
 231
 232        if (!auxlen) {
 233                fscache_unuse_cookie(_object);
 234                _leave(" [no aux]");
 235                return;
 236        }
 237
 238        auxdata = kmalloc(2 + auxlen + 3, cachefiles_gfp);
 239        if (!auxdata) {
 240                fscache_unuse_cookie(_object);
 241                _leave(" [nomem]");
 242                return;
 243        }
 244
 245        aux = (auxlen <= sizeof(cookie->inline_aux)) ?
 246                cookie->inline_aux : cookie->aux;
 247
 248        memcpy(auxdata->data, aux, auxlen);
 249        fscache_unuse_cookie(_object);
 250
 251        auxdata->len = auxlen + 1;
 252        auxdata->type = cookie->type;
 253
 254        cachefiles_begin_secure(cache, &saved_cred);
 255        cachefiles_update_object_xattr(object, auxdata);
 256        cachefiles_end_secure(cache, saved_cred);
 257        kfree(auxdata);
 258        _leave("");
 259}
 260
 261/*
 262 * discard the resources pinned by an object and effect retirement if
 263 * requested
 264 */
 265static void cachefiles_drop_object(struct fscache_object *_object)
 266{
 267        struct cachefiles_object *object;
 268        struct cachefiles_cache *cache;
 269        const struct cred *saved_cred;
 270        struct inode *inode;
 271        blkcnt_t i_blocks = 0;
 272
 273        ASSERT(_object);
 274
 275        object = container_of(_object, struct cachefiles_object, fscache);
 276
 277        _enter("{OBJ%x,%d}",
 278               object->fscache.debug_id, atomic_read(&object->usage));
 279
 280        cache = container_of(object->fscache.cache,
 281                             struct cachefiles_cache, cache);
 282
 283#ifdef CACHEFILES_DEBUG_SLAB
 284        ASSERT((atomic_read(&object->usage) & 0xffff0000) != 0x6b6b0000);
 285#endif
 286
 287        /* We need to tidy the object up if we did in fact manage to open it.
 288         * It's possible for us to get here before the object is fully
 289         * initialised if the parent goes away or the object gets retired
 290         * before we set it up.
 291         */
 292        if (object->dentry) {
 293                /* delete retired objects */
 294                if (test_bit(FSCACHE_OBJECT_RETIRED, &object->fscache.flags) &&
 295                    _object != cache->cache.fsdef
 296                    ) {
 297                        _debug("- retire object OBJ%x", object->fscache.debug_id);
 298                        inode = d_backing_inode(object->dentry);
 299                        if (inode)
 300                                i_blocks = inode->i_blocks;
 301
 302                        cachefiles_begin_secure(cache, &saved_cred);
 303                        cachefiles_delete_object(cache, object);
 304                        cachefiles_end_secure(cache, saved_cred);
 305                }
 306
 307                /* close the filesystem stuff attached to the object */
 308                if (object->backer != object->dentry)
 309                        dput(object->backer);
 310                object->backer = NULL;
 311        }
 312
 313        /* note that the object is now inactive */
 314        if (test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags))
 315                cachefiles_mark_object_inactive(cache, object, i_blocks);
 316
 317        dput(object->dentry);
 318        object->dentry = NULL;
 319
 320        _leave("");
 321}
 322
 323/*
 324 * dispose of a reference to an object
 325 */
 326static void cachefiles_put_object(struct fscache_object *_object,
 327                                  enum fscache_obj_ref_trace why)
 328{
 329        struct cachefiles_object *object;
 330        struct fscache_cache *cache;
 331        int u;
 332
 333        ASSERT(_object);
 334
 335        object = container_of(_object, struct cachefiles_object, fscache);
 336
 337        _enter("{OBJ%x,%d}",
 338               object->fscache.debug_id, atomic_read(&object->usage));
 339
 340#ifdef CACHEFILES_DEBUG_SLAB
 341        ASSERT((atomic_read(&object->usage) & 0xffff0000) != 0x6b6b0000);
 342#endif
 343
 344        ASSERTIFCMP(object->fscache.parent,
 345                    object->fscache.parent->n_children, >, 0);
 346
 347        u = atomic_dec_return(&object->usage);
 348        trace_cachefiles_ref(object, _object->cookie,
 349                             (enum cachefiles_obj_ref_trace)why, u);
 350        ASSERTCMP(u, !=, -1);
 351        if (u == 0) {
 352                _debug("- kill object OBJ%x", object->fscache.debug_id);
 353
 354                ASSERT(!test_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags));
 355                ASSERTCMP(object->fscache.parent, ==, NULL);
 356                ASSERTCMP(object->backer, ==, NULL);
 357                ASSERTCMP(object->dentry, ==, NULL);
 358                ASSERTCMP(object->fscache.n_ops, ==, 0);
 359                ASSERTCMP(object->fscache.n_children, ==, 0);
 360
 361                if (object->lookup_data) {
 362                        kfree(object->lookup_data->key);
 363                        kfree(object->lookup_data->auxdata);
 364                        kfree(object->lookup_data);
 365                        object->lookup_data = NULL;
 366                }
 367
 368                cache = object->fscache.cache;
 369                fscache_object_destroy(&object->fscache);
 370                kmem_cache_free(cachefiles_object_jar, object);
 371                fscache_object_destroyed(cache);
 372        }
 373
 374        _leave("");
 375}
 376
 377/*
 378 * sync a cache
 379 */
 380static void cachefiles_sync_cache(struct fscache_cache *_cache)
 381{
 382        struct cachefiles_cache *cache;
 383        const struct cred *saved_cred;
 384        int ret;
 385
 386        _enter("%p", _cache);
 387
 388        cache = container_of(_cache, struct cachefiles_cache, cache);
 389
 390        /* make sure all pages pinned by operations on behalf of the netfs are
 391         * written to disc */
 392        cachefiles_begin_secure(cache, &saved_cred);
 393        down_read(&cache->mnt->mnt_sb->s_umount);
 394        ret = sync_filesystem(cache->mnt->mnt_sb);
 395        up_read(&cache->mnt->mnt_sb->s_umount);
 396        cachefiles_end_secure(cache, saved_cred);
 397
 398        if (ret == -EIO)
 399                cachefiles_io_error(cache,
 400                                    "Attempt to sync backing fs superblock"
 401                                    " returned error %d",
 402                                    ret);
 403}
 404
 405/*
 406 * check if the backing cache is updated to FS-Cache
 407 * - called by FS-Cache when evaluates if need to invalidate the cache
 408 */
 409static int cachefiles_check_consistency(struct fscache_operation *op)
 410{
 411        struct cachefiles_object *object;
 412        struct cachefiles_cache *cache;
 413        const struct cred *saved_cred;
 414        int ret;
 415
 416        _enter("{OBJ%x}", op->object->debug_id);
 417
 418        object = container_of(op->object, struct cachefiles_object, fscache);
 419        cache = container_of(object->fscache.cache,
 420                             struct cachefiles_cache, cache);
 421
 422        cachefiles_begin_secure(cache, &saved_cred);
 423        ret = cachefiles_check_auxdata(object);
 424        cachefiles_end_secure(cache, saved_cred);
 425
 426        _leave(" = %d", ret);
 427        return ret;
 428}
 429
 430/*
 431 * notification the attributes on an object have changed
 432 * - called with reads/writes excluded by FS-Cache
 433 */
 434static int cachefiles_attr_changed(struct fscache_object *_object)
 435{
 436        struct cachefiles_object *object;
 437        struct cachefiles_cache *cache;
 438        const struct cred *saved_cred;
 439        struct iattr newattrs;
 440        uint64_t ni_size;
 441        loff_t oi_size;
 442        int ret;
 443
 444        ni_size = _object->store_limit_l;
 445
 446        _enter("{OBJ%x},[%llu]",
 447               _object->debug_id, (unsigned long long) ni_size);
 448
 449        object = container_of(_object, struct cachefiles_object, fscache);
 450        cache = container_of(object->fscache.cache,
 451                             struct cachefiles_cache, cache);
 452
 453        if (ni_size == object->i_size)
 454                return 0;
 455
 456        if (!object->backer)
 457                return -ENOBUFS;
 458
 459        ASSERT(d_is_reg(object->backer));
 460
 461        fscache_set_store_limit(&object->fscache, ni_size);
 462
 463        oi_size = i_size_read(d_backing_inode(object->backer));
 464        if (oi_size == ni_size)
 465                return 0;
 466
 467        cachefiles_begin_secure(cache, &saved_cred);
 468        inode_lock(d_inode(object->backer));
 469
 470        /* if there's an extension to a partial page at the end of the backing
 471         * file, we need to discard the partial page so that we pick up new
 472         * data after it */
 473        if (oi_size & ~PAGE_MASK && ni_size > oi_size) {
 474                _debug("discard tail %llx", oi_size);
 475                newattrs.ia_valid = ATTR_SIZE;
 476                newattrs.ia_size = oi_size & PAGE_MASK;
 477                ret = notify_change(object->backer, &newattrs, NULL);
 478                if (ret < 0)
 479                        goto truncate_failed;
 480        }
 481
 482        newattrs.ia_valid = ATTR_SIZE;
 483        newattrs.ia_size = ni_size;
 484        ret = notify_change(object->backer, &newattrs, NULL);
 485
 486truncate_failed:
 487        inode_unlock(d_inode(object->backer));
 488        cachefiles_end_secure(cache, saved_cred);
 489
 490        if (ret == -EIO) {
 491                fscache_set_store_limit(&object->fscache, 0);
 492                cachefiles_io_error_obj(object, "Size set failed");
 493                ret = -ENOBUFS;
 494        }
 495
 496        _leave(" = %d", ret);
 497        return ret;
 498}
 499
 500/*
 501 * Invalidate an object
 502 */
 503static void cachefiles_invalidate_object(struct fscache_operation *op)
 504{
 505        struct cachefiles_object *object;
 506        struct cachefiles_cache *cache;
 507        const struct cred *saved_cred;
 508        struct path path;
 509        uint64_t ni_size;
 510        int ret;
 511
 512        object = container_of(op->object, struct cachefiles_object, fscache);
 513        cache = container_of(object->fscache.cache,
 514                             struct cachefiles_cache, cache);
 515
 516        ni_size = op->object->store_limit_l;
 517
 518        _enter("{OBJ%x},[%llu]",
 519               op->object->debug_id, (unsigned long long)ni_size);
 520
 521        if (object->backer) {
 522                ASSERT(d_is_reg(object->backer));
 523
 524                fscache_set_store_limit(&object->fscache, ni_size);
 525
 526                path.dentry = object->backer;
 527                path.mnt = cache->mnt;
 528
 529                cachefiles_begin_secure(cache, &saved_cred);
 530                ret = vfs_truncate(&path, 0);
 531                if (ret == 0)
 532                        ret = vfs_truncate(&path, ni_size);
 533                cachefiles_end_secure(cache, saved_cred);
 534
 535                if (ret != 0) {
 536                        fscache_set_store_limit(&object->fscache, 0);
 537                        if (ret == -EIO)
 538                                cachefiles_io_error_obj(object,
 539                                                        "Invalidate failed");
 540                }
 541        }
 542
 543        fscache_op_complete(op, true);
 544        _leave("");
 545}
 546
 547/*
 548 * dissociate a cache from all the pages it was backing
 549 */
 550static void cachefiles_dissociate_pages(struct fscache_cache *cache)
 551{
 552        _enter("");
 553}
 554
 555const struct fscache_cache_ops cachefiles_cache_ops = {
 556        .name                   = "cachefiles",
 557        .alloc_object           = cachefiles_alloc_object,
 558        .lookup_object          = cachefiles_lookup_object,
 559        .lookup_complete        = cachefiles_lookup_complete,
 560        .grab_object            = cachefiles_grab_object,
 561        .update_object          = cachefiles_update_object,
 562        .invalidate_object      = cachefiles_invalidate_object,
 563        .drop_object            = cachefiles_drop_object,
 564        .put_object             = cachefiles_put_object,
 565        .sync_cache             = cachefiles_sync_cache,
 566        .attr_changed           = cachefiles_attr_changed,
 567        .read_or_alloc_page     = cachefiles_read_or_alloc_page,
 568        .read_or_alloc_pages    = cachefiles_read_or_alloc_pages,
 569        .allocate_page          = cachefiles_allocate_page,
 570        .allocate_pages         = cachefiles_allocate_pages,
 571        .write_page             = cachefiles_write_page,
 572        .uncache_page           = cachefiles_uncache_page,
 573        .dissociate_pages       = cachefiles_dissociate_pages,
 574        .check_consistency      = cachefiles_check_consistency,
 575};
 576