diff options
author | Jeff Mahoney <jeffm@suse.com> | 2006-06-26 03:27:21 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-26 12:58:34 -0400 |
commit | ba61fdd17d73ddb5c892a9f12383c6c560a20d56 (patch) | |
tree | 7623bd742e2c142a8c5a1d8e5b940095b8673f3f | |
parent | 5806f07cd2c32920d5105e0f9ff3117338f34eec (diff) |
[PATCH] dm: fix idr minor allocation
One part of the system can attempt to use a mapped device before another has
finished initialising it or while it is being freed.
This patch introduces a place holder value, MINOR_ALLOCED, to mark the minor
as allocated but in a state where it can't be used, such as mid-allocation or
mid-free. At the end of the initialization, it replaces the place holder with
the pointer to the mapped_device, making it available to the rest of the dm
subsystem.
[akpm: too late for 2.6.17 - suitable for 2.6.17.x after it has settled]
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Cc: <stable@kernel.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | drivers/md/dm.c | 19 |
1 files changed, 16 insertions, 3 deletions
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 4d710b7a133b..87d8ca1121e2 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
@@ -54,6 +54,8 @@ union map_info *dm_get_mapinfo(struct bio *bio) | |||
54 | return NULL; | 54 | return NULL; |
55 | } | 55 | } |
56 | 56 | ||
57 | #define MINOR_ALLOCED ((void *)-1) | ||
58 | |||
57 | /* | 59 | /* |
58 | * Bits for the md->flags field. | 60 | * Bits for the md->flags field. |
59 | */ | 61 | */ |
@@ -777,7 +779,7 @@ static int specific_minor(struct mapped_device *md, unsigned int minor) | |||
777 | goto out; | 779 | goto out; |
778 | } | 780 | } |
779 | 781 | ||
780 | r = idr_get_new_above(&_minor_idr, md, minor, &m); | 782 | r = idr_get_new_above(&_minor_idr, MINOR_ALLOCED, minor, &m); |
781 | if (r) { | 783 | if (r) { |
782 | goto out; | 784 | goto out; |
783 | } | 785 | } |
@@ -806,7 +808,7 @@ static int next_free_minor(struct mapped_device *md, unsigned int *minor) | |||
806 | goto out; | 808 | goto out; |
807 | } | 809 | } |
808 | 810 | ||
809 | r = idr_get_new(&_minor_idr, md, &m); | 811 | r = idr_get_new(&_minor_idr, MINOR_ALLOCED, &m); |
810 | if (r) { | 812 | if (r) { |
811 | goto out; | 813 | goto out; |
812 | } | 814 | } |
@@ -833,6 +835,7 @@ static struct mapped_device *alloc_dev(unsigned int minor, int persistent) | |||
833 | { | 835 | { |
834 | int r; | 836 | int r; |
835 | struct mapped_device *md = kmalloc(sizeof(*md), GFP_KERNEL); | 837 | struct mapped_device *md = kmalloc(sizeof(*md), GFP_KERNEL); |
838 | void *old_md; | ||
836 | 839 | ||
837 | if (!md) { | 840 | if (!md) { |
838 | DMWARN("unable to allocate device, out of memory."); | 841 | DMWARN("unable to allocate device, out of memory."); |
@@ -888,6 +891,13 @@ static struct mapped_device *alloc_dev(unsigned int minor, int persistent) | |||
888 | init_waitqueue_head(&md->wait); | 891 | init_waitqueue_head(&md->wait); |
889 | init_waitqueue_head(&md->eventq); | 892 | init_waitqueue_head(&md->eventq); |
890 | 893 | ||
894 | /* Populate the mapping, nobody knows we exist yet */ | ||
895 | mutex_lock(&_minor_lock); | ||
896 | old_md = idr_replace(&_minor_idr, md, minor); | ||
897 | mutex_unlock(&_minor_lock); | ||
898 | |||
899 | BUG_ON(old_md != MINOR_ALLOCED); | ||
900 | |||
891 | return md; | 901 | return md; |
892 | 902 | ||
893 | bad4: | 903 | bad4: |
@@ -1018,7 +1028,7 @@ static struct mapped_device *dm_find_md(dev_t dev) | |||
1018 | mutex_lock(&_minor_lock); | 1028 | mutex_lock(&_minor_lock); |
1019 | 1029 | ||
1020 | md = idr_find(&_minor_idr, minor); | 1030 | md = idr_find(&_minor_idr, minor); |
1021 | if (!md || (dm_disk(md)->first_minor != minor)) | 1031 | if (md && (md == MINOR_ALLOCED || (dm_disk(md)->first_minor != minor))) |
1022 | md = NULL; | 1032 | md = NULL; |
1023 | 1033 | ||
1024 | mutex_unlock(&_minor_lock); | 1034 | mutex_unlock(&_minor_lock); |
@@ -1057,6 +1067,9 @@ void dm_put(struct mapped_device *md) | |||
1057 | 1067 | ||
1058 | if (atomic_dec_and_test(&md->holders)) { | 1068 | if (atomic_dec_and_test(&md->holders)) { |
1059 | map = dm_get_table(md); | 1069 | map = dm_get_table(md); |
1070 | mutex_lock(&_minor_lock); | ||
1071 | idr_replace(&_minor_idr, MINOR_ALLOCED, dm_disk(md)->first_minor); | ||
1072 | mutex_unlock(&_minor_lock); | ||
1060 | if (!dm_suspended(md)) { | 1073 | if (!dm_suspended(md)) { |
1061 | dm_table_presuspend_targets(map); | 1074 | dm_table_presuspend_targets(map); |
1062 | dm_table_postsuspend_targets(map); | 1075 | dm_table_postsuspend_targets(map); |