Skip to content

Commit 857d18f

Browse files
Peter Zijlstradavejiang
authored andcommitted
cleanup: Introduce ACQUIRE() and ACQUIRE_ERR() for conditional locks
scoped_cond_guard(), automatic cleanup for conditional locks, has a couple pain points: * It causes existing straight-line code to be re-indented into a new bracketed scope. While this can be mitigated by a new helper function to contain the scope, that is not always a comfortable conversion. * The return code from the conditional lock is tossed in favor of a scheme to pass a 'return err;' statement to the macro. Other attempts to clean this up, to behave more like guard() [1], got hung up trying to both establish and evaluate the conditional lock in one statement. ACQUIRE() solves this by reflecting the result of the condition in the automatic variable established by the lock CLASS(). The result is separately retrieved with the ACQUIRE_ERR() helper, effectively a PTR_ERR() operation. Link: http://lore.kernel.org/all/[email protected] [1] Link: http://patch.msgid.link/[email protected] Link: http://patch.msgid.link/[email protected] Cc: Ingo Molnar <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: David Lechner <[email protected]> Cc: Fabio M. De Francesco <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> [djbw: wrap Peter's proposal with changelog and comments] Co-developed-by: Dan Williams <[email protected]> Signed-off-by: Dan Williams <[email protected]> Reviewed-by: Jonathan Cameron <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Dave Jiang <[email protected]>
1 parent d0b3b7b commit 857d18f

File tree

3 files changed

+83
-16
lines changed

3 files changed

+83
-16
lines changed

include/linux/cleanup.h

Lines changed: 81 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#define _LINUX_CLEANUP_H
44

55
#include <linux/compiler.h>
6+
#include <linux/err.h>
7+
#include <linux/args.h>
68

79
/**
810
* DOC: scope-based cleanup helpers
@@ -61,9 +63,21 @@
6163
* Observe the lock is held for the remainder of the "if ()" block not
6264
* the remainder of "func()".
6365
*
64-
* Now, when a function uses both __free() and guard(), or multiple
65-
* instances of __free(), the LIFO order of variable definition order
66-
* matters. GCC documentation says:
66+
* The ACQUIRE() macro can be used in all places that guard() can be
67+
* used and additionally support conditional locks
68+
*
69+
*
70+
* DEFINE_GUARD_COND(pci_dev, _try, pci_dev_trylock(_T))
71+
* ...
72+
* ACQUIRE(pci_dev_try, lock)(dev);
73+
* rc = ACQUIRE_ERR(pci_dev_try, &lock);
74+
* if (rc)
75+
* return rc;
76+
* // @lock is held
77+
*
78+
* Now, when a function uses both __free() and guard()/ACQUIRE(), or
79+
* multiple instances of __free(), the LIFO order of variable definition
80+
* order matters. GCC documentation says:
6781
*
6882
* "When multiple variables in the same scope have cleanup attributes,
6983
* at exit from the scope their associated cleanup functions are run in
@@ -305,14 +319,46 @@ static inline class_##_name##_t class_##_name##ext##_constructor(_init_args) \
305319
* acquire fails.
306320
*
307321
* Only for conditional locks.
322+
*
323+
* ACQUIRE(name, var):
324+
* a named instance of the (guard) class, suitable for conditional
325+
* locks when paired with ACQUIRE_ERR().
326+
*
327+
* ACQUIRE_ERR(name, &var):
328+
* a helper that is effectively a PTR_ERR() conversion of the guard
329+
* pointer. Returns 0 when the lock was acquired and a negative
330+
* error code otherwise.
308331
*/
309332

310333
#define __DEFINE_CLASS_IS_CONDITIONAL(_name, _is_cond) \
311334
static __maybe_unused const bool class_##_name##_is_conditional = _is_cond
312335

313-
#define __DEFINE_GUARD_LOCK_PTR(_name, _exp) \
314-
static inline void * class_##_name##_lock_ptr(class_##_name##_t *_T) \
315-
{ return (void *)(__force unsigned long)*(_exp); }
336+
#define __GUARD_IS_ERR(_ptr) \
337+
({ \
338+
unsigned long _rc = (__force unsigned long)(_ptr); \
339+
unlikely((_rc - 1) >= -MAX_ERRNO - 1); \
340+
})
341+
342+
#define __DEFINE_GUARD_LOCK_PTR(_name, _exp) \
343+
static inline void *class_##_name##_lock_ptr(class_##_name##_t *_T) \
344+
{ \
345+
void *_ptr = (void *)(__force unsigned long)*(_exp); \
346+
if (IS_ERR(_ptr)) { \
347+
_ptr = NULL; \
348+
} \
349+
return _ptr; \
350+
} \
351+
static inline int class_##_name##_lock_err(class_##_name##_t *_T) \
352+
{ \
353+
long _rc = (__force unsigned long)*(_exp); \
354+
if (!_rc) { \
355+
_rc = -EBUSY; \
356+
} \
357+
if (!IS_ERR_VALUE(_rc)) { \
358+
_rc = 0; \
359+
} \
360+
return _rc; \
361+
}
316362

317363
#define DEFINE_CLASS_IS_GUARD(_name) \
318364
__DEFINE_CLASS_IS_CONDITIONAL(_name, false); \
@@ -323,23 +369,37 @@ static __maybe_unused const bool class_##_name##_is_conditional = _is_cond
323369
__DEFINE_GUARD_LOCK_PTR(_name, _T)
324370

325371
#define DEFINE_GUARD(_name, _type, _lock, _unlock) \
326-
DEFINE_CLASS(_name, _type, if (_T) { _unlock; }, ({ _lock; _T; }), _type _T); \
372+
DEFINE_CLASS(_name, _type, if (!__GUARD_IS_ERR(_T)) { _unlock; }, ({ _lock; _T; }), _type _T); \
327373
DEFINE_CLASS_IS_GUARD(_name)
328374

329-
#define DEFINE_GUARD_COND(_name, _ext, _condlock) \
375+
#define DEFINE_GUARD_COND_4(_name, _ext, _lock, _cond) \
330376
__DEFINE_CLASS_IS_CONDITIONAL(_name##_ext, true); \
331377
EXTEND_CLASS(_name, _ext, \
332-
({ void *_t = _T; if (_T && !(_condlock)) _t = NULL; _t; }), \
378+
({ void *_t = _T; int _RET = (_lock); if (_T && !(_cond)) _t = ERR_PTR(_RET); _t; }), \
333379
class_##_name##_t _T) \
334380
static inline void * class_##_name##_ext##_lock_ptr(class_##_name##_t *_T) \
335-
{ return class_##_name##_lock_ptr(_T); }
381+
{ return class_##_name##_lock_ptr(_T); } \
382+
static inline int class_##_name##_ext##_lock_err(class_##_name##_t *_T) \
383+
{ return class_##_name##_lock_err(_T); }
384+
385+
/*
386+
* Default binary condition; success on 'true'.
387+
*/
388+
#define DEFINE_GUARD_COND_3(_name, _ext, _lock) \
389+
DEFINE_GUARD_COND_4(_name, _ext, _lock, _RET)
390+
391+
#define DEFINE_GUARD_COND(X...) CONCATENATE(DEFINE_GUARD_COND_, COUNT_ARGS(X))(X)
336392

337393
#define guard(_name) \
338394
CLASS(_name, __UNIQUE_ID(guard))
339395

340396
#define __guard_ptr(_name) class_##_name##_lock_ptr
397+
#define __guard_err(_name) class_##_name##_lock_err
341398
#define __is_cond_ptr(_name) class_##_name##_is_conditional
342399

400+
#define ACQUIRE(_name, _var) CLASS(_name, _var)
401+
#define ACQUIRE_ERR(_name, _var) __guard_err(_name)(_var)
402+
343403
/*
344404
* Helper macro for scoped_guard().
345405
*
@@ -401,7 +461,7 @@ typedef struct { \
401461
\
402462
static inline void class_##_name##_destructor(class_##_name##_t *_T) \
403463
{ \
404-
if (_T->lock) { _unlock; } \
464+
if (!__GUARD_IS_ERR(_T->lock)) { _unlock; } \
405465
} \
406466
\
407467
__DEFINE_GUARD_LOCK_PTR(_name, &_T->lock)
@@ -433,15 +493,22 @@ __DEFINE_CLASS_IS_CONDITIONAL(_name, false); \
433493
__DEFINE_UNLOCK_GUARD(_name, void, _unlock, __VA_ARGS__) \
434494
__DEFINE_LOCK_GUARD_0(_name, _lock)
435495

436-
#define DEFINE_LOCK_GUARD_1_COND(_name, _ext, _condlock) \
496+
#define DEFINE_LOCK_GUARD_1_COND_4(_name, _ext, _lock, _cond) \
437497
__DEFINE_CLASS_IS_CONDITIONAL(_name##_ext, true); \
438498
EXTEND_CLASS(_name, _ext, \
439499
({ class_##_name##_t _t = { .lock = l }, *_T = &_t;\
440-
if (_T->lock && !(_condlock)) _T->lock = NULL; \
500+
int _RET = (_lock); \
501+
if (_T->lock && !(_cond)) _T->lock = ERR_PTR(_RET);\
441502
_t; }), \
442503
typeof_member(class_##_name##_t, lock) l) \
443504
static inline void * class_##_name##_ext##_lock_ptr(class_##_name##_t *_T) \
444-
{ return class_##_name##_lock_ptr(_T); }
505+
{ return class_##_name##_lock_ptr(_T); } \
506+
static inline int class_##_name##_ext##_lock_err(class_##_name##_t *_T) \
507+
{ return class_##_name##_lock_err(_T); }
508+
509+
#define DEFINE_LOCK_GUARD_1_COND_3(_name, _ext, _lock) \
510+
DEFINE_LOCK_GUARD_1_COND_4(_name, _ext, _lock, _RET)
445511

512+
#define DEFINE_LOCK_GUARD_1_COND(X...) CONCATENATE(DEFINE_LOCK_GUARD_1_COND_, COUNT_ARGS(X))(X)
446513

447514
#endif /* _LINUX_CLEANUP_H */

include/linux/mutex.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ extern int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock);
224224

225225
DEFINE_GUARD(mutex, struct mutex *, mutex_lock(_T), mutex_unlock(_T))
226226
DEFINE_GUARD_COND(mutex, _try, mutex_trylock(_T))
227-
DEFINE_GUARD_COND(mutex, _intr, mutex_lock_interruptible(_T) == 0)
227+
DEFINE_GUARD_COND(mutex, _intr, mutex_lock_interruptible(_T), _RET == 0)
228228

229229
extern unsigned long mutex_get_owner(struct mutex *lock);
230230

include/linux/rwsem.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ extern void up_write(struct rw_semaphore *sem);
240240

241241
DEFINE_GUARD(rwsem_read, struct rw_semaphore *, down_read(_T), up_read(_T))
242242
DEFINE_GUARD_COND(rwsem_read, _try, down_read_trylock(_T))
243-
DEFINE_GUARD_COND(rwsem_read, _intr, down_read_interruptible(_T) == 0)
243+
DEFINE_GUARD_COND(rwsem_read, _intr, down_read_interruptible(_T), _RET == 0)
244244

245245
DEFINE_GUARD(rwsem_write, struct rw_semaphore *, down_write(_T), up_write(_T))
246246
DEFINE_GUARD_COND(rwsem_write, _try, down_write_trylock(_T))

0 commit comments

Comments
 (0)