rocker: fix non-portable err return codes
[cascardo/linux.git] / mm / backing-dev.c
index 0ae0df5..6dc4580 100644 (file)
 
 static atomic_long_t bdi_seq = ATOMIC_LONG_INIT(0);
 
-struct backing_dev_info default_backing_dev_info = {
-       .name           = "default",
-       .ra_pages       = VM_MAX_READAHEAD * 1024 / PAGE_CACHE_SIZE,
-       .state          = 0,
-       .capabilities   = BDI_CAP_MAP_COPY,
-};
-EXPORT_SYMBOL_GPL(default_backing_dev_info);
-
 struct backing_dev_info noop_backing_dev_info = {
        .name           = "noop",
        .capabilities   = BDI_CAP_NO_ACCT_AND_WRITEBACK,
 };
-EXPORT_SYMBOL_GPL(noop_backing_dev_info);
 
 static struct class *bdi_class;
 
@@ -40,17 +31,6 @@ LIST_HEAD(bdi_list);
 /* bdi_wq serves all asynchronous writeback tasks */
 struct workqueue_struct *bdi_wq;
 
-static void bdi_lock_two(struct bdi_writeback *wb1, struct bdi_writeback *wb2)
-{
-       if (wb1 < wb2) {
-               spin_lock(&wb1->list_lock);
-               spin_lock_nested(&wb2->list_lock, 1);
-       } else {
-               spin_lock(&wb2->list_lock);
-               spin_lock_nested(&wb1->list_lock, 1);
-       }
-}
-
 #ifdef CONFIG_DEBUG_FS
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
@@ -69,10 +49,10 @@ static int bdi_debug_stats_show(struct seq_file *m, void *v)
        unsigned long background_thresh;
        unsigned long dirty_thresh;
        unsigned long bdi_thresh;
-       unsigned long nr_dirty, nr_io, nr_more_io;
+       unsigned long nr_dirty, nr_io, nr_more_io, nr_dirty_time;
        struct inode *inode;
 
-       nr_dirty = nr_io = nr_more_io = 0;
+       nr_dirty = nr_io = nr_more_io = nr_dirty_time = 0;
        spin_lock(&wb->list_lock);
        list_for_each_entry(inode, &wb->b_dirty, i_wb_list)
                nr_dirty++;
@@ -80,6 +60,9 @@ static int bdi_debug_stats_show(struct seq_file *m, void *v)
                nr_io++;
        list_for_each_entry(inode, &wb->b_more_io, i_wb_list)
                nr_more_io++;
+       list_for_each_entry(inode, &wb->b_dirty_time, i_wb_list)
+               if (inode->i_state & I_DIRTY_TIME)
+                       nr_dirty_time++;
        spin_unlock(&wb->list_lock);
 
        global_dirty_limits(&background_thresh, &dirty_thresh);
@@ -98,6 +81,7 @@ static int bdi_debug_stats_show(struct seq_file *m, void *v)
                   "b_dirty:            %10lu\n"
                   "b_io:               %10lu\n"
                   "b_more_io:          %10lu\n"
+                  "b_dirty_time:       %10lu\n"
                   "bdi_list:           %10u\n"
                   "state:              %10lx\n",
                   (unsigned long) K(bdi_stat(bdi, BDI_WRITEBACK)),
@@ -111,6 +95,7 @@ static int bdi_debug_stats_show(struct seq_file *m, void *v)
                   nr_dirty,
                   nr_io,
                   nr_more_io,
+                  nr_dirty_time,
                   !list_empty(&bdi->bdi_list), bdi->state);
 #undef K
 
@@ -264,9 +249,6 @@ static int __init default_bdi_init(void)
        if (!bdi_wq)
                return -ENOMEM;
 
-       err = bdi_init(&default_backing_dev_info);
-       if (!err)
-               bdi_register(&default_backing_dev_info, NULL, "default");
        err = bdi_init(&noop_backing_dev_info);
 
        return err;
@@ -355,19 +337,19 @@ EXPORT_SYMBOL(bdi_register_dev);
  */
 static void bdi_wb_shutdown(struct backing_dev_info *bdi)
 {
-       if (!bdi_cap_writeback_dirty(bdi))
+       /* Make sure nobody queues further work */
+       spin_lock_bh(&bdi->wb_lock);
+       if (!test_and_clear_bit(BDI_registered, &bdi->state)) {
+               spin_unlock_bh(&bdi->wb_lock);
                return;
+       }
+       spin_unlock_bh(&bdi->wb_lock);
 
        /*
         * Make sure nobody finds us on the bdi_list anymore
         */
        bdi_remove_from_list(bdi);
 
-       /* Make sure nobody queues further work */
-       spin_lock_bh(&bdi->wb_lock);
-       clear_bit(BDI_registered, &bdi->state);
-       spin_unlock_bh(&bdi->wb_lock);
-
        /*
         * Drain work list and shutdown the delayed_work.  At this point,
         * @bdi->bdi_list is empty telling bdi_Writeback_workfn() that @bdi
@@ -375,37 +357,22 @@ static void bdi_wb_shutdown(struct backing_dev_info *bdi)
         */
        mod_delayed_work(bdi_wq, &bdi->wb.dwork, 0);
        flush_delayed_work(&bdi->wb.dwork);
-       WARN_ON(!list_empty(&bdi->work_list));
-       WARN_ON(delayed_work_pending(&bdi->wb.dwork));
 }
 
 /*
- * This bdi is going away now, make sure that no super_blocks point to it
+ * Called when the device behind @bdi has been removed or ejected.
+ *
+ * We can't really do much here except for reducing the dirty ratio at
+ * the moment.  In the future we should be able to set a flag so that
+ * the filesystem can handle errors at mark_inode_dirty time instead
+ * of only at writeback time.
  */
-static void bdi_prune_sb(struct backing_dev_info *bdi)
-{
-       struct super_block *sb;
-
-       spin_lock(&sb_lock);
-       list_for_each_entry(sb, &super_blocks, s_list) {
-               if (sb->s_bdi == bdi)
-                       sb->s_bdi = &default_backing_dev_info;
-       }
-       spin_unlock(&sb_lock);
-}
-
 void bdi_unregister(struct backing_dev_info *bdi)
 {
-       if (bdi->dev) {
-               bdi_set_min_ratio(bdi, 0);
-               trace_writeback_bdi_unregister(bdi);
-               bdi_prune_sb(bdi);
+       if (WARN_ON_ONCE(!bdi->dev))
+               return;
 
-               bdi_wb_shutdown(bdi);
-               bdi_debug_unregister(bdi);
-               device_unregister(bdi->dev);
-               bdi->dev = NULL;
-       }
+       bdi_set_min_ratio(bdi, 0);
 }
 EXPORT_SYMBOL(bdi_unregister);
 
@@ -418,6 +385,7 @@ static void bdi_wb_init(struct bdi_writeback *wb, struct backing_dev_info *bdi)
        INIT_LIST_HEAD(&wb->b_dirty);
        INIT_LIST_HEAD(&wb->b_io);
        INIT_LIST_HEAD(&wb->b_more_io);
+       INIT_LIST_HEAD(&wb->b_dirty_time);
        spin_lock_init(&wb->list_lock);
        INIT_DELAYED_WORK(&wb->dwork, bdi_writeback_workfn);
 }
@@ -474,37 +442,19 @@ void bdi_destroy(struct backing_dev_info *bdi)
 {
        int i;
 
-       /*
-        * Splice our entries to the default_backing_dev_info.  This
-        * condition shouldn't happen.  @wb must be empty at this point and
-        * dirty inodes on it might cause other issues.  This workaround is
-        * added by ce5f8e779519 ("writeback: splice dirty inode entries to
-        * default bdi on bdi_destroy()") without root-causing the issue.
-        *
-        * http://lkml.kernel.org/g/1253038617-30204-11-git-send-email-jens.axboe@oracle.com
-        * http://thread.gmane.org/gmane.linux.file-systems/35341/focus=35350
-        *
-        * We should probably add WARN_ON() to find out whether it still
-        * happens and track it down if so.
-        */
-       if (bdi_has_dirty_io(bdi)) {
-               struct bdi_writeback *dst = &default_backing_dev_info.wb;
-
-               bdi_lock_two(&bdi->wb, dst);
-               list_splice(&bdi->wb.b_dirty, &dst->b_dirty);
-               list_splice(&bdi->wb.b_io, &dst->b_io);
-               list_splice(&bdi->wb.b_more_io, &dst->b_more_io);
-               spin_unlock(&bdi->wb.list_lock);
-               spin_unlock(&dst->list_lock);
-       }
-
-       bdi_unregister(bdi);
+       bdi_wb_shutdown(bdi);
 
+       WARN_ON(!list_empty(&bdi->work_list));
        WARN_ON(delayed_work_pending(&bdi->wb.dwork));
 
+       if (bdi->dev) {
+               bdi_debug_unregister(bdi);
+               device_unregister(bdi->dev);
+               bdi->dev = NULL;
+       }
+
        for (i = 0; i < NR_BDI_STAT_ITEMS; i++)
                percpu_counter_destroy(&bdi->bdi_stat[i]);
-
        fprop_local_destroy_percpu(&bdi->completions);
 }
 EXPORT_SYMBOL(bdi_destroy);
@@ -513,13 +463,12 @@ EXPORT_SYMBOL(bdi_destroy);
  * For use from filesystems to quickly init and register a bdi associated
  * with dirty writeback
  */
-int bdi_setup_and_register(struct backing_dev_info *bdi, char *name,
-                          unsigned int cap)
+int bdi_setup_and_register(struct backing_dev_info *bdi, char *name)
 {
        int err;
 
        bdi->name = name;
-       bdi->capabilities = cap;
+       bdi->capabilities = 0;
        err = bdi_init(bdi);
        if (err)
                return err;