diff options
| author | Jeff Mahoney <jeffm@suse.com> | 2006-06-26 03:27:22 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-26 12:58:34 -0400 |
| commit | f32c10b09940cffc3620ce111315ec44343fd3ca (patch) | |
| tree | e5f1ee2febebd9c3b2426973a054ae16b5a80640 | |
| parent | 62f75c2f3244553b1290447abd1f1e6b1144d3e9 (diff) | |
[PATCH] dm: change minor_lock to spinlock
While removing a device, another another thread might attempt to resurrect it.
This patch replaces the _minor_lock mutex with a spinlock and uses
atomic_dec_and_lock() to serialize reference counting in dm_put().
[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 | 27 |
1 files changed, 13 insertions, 14 deletions
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 6e577e749329..6e65d85d0829 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
| @@ -26,6 +26,7 @@ static const char *_name = DM_NAME; | |||
| 26 | static unsigned int major = 0; | 26 | static unsigned int major = 0; |
| 27 | static unsigned int _major = 0; | 27 | static unsigned int _major = 0; |
| 28 | 28 | ||
| 29 | static DEFINE_SPINLOCK(_minor_lock); | ||
| 29 | /* | 30 | /* |
| 30 | * One of these is allocated per bio. | 31 | * One of these is allocated per bio. |
| 31 | */ | 32 | */ |
| @@ -746,14 +747,13 @@ static int dm_any_congested(void *congested_data, int bdi_bits) | |||
| 746 | /*----------------------------------------------------------------- | 747 | /*----------------------------------------------------------------- |
| 747 | * An IDR is used to keep track of allocated minor numbers. | 748 | * An IDR is used to keep track of allocated minor numbers. |
| 748 | *---------------------------------------------------------------*/ | 749 | *---------------------------------------------------------------*/ |
| 749 | static DEFINE_MUTEX(_minor_lock); | ||
| 750 | static DEFINE_IDR(_minor_idr); | 750 | static DEFINE_IDR(_minor_idr); |
| 751 | 751 | ||
| 752 | static void free_minor(unsigned int minor) | 752 | static void free_minor(unsigned int minor) |
| 753 | { | 753 | { |
| 754 | mutex_lock(&_minor_lock); | 754 | spin_lock(&_minor_lock); |
| 755 | idr_remove(&_minor_idr, minor); | 755 | idr_remove(&_minor_idr, minor); |
| 756 | mutex_unlock(&_minor_lock); | 756 | spin_unlock(&_minor_lock); |
| 757 | } | 757 | } |
| 758 | 758 | ||
| 759 | /* | 759 | /* |
| @@ -770,7 +770,7 @@ static int specific_minor(struct mapped_device *md, unsigned int minor) | |||
| 770 | if (!r) | 770 | if (!r) |
| 771 | return -ENOMEM; | 771 | return -ENOMEM; |
| 772 | 772 | ||
| 773 | mutex_lock(&_minor_lock); | 773 | spin_lock(&_minor_lock); |
| 774 | 774 | ||
| 775 | if (idr_find(&_minor_idr, minor)) { | 775 | if (idr_find(&_minor_idr, minor)) { |
| 776 | r = -EBUSY; | 776 | r = -EBUSY; |
| @@ -788,7 +788,7 @@ static int specific_minor(struct mapped_device *md, unsigned int minor) | |||
| 788 | } | 788 | } |
| 789 | 789 | ||
| 790 | out: | 790 | out: |
| 791 | mutex_unlock(&_minor_lock); | 791 | spin_unlock(&_minor_lock); |
| 792 | return r; | 792 | return r; |
| 793 | } | 793 | } |
| 794 | 794 | ||
| @@ -801,7 +801,7 @@ static int next_free_minor(struct mapped_device *md, unsigned int *minor) | |||
| 801 | if (!r) | 801 | if (!r) |
| 802 | return -ENOMEM; | 802 | return -ENOMEM; |
| 803 | 803 | ||
| 804 | mutex_lock(&_minor_lock); | 804 | spin_lock(&_minor_lock); |
| 805 | 805 | ||
| 806 | r = idr_get_new(&_minor_idr, MINOR_ALLOCED, &m); | 806 | r = idr_get_new(&_minor_idr, MINOR_ALLOCED, &m); |
| 807 | if (r) { | 807 | if (r) { |
| @@ -817,7 +817,7 @@ static int next_free_minor(struct mapped_device *md, unsigned int *minor) | |||
| 817 | *minor = m; | 817 | *minor = m; |
| 818 | 818 | ||
| 819 | out: | 819 | out: |
| 820 | mutex_unlock(&_minor_lock); | 820 | spin_unlock(&_minor_lock); |
| 821 | return r; | 821 | return r; |
| 822 | } | 822 | } |
| 823 | 823 | ||
| @@ -887,9 +887,9 @@ static struct mapped_device *alloc_dev(unsigned int minor, int persistent) | |||
| 887 | init_waitqueue_head(&md->eventq); | 887 | init_waitqueue_head(&md->eventq); |
| 888 | 888 | ||
| 889 | /* Populate the mapping, nobody knows we exist yet */ | 889 | /* Populate the mapping, nobody knows we exist yet */ |
| 890 | mutex_lock(&_minor_lock); | 890 | spin_lock(&_minor_lock); |
| 891 | old_md = idr_replace(&_minor_idr, md, minor); | 891 | old_md = idr_replace(&_minor_idr, md, minor); |
| 892 | mutex_unlock(&_minor_lock); | 892 | spin_unlock(&_minor_lock); |
| 893 | 893 | ||
| 894 | BUG_ON(old_md != MINOR_ALLOCED); | 894 | BUG_ON(old_md != MINOR_ALLOCED); |
| 895 | 895 | ||
| @@ -1020,13 +1020,13 @@ static struct mapped_device *dm_find_md(dev_t dev) | |||
| 1020 | if (MAJOR(dev) != _major || minor >= (1 << MINORBITS)) | 1020 | if (MAJOR(dev) != _major || minor >= (1 << MINORBITS)) |
| 1021 | return NULL; | 1021 | return NULL; |
| 1022 | 1022 | ||
| 1023 | mutex_lock(&_minor_lock); | 1023 | spin_lock(&_minor_lock); |
| 1024 | 1024 | ||
| 1025 | md = idr_find(&_minor_idr, minor); | 1025 | md = idr_find(&_minor_idr, minor); |
| 1026 | if (md && (md == MINOR_ALLOCED || (dm_disk(md)->first_minor != minor))) | 1026 | if (md && (md == MINOR_ALLOCED || (dm_disk(md)->first_minor != minor))) |
| 1027 | md = NULL; | 1027 | md = NULL; |
| 1028 | 1028 | ||
| 1029 | mutex_unlock(&_minor_lock); | 1029 | spin_unlock(&_minor_lock); |
| 1030 | 1030 | ||
| 1031 | return md; | 1031 | return md; |
| 1032 | } | 1032 | } |
| @@ -1060,11 +1060,10 @@ void dm_put(struct mapped_device *md) | |||
| 1060 | { | 1060 | { |
| 1061 | struct dm_table *map; | 1061 | struct dm_table *map; |
| 1062 | 1062 | ||
| 1063 | if (atomic_dec_and_test(&md->holders)) { | 1063 | if (atomic_dec_and_lock(&md->holders, &_minor_lock)) { |
| 1064 | map = dm_get_table(md); | 1064 | map = dm_get_table(md); |
| 1065 | mutex_lock(&_minor_lock); | ||
| 1066 | idr_replace(&_minor_idr, MINOR_ALLOCED, dm_disk(md)->first_minor); | 1065 | idr_replace(&_minor_idr, MINOR_ALLOCED, dm_disk(md)->first_minor); |
| 1067 | mutex_unlock(&_minor_lock); | 1066 | spin_unlock(&_minor_lock); |
| 1068 | if (!dm_suspended(md)) { | 1067 | if (!dm_suspended(md)) { |
| 1069 | dm_table_presuspend_targets(map); | 1068 | dm_table_presuspend_targets(map); |
| 1070 | dm_table_postsuspend_targets(map); | 1069 | dm_table_postsuspend_targets(map); |
