Messages in this thread Patch in this message | | | Date | Thu, 27 Aug 1998 17:28:03 +0100 | From | "Stephen C. Tweedie" <> | Subject | PATCH: Fix nbd on 2.1.118 SMP kernels |
| |
The network block device driver is completely broken when compiled on an SMP kernel, even on a UP machine. It calls blocking functions while holding the io_request spinlock.
The patch here has not been tested on an SMP machine, but prevents the deadlocks when running an SMP kernel on a UP system. It also passes a non-SMP test build with spinlock debugging enabled.
The fix is to replace some of the spin_lock_irq/spin_unlock_irq pairs with irqsave/irqrestore versions, and to forcibly drop the io request spinlock inside do_nbd_request before calling out to the network.
--Stephen
---------------------------------------------------------------- --- drivers/block/nbd.c.~1~ Wed Aug 19 15:08:25 1998 +++ drivers/block/nbd.c Wed Aug 26 15:57:21 1998 @@ -49,9 +49,11 @@ static struct nbd_device nbd_dev[MAX_NBD]; +#if 1 #define DEBUG( s ) -/* #define DEBUG( s ) printk( s ) - */ +#else +#define DEBUG( s ) printk( s ) +#endif #ifdef PARANOIA static int requests_in; @@ -81,6 +83,7 @@ int result; struct msghdr msg; struct iovec iov; + unsigned long flags; oldfs = get_fs(); set_fs(get_ds()); @@ -98,21 +101,22 @@ msg.msg_namelen = 0; msg.msg_flags = 0; - spin_lock_irq(¤t->sigmask_lock); + DEBUG("lock it, "); + spin_lock_irqsave(¤t->sigmask_lock, flags); oldset = current->blocked; sigfillset(¤t->blocked); recalc_sigpending(current); - spin_unlock_irq(¤t->sigmask_lock); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); if (send) result = sock_sendmsg(sock, &msg, size); else result = sock_recvmsg(sock, &msg, size, 0); - - spin_lock_irq(¤t->sigmask_lock); + + spin_lock_irqsave(¤t->sigmask_lock, flags); current->blocked = oldset; recalc_sigpending(current); - spin_unlock_irq(¤t->sigmask_lock); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); if (result <= 0) { #ifdef PARANOIA @@ -152,6 +156,7 @@ if (result <= 0) FAIL("Send data failed."); } + DEBUG("send OK.\n"); return; error_out: @@ -203,8 +208,10 @@ while (1) { req = nbd_read_stat(lo); - if (!req) + if (!req) { + printk(KERN_ALERT "nbd_read_stat returned NULL\n"); return; + } #ifdef PARANOIA if (req != lo->tail) { printk(KERN_ALERT "NBD: I have problem...\n"); @@ -296,7 +303,12 @@ #endif req->errors = 0; + spin_unlock_irq(&io_request_lock); nbd_send_req(lo->sock, req); /* Why does this block? */ + spin_lock_irq(&io_request_lock); + + if (CURRENT != req) + FAIL("CURRENT was modified"); CURRENT = CURRENT->next; req->next = NULL; if (lo->head == NULL) { ---------------------------------------------------------------- - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.altern.org/andrebalsa/doc/lkml-faq.html
| |