mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-22 18:40:43 +03:00
Fix buffered/direct/mmap I/O race
When a page is faulted in for memory mapped I/O the page lock may be dropped before it has been read and marked up to date. If a buffered read encounters such a page in mappedread() it must wait until the page has been updated. Failure to do so will result in a panic on debug builds and incorrect data on production builds. The critical part of this change is in mappedread() where pages which are not up to date are now handled. Additionally, it includes the following simplifications. - zfs_getpage() and zfs_fillpage() could be passed an array of pages. This could be more efficient if it was used but in practice only a single page was ever provided. These interfaces were simplified to acknowledge that. - update_pages() was modified to correctly set the PG_error bit on a page when it cannot be read by dmu_read(). - Setting PG_error and PG_uptodate was moved to zfs_fillpage() from zpl_readpage_common(). This is consistent with the handling in update_pages() and mappedread(). - Minor additional refactoring to comments and variable declarations to improve readability. - Add a test case to exercise concurrent buffered, direct, and mmap IO to the same file. - Reduce the mmap_sync test case default run time. Reviewed-by: Richard Yao <richard.yao@alumni.stonybrook.edu> Reviewed-by: Brian Atkinson <batkinson@lanl.gov> Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> Closes #13608 Closes #14498
This commit is contained in:
@@ -72,7 +72,7 @@ extern void zfs_inactive(struct inode *ip);
|
||||
extern int zfs_space(znode_t *zp, int cmd, flock64_t *bfp, int flag,
|
||||
offset_t offset, cred_t *cr);
|
||||
extern int zfs_fid(struct inode *ip, fid_t *fidp);
|
||||
extern int zfs_getpage(struct inode *ip, struct page *pl[], int nr_pages);
|
||||
extern int zfs_getpage(struct inode *ip, struct page *pp);
|
||||
extern int zfs_putpage(struct inode *ip, struct page *pp,
|
||||
struct writeback_control *wbc, boolean_t for_sync);
|
||||
extern int zfs_dirty_inode(struct inode *ip, int flags);
|
||||
|
||||
Reference in New Issue
Block a user