From fb22bec283ec121c73d3e23e5de18dd9727a1311 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Mon, 4 Dec 2023 14:46:05 -0500 Subject: [PATCH] Drop ext4-properly-sync-file-size-update-after-o_sync-dir.patch Signed-off-by: Sasha Levin --- ...nc-file-size-update-after-o_sync-dir.patch | 246 ------------------ queue-5.10/series | 1 - ...nc-file-size-update-after-o_sync-dir.patch | 246 ------------------ queue-5.15/series | 2 - 4 files changed, 495 deletions(-) delete mode 100644 queue-5.10/ext4-properly-sync-file-size-update-after-o_sync-dir.patch delete mode 100644 queue-5.15/ext4-properly-sync-file-size-update-after-o_sync-dir.patch diff --git a/queue-5.10/ext4-properly-sync-file-size-update-after-o_sync-dir.patch b/queue-5.10/ext4-properly-sync-file-size-update-after-o_sync-dir.patch deleted file mode 100644 index dc74dcefa40..00000000000 --- a/queue-5.10/ext4-properly-sync-file-size-update-after-o_sync-dir.patch +++ /dev/null @@ -1,246 +0,0 @@ -From 84133ca398f3d3a0563b2b47a0c0d86191848b2b Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Fri, 13 Oct 2023 14:13:50 +0200 -Subject: ext4: properly sync file size update after O_SYNC direct IO - -From: Jan Kara - -[ Upstream commit 91562895f8030cb9a0470b1db49de79346a69f91 ] - -Gao Xiang has reported that on ext4 O_SYNC direct IO does not properly -sync file size update and thus if we crash at unfortunate moment, the -file can have smaller size although O_SYNC IO has reported successful -completion. The problem happens because update of on-disk inode size is -handled in ext4_dio_write_iter() *after* iomap_dio_rw() (and thus -dio_complete() in particular) has returned and generic_file_sync() gets -called by dio_complete(). Fix the problem by handling on-disk inode size -update directly in our ->end_io completion handler. - -References: https://lore.kernel.org/all/02d18236-26ef-09b0-90ad-030c4fe3ee20@linux.alibaba.com -Reported-by: Gao Xiang -CC: stable@vger.kernel.org -Fixes: 378f32bab371 ("ext4: introduce direct I/O write using iomap infrastructure") -Signed-off-by: Jan Kara -Tested-by: Joseph Qi -Reviewed-by: "Ritesh Harjani (IBM)" -Link: https://lore.kernel.org/r/20231013121350.26872-1-jack@suse.cz -Signed-off-by: Theodore Ts'o -Signed-off-by: Sasha Levin ---- - fs/ext4/file.c | 153 +++++++++++++++++++++---------------------------- - 1 file changed, 65 insertions(+), 88 deletions(-) - -diff --git a/fs/ext4/file.c b/fs/ext4/file.c -index f42cc1fe0ba1d..15f45499f491a 100644 ---- a/fs/ext4/file.c -+++ b/fs/ext4/file.c -@@ -280,80 +280,38 @@ static ssize_t ext4_buffered_write_iter(struct kiocb *iocb, - } - - static ssize_t ext4_handle_inode_extension(struct inode *inode, loff_t offset, -- ssize_t written, size_t count) -+ ssize_t count) - { - handle_t *handle; -- bool truncate = false; -- u8 blkbits = inode->i_blkbits; -- ext4_lblk_t written_blk, end_blk; -- int ret; -- -- /* -- * Note that EXT4_I(inode)->i_disksize can get extended up to -- * inode->i_size while the I/O was running due to writeback of delalloc -- * blocks. But, the code in ext4_iomap_alloc() is careful to use -- * zeroed/unwritten extents if this is possible; thus we won't leave -- * uninitialized blocks in a file even if we didn't succeed in writing -- * as much as we intended. -- */ -- WARN_ON_ONCE(i_size_read(inode) < EXT4_I(inode)->i_disksize); -- if (offset + count <= EXT4_I(inode)->i_disksize) { -- /* -- * We need to ensure that the inode is removed from the orphan -- * list if it has been added prematurely, due to writeback of -- * delalloc blocks. -- */ -- if (!list_empty(&EXT4_I(inode)->i_orphan) && inode->i_nlink) { -- handle = ext4_journal_start(inode, EXT4_HT_INODE, 2); -- -- if (IS_ERR(handle)) { -- ext4_orphan_del(NULL, inode); -- return PTR_ERR(handle); -- } -- -- ext4_orphan_del(handle, inode); -- ext4_journal_stop(handle); -- } -- -- return written; -- } -- -- if (written < 0) -- goto truncate; - -+ lockdep_assert_held_write(&inode->i_rwsem); - handle = ext4_journal_start(inode, EXT4_HT_INODE, 2); -- if (IS_ERR(handle)) { -- written = PTR_ERR(handle); -- goto truncate; -- } -+ if (IS_ERR(handle)) -+ return PTR_ERR(handle); - -- if (ext4_update_inode_size(inode, offset + written)) { -- ret = ext4_mark_inode_dirty(handle, inode); -+ if (ext4_update_inode_size(inode, offset + count)) { -+ int ret = ext4_mark_inode_dirty(handle, inode); - if (unlikely(ret)) { -- written = ret; - ext4_journal_stop(handle); -- goto truncate; -+ return ret; - } - } - -- /* -- * We may need to truncate allocated but not written blocks beyond EOF. -- */ -- written_blk = ALIGN(offset + written, 1 << blkbits); -- end_blk = ALIGN(offset + count, 1 << blkbits); -- if (written_blk < end_blk && ext4_can_truncate(inode)) -- truncate = true; -- -- /* -- * Remove the inode from the orphan list if it has been extended and -- * everything went OK. -- */ -- if (!truncate && inode->i_nlink) -+ if (inode->i_nlink) - ext4_orphan_del(handle, inode); - ext4_journal_stop(handle); - -- if (truncate) { --truncate: -+ return count; -+} -+ -+/* -+ * Clean up the inode after DIO or DAX extending write has completed and the -+ * inode size has been updated using ext4_handle_inode_extension(). -+ */ -+static void ext4_inode_extension_cleanup(struct inode *inode, ssize_t count) -+{ -+ lockdep_assert_held_write(&inode->i_rwsem); -+ if (count < 0) { - ext4_truncate_failed_write(inode); - /* - * If the truncate operation failed early, then the inode may -@@ -362,9 +320,28 @@ static ssize_t ext4_handle_inode_extension(struct inode *inode, loff_t offset, - */ - if (inode->i_nlink) - ext4_orphan_del(NULL, inode); -+ return; - } -+ /* -+ * If i_disksize got extended due to writeback of delalloc blocks while -+ * the DIO was running we could fail to cleanup the orphan list in -+ * ext4_handle_inode_extension(). Do it now. -+ */ -+ if (!list_empty(&EXT4_I(inode)->i_orphan) && inode->i_nlink) { -+ handle_t *handle = ext4_journal_start(inode, EXT4_HT_INODE, 2); - -- return written; -+ if (IS_ERR(handle)) { -+ /* -+ * The write has successfully completed. Not much to -+ * do with the error here so just cleanup the orphan -+ * list and hope for the best. -+ */ -+ ext4_orphan_del(NULL, inode); -+ return; -+ } -+ ext4_orphan_del(handle, inode); -+ ext4_journal_stop(handle); -+ } - } - - static int ext4_dio_write_end_io(struct kiocb *iocb, ssize_t size, -@@ -373,31 +350,22 @@ static int ext4_dio_write_end_io(struct kiocb *iocb, ssize_t size, - loff_t pos = iocb->ki_pos; - struct inode *inode = file_inode(iocb->ki_filp); - -+ if (!error && size && flags & IOMAP_DIO_UNWRITTEN) -+ error = ext4_convert_unwritten_extents(NULL, inode, pos, size); - if (error) - return error; -- -- if (size && flags & IOMAP_DIO_UNWRITTEN) { -- error = ext4_convert_unwritten_extents(NULL, inode, pos, size); -- if (error < 0) -- return error; -- } - /* -- * If we are extending the file, we have to update i_size here before -- * page cache gets invalidated in iomap_dio_rw(). Otherwise racing -- * buffered reads could zero out too much from page cache pages. Update -- * of on-disk size will happen later in ext4_dio_write_iter() where -- * we have enough information to also perform orphan list handling etc. -- * Note that we perform all extending writes synchronously under -- * i_rwsem held exclusively so i_size update is safe here in that case. -- * If the write was not extending, we cannot see pos > i_size here -- * because operations reducing i_size like truncate wait for all -- * outstanding DIO before updating i_size. -+ * Note that EXT4_I(inode)->i_disksize can get extended up to -+ * inode->i_size while the I/O was running due to writeback of delalloc -+ * blocks. But the code in ext4_iomap_alloc() is careful to use -+ * zeroed/unwritten extents if this is possible; thus we won't leave -+ * uninitialized blocks in a file even if we didn't succeed in writing -+ * as much as we intended. - */ -- pos += size; -- if (pos > i_size_read(inode)) -- i_size_write(inode, pos); -- -- return 0; -+ WARN_ON_ONCE(i_size_read(inode) < READ_ONCE(EXT4_I(inode)->i_disksize)); -+ if (pos + size <= READ_ONCE(EXT4_I(inode)->i_disksize)) -+ return size; -+ return ext4_handle_inode_extension(inode, pos, size); - } - - static const struct iomap_dio_ops ext4_dio_write_ops = { -@@ -572,9 +540,16 @@ static ssize_t ext4_dio_write_iter(struct kiocb *iocb, struct iov_iter *from) - is_sync_kiocb(iocb) || unaligned_io || extend); - if (ret == -ENOTBLK) - ret = 0; -- -- if (extend) -- ret = ext4_handle_inode_extension(inode, offset, ret, count); -+ if (extend) { -+ /* -+ * We always perform extending DIO write synchronously so by -+ * now the IO is completed and ext4_handle_inode_extension() -+ * was called. Cleanup the inode in case of error or race with -+ * writeback of delalloc blocks. -+ */ -+ WARN_ON_ONCE(ret == -EIOCBQUEUED); -+ ext4_inode_extension_cleanup(inode, ret); -+ } - - out: - if (ilock_shared) -@@ -655,8 +630,10 @@ ext4_dax_write_iter(struct kiocb *iocb, struct iov_iter *from) - - ret = dax_iomap_rw(iocb, from, &ext4_iomap_ops); - -- if (extend) -- ret = ext4_handle_inode_extension(inode, offset, ret, count); -+ if (extend) { -+ ret = ext4_handle_inode_extension(inode, offset, ret); -+ ext4_inode_extension_cleanup(inode, ret); -+ } - out: - inode_unlock(inode); - if (ret > 0) --- -2.42.0 - diff --git a/queue-5.10/series b/queue-5.10/series index a812cb7a672..7052f4ef836 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -114,7 +114,6 @@ misc-pci_endpoint_test-add-deviceid-for-am64-and-j72.patch misc-pci_endpoint_test-add-deviceid-for-j721s2-pcie-.patch fbdev-stifb-make-the-sti-next-font-pointer-a-32-bit-.patch ima-annotate-iint-mutex-to-avoid-lockdep-false-posit.patch -ext4-properly-sync-file-size-update-after-o_sync-dir.patch driver-core-move-the-removable-attribute-from-usb-to.patch drm-amdgpu-don-t-use-atrm-for-external-devices.patch fs-add-ctime-accessors-infrastructure.patch diff --git a/queue-5.15/ext4-properly-sync-file-size-update-after-o_sync-dir.patch b/queue-5.15/ext4-properly-sync-file-size-update-after-o_sync-dir.patch deleted file mode 100644 index 7f35f1d9145..00000000000 --- a/queue-5.15/ext4-properly-sync-file-size-update-after-o_sync-dir.patch +++ /dev/null @@ -1,246 +0,0 @@ -From 91d014706a567575472e4872abeac522965cbe1f Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Fri, 13 Oct 2023 14:13:50 +0200 -Subject: ext4: properly sync file size update after O_SYNC direct IO - -From: Jan Kara - -[ Upstream commit 91562895f8030cb9a0470b1db49de79346a69f91 ] - -Gao Xiang has reported that on ext4 O_SYNC direct IO does not properly -sync file size update and thus if we crash at unfortunate moment, the -file can have smaller size although O_SYNC IO has reported successful -completion. The problem happens because update of on-disk inode size is -handled in ext4_dio_write_iter() *after* iomap_dio_rw() (and thus -dio_complete() in particular) has returned and generic_file_sync() gets -called by dio_complete(). Fix the problem by handling on-disk inode size -update directly in our ->end_io completion handler. - -References: https://lore.kernel.org/all/02d18236-26ef-09b0-90ad-030c4fe3ee20@linux.alibaba.com -Reported-by: Gao Xiang -CC: stable@vger.kernel.org -Fixes: 378f32bab371 ("ext4: introduce direct I/O write using iomap infrastructure") -Signed-off-by: Jan Kara -Tested-by: Joseph Qi -Reviewed-by: "Ritesh Harjani (IBM)" -Link: https://lore.kernel.org/r/20231013121350.26872-1-jack@suse.cz -Signed-off-by: Theodore Ts'o -Signed-off-by: Sasha Levin ---- - fs/ext4/file.c | 153 +++++++++++++++++++++---------------------------- - 1 file changed, 65 insertions(+), 88 deletions(-) - -diff --git a/fs/ext4/file.c b/fs/ext4/file.c -index 4704fe627c4e2..94ce73fadcba6 100644 ---- a/fs/ext4/file.c -+++ b/fs/ext4/file.c -@@ -279,80 +279,38 @@ static ssize_t ext4_buffered_write_iter(struct kiocb *iocb, - } - - static ssize_t ext4_handle_inode_extension(struct inode *inode, loff_t offset, -- ssize_t written, size_t count) -+ ssize_t count) - { - handle_t *handle; -- bool truncate = false; -- u8 blkbits = inode->i_blkbits; -- ext4_lblk_t written_blk, end_blk; -- int ret; -- -- /* -- * Note that EXT4_I(inode)->i_disksize can get extended up to -- * inode->i_size while the I/O was running due to writeback of delalloc -- * blocks. But, the code in ext4_iomap_alloc() is careful to use -- * zeroed/unwritten extents if this is possible; thus we won't leave -- * uninitialized blocks in a file even if we didn't succeed in writing -- * as much as we intended. -- */ -- WARN_ON_ONCE(i_size_read(inode) < EXT4_I(inode)->i_disksize); -- if (offset + count <= EXT4_I(inode)->i_disksize) { -- /* -- * We need to ensure that the inode is removed from the orphan -- * list if it has been added prematurely, due to writeback of -- * delalloc blocks. -- */ -- if (!list_empty(&EXT4_I(inode)->i_orphan) && inode->i_nlink) { -- handle = ext4_journal_start(inode, EXT4_HT_INODE, 2); -- -- if (IS_ERR(handle)) { -- ext4_orphan_del(NULL, inode); -- return PTR_ERR(handle); -- } -- -- ext4_orphan_del(handle, inode); -- ext4_journal_stop(handle); -- } -- -- return written; -- } -- -- if (written < 0) -- goto truncate; - -+ lockdep_assert_held_write(&inode->i_rwsem); - handle = ext4_journal_start(inode, EXT4_HT_INODE, 2); -- if (IS_ERR(handle)) { -- written = PTR_ERR(handle); -- goto truncate; -- } -+ if (IS_ERR(handle)) -+ return PTR_ERR(handle); - -- if (ext4_update_inode_size(inode, offset + written)) { -- ret = ext4_mark_inode_dirty(handle, inode); -+ if (ext4_update_inode_size(inode, offset + count)) { -+ int ret = ext4_mark_inode_dirty(handle, inode); - if (unlikely(ret)) { -- written = ret; - ext4_journal_stop(handle); -- goto truncate; -+ return ret; - } - } - -- /* -- * We may need to truncate allocated but not written blocks beyond EOF. -- */ -- written_blk = ALIGN(offset + written, 1 << blkbits); -- end_blk = ALIGN(offset + count, 1 << blkbits); -- if (written_blk < end_blk && ext4_can_truncate(inode)) -- truncate = true; -- -- /* -- * Remove the inode from the orphan list if it has been extended and -- * everything went OK. -- */ -- if (!truncate && inode->i_nlink) -+ if (inode->i_nlink) - ext4_orphan_del(handle, inode); - ext4_journal_stop(handle); - -- if (truncate) { --truncate: -+ return count; -+} -+ -+/* -+ * Clean up the inode after DIO or DAX extending write has completed and the -+ * inode size has been updated using ext4_handle_inode_extension(). -+ */ -+static void ext4_inode_extension_cleanup(struct inode *inode, ssize_t count) -+{ -+ lockdep_assert_held_write(&inode->i_rwsem); -+ if (count < 0) { - ext4_truncate_failed_write(inode); - /* - * If the truncate operation failed early, then the inode may -@@ -361,9 +319,28 @@ static ssize_t ext4_handle_inode_extension(struct inode *inode, loff_t offset, - */ - if (inode->i_nlink) - ext4_orphan_del(NULL, inode); -+ return; - } -+ /* -+ * If i_disksize got extended due to writeback of delalloc blocks while -+ * the DIO was running we could fail to cleanup the orphan list in -+ * ext4_handle_inode_extension(). Do it now. -+ */ -+ if (!list_empty(&EXT4_I(inode)->i_orphan) && inode->i_nlink) { -+ handle_t *handle = ext4_journal_start(inode, EXT4_HT_INODE, 2); - -- return written; -+ if (IS_ERR(handle)) { -+ /* -+ * The write has successfully completed. Not much to -+ * do with the error here so just cleanup the orphan -+ * list and hope for the best. -+ */ -+ ext4_orphan_del(NULL, inode); -+ return; -+ } -+ ext4_orphan_del(handle, inode); -+ ext4_journal_stop(handle); -+ } - } - - static int ext4_dio_write_end_io(struct kiocb *iocb, ssize_t size, -@@ -372,31 +349,22 @@ static int ext4_dio_write_end_io(struct kiocb *iocb, ssize_t size, - loff_t pos = iocb->ki_pos; - struct inode *inode = file_inode(iocb->ki_filp); - -+ if (!error && size && flags & IOMAP_DIO_UNWRITTEN) -+ error = ext4_convert_unwritten_extents(NULL, inode, pos, size); - if (error) - return error; -- -- if (size && flags & IOMAP_DIO_UNWRITTEN) { -- error = ext4_convert_unwritten_extents(NULL, inode, pos, size); -- if (error < 0) -- return error; -- } - /* -- * If we are extending the file, we have to update i_size here before -- * page cache gets invalidated in iomap_dio_rw(). Otherwise racing -- * buffered reads could zero out too much from page cache pages. Update -- * of on-disk size will happen later in ext4_dio_write_iter() where -- * we have enough information to also perform orphan list handling etc. -- * Note that we perform all extending writes synchronously under -- * i_rwsem held exclusively so i_size update is safe here in that case. -- * If the write was not extending, we cannot see pos > i_size here -- * because operations reducing i_size like truncate wait for all -- * outstanding DIO before updating i_size. -+ * Note that EXT4_I(inode)->i_disksize can get extended up to -+ * inode->i_size while the I/O was running due to writeback of delalloc -+ * blocks. But the code in ext4_iomap_alloc() is careful to use -+ * zeroed/unwritten extents if this is possible; thus we won't leave -+ * uninitialized blocks in a file even if we didn't succeed in writing -+ * as much as we intended. - */ -- pos += size; -- if (pos > i_size_read(inode)) -- i_size_write(inode, pos); -- -- return 0; -+ WARN_ON_ONCE(i_size_read(inode) < READ_ONCE(EXT4_I(inode)->i_disksize)); -+ if (pos + size <= READ_ONCE(EXT4_I(inode)->i_disksize)) -+ return size; -+ return ext4_handle_inode_extension(inode, pos, size); - } - - static const struct iomap_dio_ops ext4_dio_write_ops = { -@@ -572,9 +540,16 @@ static ssize_t ext4_dio_write_iter(struct kiocb *iocb, struct iov_iter *from) - 0); - if (ret == -ENOTBLK) - ret = 0; -- -- if (extend) -- ret = ext4_handle_inode_extension(inode, offset, ret, count); -+ if (extend) { -+ /* -+ * We always perform extending DIO write synchronously so by -+ * now the IO is completed and ext4_handle_inode_extension() -+ * was called. Cleanup the inode in case of error or race with -+ * writeback of delalloc blocks. -+ */ -+ WARN_ON_ONCE(ret == -EIOCBQUEUED); -+ ext4_inode_extension_cleanup(inode, ret); -+ } - - out: - if (ilock_shared) -@@ -655,8 +630,10 @@ ext4_dax_write_iter(struct kiocb *iocb, struct iov_iter *from) - - ret = dax_iomap_rw(iocb, from, &ext4_iomap_ops); - -- if (extend) -- ret = ext4_handle_inode_extension(inode, offset, ret, count); -+ if (extend) { -+ ret = ext4_handle_inode_extension(inode, offset, ret); -+ ext4_inode_extension_cleanup(inode, ret); -+ } - out: - inode_unlock(inode); - if (ret > 0) --- -2.42.0 - diff --git a/queue-5.15/series b/queue-5.15/series index 58f56434d60..879495ef4a3 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -55,7 +55,6 @@ asoc-sof-sof-pci-dev-add-parameter-to-override-topol.patch asoc-sof-sof-pci-dev-don-t-use-the-community-key-on-.patch asoc-sof-sof-pci-dev-fix-community-key-quirk-detecti.patch fbdev-stifb-make-the-sti-next-font-pointer-a-32-bit-.patch -ext4-properly-sync-file-size-update-after-o_sync-dir.patch fs-add-ctime-accessors-infrastructure.patch smb3-fix-caching-of-ctime-on-setxattr.patch cpufreq-imx6q-don-t-warn-for-disabling-a-non-existin.patch @@ -69,7 +68,6 @@ asoc-sof-sof-pci-dev-add-parameter-to-override-topol.patch-4431 asoc-sof-sof-pci-dev-don-t-use-the-community-key-on-.patch-15789 asoc-sof-sof-pci-dev-fix-community-key-quirk-detecti.patch-6356 fbdev-stifb-make-the-sti-next-font-pointer-a-32-bit-.patch-17578 -ext4-properly-sync-file-size-update-after-o_sync-dir.patch-12628 fs-add-ctime-accessors-infrastructure.patch-279 smb3-fix-caching-of-ctime-on-setxattr.patch-25511 cpufreq-imx6q-don-t-warn-for-disabling-a-non-existin.patch-28374 -- 2.47.3