xref: /openbmc/linux/fs/nfs/fscache.c (revision f1fe29b4)
114727281SDavid Howells /* NFS filesystem cache interface
214727281SDavid Howells  *
314727281SDavid Howells  * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
414727281SDavid Howells  * Written by David Howells (dhowells@redhat.com)
514727281SDavid Howells  *
614727281SDavid Howells  * This program is free software; you can redistribute it and/or
714727281SDavid Howells  * modify it under the terms of the GNU General Public Licence
814727281SDavid Howells  * as published by the Free Software Foundation; either version
914727281SDavid Howells  * 2 of the Licence, or (at your option) any later version.
1014727281SDavid Howells  */
1114727281SDavid Howells 
1214727281SDavid Howells #include <linux/init.h>
1314727281SDavid Howells #include <linux/kernel.h>
1414727281SDavid Howells #include <linux/sched.h>
1514727281SDavid Howells #include <linux/mm.h>
1614727281SDavid Howells #include <linux/nfs_fs.h>
1714727281SDavid Howells #include <linux/nfs_fs_sb.h>
1814727281SDavid Howells #include <linux/in6.h>
1914727281SDavid Howells #include <linux/seq_file.h>
205a0e3ad6STejun Heo #include <linux/slab.h>
2114727281SDavid Howells 
2214727281SDavid Howells #include "internal.h"
23545db45fSDavid Howells #include "iostat.h"
2414727281SDavid Howells #include "fscache.h"
2514727281SDavid Howells 
2614727281SDavid Howells #define NFSDBG_FACILITY		NFSDBG_FSCACHE
2714727281SDavid Howells 
2808734048SDavid Howells static struct rb_root nfs_fscache_keys = RB_ROOT;
2908734048SDavid Howells static DEFINE_SPINLOCK(nfs_fscache_keys_lock);
3008734048SDavid Howells 
3114727281SDavid Howells /*
3214727281SDavid Howells  * Get the per-client index cookie for an NFS client if the appropriate mount
3314727281SDavid Howells  * flag was set
3414727281SDavid Howells  * - We always try and get an index cookie for the client, but get filehandle
3514727281SDavid Howells  *   cookies on a per-superblock basis, depending on the mount flags
3614727281SDavid Howells  */
3714727281SDavid Howells void nfs_fscache_get_client_cookie(struct nfs_client *clp)
3814727281SDavid Howells {
3914727281SDavid Howells 	/* create a cache index for looking up filehandles */
4014727281SDavid Howells 	clp->fscache = fscache_acquire_cookie(nfs_fscache_netfs.primary_index,
4114727281SDavid Howells 					      &nfs_fscache_server_index_def,
4294d30ae9SDavid Howells 					      clp, true);
4314727281SDavid Howells 	dfprintk(FSCACHE, "NFS: get client cookie (0x%p/0x%p)\n",
4414727281SDavid Howells 		 clp, clp->fscache);
4514727281SDavid Howells }
4614727281SDavid Howells 
4714727281SDavid Howells /*
4814727281SDavid Howells  * Dispose of a per-client cookie
4914727281SDavid Howells  */
5014727281SDavid Howells void nfs_fscache_release_client_cookie(struct nfs_client *clp)
5114727281SDavid Howells {
5214727281SDavid Howells 	dfprintk(FSCACHE, "NFS: releasing client cookie (0x%p/0x%p)\n",
5314727281SDavid Howells 		 clp, clp->fscache);
5414727281SDavid Howells 
5514727281SDavid Howells 	fscache_relinquish_cookie(clp->fscache, 0);
5614727281SDavid Howells 	clp->fscache = NULL;
5714727281SDavid Howells }
5808734048SDavid Howells 
5908734048SDavid Howells /*
6008734048SDavid Howells  * Get the cache cookie for an NFS superblock.  We have to handle
6108734048SDavid Howells  * uniquification here because the cache doesn't do it for us.
622df54806SDavid Howells  *
632df54806SDavid Howells  * The default uniquifier is just an empty string, but it may be overridden
642df54806SDavid Howells  * either by the 'fsc=xxx' option to mount, or by inheriting it from the parent
652df54806SDavid Howells  * superblock across an automount point of some nature.
6608734048SDavid Howells  */
672311b943SBryan Schumaker void nfs_fscache_get_super_cookie(struct super_block *sb, const char *uniq, int ulen)
6808734048SDavid Howells {
6908734048SDavid Howells 	struct nfs_fscache_key *key, *xkey;
7008734048SDavid Howells 	struct nfs_server *nfss = NFS_SB(sb);
7108734048SDavid Howells 	struct rb_node **p, *parent;
722311b943SBryan Schumaker 	int diff;
732df54806SDavid Howells 
742df54806SDavid Howells 	if (!uniq) {
752df54806SDavid Howells 		uniq = "";
762df54806SDavid Howells 		ulen = 1;
772df54806SDavid Howells 	}
782df54806SDavid Howells 
7908734048SDavid Howells 	key = kzalloc(sizeof(*key) + ulen, GFP_KERNEL);
8008734048SDavid Howells 	if (!key)
8108734048SDavid Howells 		return;
8208734048SDavid Howells 
8308734048SDavid Howells 	key->nfs_client = nfss->nfs_client;
8408734048SDavid Howells 	key->key.super.s_flags = sb->s_flags & NFS_MS_MASK;
8508734048SDavid Howells 	key->key.nfs_server.flags = nfss->flags;
8608734048SDavid Howells 	key->key.nfs_server.rsize = nfss->rsize;
8708734048SDavid Howells 	key->key.nfs_server.wsize = nfss->wsize;
8808734048SDavid Howells 	key->key.nfs_server.acregmin = nfss->acregmin;
8908734048SDavid Howells 	key->key.nfs_server.acregmax = nfss->acregmax;
9008734048SDavid Howells 	key->key.nfs_server.acdirmin = nfss->acdirmin;
9108734048SDavid Howells 	key->key.nfs_server.acdirmax = nfss->acdirmax;
9208734048SDavid Howells 	key->key.nfs_server.fsid = nfss->fsid;
9308734048SDavid Howells 	key->key.rpc_auth.au_flavor = nfss->client->cl_auth->au_flavor;
9408734048SDavid Howells 
9508734048SDavid Howells 	key->key.uniq_len = ulen;
9608734048SDavid Howells 	memcpy(key->key.uniquifier, uniq, ulen);
9708734048SDavid Howells 
9808734048SDavid Howells 	spin_lock(&nfs_fscache_keys_lock);
9908734048SDavid Howells 	p = &nfs_fscache_keys.rb_node;
10008734048SDavid Howells 	parent = NULL;
10108734048SDavid Howells 	while (*p) {
10208734048SDavid Howells 		parent = *p;
10308734048SDavid Howells 		xkey = rb_entry(parent, struct nfs_fscache_key, node);
10408734048SDavid Howells 
10508734048SDavid Howells 		if (key->nfs_client < xkey->nfs_client)
10608734048SDavid Howells 			goto go_left;
10708734048SDavid Howells 		if (key->nfs_client > xkey->nfs_client)
10808734048SDavid Howells 			goto go_right;
10908734048SDavid Howells 
11008734048SDavid Howells 		diff = memcmp(&key->key, &xkey->key, sizeof(key->key));
11108734048SDavid Howells 		if (diff < 0)
11208734048SDavid Howells 			goto go_left;
11308734048SDavid Howells 		if (diff > 0)
11408734048SDavid Howells 			goto go_right;
11508734048SDavid Howells 
11608734048SDavid Howells 		if (key->key.uniq_len == 0)
11708734048SDavid Howells 			goto non_unique;
11808734048SDavid Howells 		diff = memcmp(key->key.uniquifier,
11908734048SDavid Howells 			      xkey->key.uniquifier,
12008734048SDavid Howells 			      key->key.uniq_len);
12108734048SDavid Howells 		if (diff < 0)
12208734048SDavid Howells 			goto go_left;
12308734048SDavid Howells 		if (diff > 0)
12408734048SDavid Howells 			goto go_right;
12508734048SDavid Howells 		goto non_unique;
12608734048SDavid Howells 
12708734048SDavid Howells 	go_left:
12808734048SDavid Howells 		p = &(*p)->rb_left;
12908734048SDavid Howells 		continue;
13008734048SDavid Howells 	go_right:
13108734048SDavid Howells 		p = &(*p)->rb_right;
13208734048SDavid Howells 	}
13308734048SDavid Howells 
13408734048SDavid Howells 	rb_link_node(&key->node, parent, p);
13508734048SDavid Howells 	rb_insert_color(&key->node, &nfs_fscache_keys);
13608734048SDavid Howells 	spin_unlock(&nfs_fscache_keys_lock);
13708734048SDavid Howells 	nfss->fscache_key = key;
13808734048SDavid Howells 
13908734048SDavid Howells 	/* create a cache index for looking up filehandles */
14008734048SDavid Howells 	nfss->fscache = fscache_acquire_cookie(nfss->nfs_client->fscache,
14108734048SDavid Howells 					       &nfs_fscache_super_index_def,
14294d30ae9SDavid Howells 					       nfss, true);
14308734048SDavid Howells 	dfprintk(FSCACHE, "NFS: get superblock cookie (0x%p/0x%p)\n",
14408734048SDavid Howells 		 nfss, nfss->fscache);
14508734048SDavid Howells 	return;
14608734048SDavid Howells 
14708734048SDavid Howells non_unique:
14808734048SDavid Howells 	spin_unlock(&nfs_fscache_keys_lock);
14908734048SDavid Howells 	kfree(key);
15008734048SDavid Howells 	nfss->fscache_key = NULL;
15108734048SDavid Howells 	nfss->fscache = NULL;
15208734048SDavid Howells 	printk(KERN_WARNING "NFS:"
15308734048SDavid Howells 	       " Cache request denied due to non-unique superblock keys\n");
15408734048SDavid Howells }
15508734048SDavid Howells 
15608734048SDavid Howells /*
15708734048SDavid Howells  * release a per-superblock cookie
15808734048SDavid Howells  */
15908734048SDavid Howells void nfs_fscache_release_super_cookie(struct super_block *sb)
16008734048SDavid Howells {
16108734048SDavid Howells 	struct nfs_server *nfss = NFS_SB(sb);
16208734048SDavid Howells 
16308734048SDavid Howells 	dfprintk(FSCACHE, "NFS: releasing superblock cookie (0x%p/0x%p)\n",
16408734048SDavid Howells 		 nfss, nfss->fscache);
16508734048SDavid Howells 
16608734048SDavid Howells 	fscache_relinquish_cookie(nfss->fscache, 0);
16708734048SDavid Howells 	nfss->fscache = NULL;
16808734048SDavid Howells 
16908734048SDavid Howells 	if (nfss->fscache_key) {
17008734048SDavid Howells 		spin_lock(&nfs_fscache_keys_lock);
17108734048SDavid Howells 		rb_erase(&nfss->fscache_key->node, &nfs_fscache_keys);
17208734048SDavid Howells 		spin_unlock(&nfs_fscache_keys_lock);
17308734048SDavid Howells 		kfree(nfss->fscache_key);
17408734048SDavid Howells 		nfss->fscache_key = NULL;
17508734048SDavid Howells 	}
17608734048SDavid Howells }
177ef79c097SDavid Howells 
178ef79c097SDavid Howells /*
179ef79c097SDavid Howells  * Initialise the per-inode cache cookie pointer for an NFS inode.
180ef79c097SDavid Howells  */
181f1fe29b4SDavid Howells void nfs_fscache_init_inode(struct inode *inode)
182ef79c097SDavid Howells {
183ef79c097SDavid Howells 	struct nfs_inode *nfsi = NFS_I(inode);
184ef79c097SDavid Howells 
185f1fe29b4SDavid Howells 	nfsi->fscache = NULL;
186f1fe29b4SDavid Howells 	if (!S_ISREG(inode->i_mode))
187ef79c097SDavid Howells 		return;
188f1fe29b4SDavid Howells 	nfsi->fscache = fscache_acquire_cookie(NFS_SB(inode->i_sb)->fscache,
189ef79c097SDavid Howells 					       &nfs_fscache_inode_object_def,
190f1fe29b4SDavid Howells 					       nfsi, false);
191ef79c097SDavid Howells }
192ef79c097SDavid Howells 
193ef79c097SDavid Howells /*
194ef79c097SDavid Howells  * Release a per-inode cookie.
195ef79c097SDavid Howells  */
196f1fe29b4SDavid Howells void nfs_fscache_clear_inode(struct inode *inode)
197ef79c097SDavid Howells {
198ef79c097SDavid Howells 	struct nfs_inode *nfsi = NFS_I(inode);
199f1fe29b4SDavid Howells 	struct fscache_cookie *cookie = nfs_i_fscache(inode);
200ef79c097SDavid Howells 
201f1fe29b4SDavid Howells 	dfprintk(FSCACHE, "NFS: clear cookie (0x%p/0x%p)\n", nfsi, cookie);
202ef79c097SDavid Howells 
203f1fe29b4SDavid Howells 	fscache_relinquish_cookie(cookie, false);
204ef79c097SDavid Howells 	nfsi->fscache = NULL;
205ef79c097SDavid Howells }
206ef79c097SDavid Howells 
207f1fe29b4SDavid Howells static bool nfs_fscache_can_enable(void *data)
208ef79c097SDavid Howells {
209f1fe29b4SDavid Howells 	struct inode *inode = data;
210ef79c097SDavid Howells 
211f1fe29b4SDavid Howells 	return !inode_is_open_for_write(inode);
212ef79c097SDavid Howells }
213ef79c097SDavid Howells 
214ef79c097SDavid Howells /*
215f1fe29b4SDavid Howells  * Enable or disable caching for a file that is being opened as appropriate.
216f1fe29b4SDavid Howells  * The cookie is allocated when the inode is initialised, but is not enabled at
217f1fe29b4SDavid Howells  * that time.  Enablement is deferred to file-open time to avoid stat() and
218f1fe29b4SDavid Howells  * access() thrashing the cache.
219f1fe29b4SDavid Howells  *
220f1fe29b4SDavid Howells  * For now, with NFS, only regular files that are open read-only will be able
221ef79c097SDavid Howells  * to use the cache.
222f1fe29b4SDavid Howells  *
223f1fe29b4SDavid Howells  * We enable the cache for an inode if we open it read-only and it isn't
224f1fe29b4SDavid Howells  * currently open for writing.  We disable the cache if the inode is open
225f1fe29b4SDavid Howells  * write-only.
226f1fe29b4SDavid Howells  *
227f1fe29b4SDavid Howells  * The caller uses the file struct to pin i_writecount on the inode before
228f1fe29b4SDavid Howells  * calling us when a file is opened for writing, so we can make use of that.
229f1fe29b4SDavid Howells  *
230f1fe29b4SDavid Howells  * Note that this may be invoked multiple times in parallel by parallel
231f1fe29b4SDavid Howells  * nfs_open() functions.
232ef79c097SDavid Howells  */
233f1fe29b4SDavid Howells void nfs_fscache_open_file(struct inode *inode, struct file *filp)
234ef79c097SDavid Howells {
235ef79c097SDavid Howells 	struct nfs_inode *nfsi = NFS_I(inode);
236f1fe29b4SDavid Howells 	struct fscache_cookie *cookie = nfs_i_fscache(inode);
237ef79c097SDavid Howells 
238f1fe29b4SDavid Howells 	if (!fscache_cookie_valid(cookie))
239f1fe29b4SDavid Howells 		return;
240ef79c097SDavid Howells 
241f1fe29b4SDavid Howells 	if (inode_is_open_for_write(inode)) {
242f1fe29b4SDavid Howells 		dfprintk(FSCACHE, "NFS: nfsi 0x%p disabling cache\n", nfsi);
243f1fe29b4SDavid Howells 		clear_bit(NFS_INO_FSCACHE, &nfsi->flags);
244f1fe29b4SDavid Howells 		fscache_disable_cookie(cookie, true);
245f1fe29b4SDavid Howells 		fscache_uncache_all_inode_pages(cookie, inode);
246f1fe29b4SDavid Howells 	} else {
247f1fe29b4SDavid Howells 		dfprintk(FSCACHE, "NFS: nfsi 0x%p enabling cache\n", nfsi);
248f1fe29b4SDavid Howells 		fscache_enable_cookie(cookie, nfs_fscache_can_enable, inode);
249f1fe29b4SDavid Howells 		if (fscache_cookie_enabled(cookie))
250f1fe29b4SDavid Howells 			set_bit(NFS_INO_FSCACHE, &NFS_I(inode)->flags);
251ef79c097SDavid Howells 	}
252ef79c097SDavid Howells }
253f1fe29b4SDavid Howells EXPORT_SYMBOL_GPL(nfs_fscache_open_file);
254545db45fSDavid Howells 
255545db45fSDavid Howells /*
256545db45fSDavid Howells  * Release the caching state associated with a page, if the page isn't busy
257545db45fSDavid Howells  * interacting with the cache.
258545db45fSDavid Howells  * - Returns true (can release page) or false (page busy).
259545db45fSDavid Howells  */
260545db45fSDavid Howells int nfs_fscache_release_page(struct page *page, gfp_t gfp)
261545db45fSDavid Howells {
2622c174009STrond Myklebust 	if (PageFsCache(page)) {
263f1fe29b4SDavid Howells 		struct fscache_cookie *cookie = nfs_i_fscache(page->mapping->host);
264545db45fSDavid Howells 
265545db45fSDavid Howells 		BUG_ON(!cookie);
266545db45fSDavid Howells 		dfprintk(FSCACHE, "NFS: fscache releasepage (0x%p/0x%p/0x%p)\n",
267f1fe29b4SDavid Howells 			 cookie, page, NFS_I(page->mapping->host));
268545db45fSDavid Howells 
269201a1542SDavid Howells 		if (!fscache_maybe_release_page(cookie, page, gfp))
270201a1542SDavid Howells 			return 0;
271201a1542SDavid Howells 
272545db45fSDavid Howells 		nfs_add_fscache_stats(page->mapping->host,
273545db45fSDavid Howells 				      NFSIOS_FSCACHE_PAGES_UNCACHED, 1);
274545db45fSDavid Howells 	}
275545db45fSDavid Howells 
276545db45fSDavid Howells 	return 1;
277545db45fSDavid Howells }
278545db45fSDavid Howells 
279545db45fSDavid Howells /*
280545db45fSDavid Howells  * Release the caching state associated with a page if undergoing complete page
281545db45fSDavid Howells  * invalidation.
282545db45fSDavid Howells  */
283545db45fSDavid Howells void __nfs_fscache_invalidate_page(struct page *page, struct inode *inode)
284545db45fSDavid Howells {
285f1fe29b4SDavid Howells 	struct fscache_cookie *cookie = nfs_i_fscache(inode);
286545db45fSDavid Howells 
287545db45fSDavid Howells 	BUG_ON(!cookie);
288545db45fSDavid Howells 
289545db45fSDavid Howells 	dfprintk(FSCACHE, "NFS: fscache invalidatepage (0x%p/0x%p/0x%p)\n",
290f1fe29b4SDavid Howells 		 cookie, page, NFS_I(inode));
291545db45fSDavid Howells 
292545db45fSDavid Howells 	fscache_wait_on_page_write(cookie, page);
293545db45fSDavid Howells 
294545db45fSDavid Howells 	BUG_ON(!PageLocked(page));
295545db45fSDavid Howells 	fscache_uncache_page(cookie, page);
296545db45fSDavid Howells 	nfs_add_fscache_stats(page->mapping->host,
297545db45fSDavid Howells 			      NFSIOS_FSCACHE_PAGES_UNCACHED, 1);
298545db45fSDavid Howells }
2999a9fc1c0SDavid Howells 
3009a9fc1c0SDavid Howells /*
3019a9fc1c0SDavid Howells  * Handle completion of a page being read from the cache.
3029a9fc1c0SDavid Howells  * - Called in process (keventd) context.
3039a9fc1c0SDavid Howells  */
3049a9fc1c0SDavid Howells static void nfs_readpage_from_fscache_complete(struct page *page,
3059a9fc1c0SDavid Howells 					       void *context,
3069a9fc1c0SDavid Howells 					       int error)
3079a9fc1c0SDavid Howells {
3089a9fc1c0SDavid Howells 	dfprintk(FSCACHE,
3099a9fc1c0SDavid Howells 		 "NFS: readpage_from_fscache_complete (0x%p/0x%p/%d)\n",
3109a9fc1c0SDavid Howells 		 page, context, error);
3119a9fc1c0SDavid Howells 
3129a9fc1c0SDavid Howells 	/* if the read completes with an error, we just unlock the page and let
3139a9fc1c0SDavid Howells 	 * the VM reissue the readpage */
3149a9fc1c0SDavid Howells 	if (!error) {
3159a9fc1c0SDavid Howells 		SetPageUptodate(page);
3169a9fc1c0SDavid Howells 		unlock_page(page);
3179a9fc1c0SDavid Howells 	} else {
3189a9fc1c0SDavid Howells 		error = nfs_readpage_async(context, page->mapping->host, page);
3199a9fc1c0SDavid Howells 		if (error)
3209a9fc1c0SDavid Howells 			unlock_page(page);
3219a9fc1c0SDavid Howells 	}
3229a9fc1c0SDavid Howells }
3239a9fc1c0SDavid Howells 
3249a9fc1c0SDavid Howells /*
3259a9fc1c0SDavid Howells  * Retrieve a page from fscache
3269a9fc1c0SDavid Howells  */
3279a9fc1c0SDavid Howells int __nfs_readpage_from_fscache(struct nfs_open_context *ctx,
3289a9fc1c0SDavid Howells 				struct inode *inode, struct page *page)
3299a9fc1c0SDavid Howells {
3309a9fc1c0SDavid Howells 	int ret;
3319a9fc1c0SDavid Howells 
3329a9fc1c0SDavid Howells 	dfprintk(FSCACHE,
3339a9fc1c0SDavid Howells 		 "NFS: readpage_from_fscache(fsc:%p/p:%p(i:%lx f:%lx)/0x%p)\n",
334f1fe29b4SDavid Howells 		 nfs_i_fscache(inode), page, page->index, page->flags, inode);
3359a9fc1c0SDavid Howells 
336f1fe29b4SDavid Howells 	ret = fscache_read_or_alloc_page(nfs_i_fscache(inode),
3379a9fc1c0SDavid Howells 					 page,
3389a9fc1c0SDavid Howells 					 nfs_readpage_from_fscache_complete,
3399a9fc1c0SDavid Howells 					 ctx,
3409a9fc1c0SDavid Howells 					 GFP_KERNEL);
3419a9fc1c0SDavid Howells 
3429a9fc1c0SDavid Howells 	switch (ret) {
3439a9fc1c0SDavid Howells 	case 0: /* read BIO submitted (page in fscache) */
3449a9fc1c0SDavid Howells 		dfprintk(FSCACHE,
3459a9fc1c0SDavid Howells 			 "NFS:    readpage_from_fscache: BIO submitted\n");
3469a9fc1c0SDavid Howells 		nfs_add_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_READ_OK, 1);
3479a9fc1c0SDavid Howells 		return ret;
3489a9fc1c0SDavid Howells 
3499a9fc1c0SDavid Howells 	case -ENOBUFS: /* inode not in cache */
3509a9fc1c0SDavid Howells 	case -ENODATA: /* page not in cache */
3519a9fc1c0SDavid Howells 		nfs_add_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_READ_FAIL, 1);
3529a9fc1c0SDavid Howells 		dfprintk(FSCACHE,
3539a9fc1c0SDavid Howells 			 "NFS:    readpage_from_fscache %d\n", ret);
3549a9fc1c0SDavid Howells 		return 1;
3559a9fc1c0SDavid Howells 
3569a9fc1c0SDavid Howells 	default:
3579a9fc1c0SDavid Howells 		dfprintk(FSCACHE, "NFS:    readpage_from_fscache %d\n", ret);
3589a9fc1c0SDavid Howells 		nfs_add_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_READ_FAIL, 1);
3599a9fc1c0SDavid Howells 	}
3609a9fc1c0SDavid Howells 	return ret;
3619a9fc1c0SDavid Howells }
3629a9fc1c0SDavid Howells 
3639a9fc1c0SDavid Howells /*
3649a9fc1c0SDavid Howells  * Retrieve a set of pages from fscache
3659a9fc1c0SDavid Howells  */
3669a9fc1c0SDavid Howells int __nfs_readpages_from_fscache(struct nfs_open_context *ctx,
3679a9fc1c0SDavid Howells 				 struct inode *inode,
3689a9fc1c0SDavid Howells 				 struct address_space *mapping,
3699a9fc1c0SDavid Howells 				 struct list_head *pages,
3709a9fc1c0SDavid Howells 				 unsigned *nr_pages)
3719a9fc1c0SDavid Howells {
3720f15c53dSChuck Lever 	unsigned npages = *nr_pages;
3730f15c53dSChuck Lever 	int ret;
3749a9fc1c0SDavid Howells 
3759a9fc1c0SDavid Howells 	dfprintk(FSCACHE, "NFS: nfs_getpages_from_fscache (0x%p/%u/0x%p)\n",
376f1fe29b4SDavid Howells 		 nfs_i_fscache(inode), npages, inode);
3779a9fc1c0SDavid Howells 
378f1fe29b4SDavid Howells 	ret = fscache_read_or_alloc_pages(nfs_i_fscache(inode),
3799a9fc1c0SDavid Howells 					  mapping, pages, nr_pages,
3809a9fc1c0SDavid Howells 					  nfs_readpage_from_fscache_complete,
3819a9fc1c0SDavid Howells 					  ctx,
3829a9fc1c0SDavid Howells 					  mapping_gfp_mask(mapping));
3839a9fc1c0SDavid Howells 	if (*nr_pages < npages)
3849a9fc1c0SDavid Howells 		nfs_add_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_READ_OK,
3859a9fc1c0SDavid Howells 				      npages);
3869a9fc1c0SDavid Howells 	if (*nr_pages > 0)
3879a9fc1c0SDavid Howells 		nfs_add_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_READ_FAIL,
3889a9fc1c0SDavid Howells 				      *nr_pages);
3899a9fc1c0SDavid Howells 
3909a9fc1c0SDavid Howells 	switch (ret) {
3919a9fc1c0SDavid Howells 	case 0: /* read submitted to the cache for all pages */
3929a9fc1c0SDavid Howells 		BUG_ON(!list_empty(pages));
3939a9fc1c0SDavid Howells 		BUG_ON(*nr_pages != 0);
3949a9fc1c0SDavid Howells 		dfprintk(FSCACHE,
3959a9fc1c0SDavid Howells 			 "NFS: nfs_getpages_from_fscache: submitted\n");
3969a9fc1c0SDavid Howells 
3979a9fc1c0SDavid Howells 		return ret;
3989a9fc1c0SDavid Howells 
3999a9fc1c0SDavid Howells 	case -ENOBUFS: /* some pages aren't cached and can't be */
4009a9fc1c0SDavid Howells 	case -ENODATA: /* some pages aren't cached */
4019a9fc1c0SDavid Howells 		dfprintk(FSCACHE,
4029a9fc1c0SDavid Howells 			 "NFS: nfs_getpages_from_fscache: no page: %d\n", ret);
4039a9fc1c0SDavid Howells 		return 1;
4049a9fc1c0SDavid Howells 
4059a9fc1c0SDavid Howells 	default:
4069a9fc1c0SDavid Howells 		dfprintk(FSCACHE,
4079a9fc1c0SDavid Howells 			 "NFS: nfs_getpages_from_fscache: ret  %d\n", ret);
4089a9fc1c0SDavid Howells 	}
4099a9fc1c0SDavid Howells 
4109a9fc1c0SDavid Howells 	return ret;
4119a9fc1c0SDavid Howells }
4127f8e05f6SDavid Howells 
4137f8e05f6SDavid Howells /*
4147f8e05f6SDavid Howells  * Store a newly fetched page in fscache
4157f8e05f6SDavid Howells  * - PG_fscache must be set on the page
4167f8e05f6SDavid Howells  */
4177f8e05f6SDavid Howells void __nfs_readpage_to_fscache(struct inode *inode, struct page *page, int sync)
4187f8e05f6SDavid Howells {
4197f8e05f6SDavid Howells 	int ret;
4207f8e05f6SDavid Howells 
4217f8e05f6SDavid Howells 	dfprintk(FSCACHE,
4227f8e05f6SDavid Howells 		 "NFS: readpage_to_fscache(fsc:%p/p:%p(i:%lx f:%lx)/%d)\n",
423f1fe29b4SDavid Howells 		 nfs_i_fscache(inode), page, page->index, page->flags, sync);
4247f8e05f6SDavid Howells 
425f1fe29b4SDavid Howells 	ret = fscache_write_page(nfs_i_fscache(inode), page, GFP_KERNEL);
4267f8e05f6SDavid Howells 	dfprintk(FSCACHE,
4277f8e05f6SDavid Howells 		 "NFS:     readpage_to_fscache: p:%p(i:%lu f:%lx) ret %d\n",
4287f8e05f6SDavid Howells 		 page, page->index, page->flags, ret);
4297f8e05f6SDavid Howells 
4307f8e05f6SDavid Howells 	if (ret != 0) {
431f1fe29b4SDavid Howells 		fscache_uncache_page(nfs_i_fscache(inode), page);
4327f8e05f6SDavid Howells 		nfs_add_fscache_stats(inode,
4337f8e05f6SDavid Howells 				      NFSIOS_FSCACHE_PAGES_WRITTEN_FAIL, 1);
4347f8e05f6SDavid Howells 		nfs_add_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_UNCACHED, 1);
4357f8e05f6SDavid Howells 	} else {
4367f8e05f6SDavid Howells 		nfs_add_fscache_stats(inode,
4377f8e05f6SDavid Howells 				      NFSIOS_FSCACHE_PAGES_WRITTEN_OK, 1);
4387f8e05f6SDavid Howells 	}
4397f8e05f6SDavid Howells }
440