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); |