shmem: minor fixes to splice-read implementation
authorHugh Dickins <hughd@google.com>
Sun, 23 Jul 2023 21:05:54 +0000 (14:05 -0700)
committerAndrew Morton <akpm@linux-foundation.org>
Thu, 27 Jul 2023 20:07:03 +0000 (13:07 -0700)
HWPoison: my reading of folio_test_hwpoison() is that it only tests the
head page of a large folio, whereas splice_folio_into_pipe() will splice
as much of the folio as it can: so for safety we should also check the
has_hwpoisoned flag, set if any of the folio's pages are hwpoisoned.
(Perhaps that ugliness can be improved at the mm end later.)

The call to splice_zeropage_into_pipe() risked overrunning past EOF: ask
it for "part" not "len".

Link: https://lkml.kernel.org/r/32c72c9c-72a8-115f-407d-f0148f368@google.com
Fixes: bd194b187115 ("shmem: Implement splice-read")
Signed-off-by: Hugh Dickins <hughd@google.com>
Reviewed-by: David Howells <dhowells@redhat.com>
Cc: David Hildenbrand <david@redhat.com>
Cc: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
mm/shmem.c

index 2f2e0e6..f5af4b9 100644 (file)
@@ -2796,7 +2796,8 @@ static ssize_t shmem_file_splice_read(struct file *in, loff_t *ppos,
                if (*ppos >= i_size_read(inode))
                        break;
 
-               error = shmem_get_folio(inode, *ppos / PAGE_SIZE, &folio, SGP_READ);
+               error = shmem_get_folio(inode, *ppos / PAGE_SIZE, &folio,
+                                       SGP_READ);
                if (error) {
                        if (error == -EINVAL)
                                error = 0;
@@ -2805,7 +2806,9 @@ static ssize_t shmem_file_splice_read(struct file *in, loff_t *ppos,
                if (folio) {
                        folio_unlock(folio);
 
-                       if (folio_test_hwpoison(folio)) {
+                       if (folio_test_hwpoison(folio) ||
+                           (folio_test_large(folio) &&
+                            folio_test_has_hwpoisoned(folio))) {
                                error = -EIO;
                                break;
                        }
@@ -2841,7 +2844,7 @@ static ssize_t shmem_file_splice_read(struct file *in, loff_t *ppos,
                        folio_put(folio);
                        folio = NULL;
                } else {
-                       n = splice_zeropage_into_pipe(pipe, *ppos, len);
+                       n = splice_zeropage_into_pipe(pipe, *ppos, part);
                }
 
                if (!n)