mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
erofs: fix metadata reads at the end of file-backed images
Commite587a984d3("erofs: use dedicated meta inodes for file-backed mounts") made erofs_read_meta_folio() read the metadata of a file-backed mount one whole folio at a time. However, an image only has to be a multiple of its block size. With a block size below the page size, it can end in the middle of a page. The read of that last page is then short, and erofs_fileio_ki_complete() fails it with -EIO. As of now, inodes in the last page of such an image cannot be read, and an image smaller than a page cannot be mounted. The issue can be reproduced with util-linux 2.41, whose mount uses the image file directly: mkdir src for i in $(seq 50); do echo $i > src/$i; done mkfs.erofs -b512 test.erofs src mount -t erofs test.erofs /mnt ls -l /mnt Before that commit, ls -l lists all 50 files. After it, ls -l reports "Input/output error" for 24 of them. This patch reads the folio only up to the end of the backing file and zeroes the rest, as the page cache of the backing file did before. A folio that lies wholly past the end is zeroed without a read. Fixes:e587a984d3("erofs: use dedicated meta inodes for file-backed mounts") Cc: stable@vger.kernel.org Signed-off-by: Hengyu Liang <hengyul@cs.unc.edu> Reviewed-by: Gao Xiang <xiang@kernel.org> Signed-off-by: Gao Xiang (Docker) <xiang@kernel.org>
This commit is contained in:
parent
7259fb011c
commit
52dceb8808
|
|
@ -142,17 +142,29 @@ int erofs_read_meta_folio(struct file *file, struct folio *folio)
|
|||
.dev = { .m_pa = folio_pos(folio), },
|
||||
};
|
||||
struct inode *inode = folio_inode(folio);
|
||||
size_t len = folio_size(folio);
|
||||
loff_t pos, isize;
|
||||
int err;
|
||||
|
||||
err = erofs_map_dev(inode->i_sb, &io.dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
pos = io.dev.m_dif->fsoff + io.dev.m_pa;
|
||||
isize = i_size_read(file_inode(io.dev.m_dif->file));
|
||||
if (pos + folio_size(folio) > isize) {
|
||||
len = isize > pos ? isize - pos : 0;
|
||||
folio_zero_segment(folio, len, folio_size(folio));
|
||||
if (!len) {
|
||||
folio_end_read(folio, true);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
io.rq = erofs_fileio_rq_alloc(inode->i_sb, io.dev.m_dif->file);
|
||||
io.rq->bio.bi_end_io = erofs_fileio_meta_endio;
|
||||
io.rq->bio.bi_iter.bi_sector =
|
||||
(io.dev.m_dif->fsoff + io.dev.m_pa) >> 9;
|
||||
bio_add_folio_nofail(&io.rq->bio, folio, folio_size(folio), 0);
|
||||
io.rq->bio.bi_iter.bi_sector = pos >> 9;
|
||||
bio_add_folio_nofail(&io.rq->bio, folio, len, 0);
|
||||
erofs_fileio_rq_submit(io.rq);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user