diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2016-03-16 02:00:21 -0800 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@gmail.com> | 2016-08-28 19:16:12 -0800 |
commit | e72438204b9127a36591b46fdb780a51fe5cb39d (patch) | |
tree | 18f829cf174e39982d709df38b856f0e960c1cfb | |
parent | 698f07c5f146ec48e8df0d96e6acf61b11b03f0a (diff) |
bcache: calculate capacity based off member info
-rw-r--r-- | fs/bcachefs/alloc.c | 76 | ||||
-rw-r--r-- | fs/bcachefs/bcache.h | 11 | ||||
-rw-r--r-- | fs/bcachefs/btree_gc.c | 2 | ||||
-rw-r--r-- | fs/bcachefs/buckets.c | 28 | ||||
-rw-r--r-- | fs/bcachefs/buckets.h | 2 | ||||
-rw-r--r-- | fs/bcachefs/fs.c | 5 | ||||
-rw-r--r-- | fs/bcachefs/request.c | 2 | ||||
-rw-r--r-- | fs/bcachefs/sysfs.c | 4 | ||||
-rw-r--r-- | fs/bcachefs/writeback.c | 6 | ||||
-rw-r--r-- | fs/bcachefs/writeback.h | 4 |
10 files changed, 71 insertions, 69 deletions
diff --git a/fs/bcachefs/alloc.c b/fs/bcachefs/alloc.c index b4975df07a99..1d1d302c84a1 100644 --- a/fs/bcachefs/alloc.c +++ b/fs/bcachefs/alloc.c @@ -519,10 +519,8 @@ static void bch_inc_clock_hand(struct io_timer *timer) mutex_unlock(&c->bucket_lock); - capacity = READ_ONCE(c->capacity); - - if (!capacity) - return; + capacity = READ_ONCE(c->exposed_capacity); + BUG_ON(!capacity); /* * we only increment when 0.1% of the cache_set has been read @@ -544,7 +542,7 @@ static void bch_prio_timer_init(struct cache_set *c, int rw) clock->rw = rw; timer->fn = bch_inc_clock_hand; - timer->expire = c->capacity >> 10; + timer->expire = c->exposed_capacity >> 10; } /* @@ -1500,11 +1498,13 @@ struct open_bucket *bch_alloc_sectors(struct cache_set *c, static void bch_recalc_capacity(struct cache_set *c) { - struct cache_group *tier = c->cache_tiers + ARRAY_SIZE(c->cache_tiers); + struct cache_member_rcu *mi; + struct cache_member_cpu *m; struct cache *ca; - u64 total_capacity, capacity = 0, reserved_sectors = 0; + u64 total_capacity = 0; unsigned long ra_pages = 0; - unsigned i, j; + unsigned i; + int tier; rcu_read_lock(); for_each_cache_rcu(ca, c, i) { @@ -1513,62 +1513,28 @@ static void bch_recalc_capacity(struct cache_set *c) ra_pages += bdi->ra_pages; } + rcu_read_unlock(); c->bdi.ra_pages = ra_pages; /* * Capacity of the cache set is the capacity of all the devices in the - * slowest (highest) tier - we don't include lower tier devices. + * slowest (highest) tier that has devices - we don't include lower tier + * devices: */ - for (tier = c->cache_tiers + ARRAY_SIZE(c->cache_tiers) - 1; - tier > c->cache_tiers && !tier->nr_devices; - --tier) - ; - - group_for_each_cache_rcu(ca, tier, i) { - size_t reserve = 0; - - /* - * We need to reserve buckets (from the number - * of currently available buckets) against - * foreground writes so that mainly copygc can - * make forward progress. - * - * We need enough to refill the various reserves - * from scratch - copygc will use its entire - * reserve all at once, then run against when - * its reserve is refilled (from the formerly - * available buckets). - * - * This reserve is just used when considering if - * allocations for foreground writes must wait - - * not -ENOSPC calculations. - */ - for (j = 0; j < RESERVE_NR; j++) - reserve += ca->free[j].size; - reserve += ca->free_inc.size; - - ca->reserve_buckets_count = reserve; - - reserved_sectors += reserve << ca->bucket_bits; - - capacity += (ca->mi.nbuckets - - ca->mi.first_bucket) << - ca->bucket_bits; - } - rcu_read_unlock(); - - total_capacity = capacity; - - capacity *= (100 - c->opts.gc_reserve_percent); - capacity = div64_u64(capacity, 100); - - BUG_ON(capacity + reserved_sectors > total_capacity); + mi = cache_member_info_get(c); + for (tier = CACHE_TIERS - 1; tier >= 0 && !total_capacity; --tier) + for (m = mi->m; m < mi->m + mi->nr_in_set; m++) + if (m->tier == tier && m->state == CACHE_ACTIVE) + total_capacity += (m->nbuckets - m->first_bucket) * + m->bucket_size; + cache_member_info_put(); - c->capacity = capacity; + c->exposed_capacity = div64_u64(total_capacity * + (100 - c->sector_reserve_percent), 100); - if (c->capacity) { + if (c->exposed_capacity) { bch_io_timer_add(&c->io_clock[READ], &c->prio_clock[READ].rescale); bch_io_timer_add(&c->io_clock[WRITE], diff --git a/fs/bcachefs/bcache.h b/fs/bcachefs/bcache.h index 83ee086b60fe..7f856f7fd1aa 100644 --- a/fs/bcachefs/bcache.h +++ b/fs/bcachefs/bcache.h @@ -636,7 +636,16 @@ struct cache_set { struct cache_group cache_all; struct cache_group cache_tiers[CACHE_TIERS]; - u64 capacity; /* sectors */ + /* + * If we want to be able to run rw without all devices currently + * present, we need to track capacity of currently available devices: + * but we don't want necessarily visible capacity to jump around as + * devices go temporarily offline and come back + * + * both sectors: + */ + u64 exposed_capacity; + u64 online_capacity; /* * When capacity _decreases_ (due to a disk being removed), we diff --git a/fs/bcachefs/btree_gc.c b/fs/bcachefs/btree_gc.c index 486c47372458..5e3cb929c8cf 100644 --- a/fs/bcachefs/btree_gc.c +++ b/fs/bcachefs/btree_gc.c @@ -765,7 +765,7 @@ static int bch_gc_thread(void *arg) set_freezable(); while (1) { - unsigned long next = last + c->capacity / 16; + unsigned long next = last + c->exposed_capacity / 16; while (atomic_long_read(&clock->now) < next) { set_current_state(TASK_INTERRUPTIBLE); diff --git a/fs/bcachefs/buckets.c b/fs/bcachefs/buckets.c index 35336afd0ab2..596d90034bbd 100644 --- a/fs/bcachefs/buckets.c +++ b/fs/bcachefs/buckets.c @@ -624,7 +624,7 @@ void bch_unmark_open_bucket(struct cache *ca, struct bucket *g) static u64 __recalc_sectors_available(struct cache_set *c) { - return c->capacity - cache_set_sectors_used(c); + return c->online_capacity - cache_set_sectors_used(c); } /* Used by gc when it's starting: */ @@ -737,3 +737,29 @@ int bch_disk_reservation_get(struct cache_set *c, return bch_disk_reservation_add(c, res, sectors, flags); } + +void bch_capacity_update(struct cache_set *c, u64 new_capacity) +{ + lg_global_lock(&c->bucket_stats_lock); + + if (new_capacity < c->online_capacity) { + struct bucket_stats_cache_set *stats; + int cpu; + + /* invalidate sectors_available */ + atomic64_set(&c->sectors_available, 0); + + for_each_possible_cpu(cpu) { + stats = per_cpu_ptr(c->bucket_stats_percpu, cpu); + stats->sectors_available_cache = 0; + } + + c->online_capacity = new_capacity; + smp_wmb(); + c->capacity_gen++; + } else { + c->online_capacity = new_capacity; + } + + lg_global_unlock(&c->bucket_stats_lock); +} diff --git a/fs/bcachefs/buckets.h b/fs/bcachefs/buckets.h index c96a398ca7bc..e878ac09a0f2 100644 --- a/fs/bcachefs/buckets.h +++ b/fs/bcachefs/buckets.h @@ -213,7 +213,7 @@ static inline u64 __cache_set_sectors_used(struct cache_set *c) static inline u64 cache_set_sectors_used(struct cache_set *c) { - return min(c->capacity, __cache_set_sectors_used(c)); + return min(c->exposed_capacity, __cache_set_sectors_used(c)); } /* XXX: kill? */ diff --git a/fs/bcachefs/fs.c b/fs/bcachefs/fs.c index 3432269afeeb..fbaad0c35c4d 100644 --- a/fs/bcachefs/fs.c +++ b/fs/bcachefs/fs.c @@ -1129,8 +1129,9 @@ static int bch_statfs(struct dentry *dentry, struct kstatfs *buf) buf->f_type = BCACHE_STATFS_MAGIC; buf->f_bsize = sb->s_blocksize; - buf->f_blocks = c->capacity >> PAGE_SECTOR_SHIFT; - buf->f_bfree = (c->capacity - cache_set_sectors_used(c)) >> PAGE_SECTOR_SHIFT; + buf->f_blocks = c->exposed_capacity >> PAGE_SECTOR_SHIFT; + buf->f_bfree = (c->exposed_capacity - + cache_set_sectors_used(c)) >> PAGE_SECTOR_SHIFT; buf->f_bavail = buf->f_bfree; buf->f_files = atomic_long_read(&c->nr_inodes); buf->f_ffree = U64_MAX; diff --git a/fs/bcachefs/request.c b/fs/bcachefs/request.c index 67c8d3f3d145..5baab9a92e18 100644 --- a/fs/bcachefs/request.c +++ b/fs/bcachefs/request.c @@ -99,7 +99,7 @@ static bool check_should_bypass(struct cached_dev *dc, struct bio *bio, int rw) struct io *i; if (test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags) || - sectors_available(c) * 100 < c->capacity * CUTOFF_CACHE_ADD || + sectors_available(c) * 100 < c->online_capacity * CUTOFF_CACHE_ADD || (bio->bi_rw & REQ_DISCARD)) goto skip; diff --git a/fs/bcachefs/sysfs.c b/fs/bcachefs/sysfs.c index 4df9c72486a7..a901b5d8368a 100644 --- a/fs/bcachefs/sysfs.c +++ b/fs/bcachefs/sysfs.c @@ -551,7 +551,7 @@ static size_t bch_cache_size(struct cache_set *c) static unsigned bch_cache_available_percent(struct cache_set *c) { return div64_u64((u64) sectors_available(c) * 100, - c->capacity ?: 1); + c->exposed_capacity ?: 1); } #if 0 @@ -585,7 +585,7 @@ static ssize_t show_cache_set_alloc_debug(struct cache_set *c, char *buf) "\tcached:\t\t%llu\n" "persistent reserved sectors:\t%llu\n" "online reserved sectors:\t%llu\n", - c->capacity, + c->exposed_capacity, stats.s[S_COMPRESSED][S_META], stats.s[S_COMPRESSED][S_DIRTY], stats.s[S_COMPRESSED][S_CACHED], diff --git a/fs/bcachefs/writeback.c b/fs/bcachefs/writeback.c index 846533cd527b..9d4095e5fe12 100644 --- a/fs/bcachefs/writeback.c +++ b/fs/bcachefs/writeback.c @@ -28,7 +28,7 @@ static void __update_writeback_rate(struct cached_dev *dc) { struct cache_set *c = dc->disk.c; u64 cache_dirty_target = - div_u64(c->capacity * dc->writeback_percent, 100); + div_u64(c->exposed_capacity * dc->writeback_percent, 100); s64 target = div64_u64(cache_dirty_target * bdev_sectors(dc->disk_sb.bdev), c->cached_dev_sectors); @@ -488,9 +488,9 @@ static int bch_writeback_thread(void *arg) sectors_written = bch_writeback(dc); - if (sectors_written < c->capacity >> 4) + if (sectors_written < c->exposed_capacity >> 4) bch_kthread_io_clock_wait(clock, - last + (c->capacity >> 5)); + last + (c->exposed_capacity >> 5)); } return 0; diff --git a/fs/bcachefs/writeback.h b/fs/bcachefs/writeback.h index a71a2bfe1b87..58f39d7bf291 100644 --- a/fs/bcachefs/writeback.h +++ b/fs/bcachefs/writeback.h @@ -50,7 +50,7 @@ static inline bool should_writeback(struct cached_dev *dc, struct bio *bio, if (cache_mode != CACHE_MODE_WRITEBACK || test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags) || - available * 100 < c->capacity * CUTOFF_WRITEBACK_SYNC) + available * 100 < c->online_capacity * CUTOFF_WRITEBACK_SYNC) return false; if (dc->partial_stripes_expensive && @@ -62,7 +62,7 @@ static inline bool should_writeback(struct cached_dev *dc, struct bio *bio, return false; return bio->bi_rw & REQ_SYNC || - available * 100 < c->capacity * CUTOFF_WRITEBACK; + available * 100 < c->online_capacity * CUTOFF_WRITEBACK; } static inline void bch_writeback_queue(struct cached_dev *dc) |