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