
From: Lou Langholtz <ldl@aros.net>

The following patch removes a race condition in the network block device 
driver in 2.6.0*.

Without this patch, the reply receiving thread could end (and free up the
memory for) the request structure before the request sending thread is
completely done accessing it and would then access invalid memory.

This particular patch has only been compile tested and visually inspected. 
The invalid memory access had originally been found in a derivative nbd
work that I've been developing and this race was found to be the cause (and
removing the race fixed this problem).



 drivers/block/nbd.c |   21 ++++++++++-----------
 1 files changed, 10 insertions(+), 11 deletions(-)

diff -puN drivers/block/nbd.c~nbd-race-fix drivers/block/nbd.c
--- 25/drivers/block/nbd.c~nbd-race-fix	2003-08-05 10:12:00.000000000 -0700
+++ 25-akpm/drivers/block/nbd.c	2003-08-05 10:12:00.000000000 -0700
@@ -234,15 +234,16 @@ 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;
+	int result, i, flags, rw;
 	struct nbd_request request;
 	unsigned long size = req->nr_sectors << 9;
 	struct socket *sock = lo->sock;
 
+	rw = nbd_cmd(req);
 	request.magic = htonl(NBD_REQUEST_MAGIC);
-	request.type = htonl(nbd_cmd(req));
+	request.type = htonl(rw);
 	request.from = cpu_to_be64((u64) req->sector << 9);
 	request.len = htonl(size);
 	memcpy(request.handle, &req, sizeof(req));
@@ -256,19 +257,18 @@ void nbd_send_req(struct nbd_device *lo,
 	}
 
 	dprintk(DBG_TX, "%s: request %p: sending control (%s@%llu,%luB)\n",
-			lo->disk->disk_name, req,
-			nbdcmd_to_ascii(nbd_cmd(req)),
+			lo->disk->disk_name, req, nbdcmd_to_ascii(rw),
 			(unsigned long long)req->sector << 9,
 			req->nr_sectors << 9);
 	result = sock_xmit(sock, 1, &request, sizeof(request),
-			(nbd_cmd(req) == NBD_CMD_WRITE)? MSG_MORE: 0);
+			(rw == NBD_CMD_WRITE)? MSG_MORE: 0);
 	if (result <= 0) {
 		printk(KERN_ERR "%s: Send control failed (result %d)\n",
 				lo->disk->disk_name, result);
 		goto error_out;
 	}
 
-	if (nbd_cmd(req) == NBD_CMD_WRITE) {
+	if (rw == NBD_CMD_WRITE) {
 		struct bio *bio;
 		/*
 		 * we are really probing at internals to determine
@@ -294,11 +294,12 @@ void nbd_send_req(struct nbd_device *lo,
 		}
 	}
 	up(&lo->tx_lock);
-	return;
+	return 0;
 
       error_out:
 	up(&lo->tx_lock);
 	req->errors++;
+	return req->errors;
 }
 
 static struct request *nbd_find_request(struct nbd_device *lo, char *handle)
@@ -492,9 +493,7 @@ static void do_nbd_request(request_queue
 		list_add(&req->queuelist, &lo->queue_head);
 		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);

_
