diff options
author | Cornelia Huck <cornelia.huck@de.ibm.com> | 2007-04-27 10:01:37 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2007-04-27 10:01:41 -0400 |
commit | d76123eb357a4baa653714183df286c1bb99f707 (patch) | |
tree | b7244cc14038bc337d89d7a00acd847626438ffe /drivers/s390/cio/ccwgroup.c | |
parent | 82b7ac058f60e0c92f9237fbaf440671f437ecdf (diff) |
[S390] cio: ccwgroup register vs. unregister.
Introduce a mutex for struct ccwgroup to prevent simuntaneous
register/unregister on the same ccwgroup device.
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/cio/ccwgroup.c')
-rw-r--r-- | drivers/s390/cio/ccwgroup.c | 33 |
1 files changed, 18 insertions, 15 deletions
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 5aeb68e732b0..e5ccda63e883 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c | |||
@@ -75,8 +75,10 @@ static void ccwgroup_ungroup_callback(struct device *dev) | |||
75 | { | 75 | { |
76 | struct ccwgroup_device *gdev = to_ccwgroupdev(dev); | 76 | struct ccwgroup_device *gdev = to_ccwgroupdev(dev); |
77 | 77 | ||
78 | mutex_lock(&gdev->reg_mutex); | ||
78 | __ccwgroup_remove_symlinks(gdev); | 79 | __ccwgroup_remove_symlinks(gdev); |
79 | device_unregister(dev); | 80 | device_unregister(dev); |
81 | mutex_unlock(&gdev->reg_mutex); | ||
80 | } | 82 | } |
81 | 83 | ||
82 | static ssize_t | 84 | static ssize_t |
@@ -173,7 +175,8 @@ ccwgroup_create(struct device *root, | |||
173 | return -ENOMEM; | 175 | return -ENOMEM; |
174 | 176 | ||
175 | atomic_set(&gdev->onoff, 0); | 177 | atomic_set(&gdev->onoff, 0); |
176 | 178 | mutex_init(&gdev->reg_mutex); | |
179 | mutex_lock(&gdev->reg_mutex); | ||
177 | for (i = 0; i < argc; i++) { | 180 | for (i = 0; i < argc; i++) { |
178 | gdev->cdev[i] = get_ccwdev_by_busid(cdrv, argv[i]); | 181 | gdev->cdev[i] = get_ccwdev_by_busid(cdrv, argv[i]); |
179 | 182 | ||
@@ -183,12 +186,12 @@ ccwgroup_create(struct device *root, | |||
183 | || gdev->cdev[i]->id.driver_info != | 186 | || gdev->cdev[i]->id.driver_info != |
184 | gdev->cdev[0]->id.driver_info) { | 187 | gdev->cdev[0]->id.driver_info) { |
185 | rc = -EINVAL; | 188 | rc = -EINVAL; |
186 | goto free_dev; | 189 | goto error; |
187 | } | 190 | } |
188 | /* Don't allow a device to belong to more than one group. */ | 191 | /* Don't allow a device to belong to more than one group. */ |
189 | if (gdev->cdev[i]->dev.driver_data) { | 192 | if (gdev->cdev[i]->dev.driver_data) { |
190 | rc = -EINVAL; | 193 | rc = -EINVAL; |
191 | goto free_dev; | 194 | goto error; |
192 | } | 195 | } |
193 | gdev->cdev[i]->dev.driver_data = gdev; | 196 | gdev->cdev[i]->dev.driver_data = gdev; |
194 | } | 197 | } |
@@ -203,9 +206,8 @@ ccwgroup_create(struct device *root, | |||
203 | gdev->cdev[0]->dev.bus_id); | 206 | gdev->cdev[0]->dev.bus_id); |
204 | 207 | ||
205 | rc = device_register(&gdev->dev); | 208 | rc = device_register(&gdev->dev); |
206 | |||
207 | if (rc) | 209 | if (rc) |
208 | goto free_dev; | 210 | goto error; |
209 | get_device(&gdev->dev); | 211 | get_device(&gdev->dev); |
210 | rc = device_create_file(&gdev->dev, &dev_attr_ungroup); | 212 | rc = device_create_file(&gdev->dev, &dev_attr_ungroup); |
211 | 213 | ||
@@ -216,6 +218,7 @@ ccwgroup_create(struct device *root, | |||
216 | 218 | ||
217 | rc = __ccwgroup_create_symlinks(gdev); | 219 | rc = __ccwgroup_create_symlinks(gdev); |
218 | if (!rc) { | 220 | if (!rc) { |
221 | mutex_unlock(&gdev->reg_mutex); | ||
219 | put_device(&gdev->dev); | 222 | put_device(&gdev->dev); |
220 | return 0; | 223 | return 0; |
221 | } | 224 | } |
@@ -224,19 +227,12 @@ ccwgroup_create(struct device *root, | |||
224 | error: | 227 | error: |
225 | for (i = 0; i < argc; i++) | 228 | for (i = 0; i < argc; i++) |
226 | if (gdev->cdev[i]) { | 229 | if (gdev->cdev[i]) { |
227 | put_device(&gdev->cdev[i]->dev); | ||
228 | gdev->cdev[i]->dev.driver_data = NULL; | ||
229 | } | ||
230 | put_device(&gdev->dev); | ||
231 | return rc; | ||
232 | free_dev: | ||
233 | for (i = 0; i < argc; i++) | ||
234 | if (gdev->cdev[i]) { | ||
235 | if (gdev->cdev[i]->dev.driver_data == gdev) | 230 | if (gdev->cdev[i]->dev.driver_data == gdev) |
236 | gdev->cdev[i]->dev.driver_data = NULL; | 231 | gdev->cdev[i]->dev.driver_data = NULL; |
237 | put_device(&gdev->cdev[i]->dev); | 232 | put_device(&gdev->cdev[i]->dev); |
238 | } | 233 | } |
239 | kfree(gdev); | 234 | mutex_unlock(&gdev->reg_mutex); |
235 | put_device(&gdev->dev); | ||
240 | return rc; | 236 | return rc; |
241 | } | 237 | } |
242 | 238 | ||
@@ -422,8 +418,12 @@ ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver) | |||
422 | get_driver(&cdriver->driver); | 418 | get_driver(&cdriver->driver); |
423 | while ((dev = driver_find_device(&cdriver->driver, NULL, NULL, | 419 | while ((dev = driver_find_device(&cdriver->driver, NULL, NULL, |
424 | __ccwgroup_match_all))) { | 420 | __ccwgroup_match_all))) { |
425 | __ccwgroup_remove_symlinks(to_ccwgroupdev(dev)); | 421 | struct ccwgroup_device *gdev = to_ccwgroupdev(dev); |
422 | |||
423 | mutex_lock(&gdev->reg_mutex); | ||
424 | __ccwgroup_remove_symlinks(gdev); | ||
426 | device_unregister(dev); | 425 | device_unregister(dev); |
426 | mutex_unlock(&gdev->reg_mutex); | ||
427 | put_device(dev); | 427 | put_device(dev); |
428 | } | 428 | } |
429 | put_driver(&cdriver->driver); | 429 | put_driver(&cdriver->driver); |
@@ -444,8 +444,10 @@ __ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev) | |||
444 | if (cdev->dev.driver_data) { | 444 | if (cdev->dev.driver_data) { |
445 | gdev = (struct ccwgroup_device *)cdev->dev.driver_data; | 445 | gdev = (struct ccwgroup_device *)cdev->dev.driver_data; |
446 | if (get_device(&gdev->dev)) { | 446 | if (get_device(&gdev->dev)) { |
447 | mutex_lock(&gdev->reg_mutex); | ||
447 | if (device_is_registered(&gdev->dev)) | 448 | if (device_is_registered(&gdev->dev)) |
448 | return gdev; | 449 | return gdev; |
450 | mutex_unlock(&gdev->reg_mutex); | ||
449 | put_device(&gdev->dev); | 451 | put_device(&gdev->dev); |
450 | } | 452 | } |
451 | return NULL; | 453 | return NULL; |
@@ -465,6 +467,7 @@ ccwgroup_remove_ccwdev(struct ccw_device *cdev) | |||
465 | if (gdev) { | 467 | if (gdev) { |
466 | __ccwgroup_remove_symlinks(gdev); | 468 | __ccwgroup_remove_symlinks(gdev); |
467 | device_unregister(&gdev->dev); | 469 | device_unregister(&gdev->dev); |
470 | mutex_unlock(&gdev->reg_mutex); | ||
468 | put_device(&gdev->dev); | 471 | put_device(&gdev->dev); |
469 | } | 472 | } |
470 | } | 473 | } |