aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md
diff options
context:
space:
mode:
authorKent Overstreet <koverstreet@google.com>2013-04-30 22:14:40 -0400
committerKent Overstreet <koverstreet@google.com>2013-04-30 22:14:40 -0400
commit86b26b824cf5d15d4408b33d6d716104f249e8bd (patch)
treed36395292ec70eac25ba86321a8a9361b78070a2 /drivers/md
parent8abb2a5dbadab91f9cae22270054e9ee3b3a1d2f (diff)
bcache: Allocator cleanup/fixes
The main fix is that bch_allocator_thread() wasn't waiting on garbage collection to finish (if invalidate_buckets had set ca->invalidate_needs_gc); we need that to make sure the allocator doesn't spin and potentially block gc from finishing. Signed-off-by: Kent Overstreet <koverstreet@google.com>
Diffstat (limited to 'drivers/md')
-rw-r--r--drivers/md/bcache/alloc.c72
-rw-r--r--drivers/md/bcache/btree.c3
2 files changed, 50 insertions, 25 deletions
diff --git a/drivers/md/bcache/alloc.c b/drivers/md/bcache/alloc.c
index 2879487d036a..048f2947e08b 100644
--- a/drivers/md/bcache/alloc.c
+++ b/drivers/md/bcache/alloc.c
@@ -243,31 +243,37 @@ static void invalidate_buckets_lru(struct cache *ca)
243 ca->heap.used = 0; 243 ca->heap.used = 0;
244 244
245 for_each_bucket(b, ca) { 245 for_each_bucket(b, ca) {
246 /*
247 * If we fill up the unused list, if we then return before
248 * adding anything to the free_inc list we'll skip writing
249 * prios/gens and just go back to allocating from the unused
250 * list:
251 */
252 if (fifo_full(&ca->unused))
253 return;
254
246 if (!can_invalidate_bucket(ca, b)) 255 if (!can_invalidate_bucket(ca, b))
247 continue; 256 continue;
248 257
249 if (!GC_SECTORS_USED(b)) { 258 if (!GC_SECTORS_USED(b) &&
250 if (!bch_bucket_add_unused(ca, b)) 259 bch_bucket_add_unused(ca, b))
251 return; 260 continue;
252 } else { 261
253 if (!heap_full(&ca->heap)) 262 if (!heap_full(&ca->heap))
254 heap_add(&ca->heap, b, bucket_max_cmp); 263 heap_add(&ca->heap, b, bucket_max_cmp);
255 else if (bucket_max_cmp(b, heap_peek(&ca->heap))) { 264 else if (bucket_max_cmp(b, heap_peek(&ca->heap))) {
256 ca->heap.data[0] = b; 265 ca->heap.data[0] = b;
257 heap_sift(&ca->heap, 0, bucket_max_cmp); 266 heap_sift(&ca->heap, 0, bucket_max_cmp);
258 }
259 } 267 }
260 } 268 }
261 269
262 if (ca->heap.used * 2 < ca->heap.size)
263 bch_queue_gc(ca->set);
264
265 for (i = ca->heap.used / 2 - 1; i >= 0; --i) 270 for (i = ca->heap.used / 2 - 1; i >= 0; --i)
266 heap_sift(&ca->heap, i, bucket_min_cmp); 271 heap_sift(&ca->heap, i, bucket_min_cmp);
267 272
268 while (!fifo_full(&ca->free_inc)) { 273 while (!fifo_full(&ca->free_inc)) {
269 if (!heap_pop(&ca->heap, b, bucket_min_cmp)) { 274 if (!heap_pop(&ca->heap, b, bucket_min_cmp)) {
270 /* We don't want to be calling invalidate_buckets() 275 /*
276 * We don't want to be calling invalidate_buckets()
271 * multiple times when it can't do anything 277 * multiple times when it can't do anything
272 */ 278 */
273 ca->invalidate_needs_gc = 1; 279 ca->invalidate_needs_gc = 1;
@@ -343,15 +349,22 @@ static void invalidate_buckets(struct cache *ca)
343 invalidate_buckets_random(ca); 349 invalidate_buckets_random(ca);
344 break; 350 break;
345 } 351 }
352
353 pr_debug("free %zu/%zu free_inc %zu/%zu unused %zu/%zu",
354 fifo_used(&ca->free), ca->free.size,
355 fifo_used(&ca->free_inc), ca->free_inc.size,
356 fifo_used(&ca->unused), ca->unused.size);
346} 357}
347 358
348#define allocator_wait(ca, cond) \ 359#define allocator_wait(ca, cond) \
349do { \ 360do { \
350 DEFINE_WAIT(__wait); \ 361 DEFINE_WAIT(__wait); \
351 \ 362 \
352 while (!(cond)) { \ 363 while (1) { \
353 prepare_to_wait(&ca->set->alloc_wait, \ 364 prepare_to_wait(&ca->set->alloc_wait, \
354 &__wait, TASK_INTERRUPTIBLE); \ 365 &__wait, TASK_INTERRUPTIBLE); \
366 if (cond) \
367 break; \
355 \ 368 \
356 mutex_unlock(&(ca)->set->bucket_lock); \ 369 mutex_unlock(&(ca)->set->bucket_lock); \
357 if (test_bit(CACHE_SET_STOPPING_2, &ca->set->flags)) { \ 370 if (test_bit(CACHE_SET_STOPPING_2, &ca->set->flags)) { \
@@ -360,7 +373,6 @@ do { \
360 } \ 373 } \
361 \ 374 \
362 schedule(); \ 375 schedule(); \
363 __set_current_state(TASK_RUNNING); \
364 mutex_lock(&(ca)->set->bucket_lock); \ 376 mutex_lock(&(ca)->set->bucket_lock); \
365 } \ 377 } \
366 \ 378 \
@@ -374,6 +386,11 @@ void bch_allocator_thread(struct closure *cl)
374 mutex_lock(&ca->set->bucket_lock); 386 mutex_lock(&ca->set->bucket_lock);
375 387
376 while (1) { 388 while (1) {
389 /*
390 * First, we pull buckets off of the unused and free_inc lists,
391 * possibly issue discards to them, then we add the bucket to
392 * the free list:
393 */
377 while (1) { 394 while (1) {
378 long bucket; 395 long bucket;
379 396
@@ -398,17 +415,26 @@ void bch_allocator_thread(struct closure *cl)
398 } 415 }
399 } 416 }
400 417
401 allocator_wait(ca, ca->set->gc_mark_valid); 418 /*
402 invalidate_buckets(ca); 419 * We've run out of free buckets, we need to find some buckets
420 * we can invalidate. First, invalidate them in memory and add
421 * them to the free_inc list:
422 */
403 423
404 allocator_wait(ca, !atomic_read(&ca->set->prio_blocked) || 424 allocator_wait(ca, ca->set->gc_mark_valid &&
405 !CACHE_SYNC(&ca->set->sb)); 425 (ca->need_save_prio > 64 ||
426 !ca->invalidate_needs_gc));
427 invalidate_buckets(ca);
406 428
429 /*
430 * Now, we write their new gens to disk so we can start writing
431 * new stuff to them:
432 */
433 allocator_wait(ca, !atomic_read(&ca->set->prio_blocked));
407 if (CACHE_SYNC(&ca->set->sb) && 434 if (CACHE_SYNC(&ca->set->sb) &&
408 (!fifo_empty(&ca->free_inc) || 435 (!fifo_empty(&ca->free_inc) ||
409 ca->need_save_prio > 64)) { 436 ca->need_save_prio > 64))
410 bch_prio_write(ca); 437 bch_prio_write(ca);
411 }
412 } 438 }
413} 439}
414 440
@@ -475,7 +501,7 @@ void bch_bucket_free(struct cache_set *c, struct bkey *k)
475 for (i = 0; i < KEY_PTRS(k); i++) { 501 for (i = 0; i < KEY_PTRS(k); i++) {
476 struct bucket *b = PTR_BUCKET(c, k, i); 502 struct bucket *b = PTR_BUCKET(c, k, i);
477 503
478 SET_GC_MARK(b, 0); 504 SET_GC_MARK(b, GC_MARK_RECLAIMABLE);
479 SET_GC_SECTORS_USED(b, 0); 505 SET_GC_SECTORS_USED(b, 0);
480 bch_bucket_add_unused(PTR_CACHE(c, k, i), b); 506 bch_bucket_add_unused(PTR_CACHE(c, k, i), b);
481 } 507 }
diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c
index 852340793777..7a5658f04e62 100644
--- a/drivers/md/bcache/btree.c
+++ b/drivers/md/bcache/btree.c
@@ -984,7 +984,7 @@ static void btree_node_free(struct btree *b, struct btree_op *op)
984 984
985 if (b->prio_blocked && 985 if (b->prio_blocked &&
986 !atomic_sub_return(b->prio_blocked, &b->c->prio_blocked)) 986 !atomic_sub_return(b->prio_blocked, &b->c->prio_blocked))
987 closure_wake_up(&b->c->bucket_wait); 987 wake_up(&b->c->alloc_wait);
988 988
989 b->prio_blocked = 0; 989 b->prio_blocked = 0;
990 990
@@ -1548,7 +1548,6 @@ static void bch_btree_gc(struct closure *cl)
1548 1548
1549 trace_bcache_gc_end(c->sb.set_uuid); 1549 trace_bcache_gc_end(c->sb.set_uuid);
1550 wake_up(&c->alloc_wait); 1550 wake_up(&c->alloc_wait);
1551 closure_wake_up(&c->bucket_wait);
1552 1551
1553 continue_at(cl, bch_moving_gc, bch_gc_wq); 1552 continue_at(cl, bch_moving_gc, bch_gc_wq);
1554} 1553}