Whenever the loop.o module is installed, either "manually" via a call to insmod, or automagically via modprobe (which will in turn call insmod), the module is installed, but the insmod process does not terminate. Instead, insmod enters the "uninterruptable sleep" state (denoted by D in a ps aux listing). This drives up the load average by one. Moreover, since the module is autocleaned by default, every subsequent call of insmod by modprobe results in a new instance of insmod, which continues to drive the load average ever higher. Anyone know why insmod stays asleep forever after installing loop.o? Even when loop.o is removed, it continues to do this...
I have made a patch that fixes this for me. I'll attach it to this bug; if you want to/can test it, I'd appreciate feedback.
I can't attach a file to this bug, it seems. Patch at http://www.fenrus.demon.nl/loop.diff and copy-n-pasted below (spaces vs tabs, so it might not apply, use the one in the url) --- linux/drivers/block/loop.c.org Sat Oct 14 21:01:32 2000 +++ linux//drivers/block/loop.c Sat Oct 14 21:22:15 2000 @@ -883,13 +883,18 @@ EXPORT_SYMBOL(loop_register_transfer); EXPORT_SYMBOL(loop_unregister_transfer); +static volatile int loopd_running = 0; /* Ugly/hackish refcount hack */ +static volatile int stop_loopd = 0; /* Ugly/hackish internal signal */ + static int loopd (void *unused) { struct wait_queue wait = { current, NULL }; lock_kernel(); + loopd_running = 1; /* printk("loopback system thread started ...\n"); */ strcpy(current->comm, "loopd"); + exit_mm(current); init_waitqueue(&loopd_wait); init_waitqueue(&loopd_done_wait); @@ -903,6 +908,7 @@ if (!async_queue) { spin_unlock_irq(&io_request_lock); wake_up(&loopd_done_wait); + current->state = TASK_INTERRUPTIBLE; schedule(); spin_lock_irq(&io_request_lock); } @@ -910,7 +916,10 @@ remove_wait_queue(&loopd_wait, &wait); current->state = TASK_RUNNING; - goto repeat; + if (!stop_loopd) + goto repeat; + spin_unlock_irq(&io_request_lock); + loopd_running = 0; return 0; } @@ -949,7 +958,18 @@ #ifdef MODULE void cleanup_module (void) { + int count=0; if (unregister_blkdev(MAJOR_NR, "loop")) printk(KERN_WARNING "loop: cannot unregister blkdev\n"); + stop_loopd = 1; + while (loopd_running) { + count++; + wake_up(&loopd_wait); + current->state = TASK_RUNNING; + schedule(); + if (count>50) + break; /* uh oh. but prevent an infinite loop */ + } + } #endif
Fixed in errata kernel