diff options
Diffstat (limited to 'drivers/md/bcache/writeback.c')
-rw-r--r-- | drivers/md/bcache/writeback.c | 94 |
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 | ||
324 | static bool dirty_full_stripe_pred(struct keybuf *buf, struct bkey *k) | 331 | static 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; | ||
366 | next: | ||
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 | ||
349 | static bool refill_dirty(struct cached_dev *dc) | 377 | static 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; | ||
369 | full_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 { | ||
374 | normal_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 | } |