[Devel] [PATCH RH7 4/4] ploop: io_kaio: Protect ->fastmap against EXT4_IOC_MOVE_EXT and punch hole
Kirill Tkhai
ktkhai at virtuozzo.com
Thu Aug 6 14:55:45 MSK 2020
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 9cbe923b14bf..36f4a6291c59 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 57a8cc2b8e3f..cc39aff54e03 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