spin_unlock_bh(&bdi->wb_lock);
 }
 
+/*
+ * Remove the inode from the writeback list it is on.
+ */
+void inode_wb_list_del(struct inode *inode)
+{
+       spin_lock(&inode_wb_list_lock);
+       list_del_init(&inode->i_wb_list);
+       spin_unlock(&inode_wb_list_lock);
+}
+
+
 /*
  * Redirty an inode: set its when-it-was dirtied timestamp and move it to the
  * furthest end of its superblock's dirty-inode list.
 {
        struct bdi_writeback *wb = &inode_to_bdi(inode)->wb;
 
+       assert_spin_locked(&inode_wb_list_lock);
        if (!list_empty(&wb->b_dirty)) {
                struct inode *tail;
 
 {
        struct bdi_writeback *wb = &inode_to_bdi(inode)->wb;
 
+       assert_spin_locked(&inode_wb_list_lock);
        list_move(&inode->i_wb_list, &wb->b_more_io);
 }
 
 static void inode_sync_complete(struct inode *inode)
 {
        /*
-        * Prevent speculative execution through spin_unlock(&inode_lock);
+        * Prevent speculative execution through
+        * spin_unlock(&inode_wb_list_lock);
         */
+
        smp_mb();
        wake_up_bit(&inode->i_state, __I_SYNC);
 }
  */
 static void queue_io(struct bdi_writeback *wb, unsigned long *older_than_this)
 {
+       assert_spin_locked(&inode_wb_list_lock);
        list_splice_init(&wb->b_more_io, &wb->b_io);
        move_expired_inodes(&wb->b_dirty, &wb->b_io, older_than_this);
 }
        wqh = bit_waitqueue(&inode->i_state, __I_SYNC);
        while (inode->i_state & I_SYNC) {
                spin_unlock(&inode->i_lock);
-               spin_unlock(&inode_lock);
+               spin_unlock(&inode_wb_list_lock);
                __wait_on_bit(wqh, &wq, inode_wait, TASK_UNINTERRUPTIBLE);
-               spin_lock(&inode_lock);
+               spin_lock(&inode_wb_list_lock);
                spin_lock(&inode->i_lock);
        }
 }
 
 /*
- * Write out an inode's dirty pages.  Called under inode_lock.  Either the
- * caller has ref on the inode (either via __iget or via syscall against an fd)
- * or the inode has I_WILL_FREE set (via generic_forget_inode)
+ * Write out an inode's dirty pages.  Called under inode_wb_list_lock.  Either
+ * the caller has an active reference on the inode or the inode has I_WILL_FREE
+ * set.
  *
  * If `wait' is set, wait on the writeout.
  *
  * The whole writeout design is quite complex and fragile.  We want to avoid
  * starvation of particular inodes when others are being redirtied, prevent
  * livelocks, etc.
- *
- * Called under inode_lock.
  */
 static int
 writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
        inode->i_state |= I_SYNC;
        inode->i_state &= ~I_DIRTY_PAGES;
        spin_unlock(&inode->i_lock);
-       spin_unlock(&inode_lock);
+       spin_unlock(&inode_wb_list_lock);
 
        ret = do_writepages(mapping, wbc);
 
         * due to delalloc, clear dirty metadata flags right before
         * write_inode()
         */
-       spin_lock(&inode_lock);
        spin_lock(&inode->i_lock);
        dirty = inode->i_state & I_DIRTY;
        inode->i_state &= ~(I_DIRTY_SYNC | I_DIRTY_DATASYNC);
        spin_unlock(&inode->i_lock);
-       spin_unlock(&inode_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);
                        ret = err;
        }
 
-       spin_lock(&inode_lock);
+       spin_lock(&inode_wb_list_lock);
        spin_lock(&inode->i_lock);
        inode->i_state &= ~I_SYNC;
        if (!(inode->i_state & I_FREEING)) {
                         */
                        redirty_tail(inode);
                }
-               spin_unlock(&inode_lock);
+               spin_unlock(&inode_wb_list_lock);
                iput(inode);
                cond_resched();
-               spin_lock(&inode_lock);
+               spin_lock(&inode_wb_list_lock);
                if (wbc->nr_to_write <= 0) {
                        wbc->more_io = 1;
                        return 1;
 
        if (!wbc->wb_start)
                wbc->wb_start = jiffies; /* livelock avoidance */
-       spin_lock(&inode_lock);
+       spin_lock(&inode_wb_list_lock);
        if (!wbc->for_kupdate || list_empty(&wb->b_io))
                queue_io(wb, wbc->older_than_this);
 
                if (ret)
                        break;
        }
-       spin_unlock(&inode_lock);
+       spin_unlock(&inode_wb_list_lock);
        /* Leave any unwritten inodes on b_io */
 }
 
 {
        WARN_ON(!rwsem_is_locked(&sb->s_umount));
 
-       spin_lock(&inode_lock);
+       spin_lock(&inode_wb_list_lock);
        if (!wbc->for_kupdate || list_empty(&wb->b_io))
                queue_io(wb, wbc->older_than_this);
        writeback_sb_inodes(sb, wb, wbc, true);
-       spin_unlock(&inode_lock);
+       spin_unlock(&inode_wb_list_lock);
 }
 
 /*
                 * become available for writeback. Otherwise
                 * we'll just busyloop.
                 */
-               spin_lock(&inode_lock);
+               spin_lock(&inode_wb_list_lock);
                if (!list_empty(&wb->b_more_io))  {
                        inode = wb_inode(wb->b_more_io.prev);
                        trace_wbc_writeback_wait(&wbc, wb->bdi);
                        inode_wait_for_writeback(inode);
                        spin_unlock(&inode->i_lock);
                }
-               spin_unlock(&inode_lock);
+               spin_unlock(&inode_wb_list_lock);
        }
 
        return wrote;
 {
        struct super_block *sb = inode->i_sb;
        struct backing_dev_info *bdi = NULL;
-       bool wakeup_bdi = false;
 
        /*
         * Don't do this for I_DIRTY_PAGES - that doesn't actually
        if (unlikely(block_dump))
                block_dump___mark_inode_dirty(inode);
 
-       spin_lock(&inode_lock);
        spin_lock(&inode->i_lock);
        if ((inode->i_state & flags) != flags) {
                const int was_dirty = inode->i_state & I_DIRTY;
                if (inode->i_state & I_FREEING)
                        goto out_unlock_inode;
 
-               spin_unlock(&inode->i_lock);
                /*
                 * If the inode was already on b_dirty/b_io/b_more_io, don't
                 * reposition it (that would break b_dirty time-ordering).
                 */
                if (!was_dirty) {
+                       bool wakeup_bdi = false;
                        bdi = inode_to_bdi(inode);
 
                        if (bdi_cap_writeback_dirty(bdi)) {
                                        wakeup_bdi = true;
                        }
 
+                       spin_unlock(&inode->i_lock);
+                       spin_lock(&inode_wb_list_lock);
                        inode->dirtied_when = jiffies;
                        list_move(&inode->i_wb_list, &bdi->wb.b_dirty);
+                       spin_unlock(&inode_wb_list_lock);
+
+                       if (wakeup_bdi)
+                               bdi_wakeup_thread_delayed(bdi);
+                       return;
                }
-               goto out;
        }
 out_unlock_inode:
        spin_unlock(&inode->i_lock);
-out:
-       spin_unlock(&inode_lock);
 
-       if (wakeup_bdi)
-               bdi_wakeup_thread_delayed(bdi);
 }
 EXPORT_SYMBOL(__mark_inode_dirty);
 
                wbc.nr_to_write = 0;
 
        might_sleep();
-       spin_lock(&inode_lock);
+       spin_lock(&inode_wb_list_lock);
        ret = writeback_single_inode(inode, &wbc);
-       spin_unlock(&inode_lock);
+       spin_unlock(&inode_wb_list_lock);
        if (sync)
                inode_sync_wait(inode);
        return ret;
 {
        int ret;
 
-       spin_lock(&inode_lock);
+       spin_lock(&inode_wb_list_lock);
        ret = writeback_single_inode(inode, wbc);
-       spin_unlock(&inode_lock);
+       spin_unlock(&inode_wb_list_lock);
        return ret;
 }
 EXPORT_SYMBOL(sync_inode);