[RFC][PATCH 2/2] tux3: Use writeback hook to remove duplicated core code

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Instead of re-implementing part of fs/fs-writeback.c, use a proposed
net ->writeback super operation to drive delta writeback. For each
inode that is cleaned, call inode_writeback_done(inode). For each
inode that will be kept dirty in cache, call inode_writeback_touch
so that the inode appears young to fs-writeback and does not trigger
repeated ->writeback flushes.

Signed-off-by: Daniel Phillips <daniel@xxxxxxxx>
---
 fs/tux3/Makefile              |   2 +-
 fs/tux3/commit.c              |   1 -
 fs/tux3/commit_flusher.c      | 180 ++++++++++--------
 fs/tux3/commit_flusher.h      |  16 --
 fs/tux3/commit_flusher_hack.c | 423 ------------------------------------------
 fs/tux3/inode.c               |   2 -
 fs/tux3/super.c               |  17 +-
 fs/tux3/tux3.h                |  11 +-
 fs/tux3/writeback.c           |  75 ++------
 11 files changed, 128 insertions(+), 599 deletions(-)
 delete mode 100644 fs/tux3/commit_flusher.h
 delete mode 100644 fs/tux3/commit_flusher_hack.c

diff --git a/fs/tux3/Makefile b/fs/tux3/Makefile
index 9623a54..30faba5 100644
--- a/fs/tux3/Makefile
+++ b/fs/tux3/Makefile
@@ -13,7 +13,7 @@ tux3-objs += balloc.o btree.o buffer.o commit.o dir.o dleaf.o \
 EXTRA_CFLAGS += -Werror -std=gnu99 -Wno-declaration-after-statement
 #EXTRA_CFLAGS += -DTUX3_FLUSHER=TUX3_FLUSHER_SYNC
 #EXTRA_CFLAGS += -DTUX3_FLUSHER=TUX3_FLUSHER_ASYNC_OWN
-EXTRA_CFLAGS += -DTUX3_FLUSHER=TUX3_FLUSHER_ASYNC_HACK
+EXTRA_CFLAGS += -DTUX3_FLUSHER=TUX3_FLUSHER_ASYNC

 obj-$(CONFIG_TUX3_MMAP) += mmap_builtin_hack.o
 endif
diff --git a/fs/tux3/commit.c b/fs/tux3/commit.c
index dd76d49..84e686e 100644
--- a/fs/tux3/commit.c
+++ b/fs/tux3/commit.c
@@ -638,7 +638,6 @@ static void delta_transition(struct sb *sb)
      ((int)(a) - (int)(b) >= 0))

 #include "commit_flusher.c"
-#include "commit_flusher_hack.c"

 int force_unify(struct sb *sb)
 {
diff --git a/fs/tux3/commit_flusher.c b/fs/tux3/commit_flusher.c
index 8e7057d..2d938c5 100644
--- a/fs/tux3/commit_flusher.c
+++ b/fs/tux3/commit_flusher.c
@@ -4,7 +4,7 @@
  * Copyright (c) 2008-2014 OGAWA Hirofumi
  */

-#if TUX3_FLUSHER != TUX3_FLUSHER_ASYNC_HACK
+#if TUX3_FLUSHER == TUX3_FLUSHER_SYNC
 #include "tux3.h"

 static void __tux3_init_flusher(struct sb *sb)
@@ -15,72 +15,6 @@ static void __tux3_init_flusher(struct sb *sb)
 #endif
 }

-#if TUX3_FLUSHER == TUX3_FLUSHER_ASYNC_OWN
-static int flush_delta_work(void *data)
-{
-    struct sb *sb = data;
-    int err;
-
-    set_freezable();
-
-    /*
-     * Our parent may run at a different priority, just set us to normal
-     */
-    set_user_nice(current, 0);
-
-    while (!kthread_freezable_should_stop(NULL)) {
-        if (test_bit(TUX3_COMMIT_PENDING_BIT, &sb->backend_state)) {
-            clear_bit(TUX3_COMMIT_PENDING_BIT, &sb->backend_state);
-
-            err = flush_delta(sb);
-            /* FIXME: error handling */
-        }
-
-        set_current_state(TASK_INTERRUPTIBLE);
-        if (!test_bit(TUX3_COMMIT_PENDING_BIT, &sb->backend_state) &&
-            !kthread_should_stop())
-            schedule();
-        __set_current_state(TASK_RUNNING);
-    }
-
-    return 0;
-}
-
-int tux3_init_flusher(struct sb *sb)
-{
-    struct task_struct *task;
-    char b[BDEVNAME_SIZE];
-
-    __tux3_init_flusher(sb);
-
-    bdevname(vfs_sb(sb)->s_bdev, b);
-
-    /* FIXME: we should use normal bdi-writeback by changing core */
-    task = kthread_run(flush_delta_work, sb, "tux3/%s", b);
-    if (IS_ERR(task))
-        return PTR_ERR(task);
-
-    sb->flush_task = task;
-
-    return 0;
-}
-
-void tux3_exit_flusher(struct sb *sb)
-{
-    if (sb->flush_task) {
-        kthread_stop(sb->flush_task);
-        sb->flush_task = NULL;
-    }
-}
-
-static void schedule_flush_delta(struct sb *sb)
-{
-    /* Start the flusher for pending delta */
-    wake_up_process(sb->flush_task);
-}
-
-#else /* TUX3_FLUSHER != TUX3_FLUSHER_ASYNC_OWN */
-
 int tux3_init_flusher(struct sb *sb)
 {
     __tux3_init_flusher(sb);
@@ -109,7 +43,6 @@ static int flush_pending_delta(struct sb *sb)
 out:
     return err;
 }
-#endif /* TUX3_FLUSHER != TUX3_FLUSHER_ASYNC_OWN */

 /* Try delta transition */
 static void try_delta_transition(struct sb *sb)
@@ -155,10 +88,8 @@ static int try_flush_pending_until_delta(struct sb *sb, unsigned delta)
     trace("delta %u, committed %u, backend_state %lx",
           delta, sb->committed_delta, sb->backend_state);

-#if TUX3_FLUSHER == TUX3_FLUSHER_SYNC
     if (!delta_after_eq(sb->committed_delta, delta))
         flush_pending_delta(sb);
-#endif

     return delta_after_eq(sb->committed_delta, delta);
 }
@@ -175,9 +106,7 @@ static int sync_current_delta(struct sb *sb, enum unify_flags unify_flag)
     unsigned delta;
     int err = 0;

-#if TUX3_FLUSHER == TUX3_FLUSHER_SYNC
     down_write(&sb->delta_lock);
-#endif
     /* Get delta that have to write */
     delta_ref = delta_get(sb);
 #ifdef UNIFY_DEBUG
@@ -197,10 +126,111 @@ static int sync_current_delta(struct sb *sb, enum unify_flags unify_flag)
     /* Wait until committing the current delta */
     err = wait_for_commit(sb, delta);
     assert(err || delta_after_eq(sb->committed_delta, delta));
-#if TUX3_FLUSHER == TUX3_FLUSHER_SYNC
     up_write(&sb->delta_lock);
+    return err;
+}
+
+#else /* TUX3_FLUSHER == TUX3_FLUSHER_ASYNC */
+
+static void try_delta_transition(struct sb *sb)
+{
+#if 0
+    trace("stage %u, backend_state %lx",
+          sb->staging_delta, sb->backend_state);
+    sync_inodes_sb(vfs_sb(sb));
 #endif
+}

-    return err;
+/* Do the delta transition until specified delta */
+static int try_delta_transition_until_delta(struct sb *sb, unsigned delta)
+{
+    trace("delta %u, stage %u, backend_state %lx",
+          delta, sb->staging_delta, sb->backend_state);
+
+    /* Already delta transition was started for delta */
+    if (delta_after_eq(sb->staging_delta, delta))
+        return 1;
+
+    if (!test_and_set_bit(TUX3_COMMIT_RUNNING_BIT, &sb->backend_state)) {
+        /* Recheck after grabed TUX3_COMMIT_RUNNING_BIT */
+        if (delta_after_eq(sb->staging_delta, delta)) {
+            clear_bit(TUX3_COMMIT_RUNNING_BIT, &sb->backend_state);
+            return 1;
+        }
+
+        delta_transition(sb);
+    }
+
+    return delta_after_eq(sb->staging_delta, delta);
 }
-#endif /* TUX3_FLUSHER == TUX3_FLUSHER_ASYNC_HACK */
+
+/* Advance delta transition until specified delta */
+static int wait_for_transition(struct sb *sb, unsigned delta)
+{
+    return wait_event_killable(sb->delta_event_wq,
+        try_delta_transition_until_delta(sb, delta));
+}
+
+long tux3_writeback(struct super_block *super, struct writeback_control *wbc, long *nr_pages)
+{
+    struct sb *sb = tux_sb(super);
+    struct delta_ref *delta_ref;
+    unsigned delta;
+    int err;
+
+    /* If we didn't finish replay yet, don't flush. */
+    if (!(super->s_flags & MS_ACTIVE))
+        return 0;
+
+    /* Get delta that have to write */
+    delta_ref = delta_get(sb);
+#ifdef UNIFY_DEBUG
+    /* NO_UNIFY and FORCE_UNIFY are not supported for now */
+    delta_ref->unify_flag = ALLOW_UNIFY;
+#endif
+    delta = delta_ref->delta;
+    delta_put(sb, delta_ref);
+
+    /* Make sure the delta transition was done for current delta */
+    err = wait_for_transition(sb, delta);
+    if (err)
+        return err;
+    assert(delta_after_eq(sb->staging_delta, delta));
+
+    /* Wait for last referencer of delta was gone */
+    wait_event(sb->delta_event_wq,
+           test_bit(TUX3_COMMIT_PENDING_BIT, &sb->backend_state));
+
+    if (test_bit(TUX3_COMMIT_PENDING_BIT, &sb->backend_state)) {
+        clear_bit(TUX3_COMMIT_PENDING_BIT, &sb->backend_state);
+
+        err = flush_delta(sb);
+        /* FIXME: error handling */
+#if 0
+        /* wb_update_bandwidth() is not exported to module */
+        wb_update_bandwidth(wb, wb_start);
+#endif
+    }
+
+    *nr_pages = 0;
+    return 1;
+}
+
+static int sync_current_delta(struct sb *sb, enum unify_flags unify_flag)
+{
+    /* FORCE_UNIFY is not supported */
+    WARN_ON(unify_flag == FORCE_UNIFY);
+    /* This is called only for fsync, so we can take ->s_umount here */
+    down_read(&vfs_sb(sb)->s_umount);
+    sync_inodes_sb(vfs_sb(sb));
+    up_read(&vfs_sb(sb)->s_umount);
+    return 0;    /* FIXME: error code */
+}
+
+static void schedule_flush_delta(struct sb *sb)
+{
+    /* Wake up waiters for pending delta staging */
+    wake_up_all(&sb->delta_event_wq);
+}
+
+#endif /* TUX3_FLUSHER == TUX3_FLUSHER_ASYNC */
diff --git a/fs/tux3/commit_flusher.h b/fs/tux3/commit_flusher.h
deleted file mode 100644
index 2c0a144..0000000
--- a/fs/tux3/commit_flusher.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef TUX3_COMMIT_FLUSHER_H
-#define TUX3_COMMIT_FLUSHER_H
-
-/* FIXME: Remove this file after implement of flusher interface */
-
-#if TUX3_FLUSHER == TUX3_FLUSHER_ASYNC_HACK
-/* Hack for BDI_CAP_NO_WRITEBACK */
-void tux3_set_mapping_bdi(struct inode *inode);
-#else
-static inline void tux3_set_mapping_bdi(struct inode *inode) { }
-#endif
-
-int tux3_init_flusher(struct sb *sb);
-void tux3_exit_flusher(struct sb *sb);
-
-#endif /* !TUX3_COMMIT_FLUSHER_H */
diff --git a/fs/tux3/commit_flusher_hack.c b/fs/tux3/commit_flusher_hack.c
deleted file mode 100644
index 08696ed..0000000
--- a/fs/tux3/commit_flusher_hack.c
+++ /dev/null
@@ -1,423 +0,0 @@
-/*
- * FIXME: this is hack to override writeback without patch kernel.
- * We should add proper interfaces to do this, instead. Then, remove
- * this stuff.
- */
-
-#if TUX3_FLUSHER == TUX3_FLUSHER_ASYNC_HACK
-#include "tux3.h"
-#include <linux/kthread.h>
-#include <linux/freezer.h>
-
-void tux3_set_mapping_bdi(struct inode *inode)
-{
-    /*
-     * Hack: set backing_dev_info to use our bdi.
-     */
-    inode->i_mapping->backing_dev_info = inode->i_sb->s_bdi;
-}
-
-/*
- * FIXME: dirty hack for now. We should add callback in writeback task
- * instead of custom bdi.
- */
-struct wb_writeback_work {
-    long nr_pages;
-    struct super_block *sb;
-    unsigned long *older_than_this;
-    enum writeback_sync_modes sync_mode;
-    unsigned int tagged_writepages:1;
-    unsigned int for_kupdate:1;
-    unsigned int range_cyclic:1;
-    unsigned int for_background:1;
-    unsigned int for_sync:1;    /* sync(2) WB_SYNC_ALL writeback */
-    enum wb_reason reason;        /* why was writeback initiated? */
-
-    struct list_head list;        /* pending work list */
-    struct completion *done;    /* set if the caller waits */
-};
-
-/* Do the delta transition until specified delta */
-static int try_delta_transition_until_delta(struct sb *sb, unsigned delta)
-{
-    trace("delta %u, stage %u, backend_state %lx",
-          delta, sb->staging_delta, sb->backend_state);
-
-    /* Already delta transition was started for delta */
-    if (delta_after_eq(sb->staging_delta, delta))
-        return 1;
-
-    if (!test_and_set_bit(TUX3_COMMIT_RUNNING_BIT, &sb->backend_state)) {
-        /* Recheck after grabed TUX3_COMMIT_RUNNING_BIT */
-        if (delta_after_eq(sb->staging_delta, delta)) {
-            clear_bit(TUX3_COMMIT_RUNNING_BIT, &sb->backend_state);
-            return 1;
-        }
-
-        delta_transition(sb);
-    }
-
-    return delta_after_eq(sb->staging_delta, delta);
-}
-
-/* Advance delta transition until specified delta */
-static int wait_for_transition(struct sb *sb, unsigned delta)
-{
-    return wait_event_killable(sb->delta_event_wq,
-                   try_delta_transition_until_delta(sb, delta));
-}
-
-static long tux3_wb_writeback(struct bdi_writeback *wb,
-                  struct wb_writeback_work *work)
-{
-    struct sb *sb = container_of(wb->bdi, struct sb, bdi);
-    struct delta_ref *delta_ref;
-    unsigned delta;
-    int err;
-
-    /* If we didn't finish replay yet, don't flush. */
-    if (!(vfs_sb(sb)->s_flags & MS_ACTIVE))
-        return 0;
-
-    /* Get delta that have to write */
-    delta_ref = delta_get(sb);
-#ifdef UNIFY_DEBUG
-    /* NO_UNIFY and FORCE_UNIFY are not supported for now */
-    delta_ref->unify_flag = ALLOW_UNIFY;
-#endif
-    delta = delta_ref->delta;
-    delta_put(sb, delta_ref);
-
-    /* Make sure the delta transition was done for current delta */
-    err = wait_for_transition(sb, delta);
-    if (err)
-        return err;
-    assert(delta_after_eq(sb->staging_delta, delta));
-
-    /* Wait for last referencer of delta was gone */
-    wait_event(sb->delta_event_wq,
-           test_bit(TUX3_COMMIT_PENDING_BIT, &sb->backend_state));
-
-    if (test_bit(TUX3_COMMIT_PENDING_BIT, &sb->backend_state)) {
-        clear_bit(TUX3_COMMIT_PENDING_BIT, &sb->backend_state);
-
-        err = flush_delta(sb);
-        /* FIXME: error handling */
-#if 0
-        /* wb_update_bandwidth() is not exported to module */
-        wb_update_bandwidth(wb, wb_start);
-#endif
-    }
-
-    return 1; /* FIXME: return code */
-}
-
-static bool inode_dirtied_after(struct inode *inode, unsigned long t)
-{
-    bool ret = time_after(inode->dirtied_when, t);
-#ifndef CONFIG_64BIT
-    /*
-     * For inodes being constantly redirtied, dirtied_when can get stuck.
-     * It _appears_ to be in the future, but is actually in distant past.
-     * This test is necessary to prevent such wrapped-around relative times
-     * from permanently stopping the whole bdi writeback.
-     */
-    ret = ret && time_before_eq(inode->dirtied_when, jiffies);
-#endif
-    return ret;
-}
-
-static int tux3_has_old_data(struct bdi_writeback *wb)
-{
-    static unsigned int tux3_dirty_expire_interval = 30 * 100;
-
-    int has_old = 0;
-
-    /*
-     * We don't flush for each inodes. So, we flush all for each
-     * tux3_dirty_expire_interval.
-     *
-     * FIXME: we should pickup only older inodes?
-     */
-    spin_lock(&wb->list_lock);
-    if (wb_has_dirty_io(wb)) {
-        unsigned long older_than_this = jiffies -
-            msecs_to_jiffies(tux3_dirty_expire_interval * 10);
-        struct inode *inode =
-            list_entry(wb->b_dirty.prev, struct inode, i_wb_list);
-
-        if (!inode_dirtied_after(inode, older_than_this))
-            has_old = 1;
-    }
-    spin_unlock(&wb->list_lock);
-
-    return has_old;
-}
-
-static long tux3_wb_check_old_data_flush(struct bdi_writeback *wb)
-{
-    /* Hack: dirty_expire_interval is not exported to module */
-    unsigned long expired;
-
-    /*
-     * When set to zero, disable periodic writeback
-     */
-    if (!dirty_writeback_interval)
-        return 0;
-
-    expired = wb->last_old_flush +
-            msecs_to_jiffies(dirty_writeback_interval * 10);
-    if (time_before(jiffies, expired))
-        return 0;
-
-    wb->last_old_flush = jiffies;
-
-    if (!tux3_has_old_data(wb)) {
-        /*
-         * If now after interval, we return 1 at least, to
-         * avoid to run tux3_wb_check_background_flush().
-         */
-        return 1;
-    }
-
-    struct wb_writeback_work work = {
-        .nr_pages    = 0,
-        .sync_mode    = WB_SYNC_NONE,
-        .for_kupdate    = 1,
-        .range_cyclic    = 1,
-        .reason        = WB_REASON_PERIODIC,
-    };
-
-    return tux3_wb_writeback(wb, &work);
-}
-
-static inline int tux3_over_bground_thresh(struct backing_dev_info *bdi,
-                       long wrote)
-{
-    /*
-     * FIXME: Memory pressure functions are not exported to module.
-     *
-     * So, if we didn't wrote any data on this wakeup, we assume
-     * this wakeup call is from memory pressure.
-     */
-    return !wrote;
-}
-
-static long tux3_wb_check_background_flush(struct bdi_writeback *wb, long wrote)
-{
-    if (tux3_over_bground_thresh(wb->bdi, wrote)) {
-
-        struct wb_writeback_work work = {
-            .nr_pages    = LONG_MAX,
-            .sync_mode    = WB_SYNC_NONE,
-            .for_background    = 1,
-            .range_cyclic    = 1,
-            .reason        = WB_REASON_BACKGROUND,
-        };
-
-        return tux3_wb_writeback(wb, &work);
-    }
-
-    return 0;
-}
-
-static struct wb_writeback_work *
-get_next_work_item(struct backing_dev_info *bdi)
-{
-    struct wb_writeback_work *work = NULL;
-
-    spin_lock_bh(&bdi->wb_lock);
-    if (!list_empty(&bdi->work_list)) {
-        work = list_entry(bdi->work_list.next,
-                  struct wb_writeback_work, list);
-        list_del_init(&work->list);
-    }
-    spin_unlock_bh(&bdi->wb_lock);
-    return work;
-}
-
-static long tux3_do_writeback(struct bdi_writeback *wb)
-{
-    struct backing_dev_info *bdi = wb->bdi;
-    struct wb_writeback_work *work = NULL;
-    long wrote = 0;
-
-    set_bit(BDI_writeback_running, &wb->bdi->state);
-    while ((work = get_next_work_item(bdi)) != NULL) {
-        trace("nr_pages %ld, sb %p, sync_mode %d, "
-              "tagged_writepages %d, for_kupdate %d, range_cyclic %d, "
-              "for_background %d, reason %d, done %p",
-              work->nr_pages, work->sb, work->sync_mode,
-              work->tagged_writepages, work->for_kupdate,
-              work->range_cyclic, work->for_background,
-              work->reason, work->done);
-
-        wrote += tux3_wb_writeback(wb, work);
-
-        /*
-         * Notify the caller of completion if this is a synchronous
-         * work item, otherwise just free it.
-         */
-        if (work->done)
-            complete(work->done);
-        else
-            kfree(work);
-    }
-    trace("flush done");
-
-    /*
-     * Check for periodic writeback, kupdated() style
-     */
-    wrote += tux3_wb_check_old_data_flush(wb);
-    wrote += tux3_wb_check_background_flush(wb, wrote);
-    clear_bit(BDI_writeback_running, &wb->bdi->state);
-
-    return wrote;
-}
-
-/* Dirty hack to get bdi_wq address from module */
-static struct workqueue_struct *kernel_bdi_wq;
-
-/*
- * Handle writeback of dirty data for the device backed by this bdi. Also
- * reschedules periodically and does kupdated style flushing.
- */
-static void tux3_writeback_workfn(struct work_struct *work)
-{
-    struct bdi_writeback *wb = container_of(to_delayed_work(work),
-                        struct bdi_writeback, dwork);
-    struct backing_dev_info *bdi = wb->bdi;
-    long pages_written;
-
-#if 0
-    /* set_worker_desc() is not exported to module */
-    set_worker_desc("flush-tux3-%s", dev_name(bdi->dev));
-#endif
-    current->flags |= PF_SWAPWRITE;
-
-#if 0
-    /* current_is_workqueue_rescuer() is not exported to module */
-    if (likely(!current_is_workqueue_rescuer() ||
-           list_empty(&bdi->bdi_list)))
-#endif
-    {
-        /*
-         * The normal path.  Keep writing back @bdi until its
-         * work_list is empty.  Note that this path is also taken
-         * if @bdi is shutting down even when we're running off the
-         * rescuer as work_list needs to be drained.
-         */
-        do {
-            pages_written = tux3_do_writeback(wb);
-//            trace_writeback_pages_written(pages_written);
-        } while (!list_empty(&bdi->work_list));
-    }
-#if 0
-    else {
-        /*
-         * bdi_wq can't get enough workers and we're running off
-         * the emergency worker.  Don't hog it.  Hopefully, 1024 is
-         * enough for efficient IO.
-         */
-        pages_written = writeback_inodes_wb(&bdi->wb, 1024,
-                            WB_REASON_FORKER_THREAD);
-        trace_writeback_pages_written(pages_written);
-    }
-#endif
-    if (!list_empty(&bdi->work_list) ||
-        (wb_has_dirty_io(wb) && dirty_writeback_interval))
-        queue_delayed_work(kernel_bdi_wq, &wb->dwork,
-            msecs_to_jiffies(dirty_writeback_interval * 10));
-
-    current->flags &= ~PF_SWAPWRITE;
-}
-
-#include <linux/kallsyms.h>
-static int tux3_setup_writeback(struct sb *sb, struct backing_dev_info *bdi)
-{
-    /* Dirty hack to get bdi_wq address from module */
-    if (kernel_bdi_wq == NULL) {
-        unsigned long wq_addr;
-
-        wq_addr = kallsyms_lookup_name("bdi_wq");
-        if (!wq_addr) {
-            tux3_err(sb, "couldn't find bdi_wq address\n");
-            return -EINVAL;
-        }
-        kernel_bdi_wq = *(struct workqueue_struct **)wq_addr;
-        tux3_msg(sb, "use bdi_wq %p", kernel_bdi_wq);
-    }
-
-    /* Overwrite callback by ourself handler */
-    INIT_DELAYED_WORK(&bdi->wb.dwork, tux3_writeback_workfn);
-
-    return 0;
-}
-
-static int tux3_congested_fn(void *congested_data, int bdi_bits)
-{
-    return bdi_congested(congested_data, bdi_bits);
-}
-
-/*
- * We need to disable writeback to control dirty flags of inode.
- * Otherwise, writeback will clear dirty, and inode can be reclaimed
- * without our control.
- */
-int tux3_init_flusher(struct sb *sb)
-{
-    struct backing_dev_info *bdi = &sb->bdi;
-    int err;
-
-    bdi->ra_pages        = vfs_sb(sb)->s_bdi->ra_pages;
-    bdi->congested_fn    = tux3_congested_fn;
-    bdi->congested_data    = vfs_sb(sb)->s_bdi;
-
-    err = bdi_setup_and_register(bdi, "tux3", BDI_CAP_MAP_COPY);
-    if (err)
-        return err;
-
-    err = tux3_setup_writeback(sb, bdi);
-    if (err) {
-        bdi_destroy(bdi);
-        return err;
-    }
-
-    vfs_sb(sb)->s_bdi = bdi;
-
-    return 0;
-}
-
-void tux3_exit_flusher(struct sb *sb)
-{
-    struct backing_dev_info *bdi = vfs_sb(sb)->s_bdi;
-    if (bdi == &sb->bdi)
-        bdi_destroy(bdi);
-}
-
-static void schedule_flush_delta(struct sb *sb)
-{
-    /* Wake up waiters for pending delta staging */
-    wake_up_all(&sb->delta_event_wq);
-}
-
-static void try_delta_transition(struct sb *sb)
-{
-#if 0
-    trace("stage %u, backend_state %lx",
-          sb->staging_delta, sb->backend_state);
-    sync_inodes_sb(vfs_sb(sb));
-#endif
-}
-
-static int sync_current_delta(struct sb *sb, enum unify_flags unify_flag)
-{
-    /* FORCE_UNIFY is not supported */
-    WARN_ON(unify_flag == FORCE_UNIFY);
-    /* This is called only for fsync, so we can take ->s_umount here */
-    down_read(&vfs_sb(sb)->s_umount);
-    sync_inodes_sb(vfs_sb(sb));
-    up_read(&vfs_sb(sb)->s_umount);
-    return 0;    /* FIXME: error code */
-}
-#endif /* TUX3_FLUSHER != TUX3_FLUSHER_ASYNC_HACK */
diff --git a/fs/tux3/inode.c b/fs/tux3/inode.c
index 1bfb28f..5c9b1f4 100644
--- a/fs/tux3/inode.c
+++ b/fs/tux3/inode.c
@@ -932,8 +932,6 @@ static void tux_setup_inode(struct inode *inode)

     assert(tux_inode(inode)->inum != TUX_INVALID_INO);

-    tux3_set_mapping_bdi(inode);
-
 //    inode->i_generation = 0;
 //    inode->i_flags = 0;

diff --git a/fs/tux3/super.c b/fs/tux3/super.c
index 931c86d..68642d4 100644
--- a/fs/tux3/super.c
+++ b/fs/tux3/super.c
@@ -126,9 +126,6 @@ static void __tux3_put_super(struct sb *sbi)
     iput(sbi->volmap);
     sbi->volmap = NULL;

-    /* Cleanup flusher after inode was evicted */
-    tux3_exit_flusher(sbi);
-
     tux3_free_idefer_map(sbi->idefer_map);
     sbi->idefer_map = NULL;
     /* FIXME: add more sanity check */
@@ -178,13 +175,6 @@ struct replay *tux3_init_fs(struct sb *sbi)
     char *name;
     int err;

-    /* Initialize flusher before setup inode */
-    err = tux3_init_flusher(sbi);
-    if (err) {
-        tux3_err(sbi, "failed to initialize flusher");
-        goto error;
-    }
-
     err = -ENOMEM;

     /* Prepare non on-disk inodes */
@@ -375,7 +365,7 @@ static void tux3_destroy_inode(struct inode *inode)
     call_rcu(&inode->i_rcu, tux3_i_callback);
 }

-#if TUX3_FLUSHER != TUX3_FLUSHER_ASYNC_HACK
+#if TUX3_FLUSHER != TUX3_FLUSHER_ASYNC
 static int tux3_sync_fs(struct super_block *sb, int wait)
 {
     /* FIXME: We should support "wait" parameter. */
@@ -423,12 +413,13 @@ static const struct super_operations tux3_super_ops = {
     .evict_inode    = tux3_evict_inode,
     /* FIXME: we have to handle write_inode of sync (e.g. cache pressure) */
 //    .write_inode    = tux3_write_inode,
-#if TUX3_FLUSHER != TUX3_FLUSHER_ASYNC_HACK
-    /* If TUX3_FLUSHER_ASYNC_HACK, normal kernel flush request does all */
+#if TUX3_FLUSHER != TUX3_FLUSHER_ASYNC
+    /* If TUX3_FLUSHER_ASYNC, normal kernel flush request does all */
     .sync_fs    = tux3_sync_fs,
 #endif
     .put_super    = tux3_put_super,
     .statfs        = tux3_statfs,
+    .writeback = tux3_writeback,
 };

 static int tux3_fill_super(struct super_block *sb, void *data, int silent)
diff --git a/fs/tux3/tux3.h b/fs/tux3/tux3.h
index 002d6d4..3ca6756 100644
--- a/fs/tux3/tux3.h
+++ b/fs/tux3/tux3.h
@@ -222,7 +222,7 @@ struct stash { struct flink_head head; u64 *pos, *top; };
 /* Flush asynchronously by own timing */
 #define TUX3_FLUSHER_ASYNC_OWN        2
 /* Flush asynchronously by kernel normal timing (by hackish way) */
-#define TUX3_FLUSHER_ASYNC_HACK        3
+#define TUX3_FLUSHER_ASYNC        3

 /* Refcount for delta */
 struct delta_ref {
@@ -271,9 +271,6 @@ struct sb {
 #if TUX3_FLUSHER == TUX3_FLUSHER_ASYNC_OWN
     struct task_struct *flush_task;        /* work to flush delta */
 #endif
-#if TUX3_FLUSHER == TUX3_FLUSHER_ASYNC_HACK
-    struct backing_dev_info bdi;
-#endif

     struct btree itree;    /* Inode btree */
     struct btree otree;    /* Orphan btree */
@@ -793,9 +790,6 @@ int change_end(struct sb *sb);
 void change_begin_if_needed(struct sb *sb, int need_sep);
 void change_end_if_needed(struct sb *sb);

-/* commit_flusher.c */
-#include "commit_flusher.h"
-
 /* dir.c */
 void tux_set_entry(struct buffer_head *buffer, struct tux3_dirent *entry,
            inum_t inum, umode_t mode);
@@ -978,6 +972,9 @@ static inline void tux3_mark_inode_dirty_sync(struct inode *inode)
     __tux3_mark_inode_dirty(inode, I_DIRTY_SYNC);
 }

+struct super_block;
+struct writeback_control;
+long tux3_writeback(struct super_block *super, struct writeback_control *wbc, long *nr_pages);
 void tux3_dirty_inode(struct inode *inode, int flags);
 void tux3_mark_inode_to_delete(struct inode *inode);
 void tux3_iattrdirty(struct inode *inode);
diff --git a/fs/tux3/writeback.c b/fs/tux3/writeback.c
index 9ecafc0..b4b4798 100644
--- a/fs/tux3/writeback.c
+++ b/fs/tux3/writeback.c
@@ -124,57 +124,6 @@ static inline unsigned tux3_dirty_flags(struct inode *inode, unsigned delta)
     return ret;
 }

-/*
- * We don't use i_wb_list though, bdi flusher checks this via
- * wb_has_dirty_io(). So if inode become clean, we remove inode from
- * it.
- */
-static inline void tux3_inode_wb_lock(struct inode *inode)
-{
-#ifdef __KERNEL__
-    struct backing_dev_info *bdi = inode->i_sb->s_bdi;
-    spin_lock(&bdi->wb.list_lock);
-#endif
-}
-
-static inline void tux3_inode_wb_unlock(struct inode *inode)
-{
-#ifdef __KERNEL__
-    struct backing_dev_info *bdi = inode->i_sb->s_bdi;
-    spin_unlock(&bdi->wb.list_lock);
-#endif
-}
-
-static inline void tux3_inode_wb_list_del(struct inode *inode)
-{
-#ifdef __KERNEL__
-    list_del_init(&inode->i_wb_list);
-#endif
-}
-
-/*
- * __mark_inode_dirty() doesn't know about delta boundary (we don't
- * clear I_DIRTY before flush, in order to prevent the inode to be
- * freed). So, if inode was re-dirtied for frontend delta while
- * flushing old delta, ->dirtied_when may not be updated by
- * __mark_inode_dirty() forever.
- *
- * Although we don't use ->dirtied_when, bdi flusher uses
- * ->dirtied_when to decide flush timing, so we have to update
- * ->dirtied_when ourself.
- */
-static void tux3_inode_wb_update_dirtied_when(struct inode *inode)
-{
-#ifdef __KERNEL__
-    /* Take lock only if we have to update. */
-    struct backing_dev_info *bdi = inode->i_sb->s_bdi;
-    tux3_inode_wb_lock(inode);
-    inode->dirtied_when = jiffies;
-    list_move(&inode->i_wb_list, &bdi->wb.b_dirty);
-    tux3_inode_wb_unlock(inode);
-#endif
-}
-
 /* This is hook of __mark_inode_dirty() and called I_DIRTY_PAGES too */
 void tux3_dirty_inode(struct inode *inode, int flags)
 {
@@ -220,11 +169,19 @@ void tux3_dirty_inode(struct inode *inode, int flags)
     spin_unlock(&tuxnode->lock);

     /*
-     * Update ->i_wb_list and ->dirtied_when if need. See comment
-     * of tux3_inode_wb_update_dirtied_when().
+     * Update ->i_wb_list and ->dirtied_when if needed.
+     * __mark_inode_dirty() doesn't know about delta boundary (we don't
+     * clear I_DIRTY before flush, in order to prevent the inode to be
+     * freed). So, if inode was re-dirtied for frontend delta while
+     * flushing old delta, ->dirtied_when may not be updated by
+     * __mark_inode_dirty() forever.
+     *
+     * Although we don't use ->dirtied_when, bdi flusher uses
+     * ->dirtied_when to decide flush timing, so we have to update
+     * ->dirtied_when ourself.
      */
     if (re_dirtied)
-        tux3_inode_wb_update_dirtied_when(inode);
+        inode_writeback_touch(inode);
 }

 /*
@@ -289,23 +246,20 @@ static void tux3_clear_dirty_inode_nolock(struct inode *inode, unsigned delta,
     }

     /* Update state if inode isn't dirty anymore */
-    if (!(tuxnode->flags & ~NON_DIRTY_FLAGS)) {
+    if (!(tuxnode->flags & ~NON_DIRTY_FLAGS))
         inode->i_state &= ~I_DIRTY;
-        tux3_inode_wb_list_del(inode);
-    }
 }

 /* Clear dirty flags for delta */
 static void __tux3_clear_dirty_inode(struct inode *inode, unsigned delta)
 {
     struct tux3_inode *tuxnode = tux_inode(inode);
-    tux3_inode_wb_lock(inode);
     spin_lock(&inode->i_lock);
     spin_lock(&tuxnode->lock);
     tux3_clear_dirty_inode_nolock(inode, delta, 0);
     spin_unlock(&tuxnode->lock);
     spin_unlock(&inode->i_lock);
-    tux3_inode_wb_unlock(inode);
+    inode_writeback_done(inode);
 }

 /*
@@ -315,14 +269,13 @@ static void __tux3_clear_dirty_inode(struct inode *inode, unsigned delta)
 void tux3_clear_dirty_inode(struct inode *inode)
 {
     struct tux3_inode *tuxnode = tux_inode(inode);
-    tux3_inode_wb_lock(inode);
     spin_lock(&inode->i_lock);
     spin_lock(&tuxnode->lock);
     tux3_iattr_clear_dirty(tuxnode);
     tux3_clear_dirty_inode_nolock(inode, tux3_inode_delta(inode), 1);
     spin_unlock(&tuxnode->lock);
     spin_unlock(&inode->i_lock);
-    tux3_inode_wb_unlock(inode);
+    inode_writeback_done(inode);
 }

 void __tux3_mark_inode_dirty(struct inode *inode, int flags)



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




[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]
  Powered by Linux