aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2006-03-18 15:05:53 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2006-03-18 18:34:15 -0500
commit334e94de9bea353156abd6f2242d3cc4a24562b0 (patch)
treeff4a253e9e3bf487be03bf58727a7ea40a34ba87
parente17a9489b4a686bb5e9615e1d375c67619cb99c5 (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.c15
-rw-r--r--block/cfq-iosched.c16
-rw-r--r--block/ll_rw_blk.c2
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
183static kmem_cache_t *arq_pool; 183static kmem_cache_t *arq_pool;
184 184
185static atomic_t ioc_count = ATOMIC_INIT(0);
186static struct completion *ioc_gone;
187
185static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq); 188static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq);
186static void as_antic_stop(struct as_data *ad); 189static void as_antic_stop(struct as_data *ad);
187 190
@@ -193,11 +196,14 @@ static void as_antic_stop(struct as_data *ad);
193static void free_as_io_context(struct as_io_context *aic) 196static 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
198static void as_trim(struct io_context *ioc) 203static 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
1901static void __exit as_exit(void) 1908static 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;
91static kmem_cache_t *cfq_pool; 91static kmem_cache_t *cfq_pool;
92static kmem_cache_t *cfq_ioc_pool; 92static kmem_cache_t *cfq_ioc_pool;
93 93
94static atomic_t ioc_count = ATOMIC_INIT(0);
95static 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
1214static void cfq_trim(struct io_context *ioc) 1221static 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
2511static void __exit cfq_exit(void) 2521static 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 }