1b4d0d230SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 214727281SDavid Howells /* NFS filesystem cache interface 314727281SDavid Howells * 414727281SDavid Howells * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved. 514727281SDavid Howells * Written by David Howells (dhowells@redhat.com) 614727281SDavid Howells */ 714727281SDavid Howells 814727281SDavid Howells #include <linux/init.h> 914727281SDavid Howells #include <linux/kernel.h> 1014727281SDavid Howells #include <linux/sched.h> 1114727281SDavid Howells #include <linux/mm.h> 1214727281SDavid Howells #include <linux/nfs_fs.h> 1314727281SDavid Howells #include <linux/nfs_fs_sb.h> 1414727281SDavid Howells #include <linux/in6.h> 1514727281SDavid Howells #include <linux/seq_file.h> 165a0e3ad6STejun Heo #include <linux/slab.h> 17402cb8ddSDavid Howells #include <linux/iversion.h> 1814727281SDavid Howells 1914727281SDavid Howells #include "internal.h" 20545db45fSDavid Howells #include "iostat.h" 2114727281SDavid Howells #include "fscache.h" 2214727281SDavid Howells 2314727281SDavid Howells #define NFSDBG_FACILITY NFSDBG_FSCACHE 2414727281SDavid Howells 25a6b5a28eSDave Wysochanski #define NFS_MAX_KEY_LEN 1000 2608734048SDavid Howells 27a6b5a28eSDave Wysochanski static bool nfs_append_int(char *key, int *_len, unsigned long long x) 28a6b5a28eSDave Wysochanski { 29a6b5a28eSDave Wysochanski if (*_len > NFS_MAX_KEY_LEN) 30a6b5a28eSDave Wysochanski return false; 31a6b5a28eSDave Wysochanski if (x == 0) 32a6b5a28eSDave Wysochanski key[(*_len)++] = ','; 33a6b5a28eSDave Wysochanski else 34a6b5a28eSDave Wysochanski *_len += sprintf(key + *_len, ",%llx", x); 35a6b5a28eSDave Wysochanski return true; 36a6b5a28eSDave Wysochanski } 37402cb8ddSDavid Howells 38402cb8ddSDavid Howells /* 3914727281SDavid Howells * Get the per-client index cookie for an NFS client if the appropriate mount 4014727281SDavid Howells * flag was set 4114727281SDavid Howells * - We always try and get an index cookie for the client, but get filehandle 4214727281SDavid Howells * cookies on a per-superblock basis, depending on the mount flags 4314727281SDavid Howells */ 44a6b5a28eSDave Wysochanski static bool nfs_fscache_get_client_key(struct nfs_client *clp, 45a6b5a28eSDave Wysochanski char *key, int *_len) 4614727281SDavid Howells { 47402cb8ddSDavid Howells const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &clp->cl_addr; 48402cb8ddSDavid Howells const struct sockaddr_in *sin = (struct sockaddr_in *) &clp->cl_addr; 49402cb8ddSDavid Howells 50a6b5a28eSDave Wysochanski *_len += snprintf(key + *_len, NFS_MAX_KEY_LEN - *_len, 51a6b5a28eSDave Wysochanski ",%u.%u,%x", 52a6b5a28eSDave Wysochanski clp->rpc_ops->version, 53a6b5a28eSDave Wysochanski clp->cl_minorversion, 54a6b5a28eSDave Wysochanski clp->cl_addr.ss_family); 55402cb8ddSDavid Howells 56402cb8ddSDavid Howells switch (clp->cl_addr.ss_family) { 57402cb8ddSDavid Howells case AF_INET: 58a6b5a28eSDave Wysochanski if (!nfs_append_int(key, _len, sin->sin_port) || 59a6b5a28eSDave Wysochanski !nfs_append_int(key, _len, sin->sin_addr.s_addr)) 60a6b5a28eSDave Wysochanski return false; 61a6b5a28eSDave Wysochanski return true; 62402cb8ddSDavid Howells 63402cb8ddSDavid Howells case AF_INET6: 64a6b5a28eSDave Wysochanski if (!nfs_append_int(key, _len, sin6->sin6_port) || 65a6b5a28eSDave Wysochanski !nfs_append_int(key, _len, sin6->sin6_addr.s6_addr32[0]) || 66a6b5a28eSDave Wysochanski !nfs_append_int(key, _len, sin6->sin6_addr.s6_addr32[1]) || 67a6b5a28eSDave Wysochanski !nfs_append_int(key, _len, sin6->sin6_addr.s6_addr32[2]) || 68a6b5a28eSDave Wysochanski !nfs_append_int(key, _len, sin6->sin6_addr.s6_addr32[3])) 69a6b5a28eSDave Wysochanski return false; 70a6b5a28eSDave Wysochanski return true; 71402cb8ddSDavid Howells 72402cb8ddSDavid Howells default: 73402cb8ddSDavid Howells printk(KERN_WARNING "NFS: Unknown network family '%d'\n", 74402cb8ddSDavid Howells clp->cl_addr.ss_family); 75a6b5a28eSDave Wysochanski return false; 76402cb8ddSDavid Howells } 7714727281SDavid Howells } 7814727281SDavid Howells 7914727281SDavid Howells /* 80a6b5a28eSDave Wysochanski * Get the cache cookie for an NFS superblock. 812df54806SDavid Howells * 822df54806SDavid Howells * The default uniquifier is just an empty string, but it may be overridden 832df54806SDavid Howells * either by the 'fsc=xxx' option to mount, or by inheriting it from the parent 842df54806SDavid Howells * superblock across an automount point of some nature. 8508734048SDavid Howells */ 86a6b5a28eSDave Wysochanski int nfs_fscache_get_super_cookie(struct super_block *sb, const char *uniq, int ulen) 8708734048SDavid Howells { 88a6b5a28eSDave Wysochanski struct fscache_volume *vcookie; 8908734048SDavid Howells struct nfs_server *nfss = NFS_SB(sb); 90a6b5a28eSDave Wysochanski unsigned int len = 3; 91a6b5a28eSDave Wysochanski char *key; 922df54806SDavid Howells 93a6b5a28eSDave Wysochanski if (uniq) { 94a6b5a28eSDave Wysochanski nfss->fscache_uniq = kmemdup_nul(uniq, ulen, GFP_KERNEL); 95a6b5a28eSDave Wysochanski if (!nfss->fscache_uniq) 96a6b5a28eSDave Wysochanski return -ENOMEM; 972df54806SDavid Howells } 982df54806SDavid Howells 99a6b5a28eSDave Wysochanski key = kmalloc(NFS_MAX_KEY_LEN + 24, GFP_KERNEL); 10008734048SDavid Howells if (!key) 101a6b5a28eSDave Wysochanski return -ENOMEM; 10208734048SDavid Howells 103a6b5a28eSDave Wysochanski memcpy(key, "nfs", 3); 104a6b5a28eSDave Wysochanski if (!nfs_fscache_get_client_key(nfss->nfs_client, key, &len) || 105a6b5a28eSDave Wysochanski !nfs_append_int(key, &len, nfss->fsid.major) || 106a6b5a28eSDave Wysochanski !nfs_append_int(key, &len, nfss->fsid.minor) || 107a6b5a28eSDave Wysochanski !nfs_append_int(key, &len, sb->s_flags & NFS_SB_MASK) || 108a6b5a28eSDave Wysochanski !nfs_append_int(key, &len, nfss->flags) || 109a6b5a28eSDave Wysochanski !nfs_append_int(key, &len, nfss->rsize) || 110a6b5a28eSDave Wysochanski !nfs_append_int(key, &len, nfss->wsize) || 111a6b5a28eSDave Wysochanski !nfs_append_int(key, &len, nfss->acregmin) || 112a6b5a28eSDave Wysochanski !nfs_append_int(key, &len, nfss->acregmax) || 113a6b5a28eSDave Wysochanski !nfs_append_int(key, &len, nfss->acdirmin) || 114a6b5a28eSDave Wysochanski !nfs_append_int(key, &len, nfss->acdirmax) || 115a6b5a28eSDave Wysochanski !nfs_append_int(key, &len, nfss->client->cl_auth->au_flavor)) 116a6b5a28eSDave Wysochanski goto out; 11708734048SDavid Howells 118a6b5a28eSDave Wysochanski if (ulen > 0) { 119a6b5a28eSDave Wysochanski if (ulen > NFS_MAX_KEY_LEN - len) 120a6b5a28eSDave Wysochanski goto out; 121a6b5a28eSDave Wysochanski key[len++] = ','; 122a6b5a28eSDave Wysochanski memcpy(key + len, uniq, ulen); 123a6b5a28eSDave Wysochanski len += ulen; 12408734048SDavid Howells } 125a6b5a28eSDave Wysochanski key[len] = 0; 12608734048SDavid Howells 12708734048SDavid Howells /* create a cache index for looking up filehandles */ 128a6b5a28eSDave Wysochanski vcookie = fscache_acquire_volume(key, 129a6b5a28eSDave Wysochanski NULL, /* preferred_cache */ 130a6b5a28eSDave Wysochanski NULL, 0 /* coherency_data */); 13108734048SDavid Howells dfprintk(FSCACHE, "NFS: get superblock cookie (0x%p/0x%p)\n", 132a6b5a28eSDave Wysochanski nfss, vcookie); 133a6b5a28eSDave Wysochanski if (IS_ERR(vcookie)) { 134a6b5a28eSDave Wysochanski if (vcookie != ERR_PTR(-EBUSY)) { 13508734048SDavid Howells kfree(key); 136a6b5a28eSDave Wysochanski return PTR_ERR(vcookie); 137a6b5a28eSDave Wysochanski } 138a6b5a28eSDave Wysochanski pr_err("NFS: Cache volume key already in use (%s)\n", key); 139a6b5a28eSDave Wysochanski vcookie = NULL; 140a6b5a28eSDave Wysochanski } 141a6b5a28eSDave Wysochanski nfss->fscache = vcookie; 142a6b5a28eSDave Wysochanski 143a6b5a28eSDave Wysochanski out: 144a6b5a28eSDave Wysochanski kfree(key); 145a6b5a28eSDave Wysochanski return 0; 14608734048SDavid Howells } 14708734048SDavid Howells 14808734048SDavid Howells /* 14908734048SDavid Howells * release a per-superblock cookie 15008734048SDavid Howells */ 15108734048SDavid Howells void nfs_fscache_release_super_cookie(struct super_block *sb) 15208734048SDavid Howells { 15308734048SDavid Howells struct nfs_server *nfss = NFS_SB(sb); 15408734048SDavid Howells 15508734048SDavid Howells dfprintk(FSCACHE, "NFS: releasing superblock cookie (0x%p/0x%p)\n", 15608734048SDavid Howells nfss, nfss->fscache); 15708734048SDavid Howells 158a6b5a28eSDave Wysochanski fscache_relinquish_volume(nfss->fscache, NULL, false); 15908734048SDavid Howells nfss->fscache = NULL; 160a6b5a28eSDave Wysochanski kfree(nfss->fscache_uniq); 16150eaa652SDave Wysochanski } 16250eaa652SDave Wysochanski 163ef79c097SDavid Howells /* 164ef79c097SDavid Howells * Initialise the per-inode cache cookie pointer for an NFS inode. 165ef79c097SDavid Howells */ 166f1fe29b4SDavid Howells void nfs_fscache_init_inode(struct inode *inode) 167ef79c097SDavid Howells { 168402cb8ddSDavid Howells struct nfs_fscache_inode_auxdata auxdata; 169dea1bb35STrond Myklebust struct nfs_server *nfss = NFS_SERVER(inode); 170ef79c097SDavid Howells struct nfs_inode *nfsi = NFS_I(inode); 171ef79c097SDavid Howells 172f1fe29b4SDavid Howells nfsi->fscache = NULL; 173dea1bb35STrond Myklebust if (!(nfss->fscache && S_ISREG(inode->i_mode))) 174ef79c097SDavid Howells return; 175402cb8ddSDavid Howells 176*45f3a70bSDave Wysochanski nfs_fscache_update_auxdata(&auxdata, inode); 177402cb8ddSDavid Howells 178f1fe29b4SDavid Howells nfsi->fscache = fscache_acquire_cookie(NFS_SB(inode->i_sb)->fscache, 179a6b5a28eSDave Wysochanski 0, 180a6b5a28eSDave Wysochanski nfsi->fh.data, /* index_key */ 181a6b5a28eSDave Wysochanski nfsi->fh.size, 182a6b5a28eSDave Wysochanski &auxdata, /* aux_data */ 183a6b5a28eSDave Wysochanski sizeof(auxdata), 184*45f3a70bSDave Wysochanski i_size_read(inode)); 185ef79c097SDavid Howells } 186ef79c097SDavid Howells 187ef79c097SDavid Howells /* 188ef79c097SDavid Howells * Release a per-inode cookie. 189ef79c097SDavid Howells */ 190f1fe29b4SDavid Howells void nfs_fscache_clear_inode(struct inode *inode) 191ef79c097SDavid Howells { 192ef79c097SDavid Howells struct nfs_inode *nfsi = NFS_I(inode); 193f1fe29b4SDavid Howells struct fscache_cookie *cookie = nfs_i_fscache(inode); 194ef79c097SDavid Howells 195f1fe29b4SDavid Howells dfprintk(FSCACHE, "NFS: clear cookie (0x%p/0x%p)\n", nfsi, cookie); 196ef79c097SDavid Howells 197a6b5a28eSDave Wysochanski fscache_relinquish_cookie(cookie, false); 198ef79c097SDavid Howells nfsi->fscache = NULL; 199ef79c097SDavid Howells } 200ef79c097SDavid Howells 201ef79c097SDavid Howells /* 202f1fe29b4SDavid Howells * Enable or disable caching for a file that is being opened as appropriate. 203f1fe29b4SDavid Howells * The cookie is allocated when the inode is initialised, but is not enabled at 204f1fe29b4SDavid Howells * that time. Enablement is deferred to file-open time to avoid stat() and 205f1fe29b4SDavid Howells * access() thrashing the cache. 206f1fe29b4SDavid Howells * 207f1fe29b4SDavid Howells * For now, with NFS, only regular files that are open read-only will be able 208ef79c097SDavid Howells * to use the cache. 209f1fe29b4SDavid Howells * 210f1fe29b4SDavid Howells * We enable the cache for an inode if we open it read-only and it isn't 211f1fe29b4SDavid Howells * currently open for writing. We disable the cache if the inode is open 212f1fe29b4SDavid Howells * write-only. 213f1fe29b4SDavid Howells * 214f1fe29b4SDavid Howells * The caller uses the file struct to pin i_writecount on the inode before 215f1fe29b4SDavid Howells * calling us when a file is opened for writing, so we can make use of that. 216f1fe29b4SDavid Howells * 217f1fe29b4SDavid Howells * Note that this may be invoked multiple times in parallel by parallel 218f1fe29b4SDavid Howells * nfs_open() functions. 219ef79c097SDavid Howells */ 220f1fe29b4SDavid Howells void nfs_fscache_open_file(struct inode *inode, struct file *filp) 221ef79c097SDavid Howells { 222402cb8ddSDavid Howells struct nfs_fscache_inode_auxdata auxdata; 223f1fe29b4SDavid Howells struct fscache_cookie *cookie = nfs_i_fscache(inode); 224a6b5a28eSDave Wysochanski bool open_for_write = inode_is_open_for_write(inode); 225ef79c097SDavid Howells 226f1fe29b4SDavid Howells if (!fscache_cookie_valid(cookie)) 227f1fe29b4SDavid Howells return; 228ef79c097SDavid Howells 229a6b5a28eSDave Wysochanski fscache_use_cookie(cookie, open_for_write); 230a6b5a28eSDave Wysochanski if (open_for_write) { 231f1fe29b4SDavid Howells dfprintk(FSCACHE, "NFS: nfsi 0x%p disabling cache\n", nfsi); 232*45f3a70bSDave Wysochanski nfs_fscache_update_auxdata(&auxdata, inode); 233a6b5a28eSDave Wysochanski fscache_invalidate(cookie, &auxdata, i_size_read(inode), 234a6b5a28eSDave Wysochanski FSCACHE_INVAL_DIO_WRITE); 235ef79c097SDavid Howells } 236ef79c097SDavid Howells } 237f1fe29b4SDavid Howells EXPORT_SYMBOL_GPL(nfs_fscache_open_file); 238545db45fSDavid Howells 239a6b5a28eSDave Wysochanski void nfs_fscache_release_file(struct inode *inode, struct file *filp) 240545db45fSDavid Howells { 241a6b5a28eSDave Wysochanski struct nfs_fscache_inode_auxdata auxdata; 242f1fe29b4SDavid Howells struct fscache_cookie *cookie = nfs_i_fscache(inode); 243545db45fSDavid Howells 244a6b5a28eSDave Wysochanski if (fscache_cookie_valid(cookie)) { 245*45f3a70bSDave Wysochanski nfs_fscache_update_auxdata(&auxdata, inode); 246a6b5a28eSDave Wysochanski fscache_unuse_cookie(cookie, &auxdata, NULL); 247545db45fSDavid Howells } 2489a9fc1c0SDavid Howells } 2499a9fc1c0SDavid Howells 25016f2f4e6SDavid Howells static inline void fscache_end_operation(struct netfs_cache_resources *cres) 25116f2f4e6SDavid Howells { 25216f2f4e6SDavid Howells const struct netfs_cache_ops *ops = fscache_operation_valid(cres); 25316f2f4e6SDavid Howells 25416f2f4e6SDavid Howells if (ops) 25516f2f4e6SDavid Howells ops->end_operation(cres); 25616f2f4e6SDavid Howells } 25716f2f4e6SDavid Howells 25816f2f4e6SDavid Howells /* 25916f2f4e6SDavid Howells * Fallback page reading interface. 26016f2f4e6SDavid Howells */ 26116f2f4e6SDavid Howells static int fscache_fallback_read_page(struct inode *inode, struct page *page) 26216f2f4e6SDavid Howells { 26316f2f4e6SDavid Howells struct netfs_cache_resources cres; 26416f2f4e6SDavid Howells struct fscache_cookie *cookie = nfs_i_fscache(inode); 26516f2f4e6SDavid Howells struct iov_iter iter; 26616f2f4e6SDavid Howells struct bio_vec bvec[1]; 26716f2f4e6SDavid Howells int ret; 26816f2f4e6SDavid Howells 26916f2f4e6SDavid Howells memset(&cres, 0, sizeof(cres)); 27016f2f4e6SDavid Howells bvec[0].bv_page = page; 27116f2f4e6SDavid Howells bvec[0].bv_offset = 0; 27216f2f4e6SDavid Howells bvec[0].bv_len = PAGE_SIZE; 27316f2f4e6SDavid Howells iov_iter_bvec(&iter, READ, bvec, ARRAY_SIZE(bvec), PAGE_SIZE); 27416f2f4e6SDavid Howells 27516f2f4e6SDavid Howells ret = fscache_begin_read_operation(&cres, cookie); 27616f2f4e6SDavid Howells if (ret < 0) 27716f2f4e6SDavid Howells return ret; 27816f2f4e6SDavid Howells 27916f2f4e6SDavid Howells ret = fscache_read(&cres, page_offset(page), &iter, NETFS_READ_HOLE_FAIL, 28016f2f4e6SDavid Howells NULL, NULL); 28116f2f4e6SDavid Howells fscache_end_operation(&cres); 28216f2f4e6SDavid Howells return ret; 28316f2f4e6SDavid Howells } 28416f2f4e6SDavid Howells 28516f2f4e6SDavid Howells /* 28616f2f4e6SDavid Howells * Fallback page writing interface. 28716f2f4e6SDavid Howells */ 28816f2f4e6SDavid Howells static int fscache_fallback_write_page(struct inode *inode, struct page *page, 28916f2f4e6SDavid Howells bool no_space_allocated_yet) 29016f2f4e6SDavid Howells { 29116f2f4e6SDavid Howells struct netfs_cache_resources cres; 29216f2f4e6SDavid Howells struct fscache_cookie *cookie = nfs_i_fscache(inode); 29316f2f4e6SDavid Howells struct iov_iter iter; 29416f2f4e6SDavid Howells struct bio_vec bvec[1]; 29516f2f4e6SDavid Howells loff_t start = page_offset(page); 29616f2f4e6SDavid Howells size_t len = PAGE_SIZE; 29716f2f4e6SDavid Howells int ret; 29816f2f4e6SDavid Howells 29916f2f4e6SDavid Howells memset(&cres, 0, sizeof(cres)); 30016f2f4e6SDavid Howells bvec[0].bv_page = page; 30116f2f4e6SDavid Howells bvec[0].bv_offset = 0; 30216f2f4e6SDavid Howells bvec[0].bv_len = PAGE_SIZE; 30316f2f4e6SDavid Howells iov_iter_bvec(&iter, WRITE, bvec, ARRAY_SIZE(bvec), PAGE_SIZE); 30416f2f4e6SDavid Howells 30516f2f4e6SDavid Howells ret = fscache_begin_write_operation(&cres, cookie); 30616f2f4e6SDavid Howells if (ret < 0) 30716f2f4e6SDavid Howells return ret; 30816f2f4e6SDavid Howells 30916f2f4e6SDavid Howells ret = cres.ops->prepare_write(&cres, &start, &len, i_size_read(inode), 31016f2f4e6SDavid Howells no_space_allocated_yet); 31116f2f4e6SDavid Howells if (ret == 0) 31216f2f4e6SDavid Howells ret = fscache_write(&cres, page_offset(page), &iter, NULL, NULL); 31316f2f4e6SDavid Howells fscache_end_operation(&cres); 31416f2f4e6SDavid Howells return ret; 31516f2f4e6SDavid Howells } 31616f2f4e6SDavid Howells 3179a9fc1c0SDavid Howells /* 3189a9fc1c0SDavid Howells * Retrieve a page from fscache 3199a9fc1c0SDavid Howells */ 32016f2f4e6SDavid Howells int __nfs_readpage_from_fscache(struct inode *inode, struct page *page) 3219a9fc1c0SDavid Howells { 32216f2f4e6SDavid Howells int ret; 32316f2f4e6SDavid Howells 3249a9fc1c0SDavid Howells dfprintk(FSCACHE, 3259a9fc1c0SDavid Howells "NFS: readpage_from_fscache(fsc:%p/p:%p(i:%lx f:%lx)/0x%p)\n", 326f1fe29b4SDavid Howells nfs_i_fscache(inode), page, page->index, page->flags, inode); 3279a9fc1c0SDavid Howells 328ba512c1bSDave Wysochanski if (PageChecked(page)) { 32916f2f4e6SDavid Howells dfprintk(FSCACHE, "NFS: readpage_from_fscache: PageChecked\n"); 330ba512c1bSDave Wysochanski ClearPageChecked(page); 331ba512c1bSDave Wysochanski return 1; 332ba512c1bSDave Wysochanski } 333ba512c1bSDave Wysochanski 33416f2f4e6SDavid Howells ret = fscache_fallback_read_page(inode, page); 33516f2f4e6SDavid Howells if (ret < 0) { 33616f2f4e6SDavid Howells nfs_inc_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_READ_FAIL); 3377f8e05f6SDavid Howells dfprintk(FSCACHE, 33816f2f4e6SDavid Howells "NFS: readpage_from_fscache failed %d\n", ret); 33916f2f4e6SDavid Howells SetPageChecked(page); 34016f2f4e6SDavid Howells return ret; 34116f2f4e6SDavid Howells } 3427f8e05f6SDavid Howells 34316f2f4e6SDavid Howells /* Read completed synchronously */ 34416f2f4e6SDavid Howells dfprintk(FSCACHE, "NFS: readpage_from_fscache: read successful\n"); 34516f2f4e6SDavid Howells nfs_inc_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_READ_OK); 34616f2f4e6SDavid Howells SetPageUptodate(page); 34716f2f4e6SDavid Howells return 0; 34816f2f4e6SDavid Howells } 34916f2f4e6SDavid Howells 35016f2f4e6SDavid Howells /* 35116f2f4e6SDavid Howells * Store a newly fetched page in fscache. We can be certain there's no page 35216f2f4e6SDavid Howells * stored in the cache as yet otherwise we would've read it from there. 35316f2f4e6SDavid Howells */ 35416f2f4e6SDavid Howells void __nfs_readpage_to_fscache(struct inode *inode, struct page *page) 35516f2f4e6SDavid Howells { 35616f2f4e6SDavid Howells int ret; 35716f2f4e6SDavid Howells 35816f2f4e6SDavid Howells dfprintk(FSCACHE, 35916f2f4e6SDavid Howells "NFS: readpage_to_fscache(fsc:%p/p:%p(i:%lx f:%lx))\n", 36016f2f4e6SDavid Howells nfs_i_fscache(inode), page, page->index, page->flags); 36116f2f4e6SDavid Howells 36216f2f4e6SDavid Howells ret = fscache_fallback_write_page(inode, page, true); 36316f2f4e6SDavid Howells 36416f2f4e6SDavid Howells dfprintk(FSCACHE, 36516f2f4e6SDavid Howells "NFS: readpage_to_fscache: p:%p(i:%lu f:%lx) ret %d\n", 36616f2f4e6SDavid Howells page, page->index, page->flags, ret); 36716f2f4e6SDavid Howells 36816f2f4e6SDavid Howells if (ret != 0) { 36916f2f4e6SDavid Howells nfs_inc_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_WRITTEN_FAIL); 37016f2f4e6SDavid Howells nfs_inc_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_UNCACHED); 37116f2f4e6SDavid Howells } else { 37216f2f4e6SDavid Howells nfs_inc_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_WRITTEN_OK); 37316f2f4e6SDavid Howells } 3747f8e05f6SDavid Howells } 375