aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um
diff options
context:
space:
mode:
authorPaolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>2006-01-18 20:42:57 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-18 22:20:21 -0500
commitb6a2b13778873bd9edd0b4a7d24a7bd730369021 (patch)
treedc534ba13079c9fcecb2c02798c5021a26a95ae4 /arch/um
parent71c8d4c3aad3132765d30b05dce98bb8a9508f02 (diff)
[PATCH] uml: sigio code - reduce spinlock hold time
In a previous patch I shifted an allocation to being atomic. In this patch, a better but more intrusive solution is implemented, i.e. hold the lock only when really needing it, especially not over pipe operations, nor over the culprit allocation. Additionally, while at it, add a missing kfree in the failure path, and make sure that if we fail in forking, write_sigio_pid is -1 and not, say, -ENOMEM. And fix whitespace, at least for things I was touching anyway. Signed-off-by: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> Cc: Jeff Dike <jdike@addtoit.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/um')
-rw-r--r--arch/um/kernel/sigio_user.c83
1 files changed, 58 insertions, 25 deletions
diff --git a/arch/um/kernel/sigio_user.c b/arch/um/kernel/sigio_user.c
index 62e5cfdf218..f7b18e157d3 100644
--- a/arch/um/kernel/sigio_user.c
+++ b/arch/um/kernel/sigio_user.c
@@ -337,70 +337,103 @@ int ignore_sigio_fd(int fd)
337 return(err); 337 return(err);
338} 338}
339 339
340static int setup_initial_poll(int fd) 340static struct pollfd* setup_initial_poll(int fd)
341{ 341{
342 struct pollfd *p; 342 struct pollfd *p;
343 343
344 p = um_kmalloc_atomic(sizeof(struct pollfd)); 344 p = um_kmalloc(sizeof(struct pollfd));
345 if(p == NULL){ 345 if (p == NULL) {
346 printk("setup_initial_poll : failed to allocate poll\n"); 346 printk("setup_initial_poll : failed to allocate poll\n");
347 return(-1); 347 return NULL;
348 } 348 }
349 *p = ((struct pollfd) { .fd = fd, 349 *p = ((struct pollfd) { .fd = fd,
350 .events = POLLIN, 350 .events = POLLIN,
351 .revents = 0 }); 351 .revents = 0 });
352 current_poll = ((struct pollfds) { .poll = p, 352 return p;
353 .used = 1,
354 .size = 1 });
355 return(0);
356} 353}
357 354
358void write_sigio_workaround(void) 355void write_sigio_workaround(void)
359{ 356{
360 unsigned long stack; 357 unsigned long stack;
358 struct pollfd *p;
361 int err; 359 int err;
360 int l_write_sigio_fds[2];
361 int l_sigio_private[2];
362 int l_write_sigio_pid;
362 363
364 /* We call this *tons* of times - and most ones we must just fail. */
363 sigio_lock(); 365 sigio_lock();
364 if(write_sigio_pid != -1) 366 l_write_sigio_pid = write_sigio_pid;
365 goto out; 367 sigio_unlock();
366 368
367 err = os_pipe(write_sigio_fds, 1, 1); 369 if (l_write_sigio_pid != -1)
370 return;
371
372 err = os_pipe(l_write_sigio_fds, 1, 1);
368 if(err < 0){ 373 if(err < 0){
369 printk("write_sigio_workaround - os_pipe 1 failed, " 374 printk("write_sigio_workaround - os_pipe 1 failed, "
370 "err = %d\n", -err); 375 "err = %d\n", -err);
371 goto out; 376 return;
372 } 377 }
373 err = os_pipe(sigio_private, 1, 1); 378 err = os_pipe(l_sigio_private, 1, 1);
374 if(err < 0){ 379 if(err < 0){
375 printk("write_sigio_workaround - os_pipe 2 failed, " 380 printk("write_sigio_workaround - os_pipe 1 failed, "
376 "err = %d\n", -err); 381 "err = %d\n", -err);
377 goto out_close1; 382 goto out_close1;
378 } 383 }
379 if(setup_initial_poll(sigio_private[1])) 384
385 p = setup_initial_poll(l_sigio_private[1]);
386 if(!p)
380 goto out_close2; 387 goto out_close2;
381 388
382 write_sigio_pid = run_helper_thread(write_sigio_thread, NULL, 389 sigio_lock();
390
391 /* Did we race? Don't try to optimize this, please, it's not so likely
392 * to happen, and no more than once at the boot. */
393 if(write_sigio_pid != -1)
394 goto out_unlock;
395
396 write_sigio_pid = run_helper_thread(write_sigio_thread, NULL,
383 CLONE_FILES | CLONE_VM, &stack, 0); 397 CLONE_FILES | CLONE_VM, &stack, 0);
384 398
385 if(write_sigio_pid < 0) goto out_close2; 399 if (write_sigio_pid < 0)
400 goto out_clear;
386 401
387 if(write_sigio_irq(write_sigio_fds[0])) 402 if (write_sigio_irq(l_write_sigio_fds[0]))
388 goto out_kill; 403 goto out_kill;
389 404
390 out: 405 /* Success, finally. */
406 memcpy(write_sigio_fds, l_write_sigio_fds, sizeof(l_write_sigio_fds));
407 memcpy(sigio_private, l_sigio_private, sizeof(l_sigio_private));
408
409 current_poll = ((struct pollfds) { .poll = p,
410 .used = 1,
411 .size = 1 });
412
391 sigio_unlock(); 413 sigio_unlock();
392 return; 414 return;
393 415
394 out_kill: 416 out_kill:
395 os_kill_process(write_sigio_pid, 1); 417 l_write_sigio_pid = write_sigio_pid;
396 write_sigio_pid = -1; 418 write_sigio_pid = -1;
419 sigio_unlock();
420 /* Going to call waitpid, avoid holding the lock. */
421 os_kill_process(l_write_sigio_pid, 1);
422 goto out_free;
423
424 out_clear:
425 write_sigio_pid = -1;
426 out_unlock:
427 sigio_unlock();
428 out_free:
429 kfree(p);
397 out_close2: 430 out_close2:
398 os_close_file(sigio_private[0]); 431 os_close_file(l_sigio_private[0]);
399 os_close_file(sigio_private[1]); 432 os_close_file(l_sigio_private[1]);
400 out_close1: 433 out_close1:
401 os_close_file(write_sigio_fds[0]); 434 os_close_file(l_write_sigio_fds[0]);
402 os_close_file(write_sigio_fds[1]); 435 os_close_file(l_write_sigio_fds[1]);
403 sigio_unlock(); 436 return;
404} 437}
405 438
406int read_sigio_fd(int fd) 439int read_sigio_fd(int fd)