Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[cascardo/linux.git] / fs / ext2 / inode.c
index b66a658..d831e24 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/buffer_head.h>
 #include <linux/mpage.h>
 #include <linux/fiemap.h>
+#include <linux/iomap.h>
 #include <linux/namei.h>
 #include <linux/uio.h>
 #include "ext2.h"
@@ -618,7 +619,7 @@ static void ext2_splice_branch(struct inode *inode,
  */
 static int ext2_get_blocks(struct inode *inode,
                           sector_t iblock, unsigned long maxblocks,
-                          struct buffer_head *bh_result,
+                          u32 *bno, bool *new, bool *boundary,
                           int create)
 {
        int err = -EIO;
@@ -644,7 +645,6 @@ static int ext2_get_blocks(struct inode *inode,
        /* Simplest case - block found, no allocation needed */
        if (!partial) {
                first_block = le32_to_cpu(chain[depth - 1].key);
-               clear_buffer_new(bh_result); /* What's this do? */
                count++;
                /*map more blocks*/
                while (count < maxblocks && count <= blocks_to_boundary) {
@@ -699,7 +699,6 @@ static int ext2_get_blocks(struct inode *inode,
                        mutex_unlock(&ei->truncate_mutex);
                        if (err)
                                goto cleanup;
-                       clear_buffer_new(bh_result);
                        goto got_it;
                }
        }
@@ -733,6 +732,16 @@ static int ext2_get_blocks(struct inode *inode,
        }
 
        if (IS_DAX(inode)) {
+               int i;
+
+               /*
+                * We must unmap blocks before zeroing so that writeback cannot
+                * overwrite zeros with stale data from block device page cache.
+                */
+               for (i = 0; i < count; i++) {
+                       unmap_underlying_metadata(inode->i_sb->s_bdev,
+                                       le32_to_cpu(chain[depth-1].key) + i);
+               }
                /*
                 * block must be initialised before we put it in the tree
                 * so that it's not found by another thread before it's
@@ -745,15 +754,16 @@ static int ext2_get_blocks(struct inode *inode,
                        mutex_unlock(&ei->truncate_mutex);
                        goto cleanup;
                }
-       } else
-               set_buffer_new(bh_result);
+       } else {
+               *new = true;
+       }
 
        ext2_splice_branch(inode, iblock, partial, indirect_blks, count);
        mutex_unlock(&ei->truncate_mutex);
 got_it:
-       map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key));
+       *bno = le32_to_cpu(chain[depth-1].key);
        if (count > blocks_to_boundary)
-               set_buffer_boundary(bh_result);
+               *boundary = true;
        err = count;
        /* Clean up and exit */
        partial = chain + depth - 1;    /* the whole chain */
@@ -765,19 +775,82 @@ cleanup:
        return err;
 }
 
-int ext2_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create)
+int ext2_get_block(struct inode *inode, sector_t iblock,
+               struct buffer_head *bh_result, int create)
 {
        unsigned max_blocks = bh_result->b_size >> inode->i_blkbits;
-       int ret = ext2_get_blocks(inode, iblock, max_blocks,
-                             bh_result, create);
-       if (ret > 0) {
-               bh_result->b_size = (ret << inode->i_blkbits);
-               ret = 0;
+       bool new = false, boundary = false;
+       u32 bno;
+       int ret;
+
+       ret = ext2_get_blocks(inode, iblock, max_blocks, &bno, &new, &boundary,
+                       create);
+       if (ret <= 0)
+               return ret;
+
+       map_bh(bh_result, inode->i_sb, bno);
+       bh_result->b_size = (ret << inode->i_blkbits);
+       if (new)
+               set_buffer_new(bh_result);
+       if (boundary)
+               set_buffer_boundary(bh_result);
+       return 0;
+
+}
+
+#ifdef CONFIG_FS_DAX
+static int ext2_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
+               unsigned flags, struct iomap *iomap)
+{
+       unsigned int blkbits = inode->i_blkbits;
+       unsigned long first_block = offset >> blkbits;
+       unsigned long max_blocks = (length + (1 << blkbits) - 1) >> blkbits;
+       bool new = false, boundary = false;
+       u32 bno;
+       int ret;
+
+       ret = ext2_get_blocks(inode, first_block, max_blocks,
+                       &bno, &new, &boundary, flags & IOMAP_WRITE);
+       if (ret < 0)
+               return ret;
+
+       iomap->flags = 0;
+       iomap->bdev = inode->i_sb->s_bdev;
+       iomap->offset = (u64)first_block << blkbits;
+
+       if (ret == 0) {
+               iomap->type = IOMAP_HOLE;
+               iomap->blkno = IOMAP_NULL_BLOCK;
+               iomap->length = 1 << blkbits;
+       } else {
+               iomap->type = IOMAP_MAPPED;
+               iomap->blkno = (sector_t)bno << (blkbits - 9);
+               iomap->length = (u64)ret << blkbits;
+               iomap->flags |= IOMAP_F_MERGED;
        }
-       return ret;
 
+       if (new)
+               iomap->flags |= IOMAP_F_NEW;
+       return 0;
 }
 
+static int
+ext2_iomap_end(struct inode *inode, loff_t offset, loff_t length,
+               ssize_t written, unsigned flags, struct iomap *iomap)
+{
+       if (iomap->type == IOMAP_MAPPED &&
+           written < length &&
+           (flags & IOMAP_WRITE))
+               ext2_write_failed(inode->i_mapping, offset + length);
+       return 0;
+}
+
+struct iomap_ops ext2_iomap_ops = {
+       .iomap_begin            = ext2_iomap_begin,
+       .iomap_end              = ext2_iomap_end,
+};
+#endif /* CONFIG_FS_DAX */
+
 int ext2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                u64 start, u64 len)
 {
@@ -863,11 +936,10 @@ ext2_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
        loff_t offset = iocb->ki_pos;
        ssize_t ret;
 
-       if (IS_DAX(inode))
-               ret = dax_do_io(iocb, inode, iter, ext2_get_block, NULL,
-                               DIO_LOCKING);
-       else
-               ret = blockdev_direct_IO(iocb, inode, iter, ext2_get_block);
+       if (WARN_ON_ONCE(IS_DAX(inode)))
+               return -EIO;
+
+       ret = blockdev_direct_IO(iocb, inode, iter, ext2_get_block);
        if (ret < 0 && iov_iter_rw(iter) == WRITE)
                ext2_write_failed(mapping, offset + count);
        return ret;
@@ -1580,7 +1652,7 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr)
        struct inode *inode = d_inode(dentry);
        int error;
 
-       error = inode_change_ok(inode, iattr);
+       error = setattr_prepare(dentry, iattr);
        if (error)
                return error;