Merge tag 'driver-core-6.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / fs / ext2 / inode.c
index 26f135e..7598321 100644 (file)
@@ -56,7 +56,7 @@ static inline int ext2_inode_is_fast_symlink(struct inode *inode)
 
 static void ext2_truncate_blocks(struct inode *inode, loff_t offset);
 
-static void ext2_write_failed(struct address_space *mapping, loff_t to)
+void ext2_write_failed(struct address_space *mapping, loff_t to)
 {
        struct inode *inode = mapping->host;
 
@@ -809,9 +809,27 @@ static int ext2_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
        bool new = false, boundary = false;
        u32 bno;
        int ret;
+       bool create = flags & IOMAP_WRITE;
+
+       /*
+        * For writes that could fill holes inside i_size on a
+        * DIO_SKIP_HOLES filesystem we forbid block creations: only
+        * overwrites are permitted.
+        */
+       if ((flags & IOMAP_DIRECT) &&
+           (first_block << blkbits) < i_size_read(inode))
+               create = 0;
+
+       /*
+        * Writes that span EOF might trigger an IO size update on completion,
+        * so consider them to be dirty for the purposes of O_DSYNC even if
+        * there is no other metadata changes pending or have been made here.
+        */
+       if ((flags & IOMAP_WRITE) && offset + length > i_size_read(inode))
+               iomap->flags |= IOMAP_F_DIRTY;
 
        ret = ext2_get_blocks(inode, first_block, max_blocks,
-                       &bno, &new, &boundary, flags & IOMAP_WRITE);
+                       &bno, &new, &boundary, create);
        if (ret < 0)
                return ret;
 
@@ -823,6 +841,12 @@ static int ext2_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
                iomap->bdev = inode->i_sb->s_bdev;
 
        if (ret == 0) {
+               /*
+                * Switch to buffered-io for writing to holes in a non-extent
+                * based filesystem to avoid stale data exposure problem.
+                */
+               if (!create && (flags & IOMAP_WRITE) && (flags & IOMAP_DIRECT))
+                       return -ENOTBLK;
                iomap->type = IOMAP_HOLE;
                iomap->addr = IOMAP_NULL_ADDR;
                iomap->length = 1 << blkbits;
@@ -844,6 +868,13 @@ static int
 ext2_iomap_end(struct inode *inode, loff_t offset, loff_t length,
                ssize_t written, unsigned flags, struct iomap *iomap)
 {
+       /*
+        * Switch to buffered-io in case of any error.
+        * Blocks allocated can be used by the buffered-io path.
+        */
+       if ((flags & IOMAP_DIRECT) && (flags & IOMAP_WRITE) && written == 0)
+               return -ENOTBLK;
+
        if (iomap->type == IOMAP_MAPPED &&
            written < length &&
            (flags & IOMAP_WRITE))
@@ -908,22 +939,6 @@ static sector_t ext2_bmap(struct address_space *mapping, sector_t block)
        return generic_block_bmap(mapping,block,ext2_get_block);
 }
 
-static ssize_t
-ext2_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
-{
-       struct file *file = iocb->ki_filp;
-       struct address_space *mapping = file->f_mapping;
-       struct inode *inode = mapping->host;
-       size_t count = iov_iter_count(iter);
-       loff_t offset = iocb->ki_pos;
-       ssize_t ret;
-
-       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;
-}
-
 static int
 ext2_writepages(struct address_space *mapping, struct writeback_control *wbc)
 {
@@ -946,7 +961,7 @@ const struct address_space_operations ext2_aops = {
        .write_begin            = ext2_write_begin,
        .write_end              = ext2_write_end,
        .bmap                   = ext2_bmap,
-       .direct_IO              = ext2_direct_IO,
+       .direct_IO              = noop_direct_IO,
        .writepages             = ext2_writepages,
        .migrate_folio          = buffer_migrate_folio,
        .is_partially_uptodate  = block_is_partially_uptodate,
@@ -1259,9 +1274,8 @@ static int ext2_setsize(struct inode *inode, loff_t newsize)
        inode_dio_wait(inode);
 
        if (IS_DAX(inode))
-               error = dax_zero_range(inode, newsize,
-                                      PAGE_ALIGN(newsize) - newsize, NULL,
-                                      &ext2_iomap_ops);
+               error = dax_truncate_page(inode, newsize, NULL,
+                                         &ext2_iomap_ops);
        else
                error = block_truncate_page(inode->i_mapping,
                                newsize, ext2_get_block);