aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/dm.c
diff options
context:
space:
mode:
authorMikulas Patocka <mpatocka@redhat.com>2014-01-13 19:37:54 -0500
committerMike Snitzer <snitzer@redhat.com>2014-01-14 23:23:04 -0500
commit2995fa78e423d7193f3b57835f6c1c75006a0315 (patch)
tree9f107c0503a3c0ba58559a62847e9236f3fd1951 /drivers/md/dm.c
parent55b082e614e219fb5199a6f93e648ed35d3c96d5 (diff)
dm sysfs: fix a module unload race
This reverts commit be35f48610 ("dm: wait until embedded kobject is released before destroying a device") and provides an improved fix. The kobject release code that calls the completion must be placed in a non-module file, otherwise there is a module unload race (if the process calling dm_kobject_release is preempted and the DM module unloaded after the completion is triggered, but before dm_kobject_release returns). To fix this race, this patch moves the completion code to dm-builtin.c which is always compiled directly into the kernel if BLK_DEV_DM is selected. The patch introduces a new dm_kobject_holder structure, its purpose is to keep the completion and kobject in one place, so that it can be accessed from non-module code without the need to export the layout of struct mapped_device to that code. Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Signed-off-by: Mike Snitzer <snitzer@redhat.com> Cc: stable@vger.kernel.org
Diffstat (limited to 'drivers/md/dm.c')
-rw-r--r--drivers/md/dm.c20
1 files changed, 5 insertions, 15 deletions
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index e290e72922a4..b49c76284241 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -200,11 +200,8 @@ struct mapped_device {
200 /* forced geometry settings */ 200 /* forced geometry settings */
201 struct hd_geometry geometry; 201 struct hd_geometry geometry;
202 202
203 /* sysfs handle */ 203 /* kobject and completion */
204 struct kobject kobj; 204 struct dm_kobject_holder kobj_holder;
205
206 /* wait until the kobject is released */
207 struct completion kobj_completion;
208 205
209 /* zero-length flush that will be cloned and submitted to targets */ 206 /* zero-length flush that will be cloned and submitted to targets */
210 struct bio flush_bio; 207 struct bio flush_bio;
@@ -2044,7 +2041,7 @@ static struct mapped_device *alloc_dev(int minor)
2044 init_waitqueue_head(&md->wait); 2041 init_waitqueue_head(&md->wait);
2045 INIT_WORK(&md->work, dm_wq_work); 2042 INIT_WORK(&md->work, dm_wq_work);
2046 init_waitqueue_head(&md->eventq); 2043 init_waitqueue_head(&md->eventq);
2047 init_completion(&md->kobj_completion); 2044 init_completion(&md->kobj_holder.completion);
2048 2045
2049 md->disk->major = _major; 2046 md->disk->major = _major;
2050 md->disk->first_minor = minor; 2047 md->disk->first_minor = minor;
@@ -2906,14 +2903,14 @@ struct gendisk *dm_disk(struct mapped_device *md)
2906 2903
2907struct kobject *dm_kobject(struct mapped_device *md) 2904struct kobject *dm_kobject(struct mapped_device *md)
2908{ 2905{
2909 return &md->kobj; 2906 return &md->kobj_holder.kobj;
2910} 2907}
2911 2908
2912struct mapped_device *dm_get_from_kobject(struct kobject *kobj) 2909struct mapped_device *dm_get_from_kobject(struct kobject *kobj)
2913{ 2910{
2914 struct mapped_device *md; 2911 struct mapped_device *md;
2915 2912
2916 md = container_of(kobj, struct mapped_device, kobj); 2913 md = container_of(kobj, struct mapped_device, kobj_holder.kobj);
2917 2914
2918 if (test_bit(DMF_FREEING, &md->flags) || 2915 if (test_bit(DMF_FREEING, &md->flags) ||
2919 dm_deleting_md(md)) 2916 dm_deleting_md(md))
@@ -2923,13 +2920,6 @@ struct mapped_device *dm_get_from_kobject(struct kobject *kobj)
2923 return md; 2920 return md;
2924} 2921}
2925 2922
2926struct completion *dm_get_completion_from_kobject(struct kobject *kobj)
2927{
2928 struct mapped_device *md = container_of(kobj, struct mapped_device, kobj);
2929
2930 return &md->kobj_completion;
2931}
2932
2933int dm_suspended_md(struct mapped_device *md) 2923int dm_suspended_md(struct mapped_device *md)
2934{ 2924{
2935 return test_bit(DMF_SUSPENDED, &md->flags); 2925 return test_bit(DMF_SUSPENDED, &md->flags);