CIFS: Fix SMB2+ interim response processing for read requests
[firefly-linux-kernel-4.4.55.git] / fs / fs-writeback.c
index 29e4599f6fc1c20b73acb2c580ce8383e169c5f2..e5232bbcbe3d40ec585c25351de34935671e8667 100644 (file)
@@ -317,6 +317,7 @@ static void inode_switch_wbs_work_fn(struct work_struct *work)
        struct inode_switch_wbs_context *isw =
                container_of(work, struct inode_switch_wbs_context, work);
        struct inode *inode = isw->inode;
+       struct super_block *sb = inode->i_sb;
        struct address_space *mapping = inode->i_mapping;
        struct bdi_writeback *old_wb = inode->i_wb;
        struct bdi_writeback *new_wb = isw->new_wb;
@@ -423,6 +424,7 @@ skip_switch:
        wb_put(new_wb);
 
        iput(inode);
+       deactivate_super(sb);
        kfree(isw);
 }
 
@@ -469,11 +471,14 @@ static void inode_switch_wbs(struct inode *inode, int new_wb_id)
 
        /* while holding I_WB_SWITCH, no one else can update the association */
        spin_lock(&inode->i_lock);
+
        if (inode->i_state & (I_WB_SWITCH | I_FREEING) ||
-           inode_to_wb(inode) == isw->new_wb) {
-               spin_unlock(&inode->i_lock);
-               goto out_free;
-       }
+           inode_to_wb(inode) == isw->new_wb)
+               goto out_unlock;
+
+       if (!atomic_inc_not_zero(&inode->i_sb->s_active))
+               goto out_unlock;
+
        inode->i_state |= I_WB_SWITCH;
        spin_unlock(&inode->i_lock);
 
@@ -489,6 +494,8 @@ static void inode_switch_wbs(struct inode *inode, int new_wb_id)
        call_rcu(&isw->rcu_head, inode_switch_wbs_rcu_fn);
        return;
 
+out_unlock:
+       spin_unlock(&inode->i_lock);
 out_free:
        if (isw->new_wb)
                wb_put(isw->new_wb);
@@ -779,8 +786,8 @@ static void bdi_split_work_to_wbs(struct backing_dev_info *bdi,
                                  bool skip_if_busy)
 {
        struct bdi_writeback *last_wb = NULL;
-       struct bdi_writeback *wb = list_entry_rcu(&bdi->wb_list,
-                                               struct bdi_writeback, bdi_node);
+       struct bdi_writeback *wb = list_entry(&bdi->wb_list,
+                                             struct bdi_writeback, bdi_node);
 
        might_sleep();
 restart:
@@ -1981,9 +1988,9 @@ static noinline void block_dump___mark_inode_dirty(struct inode *inode)
  * page->mapping->host, so the page-dirtying time is recorded in the internal
  * blockdev inode.
  */
-#define I_DIRTY_INODE (I_DIRTY_SYNC | I_DIRTY_DATASYNC)
 void __mark_inode_dirty(struct inode *inode, int flags)
 {
+#define I_DIRTY_INODE (I_DIRTY_SYNC | I_DIRTY_DATASYNC)
        struct super_block *sb = inode->i_sb;
        int dirtytime;
 
@@ -2093,6 +2100,7 @@ void __mark_inode_dirty(struct inode *inode, int flags)
 out_unlock_inode:
        spin_unlock(&inode->i_lock);
 
+#undef I_DIRTY_INODE
 }
 EXPORT_SYMBOL(__mark_inode_dirty);
 
@@ -2149,7 +2157,12 @@ static void wait_sb_inodes(struct super_block *sb)
                iput(old_inode);
                old_inode = inode;
 
-               filemap_fdatawait(mapping);
+               /*
+                * We keep the error status of individual mapping so that
+                * applications can catch the writeback error using fsync(2).
+                * See filemap_fdatawait_keep_errors() for details.
+                */
+               filemap_fdatawait_keep_errors(mapping);
 
                cond_resched();