[PATCH 2/5] writeback: stop periodic/background work on seeing sync works

Wu Fengguang
2010-07-29T11:51:44Z

[-- Attachment #1: writeback-sync-pending.patch --]
[-- Type: text/plain, Size: 2679 bytes --]

The periodic/background writeback can run forever. So when any
sync work is enqueued, increase bdi->sync_works to notify the
active non-sync works to exit. Non-sync works queued after sync
works won't be affected.

Signed-off-by: Wu Fengguang <fengguang.wu@intel.com>
---
fs/fs-writeback.c | 13 +++++++++++++
include/linux/backing-dev.h | 6 ++++++
mm/backing-dev.c | 1 +
3 files changed, 20 insertions(+)

--- linux-next.orig/fs/fs-writeback.c 2010-07-29 17:13:23.000000000 +0800
+++ linux-next/fs/fs-writeback.c 2010-07-29 17:13:49.000000000 +0800
@@ -80,6 +80,8 @@ static void bdi_queue_work(struct backin

spin_lock(&bdi->wb_lock);
list_add_tail(&work->list, &bdi->work_list);
+ if (work->for_sync)
+ atomic_inc(&bdi->wb.sync_works);
spin_unlock(&bdi->wb_lock);

/*
@@ -633,6 +635,14 @@ static long wb_writeback(struct bdi_writ
break;

/*
+ * background/periodic works can run forever, need to abort
+ * on seeing any pending sync work, to prevent livelock it.
+ */
+ if (atomic_read(&wb->sync_works) &&
+ (work->for_background || work->for_kupdate))
+ break;
+
+ /*
* For background writeout, stop when we are below the
* background dirty threshold
*/
@@ -765,6 +775,9 @@ long wb_do_writeback(struct bdi_writebac

wrote += wb_writeback(wb, work);

+ if (work->for_sync)
+ atomic_dec(&wb->sync_works);
+
/*
* Notify the caller of completion if this is a synchronous
* work item, otherwise just free it.
--- linux-next.orig/include/linux/backing-dev.h 2010-07-29 17:13:23.000000000 +0800
+++ linux-next/include/linux/backing-dev.h 2010-07-29 17:13:31.000000000 +0800
@@ -50,6 +50,12 @@ struct bdi_writeback {

unsigned long last_old_flush; /* last old data flush */

+ /*
+ * sync works queued, background works shall abort on seeing this,
+ * to prevent livelocking the sync works
+ */
+ atomic_t sync_works;
+
struct task_struct *task; /* writeback task */
struct list_head b_dirty; /* dirty inodes */
struct list_head b_io; /* parked for writeback */
--- linux-next.orig/mm/backing-dev.c 2010-07-29 17:13:23.000000000 +0800
+++ linux-next/mm/backing-dev.c 2010-07-29 17:13:31.000000000 +0800
@@ -257,6 +257,7 @@ static void bdi_wb_init(struct bdi_write

wb->bdi = bdi;
wb->last_old_flush = jiffies;
+ atomic_set(&wb->sync_works, 0);
INIT_LIST_HEAD(&wb->b_dirty);
INIT_LIST_HEAD(&wb->b_io);
INIT_LIST_HEAD(&wb->b_more_io);