diff options
author | Tejun Heo <htejun@gmail.com> | 2005-10-20 04:56:41 -0400 |
---|---|---|
committer | Jens Axboe <axboe@nelson.home.kernel.dk> | 2005-10-28 02:15:58 -0400 |
commit | 2824bc9328467127083c1325f54b67d298c333b2 (patch) | |
tree | 0d19aeb555c35ddbdbcf195b976964523fecc404 /drivers/block/elevator.c | |
parent | b2982649ce38293b14684b26bcda20cfc54164e6 (diff) |
[PATCH] fix try_module_get race in elevator_find
This patch removes try_module_get race in elevator_find.
try_module_get should always be called with the spinlock protecting
what the module init/cleanup routines register/unregister to held. In
the case of elevators, we should be holding elv_list to avoid it going
away between spin_unlock_irq and try_module_get.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jens Axboe <axboe@suse.de>
Diffstat (limited to 'drivers/block/elevator.c')
-rw-r--r-- | drivers/block/elevator.c | 24 |
1 files changed, 14 insertions, 10 deletions
diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c index 98f0126a2deb..4144f30d82a9 100644 --- a/drivers/block/elevator.c +++ b/drivers/block/elevator.c | |||
@@ -97,7 +97,6 @@ static struct elevator_type *elevator_find(const char *name) | |||
97 | struct elevator_type *e = NULL; | 97 | struct elevator_type *e = NULL; |
98 | struct list_head *entry; | 98 | struct list_head *entry; |
99 | 99 | ||
100 | spin_lock_irq(&elv_list_lock); | ||
101 | list_for_each(entry, &elv_list) { | 100 | list_for_each(entry, &elv_list) { |
102 | struct elevator_type *__e; | 101 | struct elevator_type *__e; |
103 | 102 | ||
@@ -108,7 +107,6 @@ static struct elevator_type *elevator_find(const char *name) | |||
108 | break; | 107 | break; |
109 | } | 108 | } |
110 | } | 109 | } |
111 | spin_unlock_irq(&elv_list_lock); | ||
112 | 110 | ||
113 | return e; | 111 | return e; |
114 | } | 112 | } |
@@ -120,12 +118,15 @@ static void elevator_put(struct elevator_type *e) | |||
120 | 118 | ||
121 | static struct elevator_type *elevator_get(const char *name) | 119 | static struct elevator_type *elevator_get(const char *name) |
122 | { | 120 | { |
123 | struct elevator_type *e = elevator_find(name); | 121 | struct elevator_type *e; |
124 | 122 | ||
125 | if (!e) | 123 | spin_lock_irq(&elv_list_lock); |
126 | return NULL; | 124 | |
127 | if (!try_module_get(e->elevator_owner)) | 125 | e = elevator_find(name); |
128 | return NULL; | 126 | if (e && !try_module_get(e->elevator_owner)) |
127 | e = NULL; | ||
128 | |||
129 | spin_unlock_irq(&elv_list_lock); | ||
129 | 130 | ||
130 | return e; | 131 | return e; |
131 | } | 132 | } |
@@ -153,11 +154,15 @@ static char chosen_elevator[16]; | |||
153 | 154 | ||
154 | static void elevator_setup_default(void) | 155 | static void elevator_setup_default(void) |
155 | { | 156 | { |
157 | struct elevator_type *e; | ||
158 | |||
156 | /* | 159 | /* |
157 | * check if default is set and exists | 160 | * check if default is set and exists |
158 | */ | 161 | */ |
159 | if (chosen_elevator[0] && elevator_find(chosen_elevator)) | 162 | if (chosen_elevator[0] && (e = elevator_get(chosen_elevator))) { |
163 | elevator_put(e); | ||
160 | return; | 164 | return; |
165 | } | ||
161 | 166 | ||
162 | #if defined(CONFIG_IOSCHED_AS) | 167 | #if defined(CONFIG_IOSCHED_AS) |
163 | strcpy(chosen_elevator, "anticipatory"); | 168 | strcpy(chosen_elevator, "anticipatory"); |
@@ -555,10 +560,9 @@ void elv_unregister_queue(struct request_queue *q) | |||
555 | 560 | ||
556 | int elv_register(struct elevator_type *e) | 561 | int elv_register(struct elevator_type *e) |
557 | { | 562 | { |
563 | spin_lock_irq(&elv_list_lock); | ||
558 | if (elevator_find(e->elevator_name)) | 564 | if (elevator_find(e->elevator_name)) |
559 | BUG(); | 565 | BUG(); |
560 | |||
561 | spin_lock_irq(&elv_list_lock); | ||
562 | list_add_tail(&e->list, &elv_list); | 566 | list_add_tail(&e->list, &elv_list); |
563 | spin_unlock_irq(&elv_list_lock); | 567 | spin_unlock_irq(&elv_list_lock); |
564 | 568 | ||