aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/bcache/writeback.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/md/bcache/writeback.c')
-rw-r--r--drivers/md/bcache/writeback.c94
1 files changed, 56 insertions, 38 deletions
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}