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: 19508b204740 ("s390/dasd: Display FC Endpoint Security information via sysfs") Reported-by: Stefan Haberland <sth@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com> Reviewed-by: Stefan Haberland <sth@linux.ibm.com> Reviewed-by: Cornelia Huck <cohuck@redhat.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
parent
ef49d40b61
commit
ac55ad2b5f
@ -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)
|
||||
{
|
||||
|
@ -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 @@ out_err2:
|
||||
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 *
|
||||
|
@ -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 *);
|
||||
|
Loading…
x
Reference in New Issue
Block a user