[patch 21/22] fuse: limit dirty pages

From: Miklos Szeredi
Date: Tue Feb 27 2007 - 18:19:59 EST


From: Miklos Szeredi <mszeredi@xxxxxxx>

Add a per-filesystem limit for the number of dirty pages. If half the
limit is reached, background writeback is started. If the limit is
reached, then start some writeback and wait until the the number goes
below the limit again.

The dirty limit is currently hardcoded at 1MB. This limiting is
necessary, so that buggy or unfriendly filesystems don't hurt system
performance too badly.

Signed-off-by: Miklos Szeredi <mszeredi@xxxxxxx>
---

Index: linux/fs/fuse/file.c
===================================================================
--- linux.orig/fs/fuse/file.c 2007-02-27 14:41:12.000000000 +0100
+++ linux/fs/fuse/file.c 2007-02-27 14:41:13.000000000 +0100
@@ -780,10 +780,35 @@ static void fuse_vma_close(struct vm_are
filemap_write_and_wait(vma->vm_file->f_mapping);
}

+static int fuse_page_mkwrite(struct vm_area_struct *vma, struct page *page)
+{
+ struct inode *inode = page->mapping->host;
+ struct fuse_conn *fc = get_fuse_conn(inode);
+ long nr_dirty = atomic_long_read(&fc->bdi.nr_dirty);
+ struct writeback_control wbc = {
+ .sync_mode = WB_SYNC_NONE,
+ .nr_to_write = FUSE_MAX_PAGES_PER_REQ,
+ .range_cyclic = 1,
+ };
+
+ while (nr_dirty >= fc->max_dirty) {
+ sync_sb(inode->i_sb, &wbc);
+ congestion_wait(WRITE, HZ / 10);
+ nr_dirty = atomic_long_read(&fc->bdi.nr_dirty);
+ wbc.nr_to_write = FUSE_MAX_PAGES_PER_REQ;
+ }
+ if (nr_dirty >= fc->max_dirty / 2) {
+ wbc.nonblocking = 1;
+ sync_sb(inode->i_sb, &wbc);
+ }
+ return 0;
+}
+
static struct vm_operations_struct fuse_file_vm_ops = {
.close = fuse_vma_close,
.nopage = filemap_nopage,
.populate = filemap_populate,
+ .page_mkwrite = fuse_page_mkwrite,
};

static void fuse_send_writepages(struct fuse_req *req, struct inode *inode)
Index: linux/fs/fuse/fuse_i.h
===================================================================
--- linux.orig/fs/fuse/fuse_i.h 2007-02-27 14:41:13.000000000 +0100
+++ linux/fs/fuse/fuse_i.h 2007-02-27 14:41:13.000000000 +0100
@@ -397,6 +397,9 @@ struct fuse_conn {

/** Reserved request for the DESTROY message */
struct fuse_req *destroy_req;
+
+ /** Maximum number of dirty pages in this fs */
+ unsigned long max_dirty;
};

static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb)
Index: linux/fs/fuse/inode.c
===================================================================
--- linux.orig/fs/fuse/inode.c 2007-02-27 14:41:11.000000000 +0100
+++ linux/fs/fuse/inode.c 2007-02-27 14:41:13.000000000 +0100
@@ -425,6 +425,7 @@ static struct fuse_conn *new_conn(void)
fc->bdi.unplug_io_fn = default_unplug_io_fn;
fc->reqctr = 0;
fc->blocked = 1;
+ fc->max_dirty = (1024 * 1024) / PAGE_CACHE_SIZE;
get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key));
}
return fc;

--
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/