Merge 6f49693a6c ("Merge tag 'smp-core-2023-08-28' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip") into android-mainline
Steps on the way to 6.6-rc1 Change-Id: I649b5cf1239bcc2d2487e5bb033d3be4f5a970b4 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
@@ -556,6 +556,7 @@ Description: Control Symmetric Multi Threading (SMT)
|
||||
================ =========================================
|
||||
"on" SMT is enabled
|
||||
"off" SMT is disabled
|
||||
"<N>" SMT is enabled with N threads per core.
|
||||
"forceoff" SMT is force disabled. Cannot be changed.
|
||||
"notsupported" SMT is not supported by the CPU
|
||||
"notimplemented" SMT runtime toggling is not
|
||||
|
||||
@@ -10,7 +10,7 @@ misuses of the RCU API, most notably using one of the rcu_dereference()
|
||||
family to access an RCU-protected pointer without the proper protection.
|
||||
When such misuse is detected, an lockdep-RCU splat is emitted.
|
||||
|
||||
The usual cause of a lockdep-RCU slat is someone accessing an
|
||||
The usual cause of a lockdep-RCU splat is someone accessing an
|
||||
RCU-protected data structure without either (1) being in the right kind of
|
||||
RCU read-side critical section or (2) holding the right update-side lock.
|
||||
This problem can therefore be serious: it might result in random memory
|
||||
|
||||
@@ -18,7 +18,16 @@ to solve following problem.
|
||||
|
||||
Without 'nulls', a typical RCU linked list managing objects which are
|
||||
allocated with SLAB_TYPESAFE_BY_RCU kmem_cache can use the following
|
||||
algorithms:
|
||||
algorithms. Following examples assume 'obj' is a pointer to such
|
||||
objects, which is having below type.
|
||||
|
||||
::
|
||||
|
||||
struct object {
|
||||
struct hlist_node obj_node;
|
||||
atomic_t refcnt;
|
||||
unsigned int key;
|
||||
};
|
||||
|
||||
1) Lookup algorithm
|
||||
-------------------
|
||||
@@ -26,11 +35,13 @@ algorithms:
|
||||
::
|
||||
|
||||
begin:
|
||||
rcu_read_lock()
|
||||
rcu_read_lock();
|
||||
obj = lockless_lookup(key);
|
||||
if (obj) {
|
||||
if (!try_get_ref(obj)) // might fail for free objects
|
||||
if (!try_get_ref(obj)) { // might fail for free objects
|
||||
rcu_read_unlock();
|
||||
goto begin;
|
||||
}
|
||||
/*
|
||||
* Because a writer could delete object, and a writer could
|
||||
* reuse these object before the RCU grace period, we
|
||||
@@ -54,7 +65,7 @@ but a version with an additional memory barrier (smp_rmb())
|
||||
struct hlist_node *node, *next;
|
||||
for (pos = rcu_dereference((head)->first);
|
||||
pos && ({ next = pos->next; smp_rmb(); prefetch(next); 1; }) &&
|
||||
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; });
|
||||
({ obj = hlist_entry(pos, typeof(*obj), obj_node); 1; });
|
||||
pos = rcu_dereference(next))
|
||||
if (obj->key == key)
|
||||
return obj;
|
||||
@@ -66,10 +77,10 @@ And note the traditional hlist_for_each_entry_rcu() misses this smp_rmb()::
|
||||
struct hlist_node *node;
|
||||
for (pos = rcu_dereference((head)->first);
|
||||
pos && ({ prefetch(pos->next); 1; }) &&
|
||||
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; });
|
||||
({ obj = hlist_entry(pos, typeof(*obj), obj_node); 1; });
|
||||
pos = rcu_dereference(pos->next))
|
||||
if (obj->key == key)
|
||||
return obj;
|
||||
if (obj->key == key)
|
||||
return obj;
|
||||
return NULL;
|
||||
|
||||
Quoting Corey Minyard::
|
||||
@@ -86,7 +97,7 @@ Quoting Corey Minyard::
|
||||
2) Insertion algorithm
|
||||
----------------------
|
||||
|
||||
We need to make sure a reader cannot read the new 'obj->obj_next' value
|
||||
We need to make sure a reader cannot read the new 'obj->obj_node.next' value
|
||||
and previous value of 'obj->key'. Otherwise, an item could be deleted
|
||||
from a chain, and inserted into another chain. If new chain was empty
|
||||
before the move, 'next' pointer is NULL, and lockless reader can not
|
||||
@@ -129,8 +140,7 @@ very very fast (before the end of RCU grace period)
|
||||
Avoiding extra smp_rmb()
|
||||
========================
|
||||
|
||||
With hlist_nulls we can avoid extra smp_rmb() in lockless_lookup()
|
||||
and extra _release() in insert function.
|
||||
With hlist_nulls we can avoid extra smp_rmb() in lockless_lookup().
|
||||
|
||||
For example, if we choose to store the slot number as the 'nulls'
|
||||
end-of-list marker for each slot of the hash table, we can detect
|
||||
@@ -142,6 +152,9 @@ the beginning. If the object was moved to the same chain,
|
||||
then the reader doesn't care: It might occasionally
|
||||
scan the list again without harm.
|
||||
|
||||
Note that using hlist_nulls means the type of 'obj_node' field of
|
||||
'struct object' becomes 'struct hlist_nulls_node'.
|
||||
|
||||
|
||||
1) lookup algorithm
|
||||
-------------------
|
||||
@@ -151,7 +164,7 @@ scan the list again without harm.
|
||||
head = &table[slot];
|
||||
begin:
|
||||
rcu_read_lock();
|
||||
hlist_nulls_for_each_entry_rcu(obj, node, head, member) {
|
||||
hlist_nulls_for_each_entry_rcu(obj, node, head, obj_node) {
|
||||
if (obj->key == key) {
|
||||
if (!try_get_ref(obj)) { // might fail for free objects
|
||||
rcu_read_unlock();
|
||||
@@ -182,6 +195,9 @@ scan the list again without harm.
|
||||
2) Insert algorithm
|
||||
-------------------
|
||||
|
||||
Same to the above one, but uses hlist_nulls_add_head_rcu() instead of
|
||||
hlist_add_head_rcu().
|
||||
|
||||
::
|
||||
|
||||
/*
|
||||
|
||||
@@ -2942,6 +2942,10 @@
|
||||
locktorture.torture_type= [KNL]
|
||||
Specify the locking implementation to test.
|
||||
|
||||
locktorture.writer_fifo= [KNL]
|
||||
Run the write-side locktorture kthreads at
|
||||
sched_set_fifo() real-time priority.
|
||||
|
||||
locktorture.verbose= [KNL]
|
||||
Enable additional printk() statements.
|
||||
|
||||
@@ -4953,6 +4957,15 @@
|
||||
test until boot completes in order to avoid
|
||||
interference.
|
||||
|
||||
rcuscale.kfree_by_call_rcu= [KNL]
|
||||
In kernels built with CONFIG_RCU_LAZY=y, test
|
||||
call_rcu() instead of kfree_rcu().
|
||||
|
||||
rcuscale.kfree_mult= [KNL]
|
||||
Instead of allocating an object of size kfree_obj,
|
||||
allocate one of kfree_mult * sizeof(kfree_obj).
|
||||
Defaults to 1.
|
||||
|
||||
rcuscale.kfree_rcu_test= [KNL]
|
||||
Set to measure performance of kfree_rcu() flooding.
|
||||
|
||||
@@ -4978,6 +4991,12 @@
|
||||
Number of loops doing rcuscale.kfree_alloc_num number
|
||||
of allocations and frees.
|
||||
|
||||
rcuscale.minruntime= [KNL]
|
||||
Set the minimum test run time in seconds. This
|
||||
does not affect the data-collection interval,
|
||||
but instead allows better measurement of things
|
||||
like CPU consumption.
|
||||
|
||||
rcuscale.nreaders= [KNL]
|
||||
Set number of RCU readers. The value -1 selects
|
||||
N, where N is the number of CPUs. A value
|
||||
@@ -4992,7 +5011,7 @@
|
||||
the same as for rcuscale.nreaders.
|
||||
N, where N is the number of CPUs
|
||||
|
||||
rcuscale.perf_type= [KNL]
|
||||
rcuscale.scale_type= [KNL]
|
||||
Specify the RCU implementation to test.
|
||||
|
||||
rcuscale.shutdown= [KNL]
|
||||
@@ -5008,6 +5027,11 @@
|
||||
in microseconds. The default of zero says
|
||||
no holdoff.
|
||||
|
||||
rcuscale.writer_holdoff_jiffies= [KNL]
|
||||
Additional write-side holdoff between grace
|
||||
periods, but in jiffies. The default of zero
|
||||
says no holdoff.
|
||||
|
||||
rcutorture.fqs_duration= [KNL]
|
||||
Set duration of force_quiescent_state bursts
|
||||
in microseconds.
|
||||
@@ -5289,6 +5313,13 @@
|
||||
number avoids disturbing real-time workloads,
|
||||
but lengthens grace periods.
|
||||
|
||||
rcupdate.rcu_task_lazy_lim= [KNL]
|
||||
Number of callbacks on a given CPU that will
|
||||
cancel laziness on that CPU. Use -1 to disable
|
||||
cancellation of laziness, but be advised that
|
||||
doing so increases the danger of OOM due to
|
||||
callback flooding.
|
||||
|
||||
rcupdate.rcu_task_stall_info= [KNL]
|
||||
Set initial timeout in jiffies for RCU task stall
|
||||
informational messages, which give some indication
|
||||
@@ -5318,6 +5349,29 @@
|
||||
A change in value does not take effect until
|
||||
the beginning of the next grace period.
|
||||
|
||||
rcupdate.rcu_tasks_lazy_ms= [KNL]
|
||||
Set timeout in milliseconds RCU Tasks asynchronous
|
||||
callback batching for call_rcu_tasks().
|
||||
A negative value will take the default. A value
|
||||
of zero will disable batching. Batching is
|
||||
always disabled for synchronize_rcu_tasks().
|
||||
|
||||
rcupdate.rcu_tasks_rude_lazy_ms= [KNL]
|
||||
Set timeout in milliseconds RCU Tasks
|
||||
Rude asynchronous callback batching for
|
||||
call_rcu_tasks_rude(). A negative value
|
||||
will take the default. A value of zero will
|
||||
disable batching. Batching is always disabled
|
||||
for synchronize_rcu_tasks_rude().
|
||||
|
||||
rcupdate.rcu_tasks_trace_lazy_ms= [KNL]
|
||||
Set timeout in milliseconds RCU Tasks
|
||||
Trace asynchronous callback batching for
|
||||
call_rcu_tasks_trace(). A negative value
|
||||
will take the default. A value of zero will
|
||||
disable batching. Batching is always disabled
|
||||
for synchronize_rcu_tasks_trace().
|
||||
|
||||
rcupdate.rcu_self_test= [KNL]
|
||||
Run the RCU early boot self tests
|
||||
|
||||
|
||||
@@ -395,8 +395,8 @@ multi-instance state the following function is available:
|
||||
* cpuhp_setup_state_multi(state, name, startup, teardown)
|
||||
|
||||
The @state argument is either a statically allocated state or one of the
|
||||
constants for dynamically allocated states - CPUHP_PREPARE_DYN,
|
||||
CPUHP_ONLINE_DYN - depending on the state section (PREPARE, ONLINE) for
|
||||
constants for dynamically allocated states - CPUHP_BP_PREPARE_DYN,
|
||||
CPUHP_AP_ONLINE_DYN - depending on the state section (PREPARE, ONLINE) for
|
||||
which a dynamic state should be allocated.
|
||||
|
||||
The @name argument is used for sysfs output and for instrumentation. The
|
||||
@@ -588,7 +588,7 @@ notifications on online and offline operations::
|
||||
Setup and teardown a dynamically allocated state in the ONLINE section
|
||||
for notifications on offline operations::
|
||||
|
||||
state = cpuhp_setup_state(CPUHP_ONLINE_DYN, "subsys:offline", NULL, subsys_cpu_offline);
|
||||
state = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "subsys:offline", NULL, subsys_cpu_offline);
|
||||
if (state < 0)
|
||||
return state;
|
||||
....
|
||||
@@ -597,7 +597,7 @@ for notifications on offline operations::
|
||||
Setup and teardown a dynamically allocated state in the ONLINE section
|
||||
for notifications on online operations without invoking the callbacks::
|
||||
|
||||
state = cpuhp_setup_state_nocalls(CPUHP_ONLINE_DYN, "subsys:online", subsys_cpu_online, NULL);
|
||||
state = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "subsys:online", subsys_cpu_online, NULL);
|
||||
if (state < 0)
|
||||
return state;
|
||||
....
|
||||
@@ -606,7 +606,7 @@ for notifications on online operations without invoking the callbacks::
|
||||
Setup, use and teardown a dynamically allocated multi-instance state in the
|
||||
ONLINE section for notifications on online and offline operation::
|
||||
|
||||
state = cpuhp_setup_state_multi(CPUHP_ONLINE_DYN, "subsys:online", subsys_cpu_online, subsys_cpu_offline);
|
||||
state = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "subsys:online", subsys_cpu_online, subsys_cpu_offline);
|
||||
if (state < 0)
|
||||
return state;
|
||||
....
|
||||
|
||||
@@ -35,6 +35,7 @@ properties:
|
||||
- amlogic,meson-sm1-gpio-intc
|
||||
- amlogic,meson-a1-gpio-intc
|
||||
- amlogic,meson-s4-gpio-intc
|
||||
- amlogic,c3-gpio-intc
|
||||
- const: amlogic,meson-gpio-intc
|
||||
|
||||
reg:
|
||||
|
||||
@@ -34,6 +34,9 @@ config ARCH_HAS_SUBPAGE_FAULTS
|
||||
config HOTPLUG_SMT
|
||||
bool
|
||||
|
||||
config SMT_NUM_THREADS_DYNAMIC
|
||||
bool
|
||||
|
||||
# Selected by HOTPLUG_CORE_SYNC_DEAD or HOTPLUG_CORE_SYNC_FULL
|
||||
config HOTPLUG_CORE_SYNC
|
||||
bool
|
||||
|
||||
@@ -97,7 +97,7 @@ struct osf_dirent {
|
||||
unsigned int d_ino;
|
||||
unsigned short d_reclen;
|
||||
unsigned short d_namlen;
|
||||
char d_name[1];
|
||||
char d_name[];
|
||||
};
|
||||
|
||||
struct osf_dirent_callback {
|
||||
|
||||
@@ -25,6 +25,9 @@ static inline int syscall_get_nr(struct task_struct *task,
|
||||
if (IS_ENABLED(CONFIG_AEABI) && !IS_ENABLED(CONFIG_OABI_COMPAT))
|
||||
return task_thread_info(task)->abi_syscall;
|
||||
|
||||
if (task_thread_info(task)->abi_syscall == -1)
|
||||
return -1;
|
||||
|
||||
return task_thread_info(task)->abi_syscall & __NR_SYSCALL_MASK;
|
||||
}
|
||||
|
||||
|
||||
@@ -90,6 +90,7 @@ slow_work_pending:
|
||||
cmp r0, #0
|
||||
beq no_work_pending
|
||||
movlt scno, #(__NR_restart_syscall - __NR_SYSCALL_BASE)
|
||||
str scno, [tsk, #TI_ABI_SYSCALL] @ make sure tracers see update
|
||||
ldmia sp, {r0 - r6} @ have to reload r0 - r6
|
||||
b local_restart @ ... and off we go
|
||||
ENDPROC(ret_fast_syscall)
|
||||
|
||||
@@ -783,8 +783,9 @@ long arch_ptrace(struct task_struct *child, long request,
|
||||
break;
|
||||
|
||||
case PTRACE_SET_SYSCALL:
|
||||
task_thread_info(child)->abi_syscall = data &
|
||||
__NR_SYSCALL_MASK;
|
||||
if (data != -1)
|
||||
data &= __NR_SYSCALL_MASK;
|
||||
task_thread_info(child)->abi_syscall = data;
|
||||
ret = 0;
|
||||
break;
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ hyp-obj-y := timer-sr.o sysreg-sr.o debug-sr.o switch.o tlb.o hyp-init.o host.o
|
||||
cache.o setup.o mm.o mem_protect.o sys_regs.o pkvm.o stacktrace.o ffa.o
|
||||
hyp-obj-y += ../vgic-v3-sr.o ../aarch32.o ../vgic-v2-cpuif-proxy.o ../entry.o \
|
||||
../fpsimd.o ../hyp-entry.o ../exception.o ../pgtable.o
|
||||
hyp-obj-$(CONFIG_DEBUG_LIST) += list_debug.o
|
||||
hyp-obj-$(CONFIG_LIST_HARDENED) += list_debug.o
|
||||
hyp-obj-y += $(lib-objs)
|
||||
|
||||
##
|
||||
|
||||
@@ -26,8 +26,9 @@ static inline __must_check bool nvhe_check_data_corruption(bool v)
|
||||
|
||||
/* The predicates checked here are taken from lib/list_debug.c. */
|
||||
|
||||
bool __list_add_valid(struct list_head *new, struct list_head *prev,
|
||||
struct list_head *next)
|
||||
__list_valid_slowpath
|
||||
bool __list_add_valid_or_report(struct list_head *new, struct list_head *prev,
|
||||
struct list_head *next)
|
||||
{
|
||||
if (NVHE_CHECK_DATA_CORRUPTION(next->prev != prev) ||
|
||||
NVHE_CHECK_DATA_CORRUPTION(prev->next != next) ||
|
||||
@@ -37,7 +38,8 @@ bool __list_add_valid(struct list_head *new, struct list_head *prev,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool __list_del_entry_valid(struct list_head *entry)
|
||||
__list_valid_slowpath
|
||||
bool __list_del_entry_valid_or_report(struct list_head *entry)
|
||||
{
|
||||
struct list_head *prev, *next;
|
||||
|
||||
|
||||
@@ -554,7 +554,7 @@ struct mconsole_output {
|
||||
|
||||
static DEFINE_SPINLOCK(client_lock);
|
||||
static LIST_HEAD(clients);
|
||||
static char console_buf[MCONSOLE_MAX_DATA];
|
||||
static char console_buf[MCONSOLE_MAX_DATA] __nonstring;
|
||||
|
||||
static void console_write(struct console *console, const char *string,
|
||||
unsigned int len)
|
||||
@@ -567,7 +567,7 @@ static void console_write(struct console *console, const char *string,
|
||||
|
||||
while (len > 0) {
|
||||
n = min((size_t) len, ARRAY_SIZE(console_buf));
|
||||
strncpy(console_buf, string, n);
|
||||
memcpy(console_buf, string, n);
|
||||
string += n;
|
||||
len -= n;
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@ static int create_tap_fd(char *iface)
|
||||
}
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR;
|
||||
strncpy((char *)&ifr.ifr_name, iface, sizeof(ifr.ifr_name) - 1);
|
||||
strscpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
|
||||
|
||||
err = ioctl(fd, TUNSETIFF, (void *) &ifr);
|
||||
if (err != 0) {
|
||||
@@ -171,7 +171,7 @@ static int create_raw_fd(char *iface, int flags, int proto)
|
||||
goto raw_fd_cleanup;
|
||||
}
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strncpy((char *)&ifr.ifr_name, iface, sizeof(ifr.ifr_name) - 1);
|
||||
strscpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
|
||||
if (ioctl(fd, SIOCGIFINDEX, (void *) &ifr) < 0) {
|
||||
err = -errno;
|
||||
goto raw_fd_cleanup;
|
||||
|
||||
@@ -50,7 +50,6 @@ static inline int printk(const char *fmt, ...)
|
||||
#endif
|
||||
|
||||
extern int in_aton(char *str);
|
||||
extern size_t strlcpy(char *, const char *, size_t);
|
||||
extern size_t strlcat(char *, const char *, size_t);
|
||||
extern size_t strscpy(char *, const char *, size_t);
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ static int __init make_uml_dir(void)
|
||||
__func__);
|
||||
goto err;
|
||||
}
|
||||
strlcpy(dir, home, sizeof(dir));
|
||||
strscpy(dir, home, sizeof(dir));
|
||||
uml_dir++;
|
||||
}
|
||||
strlcat(dir, uml_dir, sizeof(dir));
|
||||
@@ -243,7 +243,7 @@ int __init set_umid(char *name)
|
||||
if (strlen(name) > UMID_LEN - 1)
|
||||
return -E2BIG;
|
||||
|
||||
strlcpy(umid, name, sizeof(umid));
|
||||
strscpy(umid, name, sizeof(umid));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -262,7 +262,7 @@ static int __init make_umid(void)
|
||||
make_uml_dir();
|
||||
|
||||
if (*umid == '\0') {
|
||||
strlcpy(tmp, uml_dir, sizeof(tmp));
|
||||
strscpy(tmp, uml_dir, sizeof(tmp));
|
||||
strlcat(tmp, "XXXXXX", sizeof(tmp));
|
||||
fd = mkstemp(tmp);
|
||||
if (fd < 0) {
|
||||
|
||||
@@ -136,10 +136,11 @@ static inline int topology_max_smt_threads(void)
|
||||
return __max_smt_threads;
|
||||
}
|
||||
|
||||
#include <linux/cpu_smt.h>
|
||||
|
||||
int topology_update_package_map(unsigned int apicid, unsigned int cpu);
|
||||
int topology_update_die_map(unsigned int dieid, unsigned int cpu);
|
||||
int topology_phys_to_logical_pkg(unsigned int pkg);
|
||||
bool topology_smt_supported(void);
|
||||
|
||||
extern struct cpumask __cpu_primary_thread_mask;
|
||||
#define cpu_primary_thread_mask ((const struct cpumask *)&__cpu_primary_thread_mask)
|
||||
@@ -162,7 +163,6 @@ static inline int topology_phys_to_logical_pkg(unsigned int pkg) { return 0; }
|
||||
static inline int topology_max_die_per_package(void) { return 1; }
|
||||
static inline int topology_max_smt_threads(void) { return 1; }
|
||||
static inline bool topology_is_primary_thread(unsigned int cpu) { return true; }
|
||||
static inline bool topology_smt_supported(void) { return false; }
|
||||
#endif /* !CONFIG_SMP */
|
||||
|
||||
static inline void arch_fix_phys_package_id(int num, u32 slot)
|
||||
|
||||
@@ -2343,7 +2343,7 @@ void __init arch_cpu_finalize_init(void)
|
||||
* identify_boot_cpu() initialized SMT support information, let the
|
||||
* core code know.
|
||||
*/
|
||||
cpu_smt_check_topology();
|
||||
cpu_smt_set_num_threads(smp_num_siblings, smp_num_siblings);
|
||||
|
||||
if (!IS_ENABLED(CONFIG_SMP)) {
|
||||
pr_info("CPU: ");
|
||||
|
||||
@@ -79,6 +79,11 @@ void __init native_pv_lock_init(void)
|
||||
static_branch_disable(&virt_spin_lock_key);
|
||||
}
|
||||
|
||||
static void native_tlb_remove_table(struct mmu_gather *tlb, void *table)
|
||||
{
|
||||
tlb_remove_page(tlb, table);
|
||||
}
|
||||
|
||||
unsigned int paravirt_patch(u8 type, void *insn_buff, unsigned long addr,
|
||||
unsigned int len)
|
||||
{
|
||||
@@ -295,8 +300,7 @@ struct paravirt_patch_template pv_ops = {
|
||||
.mmu.flush_tlb_kernel = native_flush_tlb_global,
|
||||
.mmu.flush_tlb_one_user = native_flush_tlb_one_user,
|
||||
.mmu.flush_tlb_multi = native_flush_tlb_multi,
|
||||
.mmu.tlb_remove_table =
|
||||
(void (*)(struct mmu_gather *, void *))tlb_remove_page,
|
||||
.mmu.tlb_remove_table = native_tlb_remove_table,
|
||||
|
||||
.mmu.exit_mmap = paravirt_nop,
|
||||
.mmu.notify_page_enc_status_changed = paravirt_nop,
|
||||
|
||||
@@ -326,14 +326,6 @@ static void notrace start_secondary(void *unused)
|
||||
cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* topology_smt_supported - Check whether SMT is supported by the CPUs
|
||||
*/
|
||||
bool topology_smt_supported(void)
|
||||
{
|
||||
return smp_num_siblings > 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* topology_phys_to_logical_pkg - Map a physical package id to a logical
|
||||
* @phys_pkg: The physical package id to map
|
||||
|
||||
@@ -1258,7 +1258,7 @@ static void __init check_system_tsc_reliable(void)
|
||||
if (boot_cpu_has(X86_FEATURE_CONSTANT_TSC) &&
|
||||
boot_cpu_has(X86_FEATURE_NONSTOP_TSC) &&
|
||||
boot_cpu_has(X86_FEATURE_TSC_ADJUST) &&
|
||||
nr_online_nodes <= 2)
|
||||
nr_online_nodes <= 4)
|
||||
tsc_disable_clocksource_watchdog();
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ static void __init eisa_name_device(struct eisa_device *edev)
|
||||
int i;
|
||||
for (i = 0; i < EISA_INFOS; i++) {
|
||||
if (!strcmp(edev->id.sig, eisa_table[i].id.sig)) {
|
||||
strlcpy(edev->pretty_name,
|
||||
strscpy(edev->pretty_name,
|
||||
eisa_table[i].name,
|
||||
sizeof(edev->pretty_name));
|
||||
return;
|
||||
|
||||
@@ -60,7 +60,6 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/smp.h>
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/smp.h>
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/irqchip/arm-gic.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/acpi_iort.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/msi.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
@@ -340,7 +340,7 @@ static void i8259_irq_dispatch(struct irq_desc *desc)
|
||||
generic_handle_domain_irq(domain, hwirq);
|
||||
}
|
||||
|
||||
int __init i8259_of_init(struct device_node *node, struct device_node *parent)
|
||||
static int __init i8259_of_init(struct device_node *node, struct device_node *parent)
|
||||
{
|
||||
struct irq_domain *domain;
|
||||
unsigned int parent_irq;
|
||||
|
||||
@@ -50,8 +50,9 @@
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
|
||||
@@ -10,8 +10,9 @@
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
|
||||
@@ -339,8 +339,8 @@ static int __init imx_mu_of_init(struct device_node *dn,
|
||||
msi_data->msiir_addr = res->start + msi_data->cfg->xTR;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq <= 0)
|
||||
return -ENODEV;
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
platform_set_drvdata(pdev, msi_data);
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/irqchip.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ static int eiointc_router_init(unsigned int cpu)
|
||||
int i, bit;
|
||||
uint32_t data;
|
||||
uint32_t node = cpu_to_eio_node(cpu);
|
||||
uint32_t index = eiointc_index(node);
|
||||
int index = eiointc_index(node);
|
||||
|
||||
if (index < 0) {
|
||||
pr_err("Error: invalid nodemap!\n");
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
|
||||
/* Registers */
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
|
||||
/* Registers */
|
||||
|
||||
@@ -349,8 +349,7 @@ static int ls_scfg_msi_probe(struct platform_device *pdev)
|
||||
|
||||
msi_data->cfg = (struct ls_scfg_msi_cfg *) match->data;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
msi_data->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||
msi_data->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
|
||||
if (IS_ERR(msi_data->regs)) {
|
||||
dev_err(&pdev->dev, "failed to initialize 'regs'\n");
|
||||
return PTR_ERR(msi_data->regs);
|
||||
|
||||
@@ -10,12 +10,10 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/irqchip/irq-madera.h>
|
||||
#include <linux/mfd/madera/core.h>
|
||||
#include <linux/mfd/madera/pdata.h>
|
||||
|
||||
@@ -150,6 +150,10 @@ static const struct meson_gpio_irq_params s4_params = {
|
||||
INIT_MESON_S4_COMMON_DATA(82)
|
||||
};
|
||||
|
||||
static const struct meson_gpio_irq_params c3_params = {
|
||||
INIT_MESON_S4_COMMON_DATA(55)
|
||||
};
|
||||
|
||||
static const struct of_device_id meson_irq_gpio_matches[] __maybe_unused = {
|
||||
{ .compatible = "amlogic,meson8-gpio-intc", .data = &meson8_params },
|
||||
{ .compatible = "amlogic,meson8b-gpio-intc", .data = &meson8b_params },
|
||||
@@ -160,6 +164,7 @@ static const struct of_device_id meson_irq_gpio_matches[] __maybe_unused = {
|
||||
{ .compatible = "amlogic,meson-sm1-gpio-intc", .data = &sm1_params },
|
||||
{ .compatible = "amlogic,meson-a1-gpio-intc", .data = &a1_params },
|
||||
{ .compatible = "amlogic,meson-s4-gpio-intc", .data = &s4_params },
|
||||
{ .compatible = "amlogic,c3-gpio-intc", .data = &c3_params },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
@@ -557,7 +557,7 @@ static int gic_irq_domain_alloc(struct irq_domain *d, unsigned int virq,
|
||||
return gic_irq_domain_map(d, virq, hwirq);
|
||||
}
|
||||
|
||||
void gic_irq_domain_free(struct irq_domain *d, unsigned int virq,
|
||||
static void gic_irq_domain_free(struct irq_domain *d, unsigned int virq,
|
||||
unsigned int nr_irqs)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -377,8 +377,7 @@ static int mvebu_sei_probe(struct platform_device *pdev)
|
||||
mutex_init(&sei->cp_msi_lock);
|
||||
raw_spin_lock_init(&sei->mask_lock);
|
||||
|
||||
sei->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
sei->base = devm_ioremap_resource(sei->dev, sei->res);
|
||||
sei->base = devm_platform_get_and_ioremap_resource(pdev, 0, &sei->res);
|
||||
if (IS_ERR(sei->base))
|
||||
return PTR_ERR(sei->base);
|
||||
|
||||
|
||||
@@ -57,8 +57,7 @@ static int __init orion_irq_init(struct device_node *np,
|
||||
struct resource r;
|
||||
|
||||
/* count number of irq chips by valid reg addresses */
|
||||
while (of_address_to_resource(np, num_chips, &r) == 0)
|
||||
num_chips++;
|
||||
num_chips = of_address_count(np);
|
||||
|
||||
orion_irq_domain = irq_domain_add_linear(np,
|
||||
num_chips * ORION_IRQS_PER_CHIP,
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
/*
|
||||
@@ -565,8 +565,8 @@ static int pruss_intc_probe(struct platform_device *pdev)
|
||||
continue;
|
||||
|
||||
irq = platform_get_irq_byname(pdev, irq_names[i]);
|
||||
if (irq <= 0) {
|
||||
ret = (irq == 0) ? -EINVAL : irq;
|
||||
if (irq < 0) {
|
||||
ret = irq;
|
||||
goto fail_irq;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include <linux/mailbox_client.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#define INTC_IRQPIN_MAX 8 /* maximum 8 interrupts per driver instance */
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include <dt-bindings/interrupt-controller/irq-st.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
@@ -14,10 +14,11 @@
|
||||
#include <linux/irqchip.h>
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/irqchip.h>
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include <linux/irqchip.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
#include <linux/msi.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
#include <linux/soc/ti/ti_sci_inta_msi.h>
|
||||
#include <linux/soc/ti/ti_sci_protocol.h>
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/irqchip.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/soc/ti/ti_sci_protocol.h>
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqchip.h>
|
||||
#include <linux/irqchip/xtensa-pic.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
unsigned int cached_irq_mask;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/irqchip.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/soc/qcom/irq.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
@@ -273,8 +273,8 @@ static void lkdtm_HUNG_TASK(void)
|
||||
schedule();
|
||||
}
|
||||
|
||||
volatile unsigned int huge = INT_MAX - 2;
|
||||
volatile unsigned int ignored;
|
||||
static volatile unsigned int huge = INT_MAX - 2;
|
||||
static volatile unsigned int ignored;
|
||||
|
||||
static void lkdtm_OVERFLOW_SIGNED(void)
|
||||
{
|
||||
@@ -305,7 +305,7 @@ static void lkdtm_OVERFLOW_UNSIGNED(void)
|
||||
ignored = value;
|
||||
}
|
||||
|
||||
/* Intentionally using old-style flex array definition of 1 byte. */
|
||||
/* Intentionally using unannotated flex array definition. */
|
||||
struct array_bounds_flex_array {
|
||||
int one;
|
||||
int two;
|
||||
@@ -357,6 +357,46 @@ static void lkdtm_ARRAY_BOUNDS(void)
|
||||
pr_expected_config(CONFIG_UBSAN_BOUNDS);
|
||||
}
|
||||
|
||||
struct lkdtm_annotated {
|
||||
unsigned long flags;
|
||||
int count;
|
||||
int array[] __counted_by(count);
|
||||
};
|
||||
|
||||
static volatile int fam_count = 4;
|
||||
|
||||
static void lkdtm_FAM_BOUNDS(void)
|
||||
{
|
||||
struct lkdtm_annotated *inst;
|
||||
|
||||
inst = kzalloc(struct_size(inst, array, fam_count + 1), GFP_KERNEL);
|
||||
if (!inst) {
|
||||
pr_err("FAIL: could not allocate test struct!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
inst->count = fam_count;
|
||||
pr_info("Array access within bounds ...\n");
|
||||
inst->array[1] = fam_count;
|
||||
ignored = inst->array[1];
|
||||
|
||||
pr_info("Array access beyond bounds ...\n");
|
||||
inst->array[fam_count] = fam_count;
|
||||
ignored = inst->array[fam_count];
|
||||
|
||||
kfree(inst);
|
||||
|
||||
pr_err("FAIL: survived access of invalid flexible array member index!\n");
|
||||
|
||||
if (!__has_attribute(__counted_by__))
|
||||
pr_warn("This is expected since this %s was built a compiler supporting __counted_by\n",
|
||||
lkdtm_kernel_info);
|
||||
else if (IS_ENABLED(CONFIG_UBSAN_BOUNDS))
|
||||
pr_expected_config(CONFIG_UBSAN_TRAP);
|
||||
else
|
||||
pr_expected_config(CONFIG_UBSAN_BOUNDS);
|
||||
}
|
||||
|
||||
static void lkdtm_CORRUPT_LIST_ADD(void)
|
||||
{
|
||||
/*
|
||||
@@ -393,7 +433,7 @@ static void lkdtm_CORRUPT_LIST_ADD(void)
|
||||
pr_err("Overwrite did not happen, but no BUG?!\n");
|
||||
else {
|
||||
pr_err("list_add() corruption not detected!\n");
|
||||
pr_expected_config(CONFIG_DEBUG_LIST);
|
||||
pr_expected_config(CONFIG_LIST_HARDENED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -420,7 +460,7 @@ static void lkdtm_CORRUPT_LIST_DEL(void)
|
||||
pr_err("Overwrite did not happen, but no BUG?!\n");
|
||||
else {
|
||||
pr_err("list_del() corruption not detected!\n");
|
||||
pr_expected_config(CONFIG_DEBUG_LIST);
|
||||
pr_expected_config(CONFIG_LIST_HARDENED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -616,6 +656,7 @@ static struct crashtype crashtypes[] = {
|
||||
CRASHTYPE(OVERFLOW_SIGNED),
|
||||
CRASHTYPE(OVERFLOW_UNSIGNED),
|
||||
CRASHTYPE(ARRAY_BOUNDS),
|
||||
CRASHTYPE(FAM_BOUNDS),
|
||||
CRASHTYPE(CORRUPT_LIST_ADD),
|
||||
CRASHTYPE(CORRUPT_LIST_DEL),
|
||||
CRASHTYPE(STACK_GUARD_PAGE_LEADING),
|
||||
|
||||
@@ -524,7 +524,7 @@ int qe_upload_firmware(const struct qe_firmware *firmware)
|
||||
* saved microcode information and put in the new.
|
||||
*/
|
||||
memset(&qe_firmware_info, 0, sizeof(qe_firmware_info));
|
||||
strlcpy(qe_firmware_info.id, firmware->id, sizeof(qe_firmware_info.id));
|
||||
strscpy(qe_firmware_info.id, firmware->id, sizeof(qe_firmware_info.id));
|
||||
qe_firmware_info.extended_modes = be64_to_cpu(firmware->extended_modes);
|
||||
memcpy(qe_firmware_info.vtraps, firmware->vtraps,
|
||||
sizeof(firmware->vtraps));
|
||||
@@ -599,7 +599,7 @@ struct qe_firmware_info *qe_get_firmware_info(void)
|
||||
/* Copy the data into qe_firmware_info*/
|
||||
sprop = of_get_property(fw, "id", NULL);
|
||||
if (sprop)
|
||||
strlcpy(qe_firmware_info.id, sprop,
|
||||
strscpy(qe_firmware_info.id, sprop,
|
||||
sizeof(qe_firmware_info.id));
|
||||
|
||||
of_property_read_u64(fw, "extended-modes",
|
||||
|
||||
@@ -94,6 +94,19 @@
|
||||
# define __copy(symbol)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Optional: only supported since gcc >= 14
|
||||
* Optional: only supported since clang >= 18
|
||||
*
|
||||
* gcc: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108896
|
||||
* clang: https://reviews.llvm.org/D148381
|
||||
*/
|
||||
#if __has_attribute(__counted_by__)
|
||||
# define __counted_by(member) __attribute__((__counted_by__(member)))
|
||||
#else
|
||||
# define __counted_by(member)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Optional: not supported by gcc
|
||||
* Optional: only supported since clang >= 14.0
|
||||
@@ -129,19 +142,6 @@
|
||||
# define __designated_init
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Optional: only supported since gcc >= 14
|
||||
* Optional: only supported since clang >= 17
|
||||
*
|
||||
* gcc: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108896
|
||||
* clang: https://reviews.llvm.org/D148381
|
||||
*/
|
||||
#if __has_attribute(__element_count__)
|
||||
# define __counted_by(member) __attribute__((__element_count__(#member)))
|
||||
#else
|
||||
# define __counted_by(member)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Optional: only supported since clang >= 14.0
|
||||
*
|
||||
|
||||
@@ -106,6 +106,34 @@ static inline void __chk_io_ptr(const volatile void __iomem *ptr) { }
|
||||
#define __cold
|
||||
#endif
|
||||
|
||||
/*
|
||||
* On x86-64 and arm64 targets, __preserve_most changes the calling convention
|
||||
* of a function to make the code in the caller as unintrusive as possible. This
|
||||
* convention behaves identically to the C calling convention on how arguments
|
||||
* and return values are passed, but uses a different set of caller- and callee-
|
||||
* saved registers.
|
||||
*
|
||||
* The purpose is to alleviates the burden of saving and recovering a large
|
||||
* register set before and after the call in the caller. This is beneficial for
|
||||
* rarely taken slow paths, such as error-reporting functions that may be called
|
||||
* from hot paths.
|
||||
*
|
||||
* Note: This may conflict with instrumentation inserted on function entry which
|
||||
* does not use __preserve_most or equivalent convention (if in assembly). Since
|
||||
* function tracing assumes the normal C calling convention, where the attribute
|
||||
* is supported, __preserve_most implies notrace. It is recommended to restrict
|
||||
* use of the attribute to functions that should or already disable tracing.
|
||||
*
|
||||
* Optional: not supported by gcc.
|
||||
*
|
||||
* clang: https://clang.llvm.org/docs/AttributeReference.html#preserve-most
|
||||
*/
|
||||
#if __has_attribute(__preserve_most__) && (defined(CONFIG_X86_64) || defined(CONFIG_ARM64))
|
||||
# define __preserve_most notrace __attribute__((__preserve_most__))
|
||||
#else
|
||||
# define __preserve_most
|
||||
#endif
|
||||
|
||||
/* Builtins */
|
||||
|
||||
/*
|
||||
|
||||
@@ -116,6 +116,7 @@ extern bool try_wait_for_completion(struct completion *x);
|
||||
extern bool completion_done(struct completion *x);
|
||||
|
||||
extern void complete(struct completion *);
|
||||
extern void complete_on_current_cpu(struct completion *x);
|
||||
extern void complete_all(struct completion *);
|
||||
|
||||
#endif
|
||||
|
||||
+1
-25
@@ -18,6 +18,7 @@
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/cpuhotplug.h>
|
||||
#include <linux/cpu_smt.h>
|
||||
|
||||
struct device;
|
||||
struct device_node;
|
||||
@@ -194,7 +195,6 @@ void arch_cpu_finalize_init(void);
|
||||
static inline void arch_cpu_finalize_init(void) { }
|
||||
#endif
|
||||
|
||||
void cpu_set_state_online(int cpu);
|
||||
void play_idle_precise(u64 duration_ns, u64 latency_ns);
|
||||
|
||||
static inline void play_idle(unsigned long duration_us)
|
||||
@@ -208,30 +208,6 @@ void cpuhp_report_idle_dead(void);
|
||||
static inline void cpuhp_report_idle_dead(void) { }
|
||||
#endif /* #ifdef CONFIG_HOTPLUG_CPU */
|
||||
|
||||
enum cpuhp_smt_control {
|
||||
CPU_SMT_ENABLED,
|
||||
CPU_SMT_DISABLED,
|
||||
CPU_SMT_FORCE_DISABLED,
|
||||
CPU_SMT_NOT_SUPPORTED,
|
||||
CPU_SMT_NOT_IMPLEMENTED,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_SMP) && defined(CONFIG_HOTPLUG_SMT)
|
||||
extern enum cpuhp_smt_control cpu_smt_control;
|
||||
extern void cpu_smt_disable(bool force);
|
||||
extern void cpu_smt_check_topology(void);
|
||||
extern bool cpu_smt_possible(void);
|
||||
extern int cpuhp_smt_enable(void);
|
||||
extern int cpuhp_smt_disable(enum cpuhp_smt_control ctrlval);
|
||||
#else
|
||||
# define cpu_smt_control (CPU_SMT_NOT_IMPLEMENTED)
|
||||
static inline void cpu_smt_disable(bool force) { }
|
||||
static inline void cpu_smt_check_topology(void) { }
|
||||
static inline bool cpu_smt_possible(void) { return false; }
|
||||
static inline int cpuhp_smt_enable(void) { return 0; }
|
||||
static inline int cpuhp_smt_disable(enum cpuhp_smt_control ctrlval) { return 0; }
|
||||
#endif
|
||||
|
||||
extern bool cpu_mitigations_off(void);
|
||||
extern bool cpu_mitigations_auto_nosmt(void);
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _LINUX_CPU_SMT_H_
|
||||
#define _LINUX_CPU_SMT_H_
|
||||
|
||||
enum cpuhp_smt_control {
|
||||
CPU_SMT_ENABLED,
|
||||
CPU_SMT_DISABLED,
|
||||
CPU_SMT_FORCE_DISABLED,
|
||||
CPU_SMT_NOT_SUPPORTED,
|
||||
CPU_SMT_NOT_IMPLEMENTED,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_SMP) && defined(CONFIG_HOTPLUG_SMT)
|
||||
extern enum cpuhp_smt_control cpu_smt_control;
|
||||
extern unsigned int cpu_smt_num_threads;
|
||||
extern void cpu_smt_disable(bool force);
|
||||
extern void cpu_smt_set_num_threads(unsigned int num_threads,
|
||||
unsigned int max_threads);
|
||||
extern bool cpu_smt_possible(void);
|
||||
extern int cpuhp_smt_enable(void);
|
||||
extern int cpuhp_smt_disable(enum cpuhp_smt_control ctrlval);
|
||||
#else
|
||||
# define cpu_smt_control (CPU_SMT_NOT_IMPLEMENTED)
|
||||
# define cpu_smt_num_threads 1
|
||||
static inline void cpu_smt_disable(bool force) { }
|
||||
static inline void cpu_smt_set_num_threads(unsigned int num_threads,
|
||||
unsigned int max_threads) { }
|
||||
static inline bool cpu_smt_possible(void) { return false; }
|
||||
static inline int cpuhp_smt_enable(void) { return 0; }
|
||||
static inline int cpuhp_smt_disable(enum cpuhp_smt_control ctrlval) { return 0; }
|
||||
#endif
|
||||
|
||||
#endif /* _LINUX_CPU_SMT_H_ */
|
||||
@@ -48,7 +48,7 @@
|
||||
* same section.
|
||||
*
|
||||
* If neither #1 nor #2 apply, please use the dynamic state space when
|
||||
* setting up a state by using CPUHP_PREPARE_DYN or CPUHP_PREPARE_ONLINE
|
||||
* setting up a state by using CPUHP_BP_PREPARE_DYN or CPUHP_AP_ONLINE_DYN
|
||||
* for the @state argument of the setup function.
|
||||
*
|
||||
* See Documentation/core-api/cpu_hotplug.rst for further information and
|
||||
|
||||
@@ -12,7 +12,7 @@ extern struct list_head dm_verity_loadpin_trusted_root_digests;
|
||||
struct dm_verity_loadpin_trusted_root_digest {
|
||||
struct list_head node;
|
||||
unsigned int len;
|
||||
u8 data[];
|
||||
u8 data[] __counted_by(len);
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_SECURITY_LOADPIN_VERITY)
|
||||
|
||||
+85
-4
@@ -38,11 +38,92 @@ static inline void INIT_LIST_HEAD(struct list_head *list)
|
||||
WRITE_ONCE(list->prev, list);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_LIST_HARDENED
|
||||
|
||||
#ifdef CONFIG_DEBUG_LIST
|
||||
extern bool __list_add_valid(struct list_head *new,
|
||||
struct list_head *prev,
|
||||
struct list_head *next);
|
||||
extern bool __list_del_entry_valid(struct list_head *entry);
|
||||
# define __list_valid_slowpath
|
||||
#else
|
||||
# define __list_valid_slowpath __cold __preserve_most
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Performs the full set of list corruption checks before __list_add().
|
||||
* On list corruption reports a warning, and returns false.
|
||||
*/
|
||||
extern bool __list_valid_slowpath __list_add_valid_or_report(struct list_head *new,
|
||||
struct list_head *prev,
|
||||
struct list_head *next);
|
||||
|
||||
/*
|
||||
* Performs list corruption checks before __list_add(). Returns false if a
|
||||
* corruption is detected, true otherwise.
|
||||
*
|
||||
* With CONFIG_LIST_HARDENED only, performs minimal list integrity checking
|
||||
* inline to catch non-faulting corruptions, and only if a corruption is
|
||||
* detected calls the reporting function __list_add_valid_or_report().
|
||||
*/
|
||||
static __always_inline bool __list_add_valid(struct list_head *new,
|
||||
struct list_head *prev,
|
||||
struct list_head *next)
|
||||
{
|
||||
bool ret = true;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_DEBUG_LIST)) {
|
||||
/*
|
||||
* With the hardening version, elide checking if next and prev
|
||||
* are NULL, since the immediate dereference of them below would
|
||||
* result in a fault if NULL.
|
||||
*
|
||||
* With the reduced set of checks, we can afford to inline the
|
||||
* checks, which also gives the compiler a chance to elide some
|
||||
* of them completely if they can be proven at compile-time. If
|
||||
* one of the pre-conditions does not hold, the slow-path will
|
||||
* show a report which pre-condition failed.
|
||||
*/
|
||||
if (likely(next->prev == prev && prev->next == next && new != prev && new != next))
|
||||
return true;
|
||||
ret = false;
|
||||
}
|
||||
|
||||
ret &= __list_add_valid_or_report(new, prev, next);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Performs the full set of list corruption checks before __list_del_entry().
|
||||
* On list corruption reports a warning, and returns false.
|
||||
*/
|
||||
extern bool __list_valid_slowpath __list_del_entry_valid_or_report(struct list_head *entry);
|
||||
|
||||
/*
|
||||
* Performs list corruption checks before __list_del_entry(). Returns false if a
|
||||
* corruption is detected, true otherwise.
|
||||
*
|
||||
* With CONFIG_LIST_HARDENED only, performs minimal list integrity checking
|
||||
* inline to catch non-faulting corruptions, and only if a corruption is
|
||||
* detected calls the reporting function __list_del_entry_valid_or_report().
|
||||
*/
|
||||
static __always_inline bool __list_del_entry_valid(struct list_head *entry)
|
||||
{
|
||||
bool ret = true;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_DEBUG_LIST)) {
|
||||
struct list_head *prev = entry->prev;
|
||||
struct list_head *next = entry->next;
|
||||
|
||||
/*
|
||||
* With the hardening version, elide checking if next and prev
|
||||
* are NULL, LIST_POISON1 or LIST_POISON2, since the immediate
|
||||
* dereference of them below would result in a fault.
|
||||
*/
|
||||
if (likely(prev->next == entry && next->prev == entry))
|
||||
return true;
|
||||
ret = false;
|
||||
}
|
||||
|
||||
ret &= __list_del_entry_valid_or_report(entry);
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
static inline bool __list_add_valid(struct list_head *new,
|
||||
struct list_head *prev,
|
||||
|
||||
@@ -73,9 +73,7 @@ struct raw_notifier_head {
|
||||
|
||||
struct srcu_notifier_head {
|
||||
struct mutex mutex;
|
||||
#ifdef CONFIG_TREE_SRCU
|
||||
struct srcu_usage srcuu;
|
||||
#endif
|
||||
struct srcu_struct srcu;
|
||||
struct notifier_block __rcu *head;
|
||||
};
|
||||
@@ -106,7 +104,6 @@ extern void srcu_init_notifier_head(struct srcu_notifier_head *nh);
|
||||
#define RAW_NOTIFIER_INIT(name) { \
|
||||
.head = NULL }
|
||||
|
||||
#ifdef CONFIG_TREE_SRCU
|
||||
#define SRCU_NOTIFIER_INIT(name, pcpu) \
|
||||
{ \
|
||||
.mutex = __MUTEX_INITIALIZER(name.mutex), \
|
||||
@@ -114,14 +111,6 @@ extern void srcu_init_notifier_head(struct srcu_notifier_head *nh);
|
||||
.srcuu = __SRCU_USAGE_INIT(name.srcuu), \
|
||||
.srcu = __SRCU_STRUCT_INIT(name.srcu, name.srcuu, pcpu), \
|
||||
}
|
||||
#else
|
||||
#define SRCU_NOTIFIER_INIT(name, pcpu) \
|
||||
{ \
|
||||
.mutex = __MUTEX_INITIALIZER(name.mutex), \
|
||||
.head = NULL, \
|
||||
.srcu = __SRCU_STRUCT_INIT(name.srcu, name.srcuu, pcpu), \
|
||||
}
|
||||
#endif
|
||||
|
||||
#define ATOMIC_NOTIFIER_HEAD(name) \
|
||||
struct atomic_notifier_head name = \
|
||||
|
||||
@@ -29,7 +29,7 @@ struct fs_struct;
|
||||
* nsproxy is copied.
|
||||
*/
|
||||
struct nsproxy {
|
||||
atomic_t count;
|
||||
refcount_t count;
|
||||
struct uts_namespace *uts_ns;
|
||||
struct ipc_namespace *ipc_ns;
|
||||
struct mnt_namespace *mnt_ns;
|
||||
@@ -102,14 +102,13 @@ int __init nsproxy_cache_init(void);
|
||||
|
||||
static inline void put_nsproxy(struct nsproxy *ns)
|
||||
{
|
||||
if (atomic_dec_and_test(&ns->count)) {
|
||||
if (refcount_dec_and_test(&ns->count))
|
||||
free_nsproxy(ns);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void get_nsproxy(struct nsproxy *ns)
|
||||
{
|
||||
atomic_inc(&ns->count);
|
||||
refcount_inc(&ns->count);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -101,7 +101,7 @@ static inline void hlist_nulls_add_head_rcu(struct hlist_nulls_node *n,
|
||||
{
|
||||
struct hlist_nulls_node *first = h->first;
|
||||
|
||||
n->next = first;
|
||||
WRITE_ONCE(n->next, first);
|
||||
WRITE_ONCE(n->pprev, &h->first);
|
||||
rcu_assign_pointer(hlist_nulls_first_rcu(h), n);
|
||||
if (!is_a_nulls(first))
|
||||
@@ -137,7 +137,7 @@ static inline void hlist_nulls_add_tail_rcu(struct hlist_nulls_node *n,
|
||||
last = i;
|
||||
|
||||
if (last) {
|
||||
n->next = last->next;
|
||||
WRITE_ONCE(n->next, last->next);
|
||||
n->pprev = &last->next;
|
||||
rcu_assign_pointer(hlist_nulls_next_rcu(last), n);
|
||||
} else {
|
||||
|
||||
@@ -87,6 +87,7 @@ static inline void rcu_read_unlock_trace(void)
|
||||
void call_rcu_tasks_trace(struct rcu_head *rhp, rcu_callback_t func);
|
||||
void synchronize_rcu_tasks_trace(void);
|
||||
void rcu_barrier_tasks_trace(void);
|
||||
struct task_struct *get_rcu_tasks_trace_gp_kthread(void);
|
||||
#else
|
||||
/*
|
||||
* The BPF JIT forms these addresses even when it doesn't call these
|
||||
|
||||
@@ -42,6 +42,11 @@ do { \
|
||||
* call_srcu() function, with this wrapper supplying the pointer to the
|
||||
* corresponding srcu_struct.
|
||||
*
|
||||
* Note that call_rcu_hurry() should be used instead of call_rcu()
|
||||
* because in kernels built with CONFIG_RCU_LAZY=y the delay between the
|
||||
* invocation of call_rcu() and that of the corresponding RCU callback
|
||||
* can be multiple seconds.
|
||||
*
|
||||
* The first argument tells Tiny RCU's _wait_rcu_gp() not to
|
||||
* bother waiting for RCU. The reason for this is because anywhere
|
||||
* synchronize_rcu_mult() can be called is automatically already a full
|
||||
|
||||
@@ -249,18 +249,19 @@ static inline void seq_show_option(struct seq_file *m, const char *name,
|
||||
|
||||
/**
|
||||
* seq_show_option_n - display mount options with appropriate escapes
|
||||
* where @value must be a specific length.
|
||||
* where @value must be a specific length (i.e.
|
||||
* not NUL-terminated).
|
||||
* @m: the seq_file handle
|
||||
* @name: the mount option name
|
||||
* @value: the mount option name's value, cannot be NULL
|
||||
* @length: the length of @value to display
|
||||
* @length: the exact length of @value to display, must be constant expression
|
||||
*
|
||||
* This is a macro since this uses "length" to define the size of the
|
||||
* stack buffer.
|
||||
*/
|
||||
#define seq_show_option_n(m, name, value, length) { \
|
||||
char val_buf[length + 1]; \
|
||||
strncpy(val_buf, value, length); \
|
||||
memcpy(val_buf, value, length); \
|
||||
val_buf[length] = '\0'; \
|
||||
seq_show_option(m, name, val_buf); \
|
||||
}
|
||||
|
||||
@@ -48,6 +48,10 @@ void srcu_drive_gp(struct work_struct *wp);
|
||||
#define DEFINE_STATIC_SRCU(name) \
|
||||
static struct srcu_struct name = __SRCU_STRUCT_INIT(name, name, name)
|
||||
|
||||
// Dummy structure for srcu_notifier_head.
|
||||
struct srcu_usage { };
|
||||
#define __SRCU_USAGE_INIT(name) { }
|
||||
|
||||
void synchronize_srcu(struct srcu_struct *ssp);
|
||||
|
||||
/*
|
||||
|
||||
@@ -146,7 +146,7 @@ static inline bool swq_has_sleeper(struct swait_queue_head *wq)
|
||||
|
||||
extern void swake_up_one(struct swait_queue_head *q);
|
||||
extern void swake_up_all(struct swait_queue_head *q);
|
||||
extern void swake_up_locked(struct swait_queue_head *q);
|
||||
extern void swake_up_locked(struct swait_queue_head *q, int wake_flags);
|
||||
|
||||
extern void prepare_to_swait_exclusive(struct swait_queue_head *q, struct swait_queue *wait, int state);
|
||||
extern long prepare_to_swait_event(struct swait_queue_head *q, struct swait_queue *wait, int state);
|
||||
|
||||
@@ -283,22 +283,6 @@ static inline int is_syscall_trace_event(struct trace_event_call *tp_event)
|
||||
#define SYSCALL32_DEFINE6 SYSCALL_DEFINE6
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Called before coming back to user-mode. Returning to user-mode with an
|
||||
* address limit different than USER_DS can allow to overwrite kernel memory.
|
||||
*/
|
||||
static inline void addr_limit_user_check(void)
|
||||
{
|
||||
#ifdef TIF_FSCHECK
|
||||
if (!test_thread_flag(TIF_FSCHECK))
|
||||
return;
|
||||
#endif
|
||||
|
||||
#ifdef TIF_FSCHECK
|
||||
clear_thread_flag(TIF_FSCHECK);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* These syscall function prototypes are kept in the same order as
|
||||
* include/uapi/asm-generic/unistd.h. Architecture specific entries go below,
|
||||
|
||||
@@ -108,12 +108,15 @@ bool torture_must_stop(void);
|
||||
bool torture_must_stop_irq(void);
|
||||
void torture_kthread_stopping(char *title);
|
||||
int _torture_create_kthread(int (*fn)(void *arg), void *arg, char *s, char *m,
|
||||
char *f, struct task_struct **tp);
|
||||
char *f, struct task_struct **tp, void (*cbf)(struct task_struct *tp));
|
||||
void _torture_stop_kthread(char *m, struct task_struct **tp);
|
||||
|
||||
#define torture_create_kthread(n, arg, tp) \
|
||||
_torture_create_kthread(n, (arg), #n, "Creating " #n " task", \
|
||||
"Failed to create " #n, &(tp))
|
||||
"Failed to create " #n, &(tp), NULL)
|
||||
#define torture_create_kthread_cb(n, arg, tp, cbf) \
|
||||
_torture_create_kthread(n, (arg), #n, "Creating " #n " task", \
|
||||
"Failed to create " #n, &(tp), cbf)
|
||||
#define torture_stop_kthread(n, tp) \
|
||||
_torture_stop_kthread("Stopping " #n " task", &(tp))
|
||||
|
||||
|
||||
@@ -210,6 +210,7 @@ __remove_wait_queue(struct wait_queue_head *wq_head, struct wait_queue_entry *wq
|
||||
}
|
||||
|
||||
int __wake_up(struct wait_queue_head *wq_head, unsigned int mode, int nr, void *key);
|
||||
void __wake_up_on_current_cpu(struct wait_queue_head *wq_head, unsigned int mode, void *key);
|
||||
void __wake_up_locked_key(struct wait_queue_head *wq_head, unsigned int mode, void *key);
|
||||
void __wake_up_locked_key_bookmark(struct wait_queue_head *wq_head,
|
||||
unsigned int mode, void *key, wait_queue_entry_t *bookmark);
|
||||
@@ -238,6 +239,8 @@ void __wake_up_pollfree(struct wait_queue_head *wq_head);
|
||||
#define key_to_poll(m) ((__force __poll_t)(uintptr_t)(void *)(m))
|
||||
#define wake_up_poll(x, m) \
|
||||
__wake_up(x, TASK_NORMAL, 1, poll_to_key(m))
|
||||
#define wake_up_poll_on_current_cpu(x, m) \
|
||||
__wake_up_on_current_cpu(x, TASK_NORMAL, poll_to_key(m))
|
||||
#define wake_up_locked_poll(x, m) \
|
||||
__wake_up_locked_key((x), TASK_NORMAL, poll_to_key(m))
|
||||
#define wake_up_interruptible_poll(x, m) \
|
||||
|
||||
@@ -115,6 +115,8 @@ struct seccomp_notif_resp {
|
||||
__u32 flags;
|
||||
};
|
||||
|
||||
#define SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP (1UL << 0)
|
||||
|
||||
/* valid flags for seccomp_notif_addfd */
|
||||
#define SECCOMP_ADDFD_FLAG_SETFD (1UL << 0) /* Specify remote fd */
|
||||
#define SECCOMP_ADDFD_FLAG_SEND (1UL << 1) /* Addfd and return it, atomically */
|
||||
@@ -150,4 +152,6 @@ struct seccomp_notif_addfd {
|
||||
#define SECCOMP_IOCTL_NOTIF_ADDFD SECCOMP_IOW(3, \
|
||||
struct seccomp_notif_addfd)
|
||||
|
||||
#define SECCOMP_IOCTL_NOTIF_SET_FLAGS SECCOMP_IOW(4, __u64)
|
||||
|
||||
#endif /* _UAPI_LINUX_SECCOMP_H */
|
||||
|
||||
@@ -45,3 +45,7 @@
|
||||
TYPE NAME[]; \
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef __counted_by
|
||||
#define __counted_by(m)
|
||||
#endif
|
||||
|
||||
+105
-39
@@ -592,7 +592,10 @@ static void lockdep_release_cpus_lock(void)
|
||||
void __weak arch_smt_update(void) { }
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_SMT
|
||||
|
||||
enum cpuhp_smt_control cpu_smt_control __read_mostly = CPU_SMT_ENABLED;
|
||||
static unsigned int cpu_smt_max_threads __ro_after_init;
|
||||
unsigned int cpu_smt_num_threads __read_mostly = UINT_MAX;
|
||||
|
||||
void __init cpu_smt_disable(bool force)
|
||||
{
|
||||
@@ -606,16 +609,33 @@ void __init cpu_smt_disable(bool force)
|
||||
pr_info("SMT: disabled\n");
|
||||
cpu_smt_control = CPU_SMT_DISABLED;
|
||||
}
|
||||
cpu_smt_num_threads = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The decision whether SMT is supported can only be done after the full
|
||||
* CPU identification. Called from architecture code.
|
||||
*/
|
||||
void __init cpu_smt_check_topology(void)
|
||||
void __init cpu_smt_set_num_threads(unsigned int num_threads,
|
||||
unsigned int max_threads)
|
||||
{
|
||||
if (!topology_smt_supported())
|
||||
WARN_ON(!num_threads || (num_threads > max_threads));
|
||||
|
||||
if (max_threads == 1)
|
||||
cpu_smt_control = CPU_SMT_NOT_SUPPORTED;
|
||||
|
||||
cpu_smt_max_threads = max_threads;
|
||||
|
||||
/*
|
||||
* If SMT has been disabled via the kernel command line or SMT is
|
||||
* not supported, set cpu_smt_num_threads to 1 for consistency.
|
||||
* If enabled, take the architecture requested number of threads
|
||||
* to bring up into account.
|
||||
*/
|
||||
if (cpu_smt_control != CPU_SMT_ENABLED)
|
||||
cpu_smt_num_threads = 1;
|
||||
else if (num_threads < cpu_smt_num_threads)
|
||||
cpu_smt_num_threads = num_threads;
|
||||
}
|
||||
|
||||
static int __init smt_cmdline_disable(char *str)
|
||||
@@ -625,9 +645,23 @@ static int __init smt_cmdline_disable(char *str)
|
||||
}
|
||||
early_param("nosmt", smt_cmdline_disable);
|
||||
|
||||
/*
|
||||
* For Archicture supporting partial SMT states check if the thread is allowed.
|
||||
* Otherwise this has already been checked through cpu_smt_max_threads when
|
||||
* setting the SMT level.
|
||||
*/
|
||||
static inline bool cpu_smt_thread_allowed(unsigned int cpu)
|
||||
{
|
||||
#ifdef CONFIG_SMT_NUM_THREADS_DYNAMIC
|
||||
return topology_smt_thread_allowed(cpu);
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool cpu_smt_allowed(unsigned int cpu)
|
||||
{
|
||||
if (cpu_smt_control == CPU_SMT_ENABLED)
|
||||
if (cpu_smt_control == CPU_SMT_ENABLED && cpu_smt_thread_allowed(cpu))
|
||||
return true;
|
||||
|
||||
if (topology_is_primary_thread(cpu))
|
||||
@@ -642,7 +676,7 @@ static inline bool cpu_smt_allowed(unsigned int cpu)
|
||||
return !cpumask_test_cpu(cpu, &cpus_booted_once_mask);
|
||||
}
|
||||
|
||||
/* Returns true if SMT is not supported of forcefully (irreversibly) disabled */
|
||||
/* Returns true if SMT is supported and not forcefully (irreversibly) disabled */
|
||||
bool cpu_smt_possible(void)
|
||||
{
|
||||
return cpu_smt_control != CPU_SMT_FORCE_DISABLED &&
|
||||
@@ -650,22 +684,8 @@ bool cpu_smt_possible(void)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cpu_smt_possible);
|
||||
|
||||
static inline bool cpuhp_smt_aware(void)
|
||||
{
|
||||
return topology_smt_supported();
|
||||
}
|
||||
|
||||
static inline const struct cpumask *cpuhp_get_primary_thread_mask(void)
|
||||
{
|
||||
return cpu_primary_thread_mask;
|
||||
}
|
||||
#else
|
||||
static inline bool cpu_smt_allowed(unsigned int cpu) { return true; }
|
||||
static inline bool cpuhp_smt_aware(void) { return false; }
|
||||
static inline const struct cpumask *cpuhp_get_primary_thread_mask(void)
|
||||
{
|
||||
return cpu_present_mask;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline enum cpuhp_state
|
||||
@@ -1793,6 +1813,16 @@ static int __init parallel_bringup_parse_param(char *arg)
|
||||
}
|
||||
early_param("cpuhp.parallel", parallel_bringup_parse_param);
|
||||
|
||||
static inline bool cpuhp_smt_aware(void)
|
||||
{
|
||||
return cpu_smt_max_threads > 1;
|
||||
}
|
||||
|
||||
static inline const struct cpumask *cpuhp_get_primary_thread_mask(void)
|
||||
{
|
||||
return cpu_primary_thread_mask;
|
||||
}
|
||||
|
||||
/*
|
||||
* On architectures which have enabled parallel bringup this invokes all BP
|
||||
* prepare states for each of the to be onlined APs first. The last state
|
||||
@@ -2626,6 +2656,12 @@ int cpuhp_smt_disable(enum cpuhp_smt_control ctrlval)
|
||||
for_each_online_cpu(cpu) {
|
||||
if (topology_is_primary_thread(cpu))
|
||||
continue;
|
||||
/*
|
||||
* Disable can be called with CPU_SMT_ENABLED when changing
|
||||
* from a higher to lower number of SMT threads per core.
|
||||
*/
|
||||
if (ctrlval == CPU_SMT_ENABLED && cpu_smt_thread_allowed(cpu))
|
||||
continue;
|
||||
ret = cpu_down_maps_locked(cpu, CPUHP_OFFLINE);
|
||||
if (ret)
|
||||
break;
|
||||
@@ -2660,6 +2696,8 @@ int cpuhp_smt_enable(void)
|
||||
/* Skip online CPUs and CPUs on offline nodes */
|
||||
if (cpu_online(cpu) || !node_online(cpu_to_node(cpu)))
|
||||
continue;
|
||||
if (!cpu_smt_thread_allowed(cpu))
|
||||
continue;
|
||||
ret = _cpu_up(cpu, 0, CPUHP_ONLINE);
|
||||
if (ret)
|
||||
break;
|
||||
@@ -2838,20 +2876,19 @@ static const struct attribute_group cpuhp_cpu_root_attr_group = {
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_SMT
|
||||
|
||||
static bool cpu_smt_num_threads_valid(unsigned int threads)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_SMT_NUM_THREADS_DYNAMIC))
|
||||
return threads >= 1 && threads <= cpu_smt_max_threads;
|
||||
return threads == 1 || threads == cpu_smt_max_threads;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
__store_smt_control(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int ctrlval, ret;
|
||||
|
||||
if (sysfs_streq(buf, "on"))
|
||||
ctrlval = CPU_SMT_ENABLED;
|
||||
else if (sysfs_streq(buf, "off"))
|
||||
ctrlval = CPU_SMT_DISABLED;
|
||||
else if (sysfs_streq(buf, "forceoff"))
|
||||
ctrlval = CPU_SMT_FORCE_DISABLED;
|
||||
else
|
||||
return -EINVAL;
|
||||
int ctrlval, ret, num_threads, orig_threads;
|
||||
bool force_off;
|
||||
|
||||
if (cpu_smt_control == CPU_SMT_FORCE_DISABLED)
|
||||
return -EPERM;
|
||||
@@ -2859,21 +2896,39 @@ __store_smt_control(struct device *dev, struct device_attribute *attr,
|
||||
if (cpu_smt_control == CPU_SMT_NOT_SUPPORTED)
|
||||
return -ENODEV;
|
||||
|
||||
if (sysfs_streq(buf, "on")) {
|
||||
ctrlval = CPU_SMT_ENABLED;
|
||||
num_threads = cpu_smt_max_threads;
|
||||
} else if (sysfs_streq(buf, "off")) {
|
||||
ctrlval = CPU_SMT_DISABLED;
|
||||
num_threads = 1;
|
||||
} else if (sysfs_streq(buf, "forceoff")) {
|
||||
ctrlval = CPU_SMT_FORCE_DISABLED;
|
||||
num_threads = 1;
|
||||
} else if (kstrtoint(buf, 10, &num_threads) == 0) {
|
||||
if (num_threads == 1)
|
||||
ctrlval = CPU_SMT_DISABLED;
|
||||
else if (cpu_smt_num_threads_valid(num_threads))
|
||||
ctrlval = CPU_SMT_ENABLED;
|
||||
else
|
||||
return -EINVAL;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = lock_device_hotplug_sysfs();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (ctrlval != cpu_smt_control) {
|
||||
switch (ctrlval) {
|
||||
case CPU_SMT_ENABLED:
|
||||
ret = cpuhp_smt_enable();
|
||||
break;
|
||||
case CPU_SMT_DISABLED:
|
||||
case CPU_SMT_FORCE_DISABLED:
|
||||
ret = cpuhp_smt_disable(ctrlval);
|
||||
break;
|
||||
}
|
||||
}
|
||||
orig_threads = cpu_smt_num_threads;
|
||||
cpu_smt_num_threads = num_threads;
|
||||
|
||||
force_off = ctrlval != cpu_smt_control && ctrlval == CPU_SMT_FORCE_DISABLED;
|
||||
|
||||
if (num_threads > orig_threads)
|
||||
ret = cpuhp_smt_enable();
|
||||
else if (num_threads < orig_threads || force_off)
|
||||
ret = cpuhp_smt_disable(ctrlval);
|
||||
|
||||
unlock_device_hotplug();
|
||||
return ret ? ret : count;
|
||||
@@ -2901,6 +2956,17 @@ static ssize_t control_show(struct device *dev,
|
||||
{
|
||||
const char *state = smt_states[cpu_smt_control];
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_SMT
|
||||
/*
|
||||
* If SMT is enabled but not all threads are enabled then show the
|
||||
* number of threads. If all threads are enabled show "on". Otherwise
|
||||
* show the state name.
|
||||
*/
|
||||
if (cpu_smt_control == CPU_SMT_ENABLED &&
|
||||
cpu_smt_num_threads != cpu_smt_max_threads)
|
||||
return sysfs_emit(buf, "%d\n", cpu_smt_num_threads);
|
||||
#endif
|
||||
|
||||
return snprintf(buf, PAGE_SIZE - 2, "%s\n", state);
|
||||
}
|
||||
|
||||
|
||||
@@ -205,8 +205,7 @@ static void exit_to_user_mode_prepare(struct pt_regs *regs)
|
||||
|
||||
arch_exit_to_user_mode_prepare(regs, ti_work);
|
||||
|
||||
/* Ensure that the address limit is intact and no locks are held */
|
||||
addr_limit_user_check();
|
||||
/* Ensure that kernel state is sane for a return to userspace */
|
||||
kmap_assert_nomap();
|
||||
lockdep_assert_irqs_disabled();
|
||||
lockdep_sys_exit();
|
||||
|
||||
@@ -8235,7 +8235,7 @@ static void perf_event_comm_event(struct perf_comm_event *comm_event)
|
||||
unsigned int size;
|
||||
|
||||
memset(comm, 0, sizeof(comm));
|
||||
strlcpy(comm, comm_event->task->comm, sizeof(comm));
|
||||
strscpy(comm, comm_event->task->comm, sizeof(comm));
|
||||
size = ALIGN(strlen(comm)+1, sizeof(u64));
|
||||
|
||||
comm_event->comm = comm;
|
||||
@@ -8690,7 +8690,7 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event)
|
||||
}
|
||||
|
||||
cpy_name:
|
||||
strlcpy(tmp, name, sizeof(tmp));
|
||||
strscpy(tmp, name, sizeof(tmp));
|
||||
name = tmp;
|
||||
got_name:
|
||||
/*
|
||||
@@ -9114,7 +9114,7 @@ void perf_event_ksymbol(u16 ksym_type, u64 addr, u32 len, bool unregister,
|
||||
ksym_type == PERF_RECORD_KSYMBOL_TYPE_UNKNOWN)
|
||||
goto err;
|
||||
|
||||
strlcpy(name, sym, KSYM_NAME_LEN);
|
||||
strscpy(name, sym, KSYM_NAME_LEN);
|
||||
name_len = strlen(name) + 1;
|
||||
while (!IS_ALIGNED(name_len, sizeof(u64)))
|
||||
name[name_len++] = '\0';
|
||||
|
||||
+4
-7
@@ -474,11 +474,12 @@ void handle_nested_irq(unsigned int irq)
|
||||
action = desc->action;
|
||||
if (unlikely(!action || irqd_irq_disabled(&desc->irq_data))) {
|
||||
desc->istate |= IRQS_PENDING;
|
||||
goto out_unlock;
|
||||
raw_spin_unlock_irq(&desc->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
kstat_incr_irqs_this_cpu(desc);
|
||||
irqd_set(&desc->irq_data, IRQD_IRQ_INPROGRESS);
|
||||
atomic_inc(&desc->threads_active);
|
||||
raw_spin_unlock_irq(&desc->lock);
|
||||
|
||||
action_ret = IRQ_NONE;
|
||||
@@ -488,11 +489,7 @@ void handle_nested_irq(unsigned int irq)
|
||||
if (!irq_settings_no_debug(desc))
|
||||
note_interrupt(desc, action_ret);
|
||||
|
||||
raw_spin_lock_irq(&desc->lock);
|
||||
irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS);
|
||||
|
||||
out_unlock:
|
||||
raw_spin_unlock_irq(&desc->lock);
|
||||
wake_threads_waitq(desc);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(handle_nested_irq);
|
||||
|
||||
|
||||
@@ -108,8 +108,6 @@ extern int __irq_get_irqchip_state(struct irq_data *data,
|
||||
enum irqchip_irq_state which,
|
||||
bool *state);
|
||||
|
||||
extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr);
|
||||
|
||||
irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc);
|
||||
irqreturn_t handle_irq_event_percpu(struct irq_desc *desc);
|
||||
irqreturn_t handle_irq_event(struct irq_desc *desc);
|
||||
@@ -121,6 +119,8 @@ void irq_resend_init(struct irq_desc *desc);
|
||||
bool irq_wait_for_poll(struct irq_desc *desc);
|
||||
void __irq_wake_thread(struct irq_desc *desc, struct irqaction *action);
|
||||
|
||||
void wake_threads_waitq(struct irq_desc *desc);
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
extern void register_irq_proc(unsigned int irq, struct irq_desc *desc);
|
||||
extern void unregister_irq_proc(unsigned int irq, struct irq_desc *desc);
|
||||
|
||||
+14
-12
@@ -108,6 +108,16 @@ bool synchronize_hardirq(unsigned int irq)
|
||||
}
|
||||
EXPORT_SYMBOL(synchronize_hardirq);
|
||||
|
||||
static void __synchronize_irq(struct irq_desc *desc)
|
||||
{
|
||||
__synchronize_hardirq(desc, true);
|
||||
/*
|
||||
* We made sure that no hardirq handler is running. Now verify that no
|
||||
* threaded handlers are active.
|
||||
*/
|
||||
wait_event(desc->wait_for_threads, !atomic_read(&desc->threads_active));
|
||||
}
|
||||
|
||||
/**
|
||||
* synchronize_irq - wait for pending IRQ handlers (on other CPUs)
|
||||
* @irq: interrupt number to wait for
|
||||
@@ -127,16 +137,8 @@ void synchronize_irq(unsigned int irq)
|
||||
{
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
|
||||
if (desc) {
|
||||
__synchronize_hardirq(desc, true);
|
||||
/*
|
||||
* We made sure that no hardirq handler is
|
||||
* running. Now verify that no threaded handlers are
|
||||
* active.
|
||||
*/
|
||||
wait_event(desc->wait_for_threads,
|
||||
!atomic_read(&desc->threads_active));
|
||||
}
|
||||
if (desc)
|
||||
__synchronize_irq(desc);
|
||||
}
|
||||
EXPORT_SYMBOL(synchronize_irq);
|
||||
|
||||
@@ -1216,7 +1218,7 @@ static irqreturn_t irq_thread_fn(struct irq_desc *desc,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void wake_threads_waitq(struct irq_desc *desc)
|
||||
void wake_threads_waitq(struct irq_desc *desc)
|
||||
{
|
||||
if (atomic_dec_and_test(&desc->threads_active))
|
||||
wake_up(&desc->wait_for_threads);
|
||||
@@ -1944,7 +1946,7 @@ static struct irqaction *__free_irq(struct irq_desc *desc, void *dev_id)
|
||||
* supports it also make sure that there is no (not yet serviced)
|
||||
* interrupt in flight at the hardware level.
|
||||
*/
|
||||
__synchronize_hardirq(desc, true);
|
||||
__synchronize_irq(desc);
|
||||
|
||||
#ifdef CONFIG_DEBUG_SHIRQ
|
||||
/*
|
||||
|
||||
+11
-16
@@ -163,12 +163,12 @@ unsigned long kallsyms_sym_address(int idx)
|
||||
return kallsyms_relative_base - 1 - kallsyms_offsets[idx];
|
||||
}
|
||||
|
||||
static bool cleanup_symbol_name(char *s)
|
||||
static void cleanup_symbol_name(char *s)
|
||||
{
|
||||
char *res;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_LTO_CLANG))
|
||||
return false;
|
||||
return;
|
||||
|
||||
/*
|
||||
* LLVM appends various suffixes for local functions and variables that
|
||||
@@ -178,26 +178,21 @@ static bool cleanup_symbol_name(char *s)
|
||||
* - foo.llvm.[0-9a-f]+
|
||||
*/
|
||||
res = strstr(s, ".llvm.");
|
||||
if (res) {
|
||||
if (res)
|
||||
*res = '\0';
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
static int compare_symbol_name(const char *name, char *namebuf)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = strcmp(name, namebuf);
|
||||
if (!ret)
|
||||
return ret;
|
||||
|
||||
if (cleanup_symbol_name(namebuf) && !strcmp(name, namebuf))
|
||||
return 0;
|
||||
|
||||
return ret;
|
||||
/* The kallsyms_seqs_of_names is sorted based on names after
|
||||
* cleanup_symbol_name() (see scripts/kallsyms.c) if clang lto is enabled.
|
||||
* To ensure correct bisection in kallsyms_lookup_names(), do
|
||||
* cleanup_symbol_name(namebuf) before comparing name and namebuf.
|
||||
*/
|
||||
cleanup_symbol_name(namebuf);
|
||||
return strcmp(name, namebuf);
|
||||
}
|
||||
|
||||
static unsigned int get_symbol_seq(int index)
|
||||
|
||||
@@ -196,7 +196,7 @@ static bool match_cleanup_name(const char *s, const char *name)
|
||||
if (!IS_ENABLED(CONFIG_LTO_CLANG))
|
||||
return false;
|
||||
|
||||
p = strchr(s, '.');
|
||||
p = strstr(s, ".llvm.");
|
||||
if (!p)
|
||||
return false;
|
||||
|
||||
@@ -344,27 +344,6 @@ static int test_kallsyms_basic_function(void)
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/*
|
||||
* The first '.' may be the initial letter, in which case the
|
||||
* entire symbol name will be truncated to an empty string in
|
||||
* cleanup_symbol_name(). Do not test these symbols.
|
||||
*
|
||||
* For example:
|
||||
* cat /proc/kallsyms | awk '{print $3}' | grep -E "^\." | head
|
||||
* .E_read_words
|
||||
* .E_leading_bytes
|
||||
* .E_trailing_bytes
|
||||
* .E_write_words
|
||||
* .E_copy
|
||||
* .str.292.llvm.12122243386960820698
|
||||
* .str.24.llvm.12122243386960820698
|
||||
* .str.29.llvm.12122243386960820698
|
||||
* .str.75.llvm.12122243386960820698
|
||||
* .str.99.llvm.12122243386960820698
|
||||
*/
|
||||
if (IS_ENABLED(CONFIG_LTO_CLANG) && !namebuf[0])
|
||||
continue;
|
||||
|
||||
lookup_addr = kallsyms_lookup_name(namebuf);
|
||||
|
||||
memset(stat, 0, sizeof(*stat));
|
||||
|
||||
@@ -45,6 +45,7 @@ torture_param(int, stutter, 5, "Number of jiffies to run/halt test, 0=disable");
|
||||
torture_param(int, rt_boost, 2,
|
||||
"Do periodic rt-boost. 0=Disable, 1=Only for rt_mutex, 2=For all lock types.");
|
||||
torture_param(int, rt_boost_factor, 50, "A factor determining how often rt-boost happens.");
|
||||
torture_param(int, writer_fifo, 0, "Run writers at sched_set_fifo() priority");
|
||||
torture_param(int, verbose, 1, "Enable verbose debugging printk()s");
|
||||
torture_param(int, nested_locks, 0, "Number of nested locks (max = 8)");
|
||||
/* Going much higher trips "BUG: MAX_LOCKDEP_CHAIN_HLOCKS too low!" errors */
|
||||
@@ -809,7 +810,8 @@ static int lock_torture_writer(void *arg)
|
||||
bool skip_main_lock;
|
||||
|
||||
VERBOSE_TOROUT_STRING("lock_torture_writer task started");
|
||||
set_user_nice(current, MAX_NICE);
|
||||
if (!rt_task(current))
|
||||
set_user_nice(current, MAX_NICE);
|
||||
|
||||
do {
|
||||
if ((torture_random(&rand) & 0xfffff) == 0)
|
||||
@@ -1015,8 +1017,7 @@ static void lock_torture_cleanup(void)
|
||||
|
||||
if (writer_tasks) {
|
||||
for (i = 0; i < cxt.nrealwriters_stress; i++)
|
||||
torture_stop_kthread(lock_torture_writer,
|
||||
writer_tasks[i]);
|
||||
torture_stop_kthread(lock_torture_writer, writer_tasks[i]);
|
||||
kfree(writer_tasks);
|
||||
writer_tasks = NULL;
|
||||
}
|
||||
@@ -1244,8 +1245,9 @@ static int __init lock_torture_init(void)
|
||||
goto create_reader;
|
||||
|
||||
/* Create writer. */
|
||||
firsterr = torture_create_kthread(lock_torture_writer, &cxt.lwsa[i],
|
||||
writer_tasks[i]);
|
||||
firsterr = torture_create_kthread_cb(lock_torture_writer, &cxt.lwsa[i],
|
||||
writer_tasks[i],
|
||||
writer_fifo ? sched_set_fifo : NULL);
|
||||
if (torture_init_error(firsterr))
|
||||
goto unwind;
|
||||
|
||||
|
||||
+2
-2
@@ -30,7 +30,7 @@
|
||||
static struct kmem_cache *nsproxy_cachep;
|
||||
|
||||
struct nsproxy init_nsproxy = {
|
||||
.count = ATOMIC_INIT(1),
|
||||
.count = REFCOUNT_INIT(1),
|
||||
.uts_ns = &init_uts_ns,
|
||||
#if defined(CONFIG_POSIX_MQUEUE) || defined(CONFIG_SYSVIPC)
|
||||
.ipc_ns = &init_ipc_ns,
|
||||
@@ -55,7 +55,7 @@ static inline struct nsproxy *create_nsproxy(void)
|
||||
|
||||
nsproxy = kmem_cache_alloc(nsproxy_cachep, GFP_KERNEL);
|
||||
if (nsproxy)
|
||||
atomic_set(&nsproxy->count, 1);
|
||||
refcount_set(&nsproxy->count, 1);
|
||||
return nsproxy;
|
||||
}
|
||||
|
||||
|
||||
@@ -511,6 +511,14 @@ static inline void show_rcu_tasks_gp_kthreads(void) {}
|
||||
void rcu_request_urgent_qs_task(struct task_struct *t);
|
||||
#endif /* #else #ifdef CONFIG_TINY_RCU */
|
||||
|
||||
#ifdef CONFIG_TASKS_RCU
|
||||
struct task_struct *get_rcu_tasks_gp_kthread(void);
|
||||
#endif // # ifdef CONFIG_TASKS_RCU
|
||||
|
||||
#ifdef CONFIG_TASKS_RUDE_RCU
|
||||
struct task_struct *get_rcu_tasks_rude_gp_kthread(void);
|
||||
#endif // # ifdef CONFIG_TASKS_RUDE_RCU
|
||||
|
||||
#define RCU_SCHEDULER_INACTIVE 0
|
||||
#define RCU_SCHEDULER_INIT 1
|
||||
#define RCU_SCHEDULER_RUNNING 2
|
||||
|
||||
+77
-6
@@ -84,15 +84,17 @@ MODULE_AUTHOR("Paul E. McKenney <paulmck@linux.ibm.com>");
|
||||
#endif
|
||||
|
||||
torture_param(bool, gp_async, false, "Use asynchronous GP wait primitives");
|
||||
torture_param(int, gp_async_max, 1000, "Max # outstanding waits per reader");
|
||||
torture_param(int, gp_async_max, 1000, "Max # outstanding waits per writer");
|
||||
torture_param(bool, gp_exp, false, "Use expedited GP wait primitives");
|
||||
torture_param(int, holdoff, 10, "Holdoff time before test start (s)");
|
||||
torture_param(int, minruntime, 0, "Minimum run time (s)");
|
||||
torture_param(int, nreaders, -1, "Number of RCU reader threads");
|
||||
torture_param(int, nwriters, -1, "Number of RCU updater threads");
|
||||
torture_param(bool, shutdown, RCUSCALE_SHUTDOWN,
|
||||
"Shutdown at end of scalability tests.");
|
||||
torture_param(int, verbose, 1, "Enable verbose debugging printk()s");
|
||||
torture_param(int, writer_holdoff, 0, "Holdoff (us) between GPs, zero to disable");
|
||||
torture_param(int, writer_holdoff_jiffies, 0, "Holdoff (jiffies) between GPs, zero to disable");
|
||||
torture_param(int, kfree_rcu_test, 0, "Do we run a kfree_rcu() scale test?");
|
||||
torture_param(int, kfree_mult, 1, "Multiple of kfree_obj size to allocate.");
|
||||
torture_param(int, kfree_by_call_rcu, 0, "Use call_rcu() to emulate kfree_rcu()?");
|
||||
@@ -139,6 +141,7 @@ struct rcu_scale_ops {
|
||||
void (*gp_barrier)(void);
|
||||
void (*sync)(void);
|
||||
void (*exp_sync)(void);
|
||||
struct task_struct *(*rso_gp_kthread)(void);
|
||||
const char *name;
|
||||
};
|
||||
|
||||
@@ -295,6 +298,7 @@ static struct rcu_scale_ops tasks_ops = {
|
||||
.gp_barrier = rcu_barrier_tasks,
|
||||
.sync = synchronize_rcu_tasks,
|
||||
.exp_sync = synchronize_rcu_tasks,
|
||||
.rso_gp_kthread = get_rcu_tasks_gp_kthread,
|
||||
.name = "tasks"
|
||||
};
|
||||
|
||||
@@ -306,6 +310,44 @@ static struct rcu_scale_ops tasks_ops = {
|
||||
|
||||
#endif // #else // #ifdef CONFIG_TASKS_RCU
|
||||
|
||||
#ifdef CONFIG_TASKS_RUDE_RCU
|
||||
|
||||
/*
|
||||
* Definitions for RCU-tasks-rude scalability testing.
|
||||
*/
|
||||
|
||||
static int tasks_rude_scale_read_lock(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tasks_rude_scale_read_unlock(int idx)
|
||||
{
|
||||
}
|
||||
|
||||
static struct rcu_scale_ops tasks_rude_ops = {
|
||||
.ptype = RCU_TASKS_RUDE_FLAVOR,
|
||||
.init = rcu_sync_scale_init,
|
||||
.readlock = tasks_rude_scale_read_lock,
|
||||
.readunlock = tasks_rude_scale_read_unlock,
|
||||
.get_gp_seq = rcu_no_completed,
|
||||
.gp_diff = rcu_seq_diff,
|
||||
.async = call_rcu_tasks_rude,
|
||||
.gp_barrier = rcu_barrier_tasks_rude,
|
||||
.sync = synchronize_rcu_tasks_rude,
|
||||
.exp_sync = synchronize_rcu_tasks_rude,
|
||||
.rso_gp_kthread = get_rcu_tasks_rude_gp_kthread,
|
||||
.name = "tasks-rude"
|
||||
};
|
||||
|
||||
#define TASKS_RUDE_OPS &tasks_rude_ops,
|
||||
|
||||
#else // #ifdef CONFIG_TASKS_RUDE_RCU
|
||||
|
||||
#define TASKS_RUDE_OPS
|
||||
|
||||
#endif // #else // #ifdef CONFIG_TASKS_RUDE_RCU
|
||||
|
||||
#ifdef CONFIG_TASKS_TRACE_RCU
|
||||
|
||||
/*
|
||||
@@ -334,6 +376,7 @@ static struct rcu_scale_ops tasks_tracing_ops = {
|
||||
.gp_barrier = rcu_barrier_tasks_trace,
|
||||
.sync = synchronize_rcu_tasks_trace,
|
||||
.exp_sync = synchronize_rcu_tasks_trace,
|
||||
.rso_gp_kthread = get_rcu_tasks_trace_gp_kthread,
|
||||
.name = "tasks-tracing"
|
||||
};
|
||||
|
||||
@@ -410,10 +453,12 @@ rcu_scale_writer(void *arg)
|
||||
{
|
||||
int i = 0;
|
||||
int i_max;
|
||||
unsigned long jdone;
|
||||
long me = (long)arg;
|
||||
struct rcu_head *rhp = NULL;
|
||||
bool started = false, done = false, alldone = false;
|
||||
u64 t;
|
||||
DEFINE_TORTURE_RANDOM(tr);
|
||||
u64 *wdp;
|
||||
u64 *wdpp = writer_durations[me];
|
||||
|
||||
@@ -424,7 +469,7 @@ rcu_scale_writer(void *arg)
|
||||
sched_set_fifo_low(current);
|
||||
|
||||
if (holdoff)
|
||||
schedule_timeout_uninterruptible(holdoff * HZ);
|
||||
schedule_timeout_idle(holdoff * HZ);
|
||||
|
||||
/*
|
||||
* Wait until rcu_end_inkernel_boot() is called for normal GP tests
|
||||
@@ -445,9 +490,12 @@ rcu_scale_writer(void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
jdone = jiffies + minruntime * HZ;
|
||||
do {
|
||||
if (writer_holdoff)
|
||||
udelay(writer_holdoff);
|
||||
if (writer_holdoff_jiffies)
|
||||
schedule_timeout_idle(torture_random(&tr) % writer_holdoff_jiffies + 1);
|
||||
wdp = &wdpp[i];
|
||||
*wdp = ktime_get_mono_fast_ns();
|
||||
if (gp_async) {
|
||||
@@ -475,7 +523,7 @@ retry:
|
||||
if (!started &&
|
||||
atomic_read(&n_rcu_scale_writer_started) >= nrealwriters)
|
||||
started = true;
|
||||
if (!done && i >= MIN_MEAS) {
|
||||
if (!done && i >= MIN_MEAS && time_after(jiffies, jdone)) {
|
||||
done = true;
|
||||
sched_set_normal(current, 0);
|
||||
pr_alert("%s%s rcu_scale_writer %ld has %d measurements\n",
|
||||
@@ -518,8 +566,8 @@ static void
|
||||
rcu_scale_print_module_parms(struct rcu_scale_ops *cur_ops, const char *tag)
|
||||
{
|
||||
pr_alert("%s" SCALE_FLAG
|
||||
"--- %s: nreaders=%d nwriters=%d verbose=%d shutdown=%d\n",
|
||||
scale_type, tag, nrealreaders, nrealwriters, verbose, shutdown);
|
||||
"--- %s: gp_async=%d gp_async_max=%d gp_exp=%d holdoff=%d minruntime=%d nreaders=%d nwriters=%d writer_holdoff=%d writer_holdoff_jiffies=%d verbose=%d shutdown=%d\n",
|
||||
scale_type, tag, gp_async, gp_async_max, gp_exp, holdoff, minruntime, nrealreaders, nrealwriters, writer_holdoff, writer_holdoff_jiffies, verbose, shutdown);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -556,6 +604,8 @@ static struct task_struct **kfree_reader_tasks;
|
||||
static int kfree_nrealthreads;
|
||||
static atomic_t n_kfree_scale_thread_started;
|
||||
static atomic_t n_kfree_scale_thread_ended;
|
||||
static struct task_struct *kthread_tp;
|
||||
static u64 kthread_stime;
|
||||
|
||||
struct kfree_obj {
|
||||
char kfree_obj[8];
|
||||
@@ -701,6 +751,10 @@ kfree_scale_init(void)
|
||||
unsigned long jif_start;
|
||||
unsigned long orig_jif;
|
||||
|
||||
pr_alert("%s" SCALE_FLAG
|
||||
"--- kfree_rcu_test: kfree_mult=%d kfree_by_call_rcu=%d kfree_nthreads=%d kfree_alloc_num=%d kfree_loops=%d kfree_rcu_test_double=%d kfree_rcu_test_single=%d\n",
|
||||
scale_type, kfree_mult, kfree_by_call_rcu, kfree_nthreads, kfree_alloc_num, kfree_loops, kfree_rcu_test_double, kfree_rcu_test_single);
|
||||
|
||||
// Also, do a quick self-test to ensure laziness is as much as
|
||||
// expected.
|
||||
if (kfree_by_call_rcu && !IS_ENABLED(CONFIG_RCU_LAZY)) {
|
||||
@@ -797,6 +851,18 @@ rcu_scale_cleanup(void)
|
||||
if (gp_exp && gp_async)
|
||||
SCALEOUT_ERRSTRING("No expedited async GPs, so went with async!");
|
||||
|
||||
// If built-in, just report all of the GP kthread's CPU time.
|
||||
if (IS_BUILTIN(CONFIG_RCU_SCALE_TEST) && !kthread_tp && cur_ops->rso_gp_kthread)
|
||||
kthread_tp = cur_ops->rso_gp_kthread();
|
||||
if (kthread_tp) {
|
||||
u32 ns;
|
||||
u64 us;
|
||||
|
||||
kthread_stime = kthread_tp->stime - kthread_stime;
|
||||
us = div_u64_rem(kthread_stime, 1000, &ns);
|
||||
pr_info("rcu_scale: Grace-period kthread CPU time: %llu.%03u us\n", us, ns);
|
||||
show_rcu_gp_kthreads();
|
||||
}
|
||||
if (kfree_rcu_test) {
|
||||
kfree_scale_cleanup();
|
||||
return;
|
||||
@@ -885,7 +951,7 @@ rcu_scale_init(void)
|
||||
long i;
|
||||
int firsterr = 0;
|
||||
static struct rcu_scale_ops *scale_ops[] = {
|
||||
&rcu_ops, &srcu_ops, &srcud_ops, TASKS_OPS TASKS_TRACING_OPS
|
||||
&rcu_ops, &srcu_ops, &srcud_ops, TASKS_OPS TASKS_RUDE_OPS TASKS_TRACING_OPS
|
||||
};
|
||||
|
||||
if (!torture_init_begin(scale_type, verbose))
|
||||
@@ -910,6 +976,11 @@ rcu_scale_init(void)
|
||||
if (cur_ops->init)
|
||||
cur_ops->init();
|
||||
|
||||
if (cur_ops->rso_gp_kthread) {
|
||||
kthread_tp = cur_ops->rso_gp_kthread();
|
||||
if (kthread_tp)
|
||||
kthread_stime = kthread_tp->stime;
|
||||
}
|
||||
if (kfree_rcu_test)
|
||||
return kfree_scale_init();
|
||||
|
||||
|
||||
@@ -1581,6 +1581,7 @@ rcu_torture_writer(void *arg)
|
||||
rcu_access_pointer(rcu_torture_current) !=
|
||||
&rcu_tortures[i]) {
|
||||
tracing_off();
|
||||
show_rcu_gp_kthreads();
|
||||
WARN(1, "%s: rtort_pipe_count: %d\n", __func__, rcu_tortures[i].rtort_pipe_count);
|
||||
rcu_ftrace_dump(DUMP_ALL);
|
||||
}
|
||||
@@ -1876,7 +1877,7 @@ static int
|
||||
rcutorture_extend_mask(int oldmask, struct torture_random_state *trsp)
|
||||
{
|
||||
int mask = rcutorture_extend_mask_max();
|
||||
unsigned long randmask1 = torture_random(trsp) >> 8;
|
||||
unsigned long randmask1 = torture_random(trsp);
|
||||
unsigned long randmask2 = randmask1 >> 3;
|
||||
unsigned long preempts = RCUTORTURE_RDR_PREEMPT | RCUTORTURE_RDR_SCHED;
|
||||
unsigned long preempts_irq = preempts | RCUTORTURE_RDR_IRQ;
|
||||
@@ -1935,7 +1936,7 @@ rcutorture_loop_extend(int *readstate, struct torture_random_state *trsp,
|
||||
if (!((mask - 1) & mask))
|
||||
return rtrsp; /* Current RCU reader not extendable. */
|
||||
/* Bias towards larger numbers of loops. */
|
||||
i = (torture_random(trsp) >> 3);
|
||||
i = torture_random(trsp);
|
||||
i = ((i | (i >> 3)) & RCUTORTURE_RDR_MAX_LOOPS) + 1;
|
||||
for (j = 0; j < i; j++) {
|
||||
mask = rcutorture_extend_mask(*readstate, trsp);
|
||||
@@ -2136,7 +2137,7 @@ static int rcu_nocb_toggle(void *arg)
|
||||
toggle_fuzz = NSEC_PER_USEC;
|
||||
do {
|
||||
r = torture_random(&rand);
|
||||
cpu = (r >> 4) % (maxcpu + 1);
|
||||
cpu = (r >> 1) % (maxcpu + 1);
|
||||
if (r & 0x1) {
|
||||
rcu_nocb_cpu_offload(cpu);
|
||||
atomic_long_inc(&n_nocb_offload);
|
||||
|
||||
+34
-3
@@ -528,6 +528,38 @@ static struct ref_scale_ops clock_ops = {
|
||||
.name = "clock"
|
||||
};
|
||||
|
||||
static void ref_jiffies_section(const int nloops)
|
||||
{
|
||||
u64 x = 0;
|
||||
int i;
|
||||
|
||||
preempt_disable();
|
||||
for (i = nloops; i >= 0; i--)
|
||||
x += jiffies;
|
||||
preempt_enable();
|
||||
stopopts = x;
|
||||
}
|
||||
|
||||
static void ref_jiffies_delay_section(const int nloops, const int udl, const int ndl)
|
||||
{
|
||||
u64 x = 0;
|
||||
int i;
|
||||
|
||||
preempt_disable();
|
||||
for (i = nloops; i >= 0; i--) {
|
||||
x += jiffies;
|
||||
un_delay(udl, ndl);
|
||||
}
|
||||
preempt_enable();
|
||||
stopopts = x;
|
||||
}
|
||||
|
||||
static struct ref_scale_ops jiffies_ops = {
|
||||
.readsection = ref_jiffies_section,
|
||||
.delaysection = ref_jiffies_delay_section,
|
||||
.name = "jiffies"
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Methods leveraging SLAB_TYPESAFE_BY_RCU.
|
||||
@@ -1047,7 +1079,7 @@ ref_scale_init(void)
|
||||
int firsterr = 0;
|
||||
static struct ref_scale_ops *scale_ops[] = {
|
||||
&rcu_ops, &srcu_ops, RCU_TRACE_OPS RCU_TASKS_OPS &refcnt_ops, &rwlock_ops,
|
||||
&rwsem_ops, &lock_ops, &lock_irq_ops, &acqrel_ops, &clock_ops,
|
||||
&rwsem_ops, &lock_ops, &lock_irq_ops, &acqrel_ops, &clock_ops, &jiffies_ops,
|
||||
&typesafe_ref_ops, &typesafe_lock_ops, &typesafe_seqlock_ops,
|
||||
};
|
||||
|
||||
@@ -1107,12 +1139,11 @@ ref_scale_init(void)
|
||||
VERBOSE_SCALEOUT("Starting %d reader threads", nreaders);
|
||||
|
||||
for (i = 0; i < nreaders; i++) {
|
||||
init_waitqueue_head(&reader_tasks[i].wq);
|
||||
firsterr = torture_create_kthread(ref_scale_reader, (void *)i,
|
||||
reader_tasks[i].task);
|
||||
if (torture_init_error(firsterr))
|
||||
goto unwind;
|
||||
|
||||
init_waitqueue_head(&(reader_tasks[i].wq));
|
||||
}
|
||||
|
||||
// Main Task
|
||||
|
||||
+117
-19
@@ -25,6 +25,8 @@ typedef void (*postgp_func_t)(struct rcu_tasks *rtp);
|
||||
* @cblist: Callback list.
|
||||
* @lock: Lock protecting per-CPU callback list.
|
||||
* @rtp_jiffies: Jiffies counter value for statistics.
|
||||
* @lazy_timer: Timer to unlazify callbacks.
|
||||
* @urgent_gp: Number of additional non-lazy grace periods.
|
||||
* @rtp_n_lock_retries: Rough lock-contention statistic.
|
||||
* @rtp_work: Work queue for invoking callbacks.
|
||||
* @rtp_irq_work: IRQ work queue for deferred wakeups.
|
||||
@@ -38,6 +40,8 @@ struct rcu_tasks_percpu {
|
||||
raw_spinlock_t __private lock;
|
||||
unsigned long rtp_jiffies;
|
||||
unsigned long rtp_n_lock_retries;
|
||||
struct timer_list lazy_timer;
|
||||
unsigned int urgent_gp;
|
||||
struct work_struct rtp_work;
|
||||
struct irq_work rtp_irq_work;
|
||||
struct rcu_head barrier_q_head;
|
||||
@@ -51,7 +55,6 @@ struct rcu_tasks_percpu {
|
||||
* @cbs_wait: RCU wait allowing a new callback to get kthread's attention.
|
||||
* @cbs_gbl_lock: Lock protecting callback list.
|
||||
* @tasks_gp_mutex: Mutex protecting grace period, needed during mid-boot dead zone.
|
||||
* @kthread_ptr: This flavor's grace-period/callback-invocation kthread.
|
||||
* @gp_func: This flavor's grace-period-wait function.
|
||||
* @gp_state: Grace period's most recent state transition (debugging).
|
||||
* @gp_sleep: Per-grace-period sleep to prevent CPU-bound looping.
|
||||
@@ -61,6 +64,8 @@ struct rcu_tasks_percpu {
|
||||
* @tasks_gp_seq: Number of grace periods completed since boot.
|
||||
* @n_ipis: Number of IPIs sent to encourage grace periods to end.
|
||||
* @n_ipis_fails: Number of IPI-send failures.
|
||||
* @kthread_ptr: This flavor's grace-period/callback-invocation kthread.
|
||||
* @lazy_jiffies: Number of jiffies to allow callbacks to be lazy.
|
||||
* @pregp_func: This flavor's pre-grace-period function (optional).
|
||||
* @pertask_func: This flavor's per-task scan function (optional).
|
||||
* @postscan_func: This flavor's post-task scan function (optional).
|
||||
@@ -92,6 +97,7 @@ struct rcu_tasks {
|
||||
unsigned long n_ipis;
|
||||
unsigned long n_ipis_fails;
|
||||
struct task_struct *kthread_ptr;
|
||||
unsigned long lazy_jiffies;
|
||||
rcu_tasks_gp_func_t gp_func;
|
||||
pregp_func_t pregp_func;
|
||||
pertask_func_t pertask_func;
|
||||
@@ -127,6 +133,7 @@ static struct rcu_tasks rt_name = \
|
||||
.gp_func = gp, \
|
||||
.call_func = call, \
|
||||
.rtpcpu = &rt_name ## __percpu, \
|
||||
.lazy_jiffies = DIV_ROUND_UP(HZ, 4), \
|
||||
.name = n, \
|
||||
.percpu_enqueue_shift = order_base_2(CONFIG_NR_CPUS), \
|
||||
.percpu_enqueue_lim = 1, \
|
||||
@@ -139,9 +146,7 @@ static struct rcu_tasks rt_name = \
|
||||
#ifdef CONFIG_TASKS_RCU
|
||||
/* Track exiting tasks in order to allow them to be waited for. */
|
||||
DEFINE_STATIC_SRCU(tasks_rcu_exit_srcu);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TASKS_RCU
|
||||
/* Report delay in synchronize_srcu() completion in rcu_tasks_postscan(). */
|
||||
static void tasks_rcu_exit_srcu_stall(struct timer_list *unused);
|
||||
static DEFINE_TIMER(tasks_rcu_exit_srcu_stall_timer, tasks_rcu_exit_srcu_stall);
|
||||
@@ -171,6 +176,8 @@ static int rcu_task_contend_lim __read_mostly = 100;
|
||||
module_param(rcu_task_contend_lim, int, 0444);
|
||||
static int rcu_task_collapse_lim __read_mostly = 10;
|
||||
module_param(rcu_task_collapse_lim, int, 0444);
|
||||
static int rcu_task_lazy_lim __read_mostly = 32;
|
||||
module_param(rcu_task_lazy_lim, int, 0444);
|
||||
|
||||
/* RCU tasks grace-period state for debugging. */
|
||||
#define RTGS_INIT 0
|
||||
@@ -229,7 +236,7 @@ static const char *tasks_gp_state_getname(struct rcu_tasks *rtp)
|
||||
#endif /* #ifndef CONFIG_TINY_RCU */
|
||||
|
||||
// Initialize per-CPU callback lists for the specified flavor of
|
||||
// Tasks RCU.
|
||||
// Tasks RCU. Do not enqueue callbacks before this function is invoked.
|
||||
static void cblist_init_generic(struct rcu_tasks *rtp)
|
||||
{
|
||||
int cpu;
|
||||
@@ -237,7 +244,6 @@ static void cblist_init_generic(struct rcu_tasks *rtp)
|
||||
int lim;
|
||||
int shift;
|
||||
|
||||
raw_spin_lock_irqsave(&rtp->cbs_gbl_lock, flags);
|
||||
if (rcu_task_enqueue_lim < 0) {
|
||||
rcu_task_enqueue_lim = 1;
|
||||
rcu_task_cb_adjust = true;
|
||||
@@ -260,22 +266,48 @@ static void cblist_init_generic(struct rcu_tasks *rtp)
|
||||
WARN_ON_ONCE(!rtpcp);
|
||||
if (cpu)
|
||||
raw_spin_lock_init(&ACCESS_PRIVATE(rtpcp, lock));
|
||||
raw_spin_lock_rcu_node(rtpcp); // irqs already disabled.
|
||||
local_irq_save(flags); // serialize initialization
|
||||
if (rcu_segcblist_empty(&rtpcp->cblist))
|
||||
rcu_segcblist_init(&rtpcp->cblist);
|
||||
local_irq_restore(flags);
|
||||
INIT_WORK(&rtpcp->rtp_work, rcu_tasks_invoke_cbs_wq);
|
||||
rtpcp->cpu = cpu;
|
||||
rtpcp->rtpp = rtp;
|
||||
if (!rtpcp->rtp_blkd_tasks.next)
|
||||
INIT_LIST_HEAD(&rtpcp->rtp_blkd_tasks);
|
||||
raw_spin_unlock_rcu_node(rtpcp); // irqs remain disabled.
|
||||
}
|
||||
raw_spin_unlock_irqrestore(&rtp->cbs_gbl_lock, flags);
|
||||
|
||||
pr_info("%s: Setting shift to %d and lim to %d rcu_task_cb_adjust=%d.\n", rtp->name,
|
||||
data_race(rtp->percpu_enqueue_shift), data_race(rtp->percpu_enqueue_lim), rcu_task_cb_adjust);
|
||||
}
|
||||
|
||||
// Compute wakeup time for lazy callback timer.
|
||||
static unsigned long rcu_tasks_lazy_time(struct rcu_tasks *rtp)
|
||||
{
|
||||
return jiffies + rtp->lazy_jiffies;
|
||||
}
|
||||
|
||||
// Timer handler that unlazifies lazy callbacks.
|
||||
static void call_rcu_tasks_generic_timer(struct timer_list *tlp)
|
||||
{
|
||||
unsigned long flags;
|
||||
bool needwake = false;
|
||||
struct rcu_tasks *rtp;
|
||||
struct rcu_tasks_percpu *rtpcp = from_timer(rtpcp, tlp, lazy_timer);
|
||||
|
||||
rtp = rtpcp->rtpp;
|
||||
raw_spin_lock_irqsave_rcu_node(rtpcp, flags);
|
||||
if (!rcu_segcblist_empty(&rtpcp->cblist) && rtp->lazy_jiffies) {
|
||||
if (!rtpcp->urgent_gp)
|
||||
rtpcp->urgent_gp = 1;
|
||||
needwake = true;
|
||||
mod_timer(&rtpcp->lazy_timer, rcu_tasks_lazy_time(rtp));
|
||||
}
|
||||
raw_spin_unlock_irqrestore_rcu_node(rtpcp, flags);
|
||||
if (needwake)
|
||||
rcuwait_wake_up(&rtp->cbs_wait);
|
||||
}
|
||||
|
||||
// IRQ-work handler that does deferred wakeup for call_rcu_tasks_generic().
|
||||
static void call_rcu_tasks_iw_wakeup(struct irq_work *iwp)
|
||||
{
|
||||
@@ -292,6 +324,7 @@ static void call_rcu_tasks_generic(struct rcu_head *rhp, rcu_callback_t func,
|
||||
{
|
||||
int chosen_cpu;
|
||||
unsigned long flags;
|
||||
bool havekthread = smp_load_acquire(&rtp->kthread_ptr);
|
||||
int ideal_cpu;
|
||||
unsigned long j;
|
||||
bool needadjust = false;
|
||||
@@ -316,12 +349,19 @@ static void call_rcu_tasks_generic(struct rcu_head *rhp, rcu_callback_t func,
|
||||
READ_ONCE(rtp->percpu_enqueue_lim) != nr_cpu_ids)
|
||||
needadjust = true; // Defer adjustment to avoid deadlock.
|
||||
}
|
||||
if (!rcu_segcblist_is_enabled(&rtpcp->cblist)) {
|
||||
raw_spin_unlock_rcu_node(rtpcp); // irqs remain disabled.
|
||||
cblist_init_generic(rtp);
|
||||
raw_spin_lock_rcu_node(rtpcp); // irqs already disabled.
|
||||
// Queuing callbacks before initialization not yet supported.
|
||||
if (WARN_ON_ONCE(!rcu_segcblist_is_enabled(&rtpcp->cblist)))
|
||||
rcu_segcblist_init(&rtpcp->cblist);
|
||||
needwake = (func == wakeme_after_rcu) ||
|
||||
(rcu_segcblist_n_cbs(&rtpcp->cblist) == rcu_task_lazy_lim);
|
||||
if (havekthread && !needwake && !timer_pending(&rtpcp->lazy_timer)) {
|
||||
if (rtp->lazy_jiffies)
|
||||
mod_timer(&rtpcp->lazy_timer, rcu_tasks_lazy_time(rtp));
|
||||
else
|
||||
needwake = rcu_segcblist_empty(&rtpcp->cblist);
|
||||
}
|
||||
needwake = rcu_segcblist_empty(&rtpcp->cblist);
|
||||
if (needwake)
|
||||
rtpcp->urgent_gp = 3;
|
||||
rcu_segcblist_enqueue(&rtpcp->cblist, rhp);
|
||||
raw_spin_unlock_irqrestore_rcu_node(rtpcp, flags);
|
||||
if (unlikely(needadjust)) {
|
||||
@@ -415,9 +455,14 @@ static int rcu_tasks_need_gpcb(struct rcu_tasks *rtp)
|
||||
}
|
||||
rcu_segcblist_advance(&rtpcp->cblist, rcu_seq_current(&rtp->tasks_gp_seq));
|
||||
(void)rcu_segcblist_accelerate(&rtpcp->cblist, rcu_seq_snap(&rtp->tasks_gp_seq));
|
||||
if (rcu_segcblist_pend_cbs(&rtpcp->cblist))
|
||||
if (rtpcp->urgent_gp > 0 && rcu_segcblist_pend_cbs(&rtpcp->cblist)) {
|
||||
if (rtp->lazy_jiffies)
|
||||
rtpcp->urgent_gp--;
|
||||
needgpcb |= 0x3;
|
||||
if (!rcu_segcblist_empty(&rtpcp->cblist))
|
||||
} else if (rcu_segcblist_empty(&rtpcp->cblist)) {
|
||||
rtpcp->urgent_gp = 0;
|
||||
}
|
||||
if (rcu_segcblist_ready_cbs(&rtpcp->cblist))
|
||||
needgpcb |= 0x1;
|
||||
raw_spin_unlock_irqrestore_rcu_node(rtpcp, flags);
|
||||
}
|
||||
@@ -525,10 +570,12 @@ static void rcu_tasks_one_gp(struct rcu_tasks *rtp, bool midboot)
|
||||
if (unlikely(midboot)) {
|
||||
needgpcb = 0x2;
|
||||
} else {
|
||||
mutex_unlock(&rtp->tasks_gp_mutex);
|
||||
set_tasks_gp_state(rtp, RTGS_WAIT_CBS);
|
||||
rcuwait_wait_event(&rtp->cbs_wait,
|
||||
(needgpcb = rcu_tasks_need_gpcb(rtp)),
|
||||
TASK_IDLE);
|
||||
mutex_lock(&rtp->tasks_gp_mutex);
|
||||
}
|
||||
|
||||
if (needgpcb & 0x2) {
|
||||
@@ -549,11 +596,19 @@ static void rcu_tasks_one_gp(struct rcu_tasks *rtp, bool midboot)
|
||||
// RCU-tasks kthread that detects grace periods and invokes callbacks.
|
||||
static int __noreturn rcu_tasks_kthread(void *arg)
|
||||
{
|
||||
int cpu;
|
||||
struct rcu_tasks *rtp = arg;
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
struct rcu_tasks_percpu *rtpcp = per_cpu_ptr(rtp->rtpcpu, cpu);
|
||||
|
||||
timer_setup(&rtpcp->lazy_timer, call_rcu_tasks_generic_timer, 0);
|
||||
rtpcp->urgent_gp = 1;
|
||||
}
|
||||
|
||||
/* Run on housekeeping CPUs by default. Sysadm can move if desired. */
|
||||
housekeeping_affine(current, HK_TYPE_RCU);
|
||||
WRITE_ONCE(rtp->kthread_ptr, current); // Let GPs start!
|
||||
smp_store_release(&rtp->kthread_ptr, current); // Let GPs start!
|
||||
|
||||
/*
|
||||
* Each pass through the following loop makes one check for
|
||||
@@ -635,16 +690,22 @@ static void show_rcu_tasks_generic_gp_kthread(struct rcu_tasks *rtp, char *s)
|
||||
{
|
||||
int cpu;
|
||||
bool havecbs = false;
|
||||
bool haveurgent = false;
|
||||
bool haveurgentcbs = false;
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
struct rcu_tasks_percpu *rtpcp = per_cpu_ptr(rtp->rtpcpu, cpu);
|
||||
|
||||
if (!data_race(rcu_segcblist_empty(&rtpcp->cblist))) {
|
||||
if (!data_race(rcu_segcblist_empty(&rtpcp->cblist)))
|
||||
havecbs = true;
|
||||
if (data_race(rtpcp->urgent_gp))
|
||||
haveurgent = true;
|
||||
if (!data_race(rcu_segcblist_empty(&rtpcp->cblist)) && data_race(rtpcp->urgent_gp))
|
||||
haveurgentcbs = true;
|
||||
if (havecbs && haveurgent && haveurgentcbs)
|
||||
break;
|
||||
}
|
||||
}
|
||||
pr_info("%s: %s(%d) since %lu g:%lu i:%lu/%lu %c%c %s\n",
|
||||
pr_info("%s: %s(%d) since %lu g:%lu i:%lu/%lu %c%c%c%c l:%lu %s\n",
|
||||
rtp->kname,
|
||||
tasks_gp_state_getname(rtp), data_race(rtp->gp_state),
|
||||
jiffies - data_race(rtp->gp_jiffies),
|
||||
@@ -652,6 +713,9 @@ static void show_rcu_tasks_generic_gp_kthread(struct rcu_tasks *rtp, char *s)
|
||||
data_race(rtp->n_ipis_fails), data_race(rtp->n_ipis),
|
||||
".k"[!!data_race(rtp->kthread_ptr)],
|
||||
".C"[havecbs],
|
||||
".u"[haveurgent],
|
||||
".U"[haveurgentcbs],
|
||||
rtp->lazy_jiffies,
|
||||
s);
|
||||
}
|
||||
#endif // #ifndef CONFIG_TINY_RCU
|
||||
@@ -1020,11 +1084,16 @@ void rcu_barrier_tasks(void)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rcu_barrier_tasks);
|
||||
|
||||
int rcu_tasks_lazy_ms = -1;
|
||||
module_param(rcu_tasks_lazy_ms, int, 0444);
|
||||
|
||||
static int __init rcu_spawn_tasks_kthread(void)
|
||||
{
|
||||
cblist_init_generic(&rcu_tasks);
|
||||
rcu_tasks.gp_sleep = HZ / 10;
|
||||
rcu_tasks.init_fract = HZ / 10;
|
||||
if (rcu_tasks_lazy_ms >= 0)
|
||||
rcu_tasks.lazy_jiffies = msecs_to_jiffies(rcu_tasks_lazy_ms);
|
||||
rcu_tasks.pregp_func = rcu_tasks_pregp_step;
|
||||
rcu_tasks.pertask_func = rcu_tasks_pertask;
|
||||
rcu_tasks.postscan_func = rcu_tasks_postscan;
|
||||
@@ -1042,6 +1111,12 @@ void show_rcu_tasks_classic_gp_kthread(void)
|
||||
EXPORT_SYMBOL_GPL(show_rcu_tasks_classic_gp_kthread);
|
||||
#endif // !defined(CONFIG_TINY_RCU)
|
||||
|
||||
struct task_struct *get_rcu_tasks_gp_kthread(void)
|
||||
{
|
||||
return rcu_tasks.kthread_ptr;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(get_rcu_tasks_gp_kthread);
|
||||
|
||||
/*
|
||||
* Contribute to protect against tasklist scan blind spot while the
|
||||
* task is exiting and may be removed from the tasklist. See
|
||||
@@ -1173,10 +1248,15 @@ void rcu_barrier_tasks_rude(void)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rcu_barrier_tasks_rude);
|
||||
|
||||
int rcu_tasks_rude_lazy_ms = -1;
|
||||
module_param(rcu_tasks_rude_lazy_ms, int, 0444);
|
||||
|
||||
static int __init rcu_spawn_tasks_rude_kthread(void)
|
||||
{
|
||||
cblist_init_generic(&rcu_tasks_rude);
|
||||
rcu_tasks_rude.gp_sleep = HZ / 10;
|
||||
if (rcu_tasks_rude_lazy_ms >= 0)
|
||||
rcu_tasks_rude.lazy_jiffies = msecs_to_jiffies(rcu_tasks_rude_lazy_ms);
|
||||
rcu_spawn_tasks_kthread_generic(&rcu_tasks_rude);
|
||||
return 0;
|
||||
}
|
||||
@@ -1188,6 +1268,13 @@ void show_rcu_tasks_rude_gp_kthread(void)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(show_rcu_tasks_rude_gp_kthread);
|
||||
#endif // !defined(CONFIG_TINY_RCU)
|
||||
|
||||
struct task_struct *get_rcu_tasks_rude_gp_kthread(void)
|
||||
{
|
||||
return rcu_tasks_rude.kthread_ptr;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(get_rcu_tasks_rude_gp_kthread);
|
||||
|
||||
#endif /* #ifdef CONFIG_TASKS_RUDE_RCU */
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
@@ -1793,6 +1880,9 @@ void rcu_barrier_tasks_trace(void)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rcu_barrier_tasks_trace);
|
||||
|
||||
int rcu_tasks_trace_lazy_ms = -1;
|
||||
module_param(rcu_tasks_trace_lazy_ms, int, 0444);
|
||||
|
||||
static int __init rcu_spawn_tasks_trace_kthread(void)
|
||||
{
|
||||
cblist_init_generic(&rcu_tasks_trace);
|
||||
@@ -1807,6 +1897,8 @@ static int __init rcu_spawn_tasks_trace_kthread(void)
|
||||
if (rcu_tasks_trace.init_fract <= 0)
|
||||
rcu_tasks_trace.init_fract = 1;
|
||||
}
|
||||
if (rcu_tasks_trace_lazy_ms >= 0)
|
||||
rcu_tasks_trace.lazy_jiffies = msecs_to_jiffies(rcu_tasks_trace_lazy_ms);
|
||||
rcu_tasks_trace.pregp_func = rcu_tasks_trace_pregp_step;
|
||||
rcu_tasks_trace.postscan_func = rcu_tasks_trace_postscan;
|
||||
rcu_tasks_trace.holdouts_func = check_all_holdout_tasks_trace;
|
||||
@@ -1830,6 +1922,12 @@ void show_rcu_tasks_trace_gp_kthread(void)
|
||||
EXPORT_SYMBOL_GPL(show_rcu_tasks_trace_gp_kthread);
|
||||
#endif // !defined(CONFIG_TINY_RCU)
|
||||
|
||||
struct task_struct *get_rcu_tasks_trace_gp_kthread(void)
|
||||
{
|
||||
return rcu_tasks_trace.kthread_ptr;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(get_rcu_tasks_trace_gp_kthread);
|
||||
|
||||
#else /* #ifdef CONFIG_TASKS_TRACE_RCU */
|
||||
static void exit_tasks_rcu_finish_trace(struct task_struct *t) { }
|
||||
#endif /* #else #ifdef CONFIG_TASKS_TRACE_RCU */
|
||||
|
||||
+10
-6
@@ -632,7 +632,7 @@ void __rcu_irq_enter_check_tick(void)
|
||||
// prevents self-deadlock. So we can safely recheck under the lock.
|
||||
// Note that the nohz_full state currently cannot change.
|
||||
raw_spin_lock_rcu_node(rdp->mynode);
|
||||
if (rdp->rcu_urgent_qs && !rdp->rcu_forced_tick) {
|
||||
if (READ_ONCE(rdp->rcu_urgent_qs) && !rdp->rcu_forced_tick) {
|
||||
// A nohz_full CPU is in the kernel and RCU needs a
|
||||
// quiescent state. Turn on the tick!
|
||||
WRITE_ONCE(rdp->rcu_forced_tick, true);
|
||||
@@ -677,12 +677,16 @@ static void rcu_disable_urgency_upon_qs(struct rcu_data *rdp)
|
||||
}
|
||||
|
||||
/**
|
||||
* rcu_is_watching - see if RCU thinks that the current CPU is not idle
|
||||
* rcu_is_watching - RCU read-side critical sections permitted on current CPU?
|
||||
*
|
||||
* Return true if RCU is watching the running CPU, which means that this
|
||||
* CPU can safely enter RCU read-side critical sections. In other words,
|
||||
* if the current CPU is not in its idle loop or is in an interrupt or
|
||||
* NMI handler, return true.
|
||||
* Return @true if RCU is watching the running CPU and @false otherwise.
|
||||
* An @true return means that this CPU can safely enter RCU read-side
|
||||
* critical sections.
|
||||
*
|
||||
* Although calls to rcu_is_watching() from most parts of the kernel
|
||||
* will return @true, there are important exceptions. For example, if the
|
||||
* current CPU is deep within its idle loop, in kernel entry/exit code,
|
||||
* or offline, rcu_is_watching() will return @false.
|
||||
*
|
||||
* Make notrace because it can be called by the internal functions of
|
||||
* ftrace, and making this notrace removes unnecessary recursion calls.
|
||||
|
||||
@@ -77,9 +77,9 @@ __setup("rcu_nocbs", rcu_nocb_setup);
|
||||
static int __init parse_rcu_nocb_poll(char *arg)
|
||||
{
|
||||
rcu_nocb_poll = true;
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
early_param("rcu_nocb_poll", parse_rcu_nocb_poll);
|
||||
__setup("rcu_nocb_poll", parse_rcu_nocb_poll);
|
||||
|
||||
/*
|
||||
* Don't bother bypassing ->cblist if the call_rcu() rate is low.
|
||||
|
||||
+9
-3
@@ -171,7 +171,8 @@ static void scf_torture_stats_print(void)
|
||||
scfs.n_all_wait += scf_stats_p[i].n_all_wait;
|
||||
}
|
||||
if (atomic_read(&n_errs) || atomic_read(&n_mb_in_errs) ||
|
||||
atomic_read(&n_mb_out_errs) || atomic_read(&n_alloc_errs))
|
||||
atomic_read(&n_mb_out_errs) ||
|
||||
(!IS_ENABLED(CONFIG_KASAN) && atomic_read(&n_alloc_errs)))
|
||||
bangstr = "!!! ";
|
||||
pr_alert("%s %sscf_invoked_count %s: %lld resched: %lld single: %lld/%lld single_ofl: %lld/%lld single_rpc: %lld single_rpc_ofl: %lld many: %lld/%lld all: %lld/%lld ",
|
||||
SCFTORT_FLAG, bangstr, isdone ? "VER" : "ver", invoked_count, scfs.n_resched,
|
||||
@@ -312,6 +313,7 @@ static void scf_handler_1(void *scfc_in)
|
||||
// Randomly do an smp_call_function*() invocation.
|
||||
static void scftorture_invoke_one(struct scf_statistics *scfp, struct torture_random_state *trsp)
|
||||
{
|
||||
bool allocfail = false;
|
||||
uintptr_t cpu;
|
||||
int ret = 0;
|
||||
struct scf_check *scfcp = NULL;
|
||||
@@ -323,8 +325,10 @@ static void scftorture_invoke_one(struct scf_statistics *scfp, struct torture_ra
|
||||
preempt_disable();
|
||||
if (scfsp->scfs_prim == SCF_PRIM_SINGLE || scfsp->scfs_wait) {
|
||||
scfcp = kmalloc(sizeof(*scfcp), GFP_ATOMIC);
|
||||
if (WARN_ON_ONCE(!scfcp)) {
|
||||
if (!scfcp) {
|
||||
WARN_ON_ONCE(!IS_ENABLED(CONFIG_KASAN));
|
||||
atomic_inc(&n_alloc_errs);
|
||||
allocfail = true;
|
||||
} else {
|
||||
scfcp->scfc_cpu = -1;
|
||||
scfcp->scfc_wait = scfsp->scfs_wait;
|
||||
@@ -431,7 +435,9 @@ static void scftorture_invoke_one(struct scf_statistics *scfp, struct torture_ra
|
||||
cpus_read_unlock();
|
||||
else
|
||||
preempt_enable();
|
||||
if (!(torture_random(trsp) & 0xfff))
|
||||
if (allocfail)
|
||||
schedule_timeout_idle((1 + longwait) * HZ); // Let no-wait handlers complete.
|
||||
else if (!(torture_random(trsp) & 0xfff))
|
||||
schedule_timeout_uninterruptible(1);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,23 @@
|
||||
* Waiting for completion is a typically sync point, but not an exclusion point.
|
||||
*/
|
||||
|
||||
static void complete_with_flags(struct completion *x, int wake_flags)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&x->wait.lock, flags);
|
||||
|
||||
if (x->done != UINT_MAX)
|
||||
x->done++;
|
||||
swake_up_locked(&x->wait, wake_flags);
|
||||
raw_spin_unlock_irqrestore(&x->wait.lock, flags);
|
||||
}
|
||||
|
||||
void complete_on_current_cpu(struct completion *x)
|
||||
{
|
||||
return complete_with_flags(x, WF_CURRENT_CPU);
|
||||
}
|
||||
|
||||
/**
|
||||
* complete: - signals a single thread waiting on this completion
|
||||
* @x: holds the state of this particular completion
|
||||
@@ -27,14 +44,7 @@
|
||||
*/
|
||||
void complete(struct completion *x)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&x->wait.lock, flags);
|
||||
|
||||
if (x->done != UINT_MAX)
|
||||
x->done++;
|
||||
swake_up_locked(&x->wait);
|
||||
raw_spin_unlock_irqrestore(&x->wait.lock, flags);
|
||||
complete_with_flags(x, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(complete);
|
||||
|
||||
|
||||
+2
-3
@@ -4264,8 +4264,7 @@ bool ttwu_state_match(struct task_struct *p, unsigned int state, int *success)
|
||||
* Return: %true if @p->state changes (an actual wakeup was done),
|
||||
* %false otherwise.
|
||||
*/
|
||||
static int
|
||||
try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
|
||||
int try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
|
||||
{
|
||||
unsigned long flags;
|
||||
int cpu, success = 0;
|
||||
@@ -7120,7 +7119,7 @@ asmlinkage __visible void __sched preempt_schedule_irq(void)
|
||||
int default_wake_function(wait_queue_entry_t *curr, unsigned mode, int wake_flags,
|
||||
void *key)
|
||||
{
|
||||
WARN_ON_ONCE(IS_ENABLED(CONFIG_SCHED_DEBUG) && wake_flags & ~WF_SYNC);
|
||||
WARN_ON_ONCE(IS_ENABLED(CONFIG_SCHED_DEBUG) && wake_flags & ~(WF_SYNC|WF_CURRENT_CPU));
|
||||
return try_to_wake_up(curr->private, mode, wake_flags);
|
||||
}
|
||||
EXPORT_SYMBOL(default_wake_function);
|
||||
|
||||
@@ -7788,6 +7788,10 @@ select_task_rq_fair(struct task_struct *p, int prev_cpu, int wake_flags)
|
||||
if (wake_flags & WF_TTWU) {
|
||||
record_wakee(p);
|
||||
|
||||
if ((wake_flags & WF_CURRENT_CPU) &&
|
||||
cpumask_test_cpu(cpu, p->cpus_ptr))
|
||||
return cpu;
|
||||
|
||||
if (sched_energy_enabled()) {
|
||||
new_cpu = find_energy_efficient_cpu(p, prev_cpu, sync);
|
||||
if (new_cpu >= 0)
|
||||
|
||||
@@ -2146,12 +2146,13 @@ static inline int task_on_rq_migrating(struct task_struct *p)
|
||||
}
|
||||
|
||||
/* Wake flags. The first three directly map to some SD flag value */
|
||||
#define WF_EXEC 0x02 /* Wakeup after exec; maps to SD_BALANCE_EXEC */
|
||||
#define WF_FORK 0x04 /* Wakeup after fork; maps to SD_BALANCE_FORK */
|
||||
#define WF_TTWU 0x08 /* Wakeup; maps to SD_BALANCE_WAKE */
|
||||
#define WF_EXEC 0x02 /* Wakeup after exec; maps to SD_BALANCE_EXEC */
|
||||
#define WF_FORK 0x04 /* Wakeup after fork; maps to SD_BALANCE_FORK */
|
||||
#define WF_TTWU 0x08 /* Wakeup; maps to SD_BALANCE_WAKE */
|
||||
|
||||
#define WF_SYNC 0x10 /* Waker goes to sleep after wakeup */
|
||||
#define WF_MIGRATED 0x20 /* Internal use, task got migrated */
|
||||
#define WF_SYNC 0x10 /* Waker goes to sleep after wakeup */
|
||||
#define WF_MIGRATED 0x20 /* Internal use, task got migrated */
|
||||
#define WF_CURRENT_CPU 0x40 /* Prefer to move the wakee to the current CPU. */
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
static_assert(WF_EXEC == SD_BALANCE_EXEC);
|
||||
@@ -3245,6 +3246,8 @@ static inline bool is_per_cpu_kthread(struct task_struct *p)
|
||||
extern void swake_up_all_locked(struct swait_queue_head *q);
|
||||
extern void __prepare_to_swait(struct swait_queue_head *q, struct swait_queue *wait);
|
||||
|
||||
extern int try_to_wake_up(struct task_struct *tsk, unsigned int state, int wake_flags);
|
||||
|
||||
#ifdef CONFIG_PREEMPT_DYNAMIC
|
||||
extern int preempt_dynamic_mode;
|
||||
extern int sched_dynamic_mode(const char *str);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user