s390/cio: fix driver callback initialization for ccw consoles
authorSebastian Ott <sebott@linux.vnet.ibm.com>
Mon, 27 Jan 2014 12:26:10 +0000 (13:26 +0100)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Fri, 21 Feb 2014 07:50:11 +0000 (08:50 +0100)
ccw consoles are in use before they can be properly registered with
the driver core. For devices which are in use by a device driver we
rely on the ccw_device's pointer to the driver callbacks to be valid.
For ccw consoles this pointer is NULL until they are registered later
during boot and we dereferenced this pointer. This worked by
chance on 64 bit builds (cdev->drv was NULL but the optional callback
cdev->drv->path_event was also NULL by coincidence) and was unnoticed
until we received reports about boot failures on 31 bit systems.
Fix it by initializing the driver pointer for ccw consoles.

Cc: <stable@vger.kernel.org> # 3.10+
Reported-by: Mike Frysinger <vapier@gentoo.org>
Reported-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
arch/s390/include/asm/ccwdev.h
drivers/s390/char/con3215.c
drivers/s390/char/con3270.c
drivers/s390/char/raw3270.c
drivers/s390/char/raw3270.h
drivers/s390/cio/device.c

index f201af8be580ddc876de2f5de96952aaaf493cb5..31b5ca8f8c3dcee17ff3008d4ace3d8c177a4334 100644 (file)
@@ -219,7 +219,7 @@ extern void ccw_device_get_id(struct ccw_device *, struct ccw_dev_id *);
 #define to_ccwdev(n) container_of(n, struct ccw_device, dev)
 #define to_ccwdrv(n) container_of(n, struct ccw_driver, driver)
 
-extern struct ccw_device *ccw_device_probe_console(void);
+extern struct ccw_device *ccw_device_probe_console(struct ccw_driver *);
 extern void ccw_device_wait_idle(struct ccw_device *);
 extern int ccw_device_force_console(struct ccw_device *);
 
index eb5d22795c47a55744381ee3f9e70c1666701835..bb86494e2b7b7878aecddf25b9df4b53fa443260 100644 (file)
@@ -922,7 +922,7 @@ static int __init con3215_init(void)
                raw3215_freelist = req;
        }
 
-       cdev = ccw_device_probe_console();
+       cdev = ccw_device_probe_console(&raw3215_ccw_driver);
        if (IS_ERR(cdev))
                return -ENODEV;
 
index 699fd3e363dfba2f7b0fe8dbab3f43961ec1a108..bb6b0df50b33618ae337f623038d042f96a2430a 100644 (file)
@@ -576,7 +576,6 @@ static struct console con3270 = {
 static int __init
 con3270_init(void)
 {
-       struct ccw_device *cdev;
        struct raw3270 *rp;
        void *cbuf;
        int i;
@@ -591,10 +590,7 @@ con3270_init(void)
                cpcmd("TERM AUTOCR OFF", NULL, 0, NULL);
        }
 
-       cdev = ccw_device_probe_console();
-       if (IS_ERR(cdev))
-               return -ENODEV;
-       rp = raw3270_setup_console(cdev);
+       rp = raw3270_setup_console();
        if (IS_ERR(rp))
                return PTR_ERR(rp);
 
index 2cdec21e8924ea7b0403aafd1b0bae172a76416e..de2c0483949f7a5728e54ae4a94ec581f8bea3c4 100644 (file)
@@ -776,16 +776,24 @@ raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc)
 }
 
 #ifdef CONFIG_TN3270_CONSOLE
+/* Tentative definition - see below for actual definition. */
+static struct ccw_driver raw3270_ccw_driver;
+
 /*
  * Setup 3270 device configured as console.
  */
-struct raw3270 __init *raw3270_setup_console(struct ccw_device *cdev)
+struct raw3270 __init *raw3270_setup_console(void)
 {
+       struct ccw_device *cdev;
        unsigned long flags;
        struct raw3270 *rp;
        char *ascebc;
        int rc;
 
+       cdev = ccw_device_probe_console(&raw3270_ccw_driver);
+       if (IS_ERR(cdev))
+               return ERR_CAST(cdev);
+
        rp = kzalloc(sizeof(struct raw3270), GFP_KERNEL | GFP_DMA);
        ascebc = kzalloc(256, GFP_KERNEL);
        rc = raw3270_setup_device(cdev, rp, ascebc);
index 7b73ff8c1bd7a59a5c60fe9d7886371c48d4d2c4..359276a883965734a101ba0ed5a68122ac2a843a 100644 (file)
@@ -190,7 +190,7 @@ raw3270_put_view(struct raw3270_view *view)
                wake_up(&raw3270_wait_queue);
 }
 
-struct raw3270 *raw3270_setup_console(struct ccw_device *cdev);
+struct raw3270 *raw3270_setup_console(void);
 void raw3270_wait_cons_dev(struct raw3270 *);
 
 /* Notifier for device addition/removal */
index e9d783563cbb8894182efcfde40376eb731d286b..4283dd3cdd4909ea924e478b9aafae3853d69652 100644 (file)
@@ -1609,7 +1609,7 @@ out_unlock:
        return rc;
 }
 
-struct ccw_device *ccw_device_probe_console(void)
+struct ccw_device *ccw_device_probe_console(struct ccw_driver *drv)
 {
        struct io_subchannel_private *io_priv;
        struct ccw_device *cdev;
@@ -1631,6 +1631,7 @@ struct ccw_device *ccw_device_probe_console(void)
                kfree(io_priv);
                return cdev;
        }
+       cdev->drv = drv;
        set_io_private(sch, io_priv);
        ret = ccw_device_console_enable(cdev, sch);
        if (ret) {