lkml.org 
[lkml]   [2009]   [May]   [25]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 09/12] writeback: allow sleepy exit of default writeback task
    Date
    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>
    ---
    fs/fs-writeback.c | 52 ++++++++++++++++++++++++++++++++++--------
    include/linux/backing-dev.h | 5 ++++
    include/linux/writeback.h | 2 +-
    3 files changed, 48 insertions(+), 11 deletions(-)

    diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
    index 47f5ace..1292a88 100644
    --- a/fs/fs-writeback.c
    +++ b/fs/fs-writeback.c
    @@ -247,10 +247,10 @@ int bdi_start_writeback(struct backing_dev_info *bdi, struct super_block *sb,
    * older_than_this takes precedence over nr_to_write. So we'll only write back
    * all dirty pages if they are all attached to "old" mappings.
    */
    -static void wb_kupdated(struct bdi_writeback *wb)
    +static long wb_kupdated(struct bdi_writeback *wb)
    {
    unsigned long oldest_jif;
    - long nr_to_write;
    + long nr_to_write, wrote = 0;
    struct writeback_control wbc = {
    .bdi = wb->bdi,
    .sync_mode = WB_SYNC_NONE,
    @@ -273,10 +273,13 @@ static void wb_kupdated(struct bdi_writeback *wb)
    wbc.encountered_congestion = 0;
    wbc.nr_to_write = MAX_WRITEBACK_PAGES;
    generic_sync_wb_inodes(wb, NULL, &wbc);
    + wrote += MAX_WRITEBACK_PAGES - wbc.nr_to_write;
    if (wbc.nr_to_write > 0)
    break; /* All the old data is written */
    nr_to_write -= MAX_WRITEBACK_PAGES;
    }
    +
    + return wrote;
    }

    static inline bool over_bground_thresh(void)
    @@ -289,7 +292,7 @@ static inline bool over_bground_thresh(void)
    global_page_state(NR_UNSTABLE_NFS) >= background_thresh);
    }

    -static void __wb_writeback(struct bdi_writeback *wb, long nr_pages,
    +static long __wb_writeback(struct bdi_writeback *wb, long nr_pages,
    struct super_block *sb,
    enum writeback_sync_modes sync_mode)
    {
    @@ -299,6 +302,7 @@ static void __wb_writeback(struct bdi_writeback *wb, long nr_pages,
    .older_than_this = NULL,
    .range_cyclic = 1,
    };
    + long wrote = 0;

    for (;;) {
    if (sync_mode == WB_SYNC_NONE && nr_pages <= 0 &&
    @@ -311,6 +315,7 @@ static void __wb_writeback(struct bdi_writeback *wb, long nr_pages,
    wbc.pages_skipped = 0;
    generic_sync_wb_inodes(wb, sb, &wbc);
    nr_pages -= MAX_WRITEBACK_PAGES - wbc.nr_to_write;
    + wrote += MAX_WRITEBACK_PAGES - wbc.nr_to_write;
    /*
    * If we ran out of stuff to write, bail unless more_io got set
    */
    @@ -320,6 +325,8 @@ static void __wb_writeback(struct bdi_writeback *wb, long nr_pages,
    break;
    }
    }
    +
    + return wrote;
    }

    /*
    @@ -345,10 +352,11 @@ static struct bdi_work *get_next_work_item(struct backing_dev_info *bdi,
    return ret;
    }

    -static void wb_writeback(struct bdi_writeback *wb)
    +static long wb_writeback(struct bdi_writeback *wb)
    {
    struct backing_dev_info *bdi = wb->bdi;
    struct bdi_work *work;
    + long wrote = 0;

    while ((work = get_next_work_item(bdi, wb)) != NULL) {
    struct super_block *sb = bdi_work_sb(work);
    @@ -356,16 +364,20 @@ static void wb_writeback(struct bdi_writeback *wb)
    enum writeback_sync_modes sync_mode = work->sync_mode;

    wb_clear_pending(wb, work);
    - __wb_writeback(wb, nr_pages, sb, sync_mode);
    + wrote += __wb_writeback(wb, nr_pages, sb, sync_mode);
    }
    +
    + return wrote;
    }

    /*
    * This will be inlined in bdi_writeback_task() once we get rid of any
    * dirty inodes on the default_backing_dev_info
    */
    -void wb_do_writeback(struct bdi_writeback *wb)
    +long wb_do_writeback(struct bdi_writeback *wb)
    {
    + long wrote;
    +
    /*
    * We get here in two cases:
    *
    @@ -377,9 +389,11 @@ void wb_do_writeback(struct bdi_writeback *wb)
    * items on the work_list. Process those.
    */
    if (list_empty(&wb->bdi->work_list))
    - wb_kupdated(wb);
    + wrote = wb_kupdated(wb);
    else
    - wb_writeback(wb);
    + wrote = wb_writeback(wb);
    +
    + return wrote;
    }

    /*
    @@ -388,12 +402,30 @@ void wb_do_writeback(struct bdi_writeback *wb)
    */
    int bdi_writeback_task(struct bdi_writeback *wb)
    {
    + unsigned long last_active = jiffies;
    + unsigned long wait_jiffies = -1UL;
    + long pages_written;
    DEFINE_WAIT(wait);

    while (!kthread_should_stop()) {
    - unsigned long wait_jiffies;

    - wb_do_writeback(wb);
    + pages_written = wb_do_writeback(wb);
    +
    + if (pages_written)
    + last_active = jiffies;
    + else if (wait_jiffies != -1UL) {
    + unsigned long max_idle;
    +
    + /*
    + * 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;
    + }

    prepare_to_wait(&wb->wait, &wait, TASK_INTERRUPTIBLE);
    wait_jiffies = msecs_to_jiffies(dirty_writeback_interval * 10);
    diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h
    index 72b4797..53e6c8d 100644
    --- a/include/linux/backing-dev.h
    +++ b/include/linux/backing-dev.h
    @@ -113,6 +113,11 @@ int bdi_has_dirty_io(struct backing_dev_info *bdi);
    extern struct mutex 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 e414702..30e318b 100644
    --- a/include/linux/writeback.h
    +++ b/include/linux/writeback.h
    @@ -69,7 +69,7 @@ void writeback_inodes(struct writeback_control *wbc);
    int inode_wait(void *);
    void sync_inodes_sb(struct super_block *, int wait);
    void sync_inodes(int wait);
    -void wb_do_writeback(struct bdi_writeback *wb);
    +long wb_do_writeback(struct bdi_writeback *wb);

    /* writeback.h requires fs.h; it, too, is not included from here. */
    static inline void wait_on_inode(struct inode *inode)
    --
    1.6.3.rc0.1.gf800


    \
     
     \ /
      Last update: 2009-05-25 09:55    [W:0.029 / U:68.416 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site