Skip to content

Commit 10553a9

Browse files
Panky-codesbrauner
authored andcommitted
iomap: fix iomap_dio_zero() for fs bs > system page size
iomap_dio_zero() will pad a fs block with zeroes if the direct IO size < fs block size. iomap_dio_zero() has an implicit assumption that fs block size < page_size. This is true for most filesystems at the moment. If the block size > page size, this will send the contents of the page next to zero page(as len > PAGE_SIZE) to the underlying block device, causing FS corruption. iomap is a generic infrastructure and it should not make any assumptions about the fs block size and the page size of the system. Signed-off-by: Pankaj Raghav <[email protected]> Link: https://lore.kernel.org/r/[email protected] Reviewed-by: Hannes Reinecke <[email protected]> Reviewed-by: Darrick J. Wong <[email protected]> Reviewed-by: Dave Chinner <[email protected]> Reviewed-by: Daniel Gomez <[email protected]> Signed-off-by: Christian Brauner <[email protected]>
1 parent 743a275 commit 10553a9

File tree

2 files changed

+41
-8
lines changed

2 files changed

+41
-8
lines changed

fs/iomap/buffered-io.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2007,10 +2007,10 @@ iomap_writepages(struct address_space *mapping, struct writeback_control *wbc,
20072007
}
20082008
EXPORT_SYMBOL_GPL(iomap_writepages);
20092009

2010-
static int __init iomap_init(void)
2010+
static int __init iomap_buffered_init(void)
20112011
{
20122012
return bioset_init(&iomap_ioend_bioset, 4 * (PAGE_SIZE / SECTOR_SIZE),
20132013
offsetof(struct iomap_ioend, io_bio),
20142014
BIOSET_NEED_BVECS);
20152015
}
2016-
fs_initcall(iomap_init);
2016+
fs_initcall(iomap_buffered_init);

fs/iomap/direct-io.c

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <linux/iomap.h>
1212
#include <linux/backing-dev.h>
1313
#include <linux/uio.h>
14+
#include <linux/set_memory.h>
1415
#include <linux/task_io_accounting_ops.h>
1516
#include "trace.h"
1617

@@ -27,6 +28,13 @@
2728
#define IOMAP_DIO_WRITE (1U << 30)
2829
#define IOMAP_DIO_DIRTY (1U << 31)
2930

31+
/*
32+
* Used for sub block zeroing in iomap_dio_zero()
33+
*/
34+
#define IOMAP_ZERO_PAGE_SIZE (SZ_64K)
35+
#define IOMAP_ZERO_PAGE_ORDER (get_order(IOMAP_ZERO_PAGE_SIZE))
36+
static struct page *zero_page;
37+
3038
struct iomap_dio {
3139
struct kiocb *iocb;
3240
const struct iomap_dio_ops *dops;
@@ -232,22 +240,30 @@ void iomap_dio_bio_end_io(struct bio *bio)
232240
}
233241
EXPORT_SYMBOL_GPL(iomap_dio_bio_end_io);
234242

235-
static void iomap_dio_zero(const struct iomap_iter *iter, struct iomap_dio *dio,
243+
static int iomap_dio_zero(const struct iomap_iter *iter, struct iomap_dio *dio,
236244
loff_t pos, unsigned len)
237245
{
238246
struct inode *inode = file_inode(dio->iocb->ki_filp);
239-
struct page *page = ZERO_PAGE(0);
240247
struct bio *bio;
241248

249+
if (!len)
250+
return 0;
251+
/*
252+
* Max block size supported is 64k
253+
*/
254+
if (WARN_ON_ONCE(len > IOMAP_ZERO_PAGE_SIZE))
255+
return -EINVAL;
256+
242257
bio = iomap_dio_alloc_bio(iter, dio, 1, REQ_OP_WRITE | REQ_SYNC | REQ_IDLE);
243258
fscrypt_set_bio_crypt_ctx(bio, inode, pos >> inode->i_blkbits,
244259
GFP_KERNEL);
245260
bio->bi_iter.bi_sector = iomap_sector(&iter->iomap, pos);
246261
bio->bi_private = dio;
247262
bio->bi_end_io = iomap_dio_bio_end_io;
248263

249-
__bio_add_page(bio, page, len, 0);
264+
__bio_add_page(bio, zero_page, len, 0);
250265
iomap_dio_submit_bio(iter, dio, bio, pos);
266+
return 0;
251267
}
252268

253269
/*
@@ -356,8 +372,10 @@ static loff_t iomap_dio_bio_iter(const struct iomap_iter *iter,
356372
if (need_zeroout) {
357373
/* zero out from the start of the block to the write offset */
358374
pad = pos & (fs_block_size - 1);
359-
if (pad)
360-
iomap_dio_zero(iter, dio, pos - pad, pad);
375+
376+
ret = iomap_dio_zero(iter, dio, pos - pad, pad);
377+
if (ret)
378+
goto out;
361379
}
362380

363381
/*
@@ -431,7 +449,8 @@ static loff_t iomap_dio_bio_iter(const struct iomap_iter *iter,
431449
/* zero out from the end of the write to the end of the block */
432450
pad = pos & (fs_block_size - 1);
433451
if (pad)
434-
iomap_dio_zero(iter, dio, pos, fs_block_size - pad);
452+
ret = iomap_dio_zero(iter, dio, pos,
453+
fs_block_size - pad);
435454
}
436455
out:
437456
/* Undo iter limitation to current extent */
@@ -753,3 +772,17 @@ iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
753772
return iomap_dio_complete(dio);
754773
}
755774
EXPORT_SYMBOL_GPL(iomap_dio_rw);
775+
776+
static int __init iomap_dio_init(void)
777+
{
778+
zero_page = alloc_pages(GFP_KERNEL | __GFP_ZERO,
779+
IOMAP_ZERO_PAGE_ORDER);
780+
781+
if (!zero_page)
782+
return -ENOMEM;
783+
784+
set_memory_ro((unsigned long)page_address(zero_page),
785+
1U << IOMAP_ZERO_PAGE_ORDER);
786+
return 0;
787+
}
788+
fs_initcall(iomap_dio_init);

0 commit comments

Comments
 (0)