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