patch-2.4.19 linux-2.4.19/drivers/block/nbd.c
Next file: linux-2.4.19/drivers/block/paride/bpck6.c
Previous file: linux-2.4.19/drivers/block/loop.c
Back to the patch index
Back to the overall index
- Lines: 223
- Date:
Fri Aug 2 17:39:43 2002
- Orig file:
linux-2.4.18/drivers/block/nbd.c
- Orig date:
Fri Dec 21 09:41:53 2001
diff -urN linux-2.4.18/drivers/block/nbd.c linux-2.4.19/drivers/block/nbd.c
@@ -24,6 +24,8 @@
* 01-3-11 Make nbd work with new Linux block layer code. It now supports
* plugging like all the other block devices. Also added in MSG_MORE to
* reduce number of partial TCP segments sent. <steve@chygwyn.com>
+ * 01-12-6 Fix deadlock condition by making queue locks independant of
+ * the transmit lock. <steve@chygwyn.com>
*
* possible FIXME: make set_sock / set_blksize / set_size / do_it one syscall
* why not: would need verify_area and friends, would share yet another
@@ -146,11 +148,12 @@
#define FAIL( s ) { printk( KERN_ERR "NBD: " s "(result %d)\n", result ); goto error_out; }
-void nbd_send_req(struct socket *sock, struct request *req)
+void nbd_send_req(struct nbd_device *lo, struct request *req)
{
int result;
struct nbd_request request;
unsigned long size = req->nr_sectors << 9;
+ struct socket *sock = lo->sock;
DEBUG("NBD: sending control, ");
request.magic = htonl(NBD_REQUEST_MAGIC);
@@ -159,6 +162,8 @@
request.len = htonl(size);
memcpy(request.handle, &req, sizeof(req));
+ down(&lo->tx_lock);
+
result = nbd_xmit(1, sock, (char *) &request, sizeof(request), req->cmd == WRITE ? MSG_MORE : 0);
if (result <= 0)
FAIL("Sendmsg failed for control.");
@@ -173,30 +178,51 @@
bh = bh->b_reqnext;
} while(bh);
}
+ up(&lo->tx_lock);
return;
- error_out:
+error_out:
+ up(&lo->tx_lock);
req->errors++;
}
+static struct request *nbd_find_request(struct nbd_device *lo, char *handle)
+{
+ struct request *req;
+ struct list_head *tmp;
+ struct request *xreq;
+
+ memcpy(&xreq, handle, sizeof(xreq));
+
+ spin_lock(&lo->queue_lock);
+ list_for_each(tmp, &lo->queue_head) {
+ req = list_entry(tmp, struct request, queue);
+ if (req != xreq)
+ continue;
+ list_del(&req->queue);
+ spin_unlock(&lo->queue_lock);
+ return req;
+ }
+ spin_unlock(&lo->queue_lock);
+ return NULL;
+}
+
#define HARDFAIL( s ) { printk( KERN_ERR "NBD: " s "(result %d)\n", result ); lo->harderror = result; return NULL; }
struct request *nbd_read_stat(struct nbd_device *lo)
/* NULL returned = something went wrong, inform userspace */
{
int result;
struct nbd_reply reply;
- struct request *xreq, *req;
+ struct request *req;
DEBUG("reading control, ");
reply.magic = 0;
result = nbd_xmit(0, lo->sock, (char *) &reply, sizeof(reply), MSG_WAITALL);
if (result <= 0)
HARDFAIL("Recv control failed.");
- memcpy(&xreq, reply.handle, sizeof(xreq));
- req = blkdev_entry_prev_request(&lo->queue_head);
-
- if (xreq != req)
- FAIL("Unexpected handle received.\n");
+ req = nbd_find_request(lo, reply.handle);
+ if (req == NULL)
+ HARDFAIL("Unexpected reply");
DEBUG("ok, ");
if (ntohl(reply.magic) != NBD_REPLY_MAGIC)
@@ -226,20 +252,14 @@
{
struct request *req;
- down (&lo->queue_lock);
while (1) {
- up (&lo->queue_lock);
req = nbd_read_stat(lo);
- down (&lo->queue_lock);
if (!req) {
printk(KERN_ALERT "req should never be null\n" );
goto out;
}
#ifdef PARANOIA
- if (req != blkdev_entry_prev_request(&lo->queue_head)) {
- printk(KERN_ALERT "NBD: I have problem...\n");
- }
if (lo != &nbd_dev[MINOR(req->rq_dev)]) {
printk(KERN_ALERT "NBD: request corrupted!\n");
continue;
@@ -249,15 +269,12 @@
goto out;
}
#endif
- list_del(&req->queue);
- up (&lo->queue_lock);
nbd_end_request(req);
- down (&lo->queue_lock);
}
out:
- up (&lo->queue_lock);
+ return;
}
void nbd_clear_que(struct nbd_device *lo)
@@ -270,27 +287,20 @@
return;
}
#endif
-
- while (!list_empty(&lo->queue_head)) {
- req = blkdev_entry_prev_request(&lo->queue_head);
-#ifdef PARANOIA
- if (!req) {
- printk( KERN_ALERT "NBD: panic, panic, panic\n" );
- break;
+ do {
+ req = NULL;
+ spin_lock(&lo->queue_lock);
+ if (!list_empty(&lo->queue_head)) {
+ req = list_entry(lo->queue_head.next, struct request, queue);
+ list_del(&req->queue);
}
- if (lo != &nbd_dev[MINOR(req->rq_dev)]) {
- printk(KERN_ALERT "NBD: request corrupted when clearing!\n");
- continue;
+ spin_unlock(&lo->queue_lock);
+ if (req) {
+ req->errors++;
+ nbd_end_request(req);
}
-#endif
- req->errors++;
- list_del(&req->queue);
- up(&lo->queue_lock);
+ } while(req);
- nbd_end_request(req);
-
- down(&lo->queue_lock);
- }
}
/*
@@ -334,10 +344,11 @@
blkdev_dequeue_request(req);
spin_unlock_irq(&io_request_lock);
- down (&lo->queue_lock);
- list_add(&req->queue, &lo->queue_head);
- nbd_send_req(lo->sock, req); /* Why does this block? */
- up (&lo->queue_lock);
+ spin_lock(&lo->queue_lock);
+ list_add_tail(&req->queue, &lo->queue_head);
+ spin_unlock(&lo->queue_lock);
+
+ nbd_send_req(lo, req);
spin_lock_irq(&io_request_lock);
continue;
@@ -372,21 +383,21 @@
lo = &nbd_dev[dev];
switch (cmd) {
case NBD_DISCONNECT:
- printk("NBD_DISCONNECT\n") ;
+ printk("NBD_DISCONNECT\n");
sreq.cmd=2 ; /* shutdown command */
- if (!lo->sock) return -EINVAL ;
- nbd_send_req(lo->sock,&sreq) ;
+ if (!lo->sock) return -EINVAL;
+ nbd_send_req(lo, &sreq);
return 0 ;
case NBD_CLEAR_SOCK:
- down(&lo->queue_lock);
nbd_clear_que(lo);
+ spin_lock(&lo->queue_lock);
if (!list_empty(&lo->queue_head)) {
- up(&lo->queue_lock);
+ spin_unlock(&lo->queue_lock);
printk(KERN_ERR "nbd: Some requests are in progress -> can not turn off.\n");
return -EBUSY;
}
- up(&lo->queue_lock);
+ spin_unlock(&lo->queue_lock);
file = lo->file;
if (!file)
return -EINVAL;
@@ -507,8 +518,9 @@
nbd_dev[i].file = NULL;
nbd_dev[i].magic = LO_MAGIC;
nbd_dev[i].flags = 0;
+ spin_lock_init(&nbd_dev[i].queue_lock);
INIT_LIST_HEAD(&nbd_dev[i].queue_head);
- init_MUTEX(&nbd_dev[i].queue_lock);
+ init_MUTEX(&nbd_dev[i].tx_lock);
nbd_blksizes[i] = 1024;
nbd_blksize_bits[i] = 10;
nbd_bytesizes[i] = 0x7ffffc00; /* 2GB */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)