linux/fs/cifs/fscache.c
<<
>>
Prefs
   1/*
   2 *   fs/cifs/fscache.c - CIFS filesystem cache interface
   3 *
   4 *   Copyright (c) 2010 Novell, Inc.
   5 *   Author(s): Suresh Jayaraman <sjayaraman@suse.de>
   6 *
   7 *   This library is free software; you can redistribute it and/or modify
   8 *   it under the terms of the GNU Lesser General Public License as published
   9 *   by the Free Software Foundation; either version 2.1 of the License, or
  10 *   (at your option) any later version.
  11 *
  12 *   This library is distributed in the hope that it will be useful,
  13 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
  15 *   the GNU Lesser General Public License for more details.
  16 *
  17 *   You should have received a copy of the GNU Lesser General Public License
  18 *   along with this library; if not, write to the Free Software
  19 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20 */
  21#include "fscache.h"
  22#include "cifsglob.h"
  23#include "cifs_debug.h"
  24#include "cifs_fs_sb.h"
  25
  26void cifs_fscache_get_client_cookie(struct TCP_Server_Info *server)
  27{
  28        server->fscache =
  29                fscache_acquire_cookie(cifs_fscache_netfs.primary_index,
  30                                &cifs_fscache_server_index_def, server);
  31        cFYI(1, "CIFS: get client cookie (0x%p/0x%p)", server,
  32                                server->fscache);
  33}
  34
  35void cifs_fscache_release_client_cookie(struct TCP_Server_Info *server)
  36{
  37        cFYI(1, "CIFS: release client cookie (0x%p/0x%p)", server,
  38                                server->fscache);
  39        fscache_relinquish_cookie(server->fscache, 0);
  40        server->fscache = NULL;
  41}
  42
  43void cifs_fscache_get_super_cookie(struct cifsTconInfo *tcon)
  44{
  45        struct TCP_Server_Info *server = tcon->ses->server;
  46
  47        tcon->fscache =
  48                fscache_acquire_cookie(server->fscache,
  49                                &cifs_fscache_super_index_def, tcon);
  50        cFYI(1, "CIFS: get superblock cookie (0x%p/0x%p)",
  51                                server->fscache, tcon->fscache);
  52}
  53
  54void cifs_fscache_release_super_cookie(struct cifsTconInfo *tcon)
  55{
  56        cFYI(1, "CIFS: releasing superblock cookie (0x%p)", tcon->fscache);
  57        fscache_relinquish_cookie(tcon->fscache, 0);
  58        tcon->fscache = NULL;
  59}
  60
  61static void cifs_fscache_enable_inode_cookie(struct inode *inode)
  62{
  63        struct cifsInodeInfo *cifsi = CIFS_I(inode);
  64        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
  65        struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb);
  66
  67        if (cifsi->fscache)
  68                return;
  69
  70        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE) {
  71                cifsi->fscache = fscache_acquire_cookie(tcon->fscache,
  72                                &cifs_fscache_inode_object_def, cifsi);
  73                cFYI(1, "CIFS: got FH cookie (0x%p/0x%p)", tcon->fscache,
  74                                cifsi->fscache);
  75        }
  76}
  77
  78void cifs_fscache_release_inode_cookie(struct inode *inode)
  79{
  80        struct cifsInodeInfo *cifsi = CIFS_I(inode);
  81
  82        if (cifsi->fscache) {
  83                cFYI(1, "CIFS releasing inode cookie (0x%p)",
  84                                cifsi->fscache);
  85                fscache_relinquish_cookie(cifsi->fscache, 0);
  86                cifsi->fscache = NULL;
  87        }
  88}
  89
  90static void cifs_fscache_disable_inode_cookie(struct inode *inode)
  91{
  92        struct cifsInodeInfo *cifsi = CIFS_I(inode);
  93
  94        if (cifsi->fscache) {
  95                cFYI(1, "CIFS disabling inode cookie (0x%p)",
  96                                cifsi->fscache);
  97                fscache_relinquish_cookie(cifsi->fscache, 1);
  98                cifsi->fscache = NULL;
  99        }
 100}
 101
 102void cifs_fscache_set_inode_cookie(struct inode *inode, struct file *filp)
 103{
 104        if ((filp->f_flags & O_ACCMODE) != O_RDONLY)
 105                cifs_fscache_disable_inode_cookie(inode);
 106        else
 107                cifs_fscache_enable_inode_cookie(inode);
 108}
 109
 110void cifs_fscache_reset_inode_cookie(struct inode *inode)
 111{
 112        struct cifsInodeInfo *cifsi = CIFS_I(inode);
 113        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 114        struct fscache_cookie *old = cifsi->fscache;
 115
 116        if (cifsi->fscache) {
 117                /* retire the current fscache cache and get a new one */
 118                fscache_relinquish_cookie(cifsi->fscache, 1);
 119
 120                cifsi->fscache = fscache_acquire_cookie(
 121                                        cifs_sb_master_tcon(cifs_sb)->fscache,
 122                                        &cifs_fscache_inode_object_def,
 123                                        cifsi);
 124                cFYI(1, "CIFS: new cookie 0x%p oldcookie 0x%p",
 125                                cifsi->fscache, old);
 126        }
 127}
 128
 129int cifs_fscache_release_page(struct page *page, gfp_t gfp)
 130{
 131        if (PageFsCache(page)) {
 132                struct inode *inode = page->mapping->host;
 133                struct cifsInodeInfo *cifsi = CIFS_I(inode);
 134
 135                cFYI(1, "CIFS: fscache release page (0x%p/0x%p)",
 136                                page, cifsi->fscache);
 137                if (!fscache_maybe_release_page(cifsi->fscache, page, gfp))
 138                        return 0;
 139        }
 140
 141        return 1;
 142}
 143
 144static void cifs_readpage_from_fscache_complete(struct page *page, void *ctx,
 145                                                int error)
 146{
 147        cFYI(1, "CFS: readpage_from_fscache_complete (0x%p/%d)",
 148                        page, error);
 149        if (!error)
 150                SetPageUptodate(page);
 151        unlock_page(page);
 152}
 153
 154/*
 155 * Retrieve a page from FS-Cache
 156 */
 157int __cifs_readpage_from_fscache(struct inode *inode, struct page *page)
 158{
 159        int ret;
 160
 161        cFYI(1, "CIFS: readpage_from_fscache(fsc:%p, p:%p, i:0x%p",
 162                        CIFS_I(inode)->fscache, page, inode);
 163        ret = fscache_read_or_alloc_page(CIFS_I(inode)->fscache, page,
 164                                         cifs_readpage_from_fscache_complete,
 165                                         NULL,
 166                                         GFP_KERNEL);
 167        switch (ret) {
 168
 169        case 0: /* page found in fscache, read submitted */
 170                cFYI(1, "CIFS: readpage_from_fscache: submitted");
 171                return ret;
 172        case -ENOBUFS:  /* page won't be cached */
 173        case -ENODATA:  /* page not in cache */
 174                cFYI(1, "CIFS: readpage_from_fscache %d", ret);
 175                return 1;
 176
 177        default:
 178                cERROR(1, "unknown error ret = %d", ret);
 179        }
 180        return ret;
 181}
 182
 183/*
 184 * Retrieve a set of pages from FS-Cache
 185 */
 186int __cifs_readpages_from_fscache(struct inode *inode,
 187                                struct address_space *mapping,
 188                                struct list_head *pages,
 189                                unsigned *nr_pages)
 190{
 191        int ret;
 192
 193        cFYI(1, "CIFS: __cifs_readpages_from_fscache (0x%p/%u/0x%p)",
 194                        CIFS_I(inode)->fscache, *nr_pages, inode);
 195        ret = fscache_read_or_alloc_pages(CIFS_I(inode)->fscache, mapping,
 196                                          pages, nr_pages,
 197                                          cifs_readpage_from_fscache_complete,
 198                                          NULL,
 199                                          mapping_gfp_mask(mapping));
 200        switch (ret) {
 201        case 0: /* read submitted to the cache for all pages */
 202                cFYI(1, "CIFS: readpages_from_fscache: submitted");
 203                return ret;
 204
 205        case -ENOBUFS:  /* some pages are not cached and can't be */
 206        case -ENODATA:  /* some pages are not cached */
 207                cFYI(1, "CIFS: readpages_from_fscache: no page");
 208                return 1;
 209
 210        default:
 211                cFYI(1, "unknown error ret = %d", ret);
 212        }
 213
 214        return ret;
 215}
 216
 217void __cifs_readpage_to_fscache(struct inode *inode, struct page *page)
 218{
 219        int ret;
 220
 221        cFYI(1, "CIFS: readpage_to_fscache(fsc: %p, p: %p, i: %p",
 222                        CIFS_I(inode)->fscache, page, inode);
 223        ret = fscache_write_page(CIFS_I(inode)->fscache, page, GFP_KERNEL);
 224        if (ret != 0)
 225                fscache_uncache_page(CIFS_I(inode)->fscache, page);
 226}
 227
 228void __cifs_fscache_invalidate_page(struct page *page, struct inode *inode)
 229{
 230        struct cifsInodeInfo *cifsi = CIFS_I(inode);
 231        struct fscache_cookie *cookie = cifsi->fscache;
 232
 233        cFYI(1, "CIFS: fscache invalidatepage (0x%p/0x%p)", page, cookie);
 234        fscache_wait_on_page_write(cookie, page);
 235        fscache_uncache_page(cookie, page);
 236}
 237
 238