summaryrefslogtreecommitdiff
path: root/fs/bcachefs/buckets.c
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@linux.dev>2023-05-22 14:39:44 -0400
committerKent Overstreet <kent.overstreet@linux.dev>2023-10-22 17:10:01 -0400
commit962210b281b327b236215c736b9f648369f0d39d (patch)
tree3a63cfebef930d3e6d116e75f4ec2c49621961cc /fs/bcachefs/buckets.c
parent0b438c5bfaebda3fdf6edc35d9572d4e2f66aef1 (diff)
downloadlwn-962210b281b327b236215c736b9f648369f0d39d.tar.gz
lwn-962210b281b327b236215c736b9f648369f0d39d.zip
bcachefs: Fix a buffer overrun in bch2_fs_usage_read()
We were copying the size of a struct bch_fs_usage_online to a struct bch_fs_usage, which is 8 bytes smaller. This adds some new helpers so we can do this correctly, and get rid of some magic +1s too. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
Diffstat (limited to 'fs/bcachefs/buckets.c')
-rw-r--r--fs/bcachefs/buckets.c16
1 files changed, 9 insertions, 7 deletions
diff --git a/fs/bcachefs/buckets.c b/fs/bcachefs/buckets.c
index bce42eef6f57..bd144182c1e1 100644
--- a/fs/bcachefs/buckets.c
+++ b/fs/bcachefs/buckets.c
@@ -137,17 +137,17 @@ u64 bch2_fs_usage_read_one(struct bch_fs *c, u64 *v)
struct bch_fs_usage_online *bch2_fs_usage_read(struct bch_fs *c)
{
struct bch_fs_usage_online *ret;
- unsigned seq, i, v, u64s = fs_usage_u64s(c) + 1;
+ unsigned nr_replicas = READ_ONCE(c->replicas.nr);
+ unsigned seq, i;
retry:
- ret = kmalloc(u64s * sizeof(u64), GFP_NOFS);
+ ret = kmalloc(__fs_usage_online_u64s(nr_replicas) * sizeof(u64), GFP_NOFS);
if (unlikely(!ret))
return NULL;
percpu_down_read(&c->mark_lock);
- v = fs_usage_u64s(c) + 1;
- if (unlikely(u64s != v)) {
- u64s = v;
+ if (nr_replicas != c->replicas.nr) {
+ nr_replicas = c->replicas.nr;
percpu_up_read(&c->mark_lock);
kfree(ret);
goto retry;
@@ -157,10 +157,12 @@ retry:
do {
seq = read_seqcount_begin(&c->usage_lock);
- unsafe_memcpy(&ret->u, c->usage_base, u64s * sizeof(u64),
+ unsafe_memcpy(&ret->u, c->usage_base,
+ __fs_usage_u64s(nr_replicas) * sizeof(u64),
"embedded variable length struct");
for (i = 0; i < ARRAY_SIZE(c->usage); i++)
- acc_u64s_percpu((u64 *) &ret->u, (u64 __percpu *) c->usage[i], u64s);
+ acc_u64s_percpu((u64 *) &ret->u, (u64 __percpu *) c->usage[i],
+ __fs_usage_u64s(nr_replicas));
} while (read_seqcount_retry(&c->usage_lock, seq));
return ret;