Import of kernel-5.14.0-687.36.1.el9_8

This commit is contained in:
almalinux-bot-kernel 2026-08-08 04:28:59 +00:00
parent 8fb3f67c3a
commit d8f1f57754
28 changed files with 364 additions and 166 deletions

View File

@ -12,7 +12,7 @@ RHEL_MINOR = 8
#
# Use this spot to avoid future merge conflicts.
# Do not trim this comment.
RHEL_RELEASE = 687.34.1
RHEL_RELEASE = 687.36.1
#
# ZSTREAM

View File

@ -65,6 +65,21 @@ bool arch_dma_unmap_sg_direct(struct device *dev, struct scatterlist *sg,
return true;
}
bool arch_dma_alloc_direct(struct device *dev)
{
if (dev->dma_ops_bypass && dev->bus_dma_limit)
return true;
return false;
}
bool arch_dma_free_direct(struct device *dev, dma_addr_t dma_handle)
{
if (!dev->dma_ops_bypass || !dev->bus_dma_limit)
return false;
return is_direct_handle(dev, dma_handle);
}
#endif /* CONFIG_ARCH_HAS_DMA_MAP_DIRECT */
/*
@ -148,17 +163,12 @@ int dma_iommu_dma_supported(struct device *dev, u64 mask)
if (dev_is_pci(dev) && dma_iommu_bypass_supported(dev, mask)) {
/*
* dma_iommu_bypass_supported() sets dma_max when there is
* 1:1 mapping but it is somehow limited.
* ibm,pmemory is one example.
* fixed ops will be used for RAM. This is limited by
* bus_dma_limit which is set when RAM is pre-mapped.
*/
dev->dma_ops_bypass = dev->bus_dma_limit == 0;
if (!dev->dma_ops_bypass)
dev_warn(dev,
"iommu: 64-bit OK but direct DMA is limited by %llx\n",
dev->bus_dma_limit);
else
dev_dbg(dev, "iommu: 64-bit OK, using fixed ops\n");
dev->dma_ops_bypass = true;
dev_info(dev, "iommu: 64-bit OK but direct DMA is limited by %llx\n",
dev->bus_dma_limit);
return 1;
}

View File

@ -1772,10 +1772,8 @@ out_failed:
out_unlock:
mutex_unlock(&dma_win_init_mutex);
/* If we have persistent memory and the window size is not big enough
* to directly map both RAM and vPMEM, then we need to set DMA limit.
*/
if (pmem_present && direct_mapping && len != MAX_PHYSMEM_BITS)
/* For pre-mapped memory, set bus_dma_limit to the max RAM */
if (direct_mapping)
dev->dev.bus_dma_limit = dev->dev.archdata.dma_offset +
(1ULL << max_ram_len);

View File

@ -196,7 +196,7 @@ static void octep_vf_setup_iq_regs_cn93(struct octep_vf_device *oct, int iq_no)
}
/* Setup registers for a hardware Rx Queue */
static void octep_vf_setup_oq_regs_cn93(struct octep_vf_device *oct, int oq_no)
static int octep_vf_setup_oq_regs_cn93(struct octep_vf_device *oct, int oq_no)
{
struct octep_vf_oq *oq = oct->oq[oq_no];
u32 time_threshold = 0;
@ -239,6 +239,7 @@ static void octep_vf_setup_oq_regs_cn93(struct octep_vf_device *oct, int oq_no)
time_threshold = CFG_GET_OQ_INTR_TIME(oct->conf);
reg_val = ((u64)time_threshold << 32) | CFG_GET_OQ_INTR_PKT(oct->conf);
octep_vf_write_csr64(oct, CN93_VF_SDP_R_OUT_INT_LEVELS(oq_no), reg_val);
return 0;
}
/* Setup registers for a VF mailbox */

View File

@ -199,11 +199,13 @@ static void octep_vf_setup_iq_regs_cnxk(struct octep_vf_device *oct, int iq_no)
}
/* Setup registers for a hardware Rx Queue */
static void octep_vf_setup_oq_regs_cnxk(struct octep_vf_device *oct, int oq_no)
static int octep_vf_setup_oq_regs_cnxk(struct octep_vf_device *oct, int oq_no)
{
struct octep_vf_oq *oq = oct->oq[oq_no];
unsigned long t_out_jiffies;
u32 time_threshold = 0;
u64 oq_ctl = ULL(0);
u64 reg_ba_val;
u64 reg_val;
reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_CONTROL(oq_no));
@ -214,6 +216,38 @@ static void octep_vf_setup_oq_regs_cnxk(struct octep_vf_device *oct, int oq_no)
reg_val = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_CONTROL(oq_no));
} while (!(reg_val & CNXK_VF_R_OUT_CTL_IDLE));
}
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_WMARK(oq_no),
oq->max_count);
/* Wait for WMARK to get applied */
usleep_range(10, 15);
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_BADDR(oq_no),
oq->desc_ring_dma);
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_RSIZE(oq_no),
oq->max_count);
reg_ba_val = octep_vf_read_csr64(oct,
CNXK_VF_SDP_R_OUT_SLIST_BADDR(oq_no));
if (reg_ba_val != oq->desc_ring_dma) {
t_out_jiffies = jiffies + 10 * HZ;
do {
if (reg_ba_val == ULLONG_MAX)
return -EFAULT;
octep_vf_write_csr64(oct,
CNXK_VF_SDP_R_OUT_SLIST_BADDR
(oq_no), oq->desc_ring_dma);
octep_vf_write_csr64(oct,
CNXK_VF_SDP_R_OUT_SLIST_RSIZE
(oq_no), oq->max_count);
reg_ba_val =
octep_vf_read_csr64(oct,
CNXK_VF_SDP_R_OUT_SLIST_BADDR
(oq_no));
} while ((reg_ba_val != oq->desc_ring_dma) &&
time_before(jiffies, t_out_jiffies));
if (reg_ba_val != oq->desc_ring_dma)
return -EAGAIN;
}
reg_val &= ~(CNXK_VF_R_OUT_CTL_IMODE);
reg_val &= ~(CNXK_VF_R_OUT_CTL_ROR_P);
@ -227,8 +261,6 @@ static void octep_vf_setup_oq_regs_cnxk(struct octep_vf_device *oct, int oq_no)
reg_val |= (CNXK_VF_R_OUT_CTL_ES_P);
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_CONTROL(oq_no), reg_val);
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_BADDR(oq_no), oq->desc_ring_dma);
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_SLIST_RSIZE(oq_no), oq->max_count);
oq_ctl = octep_vf_read_csr64(oct, CNXK_VF_SDP_R_OUT_CONTROL(oq_no));
/* Clear the ISIZE and BSIZE (22-0) */
@ -250,6 +282,7 @@ static void octep_vf_setup_oq_regs_cnxk(struct octep_vf_device *oct, int oq_no)
reg_val &= ~GENMASK_ULL(31, 0);
reg_val |= CFG_GET_OQ_WMARK(oct->conf);
octep_vf_write_csr64(oct, CNXK_VF_SDP_R_OUT_WMARK(oq_no), reg_val);
return 0;
}
/* Setup registers for a VF mailbox */

View File

@ -220,7 +220,7 @@ static int octep_vf_request_irqs(struct octep_vf_device *oct)
ioq_irq_err:
while (i) {
--i;
free_irq(oct->msix_entries[i].vector, oct);
free_irq(oct->msix_entries[i].vector, oct->ioq_vector[i]);
}
return -1;
}
@ -287,29 +287,46 @@ static void octep_vf_clean_irqs(struct octep_vf_device *oct)
octep_vf_free_ioq_vectors(oct);
}
/**
* octep_vf_update_pkt() - Update IQ/OQ IN/OUT_CNT registers.
*
* @iq: Octeon Tx queue data structure.
* @oq: Octeon Rx queue data structure.
*/
static void octep_vf_update_pkt(struct octep_vf_iq *iq, struct octep_vf_oq *oq)
{
u32 pkts_pend = READ_ONCE(oq->pkts_pending);
u32 last_pkt_count = READ_ONCE(oq->last_pkt_count);
u32 pkts_processed = READ_ONCE(iq->pkts_processed);
u32 pkt_in_done = READ_ONCE(iq->pkt_in_done);
netdev_dbg(iq->netdev, "enabling intr for Q-%u\n", iq->q_no);
if (pkts_processed) {
writel(pkts_processed, iq->inst_cnt_reg);
readl(iq->inst_cnt_reg);
WRITE_ONCE(iq->pkt_in_done, (pkt_in_done - pkts_processed));
WRITE_ONCE(iq->pkts_processed, 0);
}
if (last_pkt_count - pkts_pend) {
writel(last_pkt_count - pkts_pend, oq->pkts_sent_reg);
readl(oq->pkts_sent_reg);
WRITE_ONCE(oq->last_pkt_count, pkts_pend);
}
/* Flush the previous wrties before writing to RESEND bit */
smp_wmb();
}
/**
* octep_vf_enable_ioq_irq() - Enable MSI-x interrupt of a Tx/Rx queue.
*
* @iq: Octeon Tx queue data structure.
* @oq: Octeon Rx queue data structure.
*/
static void octep_vf_enable_ioq_irq(struct octep_vf_iq *iq, struct octep_vf_oq *oq)
static void octep_vf_enable_ioq_irq(struct octep_vf_iq *iq,
struct octep_vf_oq *oq)
{
u32 pkts_pend = oq->pkts_pending;
netdev_dbg(iq->netdev, "enabling intr for Q-%u\n", iq->q_no);
if (iq->pkts_processed) {
writel(iq->pkts_processed, iq->inst_cnt_reg);
iq->pkt_in_done -= iq->pkts_processed;
iq->pkts_processed = 0;
}
if (oq->last_pkt_count - pkts_pend) {
writel(oq->last_pkt_count - pkts_pend, oq->pkts_sent_reg);
oq->last_pkt_count = pkts_pend;
}
/* Flush the previous wrties before writing to RESEND bit */
smp_wmb();
writeq(1UL << OCTEP_VF_OQ_INTR_RESEND_BIT, oq->pkts_sent_reg);
writeq(1UL << OCTEP_VF_IQ_INTR_RESEND_BIT, iq->inst_cnt_reg);
}
@ -335,6 +352,7 @@ static int octep_vf_napi_poll(struct napi_struct *napi, int budget)
if (tx_pending || rx_done >= budget)
return budget;
octep_vf_update_pkt(ioq_vector->iq, ioq_vector->oq);
if (likely(napi_complete_done(napi, rx_done)))
octep_vf_enable_ioq_irq(ioq_vector->iq, ioq_vector->oq);

View File

@ -55,7 +55,7 @@ struct octep_vf_mmio {
struct octep_vf_hw_ops {
void (*setup_iq_regs)(struct octep_vf_device *oct, int q);
void (*setup_oq_regs)(struct octep_vf_device *oct, int q);
int (*setup_oq_regs)(struct octep_vf_device *oct, int q);
void (*setup_mbox_regs)(struct octep_vf_device *oct, int mbox);
irqreturn_t (*non_ioq_intr_handler)(void *ioq_vector);

View File

@ -12,6 +12,8 @@
#include "octep_vf_config.h"
#include "octep_vf_main.h"
static void octep_vf_oq_free_ring_buffers(struct octep_vf_oq *oq);
static void octep_vf_oq_reset_indices(struct octep_vf_oq *oq)
{
oq->host_read_idx = 0;
@ -171,11 +173,15 @@ static int octep_vf_setup_oq(struct octep_vf_device *oct, int q_no)
goto oq_fill_buff_err;
octep_vf_oq_reset_indices(oq);
oct->hw_ops.setup_oq_regs(oct, q_no);
if (oct->hw_ops.setup_oq_regs(oct, q_no))
goto oq_setup_err;
oct->num_oqs++;
return 0;
oq_setup_err:
octep_vf_oq_free_ring_buffers(oq);
oq_fill_buff_err:
vfree(oq->buff_info);
oq->buff_info = NULL;
@ -319,9 +325,16 @@ static int octep_vf_oq_check_hw_for_pkts(struct octep_vf_device *oct,
struct octep_vf_oq *oq)
{
u32 pkt_count, new_pkts;
u32 last_pkt_count, pkts_pending;
pkt_count = readl(oq->pkts_sent_reg);
new_pkts = pkt_count - oq->last_pkt_count;
last_pkt_count = READ_ONCE(oq->last_pkt_count);
new_pkts = pkt_count - last_pkt_count;
if (pkt_count < last_pkt_count) {
dev_err(oq->dev, "OQ-%u pkt_count(%u) < oq->last_pkt_count(%u)\n",
oq->q_no, pkt_count, last_pkt_count);
}
/* Clear the hardware packets counter register if the rx queue is
* being processed continuously with-in a single interrupt and
@ -333,11 +346,17 @@ static int octep_vf_oq_check_hw_for_pkts(struct octep_vf_device *oct,
pkt_count = readl(oq->pkts_sent_reg);
new_pkts += pkt_count;
}
oq->last_pkt_count = pkt_count;
oq->pkts_pending += new_pkts;
WRITE_ONCE(oq->last_pkt_count, pkt_count);
pkts_pending = READ_ONCE(oq->pkts_pending);
WRITE_ONCE(oq->pkts_pending, (pkts_pending + new_pkts));
return new_pkts;
}
static inline u32 octep_vf_oq_next_idx(struct octep_vf_oq *oq, u32 idx)
{
return (idx + 1 == oq->max_count) ? 0 : idx + 1;
}
/**
* __octep_vf_oq_process_rx() - Process hardware Rx queue and push to stack.
*
@ -363,7 +382,7 @@ static int __octep_vf_oq_process_rx(struct octep_vf_device *oct,
struct sk_buff *skb;
u32 read_idx;
read_idx = oq->host_read_idx;
read_idx = READ_ONCE(oq->host_read_idx);
rx_bytes = 0;
desc_used = 0;
for (pkt = 0; pkt < pkts_to_process; pkt++) {
@ -395,30 +414,52 @@ static int __octep_vf_oq_process_rx(struct octep_vf_device *oct,
data_offset = OCTEP_VF_OQ_RESP_HW_SIZE;
rx_ol_flags = 0;
}
rx_bytes += buff_info->len;
if (buff_info->len <= oq->max_single_buffer_size) {
skb = napi_build_skb((void *)resp_hw, PAGE_SIZE);
if (!skb) {
oq->stats->alloc_failures++;
desc_used++;
read_idx = octep_vf_oq_next_idx(oq, read_idx);
continue;
}
rx_bytes += buff_info->len;
skb_reserve(skb, data_offset);
skb_put(skb, buff_info->len);
read_idx++;
desc_used++;
if (read_idx == oq->max_count)
read_idx = 0;
read_idx = octep_vf_oq_next_idx(oq, read_idx);
} else {
struct skb_shared_info *shinfo;
u16 data_len;
skb = napi_build_skb((void *)resp_hw, PAGE_SIZE);
if (!skb) {
oq->stats->alloc_failures++;
desc_used++;
read_idx = octep_vf_oq_next_idx(oq, read_idx);
data_len = buff_info->len - oq->max_single_buffer_size;
while (data_len) {
dma_unmap_page(oq->dev, oq->desc_ring[read_idx].buffer_ptr,
PAGE_SIZE, DMA_FROM_DEVICE);
buff_info = (struct octep_vf_rx_buffer *)
&oq->buff_info[read_idx];
buff_info->page = NULL;
if (data_len < oq->buffer_size)
data_len = 0;
else
data_len -= oq->buffer_size;
desc_used++;
read_idx = octep_vf_oq_next_idx(oq, read_idx);
}
continue;
}
rx_bytes += buff_info->len;
skb_reserve(skb, data_offset);
/* Head fragment includes response header(s);
* subsequent fragments contains only data.
*/
skb_put(skb, oq->max_single_buffer_size);
read_idx++;
desc_used++;
if (read_idx == oq->max_count)
read_idx = 0;
read_idx = octep_vf_oq_next_idx(oq, read_idx);
shinfo = skb_shinfo(skb);
data_len = buff_info->len - oq->max_single_buffer_size;
@ -440,10 +481,8 @@ static int __octep_vf_oq_process_rx(struct octep_vf_device *oct,
buff_info->len,
buff_info->len);
buff_info->page = NULL;
read_idx++;
desc_used++;
if (read_idx == oq->max_count)
read_idx = 0;
read_idx = octep_vf_oq_next_idx(oq, read_idx);
}
}
@ -457,7 +496,7 @@ static int __octep_vf_oq_process_rx(struct octep_vf_device *oct,
napi_gro_receive(oq->napi, skb);
}
oq->host_read_idx = read_idx;
WRITE_ONCE(oq->host_read_idx, read_idx);
oq->refill_count += desc_used;
oq->stats->packets += pkt;
oq->stats->bytes += rx_bytes;
@ -480,22 +519,26 @@ int octep_vf_oq_process_rx(struct octep_vf_oq *oq, int budget)
{
u32 pkts_available, pkts_processed, total_pkts_processed;
struct octep_vf_device *oct = oq->octep_vf_dev;
u32 pkts_pending;
pkts_available = 0;
pkts_processed = 0;
total_pkts_processed = 0;
while (total_pkts_processed < budget) {
/* update pending count only when current one exhausted */
if (oq->pkts_pending == 0)
pkts_pending = READ_ONCE(oq->pkts_pending);
if (pkts_pending == 0)
octep_vf_oq_check_hw_for_pkts(oct, oq);
pkts_pending = READ_ONCE(oq->pkts_pending);
pkts_available = min(budget - total_pkts_processed,
oq->pkts_pending);
pkts_pending);
if (!pkts_available)
break;
pkts_processed = __octep_vf_oq_process_rx(oct, oq,
pkts_available);
oq->pkts_pending -= pkts_processed;
pkts_pending = READ_ONCE(oq->pkts_pending);
WRITE_ONCE(oq->pkts_pending, (pkts_pending - pkts_processed));
total_pkts_processed += pkts_processed;
}

View File

@ -26,7 +26,7 @@ static const struct file_operations proc_sys_dir_file_operations;
static const struct inode_operations proc_sys_dir_operations;
/* shared constants to be used in various sysctls */
const int sysctl_vals[] = { -1, 0, 1, 2, 4, 100, 200, 1000, 3000, INT_MAX, 65535 };
const int sysctl_vals[] = { -1, 0, 1, 2, 4, 100, 200, 1000, 3000, INT_MAX, 65535, MAX_RECLAIM_RETRIES, DEF_PRIORITY - 1 };
EXPORT_SYMBOL(sysctl_vals);
const unsigned long sysctl_long_vals[] = { 0, 1, LONG_MAX };

View File

@ -398,11 +398,15 @@ bool arch_dma_map_sg_direct(struct device *dev, struct scatterlist *sg,
int nents);
bool arch_dma_unmap_sg_direct(struct device *dev, struct scatterlist *sg,
int nents);
bool arch_dma_alloc_direct(struct device *dev);
bool arch_dma_free_direct(struct device *dev, dma_addr_t dma_handle);
#else
#define arch_dma_map_page_direct(d, a) (false)
#define arch_dma_unmap_page_direct(d, a) (false)
#define arch_dma_map_sg_direct(d, s, n) (false)
#define arch_dma_unmap_sg_direct(d, s, n) (false)
#define arch_dma_alloc_direct(d) (false)
#define arch_dma_free_direct(d, a) (false)
#endif
#ifdef CONFIG_ARCH_HAS_SETUP_DMA_OPS

View File

@ -54,9 +54,16 @@ struct mempolicy {
nodemask_t cpuset_mems_allowed; /* relative to these nodes */
nodemask_t user_nodemask; /* nodemask passed by user */
} w;
RH_KABI_RESERVE(1)
RH_KABI_RESERVE(2)
RH_KABI_USE(1, 2, struct rcu_head rcu)
RH_KABI_RESERVE(3)
/*
* RH Note:
* Struct mempolicy is always dynamically allocated with the policy_cache
* in mpol_new(), __mpol_dup() and shared_policy_replace() of mm/memplicy.c.
* It is also not embedded in any other data structures. So it can be
* safely extended with RH_KABI_EXTEND() here.
*/
};
/*

View File

@ -79,6 +79,11 @@ extern int page_cluster;
extern const int page_cluster_max;
#ifdef CONFIG_SYSCTL
#ifdef CONFIG_MEMCG
extern int sysctl_mem_cgroup_reclaim_retries;
#endif
extern int sysctl_legacy_va_layout;
#else
#define sysctl_legacy_va_layout 0
@ -3937,6 +3942,7 @@ static inline int in_gate_area(struct mm_struct *mm, unsigned long addr)
extern bool process_shares_mm(struct task_struct *p, struct mm_struct *mm);
#ifdef CONFIG_SYSCTL
extern int sysctl_dr_prio_drop;
extern int sysctl_drop_caches;
int drop_caches_sysctl_handler(struct ctl_table *, int, void *, size_t *,
loff_t *);

View File

@ -1201,6 +1201,12 @@ static inline bool zone_intersects(struct zone *zone,
*/
#define DEF_PRIORITY 12
/*
* Maximum number of reclaim retries without progress before the OOM
* killer is consider the only way forward.
*/
#define MAX_RECLAIM_RETRIES 16
/* Maximum number of zones on a zonelist */
#define MAX_ZONES_PER_ZONELIST (MAX_NUMNODES * MAX_NR_ZONES)

View File

@ -51,6 +51,8 @@ struct ctl_dir;
/* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
#define SYSCTL_MAXOLDUID ((void *)&sysctl_vals[10])
#define SYSCTL_MAX_RECLAIM_TRIES ((void *)&sysctl_vals[11])
#define SYSCTL_MAX_PRIO_DROP ((void *)&sysctl_vals[12])
extern const int sysctl_vals[];

View File

@ -1,3 +1,3 @@
sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
kernel.rhel,1,Red Hat,kernel-core,5.14.0-687.34.1.el9.x86_64,mailto:secalert@redhat.com
kernel.almalinux,1,AlmaLinux,kernel-core,5.14.0-687.34.1.el9.x86_64,mailto:security@almalinux.org
kernel.rhel,1,Red Hat,kernel-core,5.14.0-687.36.1.el9.x86_64,mailto:secalert@redhat.com
kernel.almalinux,1,AlmaLinux,kernel-core,5.14.0-687.36.1.el9.x86_64,mailto:security@almalinux.org

View File

@ -632,7 +632,7 @@ void *dma_alloc_attrs(struct device *dev, size_t size, dma_addr_t *dma_handle,
/* let the implementation decide on the zone to allocate from: */
flag &= ~(__GFP_DMA | __GFP_DMA32 | __GFP_HIGHMEM);
if (dma_alloc_direct(dev, ops)) {
if (dma_alloc_direct(dev, ops) || arch_dma_alloc_direct(dev)) {
cpu_addr = dma_direct_alloc(dev, size, dma_handle, flag, attrs);
} else if (use_dma_iommu(dev)) {
cpu_addr = iommu_dma_alloc(dev, size, dma_handle, flag, attrs);
@ -673,7 +673,7 @@ void dma_free_attrs(struct device *dev, size_t size, void *cpu_addr,
return;
debug_dma_free_coherent(dev, size, cpu_addr, dma_handle);
if (dma_alloc_direct(dev, ops))
if (dma_alloc_direct(dev, ops) || arch_dma_free_direct(dev, dma_handle))
dma_direct_free(dev, size, cpu_addr, dma_handle, attrs);
else if (use_dma_iommu(dev))
iommu_dma_free(dev, size, cpu_addr, dma_handle, attrs);

View File

@ -341,7 +341,7 @@ static int __futex_key_to_node(struct mm_struct *mm, unsigned long addr)
if (!vma)
return FUTEX_NO_NODE;
mpol = vma_policy(vma);
mpol = READ_ONCE(vma->vm_policy);
if (!mpol)
return FUTEX_NO_NODE;

View File

@ -918,7 +918,7 @@ int fixup_pi_owner(u32 __user *uaddr, struct futex_q *q, int locked)
int futex_lock_pi(u32 __user *uaddr, unsigned int flags, ktime_t *time, int trylock)
{
struct hrtimer_sleeper timeout, *to;
struct task_struct *exiting = NULL;
struct task_struct *exiting;
struct rt_mutex_waiter rt_waiter;
struct futex_q q = futex_q_init;
DEFINE_WAKE_Q(wake_q);
@ -933,6 +933,7 @@ int futex_lock_pi(u32 __user *uaddr, unsigned int flags, ktime_t *time, int tryl
to = futex_setup_timer(time, &timeout, flags, 0);
retry:
exiting = NULL;
ret = get_futex_key(uaddr, flags, &q.key, FUTEX_WRITE);
if (unlikely(ret != 0))
goto out;

View File

@ -318,8 +318,11 @@ futex_proxy_trylock_atomic(u32 __user *pifutex, struct futex_hash_bucket *hb1,
return -EINVAL;
/* Ensure that this does not race against an early wakeup */
if (!futex_requeue_pi_prepare(top_waiter, NULL))
if (!futex_requeue_pi_prepare(top_waiter, NULL)) {
plist_del(&top_waiter->list, &hb1->chain);
futex_hb_waiters_dec(hb1);
return -EAGAIN;
}
/*
* Try to take the lock for top_waiter and set the FUTEX_WAITERS bit
@ -721,10 +724,12 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,
/*
* We were woken prior to requeue by a timeout or a signal.
* Unqueue the futex_q and determine which it was.
* Conditionally unqueue the futex_q and determine which it was.
*/
plist_del(&q->list, &hb->chain);
futex_hb_waiters_dec(hb);
if (!plist_node_empty(&q->list)) {
plist_del(&q->list, &hb->chain);
futex_hb_waiters_dec(hb);
}
/* Handle spurious wakeups gracefully */
ret = -EWOULDBLOCK;

View File

@ -459,6 +459,14 @@ SYSCALL_DEFINE4(futex_requeue,
if (ret)
return ret;
/*
* For now mandate both flags are identical, like the sys_futex()
* interface has. If/when we merge the variable sized futex support,
* that patch can modify this test to allow a difference in size.
*/
if (futexes[0].w.flags != futexes[1].w.flags)
return -EINVAL;
cmpval = futexes[0].w.val;
return futex_requeue(u64_to_user_ptr(futexes[0].w.uaddr), futexes[0].w.flags,

View File

@ -71,6 +71,7 @@
#include <linux/uaccess.h>
#include <asm/processor.h>
#include <linux/mmzone.h>
#ifdef CONFIG_X86
#include <asm/nmi.h>
@ -2193,6 +2194,17 @@ static struct ctl_table vm_table[] = {
.extra1 = SYSCTL_ZERO,
.extra2 = SYSCTL_TWO_HUNDRED,
},
#ifdef CONFIG_MEMCG
{
.procname = "mem_cgroup_reclaim_retries",
.data = &sysctl_mem_cgroup_reclaim_retries,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
.extra1 = SYSCTL_ONE,
.extra2 = SYSCTL_MAX_RECLAIM_TRIES,
},
#endif
#ifdef CONFIG_NUMA
{
.procname = "numa_stat",
@ -2357,6 +2369,16 @@ static struct ctl_table vm_table[] = {
.extra2 = SYSCTL_ONE,
},
#endif
{
.procname = "dr_prio_drop",
.data = &sysctl_dr_prio_drop,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
.extra1 = SYSCTL_ZERO,
.extra2 = SYSCTL_MAX_PRIO_DROP,
},
{ }
};

View File

@ -234,12 +234,6 @@ static inline bool folio_needs_release(struct folio *folio)
extern unsigned long highest_memmap_pfn;
/*
* Maximum number of reclaim retries without progress before the OOM
* killer is consider the only way forward.
*/
#define MAX_RECLAIM_RETRIES 16
/*
* in mm/vmscan.c:
*/

View File

@ -217,6 +217,8 @@ enum percpu_stats_state {
iter != NULL; \
iter = mem_cgroup_iter(NULL, iter, NULL))
int sysctl_mem_cgroup_reclaim_retries = MAX_RECLAIM_RETRIES;
static inline bool task_is_dying(void)
{
return tsk_is_oom_victim(current) || fatal_signal_pending(current) ||
@ -2434,7 +2436,7 @@ void mem_cgroup_handle_over_high(gfp_t gfp_mask)
unsigned long pflags;
unsigned long nr_reclaimed;
unsigned int nr_pages = current->memcg_nr_pages_over_high;
int nr_retries = MAX_RECLAIM_RETRIES;
int nr_retries = sysctl_mem_cgroup_reclaim_retries;
struct mem_cgroup *memcg;
bool in_retry = false;
@ -2525,110 +2527,103 @@ static int try_charge_memcg(struct mem_cgroup *memcg, gfp_t gfp_mask,
unsigned int nr_pages)
{
unsigned int batch = max(MEMCG_CHARGE_BATCH, nr_pages);
int nr_retries = MAX_RECLAIM_RETRIES;
int nr_retries = sysctl_mem_cgroup_reclaim_retries;
struct mem_cgroup *mem_over_limit;
struct page_counter *counter;
unsigned long nr_reclaimed;
bool passed_oom = false;
unsigned int reclaim_options = MEMCG_RECLAIM_MAY_SWAP;
bool drained = false;
bool raised_max_event = false;
unsigned long pflags;
retry:
if (consume_stock(memcg, nr_pages))
return 0;
for (; nr_retries >= 0; nr_retries--) {
if (!do_memsw_account() ||
page_counter_try_charge(&memcg->memsw, batch, &counter)) {
if (page_counter_try_charge(&memcg->memory, batch, &counter))
goto done_restock;
if (do_memsw_account())
page_counter_uncharge(&memcg->memsw, batch);
mem_over_limit = mem_cgroup_from_counter(counter, memory);
} else {
mem_over_limit = mem_cgroup_from_counter(counter, memsw);
reclaim_options &= ~MEMCG_RECLAIM_MAY_SWAP;
}
if (consume_stock(memcg, nr_pages))
return 0;
if (!do_memsw_account() ||
page_counter_try_charge(&memcg->memsw, batch, &counter)) {
if (page_counter_try_charge(&memcg->memory, batch, &counter))
goto done_restock;
if (do_memsw_account())
page_counter_uncharge(&memcg->memsw, batch);
mem_over_limit = mem_cgroup_from_counter(counter, memory);
} else {
mem_over_limit = mem_cgroup_from_counter(counter, memsw);
reclaim_options &= ~MEMCG_RECLAIM_MAY_SWAP;
}
if (batch > nr_pages) {
batch = nr_pages;
goto retry;
}
if (batch > nr_pages) {
batch = nr_pages;
continue;
}
/*
* Prevent unbounded recursion when reclaim operations need to
* allocate memory. This might exceed the limits temporarily,
* but we prefer facilitating memory reclaim and getting back
* under the limit over triggering OOM kills in these cases.
*/
if (unlikely(current->flags & PF_MEMALLOC))
goto force;
/*
* Prevent unbounded recursion when reclaim operations need to
* allocate memory. This might exceed the limits temporarily,
* but we prefer facilitating memory reclaim and getting back
* under the limit over triggering OOM kills in these cases.
*/
if (unlikely(current->flags & PF_MEMALLOC))
goto force;
if (unlikely(task_in_memcg_oom(current)))
goto nomem;
if (unlikely(task_in_memcg_oom(current)))
goto nomem;
if (!gfpflags_allow_blocking(gfp_mask))
goto nomem;
if (!gfpflags_allow_blocking(gfp_mask))
goto nomem;
memcg_memory_event(mem_over_limit, MEMCG_MAX);
raised_max_event = true;
memcg_memory_event(mem_over_limit, MEMCG_MAX);
raised_max_event = true;
psi_memstall_enter(&pflags);
nr_reclaimed = try_to_free_mem_cgroup_pages(mem_over_limit, nr_pages,
psi_memstall_enter(&pflags);
nr_reclaimed = try_to_free_mem_cgroup_pages(mem_over_limit, nr_pages,
gfp_mask, reclaim_options);
psi_memstall_leave(&pflags);
psi_memstall_leave(&pflags);
if (mem_cgroup_margin(mem_over_limit) >= nr_pages)
goto retry;
if (mem_cgroup_margin(mem_over_limit) >= nr_pages) {
continue;
}
if (!drained) {
drain_all_stock(mem_over_limit);
drained = true;
goto retry;
if (!drained) {
drain_all_stock(mem_over_limit);
drained = true;
continue;
}
if (gfp_mask & __GFP_NORETRY)
goto nomem;
/*
* Even though the limit is exceeded at this point, reclaim
* may have been able to free some pages. Retry the charge
* before killing the task.
*
* Only for regular pages, though: huge pages are rather
* unlikely to succeed so close to the limit, and we fall back
* to regular pages anyway in case of failure.
*/
if (nr_reclaimed && nr_pages <= (1 << PAGE_ALLOC_COSTLY_ORDER)) {
continue;
}
/*
* At task move, charge accounts can be doubly counted. So, it's
* better to wait until the end of task_move if something is going on.
*/
if (mem_cgroup_wait_acct_move(mem_over_limit)) {
continue;
}
if ((gfp_mask & __GFP_RETRY_MAYFAIL) || task_is_dying())
goto nomem;
}
if (gfp_mask & __GFP_NORETRY)
goto nomem;
/*
* Even though the limit is exceeded at this point, reclaim
* may have been able to free some pages. Retry the charge
* before killing the task.
*
* Only for regular pages, though: huge pages are rather
* unlikely to succeed so close to the limit, and we fall back
* to regular pages anyway in case of failure.
*/
if (nr_reclaimed && nr_pages <= (1 << PAGE_ALLOC_COSTLY_ORDER))
goto retry;
/*
* At task move, charge accounts can be doubly counted. So, it's
* better to wait until the end of task_move if something is going on.
*/
if (mem_cgroup_wait_acct_move(mem_over_limit))
goto retry;
if (nr_retries--)
goto retry;
if (gfp_mask & __GFP_RETRY_MAYFAIL)
goto nomem;
/* Avoid endless loop for tasks bypassed by the oom killer */
if (passed_oom && task_is_dying())
goto nomem;
/*
* keep retrying as long as the memcg oom killer is able to make
* a forward progress or bypass the charge if the oom killer
* couldn't make any progress.
*/
if (mem_cgroup_oom(mem_over_limit, gfp_mask,
get_order(nr_pages * PAGE_SIZE))) {
passed_oom = true;
nr_retries = MAX_RECLAIM_RETRIES;
goto retry;
}
mem_cgroup_oom(mem_over_limit, gfp_mask,
get_order(nr_pages * PAGE_SIZE));
nomem:
/*
* Memcg doesn't have a dedicated reserve for atomic
@ -3518,7 +3513,7 @@ static int mem_cgroup_resize_max(struct mem_cgroup *memcg,
*/
static int mem_cgroup_force_empty(struct mem_cgroup *memcg)
{
int nr_retries = MAX_RECLAIM_RETRIES;
int nr_retries = sysctl_mem_cgroup_reclaim_retries;
/* we call try-to-free pages for make this cgroup empty */
lru_add_drain_all();
@ -6535,7 +6530,7 @@ static ssize_t memory_high_write(struct kernfs_open_file *of,
char *buf, size_t nbytes, loff_t off)
{
struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of));
unsigned int nr_retries = MAX_RECLAIM_RETRIES;
unsigned int nr_retries = sysctl_mem_cgroup_reclaim_retries;
bool drained = false;
unsigned long high;
int err;
@ -6584,7 +6579,7 @@ static ssize_t memory_max_write(struct kernfs_open_file *of,
char *buf, size_t nbytes, loff_t off)
{
struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of));
unsigned int nr_reclaims = MAX_RECLAIM_RETRIES;
unsigned int nr_reclaims = sysctl_mem_cgroup_reclaim_retries;
bool drained = false;
unsigned long max;
int err;
@ -6744,7 +6739,7 @@ static ssize_t memory_reclaim(struct kernfs_open_file *of, char *buf,
size_t nbytes, loff_t off)
{
struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of));
unsigned int nr_retries = MAX_RECLAIM_RETRIES;
unsigned int nr_retries = sysctl_mem_cgroup_reclaim_retries;
unsigned long nr_to_reclaim, nr_reclaimed = 0;
unsigned int reclaim_options;
int err;

View File

@ -312,7 +312,13 @@ void __mpol_put(struct mempolicy *pol)
{
if (!atomic_dec_and_test(&pol->refcnt))
return;
kmem_cache_free(policy_cache, pol);
/*
* Required to allow mmap_lock_speculative*() access, see for example
* futex_key_to_node_opt(). All accesses are serialized by mmap_lock,
* however the speculative lock section unbound by the normal lock
* boundaries, requiring RCU freeing.
*/
kfree_rcu(pol, rcu);
}
static void mpol_rebind_default(struct mempolicy *pol, const nodemask_t *nodes)
@ -761,7 +767,7 @@ static int vma_replace_policy(struct vm_area_struct *vma,
}
old = vma->vm_policy;
vma->vm_policy = new; /* protected by mmap_lock */
WRITE_ONCE(vma->vm_policy, new); /* protected by mmap_lock */
mpol_put(old);
return 0;

View File

@ -168,6 +168,8 @@ struct scan_control {
/* for recording the reclaimed slab by now */
struct reclaim_state reclaim_state;
bool give_up_direct_reclaim;
};
#ifdef ARCH_HAS_PREFETCHW
@ -5619,6 +5621,8 @@ static void lru_gen_shrink_node(struct pglist_data *pgdat, struct scan_control *
#endif /* CONFIG_LRU_GEN */
int sysctl_dr_prio_drop = 0;
static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc)
{
unsigned long nr[NR_LRU_LISTS];
@ -5630,6 +5634,16 @@ static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc)
bool proportional_reclaim;
struct blk_plug plug;
/*
* Prevent lruvec overscanning by direct reclaimers
* to reduce contention over the lruvec spinlock.
*/
if (unlikely(sysctl_dr_prio_drop && !current_is_kswapd() &&
sc->priority <= (DEF_PRIORITY - sysctl_dr_prio_drop))) {
sc->give_up_direct_reclaim = true;
return;
}
if (lru_gen_enabled() && !root_reclaim(sc)) {
lru_gen_shrink_lruvec(lruvec, sc);
return;
@ -6199,6 +6213,9 @@ retry:
if (sc->compaction_ready)
break;
if (sc->give_up_direct_reclaim)
break;
/*
* If we're getting trouble reclaiming, start doing
* writepage even in laptop mode.

View File

@ -603,10 +603,10 @@ restart:
goto out;
}
}
}
if (cb->args[1]) {
cb->args[1] = 0;
goto restart;
if (cb->args[1]) {
cb->args[1] = 0;
goto restart;
}
}
out:
rcu_read_unlock();

View File

@ -1,3 +1,25 @@
* Wed Aug 05 2026 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [5.14.0-687.36.1.el9_8]
- powerpc/powernv/iommu: iommu incorrectly bypass DMA APIs (Mamatha Inamdar) [RHEL-215575]
- powerpc/iommu: bypass DMA APIs for coherent allocations for pre-mapped memory (Mamatha Inamdar) [RHEL-215575]
- mm/vmscan: add sysctl to limit direct reclaim scanning depth (Audra Mitchell) [RHEL-211058]
- mm/memcg: refactor try_charge_memcg retry logic to use for loop (Audra Mitchell) [RHEL-211058]
- mm/memcg: introduce tunable sysctl for memory cgroup reclaim retries (Audra Mitchell) [RHEL-211058]
- futex: Prevent lockup in requeue-PI during signal/ timeout wakeup (Waiman Long) [RHEL-193526] {CVE-2026-52977}
- futex: Require sys_futex_requeue() to have identical flags (Waiman Long) [RHEL-193526] {CVE-2026-31554}
- futex: Clear stale exiting pointer in futex_lock_pi() retry path (Waiman Long) [RHEL-193526] {CVE-2026-31555}
- futex: Fix UaF between futex_key_to_node_opt() and vma_replace_policy() (Waiman Long) [RHEL-193526] {CVE-2026-23415}
Resolves: RHEL-193526, RHEL-211058, RHEL-215575
* Tue Aug 04 2026 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [5.14.0-687.35.1.el9_8]
- octeon_ep_vf: add NULL check for napi_build_skb() (CKI Backport Bot) [RHEL-186331]
- octeon_ep_vf: introduce octep_vf_oq_next_idx() helper (CKI Backport Bot) [RHEL-186331]
- octeon_ep_vf: avoid compiler and IQ/OQ reordering (CKI Backport Bot) [RHEL-186331]
- octeon_ep_vf: Relocate counter updates before NAPI (CKI Backport Bot) [RHEL-186331]
- octeon_ep_vf: ensure dbell BADDR updation (CKI Backport Bot) [RHEL-186331]
- net: octeon_ep_vf: fix free_irq dev_id mismatch in IRQ rollback (CKI Backport Bot) [RHEL-186331]
- netfilter: nfnetlink_cthelper: fix OOB read in nfnl_cthelper_dump_table() (CKI Backport Bot) [RHEL-179745] {CVE-2026-43450}
Resolves: RHEL-179745, RHEL-186331
* Mon Aug 03 2026 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [5.14.0-687.34.1.el9_8]
- s390/mm: Ensure physical addr derived from page is passed in to uv_convert_from_secure() (Lucas Oakley) [RHEL-192430]
- s390/mm: Fix phys_to_folio() usage in do_secure_storage_access() (Charles Haithcock) [RHEL-216471]