linux/fs/bcachefs/enumerated_ref.h
Kent Overstreet f5241e4127 bcachefs: enumerated_ref.c
Factor out the debug code for rw filesystem refs into a small library.

In release mode an enumerated ref is a normal percpu refcount, but in
debug mode all enumerated users of the ref get their own atomic_long_t
ref - making it much easier to chase down refcount usage bugs for when a
refcount has many users.

For debugging, we have enumerated_ref_to_text(), which prints the
current value of each different user.

Additionally, in debug mode enumerated_ref_stop() has a 10 second
timeout, after which it will dump outstanding refcounts.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
2025-05-21 20:14:27 -04:00

66 lines
1.8 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _BCACHEFS_ENUMERATED_REF_H
#define _BCACHEFS_ENUMERATED_REF_H
#include "enumerated_ref_types.h"
/*
* A refcount where the users are enumerated: in debug mode, we create sepate
* refcounts for each user, to make leaks and refcount errors easy to track
* down:
*/
#ifdef ENUMERATED_REF_DEBUG
void enumerated_ref_get(struct enumerated_ref *, unsigned);
bool __enumerated_ref_tryget(struct enumerated_ref *, unsigned);
bool enumerated_ref_tryget(struct enumerated_ref *, unsigned);
void enumerated_ref_put(struct enumerated_ref *, unsigned);
#else
static inline void enumerated_ref_get(struct enumerated_ref *ref, unsigned idx)
{
percpu_ref_get(&ref->ref);
}
static inline bool __enumerated_ref_tryget(struct enumerated_ref *ref, unsigned idx)
{
return percpu_ref_tryget(&ref->ref);
}
static inline bool enumerated_ref_tryget(struct enumerated_ref *ref, unsigned idx)
{
return percpu_ref_tryget_live(&ref->ref);
}
static inline void enumerated_ref_put(struct enumerated_ref *ref, unsigned idx)
{
percpu_ref_put(&ref->ref);
}
#endif
static inline bool enumerated_ref_is_zero(struct enumerated_ref *ref)
{
#ifndef ENUMERATED_REF_DEBUG
return percpu_ref_is_zero(&ref->ref);
#else
for (unsigned i = 0; i < ref->nr; i++)
if (atomic_long_read(&ref->refs[i]))
return false;
return true;
#endif
}
void enumerated_ref_stop_async(struct enumerated_ref *);
void enumerated_ref_stop(struct enumerated_ref *, const char * const[]);
void enumerated_ref_start(struct enumerated_ref *);
void enumerated_ref_exit(struct enumerated_ref *);
int enumerated_ref_init(struct enumerated_ref *, unsigned,
void (*stop_fn)(struct enumerated_ref *));
struct printbuf;
void enumerated_ref_to_text(struct printbuf *,
struct enumerated_ref *,
const char * const[]);
#endif /* _BCACHEFS_ENUMERATED_REF_H */