bcachefs-tools/libbcachefs/enumerated_ref.c
Kent Overstreet 8471005b9f
Some checks failed
build / bcachefs-tools-deb (ubuntu-22.04) (push) Has been cancelled
build / bcachefs-tools-deb (ubuntu-24.04) (push) Has been cancelled
build / bcachefs-tools-rpm (push) Has been cancelled
build / bcachefs-tools-msrv (push) Has been cancelled
Nix Flake actions / nix-matrix (push) Has been cancelled
Nix Flake actions / ${{ matrix.name }} (${{ matrix.system }}) (push) Has been cancelled
Update bcachefs sources to deeffbdc52f1 bcachefs: better device too small error message
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
2025-07-15 18:41:03 -04:00

143 lines
3.1 KiB
C

// SPDX-License-Identifier: GPL-2.0
#include "bcachefs.h"
#include "enumerated_ref.h"
#include "util.h"
#include <linux/completion.h>
#ifdef ENUMERATED_REF_DEBUG
void enumerated_ref_get(struct enumerated_ref *ref, unsigned idx)
{
BUG_ON(idx >= ref->nr);
atomic_long_inc(&ref->refs[idx]);
}
bool __enumerated_ref_tryget(struct enumerated_ref *ref, unsigned idx)
{
BUG_ON(idx >= ref->nr);
return atomic_long_inc_not_zero(&ref->refs[idx]);
}
bool enumerated_ref_tryget(struct enumerated_ref *ref, unsigned idx)
{
BUG_ON(idx >= ref->nr);
return !ref->dying &&
atomic_long_inc_not_zero(&ref->refs[idx]);
}
void enumerated_ref_put(struct enumerated_ref *ref, unsigned idx)
{
BUG_ON(idx >= ref->nr);
long v = atomic_long_dec_return(&ref->refs[idx]);
BUG_ON(v < 0);
if (v)
return;
for (unsigned i = 0; i < ref->nr; i++)
if (atomic_long_read(&ref->refs[i]))
return;
if (ref->stop_fn)
ref->stop_fn(ref);
complete(&ref->stop_complete);
}
#endif
#ifndef ENUMERATED_REF_DEBUG
static void enumerated_ref_kill_cb(struct percpu_ref *percpu_ref)
{
struct enumerated_ref *ref =
container_of(percpu_ref, struct enumerated_ref, ref);
if (ref->stop_fn)
ref->stop_fn(ref);
complete(&ref->stop_complete);
}
#endif
void enumerated_ref_stop_async(struct enumerated_ref *ref)
{
reinit_completion(&ref->stop_complete);
#ifndef ENUMERATED_REF_DEBUG
percpu_ref_kill(&ref->ref);
#else
ref->dying = true;
for (unsigned i = 0; i < ref->nr; i++)
enumerated_ref_put(ref, i);
#endif
}
void enumerated_ref_stop(struct enumerated_ref *ref,
const char * const names[])
{
enumerated_ref_stop_async(ref);
while (!wait_for_completion_timeout(&ref->stop_complete, HZ * 10)) {
CLASS(printbuf, buf)();
prt_str(&buf, "Waited for 10 seconds to shutdown enumerated ref\n");
prt_str(&buf, "Outstanding refs:\n");
enumerated_ref_to_text(&buf, ref, names);
printk(KERN_ERR "%s", buf.buf);
}
}
void enumerated_ref_start(struct enumerated_ref *ref)
{
#ifndef ENUMERATED_REF_DEBUG
percpu_ref_reinit(&ref->ref);
#else
ref->dying = false;
for (unsigned i = 0; i < ref->nr; i++) {
BUG_ON(atomic_long_read(&ref->refs[i]));
atomic_long_inc(&ref->refs[i]);
}
#endif
}
void enumerated_ref_exit(struct enumerated_ref *ref)
{
#ifndef ENUMERATED_REF_DEBUG
percpu_ref_exit(&ref->ref);
#else
kfree(ref->refs);
ref->refs = NULL;
ref->nr = 0;
#endif
}
int enumerated_ref_init(struct enumerated_ref *ref, unsigned nr,
void (*stop_fn)(struct enumerated_ref *))
{
init_completion(&ref->stop_complete);
ref->stop_fn = stop_fn;
#ifndef ENUMERATED_REF_DEBUG
return percpu_ref_init(&ref->ref, enumerated_ref_kill_cb,
PERCPU_REF_INIT_DEAD, GFP_KERNEL);
#else
ref->refs = kzalloc(sizeof(ref->refs[0]) * nr, GFP_KERNEL);
if (!ref->refs)
return -ENOMEM;
ref->nr = nr;
return 0;
#endif
}
void enumerated_ref_to_text(struct printbuf *out,
struct enumerated_ref *ref,
const char * const names[])
{
#ifdef ENUMERATED_REF_DEBUG
bch2_printbuf_tabstop_push(out, 32);
for (unsigned i = 0; i < ref->nr; i++)
prt_printf(out, "%s\t%li\n", names[i],
atomic_long_read(&ref->refs[i]));
#else
prt_str(out, "(not in debug mode)\n");
#endif
}