]>
Commit | Line | Data |
---|---|---|
c9ae5004 GKH |
1 | From mingo@elte.hu Sat Feb 2 06:01:49 2008 |
2 | From: Nick Piggin <nickpiggin@yahoo.com.au> | |
3 | Date: Sat, 2 Feb 2008 15:01:17 +0100 | |
4 | Subject: fix writev regression: pan hanging unkillable and un-straceable | |
5 | To: Linus Torvalds <torvalds@linux-foundation.org> | |
6 | Cc: Andrew Morton <akpm@linux-foundation.org>, Nick Piggin <npiggin@suse.de>, "Rafael J. Wysocki" <rjw@sisk.pl>, Greg Kroah-Hartman <gregkh@suse.de>, stable@kernel.org | |
7 | Message-ID: <20080202140117.GA4038@elte.hu> | |
8 | Content-Disposition: inline | |
9 | ||
10 | From: Nick Piggin <nickpiggin@yahoo.com.au> | |
11 | ||
12 | patch 124d3b7041f9a0ca7c43a6293e1cae4576c32fd5 in mainline. | |
13 | ||
14 | Frederik Himpe reported an unkillable and un-straceable pan process. | |
15 | ||
16 | Zero length iovecs can go into an infinite loop in writev, because the | |
17 | iovec iterator does not always advance over them. | |
18 | ||
19 | The sequence required to trigger this is not trivial. I think it | |
20 | requires that a zero-length iovec be followed by a non-zero-length iovec | |
21 | which causes a pagefault in the atomic usercopy. This causes the writev | |
22 | code to drop back into single-segment copy mode, which then tries to | |
23 | copy the 0 bytes of the zero-length iovec; a zero length copy looks like | |
24 | a failure though, so it loops. | |
25 | ||
26 | Put a test into iov_iter_advance to catch zero-length iovecs. We could | |
27 | just put the test in the fallback path, but I feel it is more robust to | |
28 | skip over zero-length iovecs throughout the code (iovec iterator may be | |
29 | used in filesystems too, so it should be robust). | |
30 | ||
31 | Signed-off-by: Nick Piggin <npiggin@suse.de> | |
32 | Signed-off-by: Ingo Molnar <mingo@elte.hu> | |
33 | Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> | |
34 | Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> | |
35 | ||
36 | --- | |
37 | mm/filemap.c | 8 ++++++-- | |
38 | 1 file changed, 6 insertions(+), 2 deletions(-) | |
39 | ||
40 | --- a/mm/filemap.c | |
41 | +++ b/mm/filemap.c | |
42 | @@ -1733,7 +1733,11 @@ static void __iov_iter_advance_iov(struc | |
43 | const struct iovec *iov = i->iov; | |
44 | size_t base = i->iov_offset; | |
45 | ||
46 | - while (bytes) { | |
47 | + /* | |
48 | + * The !iov->iov_len check ensures we skip over unlikely | |
49 | + * zero-length segments. | |
50 | + */ | |
51 | + while (bytes || !iov->iov_len) { | |
52 | int copy = min(bytes, iov->iov_len - base); | |
53 | ||
54 | bytes -= copy; | |
55 | @@ -2251,6 +2255,7 @@ again: | |
56 | ||
57 | cond_resched(); | |
58 | ||
59 | + iov_iter_advance(i, copied); | |
60 | if (unlikely(copied == 0)) { | |
61 | /* | |
62 | * If we were unable to copy any data at all, we must | |
63 | @@ -2264,7 +2269,6 @@ again: | |
64 | iov_iter_single_seg_count(i)); | |
65 | goto again; | |
66 | } | |
67 | - iov_iter_advance(i, copied); | |
68 | pos += copied; | |
69 | written += copied; | |
70 |