diff options
| author | Mikulas Patocka <mpatocka@redhat.com> | 2014-01-06 23:01:22 -0500 |
|---|---|---|
| committer | Mike Snitzer <snitzer@redhat.com> | 2014-01-07 14:09:09 -0500 |
| commit | af7b1e5c767fc895788c971c8f4686402ac8344f (patch) | |
| tree | 9cfaef139722da4118b4fcd906eb1196d9577b23 | |
| parent | 1ddd641ddcfa46d719189468b6856e9b17381a61 (diff) | |
| download | linux-dm-af7b1e5c767fc895788c971c8f4686402ac8344f.tar.gz | |
dm: wait until embedded kobject is released before destroying a device
Notice: this object is not reachable from any branch.
There may be other parts of the kernel taking reference to the dm kobject.
We must wait until they drop the references before deallocating the md
structure.
The dm_kobject_release method doesn't free the kobject (which is
embedded in the mapped_device structure). dm_kobject_release just
signals the completion and returns.
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 returns
* the dm_mod unload code that waits on the completion continues
* the dm_mod unload code frees the mapped_device structure that contains
the kobject
Using kobject this way avoids 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
Notice: this object is not reachable from any branch.
| -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 84d2b91e4efb1..e0cc5d6a9e469 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 = { .show = dm_attr_show, }; +static void dm_kobject_release(struct kobject *kobj) +{ + complete(dm_get_completion_from_kobject(kobj)); +} + /* * dm kobject is embedded in mapped_device structure * no need to define release function here @@ -86,6 +91,7 @@ static const struct sysfs_ops dm_sysfs_ops = { static struct kobj_type dm_ktype = { .sysfs_ops = &dm_sysfs_ops, .default_attrs = dm_attrs, + .release = dm_kobject_release, }; /* @@ -104,5 +110,7 @@ int dm_sysfs_init(struct mapped_device *md) */ void dm_sysfs_exit(struct mapped_device *md) { - kobject_put(dm_kobject(md)); + struct kobject *kobj = dm_kobject(md); + kobject_put(kobj); + wait_for_completion(dm_get_completion_from_kobject(kobj)); } diff --git a/drivers/md/dm.c b/drivers/md/dm.c index b3d937211a488..e290e72922a44 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -203,6 +203,9 @@ struct mapped_device { /* sysfs handle */ struct kobject kobj; + /* wait until the kobject is released */ + struct completion kobj_completion; + /* zero-length flush that will be cloned and submitted to targets */ struct bio flush_bio; @@ -2041,6 +2044,7 @@ static struct mapped_device *alloc_dev(int minor) init_waitqueue_head(&md->wait); INIT_WORK(&md->work, dm_wq_work); init_waitqueue_head(&md->eventq); + init_completion(&md->kobj_completion); md->disk->major = _major; md->disk->first_minor = minor; @@ -2919,6 +2923,13 @@ struct mapped_device *dm_get_from_kobject(struct kobject *kobj) return md; } +struct completion *dm_get_completion_from_kobject(struct kobject *kobj) +{ + struct mapped_device *md = container_of(kobj, struct mapped_device, kobj); + + return &md->kobj_completion; +} + int dm_suspended_md(struct mapped_device *md) { return test_bit(DMF_SUSPENDED, &md->flags); diff --git a/drivers/md/dm.h b/drivers/md/dm.h index c57ba550f69e1..1ab2028559caa 100644 --- a/drivers/md/dm.h +++ b/drivers/md/dm.h @@ -15,6 +15,7 @@ #include <linux/list.h> #include <linux/blkdev.h> #include <linux/hdreg.h> +#include <linux/completion.h> #include "dm-stats.h" @@ -152,6 +153,7 @@ int dm_sysfs_init(struct mapped_device *md); void dm_sysfs_exit(struct mapped_device *md); struct kobject *dm_kobject(struct mapped_device *md); struct mapped_device *dm_get_from_kobject(struct kobject *kobj); +struct completion *dm_get_completion_from_kobject(struct kobject *kobj); /* * Targets for linear and striped mappings |
