bcachefs: Switch gc bucket array to a genradix

A user with a 30 tb device is overflowing the INT_MAX limit on vmalloc
allocations...

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
Kent Overstreet 2024-08-24 11:38:21 -04:00
parent a803fa551d
commit 2c6a7bff2a
4 changed files with 6 additions and 37 deletions

View File

@ -542,7 +542,7 @@ struct bch_dev {
* gc_gens_lock, for device resize - holding any is sufficient for * gc_gens_lock, for device resize - holding any is sufficient for
* access: Or rcu_read_lock(), but only for dev_ptr_stale(): * access: Or rcu_read_lock(), but only for dev_ptr_stale():
*/ */
struct bucket_array __rcu *buckets_gc; GENRADIX(struct bucket) buckets_gc;
struct bucket_gens __rcu *bucket_gens; struct bucket_gens __rcu *bucket_gens;
u8 *oldest_gen; u8 *oldest_gen;
unsigned long *buckets_nouse; unsigned long *buckets_nouse;

View File

@ -753,10 +753,8 @@ static void bch2_gc_free(struct bch_fs *c)
genradix_free(&c->reflink_gc_table); genradix_free(&c->reflink_gc_table);
genradix_free(&c->gc_stripes); genradix_free(&c->gc_stripes);
for_each_member_device(c, ca) { for_each_member_device(c, ca)
kvfree(rcu_dereference_protected(ca->buckets_gc, 1)); genradix_free(&ca->buckets_gc);
ca->buckets_gc = NULL;
}
} }
static int bch2_gc_start(struct bch_fs *c) static int bch2_gc_start(struct bch_fs *c)
@ -910,20 +908,12 @@ static int bch2_gc_alloc_start(struct bch_fs *c)
int ret = 0; int ret = 0;
for_each_member_device(c, ca) { for_each_member_device(c, ca) {
struct bucket_array *buckets = kvmalloc(sizeof(struct bucket_array) + ret = genradix_prealloc(&ca->buckets_gc, ca->mi.nbuckets, GFP_KERNEL);
ca->mi.nbuckets * sizeof(struct bucket), if (ret) {
GFP_KERNEL|__GFP_ZERO);
if (!buckets) {
bch2_dev_put(ca); bch2_dev_put(ca);
ret = -BCH_ERR_ENOMEM_gc_alloc_start; ret = -BCH_ERR_ENOMEM_gc_alloc_start;
break; break;
} }
buckets->first_bucket = ca->mi.first_bucket;
buckets->nbuckets = ca->mi.nbuckets;
buckets->nbuckets_minus_first =
buckets->nbuckets - buckets->first_bucket;
rcu_assign_pointer(ca->buckets_gc, buckets);
} }
bch_err_fn(c, ret); bch_err_fn(c, ret);

View File

@ -80,22 +80,9 @@ static inline void bucket_lock(struct bucket *b)
TASK_UNINTERRUPTIBLE); TASK_UNINTERRUPTIBLE);
} }
static inline struct bucket_array *gc_bucket_array(struct bch_dev *ca)
{
return rcu_dereference_check(ca->buckets_gc,
!ca->fs ||
percpu_rwsem_is_held(&ca->fs->mark_lock) ||
lockdep_is_held(&ca->fs->state_lock) ||
lockdep_is_held(&ca->bucket_lock));
}
static inline struct bucket *gc_bucket(struct bch_dev *ca, size_t b) static inline struct bucket *gc_bucket(struct bch_dev *ca, size_t b)
{ {
struct bucket_array *buckets = gc_bucket_array(ca); return genradix_ptr(&ca->buckets_gc, b);
if (b - buckets->first_bucket >= buckets->nbuckets_minus_first)
return NULL;
return buckets->b + b;
} }
static inline struct bucket_gens *bucket_gens(struct bch_dev *ca) static inline struct bucket_gens *bucket_gens(struct bch_dev *ca)

View File

@ -19,14 +19,6 @@ struct bucket {
u32 stripe_sectors; u32 stripe_sectors;
} __aligned(sizeof(long)); } __aligned(sizeof(long));
struct bucket_array {
struct rcu_head rcu;
u16 first_bucket;
size_t nbuckets;
size_t nbuckets_minus_first;
struct bucket b[] __counted_by(nbuckets);
};
struct bucket_gens { struct bucket_gens {
struct rcu_head rcu; struct rcu_head rcu;
u16 first_bucket; u16 first_bucket;