Commit ac55ad2b authored by Jan Höppner's avatar Jan Höppner Committed by Jens Axboe
Browse files

s390/dasd: Fix inconsistent kobject removal



Our intention was to only remove path kobjects whenever a device is
being set offline. However, one corner case was missing.

If a device is disabled and enabled (using the IOCTLs BIODASDDISABLE and
BIODASDENABLE respectively), the enabling process will call
dasd_eckd_reload_device() which itself calls dasd_eckd_read_conf() in
order to update path information. During that update,
dasd_eckd_clear_conf_data() clears all old data and also removes all
kobjects. This will leave us with an inconsistent state of path kobjects
and a subsequent path verification leads to a failing kobject creation.

Fix this by removing kobjects only in the context of offlining a device
as initially intended.

Fixes: 19508b20 ("s390/dasd: Display FC Endpoint Security information via sysfs")
Reported-by: default avatarStefan Haberland <sth@linux.ibm.com>
Signed-off-by: default avatarJan Höppner <hoeppner@linux.ibm.com>
Reviewed-by: default avatarStefan Haberland <sth@linux.ibm.com>
Reviewed-by: default avatarCornelia Huck <cohuck@redhat.com>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent ef49d40b
Loading
Loading
Loading
Loading
+14 −6
Original line number Diff line number Diff line
@@ -1874,18 +1874,26 @@ void dasd_path_create_kobjects(struct dasd_device *device)
}
EXPORT_SYMBOL(dasd_path_create_kobjects);

/*
 * As we keep kobjects for the lifetime of a device, this function must not be
 * called anywhere but in the context of offlining a device.
 */
void dasd_path_remove_kobj(struct dasd_device *device, int chp)
static void dasd_path_remove_kobj(struct dasd_device *device, int chp)
{
	if (device->path[chp].in_sysfs) {
		kobject_put(&device->path[chp].kobj);
		device->path[chp].in_sysfs = false;
	}
}
EXPORT_SYMBOL(dasd_path_remove_kobj);

/*
 * As we keep kobjects for the lifetime of a device, this function must not be
 * called anywhere but in the context of offlining a device.
 */
void dasd_path_remove_kobjects(struct dasd_device *device)
{
	int i;

	for (i = 0; i < 8; i++)
		dasd_path_remove_kobj(device, i);
}
EXPORT_SYMBOL(dasd_path_remove_kobjects);

int dasd_add_sysfs_files(struct ccw_device *cdev)
{
+2 −1
Original line number Diff line number Diff line
@@ -1036,7 +1036,6 @@ static void dasd_eckd_clear_conf_data(struct dasd_device *device)
		device->path[i].ssid = 0;
		device->path[i].chpid = 0;
		dasd_path_notoper(device, i);
		dasd_path_remove_kobj(device, i);
	}
}

@@ -2173,6 +2172,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
	device->block = NULL;
out_err1:
	dasd_eckd_clear_conf_data(device);
	dasd_path_remove_kobjects(device);
	kfree(device->private);
	device->private = NULL;
	return rc;
@@ -2191,6 +2191,7 @@ static void dasd_eckd_uncheck_device(struct dasd_device *device)
	private->vdsneq = NULL;
	private->gneq = NULL;
	dasd_eckd_clear_conf_data(device);
	dasd_path_remove_kobjects(device);
}

static struct dasd_ccw_req *
+1 −1
Original line number Diff line number Diff line
@@ -858,7 +858,7 @@ int dasd_add_sysfs_files(struct ccw_device *);
void dasd_remove_sysfs_files(struct ccw_device *);
void dasd_path_create_kobj(struct dasd_device *, int);
void dasd_path_create_kobjects(struct dasd_device *);
void dasd_path_remove_kobj(struct dasd_device *, int);
void dasd_path_remove_kobjects(struct dasd_device *);

struct dasd_device *dasd_device_from_cdev(struct ccw_device *);
struct dasd_device *dasd_device_from_cdev_locked(struct ccw_device *);