All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Updated NFS client to reflect CacheFS Spilt
@ 2004-10-07 12:18 Steve Dickson
  0 siblings, 0 replies; only message in thread
From: Steve Dickson @ 2004-10-07 12:18 UTC (permalink / raw)
  Cc: linux-cachefs, Linux NFS Mailing List

[-- Attachment #1: Type: text/plain, Size: 304 bytes --]

Hey Trond,

Attached is a patch that changes all of the names from
cachefs to fscache to reflect the recent CacheFS split.
It also moves the nfs_invalidatepage(), nfs_releasepage(),
and nfs_mkwrite() routines from file.c into read.c per
your request....

Signed-Off-By: Steve Dickson <SteveD@RedHat.com>

[-- Attachment #2: linux-2.6.9-rc3-mm2-fscache-nfs.patch --]
[-- Type: text/plain, Size: 24066 bytes --]

--- 2.6.9-rc3-mm2/include/linux/nfs_fs.h.orig	2004-10-06 19:15:53.000000000 -0400
+++ 2.6.9-rc3-mm2/include/linux/nfs_fs.h	2004-10-06 21:43:14.000000000 -0400
@@ -30,6 +30,7 @@
 #include <linux/nfs_xdr.h>
 #include <linux/rwsem.h>
 #include <linux/workqueue.h>
+#include <linux/fscache.h>
 
 /*
  * Enable debugging support for nfs client.
@@ -189,6 +190,10 @@ struct nfs_inode {
 	struct rw_semaphore	rwsem;
 #endif /* CONFIG_NFS_V4*/
 
+#ifdef CONFIG_NFS_FSCACHE
+	struct fscache_cookie	*fscache;
+#endif
+
 	struct inode		vfs_inode;
 };
 
--- 2.6.9-rc3-mm2/include/linux/nfs_fs_sb.h.orig	2004-10-06 19:15:53.000000000 -0400
+++ 2.6.9-rc3-mm2/include/linux/nfs_fs_sb.h	2004-10-06 21:43:14.000000000 -0400
@@ -3,6 +3,7 @@
 
 #include <linux/list.h>
 #include <linux/backing-dev.h>
+#include <linux/fscache.h>
 
 /*
  * NFS client parameters stored in the superblock.
@@ -46,6 +47,10 @@ struct nfs_server {
 						   that are supported on this
 						   filesystem */
 #endif
+
+#ifdef CONFIG_NFS_FSCACHE
+	struct fscache_cookie	*fscache;	/* cache cookie */
+#endif
 };
 
 /* Server capabilities */
--- 2.6.9-rc3-mm2/include/linux/nfs_mount.h.orig	2004-08-14 06:54:47.000000000 -0400
+++ 2.6.9-rc3-mm2/include/linux/nfs_mount.h	2004-10-06 21:43:14.000000000 -0400
@@ -60,6 +60,7 @@ struct nfs_mount_data {
 #define NFS_MOUNT_BROKEN_SUID	0x0400	/* 4 */
 #define NFS_MOUNT_STRICTLOCK	0x1000	/* reserved for NFSv4 */
 #define NFS_MOUNT_SECFLAVOUR	0x2000	/* 5 */
+#define NFS_MOUNT_FSCACHE		NFS_MOUNT_POSIX
 #define NFS_MOUNT_FLAGMASK	0xFFFF
 
 #endif
--- 2.6.9-rc3-mm2/fs/nfs/file.c.orig	2004-10-06 19:15:52.000000000 -0400
+++ 2.6.9-rc3-mm2/fs/nfs/file.c	2004-10-07 07:58:36.655722832 -0400
@@ -27,9 +27,11 @@
 #include <linux/slab.h>
 #include <linux/pagemap.h>
 #include <linux/smp_lock.h>
+#include <linux/buffer_head.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
+#include "nfs-fscache.h"
 
 #include "delegation.h"
 
@@ -240,6 +242,11 @@ static int nfs_commit_write(struct file 
 	return status;
 }
 
+/*
+ * since we use page->private for our own nefarious purposes when using fscache, we have to
+ * override extra address space ops to prevent fs/buffer.c from getting confused, even though we
+ * may not have asked its opinion
+ */
 struct address_space_operations nfs_file_aops = {
 	.readpage = nfs_readpage,
 	.readpages = nfs_readpages,
@@ -251,6 +258,12 @@ struct address_space_operations nfs_file
 #ifdef CONFIG_NFS_DIRECTIO
 	.direct_IO = nfs_direct_IO,
 #endif
+#ifdef CONFIG_NFS_FSCACHE
+	.sync_page	= block_sync_page,
+	.releasepage	= nfs_releasepage,
+	.invalidatepage	= nfs_invalidatepage,
+	.page_mkwrite	= nfs_mkwrite,
+#endif
 };
 
 /* 
--- 2.6.9-rc3-mm2/fs/nfs/inode.c.orig	2004-10-06 19:15:52.000000000 -0400
+++ 2.6.9-rc3-mm2/fs/nfs/inode.c	2004-10-07 07:03:12.209115536 -0400
@@ -41,6 +41,8 @@
 
 #include "delegation.h"
 
+#include "nfs-fscache.h"
+
 #define NFSDBG_FACILITY		NFSDBG_VFS
 #define NFS_PARANOIA 1
 
@@ -140,7 +142,7 @@ nfs_delete_inode(struct inode * inode)
 
 /*
  * For the moment, the only task for the NFS clear_inode method is to
- * release the mmap credential
+ * release the mmap credential and release the inode's on-disc cache
  */
 static void
 nfs_clear_inode(struct inode *inode)
@@ -153,6 +155,16 @@ nfs_clear_inode(struct inode *inode)
 	cred = nfsi->cache_access.cred;
 	if (cred)
 		put_rpccred(cred);
+
+#ifdef CONFIG_NFS_FSCACHE
+	if (NFS_SERVER(inode)->flags & NFS_MOUNT_FSCACHE) {
+		dfprintk(PAGECACHE, "NFS: relinquish cookie (0x%p/0x%p)\n",
+			nfsi, nfsi->fscache);
+		fscache_relinquish_cookie(nfsi->fscache, 0);
+		nfsi->fscache = NULL;
+	}
+#endif
+
 	BUG_ON(atomic_read(&nfsi->data_updates) != 0);
 }
 
@@ -462,6 +474,21 @@ nfs_fill_super(struct super_block *sb, s
 			server->namelen = NFS2_MAXNAMLEN;
 	}
 
+#ifdef CONFIG_NFS_FSCACHE
+	/* create a cache index for looking up filehandles */
+	server->fscache = NULL;
+	if (server->flags & NFS_MOUNT_FSCACHE) {
+		server->fscache = fscache_acquire_cookie(nfs_cache_netfs.primary_index,
+			       &nfs_cache_fh_index_def, server);
+		if (server->fscache == NULL) {
+			server->flags &= ~NFS_MOUNT_FSCACHE;
+			printk(KERN_WARNING "NFS: No Fscache cookie. Turning Fscache off!\n");
+		}
+		dfprintk(PAGECACHE,"NFS: cookie (0x%p/0x%p/0x%p)\n",
+			sb, server, server->fscache);
+	}
+#endif
+
 	sb->s_op = &nfs_sops;
 	return nfs_sb_init(sb, authflavor);
 }
@@ -518,7 +545,7 @@ static int nfs_show_options(struct seq_f
 	} nfs_info[] = {
 		{ NFS_MOUNT_SOFT, ",soft", ",hard" },
 		{ NFS_MOUNT_INTR, ",intr", "" },
-		{ NFS_MOUNT_POSIX, ",posix", "" },
+		{ NFS_MOUNT_POSIX, ",fscache", "" },
 		{ NFS_MOUNT_TCP, ",tcp", ",udp" },
 		{ NFS_MOUNT_NOCTO, ",nocto", "" },
 		{ NFS_MOUNT_NOAC, ",noac", "" },
@@ -568,6 +595,17 @@ nfs_zap_caches(struct inode *inode)
 		nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
 	else
 		nfsi->flags |= NFS_INO_INVALID_ATTR;
+
+#ifdef CONFIG_NFS_FSCACHE
+	if (NFS_SERVER(inode)->flags & NFS_MOUNT_FSCACHE) {
+		dfprintk(PAGECACHE,"NFS: zapping cookie (0x%p/0x%p/0x%p)\n",
+			inode, nfsi, nfsi->fscache);
+
+		fscache_relinquish_cookie(nfsi->fscache, 1);
+		nfsi->fscache = NULL;
+	}
+#endif
+
 }
 
 /*
@@ -705,6 +743,17 @@ nfs_fhget(struct super_block *sb, struct
 		memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));
 		nfsi->cache_access.cred = NULL;
 
+#ifdef CONFIG_NFS_FSCACHE
+{
+		struct nfs_server *server = NFS_SB(sb);
+		if (server->flags & NFS_MOUNT_FSCACHE) {
+			nfsi->fscache = fscache_acquire_cookie(server->fscache, NULL, nfsi);
+			/* XXX: Add warning when NULL is returned */
+			dprintk("NFS: fhget new cookie (0x%p/0x%p/0x%p)\n",
+				sb, nfsi, nfsi->fscache);
+		}
+}
+#endif
 		unlock_new_inode(inode);
 	} else
 		nfs_refresh_inode(inode, fattr);
@@ -1009,6 +1058,19 @@ __nfs_revalidate_inode(struct nfs_server
 				(long long)NFS_FILEID(inode));
 		/* This ensures we revalidate dentries */
 		nfsi->cache_change_attribute++;
+
+#ifdef CONFIG_NFS_FSCACHE
+		if (server->flags & NFS_MOUNT_FSCACHE) {
+			struct fscache_cookie *old =  nfsi->fscache;
+
+			/* retire the current fscache cache and get a new one */
+			fscache_relinquish_cookie(nfsi->fscache, 1);
+			nfsi->fscache = fscache_acquire_cookie(server->fscache, NULL, nfsi);
+			dfprintk(PAGECACHE,
+				"NFS: revalidation new cookie (0x%p/0x%p/0x%p/0x%p)\n",
+				server, nfsi, old, nfsi->fscache);
+		}
+#endif
 	}
 	dfprintk(PAGECACHE, "NFS: (%s/%Ld) revalidation complete\n",
 		inode->i_sb->s_id,
@@ -1417,6 +1479,14 @@ static struct super_block *nfs_get_sb(st
 		return ERR_PTR(-EINVAL);
 	}
 
+#ifndef CONFIG_NFS_FSCACHE
+	if (data->flags & NFS_MOUNT_FSCACHE) {
+		printk(KERN_WARNING "NFS: kernel not compiled with CONFIG_NFS_FSCACHE\n");
+		kfree(server);
+		return ERR_PTR(-EINVAL);
+	}
+#endif
+
 	s = sget(fs_type, nfs_compare_super, nfs_set_super, server);
 
 	if (IS_ERR(s) || s->s_root) {
@@ -1449,6 +1519,13 @@ static void nfs_kill_super(struct super_
 
 	kill_anon_super(s);
 
+#ifdef CONFIG_NFS_FSCACHE
+	if (server->flags & NFS_MOUNT_FSCACHE)
+		dfprintk(PAGECACHE,"NFS: killing cookie (0x%p/0x%p/0x%p)\n",
+			NFS_SB(s), server, server->fscache);
+		fscache_relinquish_cookie(server->fscache, 0);
+#endif
+
 	nfs4_renewd_prepare_shutdown(server);
 
 	if (server->client != NULL && !IS_ERR(server->client))
@@ -1768,6 +1845,20 @@ static struct super_block *nfs4_get_sb(s
 		s = ERR_PTR(-EIO);
 		goto out_free;
 	}
+#ifdef CONFIG_NFS_FSCACHE
+	/* create a cache index for looking up filehandles */
+	server->fscache = NULL;
+	if (server->flags & NFS_MOUNT_FSCACHE) {
+		server->fscache = fscache_acquire_cookie(nfs_cache_netfs.primary_index,
+			       &nfs_cache_fh_index_def, server);
+		if (server->fscache == NULL) {
+			server->flags &= ~NFS_MOUNT_FSCACHE;
+			printk(KERN_WARNING "NFS: No Fscache cookie. Turning Fscache off!\n");
+		}
+		dfprintk(PAGECACHE,"NFS: nfs4 cookie (0x%p/0x%p/0x%p)\n",
+			s, server, server->fscache);
+	}
+#endif
 
 	error = nfs4_fill_super(s, data, flags & MS_VERBOSE ? 1 : 0);
 	if (error) {
@@ -1888,6 +1979,14 @@ static int __init init_nfs_fs(void)
 {
 	int err;
 
+#ifdef CONFIG_NFS_FSCACHE
+	/* we want to be able to cache */
+	err = fscache_register_netfs(&nfs_cache_netfs,
+				     &nfs_cache_server_index_def);
+	if (err < 0)
+		goto out5;
+#endif
+
 	err = nfs_init_nfspagecache();
 	if (err)
 		goto out4;
@@ -1923,6 +2022,10 @@ out2:
 out3:
 	nfs_destroy_nfspagecache();
 out4:
+#ifdef CONFIG_NFS_FSCACHE
+	fscache_unregister_netfs(&nfs_cache_netfs);
+out5:
+#endif
 	return err;
 }
 
@@ -1932,6 +2035,9 @@ static void __exit exit_nfs_fs(void)
 	nfs_destroy_readpagecache();
 	nfs_destroy_inodecache();
 	nfs_destroy_nfspagecache();
+#ifdef CONFIG_NFS_FSCACHE
+	fscache_unregister_netfs(&nfs_cache_netfs);
+#endif
 #ifdef CONFIG_PROC_FS
 	rpc_proc_unregister("nfs");
 #endif
--- 2.6.9-rc3-mm2/fs/nfs/Makefile.orig	2004-10-06 19:15:52.000000000 -0400
+++ 2.6.9-rc3-mm2/fs/nfs/Makefile	2004-10-06 21:43:14.000000000 -0400
@@ -12,4 +12,5 @@ nfs-$(CONFIG_NFS_V4)	+= nfs4proc.o nfs4x
 			   delegation.o idmap.o \
 			   callback.o callback_xdr.o callback_proc.o
 nfs-$(CONFIG_NFS_DIRECTIO) += direct.o
+nfs-$(CONFIG_NFS_FSCACHE) += nfs-fscache.o
 nfs-objs		:= $(nfs-y)
--- /dev/null	2004-02-23 16:02:56.000000000 -0500
+++ 2.6.9-rc3-mm2/fs/nfs/nfs-fscache.c	2004-10-06 21:43:14.000000000 -0400
@@ -0,0 +1,204 @@
+/* nfs-fscache.c: NFS filesystem cache interface
+ *
+ * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/nfs_fs.h>
+#include <linux/nfs_fs_sb.h>
+
+#include "nfs-fscache.h"
+
+#define NFS_CACHE_FH_INDEX_SIZE sizeof(struct nfs_fh)
+
+#if 0
+#define kleave(FMT,...) \
+	printk("[%-6.6s] <== %s()"FMT"\n",current->comm,__FUNCTION__ ,##__VA_ARGS__)
+#else
+#define kleave(FMT,...) \
+	do {} while(0)
+#endif
+
+/*
+ * the root index is
+ */
+static struct fscache_page *nfs_cache_get_page_token(struct page *page);
+
+static struct fscache_netfs_operations nfs_cache_ops = {
+	.get_page_token	= nfs_cache_get_page_token,
+};
+
+struct fscache_netfs nfs_cache_netfs = {
+	.name			= "nfs",
+	.version		= 0,
+	.ops			= &nfs_cache_ops,
+};
+
+/*
+ * the root index for the filesystem is defined by nfsd IP address and ports
+ */
+static fscache_match_val_t nfs_cache_server_match(void *target,
+						  const void *entry);
+static void nfs_cache_server_update(void *source, void *entry);
+
+struct fscache_index_def nfs_cache_server_index_def = {
+	.name			= "servers",
+	.data_size		= 18,
+	.keys[0]		= { FSCACHE_INDEX_KEYS_IPV6ADDR, 16 },
+	.keys[1]		= { FSCACHE_INDEX_KEYS_BIN, 2 },
+	.match			= nfs_cache_server_match,
+	.update			= nfs_cache_server_update,
+};
+
+/*
+ * the primary index for each server is simply made up of a series of NFS file
+ * handles
+ */
+static fscache_match_val_t nfs_cache_fh_match(void *target, const void *entry);
+static void nfs_cache_fh_update(void *source, void *entry);
+
+struct fscache_index_def nfs_cache_fh_index_def = {
+	.name			= "fh",
+	.data_size		= NFS_CACHE_FH_INDEX_SIZE,
+	.keys[0]		= { FSCACHE_INDEX_KEYS_BIN_SZ2,
+				    sizeof(struct nfs_fh) },
+	.match			= nfs_cache_fh_match,
+	.update			= nfs_cache_fh_update,
+};
+
+/*
+ * get a page token for the specified page
+ * - the token will be attached to page->private and PG_private will be set on
+ *   the page
+ */
+static struct fscache_page *nfs_cache_get_page_token(struct page *page)
+{
+	return fscache_page_get_private(page, GFP_NOIO);
+}
+
+static const uint8_t nfs_cache_ipv6_wrapper_for_ipv4[12] = {
+	[0 ... 9]	= 0x00,
+	[10 ... 11]	= 0xff
+};
+
+/*
+ * match a server record obtained from the cache
+ */
+static fscache_match_val_t nfs_cache_server_match(void *target,
+						  const void *entry)
+{
+	struct nfs_server *server = target;
+	const uint8_t *data = entry;
+
+	switch (server->addr.sin_family) {
+	case AF_INET:
+		if (memcmp(data + 0,
+			   &nfs_cache_ipv6_wrapper_for_ipv4,
+			   12) != 0)
+			break;
+
+		if (memcmp(data + 12, &server->addr.sin_addr, 4) != 0)
+			break;
+
+		if (memcmp(data + 16, &server->addr.sin_port, 2) != 0)
+			break;
+
+		kleave(" = SUCCESS");
+		return FSCACHE_MATCH_SUCCESS;
+
+	case AF_INET6:
+		if (memcmp(data + 0, &server->addr.sin_addr, 16) != 0)
+			break;
+
+		if (memcmp(data + 16, &server->addr.sin_port, 2) != 0)
+			break;
+
+		kleave(" = SUCCESS");
+		return FSCACHE_MATCH_SUCCESS;
+
+	default:
+		break;
+	}
+
+	kleave(" = FAILED");
+	return FSCACHE_MATCH_FAILED;
+}
+
+/*
+ * update a server record in the cache
+ */
+static void nfs_cache_server_update(void *source, void *entry)
+{
+	struct nfs_server *server = source;
+	uint8_t *data = entry;
+
+	switch (server->addr.sin_family) {
+	case AF_INET:
+		memcpy(data + 0, &nfs_cache_ipv6_wrapper_for_ipv4, 12);
+		memcpy(data + 12, &server->addr.sin_addr, 4);
+		memcpy(data + 16, &server->addr.sin_port, 2);
+		return;
+
+	case AF_INET6:
+		memcpy(data + 0, &server->addr.sin_addr, 16);
+		memcpy(data + 16, &server->addr.sin_port, 2);
+		return;
+
+	default:
+		return;
+	}
+}
+
+/*
+ * match a file handle record obtained from the cache
+ */
+static fscache_match_val_t nfs_cache_fh_match(void *target, const void *entry)
+{
+	struct nfs_inode *nfsi = target;
+	const uint8_t *data = entry;
+	uint16_t nsize;
+
+	/* check the file handle matches */
+	memcpy(&nsize, &nfsi->fh.size, 2);
+	nsize = ntohs(nsize);
+
+	if (nsize <= NFS_CACHE_FH_INDEX_SIZE && nfsi->fh.size == nsize) {
+		if (memcmp(data, nfsi->fh.data, nsize) == 0) {
+			kleave(" = SUCCESS");
+			return FSCACHE_MATCH_SUCCESS;
+		}
+	}
+
+	kleave(" = FAILED");
+	return FSCACHE_MATCH_FAILED;
+}
+
+/*
+ * update a fh record in the cache
+ */
+static void nfs_cache_fh_update(void *source, void *entry)
+{
+	struct nfs_inode *nfsi = source;
+	uint16_t nsize;
+	uint8_t *data = entry;
+
+	BUG_ON(nfsi->fh.size > NFS_CACHE_FH_INDEX_SIZE - 2);
+
+	/* set the file handle */
+	nsize = htons(nfsi->fh.size);
+	memcpy(data, &nsize, 2);
+	memcpy(data + 2, &nfsi->fh.data, nfsi->fh.size);
+	memset(data + 2 + nfsi->fh.size,
+	       FSCACHE_INDEX_DEADFILL_PATTERN,
+	       NFS_CACHE_FH_INDEX_SIZE - 2 - nfsi->fh.size);
+}
--- /dev/null	2004-02-23 16:02:56.000000000 -0500
+++ 2.6.9-rc3-mm2/fs/nfs/nfs-fscache.h	2004-10-07 07:58:13.592229016 -0400
@@ -0,0 +1,31 @@
+/* nfs-fscache.h: NFS filesystem cache interface definitions
+ *
+ * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _NFS_FSCACHE_H
+#define _NFS_FSCACHE_H
+
+#include <linux/fscache.h>
+
+#ifdef CONFIG_NFS_FSCACHE
+#ifndef CONFIG_FSCACHE
+#error "CONFIG_NFS_FSCACHE is defined but not CONFIG_FSCACHE"
+#endif
+
+extern struct fscache_netfs nfs_cache_netfs;
+extern struct fscache_index_def nfs_cache_server_index_def;
+extern struct fscache_index_def nfs_cache_fh_index_def;
+
+extern int nfs_invalidatepage(struct page *, unsigned long);
+extern int nfs_releasepage(struct page *, int);
+extern int nfs_mkwrite(struct page *);
+
+#endif
+#endif /* _NFS_FSCACHE_H */
--- 2.6.9-rc3-mm2/fs/nfs/read.c.orig	2004-10-06 19:15:52.000000000 -0400
+++ 2.6.9-rc3-mm2/fs/nfs/read.c	2004-10-07 07:57:26.718354928 -0400
@@ -28,6 +28,7 @@
 #include <linux/sunrpc/clnt.h>
 #include <linux/nfs_fs.h>
 #include <linux/nfs_page.h>
+#include <linux/nfs_mount.h>
 #include <linux/smp_lock.h>
 
 #include <asm/system.h>
@@ -88,6 +89,47 @@ int nfs_return_empty_page(struct page *p
 	return 0;
 }
 
+#ifdef CONFIG_NFS_FSCACHE
+/*
+ * store a newly fetched page in fscache
+ */
+static void
+nfs_readpage_to_fscache_complete(void *cookie_data, struct page *page, void *data, int error)
+{
+	dprintk("NFS:     readpage_to_fscache_complete (%p/%p/%p/%d)\n",
+		cookie_data, page, data, error);
+
+	end_page_fs_misc(page);
+}
+
+static inline void
+nfs_readpage_to_fscache(struct inode *inode, struct page *page, int sync)
+{
+	int ret;
+
+	dprintk("NFS: readpage_to_fscache(0x%p/0x%p/0x%p/%d)\n",
+		NFS_I(inode)->fscache, page, inode, sync);
+
+	SetPageFsMisc(page);
+	ret = fscache_write_page(NFS_I(inode)->fscache, page,
+		nfs_readpage_to_fscache_complete, NULL, GFP_KERNEL);
+	if (ret != 0) {
+		dprintk("NFS:     readpage_to_fscache: error %d\n", ret);
+		fscache_uncache_page(NFS_I(inode)->fscache, page);
+		ClearPageFsMisc(page);
+	}
+
+	unlock_page(page);
+}
+#else
+static inline void
+nfs_readpage_to_fscache(struct inode *inode, struct page *page, int sync)
+{
+	BUG();
+}
+#endif
+
+
 /*
  * Read a page synchronously.
  */
@@ -164,6 +206,13 @@ static int nfs_readpage_sync(struct nfs_
 		ClearPageError(page);
 	result = 0;
 
+	if (NFS_SERVER(inode)->flags & NFS_MOUNT_FSCACHE)
+		nfs_readpage_to_fscache(inode, page, 1);
+	else
+		unlock_page(page);
+
+	return result;
+
 io_error:
 	unlock_page(page);
 	nfs_readdata_free(rdata);
@@ -196,7 +245,13 @@ static int nfs_readpage_async(struct nfs
 
 static void nfs_readpage_release(struct nfs_page *req)
 {
-	unlock_page(req->wb_page);
+	struct inode *d_inode = req->wb_context->dentry->d_inode;
+
+	if ((NFS_SERVER(d_inode)->flags & NFS_MOUNT_FSCACHE) && 
+			PageUptodate(req->wb_page))
+		nfs_readpage_to_fscache(d_inode, req->wb_page, 0);
+	else
+		unlock_page(req->wb_page);
 
 	nfs_clear_request(req);
 	nfs_release_request(req);
@@ -494,6 +549,64 @@ void nfs_readpage_result(struct rpc_task
 	data->complete(data, status);
 }
 
+
+/*
+ * Read a page through the on-disc cache if possible
+ */
+#ifdef CONFIG_NFS_FSCACHE
+static void
+nfs_readpage_from_fscache_complete(void *cookie_data, struct page *page, void *data, int error)
+{
+	dprintk("NFS: readpage_from_fscache_complete (0x%p/0x%p/0x%p/%d)\n",
+		cookie_data, page, data, error);
+
+	if (error)
+		SetPageError(page);
+	else
+		SetPageUptodate(page);
+
+	unlock_page(page);
+}
+
+static inline int
+nfs_readpage_from_fscache(struct inode *inode, struct page *page)
+{
+	struct fscache_page *pageio;
+	int ret;
+
+	dprintk("NFS: readpage_from_fscache(0x%p/0x%p/0x%p)\n",
+		NFS_I(inode)->fscache, page, inode);
+
+	pageio = fscache_page_get_private(page, GFP_NOIO);
+	if (IS_ERR(pageio)) {
+		 dprintk("NFS:     fscache_page_get_private error %ld\n", PTR_ERR(pageio));
+		return PTR_ERR(pageio);
+	}
+
+	ret = fscache_read_or_alloc_page(NFS_I(inode)->fscache,
+					 page,
+					 nfs_readpage_from_fscache_complete,
+					 NULL,
+					 GFP_KERNEL);
+
+	switch (ret) {
+	case 1: /* read BIO submitted and wb-journal entry found */
+		BUG();
+		
+	case 0: /* read BIO submitted (page in fscache) */
+		return ret;
+
+	case -ENOBUFS: /* inode not in cache */
+	case -ENODATA: /* page not in cache */
+		dprintk("NFS:     fscache_read_or_alloc_page error %d\n", ret);
+		return 1;
+
+	default:
+		return ret;
+	}
+}
+#endif
+
 /*
  * Read a page over NFS.
  * We read the page synchronously in the following case:
@@ -527,6 +640,13 @@ int nfs_readpage(struct file *file, stru
 		ctx = get_nfs_open_context((struct nfs_open_context *)
 				file->private_data);
 	if (!IS_SYNC(inode)) {
+		if (NFS_SERVER(inode)->flags & NFS_MOUNT_FSCACHE) {
+			error = nfs_readpage_from_fscache(inode, page);
+			if (error < 0)
+				goto out_error;
+			if (error == 0)
+				return error;
+		}
 		error = nfs_readpage_async(ctx, inode, page);
 		goto out;
 	}
@@ -557,6 +677,17 @@ readpage_async_filler(void *data, struct
 	unsigned int len;
 
 	nfs_wb_page(inode, page);
+
+#ifdef CONFIG_NFS_FSCACHE
+	if (NFS_SERVER(inode)->flags & NFS_MOUNT_FSCACHE) {
+		int error = nfs_readpage_from_fscache(inode, page);
+		if (error < 0)
+			return error;
+		if (error == 0)
+			return error;
+	}
+#endif
+
 	len = nfs_page_length(inode, page);
 	if (len == 0)
 		return nfs_return_empty_page(page);
@@ -631,3 +762,61 @@ void nfs_destroy_readpagecache(void)
 	if (kmem_cache_destroy(nfs_rdata_cachep))
 		printk(KERN_INFO "nfs_read_data: not all structures were freed\n");
 }
+
+#ifdef CONFIG_NFS_FSCACHE
+int nfs_invalidatepage(struct page *page, unsigned long offset)
+{
+	int ret = 1;
+	struct nfs_server *server = NFS_SERVER(page->mapping->host);
+
+	BUG_ON(!PageLocked(page));
+
+	if (server->flags & NFS_MOUNT_FSCACHE) {
+		if (PagePrivate(page)) {
+			struct nfs_inode *nfsi = NFS_I(page->mapping->host);
+
+			dfprintk(PAGECACHE,"NFS: fscache invalidatepage (0x%p/0x%p/0x%p)\n",
+				nfsi->fscache, page, nfsi);
+
+			fscache_uncache_page(nfsi->fscache, page);
+
+			if (offset == 0) {
+				BUG_ON(!PageLocked(page));
+				ret = 0;
+				if (!PageWriteback(page))
+					ret = page->mapping->a_ops->releasepage(page, 0);
+			}
+		}
+	} else
+		ret = 0;
+
+	return ret;
+}
+int nfs_releasepage(struct page *page, int gfp_flags)
+{
+	struct fscache_page *pageio;
+	struct nfs_server *server = NFS_SERVER(page->mapping->host);
+
+	if (server->flags & NFS_MOUNT_FSCACHE && PagePrivate(page)) {
+		struct nfs_inode *nfsi = NFS_I(page->mapping->host);
+
+		dfprintk(PAGECACHE,"NFS: fscache releasepage (0x%p/0x%p/0x%p)\n",
+			nfsi->fscache, page, nfsi);
+
+		fscache_uncache_page(nfsi->fscache, page);
+		pageio = (struct fscache_page *) page->private;
+		page->private = 0;
+		ClearPagePrivate(page);
+
+		if (pageio)
+			kfree(pageio);
+	}
+
+	return 0;
+}
+int nfs_mkwrite(struct page *page)
+{
+	wait_on_page_fs_misc(page);
+	return 0;
+}
+#endif
--- 2.6.9-rc3-mm2/fs/nfs/write.c.orig	2004-10-06 19:15:52.000000000 -0400
+++ 2.6.9-rc3-mm2/fs/nfs/write.c	2004-10-07 07:00:13.624264560 -0400
@@ -273,6 +273,38 @@ static int wb_priority(struct writeback_
 }
 
 /*
+ * store an updated page in fscache
+ */
+#ifdef CONFIG_NFS_FSCACHE
+static void
+nfs_writepage_to_fscache_complete(void *cookie_data, struct page *page, void *data, int error)
+{
+	/* really need to synchronise the end of writeback, probably using a page flag */
+}
+static inline void
+nfs_writepage_to_fscache(struct inode *inode, struct page *page)
+{
+	int ret; 
+
+	dprintk("NFS: writepage_to_fscache (0x%p/0x%p/0x%p)\n",
+		NFS_I(inode)->fscache, page, inode);
+
+	ret =  fscache_write_page(NFS_I(inode)->fscache, page,
+		nfs_writepage_to_fscache_complete, NULL, GFP_KERNEL);
+	if (ret != 0) {
+		dprintk("NFS:    fscache_write_page error %d\n", ret);
+		fscache_uncache_page(NFS_I(inode)->fscache, page);
+	}
+}
+#else
+static inline void
+nfs_writepage_to_fscache(struct inode *inode, struct page *page)
+{
+	BUG();
+}
+#endif
+
+/*
  * Write an mmapped page to the server.
  */
 int nfs_writepage(struct page *page, struct writeback_control *wbc)
@@ -317,6 +349,10 @@ do_it:
 		err = -EBADF;
 		goto out;
 	}
+
+	if (NFS_SERVER(inode)->flags & NFS_MOUNT_FSCACHE)
+		nfs_writepage_to_fscache(inode, page);
+
 	lock_kernel();
 	if (!IS_SYNC(inode) && inode_referenced) {
 		err = nfs_writepage_async(ctx, inode, page, 0, offset);
@@ -1322,6 +1358,7 @@ nfs_commit_done(struct rpc_task *task)
 			(long long)NFS_FILEID(req->wb_context->dentry->d_inode),
 			req->wb_bytes,
 			(long long)req_offset(req));
+
 		if (task->tk_status < 0) {
 			req->wb_context->error = task->tk_status;
 			nfs_inode_remove_request(req);
--- 2.6.9-rc3-mm2/fs/Kconfig.orig	2004-10-06 19:29:03.000000000 -0400
+++ 2.6.9-rc3-mm2/fs/Kconfig	2004-10-06 21:43:14.000000000 -0400
@@ -1493,6 +1493,13 @@ config NFS_V4
 
 	  If unsure, say N.
 
+config NFS_FSCACHE
+	bool "Provide NFS client caching support"
+	depends on NFS_FS && FSCACHE && EXPERIMENTAL
+	help
+	  Say Y here if you want NFS data to be cached locally on disc through
+	  the general filesystem cache manager
+
 config NFS_DIRECTIO
 	bool "Allow direct I/O on NFS files (EXPERIMENTAL)"
 	depends on NFS_FS && EXPERIMENTAL

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2004-10-07 12:18 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-10-07 12:18 [PATCH] Updated NFS client to reflect CacheFS Spilt Steve Dickson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.