PATCH: Fix nbd on 2.1.118 SMP kernels

Stephen C. Tweedie (sct@dcs.ed.ac.uk)
Thu, 27 Aug 1998 17:28:03 +0100


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(&current->sigmask_lock);
+ DEBUG("lock it, ");
+ spin_lock_irqsave(&current->sigmask_lock, flags);
oldset = current->blocked;
sigfillset(&current->blocked);
recalc_sigpending(current);
- spin_unlock_irq(&current->sigmask_lock);
+ spin_unlock_irqrestore(&current->sigmask_lock, flags);

if (send)
result = sock_sendmsg(sock, &msg, size);
else
result = sock_recvmsg(sock, &msg, size, 0);
-
- spin_lock_irq(&current->sigmask_lock);
+
+ spin_lock_irqsave(&current->sigmask_lock, flags);
current->blocked = oldset;
recalc_sigpending(current);
- spin_unlock_irq(&current->sigmask_lock);
+ spin_unlock_irqrestore(&current->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