linux/fs/afs/cache.c
<<
>>
Prefs
   1/* AFS caching stuff
   2 *
   3 * Copyright (C) 2008 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 License
   8 * as published by the Free Software Foundation; either version
   9 * 2 of the License, or (at your option) any later version.
  10 */
  11
  12#include <linux/sched.h>
  13#include "internal.h"
  14
  15static uint16_t afs_cell_cache_get_key(const void *cookie_netfs_data,
  16                                       void *buffer, uint16_t buflen);
  17static uint16_t afs_cell_cache_get_aux(const void *cookie_netfs_data,
  18                                       void *buffer, uint16_t buflen);
  19static enum fscache_checkaux afs_cell_cache_check_aux(void *cookie_netfs_data,
  20                                                      const void *buffer,
  21                                                      uint16_t buflen);
  22
  23static uint16_t afs_vlocation_cache_get_key(const void *cookie_netfs_data,
  24                                            void *buffer, uint16_t buflen);
  25static uint16_t afs_vlocation_cache_get_aux(const void *cookie_netfs_data,
  26                                            void *buffer, uint16_t buflen);
  27static enum fscache_checkaux afs_vlocation_cache_check_aux(
  28        void *cookie_netfs_data, const void *buffer, uint16_t buflen);
  29
  30static uint16_t afs_volume_cache_get_key(const void *cookie_netfs_data,
  31                                         void *buffer, uint16_t buflen);
  32
  33static uint16_t afs_vnode_cache_get_key(const void *cookie_netfs_data,
  34                                        void *buffer, uint16_t buflen);
  35static void afs_vnode_cache_get_attr(const void *cookie_netfs_data,
  36                                     uint64_t *size);
  37static uint16_t afs_vnode_cache_get_aux(const void *cookie_netfs_data,
  38                                        void *buffer, uint16_t buflen);
  39static enum fscache_checkaux afs_vnode_cache_check_aux(void *cookie_netfs_data,
  40                                                       const void *buffer,
  41                                                       uint16_t buflen);
  42static void afs_vnode_cache_now_uncached(void *cookie_netfs_data);
  43
  44struct fscache_netfs afs_cache_netfs = {
  45        .name                   = "afs",
  46        .version                = 0,
  47};
  48
  49struct fscache_cookie_def afs_cell_cache_index_def = {
  50        .name           = "AFS.cell",
  51        .type           = FSCACHE_COOKIE_TYPE_INDEX,
  52        .get_key        = afs_cell_cache_get_key,
  53        .get_aux        = afs_cell_cache_get_aux,
  54        .check_aux      = afs_cell_cache_check_aux,
  55};
  56
  57struct fscache_cookie_def afs_vlocation_cache_index_def = {
  58        .name                   = "AFS.vldb",
  59        .type                   = FSCACHE_COOKIE_TYPE_INDEX,
  60        .get_key                = afs_vlocation_cache_get_key,
  61        .get_aux                = afs_vlocation_cache_get_aux,
  62        .check_aux              = afs_vlocation_cache_check_aux,
  63};
  64
  65struct fscache_cookie_def afs_volume_cache_index_def = {
  66        .name           = "AFS.volume",
  67        .type           = FSCACHE_COOKIE_TYPE_INDEX,
  68        .get_key        = afs_volume_cache_get_key,
  69};
  70
  71struct fscache_cookie_def afs_vnode_cache_index_def = {
  72        .name                   = "AFS.vnode",
  73        .type                   = FSCACHE_COOKIE_TYPE_DATAFILE,
  74        .get_key                = afs_vnode_cache_get_key,
  75        .get_attr               = afs_vnode_cache_get_attr,
  76        .get_aux                = afs_vnode_cache_get_aux,
  77        .check_aux              = afs_vnode_cache_check_aux,
  78        .now_uncached           = afs_vnode_cache_now_uncached,
  79};
  80
  81/*
  82 * set the key for the index entry
  83 */
  84static uint16_t afs_cell_cache_get_key(const void *cookie_netfs_data,
  85                                       void *buffer, uint16_t bufmax)
  86{
  87        const struct afs_cell *cell = cookie_netfs_data;
  88        uint16_t klen;
  89
  90        _enter("%p,%p,%u", cell, buffer, bufmax);
  91
  92        klen = strlen(cell->name);
  93        if (klen > bufmax)
  94                return 0;
  95
  96        memcpy(buffer, cell->name, klen);
  97        return klen;
  98}
  99
 100/*
 101 * provide new auxilliary cache data
 102 */
 103static uint16_t afs_cell_cache_get_aux(const void *cookie_netfs_data,
 104                                       void *buffer, uint16_t bufmax)
 105{
 106        const struct afs_cell *cell = cookie_netfs_data;
 107        uint16_t dlen;
 108
 109        _enter("%p,%p,%u", cell, buffer, bufmax);
 110
 111        dlen = cell->vl_naddrs * sizeof(cell->vl_addrs[0]);
 112        dlen = min(dlen, bufmax);
 113        dlen &= ~(sizeof(cell->vl_addrs[0]) - 1);
 114
 115        memcpy(buffer, cell->vl_addrs, dlen);
 116        return dlen;
 117}
 118
 119/*
 120 * check that the auxilliary data indicates that the entry is still valid
 121 */
 122static enum fscache_checkaux afs_cell_cache_check_aux(void *cookie_netfs_data,
 123                                                      const void *buffer,
 124                                                      uint16_t buflen)
 125{
 126        _leave(" = OKAY");
 127        return FSCACHE_CHECKAUX_OKAY;
 128}
 129
 130/*****************************************************************************/
 131/*
 132 * set the key for the index entry
 133 */
 134static uint16_t afs_vlocation_cache_get_key(const void *cookie_netfs_data,
 135                                            void *buffer, uint16_t bufmax)
 136{
 137        const struct afs_vlocation *vlocation = cookie_netfs_data;
 138        uint16_t klen;
 139
 140        _enter("{%s},%p,%u", vlocation->vldb.name, buffer, bufmax);
 141
 142        klen = strnlen(vlocation->vldb.name, sizeof(vlocation->vldb.name));
 143        if (klen > bufmax)
 144                return 0;
 145
 146        memcpy(buffer, vlocation->vldb.name, klen);
 147
 148        _leave(" = %u", klen);
 149        return klen;
 150}
 151
 152/*
 153 * provide new auxilliary cache data
 154 */
 155static uint16_t afs_vlocation_cache_get_aux(const void *cookie_netfs_data,
 156                                            void *buffer, uint16_t bufmax)
 157{
 158        const struct afs_vlocation *vlocation = cookie_netfs_data;
 159        uint16_t dlen;
 160
 161        _enter("{%s},%p,%u", vlocation->vldb.name, buffer, bufmax);
 162
 163        dlen = sizeof(struct afs_cache_vlocation);
 164        dlen -= offsetof(struct afs_cache_vlocation, nservers);
 165        if (dlen > bufmax)
 166                return 0;
 167
 168        memcpy(buffer, (uint8_t *)&vlocation->vldb.nservers, dlen);
 169
 170        _leave(" = %u", dlen);
 171        return dlen;
 172}
 173
 174/*
 175 * check that the auxilliary data indicates that the entry is still valid
 176 */
 177static
 178enum fscache_checkaux afs_vlocation_cache_check_aux(void *cookie_netfs_data,
 179                                                    const void *buffer,
 180                                                    uint16_t buflen)
 181{
 182        const struct afs_cache_vlocation *cvldb;
 183        struct afs_vlocation *vlocation = cookie_netfs_data;
 184        uint16_t dlen;
 185
 186        _enter("{%s},%p,%u", vlocation->vldb.name, buffer, buflen);
 187
 188        /* check the size of the data is what we're expecting */
 189        dlen = sizeof(struct afs_cache_vlocation);
 190        dlen -= offsetof(struct afs_cache_vlocation, nservers);
 191        if (dlen != buflen)
 192                return FSCACHE_CHECKAUX_OBSOLETE;
 193
 194        cvldb = container_of(buffer, struct afs_cache_vlocation, nservers);
 195
 196        /* if what's on disk is more valid than what's in memory, then use the
 197         * VL record from the cache */
 198        if (!vlocation->valid || vlocation->vldb.rtime == cvldb->rtime) {
 199                memcpy((uint8_t *)&vlocation->vldb.nservers, buffer, dlen);
 200                vlocation->valid = 1;
 201                _leave(" = SUCCESS [c->m]");
 202                return FSCACHE_CHECKAUX_OKAY;
 203        }
 204
 205        /* need to update the cache if the cached info differs */
 206        if (memcmp(&vlocation->vldb, buffer, dlen) != 0) {
 207                /* delete if the volume IDs for this name differ */
 208                if (memcmp(&vlocation->vldb.vid, &cvldb->vid,
 209                           sizeof(cvldb->vid)) != 0
 210                    ) {
 211                        _leave(" = OBSOLETE");
 212                        return FSCACHE_CHECKAUX_OBSOLETE;
 213                }
 214
 215                _leave(" = UPDATE");
 216                return FSCACHE_CHECKAUX_NEEDS_UPDATE;
 217        }
 218
 219        _leave(" = OKAY");
 220        return FSCACHE_CHECKAUX_OKAY;
 221}
 222
 223/*****************************************************************************/
 224/*
 225 * set the key for the volume index entry
 226 */
 227static uint16_t afs_volume_cache_get_key(const void *cookie_netfs_data,
 228                                        void *buffer, uint16_t bufmax)
 229{
 230        const struct afs_volume *volume = cookie_netfs_data;
 231        uint16_t klen;
 232
 233        _enter("{%u},%p,%u", volume->type, buffer, bufmax);
 234
 235        klen = sizeof(volume->type);
 236        if (klen > bufmax)
 237                return 0;
 238
 239        memcpy(buffer, &volume->type, sizeof(volume->type));
 240
 241        _leave(" = %u", klen);
 242        return klen;
 243
 244}
 245
 246/*****************************************************************************/
 247/*
 248 * set the key for the index entry
 249 */
 250static uint16_t afs_vnode_cache_get_key(const void *cookie_netfs_data,
 251                                        void *buffer, uint16_t bufmax)
 252{
 253        const struct afs_vnode *vnode = cookie_netfs_data;
 254        uint16_t klen;
 255
 256        _enter("{%x,%x,%llx},%p,%u",
 257               vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version,
 258               buffer, bufmax);
 259
 260        klen = sizeof(vnode->fid.vnode);
 261        if (klen > bufmax)
 262                return 0;
 263
 264        memcpy(buffer, &vnode->fid.vnode, sizeof(vnode->fid.vnode));
 265
 266        _leave(" = %u", klen);
 267        return klen;
 268}
 269
 270/*
 271 * provide updated file attributes
 272 */
 273static void afs_vnode_cache_get_attr(const void *cookie_netfs_data,
 274                                     uint64_t *size)
 275{
 276        const struct afs_vnode *vnode = cookie_netfs_data;
 277
 278        _enter("{%x,%x,%llx},",
 279               vnode->fid.vnode, vnode->fid.unique,
 280               vnode->status.data_version);
 281
 282        *size = vnode->status.size;
 283}
 284
 285/*
 286 * provide new auxilliary cache data
 287 */
 288static uint16_t afs_vnode_cache_get_aux(const void *cookie_netfs_data,
 289                                        void *buffer, uint16_t bufmax)
 290{
 291        const struct afs_vnode *vnode = cookie_netfs_data;
 292        uint16_t dlen;
 293
 294        _enter("{%x,%x,%Lx},%p,%u",
 295               vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version,
 296               buffer, bufmax);
 297
 298        dlen = sizeof(vnode->fid.unique) + sizeof(vnode->status.data_version);
 299        if (dlen > bufmax)
 300                return 0;
 301
 302        memcpy(buffer, &vnode->fid.unique, sizeof(vnode->fid.unique));
 303        buffer += sizeof(vnode->fid.unique);
 304        memcpy(buffer, &vnode->status.data_version,
 305               sizeof(vnode->status.data_version));
 306
 307        _leave(" = %u", dlen);
 308        return dlen;
 309}
 310
 311/*
 312 * check that the auxilliary data indicates that the entry is still valid
 313 */
 314static enum fscache_checkaux afs_vnode_cache_check_aux(void *cookie_netfs_data,
 315                                                       const void *buffer,
 316                                                       uint16_t buflen)
 317{
 318        struct afs_vnode *vnode = cookie_netfs_data;
 319        uint16_t dlen;
 320
 321        _enter("{%x,%x,%llx},%p,%u",
 322               vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version,
 323               buffer, buflen);
 324
 325        /* check the size of the data is what we're expecting */
 326        dlen = sizeof(vnode->fid.unique) + sizeof(vnode->status.data_version);
 327        if (dlen != buflen) {
 328                _leave(" = OBSOLETE [len %hx != %hx]", dlen, buflen);
 329                return FSCACHE_CHECKAUX_OBSOLETE;
 330        }
 331
 332        if (memcmp(buffer,
 333                   &vnode->fid.unique,
 334                   sizeof(vnode->fid.unique)
 335                   ) != 0) {
 336                unsigned unique;
 337
 338                memcpy(&unique, buffer, sizeof(unique));
 339
 340                _leave(" = OBSOLETE [uniq %x != %x]",
 341                       unique, vnode->fid.unique);
 342                return FSCACHE_CHECKAUX_OBSOLETE;
 343        }
 344
 345        if (memcmp(buffer + sizeof(vnode->fid.unique),
 346                   &vnode->status.data_version,
 347                   sizeof(vnode->status.data_version)
 348                   ) != 0) {
 349                afs_dataversion_t version;
 350
 351                memcpy(&version, buffer + sizeof(vnode->fid.unique),
 352                       sizeof(version));
 353
 354                _leave(" = OBSOLETE [vers %llx != %llx]",
 355                       version, vnode->status.data_version);
 356                return FSCACHE_CHECKAUX_OBSOLETE;
 357        }
 358
 359        _leave(" = SUCCESS");
 360        return FSCACHE_CHECKAUX_OKAY;
 361}
 362
 363/*
 364 * indication the cookie is no longer uncached
 365 * - this function is called when the backing store currently caching a cookie
 366 *   is removed
 367 * - the netfs should use this to clean up any markers indicating cached pages
 368 * - this is mandatory for any object that may have data
 369 */
 370static void afs_vnode_cache_now_uncached(void *cookie_netfs_data)
 371{
 372        struct afs_vnode *vnode = cookie_netfs_data;
 373        struct pagevec pvec;
 374        pgoff_t first;
 375        int loop, nr_pages;
 376
 377        _enter("{%x,%x,%Lx}",
 378               vnode->fid.vnode, vnode->fid.unique, vnode->status.data_version);
 379
 380        pagevec_init(&pvec, 0);
 381        first = 0;
 382
 383        for (;;) {
 384                /* grab a bunch of pages to clean */
 385                nr_pages = pagevec_lookup(&pvec, vnode->vfs_inode.i_mapping,
 386                                          first,
 387                                          PAGEVEC_SIZE - pagevec_count(&pvec));
 388                if (!nr_pages)
 389                        break;
 390
 391                for (loop = 0; loop < nr_pages; loop++)
 392                        ClearPageFsCache(pvec.pages[loop]);
 393
 394                first = pvec.pages[nr_pages - 1]->index + 1;
 395
 396                pvec.nr = nr_pages;
 397                pagevec_release(&pvec);
 398                cond_resched();
 399        }
 400
 401        _leave("");
 402}
 403