diff options
author | Jens Axboe <jens.axboe@oracle.com> | 2009-06-25 09:35:01 +0200 |
---|---|---|
committer | Jens Axboe <jens.axboe@oracle.com> | 2009-06-25 12:36:33 +0200 |
commit | 3336a136d7ae49d91f4da35250feffb886f85344 (patch) | |
tree | 3829c54f9fd654f932904170d8d54c521466e051 | |
parent | f5a0e4626031b61e1ebb20b2d6c643788847aa3b (diff) |
writeback: allow sleepy exit of default writeback task
Since we do lazy create of default writeback tasks for a bdi, we can
allow sleepy exit if it has been completely idle for 5 minutes.
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
-rw-r--r-- | fs/fs-writeback.c | 28 | ||||
-rw-r--r-- | include/linux/backing-dev.h | 5 | ||||
-rw-r--r-- | include/linux/writeback.h | 2 |
3 files changed, 30 insertions, 5 deletions
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 806948389ab2..796b24389485 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -369,7 +369,7 @@ static struct bdi_work *get_next_work_item(struct backing_dev_info *bdi, /* * Retrieve work items and do the writeback they describe */ -void wb_do_writeback(struct bdi_writeback *wb, int force_wait) +long wb_do_writeback(struct bdi_writeback *wb, int force_wait) { struct backing_dev_info *bdi = wb->bdi; struct bdi_work *work; @@ -414,8 +414,10 @@ void wb_do_writeback(struct bdi_writeback *wb, int force_wait) global_page_state(NR_UNSTABLE_NFS) + (inodes_stat.nr_inodes - inodes_stat.nr_unused); - wb_writeback(wb, nr_pages, NULL, WB_SYNC_NONE, 1); + wrote = wb_writeback(wb, nr_pages, NULL, WB_SYNC_NONE, 1); } + + return wrote; } /* @@ -424,10 +426,28 @@ void wb_do_writeback(struct bdi_writeback *wb, int force_wait) */ int bdi_writeback_task(struct bdi_writeback *wb) { + unsigned long last_active = jiffies; + unsigned long wait_jiffies = -1UL; + long pages_written; + while (!kthread_should_stop()) { - unsigned long wait_jiffies; + pages_written = wb_do_writeback(wb, 0); + + if (pages_written) + last_active = jiffies; + else if (wait_jiffies != -1UL) { + unsigned long max_idle; - wb_do_writeback(wb, 0); + /* + * Longest period of inactivity that we tolerate. If we + * see dirty data again later, the task will get + * recreated automatically. + */ + max_idle = max(5UL * 60 * HZ, wait_jiffies); + if (time_after(jiffies, max_idle + last_active) && + wb_is_default_task(wb)) + break; + } wait_jiffies = msecs_to_jiffies(dirty_writeback_interval * 10); set_current_state(TASK_INTERRUPTIBLE); diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h index 210207cd1246..7256f736e570 100644 --- a/include/linux/backing-dev.h +++ b/include/linux/backing-dev.h @@ -110,6 +110,11 @@ int bdi_has_dirty_io(struct backing_dev_info *bdi); extern spinlock_t bdi_lock; extern struct list_head bdi_list; +static inline int wb_is_default_task(struct bdi_writeback *wb) +{ + return wb == &wb->bdi->wb; +} + static inline int bdi_wblist_needs_lock(struct backing_dev_info *bdi) { return test_bit(BDI_wblist_lock, &bdi->state); diff --git a/include/linux/writeback.h b/include/linux/writeback.h index 588a44972bad..e070b91905d6 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h @@ -68,7 +68,7 @@ struct writeback_control { void writeback_inodes(struct writeback_control *wbc); int inode_wait(void *); void sync_inodes_sb(struct super_block *, int wait); -void wb_do_writeback(struct bdi_writeback *wb, int force_wait); +long wb_do_writeback(struct bdi_writeback *wb, int force_wait); /* writeback.h requires fs.h; it, too, is not included from here. */ static inline void wait_on_inode(struct inode *inode) |