drivers: power: report battery voltage in AOSP compatible format
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / fs / fs-writeback.c
index 3be57189efd5b3a8005321f02e40971af9429cf6..62d426d1d5e3495c5fe7d21d2349d75d73e7ccf2 100644 (file)
@@ -87,16 +87,29 @@ static inline struct inode *wb_inode(struct list_head *head)
 #define CREATE_TRACE_POINTS
 #include <trace/events/writeback.h>
 
+static void bdi_wakeup_thread(struct backing_dev_info *bdi)
+{
+       spin_lock_bh(&bdi->wb_lock);
+       if (test_bit(BDI_registered, &bdi->state))
+               mod_delayed_work(bdi_wq, &bdi->wb.dwork, 0);
+       spin_unlock_bh(&bdi->wb_lock);
+}
+
 static void bdi_queue_work(struct backing_dev_info *bdi,
                           struct wb_writeback_work *work)
 {
        trace_writeback_queue(bdi, work);
 
        spin_lock_bh(&bdi->wb_lock);
+       if (!test_bit(BDI_registered, &bdi->state)) {
+               if (work->done)
+                       complete(work->done);
+               goto out_unlock;
+       }
        list_add_tail(&work->list, &bdi->work_list);
-       spin_unlock_bh(&bdi->wb_lock);
-
        mod_delayed_work(bdi_wq, &bdi->wb.dwork, 0);
+out_unlock:
+       spin_unlock_bh(&bdi->wb_lock);
 }
 
 static void
@@ -112,7 +125,7 @@ __bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages,
        work = kzalloc(sizeof(*work), GFP_ATOMIC);
        if (!work) {
                trace_writeback_nowork(bdi);
-               mod_delayed_work(bdi_wq, &bdi->wb.dwork, 0);
+               bdi_wakeup_thread(bdi);
                return;
        }
 
@@ -159,7 +172,7 @@ void bdi_start_background_writeback(struct backing_dev_info *bdi)
         * writeback as soon as there is no other work to do.
         */
        trace_writeback_wake_background(bdi);
-       mod_delayed_work(bdi_wq, &bdi->wb.dwork, 0);
+       bdi_wakeup_thread(bdi);
 }
 
 /*
@@ -457,12 +470,28 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
         * write_inode()
         */
        spin_lock(&inode->i_lock);
-       /* Clear I_DIRTY_PAGES if we've written out all dirty pages */
-       if (!mapping_tagged(mapping, PAGECACHE_TAG_DIRTY))
-               inode->i_state &= ~I_DIRTY_PAGES;
+
        dirty = inode->i_state & I_DIRTY;
-       inode->i_state &= ~(I_DIRTY_SYNC | I_DIRTY_DATASYNC);
+       inode->i_state &= ~I_DIRTY;
+
+       /*
+        * Paired with smp_mb() in __mark_inode_dirty().  This allows
+        * __mark_inode_dirty() to test i_state without grabbing i_lock -
+        * either they see the I_DIRTY bits cleared or we see the dirtied
+        * inode.
+        *
+        * I_DIRTY_PAGES is always cleared together above even if @mapping
+        * still has dirty pages.  The flag is reinstated after smp_mb() if
+        * necessary.  This guarantees that either __mark_inode_dirty()
+        * sees clear I_DIRTY_PAGES or we see PAGECACHE_TAG_DIRTY.
+        */
+       smp_mb();
+
+       if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY))
+               inode->i_state |= I_DIRTY_PAGES;
+
        spin_unlock(&inode->i_lock);
+
        /* Don't write the inode if only I_DIRTY_PAGES was set */
        if (dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) {
                int err = write_inode(inode, wbc);
@@ -505,13 +534,16 @@ writeback_single_inode(struct inode *inode, struct bdi_writeback *wb,
        }
        WARN_ON(inode->i_state & I_SYNC);
        /*
-        * Skip inode if it is clean. We don't want to mess with writeback
-        * lists in this function since flusher thread may be doing for example
-        * sync in parallel and if we move the inode, it could get skipped. So
-        * here we make sure inode is on some writeback list and leave it there
-        * unless we have completely cleaned the inode.
+        * Skip inode if it is clean and we have no outstanding writeback in
+        * WB_SYNC_ALL mode. We don't want to mess with writeback lists in this
+        * function since flusher thread may be doing for example sync in
+        * parallel and if we move the inode, it could get skipped. So here we
+        * make sure inode is on some writeback list and leave it there unless
+        * we have completely cleaned the inode.
         */
-       if (!(inode->i_state & I_DIRTY))
+       if (!(inode->i_state & I_DIRTY) &&
+           (wbc->sync_mode != WB_SYNC_ALL ||
+            !mapping_tagged(inode->i_mapping, PAGECACHE_TAG_WRITEBACK)))
                goto out;
        inode->i_state |= I_SYNC;
        spin_unlock(&inode->i_lock);
@@ -1013,7 +1045,7 @@ void bdi_writeback_workfn(struct work_struct *work)
        current->flags |= PF_SWAPWRITE;
 
        if (likely(!current_is_workqueue_rescuer() ||
-                  list_empty(&bdi->bdi_list))) {
+                  !test_bit(BDI_registered, &bdi->state))) {
                /*
                 * The normal path.  Keep writing back @bdi until its
                 * work_list is empty.  Note that this path is also taken
@@ -1035,10 +1067,10 @@ void bdi_writeback_workfn(struct work_struct *work)
                trace_writeback_pages_written(pages_written);
        }
 
-       if (!list_empty(&bdi->work_list) ||
-           (wb_has_dirty_io(wb) && dirty_writeback_interval))
-               queue_delayed_work(bdi_wq, &wb->dwork,
-                       msecs_to_jiffies(dirty_writeback_interval * 10));
+       if (!list_empty(&bdi->work_list))
+               mod_delayed_work(bdi_wq, &wb->dwork, 0);
+       else if (wb_has_dirty_io(wb) && dirty_writeback_interval)
+               bdi_wakeup_thread_delayed(bdi);
 
        current->flags &= ~PF_SWAPWRITE;
 }
@@ -1130,16 +1162,15 @@ void __mark_inode_dirty(struct inode *inode, int flags)
        }
 
        /*
-        * make sure that changes are seen by all cpus before we test i_state
-        * -- mikulas
+        * Paired with smp_mb() in __writeback_single_inode() for the
+        * following lockless i_state test.  See there for details.
         */
        smp_mb();
 
-       /* avoid the locking if we can */
        if ((inode->i_state & flags) == flags)
                return;
 
-       if (unlikely(block_dump))
+       if (unlikely(block_dump > 1))
                block_dump___mark_inode_dirty(inode);
 
        spin_lock(&inode->i_lock);