aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYehuda Sadeh <yehuda@hq.newdream.net>2010-02-19 00:10:11 +0000
committerSage Weil <sage@newdream.net>2010-02-19 14:40:51 -0800
commitc9af9fb68e01eb2c2165e1bc45cfeeed510c64e6 (patch)
tree9af8caecd66c6557c5ada6a38d4b2ff9be180d35
parente63dc5c780ba32d6d8b3662eecce2b8d96489b41 (diff)
ceph: don't truncate dirty pages in invalidate work thread
Instead of truncating the whole range of pages, we skip those pages that are dirty or in the middle of writeback. Those pages will be cleared later when the writeback completes. Signed-off-by: Yehuda Sadeh <yehuda@hq.newdream.net> Signed-off-by: Sage Weil <sage@newdream.net>
-rw-r--r--fs/ceph/inode.c46
1 files changed, 45 insertions, 1 deletions
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
index d7d5d492377..7abe1aed819 100644
--- a/fs/ceph/inode.c
+++ b/fs/ceph/inode.c
@@ -10,6 +10,7 @@
#include <linux/namei.h>
#include <linux/writeback.h>
#include <linux/vmalloc.h>
+#include <linux/pagevec.h>
#include "super.h"
#include "decode.h"
@@ -1280,6 +1281,49 @@ void ceph_queue_invalidate(struct inode *inode)
}
/*
+ * invalidate any pages that are not dirty or under writeback. this
+ * includes pages that are clean and mapped.
+ */
+static void ceph_invalidate_nondirty_pages(struct address_space *mapping)
+{
+ struct pagevec pvec;
+ pgoff_t next = 0;
+ int i;
+
+ pagevec_init(&pvec, 0);
+ while (pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) {
+ for (i = 0; i < pagevec_count(&pvec); i++) {
+ struct page *page = pvec.pages[i];
+ pgoff_t index;
+ int skip_page =
+ (PageDirty(page) || PageWriteback(page));
+
+ if (!skip_page)
+ skip_page = !trylock_page(page);
+
+ /*
+ * We really shouldn't be looking at the ->index of an
+ * unlocked page. But we're not allowed to lock these
+ * pages. So we rely upon nobody altering the ->index
+ * of this (pinned-by-us) page.
+ */
+ index = page->index;
+ if (index > next)
+ next = index;
+ next++;
+
+ if (skip_page)
+ continue;
+
+ generic_error_remove_page(mapping, page);
+ unlock_page(page);
+ }
+ pagevec_release(&pvec);
+ cond_resched();
+ }
+}
+
+/*
* Invalidate inode pages in a worker thread. (This can't be done
* in the message handler context.)
*/
@@ -1305,7 +1349,7 @@ static void ceph_invalidate_work(struct work_struct *work)
orig_gen = ci->i_rdcache_gen;
spin_unlock(&inode->i_lock);
- truncate_inode_pages(&inode->i_data, 0);
+ ceph_invalidate_nondirty_pages(inode->i_mapping);
spin_lock(&inode->i_lock);
if (orig_gen == ci->i_rdcache_gen) {