aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Dike <jdike@addtoit.com>2007-02-16 04:27:21 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-16 11:13:56 -0500
commit838e56a11cdb2abaf490eb7879ab021db938d47d (patch)
tree4a651d8190b6dab23040c405c1cac3645844372c
parentbeb497ab48b1639282129f7bc18fef311fffff3d (diff)
[PATCH] uml: fix 2.6.20 hang
A previous cleanup misused need_poll, which had a fairly broken interface. It implemented a growable array, changing the used elements count itself, but leaving it up to the caller to fill in the actual elements, including the entire array if the array had to be reallocated. This worked because the previous users were switching between two such structures, and the elements were copied from the inactive array to the active array after making sure the active array had enough room. maybe_sigio_broken was made to use need_poll, but it was operating on a single array, so when the buffer was reallocated, the previous contents were lost. This patch makes need_poll implement more sane semantics. It merely assures that the array is of the proper size and that the contents are preserved. It is up to the caller to adjust the used elements count and to ensure that the proper elements are resent. This manifested itself as a hang in 2.6.20 as the uninitialized buffer convinced UML that one of its own file descriptors didn't support SIGIO and needed to be watched by poll in a separate thread. The result was an interrupt flood as control traffic over this descriptor sparked interrupts, which resulted in more control traffic, ad nauseum. Signed-off-by: Jeff Dike <jdike@addtoit.com> Cc: <stable@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--arch/um/os-Linux/sigio.c38
1 files changed, 20 insertions, 18 deletions
diff --git a/arch/um/os-Linux/sigio.c b/arch/um/os-Linux/sigio.c
index 925a65240cfe..b2e1fd8e3571 100644
--- a/arch/um/os-Linux/sigio.c
+++ b/arch/um/os-Linux/sigio.c
@@ -97,20 +97,22 @@ static int write_sigio_thread(void *unused)
97 97
98static int need_poll(struct pollfds *polls, int n) 98static int need_poll(struct pollfds *polls, int n)
99{ 99{
100 if(n <= polls->size){ 100 struct pollfd *new;
101 polls->used = n; 101
102 if(n <= polls->size)
102 return 0; 103 return 0;
103 } 104
104 kfree(polls->poll); 105 new = um_kmalloc_atomic(n * sizeof(struct pollfd));
105 polls->poll = um_kmalloc_atomic(n * sizeof(struct pollfd)); 106 if(new == NULL){
106 if(polls->poll == NULL){
107 printk("need_poll : failed to allocate new pollfds\n"); 107 printk("need_poll : failed to allocate new pollfds\n");
108 polls->size = 0;
109 polls->used = 0;
110 return -ENOMEM; 108 return -ENOMEM;
111 } 109 }
110
111 memcpy(new, polls->poll, polls->used * sizeof(struct pollfd));
112 kfree(polls->poll);
113
114 polls->poll = new;
112 polls->size = n; 115 polls->size = n;
113 polls->used = n;
114 return 0; 116 return 0;
115} 117}
116 118
@@ -171,15 +173,15 @@ int add_sigio_fd(int fd)
171 goto out; 173 goto out;
172 } 174 }
173 175
174 n = current_poll.used + 1; 176 n = current_poll.used;
175 err = need_poll(&next_poll, n); 177 err = need_poll(&next_poll, n + 1);
176 if(err) 178 if(err)
177 goto out; 179 goto out;
178 180
179 for(i = 0; i < current_poll.used; i++) 181 memcpy(next_poll.poll, current_poll.poll,
180 next_poll.poll[i] = current_poll.poll[i]; 182 current_poll.used * sizeof(struct pollfd));
181 183 next_poll.poll[n] = *p;
182 next_poll.poll[n - 1] = *p; 184 next_poll.used = n + 1;
183 update_thread(); 185 update_thread();
184 out: 186 out:
185 sigio_unlock(); 187 sigio_unlock();
@@ -214,6 +216,7 @@ int ignore_sigio_fd(int fd)
214 if(p->fd != fd) 216 if(p->fd != fd)
215 next_poll.poll[n++] = *p; 217 next_poll.poll[n++] = *p;
216 } 218 }
219 next_poll.used = current_poll.used - 1;
217 220
218 update_thread(); 221 update_thread();
219 out: 222 out:
@@ -331,10 +334,9 @@ void maybe_sigio_broken(int fd, int read)
331 334
332 sigio_lock(); 335 sigio_lock();
333 err = need_poll(&all_sigio_fds, all_sigio_fds.used + 1); 336 err = need_poll(&all_sigio_fds, all_sigio_fds.used + 1);
334 if(err){ 337 if(err)
335 printk("maybe_sigio_broken - failed to add pollfd\n");
336 goto out; 338 goto out;
337 } 339
338 all_sigio_fds.poll[all_sigio_fds.used++] = 340 all_sigio_fds.poll[all_sigio_fds.used++] =
339 ((struct pollfd) { .fd = fd, 341 ((struct pollfd) { .fd = fd,
340 .events = read ? POLLIN : POLLOUT, 342 .events = read ? POLLIN : POLLOUT,