From 92f25053c0189f8d2887f837d3936cdca1cdf730 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 17 Sep 2009 14:51:44 +0200 Subject: [PATCH 1/4] nfs: nfs_kill_super() should call bdi_unregister() after killing super Otherwise we could be attempting to flush data for a writeback thread and bdi that have already disappeared. Signed-off-by: Jens Axboe --- fs/nfs/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfs/super.c b/fs/nfs/super.c index de935692d40d77..f1cc0587cfef3f 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -2190,8 +2190,8 @@ static void nfs_kill_super(struct super_block *s) { struct nfs_server *server = NFS_SB(s); - bdi_unregister(&server->backing_dev_info); kill_anon_super(s); + bdi_unregister(&server->backing_dev_info); nfs_fscache_release_super_cookie(s); nfs_free_server(server); } From 3542a5c0de3d5b33227214a692bf9b12e249078e Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 17 Sep 2009 19:56:01 +0200 Subject: [PATCH 2/4] writeback: don't use schedule_timeout() without setting runstate Just use schedule_timeout_interruptible(), saves a call to set_current_state(). Signed-off-by: Jens Axboe --- mm/page-writeback.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 1eea4fa0d410d5..2585349469e089 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -561,7 +561,7 @@ static void balance_dirty_pages(struct address_space *mapping) if (pages_written >= write_chunk) break; /* We've done our duty */ - schedule_timeout(1); + schedule_timeout_interruptible(1); } if (bdi_nr_reclaimable + bdi_nr_writeback < bdi_thresh && From 87c6a9b253520b66e7f5e8f67a37a701eaa51cee Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 17 Sep 2009 19:59:14 +0200 Subject: [PATCH 3/4] writeback: make balance_dirty_pages() gradually back more off Currently it just sleeps for a very short time, just 1 jiffy. If we keep looping in there, continually delay for a little longer of up to 100msec in total. That was the old limit for congestion wait. Signed-off-by: Jens Axboe --- mm/page-writeback.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 2585349469e089..d1ba4644105365 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -485,6 +485,7 @@ static void balance_dirty_pages(struct address_space *mapping) unsigned long bdi_thresh; unsigned long pages_written = 0; unsigned long write_chunk = sync_writeback_pages(); + unsigned long pause = 1; struct backing_dev_info *bdi = mapping->backing_dev_info; @@ -561,7 +562,15 @@ static void balance_dirty_pages(struct address_space *mapping) if (pages_written >= write_chunk) break; /* We've done our duty */ - schedule_timeout_interruptible(1); + schedule_timeout_interruptible(pause); + + /* + * Increase the delay for each loop, up to our previous + * default of taking a 100ms nap. + */ + pause <<= 1; + if (pause > HZ / 10) + pause = HZ / 10; } if (bdi_nr_reclaimable + bdi_nr_writeback < bdi_thresh && From 48d0764998ad4ab7570afab8bb3bee0fbfa55b2a Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 21 Sep 2009 09:59:39 +0200 Subject: [PATCH 4/4] nfs: initialize the backing_dev_info when creating the server NFS may free the server structure without ever having used the bdi, so we either need to flag the bdi as being uninitialized or initialize it up front. This does the latter. This fixes a crash with mounting more than one NFS file system, should people ever need that kind of obscure NFS functionality. Tested-by: Peter Zijlstra Acked-by: Trond Myklebust Signed-off-by: Jens Axboe --- fs/nfs/client.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/fs/nfs/client.c b/fs/nfs/client.c index e350bd6a2334b3..a7ce15d3c24835 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -933,10 +933,6 @@ static int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, str goto out_error; nfs_server_set_fsinfo(server, &fsinfo); - error = bdi_init(&server->backing_dev_info); - if (error) - goto out_error; - /* Get some general file system info */ if (server->namelen == 0) { @@ -995,6 +991,12 @@ static struct nfs_server *nfs_alloc_server(void) return NULL; } + if (bdi_init(&server->backing_dev_info)) { + nfs_free_iostats(server->io_stats); + kfree(server); + return NULL; + } + return server; }