Skip to content

Commit 04f2933

Browse files
committed
Merge tag 'core_guards_for_6.5_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/peterz/queue
Pull scope-based resource management infrastructure from Peter Zijlstra: "These are the first few patches in the Scope-based Resource Management series that introduce the infrastructure but not any conversions as of yet. Adding the infrastructure now allows multiple people to start using them. Of note is that Sparse will need some work since it doesn't yet understand this attribute and might have decl-after-stmt issues" * tag 'core_guards_for_6.5_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/peterz/queue: kbuild: Drop -Wdeclaration-after-statement locking: Introduce __cleanup() based infrastructure apparmor: Free up __cleanup() name dmaengine: ioat: Free up __cleanup() name
2 parents 0327558 + b5ec6fd commit 04f2933

File tree

20 files changed

+282
-17
lines changed

20 files changed

+282
-17
lines changed

Makefile

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -449,8 +449,7 @@ HOSTRUSTC = rustc
449449
HOSTPKG_CONFIG = pkg-config
450450

451451
KBUILD_USERHOSTCFLAGS := -Wall -Wmissing-prototypes -Wstrict-prototypes \
452-
-O2 -fomit-frame-pointer -std=gnu11 \
453-
-Wdeclaration-after-statement
452+
-O2 -fomit-frame-pointer -std=gnu11
454453
KBUILD_USERCFLAGS := $(KBUILD_USERHOSTCFLAGS) $(USERCFLAGS)
455454
KBUILD_USERLDFLAGS := $(USERLDFLAGS)
456455

@@ -1014,9 +1013,6 @@ endif
10141013
# arch Makefile may override CC so keep this after arch Makefile is included
10151014
NOSTDINC_FLAGS += -nostdinc
10161015

1017-
# warn about C99 declaration after statement
1018-
KBUILD_CFLAGS += -Wdeclaration-after-statement
1019-
10201016
# Variable Length Arrays (VLAs) should not be used anywhere in the kernel
10211017
KBUILD_CFLAGS += -Wvla
10221018

arch/arm64/kernel/vdso32/Makefile

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,9 @@ VDSO_CFLAGS += -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
6565
-fno-strict-aliasing -fno-common \
6666
-Werror-implicit-function-declaration \
6767
-Wno-format-security \
68-
-Wdeclaration-after-statement \
6968
-std=gnu11
7069
VDSO_CFLAGS += -O2
7170
# Some useful compiler-dependent flags from top-level Makefile
72-
VDSO_CFLAGS += $(call cc32-option,-Wdeclaration-after-statement,)
7371
VDSO_CFLAGS += $(call cc32-option,-Wno-pointer-sign)
7472
VDSO_CFLAGS += -fno-strict-overflow
7573
VDSO_CFLAGS += $(call cc32-option,-Werror=strict-prototypes)

drivers/dma/ioat/dma.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -584,11 +584,11 @@ desc_get_errstat(struct ioatdma_chan *ioat_chan, struct ioat_ring_ent *desc)
584584
}
585585

586586
/**
587-
* __cleanup - reclaim used descriptors
587+
* __ioat_cleanup - reclaim used descriptors
588588
* @ioat_chan: channel (ring) to clean
589589
* @phys_complete: zeroed (or not) completion address (from status)
590590
*/
591-
static void __cleanup(struct ioatdma_chan *ioat_chan, dma_addr_t phys_complete)
591+
static void __ioat_cleanup(struct ioatdma_chan *ioat_chan, dma_addr_t phys_complete)
592592
{
593593
struct ioatdma_device *ioat_dma = ioat_chan->ioat_dma;
594594
struct ioat_ring_ent *desc;
@@ -675,7 +675,7 @@ static void ioat_cleanup(struct ioatdma_chan *ioat_chan)
675675
spin_lock_bh(&ioat_chan->cleanup_lock);
676676

677677
if (ioat_cleanup_preamble(ioat_chan, &phys_complete))
678-
__cleanup(ioat_chan, phys_complete);
678+
__ioat_cleanup(ioat_chan, phys_complete);
679679

680680
if (is_ioat_halted(*ioat_chan->completion)) {
681681
u32 chanerr = readl(ioat_chan->reg_base + IOAT_CHANERR_OFFSET);
@@ -712,7 +712,7 @@ static void ioat_restart_channel(struct ioatdma_chan *ioat_chan)
712712

713713
ioat_quiesce(ioat_chan, 0);
714714
if (ioat_cleanup_preamble(ioat_chan, &phys_complete))
715-
__cleanup(ioat_chan, phys_complete);
715+
__ioat_cleanup(ioat_chan, phys_complete);
716716

717717
__ioat_restart_chan(ioat_chan);
718718
}
@@ -786,7 +786,7 @@ static void ioat_eh(struct ioatdma_chan *ioat_chan)
786786

787787
/* cleanup so tail points to descriptor that caused the error */
788788
if (ioat_cleanup_preamble(ioat_chan, &phys_complete))
789-
__cleanup(ioat_chan, phys_complete);
789+
__ioat_cleanup(ioat_chan, phys_complete);
790790

791791
chanerr = readl(ioat_chan->reg_base + IOAT_CHANERR_OFFSET);
792792
pci_read_config_dword(pdev, IOAT_PCI_CHANERR_INT_OFFSET, &chanerr_int);
@@ -943,7 +943,7 @@ void ioat_timer_event(struct timer_list *t)
943943
/* timer restarted in ioat_cleanup_preamble
944944
* and IOAT_COMPLETION_ACK cleared
945945
*/
946-
__cleanup(ioat_chan, phys_complete);
946+
__ioat_cleanup(ioat_chan, phys_complete);
947947
goto unlock_out;
948948
}
949949

include/linux/cleanup.h

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
#ifndef __LINUX_GUARDS_H
3+
#define __LINUX_GUARDS_H
4+
5+
#include <linux/compiler.h>
6+
7+
/*
8+
* DEFINE_FREE(name, type, free):
9+
* simple helper macro that defines the required wrapper for a __free()
10+
* based cleanup function. @free is an expression using '_T' to access
11+
* the variable.
12+
*
13+
* __free(name):
14+
* variable attribute to add a scoped based cleanup to the variable.
15+
*
16+
* no_free_ptr(var):
17+
* like a non-atomic xchg(var, NULL), such that the cleanup function will
18+
* be inhibited -- provided it sanely deals with a NULL value.
19+
*
20+
* return_ptr(p):
21+
* returns p while inhibiting the __free().
22+
*
23+
* Ex.
24+
*
25+
* DEFINE_FREE(kfree, void *, if (_T) kfree(_T))
26+
*
27+
* struct obj *p __free(kfree) = kmalloc(...);
28+
* if (!p)
29+
* return NULL;
30+
*
31+
* if (!init_obj(p))
32+
* return NULL;
33+
*
34+
* return_ptr(p);
35+
*/
36+
37+
#define DEFINE_FREE(_name, _type, _free) \
38+
static inline void __free_##_name(void *p) { _type _T = *(_type *)p; _free; }
39+
40+
#define __free(_name) __cleanup(__free_##_name)
41+
42+
#define no_free_ptr(p) \
43+
({ __auto_type __ptr = (p); (p) = NULL; __ptr; })
44+
45+
#define return_ptr(p) return no_free_ptr(p)
46+
47+
48+
/*
49+
* DEFINE_CLASS(name, type, exit, init, init_args...):
50+
* helper to define the destructor and constructor for a type.
51+
* @exit is an expression using '_T' -- similar to FREE above.
52+
* @init is an expression in @init_args resulting in @type
53+
*
54+
* EXTEND_CLASS(name, ext, init, init_args...):
55+
* extends class @name to @name@ext with the new constructor
56+
*
57+
* CLASS(name, var)(args...):
58+
* declare the variable @var as an instance of the named class
59+
*
60+
* Ex.
61+
*
62+
* DEFINE_CLASS(fdget, struct fd, fdput(_T), fdget(fd), int fd)
63+
*
64+
* CLASS(fdget, f)(fd);
65+
* if (!f.file)
66+
* return -EBADF;
67+
*
68+
* // use 'f' without concern
69+
*/
70+
71+
#define DEFINE_CLASS(_name, _type, _exit, _init, _init_args...) \
72+
typedef _type class_##_name##_t; \
73+
static inline void class_##_name##_destructor(_type *p) \
74+
{ _type _T = *p; _exit; } \
75+
static inline _type class_##_name##_constructor(_init_args) \
76+
{ _type t = _init; return t; }
77+
78+
#define EXTEND_CLASS(_name, ext, _init, _init_args...) \
79+
typedef class_##_name##_t class_##_name##ext##_t; \
80+
static inline void class_##_name##ext##_destructor(class_##_name##_t *p)\
81+
{ class_##_name##_destructor(p); } \
82+
static inline class_##_name##_t class_##_name##ext##_constructor(_init_args) \
83+
{ class_##_name##_t t = _init; return t; }
84+
85+
#define CLASS(_name, var) \
86+
class_##_name##_t var __cleanup(class_##_name##_destructor) = \
87+
class_##_name##_constructor
88+
89+
90+
/*
91+
* DEFINE_GUARD(name, type, lock, unlock):
92+
* trivial wrapper around DEFINE_CLASS() above specifically
93+
* for locks.
94+
*
95+
* guard(name):
96+
* an anonymous instance of the (guard) class
97+
*
98+
* scoped_guard (name, args...) { }:
99+
* similar to CLASS(name, scope)(args), except the variable (with the
100+
* explicit name 'scope') is declard in a for-loop such that its scope is
101+
* bound to the next (compound) statement.
102+
*
103+
*/
104+
105+
#define DEFINE_GUARD(_name, _type, _lock, _unlock) \
106+
DEFINE_CLASS(_name, _type, _unlock, ({ _lock; _T; }), _type _T)
107+
108+
#define guard(_name) \
109+
CLASS(_name, __UNIQUE_ID(guard))
110+
111+
#define scoped_guard(_name, args...) \
112+
for (CLASS(_name, scope)(args), \
113+
*done = NULL; !done; done = (void *)1)
114+
115+
/*
116+
* Additional helper macros for generating lock guards with types, either for
117+
* locks that don't have a native type (eg. RCU, preempt) or those that need a
118+
* 'fat' pointer (eg. spin_lock_irqsave).
119+
*
120+
* DEFINE_LOCK_GUARD_0(name, lock, unlock, ...)
121+
* DEFINE_LOCK_GUARD_1(name, type, lock, unlock, ...)
122+
*
123+
* will result in the following type:
124+
*
125+
* typedef struct {
126+
* type *lock; // 'type := void' for the _0 variant
127+
* __VA_ARGS__;
128+
* } class_##name##_t;
129+
*
130+
* As above, both _lock and _unlock are statements, except this time '_T' will
131+
* be a pointer to the above struct.
132+
*/
133+
134+
#define __DEFINE_UNLOCK_GUARD(_name, _type, _unlock, ...) \
135+
typedef struct { \
136+
_type *lock; \
137+
__VA_ARGS__; \
138+
} class_##_name##_t; \
139+
\
140+
static inline void class_##_name##_destructor(class_##_name##_t *_T) \
141+
{ \
142+
if (_T->lock) { _unlock; } \
143+
}
144+
145+
146+
#define __DEFINE_LOCK_GUARD_1(_name, _type, _lock) \
147+
static inline class_##_name##_t class_##_name##_constructor(_type *l) \
148+
{ \
149+
class_##_name##_t _t = { .lock = l }, *_T = &_t; \
150+
_lock; \
151+
return _t; \
152+
}
153+
154+
#define __DEFINE_LOCK_GUARD_0(_name, _lock) \
155+
static inline class_##_name##_t class_##_name##_constructor(void) \
156+
{ \
157+
class_##_name##_t _t = { .lock = (void*)1 }, \
158+
*_T __maybe_unused = &_t; \
159+
_lock; \
160+
return _t; \
161+
}
162+
163+
#define DEFINE_LOCK_GUARD_1(_name, _type, _lock, _unlock, ...) \
164+
__DEFINE_UNLOCK_GUARD(_name, _type, _unlock, __VA_ARGS__) \
165+
__DEFINE_LOCK_GUARD_1(_name, _type, _lock)
166+
167+
#define DEFINE_LOCK_GUARD_0(_name, _lock, _unlock, ...) \
168+
__DEFINE_UNLOCK_GUARD(_name, void, _unlock, __VA_ARGS__) \
169+
__DEFINE_LOCK_GUARD_0(_name, _lock)
170+
171+
#endif /* __LINUX_GUARDS_H */

include/linux/compiler-clang.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@
55

66
/* Compiler specific definitions for Clang compiler */
77

8+
/*
9+
* Clang prior to 17 is being silly and considers many __cleanup() variables
10+
* as unused (because they are, their sole purpose is to go out of scope).
11+
*
12+
* https://reviews.llvm.org/D152180
13+
*/
14+
#undef __cleanup
15+
#define __cleanup(func) __maybe_unused __attribute__((__cleanup__(func)))
16+
817
/* same as gcc, this was present in clang-2.6 so we can assume it works
918
* with any version that can compile the kernel
1019
*/

include/linux/compiler_attributes.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@
6969
*/
7070
#define __assume_aligned(a, ...) __attribute__((__assume_aligned__(a, ## __VA_ARGS__)))
7171

72+
/*
73+
* gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html#index-cleanup-variable-attribute
74+
* clang: https://clang.llvm.org/docs/AttributeReference.html#cleanup
75+
*/
76+
#define __cleanup(func) __attribute__((__cleanup__(func)))
77+
7278
/*
7379
* Note the long name.
7480
*

include/linux/device.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <linux/device/bus.h>
3131
#include <linux/device/class.h>
3232
#include <linux/device/driver.h>
33+
#include <linux/cleanup.h>
3334
#include <asm/device.h>
3435

3536
struct device;
@@ -1019,6 +1020,9 @@ void device_unregister(struct device *dev);
10191020
void device_initialize(struct device *dev);
10201021
int __must_check device_add(struct device *dev);
10211022
void device_del(struct device *dev);
1023+
1024+
DEFINE_FREE(device_del, struct device *, if (_T) device_del(_T))
1025+
10221026
int device_for_each_child(struct device *dev, void *data,
10231027
int (*fn)(struct device *dev, void *data));
10241028
int device_for_each_child_reverse(struct device *dev, void *data,
@@ -1186,6 +1190,9 @@ extern int (*platform_notify_remove)(struct device *dev);
11861190
*/
11871191
struct device *get_device(struct device *dev);
11881192
void put_device(struct device *dev);
1193+
1194+
DEFINE_FREE(put_device, struct device *, if (_T) put_device(_T))
1195+
11891196
bool kill_device(struct device *dev);
11901197

11911198
#ifdef CONFIG_DEVTMPFS

include/linux/file.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <linux/types.h>
1111
#include <linux/posix_types.h>
1212
#include <linux/errno.h>
13+
#include <linux/cleanup.h>
1314

1415
struct file;
1516

@@ -80,6 +81,8 @@ static inline void fdput_pos(struct fd f)
8081
fdput(f);
8182
}
8283

84+
DEFINE_CLASS(fd, struct fd, fdput(_T), fdget(fd), int fd)
85+
8386
extern int f_dupfd(unsigned int from, struct file *file, unsigned flags);
8487
extern int replace_fd(unsigned fd, struct file *file, unsigned flags);
8588
extern void set_close_on_exec(unsigned int fd, int flag);
@@ -88,6 +91,9 @@ extern int __get_unused_fd_flags(unsigned flags, unsigned long nofile);
8891
extern int get_unused_fd_flags(unsigned flags);
8992
extern void put_unused_fd(unsigned int fd);
9093

94+
DEFINE_CLASS(get_unused_fd, int, if (_T >= 0) put_unused_fd(_T),
95+
get_unused_fd_flags(flags), unsigned flags)
96+
9197
extern void fd_install(unsigned int fd, struct file *file);
9298

9399
extern int __receive_fd(struct file *file, int __user *ufd,

include/linux/irqflags.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#define _LINUX_TRACE_IRQFLAGS_H
1414

1515
#include <linux/typecheck.h>
16+
#include <linux/cleanup.h>
1617
#include <asm/irqflags.h>
1718
#include <asm/percpu.h>
1819

@@ -267,4 +268,10 @@ extern void warn_bogus_irq_restore(void);
267268

268269
#define irqs_disabled_flags(flags) raw_irqs_disabled_flags(flags)
269270

271+
DEFINE_LOCK_GUARD_0(irq, local_irq_disable(), local_irq_enable())
272+
DEFINE_LOCK_GUARD_0(irqsave,
273+
local_irq_save(_T->flags),
274+
local_irq_restore(_T->flags),
275+
unsigned long flags)
276+
270277
#endif

include/linux/mutex.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <asm/processor.h>
2020
#include <linux/osq_lock.h>
2121
#include <linux/debug_locks.h>
22+
#include <linux/cleanup.h>
2223

2324
#ifdef CONFIG_DEBUG_LOCK_ALLOC
2425
# define __DEP_MAP_MUTEX_INITIALIZER(lockname) \
@@ -219,4 +220,7 @@ extern void mutex_unlock(struct mutex *lock);
219220

220221
extern int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock);
221222

223+
DEFINE_GUARD(mutex, struct mutex *, mutex_lock(_T), mutex_unlock(_T))
224+
DEFINE_FREE(mutex, struct mutex *, if (_T) mutex_unlock(_T))
225+
222226
#endif /* __LINUX_MUTEX_H */

0 commit comments

Comments
 (0)