aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/md/bcache/bcache.h5
-rw-r--r--drivers/md/bcache/btree.c19
-rw-r--r--drivers/md/bcache/super.c17
-rw-r--r--drivers/md/bcache/writeback.c94
-rw-r--r--drivers/md/bcache/writeback.h21
-rw-r--r--include/trace/events/bcache.h29
6 files changed, 128 insertions, 57 deletions
diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h
index 816d07958fac..ab0b2150fed6 100644
--- a/drivers/md/bcache/bcache.h
+++ b/drivers/md/bcache/bcache.h
@@ -237,7 +237,7 @@ struct keybuf {
237 237
238 struct rb_root keys; 238 struct rb_root keys;
239 239
240#define KEYBUF_NR 100 240#define KEYBUF_NR 500
241 DECLARE_ARRAY_ALLOCATOR(struct keybuf_key, freelist, KEYBUF_NR); 241 DECLARE_ARRAY_ALLOCATOR(struct keybuf_key, freelist, KEYBUF_NR);
242}; 242};
243 243
@@ -273,9 +273,10 @@ struct bcache_device {
273 atomic_t detaching; 273 atomic_t detaching;
274 int flush_done; 274 int flush_done;
275 275
276 uint64_t nr_stripes; 276 unsigned nr_stripes;
277 unsigned stripe_size; 277 unsigned stripe_size;
278 atomic_t *stripe_sectors_dirty; 278 atomic_t *stripe_sectors_dirty;
279 unsigned long *full_dirty_stripes;
279 280
280 unsigned long sectors_dirty_last; 281 unsigned long sectors_dirty_last;
281 long sectors_dirty_derivative; 282 long sectors_dirty_derivative;
diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c
index 6def7c9a1228..5e2765aadce1 100644
--- a/drivers/md/bcache/btree.c
+++ b/drivers/md/bcache/btree.c
@@ -2378,6 +2378,7 @@ static inline int keybuf_nonoverlapping_cmp(struct keybuf_key *l,
2378 2378
2379struct refill { 2379struct refill {
2380 struct btree_op op; 2380 struct btree_op op;
2381 unsigned nr_found;
2381 struct keybuf *buf; 2382 struct keybuf *buf;
2382 struct bkey *end; 2383 struct bkey *end;
2383 keybuf_pred_fn *pred; 2384 keybuf_pred_fn *pred;
@@ -2414,6 +2415,8 @@ static int refill_keybuf_fn(struct btree_op *op, struct btree *b,
2414 2415
2415 if (RB_INSERT(&buf->keys, w, node, keybuf_cmp)) 2416 if (RB_INSERT(&buf->keys, w, node, keybuf_cmp))
2416 array_free(&buf->freelist, w); 2417 array_free(&buf->freelist, w);
2418 else
2419 refill->nr_found++;
2417 2420
2418 if (array_freelist_empty(&buf->freelist)) 2421 if (array_freelist_empty(&buf->freelist))
2419 ret = MAP_DONE; 2422 ret = MAP_DONE;
@@ -2434,18 +2437,18 @@ void bch_refill_keybuf(struct cache_set *c, struct keybuf *buf,
2434 cond_resched(); 2437 cond_resched();
2435 2438
2436 bch_btree_op_init(&refill.op, -1); 2439 bch_btree_op_init(&refill.op, -1);
2437 refill.buf = buf; 2440 refill.nr_found = 0;
2438 refill.end = end; 2441 refill.buf = buf;
2439 refill.pred = pred; 2442 refill.end = end;
2443 refill.pred = pred;
2440 2444
2441 bch_btree_map_keys(&refill.op, c, &buf->last_scanned, 2445 bch_btree_map_keys(&refill.op, c, &buf->last_scanned,
2442 refill_keybuf_fn, MAP_END_KEY); 2446 refill_keybuf_fn, MAP_END_KEY);
2443 2447
2444 pr_debug("found %s keys from %llu:%llu to %llu:%llu", 2448 trace_bcache_keyscan(refill.nr_found,
2445 RB_EMPTY_ROOT(&buf->keys) ? "no" : 2449 KEY_INODE(&start), KEY_OFFSET(&start),
2446 array_freelist_empty(&buf->freelist) ? "some" : "a few", 2450 KEY_INODE(&buf->last_scanned),
2447 KEY_INODE(&start), KEY_OFFSET(&start), 2451 KEY_OFFSET(&buf->last_scanned));
2448 KEY_INODE(&buf->last_scanned), KEY_OFFSET(&buf->last_scanned));
2449 2452
2450 spin_lock(&buf->lock); 2453 spin_lock(&buf->lock);
2451 2454
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index 4813ef67cef5..43fcfe38be11 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -738,6 +738,10 @@ static void bcache_device_free(struct bcache_device *d)
738 mempool_destroy(d->unaligned_bvec); 738 mempool_destroy(d->unaligned_bvec);
739 if (d->bio_split) 739 if (d->bio_split)
740 bioset_free(d->bio_split); 740 bioset_free(d->bio_split);
741 if (is_vmalloc_addr(d->full_dirty_stripes))
742 vfree(d->full_dirty_stripes);
743 else
744 kfree(d->full_dirty_stripes);
741 if (is_vmalloc_addr(d->stripe_sectors_dirty)) 745 if (is_vmalloc_addr(d->stripe_sectors_dirty))
742 vfree(d->stripe_sectors_dirty); 746 vfree(d->stripe_sectors_dirty);
743 else 747 else
@@ -757,8 +761,12 @@ static int bcache_device_init(struct bcache_device *d, unsigned block_size,
757 761
758 d->nr_stripes = DIV_ROUND_UP_ULL(sectors, d->stripe_size); 762 d->nr_stripes = DIV_ROUND_UP_ULL(sectors, d->stripe_size);
759 763
760 if (!d->nr_stripes || d->nr_stripes > SIZE_MAX / sizeof(atomic_t)) 764 if (!d->nr_stripes ||
765 d->nr_stripes > INT_MAX ||
766 d->nr_stripes > SIZE_MAX / sizeof(atomic_t)) {
767 pr_err("nr_stripes too large");
761 return -ENOMEM; 768 return -ENOMEM;
769 }
762 770
763 n = d->nr_stripes * sizeof(atomic_t); 771 n = d->nr_stripes * sizeof(atomic_t);
764 d->stripe_sectors_dirty = n < PAGE_SIZE << 6 772 d->stripe_sectors_dirty = n < PAGE_SIZE << 6
@@ -767,6 +775,13 @@ static int bcache_device_init(struct bcache_device *d, unsigned block_size,
767 if (!d->stripe_sectors_dirty) 775 if (!d->stripe_sectors_dirty)
768 return -ENOMEM; 776 return -ENOMEM;
769 777
778 n = BITS_TO_LONGS(d->nr_stripes) * sizeof(unsigned long);
779 d->full_dirty_stripes = n < PAGE_SIZE << 6
780 ? kzalloc(n, GFP_KERNEL)
781 : vzalloc(n);
782 if (!d->full_dirty_stripes)
783 return -ENOMEM;
784
770 if (!(d->bio_split = bioset_create(4, offsetof(struct bbio, bio))) || 785 if (!(d->bio_split = bioset_create(4, offsetof(struct bbio, bio))) ||
771 !(d->unaligned_bvec = mempool_create_kmalloc_pool(1, 786 !(d->unaligned_bvec = mempool_create_kmalloc_pool(1,
772 sizeof(struct bio_vec) * BIO_MAX_PAGES)) || 787 sizeof(struct bio_vec) * BIO_MAX_PAGES)) ||
diff --git a/drivers/md/bcache/writeback.c b/drivers/md/bcache/writeback.c
index ab0f6b449111..22e21dc9a037 100644
--- a/drivers/md/bcache/writeback.c
+++ b/drivers/md/bcache/writeback.c
@@ -292,14 +292,12 @@ void bcache_dev_sectors_dirty_add(struct cache_set *c, unsigned inode,
292 uint64_t offset, int nr_sectors) 292 uint64_t offset, int nr_sectors)
293{ 293{
294 struct bcache_device *d = c->devices[inode]; 294 struct bcache_device *d = c->devices[inode];
295 unsigned stripe_offset; 295 unsigned stripe_offset, stripe, sectors_dirty;
296 uint64_t stripe = offset;
297 296
298 if (!d) 297 if (!d)
299 return; 298 return;
300 299
301 do_div(stripe, d->stripe_size); 300 stripe = offset_to_stripe(d, offset);
302
303 stripe_offset = offset & (d->stripe_size - 1); 301 stripe_offset = offset & (d->stripe_size - 1);
304 302
305 while (nr_sectors) { 303 while (nr_sectors) {
@@ -309,7 +307,16 @@ void bcache_dev_sectors_dirty_add(struct cache_set *c, unsigned inode,
309 if (nr_sectors < 0) 307 if (nr_sectors < 0)
310 s = -s; 308 s = -s;
311 309
312 atomic_add(s, d->stripe_sectors_dirty + stripe); 310 if (stripe >= d->nr_stripes)
311 return;
312
313 sectors_dirty = atomic_add_return(s,
314 d->stripe_sectors_dirty + stripe);
315 if (sectors_dirty == d->stripe_size)
316 set_bit(stripe, d->full_dirty_stripes);
317 else
318 clear_bit(stripe, d->full_dirty_stripes);
319
313 nr_sectors -= s; 320 nr_sectors -= s;
314 stripe_offset = 0; 321 stripe_offset = 0;
315 stripe++; 322 stripe++;
@@ -321,59 +328,70 @@ static bool dirty_pred(struct keybuf *buf, struct bkey *k)
321 return KEY_DIRTY(k); 328 return KEY_DIRTY(k);
322} 329}
323 330
324static bool dirty_full_stripe_pred(struct keybuf *buf, struct bkey *k) 331static void refill_full_stripes(struct cached_dev *dc)
325{ 332{
326 uint64_t stripe = KEY_START(k); 333 struct keybuf *buf = &dc->writeback_keys;
327 unsigned nr_sectors = KEY_SIZE(k); 334 unsigned start_stripe, stripe, next_stripe;
328 struct cached_dev *dc = container_of(buf, struct cached_dev, 335 bool wrapped = false;
329 writeback_keys); 336
337 stripe = offset_to_stripe(&dc->disk, KEY_OFFSET(&buf->last_scanned));
330 338
331 if (!KEY_DIRTY(k)) 339 if (stripe >= dc->disk.nr_stripes)
332 return false; 340 stripe = 0;
333 341
334 do_div(stripe, dc->disk.stripe_size); 342 start_stripe = stripe;
335 343
336 while (1) { 344 while (1) {
337 if (atomic_read(dc->disk.stripe_sectors_dirty + stripe) == 345 stripe = find_next_bit(dc->disk.full_dirty_stripes,
338 dc->disk.stripe_size) 346 dc->disk.nr_stripes, stripe);
339 return true;
340 347
341 if (nr_sectors <= dc->disk.stripe_size) 348 if (stripe == dc->disk.nr_stripes)
342 return false; 349 goto next;
343 350
344 nr_sectors -= dc->disk.stripe_size; 351 next_stripe = find_next_zero_bit(dc->disk.full_dirty_stripes,
345 stripe++; 352 dc->disk.nr_stripes, stripe);
353
354 buf->last_scanned = KEY(dc->disk.id,
355 stripe * dc->disk.stripe_size, 0);
356
357 bch_refill_keybuf(dc->disk.c, buf,
358 &KEY(dc->disk.id,
359 next_stripe * dc->disk.stripe_size, 0),
360 dirty_pred);
361
362 if (array_freelist_empty(&buf->freelist))
363 return;
364
365 stripe = next_stripe;
366next:
367 if (wrapped && stripe > start_stripe)
368 return;
369
370 if (stripe == dc->disk.nr_stripes) {
371 stripe = 0;
372 wrapped = true;
373 }
346 } 374 }
347} 375}
348 376
349static bool refill_dirty(struct cached_dev *dc) 377static bool refill_dirty(struct cached_dev *dc)
350{ 378{
351 struct keybuf *buf = &dc->writeback_keys; 379 struct keybuf *buf = &dc->writeback_keys;
352 bool searched_from_start = false;
353 struct bkey end = KEY(dc->disk.id, MAX_KEY_OFFSET, 0); 380 struct bkey end = KEY(dc->disk.id, MAX_KEY_OFFSET, 0);
381 bool searched_from_start = false;
382
383 if (dc->partial_stripes_expensive) {
384 refill_full_stripes(dc);
385 if (array_freelist_empty(&buf->freelist))
386 return false;
387 }
354 388
355 if (bkey_cmp(&buf->last_scanned, &end) >= 0) { 389 if (bkey_cmp(&buf->last_scanned, &end) >= 0) {
356 buf->last_scanned = KEY(dc->disk.id, 0, 0); 390 buf->last_scanned = KEY(dc->disk.id, 0, 0);
357 searched_from_start = true; 391 searched_from_start = true;
358 } 392 }
359 393
360 if (dc->partial_stripes_expensive) { 394 bch_refill_keybuf(dc->disk.c, buf, &end, dirty_pred);
361 uint64_t i;
362
363 for (i = 0; i < dc->disk.nr_stripes; i++)
364 if (atomic_read(dc->disk.stripe_sectors_dirty + i) ==
365 dc->disk.stripe_size)
366 goto full_stripes;
367
368 goto normal_refill;
369full_stripes:
370 searched_from_start = false; /* not searching entire btree */
371 bch_refill_keybuf(dc->disk.c, buf, &end,
372 dirty_full_stripe_pred);
373 } else {
374normal_refill:
375 bch_refill_keybuf(dc->disk.c, buf, &end, dirty_pred);
376 }
377 395
378 return bkey_cmp(&buf->last_scanned, &end) >= 0 && searched_from_start; 396 return bkey_cmp(&buf->last_scanned, &end) >= 0 && searched_from_start;
379} 397}
diff --git a/drivers/md/bcache/writeback.h b/drivers/md/bcache/writeback.h
index 60516bfa6052..fe7d9d56492b 100644
--- a/drivers/md/bcache/writeback.h
+++ b/drivers/md/bcache/writeback.h
@@ -14,22 +14,27 @@ static inline uint64_t bcache_dev_sectors_dirty(struct bcache_device *d)
14 return ret; 14 return ret;
15} 15}
16 16
17static inline bool bcache_dev_stripe_dirty(struct bcache_device *d, 17static inline unsigned offset_to_stripe(struct bcache_device *d,
18 uint64_t offset)
19{
20 do_div(offset, d->stripe_size);
21 return offset;
22}
23
24static inline bool bcache_dev_stripe_dirty(struct cached_dev *dc,
18 uint64_t offset, 25 uint64_t offset,
19 unsigned nr_sectors) 26 unsigned nr_sectors)
20{ 27{
21 uint64_t stripe = offset; 28 unsigned stripe = offset_to_stripe(&dc->disk, offset);
22
23 do_div(stripe, d->stripe_size);
24 29
25 while (1) { 30 while (1) {
26 if (atomic_read(d->stripe_sectors_dirty + stripe)) 31 if (atomic_read(dc->disk.stripe_sectors_dirty + stripe))
27 return true; 32 return true;
28 33
29 if (nr_sectors <= d->stripe_size) 34 if (nr_sectors <= dc->disk.stripe_size)
30 return false; 35 return false;
31 36
32 nr_sectors -= d->stripe_size; 37 nr_sectors -= dc->disk.stripe_size;
33 stripe++; 38 stripe++;
34 } 39 }
35} 40}
@@ -45,7 +50,7 @@ static inline bool should_writeback(struct cached_dev *dc, struct bio *bio,
45 return false; 50 return false;
46 51
47 if (dc->partial_stripes_expensive && 52 if (dc->partial_stripes_expensive &&
48 bcache_dev_stripe_dirty(&dc->disk, bio->bi_sector, 53 bcache_dev_stripe_dirty(dc, bio->bi_sector,
49 bio_sectors(bio))) 54 bio_sectors(bio)))
50 return true; 55 return true;
51 56
diff --git a/include/trace/events/bcache.h b/include/trace/events/bcache.h
index 32c89b33c391..e2b9576d00e2 100644
--- a/include/trace/events/bcache.h
+++ b/include/trace/events/bcache.h
@@ -368,6 +368,35 @@ DEFINE_EVENT(btree_node, bcache_btree_set_root,
368 TP_ARGS(b) 368 TP_ARGS(b)
369); 369);
370 370
371TRACE_EVENT(bcache_keyscan,
372 TP_PROTO(unsigned nr_found,
373 unsigned start_inode, uint64_t start_offset,
374 unsigned end_inode, uint64_t end_offset),
375 TP_ARGS(nr_found,
376 start_inode, start_offset,
377 end_inode, end_offset),
378
379 TP_STRUCT__entry(
380 __field(__u32, nr_found )
381 __field(__u32, start_inode )
382 __field(__u64, start_offset )
383 __field(__u32, end_inode )
384 __field(__u64, end_offset )
385 ),
386
387 TP_fast_assign(
388 __entry->nr_found = nr_found;
389 __entry->start_inode = start_inode;
390 __entry->start_offset = start_offset;
391 __entry->end_inode = end_inode;
392 __entry->end_offset = end_offset;
393 ),
394
395 TP_printk("found %u keys from %u:%llu to %u:%llu", __entry->nr_found,
396 __entry->start_inode, __entry->start_offset,
397 __entry->end_inode, __entry->end_offset)
398);
399
371/* Allocator */ 400/* Allocator */
372 401
373TRACE_EVENT(bcache_alloc_invalidate, 402TRACE_EVENT(bcache_alloc_invalidate,