summaryrefslogtreecommitdiff
path: root/mm
diff options
context:
space:
mode:
authorJan Kara <jack@suse.com>2015-10-22 23:32:21 +0300
committerBen Hutchings <ben@decadent.org.uk>2015-11-17 18:54:44 +0300
commit279fc860b960bfa4bff4083607a5647d3b0982cb (patch)
treedcf122efacbf4351fe80c33daabeade5b6f71f78 /mm
parent08fd1afd90a71c8e061061c7153808b36cf6b8f7 (diff)
downloadlinux-279fc860b960bfa4bff4083607a5647d3b0982cb.tar.xz
mm: make sendfile(2) killable
commit 296291cdd1629c308114504b850dc343eabc2782 upstream. 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> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Diffstat (limited to 'mm')
-rw-r--r--mm/filemap.c9
1 files changed, 5 insertions, 4 deletions
diff --git a/mm/filemap.c b/mm/filemap.c
index 6c009c258363..f2f52478dd75 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -2408,6 +2408,11 @@ again:
break;
}
+ if (fatal_signal_pending(current)) {
+ status = -EINTR;
+ break;
+ }
+
status = a_ops->write_begin(file, mapping, pos, bytes, flags,
&page, &fsdata);
if (unlikely(status))
@@ -2448,10 +2453,6 @@ again:
written += copied;
balance_dirty_pages_ratelimited(mapping);
- if (fatal_signal_pending(current)) {
- status = -EINTR;
- break;
- }
} while (iov_iter_count(i));
return written ? written : status;