Date: Tue, 10 Feb 2026 00:46:46 +0000 From: Bjoern A. Zeeb <bz@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: 31393810a168 - main - LinuxKPI: add scoped_guard(), spinlock guard support Message-ID: <698a7ff6.314a9.1c8ee0da@gitrepo.freebsd.org>
index | next in thread | raw e-mail
The branch main has been updated by bz: URL: https://cgit.FreeBSD.org/src/commit/?id=31393810a168b74cf13ace0e1d35dae6b4a12bf5 commit 31393810a168b74cf13ace0e1d35dae6b4a12bf5 Author: Bjoern A. Zeeb <bz@FreeBSD.org> AuthorDate: 2026-01-20 22:54:30 +0000 Commit: Bjoern A. Zeeb <bz@FreeBSD.org> CommitDate: 2026-02-09 21:49:45 +0000 LinuxKPI: add scoped_guard(), spinlock guard support The "cleanup.h" implementation got a bit more complicated. For one we now use a macro to concatenate a prefix, the name, and a suffix for variable and function declarations. This was triggered by the fact that the "guard_" prefix we used was confusing. We now use a generic "cleanup_" which is only encoded in the single place rather than all over the file. As already indicated by the comment the DEFINE_LOCK_GUARD_0() macro got split up and a _1 version which also takes a type got implemented and is used for a spinlock variant used by rtw89(4) via the new scoped_guard() bits. Sponsored by: The FreeBSD Foundation MFC after: 3 days Differential Revision: https://reviews.freebsd.org/D54808 --- sys/compat/linuxkpi/common/include/linux/cleanup.h | 127 ++++++++++++++++----- .../linuxkpi/common/include/linux/spinlock.h | 10 ++ 2 files changed, 109 insertions(+), 28 deletions(-) diff --git a/sys/compat/linuxkpi/common/include/linux/cleanup.h b/sys/compat/linuxkpi/common/include/linux/cleanup.h index 5bb146f082ed..fb21a81f121b 100644 --- a/sys/compat/linuxkpi/common/include/linux/cleanup.h +++ b/sys/compat/linuxkpi/common/include/linux/cleanup.h @@ -1,7 +1,7 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (c) 2024-2025 The FreeBSD Foundation + * Copyright (c) 2024-2026 The FreeBSD Foundation * * This software was developed by Björn Zeeb under sponsorship from * the FreeBSD Foundation. @@ -10,18 +10,26 @@ #ifndef _LINUXKPI_LINUX_CLEANUP_H #define _LINUXKPI_LINUX_CLEANUP_H +#include <linux/err.h> + +#define CLEANUP_NAME(_n, _s) __CONCAT(__CONCAT(cleanup_, _n), _s) + #define __cleanup(_f) __attribute__((__cleanup__(_f))) +#define DECLARE(_n, _x) \ + CLEANUP_NAME(_n, _t) _x __cleanup(CLEANUP_NAME(_n, _destroy)) = \ + CLEANUP_NAME(_n, _create) + /* * Note: "_T" are special as they are exposed into common code for * statements. Extra care should be taken when changing the code. */ #define DEFINE_GUARD(_n, _dt, _lock, _unlock) \ \ - typedef _dt guard_ ## _n ## _t; \ + typedef _dt CLEANUP_NAME(_n, _t); \ \ static inline _dt \ - guard_ ## _n ## _create( _dt _T) \ + CLEANUP_NAME(_n, _create)( _dt _T) \ { \ _dt c; \ \ @@ -30,7 +38,7 @@ } \ \ static inline void \ - guard_ ## _n ## _destroy(_dt *t) \ + CLEANUP_NAME(_n, _destroy)(_dt *t) \ { \ _dt _T; \ \ @@ -39,9 +47,10 @@ } /* We need to keep these calls unique. */ +#define _guard(_n, _x) \ + DECLARE(_n, _x) #define guard(_n) \ - guard_ ## _n ## _t guard_ ## _n ## _ ## __COUNTER__ \ - __cleanup(guard_ ## _n ## _destroy) = guard_ ## _n ## _create + _guard(_n, guard_ ## _n ## _ ## __COUNTER__) #define DEFINE_FREE(_n, _t, _f) \ static inline void \ @@ -56,38 +65,100 @@ #define __free(_n) __cleanup(__free_##_n) /* - * Given this is a _0 version it should likely be broken up into parts. - * But we have no idead what a _1, _2, ... version would do different - * until we see a call. - * This is used for a not-real-type (rcu). We use a bool to "simulate" - * the lock held. Also _T still special, may not always be used, so tag - * with __unused (or better the LinuxKPI __maybe_unused). + * Our initial version go broken up. Some simplifications like using + * "bool" for the lock had to be changed to a more general type. + * _T is still special and, like other bits, may not always be used, + * so tag with __unused (or better the LinuxKPI __maybe_unused). */ -#define DEFINE_LOCK_GUARD_0(_n, _lock, _unlock, ...) \ +#define _DEFINE_LOCK_GUARD_0(_n, _lock) \ + static inline CLEANUP_NAME(_n, _t) \ + CLEANUP_NAME(_n, _create)(void) \ + { \ + CLEANUP_NAME(_n, _t) _tmp; \ + CLEANUP_NAME(_n, _t) *_T __maybe_unused; \ + \ + _tmp.lock = (void *)1; \ + _T = &_tmp; \ + _lock; \ + return (_tmp); \ + } + +#define _DEFINE_LOCK_GUARD_1(_n, _type, _lock) \ + static inline CLEANUP_NAME(_n, _t) \ + CLEANUP_NAME(_n, _create)(_type *l) \ + { \ + CLEANUP_NAME(_n, _t) _tmp; \ + CLEANUP_NAME(_n, _t) *_T __maybe_unused; \ \ + _tmp.lock = l; \ + _T = &_tmp; \ + _lock; \ + return (_tmp); \ + } + +#define _GUARD_IS_ERR(_v) \ + ({ \ + uintptr_t x = (uintptr_t)(void *)(_v); \ + IS_ERR_VALUE(x); \ + }) + +#define __is_cond_ptr(_n) \ + CLEANUP_NAME(_n, _is_cond) +#define __guard_ptr(_n) \ + CLEANUP_NAME(_n, _ptr) + +#define _DEFINE_CLEANUP_IS_CONDITIONAL(_n, _b) \ + static const bool CLEANUP_NAME(_n, _is_cond) __maybe_unused = _b + +#define _DEFINE_GUARD_LOCK_PTR(_n, _lp) \ + static inline void * \ + CLEANUP_NAME(_n, _lock_ptr)(CLEANUP_NAME(_n, _t) *_T) \ + { \ + void *_p; \ + \ + _p = (void *)(uintptr_t)*(_lp); \ + if (IS_ERR(_p)) \ + _p = NULL; \ + return (_p); \ + } + +#define _DEFINE_UNLOCK_GUARD(_n, _type, _unlock, ...) \ typedef struct { \ - bool lock; \ + _type *lock; \ __VA_ARGS__; \ - } guard_ ## _n ## _t; \ + } CLEANUP_NAME(_n, _t); \ \ static inline void \ - guard_ ## _n ## _destroy(guard_ ## _n ## _t *_T) \ + CLEANUP_NAME(_n, _destroy)(CLEANUP_NAME(_n, _t) *_T) \ { \ - if (_T->lock) { \ + if (!_GUARD_IS_ERR(_T->lock)) { \ _unlock; \ } \ } \ \ - static inline guard_ ## _n ## _t \ - guard_ ## _n ## _create(void) \ - { \ - guard_ ## _n ## _t _tmp; \ - guard_ ## _n ## _t *_T __maybe_unused; \ - \ - _tmp.lock = true; \ - _T = &_tmp; \ - _lock; \ - return (_tmp); \ - } + _DEFINE_GUARD_LOCK_PTR(_n, &_T->lock) + +#define DEFINE_LOCK_GUARD_0(_n, _lock, _unlock, ...) \ + _DEFINE_CLEANUP_IS_CONDITIONAL(_n, false); \ + _DEFINE_UNLOCK_GUARD(_n, void, _unlock, __VA_ARGS__) \ + _DEFINE_LOCK_GUARD_0(_n, _lock) + +/* This allows the type to be set. */ +#define DEFINE_LOCK_GUARD_1(_n, _t, _lock, _unlock, ...) \ + _DEFINE_CLEANUP_IS_CONDITIONAL(_n, false); \ + _DEFINE_UNLOCK_GUARD(_n, _t, _unlock, __VA_ARGS__) \ + _DEFINE_LOCK_GUARD_1(_n, _t, _lock) + +#define _scoped_guard(_n, _l, ...) \ + for (DECLARE(_n, _scoped)(__VA_ARGS__); \ + 1 /*__guard_ptr(_n)(&_scoped) || !__is_cond_ptr(_n) */; \ + ({ goto _l; })) \ + if (0) { \ +_l: \ + break; \ + } else + +#define scoped_guard(_n, ...) \ + _scoped_guard(_n, ___label_ ## __COUNTER__, ##__VA_ARGS__) #endif /* _LINUXKPI_LINUX_CLEANUP_H */ diff --git a/sys/compat/linuxkpi/common/include/linux/spinlock.h b/sys/compat/linuxkpi/common/include/linux/spinlock.h index 341e89b6feed..63dc343d1461 100644 --- a/sys/compat/linuxkpi/common/include/linux/spinlock.h +++ b/sys/compat/linuxkpi/common/include/linux/spinlock.h @@ -36,6 +36,7 @@ #include <sys/mutex.h> #include <sys/kdb.h> +#include <linux/cleanup.h> #include <linux/compiler.h> #include <linux/rwlock.h> #include <linux/bottom_half.h> @@ -198,4 +199,13 @@ typedef struct raw_spinlock { #define raw_spin_trylock_irqsave(rl, f) spin_trylock_irqsave(&(rl)->lock, (f)) #define raw_spin_unlock_irqrestore(rl, f) spin_unlock_irqrestore(&(rl)->lock, (f)) +/* + * cleanup.h related pre-defined cases. + */ +DEFINE_LOCK_GUARD_1(spinlock_irqsave, + spinlock_t, + spin_lock_irqsave(_T->lock, _T->flags), + spin_unlock_irqrestore(_T->lock, _T->flags), + unsigned long flags) + #endif /* _LINUXKPI_LINUX_SPINLOCK_H_ */home | help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?698a7ff6.314a9.1c8ee0da>
