From: David Howells <dhowells@redhat.com>
To: Nick Piggin <nickpiggin@yahoo.com.au>
Cc: dhowells@redhat.com, viro@zeniv.linux.org.uk,
nfsv4@linux-nfs.org, linux-kernel@vger.kernel.org,
linux-fsdevel@vger.kernel.org
Subject: Re: [PATCH 06/43] FS-Cache: Recruit a couple of page flags for cache management [ver #46]
Date: Fri, 03 Apr 2009 02:11:10 +0100 [thread overview]
Message-ID: <31146.1238721070@redhat.com> (raw)
In-Reply-To: <200904030514.42687.nickpiggin@yahoo.com.au>
Nick Piggin <nickpiggin@yahoo.com.au> wrote:
> > Besides, as I said NFS uses PG_private for its own purposes, and entangling
> > the two wasn't the most fun I've had. Trond didn't like it either.
>
> IMO that is quite OK to make them go through the pain of that if it
> avoids resulting in a new page flag that is probably unusable to most
> other filesystems.
>
> But... I guess I won't get hung up on it. If you avoid at least one of
> these flags it would be a good start.
Okay, the attached patch allows PageFsCacheWrite to be dispensed with. I have
a radix tree already to track pages that need writing, so I just extend the
use of that.
It does make waiting for a page to be written more tricky, though, as I can't
now just wait on a page flag. It's also theoretically slower as I now have to
take extra spinlocks.
I've benchmarked it three times:
Fri Apr 3 01:42:16 BST 2009
Fri Apr 3 01:44:25 BST 2009 2m 9s
Fri Apr 3 01:46:45 BST 2009
Fri Apr 3 01:48:24 BST 2009 1m 39s
Fri Apr 3 01:50:28 BST 2009
Fri Apr 3 01:52:40 BST 2009 2m 12s
using the same benchmark as for the patch to use the write() file op.
David
---
commit 9a10592512b01b42eb65f32c1028c57a1a6c864e
Author: David Howells <dhowells@redhat.com>
Date: Fri Apr 3 02:04:15 2009 +0100
FS-Cache: Use a radix tree to track pages being written rather than a page flag
Use a radix tree attached to struct fscache_cookie to track what pages are
undergoing write, rather than using a page flag.
The radix tree that was resident in struct fscache_object to track pages that
need writing is moved to fscache_cookie. Pages that need writing and pages
that are being written are both held in there. The difference being that the
former are tagged with FSCACHE_COOKIE_PENDING_TAG.
Signed-off-by: David Howells <dhowells@redhat.com>
diff --git a/Documentation/filesystems/caching/netfs-api.txt b/Documentation/filesystems/caching/netfs-api.txt
index da8f92f..4db125b 100644
--- a/Documentation/filesystems/caching/netfs-api.txt
+++ b/Documentation/filesystems/caching/netfs-api.txt
@@ -640,7 +640,18 @@ Note that pages can't be explicitly deleted from the a data file. The whole
data file must be retired (see the relinquish cookie function below).
Furthermore, note that this does not cancel the asynchronous read or write
-operation started by the read/alloc and write functions.
+operation started by the read/alloc and write functions, so the page
+invalidation and release functions must use:
+
+ bool fscache_check_page_write(struct fscache_cookie *cookie,
+ struct page *page);
+
+to see if a page is being written to the cache, and:
+
+ void fscache_wait_on_page_write(struct fscache_cookie *cookie,
+ struct page *page);
+
+to wait for it to finish if it is.
==========================
@@ -730,52 +741,32 @@ this, the caller should relinquish and retire the cookie they have, and then
acquire a new one.
-============================
-FS-CACHE SPECIFIC PAGE FLAGS
-============================
-
-FS-Cache makes use of two page flags, PG_private_2 and PG_owner_priv_2, for
-its own purpose. The first is given the alternative name PG_fscache and the
-second PG_fscache_write.
-
-FS-Cache uses these flags to keep track of two bits of information per cached
-netfs page:
+===========================
+FS-CACHE SPECIFIC PAGE FLAG
+===========================
- (1) PG_fscache.
+FS-Cache makes use of a page flag, PG_private_2, for its own purpose. This is
+given the alternative name PG_fscache.
- This indicates that the page is known by the cache, and that the cache
- must be informed if the page is going to go away. It's an indication to
- the netfs that the cache has an interest in this page, where an interest
- may be a pointer to it, resources allocated or reserved for it, or I/O in
- progress upon it.
+PG_fscache is used to indicate that the page is known by the cache, and that
+the cache must be informed if the page is going to go away. It's an indication
+to the netfs that the cache has an interest in this page, where an interest may
+be a pointer to it, resources allocated or reserved for it, or I/O in progress
+upon it.
- The netfs can use this information in methods such as releasepage() to
- determine whether it needs to uncache a page or update it.
+The netfs can use this information in methods such as releasepage() to
+determine whether it needs to uncache a page or update it.
- Furthermore, if this bit is set, releasepage() and invalidatepage()
- operations will be called on a page to get rid of it, even if PG_private
- is not set. This allows caching to attempted on a page before
- read_cache_pages() to be called after fscache_read_or_alloc_pages() as
- the former will try and release pages it was given under certain
- circumstances.
+Furthermore, if this bit is set, releasepage() and invalidatepage() operations
+will be called on a page to get rid of it, even if PG_private is not set. This
+allows caching to attempted on a page before read_cache_pages() to be called
+after fscache_read_or_alloc_pages() as the former will try and release pages it
+was given under certain circumstances.
- (2) PG_fscache_write.
+This bit does not overlap with such as PG_private. This means that FS-Cache
+can be used with a filesystem that uses the block buffering code.
- This indicates that the page is being written to disk by the cache, and
- that it cannot be released until completion. Ideally it shouldn't be
- changed until completion either so as to maintain the known state of the
- cache. This cannot be unified with PG_writeback as the page may be being
- written to both the server and the cache at the same time or at different
- times.
-
- This can be used by the netfs to wait for a page to be written out to the
- cache before, say, releasing or invalidating it, or before allowing
- someone to modify it in page_mkwrite(), say.
-
-Neither of these two bits overlaps with such as PG_private. This means that
-FS-Cache can be used with a filesystem that uses the block buffering code.
-
-There are a number of operations defined on these two bits:
+There are a number of operations defined on this flag:
int PageFsCache(struct page *page);
void SetPageFsCache(struct page *page)
@@ -783,18 +774,5 @@ There are a number of operations defined on these two bits:
int TestSetPageFsCache(struct page *page)
int TestClearPageFsCache(struct page *page)
- int PageFsCacheWrite(struct page *page)
- void SetPageFsCacheWrite(struct page *page)
- void ClearPageFsCacheWrite(struct page *page)
- int TestSetPageFsCacheWrite(struct page *page)
- int TestClearPageFsCacheWrite(struct page *page)
-
These functions are bit test, bit set, bit clear, bit test and set and bit
-test and clear operations on PG_fscache and PG_fscache_write.
-
- void wait_on_page_fscache_write(struct page *page)
- void end_page_fscache_write(struct page *page)
-
-The first of these two functions waits uninterruptibly for PG_fscache_write to
-become clear, if it isn't already so. The second clears PG_fscache_write and
-wakes up anyone waiting for it.
+test and clear operations on PG_fscache.
diff --git a/fs/afs/file.c b/fs/afs/file.c
index aeb6cdd..7a1d942 100644
--- a/fs/afs/file.c
+++ b/fs/afs/file.c
@@ -299,7 +299,7 @@ static void afs_invalidatepage(struct page *page, unsigned long offset)
#ifdef CONFIG_AFS_FSCACHE
if (PageFsCache(page)) {
struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
- wait_on_page_fscache_write(page);
+ fscache_wait_on_page_write(vnode->cache, page);
fscache_uncache_page(vnode->cache, page);
ClearPageFsCache(page);
}
@@ -336,12 +336,12 @@ static int afs_releasepage(struct page *page, gfp_t gfp_flags)
* elected to wait */
#ifdef CONFIG_AFS_FSCACHE
if (PageFsCache(page)) {
- if (PageFsCacheWrite(page)) {
+ if (fscache_check_page_write(vnode->cache, page)) {
if (!(gfp_flags & __GFP_WAIT)) {
_leave(" = F [cache busy]");
return 0;
}
- wait_on_page_fscache_write(page);
+ fscache_wait_on_page_write(vnode->cache, page);
}
fscache_uncache_page(vnode->cache, page);
diff --git a/fs/afs/write.c b/fs/afs/write.c
index 7884518..c2e7a7f 100644
--- a/fs/afs/write.c
+++ b/fs/afs/write.c
@@ -795,7 +795,7 @@ int afs_page_mkwrite(struct vm_area_struct *vma, struct page *page)
/* wait for the page to be written to the cache before we allow it to
* be modified */
#ifdef CONFIG_AFS_FSCACHE
- wait_on_page_fscache_write(page);
+ fscache_wait_on_page_write(vnode->cache, page);
#endif
_leave(" = 0");
diff --git a/fs/fscache/cookie.c b/fs/fscache/cookie.c
index cd9d065..72fd18f 100644
--- a/fs/fscache/cookie.c
+++ b/fs/fscache/cookie.c
@@ -102,6 +102,8 @@ struct fscache_cookie *__fscache_acquire_cookie(
cookie->netfs_data = netfs_data;
cookie->flags = 0;
+ INIT_RADIX_TREE(&cookie->stores, GFP_NOFS);
+
switch (cookie->def->type) {
case FSCACHE_COOKIE_TYPE_INDEX:
fscache_stat(&fscache_n_cookie_index);
diff --git a/fs/fscache/page.c b/fs/fscache/page.c
index 512ec2c..2568e0e 100644
--- a/fs/fscache/page.c
+++ b/fs/fscache/page.c
@@ -17,6 +17,47 @@
#include "internal.h"
/*
+ * check to see if a page is being written to the cache
+ */
+bool __fscache_check_page_write(struct fscache_cookie *cookie, struct page *page)
+{
+ void *val;
+
+ rcu_read_lock();
+ val = radix_tree_lookup(&cookie->stores, page->index);
+ rcu_read_unlock();
+
+ return val != NULL;
+}
+EXPORT_SYMBOL(__fscache_check_page_write);
+
+/*
+ * wait for a page to finish being written to the cache
+ */
+void __fscache_wait_on_page_write(struct fscache_cookie *cookie, struct page *page)
+{
+ wait_queue_head_t *wq = bit_waitqueue(&cookie->flags, 0);
+
+ wait_event(*wq, !__fscache_check_page_write(cookie, page));
+}
+EXPORT_SYMBOL(__fscache_wait_on_page_write);
+
+/*
+ * note that a page has finished being written to the cache
+ */
+static void fscache_end_page_write(struct fscache_cookie *cookie, struct page *page)
+{
+ struct page *xpage;
+
+ spin_lock(&cookie->lock);
+ xpage = radix_tree_delete(&cookie->stores, page->index);
+ spin_unlock(&cookie->lock);
+ ASSERT(xpage != NULL);
+
+ wake_up_bit(&cookie->flags, 0);
+}
+
+/*
* actually apply the changed attributes to a cache object
*/
static void fscache_attr_changed_op(struct fscache_operation *op)
@@ -480,6 +521,7 @@ static void fscache_write_op(struct fscache_operation *_op)
struct fscache_storage *op =
container_of(_op, struct fscache_storage, op);
struct fscache_object *object = op->op.object;
+ struct fscache_cookie *cookie = object->cookie;
struct page *page;
unsigned n;
void *results[1];
@@ -487,10 +529,12 @@ static void fscache_write_op(struct fscache_operation *_op)
_enter("{OP%x,%d}", op->op.debug_id, atomic_read(&op->op.usage));
+ spin_lock(&cookie->lock);
spin_lock(&object->lock);
if (!fscache_object_is_active(object)) {
spin_unlock(&object->lock);
+ spin_unlock(&cookie->lock);
_leave("");
return;
}
@@ -499,23 +543,24 @@ static void fscache_write_op(struct fscache_operation *_op)
/* find a page to store */
page = NULL;
- n = radix_tree_gang_lookup(&object->stores, results, 0, 1);
- if (n == 1) {
- page = results[0];
- _debug("gang %d [%lx]", n, page->index);
- if (page->index <= op->store_limit)
- radix_tree_delete(&object->stores, page->index);
- else
- goto superseded;
- } else {
+ n = radix_tree_gang_lookup_tag(&cookie->stores, results, 0, 1,
+ FSCACHE_COOKIE_PENDING_TAG);
+ if (n != 1)
+ goto superseded;
+ page = results[0];
+ _debug("gang %d [%lx]", n, page->index);
+ if (page->index > op->store_limit)
goto superseded;
- }
+
+ radix_tree_tag_clear(&cookie->stores, page->index,
+ FSCACHE_COOKIE_PENDING_TAG);
spin_unlock(&object->lock);
+ spin_unlock(&cookie->lock);
if (page) {
ret = object->cache->ops->write_page(op, page);
- end_page_fscache_write(page);
+ fscache_end_page_write(cookie, page);
page_cache_release(page);
if (ret < 0)
fscache_abort_object(object);
@@ -532,6 +577,7 @@ superseded:
_debug("cease");
clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags);
spin_unlock(&object->lock);
+ spin_unlock(&cookie->lock);
_leave("");
}
@@ -609,7 +655,7 @@ int __fscache_write_page(struct fscache_cookie *cookie,
_debug("store limit %llx", (unsigned long long) object->store_limit);
- ret = radix_tree_insert(&object->stores, page->index, page);
+ ret = radix_tree_insert(&cookie->stores, page->index, page);
if (ret < 0) {
if (ret == -EEXIST)
goto already_queued;
@@ -617,9 +663,9 @@ int __fscache_write_page(struct fscache_cookie *cookie,
goto nobufs_unlock_obj;
}
+ radix_tree_tag_set(&cookie->stores, page->index,
+ FSCACHE_COOKIE_PENDING_TAG);
page_cache_get(page);
- if (TestSetPageFsCacheWrite(page))
- BUG();
/* we only want one writer at a time, but we do need to queue new
* writers after exclusive ops */
@@ -656,8 +702,7 @@ already_pending:
return 0;
submit_failed:
- radix_tree_delete(&object->stores, page->index);
- end_page_fscache_write(page);
+ radix_tree_delete(&cookie->stores, page->index);
page_cache_release(page);
ret = -ENOBUFS;
goto nobufs;
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index d3060c4..3523b89 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -456,11 +456,12 @@ static int nfs_release_page(struct page *page, gfp_t gfp)
static int nfs_launder_page(struct page *page)
{
struct inode *inode = page->mapping->host;
+ struct nfs_inode *nfsi = NFS_I(inode);
dfprintk(PAGECACHE, "NFS: launder_page(%ld, %llu)\n",
inode->i_ino, (long long)page_offset(page));
- wait_on_page_fscache_write(page);
+ nfs_fscache_wait_on_page_write(nfsi, page);
return nfs_wb_page(inode, page);
}
@@ -498,7 +499,7 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
(long long)page_offset(page));
/* make sure the cache has finished storing the page */
- wait_on_page_fscache_write(page);
+ nfs_fscache_wait_on_page_write(NFS_I(dentry->d_inode), page);
lock_page(page);
mapping = page->mapping;
diff --git a/fs/nfs/fscache.c b/fs/nfs/fscache.c
index 968cf5d..379be67 100644
--- a/fs/nfs/fscache.c
+++ b/fs/nfs/fscache.c
@@ -337,21 +337,22 @@ void nfs_fscache_reset_inode_cookie(struct inode *inode)
*/
int nfs_fscache_release_page(struct page *page, gfp_t gfp)
{
- if (PageFsCacheWrite(page)) {
+ struct nfs_inode *nfsi = NFS_I(page->mapping->host);
+ struct fscache_cookie *cookie = nfsi->fscache;
+
+ BUG_ON(!cookie);
+
+ if (fscache_check_page_write(cookie, page)) {
if (!(gfp & __GFP_WAIT))
return 0;
- wait_on_page_fscache_write(page);
+ fscache_wait_on_page_write(cookie, page);
}
if (PageFsCache(page)) {
- struct nfs_inode *nfsi = NFS_I(page->mapping->host);
-
- BUG_ON(!nfsi->fscache);
-
dfprintk(FSCACHE, "NFS: fscache releasepage (0x%p/0x%p/0x%p)\n",
- nfsi->fscache, page, nfsi);
+ cookie, page, nfsi);
- fscache_uncache_page(nfsi->fscache, page);
+ fscache_uncache_page(cookie, page);
nfs_add_fscache_stats(page->mapping->host,
NFSIOS_FSCACHE_PAGES_UNCACHED, 1);
}
@@ -366,16 +367,17 @@ int nfs_fscache_release_page(struct page *page, gfp_t gfp)
void __nfs_fscache_invalidate_page(struct page *page, struct inode *inode)
{
struct nfs_inode *nfsi = NFS_I(inode);
+ struct fscache_cookie *cookie = nfsi->fscache;
- BUG_ON(!nfsi->fscache);
+ BUG_ON(!cookie);
dfprintk(FSCACHE, "NFS: fscache invalidatepage (0x%p/0x%p/0x%p)\n",
- nfsi->fscache, page, nfsi);
+ cookie, page, nfsi);
- wait_on_page_fscache_write(page);
+ fscache_wait_on_page_write(cookie, page);
BUG_ON(!PageLocked(page));
- fscache_uncache_page(nfsi->fscache, page);
+ fscache_uncache_page(cookie, page);
nfs_add_fscache_stats(page->mapping->host,
NFSIOS_FSCACHE_PAGES_UNCACHED, 1);
}
diff --git a/fs/nfs/fscache.h b/fs/nfs/fscache.h
index 2d43b67..6e809bb 100644
--- a/fs/nfs/fscache.h
+++ b/fs/nfs/fscache.h
@@ -94,6 +94,16 @@ extern int __nfs_readpages_from_fscache(struct nfs_open_context *,
extern void __nfs_readpage_to_fscache(struct inode *, struct page *, int);
/*
+ * wait for a page to complete writing to the cache
+ */
+static inline void nfs_fscache_wait_on_page_write(struct nfs_inode *nfsi,
+ struct page *page)
+{
+ if (PageFsCache(page))
+ fscache_wait_on_page_write(nfsi->fscache, page);
+}
+
+/*
* release the caching state associated with a page if undergoing complete page
* invalidation
*/
@@ -181,6 +191,8 @@ static inline int nfs_fscache_release_page(struct page *page, gfp_t gfp)
}
static inline void nfs_fscache_invalidate_page(struct page *page,
struct inode *inode) {}
+static inline void nfs_fscache_wait_on_page_write(struct nfs_inode *nfsi,
+ struct page *page) {}
static inline int nfs_readpage_from_fscache(struct nfs_open_context *ctx,
struct inode *inode,
diff --git a/include/linux/fscache-cache.h b/include/linux/fscache-cache.h
index 0410bd9..84d3532 100644
--- a/include/linux/fscache-cache.h
+++ b/include/linux/fscache-cache.h
@@ -301,6 +301,9 @@ struct fscache_cookie {
const struct fscache_cookie_def *def; /* definition */
struct fscache_cookie *parent; /* parent of this entry */
void *netfs_data; /* back pointer to netfs */
+ struct radix_tree_root stores; /* pages to be stored on this cookie */
+#define FSCACHE_COOKIE_PENDING_TAG 0 /* pages tag: pending write to cache */
+
unsigned long flags;
#define FSCACHE_COOKIE_LOOKING_UP 0 /* T if non-index cookie being looked up still */
#define FSCACHE_COOKIE_CREATING 1 /* T if non-index object being created still */
@@ -370,7 +373,6 @@ struct fscache_object {
struct list_head dependents; /* FIFO of dependent objects */
struct list_head dep_link; /* link in parent's dependents list */
struct list_head pending_ops; /* unstarted operations on this object */
- struct radix_tree_root stores; /* data to be stored */
pgoff_t store_limit; /* current storage limit */
};
@@ -407,7 +409,6 @@ void fscache_object_init(struct fscache_object *object,
INIT_LIST_HEAD(&object->dependents);
INIT_LIST_HEAD(&object->dep_link);
INIT_LIST_HEAD(&object->pending_ops);
- INIT_RADIX_TREE(&object->stores, GFP_NOFS);
object->n_children = 0;
object->n_ops = object->n_in_progress = object->n_exclusive = 0;
object->events = object->event_mask = 0;
diff --git a/include/linux/fscache.h b/include/linux/fscache.h
index 006c919..6d8ee46 100644
--- a/include/linux/fscache.h
+++ b/include/linux/fscache.h
@@ -42,20 +42,6 @@
#define TestSetPageFsCache(page) TestSetPagePrivate2((page))
#define TestClearPageFsCache(page) TestClearPagePrivate2((page))
-/*
- * overload PG_owner_priv_2 to give us PG_fscache_write - this is used to
- * indicate that a page is currently being written to a local disk cache
- */
-#define PageFsCacheWrite(page) PageOwnerPriv2((page))
-#define SetPageFsCacheWrite(page) SetPageOwnerPriv2((page))
-#define ClearPageFsCacheWrite(page) ClearPageOwnerPriv2((page))
-#define TestSetPageFsCacheWrite(page) TestSetPageOwnerPriv2((page))
-#define TestClearPageFsCacheWrite(page) TestClearPageOwnerPriv2((page))
-
-#define wait_on_page_fscache_write(page) wait_on_page_owner_priv_2((page))
-#define end_page_fscache_write(page) end_page_owner_priv_2((page))
-
-
/* pattern used to fill dead space in an index entry */
#define FSCACHE_INDEX_DEADFILL_PATTERN 0x79
@@ -214,6 +200,8 @@ extern int __fscache_read_or_alloc_pages(struct fscache_cookie *,
extern int __fscache_alloc_page(struct fscache_cookie *, struct page *, gfp_t);
extern int __fscache_write_page(struct fscache_cookie *, struct page *, gfp_t);
extern void __fscache_uncache_page(struct fscache_cookie *, struct page *);
+extern bool __fscache_check_page_write(struct fscache_cookie *, struct page *);
+extern void __fscache_wait_on_page_write(struct fscache_cookie *, struct page *);
/**
* fscache_register_netfs - Register a filesystem as desiring caching services
@@ -589,4 +577,42 @@ void fscache_uncache_page(struct fscache_cookie *cookie,
__fscache_uncache_page(cookie, page);
}
+/**
+ * fscache_check_page_write - Ask if a page is being writing to the cache
+ * @cookie: The cookie representing the cache object
+ * @page: The netfs page that is being cached.
+ *
+ * Ask the cache if a page is being written to the cache.
+ *
+ * See Documentation/filesystems/caching/netfs-api.txt for a complete
+ * description.
+ */
+static inline
+bool fscache_check_page_write(struct fscache_cookie *cookie,
+ struct page *page)
+{
+ if (fscache_cookie_valid(cookie))
+ return __fscache_check_page_write(cookie, page);
+ return false;
+}
+
+/**
+ * fscache_wait_on_page_write - Wait for a page to complete writing to the cache
+ * @cookie: The cookie representing the cache object
+ * @page: The netfs page that is being cached.
+ *
+ * Ask the cache to wake us up when a page is no longer being written to the
+ * cache.
+ *
+ * See Documentation/filesystems/caching/netfs-api.txt for a complete
+ * description.
+ */
+static inline
+void fscache_wait_on_page_write(struct fscache_cookie *cookie,
+ struct page *page)
+{
+ if (fscache_cookie_valid(cookie))
+ __fscache_wait_on_page_write(cookie, page);
+}
+
#endif /* _LINUX_FSCACHE_H */
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index 0633e06..62214c7 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -79,7 +79,6 @@ enum pageflags {
PG_active,
PG_slab,
PG_owner_priv_1, /* Owner use. If pagecache, fs may use*/
- PG_owner_priv_2, /* Owner use. fs may use in pagecache */
PG_arch_1,
PG_reserved,
PG_private, /* If pagecache, has fs-private data */
@@ -115,7 +114,6 @@ enum pageflags {
* when those inodes are being locally cached.
*/
PG_fscache = PG_private_2, /* page backed by cache */
- PG_fscache_write = PG_owner_priv_2, /* page being written to cache */
/* XEN */
PG_pinned = PG_owner_priv_1,
@@ -220,7 +218,6 @@ PAGEFLAG(Private, private) __SETPAGEFLAG(Private, private)
__CLEARPAGEFLAG(Private, private)
PAGEFLAG(Private2, private_2) TESTSCFLAG(Private2, private_2)
PAGEFLAG(OwnerPriv1, owner_priv_1) TESTCLEARFLAG(OwnerPriv1, owner_priv_1)
-PAGEFLAG(OwnerPriv2, owner_priv_2) TESTSCFLAG(OwnerPriv2, owner_priv_2)
/*
* Only test-and-set exist for PG_writeback. The unconditional operators are
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index 135028e..fc8a67f 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -379,22 +379,6 @@ static inline void wait_on_page_writeback(struct page *page)
extern void end_page_writeback(struct page *page);
-/**
- * wait_on_page_owner_priv_2 - Wait for PG_owner_priv_2 to become clear
- * @page: The page to monitor
- *
- * Wait for a PG_owner_priv_2 to become clear on the specified page. This is
- * also used to monitor PG_fscache_write (which is an alternate name for the
- * same bit).
- */
-static inline void wait_on_page_owner_priv_2(struct page *page)
-{
- if (PageOwnerPriv2(page))
- wait_on_page_bit(page, PG_owner_priv_2);
-}
-
-extern void end_page_owner_priv_2(struct page *page);
-
/*
* Add an arbitrary waiter to a page's wait queue
*/
diff --git a/mm/filemap.c b/mm/filemap.c
index 15dda3c..9eb70e5 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -621,23 +621,6 @@ void end_page_writeback(struct page *page)
EXPORT_SYMBOL(end_page_writeback);
/**
- * end_page_owner_priv_2 - Clear PG_owner_priv_2 and wake up any waiters
- * @page: the page
- *
- * Clear PG_owner_priv_2 and wake up any processes waiting for that event.
- * This is used to indicate - using PG_fscache_write (an alternate name for the
- * same bit) - that a page has finished being written to the local disk cache.
- */
-void end_page_owner_priv_2(struct page *page)
-{
- if (!TestClearPageOwnerPriv2(page))
- BUG();
- smp_mb__after_clear_bit();
- wake_up_page(page, PG_owner_priv_2);
-}
-EXPORT_SYMBOL(end_page_owner_priv_2);
-
-/**
* __lock_page - get a lock on the page, assuming we need to sleep to get it
* @page: the page to lock
*
WARNING: multiple messages have this Message-ID (diff)
From: David Howells <dhowells@redhat.com>
To: Nick Piggin <nickpiggin@yahoo.com.au>
Cc: dhowells@redhat.com, linux-fsdevel@vger.kernel.org,
nfsv4@linux-nfs.org, viro@zeniv.linux.org.uk,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH 06/43] FS-Cache: Recruit a couple of page flags for cache management [ver #46]
Date: Fri, 03 Apr 2009 02:11:10 +0100 [thread overview]
Message-ID: <31146.1238721070@redhat.com> (raw)
In-Reply-To: <200904030514.42687.nickpiggin@yahoo.com.au>
Nick Piggin <nickpiggin@yahoo.com.au> wrote:
> > Besides, as I said NFS uses PG_private for its own purposes, and entangling
> > the two wasn't the most fun I've had. Trond didn't like it either.
>
> IMO that is quite OK to make them go through the pain of that if it
> avoids resulting in a new page flag that is probably unusable to most
> other filesystems.
>
> But... I guess I won't get hung up on it. If you avoid at least one of
> these flags it would be a good start.
Okay, the attached patch allows PageFsCacheWrite to be dispensed with. I have
a radix tree already to track pages that need writing, so I just extend the
use of that.
It does make waiting for a page to be written more tricky, though, as I can't
now just wait on a page flag. It's also theoretically slower as I now have to
take extra spinlocks.
I've benchmarked it three times:
Fri Apr 3 01:42:16 BST 2009
Fri Apr 3 01:44:25 BST 2009 2m 9s
Fri Apr 3 01:46:45 BST 2009
Fri Apr 3 01:48:24 BST 2009 1m 39s
Fri Apr 3 01:50:28 BST 2009
Fri Apr 3 01:52:40 BST 2009 2m 12s
using the same benchmark as for the patch to use the write() file op.
David
---
commit 9a10592512b01b42eb65f32c1028c57a1a6c864e
Author: David Howells <dhowells@redhat.com>
Date: Fri Apr 3 02:04:15 2009 +0100
FS-Cache: Use a radix tree to track pages being written rather than a page flag
Use a radix tree attached to struct fscache_cookie to track what pages are
undergoing write, rather than using a page flag.
The radix tree that was resident in struct fscache_object to track pages that
need writing is moved to fscache_cookie. Pages that need writing and pages
that are being written are both held in there. The difference being that the
former are tagged with FSCACHE_COOKIE_PENDING_TAG.
Signed-off-by: David Howells <dhowells@redhat.com>
diff --git a/Documentation/filesystems/caching/netfs-api.txt b/Documentation/filesystems/caching/netfs-api.txt
index da8f92f..4db125b 100644
--- a/Documentation/filesystems/caching/netfs-api.txt
+++ b/Documentation/filesystems/caching/netfs-api.txt
@@ -640,7 +640,18 @@ Note that pages can't be explicitly deleted from the a data file. The whole
data file must be retired (see the relinquish cookie function below).
Furthermore, note that this does not cancel the asynchronous read or write
-operation started by the read/alloc and write functions.
+operation started by the read/alloc and write functions, so the page
+invalidation and release functions must use:
+
+ bool fscache_check_page_write(struct fscache_cookie *cookie,
+ struct page *page);
+
+to see if a page is being written to the cache, and:
+
+ void fscache_wait_on_page_write(struct fscache_cookie *cookie,
+ struct page *page);
+
+to wait for it to finish if it is.
==========================
@@ -730,52 +741,32 @@ this, the caller should relinquish and retire the cookie they have, and then
acquire a new one.
-============================
-FS-CACHE SPECIFIC PAGE FLAGS
-============================
-
-FS-Cache makes use of two page flags, PG_private_2 and PG_owner_priv_2, for
-its own purpose. The first is given the alternative name PG_fscache and the
-second PG_fscache_write.
-
-FS-Cache uses these flags to keep track of two bits of information per cached
-netfs page:
+===========================
+FS-CACHE SPECIFIC PAGE FLAG
+===========================
- (1) PG_fscache.
+FS-Cache makes use of a page flag, PG_private_2, for its own purpose. This is
+given the alternative name PG_fscache.
- This indicates that the page is known by the cache, and that the cache
- must be informed if the page is going to go away. It's an indication to
- the netfs that the cache has an interest in this page, where an interest
- may be a pointer to it, resources allocated or reserved for it, or I/O in
- progress upon it.
+PG_fscache is used to indicate that the page is known by the cache, and that
+the cache must be informed if the page is going to go away. It's an indication
+to the netfs that the cache has an interest in this page, where an interest may
+be a pointer to it, resources allocated or reserved for it, or I/O in progress
+upon it.
- The netfs can use this information in methods such as releasepage() to
- determine whether it needs to uncache a page or update it.
+The netfs can use this information in methods such as releasepage() to
+determine whether it needs to uncache a page or update it.
- Furthermore, if this bit is set, releasepage() and invalidatepage()
- operations will be called on a page to get rid of it, even if PG_private
- is not set. This allows caching to attempted on a page before
- read_cache_pages() to be called after fscache_read_or_alloc_pages() as
- the former will try and release pages it was given under certain
- circumstances.
+Furthermore, if this bit is set, releasepage() and invalidatepage() operations
+will be called on a page to get rid of it, even if PG_private is not set. This
+allows caching to attempted on a page before read_cache_pages() to be called
+after fscache_read_or_alloc_pages() as the former will try and release pages it
+was given under certain circumstances.
- (2) PG_fscache_write.
+This bit does not overlap with such as PG_private. This means that FS-Cache
+can be used with a filesystem that uses the block buffering code.
- This indicates that the page is being written to disk by the cache, and
- that it cannot be released until completion. Ideally it shouldn't be
- changed until completion either so as to maintain the known state of the
- cache. This cannot be unified with PG_writeback as the page may be being
- written to both the server and the cache at the same time or at different
- times.
-
- This can be used by the netfs to wait for a page to be written out to the
- cache before, say, releasing or invalidating it, or before allowing
- someone to modify it in page_mkwrite(), say.
-
-Neither of these two bits overlaps with such as PG_private. This means that
-FS-Cache can be used with a filesystem that uses the block buffering code.
-
-There are a number of operations defined on these two bits:
+There are a number of operations defined on this flag:
int PageFsCache(struct page *page);
void SetPageFsCache(struct page *page)
@@ -783,18 +774,5 @@ There are a number of operations defined on these two bits:
int TestSetPageFsCache(struct page *page)
int TestClearPageFsCache(struct page *page)
- int PageFsCacheWrite(struct page *page)
- void SetPageFsCacheWrite(struct page *page)
- void ClearPageFsCacheWrite(struct page *page)
- int TestSetPageFsCacheWrite(struct page *page)
- int TestClearPageFsCacheWrite(struct page *page)
-
These functions are bit test, bit set, bit clear, bit test and set and bit
-test and clear operations on PG_fscache and PG_fscache_write.
-
- void wait_on_page_fscache_write(struct page *page)
- void end_page_fscache_write(struct page *page)
-
-The first of these two functions waits uninterruptibly for PG_fscache_write to
-become clear, if it isn't already so. The second clears PG_fscache_write and
-wakes up anyone waiting for it.
+test and clear operations on PG_fscache.
diff --git a/fs/afs/file.c b/fs/afs/file.c
index aeb6cdd..7a1d942 100644
--- a/fs/afs/file.c
+++ b/fs/afs/file.c
@@ -299,7 +299,7 @@ static void afs_invalidatepage(struct page *page, unsigned long offset)
#ifdef CONFIG_AFS_FSCACHE
if (PageFsCache(page)) {
struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
- wait_on_page_fscache_write(page);
+ fscache_wait_on_page_write(vnode->cache, page);
fscache_uncache_page(vnode->cache, page);
ClearPageFsCache(page);
}
@@ -336,12 +336,12 @@ static int afs_releasepage(struct page *page, gfp_t gfp_flags)
* elected to wait */
#ifdef CONFIG_AFS_FSCACHE
if (PageFsCache(page)) {
- if (PageFsCacheWrite(page)) {
+ if (fscache_check_page_write(vnode->cache, page)) {
if (!(gfp_flags & __GFP_WAIT)) {
_leave(" = F [cache busy]");
return 0;
}
- wait_on_page_fscache_write(page);
+ fscache_wait_on_page_write(vnode->cache, page);
}
fscache_uncache_page(vnode->cache, page);
diff --git a/fs/afs/write.c b/fs/afs/write.c
index 7884518..c2e7a7f 100644
--- a/fs/afs/write.c
+++ b/fs/afs/write.c
@@ -795,7 +795,7 @@ int afs_page_mkwrite(struct vm_area_struct *vma, struct page *page)
/* wait for the page to be written to the cache before we allow it to
* be modified */
#ifdef CONFIG_AFS_FSCACHE
- wait_on_page_fscache_write(page);
+ fscache_wait_on_page_write(vnode->cache, page);
#endif
_leave(" = 0");
diff --git a/fs/fscache/cookie.c b/fs/fscache/cookie.c
index cd9d065..72fd18f 100644
--- a/fs/fscache/cookie.c
+++ b/fs/fscache/cookie.c
@@ -102,6 +102,8 @@ struct fscache_cookie *__fscache_acquire_cookie(
cookie->netfs_data = netfs_data;
cookie->flags = 0;
+ INIT_RADIX_TREE(&cookie->stores, GFP_NOFS);
+
switch (cookie->def->type) {
case FSCACHE_COOKIE_TYPE_INDEX:
fscache_stat(&fscache_n_cookie_index);
diff --git a/fs/fscache/page.c b/fs/fscache/page.c
index 512ec2c..2568e0e 100644
--- a/fs/fscache/page.c
+++ b/fs/fscache/page.c
@@ -17,6 +17,47 @@
#include "internal.h"
/*
+ * check to see if a page is being written to the cache
+ */
+bool __fscache_check_page_write(struct fscache_cookie *cookie, struct page *page)
+{
+ void *val;
+
+ rcu_read_lock();
+ val = radix_tree_lookup(&cookie->stores, page->index);
+ rcu_read_unlock();
+
+ return val != NULL;
+}
+EXPORT_SYMBOL(__fscache_check_page_write);
+
+/*
+ * wait for a page to finish being written to the cache
+ */
+void __fscache_wait_on_page_write(struct fscache_cookie *cookie, struct page *page)
+{
+ wait_queue_head_t *wq = bit_waitqueue(&cookie->flags, 0);
+
+ wait_event(*wq, !__fscache_check_page_write(cookie, page));
+}
+EXPORT_SYMBOL(__fscache_wait_on_page_write);
+
+/*
+ * note that a page has finished being written to the cache
+ */
+static void fscache_end_page_write(struct fscache_cookie *cookie, struct page *page)
+{
+ struct page *xpage;
+
+ spin_lock(&cookie->lock);
+ xpage = radix_tree_delete(&cookie->stores, page->index);
+ spin_unlock(&cookie->lock);
+ ASSERT(xpage != NULL);
+
+ wake_up_bit(&cookie->flags, 0);
+}
+
+/*
* actually apply the changed attributes to a cache object
*/
static void fscache_attr_changed_op(struct fscache_operation *op)
@@ -480,6 +521,7 @@ static void fscache_write_op(struct fscache_operation *_op)
struct fscache_storage *op =
container_of(_op, struct fscache_storage, op);
struct fscache_object *object = op->op.object;
+ struct fscache_cookie *cookie = object->cookie;
struct page *page;
unsigned n;
void *results[1];
@@ -487,10 +529,12 @@ static void fscache_write_op(struct fscache_operation *_op)
_enter("{OP%x,%d}", op->op.debug_id, atomic_read(&op->op.usage));
+ spin_lock(&cookie->lock);
spin_lock(&object->lock);
if (!fscache_object_is_active(object)) {
spin_unlock(&object->lock);
+ spin_unlock(&cookie->lock);
_leave("");
return;
}
@@ -499,23 +543,24 @@ static void fscache_write_op(struct fscache_operation *_op)
/* find a page to store */
page = NULL;
- n = radix_tree_gang_lookup(&object->stores, results, 0, 1);
- if (n == 1) {
- page = results[0];
- _debug("gang %d [%lx]", n, page->index);
- if (page->index <= op->store_limit)
- radix_tree_delete(&object->stores, page->index);
- else
- goto superseded;
- } else {
+ n = radix_tree_gang_lookup_tag(&cookie->stores, results, 0, 1,
+ FSCACHE_COOKIE_PENDING_TAG);
+ if (n != 1)
+ goto superseded;
+ page = results[0];
+ _debug("gang %d [%lx]", n, page->index);
+ if (page->index > op->store_limit)
goto superseded;
- }
+
+ radix_tree_tag_clear(&cookie->stores, page->index,
+ FSCACHE_COOKIE_PENDING_TAG);
spin_unlock(&object->lock);
+ spin_unlock(&cookie->lock);
if (page) {
ret = object->cache->ops->write_page(op, page);
- end_page_fscache_write(page);
+ fscache_end_page_write(cookie, page);
page_cache_release(page);
if (ret < 0)
fscache_abort_object(object);
@@ -532,6 +577,7 @@ superseded:
_debug("cease");
clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags);
spin_unlock(&object->lock);
+ spin_unlock(&cookie->lock);
_leave("");
}
@@ -609,7 +655,7 @@ int __fscache_write_page(struct fscache_cookie *cookie,
_debug("store limit %llx", (unsigned long long) object->store_limit);
- ret = radix_tree_insert(&object->stores, page->index, page);
+ ret = radix_tree_insert(&cookie->stores, page->index, page);
if (ret < 0) {
if (ret == -EEXIST)
goto already_queued;
@@ -617,9 +663,9 @@ int __fscache_write_page(struct fscache_cookie *cookie,
goto nobufs_unlock_obj;
}
+ radix_tree_tag_set(&cookie->stores, page->index,
+ FSCACHE_COOKIE_PENDING_TAG);
page_cache_get(page);
- if (TestSetPageFsCacheWrite(page))
- BUG();
/* we only want one writer at a time, but we do need to queue new
* writers after exclusive ops */
@@ -656,8 +702,7 @@ already_pending:
return 0;
submit_failed:
- radix_tree_delete(&object->stores, page->index);
- end_page_fscache_write(page);
+ radix_tree_delete(&cookie->stores, page->index);
page_cache_release(page);
ret = -ENOBUFS;
goto nobufs;
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index d3060c4..3523b89 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -456,11 +456,12 @@ static int nfs_release_page(struct page *page, gfp_t gfp)
static int nfs_launder_page(struct page *page)
{
struct inode *inode = page->mapping->host;
+ struct nfs_inode *nfsi = NFS_I(inode);
dfprintk(PAGECACHE, "NFS: launder_page(%ld, %llu)\n",
inode->i_ino, (long long)page_offset(page));
- wait_on_page_fscache_write(page);
+ nfs_fscache_wait_on_page_write(nfsi, page);
return nfs_wb_page(inode, page);
}
@@ -498,7 +499,7 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
(long long)page_offset(page));
/* make sure the cache has finished storing the page */
- wait_on_page_fscache_write(page);
+ nfs_fscache_wait_on_page_write(NFS_I(dentry->d_inode), page);
lock_page(page);
mapping = page->mapping;
diff --git a/fs/nfs/fscache.c b/fs/nfs/fscache.c
index 968cf5d..379be67 100644
--- a/fs/nfs/fscache.c
+++ b/fs/nfs/fscache.c
@@ -337,21 +337,22 @@ void nfs_fscache_reset_inode_cookie(struct inode *inode)
*/
int nfs_fscache_release_page(struct page *page, gfp_t gfp)
{
- if (PageFsCacheWrite(page)) {
+ struct nfs_inode *nfsi = NFS_I(page->mapping->host);
+ struct fscache_cookie *cookie = nfsi->fscache;
+
+ BUG_ON(!cookie);
+
+ if (fscache_check_page_write(cookie, page)) {
if (!(gfp & __GFP_WAIT))
return 0;
- wait_on_page_fscache_write(page);
+ fscache_wait_on_page_write(cookie, page);
}
if (PageFsCache(page)) {
- struct nfs_inode *nfsi = NFS_I(page->mapping->host);
-
- BUG_ON(!nfsi->fscache);
-
dfprintk(FSCACHE, "NFS: fscache releasepage (0x%p/0x%p/0x%p)\n",
- nfsi->fscache, page, nfsi);
+ cookie, page, nfsi);
- fscache_uncache_page(nfsi->fscache, page);
+ fscache_uncache_page(cookie, page);
nfs_add_fscache_stats(page->mapping->host,
NFSIOS_FSCACHE_PAGES_UNCACHED, 1);
}
@@ -366,16 +367,17 @@ int nfs_fscache_release_page(struct page *page, gfp_t gfp)
void __nfs_fscache_invalidate_page(struct page *page, struct inode *inode)
{
struct nfs_inode *nfsi = NFS_I(inode);
+ struct fscache_cookie *cookie = nfsi->fscache;
- BUG_ON(!nfsi->fscache);
+ BUG_ON(!cookie);
dfprintk(FSCACHE, "NFS: fscache invalidatepage (0x%p/0x%p/0x%p)\n",
- nfsi->fscache, page, nfsi);
+ cookie, page, nfsi);
- wait_on_page_fscache_write(page);
+ fscache_wait_on_page_write(cookie, page);
BUG_ON(!PageLocked(page));
- fscache_uncache_page(nfsi->fscache, page);
+ fscache_uncache_page(cookie, page);
nfs_add_fscache_stats(page->mapping->host,
NFSIOS_FSCACHE_PAGES_UNCACHED, 1);
}
diff --git a/fs/nfs/fscache.h b/fs/nfs/fscache.h
index 2d43b67..6e809bb 100644
--- a/fs/nfs/fscache.h
+++ b/fs/nfs/fscache.h
@@ -94,6 +94,16 @@ extern int __nfs_readpages_from_fscache(struct nfs_open_context *,
extern void __nfs_readpage_to_fscache(struct inode *, struct page *, int);
/*
+ * wait for a page to complete writing to the cache
+ */
+static inline void nfs_fscache_wait_on_page_write(struct nfs_inode *nfsi,
+ struct page *page)
+{
+ if (PageFsCache(page))
+ fscache_wait_on_page_write(nfsi->fscache, page);
+}
+
+/*
* release the caching state associated with a page if undergoing complete page
* invalidation
*/
@@ -181,6 +191,8 @@ static inline int nfs_fscache_release_page(struct page *page, gfp_t gfp)
}
static inline void nfs_fscache_invalidate_page(struct page *page,
struct inode *inode) {}
+static inline void nfs_fscache_wait_on_page_write(struct nfs_inode *nfsi,
+ struct page *page) {}
static inline int nfs_readpage_from_fscache(struct nfs_open_context *ctx,
struct inode *inode,
diff --git a/include/linux/fscache-cache.h b/include/linux/fscache-cache.h
index 0410bd9..84d3532 100644
--- a/include/linux/fscache-cache.h
+++ b/include/linux/fscache-cache.h
@@ -301,6 +301,9 @@ struct fscache_cookie {
const struct fscache_cookie_def *def; /* definition */
struct fscache_cookie *parent; /* parent of this entry */
void *netfs_data; /* back pointer to netfs */
+ struct radix_tree_root stores; /* pages to be stored on this cookie */
+#define FSCACHE_COOKIE_PENDING_TAG 0 /* pages tag: pending write to cache */
+
unsigned long flags;
#define FSCACHE_COOKIE_LOOKING_UP 0 /* T if non-index cookie being looked up still */
#define FSCACHE_COOKIE_CREATING 1 /* T if non-index object being created still */
@@ -370,7 +373,6 @@ struct fscache_object {
struct list_head dependents; /* FIFO of dependent objects */
struct list_head dep_link; /* link in parent's dependents list */
struct list_head pending_ops; /* unstarted operations on this object */
- struct radix_tree_root stores; /* data to be stored */
pgoff_t store_limit; /* current storage limit */
};
@@ -407,7 +409,6 @@ void fscache_object_init(struct fscache_object *object,
INIT_LIST_HEAD(&object->dependents);
INIT_LIST_HEAD(&object->dep_link);
INIT_LIST_HEAD(&object->pending_ops);
- INIT_RADIX_TREE(&object->stores, GFP_NOFS);
object->n_children = 0;
object->n_ops = object->n_in_progress = object->n_exclusive = 0;
object->events = object->event_mask = 0;
diff --git a/include/linux/fscache.h b/include/linux/fscache.h
index 006c919..6d8ee46 100644
--- a/include/linux/fscache.h
+++ b/include/linux/fscache.h
@@ -42,20 +42,6 @@
#define TestSetPageFsCache(page) TestSetPagePrivate2((page))
#define TestClearPageFsCache(page) TestClearPagePrivate2((page))
-/*
- * overload PG_owner_priv_2 to give us PG_fscache_write - this is used to
- * indicate that a page is currently being written to a local disk cache
- */
-#define PageFsCacheWrite(page) PageOwnerPriv2((page))
-#define SetPageFsCacheWrite(page) SetPageOwnerPriv2((page))
-#define ClearPageFsCacheWrite(page) ClearPageOwnerPriv2((page))
-#define TestSetPageFsCacheWrite(page) TestSetPageOwnerPriv2((page))
-#define TestClearPageFsCacheWrite(page) TestClearPageOwnerPriv2((page))
-
-#define wait_on_page_fscache_write(page) wait_on_page_owner_priv_2((page))
-#define end_page_fscache_write(page) end_page_owner_priv_2((page))
-
-
/* pattern used to fill dead space in an index entry */
#define FSCACHE_INDEX_DEADFILL_PATTERN 0x79
@@ -214,6 +200,8 @@ extern int __fscache_read_or_alloc_pages(struct fscache_cookie *,
extern int __fscache_alloc_page(struct fscache_cookie *, struct page *, gfp_t);
extern int __fscache_write_page(struct fscache_cookie *, struct page *, gfp_t);
extern void __fscache_uncache_page(struct fscache_cookie *, struct page *);
+extern bool __fscache_check_page_write(struct fscache_cookie *, struct page *);
+extern void __fscache_wait_on_page_write(struct fscache_cookie *, struct page *);
/**
* fscache_register_netfs - Register a filesystem as desiring caching services
@@ -589,4 +577,42 @@ void fscache_uncache_page(struct fscache_cookie *cookie,
__fscache_uncache_page(cookie, page);
}
+/**
+ * fscache_check_page_write - Ask if a page is being writing to the cache
+ * @cookie: The cookie representing the cache object
+ * @page: The netfs page that is being cached.
+ *
+ * Ask the cache if a page is being written to the cache.
+ *
+ * See Documentation/filesystems/caching/netfs-api.txt for a complete
+ * description.
+ */
+static inline
+bool fscache_check_page_write(struct fscache_cookie *cookie,
+ struct page *page)
+{
+ if (fscache_cookie_valid(cookie))
+ return __fscache_check_page_write(cookie, page);
+ return false;
+}
+
+/**
+ * fscache_wait_on_page_write - Wait for a page to complete writing to the cache
+ * @cookie: The cookie representing the cache object
+ * @page: The netfs page that is being cached.
+ *
+ * Ask the cache to wake us up when a page is no longer being written to the
+ * cache.
+ *
+ * See Documentation/filesystems/caching/netfs-api.txt for a complete
+ * description.
+ */
+static inline
+void fscache_wait_on_page_write(struct fscache_cookie *cookie,
+ struct page *page)
+{
+ if (fscache_cookie_valid(cookie))
+ __fscache_wait_on_page_write(cookie, page);
+}
+
#endif /* _LINUX_FSCACHE_H */
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index 0633e06..62214c7 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -79,7 +79,6 @@ enum pageflags {
PG_active,
PG_slab,
PG_owner_priv_1, /* Owner use. If pagecache, fs may use*/
- PG_owner_priv_2, /* Owner use. fs may use in pagecache */
PG_arch_1,
PG_reserved,
PG_private, /* If pagecache, has fs-private data */
@@ -115,7 +114,6 @@ enum pageflags {
* when those inodes are being locally cached.
*/
PG_fscache = PG_private_2, /* page backed by cache */
- PG_fscache_write = PG_owner_priv_2, /* page being written to cache */
/* XEN */
PG_pinned = PG_owner_priv_1,
@@ -220,7 +218,6 @@ PAGEFLAG(Private, private) __SETPAGEFLAG(Private, private)
__CLEARPAGEFLAG(Private, private)
PAGEFLAG(Private2, private_2) TESTSCFLAG(Private2, private_2)
PAGEFLAG(OwnerPriv1, owner_priv_1) TESTCLEARFLAG(OwnerPriv1, owner_priv_1)
-PAGEFLAG(OwnerPriv2, owner_priv_2) TESTSCFLAG(OwnerPriv2, owner_priv_2)
/*
* Only test-and-set exist for PG_writeback. The unconditional operators are
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index 135028e..fc8a67f 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -379,22 +379,6 @@ static inline void wait_on_page_writeback(struct page *page)
extern void end_page_writeback(struct page *page);
-/**
- * wait_on_page_owner_priv_2 - Wait for PG_owner_priv_2 to become clear
- * @page: The page to monitor
- *
- * Wait for a PG_owner_priv_2 to become clear on the specified page. This is
- * also used to monitor PG_fscache_write (which is an alternate name for the
- * same bit).
- */
-static inline void wait_on_page_owner_priv_2(struct page *page)
-{
- if (PageOwnerPriv2(page))
- wait_on_page_bit(page, PG_owner_priv_2);
-}
-
-extern void end_page_owner_priv_2(struct page *page);
-
/*
* Add an arbitrary waiter to a page's wait queue
*/
diff --git a/mm/filemap.c b/mm/filemap.c
index 15dda3c..9eb70e5 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -621,23 +621,6 @@ void end_page_writeback(struct page *page)
EXPORT_SYMBOL(end_page_writeback);
/**
- * end_page_owner_priv_2 - Clear PG_owner_priv_2 and wake up any waiters
- * @page: the page
- *
- * Clear PG_owner_priv_2 and wake up any processes waiting for that event.
- * This is used to indicate - using PG_fscache_write (an alternate name for the
- * same bit) - that a page has finished being written to the local disk cache.
- */
-void end_page_owner_priv_2(struct page *page)
-{
- if (!TestClearPageOwnerPriv2(page))
- BUG();
- smp_mb__after_clear_bit();
- wake_up_page(page, PG_owner_priv_2);
-}
-EXPORT_SYMBOL(end_page_owner_priv_2);
-
-/**
* __lock_page - get a lock on the page, assuming we need to sleep to get it
* @page: the page to lock
*
next prev parent reply other threads:[~2009-04-03 1:11 UTC|newest]
Thread overview: 117+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-04-01 23:03 [PATCH 00/43] Permit filesystem local caching [ver #46] David Howells
2009-04-01 23:03 ` [PATCH 01/43] Create a dynamically sized pool of threads for doing very slow work items " David Howells
2009-04-01 23:03 ` [PATCH 02/43] Make slow-work thread pool actually dynamic " David Howells
2009-04-01 23:03 ` [PATCH 03/43] Make the slow work pool configurable " David Howells
2009-04-01 23:03 ` [PATCH 04/43] Document the slow work thread pool " David Howells
2009-04-01 23:03 ` [PATCH 05/43] FS-Cache: Release page->private after failed readahead " David Howells
2009-04-02 13:51 ` Nick Piggin
2009-04-02 14:21 ` David Howells
2009-04-02 17:17 ` Rik van Riel
2009-04-01 23:03 ` [PATCH 06/43] FS-Cache: Recruit a couple of page flags for cache management " David Howells
2009-04-02 13:55 ` Nick Piggin
2009-04-02 14:36 ` David Howells
2009-04-02 14:36 ` David Howells
2009-04-02 15:25 ` Nick Piggin
2009-04-02 15:25 ` Nick Piggin
2009-04-02 15:51 ` David Howells
2009-04-02 15:51 ` David Howells
2009-04-02 16:15 ` Nick Piggin
2009-04-02 16:15 ` Nick Piggin
2009-04-02 16:48 ` What I mean by a 'netfs' when dealing with FS-Cache David Howells
2009-04-02 16:48 ` David Howells
2009-04-02 17:06 ` David Howells
2009-04-02 17:06 ` David Howells
2009-04-02 16:53 ` [PATCH 06/43] FS-Cache: Recruit a couple of page flags for cache management [ver #46] Nick Piggin
2009-04-02 16:53 ` Nick Piggin
2009-04-02 17:09 ` David Howells
2009-04-02 17:09 ` David Howells
2009-04-02 17:31 ` Nick Piggin
2009-04-02 17:31 ` Nick Piggin
2009-04-02 17:40 ` David Howells
2009-04-02 17:40 ` David Howells
2009-04-02 18:14 ` Nick Piggin
2009-04-02 18:14 ` Nick Piggin
2009-04-03 1:11 ` David Howells [this message]
2009-04-03 1:11 ` David Howells
2009-04-02 19:19 ` Trond Myklebust
2009-04-02 18:23 ` Rik van Riel
2009-04-02 18:23 ` Rik van Riel
2009-04-01 23:03 ` [PATCH 07/43] FS-Cache: Add the FS-Cache netfs API and documentation " David Howells
2009-04-01 23:04 ` [PATCH 08/43] FS-Cache: Add the FS-Cache cache backend " David Howells
2009-04-01 23:04 ` [PATCH 09/43] FS-Cache: Add main configuration option, module entry points and debugging " David Howells
2009-04-01 23:04 ` [PATCH 10/43] FS-Cache: Add use of /proc and presentation of statistics " David Howells
2009-04-01 23:04 ` [PATCH 11/43] FS-Cache: Root index definition " David Howells
2009-04-01 23:04 ` [PATCH 12/43] FS-Cache: Add cache tag handling " David Howells
2009-04-01 23:04 ` [PATCH 13/43] FS-Cache: Add cache management " David Howells
2009-04-01 23:04 ` [PATCH 14/43] FS-Cache: Provide a slab for cookie allocation " David Howells
2009-04-01 23:04 ` [PATCH 15/43] FS-Cache: Add netfs registration " David Howells
2009-04-01 23:04 ` [PATCH 16/43] FS-Cache: Bit waiting helpers " David Howells
2009-04-01 23:04 ` [PATCH 17/43] FS-Cache: Object management state machine " David Howells
2009-04-01 23:04 ` [PATCH 18/43] FS-Cache: Implement the cookie management part of the netfs API " David Howells
2009-04-01 23:04 ` [PATCH 19/43] FS-Cache: Add and document asynchronous operation handling " David Howells
2009-04-01 23:05 ` [PATCH 20/43] FS-Cache: Implement data I/O part of netfs API " David Howells
2009-04-01 23:05 ` [PATCH 21/43] CacheFiles: Be consistent about the use of mapping vs file->f_mapping in Ext3 " David Howells
2009-04-02 18:52 ` Rik van Riel
2009-04-02 18:52 ` Rik van Riel
2009-04-01 23:05 ` [PATCH 22/43] CacheFiles: Add a hook to write a single page of data to an inode " David Howells
2009-04-02 14:00 ` Nick Piggin
2009-04-02 14:55 ` David Howells
2009-04-02 14:55 ` David Howells
2009-04-02 15:32 ` Nick Piggin
2009-04-02 15:32 ` Nick Piggin
2009-04-02 16:02 ` David Howells
2009-04-02 16:02 ` David Howells
2009-04-02 16:37 ` Christoph Hellwig
2009-04-02 16:47 ` Nick Piggin
2009-04-02 16:47 ` Nick Piggin
2009-04-02 16:55 ` Christoph Hellwig
2009-04-02 16:55 ` Christoph Hellwig
2009-04-02 17:07 ` Nick Piggin
2009-04-02 17:07 ` Nick Piggin
2009-04-02 17:26 ` Jan Kara
2009-04-02 17:22 ` David Howells
2009-04-02 17:22 ` David Howells
2009-04-02 18:18 ` David Howells
2009-04-02 22:44 ` David Howells
2009-04-02 22:44 ` David Howells
2009-04-03 13:41 ` David Howells
2009-04-03 13:41 ` David Howells
2009-04-02 15:32 ` Peter Staubach
2009-04-02 16:03 ` David Howells
2009-04-02 16:03 ` David Howells
2009-04-02 18:48 ` Rik van Riel
2009-04-01 23:05 ` [PATCH 23/43] CacheFiles: Permit the page lock state to be monitored " David Howells
2009-04-02 15:37 ` Nick Piggin
2009-04-02 15:37 ` Nick Piggin
2009-04-02 16:14 ` David Howells
2009-04-02 16:14 ` David Howells
2009-04-02 16:35 ` Nick Piggin
2009-04-02 16:35 ` Nick Piggin
2009-04-02 17:05 ` David Howells
2009-04-02 17:05 ` David Howells
2009-04-02 18:03 ` Nick Piggin
2009-04-02 18:03 ` Nick Piggin
2009-04-02 18:51 ` Rik van Riel
2009-04-02 18:51 ` Rik van Riel
2009-04-01 23:05 ` [PATCH 24/43] CacheFiles: Export things for CacheFiles " David Howells
2009-04-02 18:53 ` Rik van Riel
2009-04-02 18:53 ` Rik van Riel
2009-04-01 23:05 ` [PATCH 25/43] CacheFiles: A cache that backs onto a mounted filesystem " David Howells
2009-04-01 23:05 ` [PATCH 26/43] FS-Cache: Make kAFS use FS-Cache " David Howells
2009-04-01 23:05 ` [PATCH 27/43] NFS: Add comment banners to some NFS functions " David Howells
2009-04-01 23:05 ` [PATCH 28/43] NFS: Add FS-Cache option bit and debug bit " David Howells
2009-04-01 23:05 ` [PATCH 29/43] NFS: Permit local filesystem caching to be enabled for NFS " David Howells
2009-04-01 23:05 ` [PATCH 30/43] NFS: Register NFS for caching and retrieve the top-level index " David Howells
2009-04-01 23:06 ` [PATCH 31/43] NFS: Define and create server-level objects " David Howells
2009-04-01 23:06 ` [PATCH 32/43] NFS: Define and create superblock-level " David Howells
2009-04-01 23:06 ` [PATCH 33/43] NFS: Define and create inode-level cache " David Howells
2009-04-01 23:06 ` [PATCH 34/43] NFS: Use local disk inode cache " David Howells
2009-04-01 23:06 ` [PATCH 35/43] NFS: Invalidate FsCache page flags when cache removed " David Howells
2009-04-01 23:06 ` [PATCH 36/43] NFS: Add some new I/O counters for FS-Cache doing things for NFS " David Howells
2009-04-01 23:06 ` [PATCH 37/43] NFS: FS-Cache page management " David Howells
2009-04-01 23:06 ` [PATCH 38/43] NFS: Add read context retention for FS-Cache to call back with " David Howells
2009-04-01 23:06 ` [PATCH 39/43] NFS: nfs_readpage_async() needs to be accessible as a fallback for local caching " David Howells
2009-04-01 23:06 ` [PATCH 40/43] NFS: Read pages from FS-Cache into an NFS inode " David Howells
2009-04-01 23:06 ` [PATCH 41/43] NFS: Store pages from an NFS inode into a local cache " David Howells
2009-04-01 23:06 ` [PATCH 42/43] NFS: Display local caching state " David Howells
2009-04-01 23:07 ` [PATCH 43/43] NFS: Add mount options to enable local caching on NFS " David Howells
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=31146.1238721070@redhat.com \
--to=dhowells@redhat.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=nfsv4@linux-nfs.org \
--cc=nickpiggin@yahoo.com.au \
--cc=viro@zeniv.linux.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.