Merge tag 'irqchip-5.16' into irq/core
Merge irqchip updates for Linux 5.16 from Marc Zyngier:
- A large cross-arch rework to move irq_enter()/irq_exit() into
the arch code, and removing it from the generic irq code.
Thanks to Mark Rutland for the huge effort!
- A few irqchip drivers are made modular (broadcom, meson), because
that's apparently a thing...
- A new driver for the Microchip External Interrupt Controller
- The irq_cpu_offline()/irq_cpu_online() API is now deprecated and
can only be selected on the Cavium Octeon platform. Once this
platform is removed, the API will be removed at the same time.
- A sprinkle of devm_* helper, as people seem to love that.
- The usual spattering of small fixes and minor improvements.
* tag 'irqchip-5.16': (912 commits)
h8300: Fix linux/irqchip.h include mess
dt-bindings: irqchip: renesas-irqc: Document r8a774e1 bindings
MIPS: irq: Avoid an unused-variable error
genirq: Hide irq_cpu_{on,off}line() behind a deprecated option
irqchip/mips-gic: Get rid of the reliance on irq_cpu_online()
MIPS: loongson64: Drop call to irq_cpu_offline()
irq: remove handle_domain_{irq,nmi}()
irq: remove CONFIG_HANDLE_DOMAIN_IRQ_IRQENTRY
irq: riscv: perform irqentry in entry code
irq: openrisc: perform irqentry in entry code
irq: csky: perform irqentry in entry code
irq: arm64: perform irqentry in entry code
irq: arm: perform irqentry in entry code
irq: add a (temporary) CONFIG_HANDLE_DOMAIN_IRQ_IRQENTRY
irq: nds32: avoid CONFIG_HANDLE_DOMAIN_IRQ
irq: arc: avoid CONFIG_HANDLE_DOMAIN_IRQ
irq: add generic_handle_arch_irq()
irq: unexport handle_irq_desc()
irq: simplify handle_domain_{irq,nmi}()
irq: mips: simplify do_domain_IRQ()
...
Signed-off-by: Borislav Petkov <bp@suse.de>
Link: https://lore.kernel.org/r/20211029083332.3680101-1-maz@kernel.org
This commit is contained in:
@@ -368,6 +368,7 @@ static int bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key,
|
||||
const struct btf_type *mtype, *ptype;
|
||||
struct bpf_prog *prog;
|
||||
u32 moff;
|
||||
u32 flags;
|
||||
|
||||
moff = btf_member_bit_offset(t, member) / 8;
|
||||
ptype = btf_type_resolve_ptr(btf_vmlinux, member->type, NULL);
|
||||
@@ -431,10 +432,12 @@ static int bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key,
|
||||
|
||||
tprogs[BPF_TRAMP_FENTRY].progs[0] = prog;
|
||||
tprogs[BPF_TRAMP_FENTRY].nr_progs = 1;
|
||||
flags = st_ops->func_models[i].ret_size > 0 ?
|
||||
BPF_TRAMP_F_RET_FENTRY_RET : 0;
|
||||
err = arch_prepare_bpf_trampoline(NULL, image,
|
||||
st_map->image + PAGE_SIZE,
|
||||
&st_ops->func_models[i], 0,
|
||||
tprogs, NULL);
|
||||
&st_ops->func_models[i],
|
||||
flags, tprogs, NULL);
|
||||
if (err < 0)
|
||||
goto reset_unlock;
|
||||
|
||||
|
||||
+1
-1
@@ -827,7 +827,7 @@ int bpf_jit_charge_modmem(u32 pages)
|
||||
{
|
||||
if (atomic_long_add_return(pages, &bpf_jit_current) >
|
||||
(bpf_jit_limit >> PAGE_SHIFT)) {
|
||||
if (!capable(CAP_SYS_ADMIN)) {
|
||||
if (!bpf_capable()) {
|
||||
atomic_long_sub(pages, &bpf_jit_current);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
/* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com
|
||||
* Copyright (c) 2016 Facebook
|
||||
*/
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
|
||||
/* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com
|
||||
* Copyright (c) 2016 Facebook
|
||||
*/
|
||||
|
||||
@@ -179,7 +179,7 @@ static void stack_map_get_build_id_offset(struct bpf_stack_build_id *id_offs,
|
||||
* with build_id.
|
||||
*/
|
||||
if (!user || !current || !current->mm || irq_work_busy ||
|
||||
!mmap_read_trylock_non_owner(current->mm)) {
|
||||
!mmap_read_trylock(current->mm)) {
|
||||
/* cannot access current->mm, fall back to ips */
|
||||
for (i = 0; i < trace_nr; i++) {
|
||||
id_offs[i].status = BPF_STACK_BUILD_ID_IP;
|
||||
@@ -204,9 +204,15 @@ static void stack_map_get_build_id_offset(struct bpf_stack_build_id *id_offs,
|
||||
}
|
||||
|
||||
if (!work) {
|
||||
mmap_read_unlock_non_owner(current->mm);
|
||||
mmap_read_unlock(current->mm);
|
||||
} else {
|
||||
work->mm = current->mm;
|
||||
|
||||
/* The lock will be released once we're out of interrupt
|
||||
* context. Tell lockdep that we've released it now so
|
||||
* it doesn't complain that we forgot to release it.
|
||||
*/
|
||||
rwsem_release(¤t->mm->mmap_lock.dep_map, _RET_IP_);
|
||||
irq_work_queue(&work->irq_work);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9912,6 +9912,8 @@ static int check_btf_line(struct bpf_verifier_env *env,
|
||||
nr_linfo = attr->line_info_cnt;
|
||||
if (!nr_linfo)
|
||||
return 0;
|
||||
if (nr_linfo > INT_MAX / sizeof(struct bpf_line_info))
|
||||
return -EINVAL;
|
||||
|
||||
rec_size = attr->line_info_rec_size;
|
||||
if (rec_size < MIN_BPF_LINEINFO_SIZE ||
|
||||
|
||||
+20
-43
@@ -6572,74 +6572,51 @@ int cgroup_parse_float(const char *input, unsigned dec_shift, s64 *v)
|
||||
*/
|
||||
#ifdef CONFIG_SOCK_CGROUP_DATA
|
||||
|
||||
#if defined(CONFIG_CGROUP_NET_PRIO) || defined(CONFIG_CGROUP_NET_CLASSID)
|
||||
|
||||
DEFINE_SPINLOCK(cgroup_sk_update_lock);
|
||||
static bool cgroup_sk_alloc_disabled __read_mostly;
|
||||
|
||||
void cgroup_sk_alloc_disable(void)
|
||||
{
|
||||
if (cgroup_sk_alloc_disabled)
|
||||
return;
|
||||
pr_info("cgroup: disabling cgroup2 socket matching due to net_prio or net_cls activation\n");
|
||||
cgroup_sk_alloc_disabled = true;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define cgroup_sk_alloc_disabled false
|
||||
|
||||
#endif
|
||||
|
||||
void cgroup_sk_alloc(struct sock_cgroup_data *skcd)
|
||||
{
|
||||
if (cgroup_sk_alloc_disabled) {
|
||||
skcd->no_refcnt = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Don't associate the sock with unrelated interrupted task's cgroup. */
|
||||
if (in_interrupt())
|
||||
return;
|
||||
struct cgroup *cgroup;
|
||||
|
||||
rcu_read_lock();
|
||||
/* Don't associate the sock with unrelated interrupted task's cgroup. */
|
||||
if (in_interrupt()) {
|
||||
cgroup = &cgrp_dfl_root.cgrp;
|
||||
cgroup_get(cgroup);
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
struct css_set *cset;
|
||||
|
||||
cset = task_css_set(current);
|
||||
if (likely(cgroup_tryget(cset->dfl_cgrp))) {
|
||||
skcd->val = (unsigned long)cset->dfl_cgrp;
|
||||
cgroup_bpf_get(cset->dfl_cgrp);
|
||||
cgroup = cset->dfl_cgrp;
|
||||
break;
|
||||
}
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
out:
|
||||
skcd->cgroup = cgroup;
|
||||
cgroup_bpf_get(cgroup);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void cgroup_sk_clone(struct sock_cgroup_data *skcd)
|
||||
{
|
||||
if (skcd->val) {
|
||||
if (skcd->no_refcnt)
|
||||
return;
|
||||
/*
|
||||
* We might be cloning a socket which is left in an empty
|
||||
* cgroup and the cgroup might have already been rmdir'd.
|
||||
* Don't use cgroup_get_live().
|
||||
*/
|
||||
cgroup_get(sock_cgroup_ptr(skcd));
|
||||
cgroup_bpf_get(sock_cgroup_ptr(skcd));
|
||||
}
|
||||
struct cgroup *cgrp = sock_cgroup_ptr(skcd);
|
||||
|
||||
/*
|
||||
* We might be cloning a socket which is left in an empty
|
||||
* cgroup and the cgroup might have already been rmdir'd.
|
||||
* Don't use cgroup_get_live().
|
||||
*/
|
||||
cgroup_get(cgrp);
|
||||
cgroup_bpf_get(cgrp);
|
||||
}
|
||||
|
||||
void cgroup_sk_free(struct sock_cgroup_data *skcd)
|
||||
{
|
||||
struct cgroup *cgrp = sock_cgroup_ptr(skcd);
|
||||
|
||||
if (skcd->no_refcnt)
|
||||
return;
|
||||
cgroup_bpf_put(cgrp);
|
||||
cgroup_put(cgrp);
|
||||
}
|
||||
|
||||
+2
-1
@@ -567,7 +567,8 @@ static void add_dma_entry(struct dma_debug_entry *entry)
|
||||
pr_err("cacheline tracking ENOMEM, dma-debug disabled\n");
|
||||
global_disable = true;
|
||||
} else if (rc == -EEXIST) {
|
||||
pr_err("cacheline tracking EEXIST, overlapping mappings aren't supported\n");
|
||||
err_printk(entry->dev, entry,
|
||||
"cacheline tracking EEXIST, overlapping mappings aren't supported\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -206,7 +206,8 @@ static int __dma_map_sg_attrs(struct device *dev, struct scatterlist *sg,
|
||||
/**
|
||||
* dma_map_sg_attrs - Map the given buffer for DMA
|
||||
* @dev: The device for which to perform the DMA operation
|
||||
* @sg: The sg_table object describing the buffer
|
||||
* @sg: The sg_table object describing the buffer
|
||||
* @nents: Number of entries to map
|
||||
* @dir: DMA direction
|
||||
* @attrs: Optional DMA attributes for the map operation
|
||||
*
|
||||
|
||||
@@ -171,10 +171,8 @@ static unsigned long exit_to_user_mode_loop(struct pt_regs *regs,
|
||||
if (ti_work & (_TIF_SIGPENDING | _TIF_NOTIFY_SIGNAL))
|
||||
handle_signal_work(regs, ti_work);
|
||||
|
||||
if (ti_work & _TIF_NOTIFY_RESUME) {
|
||||
if (ti_work & _TIF_NOTIFY_RESUME)
|
||||
tracehook_notify_resume(regs);
|
||||
rseq_handle_notify_resume(NULL, regs);
|
||||
}
|
||||
|
||||
/* Architecture specific TIF work */
|
||||
arch_exit_to_user_mode_work(regs, ti_work);
|
||||
|
||||
+31
-5
@@ -3707,6 +3707,29 @@ static noinline int visit_groups_merge(struct perf_cpu_context *cpuctx,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline bool event_update_userpage(struct perf_event *event)
|
||||
{
|
||||
if (likely(!atomic_read(&event->mmap_count)))
|
||||
return false;
|
||||
|
||||
perf_event_update_time(event);
|
||||
perf_set_shadow_time(event, event->ctx);
|
||||
perf_event_update_userpage(event);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void group_update_userpage(struct perf_event *group_event)
|
||||
{
|
||||
struct perf_event *event;
|
||||
|
||||
if (!event_update_userpage(group_event))
|
||||
return;
|
||||
|
||||
for_each_sibling_event(event, group_event)
|
||||
event_update_userpage(event);
|
||||
}
|
||||
|
||||
static int merge_sched_in(struct perf_event *event, void *data)
|
||||
{
|
||||
struct perf_event_context *ctx = event->ctx;
|
||||
@@ -3725,14 +3748,15 @@ static int merge_sched_in(struct perf_event *event, void *data)
|
||||
}
|
||||
|
||||
if (event->state == PERF_EVENT_STATE_INACTIVE) {
|
||||
*can_add_hw = 0;
|
||||
if (event->attr.pinned) {
|
||||
perf_cgroup_event_disable(event, ctx);
|
||||
perf_event_set_state(event, PERF_EVENT_STATE_ERROR);
|
||||
} else {
|
||||
ctx->rotate_necessary = 1;
|
||||
perf_mux_hrtimer_restart(cpuctx);
|
||||
group_update_userpage(event);
|
||||
}
|
||||
|
||||
*can_add_hw = 0;
|
||||
ctx->rotate_necessary = 1;
|
||||
perf_mux_hrtimer_restart(cpuctx);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -6324,6 +6348,8 @@ accounting:
|
||||
|
||||
ring_buffer_attach(event, rb);
|
||||
|
||||
perf_event_update_time(event);
|
||||
perf_set_shadow_time(event, event->ctx);
|
||||
perf_event_init_userpage(event);
|
||||
perf_event_update_userpage(event);
|
||||
} else {
|
||||
@@ -10193,7 +10219,7 @@ static void perf_event_addr_filters_apply(struct perf_event *event)
|
||||
return;
|
||||
|
||||
if (ifh->nr_file_filters) {
|
||||
mm = get_task_mm(event->ctx->task);
|
||||
mm = get_task_mm(task);
|
||||
if (!mm)
|
||||
goto restart;
|
||||
|
||||
|
||||
+7
-3
@@ -97,9 +97,6 @@ config GENERIC_MSI_IRQ_DOMAIN
|
||||
config IRQ_MSI_IOMMU
|
||||
bool
|
||||
|
||||
config HANDLE_DOMAIN_IRQ
|
||||
bool
|
||||
|
||||
config IRQ_TIMINGS
|
||||
bool
|
||||
|
||||
@@ -144,3 +141,10 @@ config GENERIC_IRQ_MULTI_HANDLER
|
||||
bool
|
||||
help
|
||||
Allow to specify the low level IRQ handler at run time.
|
||||
|
||||
# Cavium Octeon is the last system to use this deprecated option
|
||||
# Do not even think of enabling this on any new platform
|
||||
config DEPRECATED_IRQ_CPU_ONOFFLINE
|
||||
bool
|
||||
depends on CAVIUM_OCTEON_SOC
|
||||
default CAVIUM_OCTEON_SOC
|
||||
|
||||
@@ -1122,6 +1122,7 @@ void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_modify_status);
|
||||
|
||||
#ifdef CONFIG_DEPRECATED_IRQ_CPU_ONOFFLINE
|
||||
/**
|
||||
* irq_cpu_online - Invoke all irq_cpu_online functions.
|
||||
*
|
||||
@@ -1181,6 +1182,7 @@ void irq_cpu_offline(void)
|
||||
raw_spin_unlock_irqrestore(&desc->lock, flags);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ static DEFINE_RAW_SPINLOCK(gc_lock);
|
||||
void irq_gc_noop(struct irq_data *d)
|
||||
{
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_gc_noop);
|
||||
|
||||
/**
|
||||
* irq_gc_mask_disable_reg - Mask chip via disable register
|
||||
@@ -44,6 +45,7 @@ void irq_gc_mask_disable_reg(struct irq_data *d)
|
||||
*ct->mask_cache &= ~mask;
|
||||
irq_gc_unlock(gc);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_gc_mask_disable_reg);
|
||||
|
||||
/**
|
||||
* irq_gc_mask_set_bit - Mask chip via setting bit in mask register
|
||||
@@ -103,6 +105,7 @@ void irq_gc_unmask_enable_reg(struct irq_data *d)
|
||||
*ct->mask_cache |= mask;
|
||||
irq_gc_unlock(gc);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_gc_unmask_enable_reg);
|
||||
|
||||
/**
|
||||
* irq_gc_ack_set_bit - Ack pending interrupt via setting bit
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
|
||||
#include <asm/irq_regs.h>
|
||||
|
||||
#include <trace/events/irq.h>
|
||||
|
||||
#include "internals.h"
|
||||
@@ -226,4 +228,20 @@ int __init set_handle_irq(void (*handle_irq)(struct pt_regs *))
|
||||
handle_arch_irq = handle_irq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* generic_handle_arch_irq - root irq handler for architectures which do no
|
||||
* entry accounting themselves
|
||||
* @regs: Register file coming from the low-level handling code
|
||||
*/
|
||||
asmlinkage void noinstr generic_handle_arch_irq(struct pt_regs *regs)
|
||||
{
|
||||
struct pt_regs *old_regs;
|
||||
|
||||
irq_enter();
|
||||
old_regs = set_irq_regs(regs);
|
||||
handle_arch_irq(regs);
|
||||
set_irq_regs(old_regs);
|
||||
irq_exit();
|
||||
}
|
||||
#endif
|
||||
|
||||
+17
-64
@@ -646,13 +646,16 @@ int handle_irq_desc(struct irq_desc *desc)
|
||||
generic_handle_irq_desc(desc);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(handle_irq_desc);
|
||||
|
||||
/**
|
||||
* generic_handle_irq - Invoke the handler for a particular irq
|
||||
* @irq: The irq number to handle
|
||||
*
|
||||
*/
|
||||
* Returns: 0 on success, or -EINVAL if conversion has failed
|
||||
*
|
||||
* This function must be called from an IRQ context with irq regs
|
||||
* initialized.
|
||||
*/
|
||||
int generic_handle_irq(unsigned int irq)
|
||||
{
|
||||
return handle_irq_desc(irq_to_desc(irq));
|
||||
@@ -662,89 +665,39 @@ EXPORT_SYMBOL_GPL(generic_handle_irq);
|
||||
#ifdef CONFIG_IRQ_DOMAIN
|
||||
/**
|
||||
* generic_handle_domain_irq - Invoke the handler for a HW irq belonging
|
||||
* to a domain, usually for a non-root interrupt
|
||||
* controller
|
||||
* to a domain.
|
||||
* @domain: The domain where to perform the lookup
|
||||
* @hwirq: The HW irq number to convert to a logical one
|
||||
*
|
||||
* Returns: 0 on success, or -EINVAL if conversion has failed
|
||||
*
|
||||
* This function must be called from an IRQ context with irq regs
|
||||
* initialized.
|
||||
*/
|
||||
int generic_handle_domain_irq(struct irq_domain *domain, unsigned int hwirq)
|
||||
{
|
||||
WARN_ON_ONCE(!in_irq());
|
||||
return handle_irq_desc(irq_resolve_mapping(domain, hwirq));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(generic_handle_domain_irq);
|
||||
|
||||
#ifdef CONFIG_HANDLE_DOMAIN_IRQ
|
||||
/**
|
||||
* handle_domain_irq - Invoke the handler for a HW irq belonging to a domain,
|
||||
* usually for a root interrupt controller
|
||||
* generic_handle_domain_nmi - Invoke the handler for a HW nmi belonging
|
||||
* to a domain.
|
||||
* @domain: The domain where to perform the lookup
|
||||
* @hwirq: The HW irq number to convert to a logical one
|
||||
* @regs: Register file coming from the low-level handling code
|
||||
*
|
||||
* Returns: 0 on success, or -EINVAL if conversion has failed
|
||||
*/
|
||||
int handle_domain_irq(struct irq_domain *domain,
|
||||
unsigned int hwirq, struct pt_regs *regs)
|
||||
{
|
||||
struct pt_regs *old_regs = set_irq_regs(regs);
|
||||
struct irq_desc *desc;
|
||||
int ret = 0;
|
||||
|
||||
irq_enter();
|
||||
|
||||
/* The irqdomain code provides boundary checks */
|
||||
desc = irq_resolve_mapping(domain, hwirq);
|
||||
if (likely(desc))
|
||||
handle_irq_desc(desc);
|
||||
else
|
||||
ret = -EINVAL;
|
||||
|
||||
irq_exit();
|
||||
set_irq_regs(old_regs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* handle_domain_nmi - Invoke the handler for a HW irq belonging to a domain
|
||||
* @domain: The domain where to perform the lookup
|
||||
* @hwirq: The HW irq number to convert to a logical one
|
||||
* @regs: Register file coming from the low-level handling code
|
||||
*
|
||||
* This function must be called from an NMI context.
|
||||
*
|
||||
* Returns: 0 on success, or -EINVAL if conversion has failed
|
||||
*/
|
||||
int handle_domain_nmi(struct irq_domain *domain, unsigned int hwirq,
|
||||
struct pt_regs *regs)
|
||||
* This function must be called from an NMI context with irq regs
|
||||
* initialized.
|
||||
**/
|
||||
int generic_handle_domain_nmi(struct irq_domain *domain, unsigned int hwirq)
|
||||
{
|
||||
struct pt_regs *old_regs = set_irq_regs(regs);
|
||||
struct irq_desc *desc;
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* NMI context needs to be setup earlier in order to deal with tracing.
|
||||
*/
|
||||
WARN_ON(!in_nmi());
|
||||
|
||||
desc = irq_resolve_mapping(domain, hwirq);
|
||||
|
||||
/*
|
||||
* ack_bad_irq is not NMI-safe, just report
|
||||
* an invalid interrupt.
|
||||
*/
|
||||
if (likely(desc))
|
||||
handle_irq_desc(desc);
|
||||
else
|
||||
ret = -EINVAL;
|
||||
|
||||
set_irq_regs(old_regs);
|
||||
return ret;
|
||||
WARN_ON_ONCE(!in_nmi());
|
||||
return handle_irq_desc(irq_resolve_mapping(domain, hwirq));
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Dynamic interrupt handling */
|
||||
|
||||
|
||||
@@ -136,7 +136,7 @@ EXPORT_SYMBOL_GPL(irq_domain_free_fwnode);
|
||||
* Allocates and initializes an irq_domain structure.
|
||||
* Returns pointer to IRQ domain, or NULL on failure.
|
||||
*/
|
||||
struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, int size,
|
||||
struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, unsigned int size,
|
||||
irq_hw_number_t hwirq_max, int direct_max,
|
||||
const struct irq_domain_ops *ops,
|
||||
void *host_data)
|
||||
|
||||
+46
-21
@@ -41,6 +41,12 @@
|
||||
* The risk of writer starvation is there, but the pathological use cases
|
||||
* which trigger it are not necessarily the typical RT workloads.
|
||||
*
|
||||
* Fast-path orderings:
|
||||
* The lock/unlock of readers can run in fast paths: lock and unlock are only
|
||||
* atomic ops, and there is no inner lock to provide ACQUIRE and RELEASE
|
||||
* semantics of rwbase_rt. Atomic ops should thus provide _acquire()
|
||||
* and _release() (or stronger).
|
||||
*
|
||||
* Common code shared between RT rw_semaphore and rwlock
|
||||
*/
|
||||
|
||||
@@ -53,6 +59,7 @@ static __always_inline int rwbase_read_trylock(struct rwbase_rt *rwb)
|
||||
* set.
|
||||
*/
|
||||
for (r = atomic_read(&rwb->readers); r < 0;) {
|
||||
/* Fully-ordered if cmpxchg() succeeds, provides ACQUIRE */
|
||||
if (likely(atomic_try_cmpxchg(&rwb->readers, &r, r + 1)))
|
||||
return 1;
|
||||
}
|
||||
@@ -162,6 +169,8 @@ static __always_inline void rwbase_read_unlock(struct rwbase_rt *rwb,
|
||||
/*
|
||||
* rwb->readers can only hit 0 when a writer is waiting for the
|
||||
* active readers to leave the critical section.
|
||||
*
|
||||
* dec_and_test() is fully ordered, provides RELEASE.
|
||||
*/
|
||||
if (unlikely(atomic_dec_and_test(&rwb->readers)))
|
||||
__rwbase_read_unlock(rwb, state);
|
||||
@@ -172,7 +181,11 @@ static inline void __rwbase_write_unlock(struct rwbase_rt *rwb, int bias,
|
||||
{
|
||||
struct rt_mutex_base *rtm = &rwb->rtmutex;
|
||||
|
||||
atomic_add(READER_BIAS - bias, &rwb->readers);
|
||||
/*
|
||||
* _release() is needed in case that reader is in fast path, pairing
|
||||
* with atomic_try_cmpxchg() in rwbase_read_trylock(), provides RELEASE
|
||||
*/
|
||||
(void)atomic_add_return_release(READER_BIAS - bias, &rwb->readers);
|
||||
raw_spin_unlock_irqrestore(&rtm->wait_lock, flags);
|
||||
rwbase_rtmutex_unlock(rtm);
|
||||
}
|
||||
@@ -196,6 +209,23 @@ static inline void rwbase_write_downgrade(struct rwbase_rt *rwb)
|
||||
__rwbase_write_unlock(rwb, WRITER_BIAS - 1, flags);
|
||||
}
|
||||
|
||||
static inline bool __rwbase_write_trylock(struct rwbase_rt *rwb)
|
||||
{
|
||||
/* Can do without CAS because we're serialized by wait_lock. */
|
||||
lockdep_assert_held(&rwb->rtmutex.wait_lock);
|
||||
|
||||
/*
|
||||
* _acquire is needed in case the reader is in the fast path, pairing
|
||||
* with rwbase_read_unlock(), provides ACQUIRE.
|
||||
*/
|
||||
if (!atomic_read_acquire(&rwb->readers)) {
|
||||
atomic_set(&rwb->readers, WRITER_BIAS);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __sched rwbase_write_lock(struct rwbase_rt *rwb,
|
||||
unsigned int state)
|
||||
{
|
||||
@@ -210,34 +240,30 @@ static int __sched rwbase_write_lock(struct rwbase_rt *rwb,
|
||||
atomic_sub(READER_BIAS, &rwb->readers);
|
||||
|
||||
raw_spin_lock_irqsave(&rtm->wait_lock, flags);
|
||||
/*
|
||||
* set_current_state() for rw_semaphore
|
||||
* current_save_and_set_rtlock_wait_state() for rwlock
|
||||
*/
|
||||
rwbase_set_and_save_current_state(state);
|
||||
if (__rwbase_write_trylock(rwb))
|
||||
goto out_unlock;
|
||||
|
||||
/* Block until all readers have left the critical section. */
|
||||
for (; atomic_read(&rwb->readers);) {
|
||||
rwbase_set_and_save_current_state(state);
|
||||
for (;;) {
|
||||
/* Optimized out for rwlocks */
|
||||
if (rwbase_signal_pending_state(state, current)) {
|
||||
__set_current_state(TASK_RUNNING);
|
||||
rwbase_restore_current_state();
|
||||
__rwbase_write_unlock(rwb, 0, flags);
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
if (__rwbase_write_trylock(rwb))
|
||||
break;
|
||||
|
||||
raw_spin_unlock_irqrestore(&rtm->wait_lock, flags);
|
||||
|
||||
/*
|
||||
* Schedule and wait for the readers to leave the critical
|
||||
* section. The last reader leaving it wakes the waiter.
|
||||
*/
|
||||
if (atomic_read(&rwb->readers) != 0)
|
||||
rwbase_schedule();
|
||||
set_current_state(state);
|
||||
rwbase_schedule();
|
||||
raw_spin_lock_irqsave(&rtm->wait_lock, flags);
|
||||
}
|
||||
|
||||
atomic_set(&rwb->readers, WRITER_BIAS);
|
||||
set_current_state(state);
|
||||
}
|
||||
rwbase_restore_current_state();
|
||||
|
||||
out_unlock:
|
||||
raw_spin_unlock_irqrestore(&rtm->wait_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
@@ -253,8 +279,7 @@ static inline int rwbase_write_trylock(struct rwbase_rt *rwb)
|
||||
atomic_sub(READER_BIAS, &rwb->readers);
|
||||
|
||||
raw_spin_lock_irqsave(&rtm->wait_lock, flags);
|
||||
if (!atomic_read(&rwb->readers)) {
|
||||
atomic_set(&rwb->readers, WRITER_BIAS);
|
||||
if (__rwbase_write_trylock(rwb)) {
|
||||
raw_spin_unlock_irqrestore(&rtm->wait_lock, flags);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1166,9 +1166,9 @@ void __init setup_log_buf(int early)
|
||||
return;
|
||||
|
||||
err_free_descs:
|
||||
memblock_free(__pa(new_descs), new_descs_size);
|
||||
memblock_free_ptr(new_descs, new_descs_size);
|
||||
err_free_log_buf:
|
||||
memblock_free(__pa(new_log_buf), new_log_buf_len);
|
||||
memblock_free_ptr(new_log_buf, new_log_buf_len);
|
||||
}
|
||||
|
||||
static bool __read_mostly ignore_loglevel;
|
||||
|
||||
+11
-3
@@ -282,9 +282,17 @@ void __rseq_handle_notify_resume(struct ksignal *ksig, struct pt_regs *regs)
|
||||
|
||||
if (unlikely(t->flags & PF_EXITING))
|
||||
return;
|
||||
ret = rseq_ip_fixup(regs);
|
||||
if (unlikely(ret < 0))
|
||||
goto error;
|
||||
|
||||
/*
|
||||
* regs is NULL if and only if the caller is in a syscall path. Skip
|
||||
* fixup and leave rseq_cs as is so that rseq_sycall() will detect and
|
||||
* kill a misbehaving userspace on debug kernels.
|
||||
*/
|
||||
if (regs) {
|
||||
ret = rseq_ip_fixup(regs);
|
||||
if (unlikely(ret < 0))
|
||||
goto error;
|
||||
}
|
||||
if (unlikely(rseq_update_cpu_id(t)))
|
||||
goto error;
|
||||
return;
|
||||
|
||||
@@ -173,16 +173,22 @@ static ssize_t sched_scaling_write(struct file *filp, const char __user *ubuf,
|
||||
size_t cnt, loff_t *ppos)
|
||||
{
|
||||
char buf[16];
|
||||
unsigned int scaling;
|
||||
|
||||
if (cnt > 15)
|
||||
cnt = 15;
|
||||
|
||||
if (copy_from_user(&buf, ubuf, cnt))
|
||||
return -EFAULT;
|
||||
buf[cnt] = '\0';
|
||||
|
||||
if (kstrtouint(buf, 10, &sysctl_sched_tunable_scaling))
|
||||
if (kstrtouint(buf, 10, &scaling))
|
||||
return -EINVAL;
|
||||
|
||||
if (scaling >= SCHED_TUNABLESCALING_END)
|
||||
return -EINVAL;
|
||||
|
||||
sysctl_sched_tunable_scaling = scaling;
|
||||
if (sched_update_scaling())
|
||||
return -EINVAL;
|
||||
|
||||
|
||||
+5
-1
@@ -4936,8 +4936,12 @@ void unthrottle_cfs_rq(struct cfs_rq *cfs_rq)
|
||||
/* update hierarchical throttle state */
|
||||
walk_tg_tree_from(cfs_rq->tg, tg_nop, tg_unthrottle_up, (void *)rq);
|
||||
|
||||
if (!cfs_rq->load.weight)
|
||||
/* Nothing to run but something to decay (on_list)? Complete the branch */
|
||||
if (!cfs_rq->load.weight) {
|
||||
if (cfs_rq->on_list)
|
||||
goto unthrottle_throttle;
|
||||
return;
|
||||
}
|
||||
|
||||
task_delta = cfs_rq->h_nr_running;
|
||||
idle_task_delta = cfs_rq->idle_h_nr_running;
|
||||
|
||||
@@ -1404,7 +1404,8 @@ void set_process_cpu_timer(struct task_struct *tsk, unsigned int clkid,
|
||||
}
|
||||
}
|
||||
|
||||
*newval += now;
|
||||
if (*newval)
|
||||
*newval += now;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -1605,6 +1605,14 @@ static int blk_trace_remove_queue(struct request_queue *q)
|
||||
if (bt == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (bt->trace_state == Blktrace_running) {
|
||||
bt->trace_state = Blktrace_stopped;
|
||||
spin_lock_irq(&running_trace_lock);
|
||||
list_del_init(&bt->running_list);
|
||||
spin_unlock_irq(&running_trace_lock);
|
||||
relay_flush(bt->rchan);
|
||||
}
|
||||
|
||||
put_probe_ref();
|
||||
synchronize_rcu();
|
||||
blk_trace_free(bt);
|
||||
|
||||
Reference in New Issue
Block a user