diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2006-03-18 15:05:53 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2006-03-18 18:34:15 -0500 |
commit | 334e94de9bea353156abd6f2242d3cc4a24562b0 (patch) | |
tree | ff4a253e9e3bf487be03bf58727a7ea40a34ba87 | |
parent | e17a9489b4a686bb5e9615e1d375c67619cb99c5 (diff) |
[PATCH] deal with rmmod/put_io_context() races
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | block/as-iosched.c | 15 | ||||
-rw-r--r-- | block/cfq-iosched.c | 16 | ||||
-rw-r--r-- | block/ll_rw_blk.c | 2 |
3 files changed, 32 insertions, 1 deletions
diff --git a/block/as-iosched.c b/block/as-iosched.c index d2ee2af44b58..55a997fc4bb4 100644 --- a/block/as-iosched.c +++ b/block/as-iosched.c | |||
@@ -182,6 +182,9 @@ struct as_rq { | |||
182 | 182 | ||
183 | static kmem_cache_t *arq_pool; | 183 | static kmem_cache_t *arq_pool; |
184 | 184 | ||
185 | static atomic_t ioc_count = ATOMIC_INIT(0); | ||
186 | static struct completion *ioc_gone; | ||
187 | |||
185 | static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq); | 188 | static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq); |
186 | static void as_antic_stop(struct as_data *ad); | 189 | static void as_antic_stop(struct as_data *ad); |
187 | 190 | ||
@@ -193,11 +196,14 @@ static void as_antic_stop(struct as_data *ad); | |||
193 | static void free_as_io_context(struct as_io_context *aic) | 196 | static void free_as_io_context(struct as_io_context *aic) |
194 | { | 197 | { |
195 | kfree(aic); | 198 | kfree(aic); |
199 | if (atomic_dec_and_test(&ioc_count) && ioc_gone) | ||
200 | complete(ioc_gone); | ||
196 | } | 201 | } |
197 | 202 | ||
198 | static void as_trim(struct io_context *ioc) | 203 | static void as_trim(struct io_context *ioc) |
199 | { | 204 | { |
200 | kfree(ioc->aic); | 205 | if (ioc->aic) |
206 | free_as_io_context(ioc->aic); | ||
201 | ioc->aic = NULL; | 207 | ioc->aic = NULL; |
202 | } | 208 | } |
203 | 209 | ||
@@ -226,6 +232,7 @@ static struct as_io_context *alloc_as_io_context(void) | |||
226 | ret->seek_total = 0; | 232 | ret->seek_total = 0; |
227 | ret->seek_samples = 0; | 233 | ret->seek_samples = 0; |
228 | ret->seek_mean = 0; | 234 | ret->seek_mean = 0; |
235 | atomic_inc(&ioc_count); | ||
229 | } | 236 | } |
230 | 237 | ||
231 | return ret; | 238 | return ret; |
@@ -1900,7 +1907,13 @@ static int __init as_init(void) | |||
1900 | 1907 | ||
1901 | static void __exit as_exit(void) | 1908 | static void __exit as_exit(void) |
1902 | { | 1909 | { |
1910 | DECLARE_COMPLETION(all_gone); | ||
1903 | elv_unregister(&iosched_as); | 1911 | elv_unregister(&iosched_as); |
1912 | ioc_gone = &all_gone; | ||
1913 | barrier(); | ||
1914 | if (atomic_read(&ioc_count)) | ||
1915 | complete(ioc_gone); | ||
1916 | synchronize_rcu(); | ||
1904 | kmem_cache_destroy(arq_pool); | 1917 | kmem_cache_destroy(arq_pool); |
1905 | } | 1918 | } |
1906 | 1919 | ||
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 7102bafc98b3..3cd985bece3a 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c | |||
@@ -91,6 +91,9 @@ static kmem_cache_t *crq_pool; | |||
91 | static kmem_cache_t *cfq_pool; | 91 | static kmem_cache_t *cfq_pool; |
92 | static kmem_cache_t *cfq_ioc_pool; | 92 | static kmem_cache_t *cfq_ioc_pool; |
93 | 93 | ||
94 | static atomic_t ioc_count = ATOMIC_INIT(0); | ||
95 | static struct completion *ioc_gone; | ||
96 | |||
94 | #define CFQ_PRIO_LISTS IOPRIO_BE_NR | 97 | #define CFQ_PRIO_LISTS IOPRIO_BE_NR |
95 | #define cfq_class_idle(cfqq) ((cfqq)->ioprio_class == IOPRIO_CLASS_IDLE) | 98 | #define cfq_class_idle(cfqq) ((cfqq)->ioprio_class == IOPRIO_CLASS_IDLE) |
96 | #define cfq_class_be(cfqq) ((cfqq)->ioprio_class == IOPRIO_CLASS_BE) | 99 | #define cfq_class_be(cfqq) ((cfqq)->ioprio_class == IOPRIO_CLASS_BE) |
@@ -1202,13 +1205,17 @@ static void cfq_free_io_context(struct cfq_io_context *cic) | |||
1202 | { | 1205 | { |
1203 | struct cfq_io_context *__cic; | 1206 | struct cfq_io_context *__cic; |
1204 | struct list_head *entry, *next; | 1207 | struct list_head *entry, *next; |
1208 | int freed = 1; | ||
1205 | 1209 | ||
1206 | list_for_each_safe(entry, next, &cic->list) { | 1210 | list_for_each_safe(entry, next, &cic->list) { |
1207 | __cic = list_entry(entry, struct cfq_io_context, list); | 1211 | __cic = list_entry(entry, struct cfq_io_context, list); |
1208 | kmem_cache_free(cfq_ioc_pool, __cic); | 1212 | kmem_cache_free(cfq_ioc_pool, __cic); |
1213 | freed++; | ||
1209 | } | 1214 | } |
1210 | 1215 | ||
1211 | kmem_cache_free(cfq_ioc_pool, cic); | 1216 | kmem_cache_free(cfq_ioc_pool, cic); |
1217 | if (atomic_sub_and_test(freed, &ioc_count) && ioc_gone) | ||
1218 | complete(ioc_gone); | ||
1212 | } | 1219 | } |
1213 | 1220 | ||
1214 | static void cfq_trim(struct io_context *ioc) | 1221 | static void cfq_trim(struct io_context *ioc) |
@@ -1297,6 +1304,7 @@ cfq_alloc_io_context(struct cfq_data *cfqd, gfp_t gfp_mask) | |||
1297 | cic->dtor = cfq_free_io_context; | 1304 | cic->dtor = cfq_free_io_context; |
1298 | cic->exit = cfq_exit_io_context; | 1305 | cic->exit = cfq_exit_io_context; |
1299 | INIT_LIST_HEAD(&cic->queue_list); | 1306 | INIT_LIST_HEAD(&cic->queue_list); |
1307 | atomic_inc(&ioc_count); | ||
1300 | } | 1308 | } |
1301 | 1309 | ||
1302 | return cic; | 1310 | return cic; |
@@ -1501,6 +1509,7 @@ restart: | |||
1501 | list); | 1509 | list); |
1502 | read_unlock(&cfq_exit_lock); | 1510 | read_unlock(&cfq_exit_lock); |
1503 | kmem_cache_free(cfq_ioc_pool, cic); | 1511 | kmem_cache_free(cfq_ioc_pool, cic); |
1512 | atomic_dec(&ioc_count); | ||
1504 | goto restart; | 1513 | goto restart; |
1505 | } | 1514 | } |
1506 | 1515 | ||
@@ -1523,6 +1532,7 @@ restart: | |||
1523 | list_del(&__cic->list); | 1532 | list_del(&__cic->list); |
1524 | read_unlock(&cfq_exit_lock); | 1533 | read_unlock(&cfq_exit_lock); |
1525 | kmem_cache_free(cfq_ioc_pool, __cic); | 1534 | kmem_cache_free(cfq_ioc_pool, __cic); |
1535 | atomic_dec(&ioc_count); | ||
1526 | goto restart; | 1536 | goto restart; |
1527 | } | 1537 | } |
1528 | } | 1538 | } |
@@ -2510,7 +2520,13 @@ static int __init cfq_init(void) | |||
2510 | 2520 | ||
2511 | static void __exit cfq_exit(void) | 2521 | static void __exit cfq_exit(void) |
2512 | { | 2522 | { |
2523 | DECLARE_COMPLETION(all_gone); | ||
2513 | elv_unregister(&iosched_cfq); | 2524 | elv_unregister(&iosched_cfq); |
2525 | ioc_gone = &all_gone; | ||
2526 | barrier(); | ||
2527 | if (atomic_read(&ioc_count)) | ||
2528 | complete(ioc_gone); | ||
2529 | synchronize_rcu(); | ||
2514 | cfq_slab_kill(); | 2530 | cfq_slab_kill(); |
2515 | } | 2531 | } |
2516 | 2532 | ||
diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index caa8fcf5474b..6dc769182052 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c | |||
@@ -3477,10 +3477,12 @@ void put_io_context(struct io_context *ioc) | |||
3477 | BUG_ON(atomic_read(&ioc->refcount) == 0); | 3477 | BUG_ON(atomic_read(&ioc->refcount) == 0); |
3478 | 3478 | ||
3479 | if (atomic_dec_and_test(&ioc->refcount)) { | 3479 | if (atomic_dec_and_test(&ioc->refcount)) { |
3480 | rcu_read_lock(); | ||
3480 | if (ioc->aic && ioc->aic->dtor) | 3481 | if (ioc->aic && ioc->aic->dtor) |
3481 | ioc->aic->dtor(ioc->aic); | 3482 | ioc->aic->dtor(ioc->aic); |
3482 | if (ioc->cic && ioc->cic->dtor) | 3483 | if (ioc->cic && ioc->cic->dtor) |
3483 | ioc->cic->dtor(ioc->cic); | 3484 | ioc->cic->dtor(ioc->cic); |
3485 | rcu_read_unlock(); | ||
3484 | 3486 | ||
3485 | kmem_cache_free(iocontext_cachep, ioc); | 3487 | kmem_cache_free(iocontext_cachep, ioc); |
3486 | } | 3488 | } |