diff --git a/SOURCES/e2fsprogs-1.46.1-libext2fs-fix-un-ix_io-s-Direct-I-O-support.patch b/SOURCES/e2fsprogs-1.46.1-libext2fs-fix-un-ix_io-s-Direct-I-O-support.patch new file mode 100644 index 0000000..8bcd9cb --- /dev/null +++ b/SOURCES/e2fsprogs-1.46.1-libext2fs-fix-un-ix_io-s-Direct-I-O-support.patch @@ -0,0 +1,254 @@ +From c001596110e834a85b01a47a20811b318cb3b9e4 Mon Sep 17 00:00:00 2001 +From: Theodore Ts'o +Date: Fri, 26 Feb 2021 17:41:06 -0500 +Subject: [PATCH] libext2fs: fix unix_io's Direct I/O support + +The previous Direct I/O support worked on HDD's with 512 byte logical +sector sizes, and on FreeBSD which required 4k aligned memory buffers. +However, it was incomplete and was not correctly working on HDD's with +4k logical sector sizes (aka Advanced Format Disks). + +Based on a patch from Alexey Lyashkov but +rewritten to work with the latest e2fsprogs and to minimize changes to +make it easier to review. + +Signed-off-by: Theodore Ts'o +Reported-by: Artem Blagodarenko +Signed-off-by: Pavel Reichl +--- + lib/ext2fs/io_manager.c | 6 ++- + lib/ext2fs/unix_io.c | 87 +++++++++++++++++++++++++++++++---------- + 2 files changed, 70 insertions(+), 23 deletions(-) + +Index: e2fsprogs-1.45.6/lib/ext2fs/io_manager.c +=================================================================== +--- e2fsprogs-1.45.6.orig/lib/ext2fs/io_manager.c ++++ e2fsprogs-1.45.6/lib/ext2fs/io_manager.c +@@ -134,9 +134,11 @@ errcode_t io_channel_alloc_buf(io_channe + else + size = -count; + +- if (io->align) ++ if (io->align) { ++ if (io->align > size) ++ size = io->align; + return ext2fs_get_memalign(size, io->align, ptr); +- else ++ } else + return ext2fs_get_mem(size, ptr); + } + +Index: e2fsprogs-1.45.6/lib/ext2fs/unix_io.c +=================================================================== +--- e2fsprogs-1.45.6.orig/lib/ext2fs/unix_io.c ++++ e2fsprogs-1.45.6/lib/ext2fs/unix_io.c +@@ -165,13 +165,15 @@ static errcode_t raw_read_blk(io_channel + int actual = 0; + unsigned char *buf = bufv; + ssize_t really_read = 0; ++ unsigned long long aligned_blk; ++ int align_size, offset; + + size = (count < 0) ? -count : (ext2_loff_t) count * channel->block_size; + data->io_stats.bytes_read += size; + location = ((ext2_loff_t) block * channel->block_size) + data->offset; + + if (data->flags & IO_FLAG_FORCE_BOUNCE) { +- if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { ++ if (ext2fs_llseek(data->dev, location, SEEK_SET) < 0) { + retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; + goto error_out; + } +@@ -182,6 +184,7 @@ static errcode_t raw_read_blk(io_channel + /* Try an aligned pread */ + if ((channel->align == 0) || + (IS_ALIGNED(buf, channel->align) && ++ IS_ALIGNED(location, channel->align) && + IS_ALIGNED(size, channel->align))) { + actual = pread64(data->dev, buf, size, location); + if (actual == size) +@@ -193,6 +196,7 @@ static errcode_t raw_read_blk(io_channel + if ((sizeof(off_t) >= sizeof(ext2_loff_t)) && + ((channel->align == 0) || + (IS_ALIGNED(buf, channel->align) && ++ IS_ALIGNED(location, channel->align) && + IS_ALIGNED(size, channel->align)))) { + actual = pread(data->dev, buf, size, location); + if (actual == size) +@@ -201,12 +205,13 @@ static errcode_t raw_read_blk(io_channel + } + #endif /* HAVE_PREAD */ + +- if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { ++ if (ext2fs_llseek(data->dev, location, SEEK_SET) < 0) { + retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; + goto error_out; + } + if ((channel->align == 0) || + (IS_ALIGNED(buf, channel->align) && ++ IS_ALIGNED(location, channel->align) && + IS_ALIGNED(size, channel->align))) { + actual = read(data->dev, buf, size); + if (actual != size) { +@@ -231,21 +236,37 @@ static errcode_t raw_read_blk(io_channel + * to the O_DIRECT rules, so we need to do this the hard way... + */ + bounce_read: ++ if ((channel->block_size > channel->align) && ++ (channel->block_size % channel->align) == 0) ++ align_size = channel->block_size; ++ else ++ align_size = channel->align; ++ aligned_blk = location / align_size; ++ offset = location % align_size; ++ ++ if (ext2fs_llseek(data->dev, aligned_blk * align_size, SEEK_SET) < 0) { ++ retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; ++ goto error_out; ++ } + while (size > 0) { +- actual = read(data->dev, data->bounce, channel->block_size); +- if (actual != channel->block_size) { ++ actual = read(data->dev, data->bounce, align_size); ++ if (actual != align_size) { + actual = really_read; + buf -= really_read; + size += really_read; + goto short_read; + } +- actual = size; +- if (size > channel->block_size) +- actual = channel->block_size; +- memcpy(buf, data->bounce, actual); ++ if ((actual + offset) > align_size) ++ actual = align_size - offset; ++ if (actual > size) ++ actual = size; ++ memcpy(buf, data->bounce + offset, actual); ++ + really_read += actual; + size -= actual; + buf += actual; ++ offset = 0; ++ aligned_blk++; + } + return 0; + +@@ -268,6 +289,8 @@ static errcode_t raw_write_blk(io_channe + int actual = 0; + errcode_t retval; + const unsigned char *buf = bufv; ++ unsigned long long aligned_blk; ++ int align_size, offset; + + if (count == 1) + size = channel->block_size; +@@ -282,7 +305,7 @@ static errcode_t raw_write_blk(io_channe + location = ((ext2_loff_t) block * channel->block_size) + data->offset; + + if (data->flags & IO_FLAG_FORCE_BOUNCE) { +- if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { ++ if (ext2fs_llseek(data->dev, location, SEEK_SET) < 0) { + retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; + goto error_out; + } +@@ -293,6 +316,7 @@ static errcode_t raw_write_blk(io_channe + /* Try an aligned pwrite */ + if ((channel->align == 0) || + (IS_ALIGNED(buf, channel->align) && ++ IS_ALIGNED(location, channel->align) && + IS_ALIGNED(size, channel->align))) { + actual = pwrite64(data->dev, buf, size, location); + if (actual == size) +@@ -303,6 +327,7 @@ static errcode_t raw_write_blk(io_channe + if ((sizeof(off_t) >= sizeof(ext2_loff_t)) && + ((channel->align == 0) || + (IS_ALIGNED(buf, channel->align) && ++ IS_ALIGNED(location, channel->align) && + IS_ALIGNED(size, channel->align)))) { + actual = pwrite(data->dev, buf, size, location); + if (actual == size) +@@ -310,13 +335,14 @@ static errcode_t raw_write_blk(io_channe + } + #endif /* HAVE_PWRITE */ + +- if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { ++ if (ext2fs_llseek(data->dev, location, SEEK_SET) < 0) { + retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; + goto error_out; + } + + if ((channel->align == 0) || + (IS_ALIGNED(buf, channel->align) && ++ IS_ALIGNED(location, channel->align) && + IS_ALIGNED(size, channel->align))) { + actual = write(data->dev, buf, size); + if (actual < 0) { +@@ -340,37 +366,56 @@ static errcode_t raw_write_blk(io_channe + * to the O_DIRECT rules, so we need to do this the hard way... + */ + bounce_write: ++ if ((channel->block_size > channel->align) && ++ (channel->block_size % channel->align) == 0) ++ align_size = channel->block_size; ++ else ++ align_size = channel->align; ++ aligned_blk = location / align_size; ++ offset = location % align_size; ++ + while (size > 0) { +- if (size < channel->block_size) { ++ int actual_w; ++ ++ if (size < align_size || offset) { ++ if (ext2fs_llseek(data->dev, aligned_blk * align_size, ++ SEEK_SET) < 0) { ++ retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; ++ goto error_out; ++ } + actual = read(data->dev, data->bounce, +- channel->block_size); +- if (actual != channel->block_size) { ++ align_size); ++ if (actual != align_size) { + if (actual < 0) { + retval = errno; + goto error_out; + } + memset((char *) data->bounce + actual, 0, +- channel->block_size - actual); ++ align_size - actual); + } + } + actual = size; +- if (size > channel->block_size) +- actual = channel->block_size; +- memcpy(data->bounce, buf, actual); +- if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) { ++ if ((actual + offset) > align_size) ++ actual = align_size - offset; ++ if (actual > size) ++ actual = size; ++ memcpy(((char *)data->bounce) + offset, buf, actual); ++ if (ext2fs_llseek(data->dev, aligned_blk * align_size, SEEK_SET) < 0) { + retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; + goto error_out; + } +- actual = write(data->dev, data->bounce, channel->block_size); +- if (actual < 0) { ++ actual_w = write(data->dev, data->bounce, align_size); ++ if (actual_w < 0) { + retval = errno; + goto error_out; + } +- if (actual != channel->block_size) ++ if (actual_w != align_size) + goto short_write; + size -= actual; + buf += actual; + location += actual; ++ aligned_blk++; ++ offset = 0; + } + return 0; + diff --git a/SOURCES/e2fsprogs-1.46.2-libext2s-fix-unix_io-with-IO_FLAG_FORCE_BOUNCE-flag-.patch b/SOURCES/e2fsprogs-1.46.2-libext2s-fix-unix_io-with-IO_FLAG_FORCE_BOUNCE-flag-.patch new file mode 100644 index 0000000..eb7469e --- /dev/null +++ b/SOURCES/e2fsprogs-1.46.2-libext2s-fix-unix_io-with-IO_FLAG_FORCE_BOUNCE-flag-.patch @@ -0,0 +1,195 @@ +From e1af249abafbf4b08c5b55cab6a0564170ce0f7d Mon Sep 17 00:00:00 2001 +From: Theodore Ts'o +Date: Sun, 28 Feb 2021 09:12:47 -0500 +Subject: [PATCH] libext2s: fix unix_io with IO_FLAG_FORCE_BOUNCE flag set + +The bounce read/write code would crash with a floating point exception +if alignment is set to 0. + +Fixes: c001596110e8 ("libext2fs: fix unix_io's Direct I/O support") +Signed-off-by: Theodore Ts'o +Signed-off-by: Pavel Reichl +--- + lib/ext2fs/unix_io.c | 18 +++---- + tests/u_bounce_io/expect.1 | 106 +++++++++++++++++++++++++++++++++++++ + tests/u_bounce_io/script | 9 ++++ + 3 files changed, 121 insertions(+), 12 deletions(-) + create mode 100644 tests/u_bounce_io/expect.1 + create mode 100644 tests/u_bounce_io/script + +Index: e2fsprogs-1.45.6/lib/ext2fs/unix_io.c +=================================================================== +--- e2fsprogs-1.45.6.orig/lib/ext2fs/unix_io.c ++++ e2fsprogs-1.45.6/lib/ext2fs/unix_io.c +@@ -172,13 +172,8 @@ static errcode_t raw_read_blk(io_channel + data->io_stats.bytes_read += size; + location = ((ext2_loff_t) block * channel->block_size) + data->offset; + +- if (data->flags & IO_FLAG_FORCE_BOUNCE) { +- if (ext2fs_llseek(data->dev, location, SEEK_SET) < 0) { +- retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; +- goto error_out; +- } ++ if (data->flags & IO_FLAG_FORCE_BOUNCE) + goto bounce_read; +- } + + #ifdef HAVE_PREAD64 + /* Try an aligned pread */ +@@ -236,6 +231,8 @@ static errcode_t raw_read_blk(io_channel + * to the O_DIRECT rules, so we need to do this the hard way... + */ + bounce_read: ++ if (channel->align == 0) ++ channel->align = 1; + if ((channel->block_size > channel->align) && + (channel->block_size % channel->align) == 0) + align_size = channel->block_size; +@@ -304,13 +301,8 @@ static errcode_t raw_write_blk(io_channe + + location = ((ext2_loff_t) block * channel->block_size) + data->offset; + +- if (data->flags & IO_FLAG_FORCE_BOUNCE) { +- if (ext2fs_llseek(data->dev, location, SEEK_SET) < 0) { +- retval = errno ? errno : EXT2_ET_LLSEEK_FAILED; +- goto error_out; +- } ++ if (data->flags & IO_FLAG_FORCE_BOUNCE) + goto bounce_write; +- } + + #ifdef HAVE_PWRITE64 + /* Try an aligned pwrite */ +@@ -366,6 +358,8 @@ static errcode_t raw_write_blk(io_channe + * to the O_DIRECT rules, so we need to do this the hard way... + */ + bounce_write: ++ if (channel->align == 0) ++ channel->align = 1; + if ((channel->block_size > channel->align) && + (channel->block_size % channel->align) == 0) + align_size = channel->block_size; +Index: e2fsprogs-1.45.6/tests/u_bounce_io/expect.1 +=================================================================== +--- /dev/null ++++ e2fsprogs-1.45.6/tests/u_bounce_io/expect.1 +@@ -0,0 +1,105 @@ ++Creating filesystem with 65536 1k blocks and 16384 inodes ++Superblock backups stored on blocks: ++ 8193, 24577, 40961, 57345 ++ ++Allocating group tables: done ++Writing inode tables: done ++Writing superblocks and filesystem accounting information: done ++ ++Filesystem features: ext_attr resize_inode dir_index filetype sparse_super ++Pass 1: Checking inodes, blocks, and sizes ++Pass 2: Checking directory structure ++Pass 3: Checking directory connectivity ++Pass 4: Checking reference counts ++Pass 5: Checking group summary information ++test_filesys: 11/16384 files (0.0% non-contiguous), 3364/65536 blocks ++Exit status is 0 ++Filesystem volume name: ++Last mounted on: ++Filesystem magic number: 0xEF53 ++Filesystem revision #: 1 (dynamic) ++Filesystem features: ext_attr resize_inode dir_index filetype sparse_super ++Default mount options: (none) ++Filesystem state: clean ++Errors behavior: Continue ++Filesystem OS type: Linux ++Inode count: 16384 ++Block count: 65536 ++Reserved block count: 3276 ++Free blocks: 62172 ++Free inodes: 16373 ++First block: 1 ++Block size: 1024 ++Fragment size: 1024 ++Reserved GDT blocks: 255 ++Blocks per group: 8192 ++Fragments per group: 8192 ++Inodes per group: 2048 ++Inode blocks per group: 256 ++Mount count: 0 ++Check interval: 15552000 (6 months) ++Reserved blocks uid: 0 ++Reserved blocks gid: 0 ++First inode: 11 ++Inode size: 128 ++Default directory hash: half_md4 ++ ++ ++Group 0: (Blocks 1-8192) ++ Primary superblock at 1, Group descriptors at 2-2 ++ Reserved GDT blocks at 3-257 ++ Block bitmap at 258 (+257), Inode bitmap at 259 (+258) ++ Inode table at 260-515 (+259) ++ 7663 free blocks, 2037 free inodes, 2 directories ++ Free blocks: 530-8192 ++ Free inodes: 12-2048 ++Group 1: (Blocks 8193-16384) ++ Backup superblock at 8193, Group descriptors at 8194-8194 ++ Reserved GDT blocks at 8195-8449 ++ Block bitmap at 8450 (+257), Inode bitmap at 8451 (+258) ++ Inode table at 8452-8707 (+259) ++ 7677 free blocks, 2048 free inodes, 0 directories ++ Free blocks: 8708-16384 ++ Free inodes: 2049-4096 ++Group 2: (Blocks 16385-24576) ++ Block bitmap at 16385 (+0), Inode bitmap at 16386 (+1) ++ Inode table at 16387-16642 (+2) ++ 7934 free blocks, 2048 free inodes, 0 directories ++ Free blocks: 16643-24576 ++ Free inodes: 4097-6144 ++Group 3: (Blocks 24577-32768) ++ Backup superblock at 24577, Group descriptors at 24578-24578 ++ Reserved GDT blocks at 24579-24833 ++ Block bitmap at 24834 (+257), Inode bitmap at 24835 (+258) ++ Inode table at 24836-25091 (+259) ++ 7677 free blocks, 2048 free inodes, 0 directories ++ Free blocks: 25092-32768 ++ Free inodes: 6145-8192 ++Group 4: (Blocks 32769-40960) ++ Block bitmap at 32769 (+0), Inode bitmap at 32770 (+1) ++ Inode table at 32771-33026 (+2) ++ 7934 free blocks, 2048 free inodes, 0 directories ++ Free blocks: 33027-40960 ++ Free inodes: 8193-10240 ++Group 5: (Blocks 40961-49152) ++ Backup superblock at 40961, Group descriptors at 40962-40962 ++ Reserved GDT blocks at 40963-41217 ++ Block bitmap at 41218 (+257), Inode bitmap at 41219 (+258) ++ Inode table at 41220-41475 (+259) ++ 7677 free blocks, 2048 free inodes, 0 directories ++ Free blocks: 41476-49152 ++ Free inodes: 10241-12288 ++Group 6: (Blocks 49153-57344) ++ Block bitmap at 49153 (+0), Inode bitmap at 49154 (+1) ++ Inode table at 49155-49410 (+2) ++ 7934 free blocks, 2048 free inodes, 0 directories ++ Free blocks: 49411-57344 ++ Free inodes: 12289-14336 ++Group 7: (Blocks 57345-65535) ++ Backup superblock at 57345, Group descriptors at 57346-57346 ++ Reserved GDT blocks at 57347-57601 ++ Block bitmap at 57602 (+257), Inode bitmap at 57603 (+258) ++ Inode table at 57604-57859 (+259) ++ 7676 free blocks, 2048 free inodes, 0 directories ++ Free blocks: 57860-65535 ++ Free inodes: 14337-16384 +Index: e2fsprogs-1.45.6/tests/u_bounce_io/script +=================================================================== +--- /dev/null ++++ e2fsprogs-1.45.6/tests/u_bounce_io/script +@@ -0,0 +1,9 @@ ++DESCRIPTION="bounce I/O in unix_io" ++DUMPE2FS_IGNORE_80COL=1 ++export DUMPE2FS_IGNORE_80COL ++UNIX_IO_FORCE_BOUNCE=yes ++export UNIX_IO_FORCE_BOUNCE ++FS_SIZE=65536 ++. $cmd_dir/run_mke2fs ++unset DUMPE2FS_IGNORE_80COL ++unset UNIX_IO_FORCE_BOUNCE diff --git a/SPECS/e2fsprogs.spec b/SPECS/e2fsprogs.spec index 7235568..5b5a10e 100644 --- a/SPECS/e2fsprogs.spec +++ b/SPECS/e2fsprogs.spec @@ -1,7 +1,7 @@ Summary: Utilities for managing ext2, ext3, and ext4 file systems Name: e2fsprogs Version: 1.45.6 -Release: 6%{?dist} +Release: 7%{?dist} # License tags based on COPYING file distinctions for various components License: GPLv2 @@ -88,6 +88,8 @@ Patch57: e2fsprogs-1.45.6-libext2fs-add-sanity-check-to-extent-manipulation.patc Patch58: e2fsprogs-1.45.6-libss-fix-possible-NULL-pointer-dereferece-on-alloca.patch Patch59: e2fsprogs-1.45.7-libext2fs-retry-reading-superblock-on-open-when-chec.patch Patch60: e2fsprogs-1.47.1-resize2fs-use-Direct-I-O-when-reading-the-superblock.patch +Patch61: e2fsprogs-1.46.1-libext2fs-fix-un-ix_io-s-Direct-I-O-support.patch +Patch62: e2fsprogs-1.46.2-libext2s-fix-unix_io-with-IO_FLAG_FORCE_BOUNCE-flag-.patch %description The e2fsprogs package contains a number of utilities for creating, @@ -267,6 +269,8 @@ It was originally inspired by the Multics SubSystem library. %patch58 -p1 %patch59 -p1 %patch60 -p1 +%patch61 -p1 +%patch62 -p1 %build %configure CFLAGS="$RPM_OPT_FLAGS -fno-strict-aliasing" \ @@ -429,6 +433,10 @@ exit 0 %{_libdir}/pkgconfig/ss.pc %changelog +* Mon Sep 01 2025 Pavel Reichl +- libext2fs: fix unix_io's Direct I/O support +- Related: RHEL-106939 + * Thu Jan 23 2025 Pavel Reichl 1.45.6-6 - Fix e2fsprogs: online resize fails - Related: RHEL-60512