Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ext4: fix a race in the ext4 shutdown path

This patch fixes a race between the shutdown path and bio completion
handling. In the ext4 direct io path with async io, after submitting a
bio to the block layer, if journal starting fails,
ext4_direct_IO_write() would bail out pretending that the IO
failed. The caller would have had no way of knowing whether or not the
IO was successfully submitted. So instead, we return -EIOCBQUEUED in
this case. Now, the caller knows that the IO was submitted. The bio
completion handler takes care of the error.

Tested: Ran the shutdown xfstest test 461 in loop for over 2 hours across
4 machines resulting in over 400 runs. Verified that the race didn't
occur. Usually the race was seen in about 20-30 iterations.

Signed-off-by: Harshad Shirwadkar <harshads@google.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Cc: stable@vger.kernel.org

authored by

Harshad Shirwadkar and committed by
Theodore Ts'o
abbc3f93 9ee93ba3

+12 -4
+12 -4
fs/ext4/inode.c
··· 3767 3767 /* Credits for sb + inode write */ 3768 3768 handle = ext4_journal_start(inode, EXT4_HT_INODE, 2); 3769 3769 if (IS_ERR(handle)) { 3770 - /* This is really bad luck. We've written the data 3771 - * but cannot extend i_size. Bail out and pretend 3772 - * the write failed... */ 3773 - ret = PTR_ERR(handle); 3770 + /* 3771 + * We wrote the data but cannot extend 3772 + * i_size. Bail out. In async io case, we do 3773 + * not return error here because we have 3774 + * already submmitted the corresponding 3775 + * bio. Returning error here makes the caller 3776 + * think that this IO is done and failed 3777 + * resulting in race with bio's completion 3778 + * handler. 3779 + */ 3780 + if (!ret) 3781 + ret = PTR_ERR(handle); 3774 3782 if (inode->i_nlink) 3775 3783 ext4_orphan_del(NULL, inode); 3776 3784