Patchwork [v4,17/18] scsi: fix searching for an empty id

login
register
mail settings
Submitter Paolo Bonzini
Date Feb. 22, 2012, 2:33 p.m.
Message ID <1329921236-23461-18-git-send-email-pbonzini@redhat.com>
Download mbox | patch
Permalink /patch/142497/
State New
Headers show

Comments

Paolo Bonzini - Feb. 22, 2012, 2:33 p.m.
The conditions for detecting no free target or LUN were wrong.

The LUN loop was followed by an "if" condition that is never true, because
the loop is exited as soon as lun becomes equal to bus->info->max_lun,
and never becomes greater than it.

The target loop had a wrong condition (<= instead of <).  Once this is
fixed, the loop would fail in the same way as the LUN loop.

The fix is to see whether scsi_device_find returned the device with the
last (channel, target, LUN) pair, and fail if so.

In addition, scsi_bus_legacy_handle_cmdline also had an off-by-one error.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/scsi-bus.c |   15 ++++++++++-----
 1 files changed, 10 insertions(+), 5 deletions(-)

Patch

diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 2cf2f0d..2cb5a18 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -132,6 +132,10 @@  static int scsi_qdev_init(DeviceState *qdev)
         error_report("bad scsi device id: %d", dev->id);
         goto err;
     }
+    if (dev->lun != -1 && dev->lun > bus->info->max_lun) {
+        error_report("bad scsi device lun: %d", dev->lun);
+        goto err;
+    }
 
     if (dev->id == -1) {
         int id = -1;
@@ -140,8 +144,8 @@  static int scsi_qdev_init(DeviceState *qdev)
         }
         do {
             d = scsi_device_find(bus, dev->channel, ++id, dev->lun);
-        } while (d && d->lun == dev->lun && id <= bus->info->max_target);
-        if (id > bus->info->max_target) {
+        } while (d && d->lun == dev->lun && id < bus->info->max_target);
+        if (d && d->lun == dev->lun) {
             error_report("no free target");
             goto err;
         }
@@ -151,14 +155,15 @@  static int scsi_qdev_init(DeviceState *qdev)
         do {
             d = scsi_device_find(bus, dev->channel, dev->id, ++lun);
         } while (d && d->lun == lun && lun < bus->info->max_lun);
-        if (lun > bus->info->max_lun) {
+        if (d && d->lun == lun) {
             error_report("no free lun");
             goto err;
         }
         dev->lun = lun;
     } else {
         d = scsi_device_find(bus, dev->channel, dev->id, dev->lun);
-        if (dev->lun == d->lun && dev != d) {
+        assert(d);
+        if (d->lun == dev->lun && dev != d) {
             qdev_free(&d->qdev);
         }
     }
@@ -217,7 +222,7 @@  int scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
     int res = 0, unit;
 
     loc_push_none(&loc);
-    for (unit = 0; unit < bus->info->max_target; unit++) {
+    for (unit = 0; unit <= bus->info->max_target; unit++) {
         dinfo = drive_get(IF_SCSI, bus->busnr, unit);
         if (dinfo == NULL) {
             continue;