Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a7ddbf89 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs:
  9p: Update documentation to add fscache related bits
  9p: Add fscache support to 9p
  9p: Fix the incorrect update of inode size in v9fs_file_write()
  9p: Use the i_size_[read, write]() macros instead of using inode->i_size directly.
parents 3e56d493 f4edeeb3
Loading
Loading
Loading
Loading
+26 −14
Original line number Original line Diff line number Diff line
@@ -18,11 +18,11 @@ the 9p client is available in the form of a USENIX paper:


Other applications are described in the following papers:
Other applications are described in the following papers:
	* XCPU & Clustering
	* XCPU & Clustering
		http://www.xcpu.org/xcpu-talk.pdf
		http://xcpu.org/papers/xcpu-talk.pdf
	* KVMFS: control file system for KVM
	* KVMFS: control file system for KVM
		http://www.xcpu.org/kvmfs.pdf
		http://xcpu.org/papers/kvmfs.pdf
	* CellFS: A New Programming Model for the Cell BE
	* CellFS: A New Programming Model for the Cell BE
		http://www.xcpu.org/cellfs-talk.pdf
		http://xcpu.org/papers/cellfs-talk.pdf
	* PROSE I/O: Using 9p to enable Application Partitions
	* PROSE I/O: Using 9p to enable Application Partitions
		http://plan9.escet.urjc.es/iwp9/cready/PROSE_iwp9_2006.pdf
		http://plan9.escet.urjc.es/iwp9/cready/PROSE_iwp9_2006.pdf


@@ -48,6 +48,7 @@ OPTIONS
                                (see rfdno and wfdno)
                                (see rfdno and wfdno)
			virtio	- connect to the next virtio channel available
			virtio	- connect to the next virtio channel available
				(from lguest or KVM with trans_virtio module)
				(from lguest or KVM with trans_virtio module)
			rdma	- connect to a specified RDMA channel


  uname=name	user name to attempt mount as on the remote server.  The
  uname=name	user name to attempt mount as on the remote server.  The
  		server may override or ignore this value.  Certain user
  		server may override or ignore this value.  Certain user
@@ -59,6 +60,8 @@ OPTIONS
  cache=mode	specifies a caching policy.  By default, no caches are used.
  cache=mode	specifies a caching policy.  By default, no caches are used.
			loose = no attempts are made at consistency,
			loose = no attempts are made at consistency,
                                intended for exclusive, read-only mounts
                                intended for exclusive, read-only mounts
			fscache = use FS-Cache for a persistent, read-only
				cache backend.


  debug=n	specifies debug level.  The debug level is a bitmask.
  debug=n	specifies debug level.  The debug level is a bitmask.
			0x01  = display verbose error messages
			0x01  = display verbose error messages
@@ -69,6 +72,10 @@ OPTIONS
			0x20  = display RPC debug
			0x20  = display RPC debug
			0x40  = display transport debug
			0x40  = display transport debug
			0x80  = display allocation debug
			0x80  = display allocation debug
			0x100 = display protocol message debug
			0x200 = display Fid debug
			0x400 = display packet debug
			0x800 = display fscache tracing debug


  rfdno=n	the file descriptor for reading with trans=fd
  rfdno=n	the file descriptor for reading with trans=fd


@@ -100,6 +107,10 @@ OPTIONS
			any   = v9fs does single attach and performs all
			any   = v9fs does single attach and performs all
				operations as one user
				operations as one user


  cachetag	cache tag to use the specified persistent cache.
		cache tags for existing cache sessions can be listed at
		/sys/fs/9p/caches. (applies only to cache=fscache)

RESOURCES
RESOURCES
=========
=========


@@ -118,7 +129,7 @@ and export.
A Linux version of the 9p server is now maintained under the npfs project
A Linux version of the 9p server is now maintained under the npfs project
on sourceforge (http://sourceforge.net/projects/npfs).  The currently
on sourceforge (http://sourceforge.net/projects/npfs).  The currently
maintained version is the single-threaded version of the server (named spfs)
maintained version is the single-threaded version of the server (named spfs)
available from the same CVS repository.
available from the same SVN repository.


There are user and developer mailing lists available through the v9fs project
There are user and developer mailing lists available through the v9fs project
on sourceforge (http://sourceforge.net/projects/v9fs).
on sourceforge (http://sourceforge.net/projects/v9fs).
@@ -126,7 +137,8 @@ on sourceforge (http://sourceforge.net/projects/v9fs).
A stand-alone version of the module (which should build for any 2.6 kernel)
A stand-alone version of the module (which should build for any 2.6 kernel)
is available via (http://github.com/ericvh/9p-sac/tree/master)
is available via (http://github.com/ericvh/9p-sac/tree/master)


News and other information is maintained on SWiK (http://swik.net/v9fs).
News and other information is maintained on SWiK (http://swik.net/v9fs)
and the Wiki (http://sf.net/apps/mediawiki/v9fs/index.php).


Bug reports may be issued through the kernel.org bugzilla 
Bug reports may be issued through the kernel.org bugzilla 
(http://bugzilla.kernel.org)
(http://bugzilla.kernel.org)
+9 −0
Original line number Original line Diff line number Diff line
@@ -8,3 +8,12 @@ config 9P_FS
	  See <http://v9fs.sf.net> for more information.
	  See <http://v9fs.sf.net> for more information.


	  If unsure, say N.
	  If unsure, say N.

config 9P_FSCACHE
	bool "Enable 9P client caching support (EXPERIMENTAL)"
	depends on EXPERIMENTAL
	depends on 9P_FS=m && FSCACHE || 9P_FS=y && FSCACHE=y
	help
	  Choose Y here to enable persistent, read-only local
	  caching support for 9p clients using FS-Cache
+2 −1
Original line number Original line Diff line number Diff line
@@ -8,5 +8,6 @@ obj-$(CONFIG_9P_FS) := 9p.o
	vfs_dir.o \
	vfs_dir.o \
	vfs_dentry.o \
	vfs_dentry.o \
	v9fs.o \
	v9fs.o \
	fid.o \
	fid.o


9p-$(CONFIG_9P_FSCACHE) += cache.o

fs/9p/cache.c

0 → 100644
+474 −0
Original line number Original line Diff line number Diff line
/*
 * V9FS cache definitions.
 *
 *  Copyright (C) 2009 by Abhishek Kulkarni <adkulkar@umail.iu.edu>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2
 *  as published by the Free Software Foundation.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to:
 *  Free Software Foundation
 *  51 Franklin Street, Fifth Floor
 *  Boston, MA  02111-1301  USA
 *
 */

#include <linux/jiffies.h>
#include <linux/file.h>
#include <linux/stat.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <net/9p/9p.h>

#include "v9fs.h"
#include "cache.h"

#define CACHETAG_LEN  11

struct kmem_cache *vcookie_cache;

struct fscache_netfs v9fs_cache_netfs = {
	.name 		= "9p",
	.version 	= 0,
};

static void init_once(void *foo)
{
	struct v9fs_cookie *vcookie = (struct v9fs_cookie *) foo;
	vcookie->fscache = NULL;
	vcookie->qid = NULL;
	inode_init_once(&vcookie->inode);
}

/**
 * v9fs_init_vcookiecache - initialize a cache for vcookies to maintain
 *			    vcookie to inode mapping
 *
 * Returns 0 on success.
 */

static int v9fs_init_vcookiecache(void)
{
	vcookie_cache = kmem_cache_create("vcookie_cache",
					  sizeof(struct v9fs_cookie),
					  0, (SLAB_RECLAIM_ACCOUNT|
					      SLAB_MEM_SPREAD),
					  init_once);
	if (!vcookie_cache)
		return -ENOMEM;

	return 0;
}

/**
 * v9fs_destroy_vcookiecache - destroy the cache of vcookies
 *
 */

static void v9fs_destroy_vcookiecache(void)
{
	kmem_cache_destroy(vcookie_cache);
}

int __v9fs_cache_register(void)
{
	int ret;
	ret = v9fs_init_vcookiecache();
	if (ret < 0)
		return ret;

	return fscache_register_netfs(&v9fs_cache_netfs);
}

void __v9fs_cache_unregister(void)
{
	v9fs_destroy_vcookiecache();
	fscache_unregister_netfs(&v9fs_cache_netfs);
}

/**
 * v9fs_random_cachetag - Generate a random tag to be associated
 *			  with a new cache session.
 *
 * The value of jiffies is used for a fairly randomly cache tag.
 */

static
int v9fs_random_cachetag(struct v9fs_session_info *v9ses)
{
	v9ses->cachetag = kmalloc(CACHETAG_LEN, GFP_KERNEL);
	if (!v9ses->cachetag)
		return -ENOMEM;

	return scnprintf(v9ses->cachetag, CACHETAG_LEN, "%lu", jiffies);
}

static uint16_t v9fs_cache_session_get_key(const void *cookie_netfs_data,
					   void *buffer, uint16_t bufmax)
{
	struct v9fs_session_info *v9ses;
	uint16_t klen = 0;

	v9ses = (struct v9fs_session_info *)cookie_netfs_data;
	P9_DPRINTK(P9_DEBUG_FSC, "session %p buf %p size %u", v9ses,
		   buffer, bufmax);

	if (v9ses->cachetag)
		klen = strlen(v9ses->cachetag);

	if (klen > bufmax)
		return 0;

	memcpy(buffer, v9ses->cachetag, klen);
	P9_DPRINTK(P9_DEBUG_FSC, "cache session tag %s", v9ses->cachetag);
	return klen;
}

const struct fscache_cookie_def v9fs_cache_session_index_def = {
	.name 		= "9P.session",
	.type 		= FSCACHE_COOKIE_TYPE_INDEX,
	.get_key 	= v9fs_cache_session_get_key,
};

void v9fs_cache_session_get_cookie(struct v9fs_session_info *v9ses)
{
	/* If no cache session tag was specified, we generate a random one. */
	if (!v9ses->cachetag)
		v9fs_random_cachetag(v9ses);

	v9ses->fscache = fscache_acquire_cookie(v9fs_cache_netfs.primary_index,
						&v9fs_cache_session_index_def,
						v9ses);
	P9_DPRINTK(P9_DEBUG_FSC, "session %p get cookie %p", v9ses,
		   v9ses->fscache);
}

void v9fs_cache_session_put_cookie(struct v9fs_session_info *v9ses)
{
	P9_DPRINTK(P9_DEBUG_FSC, "session %p put cookie %p", v9ses,
		   v9ses->fscache);
	fscache_relinquish_cookie(v9ses->fscache, 0);
	v9ses->fscache = NULL;
}


static uint16_t v9fs_cache_inode_get_key(const void *cookie_netfs_data,
					 void *buffer, uint16_t bufmax)
{
	const struct v9fs_cookie *vcookie = cookie_netfs_data;
	memcpy(buffer, &vcookie->qid->path, sizeof(vcookie->qid->path));

	P9_DPRINTK(P9_DEBUG_FSC, "inode %p get key %llu", &vcookie->inode,
		   vcookie->qid->path);
	return sizeof(vcookie->qid->path);
}

static void v9fs_cache_inode_get_attr(const void *cookie_netfs_data,
				      uint64_t *size)
{
	const struct v9fs_cookie *vcookie = cookie_netfs_data;
	*size = i_size_read(&vcookie->inode);

	P9_DPRINTK(P9_DEBUG_FSC, "inode %p get attr %llu", &vcookie->inode,
		   *size);
}

static uint16_t v9fs_cache_inode_get_aux(const void *cookie_netfs_data,
					 void *buffer, uint16_t buflen)
{
	const struct v9fs_cookie *vcookie = cookie_netfs_data;
	memcpy(buffer, &vcookie->qid->version, sizeof(vcookie->qid->version));

	P9_DPRINTK(P9_DEBUG_FSC, "inode %p get aux %u", &vcookie->inode,
		   vcookie->qid->version);
	return sizeof(vcookie->qid->version);
}

static enum
fscache_checkaux v9fs_cache_inode_check_aux(void *cookie_netfs_data,
					    const void *buffer,
					    uint16_t buflen)
{
	const struct v9fs_cookie *vcookie = cookie_netfs_data;

	if (buflen != sizeof(vcookie->qid->version))
		return FSCACHE_CHECKAUX_OBSOLETE;

	if (memcmp(buffer, &vcookie->qid->version,
		   sizeof(vcookie->qid->version)))
		return FSCACHE_CHECKAUX_OBSOLETE;

	return FSCACHE_CHECKAUX_OKAY;
}

static void v9fs_cache_inode_now_uncached(void *cookie_netfs_data)
{
	struct v9fs_cookie *vcookie = cookie_netfs_data;
	struct pagevec pvec;
	pgoff_t first;
	int loop, nr_pages;

	pagevec_init(&pvec, 0);
	first = 0;

	for (;;) {
		nr_pages = pagevec_lookup(&pvec, vcookie->inode.i_mapping,
					  first,
					  PAGEVEC_SIZE - pagevec_count(&pvec));
		if (!nr_pages)
			break;

		for (loop = 0; loop < nr_pages; loop++)
			ClearPageFsCache(pvec.pages[loop]);

		first = pvec.pages[nr_pages - 1]->index + 1;

		pvec.nr = nr_pages;
		pagevec_release(&pvec);
		cond_resched();
	}
}

const struct fscache_cookie_def v9fs_cache_inode_index_def = {
	.name		= "9p.inode",
	.type		= FSCACHE_COOKIE_TYPE_DATAFILE,
	.get_key	= v9fs_cache_inode_get_key,
	.get_attr	= v9fs_cache_inode_get_attr,
	.get_aux	= v9fs_cache_inode_get_aux,
	.check_aux	= v9fs_cache_inode_check_aux,
	.now_uncached	= v9fs_cache_inode_now_uncached,
};

void v9fs_cache_inode_get_cookie(struct inode *inode)
{
	struct v9fs_cookie *vcookie;
	struct v9fs_session_info *v9ses;

	if (!S_ISREG(inode->i_mode))
		return;

	vcookie = v9fs_inode2cookie(inode);
	if (vcookie->fscache)
		return;

	v9ses = v9fs_inode2v9ses(inode);
	vcookie->fscache = fscache_acquire_cookie(v9ses->fscache,
						  &v9fs_cache_inode_index_def,
						  vcookie);

	P9_DPRINTK(P9_DEBUG_FSC, "inode %p get cookie %p", inode,
		   vcookie->fscache);
}

void v9fs_cache_inode_put_cookie(struct inode *inode)
{
	struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);

	if (!vcookie->fscache)
		return;
	P9_DPRINTK(P9_DEBUG_FSC, "inode %p put cookie %p", inode,
		   vcookie->fscache);

	fscache_relinquish_cookie(vcookie->fscache, 0);
	vcookie->fscache = NULL;
}

void v9fs_cache_inode_flush_cookie(struct inode *inode)
{
	struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);

	if (!vcookie->fscache)
		return;
	P9_DPRINTK(P9_DEBUG_FSC, "inode %p flush cookie %p", inode,
		   vcookie->fscache);

	fscache_relinquish_cookie(vcookie->fscache, 1);
	vcookie->fscache = NULL;
}

void v9fs_cache_inode_set_cookie(struct inode *inode, struct file *filp)
{
	struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
	struct p9_fid *fid;

	if (!vcookie->fscache)
		return;

	spin_lock(&vcookie->lock);
	fid = filp->private_data;
	if ((filp->f_flags & O_ACCMODE) != O_RDONLY)
		v9fs_cache_inode_flush_cookie(inode);
	else
		v9fs_cache_inode_get_cookie(inode);

	spin_unlock(&vcookie->lock);
}

void v9fs_cache_inode_reset_cookie(struct inode *inode)
{
	struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
	struct v9fs_session_info *v9ses;
	struct fscache_cookie *old;

	if (!vcookie->fscache)
		return;

	old = vcookie->fscache;

	spin_lock(&vcookie->lock);
	fscache_relinquish_cookie(vcookie->fscache, 1);

	v9ses = v9fs_inode2v9ses(inode);
	vcookie->fscache = fscache_acquire_cookie(v9ses->fscache,
						  &v9fs_cache_inode_index_def,
						  vcookie);

	P9_DPRINTK(P9_DEBUG_FSC, "inode %p revalidating cookie old %p new %p",
		   inode, old, vcookie->fscache);

	spin_unlock(&vcookie->lock);
}

int __v9fs_fscache_release_page(struct page *page, gfp_t gfp)
{
	struct inode *inode = page->mapping->host;
	struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);

	BUG_ON(!vcookie->fscache);

	if (PageFsCache(page)) {
		if (fscache_check_page_write(vcookie->fscache, page)) {
			if (!(gfp & __GFP_WAIT))
				return 0;
			fscache_wait_on_page_write(vcookie->fscache, page);
		}

		fscache_uncache_page(vcookie->fscache, page);
		ClearPageFsCache(page);
	}

	return 1;
}

void __v9fs_fscache_invalidate_page(struct page *page)
{
	struct inode *inode = page->mapping->host;
	struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);

	BUG_ON(!vcookie->fscache);

	if (PageFsCache(page)) {
		fscache_wait_on_page_write(vcookie->fscache, page);
		BUG_ON(!PageLocked(page));
		fscache_uncache_page(vcookie->fscache, page);
		ClearPageFsCache(page);
	}
}

static void v9fs_vfs_readpage_complete(struct page *page, void *data,
				       int error)
{
	if (!error)
		SetPageUptodate(page);

	unlock_page(page);
}

/**
 * __v9fs_readpage_from_fscache - read a page from cache
 *
 * Returns 0 if the pages are in cache and a BIO is submitted,
 * 1 if the pages are not in cache and -error otherwise.
 */

int __v9fs_readpage_from_fscache(struct inode *inode, struct page *page)
{
	int ret;
	const struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);

	P9_DPRINTK(P9_DEBUG_FSC, "inode %p page %p", inode, page);
	if (!vcookie->fscache)
		return -ENOBUFS;

	ret = fscache_read_or_alloc_page(vcookie->fscache,
					 page,
					 v9fs_vfs_readpage_complete,
					 NULL,
					 GFP_KERNEL);
	switch (ret) {
	case -ENOBUFS:
	case -ENODATA:
		P9_DPRINTK(P9_DEBUG_FSC, "page/inode not in cache %d", ret);
		return 1;
	case 0:
		P9_DPRINTK(P9_DEBUG_FSC, "BIO submitted");
		return ret;
	default:
		P9_DPRINTK(P9_DEBUG_FSC, "ret %d", ret);
		return ret;
	}
}

/**
 * __v9fs_readpages_from_fscache - read multiple pages from cache
 *
 * Returns 0 if the pages are in cache and a BIO is submitted,
 * 1 if the pages are not in cache and -error otherwise.
 */

int __v9fs_readpages_from_fscache(struct inode *inode,
				  struct address_space *mapping,
				  struct list_head *pages,
				  unsigned *nr_pages)
{
	int ret;
	const struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);

	P9_DPRINTK(P9_DEBUG_FSC, "inode %p pages %u", inode, *nr_pages);
	if (!vcookie->fscache)
		return -ENOBUFS;

	ret = fscache_read_or_alloc_pages(vcookie->fscache,
					  mapping, pages, nr_pages,
					  v9fs_vfs_readpage_complete,
					  NULL,
					  mapping_gfp_mask(mapping));
	switch (ret) {
	case -ENOBUFS:
	case -ENODATA:
		P9_DPRINTK(P9_DEBUG_FSC, "pages/inodes not in cache %d", ret);
		return 1;
	case 0:
		BUG_ON(!list_empty(pages));
		BUG_ON(*nr_pages != 0);
		P9_DPRINTK(P9_DEBUG_FSC, "BIO submitted");
		return ret;
	default:
		P9_DPRINTK(P9_DEBUG_FSC, "ret %d", ret);
		return ret;
	}
}

/**
 * __v9fs_readpage_to_fscache - write a page to the cache
 *
 */

void __v9fs_readpage_to_fscache(struct inode *inode, struct page *page)
{
	int ret;
	const struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);

	P9_DPRINTK(P9_DEBUG_FSC, "inode %p page %p", inode, page);
	ret = fscache_write_page(vcookie->fscache, page, GFP_KERNEL);
	P9_DPRINTK(P9_DEBUG_FSC, "ret =  %d", ret);
	if (ret != 0)
		v9fs_uncache_page(inode, page);
}

fs/9p/cache.h

0 → 100644
+176 −0
Original line number Original line Diff line number Diff line
/*
 * V9FS cache definitions.
 *
 *  Copyright (C) 2009 by Abhishek Kulkarni <adkulkar@umail.iu.edu>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2
 *  as published by the Free Software Foundation.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to:
 *  Free Software Foundation
 *  51 Franklin Street, Fifth Floor
 *  Boston, MA  02111-1301  USA
 *
 */

#ifndef _9P_CACHE_H
#ifdef CONFIG_9P_FSCACHE
#include <linux/fscache.h>
#include <linux/spinlock.h>

extern struct kmem_cache *vcookie_cache;

struct v9fs_cookie {
	spinlock_t lock;
	struct inode inode;
	struct fscache_cookie *fscache;
	struct p9_qid *qid;
};

static inline struct v9fs_cookie *v9fs_inode2cookie(const struct inode *inode)
{
	return container_of(inode, struct v9fs_cookie, inode);
}

extern struct fscache_netfs v9fs_cache_netfs;
extern const struct fscache_cookie_def v9fs_cache_session_index_def;
extern const struct fscache_cookie_def v9fs_cache_inode_index_def;

extern void v9fs_cache_session_get_cookie(struct v9fs_session_info *v9ses);
extern void v9fs_cache_session_put_cookie(struct v9fs_session_info *v9ses);

extern void v9fs_cache_inode_get_cookie(struct inode *inode);
extern void v9fs_cache_inode_put_cookie(struct inode *inode);
extern void v9fs_cache_inode_flush_cookie(struct inode *inode);
extern void v9fs_cache_inode_set_cookie(struct inode *inode, struct file *filp);
extern void v9fs_cache_inode_reset_cookie(struct inode *inode);

extern int __v9fs_cache_register(void);
extern void __v9fs_cache_unregister(void);

extern int __v9fs_fscache_release_page(struct page *page, gfp_t gfp);
extern void __v9fs_fscache_invalidate_page(struct page *page);
extern int __v9fs_readpage_from_fscache(struct inode *inode,
					struct page *page);
extern int __v9fs_readpages_from_fscache(struct inode *inode,
					 struct address_space *mapping,
					 struct list_head *pages,
					 unsigned *nr_pages);
extern void __v9fs_readpage_to_fscache(struct inode *inode, struct page *page);


/**
 * v9fs_cache_register - Register v9fs file system with the cache
 */
static inline int v9fs_cache_register(void)
{
	return __v9fs_cache_register();
}

/**
 * v9fs_cache_unregister - Unregister v9fs from the cache
 */
static inline void v9fs_cache_unregister(void)
{
	__v9fs_cache_unregister();
}

static inline int v9fs_fscache_release_page(struct page *page,
					    gfp_t gfp)
{
	return __v9fs_fscache_release_page(page, gfp);
}

static inline void v9fs_fscache_invalidate_page(struct page *page)
{
	__v9fs_fscache_invalidate_page(page);
}

static inline int v9fs_readpage_from_fscache(struct inode *inode,
					     struct page *page)
{
	return __v9fs_readpage_from_fscache(inode, page);
}

static inline int v9fs_readpages_from_fscache(struct inode *inode,
					      struct address_space *mapping,
					      struct list_head *pages,
					      unsigned *nr_pages)
{
	return __v9fs_readpages_from_fscache(inode, mapping, pages,
					     nr_pages);
}

static inline void v9fs_readpage_to_fscache(struct inode *inode,
					    struct page *page)
{
	if (PageFsCache(page))
		__v9fs_readpage_to_fscache(inode, page);
}

static inline void v9fs_uncache_page(struct inode *inode, struct page *page)
{
	struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
	fscache_uncache_page(vcookie->fscache, page);
	BUG_ON(PageFsCache(page));
}

static inline void v9fs_vcookie_set_qid(struct inode *inode,
					struct p9_qid *qid)
{
	struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode);
	spin_lock(&vcookie->lock);
	vcookie->qid = qid;
	spin_unlock(&vcookie->lock);
}

#else /* CONFIG_9P_FSCACHE */

static inline int v9fs_cache_register(void)
{
	return 1;
}

static inline void v9fs_cache_unregister(void) {}

static inline int v9fs_fscache_release_page(struct page *page,
					    gfp_t gfp) {
	return 1;
}

static inline void v9fs_fscache_invalidate_page(struct page *page) {}

static inline int v9fs_readpage_from_fscache(struct inode *inode,
					     struct page *page)
{
	return -ENOBUFS;
}

static inline int v9fs_readpages_from_fscache(struct inode *inode,
					      struct address_space *mapping,
					      struct list_head *pages,
					      unsigned *nr_pages)
{
	return -ENOBUFS;
}

static inline void v9fs_readpage_to_fscache(struct inode *inode,
					    struct page *page)
{}

static inline void v9fs_uncache_page(struct inode *inode, struct page *page)
{}

static inline void v9fs_vcookie_set_qid(struct inode *inode,
					struct p9_qid *qid)
{}

#endif /* CONFIG_9P_FSCACHE */
#endif /* _9P_CACHE_H */
Loading