Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6ab4879a authored by Cornelia Huck's avatar Cornelia Huck Committed by Martin Schwidefsky
Browse files

[S390] subchannel register/unregister mutex.



Add a reg_mutex to prevent unregistering a subchannel before it has been
registered. Since 2.6.17, we've seen oopses in kslowcrw when a device is
found to be not operational during sense id when doing initial device
recognition; it is not clear yet why that particular problem was not (yet)
observed with earlier kernels...

Signed-off-by: default avatarCornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 63f4f9e1
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -519,6 +519,7 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
	memset(sch, 0, sizeof(struct subchannel));

	spin_lock_init(&sch->lock);
	mutex_init(&sch->reg_mutex);

	/* Set a name for the subchannel */
	snprintf (sch->dev.bus_id, BUS_ID_SIZE, "0.%x.%04x", schid.ssid,
+2 −1
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@
#define S390_CIO_H

#include "schid.h"
#include <linux/mutex.h>

/*
 * where we put the ssd info
@@ -87,7 +88,7 @@ struct orb {
struct subchannel {
	struct subchannel_id schid;
	spinlock_t lock;	/* subchannel lock */

	struct mutex reg_mutex;
	enum {
		SUBCHANNEL_TYPE_IO = 0,
		SUBCHANNEL_TYPE_CHSC = 1,
+21 −3
Original line number Diff line number Diff line
@@ -108,6 +108,24 @@ css_subchannel_release(struct device *dev)

extern int css_get_ssd_info(struct subchannel *sch);


int css_sch_device_register(struct subchannel *sch)
{
	int ret;

	mutex_lock(&sch->reg_mutex);
	ret = device_register(&sch->dev);
	mutex_unlock(&sch->reg_mutex);
	return ret;
}

void css_sch_device_unregister(struct subchannel *sch)
{
	mutex_lock(&sch->reg_mutex);
	device_unregister(&sch->dev);
	mutex_unlock(&sch->reg_mutex);
}

static int
css_register_subchannel(struct subchannel *sch)
{
@@ -119,7 +137,7 @@ css_register_subchannel(struct subchannel *sch)
	sch->dev.release = &css_subchannel_release;
	
	/* make it known to the system */
	ret = device_register(&sch->dev);
	ret = css_sch_device_register(sch);
	if (ret)
		printk (KERN_WARNING "%s: could not register %s\n",
			__func__, sch->dev.bus_id);
@@ -250,7 +268,7 @@ css_evaluate_subchannel(struct subchannel_id schid, int slow)
		 * The device will be killed automatically.
		 */
		cio_disable_subchannel(sch);
		device_unregister(&sch->dev);
		css_sch_device_unregister(sch);
		/* Reset intparm to zeroes. */
		sch->schib.pmcw.intparm = 0;
		cio_modify(sch);
@@ -264,7 +282,7 @@ css_evaluate_subchannel(struct subchannel_id schid, int slow)
		 * away in any case.
		 */
		if (!disc) {
			device_unregister(&sch->dev);
			css_sch_device_unregister(sch);
			/* Reset intparm to zeroes. */
			sch->schib.pmcw.intparm = 0;
			cio_modify(sch);
+2 −0
Original line number Diff line number Diff line
@@ -136,6 +136,8 @@ extern struct bus_type css_bus_type;
extern struct css_driver io_subchannel_driver;

extern int css_probe_device(struct subchannel_id);
extern int css_sch_device_register(struct subchannel *);
extern void css_sch_device_unregister(struct subchannel *);
extern struct subchannel * get_subchannel_by_schid(struct subchannel_id);
extern int css_init_done;
extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *);
+3 −3
Original line number Diff line number Diff line
@@ -280,7 +280,7 @@ ccw_device_remove_disconnected(struct ccw_device *cdev)
	 * 'throw away device'.
	 */
	sch = to_subchannel(cdev->dev.parent);
	device_unregister(&sch->dev);
	css_sch_device_unregister(sch);
	/* Reset intparm to zeroes. */
	sch->schib.pmcw.intparm = 0;
	cio_modify(sch);
@@ -625,7 +625,7 @@ ccw_device_do_unreg_rereg(void *data)
					other_sch->schib.pmcw.intparm = 0;
					cio_modify(other_sch);
				}
				device_unregister(&other_sch->dev);
				css_sch_device_unregister(other_sch);
			}
		}
		/* Update ssd info here. */
@@ -709,7 +709,7 @@ ccw_device_call_sch_unregister(void *data)
	struct subchannel *sch;

	sch = to_subchannel(cdev->dev.parent);
	device_unregister(&sch->dev);
	css_sch_device_unregister(sch);
	/* Reset intparm to zeroes. */
	sch->schib.pmcw.intparm = 0;
	cio_modify(sch);