xref: /openbmc/linux/fs/9p/cache.c (revision 2efda799)
160e78d2cSAbhishek Kulkarni /*
260e78d2cSAbhishek Kulkarni  * V9FS cache definitions.
360e78d2cSAbhishek Kulkarni  *
460e78d2cSAbhishek Kulkarni  *  Copyright (C) 2009 by Abhishek Kulkarni <adkulkar@umail.iu.edu>
560e78d2cSAbhishek Kulkarni  *
660e78d2cSAbhishek Kulkarni  *  This program is free software; you can redistribute it and/or modify
760e78d2cSAbhishek Kulkarni  *  it under the terms of the GNU General Public License version 2
860e78d2cSAbhishek Kulkarni  *  as published by the Free Software Foundation.
960e78d2cSAbhishek Kulkarni  *
1060e78d2cSAbhishek Kulkarni  *  This program is distributed in the hope that it will be useful,
1160e78d2cSAbhishek Kulkarni  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
1260e78d2cSAbhishek Kulkarni  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1360e78d2cSAbhishek Kulkarni  *  GNU General Public License for more details.
1460e78d2cSAbhishek Kulkarni  *
1560e78d2cSAbhishek Kulkarni  *  You should have received a copy of the GNU General Public License
1660e78d2cSAbhishek Kulkarni  *  along with this program; if not, write to:
1760e78d2cSAbhishek Kulkarni  *  Free Software Foundation
1860e78d2cSAbhishek Kulkarni  *  51 Franklin Street, Fifth Floor
1960e78d2cSAbhishek Kulkarni  *  Boston, MA  02111-1301  USA
2060e78d2cSAbhishek Kulkarni  *
2160e78d2cSAbhishek Kulkarni  */
2260e78d2cSAbhishek Kulkarni 
2360e78d2cSAbhishek Kulkarni #include <linux/jiffies.h>
2460e78d2cSAbhishek Kulkarni #include <linux/file.h>
255a0e3ad6STejun Heo #include <linux/slab.h>
2660e78d2cSAbhishek Kulkarni #include <linux/stat.h>
2760e78d2cSAbhishek Kulkarni #include <linux/sched.h>
2860e78d2cSAbhishek Kulkarni #include <linux/fs.h>
2960e78d2cSAbhishek Kulkarni #include <net/9p/9p.h>
3060e78d2cSAbhishek Kulkarni 
3160e78d2cSAbhishek Kulkarni #include "v9fs.h"
3260e78d2cSAbhishek Kulkarni #include "cache.h"
3360e78d2cSAbhishek Kulkarni 
3460e78d2cSAbhishek Kulkarni #define CACHETAG_LEN  11
3560e78d2cSAbhishek Kulkarni 
3660e78d2cSAbhishek Kulkarni struct kmem_cache *vcookie_cache;
3760e78d2cSAbhishek Kulkarni 
3860e78d2cSAbhishek Kulkarni struct fscache_netfs v9fs_cache_netfs = {
3960e78d2cSAbhishek Kulkarni 	.name 		= "9p",
4060e78d2cSAbhishek Kulkarni 	.version 	= 0,
4160e78d2cSAbhishek Kulkarni };
4260e78d2cSAbhishek Kulkarni 
4360e78d2cSAbhishek Kulkarni static void init_once(void *foo)
4460e78d2cSAbhishek Kulkarni {
4560e78d2cSAbhishek Kulkarni 	struct v9fs_cookie *vcookie = (struct v9fs_cookie *) foo;
4660e78d2cSAbhishek Kulkarni 	vcookie->fscache = NULL;
4760e78d2cSAbhishek Kulkarni 	vcookie->qid = NULL;
4860e78d2cSAbhishek Kulkarni 	inode_init_once(&vcookie->inode);
4960e78d2cSAbhishek Kulkarni }
5060e78d2cSAbhishek Kulkarni 
5160e78d2cSAbhishek Kulkarni /**
5260e78d2cSAbhishek Kulkarni  * v9fs_init_vcookiecache - initialize a cache for vcookies to maintain
5360e78d2cSAbhishek Kulkarni  *			    vcookie to inode mapping
5460e78d2cSAbhishek Kulkarni  *
5560e78d2cSAbhishek Kulkarni  * Returns 0 on success.
5660e78d2cSAbhishek Kulkarni  */
5760e78d2cSAbhishek Kulkarni 
5860e78d2cSAbhishek Kulkarni static int v9fs_init_vcookiecache(void)
5960e78d2cSAbhishek Kulkarni {
6060e78d2cSAbhishek Kulkarni 	vcookie_cache = kmem_cache_create("vcookie_cache",
6160e78d2cSAbhishek Kulkarni 					  sizeof(struct v9fs_cookie),
6260e78d2cSAbhishek Kulkarni 					  0, (SLAB_RECLAIM_ACCOUNT|
6360e78d2cSAbhishek Kulkarni 					      SLAB_MEM_SPREAD),
6460e78d2cSAbhishek Kulkarni 					  init_once);
6560e78d2cSAbhishek Kulkarni 	if (!vcookie_cache)
6660e78d2cSAbhishek Kulkarni 		return -ENOMEM;
6760e78d2cSAbhishek Kulkarni 
6860e78d2cSAbhishek Kulkarni 	return 0;
6960e78d2cSAbhishek Kulkarni }
7060e78d2cSAbhishek Kulkarni 
7160e78d2cSAbhishek Kulkarni /**
7260e78d2cSAbhishek Kulkarni  * v9fs_destroy_vcookiecache - destroy the cache of vcookies
7360e78d2cSAbhishek Kulkarni  *
7460e78d2cSAbhishek Kulkarni  */
7560e78d2cSAbhishek Kulkarni 
7660e78d2cSAbhishek Kulkarni static void v9fs_destroy_vcookiecache(void)
7760e78d2cSAbhishek Kulkarni {
7860e78d2cSAbhishek Kulkarni 	kmem_cache_destroy(vcookie_cache);
7960e78d2cSAbhishek Kulkarni }
8060e78d2cSAbhishek Kulkarni 
8160e78d2cSAbhishek Kulkarni int __v9fs_cache_register(void)
8260e78d2cSAbhishek Kulkarni {
8360e78d2cSAbhishek Kulkarni 	int ret;
8460e78d2cSAbhishek Kulkarni 	ret = v9fs_init_vcookiecache();
8560e78d2cSAbhishek Kulkarni 	if (ret < 0)
8660e78d2cSAbhishek Kulkarni 		return ret;
8760e78d2cSAbhishek Kulkarni 
8860e78d2cSAbhishek Kulkarni 	return fscache_register_netfs(&v9fs_cache_netfs);
8960e78d2cSAbhishek Kulkarni }
9060e78d2cSAbhishek Kulkarni 
9160e78d2cSAbhishek Kulkarni void __v9fs_cache_unregister(void)
9260e78d2cSAbhishek Kulkarni {
9360e78d2cSAbhishek Kulkarni 	v9fs_destroy_vcookiecache();
9460e78d2cSAbhishek Kulkarni 	fscache_unregister_netfs(&v9fs_cache_netfs);
9560e78d2cSAbhishek Kulkarni }
9660e78d2cSAbhishek Kulkarni 
9760e78d2cSAbhishek Kulkarni /**
9860e78d2cSAbhishek Kulkarni  * v9fs_random_cachetag - Generate a random tag to be associated
9960e78d2cSAbhishek Kulkarni  *			  with a new cache session.
10060e78d2cSAbhishek Kulkarni  *
10160e78d2cSAbhishek Kulkarni  * The value of jiffies is used for a fairly randomly cache tag.
10260e78d2cSAbhishek Kulkarni  */
10360e78d2cSAbhishek Kulkarni 
10460e78d2cSAbhishek Kulkarni static
10560e78d2cSAbhishek Kulkarni int v9fs_random_cachetag(struct v9fs_session_info *v9ses)
10660e78d2cSAbhishek Kulkarni {
10760e78d2cSAbhishek Kulkarni 	v9ses->cachetag = kmalloc(CACHETAG_LEN, GFP_KERNEL);
10860e78d2cSAbhishek Kulkarni 	if (!v9ses->cachetag)
10960e78d2cSAbhishek Kulkarni 		return -ENOMEM;
11060e78d2cSAbhishek Kulkarni 
11160e78d2cSAbhishek Kulkarni 	return scnprintf(v9ses->cachetag, CACHETAG_LEN, "%lu", jiffies);
11260e78d2cSAbhishek Kulkarni }
11360e78d2cSAbhishek Kulkarni 
11460e78d2cSAbhishek Kulkarni static uint16_t v9fs_cache_session_get_key(const void *cookie_netfs_data,
11560e78d2cSAbhishek Kulkarni 					   void *buffer, uint16_t bufmax)
11660e78d2cSAbhishek Kulkarni {
11760e78d2cSAbhishek Kulkarni 	struct v9fs_session_info *v9ses;
11860e78d2cSAbhishek Kulkarni 	uint16_t klen = 0;
11960e78d2cSAbhishek Kulkarni 
12060e78d2cSAbhishek Kulkarni 	v9ses = (struct v9fs_session_info *)cookie_netfs_data;
12160e78d2cSAbhishek Kulkarni 	P9_DPRINTK(P9_DEBUG_FSC, "session %p buf %p size %u", v9ses,
12260e78d2cSAbhishek Kulkarni 		   buffer, bufmax);
12360e78d2cSAbhishek Kulkarni 
12460e78d2cSAbhishek Kulkarni 	if (v9ses->cachetag)
12560e78d2cSAbhishek Kulkarni 		klen = strlen(v9ses->cachetag);
12660e78d2cSAbhishek Kulkarni 
12760e78d2cSAbhishek Kulkarni 	if (klen > bufmax)
12860e78d2cSAbhishek Kulkarni 		return 0;
12960e78d2cSAbhishek Kulkarni 
13060e78d2cSAbhishek Kulkarni 	memcpy(buffer, v9ses->cachetag, klen);
13160e78d2cSAbhishek Kulkarni 	P9_DPRINTK(P9_DEBUG_FSC, "cache session tag %s", v9ses->cachetag);
13260e78d2cSAbhishek Kulkarni 	return klen;
13360e78d2cSAbhishek Kulkarni }
13460e78d2cSAbhishek Kulkarni 
13560e78d2cSAbhishek Kulkarni const struct fscache_cookie_def v9fs_cache_session_index_def = {
13660e78d2cSAbhishek Kulkarni 	.name 		= "9P.session",
13760e78d2cSAbhishek Kulkarni 	.type 		= FSCACHE_COOKIE_TYPE_INDEX,
13860e78d2cSAbhishek Kulkarni 	.get_key 	= v9fs_cache_session_get_key,
13960e78d2cSAbhishek Kulkarni };
14060e78d2cSAbhishek Kulkarni 
14160e78d2cSAbhishek Kulkarni void v9fs_cache_session_get_cookie(struct v9fs_session_info *v9ses)
14260e78d2cSAbhishek Kulkarni {
14360e78d2cSAbhishek Kulkarni 	/* If no cache session tag was specified, we generate a random one. */
14460e78d2cSAbhishek Kulkarni 	if (!v9ses->cachetag)
14560e78d2cSAbhishek Kulkarni 		v9fs_random_cachetag(v9ses);
14660e78d2cSAbhishek Kulkarni 
14760e78d2cSAbhishek Kulkarni 	v9ses->fscache = fscache_acquire_cookie(v9fs_cache_netfs.primary_index,
14860e78d2cSAbhishek Kulkarni 						&v9fs_cache_session_index_def,
14960e78d2cSAbhishek Kulkarni 						v9ses);
15060e78d2cSAbhishek Kulkarni 	P9_DPRINTK(P9_DEBUG_FSC, "session %p get cookie %p", v9ses,
15160e78d2cSAbhishek Kulkarni 		   v9ses->fscache);
15260e78d2cSAbhishek Kulkarni }
15360e78d2cSAbhishek Kulkarni 
15460e78d2cSAbhishek Kulkarni void v9fs_cache_session_put_cookie(struct v9fs_session_info *v9ses)
15560e78d2cSAbhishek Kulkarni {
15660e78d2cSAbhishek Kulkarni 	P9_DPRINTK(P9_DEBUG_FSC, "session %p put cookie %p", v9ses,
15760e78d2cSAbhishek Kulkarni 		   v9ses->fscache);
15860e78d2cSAbhishek Kulkarni 	fscache_relinquish_cookie(v9ses->fscache, 0);
15960e78d2cSAbhishek Kulkarni 	v9ses->fscache = NULL;
16060e78d2cSAbhishek Kulkarni }
16160e78d2cSAbhishek Kulkarni 
16260e78d2cSAbhishek Kulkarni 
16360e78d2cSAbhishek Kulkarni static uint16_t v9fs_cache_inode_get_key(const void *cookie_netfs_data,
16460e78d2cSAbhishek Kulkarni 					 void *buffer, uint16_t bufmax)
16560e78d2cSAbhishek Kulkarni {
16660e78d2cSAbhishek Kulkarni 	const struct v9fs_cookie *vcookie = cookie_netfs_data;
16760e78d2cSAbhishek Kulkarni 	memcpy(buffer, &vcookie->qid->path, sizeof(vcookie->qid->path));
16860e78d2cSAbhishek Kulkarni 
16960e78d2cSAbhishek Kulkarni 	P9_DPRINTK(P9_DEBUG_FSC, "inode %p get key %llu", &vcookie->inode,
17060e78d2cSAbhishek Kulkarni 		   vcookie->qid->path);
17160e78d2cSAbhishek Kulkarni 	return sizeof(vcookie->qid->path);
17260e78d2cSAbhishek Kulkarni }
17360e78d2cSAbhishek Kulkarni 
17460e78d2cSAbhishek Kulkarni static void v9fs_cache_inode_get_attr(const void *cookie_netfs_data,
17560e78d2cSAbhishek Kulkarni 				      uint64_t *size)
17660e78d2cSAbhishek Kulkarni {
17760e78d2cSAbhishek Kulkarni 	const struct v9fs_cookie *vcookie = cookie_netfs_data;
17860e78d2cSAbhishek Kulkarni 	*size = i_size_read(&vcookie->inode);
17960e78d2cSAbhishek Kulkarni 
18060e78d2cSAbhishek Kulkarni 	P9_DPRINTK(P9_DEBUG_FSC, "inode %p get attr %llu", &vcookie->inode,
18160e78d2cSAbhishek Kulkarni 		   *size);
18260e78d2cSAbhishek Kulkarni }
18360e78d2cSAbhishek Kulkarni 
18460e78d2cSAbhishek Kulkarni static uint16_t v9fs_cache_inode_get_aux(const void *cookie_netfs_data,
18560e78d2cSAbhishek Kulkarni 					 void *buffer, uint16_t buflen)
18660e78d2cSAbhishek Kulkarni {
18760e78d2cSAbhishek Kulkarni 	const struct v9fs_cookie *vcookie = cookie_netfs_data;
18860e78d2cSAbhishek Kulkarni 	memcpy(buffer, &vcookie->qid->version, sizeof(vcookie->qid->version));
18960e78d2cSAbhishek Kulkarni 
19060e78d2cSAbhishek Kulkarni 	P9_DPRINTK(P9_DEBUG_FSC, "inode %p get aux %u", &vcookie->inode,
19160e78d2cSAbhishek Kulkarni 		   vcookie->qid->version);
19260e78d2cSAbhishek Kulkarni 	return sizeof(vcookie->qid->version);
19360e78d2cSAbhishek Kulkarni }
19460e78d2cSAbhishek Kulkarni 
19560e78d2cSAbhishek Kulkarni static enum
19660e78d2cSAbhishek Kulkarni fscache_checkaux v9fs_cache_inode_check_aux(void *cookie_netfs_data,
19760e78d2cSAbhishek Kulkarni 					    const void *buffer,
19860e78d2cSAbhishek Kulkarni 					    uint16_t buflen)
19960e78d2cSAbhishek Kulkarni {
20060e78d2cSAbhishek Kulkarni 	const struct v9fs_cookie *vcookie = cookie_netfs_data;
20160e78d2cSAbhishek Kulkarni 
20260e78d2cSAbhishek Kulkarni 	if (buflen != sizeof(vcookie->qid->version))
20360e78d2cSAbhishek Kulkarni 		return FSCACHE_CHECKAUX_OBSOLETE;
20460e78d2cSAbhishek Kulkarni 
20560e78d2cSAbhishek Kulkarni 	if (memcmp(buffer, &vcookie->qid->version,
20660e78d2cSAbhishek Kulkarni 		   sizeof(vcookie->qid->version)))
20760e78d2cSAbhishek Kulkarni 		return FSCACHE_CHECKAUX_OBSOLETE;
20860e78d2cSAbhishek Kulkarni 
20960e78d2cSAbhishek Kulkarni 	return FSCACHE_CHECKAUX_OKAY;
21060e78d2cSAbhishek Kulkarni }
21160e78d2cSAbhishek Kulkarni 
21260e78d2cSAbhishek Kulkarni static void v9fs_cache_inode_now_uncached(void *cookie_netfs_data)
21360e78d2cSAbhishek Kulkarni {
21460e78d2cSAbhishek Kulkarni 	struct v9fs_cookie *vcookie = cookie_netfs_data;
21560e78d2cSAbhishek Kulkarni 	struct pagevec pvec;
21660e78d2cSAbhishek Kulkarni 	pgoff_t first;
21760e78d2cSAbhishek Kulkarni 	int loop, nr_pages;
21860e78d2cSAbhishek Kulkarni 
21960e78d2cSAbhishek Kulkarni 	pagevec_init(&pvec, 0);
22060e78d2cSAbhishek Kulkarni 	first = 0;
22160e78d2cSAbhishek Kulkarni 
22260e78d2cSAbhishek Kulkarni 	for (;;) {
22360e78d2cSAbhishek Kulkarni 		nr_pages = pagevec_lookup(&pvec, vcookie->inode.i_mapping,
22460e78d2cSAbhishek Kulkarni 					  first,
22560e78d2cSAbhishek Kulkarni 					  PAGEVEC_SIZE - pagevec_count(&pvec));
22660e78d2cSAbhishek Kulkarni 		if (!nr_pages)
22760e78d2cSAbhishek Kulkarni 			break;
22860e78d2cSAbhishek Kulkarni 
22960e78d2cSAbhishek Kulkarni 		for (loop = 0; loop < nr_pages; loop++)
23060e78d2cSAbhishek Kulkarni 			ClearPageFsCache(pvec.pages[loop]);
23160e78d2cSAbhishek Kulkarni 
23260e78d2cSAbhishek Kulkarni 		first = pvec.pages[nr_pages - 1]->index + 1;
23360e78d2cSAbhishek Kulkarni 
23460e78d2cSAbhishek Kulkarni 		pvec.nr = nr_pages;
23560e78d2cSAbhishek Kulkarni 		pagevec_release(&pvec);
23660e78d2cSAbhishek Kulkarni 		cond_resched();
23760e78d2cSAbhishek Kulkarni 	}
23860e78d2cSAbhishek Kulkarni }
23960e78d2cSAbhishek Kulkarni 
24060e78d2cSAbhishek Kulkarni const struct fscache_cookie_def v9fs_cache_inode_index_def = {
24160e78d2cSAbhishek Kulkarni 	.name		= "9p.inode",
24260e78d2cSAbhishek Kulkarni 	.type		= FSCACHE_COOKIE_TYPE_DATAFILE,
24360e78d2cSAbhishek Kulkarni 	.get_key	= v9fs_cache_inode_get_key,
24460e78d2cSAbhishek Kulkarni 	.get_attr	= v9fs_cache_inode_get_attr,
24560e78d2cSAbhishek Kulkarni 	.get_aux	= v9fs_cache_inode_get_aux,
24660e78d2cSAbhishek Kulkarni 	.check_aux	= v9fs_cache_inode_check_aux,
24760e78d2cSAbhishek Kulkarni 	.now_uncached	= v9fs_cache_inode_now_uncached,
24860e78d2cSAbhishek Kulkarni };
24960e78d2cSAbhishek Kulkarni 
25060e78d2cSAbhishek Kulkarni void v9fs_cache_inode_get_cookie(struct inode *inode)
25160e78d2cSAbhishek Kulkarni {
25260e78d2cSAbhishek Kulkarni 	struct v9fs_cookie *vcookie;
25360e78d2cSAbhishek Kulkarni 	struct v9fs_session_info *v9ses;
25460e78d2cSAbhishek Kulkarni 
25560e78d2cSAbhishek Kulkarni 	if (!S_ISREG(inode->i_mode))
25660e78d2cSAbhishek Kulkarni 		return;
25760e78d2cSAbhishek Kulkarni 
25860e78d2cSAbhishek Kulkarni 	vcookie = v9fs_inode2cookie(inode);
25960e78d2cSAbhishek Kulkarni 	if (vcookie->fscache)
26060e78d2cSAbhishek Kulkarni 		return;
26160e78d2cSAbhishek Kulkarni 
26260e78d2cSAbhishek Kulkarni 	v9ses = v9fs_inode2v9ses(inode);
26360e78d2cSAbhishek Kulkarni 	vcookie->fscache = fscache_acquire_cookie(v9ses->fscache,
26460e78d2cSAbhishek Kulkarni 						  &v9fs_cache_inode_index_def,
26560e78d2cSAbhishek Kulkarni 						  vcookie);
26660e78d2cSAbhishek Kulkarni 
26760e78d2cSAbhishek Kulkarni 	P9_DPRINTK(P9_DEBUG_FSC, "inode %p get cookie %p", inode,
26860e78d2cSAbhishek Kulkarni 		   vcookie->fscache);
26960e78d2cSAbhishek Kulkarni }
27060e78d2cSAbhishek Kulkarni 
27160e78d2cSAbhishek Kulkarni void v9fs_cache_inode_put_cookie(struct inode *inode)
27260e78d2cSAbhishek Kulkarni {
27360e78d2cSAbhishek Kulkarni 	struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
27460e78d2cSAbhishek Kulkarni 
27560e78d2cSAbhishek Kulkarni 	if (!vcookie->fscache)
27660e78d2cSAbhishek Kulkarni 		return;
27760e78d2cSAbhishek Kulkarni 	P9_DPRINTK(P9_DEBUG_FSC, "inode %p put cookie %p", inode,
27860e78d2cSAbhishek Kulkarni 		   vcookie->fscache);
27960e78d2cSAbhishek Kulkarni 
28060e78d2cSAbhishek Kulkarni 	fscache_relinquish_cookie(vcookie->fscache, 0);
28160e78d2cSAbhishek Kulkarni 	vcookie->fscache = NULL;
28260e78d2cSAbhishek Kulkarni }
28360e78d2cSAbhishek Kulkarni 
28460e78d2cSAbhishek Kulkarni void v9fs_cache_inode_flush_cookie(struct inode *inode)
28560e78d2cSAbhishek Kulkarni {
28660e78d2cSAbhishek Kulkarni 	struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
28760e78d2cSAbhishek Kulkarni 
28860e78d2cSAbhishek Kulkarni 	if (!vcookie->fscache)
28960e78d2cSAbhishek Kulkarni 		return;
29060e78d2cSAbhishek Kulkarni 	P9_DPRINTK(P9_DEBUG_FSC, "inode %p flush cookie %p", inode,
29160e78d2cSAbhishek Kulkarni 		   vcookie->fscache);
29260e78d2cSAbhishek Kulkarni 
29360e78d2cSAbhishek Kulkarni 	fscache_relinquish_cookie(vcookie->fscache, 1);
29460e78d2cSAbhishek Kulkarni 	vcookie->fscache = NULL;
29560e78d2cSAbhishek Kulkarni }
29660e78d2cSAbhishek Kulkarni 
29760e78d2cSAbhishek Kulkarni void v9fs_cache_inode_set_cookie(struct inode *inode, struct file *filp)
29860e78d2cSAbhishek Kulkarni {
29960e78d2cSAbhishek Kulkarni 	struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
30060e78d2cSAbhishek Kulkarni 	struct p9_fid *fid;
30160e78d2cSAbhishek Kulkarni 
30260e78d2cSAbhishek Kulkarni 	if (!vcookie->fscache)
30360e78d2cSAbhishek Kulkarni 		return;
30460e78d2cSAbhishek Kulkarni 
30560e78d2cSAbhishek Kulkarni 	spin_lock(&vcookie->lock);
30660e78d2cSAbhishek Kulkarni 	fid = filp->private_data;
30760e78d2cSAbhishek Kulkarni 	if ((filp->f_flags & O_ACCMODE) != O_RDONLY)
30860e78d2cSAbhishek Kulkarni 		v9fs_cache_inode_flush_cookie(inode);
30960e78d2cSAbhishek Kulkarni 	else
31060e78d2cSAbhishek Kulkarni 		v9fs_cache_inode_get_cookie(inode);
31160e78d2cSAbhishek Kulkarni 
31260e78d2cSAbhishek Kulkarni 	spin_unlock(&vcookie->lock);
31360e78d2cSAbhishek Kulkarni }
31460e78d2cSAbhishek Kulkarni 
31560e78d2cSAbhishek Kulkarni void v9fs_cache_inode_reset_cookie(struct inode *inode)
31660e78d2cSAbhishek Kulkarni {
31760e78d2cSAbhishek Kulkarni 	struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
31860e78d2cSAbhishek Kulkarni 	struct v9fs_session_info *v9ses;
31960e78d2cSAbhishek Kulkarni 	struct fscache_cookie *old;
32060e78d2cSAbhishek Kulkarni 
32160e78d2cSAbhishek Kulkarni 	if (!vcookie->fscache)
32260e78d2cSAbhishek Kulkarni 		return;
32360e78d2cSAbhishek Kulkarni 
32460e78d2cSAbhishek Kulkarni 	old = vcookie->fscache;
32560e78d2cSAbhishek Kulkarni 
32660e78d2cSAbhishek Kulkarni 	spin_lock(&vcookie->lock);
32760e78d2cSAbhishek Kulkarni 	fscache_relinquish_cookie(vcookie->fscache, 1);
32860e78d2cSAbhishek Kulkarni 
32960e78d2cSAbhishek Kulkarni 	v9ses = v9fs_inode2v9ses(inode);
33060e78d2cSAbhishek Kulkarni 	vcookie->fscache = fscache_acquire_cookie(v9ses->fscache,
33160e78d2cSAbhishek Kulkarni 						  &v9fs_cache_inode_index_def,
33260e78d2cSAbhishek Kulkarni 						  vcookie);
33360e78d2cSAbhishek Kulkarni 
33460e78d2cSAbhishek Kulkarni 	P9_DPRINTK(P9_DEBUG_FSC, "inode %p revalidating cookie old %p new %p",
33560e78d2cSAbhishek Kulkarni 		   inode, old, vcookie->fscache);
33660e78d2cSAbhishek Kulkarni 
33760e78d2cSAbhishek Kulkarni 	spin_unlock(&vcookie->lock);
33860e78d2cSAbhishek Kulkarni }
33960e78d2cSAbhishek Kulkarni 
34060e78d2cSAbhishek Kulkarni int __v9fs_fscache_release_page(struct page *page, gfp_t gfp)
34160e78d2cSAbhishek Kulkarni {
34260e78d2cSAbhishek Kulkarni 	struct inode *inode = page->mapping->host;
34360e78d2cSAbhishek Kulkarni 	struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
34460e78d2cSAbhishek Kulkarni 
34560e78d2cSAbhishek Kulkarni 	BUG_ON(!vcookie->fscache);
34660e78d2cSAbhishek Kulkarni 
3476f054164SDavid Howells 	return fscache_maybe_release_page(vcookie->fscache, page, gfp);
34860e78d2cSAbhishek Kulkarni }
34960e78d2cSAbhishek Kulkarni 
35060e78d2cSAbhishek Kulkarni void __v9fs_fscache_invalidate_page(struct page *page)
35160e78d2cSAbhishek Kulkarni {
35260e78d2cSAbhishek Kulkarni 	struct inode *inode = page->mapping->host;
35360e78d2cSAbhishek Kulkarni 	struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
35460e78d2cSAbhishek Kulkarni 
35560e78d2cSAbhishek Kulkarni 	BUG_ON(!vcookie->fscache);
35660e78d2cSAbhishek Kulkarni 
35760e78d2cSAbhishek Kulkarni 	if (PageFsCache(page)) {
35860e78d2cSAbhishek Kulkarni 		fscache_wait_on_page_write(vcookie->fscache, page);
35960e78d2cSAbhishek Kulkarni 		BUG_ON(!PageLocked(page));
36060e78d2cSAbhishek Kulkarni 		fscache_uncache_page(vcookie->fscache, page);
36160e78d2cSAbhishek Kulkarni 	}
36260e78d2cSAbhishek Kulkarni }
36360e78d2cSAbhishek Kulkarni 
36460e78d2cSAbhishek Kulkarni static void v9fs_vfs_readpage_complete(struct page *page, void *data,
36560e78d2cSAbhishek Kulkarni 				       int error)
36660e78d2cSAbhishek Kulkarni {
36760e78d2cSAbhishek Kulkarni 	if (!error)
36860e78d2cSAbhishek Kulkarni 		SetPageUptodate(page);
36960e78d2cSAbhishek Kulkarni 
37060e78d2cSAbhishek Kulkarni 	unlock_page(page);
37160e78d2cSAbhishek Kulkarni }
37260e78d2cSAbhishek Kulkarni 
37360e78d2cSAbhishek Kulkarni /**
37460e78d2cSAbhishek Kulkarni  * __v9fs_readpage_from_fscache - read a page from cache
37560e78d2cSAbhishek Kulkarni  *
37660e78d2cSAbhishek Kulkarni  * Returns 0 if the pages are in cache and a BIO is submitted,
37760e78d2cSAbhishek Kulkarni  * 1 if the pages are not in cache and -error otherwise.
37860e78d2cSAbhishek Kulkarni  */
37960e78d2cSAbhishek Kulkarni 
38060e78d2cSAbhishek Kulkarni int __v9fs_readpage_from_fscache(struct inode *inode, struct page *page)
38160e78d2cSAbhishek Kulkarni {
38260e78d2cSAbhishek Kulkarni 	int ret;
38360e78d2cSAbhishek Kulkarni 	const struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
38460e78d2cSAbhishek Kulkarni 
38560e78d2cSAbhishek Kulkarni 	P9_DPRINTK(P9_DEBUG_FSC, "inode %p page %p", inode, page);
38660e78d2cSAbhishek Kulkarni 	if (!vcookie->fscache)
38760e78d2cSAbhishek Kulkarni 		return -ENOBUFS;
38860e78d2cSAbhishek Kulkarni 
38960e78d2cSAbhishek Kulkarni 	ret = fscache_read_or_alloc_page(vcookie->fscache,
39060e78d2cSAbhishek Kulkarni 					 page,
39160e78d2cSAbhishek Kulkarni 					 v9fs_vfs_readpage_complete,
39260e78d2cSAbhishek Kulkarni 					 NULL,
39360e78d2cSAbhishek Kulkarni 					 GFP_KERNEL);
39460e78d2cSAbhishek Kulkarni 	switch (ret) {
39560e78d2cSAbhishek Kulkarni 	case -ENOBUFS:
39660e78d2cSAbhishek Kulkarni 	case -ENODATA:
39760e78d2cSAbhishek Kulkarni 		P9_DPRINTK(P9_DEBUG_FSC, "page/inode not in cache %d", ret);
39860e78d2cSAbhishek Kulkarni 		return 1;
39960e78d2cSAbhishek Kulkarni 	case 0:
40060e78d2cSAbhishek Kulkarni 		P9_DPRINTK(P9_DEBUG_FSC, "BIO submitted");
40160e78d2cSAbhishek Kulkarni 		return ret;
40260e78d2cSAbhishek Kulkarni 	default:
40360e78d2cSAbhishek Kulkarni 		P9_DPRINTK(P9_DEBUG_FSC, "ret %d", ret);
40460e78d2cSAbhishek Kulkarni 		return ret;
40560e78d2cSAbhishek Kulkarni 	}
40660e78d2cSAbhishek Kulkarni }
40760e78d2cSAbhishek Kulkarni 
40860e78d2cSAbhishek Kulkarni /**
40960e78d2cSAbhishek Kulkarni  * __v9fs_readpages_from_fscache - read multiple pages from cache
41060e78d2cSAbhishek Kulkarni  *
41160e78d2cSAbhishek Kulkarni  * Returns 0 if the pages are in cache and a BIO is submitted,
41260e78d2cSAbhishek Kulkarni  * 1 if the pages are not in cache and -error otherwise.
41360e78d2cSAbhishek Kulkarni  */
41460e78d2cSAbhishek Kulkarni 
41560e78d2cSAbhishek Kulkarni int __v9fs_readpages_from_fscache(struct inode *inode,
41660e78d2cSAbhishek Kulkarni 				  struct address_space *mapping,
41760e78d2cSAbhishek Kulkarni 				  struct list_head *pages,
41860e78d2cSAbhishek Kulkarni 				  unsigned *nr_pages)
41960e78d2cSAbhishek Kulkarni {
42060e78d2cSAbhishek Kulkarni 	int ret;
42160e78d2cSAbhishek Kulkarni 	const struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
42260e78d2cSAbhishek Kulkarni 
42360e78d2cSAbhishek Kulkarni 	P9_DPRINTK(P9_DEBUG_FSC, "inode %p pages %u", inode, *nr_pages);
42460e78d2cSAbhishek Kulkarni 	if (!vcookie->fscache)
42560e78d2cSAbhishek Kulkarni 		return -ENOBUFS;
42660e78d2cSAbhishek Kulkarni 
42760e78d2cSAbhishek Kulkarni 	ret = fscache_read_or_alloc_pages(vcookie->fscache,
42860e78d2cSAbhishek Kulkarni 					  mapping, pages, nr_pages,
42960e78d2cSAbhishek Kulkarni 					  v9fs_vfs_readpage_complete,
43060e78d2cSAbhishek Kulkarni 					  NULL,
43160e78d2cSAbhishek Kulkarni 					  mapping_gfp_mask(mapping));
43260e78d2cSAbhishek Kulkarni 	switch (ret) {
43360e78d2cSAbhishek Kulkarni 	case -ENOBUFS:
43460e78d2cSAbhishek Kulkarni 	case -ENODATA:
43560e78d2cSAbhishek Kulkarni 		P9_DPRINTK(P9_DEBUG_FSC, "pages/inodes not in cache %d", ret);
43660e78d2cSAbhishek Kulkarni 		return 1;
43760e78d2cSAbhishek Kulkarni 	case 0:
43860e78d2cSAbhishek Kulkarni 		BUG_ON(!list_empty(pages));
43960e78d2cSAbhishek Kulkarni 		BUG_ON(*nr_pages != 0);
44060e78d2cSAbhishek Kulkarni 		P9_DPRINTK(P9_DEBUG_FSC, "BIO submitted");
44160e78d2cSAbhishek Kulkarni 		return ret;
44260e78d2cSAbhishek Kulkarni 	default:
44360e78d2cSAbhishek Kulkarni 		P9_DPRINTK(P9_DEBUG_FSC, "ret %d", ret);
44460e78d2cSAbhishek Kulkarni 		return ret;
44560e78d2cSAbhishek Kulkarni 	}
44660e78d2cSAbhishek Kulkarni }
44760e78d2cSAbhishek Kulkarni 
44860e78d2cSAbhishek Kulkarni /**
44960e78d2cSAbhishek Kulkarni  * __v9fs_readpage_to_fscache - write a page to the cache
45060e78d2cSAbhishek Kulkarni  *
45160e78d2cSAbhishek Kulkarni  */
45260e78d2cSAbhishek Kulkarni 
45360e78d2cSAbhishek Kulkarni void __v9fs_readpage_to_fscache(struct inode *inode, struct page *page)
45460e78d2cSAbhishek Kulkarni {
45560e78d2cSAbhishek Kulkarni 	int ret;
45660e78d2cSAbhishek Kulkarni 	const struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
45760e78d2cSAbhishek Kulkarni 
45860e78d2cSAbhishek Kulkarni 	P9_DPRINTK(P9_DEBUG_FSC, "inode %p page %p", inode, page);
45960e78d2cSAbhishek Kulkarni 	ret = fscache_write_page(vcookie->fscache, page, GFP_KERNEL);
46060e78d2cSAbhishek Kulkarni 	P9_DPRINTK(P9_DEBUG_FSC, "ret =  %d", ret);
46160e78d2cSAbhishek Kulkarni 	if (ret != 0)
46260e78d2cSAbhishek Kulkarni 		v9fs_uncache_page(inode, page);
46360e78d2cSAbhishek Kulkarni }
4642efda799SAneesh Kumar K.V 
4652efda799SAneesh Kumar K.V /*
4662efda799SAneesh Kumar K.V  * wait for a page to complete writing to the cache
4672efda799SAneesh Kumar K.V  */
4682efda799SAneesh Kumar K.V void __v9fs_fscache_wait_on_page_write(struct inode *inode, struct page *page)
4692efda799SAneesh Kumar K.V {
4702efda799SAneesh Kumar K.V 	const struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
4712efda799SAneesh Kumar K.V 	P9_DPRINTK(P9_DEBUG_FSC, "inode %p page %p", inode, page);
4722efda799SAneesh Kumar K.V 	if (PageFsCache(page))
4732efda799SAneesh Kumar K.V 		fscache_wait_on_page_write(vcookie->fscache, page);
4742efda799SAneesh Kumar K.V }
475