mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 04:02:20 +00:00
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:
parent
a803fa551d
commit
2c6a7bff2a
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user