From e2b60048d763589d3caa711edbf95badfd07b12e Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sat, 15 Sep 2018 14:30:34 -0400 Subject: [PATCH] add patch close-race-between-direct-io-and-ext4_break_layouts --- ...e-race-between-direct-io-and-ext4_break_layouts | 70 ++++++++++++++++++++++ series | 1 + timestamps | 7 ++- 3 files changed, 75 insertions(+), 3 deletions(-) create mode 100644 close-race-between-direct-io-and-ext4_break_layouts diff --git a/close-race-between-direct-io-and-ext4_break_layouts b/close-race-between-direct-io-and-ext4_break_layouts new file mode 100644 index 00000000..c8382a87 --- /dev/null +++ b/close-race-between-direct-io-and-ext4_break_layouts @@ -0,0 +1,70 @@ +ext4: close race between direct IO and ext4_break_layouts() + +From: Ross Zwisler + +If the refcount of a page is lowered between the time that it is returned +by dax_busy_page() and when the refcount is again checked in +ext4_break_layouts() => ___wait_var_event(), the waiting function +ext4_wait_dax_page() will never be called. This means that +ext4_break_layouts() will still have 'retry' set to false, so we'll stop +looping and never check the refcount of other pages in this inode. + +Instead, always continue looping as long as dax_layout_busy_page() gives us +a page which it found with an elevated refcount. + +Signed-off-by: Ross Zwisler +Reviewed-by: Jan Kara +Signed-off-by: Jan Kara +Signed-off-by: Theodore Ts'o +Cc: stable@vger.kernel.org +--- + +v2: +- remove verbiage in comment header (Jan) + + fs/ext4/inode.c | 9 +++------ + 1 file changed, 3 insertions(+), 6 deletions(-) + +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index 8f6ad7667974..d2663a1e3ec2 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -4191,9 +4191,8 @@ int ext4_update_disksize_before_punch(struct inode *inode, loff_t offset, + return 0; + } + +-static void ext4_wait_dax_page(struct ext4_inode_info *ei, bool *did_unlock) ++static void ext4_wait_dax_page(struct ext4_inode_info *ei) + { +- *did_unlock = true; + up_write(&ei->i_mmap_sem); + schedule(); + down_write(&ei->i_mmap_sem); +@@ -4203,14 +4202,12 @@ int ext4_break_layouts(struct inode *inode) + { + struct ext4_inode_info *ei = EXT4_I(inode); + struct page *page; +- bool retry; + int error; + + if (WARN_ON_ONCE(!rwsem_is_locked(&ei->i_mmap_sem))) + return -EINVAL; + + do { +- retry = false; + page = dax_layout_busy_page(inode->i_mapping); + if (!page) + return 0; +@@ -4218,8 +4215,8 @@ int ext4_break_layouts(struct inode *inode) + error = ___wait_var_event(&page->_refcount, + atomic_read(&page->_refcount) == 1, + TASK_INTERRUPTIBLE, 0, 0, +- ext4_wait_dax_page(ei, &retry)); +- } while (error == 0 && retry); ++ ext4_wait_dax_page(ei)); ++ } while (error == 0); + + return error; + } + + diff --git a/series b/series index e0b51800..ba0e1361 100644 --- a/series +++ b/series @@ -7,6 +7,7 @@ avoid-arithmetic-overflow-that-can-trigger-a-BUG calculate-superblock-checksum-after-update-free-blocks-inodes truncate-resize-size-to-avoid-too-small-last-bg fix-online-resize-with-bigalloc-1k +close-race-between-direct-io-and-ext4_break_layouts #################################################### # unstable patches diff --git a/timestamps b/timestamps index 707ecf03..bd895c0f 100755 --- a/timestamps +++ b/timestamps @@ -38,8 +38,9 @@ touch -d @1535376041 stable-boundary touch -d @1535376165 avoid-buffer-overrun-when-deleting-inline-directories touch -d @1535820304 avoid-arithmetic-overflow-that-can-trigger-a-BUG touch -d @1535827334 calculate-superblock-checksum-after-update-free-blocks-inodes -touch -d @1536026895 series touch -d @1536027583 truncate-resize-size-to-avoid-too-small-last-bg touch -d @1536027901 fix-online-resize-with-bigalloc-1k -touch -d @1536027901 status -touch -d @1536032813 timestamps +touch -d @1536687076 close-race-between-direct-io-and-ext4_break_layouts +touch -d @1536687473 series +touch -d @1536687477 status +touch -d @1537036227 timestamps -- 2.11.4.GIT