summaryrefslogtreecommitdiff
path: root/libbcachefs/buckets.c
diff options
context:
space:
mode:
Diffstat (limited to 'libbcachefs/buckets.c')
-rw-r--r--libbcachefs/buckets.c113
1 files changed, 64 insertions, 49 deletions
diff --git a/libbcachefs/buckets.c b/libbcachefs/buckets.c
index f0a63232..8899e3c6 100644
--- a/libbcachefs/buckets.c
+++ b/libbcachefs/buckets.c
@@ -82,7 +82,7 @@ static void bch2_fs_stats_verify(struct bch_fs *c)
__bch2_fs_usage_read(c);
unsigned i;
- for (i = 0; i < BCH_REPLICAS_MAX; i++) {
+ for (i = 0; i < ARRAY_SIZE(stats.s); i++) {
if ((s64) stats.s[i].data[S_META] < 0)
panic("replicas %u meta underflow: %lli\n",
i + 1, stats.s[i].data[S_META]);
@@ -106,10 +106,10 @@ static void bch2_dev_stats_verify(struct bch_dev *ca)
struct bch_dev_usage stats =
__bch2_dev_usage_read(ca);
u64 n = ca->mi.nbuckets - ca->mi.first_bucket;
+ unsigned i;
- BUG_ON(stats.buckets[S_META] > n);
- BUG_ON(stats.buckets[S_DIRTY] > n);
- BUG_ON(stats.buckets_cached > n);
+ for (i = 0; i < ARRAY_SIZE(stats.buckets); i++)
+ BUG_ON(stats.buckets[i] > n);
BUG_ON(stats.buckets_alloc > n);
BUG_ON(stats.buckets_unavailable > n);
}
@@ -224,20 +224,43 @@ bch2_fs_usage_read(struct bch_fs *c)
c->usage_percpu);
}
-static inline int is_meta_bucket(struct bucket_mark m)
+struct fs_usage_sum {
+ u64 data;
+ u64 reserved;
+};
+
+static inline struct fs_usage_sum __fs_usage_sum(struct bch_fs_usage stats)
{
- return m.data_type != BUCKET_DATA;
+ struct fs_usage_sum sum = { 0 };
+ unsigned i;
+
+ for (i = 0; i < ARRAY_SIZE(stats.s); i++) {
+ sum.data += (stats.s[i].data[S_META] +
+ stats.s[i].data[S_DIRTY]) * (i + 1);
+ sum.reserved += stats.s[i].persistent_reserved * (i + 1);
+ }
+
+ sum.reserved += stats.online_reserved;
+ return sum;
}
-static inline int is_dirty_bucket(struct bucket_mark m)
+#define RESERVE_FACTOR 6
+
+static u64 reserve_factor(u64 r)
{
- return m.data_type == BUCKET_DATA && !!m.dirty_sectors;
+ return r + (round_up(r, (1 << RESERVE_FACTOR)) >> RESERVE_FACTOR);
+}
+
+u64 __bch2_fs_sectors_used(struct bch_fs *c, struct bch_fs_usage stats)
+{
+ struct fs_usage_sum sum = __fs_usage_sum(stats);
+
+ return sum.data + reserve_factor(sum.reserved);
}
-static inline int is_cached_bucket(struct bucket_mark m)
+u64 bch2_fs_sectors_used(struct bch_fs *c, struct bch_fs_usage stats)
{
- return m.data_type == BUCKET_DATA &&
- !m.dirty_sectors && !!m.cached_sectors;
+ return min(c->capacity, __bch2_fs_sectors_used(c, stats));
}
static inline int is_unavailable_bucket(struct bucket_mark m)
@@ -245,9 +268,11 @@ static inline int is_unavailable_bucket(struct bucket_mark m)
return !is_available_bucket(m);
}
-static inline enum s_alloc bucket_type(struct bucket_mark m)
+static inline enum bch_data_type bucket_type(struct bucket_mark m)
{
- return is_meta_bucket(m) ? S_META : S_DIRTY;
+ return m.cached_sectors && !m.dirty_sectors
+ ? BCH_DATA_CACHED
+ : m.data_type;
}
static bool bucket_became_unavailable(struct bch_fs *c,
@@ -304,26 +329,23 @@ static void bch2_dev_usage_update(struct bch_fs *c, struct bch_dev *ca,
bch2_fs_inconsistent_on(old.data_type && new.data_type &&
old.data_type != new.data_type, c,
- "different types of metadata in same bucket: %u, %u",
+ "different types of data in same bucket: %u, %u",
old.data_type, new.data_type);
preempt_disable();
dev_usage = this_cpu_ptr(ca->usage_percpu);
- dev_usage->buckets[S_META] +=
- is_meta_bucket(new) - is_meta_bucket(old);
- dev_usage->buckets[S_DIRTY] +=
- is_dirty_bucket(new) - is_dirty_bucket(old);
- dev_usage->buckets_cached +=
- is_cached_bucket(new) - is_cached_bucket(old);
+ dev_usage->buckets[bucket_type(old)]--;
+ dev_usage->buckets[bucket_type(new)]++;
+
dev_usage->buckets_alloc +=
(int) new.owned_by_allocator - (int) old.owned_by_allocator;
dev_usage->buckets_unavailable +=
is_unavailable_bucket(new) - is_unavailable_bucket(old);
- dev_usage->sectors[bucket_type(old)] -= old.dirty_sectors;
- dev_usage->sectors[bucket_type(new)] += new.dirty_sectors;
- dev_usage->sectors_cached +=
+ dev_usage->sectors[old.data_type] -= old.dirty_sectors;
+ dev_usage->sectors[new.data_type] += new.dirty_sectors;
+ dev_usage->sectors[BCH_DATA_CACHED] +=
(int) new.cached_sectors - (int) old.cached_sectors;
preempt_enable();
@@ -348,8 +370,10 @@ bool bch2_invalidate_bucket(struct bch_fs *c, struct bch_dev *ca,
lg_local_lock(&c->usage_lock);
*old = bucket_data_cmpxchg(c, ca, g, new, ({
- if (!is_available_bucket(new))
+ if (!is_available_bucket(new)) {
+ lg_local_unlock(&c->usage_lock);
return false;
+ }
new.owned_by_allocator = 1;
new.touched_this_mount = 1;
@@ -374,8 +398,10 @@ bool bch2_mark_alloc_bucket_startup(struct bch_fs *c, struct bch_dev *ca,
lg_local_lock(&c->usage_lock);
old = bucket_data_cmpxchg(c, ca, g, new, ({
if (new.touched_this_mount ||
- !is_available_bucket(new))
+ !is_available_bucket(new)) {
+ lg_local_unlock(&c->usage_lock);
return false;
+ }
new.owned_by_allocator = 1;
new.touched_this_mount = 1;
@@ -422,8 +448,9 @@ do { \
} while (0)
void bch2_mark_metadata_bucket(struct bch_fs *c, struct bch_dev *ca,
- struct bucket *g, enum bucket_data_type type,
- struct gc_pos pos, unsigned flags)
+ struct bucket *g, enum bch_data_type type,
+ unsigned sectors, struct gc_pos pos,
+ unsigned flags)
{
struct bucket_mark old, new;
@@ -437,20 +464,13 @@ void bch2_mark_metadata_bucket(struct bch_fs *c, struct bch_dev *ca,
}
old = bucket_data_cmpxchg(c, ca, g, new, ({
- saturated_add(ca, new.dirty_sectors, ca->mi.bucket_size,
+ saturated_add(ca, new.dirty_sectors, sectors,
GC_MAX_SECTORS_USED);
new.data_type = type;
new.touched_this_mount = 1;
}));
lg_local_unlock(&c->usage_lock);
- if (old.data_type != type &&
- (old.data_type ||
- old.cached_sectors ||
- old.dirty_sectors))
- bch_err(c, "bucket %zu has multiple types of data (%u, %u)",
- g - ca->buckets, old.data_type, new.data_type);
-
BUG_ON(!(flags & BCH_BUCKET_MARK_MAY_MAKE_UNAVAILABLE) &&
bucket_became_unavailable(c, old, new));
}
@@ -483,8 +503,8 @@ static void bch2_mark_pointer(struct bch_fs *c,
unsigned saturated;
struct bch_dev *ca = bch_dev_bkey_exists(c, ptr->dev);
struct bucket *g = ca->buckets + PTR_BUCKET_NR(ca, ptr);
- unsigned data_type = type == S_META
- ? BUCKET_BTREE : BUCKET_DATA;
+ enum bch_data_type data_type = type == S_META
+ ? BCH_DATA_BTREE : BCH_DATA_USER;
u64 v;
if (crc.compression_type) {
@@ -566,13 +586,6 @@ static void bch2_mark_pointer(struct bch_fs *c,
bch2_dev_usage_update(c, ca, g, old, new);
- if (old.data_type != data_type &&
- (old.data_type ||
- old.cached_sectors ||
- old.dirty_sectors))
- bch_err(c, "bucket %zu has multiple types of data (%u, %u)",
- g - ca->buckets, old.data_type, new.data_type);
-
BUG_ON(!(flags & BCH_BUCKET_MARK_MAY_MAKE_UNAVAILABLE) &&
bucket_became_unavailable(c, old, new));
@@ -644,17 +657,19 @@ void bch2_mark_key(struct bch_fs *c, struct bkey_s_c k,
replicas += !ptr->cached;
}
- BUG_ON(replicas >= BCH_REPLICAS_MAX);
-
- if (replicas)
+ if (replicas) {
+ BUG_ON(replicas - 1 > ARRAY_SIZE(stats->s));
stats->s[replicas - 1].data[type] += sectors;
+ }
break;
}
case BCH_RESERVATION: {
struct bkey_s_c_reservation r = bkey_s_c_to_reservation(k);
- if (r.v->nr_replicas)
+ if (r.v->nr_replicas) {
+ BUG_ON(r.v->nr_replicas - 1 > ARRAY_SIZE(stats->s));
stats->s[r.v->nr_replicas - 1].persistent_reserved += sectors;
+ }
break;
}
}
@@ -671,7 +686,7 @@ static u64 __recalc_sectors_available(struct bch_fs *c)
for_each_possible_cpu(cpu)
per_cpu_ptr(c->usage_percpu, cpu)->available_cache = 0;
- avail = c->capacity - bch2_fs_sectors_used(c);
+ avail = c->capacity - bch2_fs_sectors_used(c, bch2_fs_usage_read(c));
avail <<= RESERVE_FACTOR;
avail /= (1 << RESERVE_FACTOR) + 1;