linux/fs/cifs/fscache.c
<<
>>
Prefs
   1// SPDX-License-Identifier: LGPL-2.1
   2/*
   3 *   CIFS filesystem cache interface
   4 *
   5 *   Copyright (c) 2010 Novell, Inc.
   6 *   Author(s): Suresh Jayaraman <sjayaraman@suse.de>
   7 *
   8 */
   9#include "fscache.h"
  10#include "cifsglob.h"
  11#include "cifs_debug.h"
  12#include "cifs_fs_sb.h"
  13#include "cifsproto.h"
  14
  15/*
  16 * Key layout of CIFS server cache index object
  17 */
  18struct cifs_server_key {
  19        struct {
  20                uint16_t        family;         /* address family */
  21                __be16          port;           /* IP port */
  22        } hdr;
  23        union {
  24                struct in_addr  ipv4_addr;
  25                struct in6_addr ipv6_addr;
  26        };
  27} __packed;
  28
  29/*
  30 * Get a cookie for a server object keyed by {IPaddress,port,family} tuple
  31 */
  32void cifs_fscache_get_client_cookie(struct TCP_Server_Info *server)
  33{
  34        const struct sockaddr *sa = (struct sockaddr *) &server->dstaddr;
  35        const struct sockaddr_in *addr = (struct sockaddr_in *) sa;
  36        const struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) sa;
  37        struct cifs_server_key key;
  38        uint16_t key_len = sizeof(key.hdr);
  39
  40        memset(&key, 0, sizeof(key));
  41
  42        /*
  43         * Should not be a problem as sin_family/sin6_family overlays
  44         * sa_family field
  45         */
  46        key.hdr.family = sa->sa_family;
  47        switch (sa->sa_family) {
  48        case AF_INET:
  49                key.hdr.port = addr->sin_port;
  50                key.ipv4_addr = addr->sin_addr;
  51                key_len += sizeof(key.ipv4_addr);
  52                break;
  53
  54        case AF_INET6:
  55                key.hdr.port = addr6->sin6_port;
  56                key.ipv6_addr = addr6->sin6_addr;
  57                key_len += sizeof(key.ipv6_addr);
  58                break;
  59
  60        default:
  61                cifs_dbg(VFS, "Unknown network family '%d'\n", sa->sa_family);
  62                server->fscache = NULL;
  63                return;
  64        }
  65
  66        server->fscache =
  67                fscache_acquire_cookie(cifs_fscache_netfs.primary_index,
  68                                       &cifs_fscache_server_index_def,
  69                                       &key, key_len,
  70                                       NULL, 0,
  71                                       server, 0, true);
  72        cifs_dbg(FYI, "%s: (0x%p/0x%p)\n",
  73                 __func__, server, server->fscache);
  74}
  75
  76void cifs_fscache_release_client_cookie(struct TCP_Server_Info *server)
  77{
  78        cifs_dbg(FYI, "%s: (0x%p/0x%p)\n",
  79                 __func__, server, server->fscache);
  80        fscache_relinquish_cookie(server->fscache, NULL, false);
  81        server->fscache = NULL;
  82}
  83
  84void cifs_fscache_get_super_cookie(struct cifs_tcon *tcon)
  85{
  86        struct TCP_Server_Info *server = tcon->ses->server;
  87        char *sharename;
  88        struct cifs_fscache_super_auxdata auxdata;
  89
  90        sharename = extract_sharename(tcon->treeName);
  91        if (IS_ERR(sharename)) {
  92                cifs_dbg(FYI, "%s: couldn't extract sharename\n", __func__);
  93                tcon->fscache = NULL;
  94                return;
  95        }
  96
  97        memset(&auxdata, 0, sizeof(auxdata));
  98        auxdata.resource_id = tcon->resource_id;
  99        auxdata.vol_create_time = tcon->vol_create_time;
 100        auxdata.vol_serial_number = tcon->vol_serial_number;
 101
 102        tcon->fscache =
 103                fscache_acquire_cookie(server->fscache,
 104                                       &cifs_fscache_super_index_def,
 105                                       sharename, strlen(sharename),
 106                                       &auxdata, sizeof(auxdata),
 107                                       tcon, 0, true);
 108        kfree(sharename);
 109        cifs_dbg(FYI, "%s: (0x%p/0x%p)\n",
 110                 __func__, server->fscache, tcon->fscache);
 111}
 112
 113void cifs_fscache_release_super_cookie(struct cifs_tcon *tcon)
 114{
 115        struct cifs_fscache_super_auxdata auxdata;
 116
 117        memset(&auxdata, 0, sizeof(auxdata));
 118        auxdata.resource_id = tcon->resource_id;
 119        auxdata.vol_create_time = tcon->vol_create_time;
 120        auxdata.vol_serial_number = tcon->vol_serial_number;
 121
 122        cifs_dbg(FYI, "%s: (0x%p)\n", __func__, tcon->fscache);
 123        fscache_relinquish_cookie(tcon->fscache, &auxdata, false);
 124        tcon->fscache = NULL;
 125}
 126
 127static void cifs_fscache_acquire_inode_cookie(struct cifsInodeInfo *cifsi,
 128                                              struct cifs_tcon *tcon)
 129{
 130        struct cifs_fscache_inode_auxdata auxdata;
 131
 132        memset(&auxdata, 0, sizeof(auxdata));
 133        auxdata.eof = cifsi->server_eof;
 134        auxdata.last_write_time_sec = cifsi->vfs_inode.i_mtime.tv_sec;
 135        auxdata.last_change_time_sec = cifsi->vfs_inode.i_ctime.tv_sec;
 136        auxdata.last_write_time_nsec = cifsi->vfs_inode.i_mtime.tv_nsec;
 137        auxdata.last_change_time_nsec = cifsi->vfs_inode.i_ctime.tv_nsec;
 138
 139        cifsi->fscache =
 140                fscache_acquire_cookie(tcon->fscache,
 141                                       &cifs_fscache_inode_object_def,
 142                                       &cifsi->uniqueid, sizeof(cifsi->uniqueid),
 143                                       &auxdata, sizeof(auxdata),
 144                                       cifsi, cifsi->vfs_inode.i_size, true);
 145}
 146
 147static void cifs_fscache_enable_inode_cookie(struct inode *inode)
 148{
 149        struct cifsInodeInfo *cifsi = CIFS_I(inode);
 150        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 151        struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
 152
 153        if (cifsi->fscache)
 154                return;
 155
 156        if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE))
 157                return;
 158
 159        cifs_fscache_acquire_inode_cookie(cifsi, tcon);
 160
 161        cifs_dbg(FYI, "%s: got FH cookie (0x%p/0x%p)\n",
 162                 __func__, tcon->fscache, cifsi->fscache);
 163}
 164
 165void cifs_fscache_release_inode_cookie(struct inode *inode)
 166{
 167        struct cifs_fscache_inode_auxdata auxdata;
 168        struct cifsInodeInfo *cifsi = CIFS_I(inode);
 169
 170        if (cifsi->fscache) {
 171                memset(&auxdata, 0, sizeof(auxdata));
 172                auxdata.eof = cifsi->server_eof;
 173                auxdata.last_write_time_sec = cifsi->vfs_inode.i_mtime.tv_sec;
 174                auxdata.last_change_time_sec = cifsi->vfs_inode.i_ctime.tv_sec;
 175                auxdata.last_write_time_nsec = cifsi->vfs_inode.i_mtime.tv_nsec;
 176                auxdata.last_change_time_nsec = cifsi->vfs_inode.i_ctime.tv_nsec;
 177
 178                cifs_dbg(FYI, "%s: (0x%p)\n", __func__, cifsi->fscache);
 179                /* fscache_relinquish_cookie does not seem to update auxdata */
 180                fscache_update_cookie(cifsi->fscache, &auxdata);
 181                fscache_relinquish_cookie(cifsi->fscache, &auxdata, false);
 182                cifsi->fscache = NULL;
 183        }
 184}
 185
 186void cifs_fscache_update_inode_cookie(struct inode *inode)
 187{
 188        struct cifs_fscache_inode_auxdata auxdata;
 189        struct cifsInodeInfo *cifsi = CIFS_I(inode);
 190
 191        if (cifsi->fscache) {
 192                memset(&auxdata, 0, sizeof(auxdata));
 193                auxdata.eof = cifsi->server_eof;
 194                auxdata.last_write_time_sec = cifsi->vfs_inode.i_mtime.tv_sec;
 195                auxdata.last_change_time_sec = cifsi->vfs_inode.i_ctime.tv_sec;
 196                auxdata.last_write_time_nsec = cifsi->vfs_inode.i_mtime.tv_nsec;
 197                auxdata.last_change_time_nsec = cifsi->vfs_inode.i_ctime.tv_nsec;
 198
 199                cifs_dbg(FYI, "%s: (0x%p)\n", __func__, cifsi->fscache);
 200                fscache_update_cookie(cifsi->fscache, &auxdata);
 201        }
 202}
 203
 204void cifs_fscache_set_inode_cookie(struct inode *inode, struct file *filp)
 205{
 206        cifs_fscache_enable_inode_cookie(inode);
 207}
 208
 209void cifs_fscache_reset_inode_cookie(struct inode *inode)
 210{
 211        struct cifsInodeInfo *cifsi = CIFS_I(inode);
 212        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 213        struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
 214        struct fscache_cookie *old = cifsi->fscache;
 215
 216        if (cifsi->fscache) {
 217                /* retire the current fscache cache and get a new one */
 218                fscache_relinquish_cookie(cifsi->fscache, NULL, true);
 219
 220                cifs_fscache_acquire_inode_cookie(cifsi, tcon);
 221                cifs_dbg(FYI, "%s: new cookie 0x%p oldcookie 0x%p\n",
 222                         __func__, cifsi->fscache, old);
 223        }
 224}
 225
 226int cifs_fscache_release_page(struct page *page, gfp_t gfp)
 227{
 228        if (PageFsCache(page)) {
 229                struct inode *inode = page->mapping->host;
 230                struct cifsInodeInfo *cifsi = CIFS_I(inode);
 231
 232                cifs_dbg(FYI, "%s: (0x%p/0x%p)\n",
 233                         __func__, page, cifsi->fscache);
 234                if (!fscache_maybe_release_page(cifsi->fscache, page, gfp))
 235                        return 0;
 236        }
 237
 238        return 1;
 239}
 240
 241static void cifs_readpage_from_fscache_complete(struct page *page, void *ctx,
 242                                                int error)
 243{
 244        cifs_dbg(FYI, "%s: (0x%p/%d)\n", __func__, page, error);
 245        if (!error)
 246                SetPageUptodate(page);
 247        unlock_page(page);
 248}
 249
 250/*
 251 * Retrieve a page from FS-Cache
 252 */
 253int __cifs_readpage_from_fscache(struct inode *inode, struct page *page)
 254{
 255        int ret;
 256
 257        cifs_dbg(FYI, "%s: (fsc:%p, p:%p, i:0x%p\n",
 258                 __func__, CIFS_I(inode)->fscache, page, inode);
 259        ret = fscache_read_or_alloc_page(CIFS_I(inode)->fscache, page,
 260                                         cifs_readpage_from_fscache_complete,
 261                                         NULL,
 262                                         GFP_KERNEL);
 263        switch (ret) {
 264
 265        case 0: /* page found in fscache, read submitted */
 266                cifs_dbg(FYI, "%s: submitted\n", __func__);
 267                return ret;
 268        case -ENOBUFS:  /* page won't be cached */
 269        case -ENODATA:  /* page not in cache */
 270                cifs_dbg(FYI, "%s: %d\n", __func__, ret);
 271                return 1;
 272
 273        default:
 274                cifs_dbg(VFS, "unknown error ret = %d\n", ret);
 275        }
 276        return ret;
 277}
 278
 279/*
 280 * Retrieve a set of pages from FS-Cache
 281 */
 282int __cifs_readpages_from_fscache(struct inode *inode,
 283                                struct address_space *mapping,
 284                                struct list_head *pages,
 285                                unsigned *nr_pages)
 286{
 287        int ret;
 288
 289        cifs_dbg(FYI, "%s: (0x%p/%u/0x%p)\n",
 290                 __func__, CIFS_I(inode)->fscache, *nr_pages, inode);
 291        ret = fscache_read_or_alloc_pages(CIFS_I(inode)->fscache, mapping,
 292                                          pages, nr_pages,
 293                                          cifs_readpage_from_fscache_complete,
 294                                          NULL,
 295                                          mapping_gfp_mask(mapping));
 296        switch (ret) {
 297        case 0: /* read submitted to the cache for all pages */
 298                cifs_dbg(FYI, "%s: submitted\n", __func__);
 299                return ret;
 300
 301        case -ENOBUFS:  /* some pages are not cached and can't be */
 302        case -ENODATA:  /* some pages are not cached */
 303                cifs_dbg(FYI, "%s: no page\n", __func__);
 304                return 1;
 305
 306        default:
 307                cifs_dbg(FYI, "unknown error ret = %d\n", ret);
 308        }
 309
 310        return ret;
 311}
 312
 313void __cifs_readpage_to_fscache(struct inode *inode, struct page *page)
 314{
 315        struct cifsInodeInfo *cifsi = CIFS_I(inode);
 316        int ret;
 317
 318        WARN_ON(!cifsi->fscache);
 319
 320        cifs_dbg(FYI, "%s: (fsc: %p, p: %p, i: %p)\n",
 321                 __func__, cifsi->fscache, page, inode);
 322        ret = fscache_write_page(cifsi->fscache, page,
 323                                 cifsi->vfs_inode.i_size, GFP_KERNEL);
 324        if (ret != 0)
 325                fscache_uncache_page(cifsi->fscache, page);
 326}
 327
 328void __cifs_fscache_readpages_cancel(struct inode *inode, struct list_head *pages)
 329{
 330        cifs_dbg(FYI, "%s: (fsc: %p, i: %p)\n",
 331                 __func__, CIFS_I(inode)->fscache, inode);
 332        fscache_readpages_cancel(CIFS_I(inode)->fscache, pages);
 333}
 334
 335void __cifs_fscache_invalidate_page(struct page *page, struct inode *inode)
 336{
 337        struct cifsInodeInfo *cifsi = CIFS_I(inode);
 338        struct fscache_cookie *cookie = cifsi->fscache;
 339
 340        cifs_dbg(FYI, "%s: (0x%p/0x%p)\n", __func__, page, cookie);
 341        fscache_wait_on_page_write(cookie, page);
 342        fscache_uncache_page(cookie, page);
 343}
 344
 345void __cifs_fscache_wait_on_page_write(struct inode *inode, struct page *page)
 346{
 347        struct cifsInodeInfo *cifsi = CIFS_I(inode);
 348        struct fscache_cookie *cookie = cifsi->fscache;
 349
 350        cifs_dbg(FYI, "%s: (0x%p/0x%p)\n", __func__, page, cookie);
 351        fscache_wait_on_page_write(cookie, page);
 352}
 353
 354void __cifs_fscache_uncache_page(struct inode *inode, struct page *page)
 355{
 356        struct cifsInodeInfo *cifsi = CIFS_I(inode);
 357        struct fscache_cookie *cookie = cifsi->fscache;
 358
 359        cifs_dbg(FYI, "%s: (0x%p/0x%p)\n", __func__, page, cookie);
 360        fscache_uncache_page(cookie, page);
 361}
 362