<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">
From: David Howells &lt;dhowells@redhat.com&gt;

The attached patch turns what remains of CacheFS into a caching backend for
FS-Cache.

Signed-Off-By: David Howells &lt;dhowells@redhat.com&gt;
Signed-off-by: Andrew Morton &lt;akpm@osdl.org&gt;
---

 /dev/null                           |  351 ----------
 25-akpm/fs/cachefs/block.c          |   21 
 25-akpm/fs/cachefs/cachefs-int.h    |   94 --
 25-akpm/fs/cachefs/cachefs-layout.h |   20 
 25-akpm/fs/cachefs/index.c          |  130 +---
 25-akpm/fs/cachefs/indirection-io.c |   40 -
 25-akpm/fs/cachefs/inode.c          |   10 
 25-akpm/fs/cachefs/interface.c      | 1155 +++---------------------------------
 25-akpm/fs/cachefs/journal.c        |    8 
 25-akpm/fs/cachefs/linear-io.c      |    8 
 25-akpm/fs/cachefs/main.c           |   20 
 25-akpm/fs/cachefs/misc.c           |   12 
 25-akpm/fs/cachefs/recycling.c      |    2 
 25-akpm/fs/cachefs/replay.c         |    2 
 25-akpm/fs/cachefs/rootdir.c        |  148 +++-
 25-akpm/fs/cachefs/super.c          |   41 -
 25-akpm/fs/cachefs/vjournal.c       |   12 
 17 files changed, 398 insertions(+), 1676 deletions(-)

diff -puN fs/cachefs/block.c~turn-cachefs-into-a-cache-backend fs/cachefs/block.c
--- 25/fs/cachefs/block.c~turn-cachefs-into-a-cache-backend	Wed Oct  6 16:03:22 2004
+++ 25-akpm/fs/cachefs/block.c	Wed Oct  6 16:03:22 2004
@@ -40,12 +40,12 @@ void cachefs_block_init_once(void *_bloc
  */
 static int cachefs_block_dummy_filler(void *data, struct page *page)
 {
-	struct cachefs_page *pageio;
+	struct fscache_page *pageio;
 
 	_enter("%p,{%lu}", data, page-&gt;index);
 
 	/* we need somewhere to note journal ACKs that need to be made */
-	pageio = cachefs_page_get_private(page, GFP_KERNEL);
+	pageio = fscache_page_get_private(page, GFP_KERNEL);
 	if (IS_ERR(pageio))
 		return PTR_ERR(pageio);
 
@@ -67,7 +67,7 @@ static int cachefs_block_dummy_filler(vo
 int cachefs_block_set(struct cachefs_super *super,
 		      struct cachefs_block *block,
 		      struct page *page,
-		      struct cachefs_page *pageio)
+		      struct fscache_page *pageio)
 {
 	DECLARE_WAITQUEUE(myself,current);
 
@@ -137,7 +137,7 @@ int cachefs_block_set(struct cachefs_sup
 int cachefs_block_set2(struct cachefs_super *super,
 		       cachefs_blockix_t bix,
 		       struct page *page,
-		       struct cachefs_page *pageio,
+		       struct fscache_page *pageio,
 		       struct cachefs_block **_block)
 {
 	struct cachefs_block *block;
@@ -369,7 +369,7 @@ int cachefs_block_cow(struct cachefs_sup
 
 	/* duplicate the page if it's flagged copy-on-write */
 	if (test_bit(CACHEFS_BLOCK_COW, &amp;block-&gt;flags)) {
-		struct cachefs_page *newpageio;
+		struct fscache_page *newpageio;
 
 		mapping = super-&gt;imisc-&gt;i_mapping;
 
@@ -378,7 +378,7 @@ int cachefs_block_cow(struct cachefs_sup
 		if (!newpage)
 			goto error;
 
-		if (cachefs_page_get_private(newpage, &amp;newpageio,
+		if (fscache_page_get_private(newpage, &amp;newpageio,
 					     mapping_gfp_mask(mapping)) &lt; 0)
 			goto error_page;
 
@@ -614,15 +614,18 @@ void __cachefs_block_put(struct cachefs_
 /*
  * withdraw from active service all the blocks residing on a device
  */
-void cachefs_block_withdraw(struct cachefs_super *super)
+void cachefs_block_dissociate(struct fscache_cache *cache)
 {
 	struct cachefs_block *block, *xblock;
-	struct cachefs_page *pageio;
+	struct cachefs_super *super;
+	struct fscache_page *pageio;
 	struct rb_node *node;
 	unsigned long flags;
 
 	DECLARE_WAITQUEUE(myself, current);
 
+	super = container_of(cache, struct cachefs_super, cache);
+
 	_enter("");
 
 	/* first thing to do is mark all blocks withdrawn
@@ -705,4 +708,4 @@ void cachefs_block_withdraw(struct cache
 
 	_leave("");
 
-} /* end cachefs_block_withdraw() */
+} /* end cachefs_block_dissociate() */
diff -puN fs/cachefs/cachefs-int.h~turn-cachefs-into-a-cache-backend fs/cachefs/cachefs-int.h
--- 25/fs/cachefs/cachefs-int.h~turn-cachefs-into-a-cache-backend	Wed Oct  6 16:03:22 2004
+++ 25-akpm/fs/cachefs/cachefs-int.h	Wed Oct  6 16:03:22 2004
@@ -12,7 +12,7 @@
 #ifndef _LINUX_CACHEFS_INT_H
 #define _LINUX_CACHEFS_INT_H
 
-#include &lt;linux/cachefs.h&gt;
+#include &lt;linux/fscache-cache.h&gt;
 #include &lt;linux/timer.h&gt;
 #include &lt;linux/bio.h&gt;
 #include "cachefs-layout.h"
@@ -28,9 +28,9 @@ extern int cachefs_debug;
 struct cachefs_super;
 struct cachefs_block;
 struct cachefs_inode;
-struct cachefs_search_result;
 struct cachefs_transaction;
 
+extern struct fscache_cache_ops cachefs_cache_ops;
 extern struct address_space_operations cachefs_indr_io_addrspace_operations;
 extern struct address_space_operations cachefs_linear_io_addrspace_operations;
 extern struct file_operations cachefs_root_file_operations;
@@ -46,7 +46,7 @@ extern int kcachefsd(void *_super);
 extern int cachefs_io_dummy_filler(void *data, struct page *page);
 
 extern int cachefs_indr_io_get_block(struct inode *inode, struct page *page,
-				     struct cachefs_page *pageio, int create);
+				     struct fscache_page *pageio, int create);
 
 struct cachefs_reclaimable {
 	unsigned	ino;
@@ -59,8 +59,8 @@ struct cachefs_reclaimable {
  */
 struct cachefs_super
 {
+	struct fscache_cache		cache;		/* cache handle */
 	struct super_block		*sb;
-	struct list_head		mnt_link;	/* link in list of mounted caches */
 	struct cachefs_inode		*imetadata;	/* the metadata records file */
 	struct inode			*imisc;		/* an inode covering the whole blkdev */
 
@@ -70,15 +70,10 @@ struct cachefs_super
 #define CACHEFS_SUPER_DO_RECLAIM	2		/* T if should do reclamation */
 #define CACHEFS_SUPER_RCM_IMM_SCAN	3		/* T if should scan for immediately
 							 * reclaimable inodes */
-#define CACHEFS_SUPER_WITHDRAWN		4		/* T if cache has been withdrawn */
-#define CACHEFS_SUPER_REPLAYING_UJNL	5		/* T if replaying u-journal */
+#define CACHEFS_SUPER_REPLAYING_UJNL	4		/* T if replaying u-journal */
 
 	int				bio_wr_barrier;	/* command to submit a write barrier BIO */
 
-	/* index management */
-	struct list_head		ino_list;	/* list of data/index inodes */
-	spinlock_t			ino_list_lock;
-
 	/* block allocation and recycling management */
 	struct rb_root			blk_tree;	/* block mapping tree */
 	rwlock_t			blk_tree_lock;
@@ -191,10 +186,6 @@ struct cachefs_super
 	struct cachefs_ondisc_superblock *layout;
 };
 
-extern void cachefs_add_cache(struct cachefs_super *super,
-			      struct cachefs_search_result *srch);
-extern void cachefs_withdraw_cache(struct cachefs_super *super);
-
 extern void cachefs_recycle_unready_blocks(struct cachefs_super *super);
 extern void cachefs_recycle_transfer_stack(struct cachefs_super *super);
 extern void cachefs_recycle_reclaim(struct cachefs_super *super);
@@ -235,7 +226,7 @@ struct cachefs_block
 	struct list_head		batch_link;	/* link in batch writer's list */
 	struct page			*page;		/* current data for this block */
 	struct page			*writeback;	/* source of writeback for this block */
-	struct cachefs_page		*ref;		/* netfs's ref to this page */
+	struct fscache_page		*ref;		/* netfs's ref to this page */
 	rwlock_t			ref_lock;	/* lock governing ref pointer */
 	struct cachefs_vj_entry		*vjentry;	/* invalid block record */
 };
@@ -254,12 +245,12 @@ extern struct cachefs_block * cachefs_bl
 extern int cachefs_block_set(struct cachefs_super *super,
 			     struct cachefs_block *block,
 			     struct page *page,
-			     struct cachefs_page *pageio);
+			     struct fscache_page *pageio);
 
 extern int cachefs_block_set2(struct cachefs_super *super,
 			      cachefs_blockix_t bix,
 			      struct page *page,
-			      struct cachefs_page *pageio,
+			      struct fscache_page *pageio,
 			      struct cachefs_block **_block);
 
 extern int cachefs_block_read(struct cachefs_super *super,
@@ -308,7 +299,7 @@ static inline void cachefs_block_put(str
 static inline struct cachefs_block *__cachefs_get_page_block(struct page *page)
 {
 	BUG_ON(!PagePrivate(page));
-	return ((struct cachefs_page *) page-&gt;private)-&gt;mapped_block;
+	return ((struct fscache_page *) page-&gt;private)-&gt;mapped_block;
 }
 
 static inline void cachefs_page_modify(struct cachefs_super *super,
@@ -317,38 +308,10 @@ static inline void cachefs_page_modify(s
 	cachefs_block_modify(super, __cachefs_get_page_block(*page), page);
 }
 
-extern void cachefs_block_withdraw(struct cachefs_super *super);
+extern void cachefs_block_dissociate(struct fscache_cache *cache);
 
-/*****************************************************************************/
-/*
- * data file or index object cookie
- * - a file will only appear in one cache
- * - a request to cache a file may or may not be honoured, subject to
- *   constraints such as disc space
- * - indexes files are created on disc just-in-time
- */
-struct cachefs_cookie
-{
-	atomic_t			usage;		/* number of users of this cookie */
-	atomic_t			children;	/* number of children of this cookie */
-	struct cachefs_index_def	*idef;		/* index definition */
-	struct cachefs_cookie		*iparent;	/* index holding this entry */
-	struct list_head		search_results;	/* results of searching iparent */
-	struct list_head		backing_inodes;	/* inode(s) backing this file/index */
-	struct rw_semaphore		sem;
-	struct cachefs_netfs		*netfs;		/* owner network fs definition */
-	void				*netfs_data;	/* back pointer to netfs */
-};
-
-struct cachefs_search_result {
-	struct list_head		link;		/* link in search_results */
-	struct cachefs_super		*super;		/* superblock searched */
-	unsigned			ino;		/* inode number (or 0 if negative) */
-};
-
-extern kmem_cache_t *cachefs_cookie_jar;
-
-extern void cachefs_cookie_init_once(void *_cookie, kmem_cache_t *cachep, unsigned long flags);
+#define cachefs_mapped_block(PGIO) ((struct cachefs_block *) (PGIO)-&gt;mapped_block)
+#define cachefs_mapped_bix(PGIO) (((struct cachefs_block *) (PGIO)-&gt;mapped_block)-&gt;bix)
 
 /*****************************************************************************/
 /*
@@ -357,6 +320,7 @@ extern void cachefs_cookie_init_once(voi
 struct cachefs_inode
 {
 	struct inode			vfs_inode;	/* VFS inode record for this file */
+	struct fscache_node		node;		/* fscache handle */
 
 	struct cachefs_block		*metadata;	/* block containing metadata */
 	struct page			*metadata_page;	/* page mapped to metadata block */
@@ -366,16 +330,6 @@ struct cachefs_inode
 	unsigned short			index_dsize;	/* size of data in each index entry */
 	unsigned short			index_esize;	/* size of index entries */
 	unsigned short			index_epp;	/* number of index entries per page */
-
-	unsigned long			flags;
-#define CACHEFS_ACTIVE_INODE_ISINDEX	0	/* T if inode is index file (F if file) */
-#define CACHEFS_ACTIVE_INODE_RELEASING	1	/* T if inode is being released */
-#define CACHEFS_ACTIVE_INODE_RECYCLING	2	/* T if inode is being retired */
-#define CACHEFS_ACTIVE_INODE_WITHDRAWN	3	/* T if inode has been withdrawn */
-
-	struct list_head		super_link;	/* link in super-&gt;ino_list */
-	struct list_head		cookie_link;	/* link in cookie-&gt;backing_inodes */
-	struct cachefs_cookie		*cookie;	/* netfs's file/index object */
 };
 
 extern struct inode_operations cachefs_status_inode_operations;
@@ -466,16 +420,16 @@ void cachefs_metadata_postwrite(struct c
 
 extern void cachefs_withdraw_inode(struct cachefs_inode *inode);
 
-extern int cachefs_index_search(struct cachefs_inode *index,
-				struct cachefs_cookie *target,
-				unsigned *_entry,
-				unsigned *_ino);
-
-extern int cachefs_index_add(struct cachefs_inode *index,
-			     struct cachefs_cookie *cookie,
-			     unsigned *_newino);
+extern int cachefs_index_search(struct fscache_node *node,
+				struct fscache_cookie *target,
+				struct fscache_search_result *result);
+
+extern int cachefs_index_add(struct fscache_node *node,
+			     struct fscache_cookie *cookie,
+			     struct fscache_search_result *result);
 
-extern int cachefs_index_update(struct cachefs_inode *index);
+extern int cachefs_index_update(struct fscache_node *ixnode,
+				struct fscache_node *node);
 
 extern int cachefs_index_reclaim_one_entry(struct cachefs_super *super,
 					   struct cachefs_transaction **_trans);
@@ -591,7 +545,7 @@ extern void cachefs_trans_affects_block(
 
 static inline
 void cachefs_trans_affects_page(struct cachefs_transaction *trans,
-				struct cachefs_page *pageio,
+				struct fscache_page *pageio,
 				unsigned offset,
 				unsigned size)
 {
@@ -614,7 +568,7 @@ static inline void cachefs_trans_affects
 {
 	struct cachefs_super *super = trans-&gt;super;
 	cachefs_trans_affects_page(trans,
-				   cachefs_page_grab_private(
+				   fscache_page_grab_private(
 					   virt_to_page(super-&gt;layout)),
 				   0,
 				   super-&gt;sb-&gt;s_blocksize);
diff -puN fs/cachefs/cachefs-layout.h~turn-cachefs-into-a-cache-backend fs/cachefs/cachefs-layout.h
--- 25/fs/cachefs/cachefs-layout.h~turn-cachefs-into-a-cache-backend	Wed Oct  6 16:03:22 2004
+++ 25-akpm/fs/cachefs/cachefs-layout.h	Wed Oct  6 16:03:22 2004
@@ -102,9 +102,12 @@ struct cachefs_ondisc_index_def
 #define CACHEFS_ONDISC_INDEXKEY_TYPE	0xF000	/* type of key segment */
 #define CACHEFS_ONDISC_INDEXKEY_NOTUSED	0x0000	/* - segment not used */
 #define CACHEFS_ONDISC_INDEXKEY_BIN	0x1000	/* - binary data */
-#define CACHEFS_ONDISC_INDEXKEY_ASCIIZ	0x2000	/* - null-terminated string */
-#define CACHEFS_ONDISC_INDEXKEY_IPV4	0x3000	/* - IPv4 address */
-#define CACHEFS_ONDISC_INDEXKEY_IPV6	0x4000	/* - IPv6 address */
+#define CACHEFS_ONDISC_INDEXKEY_BIN_SZ1	0x2000	/* - binary data, size in byte 0 */
+#define CACHEFS_ONDISC_INDEXKEY_BIN_SZ2	0x3000	/* - binary data, size in bytes 0 &amp; 1 */
+#define CACHEFS_ONDISC_INDEXKEY_BIN_SZ4	0x4000	/* - binary data, size in bytes 0-3 */
+#define CACHEFS_ONDISC_INDEXKEY_ASCIIZ	0x5000	/* - null-terminated string */
+#define CACHEFS_ONDISC_INDEXKEY_IPV4	0x6000	/* - IPv4 address */
+#define CACHEFS_ONDISC_INDEXKEY_IPV6	0x7000	/* - IPv6 address */
 
 	uint8_t				data[0];
 };
@@ -142,17 +145,6 @@ struct cachefs_ondisc_metadata
 };
 
 /*****************************************************************************/
-/*
- * on-disc cached network filesystem definition record
- * - each entry resides in its own sector
- */
-struct cachefs_ondisc_fsdef
-{
-	uint8_t				name[24];	/* name of netfs */
-	uint32_t			version;	/* version of layout */
-};
-
-/*****************************************************************************/
 /*
  * Free blocks are kept in pair of a very one sided trees (more horsetail
  * plants than trees)
diff -puN fs/cachefs/index.c~turn-cachefs-into-a-cache-backend fs/cachefs/index.c
--- 25/fs/cachefs/index.c~turn-cachefs-into-a-cache-backend	Wed Oct  6 16:03:22 2004
+++ 25-akpm/fs/cachefs/index.c	Wed Oct  6 16:03:22 2004
@@ -20,17 +20,15 @@
  */
 
 #include &lt;linux/module.h&gt;
-#include &lt;linux/init.h&gt;
 #include &lt;linux/sched.h&gt;
-#include &lt;linux/completion.h&gt;
 #include &lt;linux/slab.h&gt;
 #include &lt;linux/bio.h&gt;
 #include &lt;linux/circ_buf.h&gt;
 #include "cachefs-int.h"
 
-struct cachefs_index_search_record {
-	struct cachefs_cookie		*index;
-	struct cachefs_cookie		*target;
+struct fscache_index_search_record {
+	struct fscache_cookie		*index;
+	struct fscache_cookie		*target;
 	struct cachefs_inode		*iinode;
 	unsigned			entsize;
 	unsigned			ino;
@@ -42,7 +40,7 @@ struct cachefs_index_search_record {
  * mark an inode/index entry pair for deletion when so requested by the match
  * function supplied by the netfs
  */
-static void cachefs_index_search_delete(struct cachefs_index_search_record *rec,
+static void cachefs_index_search_delete(struct fscache_index_search_record *rec,
 					struct page *ixpage,
 					unsigned ixentry,
 					unsigned ixoffset,
@@ -69,7 +67,7 @@ static void cachefs_index_search_delete(
 		return;
 	}
 
-	BUG_ON(!list_empty(&amp;inode-&gt;cookie_link));
+	BUG_ON(!list_empty(&amp;inode-&gt;node.cookie_link));
 
 	/* create a transaction to record the reclamation */
 	ret = -ENOMEM;
@@ -87,7 +85,7 @@ static void cachefs_index_search_delete(
 	trans-&gt;jentry-&gt;auxblock	= inode-&gt;metadata-&gt;bix;
 	trans-&gt;jentry-&gt;auxentry	= inode-&gt;metadata_offset;
 
-	cachefs_trans_affects_page(trans, cachefs_page_grab_private(ixpage),
+	cachefs_trans_affects_page(trans, fscache_page_grab_private(ixpage),
 				   ixoffset, sizeof(*xent));
 	cachefs_trans_affects_inode(trans, inode);
 
@@ -152,7 +150,7 @@ static void cachefs_index_search_delete(
  * mark an inode/index entry pair for deletion when so requested by the match
  * function supplied by the netfs
  */
-static void cachefs_index_search_update(struct cachefs_index_search_record *rec,
+static void cachefs_index_search_update(struct fscache_index_search_record *rec,
 					struct page *ixpage,
 					unsigned ixentry,
 					unsigned ixoffset,
@@ -182,7 +180,7 @@ static void cachefs_index_search_update(
 	trans-&gt;jentry-&gt;entry	= ixoffset;
 	trans-&gt;jentry-&gt;count	= rec-&gt;iinode-&gt;index_dsize;
 
-	cachefs_trans_affects_page(trans, cachefs_page_grab_private(ixpage),
+	cachefs_trans_affects_page(trans, fscache_page_grab_private(ixpage),
 				   ixoffset, sizeof(*xent));
 
 	/* have the netfs transcribe the update into the transaction */
@@ -225,14 +223,14 @@ static int cachefs_index_search_actor(re
 				      unsigned long offset,
 				      unsigned long size)
 {
-	struct cachefs_index_search_record *rec;
+	struct fscache_index_search_record *rec;
 	unsigned long stop, tmp, esize;
 	void *content;
 	int ret;
 
 	_enter(",{%lu},%lu,%lu", page-&gt;index, offset, size);
 
-	rec = (struct cachefs_index_search_record *) desc-&gt;arg.buf;
+	rec = (struct fscache_index_search_record *) desc-&gt;arg.buf;
 	ret = size;
 
 	/* round up to the first record boundary after the offset */
@@ -257,7 +255,7 @@ static int cachefs_index_search_actor(re
 
 	for (; offset + esize &lt;= stop; offset += esize) {
 		struct cachefs_ondisc_index_entry *xent = content + offset;
-		cachefs_match_val_t result;
+		fscache_match_val_t result;
 		unsigned ixentry;
 
 		/* ignore invalid entries */
@@ -273,13 +271,13 @@ static int cachefs_index_search_actor(re
 						 xent-&gt;u.data);
 
 		switch (result) {
-		case CACHEFS_MATCH_SUCCESS_UPDATE:
+		case FSCACHE_MATCH_SUCCESS_UPDATE:
 			/* the netfs said that it matched, but needs
 			 * updating */
 			cachefs_index_search_update(rec, page, ixentry, offset,
 						    xent-&gt;ino);
 
-		case CACHEFS_MATCH_SUCCESS:
+		case FSCACHE_MATCH_SUCCESS:
 			/* the netfs said that it matched */
 			rec-&gt;entry = tmp;
 			rec-&gt;ino   = xent-&gt;ino;
@@ -299,13 +297,13 @@ static int cachefs_index_search_actor(re
 			ret = 0;
 			break;
 
-		case CACHEFS_MATCH_SUCCESS_DELETE:
+		case FSCACHE_MATCH_SUCCESS_DELETE:
 			/* the netfs said that it matched, but this entry
 			 * should be marked obsolete */
 			cachefs_index_search_delete(rec, page, ixentry, offset,
 						    xent-&gt;ino);
 
-		case CACHEFS_MATCH_FAILED:
+		case FSCACHE_MATCH_FAILED:
 			/* the netfs said there wasn't a valid match */
 		default:
 			break;
@@ -330,26 +328,23 @@ static int cachefs_index_search_actor(re
  * - returns 0 if found, and stores the entry number in *_entry and the inode
  *   number of the backing file in *_ino
  */
-int cachefs_index_search(struct cachefs_inode *index,
-			 struct cachefs_cookie *target,
-			 unsigned *_entry,
-			 unsigned *_ino)
+int cachefs_index_search(struct fscache_node *node,
+			 struct fscache_cookie *target,
+			 struct fscache_search_result *result)
 {
-	struct cachefs_index_search_record rec;
+	struct fscache_index_search_record rec;
+	struct cachefs_inode *index;
 	struct file_ra_state ra;
 	read_descriptor_t desc;
 	loff_t pos;
 	int ret;
 
+	index = container_of(node, struct cachefs_inode, node);
+
 	_enter("{%s,%lu,%Lu}",
-	       index-&gt;cookie-&gt;idef-&gt;name,
+	       index-&gt;node.cookie-&gt;idef-&gt;name,
 	       index-&gt;vfs_inode.i_ino,
-	       i_size_read(index-&gt;vfs_inode));
-
-	if (_entry)
-		*_entry = UINT_MAX;
-	if (_ino)
-		*_ino = 0;
+	       i_size_read(&amp;index-&gt;vfs_inode));
 
 	ret = -ENOENT;
 	if (i_size_read(&amp;index-&gt;vfs_inode) == 0)
@@ -357,7 +352,7 @@ int cachefs_index_search(struct cachefs_
 
 	/* prepare a record of what we want to do */
 	rec.iinode	= index;
-	rec.index	= index-&gt;cookie;
+	rec.index	= index-&gt;node.cookie;
 	rec.target	= target;
 	rec.entsize	= rec.iinode-&gt;index_esize;
 	rec.entry	= UINT_MAX;
@@ -388,11 +383,7 @@ int cachefs_index_search(struct cachefs_
 	else {
 		/* we found an entry */
 		BUG_ON(rec.ino == 0);
-
-		if (_entry)
-			*_entry = rec.entry;
-		if (_ino)
-			*_ino = rec.ino;
+		result-&gt;ino = rec.ino;
 		ret = 0;
 	}
 
@@ -408,12 +399,12 @@ int cachefs_index_search(struct cachefs_
  */
 static int cachefs_index_preinit_page(void *data, struct page *page)
 {
-	struct cachefs_page *pageio;
+	struct fscache_page *pageio;
 
 	_enter(",%p{%lu}", page, page-&gt;index);
 
 	/* attach a mapping cookie to the page */
-	pageio = cachefs_page_get_private(page, GFP_KERNEL);
+	pageio = fscache_page_get_private(page, GFP_KERNEL);
 	if (IS_ERR(pageio)) {
 		_leave(" = %ld", PTR_ERR(pageio));
 		return PTR_ERR(pageio);
@@ -458,7 +449,7 @@ static int cachefs_index_select_free_ent
 	cachefs_metadata_postread(iinode, metadata);
 
 	_debug("free entry: %u [size %Lu]",
-	       newentry, i_size_read(iinode-&gt;vfs_inode));
+	       newentry, i_size_read(&amp;iinode-&gt;vfs_inode));
 
 	/* extend the index file if there are no new entries */
 	if (newentry == UINT_MAX) {
@@ -479,7 +470,7 @@ static int cachefs_index_select_free_ent
 			     i_size_read(&amp;iinode-&gt;vfs_inode) + PAGE_SIZE);
 
 		ret = cachefs_indr_io_get_block(&amp;iinode-&gt;vfs_inode, page,
-						cachefs_page_grab_private(page),
+						fscache_page_grab_private(page),
 						1);
 		if (ret &lt; 0) {
 			i_size_write(&amp;iinode-&gt;vfs_inode,
@@ -561,24 +552,27 @@ static int cachefs_index_select_free_ent
  * - if an inode is successfully allocated *_newino will be set with the inode
  *   number
  */
-int cachefs_index_add(struct cachefs_inode *index,
-		      struct cachefs_cookie *cookie,
-		      unsigned *_newino)
+int cachefs_index_add(struct fscache_node *node,
+		      struct fscache_cookie *cookie,
+		      struct fscache_search_result *result)
+//		      unsigned *_newino)
 {
 	struct cachefs_ondisc_index_entry *xent;
 	struct cachefs_ondisc_ujnl_index *jindex;
 	struct cachefs_ondisc_metadata *metadata;
-	struct cachefs_search_result *srch;
 	struct cachefs_transaction *trans;
 	struct cachefs_super *super;
+	struct cachefs_inode *index;
 	struct page *inopage, *ixpage;
 	unsigned ino, ixentry, offset, inonext, ixnext, ino_offset;
 	int ret, loop;
 
+	index = container_of(node, struct cachefs_inode, node);
+
 	_enter("{%lu},{%s},",
-	       index-&gt;vfs_inode.i_ino, index-&gt;cookie-&gt;idef-&gt;name);
+	       index-&gt;vfs_inode.i_ino, index-&gt;node.cookie-&gt;idef-&gt;name);
 
-	*_newino = 0;
+//	*_newino = 0;
 
 	super	= index-&gt;vfs_inode.i_sb-&gt;s_fs_info;
 	inopage	= NULL;
@@ -627,9 +621,9 @@ int cachefs_index_add(struct cachefs_ino
 	trans-&gt;jentry-&gt;upblock	= index-&gt;metadata-&gt;bix;
 	trans-&gt;jentry-&gt;upentry	= index-&gt;metadata_offset;
 
-	cachefs_trans_affects_page(trans, cachefs_page_grab_private(ixpage),
+	cachefs_trans_affects_page(trans, fscache_page_grab_private(ixpage),
 				   offset, index-&gt;index_esize);
-	cachefs_trans_affects_page(trans, cachefs_page_grab_private(inopage),
+	cachefs_trans_affects_page(trans, fscache_page_grab_private(inopage),
 				   ino_offset, super-&gt;layout-&gt;metadata_size);
 
 	cachefs_trans_affects_inode(trans, index);
@@ -642,12 +636,12 @@ int cachefs_index_add(struct cachefs_ino
 	jindex-&gt;next_ino	= inonext;
 	jindex-&gt;next_index	= ixnext;
 
-	index-&gt;cookie-&gt;idef-&gt;update(cookie-&gt;netfs_data, jindex-&gt;data);
+	index-&gt;node.cookie-&gt;idef-&gt;update(cookie-&gt;netfs_data, jindex-&gt;data);
 
 	/* if we're adding a new index, we store its definition in the journal
 	 * too */
 	if (cookie-&gt;idef) {
-		struct cachefs_index_def *definition = cookie-&gt;idef;
+		struct fscache_index_def *definition = cookie-&gt;idef;
 
 		jindex-&gt;def.dsize = definition-&gt;data_size;
 		jindex-&gt;def.esize = definition-&gt;data_size;
@@ -725,15 +719,8 @@ int cachefs_index_add(struct cachefs_ino
 	cachefs_trans_commit(trans);
 	trans = NULL;
 
-	/* add the new inode to the cookie's list of search results */
-	list_for_each_entry(srch, &amp;cookie-&gt;search_results, link) {
-		if (srch-&gt;super == super) {
-			srch-&gt;ino = ino;
-			break;
-		}
-	}
-
-	*_newino = ino;
+//	*_newino = ino;
+	result-&gt;ino = ino;
 
  error:
 	cachefs_trans_put(trans);
@@ -750,38 +737,29 @@ int cachefs_index_add(struct cachefs_ino
  * update the index entry for an index or data file from the associated netfs
  * data
  */
-int cachefs_index_update(struct cachefs_inode *inode)
+int cachefs_index_update(struct fscache_node *ixnode,
+			 struct fscache_node *node)
 {
 	struct cachefs_ondisc_index_entry *xent;
 	struct cachefs_ondisc_metadata *meta;
-	struct cachefs_cookie *cookie = inode-&gt;cookie;
+	struct fscache_cookie *cookie = node-&gt;cookie;
 	struct cachefs_super *super;
-	struct cachefs_inode *index;
+	struct cachefs_inode *index, *inode;
 	struct cachefs_block *block;
 	struct page *ixpage;
 	unsigned offs;
 	int ret;
 
-	_enter("");
+	index = container_of(ixnode, struct cachefs_inode, node);
+	inode = container_of(node, struct cachefs_inode, node);
+
+	_enter(",");
 
 	super = inode-&gt;vfs_inode.i_sb-&gt;s_fs_info;
 
-	if (test_bit(CACHEFS_SUPER_WITHDRAWN, &amp;super-&gt;flags))
+	if (fscache_is_cache_withdrawn(&amp;super-&gt;cache))
 		return 0;
 
-	/* the index entry for this inode lives in the parent index inode */
-	list_for_each_entry(index,
-			    &amp;cookie-&gt;iparent-&gt;backing_inodes,
-			    cookie_link) {
-		if (index-&gt;vfs_inode.i_sb == inode-&gt;vfs_inode.i_sb)
-			goto found_parent_index_inode;
-	}
-
-	/* hmmm... the parent inode is strangely absent */
-	BUG();
-	return -ENOENT;
-
- found_parent_index_inode:
 	/* find the entry number of this inode's index entry */
 	meta = cachefs_metadata_preread(inode);
 	offs = meta-&gt;pindex_entry;
diff -puN fs/cachefs/indirection-io.c~turn-cachefs-into-a-cache-backend fs/cachefs/indirection-io.c
--- 25/fs/cachefs/indirection-io.c~turn-cachefs-into-a-cache-backend	Wed Oct  6 16:03:22 2004
+++ 25-akpm/fs/cachefs/indirection-io.c	Wed Oct  6 16:03:22 2004
@@ -36,7 +36,7 @@
 
 struct cachefs_io_block_path {
 	struct page			*page;
-	struct cachefs_page		*pageio;	/* page =&gt; block mapping */
+	struct fscache_page		*pageio;	/* page =&gt; block mapping */
 	cachefs_blockix_t		bix;		/* block number for this level */
 	unsigned			offset;		/* offset into parent pointer block */
 
@@ -84,7 +84,7 @@ static int cachefs_indr_io_do_readpage(s
 				       unsigned nr_pages,
 				       sector_t *last_block_in_bio)
 {
-	struct cachefs_page *pageio;
+	struct fscache_page *pageio;
 	struct inode *inode = page-&gt;mapping-&gt;host;
 	sector_t last_block;
 	int ret;
@@ -92,7 +92,7 @@ static int cachefs_indr_io_do_readpage(s
 	_enter("");
 
 	/* get the page mapping cookie */
-	pageio = cachefs_page_get_private(page, GFP_KERNEL);
+	pageio = fscache_page_get_private(page, GFP_KERNEL);
 	if (IS_ERR(pageio)) {
 		ret = PTR_ERR(pageio);
 		goto error;
@@ -128,7 +128,7 @@ static int cachefs_indr_io_do_readpage(s
 	 */
 	if (!*_bio)
 		goto allocate_new_bio;
-	else if (*last_block_in_bio + 1 != pageio-&gt;mapped_block-&gt;bix)
+	else if (*last_block_in_bio + 1 != cachefs_mapped_bix(pageio))
 		goto dispatch_bio;
 
 	/* add the page to the current BIO */
@@ -138,12 +138,12 @@ static int cachefs_indr_io_do_readpage(s
 
 	/* dispatch the BIO immediately if the current page lives on an
 	 * indirection chain boundary */
-	if (test_bit(CACHEFS_PAGE_BOUNDARY, &amp;pageio-&gt;flags)) {
+	if (test_bit(FSCACHE_PAGE_BOUNDARY, &amp;pageio-&gt;flags)) {
 		submit_bio(READ, *_bio);
 		*_bio = NULL;
 	}
 	else {
-		*last_block_in_bio = pageio-&gt;mapped_block-&gt;bix;
+		*last_block_in_bio = cachefs_mapped_bix(pageio);
 	}
 
 	_leave(" = 0");
@@ -154,7 +154,7 @@ static int cachefs_indr_io_do_readpage(s
 	submit_bio(READ, *_bio);
  allocate_new_bio:
 	ret = cachefs_io_alloc(inode-&gt;i_sb,
-			       pageio-&gt;mapped_block-&gt;bix,
+			       cachefs_mapped_bix(pageio),
 			       nr_pages, GFP_KERNEL, _bio);
 	if (ret &lt; 0) {
 		*_bio = NULL;
@@ -168,8 +168,7 @@ static int cachefs_indr_io_do_readpage(s
 	 */
  hole:
 	ret = -ENODATA;
-	if (test_bit(CACHEFS_ACTIVE_INODE_ISINDEX,
-		     &amp;CACHEFS_FS_I(inode)-&gt;flags)) {
+	if (test_bit(FSCACHE_NODE_ISINDEX, &amp;CACHEFS_FS_I(inode)-&gt;node.flags)) {
 		printk("CacheFS: found unexpected hole in index/metadata file:"
 		       " ino=%lu pg=%lu\n",
 		       inode-&gt;i_ino, page-&gt;index);
@@ -395,7 +394,7 @@ static int cachefs_indr_io_get_block_all
 						 &amp;block, &amp;step-&gt;page);
 			if (ret &lt; 0)
 				goto error_block;
-			step-&gt;pageio = cachefs_page_grab_private(step-&gt;page);
+			step-&gt;pageio = fscache_page_grab_private(step-&gt;page);
 		}
 		else {
 			ret = cachefs_block_set2(super, jentry-&gt;block,
@@ -581,7 +580,7 @@ static int cachefs_indr_io_get_block_all
  *   index and must be initialised as part of the final journalling mark
  */
 int cachefs_indr_io_get_block(struct inode *vfs_inode, struct page *page,
-			      struct cachefs_page *pageio, int create)
+			      struct fscache_page *pageio, int create)
 {
 	struct cachefs_io_block_path path[4];
 	struct cachefs_inode *inode = CACHEFS_FS_I(vfs_inode);
@@ -688,10 +687,10 @@ int cachefs_indr_io_get_block(struct ino
 	path[pix].offset += inode-&gt;metadata_offset;
 
 	down_read(&amp;inode-&gt;metadata_sem);
-	path[pix + 1].pageio = cachefs_page_grab_private(inode-&gt;metadata_page);
+	path[pix + 1].pageio = fscache_page_grab_private(inode-&gt;metadata_page);
 	up_read(&amp;inode-&gt;metadata_sem);
 
-	path[pix + 1].bix = path[pix + 1].pageio-&gt;mapped_block-&gt;bix;
+	path[pix + 1].bix = cachefs_mapped_bix(path[pix + 1].pageio);
 
 	ret = 0;
 	for (; pix &gt;= 0; pix--) {
@@ -784,7 +783,7 @@ int cachefs_indr_io_get_block(struct ino
 		}
 
 		if (!step-&gt;pageio) {
-			step-&gt;pageio = __cachefs_page_grab_private(step-&gt;page);
+			step-&gt;pageio = __fscache_page_grab_private(step-&gt;page);
 			if (!step-&gt;pageio) {
 				printk("step level %u"
 				       " { ptr={%lu}+%u / bix=%u }",
@@ -812,21 +811,22 @@ int cachefs_indr_io_get_block(struct ino
 		return ret;
 	}
 	else if (path[0].flags &amp; CACHEFS_BLOCK_INIT_NETFSDATA) {
-		set_bit(CACHEFS_BLOCK_NETFSDATA, &amp;pageio-&gt;mapped_block-&gt;flags);
+		set_bit(CACHEFS_BLOCK_NETFSDATA,
+			&amp;cachefs_mapped_block(pageio)-&gt;flags);
 	}
 
 	/* got the block - set the block offset in the page mapping record */
 	if (path[0].flags &amp; CACHEFS_BLOCK_NEW)
-		set_bit(CACHEFS_PAGE_NEW, &amp;pageio-&gt;flags);
+		set_bit(FSCACHE_PAGE_NEW, &amp;pageio-&gt;flags);
 
 	_debug("notboundary = %u", notboundary);
 	if (!notboundary)
-		set_bit(CACHEFS_PAGE_BOUNDARY, &amp;pageio-&gt;flags);
+		set_bit(FSCACHE_PAGE_BOUNDARY, &amp;pageio-&gt;flags);
 
 	_leave(" = 0 [bix=%u %c%c]",
-	       pageio-&gt;mapped_block-&gt;bix,
-	       test_bit(CACHEFS_PAGE_BOUNDARY, &amp;pageio-&gt;flags)	? 'b' : '-',
-	       test_bit(CACHEFS_PAGE_NEW, &amp;pageio-&gt;flags)	? 'n' : '-'
+	       cachefs_mapped_bix(pageio),
+	       test_bit(FSCACHE_PAGE_BOUNDARY, &amp;pageio-&gt;flags)	? 'b' : '-',
+	       test_bit(FSCACHE_PAGE_NEW, &amp;pageio-&gt;flags)	? 'n' : '-'
 	       );
 	return 0;
 
diff -puN fs/cachefs/inode.c~turn-cachefs-into-a-cache-backend fs/cachefs/inode.c
--- 25/fs/cachefs/inode.c~turn-cachefs-into-a-cache-backend	Wed Oct  6 16:03:22 2004
+++ 25-akpm/fs/cachefs/inode.c	Wed Oct  6 16:03:22 2004
@@ -125,7 +125,7 @@ static int cachefs_iget_file0(struct cac
 	inode-&gt;index_esize	= inode-&gt;index_dsize;
 	inode-&gt;index_epp	= PAGE_SIZE / inode-&gt;index_esize;
 
-	__set_bit(CACHEFS_ACTIVE_INODE_ISINDEX, &amp;inode-&gt;flags);
+	__set_bit(FSCACHE_NODE_ISINDEX, &amp;inode-&gt;node.flags);
 
 	/* read the block containing this inode's meta-data from disc */
 	pos = inode-&gt;vfs_inode.i_ino &lt;&lt; super-&gt;layout-&gt;metadata_bits;
@@ -262,7 +262,7 @@ static int cachefs_iget_fileN(struct cac
 		inode-&gt;vfs_inode.i_op	= &amp;cachefs_root_inode_operations;
 		inode-&gt;vfs_inode.i_fop	= &amp;cachefs_root_file_operations;
 
-		__set_bit(CACHEFS_ACTIVE_INODE_ISINDEX, &amp;inode-&gt;flags);
+		__set_bit(FSCACHE_NODE_ISINDEX, &amp;inode-&gt;node.flags);
 	}
 
 	_leave(" = 0");
@@ -297,10 +297,12 @@ struct cachefs_inode *cachefs_iget(struc
 
 	/* deal with an existing inode */
 	if (!(inode-&gt;vfs_inode.i_state &amp; I_NEW)) {
-		_leave(" = 0 [exist]");
+		_leave(" = %p [exist]", inode);
 		return inode;
 	}
 
+	inode-&gt;node.cache = &amp;super-&gt;cache;
+
 	/* new inode - attempt to find in the on-disc catalogue */
 	switch (ino) {
 		/* they've asked for the virtual inode that mirrors the
@@ -346,7 +348,7 @@ struct cachefs_inode *cachefs_iget(struc
 	/* success */
 	unlock_new_inode(&amp;inode-&gt;vfs_inode);
 
-	_leave(" = %p", inode);
+	_leave(" = %p [new]", inode);
 	return inode;
 
 	/* failure */
diff -puN fs/cachefs/interface.c~turn-cachefs-into-a-cache-backend fs/cachefs/interface.c
--- 25/fs/cachefs/interface.c~turn-cachefs-into-a-cache-backend	Wed Oct  6 16:03:22 2004
+++ 25-akpm/fs/cachefs/interface.c	Wed Oct  6 16:03:22 2004
@@ -1,6 +1,6 @@
-/* interface.c: network FS interface to cache
+/* interface.c: filesystem cache interface
  *
- * Copyright (C) 2003 Red Hat, Inc. All Rights Reserved.
+ * 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
@@ -10,998 +10,120 @@
  */
 
 #include &lt;linux/module.h&gt;
+#include &lt;linux/sched.h&gt;
+#include &lt;linux/slab.h&gt;
+#include &lt;linux/bio.h&gt;
 #include "cachefs-int.h"
 
 struct cachefs_io_end {
-	cachefs_rw_complete_t	func;
+	fscache_rw_complete_t	func;
 	void			*data;
 	void			*cookie_data;
 	struct cachefs_block	*block;
 };
 
-LIST_HEAD(cachefs_netfs_list);
-LIST_HEAD(cachefs_cache_list);
-DECLARE_RWSEM(cachefs_addremove_sem);
-
-kmem_cache_t *cachefs_cookie_jar;
-
-static cachefs_match_val_t cachefs_fsdef_index_match(void *target,
-						     const void *entry);
-
-static void cachefs_fsdef_index_update(void *source, void *entry);
-
-static struct cachefs_index_def cachefs_fsdef_index_def = {
-	.name		= ".fsdef",
-	.data_size	= sizeof(struct cachefs_ondisc_fsdef),
-	.match		= cachefs_fsdef_index_match,
-	.update		= cachefs_fsdef_index_update
-};
-
-static struct cachefs_cookie cachefs_fsdef_index = {
-	.usage		= ATOMIC_INIT(1),
-	.idef		= &amp;cachefs_fsdef_index_def,
-	.sem		= __RWSEM_INITIALIZER(cachefs_fsdef_index.sem),
-	.search_results	= LIST_HEAD_INIT(cachefs_fsdef_index.search_results),
-	.backing_inodes	= LIST_HEAD_INIT(cachefs_fsdef_index.backing_inodes),
-};
-
-static void __cachefs_cookie_put(struct cachefs_cookie *cookie);
-static inline void cachefs_cookie_put(struct cachefs_cookie *cookie)
-{
-	BUG_ON(atomic_read(&amp;cookie-&gt;usage) &lt;= 0);
-
-	if (atomic_dec_and_test(&amp;cookie-&gt;usage))
-		__cachefs_cookie_put(cookie);
-
-}
-
 /*****************************************************************************/
 /*
- * register a network filesystem for caching
+ * look up the nominated node for this cache
  */
-int __cachefs_register_netfs(struct cachefs_netfs *netfs,
-			     struct cachefs_index_def *primary_idef)
-{
-	struct cachefs_netfs *ptr;
-	int ret;
-
-	_enter("{%s}", netfs-&gt;name);
-
-	INIT_LIST_HEAD(&amp;netfs-&gt;link);
-
-	/* allocate a cookie for the primary index */
-	netfs-&gt;primary_index =
-		kmem_cache_alloc(cachefs_cookie_jar, SLAB_KERNEL);
-
-	if (!netfs-&gt;primary_index) {
-		_leave(" = -ENOMEM");
-		return -ENOMEM;
-	}
-
-	/* initialise the primary index cookie */
-	memset(netfs-&gt;primary_index, 0, sizeof(*netfs-&gt;primary_index));
-
-	atomic_set(&amp;netfs-&gt;primary_index-&gt;usage, 1);
-	atomic_set(&amp;netfs-&gt;primary_index-&gt;children, 0);
-
-	netfs-&gt;primary_index-&gt;idef		= primary_idef;
-	netfs-&gt;primary_index-&gt;iparent		= &amp;cachefs_fsdef_index;
-	netfs-&gt;primary_index-&gt;netfs		= netfs;
-	netfs-&gt;primary_index-&gt;netfs_data	= netfs;
-
-	atomic_inc(&amp;netfs-&gt;primary_index-&gt;iparent-&gt;usage);
-	atomic_inc(&amp;netfs-&gt;primary_index-&gt;iparent-&gt;children);
-
-	INIT_LIST_HEAD(&amp;netfs-&gt;primary_index-&gt;search_results);
-	INIT_LIST_HEAD(&amp;netfs-&gt;primary_index-&gt;backing_inodes);
-	init_rwsem(&amp;netfs-&gt;primary_index-&gt;sem);
-
-	/* check the netfs type is not already present */
-	down_write(&amp;cachefs_addremove_sem);
-
-	ret = -EEXIST;
-	list_for_each_entry(ptr, &amp;cachefs_netfs_list,link) {
-		if (strcmp(ptr-&gt;name, netfs-&gt;name) == 0)
-			goto already_registered;
-	}
-
-	list_add(&amp;netfs-&gt;link, &amp;cachefs_netfs_list);
-	ret = 0;
-
-	printk("CacheFS: netfs '%s' registered for caching\n", netfs-&gt;name);
-
- already_registered:
-	up_write(&amp;cachefs_addremove_sem);
-
-	if (ret &lt; 0) {
-		netfs-&gt;primary_index-&gt;iparent = NULL;
-		__cachefs_cookie_put(netfs-&gt;primary_index);
-		netfs-&gt;primary_index = NULL;
-	}
-
-	_leave(" = %d", ret);
-	return ret;
-
-} /* end __cachefs_register_netfs() */
-
-EXPORT_SYMBOL(__cachefs_register_netfs);
-
-/*****************************************************************************/
-/*
- * unregister a network filesystem from the cache
- * - all cookies must have been released first
- */
-void __cachefs_unregister_netfs(struct cachefs_netfs *netfs)
-{
-	_enter("{%s.%u}", netfs-&gt;name, netfs-&gt;version);
-
-	down_write(&amp;cachefs_addremove_sem);
-
-	list_del(&amp;netfs-&gt;link);
-	cachefs_relinquish_cookie(netfs-&gt;primary_index, 0);
-
-	up_write(&amp;cachefs_addremove_sem);
-
-	printk("CacheFS: netfs '%s' unregistered from caching\n", netfs-&gt;name);
-
-	_leave("");
-
-} /* end __cachefs_unregister_netfs() */
-
-EXPORT_SYMBOL(__cachefs_unregister_netfs);
-
-/*****************************************************************************/
-/*
- * declare a mounted cache as being open for business
- * - try not to allocate memory as disposing of the superblock is a pain
- */
-void cachefs_add_cache(struct cachefs_super *super,
-		       struct cachefs_search_result *srch)
-{
-	struct cachefs_inode *ifsdef;
-
-	_enter("");
-
-	/* prepare an active-inode record for the FSDEF index of this cache */
-	ifsdef = cachefs_iget(super, CACHEFS_INO_FSDEF_CATALOGUE);
-	if (IS_ERR(ifsdef))
-		/* there shouldn't be an error as FSDEF is the root dir of the
-		 * FS and so should already be in core */
-		BUG();
-
-	if (!cachefs_igrab(ifsdef))
-		BUG();
-
-	ifsdef-&gt;cookie = &amp;cachefs_fsdef_index;
-
-	srch-&gt;super	= super;
-	srch-&gt;ino	= CACHEFS_INO_FSDEF_CATALOGUE;
-
-	down_write(&amp;cachefs_addremove_sem);
-
-	/* add the superblock to the list */
-	list_add(&amp;super-&gt;mnt_link, &amp;cachefs_cache_list);
-
-	/* add the cache's netfs definition index inode to the superblock's
-	 * list */
-	spin_lock(&amp;super-&gt;ino_list_lock);
-	list_add_tail(&amp;ifsdef-&gt;super_link, &amp;super-&gt;ino_list);
-	spin_unlock(&amp;super-&gt;ino_list_lock);
-
-	/* add the cache's netfs definition index inode to the top level index
-	 * cookie as a known backing inode */
-	down_write(&amp;cachefs_fsdef_index.sem);
-
-	list_add_tail(&amp;srch-&gt;link, &amp;cachefs_fsdef_index.search_results);
-	list_add_tail(&amp;ifsdef-&gt;cookie_link,
-		      &amp;cachefs_fsdef_index.backing_inodes);
-	atomic_inc(&amp;cachefs_fsdef_index.usage);
-
-	up_write(&amp;cachefs_fsdef_index.sem);
-
-	up_write(&amp;cachefs_addremove_sem);
-
-	_leave("");
-
-} /* end cachefs_add_cache() */
-
-/*****************************************************************************/
-/*
- * withdraw an unmounted cache from the active service
- */
-void cachefs_withdraw_cache(struct cachefs_super *super)
+static struct fscache_node *cachefs_lookup_node(struct fscache_cache *cache,
+						unsigned ino)
 {
+	struct cachefs_super *super;
 	struct cachefs_inode *inode;
 
-	_enter("");
-
-	/* make the cache unavailable for cookie acquisition */
-	set_bit(CACHEFS_SUPER_WITHDRAWN, &amp;super-&gt;flags);
-
-	down_write(&amp;cachefs_addremove_sem);
-	list_del_init(&amp;super-&gt;mnt_link);
-	up_write(&amp;cachefs_addremove_sem);
-
-	/* mark all inodes as being withdrawn */
-	spin_lock(&amp;super-&gt;ino_list_lock);
-	list_for_each_entry(inode, &amp;super-&gt;ino_list, super_link) {
-		set_bit(CACHEFS_ACTIVE_INODE_WITHDRAWN, &amp;inode-&gt;flags);
-	}
-	spin_unlock(&amp;super-&gt;ino_list_lock);
-
-	/* make sure all pages pinned by operations on behalf of the netfs are
-	 * written to disc */
-	cachefs_trans_sync(super, CACHEFS_TRANS_SYNC_WAIT_FOR_ACK);
-
-	/* mark all active blocks as being withdrawn */
-	cachefs_block_withdraw(super);
-
-	/* we now have to destroy all the active inodes pertaining to this
-	 * superblock */
-	spin_lock(&amp;super-&gt;ino_list_lock);
-
-	while (!list_empty(&amp;super-&gt;ino_list)) {
-		inode = list_entry(super-&gt;ino_list.next, struct cachefs_inode,
-				   super_link);
-		list_del(&amp;inode-&gt;super_link);
-		spin_unlock(&amp;super-&gt;ino_list_lock);
-
-		/* we've extracted an active inode from the tree - now dispose
-		 * of it */
-		cachefs_withdraw_inode(inode);
-		cachefs_iput(inode);
-
-		spin_lock(&amp;super-&gt;ino_list_lock);
-	}
-
-	spin_unlock(&amp;super-&gt;ino_list_lock);
-
-	_leave("");
-
-} /* end cachefs_withdraw_cache() */
-
-/*****************************************************************************/
-/*
- * withdraw an inode from active service
- * - need break the links to a cached object cookie
- * - called under two situations:
- *   (1) recycler decides to reclaim an in-use inode
- *   (2) a cache is unmounted
- * - have to take care as the cookie can be being relinquished by the netfs
- *   simultaneously
- * - the active inode is pinned by the caller holding a refcount on it
- */
-void cachefs_withdraw_inode(struct cachefs_inode *inode)
-{
-	struct cachefs_search_result *srch;
-	struct cachefs_cookie *cookie, *xcookie = NULL;
-
-	_enter("{ino=%lu cnt=%u ck=%p}",
-	       inode-&gt;vfs_inode.i_ino, atomic_read(&amp;inode-&gt;vfs_inode.i_count),
-	       inode-&gt;cookie);
-
-	/* first of all we have to break the links between the inode and the
-	 * cookie
-	 * - we have to hold both semaphores BUT we have to get the cookie sem
-	 *   FIRST
-	 */
-	down(&amp;inode-&gt;vfs_inode.i_sem);
-
-	cookie = inode-&gt;cookie;
-	if (cookie) {
-		/* pin the cookie so that is doesn't escape */
-		atomic_inc(&amp;cookie-&gt;usage);
-
-		/* re-order the locks to avoid deadlock */
-		up(&amp;inode-&gt;vfs_inode.i_sem);
-		down_write(&amp;cookie-&gt;sem);
-		down(&amp;inode-&gt;vfs_inode.i_sem);
-
-		/* erase references from the inode to the cookie */
-		list_del_init(&amp;inode-&gt;cookie_link);
-
-		xcookie = inode-&gt;cookie;
-		inode-&gt;cookie = NULL;
-
-		/* delete the search result record for this inode from the
-		 * cookie's list */
-		list_for_each_entry(srch, &amp;cookie-&gt;search_results, link) {
-			if (srch-&gt;super == inode-&gt;vfs_inode.i_sb-&gt;s_fs_info)
-				goto found_record;
-		}
-		BUG();
-
-	found_record:
-		list_del(&amp;srch-&gt;link);
-		dbgfree(srch);
-		kfree(srch);
-
-		up_write(&amp;cookie-&gt;sem);
-	}
-
-	up(&amp;inode-&gt;vfs_inode.i_sem);
-
-	/* we've broken the links between cookie and inode */
-	if (xcookie) {
-		cachefs_cookie_put(xcookie);
-		cachefs_iput(inode);
-	}
-
-	/* unpin the cookie */
-	if (cookie)
-		cachefs_cookie_put(cookie);
-
-	_leave("");
-
-} /* end cachefs_withdraw_inode() */
-
-/*****************************************************************************/
-/*
- * search for representation of an object in its parent cache
- * - the cookie must be locked by the caller
- * - returns -ENODATA if the object or one of its ancestors doesn't exist
- */
-static int cachefs_search_for_object(struct cachefs_cookie *cookie,
-				     struct cachefs_super *super)
-{
-	struct cachefs_search_result *srch;
-	struct cachefs_cookie *iparent;
-	struct cachefs_inode *ipinode, *inode;
-	int ret;
-
-	iparent = cookie-&gt;iparent;
-	if (!iparent)
-		return 0; /* FSDEF entries don't have a parent */
-
-	_enter("{%s/%s},",
-	       iparent-&gt;idef-&gt;name,
-	       cookie-&gt;idef ? (char *) cookie-&gt;idef-&gt;name : "&lt;file&gt;");
-
-	/* see if there's a search result for this object already */
-	list_for_each_entry(srch, &amp;cookie-&gt;search_results, link) {
-		_debug("check entry %p x %p [ino %u]",
-		       cookie, super, srch-&gt;ino);
-
-		if (srch-&gt;super == super) {
-			_debug("found entry");
-
-			if (srch-&gt;ino) {
-				_leave(" = 0 [found ino %u]", srch-&gt;ino);
-				return 0;
-			}
-
-			/* entry is negative */
-			_leave(" = -ENODATA");
-			return -ENODATA;
-		}
-	}
-
-	/* allocate an initially negative entry for this object */
-	_debug("alloc entry %p x %p", cookie, super);
-
-	srch = kmalloc(sizeof(*srch), GFP_KERNEL);
-	if (!srch) {
-		_leave(" = -ENOMEM");
-		return -ENOMEM;
-	}
-
-	memset(srch, 0, sizeof(*srch));
-
-	srch-&gt;super	= super;
-	srch-&gt;ino	= 0;
-	INIT_LIST_HEAD(&amp;srch-&gt;link);
-
- 	/* we need see if there's an entry for this cache in this object's
-	 * parent index, so the first thing to do is to see if the parent index
-	 * is represented on disc
-	 */
-	down_read(&amp;iparent-&gt;sem);
-
-	ret = cachefs_search_for_object(iparent, super);
-	if (ret &lt; 0) {
-		if (ret != -ENODATA)
-			goto error;
-
-		/* set a negative entry */
-		list_add_tail(&amp;srch-&gt;link, &amp;cookie-&gt;search_results);
-		goto done;
-	}
-
-	/* find the parent's backing inode */
-	list_for_each_entry(ipinode, &amp;iparent-&gt;backing_inodes, cookie_link) {
-		if (ipinode-&gt;vfs_inode.i_sb-&gt;s_fs_info == super)
-			goto found_parent_entry;
-	}
-
-	BUG();
-
- found_parent_entry:
-	_debug("found_parent_entry");
-
-	/* search the parent index for a reference compatible with this
-	 * object */
-	ret = cachefs_index_search(ipinode, cookie, NULL, &amp;srch-&gt;ino);
-	switch (ret) {
-	default:
-		goto error;
-
-	case 0:
-		/* found - allocate an inode */
-		inode = cachefs_iget(super, srch-&gt;ino);
-		if (IS_ERR(inode)) {
-			ret = PTR_ERR(inode);
-			goto error;
-		}
-
-		down(&amp;inode-&gt;vfs_inode.i_sem);
-
-		BUG_ON(!list_empty(&amp;inode-&gt;cookie_link));
-
-		/* attach the inode to the superblock's inode list */
-		if (list_empty(&amp;inode-&gt;super_link)) {
-			if (!cachefs_igrab(inode))
-				goto igrab_failed_upput;
-
-			spin_lock(&amp;super-&gt;ino_list_lock);
-			list_add_tail(&amp;inode-&gt;super_link, &amp;super-&gt;ino_list);
-			spin_unlock(&amp;super-&gt;ino_list_lock);
-		}
-
-		/* attach the inode to the cookie */
-		inode-&gt;cookie = cookie;
-		list_add_tail(&amp;srch-&gt;link, &amp;cookie-&gt;search_results);
-		list_add_tail(&amp;inode-&gt;cookie_link, &amp;cookie-&gt;backing_inodes);
-		atomic_inc(&amp;cookie-&gt;usage);
-
-		up(&amp;inode-&gt;vfs_inode.i_sem);
-		break;
-
-	case -ENOENT:
-		/* we can at least set a valid negative entry */
-		list_add_tail(&amp;srch-&gt;link, &amp;cookie-&gt;search_results);
-		ret = -ENODATA;
-		break;
-	}
-
- done:
-	up_read(&amp;iparent-&gt;sem);
-	_leave(" = %d", ret);
-	return ret;
-
- igrab_failed_upput:
-	up(&amp;inode-&gt;vfs_inode.i_sem);
-	cachefs_iput(inode);
-	ret = -ENOENT;
- error:
-	up_read(&amp;iparent-&gt;sem);
-	dbgfree(srch);
-	kfree(srch);
-	_leave(" = %d", ret);
-	return ret;
-
-} /* end cachefs_search_for_object() */
-
-/*****************************************************************************/
-/*
- * instantiate the object in the specified cache
- * - the cookie must be write-locked by the caller
- * - search must have been performed first (so lists of search results are
- *   filled out)
- * - all parent index objects are instantiated if necessary
- */
-static int cachefs_instantiate_object(struct cachefs_cookie *cookie,
-				      struct cachefs_super *super)
-{
-	struct cachefs_search_result *srch;
-	struct cachefs_cookie *iparent;
-	struct cachefs_inode *ipinode, *inode;
-	int ret;
-
-	iparent = cookie-&gt;iparent;
-	if (!iparent)
-		return 0; /* FSDEF entries don't have a parent */
-
-	_enter("{%s/%s},",
-	       iparent-&gt;idef-&gt;name,
-	       cookie-&gt;idef ? (char *) cookie-&gt;idef-&gt;name : "&lt;file&gt;");
-
-	/* find the search result for this object */
-	list_for_each_entry(srch, &amp;cookie-&gt;search_results, link) {
-		if (srch-&gt;super == super)
-			goto found_search_result;
-	}
-
-	BUG();
-
- found_search_result:
-	if (srch-&gt;ino) {
-		/* it was instantiated already */
-		_leave(" = 0 [found ino %u]", srch-&gt;ino);
-		return 0;
-	}
-
-	/* we need to insert an entry for this cache in the object's parent
-	 * index, so the first thing to do is make sure that the parent index
-	 * is represented on disc
-	 */
-	down_write(&amp;iparent-&gt;sem);
-
-	ret = cachefs_instantiate_object(iparent, super);
-	if (ret &lt; 0)
-		goto error;
-
-	/* the parent index's inode should now be available */
-	list_for_each_entry(ipinode, &amp;iparent-&gt;backing_inodes, cookie_link) {
-		if (ipinode-&gt;vfs_inode.i_sb-&gt;s_fs_info == super)
-			goto found_parent_inode;
-	}
-
-	BUG();
-
- found_parent_inode:
-	_debug("found_parent_inode: ino=%lu", ipinode-&gt;vfs_inode.i_ino);
-
-	BUG_ON(ipinode-&gt;cookie != iparent);
+	_enter("%p,%d", cache, ino);
 
-	/* allocate an entry within the parent index inode */
-	ret = cachefs_index_add(ipinode, cookie, &amp;srch-&gt;ino);
-	if (ret &lt; 0)
-		goto error;
+	super = container_of(cache, struct cachefs_super, cache);
 
-	/* we're going to need an in-memory reflection of the inode too */
-	inode = cachefs_iget(super, srch-&gt;ino);
+	inode = cachefs_iget(super, ino);
 	if (IS_ERR(inode)) {
-		ret = PTR_ERR(inode);
-		goto error_x; /* uh-oh... our search record is now wrong */
+		_leave(" = %ld [error]", PTR_ERR(inode));
+		return ERR_PTR(PTR_ERR(inode));
 	}
 
-	/* keep track of it */
-	down(&amp;inode-&gt;vfs_inode.i_sem);
+	_leave(" = %p", &amp;inode-&gt;node);
+	return &amp;inode-&gt;node;
 
-	BUG_ON(!list_empty(&amp;inode-&gt;cookie_link));
-
-	/* attach to the superblock's inode list */
-	if (list_empty(&amp;inode-&gt;super_link)) {
-		if (!cachefs_igrab(inode))
-			goto error_xi;
-
-		spin_lock(&amp;super-&gt;ino_list_lock);
-		list_add_tail(&amp;inode-&gt;super_link, &amp;super-&gt;ino_list);
-		spin_unlock(&amp;super-&gt;ino_list_lock);
-	}
-
-	/* attach to the cookie's search result list */
-	inode-&gt;cookie = cookie;
-	list_add_tail(&amp;inode-&gt;cookie_link, &amp;cookie-&gt;backing_inodes);
-	atomic_inc(&amp;cookie-&gt;usage);
-
-	/* done */
-	up(&amp;inode-&gt;vfs_inode.i_sem);
-	up_write(&amp;iparent-&gt;sem);
-	_leave(" = 0 [new]");
-	return 0;
-
-	/* if we get an error after having instantiated an inode on disc, just
-	 * discard the search record so we find it next time */
- error_xi:
-	up(&amp;inode-&gt;vfs_inode.i_sem);
-	cachefs_iput(inode);
-	ret = -ENOENT;
- error_x:
-	list_del(&amp;srch-&gt;link);
-	dbgfree(srch);
-	kfree(srch);
-	srch = NULL;
- error:
-	up_write(&amp;iparent-&gt;sem);
-	_leave(" = %d", ret);
-	return ret;
-
-} /* end cachefs_instantiate_object() */
+} /* end cachefs_lookup_node() */
 
 /*****************************************************************************/
 /*
- * select a cache on which to store a file
- * - the cache addremove semaphore must be at least read-locked by the caller
+ * increment the usage count on this inode (may fail if unmounting)
  */
-static struct cachefs_super *cachefs_select_cache_for_file(void)
-{
-	struct cachefs_super *super;
-
-	_enter("");
-
-	/* TODO: make more intelligent than just choosing the first cache */
-	super = NULL;
-	if (!list_empty(&amp;cachefs_cache_list))
-		super = list_entry(cachefs_cache_list.next,
-				   struct cachefs_super,
-				   mnt_link);
-
-	_leave(" = %p", super);
-	return super;
-
-} /* end cachefs_select_cache_for_file() */
-
-/*****************************************************************************/
-/*
- * request a cookie to represent a data file or an index
- * - iparent specifies the parent index to pin in memory
- *   - the top level index cookie for each netfs is stored in the cachefs_netfs
- *     struct upon registration
- * - idef is NULL for a data file
- * - idef points to the definition for an index
- * - the netfs_data will be passed to the functions pointed to in *idef
- * - all attached caches will be searched to see if they contain this object
- * - index objects aren't stored on disc until there's a dependent file that
- *   needs storing
- * - file objects are stored in a selected cache immediately, and all the
- *   indexes forming the path to it are instantiated if necessary
- * - we never let on to the netfs about errors
- *   - we may set a negative cookie pointer, but that's okay
- */
-struct cachefs_cookie *__cachefs_acquire_cookie(struct cachefs_cookie *iparent,
-						struct cachefs_index_def *idef,
-						void *netfs_data)
-{
-	struct cachefs_cookie *cookie;
-	struct cachefs_super *super;
-	int ret = 0;
-
-	_enter("{%s},{%s},%p",
-	       iparent ? (char *) iparent-&gt;idef-&gt;name : "&lt;no-parent&gt;",
-	       idef ? (char *) idef-&gt;name : "&lt;file&gt;",
-	       netfs_data);
-
-	/* if it's going to be an index then validate the index data */
-	if (idef) {
-		int dsize;
-		int loop;
-
-		if (!idef-&gt;name[0]) {
-			printk("CacheFS: %s.%s.%p: nameless index\n",
-			       iparent-&gt;netfs-&gt;name,
-			       iparent-&gt;idef-&gt;name,
-			       idef);
-			return CACHEFS_NEGATIVE_COOKIE;
-		}
-
-		dsize = CACHEFS_ONDISC_UJNL_MIN_REC_SIZE -
-			sizeof(struct cachefs_ondisc_update_journal);
-
-		if (idef-&gt;data_size &gt; dsize) {
-			printk("CacheFS: %s.%s.%s:"
-			       " index data size exceeds maximum %u&gt;%d\n",
-			       iparent-&gt;netfs-&gt;name,
-			       iparent-&gt;idef-&gt;name,
-			       idef-&gt;name,
-			       idef-&gt;data_size,
-			       dsize);
-			return CACHEFS_NEGATIVE_COOKIE;
-		}
-
-		for (loop = 0; loop &lt; 4; loop++) {
-			if (idef-&gt;keys[loop].type &gt;=
-			    CACHEFS_INDEX_KEYS__LAST) {
-				printk("CacheFS: %s.%s.%s:"
-				       " index type %u unsupported\n",
-				       iparent-&gt;netfs-&gt;name,
-				       iparent-&gt;idef-&gt;name,
-				       idef-&gt;name,
-				       idef-&gt;keys[loop].type);
-				return CACHEFS_NEGATIVE_COOKIE;
-			}
-
-			dsize -= idef-&gt;keys[loop].len;
-			if (dsize &lt; 0) {
-				printk("CacheFS: %s.%s.%s:"
-				       " index key size exceeds data size\n",
-				       iparent-&gt;netfs-&gt;name,
-				       iparent-&gt;idef-&gt;name,
-				       idef-&gt;name);
-				return CACHEFS_NEGATIVE_COOKIE;
-			}
-		}
-	}
-
-	/* if there's no parent cookie, then we don't create one here either */
-	if (iparent == CACHEFS_NEGATIVE_COOKIE) {
-		_leave(" [no parent]");
-		return CACHEFS_NEGATIVE_COOKIE;
-	}
-
-	/* allocate and initialise a cookie */
-	cookie = kmem_cache_alloc(cachefs_cookie_jar, SLAB_KERNEL);
-	if (!cookie) {
-		_leave(" [ENOMEM]");
-		return CACHEFS_NEGATIVE_COOKIE;
-	}
-
-	atomic_set(&amp;cookie-&gt;usage, 1);
-	atomic_set(&amp;cookie-&gt;children, 0);
-
-	atomic_inc(&amp;iparent-&gt;usage);
-	atomic_inc(&amp;iparent-&gt;children);
-
-	cookie-&gt;idef		= idef;
-	cookie-&gt;iparent		= iparent;
-	cookie-&gt;netfs		= iparent-&gt;netfs;
-	cookie-&gt;netfs_data	= netfs_data;
-
-	/* now we need to see whether the backing objects for this cookie yet
-	 * exist, if not there'll be nothing to search */
-	down_read(&amp;cachefs_addremove_sem);
-
-	if (list_empty(&amp;cachefs_cache_list)) {
-		up_read(&amp;cachefs_addremove_sem);
-		_leave(" [no caches]");
-		return cookie;
-	}
-
-	down_write(&amp;cookie-&gt;sem);
-
-	/* search every cache we know about to see if the object is already
-	 * present */
-	list_for_each_entry(super, &amp;cachefs_cache_list, mnt_link) {
-		ret = cachefs_search_for_object(cookie, super);
-		switch (ret) {
-		case 0:
-			if (!cookie-&gt;idef)
-				break;	/* only want the first file entry */
-		case -ENODATA:
-			ret = 0;
-			continue;
-		default:
-			goto error;
-		}
-	}
-
-	/* if the object is a cookie then we need do nothing more here - we
-	 * create indexes on disc when we need them as an index may exist in
-	 * multiple caches */
-	if (cookie-&gt;idef)
-		goto done;
-
-	/* the object is a file - we need to select a cache in which to store
-	 * it */
-	ret = -ENOMEDIUM;
-	super = cachefs_select_cache_for_file();
-	if (!super)
-		goto error; /* couldn't decide on a cache */
-
-	/* create a file index entry on disc, along with all the indexes
-	 * required to find it again later */
-	ret = cachefs_instantiate_object(cookie, super);
-	if (ret == 0)
-		goto done;
-
- error:
-	printk("CacheFS: error from cache fs: %d\n", ret);
-	if (cookie) {
-		__cachefs_cookie_put(cookie);
-		cookie = CACHEFS_NEGATIVE_COOKIE;
-		atomic_dec(&amp;iparent-&gt;children);
-	}
-
- done:
-	up_write(&amp;cookie-&gt;sem);
-	up_read(&amp;cachefs_addremove_sem);
-	_leave(" = %p", cookie);
-	return cookie;
-
-} /* end __cachefs_acquire_cookie() */
-
-EXPORT_SYMBOL(__cachefs_acquire_cookie);
-
-/*****************************************************************************/
-/*
- * release a cookie back to the cache
- * - the object will be marked as recyclable on disc if retire is true
- * - all dependents of this cookie must have already been unregistered
- *   (indexes/files/pages)
- */
-void __cachefs_relinquish_cookie(struct cachefs_cookie *cookie, int retire)
+static struct fscache_node *cachefs_grab_node(struct fscache_node *node)
 {
 	struct cachefs_inode *inode;
+	struct fscache_node *ret;
 
-	_enter("%p{%s},%d",
-	       cookie,
-	       cookie &amp;&amp; cookie-&gt;idef ? (char *) cookie-&gt;idef-&gt;name : "&lt;file&gt;",
-	       retire);
-
-	if (cookie == CACHEFS_NEGATIVE_COOKIE) {
-		_leave(" [no cookie]");
-		return;
-	}
+	_enter("%p", node);
 
-	if (atomic_read(&amp;cookie-&gt;children) != 0) {
-		printk("CacheFS: cookie still has children\n");
-		BUG();
-	}
+	inode = container_of(node, struct cachefs_inode, node);
+	inode = cachefs_igrab(inode);
+	ret = (inode ? &amp;inode-&gt;node : NULL);
 
-	/* detach pointers back to netfs */
-	down_write(&amp;cookie-&gt;sem);
-
-	cookie-&gt;netfs_data	= NULL;
-	cookie-&gt;idef		= NULL;
-
-	/* queue retired objects for recycling */
-	if (retire) {
-		list_for_each_entry(inode,
-				    &amp;cookie-&gt;backing_inodes,
-				    cookie_link) {
-			set_bit(CACHEFS_ACTIVE_INODE_RECYCLING, &amp;inode-&gt;flags);
-		}
-	}
-
-	/* break links with all the active inodes */
-	while (!list_empty(&amp;cookie-&gt;backing_inodes)) {
-		inode = list_entry(cookie-&gt;backing_inodes.next,
-				   struct cachefs_inode,
-				   cookie_link);
-
-		/* detach each cache inode from the object cookie */
-		set_bit(CACHEFS_ACTIVE_INODE_RELEASING, &amp;inode-&gt;flags);
-
-		list_del_init(&amp;inode-&gt;cookie_link);
-
-		down(&amp;inode-&gt;vfs_inode.i_sem);
-		inode-&gt;cookie = NULL;
-		up(&amp;inode-&gt;vfs_inode.i_sem);
-
-		if (atomic_dec_and_test(&amp;cookie-&gt;usage))
-			/* the cookie refcount shouldn't be reduced to 0 yet */
-			BUG();
-
-		cachefs_iput(inode);
-	}
-
-	up_write(&amp;cookie-&gt;sem);
-
-	if (cookie-&gt;iparent)
-		atomic_dec(&amp;cookie-&gt;iparent-&gt;children);
-
-	/* finally dispose of the cookie */
-	cachefs_cookie_put(cookie);
-
-	_leave("");
-
-} /* end __cachefs_relinquish_cookie() */
+	_leave(" = %p", ret);
+	return ret;
 
-EXPORT_SYMBOL(__cachefs_relinquish_cookie);
+} /* end cachefs_grab_node() */
 
 /*****************************************************************************/
 /*
- * update the index entries backing a cookie
+ * lock a semaphore on a node
  */
-void __cachefs_update_cookie(struct cachefs_cookie *cookie)
+static void cachefs_lock_node(struct fscache_node *node)
 {
 	struct cachefs_inode *inode;
 
-	_enter("{%s}",
-	       cookie &amp;&amp;
-	       cookie-&gt;idef ? (char *) cookie-&gt;idef-&gt;name : "&lt;file&gt;");
-
-	if (cookie == CACHEFS_NEGATIVE_COOKIE) {
-		_leave(" [no cookie]");
-		return;
-	}
-
-	down_read(&amp;cookie-&gt;sem);
-	down_read(&amp;cookie-&gt;iparent-&gt;sem);
-
-	/* update the index entry on disc in each cache backing this cookie */
-	list_for_each_entry(inode, &amp;cookie-&gt;backing_inodes, cookie_link) {
-		cachefs_index_update(inode);
-	}
-
-	up_read(&amp;cookie-&gt;iparent-&gt;sem);
-	up_read(&amp;cookie-&gt;sem);
-	_leave("");
-
-} /* end __cachefs_update_cookie() */
-
-EXPORT_SYMBOL(__cachefs_update_cookie);
-
-/*****************************************************************************/
-/*
- * see if the netfs definition matches
- */
-static cachefs_match_val_t cachefs_fsdef_index_match(void *target,
-						     const void *entry)
-{
-	const struct cachefs_ondisc_fsdef *fsdef = entry;
-	struct cachefs_netfs *netfs = target;
+	_enter("%p", node);
 
-	_enter("%p,%p", target, entry);
-
-	/* name and version must both match with what's on disc */
-	_debug("{%s.%u},{%s.%u}",
-	       netfs-&gt;name, netfs-&gt;version, fsdef-&gt;name, fsdef-&gt;version);
-
-	if (strncmp(netfs-&gt;name, fsdef-&gt;name, sizeof(fsdef-&gt;name)) != 0) {
-		_leave(" = FAILED");
-		return CACHEFS_MATCH_FAILED;
-	}
-
-	if (netfs-&gt;version == fsdef-&gt;version) {
-		_leave(" = SUCCESS");
-		return CACHEFS_MATCH_SUCCESS;
-	}
-
-	/* an entry of the same name but different version is scheduled for
-	 * deletion */
-	_leave(" = SUCCESS_DELETE");
-	return CACHEFS_MATCH_SUCCESS_DELETE;
+	inode = container_of(node, struct cachefs_inode, node);
+	down(&amp;inode-&gt;vfs_inode.i_sem);
 
-} /* end cachefs_fsdef_index_match() */
+} /* end cachefs_lock_node() */
 
 /*****************************************************************************/
 /*
- * update the netfs definition to be stored on disc
+ * unlock a semaphore on a node
  */
-static void cachefs_fsdef_index_update(void *source, void *entry)
+static void cachefs_unlock_node(struct fscache_node *node)
 {
-	struct cachefs_ondisc_fsdef *fsdef = entry;
-	struct cachefs_netfs *netfs = source;
-
-	_enter("{%s.%u},", netfs-&gt;name, netfs-&gt;version);
+	struct cachefs_inode *inode;
 
-	/* install the netfs name and version in the top-level index entry */
-	strncpy(fsdef-&gt;name, netfs-&gt;name, sizeof(fsdef-&gt;name));
+	_enter("%p", node);
 
-	fsdef-&gt;version = netfs-&gt;version;
+	inode = container_of(node, struct cachefs_inode, node);
+	up(&amp;inode-&gt;vfs_inode.i_sem);
 
-} /* end cachefs_fsdef_index_update() */
+} /* end cachefs_unlock_node() */
 
 /*****************************************************************************/
 /*
- * destroy a cookie
+ * dispose of a reference to a node
  */
-static void __cachefs_cookie_put(struct cachefs_cookie *cookie)
+static void cachefs_put_node(struct fscache_node *node)
 {
-	struct cachefs_search_result *srch;
+	_enter("%p", node);
 
-	_enter("%p", cookie);
+	if (node)
+		cachefs_iput(container_of(node, struct cachefs_inode, node));
 
-	if (cookie-&gt;iparent)
-		cachefs_cookie_put(cookie-&gt;iparent);
-
-	/* dispose of any cached search results */
-	while (!list_empty(&amp;cookie-&gt;search_results)) {
-		srch = list_entry(cookie-&gt;search_results.next,
-				  struct cachefs_search_result,
-				  link);
-
-		list_del(&amp;srch-&gt;link);
-		kfree(srch);
-	}
-
-	BUG_ON(!list_empty(&amp;cookie-&gt;search_results));
-	BUG_ON(!list_empty(&amp;cookie-&gt;backing_inodes));
-	kmem_cache_free(cachefs_cookie_jar, cookie);
-
-	_leave("");
-
-} /* end __cachefs_cookie_put() */
+} /* end cachefs_put_node() */
 
 /*****************************************************************************/
 /*
- * initialise an cookie jar slab element prior to any use
+ * sync a cache
  */
-void cachefs_cookie_init_once(void *_cookie, kmem_cache_t *cachep,
-			      unsigned long flags)
+static void cachefs_sync(struct fscache_cache *cache)
 {
-	struct cachefs_cookie *cookie = _cookie;
+	_enter("%p", cache);
 
-	if ((flags &amp; (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-	    SLAB_CTOR_CONSTRUCTOR) {
-		memset(cookie, 0, sizeof(*cookie));
-		INIT_LIST_HEAD(&amp;cookie-&gt;search_results);
-		INIT_LIST_HEAD(&amp;cookie-&gt;backing_inodes);
-		init_rwsem(&amp;cookie-&gt;sem);
-	}
+	/* make sure all pages pinned by operations on behalf of the netfs are
+	 * written to disc */
+	cachefs_trans_sync(container_of(cache, struct cachefs_super, cache),
+			   CACHEFS_TRANS_SYNC_WAIT_FOR_ACK);
 
-} /* end cachefs_cookie_init_once() */
+} /* end cachefs_sync() */
 
 /*****************************************************************************/
 /*
@@ -1042,9 +164,7 @@ static int cachefs_page_read_endio(struc
 /*****************************************************************************/
 /*
  * read a page from the cache or allocate a block in which to store it
- * - if the cookie is not backed by a file:
- *   - -ENOBUFS will be returned and nothing more will be done
- * - else if the page is backed by a block in the cache:
+ * - if the page is backed by a block in the cache:
  *   - a read will be started which will call end_io_func on completion
  *   - the wb-journal will be searched for an entry pertaining to this block
  *     - if an entry is found:
@@ -1056,44 +176,22 @@ static int cachefs_page_read_endio(struc
  *   - the v-journal will be marked to note the block contains invalid data
  *   - -ENODATA will be returned
  */
-int __cachefs_read_or_alloc_page(struct cachefs_cookie *cookie,
-				 struct page *page,
-				 cachefs_rw_complete_t end_io_func,
-				 void *end_io_data,
-				 unsigned long gfp)
+static int cachefs_read_or_alloc_page(struct fscache_node *node,
+				      struct page *page,
+				      struct fscache_page *pageio,
+				      fscache_rw_complete_t end_io_func,
+				      void *end_io_data,
+				      unsigned long gfp)
 {
 	struct cachefs_io_end *end_io = NULL;
 	struct cachefs_inode *inode;
-	struct cachefs_block *block;
-	struct cachefs_page *pageio;
+	struct cachefs_block *block = NULL;
 	struct bio *bio = NULL;
 	int ret;
 
-	_enter("%p,{%lu},", cookie, page-&gt;index);
-
-	if (cookie == CACHEFS_NEGATIVE_COOKIE) {
-		_leave(" -ENOBUFS [no cookie]");
-		return -ENOBUFS; /* no actual cookie */
-	}
-
-	BUG_ON(cookie-&gt;idef); /* not supposed to use this for indexes */
-
-	/* get the cache-cookie for this page */
-	pageio = cookie-&gt;netfs-&gt;ops-&gt;get_page_cookie(page);
-	if (IS_ERR(pageio)) {
-		_leave(" = %ld", PTR_ERR(pageio));
-		return PTR_ERR(pageio);
-	}
-
-	/* prevent the file from being uncached whilst we access it */
-	block = NULL;
-	down_read(&amp;cookie-&gt;sem);
+	_enter("");
 
-	/* if there's no disc space whatsoever backing this file, then leave
-	 * now */
-	ret = -ENOBUFS;
-	if (list_empty(&amp;cookie-&gt;backing_inodes))
-		goto error;
+	inode = container_of(node, struct cachefs_inode, node);
 
 	/* handle the case of there already being a mapping,
 	 * - must protect against cache removal
@@ -1102,22 +200,14 @@ int __cachefs_read_or_alloc_page(struct 
 	read_lock(&amp;pageio-&gt;lock);
 
 	block = pageio-&gt;mapped_block;
-	if (block &amp;&amp; !test_bit(CACHEFS_SUPER_WITHDRAWN, &amp;block-&gt;super-&gt;flags))
+	if (block &amp;&amp; !fscache_is_cache_withdrawn(&amp;block-&gt;super-&gt;cache))
 		goto available_on_disc; /* already mapped */
 
 	read_unlock(&amp;pageio-&gt;lock);
 	block = NULL;
 
 	/* we don't know of a backing page, but there may be one recorded on
-	 * disc... and if there isn't we'll request one be allocated */
-	_debug("igrab");
-	inode = cachefs_igrab(list_entry(cookie-&gt;backing_inodes.next,
-					 struct cachefs_inode,
-					 cookie_link));
-	ret = -ENOBUFS;
-	if (!inode)
-		goto error;
-
+	 * disc... and if there isn't we'll request that one be allocated */
 	_debug("get block");
 	down(&amp;inode-&gt;vfs_inode.i_sem);
 
@@ -1127,13 +217,13 @@ int __cachefs_read_or_alloc_page(struct 
 	if (ret &lt; 0)
 		goto error_i;
 
-	if (!test_and_clear_bit(CACHEFS_PAGE_NEW, &amp;pageio-&gt;flags)) {
+	if (!test_and_clear_bit(FSCACHE_PAGE_NEW, &amp;pageio-&gt;flags)) {
 		/* there was data - pin the block underlying it and read */
 		read_lock(&amp;pageio-&gt;lock);
 
 		block = pageio-&gt;mapped_block;
 		if (block &amp;&amp;
-		    !test_bit(CACHEFS_SUPER_WITHDRAWN, &amp;block-&gt;super-&gt;flags))
+		    !fscache_is_cache_withdrawn(&amp;block-&gt;super-&gt;cache))
 			goto available_on_disc_i;
 
 		/* it went out of service for some reason */
@@ -1145,15 +235,13 @@ int __cachefs_read_or_alloc_page(struct 
 
 	/* we allocated a new block, but didn't assign any data to it */
 	up(&amp;inode-&gt;vfs_inode.i_sem);
-	cachefs_iput(inode);
 
 	/* point the mapped block at its referencer */
-	write_lock(&amp;pageio-&gt;mapped_block-&gt;ref_lock);
-	pageio-&gt;mapped_block-&gt;ref = pageio;
-	write_unlock(&amp;pageio-&gt;mapped_block-&gt;ref_lock);
+	write_lock(&amp;cachefs_mapped_block(pageio)-&gt;ref_lock);
+	cachefs_mapped_block(pageio)-&gt;ref = pageio;
+	write_unlock(&amp;cachefs_mapped_block(pageio)-&gt;ref_lock);
 
-	_debug("no data [bix=%u ref=%p]", pageio-&gt;mapped_block-&gt;bix, pageio);
-	up_read(&amp;cookie-&gt;sem);
+	_debug("no data [bix=%u ref=%p]", cachefs_mapped_bix(pageio), pageio);
 
 	/* tell the caller we've allocated a block, but we don't have any data
 	 * for them */
@@ -1165,7 +253,6 @@ int __cachefs_read_or_alloc_page(struct 
  available_on_disc_i:
 	_debug("available_i");
 	up(&amp;inode-&gt;vfs_inode.i_sem);
-	cachefs_iput(inode);
 
  available_on_disc:
 	_debug("available");
@@ -1184,7 +271,7 @@ int __cachefs_read_or_alloc_page(struct 
 
 	end_io-&gt;func		= end_io_func;
 	end_io-&gt;data		= end_io_data;
-	end_io-&gt;cookie_data	= cookie-&gt;netfs_data;
+	end_io-&gt;cookie_data	= node-&gt;cookie-&gt;netfs_data;
 	end_io-&gt;block		= block;
 
 	/* dispatch an operation to the block device */
@@ -1205,7 +292,6 @@ int __cachefs_read_or_alloc_page(struct 
 	submit_bio(READ, bio);
 
 	_debug("done");
-	up_read(&amp;cookie-&gt;sem);
 
 	/* point the mapped block at its referencer */
 	write_lock(&amp;block-&gt;ref_lock);
@@ -1223,10 +309,8 @@ int __cachefs_read_or_alloc_page(struct 
  error_i:
 	_debug("error_i");
 	up(&amp;inode-&gt;vfs_inode.i_sem);
-	cachefs_iput(inode);
  error:
 	_debug("error");
-	up_read(&amp;cookie-&gt;sem);
 	cachefs_block_put(block);
 	if (bio)
 		bio_put(bio);
@@ -1237,9 +321,7 @@ int __cachefs_read_or_alloc_page(struct 
 	_leave(" = %d", ret);
 	return ret;
 
-} /* end __cachefs_read_or_alloc_page() */
-
-EXPORT_SYMBOL(__cachefs_read_or_alloc_page);
+} /* end cachefs_read_or_alloc_page() */
 
 /*****************************************************************************/
 /*
@@ -1300,41 +382,25 @@ static int cachefs_page_written(struct b
  *     be erased
  *   - returns 0
  */
-int __cachefs_write_page(struct cachefs_cookie *cookie,
-			 struct page *page,
-			 cachefs_rw_complete_t end_io_func,
-			 void *end_io_data,
-			 unsigned long gfp)
+static int cachefs_write_page(struct fscache_node *node,
+			      struct page *page,
+			      struct fscache_page *pageio,
+			      fscache_rw_complete_t end_io_func,
+			      void *end_io_data,
+			      unsigned long gfp)
 {
 	struct cachefs_io_end *end_io = NULL;
 	struct cachefs_block *block;
-	struct cachefs_page *pageio;
 	struct bio *bio = NULL;
 	int ret;
 
-	_enter("%p,{%lu},", cookie, page-&gt;index);
-
-	if (cookie == CACHEFS_NEGATIVE_COOKIE) {
-		_leave(" -ENOBUFS [no cookie]");
-		return -ENOBUFS; /* no actual cookie */
-	}
-
-	BUG_ON(cookie-&gt;idef); /* not supposed to use this for indexes */
-
-	/* get the cache-cookie for this page */
-	pageio = cookie-&gt;netfs-&gt;ops-&gt;get_page_cookie(page);
-	if (IS_ERR(pageio)) {
-		_leave(" = %ld", PTR_ERR(pageio));
-		return PTR_ERR(pageio);
-	}
+	_enter("");
 
-	/* prevent the file from been uncached whilst we deal with it */
-	down_read(&amp;cookie-&gt;sem);
 	read_lock(&amp;pageio-&gt;lock);
 
 	/* only write if there's somewhere to write to */
-	block = pageio-&gt;mapped_block;
-	if (!block || test_bit(CACHEFS_SUPER_WITHDRAWN, &amp;block-&gt;super-&gt;flags))
+	block = cachefs_mapped_block(pageio);
+	if (!block || fscache_is_cache_withdrawn(&amp;block-&gt;super-&gt;cache))
 		goto no_block;
 
 	/* pin the block and drop the lock */
@@ -1352,7 +418,7 @@ int __cachefs_write_page(struct cachefs_
 
 	end_io-&gt;func		= end_io_func;
 	end_io-&gt;data		= end_io_data;
-	end_io-&gt;cookie_data	= cookie-&gt;netfs_data;
+	end_io-&gt;cookie_data	= node-&gt;cookie-&gt;netfs_data;
 	end_io-&gt;block		= block;
 
 	/* dispatch an operation to the block device */
@@ -1373,11 +439,10 @@ int __cachefs_write_page(struct cachefs_
 	if (!bio_add_page(bio, page, PAGE_SIZE, 0))
 		BUG();
 
-	//dump_bio(bio,1);
+	//dump_bio(bio, 1);
 	submit_bio(WRITE, bio);
 
 	/* tell the caller it's in progress */
-	up_read(&amp;cookie-&gt;sem);
 	_leave(" = 0");
 	return 0;
 
@@ -1386,7 +451,6 @@ int __cachefs_write_page(struct cachefs_
 	clear_bit(CACHEFS_BLOCK_NETFSBUSY, &amp;block-&gt;flags);
 	wake_up(&amp;block-&gt;writewq);
 	cachefs_block_put(block);
-	up_read(&amp;cookie-&gt;sem);
 	if (bio)
 		bio_put(bio);
 	if (end_io) {
@@ -1399,40 +463,23 @@ int __cachefs_write_page(struct cachefs_
 	/* tell the caller there wasn't a block to write into */
  no_block:
 	read_unlock(&amp;pageio-&gt;lock);
-	up_read(&amp;cookie-&gt;sem);
 	_leave(" = -ENOBUFS");
 	return -ENOBUFS;
 
-} /* end __cachefs_write_page() */
-
-EXPORT_SYMBOL(__cachefs_write_page);
+} /* end cachefs_write_page() */
 
 /*****************************************************************************/
 /*
- * remove a page from the cache
+ * detach a backing block from a page
  * - if the block backing the page still has a vjentry then the block will be
  *   recycled
  */
-void __cachefs_uncache_page(struct cachefs_cookie *cookie, struct page *page)
+static void cachefs_uncache_page(struct fscache_node *node,
+				 struct fscache_page *pageio)
 {
 	struct cachefs_block *block, *xblock;
-	struct cachefs_page *pageio;
-
-	_enter(",{%lu}", page-&gt;index);
-
-	if (cookie == CACHEFS_NEGATIVE_COOKIE) {
-		_leave(" [no cookie]");
-		return;
-	}
 
-	BUG_ON(cookie-&gt;idef); /* not supposed to use this for indexes */
-
-	/* get the cache-cookie for this page */
-	pageio = cookie-&gt;netfs-&gt;ops-&gt;get_page_cookie(page);
-	if (IS_ERR(pageio)) {
-		_leave(" [get_page_cookie() = %ld]", PTR_ERR(pageio));
-		return;
-	}
+	_enter("");
 
 	/* un-cross-link the page cookie and the block */
 	xblock = NULL;
@@ -1466,8 +513,22 @@ void __cachefs_uncache_page(struct cache
 	}
 
 	_leave("");
-	return;
 
-} /* end __cachefs_uncache_page() */
+} /* end cachefs_uncache_page() */
 
-EXPORT_SYMBOL(__cachefs_uncache_page);
+struct fscache_cache_ops cachefs_cache_ops = {
+	.name			= "cachefs",
+	.lookup_node		= cachefs_lookup_node,
+	.grab_node		= cachefs_grab_node,
+	.lock_node		= cachefs_lock_node,
+	.unlock_node		= cachefs_unlock_node,
+	.put_node		= cachefs_put_node,
+	.index_search		= cachefs_index_search,
+	.index_add		= cachefs_index_add,
+	.index_update		= cachefs_index_update,
+	.sync			= cachefs_sync,
+	.dissociate_pages	= cachefs_block_dissociate,
+	.read_or_alloc_page	= cachefs_read_or_alloc_page,
+	.write_page		= cachefs_write_page,
+	.uncache_page		= cachefs_uncache_page,
+};
diff -puN fs/cachefs/journal.c~turn-cachefs-into-a-cache-backend fs/cachefs/journal.c
--- 25/fs/cachefs/journal.c~turn-cachefs-into-a-cache-backend	Wed Oct  6 16:03:22 2004
+++ 25-akpm/fs/cachefs/journal.c	Wed Oct  6 16:03:22 2004
@@ -430,7 +430,7 @@ int cachefs_trans_mark(struct cachefs_tr
 	offset = (trans-&gt;index &lt;&lt; super-&gt;sb-&gt;s_blocksize_bits) &amp; ~PAGE_MASK;
 	jentry = kmap_atomic(trans-&gt;jpage, KM_USER0) + offset;
 	memcpy(jentry, trans-&gt;jentry, super-&gt;sb-&gt;s_blocksize);
-	kunmap_atomic(trans-&gt;jpage, KM_USER0);
+	kunmap_atomic(jentry, KM_USER0);
 
 	SetPageWriteback(trans-&gt;jpage);
 
@@ -1678,11 +1678,11 @@ static int cachefs_ujnl_barrier_cap_chec
 					    unsigned int bytes_done,
 					    int error)
 {
-	kenter("%p{%lx},%u,%d", bio, bio-&gt;bi_flags, bytes_done, error);
+	_enter("%p{%lx},%u,%d", bio, bio-&gt;bi_flags, bytes_done, error);
 
 	/* we're only interested in completion */
 	if (bio-&gt;bi_size &gt; 0) {
-		kleave(" = 1");
+		_leave(" = 1");
 		return 1;
 	}
 
@@ -1690,7 +1690,7 @@ static int cachefs_ujnl_barrier_cap_chec
 	end_page_writeback(bio-&gt;bi_io_vec[0].bv_page);
 
 	bio_put(bio);
-	kleave(" = 0");
+	_leave(" = 0");
 	return 0;
 
 } /* end cachefs_trans_ack_written() */
diff -puN fs/cachefs/linear-io.c~turn-cachefs-into-a-cache-backend fs/cachefs/linear-io.c
--- 25/fs/cachefs/linear-io.c~turn-cachefs-into-a-cache-backend	Wed Oct  6 16:03:22 2004
+++ 25-akpm/fs/cachefs/linear-io.c	Wed Oct  6 16:03:22 2004
@@ -57,14 +57,14 @@ static int cachefs_linear_io_do_readpage
 					 cachefs_blockix_t *last_block_in_bio)
 {
 	struct cachefs_block *block;
-	struct cachefs_page *pageio;
+	struct fscache_page *pageio;
 	struct inode *inode = page-&gt;mapping-&gt;host;
 	int ret;
 
 	_enter("");
 
 	/* get the page mapping cookie */
-	pageio = cachefs_page_get_private(page, GFP_KERNEL);
+	pageio = fscache_page_get_private(page, GFP_KERNEL);
 	if (IS_ERR(pageio)) {
 		ret = PTR_ERR(pageio);
 		goto error;
@@ -176,7 +176,7 @@ int cachefs_linear_io_readpages(struct f
 int cachefs_linear_io_readpage(struct file *file, struct page *page)
 {
 	struct cachefs_block *block;
-	struct cachefs_page *pageio;
+	struct fscache_page *pageio;
 	struct inode *inode = page-&gt;mapping-&gt;host;
 	struct bio *bio;
 	int ret;
@@ -184,7 +184,7 @@ int cachefs_linear_io_readpage(struct fi
 	_enter(",{%lu}", page-&gt;index);
 
 	/* get the page mapping cookie */
-	pageio = cachefs_page_get_private(page, GFP_KERNEL);
+	pageio = fscache_page_get_private(page, GFP_KERNEL);
 	if (IS_ERR(pageio)) {
 		_leave(" = %ld [pgp]", PTR_ERR(pageio));
 		return PTR_ERR(pageio);
diff -puN fs/cachefs/main.c~turn-cachefs-into-a-cache-backend fs/cachefs/main.c
--- 25/fs/cachefs/main.c~turn-cachefs-into-a-cache-backend	Wed Oct  6 16:03:22 2004
+++ 25-akpm/fs/cachefs/main.c	Wed Oct  6 16:03:22 2004
@@ -36,21 +36,8 @@ static int cachefs_init(void)
 {
 	int ret;
 
-	/* create ourselves a cookie jar and a block jar */
+	/* create a block jar */
 	ret = -ENOMEM;
-	cachefs_cookie_jar =
-		kmem_cache_create("cachefs_cookie_jar",
-				  sizeof(struct cachefs_cookie),
-				  0,
-				  SLAB_HWCACHE_ALIGN,
-				  cachefs_cookie_init_once,
-				  NULL);
-	if (!cachefs_cookie_jar) {
-		printk(KERN_NOTICE
-		       "CacheFS: Failed to allocate a cookie jar\n");
-		goto error;
-	}
-
 	cachefs_block_jar =
 		kmem_cache_create("cachefs_block_jar",
 				  sizeof(struct cachefs_block),
@@ -61,7 +48,7 @@ static int cachefs_init(void)
 	if (!cachefs_block_jar) {
 		printk(KERN_NOTICE
 		       "CacheFS: Failed to allocate a block jar\n");
-		goto error_cookie_jar;
+		goto error;
 	}
 
 	/* initialise the filesystem */
@@ -75,8 +62,6 @@ static int cachefs_init(void)
 
  error_block_jar:
 	kmem_cache_destroy(cachefs_block_jar);
- error_cookie_jar:
-	kmem_cache_destroy(cachefs_cookie_jar);
  error:
 	printk(KERN_ERR "CacheFS: failed to register: %d\n", ret);
 	return ret;
@@ -92,7 +77,6 @@ static void __exit cachefs_exit(void)
 
 	cachefs_fs_exit();
 	kmem_cache_destroy(cachefs_block_jar);
-	kmem_cache_destroy(cachefs_cookie_jar);
 
 } /* end cachefs_exit() */
 
diff -puN fs/cachefs/misc.c~turn-cachefs-into-a-cache-backend fs/cachefs/misc.c
--- 25/fs/cachefs/misc.c~turn-cachefs-into-a-cache-backend	Wed Oct  6 16:03:22 2004
+++ 25-akpm/fs/cachefs/misc.c	Wed Oct  6 16:03:22 2004
@@ -30,10 +30,10 @@
  * get a page caching token from for a page, allocating it and attaching it to
  * the page's private pointer if it doesn't exist
  */
-struct cachefs_page * __cachefs_page_get_private(struct page *page,
+struct fscache_page * __cachefs_page_get_private(struct page *page,
 						 unsigned gfp_flags)
 {
-	struct cachefs_page *pageio = (struct cachefs_page *) page-&gt;private;
+	struct fscache_page *pageio = (struct fscache_page *) page-&gt;private;
 
 	if (!pageio) {
 		pageio = kmalloc(sizeof(*pageio), gfp_flags);
@@ -145,7 +145,7 @@ int cachefs_sync_page(struct page *page)
  */
 int cachefs_invalidatepage(struct page *page, unsigned long offset)
 {
-	struct cachefs_page *pageio;
+	struct fscache_page *pageio;
 	int ret = 1;
 
 	_enter("{%lu},%lu", page-&gt;index, offset);
@@ -153,7 +153,7 @@ int cachefs_invalidatepage(struct page *
 	BUG_ON(!PageLocked(page));
 
 	if (PagePrivate(page)) {
-		pageio = (struct cachefs_page *) page-&gt;private;
+		pageio = (struct fscache_page *) page-&gt;private;
 		pageio-&gt;flags = 0;
 
 		/* we release page attachments only if the entire page is being
@@ -179,14 +179,14 @@ int cachefs_invalidatepage(struct page *
 int cachefs_releasepage(struct page *page, int gfp_flags)
 {
 	struct cachefs_block *block;
-	struct cachefs_page *pageio;
+	struct fscache_page *pageio;
 
 	_enter("{%lu},%x", page-&gt;index, gfp_flags);
 
 	/* detach the page mapping cookie and mapped block */
 	if (PagePrivate(page)) {
 		/* detach the mapped block from the page if there is one */
-		pageio = (struct cachefs_page *) page-&gt;private;
+		pageio = (struct fscache_page *) page-&gt;private;
 		page-&gt;private = 0;
 		ClearPagePrivate(page);
 
diff -puN fs/cachefs/recycling.c~turn-cachefs-into-a-cache-backend fs/cachefs/recycling.c
--- 25/fs/cachefs/recycling.c~turn-cachefs-into-a-cache-backend	Wed Oct  6 16:03:22 2004
+++ 25-akpm/fs/cachefs/recycling.c	Wed Oct  6 16:03:22 2004
@@ -561,7 +561,7 @@ static int cachefs_recycle_reclaim_inode
 		cachefs_metadata_postread(iinode, metadata);
 
 		cachefs_trans_affects_page(trans,
-					   cachefs_page_grab_private(ixpage),
+					   fscache_page_grab_private(ixpage),
 					   trans-&gt;jentry-&gt;entry,
 					   trans-&gt;jentry-&gt;count);
 
diff -puN fs/cachefs/replay.c~turn-cachefs-into-a-cache-backend fs/cachefs/replay.c
--- 25/fs/cachefs/replay.c~turn-cachefs-into-a-cache-backend	Wed Oct  6 16:03:22 2004
+++ 25-akpm/fs/cachefs/replay.c	Wed Oct  6 16:03:22 2004
@@ -1638,7 +1638,7 @@ static int cachefs_replay_ujnl_data_unal
 
 			cachefs_trans_replays_effect(trans, ptrblock, "ptr");
 		}
-		kunmap_atomic(ptrpage, KM_USER0);
+		kunmap_atomic(pbix, KM_USER0);
 	}
 
 	/* make sure the vjournal entry is cleared */
diff -puN fs/cachefs/rootdir.c~turn-cachefs-into-a-cache-backend fs/cachefs/rootdir.c
--- 25/fs/cachefs/rootdir.c~turn-cachefs-into-a-cache-backend	Wed Oct  6 16:03:22 2004
+++ 25-akpm/fs/cachefs/rootdir.c	Wed Oct  6 16:03:22 2004
@@ -70,6 +70,7 @@ int cachefs_readdir_actor_cons_name(stru
 {
 	unsigned char *ptr;
 	unsigned long tmp;
+	unsigned nsize;
 	char *name;
 	int ksize, loop;
 
@@ -89,10 +90,38 @@ int cachefs_readdir_actor_cons_name(stru
 		/* add in the appropriate bit of key */
 		switch (rec-&gt;keys[loop] &amp; CACHEFS_ONDISC_INDEXKEY_TYPE) {
 		case CACHEFS_ONDISC_INDEXKEY_BIN:
-			for (tmp = 0; tmp &lt; ksize; tmp++) {
-				sprintf(name, "%02x", ptr[tmp]);
-				name += 2;
-			}
+			for (tmp = 0; tmp &lt; ksize; tmp++)
+				name += sprintf(name, "%02x", ptr[tmp]);
+			break;
+
+		case CACHEFS_ONDISC_INDEXKEY_BIN_SZ1:
+			nsize = ptr[0];
+			name += sprintf(name, "%u:", nsize);
+			nsize += 1;
+			if (nsize &gt; ksize)
+				nsize = ksize;
+			for (tmp = 1; tmp &lt; nsize; tmp++)
+				name += sprintf(name, "%02x", ptr[tmp]);
+			break;
+
+		case CACHEFS_ONDISC_INDEXKEY_BIN_SZ2:
+			nsize = (ptr[0] &lt;&lt; 8) | ptr[1];
+			name += sprintf(name, "%u:", nsize);
+			nsize += 2;
+			if (nsize &gt; ksize)
+				nsize = ksize;
+			for (tmp = 2; tmp &lt; nsize; tmp++)
+				name += sprintf(name, "%02x", ptr[tmp]);
+			break;
+
+		case CACHEFS_ONDISC_INDEXKEY_BIN_SZ4:
+			nsize = (ptr[0] &lt;&lt; 24) | (ptr[1] &lt;&lt; 16) | (ptr[2] &lt;&lt; 8) | ptr[3];
+			name += sprintf(name, "%u:", nsize);
+			nsize += 4;
+			if (nsize &gt; ksize)
+				nsize = ksize;
+			for (tmp = 4; tmp &lt; nsize; tmp++)
+				name += sprintf(name, "%02x", ptr[tmp]);
 			break;
 
 		case CACHEFS_ONDISC_INDEXKEY_ASCIIZ:
@@ -108,13 +137,15 @@ int cachefs_readdir_actor_cons_name(stru
 			break;
 
 		case CACHEFS_ONDISC_INDEXKEY_IPV6:
-			tmp = sprintf(name, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:",
-				      ptr[0], ptr[1], ptr[2], ptr[3],
-				      ptr[4], ptr[5], ptr[6], ptr[7]);
-			name += tmp;
-			tmp = sprintf(name, "%02x%02x:%02x%02x:%02x%02x:%02x%02x",
-				      ptr[8], ptr[9], ptr[10], ptr[11],
-				      ptr[12], ptr[13], ptr[14], ptr[15]);
+			tmp = sprintf(name, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx",
+				      ntohs(*(uint16_t *)(ptr + 0)),
+				      ntohs(*(uint16_t *)(ptr + 2)),
+				      ntohs(*(uint16_t *)(ptr + 4)),
+				      ntohs(*(uint16_t *)(ptr + 6)),
+				      ntohs(*(uint16_t *)(ptr + 8)),
+				      ntohs(*(uint16_t *)(ptr + 10)),
+				      ntohs(*(uint16_t *)(ptr + 12)),
+				      ntohs(*(uint16_t *)(ptr + 14)));
 			name += tmp;
 			break;
 		default:
@@ -335,8 +366,9 @@ static int cachefs_root_readdir(struct f
 		desc.arg.buf	= (char *) &amp;rec;
 		desc.error	= 0;
 
-		_debug("do read: isz=%llu pos=%llu count=%u",
-		       i_size_read(inode-&gt;vfs_inode), pos, desc.count);
+		_debug("do read: isz=%lu pos=%llu count=%u",
+		       (unsigned long) i_size_read(&amp;inode-&gt;vfs_inode),
+		       pos, desc.count);
 
 		/* use the pagecache to do readahead and stuff  */
 		do_generic_file_read(file, &amp;pos, &amp;desc, cachefs_readdir_actor);
@@ -452,7 +484,7 @@ static struct dentry *cachefs_root_looku
 	ino_t ino;
 	short ip[8];
 	char *ptr;
-	int loop, loop2, ret;
+	int loop, loop2, tmp, ret;
 
 	dir = CACHEFS_FS_I(_dir);
 	name = dentry-&gt;d_name.name;
@@ -522,19 +554,70 @@ static struct dentry *cachefs_root_looku
 	ptr = rec.key;
 	for (loop = 0; loop &lt; 4; loop++) {
 		char x;
-		int ksize = rec.keys[loop] &amp; CACHEFS_ONDISC_INDEXKEY_KLEN;
+		unsigned ksize = rec.keys[loop] &amp; CACHEFS_ONDISC_INDEXKEY_KLEN;
+		unsigned nsize = ksize;
 
 		if (ksize == 0)
 			continue;
 
-		stop = memchr(name, ',', nend - name) ?: nend;
+		stop = memchr(name, ',', nend - name);
+		stop = stop ?: nend;
 
 		_debug("- key %04hx [%*.*s]",
-		       rec.keys[loop], nend - name, nend - name, name);
+		       rec.keys[loop], stop - name, stop - name, name);
 
 		switch (rec.keys[loop] &amp; CACHEFS_ONDISC_INDEXKEY_TYPE) {
+		case CACHEFS_ONDISC_INDEXKEY_BIN_SZ1:
+			if (ksize &lt; 2)
+				goto not_found;
+			if (sscanf(name, "%u:%n", &amp;nsize, &amp;tmp) != 1)
+				goto not_found;
+
+			name += tmp;
+			*ptr++ = nsize;
+			ksize -= 1;
+			if (nsize &gt; ksize)
+				goto not_found;
+			goto do_binary;
+
+		case CACHEFS_ONDISC_INDEXKEY_BIN_SZ2:
+			if (ksize &lt; 2)
+				goto not_found;
+			if (sscanf(name, "%u:%n", &amp;nsize, &amp;tmp) != 1) {
+				printk("sscanf failed\n");
+				goto not_found;
+			}
+
+			name += tmp;
+			*ptr++ = nsize &gt;&gt; 8;
+			*ptr++ = nsize;
+			ksize -= 2;
+			if (nsize &gt; ksize)
+				goto not_found;
+			goto do_binary;
+
+		case CACHEFS_ONDISC_INDEXKEY_BIN_SZ4:
+			if (ksize &lt; 2)
+				goto not_found;
+			if (sscanf(name, "%u:%n", &amp;nsize, &amp;tmp) != 1)
+				goto not_found;
+
+			name += tmp;
+			*ptr++ = nsize &gt;&gt; 24;
+			*ptr++ = nsize &gt;&gt; 16;
+			*ptr++ = nsize &gt;&gt; 8;
+			*ptr++ = nsize;
+			ksize -= 4;
+			if (nsize &gt; ksize)
+				goto not_found;
+			goto do_binary;
+
 		case CACHEFS_ONDISC_INDEXKEY_BIN:
-			if (stop - name != ksize * 2 || ksize == 0)
+			if (nsize == 0)
+				goto not_found;
+
+		do_binary:
+			if (stop - name != nsize * 2)
 				goto not_found;
 
 			do {
@@ -562,14 +645,14 @@ static struct dentry *cachefs_root_looku
 			break;
 
 		case CACHEFS_ONDISC_INDEXKEY_ASCIIZ:
-			if (nend - name &gt; ksize || ksize == 0)
+			if (stop - name &gt; ksize || ksize == 0)
 				goto not_found;
 			memcpy(ptr, name, stop - name);
 			ptr += ksize;
 			break;
 
 		case CACHEFS_ONDISC_INDEXKEY_IPV4:
-			if (sscanf(ptr, "%hu.%hu.%hu.%hu",
+			if (sscanf(name, "%hu.%hu.%hu.%hu",
 				   &amp;ip[0], &amp;ip[1], &amp;ip[2], &amp;ip[3]) != 4)
 				goto not_found;
 			*ptr++ = ip[0];
@@ -579,17 +662,32 @@ static struct dentry *cachefs_root_looku
 			break;
 
 		case CACHEFS_ONDISC_INDEXKEY_IPV6:
-			if (sscanf(ptr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx",
-				   &amp;ip[0], &amp;ip[1], &amp;ip[2], &amp;ip[3],
-				   &amp;ip[4], &amp;ip[5], &amp;ip[6], &amp;ip[7]) != 8)
+			tmp = sscanf(name, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx",
+				     &amp;ip[0], &amp;ip[1], &amp;ip[2], &amp;ip[3],
+				     &amp;ip[4], &amp;ip[5], &amp;ip[6], &amp;ip[7]);
+			if (tmp != 8) {
+				_debug("ipv6key: sscanf failed (%d)", tmp);
 				goto not_found;
+			}
 			for (loop2 = 0; loop2 &lt; 8; loop2++) {
 				*ptr++ = ip[loop2] &gt;&gt; 8;
 				*ptr++ = ip[loop2];
 			}
 			break;
+
+		default:
+			printk("CacheFS: Unknown key type %x in index\n",
+			       rec.keys[loop] &amp; CACHEFS_ONDISC_INDEXKEY_TYPE);
+			ret = -EIO;
+			goto error;
 		}
 
+		if (nsize != ksize) {
+			BUG_ON(nsize &gt; ksize);
+			memset(ptr, FSCACHE_INDEX_DEADFILL_PATTERN,
+			       ksize - nsize);
+			ptr += ksize - nsize;
+		}
 		name = stop + 1;
 	}
 
@@ -610,7 +708,7 @@ static struct dentry *cachefs_root_looku
 	{ /* dump the key */
 		int loop;
 		for (loop = 0; loop &lt; rec.ksize; loop++)
-			printk("%02x", rec.key[loop]);
+			printk("%02x", (uint8_t) rec.key[loop]);
 		printk("\n");
 	}
 #endif
@@ -722,7 +820,7 @@ static int cachefs_root_rmdir_unlink(str
 	trans-&gt;jentry-&gt;block = __cachefs_get_page_block(ixpage)-&gt;bix;
 
 	cachefs_trans_affects_inode(trans, inode);
-	cachefs_trans_affects_page(trans, cachefs_page_grab_private(ixpage),
+	cachefs_trans_affects_page(trans, fscache_page_grab_private(ixpage),
 				   trans-&gt;jentry-&gt;entry, sizeof(*xent));
 
 	/* write the transaction mark to the journal */
diff -puN fs/cachefs/super.c~turn-cachefs-into-a-cache-backend fs/cachefs/super.c
--- 25/fs/cachefs/super.c~turn-cachefs-into-a-cache-backend	Wed Oct  6 16:03:22 2004
+++ 25-akpm/fs/cachefs/super.c	Wed Oct  6 16:03:22 2004
@@ -133,6 +133,13 @@ static struct super_block *cachefs_get_s
 	sb = get_sb_bdev(fs_type, flags, dev_name, options,
 			 cachefs_fill_super);
 
+	_debug("backing nodes %p: %p,%p -&gt; %p,%p",
+	       &amp;fscache_fsdef_index.backing_nodes,
+	       fscache_fsdef_index.backing_nodes.next,
+	       fscache_fsdef_index.backing_nodes.prev,
+	       fscache_fsdef_index.backing_nodes.next-&gt;next,
+	       fscache_fsdef_index.backing_nodes.next-&gt;prev);
+
 	_leave(" = %p", sb);
 	return sb;
 
@@ -222,7 +229,6 @@ static int cachefs_bio_submit(struct sup
  */
 static int cachefs_fill_super(struct super_block *sb, void *_data, int silent)
 {
-	struct cachefs_search_result *srch = NULL;
 	struct cachefs_super *super = NULL;
 	struct cachefs_inode *inode = NULL, *inode2;
 	struct dentry *root = NULL;
@@ -267,10 +273,6 @@ static int cachefs_fill_super(struct sup
 
 	super-&gt;vjnl_count = CACHEFS_ONDISC_VJNL_ENTS;
 
-	srch = kmalloc(sizeof(*srch), GFP_KERNEL);
-	if (!srch)
-		goto error;
-
 	/* initialise the superblock */
 	sb-&gt;s_magic		= CACHEFS_FS_MAGIC;
 	sb-&gt;s_op		= &amp;cachefs_super_ops;
@@ -278,10 +280,13 @@ static int cachefs_fill_super(struct sup
 	super-&gt;sb		= sb;
 	super-&gt;ujnl_step	= bdev_hardsect_size(super-&gt;sb-&gt;s_bdev);
 
-	INIT_LIST_HEAD(&amp;super-&gt;mnt_link);
-
-	INIT_LIST_HEAD(&amp;super-&gt;ino_list);
-	spin_lock_init(&amp;super-&gt;ino_list_lock);
+	fscache_init_cache(&amp;super-&gt;cache,
+			   &amp;cachefs_cache_ops,
+			   CACHEFS_INO_FSDEF_CATALOGUE,
+			   "%02x:%02x",
+			   MAJOR(sb-&gt;s_dev),
+			   MINOR(sb-&gt;s_dev)
+			   );
 
 	rwlock_init(&amp;super-&gt;blk_tree_lock);
 
@@ -455,17 +460,12 @@ static int cachefs_fill_super(struct sup
 			goto error;
 	}
 
-	cachefs_add_cache((struct cachefs_super *) sb-&gt;s_fs_info, srch);
+	fscache_add_cache(&amp;super-&gt;cache);
 
 	_leave(" = 0 [super=%p]", super);
 	return 0;
 
  error:
-	if (srch) {
-		dbgfree(srch);
-		kfree(srch);
-	}
-
 	if (super) {
 		if (super-&gt;dmn_task) {
 			super-&gt;dmn_die = 1;
@@ -628,7 +628,7 @@ static int cachefs_initialise_blockdev(s
 	metadata-&gt;mtime		= CURRENT_TIME.tv_sec;
 	metadata-&gt;atime		= CURRENT_TIME.tv_sec;
 
-	metadata-&gt;index.dsize	= sizeof(struct cachefs_ondisc_fsdef);
+	metadata-&gt;index.dsize	= sizeof(struct fscache_fsdef_index_entry);
 	metadata-&gt;index.esize	= sizeof(struct cachefs_ondisc_index_entry);
 	metadata-&gt;index.esize	+= metadata-&gt;index.dsize;
 	metadata-&gt;index.keys[0]	= CACHEFS_ONDISC_INDEXKEY_ASCIIZ | 24;
@@ -805,7 +805,7 @@ static void cachefs_put_super(struct sup
 	BUG_ON(!super);
 
 	/* detach the cache from all cookies that reference it */
-	cachefs_withdraw_cache(super);
+	fscache_withdraw_cache(&amp;super-&gt;cache);
 
 	/* wait for validity journalling to be sorted */
 	if (!list_empty(&amp;super-&gt;vjnl_unallocq) ||
@@ -897,14 +897,14 @@ static void cachefs_i_init_once(void *_i
 {
 	struct cachefs_inode *inode = _inode;
 
+	_enter("%p,,1", _inode);
+
 	if ((flags &amp; (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
 	    SLAB_CTOR_CONSTRUCTOR) {
 		memset(inode, 0, sizeof(*inode));
 		inode_init_once(&amp;inode-&gt;vfs_inode);
 		init_rwsem(&amp;inode-&gt;metadata_sem);
-
-		INIT_LIST_HEAD(&amp;inode-&gt;cookie_link);
-		INIT_LIST_HEAD(&amp;inode-&gt;super_link);
+		fscache_node_init(&amp;inode-&gt;node);
 	}
 
 } /* end cachefs_i_init_once() */
@@ -922,6 +922,7 @@ static struct inode *cachefs_alloc_inode
 	if (!inode)
 		return NULL;
 
+	_leave(" = %p", &amp;inode-&gt;vfs_inode);
 	return &amp;inode-&gt;vfs_inode;
 
 } /* end cachefs_alloc_inode() */
diff -puN fs/cachefs/vjournal.c~turn-cachefs-into-a-cache-backend fs/cachefs/vjournal.c
--- 25/fs/cachefs/vjournal.c~turn-cachefs-into-a-cache-backend	Wed Oct  6 16:03:22 2004
+++ 25-akpm/fs/cachefs/vjournal.c	Wed Oct  6 16:03:22 2004
@@ -307,7 +307,7 @@ void cachefs_vj_note_write_completion(st
 	ptr = kmap_atomic(vjentry-&gt;vpage, KM_USER0);
 	memset(ptr + vjentry-&gt;ventry, 0,
 	       sizeof(struct cachefs_ondisc_validity_journal));
-	kunmap_atomic(vjentry-&gt;vpage, KM_USER0);
+	kunmap_atomic(ptr, KM_USER0);
 
 	/* queue the transaction to be written to disc */
 	cachefs_trans_commit(trans);
@@ -380,7 +380,7 @@ static int cachefs_vj_replay_actor(read_
 	struct cachefs_ondisc_validity_journal *vjmark;
 	struct cachefs_vj_entry *vjentry;
 	struct cachefs_super *super = (struct cachefs_super *) desc-&gt;arg.buf;
-	struct cachefs_page *pageio;
+	struct fscache_page *pageio;
 	unsigned long stop;
 	void *data;
 	int ret;
@@ -395,7 +395,7 @@ static int cachefs_vj_replay_actor(read_
 
 	stop = offset + size;
 
-	pageio = cachefs_page_grab_private(page);
+	pageio = fscache_page_grab_private(page);
 	cachefs_block_set(super, pageio-&gt;mapped_block, page, pageio);
 
 	data = kmap(page);
@@ -483,7 +483,7 @@ static int cachefs_vj_replay_entry(struc
 
 	/* validate it */
 	ret = -EINVAL;
-	if (inode-&gt;flags &amp; CACHEFS_ACTIVE_INODE_ISINDEX) {
+	if (inode-&gt;node.flags &amp; FSCACHE_NODE_ISINDEX) {
 		printk("CacheFS: Index inode %x has block in v-journal\n",
 		       vjentry-&gt;ino);
 		goto error2;
@@ -606,10 +606,10 @@ static int cachefs_vj_walk_indirection_c
 
 		/* get the block number for this level */
 		if (!step-&gt;bix) {
-			u8 *data = kmap(step[1].page);
+			u8 *data = kmap_atomic(step[1].page, KM_USER0);
 			step-&gt;bix =
 				*(cachefs_blockix_t *)(data + step-&gt;offset);
-			kunmap(step[1].page);
+			kunmap_atomic(data, KM_USER0);
 		}
 
 		/* allocate this block if necessary */
diff -L include/linux/cachefs.h -puN include/linux/cachefs.h~turn-cachefs-into-a-cache-backend /dev/null
--- 25/include/linux/cachefs.h
+++ /dev/null	Thu Apr 11 07:25:15 2002
@@ -1,351 +0,0 @@
-/* cachefs.h: general filesystem caching 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.
- */
-
-#ifndef _LINUX_CACHEFS_H
-#define _LINUX_CACHEFS_H
-
-#include &lt;linux/config.h&gt;
-#include &lt;linux/fs.h&gt;
-#include &lt;linux/list.h&gt;
-#include &lt;linux/pagemap.h&gt;
-
-#ifdef CONFIG_CACHEFS_MODULE
-#define CONFIG_CACHEFS
-#endif
-
-struct cachefs_cookie;
-struct cachefs_netfs;
-struct cachefs_netfs_operations;
-struct cachefs_page;
-
-#define CACHEFS_NEGATIVE_COOKIE		NULL
-
-typedef void (*cachefs_rw_complete_t)(void *cookie_data,
-				      struct page *page,
-				      void *data,
-				      int error);
-
-/* result of index entry comparison */
-typedef enum {
-	/* no match */
-	CACHEFS_MATCH_FAILED,
-
-	/* successful match */
-	CACHEFS_MATCH_SUCCESS,
-
-	/* successful match, entry requires update */
-	CACHEFS_MATCH_SUCCESS_UPDATE,
-
-	/* successful match, entry requires deletion */
-	CACHEFS_MATCH_SUCCESS_DELETE,
-} cachefs_match_val_t;
-
-/*****************************************************************************/
-/*
- * cachefs index definition
- * - each index file contains a number of fixed size entries
- *   - they don't have to fit exactly into a page, but if they don't, the gap
- *     at the end of the page will not be used
- */
-struct cachefs_index_def
-{
-	/* name of index */
-	uint8_t			name[8];
-
-	/* size of data to be stored in index */
-	uint16_t		data_size;
-
-	/* key description (for displaying in cache mountpoint) */
-	struct {
-		uint8_t		type;
-		uint16_t	len;
-	} keys[4];
-
-#define CACHEFS_INDEX_KEYS_NOTUSED	0
-#define CACHEFS_INDEX_KEYS_BIN		1
-#define CACHEFS_INDEX_KEYS_ASCIIZ	2
-#define CACHEFS_INDEX_KEYS_IPV4ADDR	3
-#define CACHEFS_INDEX_KEYS_IPV6ADDR	4
-#define CACHEFS_INDEX_KEYS__LAST	CACHEFS_INDEX_KEYS_IPV6ADDR
-
-	/* see if entry matches the specified key
-	 * - the netfs data from the cookie being used as the target is
-	 *   presented
-	 * - entries that aren't in use will not be presented for matching
-	 */
-	cachefs_match_val_t (*match)(void *target_netfs_data,
-				     const void *entry);
-
-	/* update entry from key
-	 * - the netfs data from the cookie being used as the source is
-	 *   presented
-	 */
-	void (*update)(void *source_netfs_data, void *entry);
-};
-
-#ifdef CONFIG_CACHEFS
-extern struct cachefs_cookie *__cachefs_acquire_cookie(struct cachefs_cookie *iparent,
-						       struct cachefs_index_def *idef,
-						       void *netfs_data);
-
-extern void __cachefs_relinquish_cookie(struct cachefs_cookie *cookie,
-					int retire);
-
-extern void __cachefs_update_cookie(struct cachefs_cookie *cookie);
-#endif
-
-static inline
-struct cachefs_cookie *cachefs_acquire_cookie(struct cachefs_cookie *iparent,
-					      struct cachefs_index_def *idef,
-					      void *netfs_data)
-{
-#ifdef CONFIG_CACHEFS
-	if (iparent != CACHEFS_NEGATIVE_COOKIE)
-		return __cachefs_acquire_cookie(iparent, idef, netfs_data);
-#endif
-	return CACHEFS_NEGATIVE_COOKIE;
-}
-
-static inline
-void cachefs_relinquish_cookie(struct cachefs_cookie *cookie,
-			       int retire)
-{
-#ifdef CONFIG_CACHEFS
-	if (cookie != CACHEFS_NEGATIVE_COOKIE)
-		__cachefs_relinquish_cookie(cookie, retire);
-#endif
-}
-
-static inline
-void cachefs_update_cookie(struct cachefs_cookie *cookie)
-{
-#ifdef CONFIG_CACHEFS
-	if (cookie != CACHEFS_NEGATIVE_COOKIE)
-		__cachefs_update_cookie(cookie);
-#endif
-}
-
-/*****************************************************************************/
-/*
- * cachefs cached network filesystem type
- * - name, version and ops must be filled in before registration
- * - all other fields will be set during registration
- */
-struct cachefs_netfs
-{
-	const char			*name;		/* filesystem name */
-	unsigned			version;	/* indexing version */
-	struct cachefs_cookie		*primary_index;
-	struct cachefs_netfs_operations	*ops;
-	struct list_head		link;		/* internal link */
-};
-
-struct cachefs_netfs_operations
-{
-	/* get page-to-block mapping cookie for a page
-	 * - one should be allocated if it doesn't exist
-	 * - returning -ENODATA will cause this page to be ignored
-	 * - typically, the struct will be attached to page-&gt;private
-	 */
-	struct cachefs_page *(*get_page_cookie)(struct page *page);
-};
-
-#ifdef CONFIG_CACHEFS
-extern int __cachefs_register_netfs(struct cachefs_netfs *netfs,
-				    struct cachefs_index_def *primary_idef);
-extern void __cachefs_unregister_netfs(struct cachefs_netfs *netfs);
-#endif
-
-static inline
-int cachefs_register_netfs(struct cachefs_netfs *netfs,
-			   struct cachefs_index_def *primary_idef)
-{
-#ifdef CONFIG_CACHEFS
-	return __cachefs_register_netfs(netfs, primary_idef);
-#else
-	return 0;
-#endif
-}
-
-static inline
-void cachefs_unregister_netfs(struct cachefs_netfs *netfs)
-{
-#ifdef CONFIG_CACHEFS
-	__cachefs_unregister_netfs(netfs);
-#endif
-}
-
-/*****************************************************************************/
-/*
- * page mapping cookie
- * - stores the mapping of a page to a block in the cache (may also be null)
- * - note that the mapping may be removed without notice if a cache is removed
- */
-struct cachefs_page
-{
-	struct cachefs_block	*mapped_block;	/* block mirroring this page */
-	rwlock_t		lock;
-
-	unsigned long		flags;
-#define CACHEFS_PAGE_BOUNDARY	0	/* next block has a different
-					 * indirection chain */
-#define CACHEFS_PAGE_NEW	1	/* this is a newly allocated block */
-};
-
-/*
- * read a page from the cache or allocate a block in which to store it
- * - if the cookie is not backed by a file:
- *   - -ENOBUFS will be returned and nothing more will be done
- * - else if the page is backed by a block in the cache:
- *   - a read will be started which will call end_io_func on completion
- *   - the wb-journal will be searched for an entry pertaining to this block
- *     - if an entry is found:
- *       - 1 will be returned [not yet supported]
- *       else
- *       - 0 will be returned
- * - else if the page is unbacked:
- *   - a block will be allocated and attached
- *   - the validity journal will be marked to note the block does not yet
- *     contain valid data
- *   - -ENODATA will be returned
- */
-#ifdef CONFIG_CACHEFS
-extern int __cachefs_read_or_alloc_page(struct cachefs_cookie *cookie,
-					struct page *page,
-					cachefs_rw_complete_t end_io_func,
-					void *end_io_data,
-					unsigned long gfp);
-#endif
-
-static inline
-int cachefs_read_or_alloc_page(struct cachefs_cookie *cookie,
-			       struct page *page,
-			       cachefs_rw_complete_t end_io_func,
-			       void *end_io_data,
-			       unsigned long gfp)
-{
-#ifdef CONFIG_CACHEFS
-	if (cookie != CACHEFS_NEGATIVE_COOKIE)
-		return __cachefs_read_or_alloc_page(cookie, page, end_io_func,
-						    end_io_data, gfp);
-#endif
-	return -ENOBUFS;
-}
-
-/*
- * request a page be stored in the cache
- * - this request may be ignored if no cache block is currently attached, in
- *   which case it:
- *   - returns -ENOBUFS
- * - if a cache block was already allocated:
- *   - the page cookie will be updated to reflect the block selected
- *   - a BIO will be dispatched to write the page (end_io_func will be called
- *     from the completion function)
- *     - end_io_func can be NULL, in which case a default function will just
- *       clear the writeback bit on the page
- *   - any associated validity journal entry will be cleared
- *   - returns 0
- */
-#ifdef CONFIG_CACHEFS
-extern int __cachefs_write_page(struct cachefs_cookie *cookie,
-				struct page *page,
-				cachefs_rw_complete_t end_io_func,
-				void *end_io_data,
-				unsigned long gfp);
-#endif
-
-static inline
-int cachefs_write_page(struct cachefs_cookie *cookie,
-		       struct page *page,
-		       cachefs_rw_complete_t end_io_func,
-		       void *end_io_data,
-		       unsigned long gfp)
-{
-#ifdef CONFIG_CACHEFS
-	if (cookie != CACHEFS_NEGATIVE_COOKIE)
-		return __cachefs_write_page(cookie, page, end_io_func,
-					    end_io_data, gfp);
-#endif
-	return -ENOBUFS;
-}
-
-/*
- * indicate that caching is no longer required on a page
- * - note: cannot cancel any outstanding BIOs between this page and the cache
- */
-#ifdef CONFIG_CACHEFS
-extern void __cachefs_uncache_page(struct cachefs_cookie *cookie,
-				   struct page *page);
-#endif
-
-static inline
-void cachefs_uncache_page(struct cachefs_cookie *cookie,
-			  struct page *page)
-{
-#ifdef CONFIG_CACHEFS
-	__cachefs_uncache_page(cookie, page);
-#endif
-}
-
-/*
- * keep track of pages changed locally but not yet committed
- */
-#if 0 /* TODO */
-extern void cachefs_writeback_prepare(struct cachefs_cookie *cookie,
-				      struct page *page,
-				      unsigned short from,
-				      unsigned short to);
-
-extern void cachefs_writeback_committed(struct cachefs_cookie *cookie,
-					struct page *page,
-					unsigned short from,
-					unsigned short to);
-
-extern void cachefs_writeback_aborted(struct cachefs_cookie *cookie,
-				      struct page *page,
-				      unsigned short from,
-				      unsigned short to);
-#endif
-
-/*
- * convenience routines for mapping page-&gt;private directly to a struct
- * cachefs_page
- */
-static inline
-struct cachefs_page *__cachefs_page_grab_private(struct page *page)
-{
-	return (struct cachefs_page *) (PagePrivate(page) ? page-&gt;private : 0);
-}
-
-#define cachefs_page_grab_private(X)		\
-({						\
-	BUG_ON(!PagePrivate(X));		\
-	__cachefs_page_grab_private(X);		\
-})
-
-
-#ifdef CONFIG_CACHEFS
-extern struct cachefs_page *__cachefs_page_get_private(struct page *page,
-						       unsigned gfp);
-#endif
-
-static inline
-struct cachefs_page *cachefs_page_get_private(struct page *page,
-					      unsigned gfp)
-{
-#ifdef CONFIG_CACHEFS
-	return __cachefs_page_get_private(page, gfp);
-#else
-	return ERR_PTR(-EIO);
-#endif
-}
-
-#endif /* _LINUX_CACHEFS_H */
_
</pre></body></html>