Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
f47e0bd
bcachefs: validate_member(): fix device not enough buckets message
jullanggit Feb 17, 2026
b5873eb
bcachefs: validate_member(): extract variables
jullanggit Feb 17, 2026
609a1af
bcachefs: validate_member(): not enough buckets: print actual amount …
jullanggit Feb 17, 2026
8157d95
bcachefs: validate_members(): fix bad search-and-replace
jullanggit Feb 18, 2026
289e32b
bcachefs: add target_nbuckets to bch_member(_cpu)
jullanggit Feb 16, 2026
5456cdc
bcachefs: print target_nbuckets = 0 as inactive instead of 0
jullanggit Feb 16, 2026
151f43d
bcachefs: consider pointers after target_nbuckets as evacuating
jullanggit Feb 16, 2026
b96ea41
bcachefs: use dev-based evacuating check for may_reuse_stripe
jullanggit Feb 17, 2026
8c67419
bcachefs: sharpen target_nbuckets semantics to only include (triviall…
jullanggit Feb 17, 2026
24a0d16
bcachefs: split bch2_dev_resze into grow & shrink paths
jullanggit Feb 17, 2026
76bb037
bcachefs: implement shrink superblock & alloc nouse interactions
jullanggit Feb 17, 2026
c9714f5
bcachefs: refactor out per-device buckets_nouse alloc/free
jullanggit Feb 17, 2026
1b2c742
bcachefs: implement filesystem shrinking mvp
jullanggit Feb 17, 2026
75cc265
bcachefs: shrink: avoid holding two transactions at once
jullanggit Feb 17, 2026
ce82b76
bcachefs: alloc: directly check against target_nbuckets for skipping …
jullanggit Feb 18, 2026
6dab5dd
bcachefs: remove unused buckets_nouse code
jullanggit Feb 18, 2026
7c80388
bcachefs: shrink: print error message if reconcile scan fails
jullanggit Feb 18, 2026
6e47a06
bcachefs: shrink: close open buckets before evacuating data
jullanggit Feb 18, 2026
5285b74
bcachefs: shrink: explicitly pass tail_cutoff instead of implicitly r…
jullanggit Feb 18, 2026
fae49d1
bcachefs: dev_resize_alloc: cast new - old buckets calculation to sig…
jullanggit Feb 18, 2026
0c38949
bcachefs: shrink: truncate alloc info
jullanggit Feb 21, 2026
9e6f210
bcachefs: shrink: run disk accounting
jullanggit Feb 21, 2026
a2f2b52
bcachefs: shrink: disk accounting: properly handle negative changes
jullanggit Feb 21, 2026
812b9d9
bcachefs: shrink: truncate alloc: remove spurious dev_usage_remove call
jullanggit Feb 21, 2026
872f621
bcachefs: shrink: drop references to cutoff superblock copies
jullanggit Feb 21, 2026
8507ca3
bcachefs: shrink: mark superblock buckets as metadata
jullanggit Feb 21, 2026
ae100e9
bcachefs: shrink: use the same usage_remove path as dev_remove
jullanggit Feb 21, 2026
02b86dc
bcachefs: shrink: convert new nbuckets to little-endian before writin…
jullanggit Feb 21, 2026
900de51
bcachefs: shrink: use alloc info to update accounting
jullanggit Feb 21, 2026
a9b2dfd
bcachefs: shrink: add comment about data being left as cached
jullanggit Feb 25, 2026
ff0d94a
bcachefs: shrink: drop cached data after shrink cutoff
jullanggit Feb 25, 2026
6574eaf
bcachefs: shrink: remove unnecessary sb metadata marking
jullanggit Mar 3, 2026
6db36ba
bcachefs: shrink: flush journal
jullanggit Mar 3, 2026
34abba4
bcachefs: shrink: properly remove bucket gens
jullanggit Mar 18, 2026
a05fcb7
bcachefs: fix online shrink tail metadata cleanup
jullanggit Apr 12, 2026
cf0297b
fix three-device shrink reconcile races
jullanggit Apr 13, 2026
6a20513
bcachefs: tolerate transient shrink rereplicate state
jullanggit Apr 13, 2026
34c31c9
bcachefs: update reconcile-only backpointer flags in place
jullanggit Apr 13, 2026
99be08a
bcachefs: delete truncated backpointers in backpointer key space
jullanggit Apr 13, 2026
aef3e93
bcachefs: close write points before stopping copygc
jullanggit Apr 13, 2026
e6a591f
bcachefs: start reconcile extent iterators with intent locks
jullanggit Apr 13, 2026
d7a9f1c
bcachefs: let shrink metadata spill off shrinking targets
jullanggit Apr 13, 2026
b35672a
bcachefs: resume pending shrink during recovery
jullanggit Apr 14, 2026
557af95
bcachefs: make device resize converge to the latest target
jullanggit Apr 14, 2026
59c4d95
bcachefs: discard: drop need_discard iter before commit
jullanggit Apr 15, 2026
47cbc88
fs/bcachefs: drop cached reconcile paths before move work
jullanggit Apr 15, 2026
197ab69
fs/bcachefs: keep shrink discards out of the evacuated tail
jullanggit Apr 18, 2026
15c35f6
bcachefs: shrink: bch2_dev_resize_wait_done: improve readability
jullanggit Apr 19, 2026
8386a41
bcachefs: shrink: small code cleanups
jullanggit Apr 19, 2026
ca44f04
bcachefs: fail impossible shrink after reconcile drains
jullanggit Apr 19, 2026
3341e0f
bcachefs: keep shrink reconcile focused on the truncating tail
jullanggit Apr 19, 2026
9c1f061
bcachefs: stop shrink waiting once the tail is empty
jullanggit Apr 19, 2026
6161dce
bcachefs: bound shrink's final journal pin flush
jullanggit Apr 19, 2026
19cfd75
bcachefs: add comment
jullanggit Apr 20, 2026
f70b79b
bcachefs: shrink_finish: remove redundant journal moving and restart …
jullanggit Apr 20, 2026
9f3a8b5
bcachefs: rename bch2_dev_shrink_finish -> bch2_dev_shrink_finalize
jullanggit Apr 20, 2026
11c8da5
bcachefs: shorten comment about waking pending reconcile on shrink ca…
jullanggit Apr 20, 2026
5b98324
bcachefs: shrink: add TODO
jullanggit Apr 20, 2026
3f605d3
bcachefs: shrink: change not-enough-space error message
jullanggit Apr 20, 2026
a2c5355
bcachefs: shrink: bound stalled tail detection on reconcile work
jullanggit Apr 20, 2026
f4c7603
bcachefs: shrink: only fail after quiescent stalled rescans
jullanggit Apr 20, 2026
d2a62b0
bcachefs: shrink: document journal as imperfect progress signal
jullanggit Apr 20, 2026
ea79de8
bcachefs: shrink: add shrinking docs
jullanggit Jun 15, 2026
0a69452
bcachefs: shrink: docs: remove unnecessary detail
jullanggit Jun 24, 2026
d294b8d
bcachefs: shrink: make docs more concise
jullanggit Jun 24, 2026
a2f5aeb
bcachefs: shrink: address review cleanups
Komzpa Jun 28, 2026
749abf0
bcachefs: shrink: remove redundant bch2_dev_clear_need_discard call
jullanggit Jun 29, 2026
a060450
bcachefs: remove bch2_dev_clear_need_discard and merge cutoff awarene…
jullanggit Jun 29, 2026
049aa83
bcachefs: move bch2_dev_usage_remove() from bch2_dev_remove_alloc() i…
jullanggit Jun 29, 2026
85280d7
bcachefs: bch2_dev_remove_alloc(): remove unnecessary comment
jullanggit Jun 29, 2026
2906ebc
bcachefs: simplify bch2_dev_remove_bucket_gens()
jullanggit Jun 29, 2026
3d91eb2
bcachefs: shrink: add comment
jullanggit Jun 29, 2026
805df71
bcachefs: shrink: add bch2_target_has_non_shrinking_dev() helper
jullanggit Jun 29, 2026
d3c3cc6
bcachefs: rename bch2_trigger_extent_same_backpointers to bch2_trigge…
jullanggit Jul 1, 2026
f743721
bcachefs: clean up bch2_do_discards
jullanggit Jul 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions fs/bcachefs/alloc/accounting.c
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
// SPDX-License-Identifier: GPL-2.0

#include "alloc/background.h"
#include "alloc/format.h"
#include "bcachefs.h"
#include "bcachefs_format.h"
#include "bcachefs_ioctl.h"
#include "alloc/accounting_format.h"

#include "alloc/accounting.h"
#include "alloc/buckets.h"
#include "alloc/replicas.h"

#include "btree/bkey_types.h"
#include "btree/cache.h"
#include "btree/iter.h"
#include "btree/journal_overlay.h"
#include "btree/types.h"
#include "btree/update.h"
#include "btree/write_buffer.h"

Expand Down Expand Up @@ -1174,6 +1181,55 @@ int bch2_accounting_read(struct bch_fs *c)
return accounting_read_mem_fixups(trans);
}

int bch2_dev_truncate_accounting(struct bch_fs *c, struct bch_dev *ca, u64 old_nbuckets, u64 cutoff) {
struct bpos start = POS(ca->dev_idx, cutoff);
struct bpos end = POS(ca->dev_idx, old_nbuckets);

CLASS(btree_trans, trans)(c);

/* accumulate deltas per data type, then apply them */
return commit_do(trans, NULL, NULL, 0, ({
s64 delta[BCH_DATA_NR][3] = {};
s64 keys = 0;
struct bkey_s_c k;
int ret = 0;

for_each_btree_key_max_norestart(trans, iter, BTREE_ID_alloc, start, end, BTREE_ITER_prefetch, k, ret) {
if (!k.k->type)
continue;

struct bch_alloc_v4 _alloc;
const struct bch_alloc_v4 *alloc = bch2_alloc_to_v4(k, &_alloc);

enum bch_data_type data_type = alloc->data_type;

delta[data_type][0] -= 1;
delta[data_type][1] -= bch2_bucket_sectors(*alloc);
delta[data_type][2] -= bch2_bucket_sectors_fragmented(ca, *alloc);

s64 unstriped = bch2_bucket_sectors_unstriped(*alloc);
if (unstriped) {
delta[BCH_DATA_unstriped][0] -= 1;
delta[BCH_DATA_unstriped][1] -= unstriped;
}

keys++;
}
if (!ret) {
delta[BCH_DATA_free][0] -= (old_nbuckets - cutoff) - keys;

for (unsigned type = 0; type < BCH_DATA_NR; type++) {
ret = bch2_disk_accounting_mod2(trans, false, delta[type], dev_data_type, .dev = ca->dev_idx, .data_type = type);

if (ret)
break;
}
}

ret;
}));
}

int bch2_dev_usage_remove(struct bch_fs *c, struct bch_dev *ca)
{
CLASS(btree_trans, trans)(c);
Expand Down
3 changes: 3 additions & 0 deletions fs/bcachefs/alloc/accounting.h
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,9 @@ int bch2_gc_accounting_done(struct bch_fs *);

int bch2_accounting_read(struct bch_fs *);


int bch2_dev_truncate_accounting(struct bch_fs *, struct bch_dev *, u64, u64);

int bch2_dev_usage_remove(struct bch_fs *, struct bch_dev *);
int bch2_dev_usage_init(struct bch_dev *, bool);

Expand Down
2 changes: 1 addition & 1 deletion fs/bcachefs/alloc/accounting_format.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
* Here, the key has considerably more structure than a typical key (bpos); an
* accounting key is 'struct disk_accounting_pos', which is a union of bpos.
*
* More specifically: a key is just a muliword integer (where word endianness
* More specifically: a key is just a multiword integer (where word endianness
* matches native byte order), so we're treating bpos as an opaque 20 byte
* integer and mapping bch_accounting_key to that.
*
Expand Down
78 changes: 60 additions & 18 deletions fs/bcachefs/alloc/background.c
Original file line number Diff line number Diff line change
Expand Up @@ -1089,6 +1089,47 @@ int bch2_alloc_read(struct bch_fs *c)
return ret;
}

int bch2_dev_remove_bucket_gens(struct bch_fs *c, struct bch_dev *ca, u64 cutoff)
{
unsigned offset;
struct bpos pos = alloc_gens_pos(POS(ca->dev_idx, cutoff), &offset);

/* cutoff on key boundary */
if (!offset)
return bch2_btree_delete_range(c, BTREE_ID_bucket_gens,
pos,
POS(ca->dev_idx, U64_MAX),
BTREE_TRIGGER_norun);

/* Cutoff mid-key */

CLASS(btree_trans, trans)(c);

/* zero tail gens */
try(commit_do(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc, ({
CLASS(btree_iter, iter)(trans, BTREE_ID_bucket_gens, pos, BTREE_ITER_intent);
struct bkey_s_c k = bkey_try(bch2_btree_iter_peek_slot(&iter));

try(bkey_err(k));

if (k.k->type == KEY_TYPE_bucket_gens) {
struct bkey_i_bucket_gens *g =
errptr_try(bch2_trans_kmalloc(trans, sizeof(*g)));

bkey_reassemble(&g->k_i, k);
memset(&g->v.gens[offset], 0, sizeof(g->v.gens) - offset);
try(bch2_trans_update(trans, &iter, &g->k_i, 0));
}
0;
})));

/* delete remaining keys */
return bch2_btree_delete_range(c, BTREE_ID_bucket_gens,
bpos_nosnap_successor(pos),
POS(ca->dev_idx, U64_MAX),
BTREE_TRIGGER_norun);
}

/* Free space/discard btree: */

int bch2_bucket_do_freespace_index(struct btree_trans *trans,
Expand Down Expand Up @@ -1254,8 +1295,7 @@ int bch2_trigger_alloc(struct btree_trans *trans,
if (is_empty_delta < 0 &&
(new_a->data_type != BCH_DATA_sb &&
new_a->data_type != BCH_DATA_journal) &&
!bch2_bucket_is_open_safe(c, new.k->p.inode, new.k->p.offset) &&
!bch2_bucket_nouse(ca, new.k->p.offset)) {
!bch2_bucket_is_open_safe(c, new.k->p.inode, new.k->p.offset)) {
CLASS(printbuf, buf)();
log_fsck_err_on(true, trans,
alloc_key_bucket_nonempty_to_empty_not_open,
Expand Down Expand Up @@ -1415,47 +1455,49 @@ int bch2_trigger_alloc(struct btree_trans *trans,
return ret;
}

/* device removal */
/* device removal / shrinking */

static int bch2_dev_remove_need_discard(struct bch_fs *c, struct bch_dev *ca)
static int bch2_dev_remove_need_discard(struct bch_fs *c, struct bch_dev *ca, u64 cutoff)
{
CLASS(btree_trans, trans)(c);
unsigned dev_idx = ca->dev_idx;

return for_each_btree_key_commit(trans, iter,
BTREE_ID_need_discard, POS_MIN,
BTREE_ITER_intent|BTREE_ITER_prefetch, k,
NULL, NULL, BCH_TRANS_COMMIT_no_enospc, ({
NULL, NULL, BCH_WATERMARK_reclaim|
BCH_TRANS_COMMIT_no_enospc, ({
struct bpos bucket = u64_to_bucket(k.k->p.offset);
(bucket.inode == dev_idx)
(bucket.inode == dev_idx && bucket.offset >= cutoff)
? bch2_btree_delete_at(trans, &iter,
BTREE_TRIGGER_norun)
: 0;
}));
}

int bch2_dev_remove_alloc(struct bch_fs *c, struct bch_dev *ca)
int bch2_dev_remove_alloc(struct bch_fs *c, struct bch_dev *ca, u64 cutoff)
{
struct bpos start = POS(ca->dev_idx, 0);
struct bpos start = POS(ca->dev_idx, cutoff);
struct bpos end = POS(ca->dev_idx, U64_MAX);
struct bpos bp_start = bucket_pos_to_bp_start(ca, start);
struct bpos bp_end = POS(ca->dev_idx + 1, 0);
int ret;

/*
* We clear the LRU and need_discard btrees first so that we don't race
* with bch2_do_invalidates() and bch2_do_discards_async()
* with bch2_do_invalidates() and bch2_do_discards()
*/
ret = bch2_dev_remove_lrus(c, ca) ?:
bch2_dev_remove_need_discard(c, ca) ?:
ret = bch2_dev_remove_lrus(c, ca, cutoff) ?:
bch2_dev_remove_need_discard(c, ca, cutoff) ?:
bch2_btree_delete_range(c, BTREE_ID_freespace, start, end,
BTREE_TRIGGER_norun) ?:
bch2_btree_delete_range(c, BTREE_ID_backpointers, start, end,
BTREE_TRIGGER_norun) ?:
bch2_btree_delete_range(c, BTREE_ID_bucket_gens, start, end,
bch2_btree_delete_range(c, BTREE_ID_backpointers, bp_start, bp_end,
BTREE_TRIGGER_norun) ?:
bch2_dev_remove_bucket_gens(c, ca, cutoff) ?:
bch2_btree_delete_range(c, BTREE_ID_alloc, start, end,
BTREE_TRIGGER_norun) ?:
bch2_dev_usage_remove(c, ca);
bch_err_msg_dev(ca, ret, "removing dev alloc info");
BTREE_TRIGGER_norun);
bch_err_msg_dev(ca, ret, "%s dev alloc info",
cutoff ? "truncating" : "removing");
return ret;
}

Expand Down Expand Up @@ -1636,7 +1678,7 @@ void bch2_dev_allocator_remove(struct bch_fs *c, struct bch_dev *ca)
*/
bch2_recalc_capacity(c);

bch2_open_buckets_stop(c, ca, false);
bch2_open_buckets_stop(c, ca, false, 0);

/*
* Wake up threads that were blocked on allocation, so they can notice
Expand Down
3 changes: 2 additions & 1 deletion fs/bcachefs/alloc/background.h
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ void bch2_bucket_gens_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_
})

int bch2_bucket_gens_init(struct bch_fs *);
int bch2_dev_remove_bucket_gens(struct bch_fs *, struct bch_dev *, u64);

int bch2_alloc_read(struct bch_fs *);

Expand All @@ -330,7 +331,7 @@ int bch2_trigger_alloc(struct btree_trans *, enum btree_id, unsigned,
struct bkey_s_c, struct bkey_s,
enum btree_iter_update_trigger_flags);

int bch2_dev_remove_alloc(struct bch_fs *, struct bch_dev *);
int bch2_dev_remove_alloc(struct bch_fs *, struct bch_dev *, u64);

void bch2_recalc_capacity(struct bch_fs *);
unsigned long bch2_fs_ra_pages(struct bch_fs *);
Expand Down
108 changes: 80 additions & 28 deletions fs/bcachefs/alloc/buckets.c
Original file line number Diff line number Diff line change
Expand Up @@ -878,6 +878,77 @@ static int __trigger_extent(struct btree_trans *trans,
return 0;
}

/* in-place update RECONCILE_PHYS if it is the only thing that changed */
static int bch2_trigger_extent_reconcile_phys_update(struct btree_trans *trans,
enum btree_id btree,
struct bkey_s_c old,
struct bkey_s new,
bool *handled)
{
struct bch_fs *c = trans->c;
struct bkey_i_backpointer old_bp[BCH_REPLICAS_MAX * 2];
struct bkey_i_backpointer new_bp[BCH_REPLICAS_MAX * 2];
struct bkey_ptrs_c ptrs;
const union bch_extent_entry *entry;
struct extent_ptr_decoded p;
unsigned nr_old = 0, nr_new = 0;
unsigned i;

*handled = false;

ptrs = bch2_bkey_ptrs_c(old);
bkey_for_each_ptr_decode(old.k, ptrs, p, entry) {
BUG_ON(nr_old == ARRAY_SIZE(old_bp));
bch2_extent_ptr_to_bp(c, btree, level, old, p, entry, &old_bp[nr_old++]);
}

ptrs = bch2_bkey_ptrs_c(new.s_c);
bkey_for_each_ptr_decode(new.k, ptrs, p, entry) {
BUG_ON(nr_new == ARRAY_SIZE(new_bp));
bch2_extent_ptr_to_bp(c, btree, level, new.s_c, p, entry, &new_bp[nr_new++]);
}

if (nr_old != nr_new)
return 0;

for (i = 0; i < nr_old; i++) {
struct bch_backpointer old_v = old_bp[i].v;
struct bch_backpointer new_v = new_bp[i].v;

SET_BACKPOINTER_RECONCILE_PHYS(&old_v, 0);
SET_BACKPOINTER_RECONCILE_PHYS(&new_v, 0);

if (!bpos_eq(old_bp[i].k.p, new_bp[i].k.p) ||
memcmp(&old_v, &new_v, sizeof(old_v)))
return 0;
}

for (i = 0; i < nr_old; i++) {
unsigned old_phys = BACKPOINTER_RECONCILE_PHYS(&old_bp[i].v);
unsigned new_phys = BACKPOINTER_RECONCILE_PHYS(&new_bp[i].v);

if (!old_phys && !new_phys)
continue;

if (old_phys)
try(bch2_btree_bit_mod_buffered(trans,
reconcile_work_phys_btree[old_phys],
old_bp[i].k.p, false));

if (new_phys)
try(bch2_btree_bit_mod_buffered(trans,
reconcile_work_phys_btree[new_phys],
new_bp[i].k.p, true));

try(bch2_trans_update_buffered(trans,
backpointer_btree(&new_bp[i].v),
&new_bp[i].k_i));
}

*handled = true;
return 0;
}

int bch2_trigger_extent(struct btree_trans *trans,
enum btree_id btree, unsigned level,
struct bkey_s_c old, struct bkey_s new,
Expand All @@ -891,7 +962,15 @@ int bch2_trigger_extent(struct btree_trans *trans,
if (unlikely(flags & BTREE_TRIGGER_check_repair))
return bch2_check_fix_ptrs(trans, btree, level, new.s_c, flags);

/* if pointers aren't changing - nothing to do: */
/* optimization for in-place updates to reconcile_phys to avoid delete-insert churn */
if (level == 0) {
bool handled;

try(bch2_trigger_extent_reconcile_phys_update(trans, btree, old, new, &handled));
if (handled)
return bch2_trigger_extent_reconcile(trans, btree, level, old, new, flags);
}

if (new_ptrs_bytes == old_ptrs_bytes &&
!memcmp(new_ptrs.start,
old_ptrs.start,
Expand Down Expand Up @@ -1224,29 +1303,6 @@ int __bch2_disk_reservation_add(struct bch_fs *c, struct disk_reservation *res,

/* Startup/shutdown: */

void bch2_buckets_nouse_free(struct bch_fs *c)
{
for_each_member_device(c, ca) {
kvfree_rcu_mightsleep(ca->buckets_nouse);
ca->buckets_nouse = NULL;
}
}

int bch2_buckets_nouse_alloc(struct bch_fs *c)
{
for_each_member_device(c, ca) {
BUG_ON(ca->buckets_nouse);

ca->buckets_nouse = bch2_kvmalloc(BITS_TO_LONGS(ca->mi.nbuckets) *
sizeof(unsigned long),
GFP_KERNEL|__GFP_ZERO);
if (!ca->buckets_nouse)
return bch_err_throw(c, ENOMEM_buckets_nouse);
}

return 0;
}

static void bucket_gens_free_rcu(struct rcu_head *rcu)
{
struct bucket_gens *buckets =
Expand All @@ -1264,9 +1320,6 @@ int bch2_dev_buckets_resize(struct bch_fs *c, struct bch_dev *ca, u64 nbuckets)
if (resize)
lockdep_assert_held(&c->state_lock);

if (resize && ca->buckets_nouse)
return bch_err_throw(c, no_resize_with_buckets_nouse);

bucket_gens = bch2_kvmalloc(struct_size(bucket_gens, b, nbuckets),
GFP_KERNEL|__GFP_ZERO);
if (!bucket_gens)
Expand Down Expand Up @@ -1299,7 +1352,6 @@ int bch2_dev_buckets_resize(struct bch_fs *c, struct bch_dev *ca, u64 nbuckets)

void bch2_dev_buckets_free(struct bch_dev *ca)
{
kvfree(ca->buckets_nouse);
kvfree(rcu_dereference_protected(ca->bucket_gens, 1));
free_percpu(ca->usage);
}
Expand Down
Loading