]> git.hungrycats.org Git - linux/commitdiff
[PATCH] s390: dasd driver fixes.
authorAndrew Morton <akpm@osdl.org>
Tue, 16 Mar 2004 23:08:29 +0000 (15:08 -0800)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Tue, 16 Mar 2004 23:08:29 +0000 (15:08 -0800)
From: Martin Schwidefsky <schwidefsky@de.ibm.com>

dasd driver fixes:
 - Remove additional dasd attributes for a ccw-device if the discipline
   (=driver) gets unloaded.
 - Fix race of dasd_generic_offline against dasd_open.
 - Remove irq_exit calls from diag interrupt handler. The irq_enter/
   irq_exit is done in the external interrupt handler.

drivers/s390/block/Kconfig
drivers/s390/block/dasd.c
drivers/s390/block/dasd_devmap.c
drivers/s390/block/dasd_diag.c
drivers/s390/block/dasd_int.h

index 6ae6d8aff22d5351c04a29410884d72b2be6e469..dc1c89dbdb8f57a470cd1bb811ac889654087231 100644 (file)
@@ -48,12 +48,12 @@ config DASD_FBA
          say "Y".
 
 config DASD_DIAG
-       tristate "Support for DIAG access to CMS reserved Disks"
+       tristate "Support for DIAG access to Disks"
        depends on DASD && ARCH_S390X = 'n'
        help
-         Select this option if you want to use CMS reserved Disks under VM
-         with the Diagnose250 command.  If you are not running under VM or
-         unsure what it is, say "N".
+         Select this option if you want to use Diagnose250 command to access
+         Disks under VM.  If you are not running under VM or unsure what it is,
+         say "N".
 
 config DASD_CMB
        tristate "Compatibility interface for DASD channel measurement blocks"
index 3231be77f9a848f68f44e3505328d4f40251c069..a8395ca67fa091ee6d1fac274ee732fba4fdc050 100644 (file)
@@ -7,7 +7,7 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
  *
- * $Revision: 1.129 $
+ * $Revision: 1.133 $
  */
 
 #include <linux/config.h>
@@ -1655,11 +1655,24 @@ dasd_open(struct inode *inp, struct file *filp)
 {
        struct gendisk *disk = inp->i_bdev->bd_disk;
        struct dasd_device *device = disk->private_data;
-       int rc;
+       int old_count, rc;
+
+       /*
+        * We use a negative value in open_count to indicate that
+        * the device must not be used.
+        */
+       do {
+               old_count = atomic_read(&device->open_count);
+               if (old_count < 0)
+                       return -ENODEV;
+       } while (atomic_compare_and_swap(old_count, old_count + 1,
+                                        &device->open_count));
+
+       if (!try_module_get(device->discipline->owner)) {
+               rc = -EINVAL;
+               goto unlock;
+       }
 
-       if (!try_module_get(device->discipline->owner))
-               return -EINVAL;
-       
        if (dasd_probeonly) {
                MESSAGE(KERN_INFO,
                        "No access to device %s due to probeonly mode",
@@ -1676,11 +1689,12 @@ dasd_open(struct inode *inp, struct file *filp)
                goto out;
        }
 
-       atomic_inc(&device->open_count);
        return 0;
 
 out:
        module_put(device->discipline->owner);
+unlock:
+       atomic_dec(&device->open_count);
        return rc;
 }
 
@@ -1741,7 +1755,7 @@ dasd_generic_probe (struct ccw_device *cdev,
        ret = dasd_add_sysfs_files(cdev);
        if (ret) {
                printk(KERN_WARNING
-                      "dasd_generic_probe: could not add driverfs entries"
+                      "dasd_generic_probe: could not add sysfs entries "
                       "for %s\n", cdev->dev.bus_id);
        }
 
@@ -1757,8 +1771,15 @@ dasd_generic_remove (struct ccw_device *cdev)
 {
        struct dasd_device *device;
 
+       dasd_remove_sysfs_files(cdev);
        device = dasd_device_from_cdev(cdev);
        if (!IS_ERR(device)) {
+               /*
+                * This device is removed unconditionally. Set open_count
+                * to -1 to prevent dasd_open from opening it while it is
+                * no quite down yet.
+                */
+               atomic_set(&device->open_count,-1);
                dasd_set_target_state(device, DASD_STATE_NEW);
                /* dasd_delete_device destroys the device reference. */
                dasd_delete_device(device);
@@ -1830,15 +1851,23 @@ dasd_generic_set_offline (struct ccw_device *cdev)
        struct dasd_device *device;
 
        device = dasd_device_from_cdev(cdev);
-       if (atomic_read(&device->open_count) > 0) {
+       /*
+        * We must make sure that this device is currently not in use
+        * (current open_count == 0 ). We set open_count to -1 to indicate
+        * that from now on set_offline is in progress and the device must
+        * not be used otherwise.
+        */
+       if (atomic_compare_and_swap(0, -1, &device->open_count)) {
                printk (KERN_WARNING "Can't offline dasd device with open"
                        " count = %i.\n",
                        atomic_read(&device->open_count));
                dasd_put_device(device);
                return -EBUSY;
        }
-       dasd_put_device(device);
-       dasd_generic_remove (cdev);
+       dasd_set_target_state(device, DASD_STATE_NEW);
+       /* dasd_delete_device destroys the device reference. */
+       dasd_delete_device(device);
+
        return 0;
 }
 
index 94d6a7bb09b82238df696025e36837ec8cbae428..a2b38b2248a0c8e4d6d7962b5a2293ac51f61a40 100644 (file)
@@ -11,7 +11,7 @@
  * functions may not be called from interrupt context. In particular
  * dasd_get_device is a no-no from interrupt context.
  *
- * $Revision: 1.25 $
+ * $Revision: 1.26 $
  */
 
 #include <linux/config.h>
@@ -681,6 +681,13 @@ dasd_add_sysfs_files(struct ccw_device *cdev)
        return sysfs_create_group(&cdev->dev.kobj, &dasd_attr_group);
 }
 
+void
+dasd_remove_sysfs_files(struct ccw_device *cdev)
+{
+       sysfs_remove_group(&cdev->dev.kobj, &dasd_attr_group);
+}
+
+
 int
 dasd_devmap_init(void)
 {
index 5b302ad7c6fcca5d8c980e9062455f758da8cc37..67a896cd4f35d0015c67c06c6c7acc36a8dd8071 100644 (file)
@@ -6,7 +6,7 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
  *
- * $Revision: 1.33 $
+ * $Revision: 1.34 $
  */
 
 #include <linux/config.h>
@@ -173,7 +173,6 @@ dasd_ext_handler(struct pt_regs *regs, __u16 code)
 
        if (!ip) {              /* no intparm: unsolicited interrupt */
                MESSAGE(KERN_DEBUG, "%s", "caught unsolicited interrupt");
-               irq_exit();
                return;
        }
        cqr = (struct dasd_ccw_req *)(addr_t) ip;
@@ -183,7 +182,6 @@ dasd_ext_handler(struct pt_regs *regs, __u16 code)
                            " magic number of dasd_ccw_req 0x%08X doesn't"
                            " match discipline 0x%08X",
                            cqr->magic, *(int *) (&device->discipline->name));
-               irq_exit();
                return;
        }
 
index a16438139405909e3ae59ae9e778b6c86f59ff72..2cdb395dab78b70dc851ce880dc59a7dd787ab08 100644 (file)
@@ -6,7 +6,7 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
  *
- * $Revision: 1.54 $
+ * $Revision: 1.55 $
  */
 
 #ifndef DASD_INT_H
@@ -485,6 +485,8 @@ struct dasd_device *dasd_create_device(struct ccw_device *);
 void dasd_delete_device(struct dasd_device *);
 
 int dasd_add_sysfs_files(struct ccw_device *);
+void dasd_remove_sysfs_files(struct ccw_device *);
+
 struct dasd_device *dasd_device_from_cdev(struct ccw_device *);
 struct dasd_device *dasd_device_from_devindex(int);