ide: fix kmalloc() failure handling in ide_driveid_update()
authorBartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Tue, 24 Mar 2009 22:22:54 +0000 (23:22 +0100)
committerBartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Tue, 24 Mar 2009 22:22:54 +0000 (23:22 +0100)
* Doing kmalloc() in the middle of command execution is not only ugly
  but leaves drive waiting to send data on kmalloc() failure.  Fix it.

While at it:

* Unify error code paths.

* Fixup error message to be more useful and add missing KERN_ERR level.

* Rename 'stat' variable to 's'.

Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
drivers/ide/ide-iops.c

index e0cfa2d2acc77c742230f73116bb186f15668692..a955483d2404b039615db491518f0c0a7c2c0ec8 100644 (file)
@@ -293,7 +293,12 @@ int ide_driveid_update(ide_drive_t *drive)
        const struct ide_tp_ops *tp_ops = hwif->tp_ops;
        u16 *id;
        unsigned long flags;
-       u8 stat;
+       int rc;
+       u8 uninitialized_var(s);
+
+       id = kmalloc(SECTOR_SIZE, GFP_ATOMIC);
+       if (id == NULL)
+               return 0;
 
        /*
         * Re-read drive->id for possible DMA mode
@@ -306,25 +311,21 @@ int ide_driveid_update(ide_drive_t *drive)
        tp_ops->exec_command(hwif, ATA_CMD_ID_ATA);
 
        if (ide_busy_sleep(hwif, WAIT_WORSTCASE, 1)) {
-               SELECT_MASK(drive, 0);
-               return 0;
+               rc = 1;
+               goto out_err;
        }
 
        msleep(50);     /* wait for IRQ and ATA_DRQ */
-       stat = tp_ops->read_status(hwif);
 
-       if (!OK_STAT(stat, ATA_DRQ, BAD_R_STAT)) {
-               SELECT_MASK(drive, 0);
-               printk("%s: CHECK for good STATUS\n", drive->name);
-               return 0;
+       s = tp_ops->read_status(hwif);
+
+       if (!OK_STAT(s, ATA_DRQ, BAD_R_STAT)) {
+               rc = 2;
+               goto out_err;
        }
+
        local_irq_save(flags);
        SELECT_MASK(drive, 0);
-       id = kmalloc(SECTOR_SIZE, GFP_ATOMIC);
-       if (!id) {
-               local_irq_restore(flags);
-               return 0;
-       }
        tp_ops->input_data(drive, NULL, id, SECTOR_SIZE);
        (void)tp_ops->read_status(hwif);        /* clear drive IRQ */
        local_irq_enable();
@@ -342,6 +343,12 @@ int ide_driveid_update(ide_drive_t *drive)
                ide_dma_off(drive);
 
        return 1;
+out_err:
+       SELECT_MASK(drive, 0);
+       if (rc == 2)
+               printk(KERN_ERR "%s: %s: bad status\n", drive->name, __func__);
+       kfree(id);
+       return 0;
 }
 
 int ide_config_drive_speed(ide_drive_t *drive, u8 speed)