[Devel] [PATCH RHEL7 COMMIT] ploop: io_kaio: Protect ->fastmap against EXT4_IOC_MOVE_EXT and punch hole

Vasily Averin vvs at virtuozzo.com
Fri Aug 7 09:01:47 MSK 2020


The commit is pushed to "branch-rh7-3.10.0-1127.18.2.vz7.163.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-1127.18.2.vz7.163.1
------>
commit 858b07b9b794081f3d0db629ece640e9189278da
Author: Kirill Tkhai <ktkhai at virtuozzo.com>
Date:   Fri Aug 7 09:01:47 2020 +0300

    ploop: io_kaio: Protect ->fastmap against EXT4_IOC_MOVE_EXT and punch hole
    
    Patchset descritpyion:
    ploop: Protect fastmap against defrag and punch hole
    https://jira.sw.ru/browse/PSBM-105347
    
    This protects fastmap against mapped extent disappearance,
    which may be a result of extenal actions (move extent and
    punch hole) on root.hds. Thus, root.hds becomes more "normal"
    file.
    
    Kirill Tkhai (4):
          ploop: Introduce ->fastmap_end_io
          ploop: Add @write argument to ->fastmap
          fs: Export mapping_needs_writeback()
          ploop: io_kaio: Protect ->fastmap against EXT4_IOC_MOVE_EXT and punch hole
    
    Current patch description:
    [PATCH 4/4] ploop: io_kaio: Protect ->fastmap against EXT4_IOC_MOVE_EXT and punch hole
    
    This takes ->i_dio_count during fastmap submitted IO,
    so defrag and punch hole can't make this extent disappeared.
    
    Here are protection from ext4's .read_iter and .write_iter,
    a littly bit simplified (truncate() is still not allowed).
    
    Signed-off-by: Kirill Tkhai <ktkhai at virtuozzo.com>
---
 drivers/block/ploop/io_kaio.c | 19 +++++++++++++++++--
 fs/ext4/file.c                | 41 +++++++++++++++++++++++++++++++++++++++--
 2 files changed, 56 insertions(+), 4 deletions(-)

diff --git a/drivers/block/ploop/io_kaio.c b/drivers/block/ploop/io_kaio.c
index 9cbe923..36f4a62 100644
--- a/drivers/block/ploop/io_kaio.c
+++ b/drivers/block/ploop/io_kaio.c
@@ -1229,7 +1229,7 @@ kaio_fastmap(struct ploop_io *io, struct bio *orig_bio,
 	q = bdev_get_queue(bio->bi_bdev);
 
 	if (q->merge_bvec_fn == NULL)
-		return 0;
+		goto out;
 
 	bio->bi_size = 0;
 	bio->bi_vcnt = 0;
@@ -1244,12 +1244,26 @@ kaio_fastmap(struct ploop_io *io, struct bio *orig_bio,
 		};
 		if (q->merge_bvec_fn(q, &bm_data, bv) < bv->bv_len) {
 			io->plo->st.fast_neg_backing++;
-			return 1;
+			goto err_end_io;
 		}
 		bio->bi_size += bv->bv_len;
 		bio->bi_vcnt++;
 	}
+out:
 	return 0;
+
+err_end_io:
+	io->ops->fastmap_end_io(io, orig_bio);
+	return 1;
+}
+
+static void kaio_fastmap_end_io(struct ploop_io *io, struct bio *orig_bio)
+{
+	struct inode *inode = io->files.inode;
+
+	if (orig_bio->bi_size == 0)
+		return;
+	inode_dio_end(inode);
 }
 
 static struct ploop_io_ops ploop_io_ops_kaio =
@@ -1288,6 +1302,7 @@ static struct ploop_io_ops ploop_io_ops_kaio =
 
 	.autodetect     =       kaio_autodetect,
 	.fastmap	=	kaio_fastmap,
+	.fastmap_end_io	=	kaio_fastmap_end_io,
 };
 
 static int __init pio_kaio_mod_init(void)
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 57a8cc2..cc39aff 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -128,21 +128,58 @@ static bool ext4_overwrite_io(struct inode *inode, loff_t pos, loff_t len)
 static int ext4_fastmap(struct inode *inode, sector_t lblk_sec,
 			unsigned int len, sector_t *pblk_sec, bool write)
 {
+	struct address_space *mapping = inode->i_mapping;
+	bool unaligned_aio, found, locked = false;
 	struct ext4_map_blocks map;
 	loff_t pos = lblk_sec << 9;
-	bool unaligned_aio, found;
+
+	if (!S_ISREG(inode->i_mode))
+		return -ENOENT;
+	if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
+		return -ENOENT;
+	if (ext4_should_journal_data(inode))
+		return -ENOENT;
 
 	unaligned_aio = ext4_unaligned_aio(inode, len, pos);
 	if (unaligned_aio)
 		return -ENOENT;
 
+	if (write) {
+		if (!mutex_trylock(&inode->i_mutex))
+			return -ENOENT;
+		locked = true;
+	}
+
+	if (unlikely(mapping_needs_writeback(mapping)))
+		goto err_maybe_unlock;
+
+	inode_dio_begin(inode);
+	smp_mb();
+
+	if (locked) {
+		mutex_unlock(&inode->i_mutex);
+		locked = false;
+	}
+
+	if (unlikely(ext4_test_inode_state(inode,
+				EXT4_STATE_DIOREAD_LOCK))) {
+		goto err_dio_end;
+	}
+
 	found = __ext4_overwrite_io(inode, lblk_sec << 9, len, &map,
 				    EXT4_GET_BLOCKS_EXTENT_TREE_ONLY_NONBLOCK);
 	if (!found)
-		return -ENOENT;
+		goto err_dio_end;
 
 	*pblk_sec = map.m_pblk << (inode->i_blkbits - 9);
 	return 0;
+
+err_dio_end:
+	inode_dio_end(inode);
+err_maybe_unlock:
+	if (locked)
+		mutex_unlock(&inode->i_mutex);
+	return -ENOENT;
 }
 
 static ssize_t ext4_write_checks(struct kiocb *iocb, struct iov_iter *iter, loff_t *pos)


More information about the Devel mailing list