Skip to content

Commit 296291c

Browse files
Jan Karatorvalds
authored andcommitted
mm: make sendfile(2) killable
Currently a simple program below issues a sendfile(2) system call which takes about 62 days to complete in my test KVM instance. int fd; off_t off = 0; fd = open("file", O_RDWR | O_TRUNC | O_SYNC | O_CREAT, 0644); ftruncate(fd, 2); lseek(fd, 0, SEEK_END); sendfile(fd, fd, &off, 0xfffffff); Now you should not ask kernel to do a stupid stuff like copying 256MB in 2-byte chunks and call fsync(2) after each chunk but if you do, sysadmin should have a way to stop you. We actually do have a check for fatal_signal_pending() in generic_perform_write() which triggers in this path however because we always succeed in writing something before the check is done, we return value > 0 from generic_perform_write() and thus the information about signal gets lost. Fix the problem by doing the signal check before writing anything. That way generic_perform_write() returns -EINTR, the error gets propagated up and the sendfile loop terminates early. Signed-off-by: Jan Kara <jack@suse.com> Reported-by: Dmitry Vyukov <dvyukov@google.com> Cc: Al Viro <viro@ZenIV.linux.org.uk> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent 47aee4d commit 296291c

File tree

1 file changed

+5
-4
lines changed

1 file changed

+5
-4
lines changed

mm/filemap.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2488,6 +2488,11 @@ ssize_t generic_perform_write(struct file *file,
24882488
break;
24892489
}
24902490

2491+
if (fatal_signal_pending(current)) {
2492+
status = -EINTR;
2493+
break;
2494+
}
2495+
24912496
status = a_ops->write_begin(file, mapping, pos, bytes, flags,
24922497
&page, &fsdata);
24932498
if (unlikely(status < 0))
@@ -2525,10 +2530,6 @@ ssize_t generic_perform_write(struct file *file,
25252530
written += copied;
25262531

25272532
balance_dirty_pages_ratelimited(mapping);
2528-
if (fatal_signal_pending(current)) {
2529-
status = -EINTR;
2530-
break;
2531-
}
25322533
} while (iov_iter_count(i));
25332534

25342535
return written ? written : status;

0 commit comments

Comments
 (0)