+++ /dev/null
-From jiangying8582@126.com Thu Aug 6 12:24:48 2020
-From: Jiang Ying <jiangying8582@126.com>
-Date: Thu, 6 Aug 2020 17:38:11 +0800
-Subject: ext4: fix direct I/O read error for kernel stable rc4.4
-To: tytso@mit.edu, adilger.kernel@dilger.ca, linux-ext4@vger.kernel.org, linux-kernel@vger.kernel.org, jack@suse.cz, stable@vger.kernel.org
-Cc: wanglong19@meituan.com, heguanjun@meituan.com
-Message-ID: <1596706691-82760-1-git-send-email-jiangying8582@126.com>
-
-From: Jiang Ying <jiangying8582@126.com>
-
-This patch is used to fix ext4 direct I/O read error when
-the read size is not aligned with block size.
-
-Then, I will use a test to explain the error.
-
-(1) Make a file that is not aligned with block size:
- $dd if=/dev/zero of=./test.jar bs=1000 count=3
-
-(2) I wrote a source file named "direct_io_read_file.c" as following:
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <sys/file.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <string.h>
- #define BUF_SIZE 1024
-
- int main()
- {
- int fd;
- int ret;
-
- unsigned char *buf;
- ret = posix_memalign((void **)&buf, 512, BUF_SIZE);
- if (ret) {
- perror("posix_memalign failed");
- exit(1);
- }
- fd = open("./test.jar", O_RDONLY | O_DIRECT, 0755);
- if (fd < 0){
- perror("open ./test.jar failed");
- exit(1);
- }
-
- do {
- ret = read(fd, buf, BUF_SIZE);
- printf("ret=%d\n",ret);
- if (ret < 0) {
- perror("write test.jar failed");
- }
- } while (ret > 0);
-
- free(buf);
- close(fd);
- }
-
-(3) Compile the source file:
- $gcc direct_io_read_file.c -D_GNU_SOURCE
-
-(4) Run the test program:
- $./a.out
-
- The result is as following:
- ret=1024
- ret=1024
- ret=952
- ret=-1
- write test.jar failed: Invalid argument.
-
-I have tested this program on XFS filesystem, XFS does not have
-this problem, because XFS use iomap_dio_rw() to do direct I/O
-read. And the comparing between read offset and file size is done
-in iomap_dio_rw(), the code is as following:
-
- if (pos < size) {
- retval = filemap_write_and_wait_range(mapping, pos,
- pos + iov_length(iov, nr_segs) - 1);
-
- if (!retval) {
- retval = mapping->a_ops->direct_IO(READ, iocb,
- iov, pos, nr_segs);
- }
- ...
- }
-
-...only when "pos < size", direct I/O can be done, or 0 will be return.
-
-I have tested the fix patch on Ext4, it is up to the mustard of
-EINVAL in man2(read) as following:
- #include <unistd.h>
- ssize_t read(int fd, void *buf, size_t count);
-
- EINVAL
- fd is attached to an object which is unsuitable for reading;
- or the file was opened with the O_DIRECT flag, and either the
- address specified in buf, the value specified in count, or the
- current file offset is not suitably aligned.
-
-So I think this patch can be applied to fix ext4 direct I/O error.
-
-However Ext4 introduces direct I/O read using iomap infrastructure
-on kernel 5.5, the patch is commit <b1b4705d54ab>
-("ext4: introduce direct I/O read using iomap infrastructure"),
-then Ext4 will be the same as XFS, they all use iomap_dio_rw() to do direct
-I/O read. So this problem does not exist on kernel 5.5 for Ext4.
-
->From above description, we can see this problem exists on all the kernel
-versions between kernel 3.14 and kernel 5.4. It will cause the Applications
-to fail to read. For example, when the search service downloads a new full
-index file, the search engine is loading the previous index file and is
-processing the search request, it can not use buffer io that may squeeze
-the previous index file in use from pagecache, so the serch service must
-use direct I/O read.
-
-Please apply this patch on these kernel versions, or please use the method
-on kernel 5.5 to fix this problem.
-
-Fixes: 9fe55eea7e4b ("Fix race when checking i_size on direct i/o read")
-Reviewed-by: Jan Kara <jack@suse.cz>
-Reviewed-by: Wang Long <wanglong19@meituan.com>
-Signed-off-by: Jiang Ying <jiangying8582@126.com>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-
----
- fs/ext4/inode.c | 7 +++++++
- 1 file changed, 7 insertions(+)
-
---- a/fs/ext4/inode.c
-+++ b/fs/ext4/inode.c
-@@ -3608,6 +3608,13 @@ static ssize_t ext4_direct_IO(struct kio
- loff_t offset = iocb->ki_pos;
- ssize_t ret;
-
-+ if (iov_iter_rw(iter) == READ) {
-+ loff_t size = i_size_read(inode);
-+
-+ if (offset >= size)
-+ return 0;
-+ }
-+
- #ifdef CONFIG_EXT4_FS_ENCRYPTION
- if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode))
- return 0;