]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - fs/ext4/inode.c
Merge uncontroversial parts of branch 'readlink' of git://git.kernel.org/pub/scm...
[mirror_ubuntu-artful-kernel.git] / fs / ext4 / inode.c
index 9de9a5a5d2a4f9e839deea6039141ca407825730..88d57af1b516c5bbfd7b2f1bc471a9d76382c3bc 100644 (file)
@@ -72,10 +72,9 @@ static __u32 ext4_inode_csum(struct inode *inode, struct ext4_inode *raw,
                        csum = ext4_chksum(sbi, csum, (__u8 *)&dummy_csum,
                                           csum_size);
                        offset += csum_size;
-                       csum = ext4_chksum(sbi, csum, (__u8 *)raw + offset,
-                                          EXT4_INODE_SIZE(inode->i_sb) -
-                                          offset);
                }
+               csum = ext4_chksum(sbi, csum, (__u8 *)raw + offset,
+                                  EXT4_INODE_SIZE(inode->i_sb) - offset);
        }
 
        return csum;
@@ -662,12 +661,8 @@ found:
                if (flags & EXT4_GET_BLOCKS_ZERO &&
                    map->m_flags & EXT4_MAP_MAPPED &&
                    map->m_flags & EXT4_MAP_NEW) {
-                       ext4_lblk_t i;
-
-                       for (i = 0; i < map->m_len; i++) {
-                               unmap_underlying_metadata(inode->i_sb->s_bdev,
-                                                         map->m_pblk + i);
-                       }
+                       clean_bdev_aliases(inode->i_sb->s_bdev, map->m_pblk,
+                                          map->m_len);
                        ret = ext4_issue_zeroout(inode, map->m_lblk,
                                                 map->m_pblk, map->m_len);
                        if (ret) {
@@ -1138,8 +1133,7 @@ static int ext4_block_write_begin(struct page *page, loff_t pos, unsigned len,
                        if (err)
                                break;
                        if (buffer_new(bh)) {
-                               unmap_underlying_metadata(bh->b_bdev,
-                                                         bh->b_blocknr);
+                               clean_bdev_bh_alias(bh);
                                if (PageUptodate(page)) {
                                        clear_buffer_new(bh);
                                        set_buffer_uptodate(bh);
@@ -2372,11 +2366,8 @@ static int mpage_map_one_extent(handle_t *handle, struct mpage_da_data *mpd)
 
        BUG_ON(map->m_len == 0);
        if (map->m_flags & EXT4_MAP_NEW) {
-               struct block_device *bdev = inode->i_sb->s_bdev;
-               int i;
-
-               for (i = 0; i < map->m_len; i++)
-                       unmap_underlying_metadata(bdev, map->m_pblk + i);
+               clean_bdev_aliases(inode->i_sb->s_bdev, map->m_pblk,
+                                  map->m_len);
        }
        return 0;
 }
@@ -2903,7 +2894,8 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping,
 
        index = pos >> PAGE_SHIFT;
 
-       if (ext4_nonda_switch(inode->i_sb)) {
+       if (ext4_nonda_switch(inode->i_sb) ||
+           S_ISLNK(inode->i_mode)) {
                *fsdata = (void *)FALL_BACK_TO_NONDELALLOC;
                return ext4_write_begin(file, mapping, pos,
                                        len, flags, pagep, fsdata);
@@ -3280,46 +3272,6 @@ static int ext4_releasepage(struct page *page, gfp_t wait)
 }
 
 #ifdef CONFIG_FS_DAX
-/*
- * Get block function for DAX IO and mmap faults. It takes care of converting
- * unwritten extents to written ones and initializes new / converted blocks
- * to zeros.
- */
-int ext4_dax_get_block(struct inode *inode, sector_t iblock,
-                      struct buffer_head *bh_result, int create)
-{
-       int ret;
-
-       ext4_debug("inode %lu, create flag %d\n", inode->i_ino, create);
-       if (!create)
-               return _ext4_get_block(inode, iblock, bh_result, 0);
-
-       ret = ext4_get_block_trans(inode, iblock, bh_result,
-                                  EXT4_GET_BLOCKS_PRE_IO |
-                                  EXT4_GET_BLOCKS_CREATE_ZERO);
-       if (ret < 0)
-               return ret;
-
-       if (buffer_unwritten(bh_result)) {
-               /*
-                * We are protected by i_mmap_sem or i_mutex so we know block
-                * cannot go away from under us even though we dropped
-                * i_data_sem. Convert extent to written and write zeros there.
-                */
-               ret = ext4_get_block_trans(inode, iblock, bh_result,
-                                          EXT4_GET_BLOCKS_CONVERT |
-                                          EXT4_GET_BLOCKS_CREATE_ZERO);
-               if (ret < 0)
-                       return ret;
-       }
-       /*
-        * At least for now we have to clear BH_New so that DAX code
-        * doesn't attempt to zero blocks again in a racy way.
-        */
-       clear_buffer_new(bh_result);
-       return 0;
-}
-
 static int ext4_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
                            unsigned flags, struct iomap *iomap)
 {
@@ -3473,14 +3425,6 @@ struct iomap_ops ext4_iomap_ops = {
        .iomap_end              = ext4_iomap_end,
 };
 
-#else
-/* Just define empty function, it will never get called. */
-int ext4_dax_get_block(struct inode *inode, sector_t iblock,
-                      struct buffer_head *bh_result, int create)
-{
-       BUG();
-       return 0;
-}
 #endif
 
 static int ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
@@ -3602,19 +3546,7 @@ static ssize_t ext4_direct_IO_write(struct kiocb *iocb, struct iov_iter *iter)
        iocb->private = NULL;
        if (overwrite)
                get_block_func = ext4_dio_get_block_overwrite;
-       else if (IS_DAX(inode)) {
-               /*
-                * We can avoid zeroing for aligned DAX writes beyond EOF. Other
-                * writes need zeroing either because they can race with page
-                * faults or because they use partial blocks.
-                */
-               if (round_down(offset, 1<<inode->i_blkbits) >= inode->i_size &&
-                   ext4_aligned_io(inode, offset, count))
-                       get_block_func = ext4_dio_get_block;
-               else
-                       get_block_func = ext4_dax_get_block;
-               dio_flags = DIO_LOCKING;
-       } else if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) ||
+       else if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) ||
                   round_down(offset, 1 << inode->i_blkbits) >= inode->i_size) {
                get_block_func = ext4_dio_get_block;
                dio_flags = DIO_LOCKING | DIO_SKIP_HOLES;
@@ -3628,14 +3560,9 @@ static ssize_t ext4_direct_IO_write(struct kiocb *iocb, struct iov_iter *iter)
 #ifdef CONFIG_EXT4_FS_ENCRYPTION
        BUG_ON(ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode));
 #endif
-       if (IS_DAX(inode)) {
-               ret = dax_do_io(iocb, inode, iter, get_block_func,
-                               ext4_end_io_dio, dio_flags);
-       } else
-               ret = __blockdev_direct_IO(iocb, inode,
-                                          inode->i_sb->s_bdev, iter,
-                                          get_block_func,
-                                          ext4_end_io_dio, NULL, dio_flags);
+       ret = __blockdev_direct_IO(iocb, inode, inode->i_sb->s_bdev, iter,
+                                  get_block_func, ext4_end_io_dio, NULL,
+                                  dio_flags);
 
        if (ret > 0 && !overwrite && ext4_test_inode_state(inode,
                                                EXT4_STATE_DIO_UNWRITTEN)) {
@@ -3704,6 +3631,7 @@ static ssize_t ext4_direct_IO_read(struct kiocb *iocb, struct iov_iter *iter)
 {
        struct address_space *mapping = iocb->ki_filp->f_mapping;
        struct inode *inode = mapping->host;
+       size_t count = iov_iter_count(iter);
        ssize_t ret;
 
        /*
@@ -3712,19 +3640,12 @@ static ssize_t ext4_direct_IO_read(struct kiocb *iocb, struct iov_iter *iter)
         * we are protected against page writeback as well.
         */
        inode_lock_shared(inode);
-       if (IS_DAX(inode)) {
-               ret = dax_do_io(iocb, inode, iter, ext4_dio_get_block, NULL, 0);
-       } else {
-               size_t count = iov_iter_count(iter);
-
-               ret = filemap_write_and_wait_range(mapping, iocb->ki_pos,
-                                                  iocb->ki_pos + count);
-               if (ret)
-                       goto out_unlock;
-               ret = __blockdev_direct_IO(iocb, inode, inode->i_sb->s_bdev,
-                                          iter, ext4_dio_get_block,
-                                          NULL, NULL, 0);
-       }
+       ret = filemap_write_and_wait_range(mapping, iocb->ki_pos,
+                                          iocb->ki_pos + count);
+       if (ret)
+               goto out_unlock;
+       ret = __blockdev_direct_IO(iocb, inode, inode->i_sb->s_bdev,
+                                  iter, ext4_dio_get_block, NULL, NULL, 0);
 out_unlock:
        inode_unlock_shared(inode);
        return ret;
@@ -3753,6 +3674,10 @@ static ssize_t ext4_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
        if (ext4_has_inline_data(inode))
                return 0;
 
+       /* DAX uses iomap path now */
+       if (WARN_ON_ONCE(IS_DAX(inode)))
+               return 0;
+
        trace_ext4_direct_IO_enter(inode, offset, count, iov_iter_rw(iter));
        if (iov_iter_rw(iter) == READ)
                ret = ext4_direct_IO_read(iocb, iter);
@@ -3781,6 +3706,13 @@ static int ext4_journalled_set_page_dirty(struct page *page)
        return __set_page_dirty_nobuffers(page);
 }
 
+static int ext4_set_page_dirty(struct page *page)
+{
+       WARN_ON_ONCE(!PageLocked(page) && !PageDirty(page));
+       WARN_ON_ONCE(!page_has_buffers(page));
+       return __set_page_dirty_buffers(page);
+}
+
 static const struct address_space_operations ext4_aops = {
        .readpage               = ext4_readpage,
        .readpages              = ext4_readpages,
@@ -3788,6 +3720,7 @@ static const struct address_space_operations ext4_aops = {
        .writepages             = ext4_writepages,
        .write_begin            = ext4_write_begin,
        .write_end              = ext4_write_end,
+       .set_page_dirty         = ext4_set_page_dirty,
        .bmap                   = ext4_bmap,
        .invalidatepage         = ext4_invalidatepage,
        .releasepage            = ext4_releasepage,
@@ -3820,6 +3753,7 @@ static const struct address_space_operations ext4_da_aops = {
        .writepages             = ext4_writepages,
        .write_begin            = ext4_da_write_begin,
        .write_end              = ext4_da_write_end,
+       .set_page_dirty         = ext4_set_page_dirty,
        .bmap                   = ext4_bmap,
        .invalidatepage         = ext4_da_invalidatepage,
        .releasepage            = ext4_releasepage,
@@ -3909,7 +3843,6 @@ static int __ext4_block_zero_page_range(handle_t *handle,
                        /* We expect the key to be set. */
                        BUG_ON(!fscrypt_has_encryption_key(inode));
                        BUG_ON(blocksize != PAGE_SIZE);
-                       BUG_ON(!PageLocked(page));
                        WARN_ON_ONCE(fscrypt_decrypt_page(page->mapping->host,
                                                page, PAGE_SIZE, 0, page->index));
                }
@@ -4586,7 +4519,9 @@ static inline void ext4_iget_extra_inode(struct inode *inode,
 {
        __le32 *magic = (void *)raw_inode +
                        EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize;
-       if (*magic == cpu_to_le32(EXT4_XATTR_MAGIC)) {
+       if (EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize + sizeof(__le32) <=
+           EXT4_INODE_SIZE(inode->i_sb) &&
+           *magic == cpu_to_le32(EXT4_XATTR_MAGIC)) {
                ext4_set_inode_state(inode, EXT4_STATE_XATTR);
                ext4_find_inline_data_nolock(inode);
        } else
@@ -4609,6 +4544,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
        struct inode *inode;
        journal_t *journal = EXT4_SB(sb)->s_journal;
        long ret;
+       loff_t size;
        int block;
        uid_t i_uid;
        gid_t i_gid;
@@ -4631,10 +4567,12 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
        if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) {
                ei->i_extra_isize = le16_to_cpu(raw_inode->i_extra_isize);
                if (EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize >
-                   EXT4_INODE_SIZE(inode->i_sb)) {
-                       EXT4_ERROR_INODE(inode, "bad extra_isize (%u != %u)",
-                               EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize,
-                               EXT4_INODE_SIZE(inode->i_sb));
+                       EXT4_INODE_SIZE(inode->i_sb) ||
+                   (ei->i_extra_isize & 3)) {
+                       EXT4_ERROR_INODE(inode,
+                                        "bad extra_isize %u (inode size %u)",
+                                        ei->i_extra_isize,
+                                        EXT4_INODE_SIZE(inode->i_sb));
                        ret = -EFSCORRUPTED;
                        goto bad_inode;
                }
@@ -4709,6 +4647,11 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
                ei->i_file_acl |=
                        ((__u64)le16_to_cpu(raw_inode->i_file_acl_high)) << 32;
        inode->i_size = ext4_isize(raw_inode);
+       if ((size = i_size_read(inode)) < 0) {
+               EXT4_ERROR_INODE(inode, "bad i_size value: %lld", size);
+               ret = -EFSCORRUPTED;
+               goto bad_inode;
+       }
        ei->i_disksize = inode->i_size;
 #ifdef CONFIG_QUOTA
        ei->i_reserved_quota = 0;
@@ -4752,6 +4695,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
        if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) {
                if (ei->i_extra_isize == 0) {
                        /* The extra space is currently unused. Use it. */
+                       BUILD_BUG_ON(sizeof(struct ext4_inode) & 3);
                        ei->i_extra_isize = sizeof(struct ext4_inode) -
                                            EXT4_GOOD_OLD_INODE_SIZE;
                } else {