/* Rate limiting */ static uint64_t __calc_target_rate(struct cached_dev *dc) { struct cache_set *c = dc->disk.c; /* * This is the size of the cache, minus the amount used for * flash-only devices */ uint64_t cache_sectors = c->nbuckets * c->sb.bucket_size - atomic_long_read(&c->flash_dev_dirty_sectors); /* * Unfortunately there is no control of global dirty data. If the * user states that they want 10% dirty data in the cache, and has, * e.g., 5 backing volumes of equal size, we try and ensure each * backing volume uses about 2% of the cache for dirty data. */ uint32_t bdev_share = div64_u64(bdev_sectors(dc->bdev) << WRITEBACK_SHARE_SHIFT, c->cached_dev_sectors); uint64_t cache_dirty_target = div_u64(cache_sectors * dc->writeback_percent, 100); /* Ensure each backing dev gets at least one dirty share */ if (bdev_share < 1) bdev_share = 1; return (cache_dirty_target * bdev_share) >> WRITEBACK_SHARE_SHIFT; }
static void __update_writeback_rate(struct cached_dev *dc) { struct cache_set *c = dc->disk.c; uint64_t cache_sectors = c->nbuckets * c->sb.bucket_size; uint64_t cache_dirty_target = div_u64(cache_sectors * dc->writeback_percent, 100); int64_t target = div64_u64(cache_dirty_target * bdev_sectors(dc->bdev), c->cached_dev_sectors); /* PD controller */ int64_t dirty = bcache_dev_sectors_dirty(&dc->disk); int64_t derivative = dirty - dc->disk.sectors_dirty_last; int64_t proportional = dirty - target; int64_t change; dc->disk.sectors_dirty_last = dirty; /* Scale to sectors per second */ proportional *= dc->writeback_rate_update_seconds; proportional = div_s64(proportional, dc->writeback_rate_p_term_inverse); derivative = div_s64(derivative, dc->writeback_rate_update_seconds); derivative = ewma_add(dc->disk.sectors_dirty_derivative, derivative, (dc->writeback_rate_d_term / dc->writeback_rate_update_seconds) ?: 1, 0); derivative *= dc->writeback_rate_d_term; derivative = div_s64(derivative, dc->writeback_rate_p_term_inverse); change = proportional + derivative; /* Don't increase writeback rate if the device isn't keeping up */ if (change > 0 && time_after64(local_clock(), dc->writeback_rate.next + NSEC_PER_MSEC)) change = 0; dc->writeback_rate.rate = clamp_t(int64_t, (int64_t) dc->writeback_rate.rate + change, 1, NSEC_PER_MSEC); dc->writeback_rate_proportional = proportional; dc->writeback_rate_derivative = derivative; dc->writeback_rate_change = change; dc->writeback_rate_target = target; }