Merge tag 'dax-fixes-5.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm...
[platform/kernel/linux-rpi.git] / fs / ext4 / inode.c
index 9992af7..1305b81 100644 (file)
@@ -48,8 +48,6 @@
 
 #include <trace/events/ext4.h>
 
-#define MPAGE_DA_EXTENT_TAIL 0x01
-
 static __u32 ext4_inode_csum(struct inode *inode, struct ext4_inode *raw,
                              struct ext4_inode_info *ei)
 {
@@ -271,6 +269,7 @@ void ext4_evict_inode(struct inode *inode)
        if (inode->i_blocks) {
                err = ext4_truncate(inode);
                if (err) {
+                       ext4_set_errno(inode->i_sb, -err);
                        ext4_error(inode->i_sb,
                                   "couldn't truncate inode %lu (err %d)",
                                   inode->i_ino, err);
@@ -402,7 +401,7 @@ int ext4_issue_zeroout(struct inode *inode, ext4_lblk_t lblk, ext4_fsblk_t pblk,
 {
        int ret;
 
-       if (IS_ENCRYPTED(inode))
+       if (IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode))
                return fscrypt_zeroout_range(inode, lblk, pblk, len);
 
        ret = sb_issue_zeroout(inode->i_sb, pblk, len, GFP_NOFS);
@@ -2478,10 +2477,12 @@ update_disksize:
                        EXT4_I(inode)->i_disksize = disksize;
                up_write(&EXT4_I(inode)->i_data_sem);
                err2 = ext4_mark_inode_dirty(handle, inode);
-               if (err2)
+               if (err2) {
+                       ext4_set_errno(inode->i_sb, -err2);
                        ext4_error(inode->i_sb,
                                   "Failed to mark inode %lu dirty",
                                   inode->i_ino);
+               }
                if (!err)
                        err = err2;
        }
@@ -3448,6 +3449,22 @@ static int ext4_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
        return 0;
 }
 
+static int ext4_iomap_overwrite_begin(struct inode *inode, loff_t offset,
+               loff_t length, unsigned flags, struct iomap *iomap,
+               struct iomap *srcmap)
+{
+       int ret;
+
+       /*
+        * Even for writes we don't need to allocate blocks, so just pretend
+        * we are reading to save overhead of starting a transaction.
+        */
+       flags &= ~IOMAP_WRITE;
+       ret = ext4_iomap_begin(inode, offset, length, flags, iomap, srcmap);
+       WARN_ON_ONCE(iomap->type != IOMAP_MAPPED);
+       return ret;
+}
+
 static int ext4_iomap_end(struct inode *inode, loff_t offset, loff_t length,
                          ssize_t written, unsigned flags, struct iomap *iomap)
 {
@@ -3469,6 +3486,11 @@ const struct iomap_ops ext4_iomap_ops = {
        .iomap_end              = ext4_iomap_end,
 };
 
+const struct iomap_ops ext4_iomap_overwrite_ops = {
+       .iomap_begin            = ext4_iomap_overwrite_begin,
+       .iomap_end              = ext4_iomap_end,
+};
+
 static bool ext4_iomap_is_delalloc(struct inode *inode,
                                   struct ext4_map_blocks *map)
 {
@@ -3701,8 +3723,12 @@ static int __ext4_block_zero_page_range(handle_t *handle,
                if (S_ISREG(inode->i_mode) && IS_ENCRYPTED(inode)) {
                        /* We expect the key to be set. */
                        BUG_ON(!fscrypt_has_encryption_key(inode));
-                       WARN_ON_ONCE(fscrypt_decrypt_pagecache_blocks(
-                                       page, blocksize, bh_offset(bh)));
+                       err = fscrypt_decrypt_pagecache_blocks(page, blocksize,
+                                                              bh_offset(bh));
+                       if (err) {
+                               clear_buffer_uptodate(bh);
+                               goto unlock;
+                       }
                }
        }
        if (ext4_should_journal_data(inode)) {
@@ -3912,9 +3938,6 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length)
        unsigned int credits;
        int ret = 0;
 
-       if (!S_ISREG(inode->i_mode))
-               return -EOPNOTSUPP;
-
        trace_ext4_punch_hole(inode, offset, length, 0);
 
        ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA);
@@ -4240,6 +4263,8 @@ static int __ext4_get_inode_loc(struct inode *inode,
        bh = sb_getblk(sb, block);
        if (unlikely(!bh))
                return -ENOMEM;
+       if (ext4_simulate_fail(sb, EXT4_SIM_INODE_EIO))
+               goto simulate_eio;
        if (!buffer_uptodate(bh)) {
                lock_buffer(bh);
 
@@ -4338,6 +4363,8 @@ make_io:
                blk_finish_plug(&plug);
                wait_on_buffer(bh);
                if (!buffer_uptodate(bh)) {
+               simulate_eio:
+                       ext4_set_errno(inode->i_sb, EIO);
                        EXT4_ERROR_INODE_BLOCK(inode, block,
                                               "unable to read itable block");
                        brelse(bh);
@@ -4551,7 +4578,9 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
                                              sizeof(gen));
        }
 
-       if (!ext4_inode_csum_verify(inode, raw_inode, ei)) {
+       if (!ext4_inode_csum_verify(inode, raw_inode, ei) ||
+           ext4_simulate_fail(sb, EXT4_SIM_INODE_CRC)) {
+               ext4_set_errno(inode->i_sb, EFSBADCRC);
                ext4_error_inode(inode, function, line, 0,
                                 "iget: checksum invalid");
                ret = -EFSBADCRC;
@@ -5090,6 +5119,7 @@ int ext4_write_inode(struct inode *inode, struct writeback_control *wbc)
                if (wbc->sync_mode == WB_SYNC_ALL && !wbc->for_sync)
                        sync_dirty_buffer(iloc.bh);
                if (buffer_req(iloc.bh) && !buffer_uptodate(iloc.bh)) {
+                       ext4_set_errno(inode->i_sb, EIO);
                        EXT4_ERROR_INODE_BLOCK(inode, iloc.bh->b_blocknr,
                                         "IO error syncing inode");
                        err = -EIO;
@@ -5368,7 +5398,8 @@ int ext4_getattr(const struct path *path, struct kstat *stat,
        struct ext4_inode_info *ei = EXT4_I(inode);
        unsigned int flags;
 
-       if (EXT4_FITS_IN_INODE(raw_inode, ei, i_crtime)) {
+       if ((request_mask & STATX_BTIME) &&
+           EXT4_FITS_IN_INODE(raw_inode, ei, i_crtime)) {
                stat->result_mask |= STATX_BTIME;
                stat->btime.tv_sec = ei->i_crtime.tv_sec;
                stat->btime.tv_nsec = ei->i_crtime.tv_nsec;
@@ -5692,7 +5723,7 @@ int ext4_expand_extra_isize(struct inode *inode,
        error = ext4_journal_get_write_access(handle, iloc->bh);
        if (error) {
                brelse(iloc->bh);
-               goto out_stop;
+               goto out_unlock;
        }
 
        error = __ext4_expand_extra_isize(inode, new_extra_isize, iloc,
@@ -5702,8 +5733,8 @@ int ext4_expand_extra_isize(struct inode *inode,
        if (!error)
                error = rc;
 
+out_unlock:
        ext4_write_unlock_xattr(inode, &no_expand);
-out_stop:
        ext4_journal_stop(handle);
        return error;
 }