Unverified Commit 6bbb4707 authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!14271 iomap: fix zero padding data issue in concurrent append writes

parents adeca595 ad702842
Loading
Loading
Loading
Loading
+48 −0
Original line number Diff line number Diff line
@@ -1846,6 +1846,7 @@ static int iomap_add_to_ioend(struct iomap_writepage_ctx *wpc,
{
	struct iomap_folio_state *ifs = folio->private;
	size_t poff = offset_in_folio(folio, pos);
	loff_t isize = i_size_read(inode);
	int error;

	if (!wpc->ioend || !iomap_can_add_to_ioend(wpc, pos)) {
@@ -1861,7 +1862,54 @@ static int iomap_add_to_ioend(struct iomap_writepage_ctx *wpc,

	if (ifs)
		atomic_add(len, &ifs->write_bytes_pending);

	/*
	 * Clamp io_offset and io_size to the incore EOF so that ondisk
	 * file size updates in the ioend completion are byte-accurate.
	 * This avoids recovering files with zeroed tail regions when
	 * writeback races with appending writes:
	 *
	 *    Thread 1:                  Thread 2:
	 *    ------------               -----------
	 *    write [A, A+B]
	 *    update inode size to A+B
	 *    submit I/O [A, A+BS]
	 *                               write [A+B, A+B+C]
	 *                               update inode size to A+B+C
	 *    <I/O completes, updates disk size to min(A+B+C, A+BS)>
	 *    <power failure>
	 *
	 *  After reboot:
	 *    1) with A+B+C < A+BS, the file has zero padding in range
	 *       [A+B, A+B+C]
	 *
	 *    |<     Block Size (BS)   >|
	 *    |DDDDDDDDDDDD0000000000000|
	 *    ^           ^        ^
	 *    A          A+B     A+B+C
	 *                       (EOF)
	 *
	 *    2) with A+B+C > A+BS, the file has zero padding in range
	 *       [A+B, A+BS]
	 *
	 *    |<     Block Size (BS)   >|<     Block Size (BS)    >|
	 *    |DDDDDDDDDDDD0000000000000|00000000000000000000000000|
	 *    ^           ^             ^           ^
	 *    A          A+B           A+BS       A+B+C
	 *                             (EOF)
	 *
	 *    D = Valid Data
	 *    0 = Zero Padding
	 *
	 * Note that this defeats the ability to chain the ioends of
	 * appending writes. Writeback beyond EOF block may occur in
	 * concurrent scenarios(e.g. racing with truncate) and io_size
	 * should not be trimmed in such cases.
	 */
	wpc->ioend->io_size += len;
	if (pos < isize && pos + len > isize)
		wpc->ioend->io_size = isize - wpc->ioend->io_offset;

	wbc_account_cgroup_owner(wbc, &folio->page, len);
	return 0;
}
+1 −1
Original line number Diff line number Diff line
@@ -318,7 +318,7 @@ struct iomap_ioend {
	u16			io_type;
	u16			io_flags;	/* IOMAP_F_* */
	struct inode		*io_inode;	/* file being written to */
	size_t			io_size;	/* size of the extent */
	size_t			io_size;	/* size of data within eof */
	loff_t			io_offset;	/* offset in the file */
	sector_t		io_sector;	/* start sector of ioend */
	struct bio		io_bio;		/* MUST BE LAST! */