Skip to content

Commit

Permalink
Merge tag 'core_guards_for_6.5_rc1' of git://git.kernel.org/pub/scm/l…
Browse files Browse the repository at this point in the history
…inux/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
  • Loading branch information
torvalds committed Jul 4, 2023
2 parents 0327558 + b5ec6fd commit 04f2933
Show file tree
Hide file tree
Showing 20 changed files with 282 additions and 17 deletions.
6 changes: 1 addition & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -449,8 +449,7 @@ HOSTRUSTC = rustc
HOSTPKG_CONFIG = pkg-config

KBUILD_USERHOSTCFLAGS := -Wall -Wmissing-prototypes -Wstrict-prototypes \
-O2 -fomit-frame-pointer -std=gnu11 \
-Wdeclaration-after-statement
-O2 -fomit-frame-pointer -std=gnu11
KBUILD_USERCFLAGS := $(KBUILD_USERHOSTCFLAGS) $(USERCFLAGS)
KBUILD_USERLDFLAGS := $(USERLDFLAGS)

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

# warn about C99 declaration after statement
KBUILD_CFLAGS += -Wdeclaration-after-statement

# Variable Length Arrays (VLAs) should not be used anywhere in the kernel
KBUILD_CFLAGS += -Wvla

Expand Down
2 changes: 0 additions & 2 deletions arch/arm64/kernel/vdso32/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,9 @@ VDSO_CFLAGS += -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
-fno-strict-aliasing -fno-common \
-Werror-implicit-function-declaration \
-Wno-format-security \
-Wdeclaration-after-statement \
-std=gnu11
VDSO_CFLAGS += -O2
# Some useful compiler-dependent flags from top-level Makefile
VDSO_CFLAGS += $(call cc32-option,-Wdeclaration-after-statement,)
VDSO_CFLAGS += $(call cc32-option,-Wno-pointer-sign)
VDSO_CFLAGS += -fno-strict-overflow
VDSO_CFLAGS += $(call cc32-option,-Werror=strict-prototypes)
Expand Down
12 changes: 6 additions & 6 deletions drivers/dma/ioat/dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -584,11 +584,11 @@ desc_get_errstat(struct ioatdma_chan *ioat_chan, struct ioat_ring_ent *desc)
}

/**
* __cleanup - reclaim used descriptors
* __ioat_cleanup - reclaim used descriptors
* @ioat_chan: channel (ring) to clean
* @phys_complete: zeroed (or not) completion address (from status)
*/
static void __cleanup(struct ioatdma_chan *ioat_chan, dma_addr_t phys_complete)
static void __ioat_cleanup(struct ioatdma_chan *ioat_chan, dma_addr_t phys_complete)
{
struct ioatdma_device *ioat_dma = ioat_chan->ioat_dma;
struct ioat_ring_ent *desc;
Expand Down Expand Up @@ -675,7 +675,7 @@ static void ioat_cleanup(struct ioatdma_chan *ioat_chan)
spin_lock_bh(&ioat_chan->cleanup_lock);

if (ioat_cleanup_preamble(ioat_chan, &phys_complete))
__cleanup(ioat_chan, phys_complete);
__ioat_cleanup(ioat_chan, phys_complete);

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

ioat_quiesce(ioat_chan, 0);
if (ioat_cleanup_preamble(ioat_chan, &phys_complete))
__cleanup(ioat_chan, phys_complete);
__ioat_cleanup(ioat_chan, phys_complete);

__ioat_restart_chan(ioat_chan);
}
Expand Down Expand Up @@ -786,7 +786,7 @@ static void ioat_eh(struct ioatdma_chan *ioat_chan)

/* cleanup so tail points to descriptor that caused the error */
if (ioat_cleanup_preamble(ioat_chan, &phys_complete))
__cleanup(ioat_chan, phys_complete);
__ioat_cleanup(ioat_chan, phys_complete);

chanerr = readl(ioat_chan->reg_base + IOAT_CHANERR_OFFSET);
pci_read_config_dword(pdev, IOAT_PCI_CHANERR_INT_OFFSET, &chanerr_int);
Expand Down Expand Up @@ -943,7 +943,7 @@ void ioat_timer_event(struct timer_list *t)
/* timer restarted in ioat_cleanup_preamble
* and IOAT_COMPLETION_ACK cleared
*/
__cleanup(ioat_chan, phys_complete);
__ioat_cleanup(ioat_chan, phys_complete);
goto unlock_out;
}

Expand Down
171 changes: 171 additions & 0 deletions include/linux/cleanup.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __LINUX_GUARDS_H
#define __LINUX_GUARDS_H

#include <linux/compiler.h>

/*
* DEFINE_FREE(name, type, free):
* simple helper macro that defines the required wrapper for a __free()
* based cleanup function. @free is an expression using '_T' to access
* the variable.
*
* __free(name):
* variable attribute to add a scoped based cleanup to the variable.
*
* no_free_ptr(var):
* like a non-atomic xchg(var, NULL), such that the cleanup function will
* be inhibited -- provided it sanely deals with a NULL value.
*
* return_ptr(p):
* returns p while inhibiting the __free().
*
* Ex.
*
* DEFINE_FREE(kfree, void *, if (_T) kfree(_T))
*
* struct obj *p __free(kfree) = kmalloc(...);
* if (!p)
* return NULL;
*
* if (!init_obj(p))
* return NULL;
*
* return_ptr(p);
*/

#define DEFINE_FREE(_name, _type, _free) \
static inline void __free_##_name(void *p) { _type _T = *(_type *)p; _free; }

#define __free(_name) __cleanup(__free_##_name)

#define no_free_ptr(p) \
({ __auto_type __ptr = (p); (p) = NULL; __ptr; })

#define return_ptr(p) return no_free_ptr(p)


/*
* DEFINE_CLASS(name, type, exit, init, init_args...):
* helper to define the destructor and constructor for a type.
* @exit is an expression using '_T' -- similar to FREE above.
* @init is an expression in @init_args resulting in @type
*
* EXTEND_CLASS(name, ext, init, init_args...):
* extends class @name to @name@ext with the new constructor
*
* CLASS(name, var)(args...):
* declare the variable @var as an instance of the named class
*
* Ex.
*
* DEFINE_CLASS(fdget, struct fd, fdput(_T), fdget(fd), int fd)
*
* CLASS(fdget, f)(fd);
* if (!f.file)
* return -EBADF;
*
* // use 'f' without concern
*/

#define DEFINE_CLASS(_name, _type, _exit, _init, _init_args...) \
typedef _type class_##_name##_t; \
static inline void class_##_name##_destructor(_type *p) \
{ _type _T = *p; _exit; } \
static inline _type class_##_name##_constructor(_init_args) \
{ _type t = _init; return t; }

#define EXTEND_CLASS(_name, ext, _init, _init_args...) \
typedef class_##_name##_t class_##_name##ext##_t; \
static inline void class_##_name##ext##_destructor(class_##_name##_t *p)\
{ class_##_name##_destructor(p); } \
static inline class_##_name##_t class_##_name##ext##_constructor(_init_args) \
{ class_##_name##_t t = _init; return t; }

#define CLASS(_name, var) \
class_##_name##_t var __cleanup(class_##_name##_destructor) = \
class_##_name##_constructor


/*
* DEFINE_GUARD(name, type, lock, unlock):
* trivial wrapper around DEFINE_CLASS() above specifically
* for locks.
*
* guard(name):
* an anonymous instance of the (guard) class
*
* scoped_guard (name, args...) { }:
* similar to CLASS(name, scope)(args), except the variable (with the
* explicit name 'scope') is declard in a for-loop such that its scope is
* bound to the next (compound) statement.
*
*/

#define DEFINE_GUARD(_name, _type, _lock, _unlock) \
DEFINE_CLASS(_name, _type, _unlock, ({ _lock; _T; }), _type _T)

#define guard(_name) \
CLASS(_name, __UNIQUE_ID(guard))

#define scoped_guard(_name, args...) \
for (CLASS(_name, scope)(args), \
*done = NULL; !done; done = (void *)1)

/*
* Additional helper macros for generating lock guards with types, either for
* locks that don't have a native type (eg. RCU, preempt) or those that need a
* 'fat' pointer (eg. spin_lock_irqsave).
*
* DEFINE_LOCK_GUARD_0(name, lock, unlock, ...)
* DEFINE_LOCK_GUARD_1(name, type, lock, unlock, ...)
*
* will result in the following type:
*
* typedef struct {
* type *lock; // 'type := void' for the _0 variant
* __VA_ARGS__;
* } class_##name##_t;
*
* As above, both _lock and _unlock are statements, except this time '_T' will
* be a pointer to the above struct.
*/

#define __DEFINE_UNLOCK_GUARD(_name, _type, _unlock, ...) \
typedef struct { \
_type *lock; \
__VA_ARGS__; \
} class_##_name##_t; \
\
static inline void class_##_name##_destructor(class_##_name##_t *_T) \
{ \
if (_T->lock) { _unlock; } \
}


#define __DEFINE_LOCK_GUARD_1(_name, _type, _lock) \
static inline class_##_name##_t class_##_name##_constructor(_type *l) \
{ \
class_##_name##_t _t = { .lock = l }, *_T = &_t; \
_lock; \
return _t; \
}

#define __DEFINE_LOCK_GUARD_0(_name, _lock) \
static inline class_##_name##_t class_##_name##_constructor(void) \
{ \
class_##_name##_t _t = { .lock = (void*)1 }, \
*_T __maybe_unused = &_t; \
_lock; \
return _t; \
}

#define DEFINE_LOCK_GUARD_1(_name, _type, _lock, _unlock, ...) \
__DEFINE_UNLOCK_GUARD(_name, _type, _unlock, __VA_ARGS__) \
__DEFINE_LOCK_GUARD_1(_name, _type, _lock)

#define DEFINE_LOCK_GUARD_0(_name, _lock, _unlock, ...) \
__DEFINE_UNLOCK_GUARD(_name, void, _unlock, __VA_ARGS__) \
__DEFINE_LOCK_GUARD_0(_name, _lock)

#endif /* __LINUX_GUARDS_H */
9 changes: 9 additions & 0 deletions include/linux/compiler-clang.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@

/* Compiler specific definitions for Clang compiler */

/*
* Clang prior to 17 is being silly and considers many __cleanup() variables
* as unused (because they are, their sole purpose is to go out of scope).
*
* https://reviews.llvm.org/D152180
*/
#undef __cleanup
#define __cleanup(func) __maybe_unused __attribute__((__cleanup__(func)))

/* same as gcc, this was present in clang-2.6 so we can assume it works
* with any version that can compile the kernel
*/
Expand Down
6 changes: 6 additions & 0 deletions include/linux/compiler_attributes.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@
*/
#define __assume_aligned(a, ...) __attribute__((__assume_aligned__(a, ## __VA_ARGS__)))

/*
* gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html#index-cleanup-variable-attribute
* clang: https://clang.llvm.org/docs/AttributeReference.html#cleanup
*/
#define __cleanup(func) __attribute__((__cleanup__(func)))

/*
* Note the long name.
*
Expand Down
7 changes: 7 additions & 0 deletions include/linux/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <linux/device/bus.h>
#include <linux/device/class.h>
#include <linux/device/driver.h>
#include <linux/cleanup.h>
#include <asm/device.h>

struct device;
Expand Down Expand Up @@ -1019,6 +1020,9 @@ void device_unregister(struct device *dev);
void device_initialize(struct device *dev);
int __must_check device_add(struct device *dev);
void device_del(struct device *dev);

DEFINE_FREE(device_del, struct device *, if (_T) device_del(_T))

int device_for_each_child(struct device *dev, void *data,
int (*fn)(struct device *dev, void *data));
int device_for_each_child_reverse(struct device *dev, void *data,
Expand Down Expand Up @@ -1186,6 +1190,9 @@ extern int (*platform_notify_remove)(struct device *dev);
*/
struct device *get_device(struct device *dev);
void put_device(struct device *dev);

DEFINE_FREE(put_device, struct device *, if (_T) put_device(_T))

bool kill_device(struct device *dev);

#ifdef CONFIG_DEVTMPFS
Expand Down
6 changes: 6 additions & 0 deletions include/linux/file.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <linux/types.h>
#include <linux/posix_types.h>
#include <linux/errno.h>
#include <linux/cleanup.h>

struct file;

Expand Down Expand Up @@ -80,6 +81,8 @@ static inline void fdput_pos(struct fd f)
fdput(f);
}

DEFINE_CLASS(fd, struct fd, fdput(_T), fdget(fd), int fd)

extern int f_dupfd(unsigned int from, struct file *file, unsigned flags);
extern int replace_fd(unsigned fd, struct file *file, unsigned flags);
extern void set_close_on_exec(unsigned int fd, int flag);
Expand All @@ -88,6 +91,9 @@ extern int __get_unused_fd_flags(unsigned flags, unsigned long nofile);
extern int get_unused_fd_flags(unsigned flags);
extern void put_unused_fd(unsigned int fd);

DEFINE_CLASS(get_unused_fd, int, if (_T >= 0) put_unused_fd(_T),
get_unused_fd_flags(flags), unsigned flags)

extern void fd_install(unsigned int fd, struct file *file);

extern int __receive_fd(struct file *file, int __user *ufd,
Expand Down
7 changes: 7 additions & 0 deletions include/linux/irqflags.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#define _LINUX_TRACE_IRQFLAGS_H

#include <linux/typecheck.h>
#include <linux/cleanup.h>
#include <asm/irqflags.h>
#include <asm/percpu.h>

Expand Down Expand Up @@ -267,4 +268,10 @@ extern void warn_bogus_irq_restore(void);

#define irqs_disabled_flags(flags) raw_irqs_disabled_flags(flags)

DEFINE_LOCK_GUARD_0(irq, local_irq_disable(), local_irq_enable())
DEFINE_LOCK_GUARD_0(irqsave,
local_irq_save(_T->flags),
local_irq_restore(_T->flags),
unsigned long flags)

#endif
4 changes: 4 additions & 0 deletions include/linux/mutex.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <asm/processor.h>
#include <linux/osq_lock.h>
#include <linux/debug_locks.h>
#include <linux/cleanup.h>

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

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

DEFINE_GUARD(mutex, struct mutex *, mutex_lock(_T), mutex_unlock(_T))
DEFINE_FREE(mutex, struct mutex *, if (_T) mutex_unlock(_T))

#endif /* __LINUX_MUTEX_H */
4 changes: 4 additions & 0 deletions include/linux/percpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <linux/cpumask.h>
#include <linux/pfn.h>
#include <linux/init.h>
#include <linux/cleanup.h>

#include <asm/percpu.h>

Expand Down Expand Up @@ -125,6 +126,9 @@ extern void __init setup_per_cpu_areas(void);
extern void __percpu *__alloc_percpu_gfp(size_t size, size_t align, gfp_t gfp) __alloc_size(1);
extern void __percpu *__alloc_percpu(size_t size, size_t align) __alloc_size(1);
extern void free_percpu(void __percpu *__pdata);

DEFINE_FREE(free_percpu, void __percpu *, free_percpu(_T))

extern phys_addr_t per_cpu_ptr_to_phys(void *addr);

#define alloc_percpu_gfp(type, gfp) \
Expand Down
Loading

0 comments on commit 04f2933

Please sign in to comment.