rpms/kernel/devel linux-2.6.17-afs-fscache.patch, NONE, 1.1.2.1 linux-2.6.17-cachefiles-misc.patch, NONE, 1.1.2.1 linux-2.6.17-cachefiles.patch, NONE, 1.1.2.1 linux-2.6.17-cachefs-fsmisc.patch, NONE, 1.1.2.1 linux-2.6.17-cachefs-kfile.patch, NONE, 1.1.2.1 linux-2.6.17-cachefs-mkwrite.patch, NONE, 1.1.2.1 linux-2.6.17-cachefs-relpage.patch, NONE, 1.1.2.1 linux-2.6.17-fscache-fedora.patch, NONE, 1.1.2.1 linux-2.6.17-fscache.patch, NONE, 1.1.2.1 linux-2.6.17-nfs-fscache.patch, NONE, 1.1.2.1 kernel-2.6.spec, 1.2253, 1.2253.2.1
fedora-cvs-commits at redhat.com
fedora-cvs-commits at redhat.com
Thu Jun 8 18:36:20 UTC 2006
Author: steved
Update of /cvs/dist/rpms/kernel/devel
In directory cvs.devel.redhat.com:/tmp/cvs-serv4919
Modified Files:
Tag: kernel-2_6_16-1_2253_FC6_fscache
kernel-2.6.spec
Added Files:
Tag: kernel-2_6_16-1_2253_FC6_fscache
linux-2.6.17-afs-fscache.patch
linux-2.6.17-cachefiles-misc.patch
linux-2.6.17-cachefiles.patch
linux-2.6.17-cachefs-fsmisc.patch
linux-2.6.17-cachefs-kfile.patch
linux-2.6.17-cachefs-mkwrite.patch
linux-2.6.17-cachefs-relpage.patch
linux-2.6.17-fscache-fedora.patch linux-2.6.17-fscache.patch
linux-2.6.17-nfs-fscache.patch
Log Message:
Added cachefs bits to kernel-2_6_16-1_2253_FC6_fscache branch
linux-2.6.17-afs-fscache.patch:
Kconfig | 7 +
afs/cell.c | 109 ++++++++++++++----------
afs/cell.h | 16 ---
afs/cmservice.c | 2
afs/dir.c | 10 +-
afs/file.c | 243 ++++++++++++++++++++++++++++++++++++------------------
afs/fsclient.c | 4
afs/inode.c | 43 ++++++---
afs/internal.h | 24 ++---
afs/main.c | 24 ++---
afs/mntpt.c | 12 +-
afs/proc.c | 1
afs/server.c | 3
afs/vlocation.c | 185 +++++++++++++++++++++++++----------------
afs/vnode.c | 250 +++++++++++++++++++++++++++++++++++++++++++++-----------
afs/vnode.h | 10 +-
afs/volume.c | 78 ++++++-----------
afs/volume.h | 28 +-----
18 files changed, 661 insertions(+), 388 deletions(-)
--- NEW FILE linux-2.6.17-afs-fscache.patch ---
--- linux-2.6.16.noarch/fs/afs/cell.c.fsafs 2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.noarch/fs/afs/cell.c 2006-06-07 14:34:54.091672000 -0400
@@ -31,17 +31,21 @@ static DEFINE_RWLOCK(afs_cells_lock);
static DECLARE_RWSEM(afs_cells_sem); /* add/remove serialisation */
static struct afs_cell *afs_cell_root;
-#ifdef AFS_CACHING_SUPPORT
-static cachefs_match_val_t afs_cell_cache_match(void *target,
- const void *entry);
-static void afs_cell_cache_update(void *source, void *entry);
-
-struct cachefs_index_def afs_cache_cell_index_def = {
- .name = "cell_ix",
- .data_size = sizeof(struct afs_cache_cell),
- .keys[0] = { CACHEFS_INDEX_KEYS_ASCIIZ, 64 },
- .match = afs_cell_cache_match,
- .update = afs_cell_cache_update,
+#ifdef CONFIG_AFS_FSCACHE
+static uint16_t afs_cell_cache_get_key(const void *cookie_netfs_data,
+ void *buffer, uint16_t buflen);
+static uint16_t afs_cell_cache_get_aux(const void *cookie_netfs_data,
+ void *buffer, uint16_t buflen);
+static fscache_checkaux_t afs_cell_cache_check_aux(void *cookie_netfs_data,
+ const void *buffer,
+ uint16_t buflen);
+
+static struct fscache_cookie_def afs_cell_cache_index_def = {
+ .name = "AFS cell",
+ .type = FSCACHE_COOKIE_TYPE_INDEX,
+ .get_key = afs_cell_cache_get_key,
+ .get_aux = afs_cell_cache_get_aux,
+ .check_aux = afs_cell_cache_check_aux,
};
#endif
@@ -115,12 +119,11 @@ int afs_cell_create(const char *name, ch
if (ret < 0)
goto error;
-#ifdef AFS_CACHING_SUPPORT
- /* put it up for caching */
- cachefs_acquire_cookie(afs_cache_netfs.primary_index,
- &afs_vlocation_cache_index_def,
- cell,
- &cell->cache);
+#ifdef CONFIG_AFS_FSCACHE
+ /* put it up for caching (this never returns an error) */
+ cell->cache = fscache_acquire_cookie(afs_cache_netfs.primary_index,
+ &afs_cell_cache_index_def,
+ cell);
#endif
/* add to the cell lists */
@@ -345,8 +348,8 @@ static void afs_cell_destroy(struct afs_
list_del_init(&cell->proc_link);
up_write(&afs_proc_cells_sem);
-#ifdef AFS_CACHING_SUPPORT
- cachefs_relinquish_cookie(cell->cache, 0);
+#ifdef CONFIG_AFS_FSCACHE
+ fscache_relinquish_cookie(cell->cache, 0);
#endif
up_write(&afs_cells_sem);
@@ -526,44 +529,62 @@ void afs_cell_purge(void)
/*****************************************************************************/
/*
- * match a cell record obtained from the cache
+ * set the key for the index entry
*/
-#ifdef AFS_CACHING_SUPPORT
-static cachefs_match_val_t afs_cell_cache_match(void *target,
- const void *entry)
+#ifdef CONFIG_AFS_FSCACHE
+static uint16_t afs_cell_cache_get_key(const void *cookie_netfs_data,
+ void *buffer, uint16_t bufmax)
{
- const struct afs_cache_cell *ccell = entry;
- struct afs_cell *cell = target;
+ const struct afs_cell *cell = cookie_netfs_data;
+ uint16_t klen;
- _enter("{%s},{%s}", ccell->name, cell->name);
+ _enter("%p,%p,%u", cell, buffer, bufmax);
- if (strncmp(ccell->name, cell->name, sizeof(ccell->name)) == 0) {
- _leave(" = SUCCESS");
- return CACHEFS_MATCH_SUCCESS;
- }
+ klen = strlen(cell->name);
+ if (klen > bufmax)
+ return 0;
+
+ memcpy(buffer, cell->name, klen);
+ return klen;
- _leave(" = FAILED");
- return CACHEFS_MATCH_FAILED;
-} /* end afs_cell_cache_match() */
+} /* end afs_cell_cache_get_key() */
#endif
/*****************************************************************************/
/*
- * update a cell record in the cache
+ * provide new auxilliary cache data
*/
-#ifdef AFS_CACHING_SUPPORT
-static void afs_cell_cache_update(void *source, void *entry)
+#ifdef CONFIG_AFS_FSCACHE
+static uint16_t afs_cell_cache_get_aux(const void *cookie_netfs_data,
+ void *buffer, uint16_t bufmax)
{
- struct afs_cache_cell *ccell = entry;
- struct afs_cell *cell = source;
+ const struct afs_cell *cell = cookie_netfs_data;
+ uint16_t dlen;
- _enter("%p,%p", source, entry);
+ _enter("%p,%p,%u", cell, buffer, bufmax);
- strncpy(ccell->name, cell->name, sizeof(ccell->name));
+ dlen = cell->vl_naddrs * sizeof(cell->vl_addrs[0]);
+ dlen = min(dlen, bufmax);
+ dlen &= ~(sizeof(cell->vl_addrs[0]) - 1);
- memcpy(ccell->vl_servers,
- cell->vl_addrs,
- min(sizeof(ccell->vl_servers), sizeof(cell->vl_addrs)));
+ memcpy(buffer, cell->vl_addrs, dlen);
+
+ return dlen;
+
+} /* end afs_cell_cache_get_aux() */
+#endif
+
+/*****************************************************************************/
+/*
+ * check that the auxilliary data indicates that the entry is still valid
+ */
+#ifdef CONFIG_AFS_FSCACHE
+static fscache_checkaux_t afs_cell_cache_check_aux(void *cookie_netfs_data,
+ const void *buffer,
+ uint16_t buflen)
+{
+ _leave(" = OKAY");
+ return FSCACHE_CHECKAUX_OKAY;
-} /* end afs_cell_cache_update() */
+} /* end afs_cell_cache_check_aux() */
#endif
--- linux-2.6.16.noarch/fs/afs/cell.h.fsafs 2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.noarch/fs/afs/cell.h 2006-06-07 14:34:54.097676000 -0400
@@ -13,7 +13,7 @@
#define _LINUX_AFS_CELL_H
#include "types.h"
-#include "cache.h"
+#include <linux/fscache.h>
#define AFS_CELL_MAX_ADDRS 15
@@ -21,16 +21,6 @@ extern volatile int afs_cells_being_purg
/*****************************************************************************/
/*
- * entry in the cached cell catalogue
- */
-struct afs_cache_cell
-{
- char name[64]; /* cell name (padded with NULs) */
- struct in_addr vl_servers[15]; /* cached cell VL servers */
-};
-
-/*****************************************************************************/
-/*
* AFS cell record
*/
struct afs_cell
@@ -39,8 +29,8 @@ struct afs_cell
struct list_head link; /* main cell list link */
struct list_head proc_link; /* /proc cell list link */
struct proc_dir_entry *proc_dir; /* /proc dir for this cell */
-#ifdef AFS_CACHING_SUPPORT
- struct cachefs_cookie *cache; /* caching cookie */
+#ifdef CONFIG_AFS_FSCACHE
+ struct fscache_cookie *cache; /* caching cookie */
#endif
/* server record management */
--- linux-2.6.16.noarch/fs/afs/cmservice.c.fsafs 2006-06-07 14:26:17.201745000 -0400
+++ linux-2.6.16.noarch/fs/afs/cmservice.c 2006-06-07 14:34:54.153673000 -0400
@@ -24,7 +24,7 @@
#include "internal.h"
static unsigned afscm_usage; /* AFS cache manager usage count */
-static struct rw_semaphore afscm_sem; /* AFS cache manager start/stop semaphore */
+static DECLARE_RWSEM(afscm_sem); /* AFS cache manager start/stop semaphore */
static int afscm_new_call(struct rxrpc_call *call);
static void afscm_attention(struct rxrpc_call *call);
--- linux-2.6.16.noarch/fs/afs/dir.c.fsafs 2006-06-07 14:27:21.723370000 -0400
+++ linux-2.6.16.noarch/fs/afs/dir.c 2006-06-07 14:34:54.161671000 -0400
@@ -145,7 +145,7 @@ static inline void afs_dir_check_page(st
qty /= sizeof(union afs_dir_block);
/* check them */
- dbuf = page_address(page);
+ dbuf = kmap_atomic(page, KM_USER0);
for (tmp = 0; tmp < qty; tmp++) {
if (dbuf->blocks[tmp].pagehdr.magic != AFS_DIR_MAGIC) {
printk("kAFS: %s(%lu): bad magic %d/%d is %04hx\n",
@@ -154,10 +154,12 @@ static inline void afs_dir_check_page(st
goto error;
}
}
+ kunmap_atomic(dbuf, KM_USER0);
return;
error:
+ kunmap_atomic(dbuf, KM_USER0);
SetPageError(page);
} /* end afs_dir_check_page() */
@@ -168,7 +170,6 @@ static inline void afs_dir_check_page(st
*/
static inline void afs_dir_put_page(struct page *page)
{
- kunmap(page);
page_cache_release(page);
} /* end afs_dir_put_page() */
@@ -188,7 +189,6 @@ static struct page *afs_dir_get_page(str
NULL);
if (!IS_ERR(page)) {
wait_on_page_locked(page);
- kmap(page);
if (!PageUptodate(page))
goto fail;
afs_dir_check_page(dir, page);
@@ -356,7 +356,7 @@ static int afs_dir_iterate(struct inode
limit = blkoff & ~(PAGE_SIZE - 1);
- dbuf = page_address(page);
+ dbuf = kmap_atomic(page, KM_USER0);
/* deal with the individual blocks stashed on this page */
do {
@@ -365,6 +365,7 @@ static int afs_dir_iterate(struct inode
ret = afs_dir_iterate_block(fpos, dblock, blkoff,
cookie, filldir);
if (ret != 1) {
+ kunmap_atomic(dbuf, KM_USER0);
afs_dir_put_page(page);
goto out;
}
@@ -373,6 +374,7 @@ static int afs_dir_iterate(struct inode
} while (*fpos < dir->i_size && blkoff < limit);
+ kunmap_atomic(dbuf, KM_USER0);
afs_dir_put_page(page);
ret = 0;
}
--- linux-2.6.16.noarch/fs/afs/file.c.fsafs 2006-06-07 14:26:17.221746000 -0400
+++ linux-2.6.16.noarch/fs/afs/file.c 2006-06-07 14:34:54.168672000 -0400
@@ -16,12 +16,15 @@
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/pagemap.h>
+#include <linux/pagevec.h>
#include <linux/buffer_head.h>
#include "volume.h"
#include "vnode.h"
#include <rxrpc/call.h>
#include "internal.h"
+#define list_to_page(head) (list_entry((head)->prev, struct page, lru))
+
#if 0
static int afs_file_open(struct inode *inode, struct file *file);
static int afs_file_release(struct inode *inode, struct file *file);
@@ -30,34 +33,72 @@ static int afs_file_release(struct inode
static int afs_file_readpage(struct file *file, struct page *page);
static void afs_file_invalidatepage(struct page *page, unsigned long offset);
static int afs_file_releasepage(struct page *page, gfp_t gfp_flags);
+static int afs_file_mmap(struct file * file, struct vm_area_struct * vma);
+
+#ifdef CONFIG_AFS_FSCACHE
+static int afs_file_readpages(struct file *filp, struct address_space *mapping,
+ struct list_head *pages, unsigned nr_pages);
+static int afs_file_page_mkwrite(struct vm_area_struct *vma, struct page *page);
+#endif
struct inode_operations afs_file_inode_operations = {
.getattr = afs_inode_getattr,
};
+struct file_operations afs_file_file_operations = {
+ .read = generic_file_read,
+ .mmap = afs_file_mmap,
+};
+
struct address_space_operations afs_fs_aops = {
.readpage = afs_file_readpage,
+#ifdef CONFIG_AFS_FSCACHE
+ .readpages = afs_file_readpages,
+#endif
.sync_page = block_sync_page,
.set_page_dirty = __set_page_dirty_nobuffers,
.releasepage = afs_file_releasepage,
.invalidatepage = afs_file_invalidatepage,
};
+static struct vm_operations_struct afs_fs_vm_operations = {
+ .nopage = filemap_nopage,
+ .populate = filemap_populate,
+#ifdef CONFIG_AFS_FSCACHE
+ .page_mkwrite = afs_file_page_mkwrite,
+#endif
+};
+
+/*****************************************************************************/
+/*
+ * set up a memory mapping on an AFS file
+ * - we set our own VMA ops so that we can catch the page becoming writable for
+ * userspace for shared-writable mmap
+ */
+static int afs_file_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ _enter("");
+
+ file_accessed(file);
+ vma->vm_ops = &afs_fs_vm_operations;
+ return 0;
+
+} /* end afs_file_mmap() */
+
/*****************************************************************************/
/*
* deal with notification that a page was read from the cache
*/
-#ifdef AFS_CACHING_SUPPORT
-static void afs_file_readpage_read_complete(void *cookie_data,
- struct page *page,
+#ifdef CONFIG_AFS_FSCACHE
+static void afs_file_readpage_read_complete(struct page *page,
void *data,
int error)
{
- _enter("%p,%p,%p,%d", cookie_data, page, data, error);
+ _enter("%p,%p,%d", page, data, error);
- if (error)
- SetPageError(page);
- else
+ /* if the read completes with an error, we just unlock the page and let
+ * the VM reissue the readpage */
+ if (!error)
SetPageUptodate(page);
unlock_page(page);
@@ -68,15 +109,16 @@ static void afs_file_readpage_read_compl
/*
* deal with notification that a page was written to the cache
*/
-#ifdef AFS_CACHING_SUPPORT
-static void afs_file_readpage_write_complete(void *cookie_data,
- struct page *page,
+#ifdef CONFIG_AFS_FSCACHE
+static void afs_file_readpage_write_complete(struct page *page,
void *data,
int error)
{
- _enter("%p,%p,%p,%d", cookie_data, page, data, error);
+ _enter("%p,%p,%d", page, data, error);
- unlock_page(page);
+ /* note that the page has been written to the cache and can now be
+ * modified */
+ end_page_fs_misc(page);
} /* end afs_file_readpage_write_complete() */
#endif
@@ -88,16 +130,13 @@ static void afs_file_readpage_write_comp
static int afs_file_readpage(struct file *file, struct page *page)
{
struct afs_rxfs_fetch_descriptor desc;
-#ifdef AFS_CACHING_SUPPORT
- struct cachefs_page *pageio;
-#endif
struct afs_vnode *vnode;
struct inode *inode;
int ret;
inode = page->mapping->host;
- _enter("{%lu},{%lu}", inode->i_ino, page->index);
+ _enter("{%lu},%p{%lu}", inode->i_ino, page, page->index);
vnode = AFS_FS_I(inode);
@@ -107,13 +146,9 @@ static int afs_file_readpage(struct file
if (vnode->flags & AFS_VNODE_DELETED)
goto error;
-#ifdef AFS_CACHING_SUPPORT
- ret = cachefs_page_get_private(page, &pageio, GFP_NOIO);
- if (ret < 0)
- goto error;
-
+#ifdef CONFIG_AFS_FSCACHE
/* is it cached? */
- ret = cachefs_read_or_alloc_page(vnode->cache,
+ ret = fscache_read_or_alloc_page(vnode->cache,
page,
afs_file_readpage_read_complete,
NULL,
@@ -123,18 +158,20 @@ static int afs_file_readpage(struct file
#endif
switch (ret) {
- /* read BIO submitted and wb-journal entry found */
- case 1:
- BUG(); // TODO - handle wb-journal match
-
/* read BIO submitted (page in cache) */
case 0:
break;
- /* no page available in cache */
- case -ENOBUFS:
+ /* page not yet cached */
case -ENODATA:
+ _debug("cache said ENODATA");
+ goto go_on;
+
+ /* page will not be cached */
+ case -ENOBUFS:
+ _debug("cache said ENOBUFS");
default:
+ go_on:
desc.fid = vnode->fid;
desc.offset = page->index << PAGE_CACHE_SHIFT;
desc.size = min((size_t) (inode->i_size - desc.offset),
@@ -148,34 +185,40 @@ static int afs_file_readpage(struct file
ret = afs_vnode_fetch_data(vnode, &desc);
kunmap(page);
if (ret < 0) {
- if (ret==-ENOENT) {
- _debug("got NOENT from server"
+ if (ret == -ENOENT) {
+ kdebug("got NOENT from server"
" - marking file deleted and stale");
vnode->flags |= AFS_VNODE_DELETED;
ret = -ESTALE;
}
-#ifdef AFS_CACHING_SUPPORT
- cachefs_uncache_page(vnode->cache, page);
+#ifdef CONFIG_AFS_FSCACHE
+ fscache_uncache_page(vnode->cache, page);
+ ClearPagePrivate(page);
#endif
goto error;
}
SetPageUptodate(page);
-#ifdef AFS_CACHING_SUPPORT
- if (cachefs_write_page(vnode->cache,
- page,
- afs_file_readpage_write_complete,
- NULL,
- GFP_KERNEL) != 0
- ) {
- cachefs_uncache_page(vnode->cache, page);
- unlock_page(page);
+ /* send the page to the cache */
+#ifdef CONFIG_AFS_FSCACHE
+ if (PagePrivate(page)) {
+ if (TestSetPageFsMisc(page))
+ BUG();
+ if (fscache_write_page(vnode->cache,
+ page,
+ afs_file_readpage_write_complete,
+ NULL,
+ GFP_KERNEL) != 0
+ ) {
+ fscache_uncache_page(vnode->cache, page);
+ ClearPagePrivate(page);
+ end_page_fs_misc(page);
+ }
}
-#else
- unlock_page(page);
#endif
+ unlock_page(page);
}
_leave(" = 0");
@@ -192,20 +235,63 @@ static int afs_file_readpage(struct file
/*****************************************************************************/
/*
- * get a page cookie for the specified page
+ * read a set of pages
*/
-#ifdef AFS_CACHING_SUPPORT
-int afs_cache_get_page_cookie(struct page *page,
- struct cachefs_page **_page_cookie)
+#ifdef CONFIG_AFS_FSCACHE
+static int afs_file_readpages(struct file *filp, struct address_space *mapping,
+ struct list_head *pages, unsigned nr_pages)
{
- int ret;
+ struct afs_vnode *vnode;
+#if 0
+ struct pagevec lru_pvec;
+ unsigned page_idx;
+#endif
+ int ret = 0;
- _enter("");
- ret = cachefs_page_get_private(page,_page_cookie, GFP_NOIO);
+ _enter(",{%lu},,%d", mapping->host->i_ino, nr_pages);
- _leave(" = %d", ret);
+ vnode = AFS_FS_I(mapping->host);
+ if (vnode->flags & AFS_VNODE_DELETED) {
+ _leave(" = -ESTALE");
+ return -ESTALE;
+ }
+
+ /* attempt to read as many of the pages as possible */
+ ret = fscache_read_or_alloc_pages(vnode->cache,
+ mapping,
+ pages,
+ &nr_pages,
+ afs_file_readpage_read_complete,
+ NULL,
+ mapping_gfp_mask(mapping));
+
+ switch (ret) {
+ /* all pages are being read from the cache */
+ case 0:
+ BUG_ON(!list_empty(pages));
+ BUG_ON(nr_pages != 0);
+ _leave(" = 0 [reading all]");
+ return 0;
+
+ /* there were pages that couldn't be read from the cache */
+ case -ENODATA:
+ case -ENOBUFS:
+ break;
+
+ /* other error */
+ default:
+ _leave(" = %d", ret);
+ return ret;
+ }
+
+ /* load the missing pages from the network */
+ ret = read_cache_pages(mapping, pages,
+ (void *) afs_file_readpage, NULL);
+
+ _leave(" = %d [netting]", ret);
return ret;
-} /* end afs_cache_get_page_cookie() */
+
+} /* end afs_file_readpages() */
#endif
/*****************************************************************************/
@@ -214,35 +300,22 @@ int afs_cache_get_page_cookie(struct pag
*/
static void afs_file_invalidatepage(struct page *page, unsigned long offset)
{
- int ret = 1;
-
_enter("{%lu},%lu", page->index, offset);
BUG_ON(!PageLocked(page));
if (PagePrivate(page)) {
-#ifdef AFS_CACHING_SUPPORT
- struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
- cachefs_uncache_page(vnode->cache,page);
-#endif
-
/* We release buffers only if the entire page is being
* invalidated.
* The get_block cached value has been unconditionally
* invalidated, so real IO is not possible anymore.
*/
- if (offset == 0) {
- BUG_ON(!PageLocked(page));
-
- ret = 0;
- if (!PageWriteback(page))
- ret = page->mapping->a_ops->releasepage(page,
- 0);
- /* possibly should BUG_ON(!ret); - neilb */
- }
+ if (offset == 0 && !PageWriteback(page))
+ page->mapping->a_ops->releasepage(page, 0);
}
- _leave(" = %d", ret);
+ _leave("");
+
} /* end afs_file_invalidatepage() */
/*****************************************************************************/
@@ -251,23 +324,29 @@ static void afs_file_invalidatepage(stru
*/
static int afs_file_releasepage(struct page *page, gfp_t gfp_flags)
{
- struct cachefs_page *pageio;
-
_enter("{%lu},%x", page->index, gfp_flags);
- if (PagePrivate(page)) {
-#ifdef AFS_CACHING_SUPPORT
- struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
- cachefs_uncache_page(vnode->cache, page);
+#ifdef CONFIG_AFS_FSCACHE
+ wait_on_page_fs_misc(page);
+ fscache_uncache_page(AFS_FS_I(page->mapping->host)->cache, page);
+ ClearPagePrivate(page);
#endif
- pageio = (struct cachefs_page *) page_private(page);
- set_page_private(page, 0);
- ClearPagePrivate(page);
-
- kfree(pageio);
- }
-
_leave(" = 0");
return 0;
+
} /* end afs_file_releasepage() */
+
+/*****************************************************************************/
+/*
+ * wait for the disc cache to finish writing before permitting modification of
+ * our page in the page cache
+ */
+#ifdef CONFIG_AFS_FSCACHE
+static int afs_file_page_mkwrite(struct vm_area_struct *vma, struct page *page)
+{
+ wait_on_page_fs_misc(page);
+ return 0;
+
+} /* end afs_file_page_mkwrite() */
+#endif
--- linux-2.6.16.noarch/fs/afs/fsclient.c.fsafs 2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.noarch/fs/afs/fsclient.c 2006-06-07 14:34:54.194671000 -0400
@@ -398,6 +398,8 @@ int afs_rxfs_fetch_file_status(struct af
bp++; /* spare6 */
}
+ _debug("Data Version %llx\n", vnode->status.version);
+
/* success */
ret = 0;
@@ -408,7 +410,7 @@ int afs_rxfs_fetch_file_status(struct af
out_put_conn:
afs_server_release_callslot(server, &callslot);
out:
- _leave("");
+ _leave(" = %d", ret);
return ret;
abort:
--- linux-2.6.16.noarch/fs/afs/inode.c.fsafs 2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.noarch/fs/afs/inode.c 2006-06-07 14:34:54.201673000 -0400
@@ -65,6 +65,11 @@ static int afs_inode_map_status(struct a
return -EBADMSG;
}
+#ifdef CONFIG_AFS_FSCACHE
+ if (vnode->status.size != inode->i_size)
+ fscache_set_i_size(vnode->cache, vnode->status.size);
+#endif
+
inode->i_nlink = vnode->status.nlink;
inode->i_uid = vnode->status.owner;
inode->i_gid = 0;
@@ -101,13 +106,33 @@ static int afs_inode_fetch_status(struct
struct afs_vnode *vnode;
int ret;
+ _enter("");
+
vnode = AFS_FS_I(inode);
ret = afs_vnode_fetch_status(vnode);
- if (ret == 0)
+ if (ret == 0) {
+#ifdef CONFIG_AFS_FSCACHE
+ if (!vnode->cache) {
+ vnode->cache =
+ fscache_acquire_cookie(vnode->volume->cache,
+ &afs_vnode_cache_index_def,
+ vnode);
+ if (!vnode->cache)
+ printk("Negative\n");
+ }
+#endif
ret = afs_inode_map_status(vnode);
+#ifdef CONFIG_AFS_FSCACHE
+ if (ret < 0) {
+ fscache_relinquish_cookie(vnode->cache, 0);
+ vnode->cache = NULL;
+ }
+#endif
+ }
+ _leave(" = %d", ret);
return ret;
} /* end afs_inode_fetch_status() */
@@ -122,6 +147,7 @@ static int afs_iget5_test(struct inode *
return inode->i_ino == data->fid.vnode &&
inode->i_version == data->fid.unique;
+
} /* end afs_iget5_test() */
/*****************************************************************************/
@@ -179,20 +205,11 @@ inline int afs_iget(struct super_block *
return ret;
}
-#ifdef AFS_CACHING_SUPPORT
- /* set up caching before reading the status, as fetch-status reads the
- * first page of symlinks to see if they're really mntpts */
- cachefs_acquire_cookie(vnode->volume->cache,
- NULL,
- vnode,
- &vnode->cache);
-#endif
-
/* okay... it's a new inode */
inode->i_flags |= S_NOATIME;
vnode->flags |= AFS_VNODE_CHANGED;
ret = afs_inode_fetch_status(inode);
- if (ret<0)
+ if (ret < 0)
goto bad_inode;
/* success */
@@ -278,8 +295,8 @@ void afs_clear_inode(struct inode *inode
afs_vnode_give_up_callback(vnode);
-#ifdef AFS_CACHING_SUPPORT
- cachefs_relinquish_cookie(vnode->cache, 0);
+#ifdef CONFIG_AFS_FSCACHE
+ fscache_relinquish_cookie(vnode->cache, 0);
vnode->cache = NULL;
#endif
--- linux-2.6.16.noarch/fs/afs/internal.h.fsafs 2006-06-07 14:26:17.231745000 -0400
+++ linux-2.6.16.noarch/fs/afs/internal.h 2006-06-07 14:34:54.224675000 -0400
@@ -16,15 +16,17 @@
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/pagemap.h>
+#include <linux/fscache.h>
/*
* debug tracing
*/
-#define kenter(FMT, a...) printk("==> %s("FMT")\n",__FUNCTION__ , ## a)
-#define kleave(FMT, a...) printk("<== %s()"FMT"\n",__FUNCTION__ , ## a)
-#define kdebug(FMT, a...) printk(FMT"\n" , ## a)
-#define kproto(FMT, a...) printk("### "FMT"\n" , ## a)
-#define knet(FMT, a...) printk(FMT"\n" , ## a)
+#define __kdbg(FMT, a...) printk("[%05d] "FMT"\n", current->pid , ## a)
+#define kenter(FMT, a...) __kdbg("==> %s("FMT")", __FUNCTION__ , ## a)
+#define kleave(FMT, a...) __kdbg("<== %s()"FMT, __FUNCTION__ , ## a)
+#define kdebug(FMT, a...) __kdbg(FMT , ## a)
+#define kproto(FMT, a...) __kdbg("### "FMT , ## a)
+#define knet(FMT, a...) __kdbg(FMT , ## a)
#ifdef __KDEBUG
#define _enter(FMT, a...) kenter(FMT , ## a)
@@ -56,9 +58,6 @@ static inline void afs_discard_my_signal
*/
extern struct rw_semaphore afs_proc_cells_sem;
extern struct list_head afs_proc_cells;
-#ifdef AFS_CACHING_SUPPORT
-extern struct cachefs_index_def afs_cache_cell_index_def;
-#endif
/*
* dir.c
@@ -72,11 +71,6 @@ extern const struct file_operations afs_
extern struct address_space_operations afs_fs_aops;
extern struct inode_operations afs_file_inode_operations;
-#ifdef AFS_CACHING_SUPPORT
-extern int afs_cache_get_page_cookie(struct page *page,
- struct cachefs_page **_page_cookie);
-#endif
-
/*
* inode.c
*/
@@ -97,8 +91,8 @@ extern void afs_key_unregister(void);
/*
* main.c
*/
-#ifdef AFS_CACHING_SUPPORT
-extern struct cachefs_netfs afs_cache_netfs;
+#ifdef CONFIG_AFS_FSCACHE
+extern struct fscache_netfs afs_cache_netfs;
#endif
/*
--- linux-2.6.16.noarch/fs/afs/main.c.fsafs 2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.noarch/fs/afs/main.c 2006-06-07 14:34:54.247676000 -0400
@@ -1,6 +1,6 @@
/* main.c: AFS client file system
*
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2002,5 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells at redhat.com)
*
* This program is free software; you can redistribute it and/or
@@ -14,11 +14,11 @@
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/completion.h>
+#include <linux/fscache.h>
#include <rxrpc/rxrpc.h>
#include <rxrpc/transport.h>
#include <rxrpc/call.h>
#include <rxrpc/peer.h>
-#include "cache.h"
#include "cell.h"
#include "server.h"
#include "fsclient.h"
@@ -51,12 +51,11 @@ static struct rxrpc_peer_ops afs_peer_op
struct list_head afs_cb_hash_tbl[AFS_CB_HASH_COUNT];
DEFINE_SPINLOCK(afs_cb_hash_lock);
-#ifdef AFS_CACHING_SUPPORT
-static struct cachefs_netfs_operations afs_cache_ops = {
- .get_page_cookie = afs_cache_get_page_cookie,
+#ifdef CONFIG_AFS_FSCACHE
+static struct fscache_netfs_operations afs_cache_ops = {
};
-struct cachefs_netfs afs_cache_netfs = {
+struct fscache_netfs afs_cache_netfs = {
.name = "afs",
.version = 0,
.ops = &afs_cache_ops,
@@ -83,10 +82,9 @@ static int __init afs_init(void)
if (ret < 0)
return ret;
-#ifdef AFS_CACHING_SUPPORT
+#ifdef CONFIG_AFS_FSCACHE
/* we want to be able to cache */
- ret = cachefs_register_netfs(&afs_cache_netfs,
- &afs_cache_cell_index_def);
+ ret = fscache_register_netfs(&afs_cache_netfs);
if (ret < 0)
goto error;
#endif
@@ -137,8 +135,8 @@ static int __init afs_init(void)
afs_key_unregister();
error_cache:
#endif
-#ifdef AFS_CACHING_SUPPORT
- cachefs_unregister_netfs(&afs_cache_netfs);
+#ifdef CONFIG_AFS_FSCACHE
+ fscache_unregister_netfs(&afs_cache_netfs);
error:
#endif
afs_cell_purge();
@@ -167,8 +165,8 @@ static void __exit afs_exit(void)
#ifdef CONFIG_KEYS_TURNED_OFF
afs_key_unregister();
#endif
-#ifdef AFS_CACHING_SUPPORT
- cachefs_unregister_netfs(&afs_cache_netfs);
+#ifdef CONFIG_AFS_FSCACHE
+ fscache_unregister_netfs(&afs_cache_netfs);
#endif
afs_proc_cleanup();
--- linux-2.6.16.noarch/fs/afs/mntpt.c.fsafs 2006-06-07 14:26:17.240747000 -0400
+++ linux-2.6.16.noarch/fs/afs/mntpt.c 2006-06-07 14:34:54.270672000 -0400
@@ -82,7 +82,7 @@ int afs_mntpt_check_symlink(struct afs_v
ret = -EIO;
wait_on_page_locked(page);
- buf = kmap(page);
+ buf = kmap_atomic(page, KM_USER0);
if (!PageUptodate(page))
goto out_free;
if (PageError(page))
@@ -105,7 +105,7 @@ int afs_mntpt_check_symlink(struct afs_v
ret = 0;
out_free:
- kunmap(page);
+ kunmap_atomic(buf, KM_USER0);
page_cache_release(page);
out:
_leave(" = %d", ret);
@@ -195,9 +195,9 @@ static struct vfsmount *afs_mntpt_do_aut
if (!PageUptodate(page) || PageError(page))
goto error;
- buf = kmap(page);
+ buf = kmap_atomic(page, KM_USER0);
memcpy(devname, buf, size);
- kunmap(page);
+ kunmap_atomic(buf, KM_USER0);
page_cache_release(page);
page = NULL;
@@ -276,12 +276,12 @@ static void *afs_mntpt_follow_link(struc
*/
static void afs_mntpt_expiry_timed_out(struct afs_timer *timer)
{
- kenter("");
+// kenter("");
mark_mounts_for_expiry(&afs_vfsmounts);
afs_kafstimod_add_timer(&afs_mntpt_expiry_timer,
afs_mntpt_expiry_timeout * HZ);
- kleave("");
+// kleave("");
} /* end afs_mntpt_expiry_timed_out() */
--- linux-2.6.16.noarch/fs/afs/proc.c.fsafs 2006-06-07 14:26:17.251748000 -0400
+++ linux-2.6.16.noarch/fs/afs/proc.c 2006-06-07 14:34:54.278672000 -0400
@@ -177,6 +177,7 @@ int afs_proc_init(void)
*/
void afs_proc_cleanup(void)
{
+ remove_proc_entry("rootcell", proc_afs);
remove_proc_entry("cells", proc_afs);
remove_proc_entry("fs/afs", NULL);
--- linux-2.6.16.noarch/fs/afs/server.c.fsafs 2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.noarch/fs/afs/server.c 2006-06-07 14:34:54.302673000 -0400
@@ -377,7 +377,6 @@ int afs_server_request_callslot(struct a
else if (list_empty(&server->fs_callq)) {
/* no one waiting */
server->fs_conn_cnt[nconn]++;
- spin_unlock(&server->fs_lock);
}
else {
/* someone's waiting - dequeue them and wake them up */
@@ -395,9 +394,9 @@ int afs_server_request_callslot(struct a
}
pcallslot->ready = 1;
wake_up_process(pcallslot->task);
- spin_unlock(&server->fs_lock);
}
+ spin_unlock(&server->fs_lock);
rxrpc_put_connection(callslot->conn);
callslot->conn = NULL;
--- linux-2.6.16.noarch/fs/afs/vlocation.c.fsafs 2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.noarch/fs/afs/vlocation.c 2006-06-07 14:34:54.325674000 -0400
@@ -59,17 +59,21 @@ static LIST_HEAD(afs_vlocation_update_pe
static struct afs_vlocation *afs_vlocation_update; /* VL currently being updated */
static DEFINE_SPINLOCK(afs_vlocation_update_lock); /* lock guarding update queue */
-#ifdef AFS_CACHING_SUPPORT
-static cachefs_match_val_t afs_vlocation_cache_match(void *target,
- const void *entry);
-static void afs_vlocation_cache_update(void *source, void *entry);
-
-struct cachefs_index_def afs_vlocation_cache_index_def = {
- .name = "vldb",
- .data_size = sizeof(struct afs_cache_vlocation),
- .keys[0] = { CACHEFS_INDEX_KEYS_ASCIIZ, 64 },
- .match = afs_vlocation_cache_match,
- .update = afs_vlocation_cache_update,
+#ifdef CONFIG_AFS_FSCACHE
+static uint16_t afs_vlocation_cache_get_key(const void *cookie_netfs_data,
+ void *buffer, uint16_t buflen);
+static uint16_t afs_vlocation_cache_get_aux(const void *cookie_netfs_data,
+ void *buffer, uint16_t buflen);
+static fscache_checkaux_t afs_vlocation_cache_check_aux(void *cookie_netfs_data,
+ const void *buffer,
+ uint16_t buflen);
+
+static struct fscache_cookie_def afs_vlocation_cache_index_def = {
+ .name = "AFS.vldb",
+ .type = FSCACHE_COOKIE_TYPE_INDEX,
+ .get_key = afs_vlocation_cache_get_key,
+ .get_aux = afs_vlocation_cache_get_aux,
+ .check_aux = afs_vlocation_cache_check_aux,
};
#endif
@@ -300,13 +304,12 @@ int afs_vlocation_lookup(struct afs_cell
list_add_tail(&vlocation->link, &cell->vl_list);
-#ifdef AFS_CACHING_SUPPORT
+#ifdef CONFIG_AFS_FSCACHE
/* we want to store it in the cache, plus it might already be
* encached */
- cachefs_acquire_cookie(cell->cache,
- &afs_volume_cache_index_def,
- vlocation,
- &vlocation->cache);
+ vlocation->cache = fscache_acquire_cookie(cell->cache,
+ &afs_vlocation_cache_index_def,
+ vlocation);
if (vlocation->valid)
goto found_in_cache;
@@ -341,7 +344,7 @@ int afs_vlocation_lookup(struct afs_cell
active:
active = 1;
-#ifdef AFS_CACHING_SUPPORT
+#ifdef CONFIG_AFS_FSCACHE
found_in_cache:
#endif
/* try to look up a cached volume in the cell VL databases by ID */
@@ -423,9 +426,9 @@ int afs_vlocation_lookup(struct afs_cell
afs_kafstimod_add_timer(&vlocation->upd_timer, 10 * HZ);
-#ifdef AFS_CACHING_SUPPORT
+#ifdef CONFIG_AFS_FSCACHE
/* update volume entry in local cache */
- cachefs_update_cookie(vlocation->cache);
+ fscache_update_cookie(vlocation->cache);
#endif
*_vlocation = vlocation;
@@ -439,8 +442,8 @@ int afs_vlocation_lookup(struct afs_cell
}
else {
list_del(&vlocation->link);
-#ifdef AFS_CACHING_SUPPORT
- cachefs_relinquish_cookie(vlocation->cache, 0);
+#ifdef CONFIG_AFS_FSCACHE
+ fscache_relinquish_cookie(vlocation->cache, 0);
#endif
afs_put_cell(vlocation->cell);
kfree(vlocation);
@@ -538,8 +541,8 @@ void afs_vlocation_do_timeout(struct afs
}
/* we can now destroy it properly */
-#ifdef AFS_CACHING_SUPPORT
- cachefs_relinquish_cookie(vlocation->cache, 0);
+#ifdef CONFIG_AFS_FSCACHE
+ fscache_relinquish_cookie(vlocation->cache, 0);
#endif
afs_put_cell(cell);
@@ -890,65 +893,103 @@ static void afs_vlocation_update_discard
/*****************************************************************************/
/*
- * match a VLDB record stored in the cache
- * - may also load target from entry
+ * set the key for the index entry
*/
-#ifdef AFS_CACHING_SUPPORT
-static cachefs_match_val_t afs_vlocation_cache_match(void *target,
- const void *entry)
-{
- const struct afs_cache_vlocation *vldb = entry;
- struct afs_vlocation *vlocation = target;
-
- _enter("{%s},{%s}", vlocation->vldb.name, vldb->name);
-
- if (strncmp(vlocation->vldb.name, vldb->name, sizeof(vldb->name)) == 0
- ) {
- if (!vlocation->valid ||
- vlocation->vldb.rtime == vldb->rtime
- ) {
- vlocation->vldb = *vldb;
- vlocation->valid = 1;
- _leave(" = SUCCESS [c->m]");
- return CACHEFS_MATCH_SUCCESS;
- }
- /* need to update cache if cached info differs */
- else if (memcmp(&vlocation->vldb, vldb, sizeof(*vldb)) != 0) {
- /* delete if VIDs for this name differ */
- if (memcmp(&vlocation->vldb.vid,
- &vldb->vid,
- sizeof(vldb->vid)) != 0) {
- _leave(" = DELETE");
- return CACHEFS_MATCH_SUCCESS_DELETE;
- }
+#ifdef CONFIG_AFS_FSCACHE
+static uint16_t afs_vlocation_cache_get_key(const void *cookie_netfs_data,
+ void *buffer, uint16_t bufmax)
+{
+ const struct afs_vlocation *vlocation = cookie_netfs_data;
+ uint16_t klen;
- _leave(" = UPDATE");
- return CACHEFS_MATCH_SUCCESS_UPDATE;
- }
- else {
- _leave(" = SUCCESS");
- return CACHEFS_MATCH_SUCCESS;
- }
- }
+ _enter("{%s},%p,%u", vlocation->vldb.name, buffer, bufmax);
+
+ klen = strnlen(vlocation->vldb.name, sizeof(vlocation->vldb.name));
+ if (klen > bufmax)
+ return 0;
+
+ memcpy(buffer, vlocation->vldb.name, klen);
+
+ _leave(" = %u", klen);
+ return klen;
- _leave(" = FAILED");
- return CACHEFS_MATCH_FAILED;
-} /* end afs_vlocation_cache_match() */
+} /* end afs_vlocation_cache_get_key() */
#endif
/*****************************************************************************/
/*
- * update a VLDB record stored in the cache
+ * provide new auxilliary cache data
*/
-#ifdef AFS_CACHING_SUPPORT
-static void afs_vlocation_cache_update(void *source, void *entry)
+#ifdef CONFIG_AFS_FSCACHE
+static uint16_t afs_vlocation_cache_get_aux(const void *cookie_netfs_data,
+ void *buffer, uint16_t bufmax)
{
- struct afs_cache_vlocation *vldb = entry;
- struct afs_vlocation *vlocation = source;
+ const struct afs_vlocation *vlocation = cookie_netfs_data;
+ uint16_t dlen;
+
+ _enter("{%s},%p,%u", vlocation->vldb.name, buffer, bufmax);
+
+ dlen = sizeof(struct afs_cache_vlocation);
+ dlen -= offsetof(struct afs_cache_vlocation, nservers);
+ if (dlen > bufmax)
+ return 0;
+
+ memcpy(buffer, (uint8_t *)&vlocation->vldb.nservers, dlen);
- _enter("");
+ _leave(" = %u", dlen);
+ return dlen;
+
+} /* end afs_vlocation_cache_get_aux() */
+#endif
+
+/*****************************************************************************/
+/*
+ * check that the auxilliary data indicates that the entry is still valid
+ */
+#ifdef CONFIG_AFS_FSCACHE
+static fscache_checkaux_t afs_vlocation_cache_check_aux(void *cookie_netfs_data,
+ const void *buffer,
+ uint16_t buflen)
+{
+ const struct afs_cache_vlocation *cvldb;
+ struct afs_vlocation *vlocation = cookie_netfs_data;
+ uint16_t dlen;
+
+ _enter("{%s},%p,%u", vlocation->vldb.name, buffer, buflen);
+
+ /* check the size of the data is what we're expecting */
+ dlen = sizeof(struct afs_cache_vlocation);
+ dlen -= offsetof(struct afs_cache_vlocation, nservers);
+ if (dlen != buflen)
+ return FSCACHE_CHECKAUX_OBSOLETE;
+
+ cvldb = container_of(buffer, struct afs_cache_vlocation, nservers);
+
+ /* if what's on disk is more valid than what's in memory, then use the
+ * VL record from the cache */
+ if (!vlocation->valid || vlocation->vldb.rtime == cvldb->rtime) {
+ memcpy((uint8_t *)&vlocation->vldb.nservers, buffer, dlen);
+ vlocation->valid = 1;
+ _leave(" = SUCCESS [c->m]");
+ return FSCACHE_CHECKAUX_OKAY;
+ }
+
+ /* need to update the cache if the cached info differs */
+ if (memcmp(&vlocation->vldb, buffer, dlen) != 0) {
+ /* delete if the volume IDs for this name differ */
+ if (memcmp(&vlocation->vldb.vid, &cvldb->vid,
+ sizeof(cvldb->vid)) != 0
+ ) {
+ _leave(" = OBSOLETE");
+ return FSCACHE_CHECKAUX_OBSOLETE;
+ }
+
+ _leave(" = UPDATE");
+ return FSCACHE_CHECKAUX_NEEDS_UPDATE;
+ }
- *vldb = vlocation->vldb;
+ _leave(" = OKAY");
+ return FSCACHE_CHECKAUX_OKAY;
-} /* end afs_vlocation_cache_update() */
+} /* end afs_vlocation_cache_check_aux() */
#endif
--- linux-2.6.16.noarch/fs/afs/vnode.c.fsafs 2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.noarch/fs/afs/vnode.c 2006-06-07 14:34:54.352673000 -0400
@@ -29,17 +29,30 @@ struct afs_timer_ops afs_vnode_cb_timed_
.timed_out = afs_vnode_cb_timed_out,
};
-#ifdef AFS_CACHING_SUPPORT
-static cachefs_match_val_t afs_vnode_cache_match(void *target,
- const void *entry);
-static void afs_vnode_cache_update(void *source, void *entry);
-
-struct cachefs_index_def afs_vnode_cache_index_def = {
- .name = "vnode",
- .data_size = sizeof(struct afs_cache_vnode),
- .keys[0] = { CACHEFS_INDEX_KEYS_BIN, 4 },
- .match = afs_vnode_cache_match,
- .update = afs_vnode_cache_update,
+#ifdef CONFIG_AFS_FSCACHE
+static uint16_t afs_vnode_cache_get_key(const void *cookie_netfs_data,
+ void *buffer, uint16_t buflen);
+static void afs_vnode_cache_get_attr(const void *cookie_netfs_data,
+ uint64_t *size);
+static uint16_t afs_vnode_cache_get_aux(const void *cookie_netfs_data,
+ void *buffer, uint16_t buflen);
+static fscache_checkaux_t afs_vnode_cache_check_aux(void *cookie_netfs_data,
+ const void *buffer,
+ uint16_t buflen);
+static void afs_vnode_cache_mark_pages_cached(void *cookie_netfs_data,
+ struct address_space *mapping,
+ struct pagevec *cached_pvec);
+static void afs_vnode_cache_now_uncached(void *cookie_netfs_data);
+
+struct fscache_cookie_def afs_vnode_cache_index_def = {
+ .name = "AFS.vnode",
+ .type = FSCACHE_COOKIE_TYPE_DATAFILE,
+ .get_key = afs_vnode_cache_get_key,
+ .get_attr = afs_vnode_cache_get_attr,
+ .get_aux = afs_vnode_cache_get_aux,
+ .check_aux = afs_vnode_cache_check_aux,
+ .mark_pages_cached = afs_vnode_cache_mark_pages_cached,
+ .now_uncached = afs_vnode_cache_now_uncached,
};
#endif
@@ -189,6 +202,8 @@ int afs_vnode_fetch_status(struct afs_vn
if (vnode->update_cnt > 0) {
/* someone else started a fetch */
+ _debug("conflict");
+
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&vnode->update_waitq, &myself);
@@ -220,6 +235,7 @@ int afs_vnode_fetch_status(struct afs_vn
spin_unlock(&vnode->lock);
set_current_state(TASK_RUNNING);
+ _leave(" [conflicted, %d", !!(vnode->flags & AFS_VNODE_DELETED));
return vnode->flags & AFS_VNODE_DELETED ? -ENOENT : 0;
}
@@ -342,54 +358,198 @@ int afs_vnode_give_up_callback(struct af
/*****************************************************************************/
/*
- * match a vnode record stored in the cache
+ * set the key for the index entry
*/
-#ifdef AFS_CACHING_SUPPORT
-static cachefs_match_val_t afs_vnode_cache_match(void *target,
- const void *entry)
+#ifdef CONFIG_AFS_FSCACHE
+static uint16_t afs_vnode_cache_get_key(const void *cookie_netfs_data,
+ void *buffer, uint16_t bufmax)
{
- const struct afs_cache_vnode *cvnode = entry;
- struct afs_vnode *vnode = target;
+ const struct afs_vnode *vnode = cookie_netfs_data;
+ uint16_t klen;
- _enter("{%x,%x,%Lx},{%x,%x,%Lx}",
- vnode->fid.vnode,
- vnode->fid.unique,
- vnode->status.version,
- cvnode->vnode_id,
- cvnode->vnode_unique,
- cvnode->data_version);
-
- if (vnode->fid.vnode != cvnode->vnode_id) {
- _leave(" = FAILED");
- return CACHEFS_MATCH_FAILED;
- }
+ _enter("{%x,%x,%Lx},%p,%u",
+ vnode->fid.vnode, vnode->fid.unique, vnode->status.version,
+ buffer, bufmax);
+
+ klen = sizeof(vnode->fid.vnode);
+ if (klen > bufmax)
+ return 0;
+
+ memcpy(buffer, &vnode->fid.vnode, sizeof(vnode->fid.vnode));
+
+ _leave(" = %u", klen);
+ return klen;
+
+} /* end afs_vnode_cache_get_key() */
+#endif
+
+/*****************************************************************************/
+/*
+ * provide an updated file attributes
+ */
+#ifdef CONFIG_AFS_FSCACHE
+static void afs_vnode_cache_get_attr(const void *cookie_netfs_data,
+ uint64_t *size)
+{
+ const struct afs_vnode *vnode = cookie_netfs_data;
+
+ _enter("{%x,%x,%Lx},",
+ vnode->fid.vnode, vnode->fid.unique, vnode->status.version);
+
+ *size = i_size_read((struct inode *) &vnode->vfs_inode);
+
+} /* end afs_vnode_cache_get_attr() */
+#endif
+
+/*****************************************************************************/
+/*
+ * provide new auxilliary cache data
+ */
+#ifdef CONFIG_AFS_FSCACHE
+static uint16_t afs_vnode_cache_get_aux(const void *cookie_netfs_data,
+ void *buffer, uint16_t bufmax)
+{
+ const struct afs_vnode *vnode = cookie_netfs_data;
+ uint16_t dlen;
+
+ _enter("{%x,%x,%Lx},%p,%u",
+ vnode->fid.vnode, vnode->fid.unique, vnode->status.version,
+ buffer, bufmax);
- if (vnode->fid.unique != cvnode->vnode_unique ||
- vnode->status.version != cvnode->data_version) {
- _leave(" = DELETE");
- return CACHEFS_MATCH_SUCCESS_DELETE;
+ dlen = sizeof(vnode->fid.unique) + sizeof(vnode->status.version);
+ if (dlen > bufmax)
+ return 0;
+
+ memcpy(buffer, &vnode->fid.unique, sizeof(vnode->fid.unique));
+ buffer += sizeof(vnode->fid.unique);
+ memcpy(buffer, &vnode->status.version, sizeof(vnode->status.version));
+
+ _leave(" = %u", dlen);
+ return dlen;
+
+} /* end afs_vnode_cache_get_aux() */
+#endif
+
+/*****************************************************************************/
+/*
+ * check that the auxilliary data indicates that the entry is still valid
+ */
+#ifdef CONFIG_AFS_FSCACHE
+static fscache_checkaux_t afs_vnode_cache_check_aux(void *cookie_netfs_data,
+ const void *buffer,
+ uint16_t buflen)
+{
+ struct afs_vnode *vnode = cookie_netfs_data;
+ uint16_t dlen;
+
+ _enter("{%x,%x,%Lx},%p,%u",
+ vnode->fid.vnode, vnode->fid.unique, vnode->status.version,
+ buffer, buflen);
+
+ /* check the size of the data is what we're expecting */
+ dlen = sizeof(vnode->fid.unique) + sizeof(vnode->status.version);
+ if (dlen != buflen) {
+ _leave(" = OBSOLETE [len %hx != %hx]", dlen, buflen);
+ return FSCACHE_CHECKAUX_OBSOLETE;
+ }
+
+ if (memcmp(buffer,
+ &vnode->fid.unique,
+ sizeof(vnode->fid.unique)
+ ) != 0
+ ) {
+ unsigned unique;
+
+ memcpy(&unique, buffer, sizeof(unique));
+
+ _leave(" = OBSOLETE [uniq %x != %x]",
+ unique, vnode->fid.unique);
+ return FSCACHE_CHECKAUX_OBSOLETE;
+ }
+
+ if (memcmp(buffer + sizeof(vnode->fid.unique),
+ &vnode->status.version,
+ sizeof(vnode->status.version)
+ ) != 0
+ ) {
+ afs_dataversion_t version;
+
+ memcpy(&version, buffer + sizeof(vnode->fid.unique),
+ sizeof(version));
+
+ _leave(" = OBSOLETE [vers %llx != %llx]",
+ version, vnode->status.version);
+ return FSCACHE_CHECKAUX_OBSOLETE;
}
_leave(" = SUCCESS");
- return CACHEFS_MATCH_SUCCESS;
-} /* end afs_vnode_cache_match() */
+ return FSCACHE_CHECKAUX_OKAY;
+
+} /* end afs_vnode_cache_check_aux() */
#endif
/*****************************************************************************/
/*
- * update a vnode record stored in the cache
+ * indication of pages that now have cache metadata retained
+ * - this function should mark the specified pages as now being cached
*/
-#ifdef AFS_CACHING_SUPPORT
-static void afs_vnode_cache_update(void *source, void *entry)
+#ifdef CONFIG_AFS_FSCACHE
+static void afs_vnode_cache_mark_pages_cached(void *cookie_netfs_data,
+ struct address_space *mapping,
+ struct pagevec *cached_pvec)
{
- struct afs_cache_vnode *cvnode = entry;
- struct afs_vnode *vnode = source;
+ unsigned long loop;
- _enter("");
+ for (loop = 0; loop < cached_pvec->nr; loop++) {
+ struct page *page = cached_pvec->pages[loop];
- cvnode->vnode_id = vnode->fid.vnode;
- cvnode->vnode_unique = vnode->fid.unique;
- cvnode->data_version = vnode->status.version;
+ _debug("- mark %p{%lx}", page, page->index);
-} /* end afs_vnode_cache_update() */
+ SetPagePrivate(page);
+ }
+
+} /* end afs_vnode_cache_mark_pages_cached() */
#endif
+
+/*****************************************************************************/
+/*
+ * indication the cookie is no longer uncached
+ * - this function is called when the backing store currently caching a cookie
+ * is removed
+ * - the netfs should use this to clean up any markers indicating cached pages
+ * - this is mandatory for any object that may have data
+ */
+static void afs_vnode_cache_now_uncached(void *cookie_netfs_data)
+{
+ struct afs_vnode *vnode = cookie_netfs_data;
+ struct pagevec pvec;
+ pgoff_t first;
+ int loop, nr_pages;
+
+ _enter("{%x,%x,%Lx}",
+ vnode->fid.vnode, vnode->fid.unique, vnode->status.version);
+
+ pagevec_init(&pvec, 0);
+ first = 0;
+
+ for (;;) {
+ /* grab a bunch of pages to clean */
+ nr_pages = pagevec_lookup(&pvec, vnode->vfs_inode.i_mapping,
+ first,
+ PAGEVEC_SIZE - pagevec_count(&pvec));
+ if (!nr_pages)
+ break;
+
+ for (loop = 0; loop < nr_pages; loop++)
+ ClearPagePrivate(pvec.pages[loop]);
+
+ first = pvec.pages[nr_pages - 1]->index + 1;
+
+ pvec.nr = nr_pages;
+ pagevec_release(&pvec);
+ cond_resched();
+ }
+
+ _leave("");
+
+} /* end afs_vnode_cache_now_uncached() */
--- linux-2.6.16.noarch/fs/afs/vnode.h.fsafs 2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.noarch/fs/afs/vnode.h 2006-06-07 14:34:54.374675000 -0400
@@ -13,9 +13,9 @@
#define _LINUX_AFS_VNODE_H
#include <linux/fs.h>
+#include <linux/fscache.h>
#include "server.h"
#include "kafstimod.h"
-#include "cache.h"
#ifdef __KERNEL__
@@ -32,8 +32,8 @@ struct afs_cache_vnode
afs_dataversion_t data_version; /* data version */
};
-#ifdef AFS_CACHING_SUPPORT
-extern struct cachefs_index_def afs_vnode_cache_index_def;
+#ifdef CONFIG_AFS_FSCACHE
+extern struct fscache_cookie_def afs_vnode_cache_index_def;
#endif
/*****************************************************************************/
@@ -47,8 +47,8 @@ struct afs_vnode
struct afs_volume *volume; /* volume on which vnode resides */
struct afs_fid fid; /* the file identifier for this inode */
struct afs_file_status status; /* AFS status info for this file */
-#ifdef AFS_CACHING_SUPPORT
- struct cachefs_cookie *cache; /* caching cookie */
+#ifdef CONFIG_AFS_FSCACHE
+ struct fscache_cookie *cache; /* caching cookie */
#endif
wait_queue_head_t update_waitq; /* status fetch waitqueue */
--- linux-2.6.16.noarch/fs/afs/volume.c.fsafs 2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.noarch/fs/afs/volume.c 2006-06-07 14:34:54.381677000 -0400
@@ -15,10 +15,10 @@
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/pagemap.h>
+#include <linux/fscache.h>
#include "volume.h"
#include "vnode.h"
#include "cell.h"
-#include "cache.h"
#include "cmservice.h"
#include "fsclient.h"
#include "vlclient.h"
@@ -28,18 +28,14 @@
static const char *afs_voltypes[] = { "R/W", "R/O", "BAK" };
#endif
-#ifdef AFS_CACHING_SUPPORT
-static cachefs_match_val_t afs_volume_cache_match(void *target,
- const void *entry);
-static void afs_volume_cache_update(void *source, void *entry);
-
-struct cachefs_index_def afs_volume_cache_index_def = {
- .name = "volume",
- .data_size = sizeof(struct afs_cache_vhash),
- .keys[0] = { CACHEFS_INDEX_KEYS_BIN, 1 },
- .keys[1] = { CACHEFS_INDEX_KEYS_BIN, 1 },
- .match = afs_volume_cache_match,
- .update = afs_volume_cache_update,
+#ifdef CONFIG_AFS_FSCACHE
+static uint16_t afs_volume_cache_get_key(const void *cookie_netfs_data,
+ void *buffer, uint16_t buflen);
+
+static struct fscache_cookie_def afs_volume_cache_index_def = {
+ .name = "AFS.volume",
+ .type = FSCACHE_COOKIE_TYPE_INDEX,
+ .get_key = afs_volume_cache_get_key,
};
#endif
@@ -214,11 +210,10 @@ int afs_volume_lookup(const char *name,
}
/* attach the cache and volume location */
-#ifdef AFS_CACHING_SUPPORT
- cachefs_acquire_cookie(vlocation->cache,
- &afs_vnode_cache_index_def,
- volume,
- &volume->cache);
+#ifdef CONFIG_AFS_FSCACHE
+ volume->cache = fscache_acquire_cookie(vlocation->cache,
+ &afs_volume_cache_index_def,
+ volume);
#endif
afs_get_vlocation(vlocation);
@@ -286,8 +281,8 @@ void afs_put_volume(struct afs_volume *v
up_write(&vlocation->cell->vl_sem);
/* finish cleaning up the volume */
-#ifdef AFS_CACHING_SUPPORT
- cachefs_relinquish_cookie(volume->cache, 0);
+#ifdef CONFIG_AFS_FSCACHE
+ fscache_relinquish_cookie(volume->cache, 0);
#endif
afs_put_vlocation(vlocation);
@@ -481,40 +476,25 @@ int afs_volume_release_fileserver(struct
/*****************************************************************************/
/*
- * match a volume hash record stored in the cache
+ * set the key for the index entry
*/
-#ifdef AFS_CACHING_SUPPORT
-static cachefs_match_val_t afs_volume_cache_match(void *target,
- const void *entry)
+#ifdef CONFIG_AFS_FSCACHE
+static uint16_t afs_volume_cache_get_key(const void *cookie_netfs_data,
+ void *buffer, uint16_t bufmax)
{
- const struct afs_cache_vhash *vhash = entry;
- struct afs_volume *volume = target;
+ const struct afs_volume *volume = cookie_netfs_data;
+ uint16_t klen;
- _enter("{%u},{%u}", volume->type, vhash->vtype);
+ _enter("{%u},%p,%u", volume->type, buffer, bufmax);
- if (volume->type == vhash->vtype) {
- _leave(" = SUCCESS");
- return CACHEFS_MATCH_SUCCESS;
- }
-
- _leave(" = FAILED");
- return CACHEFS_MATCH_FAILED;
-} /* end afs_volume_cache_match() */
-#endif
-
-/*****************************************************************************/
-/*
- * update a volume hash record stored in the cache
- */
-#ifdef AFS_CACHING_SUPPORT
-static void afs_volume_cache_update(void *source, void *entry)
-{
- struct afs_cache_vhash *vhash = entry;
- struct afs_volume *volume = source;
+ klen = sizeof(volume->type);
+ if (klen > bufmax)
+ return 0;
- _enter("");
+ memcpy(buffer, &volume->type, sizeof(volume->type));
- vhash->vtype = volume->type;
+ _leave(" = %u", klen);
+ return klen;
-} /* end afs_volume_cache_update() */
+} /* end afs_volume_cache_get_key() */
#endif
--- linux-2.6.16.noarch/fs/afs/volume.h.fsafs 2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.noarch/fs/afs/volume.h 2006-06-07 14:34:54.406672000 -0400
@@ -12,11 +12,11 @@
#ifndef _LINUX_AFS_VOLUME_H
#define _LINUX_AFS_VOLUME_H
+#include <linux/fscache.h>
#include "types.h"
#include "fsclient.h"
#include "kafstimod.h"
#include "kafsasyncd.h"
-#include "cache.h"
typedef enum {
AFS_VLUPD_SLEEP, /* sleeping waiting for update timer to fire */
@@ -45,24 +45,6 @@ struct afs_cache_vlocation
time_t rtime; /* last retrieval time */
};
-#ifdef AFS_CACHING_SUPPORT
-extern struct cachefs_index_def afs_vlocation_cache_index_def;
-#endif
-
-/*****************************************************************************/
-/*
- * volume -> vnode hash table entry
- */
-struct afs_cache_vhash
-{
- afs_voltype_t vtype; /* which volume variation */
- uint8_t hash_bucket; /* which hash bucket this represents */
-} __attribute__((packed));
-
-#ifdef AFS_CACHING_SUPPORT
-extern struct cachefs_index_def afs_volume_cache_index_def;
-#endif
-
/*****************************************************************************/
/*
* AFS volume location record
@@ -73,8 +55,8 @@ struct afs_vlocation
struct list_head link; /* link in cell volume location list */
struct afs_timer timeout; /* decaching timer */
struct afs_cell *cell; /* cell to which volume belongs */
-#ifdef AFS_CACHING_SUPPORT
- struct cachefs_cookie *cache; /* caching cookie */
+#ifdef CONFIG_AFS_FSCACHE
+ struct fscache_cookie *cache; /* caching cookie */
#endif
struct afs_cache_vlocation vldb; /* volume information DB record */
struct afs_volume *vols[3]; /* volume access record pointer (index by type) */
@@ -109,8 +91,8 @@ struct afs_volume
atomic_t usage;
struct afs_cell *cell; /* cell to which belongs (unrefd ptr) */
struct afs_vlocation *vlocation; /* volume location */
-#ifdef AFS_CACHING_SUPPORT
- struct cachefs_cookie *cache; /* caching cookie */
+#ifdef CONFIG_AFS_FSCACHE
+ struct fscache_cookie *cache; /* caching cookie */
#endif
afs_volid_t vid; /* volume ID */
afs_voltype_t type; /* type of volume */
--- linux-2.6.16.noarch/fs/Kconfig.fsafs 2006-06-07 14:27:22.671396000 -0400
+++ linux-2.6.16.noarch/fs/Kconfig 2006-06-07 14:34:54.059673000 -0400
@@ -1908,6 +1908,13 @@ config AFS_FS
If unsure, say N.
+config AFS_FSCACHE
+ bool "Provide AFS client caching support"
+ depends on AFS_FS && FSCACHE && EXPERIMENTAL
+ help
+ Say Y here if you want AFS data to be cached locally on through the
+ generic filesystem cache manager
+
config RXRPC
tristate
linux-2.6.17-cachefiles-misc.patch:
fs/buffer.c | 2
fs/fcntl.c | 2
fs/file_table.c | 1
include/linux/pagemap.h | 6 ++
mm/filemap.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 114 insertions(+)
--- NEW FILE linux-2.6.17-cachefiles-misc.patch ---
--- linux-2.6.16.noarch/fs/buffer.c.cfmisc 2006-06-07 12:11:04.692145000 -0400
+++ linux-2.6.16.noarch/fs/buffer.c 2006-06-07 13:00:17.200895000 -0400
@@ -185,6 +185,8 @@ int fsync_super(struct super_block *sb)
return sync_blockdev(sb->s_bdev);
}
+EXPORT_SYMBOL(fsync_super);
+
/*
* Write out and wait upon all dirty data associated with this
* device. Filesystem data as well as the underlying block
--- linux-2.6.16.noarch/fs/fcntl.c.cfmisc 2006-06-07 12:12:01.255570000 -0400
+++ linux-2.6.16.noarch/fs/fcntl.c 2006-06-07 13:00:17.229895000 -0400
@@ -531,6 +531,8 @@ int send_sigurg(struct fown_struct *fown
return ret;
}
+EXPORT_SYMBOL(send_sigurg);
+
static DEFINE_RWLOCK(fasync_lock);
static kmem_cache_t *fasync_cache __read_mostly;
--- linux-2.6.16.noarch/fs/file_table.c.cfmisc 2006-06-07 12:12:08.634745000 -0400
+++ linux-2.6.16.noarch/fs/file_table.c 2006-06-07 13:00:17.258896000 -0400
@@ -265,6 +265,7 @@ struct file fastcall *fget_light(unsigne
return file;
}
+EXPORT_SYMBOL_GPL(fget_light);
void put_filp(struct file *file)
{
--- linux-2.6.16.noarch/include/linux/pagemap.h.cfmisc 2006-06-07 12:12:08.520745000 -0400
+++ linux-2.6.16.noarch/include/linux/pagemap.h 2006-06-07 13:00:17.265896000 -0400
@@ -219,6 +219,12 @@ static inline void wait_on_page_fs_misc(
extern void fastcall end_page_fs_misc(struct page *page);
/*
+ * permit installation of a state change monitor in the queue for a page
+ */
+extern void install_page_waitqueue_monitor(struct page *page,
+ wait_queue_t *monitor);
+
+/*
* Fault a userspace page into pagetables. Return non-zero on a fault.
*
* This assumes that two userspace pages are always sufficient. That's
--- linux-2.6.16.noarch/mm/filemap.c.cfmisc 2006-06-07 12:49:31.325767000 -0400
+++ linux-2.6.16.noarch/mm/filemap.c 2006-06-07 13:00:17.292895000 -0400
@@ -488,6 +488,18 @@ void fastcall wait_on_page_bit(struct pa
}
EXPORT_SYMBOL(wait_on_page_bit);
+void install_page_waitqueue_monitor(struct page *page, wait_queue_t *monitor)
+{
+ wait_queue_head_t *q = page_waitqueue(page);
+ unsigned long flags;
+
+ spin_lock_irqsave(&q->lock, flags);
+ __add_wait_queue(q, monitor);
+ spin_unlock_irqrestore(&q->lock, flags);
+}
+
+EXPORT_SYMBOL_GPL(install_page_waitqueue_monitor);
+
/**
* unlock_page() - unlock a locked page
*
@@ -2156,6 +2168,97 @@ generic_file_buffered_write(struct kiocb
}
EXPORT_SYMBOL(generic_file_buffered_write);
+/*
+ * This writes the data from the source page to the specified page offset in
+ * the nominated file
+ * - the source page does not need to have any association with the file or the
+ * page offset
+ */
+int
+generic_file_buffered_write_one_kernel_page(struct file *file,
+ pgoff_t index,
+ struct page *src)
+{
+ struct address_space *mapping = file->f_mapping;
+ struct address_space_operations *a_ops = mapping->a_ops;
+ struct pagevec lru_pvec;
+ struct page *page, *cached_page = NULL;
+ long status = 0;
+
+ pagevec_init(&lru_pvec, 0);
+
+ page = __grab_cache_page(mapping, index, &cached_page, &lru_pvec);
+ if (!page) {
+ BUG_ON(cached_page);
+ return -ENOMEM;
+ }
+
+ status = a_ops->prepare_write(file, page, 0, PAGE_CACHE_SIZE);
+ if (unlikely(status)) {
+ loff_t isize = i_size_read(mapping->host);
+
+ if (status != AOP_TRUNCATED_PAGE)
+ unlock_page(page);
+ page_cache_release(page);
+ if (status == AOP_TRUNCATED_PAGE)
+ goto sync;
+
+ /* prepare_write() may have instantiated a few blocks outside
+ * i_size. Trim these off again.
+ */
+ if ((1ULL << (index + 1)) > isize)
+ vmtruncate(mapping->host, isize);
+ goto sync;
+ }
+
+ copy_highpage(page, src);
+ flush_dcache_page(page);
+
+ status = a_ops->commit_write(file, page, 0, PAGE_CACHE_SIZE);
+ if (status == AOP_TRUNCATED_PAGE) {
+ page_cache_release(page);
+ goto sync;
+ }
+
+ if (status > 0)
+ status = 0;
+
+ unlock_page(page);
+ mark_page_accessed(page);
+ page_cache_release(page);
+ if (status < 0)
+ return status;
+
+ balance_dirty_pages_ratelimited(mapping);
+ cond_resched();
+
+sync:
+ if (cached_page)
+ page_cache_release(cached_page);
+
+ /*
+ * For now, when the user asks for O_SYNC, we'll actually give O_DSYNC
+ */
+ if (unlikely((file->f_flags & O_SYNC) || IS_SYNC(mapping->host))) {
+ if (!a_ops->writepage)
+ status = generic_osync_inode(
+ mapping->host, mapping,
+ OSYNC_METADATA | OSYNC_DATA);
+ }
+
+ /*
+ * If we get here for O_DIRECT writes then we must have fallen through
+ * to buffered writes (block instantiation inside i_size). So we sync
+ * the file data here, to try to honour O_DIRECT expectations.
+ */
+ if (unlikely(file->f_flags & O_DIRECT))
+ status = filemap_write_and_wait(mapping);
+
+ pagevec_lru_add(&lru_pvec);
+ return status;
+}
+EXPORT_SYMBOL(generic_file_buffered_write_one_kernel_page);
+
static ssize_t
__generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t *ppos)
linux-2.6.17-cachefiles.patch:
Documentation/filesystems/caching/cachefiles.txt | 281 ++++
fs/Kconfig | 20
fs/Makefile | 1
fs/cachefiles/Makefile | 18
fs/cachefiles/cf-bind.c | 283 ++++
fs/cachefiles/cf-interface.c | 1312 +++++++++++++++++++++++
fs/cachefiles/cf-key.c | 160 ++
fs/cachefiles/cf-main.c | 131 ++
fs/cachefiles/cf-namei.c | 837 ++++++++++++++
fs/cachefiles/cf-proc.c | 510 ++++++++
fs/cachefiles/cf-sysctl.c | 69 +
fs/cachefiles/cf-xattr.c | 299 +++++
fs/cachefiles/internal.h | 308 +++++
13 files changed, 4229 insertions(+)
--- NEW FILE linux-2.6.17-cachefiles.patch ---
--- /dev/null 2006-06-07 07:14:18.564562589 -0400
+++ linux-2.6.16.noarch/Documentation/filesystems/caching/cachefiles.txt 2006-06-07 12:58:10.508720000 -0400
@@ -0,0 +1,281 @@
+ ===============================================
+ CacheFiles: CACHE ON ALREADY MOUNTED FILESYSTEM
+ ===============================================
+
+Contents:
+
+ (*) Overview.
+
+ (*) Requirements.
+
+ (*) Configuration.
+
+ (*) Starting the cache.
+
+ (*) Things to avoid.
+
+
+========
+OVERVIEW
+========
+
+CacheFiles is a caching backend that's meant to use as a cache a directory on
+an already mounted filesystem of a local type (such as Ext3).
+
+CacheFiles uses a userspace daemon to do some of the cache management - such as
+reaping stale nodes and culling. This is called cachefilesd and lives in
+/sbin.
+
+The filesystem and data integrity of the cache are only as good as those of the
+filesystem providing the backing services. Note that CacheFiles does not
+attempt to journal anything since the journalling interfaces of the various
+filesystems are very specific in nature.
+
+CacheFiles creates a proc-file - "/proc/fs/cachefiles" - that is used for
+communication with the daemon. Only one thing may have this open at once, and
+whilst it is open, a cache is at least partially in existence. The daemon
+opens this and sends commands down it to control the cache.
+
+CacheFiles is currently limited to a single cache.
+
+CacheFiles attempts to maintain at least a certain percentage of free space on
+the filesystem, shrinking the cache by culling the objects it contains to make
+space if necessary - see the "Cache Culling" section. This means it can be
+placed on the same medium as a live set of data, and will expand to make use of
+spare space and automatically contract when the set of data requires more
+space.
+
+
+============
+REQUIREMENTS
+============
+
+The use of CacheFiles and its daemon requires the following features to be
+available in the system and in the cache filesystem:
+
+ - dnotify.
+
+ - extended attributes (xattrs).
+
+ - openat() and friends.
+
+ - bmap() support on files in the filesystem (FIBMAP ioctl).
+
+ - The use of bmap() to detect a partial page at the end of the file.
+
+It is strongly recommended that the "dir_index" option is enabled on Ext3
+filesystems being used as a cache.
+
+
+=============
+CONFIGURATION
+=============
+
+The cache is configured by a script in /etc/cachefilesd.conf. These commands
+set up cache ready for use. The following script commands are available:
+
+ (*) brun <N>%
+ (*) bcull <N>%
+ (*) bstop <N>%
+
+ Configure the culling limits. Optional. See the section on culling
+ The defaults are 7%, 5% and 1% respectively.
+
+ (*) dir <path>
+
+ Specify the directory containing the root of the cache. Mandatory.
+
+ (*) tag <name>
+
+ Specify a tag to FS-Cache to use in distinguishing multiple caches.
+ Optional. The default is "CacheFiles".
+
+ (*) debug <mask>
+
+ Specify a numeric bitmask to control debugging in the kernel module.
+ Optional. The default is zero (all off). The following values can be
+ OR'd into the mask to collect various information:
+
+ 1 Turn on trace of function entry (_enter() macros)
+ 2 Turn on trace of function exit (_leave() macros)
+ 4 Turn on trace of internal debug points (_debug())
+
+ This mask can also be set through /proc/sys/fs/cachefiles/debug.
+
+
+==================
+STARTING THE CACHE
+==================
+
+The cache is started by running the daemon. The daemon opens the cache proc
+file, configures the cache and tells it to begin caching. At that point the
+cache binds to fscache and the cache becomes live.
+
+The daemon is run as follows:
+
+ /sbin/cachefilesd [-d]* [-s] [-n] [-f <configfile>]
+
+The flags are:
+
+ (*) -d
+
+ Increase the debugging level. This can be specified multiple times and
+ is cumulative with itself.
+
+ (*) -s
+
+ Send messages to stderr instead of syslog.
+
+ (*) -n
+
+ Don't daemonise and go into background.
+
+ (*) -f <configfile>
+
+ Use an alternative configuration file rather than the default one.
+
+
+===============
+THINGS TO AVOID
+===============
+
+Do not mount other things within the cache as this will cause problems. The
+kernel module contains its own very cut-down path walking facility that ignores
+mountpoints, but the daemon can't avoid them.
+
+Do not create, rename or unlink files and directories in the cache whilst the
+cache is active, as this may cause the state to become uncertain.
+
+Renaming files in the cache might make objects appear to be other objects (the
+filename is part of the lookup key).
+
+Do not change or remove the extended attributes attached to cache files by the
+cache as this will cause the cache state management to get confused.
+
+Do not create files or directories in the cache, lest the cache get confused or
+serve incorrect data.
+
+Do not chmod files in the cache. The module creates things with minimal
+permissions to prevent random users being able to access them directly.
+
+
+=============
+CACHE CULLING
+=============
+
+The cache may need culling occasionally to make space. This involves
+discarding objects from the cache that have been used less recently than
+anything else. Culling is based on the access time of data objects. Empty
+directories are culled if not in use.
+
+Cache culling is done on the basis of the percentage of blocks available in the
+underlying filesystem. There are three "limits":
+
+ (*) brun
+
+ If the amount of available space in the cache rises above this limit, then
+ culling is turned off.
+
+ (*) bcull
+
+ If the amount of available space in the cache falls below this limit, then
+ culling is started.
+
+ (*) bstop
+
+ If the amount of available space in the cache falls below this limit, then
+ no further allocation of disk space is permitted until culling has raised
+ the amount above this limit again.
+
+These must be configured thusly:
+
+ 0 <= bstop < bcull < brun < 100
+
+Note that these are percentages of available space, and do _not_ appear as 100
+minus the percentage displayed by the "df" program.
+
[...3881 lines suppressed...]
+ fscache_rw_complete_t end_io_func;
+ void *context;
+};
+
+/*****************************************************************************/
+/*
+ * backing file write tracking
+ */
+struct cachefiles_one_write {
+ struct page *netfs_page; /* netfs page to copy */
+ struct cachefiles_object *object;
+ struct list_head obj_link; /* link in object's lists */
+ fscache_rw_complete_t end_io_func;
+ void *context;
+};
+
+/*****************************************************************************/
+/*
+ * auxiliary data xattr buffer
+ */
+struct cachefiles_xattr {
+ uint16_t len;
+ uint8_t type;
+ uint8_t data[];
+};
+
+
+/* cf-bind.c */
+extern int cachefiles_proc_bind(struct cachefiles_cache *cache, char *args);
+extern void cachefiles_proc_unbind(struct cachefiles_cache *cache);
+
+/* cf-interface.c */
+extern void cachefiles_read_copier_work(void *_object);
+extern void cachefiles_write_work(void *_object);
+extern int cachefiles_has_space(struct cachefiles_cache *cache, unsigned nr);
+
+/* cf-key.c */
+extern char *cachefiles_cook_key(const u8 *raw, int keylen, uint8_t type);
+
+/* cf-namei.c */
+extern int cachefiles_delete_object(struct cachefiles_cache *cache,
+ struct cachefiles_object *object);
+extern int cachefiles_walk_to_object(struct cachefiles_object *parent,
+ struct cachefiles_object *object,
+ char *key,
+ struct cachefiles_xattr *auxdata);
+extern struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache,
+ struct dentry *dir,
+ const char *name);
+
+extern int cachefiles_cull(struct cachefiles_cache *cache, struct dentry *dir,
+ char *filename);
+
+/* cf-sysctl.c */
+extern int __init cachefiles_sysctl_init(void);
+extern void __exit cachefiles_sysctl_cleanup(void);
+
+/* cf-xattr.c */
+extern int cachefiles_check_object_type(struct cachefiles_object *object);
+extern int cachefiles_set_object_xattr(struct cachefiles_object *object,
+ struct cachefiles_xattr *auxdata);
+extern int cachefiles_check_object_xattr(struct cachefiles_object *object,
+ struct cachefiles_xattr *auxdata);
+extern int cachefiles_remove_object_xattr(struct cachefiles_cache *cache,
+ struct dentry *dentry);
+
+
+/*****************************************************************************/
+/*
+ * error handling
+ */
+#define kerror(FMT,...) printk(KERN_ERR "CacheFiles: "FMT"\n" ,##__VA_ARGS__);
+
+#define cachefiles_io_error(___cache, FMT, ...) \
+do { \
+ kerror("I/O Error: " FMT ,##__VA_ARGS__); \
+ fscache_io_error(&(___cache)->cache); \
+ set_bit(CACHEFILES_DEAD, &(___cache)->flags); \
+} while(0)
+
+#define cachefiles_io_error_obj(object, FMT, ...) \
+do { \
+ struct cachefiles_cache *___cache; \
+ \
+ ___cache = container_of((object)->fscache.cache, \
+ struct cachefiles_cache, cache); \
+ cachefiles_io_error(___cache, FMT ,##__VA_ARGS__); \
+} while(0)
+
+
+/*****************************************************************************/
+/*
+ * debug tracing
+ */
+#define dbgprintk(FMT,...) \
+ printk("[%-6.6s] "FMT"\n",current->comm ,##__VA_ARGS__)
+
+/* make sure we maintain the format strings, even when debugging is disabled */
+static inline void _dbprintk(const char *fmt, ...)
+ __attribute__((format(printf,1,2)));
+static inline void _dbprintk(const char *fmt, ...)
+{
+}
+
+#define kenter(FMT,...) dbgprintk("==> %s("FMT")",__FUNCTION__ ,##__VA_ARGS__)
+#define kleave(FMT,...) dbgprintk("<== %s()"FMT"",__FUNCTION__ ,##__VA_ARGS__)
+#define kdebug(FMT,...) dbgprintk(FMT ,##__VA_ARGS__)
+
+
+#if defined(__KDEBUG)
+#define _enter(FMT,...) kenter(FMT,##__VA_ARGS__)
+#define _leave(FMT,...) kleave(FMT,##__VA_ARGS__)
+#define _debug(FMT,...) kdebug(FMT,##__VA_ARGS__)
+
+#elif defined(CONFIG_CACHEFILES_DEBUG)
+#define _enter(FMT,...) \
+do { \
+ if (cachefiles_debug & CACHEFILES_DEBUG_KENTER) \
+ kenter(FMT,##__VA_ARGS__); \
+} while (0)
+
+#define _leave(FMT,...) \
+do { \
+ if (cachefiles_debug & CACHEFILES_DEBUG_KLEAVE) \
+ kleave(FMT,##__VA_ARGS__); \
+} while (0)
+
+#define _debug(FMT,...) \
+do { \
+ if (cachefiles_debug & CACHEFILES_DEBUG_KDEBUG) \
+ kdebug(FMT,##__VA_ARGS__); \
+} while (0)
+
+#else
+#define _enter(FMT,...) _dbprintk("==> %s("FMT")",__FUNCTION__ ,##__VA_ARGS__)
+#define _leave(FMT,...) _dbprintk("<== %s()"FMT"",__FUNCTION__ ,##__VA_ARGS__)
+#define _debug(FMT,...) _dbprintk(FMT ,##__VA_ARGS__)
+#endif
+
+#if 1 // defined(__KDEBUGALL)
+
+#define ASSERT(X) \
+do { \
+ if (unlikely(!(X))) { \
+ printk(KERN_ERR "\n"); \
+ printk(KERN_ERR "CacheFiles: Assertion failed\n"); \
+ BUG(); \
+ } \
+} while(0)
+
+#define ASSERTCMP(X, OP, Y) \
+do { \
+ if (unlikely(!((X) OP (Y)))) { \
+ printk(KERN_ERR "\n"); \
+ printk(KERN_ERR "CacheFiles: Assertion failed\n"); \
+ printk(KERN_ERR "%lx " #OP " %lx is false\n", \
+ (unsigned long)(X), (unsigned long)(Y)); \
+ BUG(); \
+ } \
+} while(0)
+
+#define ASSERTIF(C, X) \
+do { \
+ if (unlikely((C) && !(X))) { \
+ printk(KERN_ERR "\n"); \
+ printk(KERN_ERR "CacheFiles: Assertion failed\n"); \
+ BUG(); \
+ } \
+} while(0)
+
+#define ASSERTIFCMP(C, X, OP, Y) \
+do { \
+ if (unlikely((C) && !((X) OP (Y)))) { \
+ printk(KERN_ERR "\n"); \
+ printk(KERN_ERR "CacheFiles: Assertion failed\n"); \
+ printk(KERN_ERR "%lx " #OP " %lx is false\n", \
+ (unsigned long)(X), (unsigned long)(Y)); \
+ BUG(); \
+ } \
+} while(0)
+
+#else
+
+#define ASSERT(X) \
+do { \
+} while(0)
+
+#define ASSERTCMP(X, OP, Y) \
+do { \
+} while(0)
+
+#define ASSERTIF(C, X) \
+do { \
+} while(0)
+
+#define ASSERTIFCMP(C, X, OP, Y) \
+do { \
+} while(0)
+
+#endif
linux-2.6.17-cachefs-fsmisc.patch:
fs/afs/dir.c | 5 +----
fs/ext2/dir.c | 6 +++---
fs/ext3/inode.c | 10 +++++-----
fs/freevxfs/vxfs_subr.c | 2 +-
fs/reiserfs/inode.c | 10 +++++-----
include/linux/page-flags.h | 15 ++++++++++-----
include/linux/pagemap.h | 11 +++++++++++
mm/filemap.c | 17 +++++++++++++++++
mm/migrate.c | 4 ++--
mm/page_alloc.c | 2 +-
10 files changed, 56 insertions(+), 26 deletions(-)
--- NEW FILE linux-2.6.17-cachefs-fsmisc.patch ---
--- linux-2.6.16.noarch/fs/afs/dir.c.fsmisc 2006-06-02 13:16:11.000000000 -0400
+++ linux-2.6.16.noarch/fs/afs/dir.c 2006-06-02 13:18:39.000000000 -0400
@@ -155,11 +155,9 @@ static inline void afs_dir_check_page(st
}
}
- SetPageChecked(page);
return;
error:
- SetPageChecked(page);
SetPageError(page);
} /* end afs_dir_check_page() */
@@ -193,8 +191,7 @@ static struct page *afs_dir_get_page(str
kmap(page);
if (!PageUptodate(page))
goto fail;
- if (!PageChecked(page))
- afs_dir_check_page(dir, page);
+ afs_dir_check_page(dir, page);
if (PageError(page))
goto fail;
}
--- linux-2.6.16.noarch/fs/ext2/dir.c.fsmisc 2006-06-02 13:16:12.000000000 -0400
+++ linux-2.6.16.noarch/fs/ext2/dir.c 2006-06-02 13:18:39.000000000 -0400
@@ -112,7 +112,7 @@ static void ext2_check_page(struct page
if (offs != limit)
goto Eend;
out:
- SetPageChecked(page);
+ SetPageFsMisc(page);
return;
/* Too bad, we had an error */
@@ -152,7 +152,7 @@ Eend:
dir->i_ino, (page->index<<PAGE_CACHE_SHIFT)+offs,
(unsigned long) le32_to_cpu(p->inode));
fail:
- SetPageChecked(page);
+ SetPageFsMisc(page);
SetPageError(page);
}
@@ -166,7 +166,7 @@ static struct page * ext2_get_page(struc
kmap(page);
if (!PageUptodate(page))
goto fail;
- if (!PageChecked(page))
+ if (!PageFsMisc(page))
ext2_check_page(page);
if (PageError(page))
goto fail;
--- linux-2.6.16.noarch/fs/ext3/inode.c.fsmisc 2006-06-02 13:16:12.000000000 -0400
+++ linux-2.6.16.noarch/fs/ext3/inode.c 2006-06-02 13:18:39.000000000 -0400
@@ -1528,12 +1528,12 @@ static int ext3_journalled_writepage(str
goto no_write;
}
- if (!page_has_buffers(page) || PageChecked(page)) {
+ if (!page_has_buffers(page) || PageFsMisc(page)) {
/*
* It's mmapped pagecache. Add buffers and journal it. There
* doesn't seem much point in redirtying the page here.
*/
- ClearPageChecked(page);
+ ClearPageFsMisc(page);
ret = block_prepare_write(page, 0, PAGE_CACHE_SIZE,
ext3_get_block);
if (ret != 0) {
@@ -1590,7 +1590,7 @@ static void ext3_invalidatepage(struct p
* If it's a full truncate we just forget about the pending dirtying
*/
if (offset == 0)
- ClearPageChecked(page);
+ ClearPageFsMisc(page);
journal_invalidatepage(journal, page, offset);
}
@@ -1599,7 +1599,7 @@ static int ext3_releasepage(struct page
{
journal_t *journal = EXT3_JOURNAL(page->mapping->host);
- WARN_ON(PageChecked(page));
+ WARN_ON(PageFsMisc(page));
if (!page_has_buffers(page))
return 0;
return journal_try_to_free_buffers(journal, page, wait);
@@ -1695,7 +1695,7 @@ out:
*/
static int ext3_journalled_set_page_dirty(struct page *page)
{
- SetPageChecked(page);
+ SetPageFsMisc(page);
return __set_page_dirty_nobuffers(page);
}
--- linux-2.6.16.noarch/fs/freevxfs/vxfs_subr.c.fsmisc 2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.noarch/fs/freevxfs/vxfs_subr.c 2006-06-02 13:18:39.000000000 -0400
@@ -79,7 +79,7 @@ vxfs_get_page(struct address_space *mapp
kmap(pp);
if (!PageUptodate(pp))
goto fail;
- /** if (!PageChecked(pp)) **/
+ /** if (!PageFsMisc(pp)) **/
/** vxfs_check_page(pp); **/
if (PageError(pp))
goto fail;
--- linux-2.6.16.noarch/fs/reiserfs/inode.c.fsmisc 2006-06-02 13:16:13.000000000 -0400
+++ linux-2.6.16.noarch/fs/reiserfs/inode.c 2006-06-02 13:18:39.000000000 -0400
@@ -2352,7 +2352,7 @@ static int reiserfs_write_full_page(stru
struct buffer_head *head, *bh;
int partial = 0;
int nr = 0;
- int checked = PageChecked(page);
+ int checked = PageFsMisc(page);
struct reiserfs_transaction_handle th;
struct super_block *s = inode->i_sb;
int bh_per_page = PAGE_CACHE_SIZE / s->s_blocksize;
@@ -2421,7 +2421,7 @@ static int reiserfs_write_full_page(stru
* blocks we're going to log
*/
if (checked) {
- ClearPageChecked(page);
+ ClearPageFsMisc(page);
reiserfs_write_lock(s);
error = journal_begin(&th, s, bh_per_page + 1);
if (error) {
@@ -2802,7 +2802,7 @@ static void reiserfs_invalidatepage(stru
BUG_ON(!PageLocked(page));
if (offset == 0)
- ClearPageChecked(page);
+ ClearPageFsMisc(page);
if (!page_has_buffers(page))
goto out;
@@ -2843,7 +2843,7 @@ static int reiserfs_set_page_dirty(struc
{
struct inode *inode = page->mapping->host;
if (reiserfs_file_data_log(inode)) {
- SetPageChecked(page);
+ SetPageFsMisc(page);
return __set_page_dirty_nobuffers(page);
}
return __set_page_dirty_buffers(page);
@@ -2866,7 +2866,7 @@ static int reiserfs_releasepage(struct p
struct buffer_head *bh;
int ret = 1;
- WARN_ON(PageChecked(page));
+ WARN_ON(PageFsMisc(page));
spin_lock(&j->j_dirty_buffers_lock);
head = page_buffers(page);
bh = head;
--- linux-2.6.16.noarch/include/linux/page-flags.h.fsmisc 2006-06-02 13:16:17.000000000 -0400
+++ linux-2.6.16.noarch/include/linux/page-flags.h 2006-06-02 13:18:39.000000000 -0400
@@ -73,7 +73,7 @@
#define PG_active 6
#define PG_slab 7 /* slab debug (Suparna wants this) */
-#define PG_checked 8 /* kill me in 2.5.<early>. */
+#define PG_fs_misc 8
#define PG_arch_1 9
#define PG_reserved 10
#define PG_private 11 /* Has something at ->private */
@@ -274,10 +274,6 @@ extern void __mod_page_state_offset(unsi
#define PageHighMem(page) 0 /* needed to optimize away at compile time */
#endif
-#define PageChecked(page) test_bit(PG_checked, &(page)->flags)
-#define SetPageChecked(page) set_bit(PG_checked, &(page)->flags)
-#define ClearPageChecked(page) clear_bit(PG_checked, &(page)->flags)
-
#define PageReserved(page) test_bit(PG_reserved, &(page)->flags)
#define SetPageReserved(page) set_bit(PG_reserved, &(page)->flags)
#define ClearPageReserved(page) clear_bit(PG_reserved, &(page)->flags)
@@ -376,4 +372,13 @@ static inline void set_page_writeback(st
test_set_page_writeback(page);
}
+/*
+ * Filesystem-specific page bit testing
+ */
+#define PageFsMisc(page) test_bit(PG_fs_misc, &(page)->flags)
+#define SetPageFsMisc(page) set_bit(PG_fs_misc, &(page)->flags)
+#define TestSetPageFsMisc(page) test_and_set_bit(PG_fs_misc, &(page)->flags)
+#define ClearPageFsMisc(page) clear_bit(PG_fs_misc, &(page)->flags)
+#define TestClearPageFsMisc(page) test_and_clear_bit(PG_fs_misc, &(page)->flags)
+
#endif /* PAGE_FLAGS_H */
--- linux-2.6.16.noarch/include/linux/pagemap.h.fsmisc 2006-06-02 13:16:17.000000000 -0400
+++ linux-2.6.16.noarch/include/linux/pagemap.h 2006-06-02 13:18:39.000000000 -0400
@@ -208,6 +208,17 @@ static inline void wait_on_page_writebac
extern void end_page_writeback(struct page *page);
/*
+ * Wait for filesystem-specific page synchronisation to complete
+ */
+static inline void wait_on_page_fs_misc(struct page *page)
+{
+ if (PageFsMisc(page))
+ wait_on_page_bit(page, PG_fs_misc);
+}
+
+extern void fastcall end_page_fs_misc(struct page *page);
+
+/*
* Fault a userspace page into pagetables. Return non-zero on a fault.
*
* This assumes that two userspace pages are always sufficient. That's
--- linux-2.6.16.noarch/mm/filemap.c.fsmisc 2006-06-02 13:16:40.000000000 -0400
+++ linux-2.6.16.noarch/mm/filemap.c 2006-06-02 13:18:39.000000000 -0400
@@ -552,6 +552,23 @@ void fastcall __lock_page(struct page *p
EXPORT_SYMBOL(__lock_page);
/*
+ * Note completion of filesystem specific page synchronisation
+ *
+ * This is used to allow a page to be written to a filesystem cache in the
+ * background without holding up the completion of readpage
+ */
+void fastcall end_page_fs_misc(struct page *page)
+{
+ smp_mb__before_clear_bit();
+ if (!TestClearPageFsMisc(page))
+ BUG();
+ smp_mb__after_clear_bit();
+ __wake_up_bit(page_waitqueue(page), &page->flags, PG_fs_misc);
+}
+
+EXPORT_SYMBOL(end_page_fs_misc);
+
+/*
* a rather lightweight function, finding and getting a reference to a
* hashed page atomically.
*/
--- linux-2.6.16.noarch/mm/migrate.c.fsmisc 2006-06-02 13:16:18.000000000 -0400
+++ linux-2.6.16.noarch/mm/migrate.c 2006-06-02 13:18:39.000000000 -0400
@@ -272,8 +272,8 @@ void migrate_page_copy(struct page *newp
SetPageUptodate(newpage);
if (PageActive(page))
SetPageActive(newpage);
- if (PageChecked(page))
- SetPageChecked(newpage);
+ if (PageFsMisc(page))
+ SetPageFsMisc(newpage);
if (PageMappedToDisk(page))
SetPageMappedToDisk(newpage);
--- linux-2.6.16.noarch/mm/page_alloc.c.fsmisc 2006-06-02 13:16:40.000000000 -0400
+++ linux-2.6.16.noarch/mm/page_alloc.c 2006-06-02 13:18:39.000000000 -0400
@@ -546,7 +546,7 @@ static int prep_new_page(struct page *pa
page->flags &= ~(1 << PG_uptodate | 1 << PG_error |
1 << PG_referenced | 1 << PG_arch_1 |
- 1 << PG_checked | 1 << PG_mappedtodisk);
+ 1 << PG_fs_misc | 1 << PG_mappedtodisk);
set_page_private(page, 0);
set_page_refcounted(page);
kernel_map_pages(page, 1 << order, 1);
linux-2.6.17-cachefs-kfile.patch:
Documentation/sysctl/fs.txt | 6 ++++-
fs/file_table.c | 48 +++++++++++++++++++++++++++++++++++---------
fs/open.c | 20 ++++++++++++++++++
include/linux/file.h | 1
include/linux/fs.h | 10 +++++++++
include/linux/sysctl.h | 1
kernel/sysctl.c | 11 ++++++++++
7 files changed, 86 insertions(+), 11 deletions(-)
--- NEW FILE linux-2.6.17-cachefs-kfile.patch ---
--- linux-2.6.16.noarch/Documentation/sysctl/fs.txt.kfile 2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.noarch/Documentation/sysctl/fs.txt 2006-06-01 10:42:02.000000000 -0400
@@ -71,7 +71,7 @@ you might want to raise the limit.
==============================================================
-file-max & file-nr:
+file-max, file-nr & file-kernel:
The kernel allocates file handles dynamically, but as yet it
doesn't free them again.
@@ -88,6 +88,10 @@ close to the maximum, but the number of
significantly greater than 0, you've encountered a peak in your
usage of file handles and you don't need to increase the maximum.
+The value in file-kernel denotes the number of internal file handles
+that the kernel has open. These do not contribute to ENFILE
+accounting.
+
==============================================================
inode-max, inode-nr & inode-state:
--- linux-2.6.16.noarch/fs/file_table.c.kfile 2006-06-01 10:38:09.000000000 -0400
+++ linux-2.6.16.noarch/fs/file_table.c 2006-06-01 10:42:02.000000000 -0400
@@ -30,10 +30,13 @@ struct files_stat_struct files_stat = {
.max_files = NR_FILE
};
+struct files_kernel_stat_struct files_kernel_stat;
+
/* public. Not pretty! */
__cacheline_aligned_in_smp DEFINE_SPINLOCK(files_lock);
static struct percpu_counter nr_files __cacheline_aligned_in_smp;
+static atomic_t nr_kernel_files;
static inline void file_free_rcu(struct rcu_head *head)
{
@@ -43,7 +46,10 @@ static inline void file_free_rcu(struct
static inline void file_free(struct file *f)
{
- percpu_counter_dec(&nr_files);
+ if (f->f_kernel_flags & FKFLAGS_NO_ENFILE)
+ atomic_dec(&nr_kernel_files);
+ else
+ percpu_counter_dec(&nr_files);
call_rcu(&f->f_u.fu_rcuhead, file_free_rcu);
}
@@ -74,45 +80,64 @@ int proc_nr_files(ctl_table *table, int
files_stat.nr_files = get_nr_files();
return proc_dointvec(table, write, filp, buffer, lenp, ppos);
}
+int proc_files_kernel(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ files_kernel_stat.nr_kernel_files = atomic_read(&nr_kernel_files);
+ return proc_dointvec(table, write, filp, buffer, lenp, ppos);
+}
#else
int proc_nr_files(ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
return -ENOSYS;
}
+int proc_files_kernel(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ return -ENOSYS;
+}
#endif
/* Find an unused file structure and return a pointer to it.
* Returns NULL, if there are no more free file structures or
* we run out of memory.
*/
-struct file *get_empty_filp(void)
+struct file *get_empty_kernel_filp(unsigned short kflags)
{
struct task_struct *tsk;
static int old_max;
struct file * f;
/*
- * Privileged users can go above max_files
+ * Privileged users can go above max_files and internal kernel users
+ * can avoid it completely
*/
- if (get_nr_files() >= files_stat.max_files && !capable(CAP_SYS_ADMIN)) {
+ if (!(kflags & FKFLAGS_NO_ENFILE) &&
+ get_nr_files() >= files_stat.max_files &&
+ !capable(CAP_SYS_ADMIN)
+ ) {
/*
- * percpu_counters are inaccurate. Do an expensive check before
- * we go and fail.
+ * percpu_counters are inaccurate. Do an expensive
+ * check before we go and fail.
*/
if (percpu_counter_sum(&nr_files) >= files_stat.max_files)
goto over;
}
- f = kmem_cache_alloc(filp_cachep, GFP_KERNEL);
+ f = kmem_cache_zalloc(filp_cachep, GFP_KERNEL);
if (f == NULL)
goto fail;
- percpu_counter_inc(&nr_files);
- memset(f, 0, sizeof(*f));
+ if (kflags & FKFLAGS_NO_ENFILE)
+ atomic_inc(&nr_kernel_files);
+ else
+ percpu_counter_inc(&nr_files);
+
if (security_file_alloc(f))
goto fail_sec;
+ f->f_kernel_flags = kflags;
tsk = current;
INIT_LIST_HEAD(&f->f_u.fu_list);
atomic_set(&f->f_count, 1);
@@ -138,6 +163,11 @@ fail:
return NULL;
}
+struct file *get_empty_filp(void)
+{
+ return get_empty_kernel_filp(0);
+}
+
EXPORT_SYMBOL(get_empty_filp);
void fastcall fput(struct file *file)
--- linux-2.6.16.noarch/fs/open.c.kfile 2006-06-01 10:38:20.000000000 -0400
+++ linux-2.6.16.noarch/fs/open.c 2006-06-01 10:42:02.000000000 -0400
@@ -978,6 +978,26 @@ struct file *dentry_open(struct dentry *
EXPORT_SYMBOL(dentry_open);
/*
+ * open a specifically in-kernel file
+ */
+struct file *dentry_open_kernel(struct dentry *dentry, struct vfsmount *mnt, int flags)
+{
+ int error;
+ struct file *f;
+
+ error = -ENFILE;
+ f = get_empty_kernel_filp(FKFLAGS_NO_ENFILE);
+ if (f == NULL) {
+ dput(dentry);
+ mntput(mnt);
+ return ERR_PTR(error);
+ }
+
+ return __dentry_open(dentry, mnt, flags, f, NULL);
+}
+EXPORT_SYMBOL_GPL(dentry_open_kernel);
+
+/*
* Find an empty file descriptor entry, and mark it busy.
*/
int get_unused_fd(void)
--- linux-2.6.16.noarch/include/linux/file.h.kfile 2006-06-01 10:38:18.000000000 -0400
+++ linux-2.6.16.noarch/include/linux/file.h 2006-06-01 10:42:02.000000000 -0400
@@ -79,7 +79,6 @@ extern void FASTCALL(set_close_on_exec(u
extern void put_filp(struct file *);
extern int get_unused_fd(void);
extern void FASTCALL(put_unused_fd(unsigned int fd));
-struct kmem_cache;
extern struct file ** alloc_fd_array(int);
extern void free_fd_array(struct file **, int);
--- linux-2.6.16.noarch/include/linux/fs.h.kfile 2006-06-01 10:38:19.000000000 -0400
+++ linux-2.6.16.noarch/include/linux/fs.h 2006-06-01 10:42:02.000000000 -0400
@@ -34,7 +34,11 @@ struct files_stat_struct {
int nr_free_files; /* read only */
int max_files; /* tunable */
};
+struct files_kernel_stat_struct {
+ int nr_kernel_files; /* read only */
+};
extern struct files_stat_struct files_stat;
+extern struct files_kernel_stat_struct files_kernel_stat;
extern int get_max_files(void);
struct inodes_stat_t {
@@ -70,6 +74,8 @@ extern int dir_notify_enable;
behavior for cross-node execution/opening_for_writing of files */
#define FMODE_EXEC 16
+#define FKFLAGS_NO_ENFILE 1 /* kernel internal file (ignored for ENFILE accounting) */
+
#define RW_MASK 1
#define RWA_MASK 2
#define READ 0
@@ -644,6 +650,7 @@ struct file {
atomic_t f_count;
unsigned int f_flags;
mode_t f_mode;
+ unsigned short f_kernel_flags;
loff_t f_pos;
struct fown_struct f_owner;
unsigned int f_uid, f_gid;
@@ -1381,6 +1388,7 @@ extern long do_sys_open(int fdf, const c
int mode);
extern struct file *filp_open(const char *, int, int);
extern struct file * dentry_open(struct dentry *, struct vfsmount *, int);
+extern struct file * dentry_open_kernel(struct dentry *, struct vfsmount *, int);
extern int filp_close(struct file *, fl_owner_t id);
extern char * getname(const char __user *);
@@ -1582,6 +1590,7 @@ static inline void insert_inode_hash(str
}
extern struct file * get_empty_filp(void);
+extern struct file * get_empty_kernel_filp(unsigned short fkflags);
extern void file_move(struct file *f, struct list_head *list);
extern void file_kill(struct file *f);
struct bio;
@@ -1607,6 +1616,7 @@ extern ssize_t generic_file_direct_write
unsigned long *, loff_t, loff_t *, size_t, size_t);
extern ssize_t generic_file_buffered_write(struct kiocb *, const struct iovec *,
unsigned long, loff_t, loff_t *, size_t, ssize_t);
+extern int generic_file_buffered_write_one_kernel_page(struct file *, pgoff_t, struct page *);
extern ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos);
extern ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos);
ssize_t generic_file_write_nolock(struct file *file, const struct iovec *iov,
--- linux-2.6.16.noarch/include/linux/sysctl.h.kfile 2006-06-01 10:38:18.000000000 -0400
+++ linux-2.6.16.noarch/include/linux/sysctl.h 2006-06-01 10:42:02.000000000 -0400
@@ -840,6 +840,7 @@ enum
FS_AIO_NR=18, /* current system-wide number of aio requests */
FS_AIO_MAX_NR=19, /* system-wide maximum number of aio requests */
FS_INOTIFY=20, /* inotify submenu */
+ FS_FILE_KERNEL=21, /* int: number of internal kernel files */
};
/* /proc/sys/fs/quota/ */
--- linux-2.6.16.noarch/kernel/sysctl.c.kfile 2006-06-01 10:38:17.000000000 -0400
+++ linux-2.6.16.noarch/kernel/sysctl.c 2006-06-01 10:42:02.000000000 -0400
@@ -53,6 +53,9 @@
extern int proc_nr_files(ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos);
+extern int proc_files_kernel(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos);
+
#if defined(CONFIG_SYSCTL)
/* External variables not in a header file. */
@@ -1013,6 +1016,14 @@ static ctl_table fs_table[] = {
.proc_handler = &proc_dointvec,
},
{
+ .ctl_name = FS_FILE_KERNEL,
+ .procname = "file-kernel",
+ .data = &files_stat,
+ .maxlen = 1*sizeof(int),
+ .mode = 0444,
+ .proc_handler = &proc_files_kernel,
+ },
+ {
.ctl_name = FS_DENTRY,
.procname = "dentry-state",
.data = &dentry_stat,
linux-2.6.17-cachefs-mkwrite.patch:
include/linux/mm.h | 4 ++
mm/memory.c | 99 ++++++++++++++++++++++++++++++++++++++++-------------
mm/mmap.c | 12 +++++-
mm/mprotect.c | 11 ++++-
4 files changed, 98 insertions(+), 28 deletions(-)
--- NEW FILE linux-2.6.17-cachefs-mkwrite.patch ---
--- linux-2.6.16.noarch/include/linux/mm.h.mkwrite 2006-06-01 10:30:48.000000000 -0400
+++ linux-2.6.16.noarch/include/linux/mm.h 2006-06-01 10:33:25.000000000 -0400
@@ -203,6 +203,10 @@ struct vm_operations_struct {
void (*close)(struct vm_area_struct * area);
struct page * (*nopage)(struct vm_area_struct * area, unsigned long address, int *type);
int (*populate)(struct vm_area_struct * area, unsigned long address, unsigned long len, pgprot_t prot, unsigned long pgoff, int nonblock);
+
+ /* notification that a previously read-only page is about to become
+ * writable, if an error is returned it will cause a SIGBUS */
+ int (*page_mkwrite)(struct vm_area_struct *vma, struct page *page);
#ifdef CONFIG_NUMA
int (*set_policy)(struct vm_area_struct *vma, struct mempolicy *new);
struct mempolicy *(*get_policy)(struct vm_area_struct *vma,
--- linux-2.6.16.noarch/mm/memory.c.mkwrite 2006-06-01 10:30:46.000000000 -0400
+++ linux-2.6.16.noarch/mm/memory.c 2006-06-01 10:33:25.000000000 -0400
@@ -1564,25 +1564,59 @@ static int do_wp_page(struct mm_struct *
{
struct page *old_page, *new_page;
pte_t entry;
- int ret = VM_FAULT_MINOR;
+ int reuse, ret = VM_FAULT_MINOR;
old_page = vm_normal_page(vma, address, orig_pte);
if (!old_page)
goto gotten;
- if (PageAnon(old_page) && !TestSetPageLocked(old_page)) {
- int reuse = can_share_swap_page(old_page);
- unlock_page(old_page);
- if (reuse) {
- flush_cache_page(vma, address, pte_pfn(orig_pte));
- entry = pte_mkyoung(orig_pte);
- entry = maybe_mkwrite(pte_mkdirty(entry), vma);
- ptep_set_access_flags(vma, address, page_table, entry, 1);
- update_mmu_cache(vma, address, entry);
- lazy_mmu_prot_update(entry);
- ret |= VM_FAULT_WRITE;
- goto unlock;
+ if (unlikely(vma->vm_flags & VM_SHARED)) {
+ if (vma->vm_ops && vma->vm_ops->page_mkwrite) {
+ /*
+ * Notify the address space that the page is about to
+ * become writable so that it can prohibit this or wait
+ * for the page to get into an appropriate state.
+ *
+ * We do this without the lock held, so that it can
+ * sleep if it needs to.
+ */
+ page_cache_get(old_page);
+ pte_unmap_unlock(page_table, ptl);
+
+ if (vma->vm_ops->page_mkwrite(vma, old_page) < 0)
+ goto unwritable_page;
+
+ page_cache_release(old_page);
+
+ /*
+ * Since we dropped the lock we need to revalidate
+ * the PTE as someone else may have changed it. If
+ * they did, we just return, as we can count on the
+ * MMU to tell us if they didn't also make it writable.
+ */
+ page_table = pte_offset_map_lock(mm, pmd, address,
+ &ptl);
+ if (!pte_same(*page_table, orig_pte))
+ goto unlock;
}
+
+ reuse = 1;
+ } else if (PageAnon(old_page) && !TestSetPageLocked(old_page)) {
+ reuse = can_share_swap_page(old_page);
+ unlock_page(old_page);
+ } else {
+ reuse = 0;
+ }
+
+ if (reuse) {
+ flush_cache_page(vma, address, pte_pfn(orig_pte));
+ entry = pte_mkyoung(orig_pte);
+ entry = maybe_mkwrite(pte_mkdirty(entry), vma);
+ ptep_set_access_flags(vma, address, page_table, entry, 1);
+ update_mmu_cache(vma, address, entry);
+ lazy_mmu_prot_update(entry);
+ ret |= VM_FAULT_WRITE;
+ goto unlock;
}
/*
@@ -1642,6 +1676,10 @@ oom:
if (old_page)
page_cache_release(old_page);
return VM_FAULT_OOM;
+
+unwritable_page:
+ page_cache_release(old_page);
+ return VM_FAULT_SIGBUS;
}
/*
@@ -2193,18 +2231,31 @@ retry:
/*
* Should we do an early C-O-W break?
*/
- if (write_access && !(vma->vm_flags & VM_SHARED)) {
- struct page *page;
+ if (write_access) {
+ if (!(vma->vm_flags & VM_SHARED)) {
+ struct page *page;
- if (unlikely(anon_vma_prepare(vma)))
- goto oom;
- page = alloc_page_vma(GFP_HIGHUSER, vma, address);
- if (!page)
- goto oom;
- copy_user_highpage(page, new_page, address);
- page_cache_release(new_page);
- new_page = page;
- anon = 1;
+ if (unlikely(anon_vma_prepare(vma)))
+ goto oom;
+ page = alloc_page_vma(GFP_HIGHUSER, vma, address);
+ if (!page)
+ goto oom;
+ copy_user_highpage(page, new_page, address);
+ page_cache_release(new_page);
+ new_page = page;
+ anon = 1;
+
+ } else {
+ /* if the page will be shareable, see if the backing
+ * address space wants to know that the page is about
+ * to become writable */
+ if (vma->vm_ops->page_mkwrite &&
+ vma->vm_ops->page_mkwrite(vma, new_page) < 0
+ ) {
+ page_cache_release(new_page);
+ return VM_FAULT_SIGBUS;
+ }
+ }
}
page_table = pte_offset_map_lock(mm, pmd, address, &ptl);
--- linux-2.6.16.noarch/mm/mmap.c.mkwrite 2006-06-01 10:30:48.000000000 -0400
+++ linux-2.6.16.noarch/mm/mmap.c 2006-06-01 10:33:25.000000000 -0400
@@ -1072,7 +1072,8 @@ munmap_back:
vma->vm_start = addr;
vma->vm_end = addr + len;
vma->vm_flags = vm_flags;
- vma->vm_page_prot = protection_map[vm_flags & 0x0f];
+ vma->vm_page_prot = protection_map[vm_flags &
+ (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)];
vma->vm_pgoff = pgoff;
if (file) {
@@ -1096,6 +1097,12 @@ munmap_back:
goto free_vma;
}
+ /* Don't make the VMA automatically writable if it's shared, but the
+ * backer wishes to know when pages are first written to */
+ if (vma->vm_ops && vma->vm_ops->page_mkwrite)
+ vma->vm_page_prot =
+ protection_map[vm_flags & (VM_READ|VM_WRITE|VM_EXEC)];
+
/* We set VM_ACCOUNT in a shared mapping's vm_flags, to inform
* shmem_zero_setup (perhaps called through /dev/zero's ->mmap)
* that memory reservation must be checked; but that reservation
@@ -2009,7 +2016,8 @@ unsigned long do_brk(unsigned long addr,
vma->vm_end = addr + len;
vma->vm_pgoff = pgoff;
vma->vm_flags = flags;
- vma->vm_page_prot = protection_map[flags & 0x0f];
+ vma->vm_page_prot = protection_map[flags &
+ (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)];
vma_link(mm, vma, prev, rb_link, rb_parent);
out:
mm->total_vm += len >> PAGE_SHIFT;
--- linux-2.6.16.noarch/mm/mprotect.c.mkwrite 2006-06-01 10:30:48.000000000 -0400
+++ linux-2.6.16.noarch/mm/mprotect.c 2006-06-01 10:34:22.000000000 -0400
@@ -107,6 +107,7 @@ mprotect_fixup(struct vm_area_struct *vm
unsigned long oldflags = vma->vm_flags;
long nrpages = (end - start) >> PAGE_SHIFT;
unsigned long charged = 0, old_end = vma->vm_end;
+ unsigned int mask;
pgprot_t newprot;
pgoff_t pgoff;
int error;
@@ -133,8 +134,6 @@ mprotect_fixup(struct vm_area_struct *vm
}
}
- newprot = protection_map[newflags & 0xf];
-
/*
* First try to merge with previous and/or next vma.
*/
@@ -161,6 +160,14 @@ mprotect_fixup(struct vm_area_struct *vm
}
success:
+ /* Don't make the VMA automatically writable if it's shared, but the
+ * backer wishes to know when pages are first written to */
+ mask = VM_READ|VM_WRITE|VM_EXEC|VM_SHARED;
+ if (vma->vm_ops && vma->vm_ops->page_mkwrite)
+ mask &= ~VM_SHARED;
+
+ newprot = protection_map[newflags & mask];
+
/*
* vm_flags and vm_page_prot are protected by the mmap_sem
* held in write mode.
linux-2.6.17-cachefs-relpage.patch:
readahead.c | 25 +++++++++++++++++++++++--
1 files changed, 23 insertions(+), 2 deletions(-)
--- NEW FILE linux-2.6.17-cachefs-relpage.patch ---
--- linux-2.6.16.noarch/mm/readahead.c.relpage 2006-06-01 10:49:49.000000000 -0400
+++ linux-2.6.16.noarch/mm/readahead.c 2006-06-01 10:52:33.000000000 -0400
@@ -14,6 +14,7 @@
#include <linux/blkdev.h>
#include <linux/backing-dev.h>
#include <linux/pagevec.h>
+#include <linux/buffer_head.h>
void default_unplug_io_fn(struct backing_dev_info *bdi, struct page *page)
{
@@ -118,6 +119,26 @@ static inline unsigned long get_next_ra_
#define list_to_page(head) (list_entry((head)->prev, struct page, lru))
+/*
+ * see if a page needs releasing upon read_cache_pages() failure
+ * - the caller of read_cache_pages() may have set PG_private before calling,
+ * such as the NFS fs marking pages that are cached locally on disk, thus we
+ * need to give the fs a chance to clean up in the event of an error
+ */
+static inline void read_cache_pages_release_page(struct address_space *mapping,
+ struct page *page)
+{
+ if (PagePrivate(page)) {
+ if (TestSetPageLocked(page))
+ BUG();
+ page->mapping = mapping;
+ try_to_release_page(page, GFP_KERNEL);
+ page->mapping = NULL;
+ unlock_page(page);
+ }
+ page_cache_release(page);
+}
+
/**
* read_cache_pages - populate an address space with some pages, and
* start reads against them.
@@ -142,7 +163,7 @@ int read_cache_pages(struct address_spac
page = list_to_page(pages);
list_del(&page->lru);
if (add_to_page_cache(page, mapping, page->index, GFP_KERNEL)) {
- page_cache_release(page);
+ read_cache_pages_release_page(mapping, page);
continue;
}
ret = filler(data, page);
@@ -154,7 +175,7 @@ int read_cache_pages(struct address_spac
victim = list_to_page(pages);
list_del(&victim->lru);
- page_cache_release(victim);
+ read_cache_pages_release_page(mapping, victim);
}
break;
}
linux-2.6.17-fscache-fedora.patch:
kernel/auditsc.c | 1 +
mm/filemap.c | 1 +
2 files changed, 2 insertions(+)
--- NEW FILE linux-2.6.17-fscache-fedora.patch ---
--- linux-2.6.16.noarch/kernel/auditsc.c.fedora 2006-06-07 12:11:23.607621000 -0400
+++ linux-2.6.16.noarch/kernel/auditsc.c 2006-06-07 12:49:31.314757000 -0400
@@ -1111,6 +1111,7 @@ update_context:
audit_inode_context(idx, inode);
}
}
+EXPORT_SYMBOL(__audit_inode_child);
/**
* auditsc_get_stamp - get local copies of audit_context values
--- linux-2.6.16.noarch/mm/filemap.c.fedora 2006-06-07 12:12:08.531746000 -0400
+++ linux-2.6.16.noarch/mm/filemap.c 2006-06-07 12:49:31.325767000 -0400
@@ -720,6 +720,7 @@ unsigned find_get_pages(struct address_s
read_unlock_irq(&mapping->tree_lock);
return ret;
}
+EXPORT_SYMBOL_GPL(find_get_pages);
/**
* find_get_pages_contig - gang contiguous pagecache lookup
linux-2.6.17-fscache.patch:
Documentation/filesystems/caching/backend-api.txt | 357 +++++++
Documentation/filesystems/caching/fscache.txt | 151 +++
Documentation/filesystems/caching/netfs-api.txt | 752 +++++++++++++++
fs/Kconfig | 15
fs/Makefile | 1
fs/fscache/Makefile | 11
fs/fscache/cookie.c | 1063 ++++++++++++++++++++++
fs/fscache/fscache-int.h | 93 +
fs/fscache/fsdef.c | 113 ++
fs/fscache/main.c | 105 ++
fs/fscache/page.c | 548 +++++++++++
include/linux/fscache-cache.h | 243 +++++
include/linux/fscache.h | 496 ++++++++++
13 files changed, 3948 insertions(+)
--- NEW FILE linux-2.6.17-fscache.patch ---
--- /dev/null 2006-06-07 07:14:18.564562589 -0400
+++ linux-2.6.16.noarch/Documentation/filesystems/caching/backend-api.txt 2006-06-07 11:38:46.818862000 -0400
@@ -0,0 +1,357 @@
+ ==========================
+ FS-CACHE CACHE BACKEND API
+ ==========================
+
+The FS-Cache system provides an API by which actual caches can be supplied to
+FS-Cache for it to then serve out to network filesystems and other interested
+parties.
+
+This API is declared in <linux/fscache-cache.h>.
+
+
+====================================
+INITIALISING AND REGISTERING A CACHE
+====================================
+
+To start off, a cache definition must be initialised and registered for each
+cache the backend wants to make available. For instance, CacheFS does this in
+the fill_super() operation on mounting.
+
+The cache definition (struct fscache_cache) should be initialised by calling:
+
+ void fscache_init_cache(struct fscache_cache *cache,
+ struct fscache_cache_ops *ops,
+ const char *idfmt,
+ ...)
+
+Where:
+
+ (*) "cache" is a pointer to the cache definition;
+
+ (*) "ops" is a pointer to the table of operations that the backend supports on
+ this cache;
+
+ (*) and a format and printf-style arguments for constructing a label for the
+ cache.
+
+
+The cache should then be registered with FS-Cache by passing a pointer to the
+previously initialised cache definition to:
+
+ int fscache_add_cache(struct fscache_cache *cache,
+ struct fscache_object *fsdef,
+ const char *tagname);
+
+Two extra arguments should also be supplied:
+
+ (*) "fsdef" which should point to the object representation for the FS-Cache
+ master index in this cache. Netfs primary index entries will be created
+ here.
+
+ (*) "tagname" which, if given, should be a text string naming this cache. If
+ this is NULL, the identifier will be used instead. For CacheFS, the
+ identifier is set to name the underlying block device and the tag can be
+ supplied by mount.
+
+This function may return -ENOMEM if it ran out of memory or -EEXIST if the tag
+is already in use. 0 will be returned on success.
+
+
+=====================
+UNREGISTERING A CACHE
+=====================
+
+A cache can be withdrawn from the system by calling this function with a
+pointer to the cache definition:
+
+ void fscache_withdraw_cache(struct fscache_cache *cache)
+
+In CacheFS's case, this is called by put_super().
+
+
+==================
+FS-CACHE UTILITIES
+==================
+
+FS-Cache provides some utilities that a cache backend may make use of:
+
+ (*) Find the parent of an object:
+
+ struct fscache_object *
+ fscache_find_parent_object(struct fscache_object *object)
+
+ This allows a backend to find the logical parent of an index or data file
+ in the cache hierarchy.
+
+ (*) Note occurrence of an I/O error in a cache:
+
+ void fscache_io_error(struct fscache_cache *cache)
+
+ This tells FS-Cache that an I/O error occurred in the cache. After this
+ has been called, only resource dissociation operations (object and page
+ release) will be passed from the netfs to the cache backend for the
+ specified cache.
+
+ This does not actually withdraw the cache. That must be done separately.
+
+ (*) Get an extra reference to a read or write context:
+
+ void *fscache_get_context(struct fscache_cookie *cookie, void *context)
+
+ and release a reference:
+
+ void *fscache_put_context(struct fscache_cookie *cookie, void *context)
+
+ These should be used to maintain the presence of the read or write context
+ passed to the cache read/write functions. This context must then be
+ passed to the I/O completion function.
+
+
+========================
+RELEVANT DATA STRUCTURES
+========================
+
+ (*) Index/Data file FS-Cache representation cookie:
+
+ struct fscache_cookie {
+ struct fscache_object_def *def;
+ struct fscache_netfs *netfs;
+ void *netfs_data;
+ ...
+ };
+
+ The fields that might be of use to the backend describe the object
+ definition, the netfs definition and the netfs's data for this cookie.
+ The object definition contain functions supplied by the netfs for loading
+ and matching index entries; these are required to provide some of the
+ cache operations.
+
+ (*) In-cache object representation:
+
+ struct fscache_object {
+ struct fscache_cache *cache;
+ struct fscache_cookie *cookie;
+ unsigned long flags;
+ #define FSCACHE_OBJECT_RECYCLING 1
+ ...
+ };
+
+ Structures of this type should be allocated by the cache backend and
+ passed to FS-Cache when requested by the appropriate cache operation. In
+ the case of CacheFS, they're embedded in CacheFS's internal object
+ structures.
+
+ Each object contains a pointer to the cookie that represents the object it
+ is backing. It also contains a flag that indicates whether the object is
+ being retired when put_object() is called. This should be initialised by
+ calling fscache_object_init(object).
+
+
+================
+CACHE OPERATIONS
+================
+
+The cache backend provides FS-Cache with a table of operations that can be
+performed on the denizens of the cache. These are held in a structure of type:
+
+ struct fscache_cache_ops
+
+ (*) Name of cache provider [mandatory]:
+
+ const char *name
+
+ This isn't strictly an operation, but should be pointed at a string naming
+ the backend.
+
+ (*) Object lookup [mandatory]:
+
+ struct fscache_object *(*lookup_object)(struct fscache_cache *cache,
+ struct fscache_object *parent,
+ struct fscache_cookie *cookie)
+
+ This method is used to look up an object in the specified cache, given a
+ pointer to the parent object and the cookie to which the object will be
+ attached. This should instantiate that object in the cache if it can, or
+ return -ENOBUFS or -ENOMEM if it can't.
+
+ (*) Increment object refcount [mandatory]:
+
+ struct fscache_object *(*grab_object)(struct fscache_object *object)
+
+ This method is called to increment the reference count on an object. It
+ may fail (for instance if the cache is being withdrawn) by returning NULL.
+ It should return the object pointer if successful.
+
+ (*) Lock/Unlock object [mandatory]:
+
+ void (*lock_object)(struct fscache_object *object)
+ void (*unlock_object)(struct fscache_object *object)
+
+ These methods are used to exclusively lock an object. It must be possible
+ to schedule with the lock held, so a spinlock isn't sufficient.
+
+ (*) Pin/Unpin object [optional]:
+
+ int (*pin_object)(struct fscache_object *object)
+ void (*unpin_object)(struct fscache_object *object)
[...3600 lines suppressed...]
+ return __fscache_set_i_size(cookie, i_size);
+#endif
+ return -ENOBUFS;
+}
+
+/*****************************************************************************/
+/*
+ * reserve data space for a cached object
+ * - returns -ENOBUFS if the file is not backed
+ * - returns -ENOSPC if there isn't enough space to honour the reservation
+ * - returns 0 if okay
+ */
+#if defined(CONFIG_FSCACHE) || defined(CONFIG_FSCACHE_MODULE)
+extern int __fscache_reserve_space(struct fscache_cookie *cookie, loff_t size);
+#endif
+
+static inline
+int fscache_reserve_space(struct fscache_cookie *cookie, loff_t size)
+{
+#if defined(CONFIG_FSCACHE) || defined(CONFIG_FSCACHE_MODULE)
+ if (cookie)
+ return __fscache_reserve_space(cookie, size);
+#endif
+ return -ENOBUFS;
+}
+
+/*****************************************************************************/
+/*
+ * read a page from the cache or allocate a block in which to store it
+ * - if the page 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
+ * - else if the page is unbacked:
+ * - a block will be allocated
+ * - -ENODATA will be returned
+ */
+#if defined(CONFIG_FSCACHE) || defined(CONFIG_FSCACHE_MODULE)
+extern int __fscache_read_or_alloc_page(struct fscache_cookie *cookie,
+ struct page *page,
+ fscache_rw_complete_t end_io_func,
+ void *context,
+ gfp_t gfp);
+#endif
+
+static inline
+int fscache_read_or_alloc_page(struct fscache_cookie *cookie,
+ struct page *page,
+ fscache_rw_complete_t end_io_func,
+ void *context,
+ gfp_t gfp)
+{
+#if defined(CONFIG_FSCACHE) || defined(CONFIG_FSCACHE_MODULE)
+ if (cookie)
+ return __fscache_read_or_alloc_page(cookie, page, end_io_func,
+ context, gfp);
+#endif
+ return -ENOBUFS;
+}
+
+#if defined(CONFIG_FSCACHE) || defined(CONFIG_FSCACHE_MODULE)
+extern int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie,
+ struct address_space *mapping,
+ struct list_head *pages,
+ unsigned *nr_pages,
+ fscache_rw_complete_t end_io_func,
+ void *context,
+ gfp_t gfp);
+#endif
+
+static inline
+int fscache_read_or_alloc_pages(struct fscache_cookie *cookie,
+ struct address_space *mapping,
+ struct list_head *pages,
+ unsigned *nr_pages,
+ fscache_rw_complete_t end_io_func,
+ void *context,
+ gfp_t gfp)
+{
+#if defined(CONFIG_FSCACHE) || defined(CONFIG_FSCACHE_MODULE)
+ if (cookie)
+ return __fscache_read_or_alloc_pages(cookie, mapping, pages,
+ nr_pages, end_io_func,
+ context, gfp);
+#endif
+ return -ENOBUFS;
+}
+
+/*
+ * allocate a block in which to store a page
+ * - if the page is not backed by a file:
+ * - -ENOBUFS will be returned and nothing more will be done
+ * - else
+ * - a block will be allocated if there isn't one
+ * - 0 will be returned
+ */
+#if defined(CONFIG_FSCACHE) || defined(CONFIG_FSCACHE_MODULE)
+extern int __fscache_alloc_page(struct fscache_cookie *cookie,
+ struct page *page,
+ gfp_t gfp);
+#endif
+
+static inline
+int fscache_alloc_page(struct fscache_cookie *cookie,
+ struct page *page,
+ gfp_t gfp)
+{
+#if defined(CONFIG_FSCACHE) || defined(CONFIG_FSCACHE_MODULE)
+ if (cookie)
+ return __fscache_alloc_page(cookie, page, gfp);
+#endif
+ return -ENOBUFS;
+}
+
+/*
+ * request a page be stored in the cache
+ * - this request may be ignored if no cache block is currently allocated, in
+ * which case it:
+ * - returns -ENOBUFS
+ * - if a cache block was already allocated:
+ * - a BIO will be dispatched to write the page (end_io_func will be called
+ * from the completion function)
+ * - returns 0
+ */
+#if defined(CONFIG_FSCACHE) || defined(CONFIG_FSCACHE_MODULE)
+extern int __fscache_write_page(struct fscache_cookie *cookie,
+ struct page *page,
+ fscache_rw_complete_t end_io_func,
+ void *context,
+ gfp_t gfp);
+
+extern int __fscache_write_pages(struct fscache_cookie *cookie,
+ struct pagevec *pagevec,
+ fscache_rw_complete_t end_io_func,
+ void *context,
+ gfp_t gfp);
+#endif
+
+static inline
+int fscache_write_page(struct fscache_cookie *cookie,
+ struct page *page,
+ fscache_rw_complete_t end_io_func,
+ void *context,
+ gfp_t gfp)
+{
+#if defined(CONFIG_FSCACHE) || defined(CONFIG_FSCACHE_MODULE)
+ if (cookie)
+ return __fscache_write_page(cookie, page, end_io_func,
+ context, gfp);
+#endif
+ return -ENOBUFS;
+}
+
+static inline
+int fscache_write_pages(struct fscache_cookie *cookie,
+ struct pagevec *pagevec,
+ fscache_rw_complete_t end_io_func,
+ void *context,
+ gfp_t gfp)
+{
+#if defined(CONFIG_FSCACHE) || defined(CONFIG_FSCACHE_MODULE)
+ if (cookie)
+ return __fscache_write_pages(cookie, pagevec, end_io_func,
+ context, 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
+ */
+#if defined(CONFIG_FSCACHE) || defined(CONFIG_FSCACHE_MODULE)
+extern void __fscache_uncache_page(struct fscache_cookie *cookie,
+ struct page *page);
+extern void __fscache_uncache_pages(struct fscache_cookie *cookie,
+ struct pagevec *pagevec);
+#endif
+
+static inline
+void fscache_uncache_page(struct fscache_cookie *cookie,
+ struct page *page)
+{
+#if defined(CONFIG_FSCACHE) || defined(CONFIG_FSCACHE_MODULE)
+ if (cookie)
+ __fscache_uncache_page(cookie, page);
+#endif
+}
+
+static inline
+void fscache_uncache_pagevec(struct fscache_cookie *cookie,
+ struct pagevec *pagevec)
+{
+#if defined(CONFIG_FSCACHE) || defined(CONFIG_FSCACHE_MODULE)
+ if (cookie)
+ __fscache_uncache_pages(cookie, pagevec);
+#endif
+}
+
+#endif /* _LINUX_FSCACHE_H */
linux-2.6.17-nfs-fscache.patch:
fs/Kconfig | 7 +
fs/nfs/Makefile | 1
fs/nfs/file.c | 31 ++++
fs/nfs/fscache.c | 301 +++++++++++++++++++++++++++++++++++++++++++++
fs/nfs/fscache.h | 244 ++++++++++++++++++++++++++++++++++++
fs/nfs/inode.c | 44 ++++++
fs/nfs/pagelist.c | 2
fs/nfs/read.c | 240 +++++++++++++++++++++++++++++++++++
fs/nfs/sysctl.c | 43 ++++++
fs/nfs/write.c | 4
include/linux/nfs4_mount.h | 1
include/linux/nfs_fs.h | 5
include/linux/nfs_fs_sb.h | 9 +
include/linux/nfs_mount.h | 1
include/linux/nfs_page.h | 23 +++
15 files changed, 953 insertions(+), 3 deletions(-)
--- NEW FILE linux-2.6.17-nfs-fscache.patch ---
--- linux-2.6.16.noarch/fs/nfs/Makefile.fsnfs 2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.noarch/fs/nfs/Makefile 2006-06-07 13:13:18.163396000 -0400
@@ -14,4 +14,5 @@ nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4x
callback.o callback_xdr.o callback_proc.o
nfs-$(CONFIG_NFS_DIRECTIO) += direct.o
nfs-$(CONFIG_SYSCTL) += sysctl.o
+nfs-$(CONFIG_NFS_FSCACHE) += fscache.o
nfs-objs := $(nfs-y)
--- linux-2.6.16.noarch/fs/nfs/file.c.fsnfs 2006-06-07 13:06:22.851020000 -0400
+++ linux-2.6.16.noarch/fs/nfs/file.c 2006-06-07 13:52:16.309796000 -0400
@@ -27,12 +27,14 @@
#include <linux/slab.h>
#include <linux/pagemap.h>
#include <linux/smp_lock.h>
+#include <linux/buffer_head.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include "delegation.h"
#include "iostat.h"
+#include "fscache.h"
#define NFSDBG_FACILITY NFSDBG_FILE
@@ -253,6 +255,19 @@ nfs_file_sendfile(struct file *filp, lof
return res;
}
+#ifdef CONFIG_NFS_FSCACHE
+static int nfs_file_page_mkwrite(struct vm_area_struct *vma, struct page *page)
+{
+ wait_on_page_fs_misc(page);
+ return 0;
+}
+static struct vm_operations_struct nfs_fs_vm_operations = {
+ .nopage = filemap_nopage,
+ .populate = filemap_populate,
+ .page_mkwrite = nfs_file_page_mkwrite,
+};
+#endif
+
static int
nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
{
@@ -266,6 +281,12 @@ nfs_file_mmap(struct file * file, struct
status = nfs_revalidate_file(inode, file);
if (!status)
status = generic_file_mmap(file, vma);
+
+#ifdef CONFIG_NFS_FSCACHE
+ if (NFS_I(inode)->fscache != NULL)
+ vma->vm_ops = &nfs_fs_vm_operations;
+#endif
+
return status;
}
@@ -328,6 +349,11 @@ static int nfs_release_page(struct page
return !nfs_wb_page(page->mapping->host, page);
}
+/*
+ * since we use page->private for our own nefarious purposes when using fscache, we have to
+ * override extra address space ops to prevent fs/buffer.c from getting confused, even though we
+ * may not have asked its opinion
+ */
struct address_space_operations nfs_file_aops = {
.readpage = nfs_readpage,
.readpages = nfs_readpages,
@@ -341,6 +367,11 @@ struct address_space_operations nfs_file
#ifdef CONFIG_NFS_DIRECTIO
.direct_IO = nfs_direct_IO,
#endif
+#ifdef CONFIG_NFS_FSCACHE
+ .sync_page = block_sync_page,
+ .releasepage = nfs_releasepage,
+ .invalidatepage = nfs_invalidatepage,
+#endif
};
/*
--- linux-2.6.16.noarch/fs/nfs/inode.c.fsnfs 2006-06-07 13:06:22.876021000 -0400
+++ linux-2.6.16.noarch/fs/nfs/inode.c 2006-06-07 13:53:07.298070000 -0400
@@ -44,6 +44,7 @@
#include "callback.h"
#include "delegation.h"
#include "iostat.h"
+#include "fscache.h"
#define NFSDBG_FACILITY NFSDBG_VFS
#define NFS_PARANOIA 1
@@ -176,6 +177,8 @@ nfs_clear_inode(struct inode *inode)
cred = nfsi->cache_access.cred;
if (cred)
put_rpccred(cred);
+
+ nfs_clear_fscookie(NFS_SERVER(inode), nfsi);
BUG_ON(atomic_read(&nfsi->data_updates) != 0);
}
@@ -529,6 +532,9 @@ nfs_fill_super(struct super_block *sb, s
server->namelen = NFS2_MAXNAMLEN;
}
+ if (server->flags & NFS_MOUNT_FSCACHE)
+ nfs_fill_fscookie(sb);
+
sb->s_op = &nfs_sops;
return nfs_sb_init(sb, authflavor);
}
@@ -602,6 +608,7 @@ static void nfs_show_mount_options(struc
{ NFS_MOUNT_NOAC, ",noac", "" },
{ NFS_MOUNT_NONLM, ",nolock", "" },
{ NFS_MOUNT_NOACL, ",noacl", "" },
+ { NFS_MOUNT_FSCACHE, ",fsc", "" },
{ 0, NULL, NULL }
};
struct proc_nfs_info *nfs_infop;
@@ -770,6 +777,8 @@ void nfs_zap_caches(struct inode *inode)
spin_lock(&inode->i_lock);
nfs_zap_caches_locked(inode);
spin_unlock(&inode->i_lock);
+
+ nfs_zap_fscookie(NFS_SERVER(inode), NFS_I(inode));
}
static void nfs_zap_acl_cache(struct inode *inode)
@@ -920,6 +929,8 @@ nfs_fhget(struct super_block *sb, struct
memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));
nfsi->cache_access.cred = NULL;
+ nfs_fhget_fscookie(sb, nfsi);
+
unlock_new_inode(inode);
} else
nfs_refresh_inode(inode, fattr);
@@ -1002,6 +1013,7 @@ void nfs_setattr_update_inode(struct ino
if ((attr->ia_valid & ATTR_SIZE) != 0) {
nfs_inc_stats(inode, NFSIOS_SETATTRTRUNC);
inode->i_size = attr->ia_size;
+ nfs_set_fscsize(NFS_SERVER(inode), NFS_I(inode), inode->i_size);
vmtruncate(inode, attr->ia_size);
}
}
@@ -1184,6 +1196,9 @@ int nfs_open(struct inode *inode, struct
ctx->mode = filp->f_mode;
nfs_file_set_open_context(filp, ctx);
put_nfs_open_context(ctx);
+
+ nfs_set_fscache(inode, ((filp->f_flags & O_ACCMODE) == O_RDONLY));
+
return 0;
}
@@ -1317,6 +1332,8 @@ void nfs_revalidate_mapping(struct inode
}
spin_unlock(&inode->i_lock);
+ nfs_renew_fscookie(NFS_SERVER(inode), nfsi);
+
dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n",
inode->i_sb->s_id,
(long long)NFS_FILEID(inode));
@@ -1563,11 +1580,13 @@ static int nfs_update_inode(struct inode
if (data_stable) {
inode->i_size = new_isize;
invalid |= NFS_INO_INVALID_DATA;
+ nfs_set_fscsize(NFS_SERVER(inode), nfsi, inode->i_size);
}
invalid |= NFS_INO_INVALID_ATTR;
} else if (new_isize > cur_isize) {
inode->i_size = new_isize;
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
+ nfs_set_fscsize(NFS_SERVER(inode), nfsi, inode->i_size);
}
nfsi->cache_change_attribute = jiffies;
dprintk("NFS: isize change on server for file %s/%ld\n",
@@ -1740,6 +1759,15 @@ static struct super_block *nfs_get_sb(st
goto out_err;
}
#endif /* CONFIG_NFS_V3 */
+ /* if filesystem caching isn't compiled in, then requesting its use is
+ * invalid */
+#ifndef CONFIG_NFS_FSCACHE
+ if (data->flags & NFS_MOUNT_FSCACHE) {
+ printk(KERN_WARNING
+ "NFS: kernel not compiled with CONFIG_NFS_FSCACHE\n");
+ return -EINVAL;
+ }
+#endif
s = ERR_PTR(-ENOMEM);
server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL);
@@ -1804,6 +1832,8 @@ static void nfs_kill_super(struct super_
kill_anon_super(s);
+ nfs_kill_fscookie(server);
+
if (!IS_ERR(server->client))
rpc_shutdown_client(server->client);
if (!IS_ERR(server->client_sys))
@@ -1987,6 +2017,9 @@ static int nfs4_fill_super(struct super_
}
sb->s_time_gran = 1;
+
+ if (server->flags & NFS4_MOUNT_FSCACHE)
+ nfs4_fill_fscookie(sb);
sb->s_op = &nfs4_sops;
err = nfs_sb_init(sb, authflavour);
@@ -2130,6 +2163,8 @@ static void nfs4_kill_super(struct super
nfs4_renewd_prepare_shutdown(server);
+ nfs_kill_fscookie(NFS_SB(sb));
+
if (server->client != NULL && !IS_ERR(server->client))
rpc_shutdown_client(server->client);
@@ -2295,6 +2330,11 @@ static int __init init_nfs_fs(void)
{
int err;
+ /* we want to be able to cache */
+ err = nfs_register_netfs();
+ if (err < 0)
+ goto out5;
+
err = nfs_init_nfspagecache();
if (err)
goto out4;
@@ -2342,6 +2382,9 @@ out2:
out3:
nfs_destroy_nfspagecache();
out4:
+ nfs_unregister_netfs();
+out5:
+
return err;
}
@@ -2354,6 +2397,7 @@ static void __exit exit_nfs_fs(void)
nfs_destroy_readpagecache();
nfs_destroy_inodecache();
nfs_destroy_nfspagecache();
+ nfs_unregister_netfs();
#ifdef CONFIG_PROC_FS
rpc_proc_unregister("nfs");
#endif
--- /dev/null 2006-06-07 07:14:18.564562589 -0400
+++ linux-2.6.16.noarch/fs/nfs/fscache.c 2006-06-07 13:52:38.595345000 -0400
@@ -0,0 +1,301 @@
+/* fscache.c: NFS filesystem cache interface
+ *
+ * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells at redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/nfs_fs.h>
+#include <linux/nfs_fs_sb.h>
+#include <keys/user-type.h>
+
+#include "fscache.h"
+
+/*
+ * Sysctl variables
+ */
+int nfs_fscache_to_pages;
+int nfs_fscache_from_pages;
+int nfs_fscache_uncache_page;
+int nfs_fscache_from_error;
+int nfs_fscache_to_error;
+
+#define NFSDBG_FACILITY NFSDBG_FSCACHE
+
+struct nfs_fh_auxdata {
+ struct timespec i_mtime;
+ struct timespec i_ctime;
+ loff_t i_size;
+};
+
+static struct fscache_netfs_operations nfs_cache_ops = {
+};
+
+struct fscache_netfs nfs_cache_netfs = {
+ .name = "nfs",
+ .version = 0,
+ .ops = &nfs_cache_ops,
+};
+
+static const uint8_t nfs_cache_ipv6_wrapper_for_ipv4[12] = {
+ [0 ... 9] = 0x00,
+ [10 ... 11] = 0xff
+};
+
+static uint16_t nfs_server_get_key(const void *cookie_netfs_data,
+ void *buffer, uint16_t bufmax)
+{
+ const struct nfs_server *server = cookie_netfs_data;
+ uint16_t len = 0;
+
+ switch (server->addr.sin_family) {
+ case AF_INET:
+ memcpy(buffer + 0, &nfs_cache_ipv6_wrapper_for_ipv4, 12);
+ memcpy(buffer + 12, &server->addr.sin_addr, 4);
+ memcpy(buffer + 16, &server->addr.sin_port, 2);
+ len = 18;
+ break;
+
+ case AF_INET6:
+ memcpy(buffer + 0, &server->addr.sin_addr, 16);
+ memcpy(buffer + 16, &server->addr.sin_port, 2);
+ len = 18;
+ break;
+
+ default:
+ len = 0;
+ printk(KERN_WARNING "NFS: Unknown network family '%d'\n",
+ server->addr.sin_family);
+ break;
+ }
+
+ return len;
+}
+
+/*
+ * the root index for the filesystem is defined by nfsd IP address and ports
+ */
+struct fscache_cookie_def nfs_cache_server_index_def = {
+ .name = "NFS.servers",
+ .type = FSCACHE_COOKIE_TYPE_INDEX,
+ .get_key = nfs_server_get_key,
+};
+
+static uint16_t nfs_fsctag_get_key(const void *cookie_netfs_data,
+ void *buffer, uint16_t bufmax)
+{
+ const struct nfs_server *server = cookie_netfs_data;
+ uint16_t len = 0;
+
+ len = server->fsctag.size;
+ memcpy(buffer, server->fsctag.buf, len);
+
+ return len;
+}
+
+/*
+ * the root index for the filesystem is defined by nfsd IP address and ports
+ */
+struct fscache_cookie_def nfs_fsctag_index_def = {
+ .name = "NFS.fsctag",
+ .type = FSCACHE_COOKIE_TYPE_INDEX,
+ .get_key = nfs_fsctag_get_key,
+};
+struct fscache_cookie_def nfs4_fsctag_index_def = {
+ .name = "NFS4.fsctag",
+ .type = FSCACHE_COOKIE_TYPE_INDEX,
+ .get_key = nfs_fsctag_get_key,
+};
+
+static uint16_t nfs_fh_get_key(const void *cookie_netfs_data,
+ void *buffer, uint16_t bufmax)
+{
+ const struct nfs_inode *nfsi = cookie_netfs_data;
+ uint16_t nsize;
+
+ /* set the file handle */
+ nsize = nfsi->fh.size;
+ memcpy(buffer, nfsi->fh.data, nsize);
+
+ return nsize;
+}
+
+/*
+ * indication of pages that now have cache metadata retained
+ * - this function should mark the specified pages as now being cached
+ */
+static void nfs_fh_mark_pages_cached(void *cookie_netfs_data,
+ struct address_space *mapping,
+ struct pagevec *cached_pvec)
+{
+ unsigned long loop;
+
+ dprintk("NFS: nfs_fh_mark_pages_cached: nfsi 0x%p pages %ld\n",
+ cookie_netfs_data, cached_pvec->nr);
+
+ for (loop = 0; loop < cached_pvec->nr; loop++)
+ SetPagePrivate(cached_pvec->pages[loop]);
+
+ return;
+}
+
+/*
+ * indication the cookie is no longer uncached
+ * - this function is called when the backing store currently caching a cookie
+ * is removed
+ * - the netfs should use this to clean up any markers indicating cached pages
+ * - this is mandatory for any object that may have data
+ */
+static void nfs_fh_now_uncached(void *cookie_netfs_data)
+{
+ struct nfs_inode *nfsi = cookie_netfs_data;
+ struct pagevec pvec;
+ pgoff_t first;
+ int loop, nr_pages;
+
+ pagevec_init(&pvec, 0);
+ first = 0;
+
+ dprintk("NFS: nfs_fh_now_uncached: nfs_inode 0x%p\n", nfsi);
+
+ for (;;) {
+ /* grab a bunch of pages to clean */
+ nr_pages = find_get_pages(nfsi->vfs_inode.i_mapping, first,
+ PAGEVEC_SIZE, pvec.pages);
+ if (!nr_pages)
+ break;
+
+ for (loop = 0; loop < nr_pages; loop++)
+ ClearPagePrivate(pvec.pages[loop]);
+
+ first = pvec.pages[nr_pages - 1]->index + 1;
+
+ pvec.nr = nr_pages;
+ pagevec_release(&pvec);
+ cond_resched();
+ }
+}
+
+/*****************************************************************************/
+/*
+ * get certain file attributes from the netfs data
+ * - this function can be absent for an index
+ * - not permitted to return an error
+ * - the netfs data from the cookie being used as the source is
+ * presented
+ */
+static void nfs_fh_get_attr(const void *cookie_netfs_data, uint64_t *size)
+{
+ const struct nfs_inode *nfsi = cookie_netfs_data;
+
+ *size = nfsi->vfs_inode.i_size;
+}
+
+/*****************************************************************************/
+/*
+ * get the auxilliary data from netfs data
+ * - this function can be absent if the index carries no state data
+ * - should store the auxilliary data in the buffer
+ * - should return the amount of amount stored
+ * - not permitted to return an error
+ * - the netfs data from the cookie being used as the source is
+ * presented
+ */
+static uint16_t nfs_fh_get_aux(const void *cookie_netfs_data,
+ void *buffer, uint16_t bufmax)
+{
+ struct nfs_fh_auxdata auxdata;
+ const struct nfs_inode *nfsi = cookie_netfs_data;
+
+ auxdata.i_size = nfsi->vfs_inode.i_size;
+ auxdata.i_mtime = nfsi->vfs_inode.i_mtime;
+ auxdata.i_ctime = nfsi->vfs_inode.i_ctime;
+
+ if (bufmax > sizeof(auxdata))
+ bufmax = sizeof(auxdata);
+
+ memcpy(buffer, &auxdata, bufmax);
+ return bufmax;
+}
+
+/*****************************************************************************/
+/*
+ * consult the netfs about the state of an object
+ * - this function can be absent if the index carries no state data
+ * - the netfs data from the cookie being used as the target is
+ * presented, as is the auxilliary data
+ */
+static fscache_checkaux_t nfs_fh_check_aux(void *cookie_netfs_data,
+ const void *data, uint16_t datalen)
+{
+ struct nfs_fh_auxdata auxdata;
+ struct nfs_inode *nfsi = cookie_netfs_data;
+
+ if (datalen > sizeof(auxdata))
+ return FSCACHE_CHECKAUX_OBSOLETE;
+
+ auxdata.i_size = nfsi->vfs_inode.i_size;
+ auxdata.i_mtime = nfsi->vfs_inode.i_mtime;
+ auxdata.i_ctime = nfsi->vfs_inode.i_ctime;
+
+ if (memcmp(data, &auxdata, datalen) != 0)
+ return FSCACHE_CHECKAUX_OBSOLETE;
+
+ return FSCACHE_CHECKAUX_OKAY;
+}
+
+/*
+ * the primary index for each server is simply made up of a series of NFS file
+ * handles
+ */
+struct fscache_cookie_def nfs_cache_fh_index_def = {
+ .name = "NFS.fh",
+ .type = FSCACHE_COOKIE_TYPE_DATAFILE,
+ .get_key = nfs_fh_get_key,
+ .get_attr = nfs_fh_get_attr,
+ .get_aux = nfs_fh_get_aux,
+ .check_aux = nfs_fh_check_aux,
+ .mark_pages_cached = nfs_fh_mark_pages_cached,
+ .now_uncached = nfs_fh_now_uncached,
+};
+
+int nfs_load_fsctag(const char *tag, struct nfs_server *server)
+{
+ struct user_key_payload *payload;
+ struct key *key;
+ int plen = 0;
+ char *mntpt = NULL;
+
+ server->fsctag.size = 0;
+ server->fsctag.buf = NULL;
+
+ key = request_key(&key_type_user, tag, NULL);
+ if (IS_ERR(key)) {
+ dprintk("NFS: request_key failed: %ld\n", PTR_ERR(key));
+ return plen;
+ }
+ rcu_read_lock();
+ payload = key->payload.data;
+ if (payload) {
+ plen = payload->datalen;
+ if (plen) {
+ if ((mntpt = kmalloc(plen, GFP_KERNEL)))
+ memcpy(mntpt, payload->data, plen);
+ }
+ }
+ rcu_read_unlock();
+ if (plen && mntpt) {
+ server->fsctag.size = plen;
+ server->fsctag.buf = mntpt;
+ }
+ return plen;
+}
--- linux-2.6.16.noarch/fs/nfs/read.c.fsnfs 2006-06-07 13:06:23.030020000 -0400
+++ linux-2.6.16.noarch/fs/nfs/read.c 2006-06-07 13:53:38.311845000 -0400
@@ -27,11 +27,14 @@
#include <linux/sunrpc/clnt.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_page.h>
+#include <linux/nfs_mount.h>
#include <linux/smp_lock.h>
+
#include <asm/system.h>
#include "iostat.h"
+#include "fscache.h"
#define NFSDBG_FACILITY NFSDBG_PAGECACHE
@@ -104,6 +107,53 @@ int nfs_return_empty_page(struct page *p
return 0;
}
+#ifdef CONFIG_NFS_FSCACHE
+/*
+ * store a newly fetched page in fscache
+ */
+static void
+nfs_readpage_to_fscache_complete(struct page *page, void *data, int error)
+{
+ dfprintk(FSCACHE,
+ "NFS: readpage_to_fscache_complete (p:%p(i:%lx f:%lx)/%d)\n",
+ page, page->index, page->flags, error);
+
+ end_page_fs_misc(page);
+}
+
+static inline void
+nfs_readpage_to_fscache(struct inode *inode, struct page *page, int sync)
+{
+ int ret;
+
+ dfprintk(FSCACHE, "NFS: readpage_to_fscache(fsc:%p/p:%p(i:%lx f:%lx)/%d)\n",
+ NFS_I(inode)->fscache, page, page->index, page->flags, sync);
+
+ if (TestSetPageFsMisc(page))
+ BUG();
+ ret = fscache_write_page(NFS_I(inode)->fscache, page,
+ nfs_readpage_to_fscache_complete, NULL, GFP_KERNEL);
+ dfprintk(FSCACHE,
+ "NFS: readpage_to_fscache: p:%p(i:%lu f:%lx) ret %d\n",
+ page, page->index, page->flags, ret);
+ if (ret != 0) {
+ fscache_uncache_page(NFS_I(inode)->fscache, page);
+ nfs_fscache_uncache_page++;
+ ClearPagePrivate(page);
+ end_page_fs_misc(page);
+ nfs_fscache_to_error = ret;
+ } else
+ nfs_fscache_to_pages++;
+}
+#else
+static inline void
+nfs_readpage_to_fscache(struct inode *inode, struct page *page, int sync)
+{
+ BUG();
+}
+#endif
+
+
/*
* Read a page synchronously.
*/
@@ -184,6 +234,14 @@ static int nfs_readpage_sync(struct nfs_
ClearPageError(page);
result = 0;
+#ifdef CONFIG_NFS_FSCACHE
+ if (PagePrivate(page))
+ nfs_readpage_to_fscache(inode, page, 1);
+#endif
+ unlock_page(page);
+
+ return result;
+
io_error:
unlock_page(page);
nfs_readdata_free(rdata);
@@ -215,6 +273,12 @@ static int nfs_readpage_async(struct nfs
static void nfs_readpage_release(struct nfs_page *req)
{
+#ifdef CONFIG_NFS_FSCACHE
+ struct inode *d_inode = req->wb_context->dentry->d_inode;
+
+ if (PagePrivate(req->wb_page) && PageUptodate(req->wb_page))
+ nfs_readpage_to_fscache(d_inode, req->wb_page, 0);
+#endif
unlock_page(req->wb_page);
dprintk("NFS: read done (%s/%Ld %d@%Ld)\n",
@@ -538,6 +602,118 @@ int nfs_readpage_result(struct rpc_task
return 0;
}
+
+/*
+ * Read a page through the on-disc cache if possible
+ */
+#ifdef CONFIG_NFS_FSCACHE
+static void
+nfs_readpage_from_fscache_complete(struct page *page, void *data, int error)
+{
+ dfprintk(FSCACHE,
+ "NFS: readpage_from_fscache_complete (0x%p/0x%p/%d)\n",
+ page, data, error);
+
+ if (error)
+ SetPageError(page);
+ else
+ SetPageUptodate(page);
+
+ unlock_page(page);
+}
+
+static inline int
+nfs_readpage_from_fscache(struct inode *inode, struct page *page)
+{
+ int ret;
+
+ if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_FSCACHE))
+ return 1;
+
+ dfprintk(FSCACHE,
+ "NFS: readpage_from_fscache(fsc:%p/p:%p(i:%lx f:%lx)/0x%p)\n",
+ NFS_I(inode)->fscache, page, page->index, page->flags, inode);
+
+ ret = fscache_read_or_alloc_page(NFS_I(inode)->fscache,
+ page,
+ nfs_readpage_from_fscache_complete,
+ NULL,
+ GFP_KERNEL);
+
+ switch (ret) {
+ case 0: /* read BIO submitted (page in fscache) */
+ dfprintk(FSCACHE,
+ "NFS: readpage_from_fscache: BIO submitted\n");
+ nfs_fscache_from_pages++;
+ return ret;
+
+ case -ENOBUFS: /* inode not in cache */
+ case -ENODATA: /* page not in cache */
+ dfprintk(FSCACHE,
+ "NFS: readpage_from_fscache error %d\n", ret);
+ return 1;
+
+ default:
+ dfprintk(FSCACHE, "NFS: readpage_from_fscache %d\n", ret);
+ nfs_fscache_from_error = ret;
+ }
+ return ret;
+}
+
+static inline
+int nfs_getpages_from_fscache(struct inode *inode,
+ struct address_space *mapping,
+ struct list_head *pages,
+ unsigned *nr_pages)
+{
+ int ret, npages = *nr_pages;
+
+ if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_FSCACHE))
+ return 1;
+
+ dfprintk(FSCACHE,
+ "NFS: nfs_getpages_from_fscache (0x%p/%u/0x%p)\n",
+ NFS_I(inode)->fscache, *nr_pages, inode);
+
+ ret = fscache_read_or_alloc_pages(NFS_I(inode)->fscache,
+ mapping, pages, nr_pages,
+ nfs_readpage_from_fscache_complete,
+ NULL, mapping_gfp_mask(mapping));
+
+
+ switch (ret) {
+ case 0: /* read BIO submitted (page in fscache) */
+ BUG_ON(!list_empty(pages));
+ BUG_ON(*nr_pages != 0);
+ dfprintk(FSCACHE,
+ "NFS: nfs_getpages_from_fscache: BIO submitted\n");
+
+ nfs_fscache_from_pages += npages;
+ return ret;
+
+ case -ENOBUFS: /* inode not in cache */
+ case -ENODATA: /* page not in cache */
+ dfprintk(FSCACHE,
+ "NFS: nfs_getpages_from_fscache: no page: %d\n", ret);
+ return 1;
+
+ default:
+ dfprintk(FSCACHE,
+ "NFS: nfs_getpages_from_fscache: ret %d\n", ret);
+ nfs_fscache_from_error = ret;
+ }
+
+ return ret;
+}
+#else
+static inline
+int nfs_getpages_from_fscache(struct inode *inode,
+ struct address_space *mapping,
+ struct list_head *pages,
+ unsigned *nr_pages)
+{ return 1; }
+#endif
+
/*
* Read a page over NFS.
* We read the page synchronously in the following case:
@@ -574,6 +750,15 @@ int nfs_readpage(struct file *file, stru
ctx = get_nfs_open_context((struct nfs_open_context *)
file->private_data);
if (!IS_SYNC(inode)) {
+#ifdef CONFIG_NFS_FSCACHE
+ error = nfs_readpage_from_fscache(inode, page);
+#if 0
+ if (error < 0)
+ goto out_error;
+#endif
+ if (error == 0)
+ goto out;
+#endif
error = nfs_readpage_async(ctx, inode, page);
goto out;
}
@@ -604,6 +789,7 @@ readpage_async_filler(void *data, struct
unsigned int len;
nfs_wb_page(inode, page);
+
len = nfs_page_length(inode, page);
if (len == 0)
return nfs_return_empty_page(page);
@@ -636,6 +822,15 @@ int nfs_readpages(struct file *filp, str
nr_pages);
nfs_inc_stats(inode, NFSIOS_VFSREADPAGES);
+#ifdef CONFIG_NFS_FSCACHE
+ /* attempt to read as many of the pages as possible from the cache
+ * - this returns -ENOBUFS immediately if the cookie is negative
+ */
+ ret = nfs_getpages_from_fscache(inode, mapping, pages, &nr_pages);
+ if (ret == 0)
+ return ret; /* all read */
+#endif
+
if (filp == NULL) {
desc.ctx = nfs_find_open_context(inode, NULL, FMODE_READ);
if (desc.ctx == NULL)
@@ -677,3 +872,48 @@ void nfs_destroy_readpagecache(void)
if (kmem_cache_destroy(nfs_rdata_cachep))
printk(KERN_INFO "nfs_read_data: not all structures were freed\n");
}
+
+#ifdef CONFIG_NFS_FSCACHE
+void nfs_invalidatepage(struct page *page, unsigned long offset)
+{
+ BUG_ON(!PageLocked(page));
+
+ if (PagePrivate(page)) {
+ struct nfs_inode *nfsi = NFS_I(page->mapping->host);
+
+ //BUG_ON(nfsi->fscache == NULL);
+
+ dfprintk(FSCACHE,
+ "NFS: fscache invalidatepage (0x%p/0x%p/0x%p)\n",
+ nfsi->fscache, page, nfsi);
+
+ if (offset == 0) {
+ BUG_ON(!PageLocked(page));
+ if (!PageWriteback(page))
+ page->mapping->a_ops->releasepage(page, 0);
+ }
+ }
+
+ return;
+}
+int nfs_releasepage(struct page *page, gfp_t gfp_flags)
+{
+ struct nfs_inode *nfsi = NFS_I(page->mapping->host);
+
+ //BUG_ON(nfsi->fscache == NULL);
+
+ dfprintk(FSCACHE, "NFS: fscache releasepage (0x%p/0x%p/0x%p)\n",
+ nfsi->fscache, page, nfsi);
+
+ wait_on_page_fs_misc(page);
+ fscache_uncache_page(nfsi->fscache, page);
+ nfs_fscache_uncache_page++;
+ ClearPagePrivate(page);
+ return 0;
+}
+int nfs_mkwrite(struct page *page)
+{
+ wait_on_page_fs_misc(page);
+ return 0;
+}
+#endif
--- linux-2.6.16.noarch/fs/nfs/sysctl.c.fsnfs 2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.noarch/fs/nfs/sysctl.c 2006-06-07 13:53:57.413321000 -0400
@@ -14,6 +14,7 @@
#include <linux/nfs_idmap.h>
#include "callback.h"
+#include "fscache.h"
static const int nfs_set_port_min = 0;
static const int nfs_set_port_max = 65535;
@@ -46,6 +47,48 @@ static ctl_table nfs_cb_sysctls[] = {
.strategy = &sysctl_jiffies,
},
#endif
+#ifdef CONFIG_NFS_FSCACHE
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "fscache_from_error",
+ .data = &nfs_fscache_from_error,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "fscache_to_error",
+ .data = &nfs_fscache_to_error,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "fscache_uncache_page",
+ .data = &nfs_fscache_uncache_page,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "fscache_to_pages",
+ .data = &nfs_fscache_to_pages,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_minmax,
+ },
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "fscache_from_pages",
+ .data = &nfs_fscache_from_pages,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+#endif
{ .ctl_name = 0 }
};
--- linux-2.6.16.noarch/fs/nfs/write.c.fsnfs 2006-06-07 13:06:23.054020000 -0400
+++ linux-2.6.16.noarch/fs/nfs/write.c 2006-06-07 13:13:18.274396000 -0400
@@ -429,7 +429,7 @@ static int nfs_inode_add_request(struct
if (nfs_have_delegation(inode, FMODE_WRITE))
nfsi->change_attr++;
}
- SetPagePrivate(req->wb_page);
+ nfs_setwriting(req->wb_page);
nfsi->npages++;
atomic_inc(&req->wb_count);
return 0;
@@ -446,7 +446,7 @@ static void nfs_inode_remove_request(str
BUG_ON (!NFS_WBACK_BUSY(req));
spin_lock(&nfsi->req_lock);
- ClearPagePrivate(req->wb_page);
+ nfs_clearwriting(req->wb_page);
radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index);
nfsi->npages--;
if (!nfsi->npages) {
--- linux-2.6.16.noarch/fs/nfs/pagelist.c.fsnfs 2006-06-07 13:06:23.000020000 -0400
+++ linux-2.6.16.noarch/fs/nfs/pagelist.c 2006-06-07 13:13:18.299395000 -0400
@@ -85,7 +85,7 @@ nfs_create_request(struct nfs_open_conte
atomic_set(&req->wb_complete, 0);
req->wb_index = page->index;
page_cache_get(page);
- BUG_ON(PagePrivate(page));
+ BUG_ON(nfs_writing(page));
BUG_ON(!PageLocked(page));
BUG_ON(page->mapping->host != inode);
req->wb_offset = offset;
--- /dev/null 2006-06-07 07:14:18.564562589 -0400
+++ linux-2.6.16.noarch/fs/nfs/fscache.h 2006-06-07 13:13:18.640395000 -0400
@@ -0,0 +1,244 @@
+/* nfs_fscache.h: NFS filesystem cache interface definitions
+ *
+ * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells at redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _NFS_FSCACHE_H
+#define _NFS_FSCACHE_H
+
+#include <linux/nfs_fs.h>
+#include <linux/nfs_mount.h>
+#include <linux/nfs4_mount.h>
+
+#ifdef CONFIG_NFS_FSCACHE
+#include <linux/fscache.h>
+
+extern struct fscache_netfs nfs_cache_netfs;
+extern struct fscache_cookie_def nfs_cache_server_index_def;
+extern struct fscache_cookie_def nfs_fsctag_index_def;
+extern struct fscache_cookie_def nfs_cache_fh_index_def;
+extern struct fscache_cookie_def nfs4_fsctag_index_def;
+
+extern void nfs_invalidatepage(struct page *, unsigned long);
+extern int nfs_releasepage(struct page *, gfp_t);
+extern int nfs_mkwrite(struct page *);
+extern int nfs_load_fsctag(const char *tag, struct nfs_server *server);
+
+extern int nfs_fscache_to_pages;
+extern int nfs_fscache_from_pages;
+extern int nfs_fscache_uncache_page;
+extern int nfs_fscache_from_error;
+extern int nfs_fscache_to_error;
+
+static inline void
+nfs_set_fscsize(struct nfs_server *server,
+ struct nfs_inode *nfsi, loff_t i_size)
+{
+ if (!(server->flags & NFS_MOUNT_FSCACHE))
+ return;
+
+ fscache_set_i_size(nfsi->fscache, i_size);
+
+ return;
+}
+static inline void
+nfs_renew_fscookie(struct nfs_server *server, struct nfs_inode *nfsi)
+{
+ struct fscache_cookie *old = nfsi->fscache;
+
+ if (!(server->flags & NFS_MOUNT_FSCACHE)) {
+ nfsi->fscache = NULL;
+ return;
+ }
+
+ /* retire the current fscache cache and get a new one */
+ fscache_relinquish_cookie(nfsi->fscache, 1);
+ nfsi->fscache = fscache_acquire_cookie(server->fscache,
+ &nfs_cache_fh_index_def, nfsi);
+ fscache_set_i_size(nfsi->fscache, nfsi->vfs_inode.i_size);
+
+ dfprintk(FSCACHE,
+ "NFS: revalidation new cookie (0x%p/0x%p/0x%p/0x%p)\n",
+ server, nfsi, old, nfsi->fscache);
+
+ return;
+}
+
+static inline void nfs4_fill_fscookie(struct super_block *sb)
+{
+ struct nfs_server *server = NFS_SB(sb);
+
+ if (!(server->flags & NFS4_MOUNT_FSCACHE)) {
+ server->fscache = NULL;
+ return;
+ }
+ server->fscache = NULL;
+ if (nfs_load_fsctag("mount:nfs4:fsctag", server)) {
+ /* create a cache index for looking up filehandles */
+ server->fscache = fscache_acquire_cookie(nfs_cache_netfs.primary_index,
+ &nfs4_fsctag_index_def, server);
+ }
+
+ if (server->fscache == NULL) {
+ printk(KERN_WARNING "NFS4: No Fscache cookie. Turning "
+ "Fscache off!\n");
+ } else {
+ /* reuse the NFS mount option */
+ server->flags |= NFS_MOUNT_FSCACHE;
+ }
+
+ dfprintk(FSCACHE,"NFS: nfs4 cookie (0x%p,0x%p/0x%p)\n",
+ sb, server, server->fscache);
+
+ return;
+}
+
+static inline void nfs_fill_fscookie(struct super_block *sb)
+{
+ struct nfs_server *server = NFS_SB(sb);
+
+ if (!(server->flags & NFS_MOUNT_FSCACHE)) {
+ server->fscache = NULL;
+ return;
+ }
+
+ server->fscache = NULL;
+ if (nfs_load_fsctag("mount:nfs:fsctag", server)) {
+ /* create a cache index for looking up filehandles */
+ server->fscache = fscache_acquire_cookie(nfs_cache_netfs.primary_index,
+ &nfs_fsctag_index_def, server);
+ }
+ if (server->fscache == NULL) {
+ server->flags &= ~NFS_MOUNT_FSCACHE;
+ printk(KERN_WARNING "NFS: No Fscache cookie. Turning "
+ "Fscache off!\n");
+ }
+
+ dfprintk(FSCACHE,"NFS: server cookie (0x%p/0x%p/0x%p)\n",
+ sb, server, server->fscache);
+
+ return;
+}
+
+static inline void
+nfs_fhget_fscookie(struct super_block *sb, struct nfs_inode *nfsi)
+{
+ struct nfs_server *server = NFS_SB(sb);
+
+ if (!(server->flags & NFS_MOUNT_FSCACHE)) {
+ nfsi->fscache = NULL;
+ return;
+ }
+
+ nfsi->fscache = fscache_acquire_cookie(server->fscache,
+ &nfs_cache_fh_index_def, nfsi);
+ if (server->fscache == NULL)
+ printk(KERN_WARNING "NFS: NULL FScache cookie: "
+ "sb 0x%p nfsi 0x%p\n", sb, nfsi);
+ fscache_set_i_size(nfsi->fscache, nfsi->vfs_inode.i_size);
+
+ dfprintk(FSCACHE, "NFS: fhget new cookie (0x%p/0x%p/0x%p)\n",
+ sb, nfsi, nfsi->fscache);
+
+ return;
+}
+
+static inline void nfs_kill_fscookie(struct nfs_server *server)
+{
+ if (!(server->flags & NFS_MOUNT_FSCACHE))
+ return;
+
+ dfprintk(FSCACHE,"NFS: killing cookie (0x%p/0x%p)\n",
+ server, server->fscache);
+
+ fscache_relinquish_cookie(server->fscache, 0);
+ server->fscache = NULL;
+
+ return;
+}
+
+static inline void nfs_clear_fscookie(
+ struct nfs_server *server, struct nfs_inode *nfsi)
+{
+ if (!(server->flags & NFS_MOUNT_FSCACHE))
+ return;
+
+ dfprintk(FSCACHE, "NFS: clear cookie (0x%p/0x%p)\n",
+ nfsi, nfsi->fscache);
+
+ fscache_relinquish_cookie(nfsi->fscache, 0);
+ nfsi->fscache = NULL;
+
+ return;
+}
+
+static inline void nfs_zap_fscookie(
+ struct nfs_server *server, struct nfs_inode *nfsi)
+{
+ if (!(server->flags & NFS_MOUNT_FSCACHE))
+ return;
+
+ dfprintk(FSCACHE,"NFS: zapping cookie (0x%p/0x%p)\n",
+ nfsi, nfsi->fscache);
+
+ fscache_relinquish_cookie(nfsi->fscache, 1);
+ nfsi->fscache = NULL;
+
+ return;
+}
+
+static inline void nfs_set_fscache(struct inode *inode, int cache_on)
+{
+ if (!cache_on && NFS_I(inode)->fscache) {
+ dfprintk(FSCACHE,
+ "NFS: nfsi 0x%p turning cache off\n", NFS_I(inode));
+ /*
+ * Need to invalided any mapped pages that were
+ * read in before turning off the cache.
+ */
+ if (inode->i_mapping && inode->i_mapping->nrpages)
+ invalidate_inode_pages2(inode->i_mapping);
+
+ nfs_zap_fscookie(NFS_SERVER(inode), NFS_I(inode));
+ }
+
+ return;
+}
+
+static inline int nfs_register_netfs(void)
+{
+ int err;
+
+ err = fscache_register_netfs(&nfs_cache_netfs);
+
+ return err;
+}
+
+static inline void nfs_unregister_netfs(void)
+{
+ fscache_unregister_netfs(&nfs_cache_netfs);
+
+ return;
+}
+#else
+static inline void nfs_set_fscsize(struct nfs_server *server, struct nfs_inode *nfsi, loff_t i_size) {}
+static inline void nfs_fill_fscookie(struct super_block *sb) {}
+static inline void nfs_fhget_fscookie(struct super_block *sb, struct nfs_inode *nfsi) {}
+static inline void nfs4_fill_fscookie(struct super_block *sb) {}
+static inline void nfs_kill_fscookie(struct nfs_server *server) {}
+static inline void nfs_clear_fscookie(struct nfs_server *server, struct nfs_inode *nfsi) {}
+static inline void nfs_zap_fscookie(struct nfs_server *server, struct nfs_inode *nfsi) {}
+static inline void nfs_set_fscache(struct inode *inode, int cache_on) {}
+static inline void
+ nfs_renew_fscookie(struct nfs_server *server, struct nfs_inode *nfsi) {}
+static inline int nfs_register_netfs(void) { return 0; }
+static inline void nfs_unregister_netfs(void) {}
+
+#endif
+#endif /* _NFS_FSCACHE_H */
--- linux-2.6.16.noarch/fs/Kconfig.fsnfs 2006-06-07 13:07:25.320570000 -0400
+++ linux-2.6.16.noarch/fs/Kconfig 2006-06-07 13:13:18.315396000 -0400
@@ -1501,6 +1501,13 @@ config NFS_V4
If unsure, say N.
+config NFS_FSCACHE
+ bool "Provide NFS client caching support (EXPERIMENTAL)"
+ depends on NFS_FS && FSCACHE && EXPERIMENTAL
+ help
+ Say Y here if you want NFS data to be cached locally on disc through
+ the general filesystem cache manager
+
config NFS_DIRECTIO
bool "Allow direct I/O on NFS files (EXPERIMENTAL)"
depends on NFS_FS && EXPERIMENTAL
--- linux-2.6.16.noarch/include/linux/nfs_fs.h.fsnfs 2006-06-07 13:06:36.917371000 -0400
+++ linux-2.6.16.noarch/include/linux/nfs_fs.h 2006-06-07 13:13:18.451395000 -0400
@@ -29,6 +29,7 @@
#include <linux/nfs_xdr.h>
#include <linux/rwsem.h>
#include <linux/mempool.h>
+#include <linux/fscache.h>
/*
* Enable debugging support for nfs client.
@@ -179,6 +180,9 @@ struct nfs_inode {
int delegation_state;
struct rw_semaphore rwsem;
#endif /* CONFIG_NFS_V4*/
+#ifdef CONFIG_NFS_FSCACHE
+ struct fscache_cookie *fscache;
+#endif
struct inode vfs_inode;
};
@@ -563,6 +567,7 @@ extern void * nfs_root_data(void);
#define NFSDBG_FILE 0x0040
#define NFSDBG_ROOT 0x0080
#define NFSDBG_CALLBACK 0x0100
+#define NFSDBG_FSCACHE 0x0200
#define NFSDBG_ALL 0xFFFF
#ifdef __KERNEL__
--- linux-2.6.16.noarch/include/linux/nfs_page.h.fsnfs 2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.noarch/include/linux/nfs_page.h 2006-06-07 13:13:18.695396000 -0400
@@ -32,6 +32,11 @@
#define PG_NEED_COMMIT 1
#define PG_NEED_RESCHED 2
+/*
+ * Valid bits for page->private
+ */
+#define PG_NFS_WRITING 0
+
struct nfs_inode;
struct nfs_page {
struct list_head wb_list, /* Defines state of page: */
@@ -160,4 +165,22 @@ loff_t req_offset(struct nfs_page *req)
return (((loff_t)req->wb_index) << PAGE_CACHE_SHIFT) + req->wb_offset;
}
+static inline int
+nfs_writing(struct page *page)
+{
+ return test_bit(PG_NFS_WRITING, &page->private);
+}
+
+static inline void
+nfs_setwriting(struct page *page)
+{
+ set_bit(PG_NFS_WRITING, &page->private);
+}
+
+static inline void
+nfs_clearwriting(struct page *page)
+{
+ clear_bit(PG_NFS_WRITING, &page->private);
+}
+
#endif /* _LINUX_NFS_PAGE_H */
--- linux-2.6.16.noarch/include/linux/nfs4_mount.h.fsnfs 2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.noarch/include/linux/nfs4_mount.h 2006-06-07 14:04:11.798645000 -0400
@@ -65,6 +65,7 @@ struct nfs4_mount_data {
#define NFS4_MOUNT_NOCTO 0x0010 /* 1 */
#define NFS4_MOUNT_NOAC 0x0020 /* 1 */
#define NFS4_MOUNT_STRICTLOCK 0x1000 /* 1 */
+#define NFS4_MOUNT_FSCACHE 0x4000 /* 1 */
#define NFS4_MOUNT_FLAGMASK 0xFFFF
#endif
--- linux-2.6.16.noarch/include/linux/nfs_fs_sb.h.fsnfs 2006-06-07 13:06:36.936372000 -0400
+++ linux-2.6.16.noarch/include/linux/nfs_fs_sb.h 2006-06-07 13:13:18.508395000 -0400
@@ -3,6 +3,7 @@
#include <linux/list.h>
#include <linux/backing-dev.h>
+#include <linux/fscache.h>
struct nfs_iostats;
@@ -53,6 +54,14 @@ struct nfs_server {
that are supported on this
filesystem */
#endif
+
+#ifdef CONFIG_NFS_FSCACHE
+ struct fscache_cookie *fscache; /* cache cookie */
+ struct {
+ uint16_t size;
+ void *buf;
+ } fsctag;
+#endif
};
/* Server capabilities */
--- linux-2.6.16.noarch/include/linux/nfs_mount.h.fsnfs 2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.noarch/include/linux/nfs_mount.h 2006-06-07 13:13:18.579396000 -0400
@@ -61,6 +61,7 @@ struct nfs_mount_data {
#define NFS_MOUNT_NOACL 0x0800 /* 4 */
#define NFS_MOUNT_STRICTLOCK 0x1000 /* reserved for NFSv4 */
#define NFS_MOUNT_SECFLAVOUR 0x2000 /* 5 */
+#define NFS_MOUNT_FSCACHE 0x4000
#define NFS_MOUNT_FLAGMASK 0xFFFF
#endif
Index: kernel-2.6.spec
===================================================================
RCS file: /cvs/dist/rpms/kernel/devel/kernel-2.6.spec,v
retrieving revision 1.2253
retrieving revision 1.2253.2.1
diff -u -r1.2253 -r1.2253.2.1
--- kernel-2.6.spec 6 Jun 2006 21:15:47 -0000 1.2253
+++ kernel-2.6.spec 8 Jun 2006 18:35:27 -0000 1.2253.2.1
@@ -26,7 +26,7 @@
%define sublevel 16
%define kversion 2.6.%{sublevel}
%define rpmversion 2.6.%{sublevel}
-%define release %(R="$Revision$"; RR="${R##: }"; echo ${RR%%?})_FC6
+%define release %(R="$Revision$"; RR="${R##: }"; echo ${RR%%?})_FC6.fscache
%define signmodules 0
%define xen_version 20060602
%define make_target bzImage
@@ -412,11 +412,25 @@
Patch2301: linux-2.6-acpi-ecdt-uid-hack.patch
Patch2302: linux-2.6-cpufreq-acpi-sticky.patch
+# Cachefs Bits
+Patch7000: linux-2.6.17-cachefs-fsmisc.patch
+Patch7001: linux-2.6.17-cachefs-mkwrite.patch
+Patch7002: linux-2.6.17-cachefs-kfile.patch
+Patch7003: linux-2.6.17-cachefs-relpage.patch
+Patch7004: linux-2.6.17-fscache.patch
+Patch7005: linux-2.6.17-fscache-fedora.patch
+Patch7006: linux-2.6.17-cachefiles.patch
+Patch7007: linux-2.6.17-cachefiles-misc.patch
+Patch7008: linux-2.6.17-nfs-fscache.patch
+Patch7009: linux-2.6.17-afs-fscache.patch
+
+
#
# 10000 to 20000 is for stuff that has to come last due to the
# amount of drivers they touch. But only these should go here.
# Not patches you're too lazy for to put in the proper place.
#
+Patch9000: linux-2.6.16-devel-klogger.patch
Patch10000: linux-2.6-compile-fixes.patch
@@ -1074,6 +1088,20 @@
# Patches 5000 to 6000 are reserved for new drivers that are about to
# be merged upstream
#
+# Cachefs bits
+%patch7000 -p1
+%patch7001 -p1
+%patch7002 -p1
+%patch7003 -p1
+%patch7004 -p1
+%patch7005 -p1
+%patch7006 -p1
+%patch7007 -p1
+%patch7008 -p1
+%patch7009 -p1
+
+# klogger
+%patch9000 -p1
#
# final stuff
@@ -1774,6 +1802,9 @@
%endif
%changelog
+* Thu Jun 8 2006 Steve Dickson <steved at redhat.com>
+- Added cachefs bits to kernel-2_6_16-1_2253_FC6_fscache branch
+
* Tue Jun 6 2006 Dave Jones <davej at redhat.com>
- 2.6.17rc6. Special 6/6/6 edition, what could go wrong?
- Add a kdump kernel for PPC64 (Don Zickus)
More information about the fedora-cvs-commits
mailing list