diff options
author | Mikulas Patocka <mpatocka@redhat.com> | 2014-01-06 23:01:22 -0500 |
---|---|---|
committer | Mike Snitzer <snitzer@redhat.com> | 2014-01-07 21:01:43 -0500 |
commit | be35f486108227e10fe5d96fd42fb2b344c59983 (patch) | |
tree | 9cfaef139722da4118b4fcd906eb1196d9577b23 /drivers/md | |
parent | 1ddd641ddcfa46d719189468b6856e9b17381a61 (diff) |
dm: wait until embedded kobject is released before destroying a device
There may be other parts of the kernel holding a reference on the dm
kobject. We must wait until all references are dropped before
deallocating the mapped_device structure.
The dm_kobject_release method signals that all references are dropped
via completion. But dm_kobject_release doesn't free the kobject (which
is embedded in the mapped_device structure).
This is the sequence of operations:
* when destroying a DM device, call kobject_put from dm_sysfs_exit
* wait until all users stop using the kobject, when it happens the
release method is called
* the release method signals the completion and should return without
delay
* the dm device removal code that waits on the completion continues
* the dm device removal code drops the dm_mod reference the device had
* the dm device removal code frees the mapped_device structure that
contains the kobject
Using kobject this way should avoid the module unload race that was
mentioned at the beginning of this thread:
https://lkml.org/lkml/2014/1/4/83
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')
-rw-r--r-- | drivers/md/dm-sysfs.c | 10 | ||||
-rw-r--r-- | drivers/md/dm.c | 11 | ||||
-rw-r--r-- | drivers/md/dm.h | 2 |
3 files changed, 22 insertions, 1 deletions
diff --git a/drivers/md/dm-sysfs.c b/drivers/md/dm-sysfs.c index 84d2b91e4efb..e0cc5d6a9e46 100644 --- a/drivers/md/dm-sysfs.c +++ b/drivers/md/dm-sysfs.c | |||
@@ -79,6 +79,11 @@ static const struct sysfs_ops dm_sysfs_ops = { | |||
79 | .show = dm_attr_show, | 79 | .show = dm_attr_show, |
80 | }; | 80 | }; |
81 | 81 | ||
82 | static void dm_kobject_release(struct kobject *kobj) | ||
83 | { | ||
84 | complete(dm_get_completion_from_kobject(kobj)); | ||
85 | } | ||
86 | |||
82 | /* | 87 | /* |
83 | * dm kobject is embedded in mapped_device structure | 88 | * dm kobject is embedded in mapped_device structure |
84 | * no need to define release function here | 89 | * no need to define release function here |
@@ -86,6 +91,7 @@ static const struct sysfs_ops dm_sysfs_ops = { | |||
86 | static struct kobj_type dm_ktype = { | 91 | static struct kobj_type dm_ktype = { |
87 | .sysfs_ops = &dm_sysfs_ops, | 92 | .sysfs_ops = &dm_sysfs_ops, |
88 | .default_attrs = dm_attrs, | 93 | .default_attrs = dm_attrs, |
94 | .release = dm_kobject_release, | ||
89 | }; | 95 | }; |
90 | 96 | ||
91 | /* | 97 | /* |
@@ -104,5 +110,7 @@ int dm_sysfs_init(struct mapped_device *md) | |||
104 | */ | 110 | */ |
105 | void dm_sysfs_exit(struct mapped_device *md) | 111 | void dm_sysfs_exit(struct mapped_device *md) |
106 | { | 112 | { |
107 | kobject_put(dm_kobject(md)); | 113 | struct kobject *kobj = dm_kobject(md); |
114 | kobject_put(kobj); | ||
115 | wait_for_completion(dm_get_completion_from_kobject(kobj)); | ||
108 | } | 116 | } |
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index b3d937211a48..e290e72922a4 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
@@ -203,6 +203,9 @@ struct mapped_device { | |||
203 | /* sysfs handle */ | 203 | /* sysfs handle */ |
204 | struct kobject kobj; | 204 | struct kobject kobj; |
205 | 205 | ||
206 | /* wait until the kobject is released */ | ||
207 | struct completion kobj_completion; | ||
208 | |||
206 | /* zero-length flush that will be cloned and submitted to targets */ | 209 | /* zero-length flush that will be cloned and submitted to targets */ |
207 | struct bio flush_bio; | 210 | struct bio flush_bio; |
208 | 211 | ||
@@ -2041,6 +2044,7 @@ static struct mapped_device *alloc_dev(int minor) | |||
2041 | init_waitqueue_head(&md->wait); | 2044 | init_waitqueue_head(&md->wait); |
2042 | INIT_WORK(&md->work, dm_wq_work); | 2045 | INIT_WORK(&md->work, dm_wq_work); |
2043 | init_waitqueue_head(&md->eventq); | 2046 | init_waitqueue_head(&md->eventq); |
2047 | init_completion(&md->kobj_completion); | ||
2044 | 2048 | ||
2045 | md->disk->major = _major; | 2049 | md->disk->major = _major; |
2046 | md->disk->first_minor = minor; | 2050 | md->disk->first_minor = minor; |
@@ -2919,6 +2923,13 @@ struct mapped_device *dm_get_from_kobject(struct kobject *kobj) | |||
2919 | return md; | 2923 | return md; |
2920 | } | 2924 | } |
2921 | 2925 | ||
2926 | struct 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 | |||
2922 | int dm_suspended_md(struct mapped_device *md) | 2933 | int dm_suspended_md(struct mapped_device *md) |
2923 | { | 2934 | { |
2924 | return test_bit(DMF_SUSPENDED, &md->flags); | 2935 | return test_bit(DMF_SUSPENDED, &md->flags); |
diff --git a/drivers/md/dm.h b/drivers/md/dm.h index c57ba550f69e..1ab2028559ca 100644 --- a/drivers/md/dm.h +++ b/drivers/md/dm.h | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/list.h> | 15 | #include <linux/list.h> |
16 | #include <linux/blkdev.h> | 16 | #include <linux/blkdev.h> |
17 | #include <linux/hdreg.h> | 17 | #include <linux/hdreg.h> |
18 | #include <linux/completion.h> | ||
18 | 19 | ||
19 | #include "dm-stats.h" | 20 | #include "dm-stats.h" |
20 | 21 | ||
@@ -152,6 +153,7 @@ int dm_sysfs_init(struct mapped_device *md); | |||
152 | void dm_sysfs_exit(struct mapped_device *md); | 153 | void dm_sysfs_exit(struct mapped_device *md); |
153 | struct kobject *dm_kobject(struct mapped_device *md); | 154 | struct kobject *dm_kobject(struct mapped_device *md); |
154 | struct mapped_device *dm_get_from_kobject(struct kobject *kobj); | 155 | struct mapped_device *dm_get_from_kobject(struct kobject *kobj); |
156 | struct completion *dm_get_completion_from_kobject(struct kobject *kobj); | ||
155 | 157 | ||
156 | /* | 158 | /* |
157 | * Targets for linear and striped mappings | 159 | * Targets for linear and striped mappings |