]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - fs/ext4/inode.c
ext4: add shutdown bit and check for it
[mirror_ubuntu-artful-kernel.git] / fs / ext4 / inode.c
index 88d57af1b516c5bbfd7b2f1bc471a9d76382c3bc..bc282f9d0969355b865c20c1488776029bb20111 100644 (file)
@@ -1189,6 +1189,9 @@ static int ext4_write_begin(struct file *file, struct address_space *mapping,
        pgoff_t index;
        unsigned from, to;
 
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
+               return -EIO;
+
        trace_ext4_write_begin(inode, pos, len, flags);
        /*
         * Reserve one block more for addition to orphan list in case
@@ -1330,8 +1333,11 @@ static int ext4_write_end(struct file *file,
        if (ext4_has_inline_data(inode)) {
                ret = ext4_write_inline_data_end(inode, pos, len,
                                                 copied, page);
-               if (ret < 0)
+               if (ret < 0) {
+                       unlock_page(page);
+                       put_page(page);
                        goto errout;
+               }
                copied = ret;
        } else
                copied = block_write_end(file, mapping, pos,
@@ -1385,7 +1391,9 @@ errout:
  * set the buffer to be dirty, since in data=journalled mode we need
  * to call ext4_handle_dirty_metadata() instead.
  */
-static void zero_new_buffers(struct page *page, unsigned from, unsigned to)
+static void ext4_journalled_zero_new_buffers(handle_t *handle,
+                                           struct page *page,
+                                           unsigned from, unsigned to)
 {
        unsigned int block_start = 0, block_end;
        struct buffer_head *head, *bh;
@@ -1402,7 +1410,7 @@ static void zero_new_buffers(struct page *page, unsigned from, unsigned to)
                                        size = min(to, block_end) - start;
 
                                        zero_user(page, start, size);
-                                       set_buffer_uptodate(bh);
+                                       write_end_fn(handle, bh);
                                }
                                clear_buffer_new(bh);
                        }
@@ -1431,18 +1439,25 @@ static int ext4_journalled_write_end(struct file *file,
 
        BUG_ON(!ext4_handle_valid(handle));
 
-       if (ext4_has_inline_data(inode))
-               copied = ext4_write_inline_data_end(inode, pos, len,
-                                                   copied, page);
-       else {
-               if (copied < len) {
-                       if (!PageUptodate(page))
-                               copied = 0;
-                       zero_new_buffers(page, from+copied, to);
+       if (ext4_has_inline_data(inode)) {
+               ret = ext4_write_inline_data_end(inode, pos, len,
+                                                copied, page);
+               if (ret < 0) {
+                       unlock_page(page);
+                       put_page(page);
+                       goto errout;
                }
-
+               copied = ret;
+       } else if (unlikely(copied < len) && !PageUptodate(page)) {
+               copied = 0;
+               ext4_journalled_zero_new_buffers(handle, page, from, to);
+       } else {
+               if (unlikely(copied < len))
+                       ext4_journalled_zero_new_buffers(handle, page,
+                                                        from + copied, to);
                ret = ext4_walk_page_buffers(handle, page_buffers(page), from,
-                                            to, &partial, write_end_fn);
+                                            from + copied, &partial,
+                                            write_end_fn);
                if (!partial)
                        SetPageUptodate(page);
        }
@@ -1468,6 +1483,7 @@ static int ext4_journalled_write_end(struct file *file,
                 */
                ext4_orphan_add(handle, inode);
 
+errout:
        ret2 = ext4_journal_stop(handle);
        if (!ret)
                ret = ret2;
@@ -2034,6 +2050,12 @@ static int ext4_writepage(struct page *page,
        struct ext4_io_submit io_submit;
        bool keep_towrite = false;
 
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb)))) {
+               ext4_invalidatepage(page, 0, PAGE_SIZE);
+               unlock_page(page);
+               return -EIO;
+       }
+
        trace_ext4_writepage(page);
        size = i_size_read(inode);
        if (page->index == size >> PAGE_SHIFT)
@@ -2409,7 +2431,8 @@ static int mpage_map_and_submit_extent(handle_t *handle,
                if (err < 0) {
                        struct super_block *sb = inode->i_sb;
 
-                       if (EXT4_SB(sb)->s_mount_flags & EXT4_MF_FS_ABORTED)
+                       if (ext4_forced_shutdown(EXT4_SB(sb)) ||
+                           EXT4_SB(sb)->s_mount_flags & EXT4_MF_FS_ABORTED)
                                goto invalidate_dirty_pages;
                        /*
                         * Let the uper layers retry transient errors.
@@ -2464,8 +2487,8 @@ update_disksize:
                        disksize = i_size;
                if (disksize > EXT4_I(inode)->i_disksize)
                        EXT4_I(inode)->i_disksize = disksize;
-               err2 = ext4_mark_inode_dirty(handle, inode);
                up_write(&EXT4_I(inode)->i_data_sem);
+               err2 = ext4_mark_inode_dirty(handle, inode);
                if (err2)
                        ext4_error(inode->i_sb,
                                   "Failed to mark inode %lu dirty",
@@ -2631,6 +2654,9 @@ static int ext4_writepages(struct address_space *mapping,
        struct blk_plug plug;
        bool give_up_on_write = false;
 
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
+               return -EIO;
+
        percpu_down_read(&sbi->s_journal_flag_rwsem);
        trace_ext4_writepages(inode, wbc);
 
@@ -2667,7 +2693,8 @@ static int ext4_writepages(struct address_space *mapping,
         * *never* be called, so if that ever happens, we would want
         * the stack trace.
         */
-       if (unlikely(sbi->s_mount_flags & EXT4_MF_FS_ABORTED)) {
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(mapping->host->i_sb)) ||
+                    sbi->s_mount_flags & EXT4_MF_FS_ABORTED)) {
                ret = -EROFS;
                goto out_writepages;
        }
@@ -2892,6 +2919,9 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping,
        struct inode *inode = mapping->host;
        handle_t *handle;
 
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
+               return -EIO;
+
        index = pos >> PAGE_SHIFT;
 
        if (ext4_nonda_switch(inode->i_sb) ||
@@ -4222,7 +4252,9 @@ int ext4_truncate(struct inode *inode)
        if (ext4_has_inline_data(inode)) {
                int has_inline = 1;
 
-               ext4_inline_data_truncate(inode, &has_inline);
+               err = ext4_inline_data_truncate(inode, &has_inline);
+               if (err)
+                       return err;
                if (has_inline)
                        return 0;
        }
@@ -5197,6 +5229,9 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
        int orphan = 0;
        const unsigned int ia_valid = attr->ia_valid;
 
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
+               return -EIO;
+
        error = setattr_prepare(dentry, attr);
        if (error)
                return error;
@@ -5483,6 +5518,9 @@ int ext4_mark_iloc_dirty(handle_t *handle,
 {
        int err = 0;
 
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
+               return -EIO;
+
        if (IS_I_VERSION(inode))
                inode_inc_iversion(inode);
 
@@ -5506,6 +5544,9 @@ ext4_reserve_inode_write(handle_t *handle, struct inode *inode,
 {
        int err;
 
+       if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
+               return -EIO;
+
        err = ext4_get_inode_loc(inode, iloc);
        if (!err) {
                BUFFER_TRACE(iloc->bh, "get_write_access");