Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

s390/cio: use device_lock during cmb activation

Hold the device_lock during [de]activation of the channel measurement
block to synchronize concurrent usage of these functions.

Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Reviewed-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

authored by

Sebastian Ott and committed by
Martin Schwidefsky
1bc6664b 279b8f9a

+40 -14
+1
arch/s390/include/asm/cmb.h
··· 6 6 struct ccw_device; 7 7 extern int enable_cmf(struct ccw_device *cdev); 8 8 extern int disable_cmf(struct ccw_device *cdev); 9 + extern int __disable_cmf(struct ccw_device *cdev); 9 10 extern u64 cmf_read(struct ccw_device *cdev, int index); 10 11 extern int cmf_readall(struct ccw_device *cdev, struct cmbdata *data); 11 12
+38 -13
drivers/s390/cio/cmf.c
··· 1226 1226 { 1227 1227 int ret; 1228 1228 1229 + device_lock(&cdev->dev); 1229 1230 ret = cmbops->alloc(cdev); 1230 - cmbops->reset(cdev); 1231 1231 if (ret) 1232 - return ret; 1233 - ret = cmbops->set(cdev, 2); 1232 + goto out; 1233 + cmbops->reset(cdev); 1234 + ret = sysfs_create_group(&cdev->dev.kobj, cmbops->attr_group); 1234 1235 if (ret) { 1235 1236 cmbops->free(cdev); 1236 - return ret; 1237 + goto out; 1237 1238 } 1238 - ret = sysfs_create_group(&cdev->dev.kobj, cmbops->attr_group); 1239 - if (!ret) 1240 - return 0; 1241 - cmbops->set(cdev, 0); //FIXME: this can fail 1239 + ret = cmbops->set(cdev, 2); 1240 + if (ret) { 1241 + sysfs_remove_group(&cdev->dev.kobj, cmbops->attr_group); 1242 + cmbops->free(cdev); 1243 + } 1244 + out: 1245 + device_unlock(&cdev->dev); 1246 + return ret; 1247 + } 1248 + 1249 + /** 1250 + * __disable_cmf() - switch off the channel measurement for a specific device 1251 + * @cdev: The ccw device to be disabled 1252 + * 1253 + * Returns %0 for success or a negative error value. 1254 + * 1255 + * Context: 1256 + * non-atomic, device_lock() held. 1257 + */ 1258 + int __disable_cmf(struct ccw_device *cdev) 1259 + { 1260 + int ret; 1261 + 1262 + ret = cmbops->set(cdev, 0); 1263 + if (ret) 1264 + return ret; 1265 + 1266 + sysfs_remove_group(&cdev->dev.kobj, cmbops->attr_group); 1242 1267 cmbops->free(cdev); 1268 + 1243 1269 return ret; 1244 1270 } 1245 1271 ··· 1282 1256 { 1283 1257 int ret; 1284 1258 1285 - ret = cmbops->set(cdev, 0); 1286 - if (ret) 1287 - return ret; 1288 - cmbops->free(cdev); 1289 - sysfs_remove_group(&cdev->dev.kobj, cmbops->attr_group); 1259 + device_lock(&cdev->dev); 1260 + ret = __disable_cmf(cdev); 1261 + device_unlock(&cdev->dev); 1262 + 1290 1263 return ret; 1291 1264 } 1292 1265
+1 -1
drivers/s390/cio/device.c
··· 1797 1797 cdev = to_ccwdev(dev); 1798 1798 if (cdev->drv && cdev->drv->shutdown) 1799 1799 cdev->drv->shutdown(cdev); 1800 - disable_cmf(cdev); 1800 + __disable_cmf(cdev); 1801 1801 } 1802 1802 1803 1803 static int ccw_device_pm_prepare(struct device *dev)