public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] nbd: fix struct request race condition
@ 2004-08-02 15:18 Paul Clements
  0 siblings, 0 replies; only message in thread
From: Paul Clements @ 2004-08-02 15:18 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel

[-- Attachment #1: Type: text/plain, Size: 477 bytes --]

Andrew,

Here's a patch to fix a race condition in nbd that was causing struct 
request corruption (requests were being freed while still in use). This 
patch improves on the previous one, which admittedly was a bit dodgy, 
using struct request's ref_count field (I should have listened to Jens 
in the first place :). This should fix all the corner cases related to 
struct request usage/freeing in nbd. My stress tests do a lot better 
with this patch applied.

Thanks,
Paul

[-- Attachment #2: nbd_cant_find_req_2_6.diff --]
[-- Type: text/plain, Size: 2465 bytes --]

--- linux-2.6.7/drivers/block/nbd.c.PRISTINE	Fri Jul 30 12:09:00 2004
+++ linux-2.6.7/drivers/block/nbd.c	Fri Jul 30 12:37:43 2004
@@ -128,23 +128,11 @@ static void nbd_end_request(struct reque
 {
 	int uptodate = (req->errors == 0) ? 1 : 0;
 	request_queue_t *q = req->q;
-	struct nbd_device *lo = req->rq_disk->private_data;
 	unsigned long flags;
 
 	dprintk(DBG_BLKDEV, "%s: request %p: %s\n", req->rq_disk->disk_name,
 			req, uptodate? "done": "failed");
 
-	spin_lock(&lo->queue_lock);
-	while (req->ref_count > 1) { /* still in send */
-		spin_unlock(&lo->queue_lock);
-		printk(KERN_DEBUG "%s: request %p still in use (%d), waiting\n",
-		    lo->disk->disk_name, req, req->ref_count);
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(HZ); /* wait a second */
-		spin_lock(&lo->queue_lock);
-	}
-	spin_unlock(&lo->queue_lock);
-
 	spin_lock_irqsave(q->queue_lock, flags);
 	if (!end_that_request_first(req, uptodate, req->nr_sectors)) {
 		end_that_request_last(req);
@@ -234,7 +222,7 @@ static inline int sock_send_bvec(struct 
 	return result;
 }
 
-void nbd_send_req(struct nbd_device *lo, struct request *req)
+static int nbd_send_req(struct nbd_device *lo, struct request *req)
 {
 	int result, i, flags;
 	struct nbd_request request;
@@ -294,11 +282,11 @@ void nbd_send_req(struct nbd_device *lo,
 		}
 	}
 	up(&lo->tx_lock);
-	return;
+	return 0;
 
 error_out:
 	up(&lo->tx_lock);
-	req->errors++;
+	return 1;
 }
 
 static struct request *nbd_find_request(struct nbd_device *lo, char *handle)
@@ -483,26 +471,19 @@ static void do_nbd_request(request_queue
 		}
 
 		list_add(&req->queuelist, &lo->queue_head);
-		req->ref_count++; /* make sure req does not get freed */
 		spin_unlock(&lo->queue_lock);
 
-		nbd_send_req(lo, req);
-
-		if (req->errors) {
+		if (nbd_send_req(lo, req) != 0) {
 			printk(KERN_ERR "%s: Request send failed\n",
 					lo->disk->disk_name);
-			spin_lock(&lo->queue_lock);
-			list_del_init(&req->queuelist);
-			req->ref_count--;
-			spin_unlock(&lo->queue_lock);
-			nbd_end_request(req);
-			spin_lock_irq(q->queue_lock);
-			continue;
+			if (nbd_find_request(lo, (char *)&req) != NULL) {
+				/* we still own req */
+				req->errors++;
+				nbd_end_request(req);
+			} else /* we're racing with nbd_clear_que */
+				printk(KERN_DEBUG "nbd: can't find req\n");
 		}
 
-		spin_lock(&lo->queue_lock);
-		req->ref_count--;
-		spin_unlock(&lo->queue_lock);
 		spin_lock_irq(q->queue_lock);
 		continue;
 

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2004-08-02 15:19 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-08-02 15:18 [PATCH] nbd: fix struct request race condition Paul Clements

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox