[prev in list] [next in list] [prev in thread] [next in thread] 

List:       xen-cvs
Subject:    [Xen-changelog] [linux-2.6.18-xen] scsifront: respect full ring on reset processing
From:       Xen patchbot-linux-2.6.18-xen <patchbot () xen ! org>
Date:       2012-11-26 8:33:03
Message-ID: E1Tcu7j-0006Sq-Kd () xenbits ! xen ! org
[Download RAW message or body]

# HG changeset patch
# User Jan Beulich <jbeulich@suse.com>
# Date 1353918342 -3600
# Node ID 4d1471ca031e65eca5e508eab8330bef9799f5fb
# Parent  39a26cb5fb0eb16bbfca425084b345c7130b6ad1
scsifront: respect full ring on reset processing

Additionally, the error return case of the wait_event_interruptible()
at the end of scsifront_dev_reset_handler() wasn't handled, potentially
causing shadow slot corruption.

Doing this also revealed that io_lock was pointless - it was only used
inside the worker thread, i.e. protected nothing.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
---


diff -r 39a26cb5fb0e -r 4d1471ca031e drivers/xen/scsifront/common.h
--- a/drivers/xen/scsifront/common.h	Fri Nov 23 11:53:50 2012 +0100
+++ b/drivers/xen/scsifront/common.h	Mon Nov 26 09:25:42 2012 +0100
@@ -99,7 +99,6 @@ struct vscsifrnt_info {
 
 	struct Scsi_Host *host;
 
-	spinlock_t io_lock;
 	spinlock_t shadow_lock;
 	unsigned int evtchn;
 	unsigned int irq;
@@ -113,8 +112,9 @@ struct vscsifrnt_info {
 
 	struct task_struct *kthread;
 	wait_queue_head_t wq;
-	unsigned int waiting_resp;
-
+	wait_queue_head_t wq_sync;
+	unsigned int waiting_resp:1;
+	unsigned int waiting_sync:1;
 };
 
 #define DPRINTK(_f, _a...)				\
diff -r 39a26cb5fb0e -r 4d1471ca031e drivers/xen/scsifront/scsifront.c
--- a/drivers/xen/scsifront/scsifront.c	Fri Nov 23 11:53:50 2012 +0100
+++ b/drivers/xen/scsifront/scsifront.c	Mon Nov 26 09:25:42 2012 +0100
@@ -49,16 +49,19 @@ static int get_id_from_freelist(struct v
 	return free;
 }
 
+static void _add_id_to_freelist(struct vscsifrnt_info *info, uint32_t id)
+{
+	info->shadow[id].next_free = info->shadow_free;
+	info->shadow[id].sc = NULL;
+	info->shadow_free = id;
+}
+
 static void add_id_to_freelist(struct vscsifrnt_info *info, uint32_t id)
 {
 	unsigned long flags;
 
 	spin_lock_irqsave(&info->shadow_lock, flags);
-
-	info->shadow[id].next_free = info->shadow_free;
-	info->shadow[id].sc = NULL;
-	info->shadow_free = id;
-
+	_add_id_to_freelist(info, id);
 	spin_unlock_irqrestore(&info->shadow_lock, flags);
 }
 
@@ -169,7 +172,19 @@ static void scsifront_sync_cmd_done(stru
 	
 	spin_lock_irqsave(&info->shadow_lock, flags);
 	info->shadow[id].wait_reset = 1;
-	info->shadow[id].rslt_reset = ring_res->rslt;
+	switch (info->shadow[id].rslt_reset) {
+	case 0:
+		info->shadow[id].rslt_reset = ring_res->rslt;
+		break;
+	case -1:
+		_add_id_to_freelist(info, id);
+		break;
+	default:
+		shost_printk(KERN_ERR "scsifront: ", info->host,
+			     "bad reset state %d, possibly leaking %u\n",
+			     info->shadow[id].rslt_reset, id);
+		break;
+	}
 	spin_unlock_irqrestore(&info->shadow_lock, flags);
 
 	wake_up(&(info->shadow[id].wq_reset));
@@ -184,7 +199,7 @@ static int scsifront_cmd_done(struct vsc
 	int more_to_do = 0;
 	unsigned long flags;
 
-	spin_lock_irqsave(&info->io_lock, flags);
+	spin_lock_irqsave(info->host->host_lock, flags);
 
 	rp = info->ring.sring->rsp_prod;
 	rmb();
@@ -206,8 +221,11 @@ static int scsifront_cmd_done(struct vsc
 		info->ring.sring->rsp_event = i + 1;
 	}
 
-	spin_unlock_irqrestore(&info->io_lock, flags);
+	info->waiting_sync = 0;
 
+	spin_unlock_irqrestore(info->host->host_lock, flags);
+
+	wake_up(&info->wq_sync);
 
 	/* Yield point for this unbounded loop. */
 	cond_resched();
@@ -425,17 +443,33 @@ static int scsifront_dev_reset_handler(s
 
 	vscsiif_request_t *ring_req;
 	uint16_t rqid;
-	int err;
+	int err = 0;
 
+	for (;;) {
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)
-	spin_lock_irq(host->host_lock);
+		spin_lock_irq(host->host_lock);
 #endif
+		if (!RING_FULL(&info->ring))
+			break;
+		if (err) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)
+			spin_unlock_irq(host->host_lock);
+#endif
+			return FAILED;
+		}
+		info->waiting_sync = 1;
+		spin_unlock_irq(host->host_lock);
+		err = wait_event_interruptible(info->wq_sync,
+					       !info->waiting_sync);
+		spin_lock_irq(host->host_lock);
+	}
 
 	ring_req      = scsifront_pre_request(info);
 	ring_req->act = VSCSIIF_ACT_SCSI_RESET;
 
 	rqid          = ring_req->rqid;
 	info->shadow[rqid].act = VSCSIIF_ACT_SCSI_RESET;
+	info->shadow[rqid].rslt_reset = 0;
 
 	ring_req->channel = sc->device->channel;
 	ring_req->id      = sc->device->id;
@@ -454,13 +488,19 @@ static int scsifront_dev_reset_handler(s
 	scsifront_do_request(info);	
 
 	spin_unlock_irq(host->host_lock);
-	wait_event_interruptible(info->shadow[rqid].wq_reset,
-			 info->shadow[rqid].wait_reset);
+	err = wait_event_interruptible(info->shadow[rqid].wq_reset,
+				       info->shadow[rqid].wait_reset);
 	spin_lock_irq(host->host_lock);
 
-	err = info->shadow[rqid].rslt_reset;
-
-	add_id_to_freelist(info, rqid);
+	if (!err) {
+		err = info->shadow[rqid].rslt_reset;
+		add_id_to_freelist(info, rqid);
+	} else {
+		spin_lock(&info->shadow_lock);
+		info->shadow[rqid].rslt_reset = -1;
+		spin_unlock(&info->shadow_lock);
+		err = FAILED;
+	}
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)
 	spin_unlock_irq(host->host_lock);
diff -r 39a26cb5fb0e -r 4d1471ca031e drivers/xen/scsifront/xenbus.c
--- a/drivers/xen/scsifront/xenbus.c	Fri Nov 23 11:53:50 2012 +0100
+++ b/drivers/xen/scsifront/xenbus.c	Mon Nov 26 09:25:42 2012 +0100
@@ -205,7 +205,7 @@ static int scsifront_probe(struct xenbus
 	}
 
 	init_waitqueue_head(&info->wq);
-	spin_lock_init(&info->io_lock);
+	init_waitqueue_head(&info->wq_sync);
 	spin_lock_init(&info->shadow_lock);
 
 	snprintf(name, DEFAULT_TASK_COMM_LEN, "vscsiif.%d", info->host->host_no);

_______________________________________________
Xen-changelog mailing list
Xen-changelog@lists.xen.org
http://lists.xensource.com/xen-changelog
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic