forked from mirrors/linux
		
	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>
			
			
This commit is contained in:
		
							parent
							
								
									47aee4d8e3
								
							
						
					
					
						commit
						296291cdd1
					
				
					 1 changed files with 5 additions and 4 deletions
				
			
		| 
						 | 
					@ -2488,6 +2488,11 @@ ssize_t generic_perform_write(struct file *file,
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (fatal_signal_pending(current)) {
 | 
				
			||||||
 | 
								status = -EINTR;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		status = a_ops->write_begin(file, mapping, pos, bytes, flags,
 | 
							status = a_ops->write_begin(file, mapping, pos, bytes, flags,
 | 
				
			||||||
						&page, &fsdata);
 | 
											&page, &fsdata);
 | 
				
			||||||
		if (unlikely(status < 0))
 | 
							if (unlikely(status < 0))
 | 
				
			||||||
| 
						 | 
					@ -2525,10 +2530,6 @@ ssize_t generic_perform_write(struct file *file,
 | 
				
			||||||
		written += copied;
 | 
							written += copied;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		balance_dirty_pages_ratelimited(mapping);
 | 
							balance_dirty_pages_ratelimited(mapping);
 | 
				
			||||||
		if (fatal_signal_pending(current)) {
 | 
					 | 
				
			||||||
			status = -EINTR;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} while (iov_iter_count(i));
 | 
						} while (iov_iter_count(i));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return written ? written : status;
 | 
						return written ? written : status;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue