Skip to content

Commit

Permalink
once: implement DO_ONCE_LITE for non-fast-path "do once" functionality
Browse files Browse the repository at this point in the history
Certain uses of "do once" functionality reside outside of fast path,
and so do not require jump label patching via static keys, making
existing DO_ONCE undesirable in such cases.

Replace uses of __section(".data.once") with DO_ONCE_LITE(_IF)?

This patch changes the return values of xfs_printk_once, printk_once,
and printk_deferred_once. Before, they returned whether the print was
performed, but now, they always return true. This is okay because the
return values of the following macros are entirely ignored throughout
the kernel:
- xfs_printk_once
- xfs_warn_once
- xfs_notice_once
- xfs_info_once
- printk_once
- pr_emerg_once
- pr_alert_once
- pr_crit_once
- pr_err_once
- pr_warn_once
- pr_notice_once
- pr_info_once
- pr_devel_once
- pr_debug_once
- printk_deferred_once
- orc_warn

Changes
v3:
  - Expand commit message to explain why changing return values of
    xfs_printk_once, printk_once, printk_deferred_once is benign
v2:
  - Fix i386 build warnings

Signed-off-by: Tanner Love <[email protected]>
Acked-by: Eric Dumazet <[email protected]>
Acked-by: Mahesh Bandewar <[email protected]>
Acked-by: Steven Rostedt (VMware) <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
tannerlove authored and davem330 committed Jun 28, 2021
1 parent b74ef9f commit a358f40
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 70 deletions.
13 changes: 3 additions & 10 deletions fs/xfs/xfs_message.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#ifndef __XFS_MESSAGE_H
#define __XFS_MESSAGE_H 1

#include <linux/once_lite.h>

struct xfs_mount;

extern __printf(2, 3)
Expand Down Expand Up @@ -41,16 +43,7 @@ do { \
} while (0)

#define xfs_printk_once(func, dev, fmt, ...) \
({ \
static bool __section(".data.once") __print_once; \
bool __ret_print_once = !__print_once; \
\
if (!__print_once) { \
__print_once = true; \
func(dev, fmt, ##__VA_ARGS__); \
} \
unlikely(__ret_print_once); \
})
DO_ONCE_LITE(func, dev, fmt, ##__VA_ARGS__)

#define xfs_emerg_ratelimited(dev, fmt, ...) \
xfs_printk_ratelimited(xfs_emerg, dev, fmt, ##__VA_ARGS__)
Expand Down
37 changes: 7 additions & 30 deletions include/asm-generic/bug.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include <linux/compiler.h>
#include <linux/instrumentation.h>
#include <linux/once_lite.h>

#define CUT_HERE "------------[ cut here ]------------\n"

Expand Down Expand Up @@ -140,39 +141,15 @@ void __warn(const char *file, int line, void *caller, unsigned taint,
})

#ifndef WARN_ON_ONCE
#define WARN_ON_ONCE(condition) ({ \
static bool __section(".data.once") __warned; \
int __ret_warn_once = !!(condition); \
\
if (unlikely(__ret_warn_once && !__warned)) { \
__warned = true; \
WARN_ON(1); \
} \
unlikely(__ret_warn_once); \
})
#define WARN_ON_ONCE(condition) \
DO_ONCE_LITE_IF(condition, WARN_ON, 1)
#endif

#define WARN_ONCE(condition, format...) ({ \
static bool __section(".data.once") __warned; \
int __ret_warn_once = !!(condition); \
\
if (unlikely(__ret_warn_once && !__warned)) { \
__warned = true; \
WARN(1, format); \
} \
unlikely(__ret_warn_once); \
})
#define WARN_ONCE(condition, format...) \
DO_ONCE_LITE_IF(condition, WARN, 1, format)

#define WARN_TAINT_ONCE(condition, taint, format...) ({ \
static bool __section(".data.once") __warned; \
int __ret_warn_once = !!(condition); \
\
if (unlikely(__ret_warn_once && !__warned)) { \
__warned = true; \
WARN_TAINT(1, taint, format); \
} \
unlikely(__ret_warn_once); \
})
#define WARN_TAINT_ONCE(condition, taint, format...) \
DO_ONCE_LITE_IF(condition, WARN_TAINT, 1, taint, format)

#else /* !CONFIG_BUG */
#ifndef HAVE_ARCH_BUG
Expand Down
24 changes: 24 additions & 0 deletions include/linux/once_lite.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LINUX_ONCE_LITE_H
#define _LINUX_ONCE_LITE_H

#include <linux/types.h>

/* Call a function once. Similar to DO_ONCE(), but does not use jump label
* patching via static keys.
*/
#define DO_ONCE_LITE(func, ...) \
DO_ONCE_LITE_IF(true, func, ##__VA_ARGS__)
#define DO_ONCE_LITE_IF(condition, func, ...) \
({ \
static bool __section(".data.once") __already_done; \
bool __ret_do_once = !!(condition); \
\
if (unlikely(__ret_do_once && !__already_done)) { \
__already_done = true; \
func(__VA_ARGS__); \
} \
unlikely(__ret_do_once); \
})

#endif /* _LINUX_ONCE_LITE_H */
23 changes: 3 additions & 20 deletions include/linux/printk.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <linux/linkage.h>
#include <linux/cache.h>
#include <linux/ratelimit_types.h>
#include <linux/once_lite.h>

extern const char linux_banner[];
extern const char linux_proc_banner[];
Expand Down Expand Up @@ -436,27 +437,9 @@ extern int kptr_restrict;

#ifdef CONFIG_PRINTK
#define printk_once(fmt, ...) \
({ \
static bool __section(".data.once") __print_once; \
bool __ret_print_once = !__print_once; \
\
if (!__print_once) { \
__print_once = true; \
printk(fmt, ##__VA_ARGS__); \
} \
unlikely(__ret_print_once); \
})
DO_ONCE_LITE(printk, fmt, ##__VA_ARGS__)
#define printk_deferred_once(fmt, ...) \
({ \
static bool __section(".data.once") __print_once; \
bool __ret_print_once = !__print_once; \
\
if (!__print_once) { \
__print_once = true; \
printk_deferred(fmt, ##__VA_ARGS__); \
} \
unlikely(__ret_print_once); \
})
DO_ONCE_LITE(printk_deferred, fmt, ##__VA_ARGS__)
#else
#define printk_once(fmt, ...) \
no_printk(fmt, ##__VA_ARGS__)
Expand Down
13 changes: 3 additions & 10 deletions kernel/trace/trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <linux/irq_work.h>
#include <linux/workqueue.h>
#include <linux/ctype.h>
#include <linux/once_lite.h>

#ifdef CONFIG_FTRACE_SYSCALLS
#include <asm/unistd.h> /* For NR_SYSCALLS */
Expand Down Expand Up @@ -99,16 +100,8 @@ enum trace_type {
#include "trace_entries.h"

/* Use this for memory failure errors */
#define MEM_FAIL(condition, fmt, ...) ({ \
static bool __section(".data.once") __warned; \
int __ret_warn_once = !!(condition); \
\
if (unlikely(__ret_warn_once && !__warned)) { \
__warned = true; \
pr_err("ERROR: " fmt, ##__VA_ARGS__); \
} \
unlikely(__ret_warn_once); \
})
#define MEM_FAIL(condition, fmt, ...) \
DO_ONCE_LITE_IF(condition, pr_err, "ERROR: " fmt, ##__VA_ARGS__)

/*
* syscalls are special, and need special handling, this is why
Expand Down

0 comments on commit a358f40

Please sign in to comment.