summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2018-07-24 23:32:20 -0400
committerKent Overstreet <kent.overstreet@gmail.com>2018-08-01 15:33:50 -0400
commit8f70bd45d2f9bfe416d606b68cde9ca49dac5d49 (patch)
tree51549678593c056dbb6170658389166cf3aecd99
parent14b8a2dff574ac276acd5921dce36c011f838203 (diff)
-rw-r--r--fs/bcachefs/bcachefs_format.h1
-rw-r--r--fs/bcachefs/buckets.c118
-rw-r--r--fs/bcachefs/buckets.h6
-rw-r--r--fs/bcachefs/extents.c12
-rw-r--r--fs/bcachefs/sysfs.c4
5 files changed, 99 insertions, 42 deletions
diff --git a/fs/bcachefs/bcachefs_format.h b/fs/bcachefs/bcachefs_format.h
index f1814f4caf21..1616ab2678fb 100644
--- a/fs/bcachefs/bcachefs_format.h
+++ b/fs/bcachefs/bcachefs_format.h
@@ -827,6 +827,7 @@ enum {
enum {
BCH_ALLOC_FIELD_READ_TIME = 0,
BCH_ALLOC_FIELD_WRITE_TIME = 1,
+ /* XXX last_gc has to be persistent too */
};
struct bch_alloc {
diff --git a/fs/bcachefs/buckets.c b/fs/bcachefs/buckets.c
index 3a3f6ffee72a..478f7f5b3d58 100644
--- a/fs/bcachefs/buckets.c
+++ b/fs/bcachefs/buckets.c
@@ -73,6 +73,15 @@
#include <linux/preempt.h>
#include <trace/events/bcachefs.h>
+#define bch2_usage_add(_acc, _stats) \
+do { \
+ typeof(_acc) _a = (_acc), _s = (_stats); \
+ unsigned i; \
+ \
+ for (i = 0; i < sizeof(*_a) / sizeof(u64); i++) \
+ ((u64 *) (_a))[i] += ((u64 *) (_s))[i]; \
+} while (0)
+
static inline u64 __bch2_fs_sectors_used(struct bch_fs *, struct bch_fs_usage);
static inline int is_unavailable_bucket(struct bucket_mark m)
@@ -121,12 +130,28 @@ static inline void __dev_usage_update(struct bch_dev *ca,
is_fragmented_bucket(new, ca) - is_fragmented_bucket(old, ca);
}
+void bch2_dev_usage_verify_full(struct bch_dev *ca)
+{
+ struct bch_dev_usage s1 = __bch2_dev_usage_read(ca), s2 = { 0 };
+ struct bucket_array *buckets = bucket_array(ca);
+ struct bucket_mark zero_mark;
+ struct bucket *g;
+
+ memset(&zero_mark, 0, sizeof(zero_mark));
+
+ for_each_bucket(g, buckets)
+ __dev_usage_update(ca, &s2, zero_mark, g->mark);
+
+ BUG_ON(memcmp(&s1, &s2, sizeof(s1)));
+}
+
#ifdef DEBUG_BUCKETS
static void bch2_fs_usage_verify(struct bch_fs *c)
{
- struct bch_fs_usage stats =
- __bch2_fs_usage_read(c);
+ struct bch_fs_usage stats = __bch2_fs_usage_read(c);
+ struct bch_dev_usage dev_u = { 0 };
+ struct bch_dev *ca;
unsigned i, j;
for (i = 0; i < ARRAY_SIZE(stats.replicas); i++) {
@@ -153,21 +178,31 @@ static void bch2_fs_usage_verify(struct bch_fs *c)
if ((s64) stats.online_reserved < 0)
panic("sectors_online_reserved underflow: %lli\n",
stats.online_reserved);
-}
-static void bch2_dev_usage_verify_full(struct bch_dev *ca)
-{
- struct bch_dev_usage s1 = __bch2_dev_usage_read(ca), s2 = { 0 };
- struct bucket_array *buckets = bucket_array(ca);
- struct bucket_mark zero_mark;
- struct bucket *g;
+ for_each_member_device(ca, c, i) {
+ struct bch_dev_usage a = __bch2_dev_usage_read(ca);
- memset(&zero_mark, 0, sizeof(zero_mark));
+ bch2_usage_add(&dev_u, &a);
+ }
- for_each_bucket(g, buckets)
- __dev_usage_update(ca, &s2, zero_mark, g->mark);
+ /* XXX: not currently correct if compression is enabled */
+ for (i = 0; i < BCH_DATA_NR; i++) {
+ u64 a = 0;
- BUG_ON(memcmp(&s1, &s2, sizeof(s1)));
+ /*
+ * btree nodes that are pending delete aren't counted under fs
+ * usage, but are under dev usage...
+ */
+ if (i == BCH_DATA_BTREE)
+ continue;
+
+ for (j = 0; j < ARRAY_SIZE(stats.replicas); j++)
+ a += stats.replicas[j].data[i];
+
+ if (a != dev_u.sectors[i])
+ panic("data type %s: got %llu should be %llu\n",
+ bch2_data_types[i], a, dev_u.sectors[i]);
+ }
}
static void bch2_dev_usage_verify(struct bch_dev *ca)
@@ -185,8 +220,6 @@ static void bch2_dev_usage_verify(struct bch_dev *ca)
if (expensive_debug_checks(ca->fs))
bch2_dev_usage_verify_full(ca);
-
- bch2_fs_usage_verify(ca->fs);
}
static void bch2_disk_reservations_verify(struct bch_fs *c, int flags)
@@ -251,15 +284,6 @@ void bch2_bucket_seq_cleanup(struct bch_fs *c)
}
}
-#define bch2_usage_add(_acc, _stats) \
-do { \
- typeof(_acc) _a = (_acc), _s = (_stats); \
- unsigned i; \
- \
- for (i = 0; i < sizeof(*_a) / sizeof(u64); i++) \
- ((u64 *) (_a))[i] += ((u64 *) (_s))[i]; \
-} while (0)
-
#define bch2_usage_read_raw(_stats) \
({ \
typeof(*this_cpu_ptr(_stats)) _acc; \
@@ -381,10 +405,10 @@ static bool bucket_became_unavailable(struct bch_fs *c,
(!c || c->gc_pos.phase == GC_PHASE_DONE);
}
-void bch2_fs_usage_apply(struct bch_fs *c,
- struct bch_fs_usage *stats,
- struct disk_reservation *disk_res,
- struct gc_pos gc_pos)
+void __bch2_fs_usage_apply(struct bch_fs *c,
+ struct bch_fs_usage *stats,
+ struct disk_reservation *disk_res,
+ struct gc_pos gc_pos)
{
struct fs_usage_sum sum = __fs_usage_sum(*stats);
s64 added = sum.data + sum.reserved;
@@ -400,8 +424,6 @@ void bch2_fs_usage_apply(struct bch_fs *c,
stats->online_reserved -= added;
}
- percpu_down_read_preempt_disable(&c->usage_lock);
-
/* online_reserved not subject to gc: */
if (likely(!gc_will_visit(c, gc_pos)))
bch2_usage_add(this_cpu_ptr(c->usage_percpu), stats);
@@ -409,10 +431,19 @@ void bch2_fs_usage_apply(struct bch_fs *c,
this_cpu_ptr(c->usage_percpu)->online_reserved +=
stats->online_reserved;
+ memset(stats, 0, sizeof(*stats));
+
bch2_fs_usage_verify(c);
- percpu_up_read_preempt_enable(&c->usage_lock);
+}
- memset(stats, 0, sizeof(*stats));
+void bch2_fs_usage_apply(struct bch_fs *c,
+ struct bch_fs_usage *stats,
+ struct disk_reservation *disk_res,
+ struct gc_pos gc_pos)
+{
+ percpu_down_read_preempt_disable(&c->usage_lock);
+ __bch2_fs_usage_apply(c, stats, disk_res, gc_pos);
+ percpu_up_read_preempt_enable(&c->usage_lock);
}
static void bch2_dev_usage_update(struct bch_fs *c, struct bch_dev *ca,
@@ -447,6 +478,7 @@ void bch2_invalidate_bucket(struct bch_fs *c, struct bch_dev *ca,
struct bucket *g;
struct bucket_mark new;
+ lockdep_assert_held(&c->gc_lock);
percpu_rwsem_assert_held(&c->usage_lock);
bch2_dev_usage_verify(ca);
@@ -681,11 +713,11 @@ fs_usage:
uncompressed_sectors;
}
-void bch2_mark_key(struct bch_fs *c, struct bkey_s_c k,
- s64 sectors, enum bch_data_type data_type,
- struct gc_pos pos,
- struct bch_fs_usage *stats,
- u64 journal_seq, unsigned flags)
+void __bch2_mark_key(struct bch_fs *c, struct bkey_s_c k,
+ s64 sectors, enum bch_data_type data_type,
+ struct gc_pos pos,
+ struct bch_fs_usage *stats,
+ u64 journal_seq, unsigned flags)
{
unsigned replicas = bch2_extent_nr_dirty_ptrs(k);
@@ -719,7 +751,6 @@ void bch2_mark_key(struct bch_fs *c, struct bkey_s_c k,
* (e.g. the btree node lock, or the relevant allocator lock).
*/
- percpu_down_read_preempt_disable(&c->usage_lock);
if (!(flags & BCH_BUCKET_MARK_GC_LOCK_HELD) &&
gc_will_visit(c, pos))
flags |= BCH_BUCKET_MARK_GC_WILL_VISIT;
@@ -747,6 +778,17 @@ void bch2_mark_key(struct bch_fs *c, struct bkey_s_c k,
sectors * replicas;
break;
}
+}
+
+void bch2_mark_key(struct bch_fs *c, struct bkey_s_c k,
+ s64 sectors, enum bch_data_type data_type,
+ struct gc_pos pos,
+ struct bch_fs_usage *stats,
+ u64 journal_seq, unsigned flags)
+{
+ percpu_down_read_preempt_disable(&c->usage_lock);
+ __bch2_mark_key(c, k, sectors, data_type, pos,
+ stats, journal_seq, flags);
percpu_up_read_preempt_enable(&c->usage_lock);
}
diff --git a/fs/bcachefs/buckets.h b/fs/bcachefs/buckets.h
index 3a6b31d40b73..e37a6207fac5 100644
--- a/fs/bcachefs/buckets.h
+++ b/fs/bcachefs/buckets.h
@@ -144,6 +144,8 @@ static inline bool bucket_unused(struct bucket_mark mark)
/* Device usage: */
+void bch2_dev_usage_verify_full(struct bch_dev *);
+
struct bch_dev_usage __bch2_dev_usage_read(struct bch_dev *);
struct bch_dev_usage bch2_dev_usage_read(struct bch_fs *, struct bch_dev *);
@@ -185,6 +187,8 @@ static inline u64 dev_buckets_free(struct bch_fs *c, struct bch_dev *ca)
struct bch_fs_usage __bch2_fs_usage_read(struct bch_fs *);
struct bch_fs_usage bch2_fs_usage_read(struct bch_fs *);
+void __bch2_fs_usage_apply(struct bch_fs *, struct bch_fs_usage *,
+ struct disk_reservation *, struct gc_pos);
void bch2_fs_usage_apply(struct bch_fs *, struct bch_fs_usage *,
struct disk_reservation *, struct gc_pos);
@@ -219,6 +223,8 @@ void bch2_mark_metadata_bucket(struct bch_fs *, struct bch_dev *,
#define BCH_BUCKET_MARK_GC_WILL_VISIT (1 << 2)
#define BCH_BUCKET_MARK_GC_LOCK_HELD (1 << 3)
+void __bch2_mark_key(struct bch_fs *, struct bkey_s_c, s64, enum bch_data_type,
+ struct gc_pos, struct bch_fs_usage *, u64, unsigned);
void bch2_mark_key(struct bch_fs *, struct bkey_s_c, s64, enum bch_data_type,
struct gc_pos, struct bch_fs_usage *, u64, unsigned);
diff --git a/fs/bcachefs/extents.c b/fs/bcachefs/extents.c
index be4dd2307a43..28de20cccd92 100644
--- a/fs/bcachefs/extents.c
+++ b/fs/bcachefs/extents.c
@@ -1071,8 +1071,8 @@ static void bch2_add_sectors(struct extent_insert_state *s,
if (!sectors)
return;
- bch2_mark_key(c, k, sectors, BCH_DATA_USER, gc_pos_btree_node(b),
- &s->stats, s->trans->journal_res.seq, 0);
+ __bch2_mark_key(c, k, sectors, BCH_DATA_USER, gc_pos_btree_node(b),
+ &s->stats, s->trans->journal_res.seq, 0);
}
static void bch2_subtract_sectors(struct extent_insert_state *s,
@@ -1650,6 +1650,8 @@ bch2_insert_fixup_extent(struct btree_insert *trans,
*/
EBUG_ON(bkey_cmp(iter->pos, bkey_start_pos(&insert->k->k)));
+ percpu_down_read_preempt_disable(&c->usage_lock);
+
if (!s.deleting &&
!(trans->flags & BTREE_INSERT_JOURNAL_REPLAY))
bch2_add_sectors(&s, bkey_i_to_s_c(insert->k),
@@ -1680,8 +1682,10 @@ bch2_insert_fixup_extent(struct btree_insert *trans,
bkey_start_offset(&insert->k->k),
insert->k->k.size);
- bch2_fs_usage_apply(c, &s.stats, trans->disk_res,
- gc_pos_btree_node(b));
+ __bch2_fs_usage_apply(c, &s.stats, trans->disk_res,
+ gc_pos_btree_node(b));
+
+ percpu_up_read_preempt_enable(&c->usage_lock);
EBUG_ON(bkey_cmp(iter->pos, bkey_start_pos(&insert->k->k)));
EBUG_ON(bkey_cmp(iter->pos, s.committed));
diff --git a/fs/bcachefs/sysfs.c b/fs/bcachefs/sysfs.c
index b353d7cdb6cd..6ebaf1136aa7 100644
--- a/fs/bcachefs/sysfs.c
+++ b/fs/bcachefs/sysfs.c
@@ -767,6 +767,10 @@ static ssize_t show_dev_alloc_debug(struct bch_dev *ca, char *buf)
struct bch_fs *c = ca->fs;
struct bch_dev_usage stats = bch2_dev_usage_read(c, ca);
+ percpu_down_write(&c->usage_lock);
+ bch2_dev_usage_verify_full(ca);
+ percpu_up_write(&c->usage_lock);
+
return scnprintf(buf, PAGE_SIZE,
"free_inc: %zu/%zu\n"
"free[RESERVE_BTREE]: %zu/%zu\n"