Import of kernel-5.14.0-687.41.1.el9_8

This commit is contained in:
almalinux-bot-kernel 2026-08-27 06:09:55 +00:00
parent 8b119a97cd
commit 3cbb97e6f5
50 changed files with 1020 additions and 384 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.39.1
RHEL_RELEASE = 687.41.1
#
# ZSTREAM

View File

@ -19,6 +19,15 @@ EXPORT_SYMBOL_GPL(fips_enabled);
ATOMIC_NOTIFIER_HEAD(fips_fail_notif_chain);
EXPORT_SYMBOL_GPL(fips_fail_notif_chain);
static unsigned long rh_fips_exception;
int fips_allows(unsigned long feature)
{
return !fips_enabled ||
(rh_fips_exception & feature);
}
EXPORT_SYMBOL_GPL(fips_allows);
/* Process kernel command-line parameter at boot time. fips=0 or fips=1 */
static int fips_enable(char *str)
{
@ -30,6 +39,17 @@ static int fips_enable(char *str)
__setup("fips=", fips_enable);
static int fips_exception(char *str)
{
if (kstrtoul(str, 0, &rh_fips_exception))
return 0;
printk(KERN_INFO "fips exceptions: 0x%lx\n", rh_fips_exception);
return 1;
}
__setup("rh_fips_exception=", fips_exception);
static char fips_name[] = FIPS_MODULE_NAME;
static char fips_version[] = FIPS_MODULE_VERSION;
@ -41,6 +61,13 @@ static struct ctl_table crypto_sysctl_table[] = {
.mode = 0444,
.proc_handler = proc_dointvec
},
{
.procname = "rh_fips_exception",
.data = &rh_fips_exception,
.maxlen = sizeof(unsigned long),
.mode = 0444,
.proc_handler = proc_doulongvec_minmax
},
{
.procname = "fips_name",
.data = &fips_name,

View File

@ -262,12 +262,19 @@ void amdgpu_gart_table_ram_free(struct amdgpu_device *adev)
*/
int amdgpu_gart_table_vram_alloc(struct amdgpu_device *adev)
{
int r;
if (adev->gart.bo != NULL)
return 0;
return amdgpu_bo_create_kernel(adev, adev->gart.table_size, PAGE_SIZE,
AMDGPU_GEM_DOMAIN_VRAM, &adev->gart.bo,
NULL, (void *)&adev->gart.ptr);
r = amdgpu_bo_create_kernel(adev, adev->gart.table_size, PAGE_SIZE,
AMDGPU_GEM_DOMAIN_VRAM, &adev->gart.bo,
NULL, (void *)&adev->gart.ptr);
if (r)
return r;
memset_io(adev->gart.ptr, adev->gart.gart_pte_flags, adev->gart.table_size);
return 0;
}
/**

View File

@ -112,47 +112,6 @@ amdgpu_gem_update_timeline_node(struct drm_file *filp,
return 0;
}
static void
amdgpu_gem_update_bo_mapping(struct drm_file *filp,
struct amdgpu_bo_va *bo_va,
uint32_t operation,
uint64_t point,
struct dma_fence *fence,
struct drm_syncobj *syncobj,
struct dma_fence_chain *chain)
{
struct amdgpu_bo *bo = bo_va ? bo_va->base.bo : NULL;
struct amdgpu_fpriv *fpriv = filp->driver_priv;
struct amdgpu_vm *vm = &fpriv->vm;
struct dma_fence *last_update;
if (!syncobj)
return;
/* Find the last update fence */
switch (operation) {
case AMDGPU_VA_OP_MAP:
case AMDGPU_VA_OP_REPLACE:
if (bo && (bo->tbo.base.resv == vm->root.bo->tbo.base.resv))
last_update = vm->last_update;
else
last_update = bo_va->last_pt_update;
break;
case AMDGPU_VA_OP_UNMAP:
case AMDGPU_VA_OP_CLEAR:
last_update = fence;
break;
default:
return;
}
/* Add fence to timeline */
if (!point)
drm_syncobj_replace_fence(syncobj, last_update);
else
drm_syncobj_add_point(syncobj, chain, last_update, point);
}
static vm_fault_t amdgpu_gem_fault(struct vm_fault *vmf)
{
struct ttm_buffer_object *bo = vmf->vma->vm_private_data;
@ -761,16 +720,27 @@ amdgpu_gem_va_update_vm(struct amdgpu_device *adev,
struct amdgpu_bo_va *bo_va,
uint32_t operation)
{
struct dma_fence *fence = dma_fence_get_stub();
int r;
struct dma_fence *fence;
int r = 0;
/* Always start from the VM's existing last update fence. */
fence = dma_fence_get(vm->last_update);
if (!amdgpu_vm_ready(vm))
return fence;
/*
* First clean up any freed mappings in the VM.
*
* amdgpu_vm_clear_freed() may replace @fence with a new fence if it
* schedules GPU work. If nothing needs clearing, @fence can remain as
* the original vm->last_update.
*/
r = amdgpu_vm_clear_freed(adev, vm, &fence);
if (r)
goto error;
/* For MAP/REPLACE we also need to update the BO mappings. */
if (operation == AMDGPU_VA_OP_MAP ||
operation == AMDGPU_VA_OP_REPLACE) {
r = amdgpu_vm_bo_update(adev, bo_va, false);
@ -778,7 +748,46 @@ amdgpu_gem_va_update_vm(struct amdgpu_device *adev,
goto error;
}
/* Always update PDEs after we touched the mappings. */
r = amdgpu_vm_update_pdes(adev, vm, false);
if (r)
goto error;
/*
* Decide which fence best represents the last update:
*
* MAP/REPLACE:
* - For always-valid mappings, use vm->last_update.
* - Otherwise, export bo_va->last_pt_update.
*
* UNMAP/CLEAR:
* Keep the fence returned by amdgpu_vm_clear_freed(). If no work was
* needed, it can remain as vm->last_pt_update.
*
* The VM and BO update fences are always initialized to a valid value.
* vm->last_update and bo_va->last_pt_update always start as valid fences.
* and are never expected to be NULL.
*/
switch (operation) {
case AMDGPU_VA_OP_MAP:
case AMDGPU_VA_OP_REPLACE:
/*
* For MAP/REPLACE, return the page table update fence for the
* mapping we just modified. bo_va is expected to be valid here.
*/
dma_fence_put(fence);
if (amdgpu_vm_is_bo_always_valid(vm, bo_va->base.bo))
fence = dma_fence_get(vm->last_update);
else
fence = dma_fence_get(bo_va->last_pt_update);
break;
case AMDGPU_VA_OP_UNMAP:
case AMDGPU_VA_OP_CLEAR:
default:
/* keep @fence as returned by amdgpu_vm_clear_freed() */
break;
}
error:
if (r && r != -ERESTARTSYS)
@ -810,6 +819,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
uint64_t vm_size;
int r = 0;
/* Validate virtual address range against reserved regions. */
if (args->va_address < AMDGPU_VA_RESERVED_BOTTOM) {
dev_dbg(dev->dev,
"va_address 0x%llx is in reserved area 0x%llx\n",
@ -843,6 +853,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
return -EINVAL;
}
/* Validate operation type. */
switch (args->operation) {
case AMDGPU_VA_OP_MAP:
case AMDGPU_VA_OP_UNMAP:
@ -866,6 +877,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
abo = NULL;
}
/* Add input syncobj fences (if any) for synchronization. */
r = amdgpu_gem_add_input_fence(filp,
args->input_fence_syncobj_handles,
args->num_syncobj_handles);
@ -888,6 +900,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
goto error;
}
/* Resolve the BO-VA mapping for this VM/BO combination. */
if (abo) {
bo_va = amdgpu_vm_bo_find(&fpriv->vm, abo);
if (!bo_va) {
@ -900,6 +913,11 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
bo_va = NULL;
}
/*
* Prepare the timeline syncobj node if the user requested a VM
* timeline update. This only allocates/looks up the syncobj and
* chain node; the actual fence is attached later.
*/
r = amdgpu_gem_update_timeline_node(filp,
args->vm_timeline_syncobj_out,
args->vm_timeline_point,
@ -931,18 +949,30 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
default:
break;
}
/*
* Once the VA operation is done, update the VM and obtain the fence
* that represents the last relevant update for this mapping. This
* fence can then be exported to the user-visible VM timeline.
*/
if (!r && !(args->flags & AMDGPU_VM_DELAY_UPDATE) && !adev->debug_vm) {
fence = amdgpu_gem_va_update_vm(adev, &fpriv->vm, bo_va,
args->operation);
if (timeline_syncobj)
amdgpu_gem_update_bo_mapping(filp, bo_va,
args->operation,
args->vm_timeline_point,
fence, timeline_syncobj,
timeline_chain);
else
dma_fence_put(fence);
if (timeline_syncobj && fence) {
if (!args->vm_timeline_point) {
/* Replace the existing fence when no point is given. */
drm_syncobj_replace_fence(timeline_syncobj,
fence);
} else {
/* Attach the last-update fence at a specific point. */
drm_syncobj_add_point(timeline_syncobj,
timeline_chain,
fence,
args->vm_timeline_point);
}
}
dma_fence_put(fence);
}

View File

@ -51,8 +51,6 @@
#include "amdgpu_amdkfd.h"
#include "amdgpu_hmm.h"
#define MAX_WALK_BYTE (2UL << 30)
/**
* amdgpu_hmm_invalidate_gfx - callback to notify about mm change
*
@ -170,11 +168,13 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier,
void *owner,
struct hmm_range **phmm_range)
{
const u64 max_bytes = SZ_2G;
struct hmm_range *hmm_range;
unsigned long end;
unsigned long timeout;
unsigned long *pfns;
int r = 0;
unsigned long end;
int r;
hmm_range = kzalloc(sizeof(*hmm_range), GFP_KERNEL);
if (unlikely(!hmm_range))
@ -195,8 +195,9 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier,
end = start + npages * PAGE_SIZE;
hmm_range->dev_private_owner = owner;
hmm_range->notifier_seq = mmu_interval_read_begin(notifier);
do {
hmm_range->end = min(hmm_range->start + MAX_WALK_BYTE, end);
hmm_range->end = min(hmm_range->start + max_bytes, end);
pr_debug("hmm range: start = 0x%lx, end = 0x%lx",
hmm_range->start, hmm_range->end);
@ -204,7 +205,6 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier,
timeout = jiffies + msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT);
retry:
hmm_range->notifier_seq = mmu_interval_read_begin(notifier);
r = hmm_range_fault(hmm_range);
if (unlikely(r)) {
if (r == -EBUSY && !time_after(jiffies, timeout))
@ -214,7 +214,7 @@ retry:
if (hmm_range->end == end)
break;
hmm_range->hmm_pfns += MAX_WALK_BYTE >> PAGE_SHIFT;
hmm_range->hmm_pfns += max_bytes >> PAGE_SHIFT;
hmm_range->start = hmm_range->end;
} while (hmm_range->end < end);

View File

@ -401,27 +401,25 @@ static int kfd_dbg_get_dev_watch_id(struct kfd_process_device *pdd, int *watch_i
return -ENOMEM;
}
static void kfd_dbg_clear_dev_watch_id(struct kfd_process_device *pdd, int watch_id)
static void kfd_dbg_clear_dev_watch_id(struct kfd_process_device *pdd, u32 watch_id)
{
spin_lock(&pdd->dev->watch_points_lock);
/* process owns device watch point so safe to clear */
if ((pdd->alloc_watch_ids >> watch_id) & 0x1) {
pdd->alloc_watch_ids &= ~(0x1 << watch_id);
pdd->dev->alloc_watch_ids &= ~(0x1 << watch_id);
if (pdd->alloc_watch_ids & BIT(watch_id)) {
pdd->alloc_watch_ids &= ~BIT(watch_id);
pdd->dev->alloc_watch_ids &= ~BIT(watch_id);
}
spin_unlock(&pdd->dev->watch_points_lock);
}
static bool kfd_dbg_owns_dev_watch_id(struct kfd_process_device *pdd, int watch_id)
static bool kfd_dbg_owns_dev_watch_id(struct kfd_process_device *pdd, u32 watch_id)
{
bool owns_watch_id = false;
spin_lock(&pdd->dev->watch_points_lock);
owns_watch_id = watch_id < MAX_WATCH_ADDRESSES &&
((pdd->alloc_watch_ids >> watch_id) & 0x1);
owns_watch_id = pdd->alloc_watch_ids & BIT(watch_id);
spin_unlock(&pdd->dev->watch_points_lock);
return owns_watch_id;
@ -432,6 +430,9 @@ int kfd_dbg_trap_clear_dev_address_watch(struct kfd_process_device *pdd,
{
int r;
if (watch_id >= MAX_WATCH_ADDRESSES)
return -EINVAL;
if (!kfd_dbg_owns_dev_watch_id(pdd, watch_id))
return -EINVAL;
@ -469,6 +470,9 @@ int kfd_dbg_trap_set_dev_address_watch(struct kfd_process_device *pdd,
if (r)
return r;
if (*watch_id >= MAX_WATCH_ADDRESSES)
return -EINVAL;
if (!pdd->dev->kfd->shared_resources.enable_mes) {
r = debug_lock_and_unmap(pdd->dev->dqm);
if (r) {

View File

@ -331,6 +331,12 @@ static int kfd_event_page_set(struct kfd_process *p, void *kernel_address,
if (p->signal_page)
return -EBUSY;
if (size < KFD_SIGNAL_EVENT_LIMIT * 8) {
pr_err("Event page size %llu is too small, need at least %lu bytes\n",
size, (unsigned long)(KFD_SIGNAL_EVENT_LIMIT * 8));
return -EINVAL;
}
page = kzalloc(sizeof(*page), GFP_KERNEL);
if (!page)
return -ENOMEM;

View File

@ -334,8 +334,7 @@ static void checkpoint_mqd(struct mqd_manager *mm, void *mqd, void *mqd_dst, voi
static void restore_mqd(struct mqd_manager *mm, void **mqd,
struct kfd_mem_obj *mqd_mem_obj, uint64_t *gart_addr,
struct queue_properties *qp,
const void *mqd_src,
struct queue_properties *qp, const void *mqd_src,
const void *ctl_stack_src, const u32 ctl_stack_size)
{
uint64_t addr;
@ -351,14 +350,48 @@ static void restore_mqd(struct mqd_manager *mm, void **mqd,
*gart_addr = addr;
m->cp_hqd_pq_doorbell_control =
qp->doorbell_off <<
CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET__SHIFT;
pr_debug("cp_hqd_pq_doorbell_control 0x%x\n",
m->cp_hqd_pq_doorbell_control);
qp->doorbell_off << CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET__SHIFT;
pr_debug("cp_hqd_pq_doorbell_control 0x%x\n", m->cp_hqd_pq_doorbell_control);
qp->is_active = 0;
}
static void checkpoint_mqd_sdma(struct mqd_manager *mm,
void *mqd,
void *mqd_dst,
void *ctl_stack_dst)
{
struct v11_sdma_mqd *m;
m = get_sdma_mqd(mqd);
memcpy(mqd_dst, m, sizeof(struct v11_sdma_mqd));
}
static void restore_mqd_sdma(struct mqd_manager *mm, void **mqd,
struct kfd_mem_obj *mqd_mem_obj, uint64_t *gart_addr,
struct queue_properties *qp,
const void *mqd_src,
const void *ctl_stack_src,
const u32 ctl_stack_size)
{
uint64_t addr;
struct v11_sdma_mqd *m;
m = (struct v11_sdma_mqd *) mqd_mem_obj->cpu_ptr;
addr = mqd_mem_obj->gpu_addr;
memcpy(m, mqd_src, sizeof(*m));
m->sdmax_rlcx_doorbell_offset =
qp->doorbell_off << SDMA0_QUEUE0_DOORBELL_OFFSET__OFFSET__SHIFT;
*mqd = m;
if (gart_addr)
*gart_addr = addr;
qp->is_active = 0;
}
static void init_mqd_hiq(struct mqd_manager *mm, void **mqd,
struct kfd_mem_obj *mqd_mem_obj, uint64_t *gart_addr,
@ -543,8 +576,8 @@ struct mqd_manager *mqd_manager_init_v11(enum KFD_MQD_TYPE type,
mqd->update_mqd = update_mqd_sdma;
mqd->destroy_mqd = kfd_destroy_mqd_sdma;
mqd->is_occupied = kfd_is_occupied_sdma;
mqd->checkpoint_mqd = checkpoint_mqd;
mqd->restore_mqd = restore_mqd;
mqd->checkpoint_mqd = checkpoint_mqd_sdma;
mqd->restore_mqd = restore_mqd_sdma;
mqd->mqd_size = sizeof(struct v11_sdma_mqd);
mqd->mqd_stride = kfd_mqd_stride;
#if defined(CONFIG_DEBUG_FS)

View File

@ -288,8 +288,8 @@ bool dal_vector_reserve(struct vector *vector, uint32_t capacity)
if (capacity <= vector->capacity)
return true;
new_container = krealloc(vector->container,
capacity * vector->struct_size, GFP_KERNEL);
new_container = krealloc_array(vector->container,
capacity, vector->struct_size, GFP_KERNEL);
if (new_container) {
vector->container = new_container;

View File

@ -2584,14 +2584,16 @@ static enum bp_result get_integrated_info_v11(
info_v11->extdispconninfo.checksum;
info->dp0_ext_hdmi_slv_addr = info_v11->dp0_retimer_set.HdmiSlvAddr;
info->dp0_ext_hdmi_reg_num = info_v11->dp0_retimer_set.HdmiRegNum;
info->dp0_ext_hdmi_reg_num = min_t(u8, info_v11->dp0_retimer_set.HdmiRegNum,
ARRAY_SIZE(info->dp0_ext_hdmi_reg_settings));
for (i = 0; i < info->dp0_ext_hdmi_reg_num; i++) {
info->dp0_ext_hdmi_reg_settings[i].i2c_reg_index =
info_v11->dp0_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
info->dp0_ext_hdmi_reg_settings[i].i2c_reg_val =
info_v11->dp0_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
}
info->dp0_ext_hdmi_6g_reg_num = info_v11->dp0_retimer_set.Hdmi6GRegNum;
info->dp0_ext_hdmi_6g_reg_num = min_t(u8, info_v11->dp0_retimer_set.Hdmi6GRegNum,
ARRAY_SIZE(info->dp0_ext_hdmi_6g_reg_settings));
for (i = 0; i < info->dp0_ext_hdmi_6g_reg_num; i++) {
info->dp0_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
info_v11->dp0_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@ -2600,14 +2602,16 @@ static enum bp_result get_integrated_info_v11(
}
info->dp1_ext_hdmi_slv_addr = info_v11->dp1_retimer_set.HdmiSlvAddr;
info->dp1_ext_hdmi_reg_num = info_v11->dp1_retimer_set.HdmiRegNum;
info->dp1_ext_hdmi_reg_num = min_t(u8, info_v11->dp1_retimer_set.HdmiRegNum,
ARRAY_SIZE(info->dp1_ext_hdmi_reg_settings));
for (i = 0; i < info->dp1_ext_hdmi_reg_num; i++) {
info->dp1_ext_hdmi_reg_settings[i].i2c_reg_index =
info_v11->dp1_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
info->dp1_ext_hdmi_reg_settings[i].i2c_reg_val =
info_v11->dp1_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
}
info->dp1_ext_hdmi_6g_reg_num = info_v11->dp1_retimer_set.Hdmi6GRegNum;
info->dp1_ext_hdmi_6g_reg_num = min_t(u8, info_v11->dp1_retimer_set.Hdmi6GRegNum,
ARRAY_SIZE(info->dp1_ext_hdmi_6g_reg_settings));
for (i = 0; i < info->dp1_ext_hdmi_6g_reg_num; i++) {
info->dp1_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
info_v11->dp1_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@ -2616,14 +2620,16 @@ static enum bp_result get_integrated_info_v11(
}
info->dp2_ext_hdmi_slv_addr = info_v11->dp2_retimer_set.HdmiSlvAddr;
info->dp2_ext_hdmi_reg_num = info_v11->dp2_retimer_set.HdmiRegNum;
info->dp2_ext_hdmi_reg_num = min_t(u8, info_v11->dp2_retimer_set.HdmiRegNum,
ARRAY_SIZE(info->dp2_ext_hdmi_reg_settings));
for (i = 0; i < info->dp2_ext_hdmi_reg_num; i++) {
info->dp2_ext_hdmi_reg_settings[i].i2c_reg_index =
info_v11->dp2_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
info->dp2_ext_hdmi_reg_settings[i].i2c_reg_val =
info_v11->dp2_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
}
info->dp2_ext_hdmi_6g_reg_num = info_v11->dp2_retimer_set.Hdmi6GRegNum;
info->dp2_ext_hdmi_6g_reg_num = min_t(u8, info_v11->dp2_retimer_set.Hdmi6GRegNum,
ARRAY_SIZE(info->dp2_ext_hdmi_6g_reg_settings));
for (i = 0; i < info->dp2_ext_hdmi_6g_reg_num; i++) {
info->dp2_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
info_v11->dp2_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@ -2632,14 +2638,16 @@ static enum bp_result get_integrated_info_v11(
}
info->dp3_ext_hdmi_slv_addr = info_v11->dp3_retimer_set.HdmiSlvAddr;
info->dp3_ext_hdmi_reg_num = info_v11->dp3_retimer_set.HdmiRegNum;
info->dp3_ext_hdmi_reg_num = min_t(u8, info_v11->dp3_retimer_set.HdmiRegNum,
ARRAY_SIZE(info->dp3_ext_hdmi_reg_settings));
for (i = 0; i < info->dp3_ext_hdmi_reg_num; i++) {
info->dp3_ext_hdmi_reg_settings[i].i2c_reg_index =
info_v11->dp3_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
info->dp3_ext_hdmi_reg_settings[i].i2c_reg_val =
info_v11->dp3_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
}
info->dp3_ext_hdmi_6g_reg_num = info_v11->dp3_retimer_set.Hdmi6GRegNum;
info->dp3_ext_hdmi_6g_reg_num = min_t(u8, info_v11->dp3_retimer_set.Hdmi6GRegNum,
ARRAY_SIZE(info->dp3_ext_hdmi_6g_reg_settings));
for (i = 0; i < info->dp3_ext_hdmi_6g_reg_num; i++) {
info->dp3_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
info_v11->dp3_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@ -2789,14 +2797,16 @@ static enum bp_result get_integrated_info_v2_1(
info->ext_disp_conn_info.checksum =
info_v2_1->extdispconninfo.checksum;
info->dp0_ext_hdmi_slv_addr = info_v2_1->dp0_retimer_set.HdmiSlvAddr;
info->dp0_ext_hdmi_reg_num = info_v2_1->dp0_retimer_set.HdmiRegNum;
info->dp0_ext_hdmi_reg_num = min_t(u8, info_v2_1->dp0_retimer_set.HdmiRegNum,
ARRAY_SIZE(info->dp0_ext_hdmi_reg_settings));
for (i = 0; i < info->dp0_ext_hdmi_reg_num; i++) {
info->dp0_ext_hdmi_reg_settings[i].i2c_reg_index =
info_v2_1->dp0_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
info->dp0_ext_hdmi_reg_settings[i].i2c_reg_val =
info_v2_1->dp0_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
}
info->dp0_ext_hdmi_6g_reg_num = info_v2_1->dp0_retimer_set.Hdmi6GRegNum;
info->dp0_ext_hdmi_6g_reg_num = min_t(u8, info_v2_1->dp0_retimer_set.Hdmi6GRegNum,
ARRAY_SIZE(info->dp0_ext_hdmi_6g_reg_settings));
for (i = 0; i < info->dp0_ext_hdmi_6g_reg_num; i++) {
info->dp0_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
info_v2_1->dp0_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@ -2804,14 +2814,16 @@ static enum bp_result get_integrated_info_v2_1(
info_v2_1->dp0_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegVal;
}
info->dp1_ext_hdmi_slv_addr = info_v2_1->dp1_retimer_set.HdmiSlvAddr;
info->dp1_ext_hdmi_reg_num = info_v2_1->dp1_retimer_set.HdmiRegNum;
info->dp1_ext_hdmi_reg_num = min_t(u8, info_v2_1->dp1_retimer_set.HdmiRegNum,
ARRAY_SIZE(info->dp1_ext_hdmi_reg_settings));
for (i = 0; i < info->dp1_ext_hdmi_reg_num; i++) {
info->dp1_ext_hdmi_reg_settings[i].i2c_reg_index =
info_v2_1->dp1_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
info->dp1_ext_hdmi_reg_settings[i].i2c_reg_val =
info_v2_1->dp1_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
}
info->dp1_ext_hdmi_6g_reg_num = info_v2_1->dp1_retimer_set.Hdmi6GRegNum;
info->dp1_ext_hdmi_6g_reg_num = min_t(u8, info_v2_1->dp1_retimer_set.Hdmi6GRegNum,
ARRAY_SIZE(info->dp1_ext_hdmi_6g_reg_settings));
for (i = 0; i < info->dp1_ext_hdmi_6g_reg_num; i++) {
info->dp1_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
info_v2_1->dp1_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@ -2819,14 +2831,16 @@ static enum bp_result get_integrated_info_v2_1(
info_v2_1->dp1_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegVal;
}
info->dp2_ext_hdmi_slv_addr = info_v2_1->dp2_retimer_set.HdmiSlvAddr;
info->dp2_ext_hdmi_reg_num = info_v2_1->dp2_retimer_set.HdmiRegNum;
info->dp2_ext_hdmi_reg_num = min_t(u8, info_v2_1->dp2_retimer_set.HdmiRegNum,
ARRAY_SIZE(info->dp2_ext_hdmi_reg_settings));
for (i = 0; i < info->dp2_ext_hdmi_reg_num; i++) {
info->dp2_ext_hdmi_reg_settings[i].i2c_reg_index =
info_v2_1->dp2_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
info->dp2_ext_hdmi_reg_settings[i].i2c_reg_val =
info_v2_1->dp2_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
}
info->dp2_ext_hdmi_6g_reg_num = info_v2_1->dp2_retimer_set.Hdmi6GRegNum;
info->dp2_ext_hdmi_6g_reg_num = min_t(u8, info_v2_1->dp2_retimer_set.Hdmi6GRegNum,
ARRAY_SIZE(info->dp2_ext_hdmi_6g_reg_settings));
for (i = 0; i < info->dp2_ext_hdmi_6g_reg_num; i++) {
info->dp2_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
info_v2_1->dp2_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;
@ -2834,14 +2848,16 @@ static enum bp_result get_integrated_info_v2_1(
info_v2_1->dp2_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegVal;
}
info->dp3_ext_hdmi_slv_addr = info_v2_1->dp3_retimer_set.HdmiSlvAddr;
info->dp3_ext_hdmi_reg_num = info_v2_1->dp3_retimer_set.HdmiRegNum;
info->dp3_ext_hdmi_reg_num = min_t(u8, info_v2_1->dp3_retimer_set.HdmiRegNum,
ARRAY_SIZE(info->dp3_ext_hdmi_reg_settings));
for (i = 0; i < info->dp3_ext_hdmi_reg_num; i++) {
info->dp3_ext_hdmi_reg_settings[i].i2c_reg_index =
info_v2_1->dp3_retimer_set.HdmiRegSetting[i].ucI2cRegIndex;
info->dp3_ext_hdmi_reg_settings[i].i2c_reg_val =
info_v2_1->dp3_retimer_set.HdmiRegSetting[i].ucI2cRegVal;
}
info->dp3_ext_hdmi_6g_reg_num = info_v2_1->dp3_retimer_set.Hdmi6GRegNum;
info->dp3_ext_hdmi_6g_reg_num = min_t(u8, info_v2_1->dp3_retimer_set.Hdmi6GRegNum,
ARRAY_SIZE(info->dp3_ext_hdmi_6g_reg_settings));
for (i = 0; i < info->dp3_ext_hdmi_6g_reg_num; i++) {
info->dp3_ext_hdmi_6g_reg_settings[i].i2c_reg_index =
info_v2_1->dp3_retimer_set.Hdmi6GhzRegSetting[i].ucI2cRegIndex;

View File

@ -5884,7 +5884,11 @@ bool dc_process_dmub_aux_transfer_async(struct dc *dc,
uint8_t action;
union dmub_rb_cmd cmd = {0};
ASSERT(payload->length <= 16);
if (link_index >= dc->link_count || !dc->links[link_index])
return false;
if (payload->length > sizeof(cmd.dp_aux_access.aux_control.dpaux.data))
return false;
cmd.dp_aux_access.header.type = DMUB_CMD__DP_AUX_ACCESS;
cmd.dp_aux_access.header.payload_bytes = 0;

View File

@ -17,6 +17,17 @@
#include "i915_gem_tiling.h"
#include "i915_scatterlist.h"
/* Abuse scatterlist to store pointer instead of struct page. */
static inline void __set_phys_vaddr(struct scatterlist *sg, void *vaddr)
{
sg_assign_page(sg, (struct page *)vaddr);
}
static inline void *__get_phys_vaddr(struct scatterlist *sg)
{
return (void *)sg_page(sg);
}
static int i915_gem_object_get_pages_phys(struct drm_i915_gem_object *obj)
{
struct address_space *mapping = obj->base.filp->f_mapping;
@ -57,7 +68,7 @@ static int i915_gem_object_get_pages_phys(struct drm_i915_gem_object *obj)
sg->offset = 0;
sg->length = obj->base.size;
sg_assign_page(sg, (struct page *)vaddr);
__set_phys_vaddr(sg, vaddr);
sg_dma_address(sg) = dma;
sg_dma_len(sg) = obj->base.size;
@ -98,7 +109,7 @@ i915_gem_object_put_pages_phys(struct drm_i915_gem_object *obj,
struct sg_table *pages)
{
dma_addr_t dma = sg_dma_address(pages->sgl);
void *vaddr = sg_page(pages->sgl);
void *vaddr = __get_phys_vaddr(pages->sgl);
__i915_gem_object_release_shmem(obj, pages, false);
@ -138,7 +149,7 @@ i915_gem_object_put_pages_phys(struct drm_i915_gem_object *obj,
int i915_gem_object_pwrite_phys(struct drm_i915_gem_object *obj,
const struct drm_i915_gem_pwrite *args)
{
void *vaddr = sg_page(obj->mm.pages->sgl) + args->offset;
void *vaddr = __get_phys_vaddr(obj->mm.pages->sgl) + args->offset;
char __user *user_data = u64_to_user_ptr(args->data_ptr);
struct drm_i915_private *i915 = to_i915(obj->base.dev);
int err;
@ -169,7 +180,7 @@ int i915_gem_object_pwrite_phys(struct drm_i915_gem_object *obj,
int i915_gem_object_pread_phys(struct drm_i915_gem_object *obj,
const struct drm_i915_gem_pread *args)
{
void *vaddr = sg_page(obj->mm.pages->sgl) + args->offset;
void *vaddr = __get_phys_vaddr(obj->mm.pages->sgl) + args->offset;
char __user *user_data = u64_to_user_ptr(args->data_ptr);
int err;

View File

@ -416,8 +416,6 @@ void i915_ttm_free_cached_io_rsgt(struct drm_i915_gem_object *obj)
int i915_ttm_purge(struct drm_i915_gem_object *obj)
{
struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
struct i915_ttm_tt *i915_tt =
container_of(bo->ttm, typeof(*i915_tt), ttm);
struct ttm_operation_ctx ctx = {
.interruptible = true,
.no_wait_gpu = false,
@ -432,16 +430,22 @@ int i915_ttm_purge(struct drm_i915_gem_object *obj)
if (ret)
return ret;
if (bo->ttm && i915_tt->filp) {
/*
* The below fput(which eventually calls shmem_truncate) might
* be delayed by worker, so when directly called to purge the
* pages(like by the shrinker) we should try to be more
* aggressive and release the pages immediately.
*/
shmem_truncate_range(file_inode(i915_tt->filp),
0, (loff_t)-1);
fput(fetch_and_zero(&i915_tt->filp));
if (bo->ttm) {
struct i915_ttm_tt *i915_tt =
container_of(bo->ttm, typeof(*i915_tt), ttm);
if (i915_tt->filp) {
/*
* The below fput(which eventually calls shmem_truncate)
* might be delayed by worker, so when directly called
* to purge the pages(like by the shrinker) we should
* try to be more aggressive and release the pages
* immediately.
*/
shmem_truncate_range(file_inode(i915_tt->filp),
0, (loff_t)-1);
fput(fetch_and_zero(&i915_tt->filp));
}
}
obj->write_domain = 0;

View File

@ -52,13 +52,13 @@
#define GVE_DEFAULT_RX_BUFFER_OFFSET 2048
#define GVE_DEFAULT_MIN_TX_RING_SIZE 256
#define GVE_DEFAULT_MIN_RX_RING_SIZE 512
#define GVE_XDP_ACTIONS 5
#define GVE_GQ_TX_MIN_PKT_DESC_BYTES 182
#define DQO_QPL_DEFAULT_TX_PAGES 512
#define DQO_QPL_DEFAULT_RX_PAGES 2048
/* Maximum TSO size supported on DQO */
#define GVE_DQO_TX_MAX 0x3FFFF
@ -650,8 +650,14 @@ struct gve_priv {
u16 num_event_counters;
u16 tx_desc_cnt; /* num desc per ring */
u16 rx_desc_cnt; /* num desc per ring */
u16 tx_pages_per_qpl; /* Suggested number of pages per qpl for TX queues by NIC */
u16 rx_pages_per_qpl; /* Suggested number of pages per qpl for RX queues by NIC */
u16 max_tx_desc_cnt;
u16 max_rx_desc_cnt;
u16 min_tx_desc_cnt;
u16 min_rx_desc_cnt;
bool modify_ring_size_enabled;
bool default_min_ring_size;
u16 tx_pages_per_qpl; /* Number of pages per qpl for TX queues */
u16 rx_pages_per_qpl; /* Number of pages per qpl for RX queues */
u16 rx_data_slot_cnt; /* rx buffer length */
u64 max_registered_pages;
u64 num_registered_pages; /* num pages registered with NIC */
@ -1068,6 +1074,9 @@ int gve_reset(struct gve_priv *priv, bool attempt_teardown);
int gve_adjust_queues(struct gve_priv *priv,
struct gve_queue_config new_rx_config,
struct gve_queue_config new_tx_config);
int gve_adjust_ring_sizes(struct gve_priv *priv,
u16 new_tx_desc_cnt,
u16 new_rx_desc_cnt);
/* report stats handling */
void gve_handle_report_stats(struct gve_priv *priv);
/* exported by ethtool.c */

View File

@ -20,6 +20,8 @@
#define GVE_DEVICE_OPTION_TOO_BIG_FMT "Length of %s option larger than expected. Possible older version of guest driver.\n"
#define GVE_DEVICE_OPTION_NO_MIN_RING_SIZE 8
static
struct gve_device_option *gve_get_next_option(struct gve_device_descriptor *descriptor,
struct gve_device_option *option)
@ -40,7 +42,8 @@ void gve_parse_device_option(struct gve_priv *priv,
struct gve_device_option_gqi_qpl **dev_op_gqi_qpl,
struct gve_device_option_dqo_rda **dev_op_dqo_rda,
struct gve_device_option_jumbo_frames **dev_op_jumbo_frames,
struct gve_device_option_dqo_qpl **dev_op_dqo_qpl)
struct gve_device_option_dqo_qpl **dev_op_dqo_qpl,
struct gve_device_option_modify_ring **dev_op_modify_ring)
{
u32 req_feat_mask = be32_to_cpu(option->required_features_mask);
u16 option_length = be16_to_cpu(option->option_length);
@ -129,6 +132,27 @@ void gve_parse_device_option(struct gve_priv *priv,
}
*dev_op_dqo_qpl = (void *)(option + 1);
break;
case GVE_DEV_OPT_ID_MODIFY_RING:
if (option_length < GVE_DEVICE_OPTION_NO_MIN_RING_SIZE ||
req_feat_mask != GVE_DEV_OPT_REQ_FEAT_MASK_MODIFY_RING) {
dev_warn(&priv->pdev->dev, GVE_DEVICE_OPTION_ERROR_FMT,
"Modify Ring", (int)sizeof(**dev_op_modify_ring),
GVE_DEV_OPT_REQ_FEAT_MASK_MODIFY_RING,
option_length, req_feat_mask);
break;
}
if (option_length > sizeof(**dev_op_modify_ring)) {
dev_warn(&priv->pdev->dev,
GVE_DEVICE_OPTION_TOO_BIG_FMT, "Modify Ring");
}
*dev_op_modify_ring = (void *)(option + 1);
/* device has not provided min ring size */
if (option_length == GVE_DEVICE_OPTION_NO_MIN_RING_SIZE)
priv->default_min_ring_size = true;
break;
case GVE_DEV_OPT_ID_JUMBO_FRAMES:
if (option_length < sizeof(**dev_op_jumbo_frames) ||
req_feat_mask != GVE_DEV_OPT_REQ_FEAT_MASK_JUMBO_FRAMES) {
@ -164,7 +188,8 @@ gve_process_device_options(struct gve_priv *priv,
struct gve_device_option_gqi_qpl **dev_op_gqi_qpl,
struct gve_device_option_dqo_rda **dev_op_dqo_rda,
struct gve_device_option_jumbo_frames **dev_op_jumbo_frames,
struct gve_device_option_dqo_qpl **dev_op_dqo_qpl)
struct gve_device_option_dqo_qpl **dev_op_dqo_qpl,
struct gve_device_option_modify_ring **dev_op_modify_ring)
{
const int num_options = be16_to_cpu(descriptor->num_device_options);
struct gve_device_option *dev_opt;
@ -185,7 +210,7 @@ gve_process_device_options(struct gve_priv *priv,
gve_parse_device_option(priv, descriptor, dev_opt,
dev_op_gqi_rda, dev_op_gqi_qpl,
dev_op_dqo_rda, dev_op_jumbo_frames,
dev_op_dqo_qpl);
dev_op_dqo_qpl, dev_op_modify_ring);
dev_opt = next_opt;
}
@ -728,6 +753,12 @@ static int gve_set_desc_cnt(struct gve_priv *priv,
{
priv->tx_desc_cnt = be16_to_cpu(descriptor->tx_queue_entries);
priv->rx_desc_cnt = be16_to_cpu(descriptor->rx_queue_entries);
/* set default ranges */
priv->max_tx_desc_cnt = priv->tx_desc_cnt;
priv->max_rx_desc_cnt = priv->rx_desc_cnt;
priv->min_tx_desc_cnt = priv->tx_desc_cnt;
priv->min_rx_desc_cnt = priv->rx_desc_cnt;
return 0;
}
@ -739,6 +770,12 @@ gve_set_desc_cnt_dqo(struct gve_priv *priv,
priv->tx_desc_cnt = be16_to_cpu(descriptor->tx_queue_entries);
priv->rx_desc_cnt = be16_to_cpu(descriptor->rx_queue_entries);
/* set default ranges */
priv->max_tx_desc_cnt = priv->tx_desc_cnt;
priv->max_rx_desc_cnt = priv->rx_desc_cnt;
priv->min_tx_desc_cnt = priv->tx_desc_cnt;
priv->min_rx_desc_cnt = priv->rx_desc_cnt;
if (priv->queue_format == GVE_DQO_QPL_FORMAT)
return 0;
@ -755,7 +792,9 @@ static void gve_enable_supported_features(struct gve_priv *priv,
const struct gve_device_option_jumbo_frames
*dev_op_jumbo_frames,
const struct gve_device_option_dqo_qpl
*dev_op_dqo_qpl)
*dev_op_dqo_qpl,
const struct gve_device_option_modify_ring
*dev_op_modify_ring)
{
/* Before control reaches this point, the page-size-capped max MTU from
* the gve_device_descriptor field has already been stored in
@ -768,21 +807,59 @@ static void gve_enable_supported_features(struct gve_priv *priv,
priv->dev->max_mtu = be16_to_cpu(dev_op_jumbo_frames->max_mtu);
}
/* Override pages for qpl for DQO-QPL */
if (dev_op_dqo_qpl) {
priv->tx_pages_per_qpl =
be16_to_cpu(dev_op_dqo_qpl->tx_pages_per_qpl);
priv->rx_pages_per_qpl =
be16_to_cpu(dev_op_dqo_qpl->rx_pages_per_qpl);
if (priv->tx_pages_per_qpl == 0)
priv->tx_pages_per_qpl = DQO_QPL_DEFAULT_TX_PAGES;
if (priv->rx_pages_per_qpl == 0)
priv->rx_pages_per_qpl = DQO_QPL_DEFAULT_RX_PAGES;
/* Read and store ring size ranges given by device.
*
* Modifiable ring sizes are supported for DQO queue formats only.
* In this kernel's gve, the GQI branches of
* gve_adminq_create_{tx,rx}_queue do not carry a ring size, so after
* a resize the device would keep using its default ring size against
* rings the driver re-sized, desynchronizing device and driver views
* of the rings. The GQI datapath (rx_data_slot_cnt data ring, TX
* FIFO) also assumes the probe-time fixed ring sizes. Keep GQI at
* fixed ring sizes.
*/
if (dev_op_modify_ring && !gve_is_gqi(priv) &&
(supported_features_mask & GVE_SUP_MODIFY_RING_MASK)) {
priv->modify_ring_size_enabled = true;
priv->max_rx_desc_cnt = be16_to_cpu(dev_op_modify_ring->max_rx_ring_size);
priv->max_tx_desc_cnt = be16_to_cpu(dev_op_modify_ring->max_tx_ring_size);
if (priv->default_min_ring_size) {
/* If device hasn't provided minimums, use default minimums */
priv->min_tx_desc_cnt = GVE_DEFAULT_MIN_TX_RING_SIZE;
priv->min_rx_desc_cnt = GVE_DEFAULT_MIN_RX_RING_SIZE;
} else {
priv->min_rx_desc_cnt = be16_to_cpu(dev_op_modify_ring->min_rx_ring_size);
priv->min_tx_desc_cnt = be16_to_cpu(dev_op_modify_ring->min_tx_ring_size);
}
/* In this kernel's gve, the DQO-RDA TX completion ring and RX
* buffer ring keep the fixed sizes provided in the DQO-RDA
* device option; they do not scale with the descriptor rings
* (upstream removed that coupling before modifiable ring
* sizes were introduced). Clamp the advertised range so a
* resize cannot create a descriptor ring the fixed rings
* cannot absorb:
* - growing the TX ring beyond tx_comp_ring_entries could
* overrun the TX completion queue with report-event
* completions (or be rejected at queue creation);
* - shrinking the RX ring (the RX completion queue) below
* rx_buff_ring_entries could overflow the RX completion
* queue.
*/
if (priv->queue_format == GVE_DQO_RDA_FORMAT) {
priv->max_tx_desc_cnt = min(priv->max_tx_desc_cnt,
priv->options_dqo_rda.tx_comp_ring_entries);
priv->min_rx_desc_cnt = max(priv->min_rx_desc_cnt,
priv->options_dqo_rda.rx_buff_ring_entries);
}
}
}
int gve_adminq_describe_device(struct gve_priv *priv)
{
struct gve_device_option_modify_ring *dev_op_modify_ring = NULL;
struct gve_device_option_jumbo_frames *dev_op_jumbo_frames = NULL;
struct gve_device_option_gqi_rda *dev_op_gqi_rda = NULL;
struct gve_device_option_gqi_qpl *dev_op_gqi_qpl = NULL;
@ -816,7 +893,7 @@ int gve_adminq_describe_device(struct gve_priv *priv)
err = gve_process_device_options(priv, descriptor, &dev_op_gqi_rda,
&dev_op_gqi_qpl, &dev_op_dqo_rda,
&dev_op_jumbo_frames,
&dev_op_dqo_qpl);
&dev_op_dqo_qpl, &dev_op_modify_ring);
if (err)
goto free_device_descriptor;
@ -885,7 +962,8 @@ int gve_adminq_describe_device(struct gve_priv *priv)
priv->default_num_queues = be16_to_cpu(descriptor->default_num_queues);
gve_enable_supported_features(priv, supported_features_mask,
dev_op_jumbo_frames, dev_op_dqo_qpl);
dev_op_jumbo_frames, dev_op_dqo_qpl,
dev_op_modify_ring);
free_device_descriptor:
dma_pool_free(priv->adminq_pool, descriptor, descriptor_bus);

View File

@ -125,6 +125,16 @@ struct gve_device_option_jumbo_frames {
static_assert(sizeof(struct gve_device_option_jumbo_frames) == 8);
struct gve_device_option_modify_ring {
__be32 supported_featured_mask;
__be16 max_rx_ring_size;
__be16 max_tx_ring_size;
__be16 min_rx_ring_size;
__be16 min_tx_ring_size;
};
static_assert(sizeof(struct gve_device_option_modify_ring) == 12);
/* Terminology:
*
* RDA - Raw DMA Addressing - Buffers associated with SKBs are directly DMA
@ -138,6 +148,7 @@ enum gve_dev_opt_id {
GVE_DEV_OPT_ID_GQI_RDA = 0x2,
GVE_DEV_OPT_ID_GQI_QPL = 0x3,
GVE_DEV_OPT_ID_DQO_RDA = 0x4,
GVE_DEV_OPT_ID_MODIFY_RING = 0x6,
GVE_DEV_OPT_ID_DQO_QPL = 0x7,
GVE_DEV_OPT_ID_JUMBO_FRAMES = 0x8,
};
@ -149,9 +160,11 @@ enum gve_dev_opt_req_feat_mask {
GVE_DEV_OPT_REQ_FEAT_MASK_DQO_RDA = 0x0,
GVE_DEV_OPT_REQ_FEAT_MASK_JUMBO_FRAMES = 0x0,
GVE_DEV_OPT_REQ_FEAT_MASK_DQO_QPL = 0x0,
GVE_DEV_OPT_REQ_FEAT_MASK_MODIFY_RING = 0x0,
};
enum gve_sup_feature_mask {
GVE_SUP_MODIFY_RING_MASK = 1 << 0,
GVE_SUP_JUMBO_FRAMES_MASK = 1 << 2,
};

View File

@ -6,6 +6,7 @@
#include <linux/ethtool.h>
#include <linux/rtnetlink.h>
#include <linux/log2.h>
#include "gve.h"
#include "gve_adminq.h"
#include "gve_dqo.h"
@ -476,12 +477,56 @@ static void gve_get_ringparam(struct net_device *netdev,
{
struct gve_priv *priv = netdev_priv(netdev);
cmd->rx_max_pending = priv->rx_desc_cnt;
cmd->tx_max_pending = priv->tx_desc_cnt;
cmd->rx_max_pending = priv->max_rx_desc_cnt;
cmd->tx_max_pending = priv->max_tx_desc_cnt;
cmd->rx_pending = priv->rx_desc_cnt;
cmd->tx_pending = priv->tx_desc_cnt;
}
static int gve_validate_req_ring_size(struct gve_priv *priv, u16 new_tx_desc_cnt,
u16 new_rx_desc_cnt)
{
/* check for valid range */
if (new_tx_desc_cnt < priv->min_tx_desc_cnt ||
new_tx_desc_cnt > priv->max_tx_desc_cnt ||
new_rx_desc_cnt < priv->min_rx_desc_cnt ||
new_rx_desc_cnt > priv->max_rx_desc_cnt) {
dev_err(&priv->pdev->dev, "Requested descriptor count out of range\n");
return -EINVAL;
}
if (!is_power_of_2(new_tx_desc_cnt) || !is_power_of_2(new_rx_desc_cnt)) {
dev_err(&priv->pdev->dev, "Requested descriptor count has to be a power of 2\n");
return -EINVAL;
}
return 0;
}
static int gve_set_ringparam(struct net_device *netdev,
struct ethtool_ringparam *cmd,
struct kernel_ethtool_ringparam *kernel_cmd,
struct netlink_ext_ack *extack)
{
struct gve_priv *priv = netdev_priv(netdev);
u16 new_tx_cnt, new_rx_cnt;
if (cmd->tx_pending == priv->tx_desc_cnt && cmd->rx_pending == priv->rx_desc_cnt)
return 0;
if (!priv->modify_ring_size_enabled) {
dev_err(&priv->pdev->dev, "Modify ring size is not supported.\n");
return -EOPNOTSUPP;
}
new_tx_cnt = cmd->tx_pending;
new_rx_cnt = cmd->rx_pending;
if (gve_validate_req_ring_size(priv, new_tx_cnt, new_rx_cnt))
return -EINVAL;
return gve_adjust_ring_sizes(priv, new_tx_cnt, new_rx_cnt);
}
static int gve_user_reset(struct net_device *netdev, u32 *flags)
{
struct gve_priv *priv = netdev_priv(netdev);
@ -667,6 +712,7 @@ const struct ethtool_ops gve_ethtool_ops = {
.get_coalesce = gve_get_coalesce,
.set_coalesce = gve_set_coalesce,
.get_ringparam = gve_get_ringparam,
.set_ringparam = gve_set_ringparam,
.reset = gve_user_reset,
.get_tunable = gve_get_tunable,
.set_tunable = gve_set_tunable,

View File

@ -9,6 +9,7 @@
#include <linux/etherdevice.h>
#include <linux/filter.h>
#include <linux/interrupt.h>
#include <linux/math64.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/sched.h>
@ -1106,6 +1107,43 @@ free_qpls:
return err;
}
/* For DQO, update the suggested number of pages per qpl to be more flexible
* and honor the "max_registered_pages" parameter from the gVNIC device.
*
* Ignore the "tx_pages_per_qpl"/"rx_pages_per_qpl" parameters indicated in the
* DQO-QPL device option and instead allocate up to (tx_queue_length / 2) pages
* per TX QPL and up to (rx_queue_length * 2) pages per RX QPL while keeping the
* total number of pages under "max_registered_pages".
*/
static void gve_update_num_qpl_pages(struct gve_priv *priv)
{
u64 ideal_tx_pages, ideal_rx_pages;
u16 tx_num_queues, rx_num_queues;
u64 max_pages, tx_pages;
if (priv->queue_format != GVE_DQO_QPL_FORMAT)
return;
/* We want 2 pages per RX descriptor and half a page per TX descriptor,
* which means the fraction ideal_tx_pages / (ideal_tx_pages +
* ideal_rx_pages) of the pages we allocate should be for TX. Shrink
* proportionally as necessary to avoid allocating more than
* max_registered_pages total pages.
*/
tx_num_queues = priv->tx_cfg.num_queues;
rx_num_queues = priv->rx_cfg.num_queues;
ideal_tx_pages = (u64)priv->tx_desc_cnt * tx_num_queues / 2;
ideal_rx_pages = (u64)priv->rx_desc_cnt * rx_num_queues * 2;
max_pages = min(priv->max_registered_pages,
ideal_tx_pages + ideal_rx_pages);
tx_pages = div64_u64(max_pages * ideal_tx_pages,
ideal_tx_pages + ideal_rx_pages);
priv->tx_pages_per_qpl = div_u64(tx_pages, tx_num_queues);
priv->rx_pages_per_qpl = div_u64(max_pages - tx_pages, rx_num_queues);
}
static int gve_alloc_qpls(struct gve_priv *priv)
{
int max_queues = priv->tx_cfg.max_queues + priv->rx_cfg.max_queues;
@ -1117,6 +1155,8 @@ static int gve_alloc_qpls(struct gve_priv *priv)
if (!gve_is_qpl(priv))
return 0;
gve_update_num_qpl_pages(priv);
priv->qpls = kvcalloc(max_queues, sizeof(*priv->qpls), GFP_KERNEL);
if (!priv->qpls)
return -ENOMEM;
@ -1740,6 +1780,51 @@ err:
return err;
}
int gve_adjust_ring_sizes(struct gve_priv *priv,
u16 new_tx_desc_cnt,
u16 new_rx_desc_cnt)
{
int err;
/* Key on the administrative state (netif_running), not the link
* state: the rings are allocated whenever the interface is up, even
* while the carrier is down. Changing the descriptor counts without
* reallocating the rings would desynchronize them from
* priv->{tx,rx}_desc_cnt, which the GQI free path uses to size
* dma_free_coherent().
*/
if (netif_running(priv->dev)) {
/* To make this process as simple as possible we teardown the
* device, set the new ring sizes, and then bring the device
* up again.
*/
err = gve_close(priv->dev);
/* we have already tried to reset in close,
* just fail at this point
*/
if (err)
return err;
priv->tx_desc_cnt = new_tx_desc_cnt;
priv->rx_desc_cnt = new_rx_desc_cnt;
err = gve_open(priv->dev);
if (err)
goto err;
return 0;
}
/* Set the ring sizes for the next up. */
priv->tx_desc_cnt = new_tx_desc_cnt;
priv->rx_desc_cnt = new_rx_desc_cnt;
return 0;
err:
netif_err(priv, drv, priv->dev,
"Adjust ring sizes failed! !!! DISABLING ALL QUEUES !!!\n");
gve_turndown(priv);
return err;
}
static void gve_turndown(struct gve_priv *priv)
{
int idx;

View File

@ -484,14 +484,16 @@ static void iwl_init_vht_hw_capab(struct iwl_trans *trans,
*/
switch (iwlwifi_mod_params.amsdu_size) {
case IWL_AMSDU_DEF:
if (trans->mac_cfg->mq_rx_supported && !fips_enabled)
if (trans->mac_cfg->mq_rx_supported &&
fips_allows(FIPS_EXCEPTION_WIFI_MFP))
vht_cap->cap |=
IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454;
else
vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895;
break;
case IWL_AMSDU_2K:
if (trans->mac_cfg->mq_rx_supported && !fips_enabled)
if (trans->mac_cfg->mq_rx_supported &&
fips_allows(FIPS_EXCEPTION_WIFI_MFP))
vht_cap->cap |=
IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454;
else
@ -850,7 +852,7 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans,
/* EHT needs WPA3/MFP so cannot do it for fips_enabled */
if (!data->sku_cap_11be_enable || iwlwifi_mod_params.disable_11be ||
fips_enabled)
!fips_allows(FIPS_EXCEPTION_WIFI_MFP))
iftype_data->eht_cap.has_eht = false;
/* Advertise an A-MPDU exponent extension based on
@ -1140,7 +1142,8 @@ static void iwl_init_sbands(struct iwl_trans *trans,
* avoid spending time on scanning those channels and perhaps
* even finding APs there that cannot be used.
*/
if (!fips_enabled && data->sku_cap_11ax_enable &&
if (fips_allows(FIPS_EXCEPTION_WIFI_MFP) &&
data->sku_cap_11ax_enable &&
!iwlwifi_mod_params.disable_11ax)
iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains,
fw);

View File

@ -157,7 +157,7 @@ static void iwl_mld_hw_set_security(struct iwl_mld *mld)
WLAN_CIPHER_SUITE_BIP_GMAC_256
};
if (fips_enabled)
if (!fips_allows(FIPS_EXCEPTION_WIFI_MFP))
return;
hw->wiphy->n_cipher_suites = ARRAY_SIZE(mld_ciphers);
@ -166,6 +166,9 @@ static void iwl_mld_hw_set_security(struct iwl_mld *mld)
ieee80211_hw_set(hw, MFP_CAPABLE);
wiphy_ext_feature_set(hw->wiphy,
NL80211_EXT_FEATURE_BEACON_PROTECTION);
if (fips_enabled)
IWL_WARN(mld, "FIPS: MFP enabled with known firmware limitation\n");
}
static void iwl_mld_hw_set_antennas(struct iwl_mld *mld)
@ -295,7 +298,7 @@ static void iwl_mac_hw_set_wiphy(struct iwl_mld *mld)
if (mld->nvm_data->sku_cap_11be_enable &&
!iwlwifi_mod_params.disable_11ax &&
!iwlwifi_mod_params.disable_11be &&
!fips_enabled)
fips_allows(FIPS_EXCEPTION_WIFI_MFP))
wiphy->flags |= WIPHY_FLAG_SUPPORTS_MLO;
/* the firmware uses u8 for num of iterations, but 0xff is saved for

View File

@ -462,8 +462,11 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
IWL_ERR(mvm,
"iwlmvm doesn't allow to disable BT Coex, check bt_coex_active module parameter\n");
if (!fips_enabled)
if (fips_allows(FIPS_EXCEPTION_WIFI_MFP)) {
ieee80211_hw_set(hw, MFP_CAPABLE);
if (fips_enabled)
IWL_WARN(mvm, "FIPS: MFP enabled with known firmware limitation\n");
}
mvm->ciphers[hw->wiphy->n_cipher_suites] = WLAN_CIPHER_SUITE_AES_CMAC;
hw->wiphy->n_cipher_suites++;
@ -492,12 +495,12 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
* beacon protection must be handled by firmware,
* so cannot be done with fips_enabled
*/
if (!fips_enabled && sec_key_ver &&
if (fips_allows(FIPS_EXCEPTION_WIFI_MFP) && sec_key_ver &&
fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_BIGTK_TX_SUPPORT))
wiphy_ext_feature_set(hw->wiphy,
NL80211_EXT_FEATURE_BEACON_PROTECTION);
else if (!fips_enabled &&
else if (fips_allows(FIPS_EXCEPTION_WIFI_MFP) &&
fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_BIGTK_SUPPORT))
wiphy_ext_feature_set(hw->wiphy,

View File

@ -6,6 +6,7 @@
*/
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/fips.h>
#include "iwl-trans.h"
#include "mvm.h"
#include "fw-api.h"
@ -494,6 +495,14 @@ static int iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
return 0;
case RX_MPDU_RES_STATUS_SEC_CMAC_GMAC_ENC:
break;
case RX_MPDU_RES_STATUS_SEC_ENC_ERR:
if (fips_enabled) {
IWL_DEBUG_RX(mvm,
"FIPS mode: firmware cannot decrypt, status: 0x%x\n",
status);
break;
}
fallthrough;
default:
/*
* Sometimes we can get frames that were not decrypted

View File

@ -2329,8 +2329,8 @@ iscsit_handle_text_cmd(struct iscsit_conn *conn, struct iscsit_cmd *cmd,
if (conn->conn_ops->DataDigest) {
iscsit_do_crypto_hash_buf(conn->conn_rx_hash,
text_in, rx_size, 0, NULL,
&data_crc);
text_in, ALIGN(payload_length, 4),
0, NULL, &data_crc);
if (checksum != data_crc) {
pr_err("Text data CRC32C DataDigest"
@ -2350,6 +2350,7 @@ iscsit_handle_text_cmd(struct iscsit_conn *conn, struct iscsit_cmd *cmd,
" Command CmdSN: 0x%08x due to"
" DataCRC error.\n", hdr->cmdsn);
kfree(text_in);
cmd->text_in_ptr = NULL;
return 0;
}
} else {

View File

@ -1642,6 +1642,14 @@ static long vhost_vring_set_num_addr(struct vhost_dev *d,
BUG();
}
/*
* The metadata cache holds the IOTLB mapping that backed the previous
* desc/avail/used addresses and vring size, both of which are being
* replaced here. iotlb_access_ok() takes a cache hit as proof that the
* region was validated, so the stale entries have to go.
*/
__vhost_vq_meta_reset(vq);
mutex_unlock(&vq->mutex);
return r;

View File

@ -889,7 +889,7 @@ static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl,
*/
fattr->cf_mode &= ~07777;
fattr->cf_mode |=
le32_to_cpu(ppace[i]->sid.sub_auth[2]);
le32_to_cpu(ppace[i]->sid.sub_auth[2]) & 07777;
break;
} else {
if (compare_sids(&(ppace[i]->sid), pownersid) == 0) {

View File

@ -254,9 +254,23 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
goto out;
if (out_buf) {
*pbytes_returned = resp_iov.iov_len;
if (resp_iov.iov_len)
memcpy(out_buf, resp_iov.iov_base, resp_iov.iov_len);
/* Use smbCalcSize() for both single- and multi-part T2 responses,
* both here and in coalesce_t2().
*/
unsigned int copy_len;
if (WARN_ON_ONCE(!resp_iov.iov_base)) {
rc = -EIO;
goto out;
}
copy_len = smbCalcSize(resp_iov.iov_base);
if (copy_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
cifs_dbg(VFS, "response size %u exceeds buffer\n",
copy_len);
rc = -ENOBUFS;
goto out;
}
*pbytes_returned = copy_len;
memcpy(out_buf, resp_iov.iov_base, copy_len);
}
out:

View File

@ -935,6 +935,8 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size,
int i, rc = 0;
char *data_end;
struct dfs_referral_level_3 *ref;
unsigned int path_consumed;
size_t search_name_len;
if (rsp_size < sizeof(*rsp)) {
cifs_dbg(VFS | ONCE,
@ -982,6 +984,7 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size,
rc = -ENOMEM;
goto parse_DFS_referrals_exit;
}
search_name_len = strlen(searchName);
/* collect necessary data from referrals */
for (i = 0; i < *num_of_nodes; i++) {
@ -990,21 +993,34 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size,
struct dfs_info3_param *node = (*target_nodes)+i;
node->flags = le32_to_cpu(rsp->DFSFlags);
path_consumed = le16_to_cpu(rsp->PathConsumed);
if (is_unicode) {
__le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
GFP_KERNEL);
if (tmp == NULL) {
size_t search_name_utf16_len = search_name_len * 2 + 2;
__le16 *tmp;
if (path_consumed > search_name_utf16_len) {
rc = -EINVAL;
goto parse_DFS_referrals_exit;
}
tmp = kmalloc(search_name_utf16_len, GFP_KERNEL);
if (!tmp) {
rc = -ENOMEM;
goto parse_DFS_referrals_exit;
}
cifsConvertToUTF16((__le16 *) tmp, searchName,
cifsConvertToUTF16((__le16 *)tmp, searchName,
PATH_MAX, nls_codepage, remap);
node->path_consumed = cifs_utf16_bytes(tmp,
le16_to_cpu(rsp->PathConsumed),
nls_codepage);
node->path_consumed = cifs_utf16_bytes(tmp, path_consumed,
nls_codepage);
kfree(tmp);
} else
node->path_consumed = le16_to_cpu(rsp->PathConsumed);
} else {
if (path_consumed > search_name_len) {
rc = -EINVAL;
goto parse_DFS_referrals_exit;
}
node->path_consumed = path_consumed;
}
node->server_type = le16_to_cpu(ref->ServerType);
node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);

View File

@ -399,11 +399,13 @@ coalesce_t2(char *second_buf, struct smb_hdr *target_hdr, unsigned int *pdu_len)
}
put_bcc(byte_count, target_hdr);
byte_count = *pdu_len;
byte_count += total_in_src;
/* use smbCalcSize() rather than *pdu_len: the demux loop resets
* *pdu_len to each secondary's pdu_length, making it unreliable.
*/
byte_count = smbCalcSize(target_hdr);
/* don't allow buffer to overflow */
if (byte_count > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
cifs_dbg(FYI, "coalesced BCC exceeds buffer size (%u)\n",
cifs_dbg(FYI, "coalesced size exceeds buffer size (%u)\n",
byte_count);
return -ENOBUFS;
}

View File

@ -3498,6 +3498,7 @@ static int smb3_simple_fallocate_range(unsigned int xid,
struct file_allocated_range_buffer in_data, *out_data = NULL, *tmp_data;
u32 out_data_len;
char *buf = NULL;
u64 range_start, range_len, range_end;
loff_t l;
int rc;
@ -3534,13 +3535,21 @@ static int smb3_simple_fallocate_range(unsigned int xid,
goto out;
}
if (off < le64_to_cpu(tmp_data->file_offset)) {
range_start = le64_to_cpu(tmp_data->file_offset);
range_len = le64_to_cpu(tmp_data->length);
if (check_add_overflow(range_start, range_len, &range_end) ||
range_end > S64_MAX) {
rc = -EINVAL;
goto out;
}
if (off < range_start) {
/*
* We are at a hole. Write until the end of the region
* or until the next allocated data,
* whichever comes next.
*/
l = le64_to_cpu(tmp_data->file_offset) - off;
l = range_start - off;
if (len < l)
l = len;
rc = smb3_simple_fallocate_write_range(xid, tcon,
@ -3557,11 +3566,13 @@ static int smb3_simple_fallocate_range(unsigned int xid,
* until the end of the data or the end of the region
* we are supposed to fallocate, whichever comes first.
*/
l = le64_to_cpu(tmp_data->length);
if (len < l)
l = len;
off += l;
len -= l;
if (off < range_end) {
l = range_end - off;
if (len < l)
l = len;
off += l;
len -= l;
}
tmp_data = &tmp_data[1];
out_data_len -= sizeof(struct file_allocated_range_buffer);

View File

@ -3231,6 +3231,8 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
replay_again:
/* reinitialize for possible replay */
resp_buftype = CIFS_NO_BUFFER;
memset(&rsp_iov, 0, sizeof(rsp_iov));
flags = 0;
server = cifs_pick_channel(ses);
oparms->replay = !!(retries);
@ -3847,6 +3849,8 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
replay_again:
/* reinitialize for possible replay */
resp_buftype = CIFS_NO_BUFFER;
memset(&rsp_iov, 0, sizeof(rsp_iov));
flags = 0;
allocated = false;
server = cifs_pick_channel(ses);

View File

@ -1617,8 +1617,9 @@ static struct udf_vds_record *handle_partition_descriptor(
return &(data->part_descs_loc[i].rec);
if (data->num_part_descs >= data->size_part_descs) {
struct part_desc_seq_scan_data *new_loc;
unsigned int new_size = ALIGN(partnum, PART_DESC_ALLOC_STEP);
unsigned int new_size;
new_size = data->num_part_descs + PART_DESC_ALLOC_STEP;
new_loc = kcalloc(new_size, sizeof(*new_loc), GFP_KERNEL);
if (!new_loc)
return ERR_PTR(-ENOMEM);
@ -1628,6 +1629,7 @@ static struct udf_vds_record *handle_partition_descriptor(
data->part_descs_loc = new_loc;
data->size_part_descs = new_size;
}
data->part_descs_loc[data->num_part_descs].partnum = partnum;
return &(data->part_descs_loc[data->num_part_descs++].rec);
}

View File

@ -16,12 +16,24 @@ extern struct atomic_notifier_head fips_fail_notif_chain;
#endif
void fips_fail_notify(void);
/*
* fips_allows - check if a not fully FIPS-compliant feature is allowed
* via an explicit boot-time exception (rh_fips_exception=).
* Not for fully FIPS-compliant features.
*/
int fips_allows(unsigned long feature);
#else
#define fips_enabled 0
static inline void fips_fail_notify(void) {}
static inline int fips_allows(unsigned long feature)
{
return 1;
}
#endif
#define FIPS_EXCEPTION_WIFI_MFP BIT(0)
#endif

View File

@ -24,7 +24,9 @@ void psi_memstall_leave(unsigned long *flags);
int psi_show(struct seq_file *s, struct psi_group *group, enum psi_res res);
struct psi_trigger *psi_trigger_create(struct psi_group *group, char *buf,
enum psi_res res, struct file *file,
struct kernfs_open_file *of);
struct kernfs_open_file *of,
bool *need_rtpoll_worker);
int psi_trigger_create_rtpoll_worker(struct psi_group *group);
void psi_trigger_destroy(struct psi_trigger *t);
__poll_t psi_trigger_poll(void **trigger_ptr, struct file *file,

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.39.1.el9.x86_64,mailto:secalert@redhat.com
kernel.almalinux,1,AlmaLinux,kernel-core,5.14.0-687.39.1.el9.x86_64,mailto:security@almalinux.org
kernel.rhel,1,Red Hat,kernel-core,5.14.0-687.41.1.el9.x86_64,mailto:secalert@redhat.com
kernel.almalinux,1,AlmaLinux,kernel-core,5.14.0-687.41.1.el9.x86_64,mailto:security@almalinux.org

View File

@ -3859,33 +3859,62 @@ static int cgroup_cpu_pressure_show(struct seq_file *seq, void *v)
static ssize_t pressure_write(struct kernfs_open_file *of, char *buf,
size_t nbytes, enum psi_res res)
{
struct cgroup_file_ctx *ctx = of->priv;
struct cgroup_file_ctx *ctx;
struct psi_trigger *new;
struct cgroup *cgrp;
struct psi_group *psi;
bool need_rtpoll_worker;
ssize_t ret = 0;
cgrp = cgroup_kn_lock_live(of->kn, false);
if (!cgrp)
return -ENODEV;
cgroup_get(cgrp);
cgroup_kn_unlock(of->kn);
ctx = of->priv;
if (!ctx) {
ret = -ENODEV;
goto out_unlock;
}
/* Allow only one trigger per file descriptor */
if (ctx->psi.trigger) {
cgroup_put(cgrp);
return -EBUSY;
ret = -EBUSY;
goto out_unlock;
}
psi = cgroup_psi(cgrp);
new = psi_trigger_create(psi, buf, res, of->file, of);
new = psi_trigger_create(psi, buf, res, of->file, of,
&need_rtpoll_worker);
if (IS_ERR(new)) {
cgroup_put(cgrp);
return PTR_ERR(new);
ret = PTR_ERR(new);
goto out_unlock;
}
/*
* The worker fork must run with neither cgroup_mutex nor the file's
* kernfs active reference held. The latter is broken since
* cgroup_kn_lock_live(). @of->priv may be released while unlocked, so
* recheck before publishing @new.
*/
if (need_rtpoll_worker) {
cgroup_unlock();
ret = psi_trigger_create_rtpoll_worker(psi);
cgroup_lock();
if (!ret && !of->priv)
ret = -ENODEV;
if (ret) {
psi_trigger_destroy(new);
goto out_unlock;
}
}
smp_store_release(&ctx->psi.trigger, new);
cgroup_put(cgrp);
out_unlock:
cgroup_kn_unlock(of->kn);
if (ret)
return ret;
return nbytes;
}
@ -4149,6 +4178,7 @@ static void cgroup_file_release(struct kernfs_open_file *of)
cft->release(of);
put_cgroup_ns(ctx->ns);
kfree(ctx);
of->priv = NULL;
}
static ssize_t cgroup_file_write(struct kernfs_open_file *of, char *buf,

View File

@ -184,7 +184,13 @@ static void __exit_signal(struct task_struct *tsk)
* doing sigqueue_free() if we have SIGQUEUE_PREALLOC signals.
*/
flush_sigqueue(&tsk->pending);
tsk->sighand = NULL;
/*
* Ensure that all preceeding state is visible. Pairs with
* the smp_acquire__after_ctrl_dep() in the sighand == NULL
* path of lock_task_sighand().
*/
smp_store_release(&tsk->sighand, NULL);
spin_unlock(&sighand->siglock);
__cleanup_sighand(sighand);

View File

@ -1312,9 +1312,44 @@ static int psi_cpu_open(struct inode *inode, struct file *file)
return single_open(file, psi_cpu_show, NULL);
}
/*
* Create @group's rtpoll worker after psi_trigger_create() reported the need
* for one. kthread creation depends on the whole fork path and we don't want
* all of that nested inside cgroup_mutex, so the caller must drop it and any
* other lock that forks can wait behind. If two callers race, the loser stops
* its never-woken kthread.
*/
int psi_trigger_create_rtpoll_worker(struct psi_group *group)
{
struct task_struct *task;
task = kthread_create(psi_rtpoll_worker, group, "psimon");
if (IS_ERR(task))
return PTR_ERR(task);
scoped_guard(mutex, &group->rtpoll_trigger_lock) {
if (!rcu_access_pointer(group->rtpoll_task)) {
atomic_set(&group->rtpoll_wakeup, 0);
wake_up_process(task);
rcu_assign_pointer(group->rtpoll_task, task);
/*
* Poll once to catch up on scheduling attempts dropped
* while there was no rtpoll worker.
*/
psi_schedule_rtpoll_work(group, 1, true);
return 0;
}
}
kthread_stop(task);
return 0;
}
struct psi_trigger *psi_trigger_create(struct psi_group *group, char *buf,
enum psi_res res, struct file *file,
struct kernfs_open_file *of)
struct kernfs_open_file *of,
bool *need_rtpoll_worker)
{
struct psi_trigger *t;
enum psi_states state;
@ -1322,6 +1357,8 @@ struct psi_trigger *psi_trigger_create(struct psi_group *group, char *buf,
bool privileged;
u32 window_us;
*need_rtpoll_worker = false;
if (static_branch_likely(&psi_disabled))
return ERR_PTR(-EOPNOTSUPP);
@ -1381,26 +1418,14 @@ struct psi_trigger *psi_trigger_create(struct psi_group *group, char *buf,
if (privileged) {
mutex_lock(&group->rtpoll_trigger_lock);
if (!rcu_access_pointer(group->rtpoll_task)) {
struct task_struct *task;
task = kthread_create(psi_rtpoll_worker, group, "psimon");
if (IS_ERR(task)) {
kfree(t);
mutex_unlock(&group->rtpoll_trigger_lock);
return ERR_CAST(task);
}
atomic_set(&group->rtpoll_wakeup, 0);
wake_up_process(task);
rcu_assign_pointer(group->rtpoll_task, task);
}
list_add(&t->node, &group->rtpoll_triggers);
group->rtpoll_min_period = min(group->rtpoll_min_period,
div_u64(t->win.size, UPDATES_PER_WINDOW));
group->rtpoll_nr_triggers[t->state]++;
group->rtpoll_states |= (1 << t->state);
*need_rtpoll_worker = !rcu_access_pointer(group->rtpoll_task);
mutex_unlock(&group->rtpoll_trigger_lock);
} else {
mutex_lock(&group->avgs_lock);
@ -1524,6 +1549,8 @@ static ssize_t psi_write(struct file *file, const char __user *user_buf,
size_t buf_size;
struct seq_file *seq;
struct psi_trigger *new;
bool need_rtpoll_worker;
int ret;
if (static_branch_likely(&psi_disabled))
return -EOPNOTSUPP;
@ -1548,12 +1575,22 @@ static ssize_t psi_write(struct file *file, const char __user *user_buf,
return -EBUSY;
}
new = psi_trigger_create(&psi_system, buf, res, file, NULL);
new = psi_trigger_create(&psi_system, buf, res, file, NULL,
&need_rtpoll_worker);
if (IS_ERR(new)) {
mutex_unlock(&seq->lock);
return PTR_ERR(new);
}
if (need_rtpoll_worker) {
ret = psi_trigger_create_rtpoll_worker(&psi_system);
if (ret) {
psi_trigger_destroy(new);
mutex_unlock(&seq->lock);
return ret;
}
}
smp_store_release(&seq->private, new);
mutex_unlock(&seq->lock);

View File

@ -1395,8 +1395,16 @@ struct sighand_struct *__lock_task_sighand(struct task_struct *tsk,
rcu_read_lock();
for (;;) {
sighand = rcu_dereference(tsk->sighand);
if (unlikely(sighand == NULL))
if (unlikely(sighand == NULL)) {
/*
* Pairs with the smp_store_release() in
* __exit_signal(). It ensures that all state
* modifications to the task preceeding the store are
* visible to the callers of lock_task_sighand().
*/
smp_acquire__after_ctrl_dep();
break;
}
/*
* This sighand can be already freed and even reused, but

View File

@ -462,6 +462,109 @@ static void disarm_timer(struct k_itimer *timer, struct task_struct *p)
trigger_base_recalc_expires(timer, p);
}
/*
* Lookup the task via timer->it.cpu.pid and attempt to lock the task's sighand.
*
* This can race with the reaping of the task:
*
* CPU0 CPU1
*
* // Finds task
* p = pid_task(pid, pid_type); __exit_signal(p)
* lock(p, sighand);
* posix_cpu_timers*_exit();
* sighand = lock_task_sighand(p); unhash_task(p);
* p->sighand = NULL;
* unlock(sighand);
*
* In this case sighand is NULL, which means the task and the associated timer
* queue cannot be longer accessed safely.
*
* __exit_signal() invokes posix_cpu_timers_exit() and if the thread group is
* dead it also invokes posix_cpu_timers_group_exit(). These functions delete
* all pending timers from the related timer queues. The POSIX timers (k_itimer)
* themself are still accessible, but not longer connected to the task.
*
* exec() works slightly differently. The task which exec()'s terminates all
* other threads in the thread group and runs __exit_signal() on them. As the
* thread group is not dead they only clean up the per task timers via
* posix_cpu_timers_exit().
*
* As the TGID on exec() stays the same per process timers stay queued, if they
* are armed. This works without a problem when exec() is done by the thread
* group leader. If a non-leader thread exec()'s this can end up in the
* following scenario:
*
* CPU0 CPU1
* // Returns old leader
* p = pid_task(pid, pid_type); de_thread()
* switch_leader()
* release_task(old leader)
* __exit_signal()
* old_leader->sighand = NULL;
* // Returns NULL
* sighand = lock_task_sighand(p)
*
* That's problematic for several functions:
*
* - posix_cpu_timer_del(): If the timer is still enqueued on the task the
* underlying k_itimer will be freed which results in a UAF in
* run_posix_cpu_timers() or on timerqueue related add/delete operations.
* If the timer is not enqueued, the failure is harmless
*
* - posix_cpu_timer_set(): Independent of the enqueued state that results in a
* transient failure which is user space visible (-ESRCH) for regular posix
* timers. But for the use case in do_cpu_nanosleep() it's the same UAF
* problem just that the timer is allocated on the stack.
*
* - posix_cpu_timer_rearm(): Timer is not enqueued at that point, but this
* silently ignores the rearm request, which is a functional problem as the
* timer wont expire anymore.
*/
static struct task_struct *timer_lock_sighand(struct k_itimer *timer, unsigned long *flags)
{
enum pid_type type = clock_pid_type(timer->it_clock);
struct cpu_timer *ctmr = &timer->it.cpu;
guard(rcu)();
for (;;) {
struct task_struct *t = pid_task(timer->it.cpu.pid, type);
/* Fail if the task cannot be found. */
if (!t)
break;
/* Try to lock the task's sighand */
if (lock_task_sighand(t, flags))
return t;
/*
* The next PID lookup might either fail or return the new
* leader. This is correct for both exit() and exec().
*/
}
/*
* If the timer is still enqueued, warn. There is nothing safe to do
* here as there might be two timers in there which are removed in
* parallel and that will cause more damage than good. This should never
* happen!
*
* Ensure that the stores to the timer and timerqueue are visible:
*
* __exit_signal()
* posix_cpu_timers*_exit()
* write_seqlock(seqlock)
* smp_wmb(); <-------
* __unhash_process() | !pid_task()
* ----> smp_rmb();
* WARN_ON_ONCE(...)
*/
smp_rmb();
WARN_ON_ONCE(ctmr->head || timerqueue_node_queued(&ctmr->node));
return NULL;
}
/*
* Clean up a CPU-clock timer that is about to be destroyed.
@ -471,29 +574,13 @@ static void disarm_timer(struct k_itimer *timer, struct task_struct *p)
*/
static int posix_cpu_timer_del(struct k_itimer *timer)
{
struct cpu_timer *ctmr = &timer->it.cpu;
struct sighand_struct *sighand;
struct task_struct *p;
unsigned long flags;
int ret = 0;
rcu_read_lock();
p = cpu_timer_task_rcu(timer);
if (!p)
goto out;
p = timer_lock_sighand(timer, &flags);
/*
* Protect against sighand release/switch in exit/exec and process/
* thread timer list entry concurrent read/writes.
*/
sighand = lock_task_sighand(p, &flags);
if (unlikely(sighand == NULL)) {
/*
* This raced with the reaping of the task. The exit cleanup
* should have removed this timer from the timer queue.
*/
WARN_ON_ONCE(ctmr->head || timerqueue_node_queued(&ctmr->node));
} else {
if (likely(p)) {
if (timer->it.cpu.firing)
ret = TIMER_RETRY;
else
@ -502,10 +589,8 @@ static int posix_cpu_timer_del(struct k_itimer *timer)
unlock_task_sighand(p, &flags);
}
out:
rcu_read_unlock();
if (!ret)
put_pid(ctmr->pid);
put_pid(timer->it.cpu.pid);
return ret;
}
@ -585,12 +670,7 @@ static void cpu_timer_fire(struct k_itimer *timer)
{
struct cpu_timer *ctmr = &timer->it.cpu;
if ((timer->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE) {
/*
* User don't want any signal.
*/
cpu_timer_setexpires(ctmr, 0);
} else if (unlikely(timer->sigq == NULL)) {
if (unlikely(timer->sigq == NULL)) {
/*
* This a special case for clock_nanosleep,
* not a normal timer from sys_timer_create.
@ -615,6 +695,8 @@ static void cpu_timer_fire(struct k_itimer *timer)
}
}
static void __posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp, u64 now);
/*
* Guts of sys_timer_settime for CPU timers.
* This is called with the timer locked and interrupts disabled.
@ -624,24 +706,21 @@ static void cpu_timer_fire(struct k_itimer *timer)
static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags,
struct itimerspec64 *new, struct itimerspec64 *old)
{
bool sigev_none = timer->it_sigev_notify == SIGEV_NONE;
clockid_t clkid = CPUCLOCK_WHICH(timer->it_clock);
u64 old_expires, new_expires, old_incr, val;
struct cpu_timer *ctmr = &timer->it.cpu;
struct sighand_struct *sighand;
u64 old_expires, new_expires, now;
struct task_struct *p;
unsigned long flags;
int ret = 0;
rcu_read_lock();
p = cpu_timer_task_rcu(timer);
if (!p) {
/*
* If p has just been reaped, we can no
* longer get any information about it at all.
*/
rcu_read_unlock();
p = timer_lock_sighand(timer, &flags);
/*
* If p has just been reaped, we can no longer get any information about
* it at all.
*/
if (!p)
return -ESRCH;
}
/*
* Use the to_ktime conversion because that clamps the maximum
@ -649,24 +728,7 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags,
*/
new_expires = ktime_to_ns(timespec64_to_ktime(new->it_value));
/*
* Protect against sighand release/switch in exit/exec and p->cpu_timers
* and p->signal->cpu_timers read/write in arm_timer()
*/
sighand = lock_task_sighand(p, &flags);
/*
* If p has just been reaped, we can no
* longer get any information about it at all.
*/
if (unlikely(sighand == NULL)) {
rcu_read_unlock();
return -ESRCH;
}
/*
* Disarm any old timer after extracting its expiry time.
*/
old_incr = timer->it_interval;
/* Retrieve the current expiry time before disarming the timer */
old_expires = cpu_timer_getexpires(ctmr);
if (unlikely(timer->it.cpu.firing)) {
@ -677,65 +739,46 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags,
}
/*
* We need to sample the current value to convert the new
* value from to relative and absolute, and to convert the
* old value from absolute to relative. To set a process
* timer, we need a sample to balance the thread expiry
* times (in arm_timer). With an absolute time, we must
* check if it's already passed. In short, we need a sample.
* Sample the current clock for saving the previous setting
* and for rearming the timer.
*/
if (CPUCLOCK_PERTHREAD(timer->it_clock))
val = cpu_clock_sample(clkid, p);
now = cpu_clock_sample(clkid, p);
else
val = cpu_clock_sample_group(clkid, p, true);
now = cpu_clock_sample_group(clkid, p, !sigev_none);
/* Retrieve the previous expiry value if requested. */
if (old) {
if (old_expires == 0) {
old->it_value.tv_sec = 0;
old->it_value.tv_nsec = 0;
} else {
/*
* Update the timer in case it has overrun already.
* If it has, we'll report it as having overrun and
* with the next reloaded timer already ticking,
* though we are swallowing that pending
* notification here to install the new setting.
*/
u64 exp = bump_cpu_timer(timer, val);
if (val < exp) {
old_expires = exp - val;
old->it_value = ns_to_timespec64(old_expires);
} else {
old->it_value.tv_nsec = 1;
old->it_value.tv_sec = 0;
}
}
old->it_value = (struct timespec64){ };
if (old_expires)
__posix_cpu_timer_get(timer, old, now);
}
/* Retry if the timer expiry is running concurrently */
if (unlikely(ret)) {
/*
* We are colliding with the timer actually firing.
* Punt after filling in the timer's old value, and
* disable this firing since we are already reporting
* it as an overrun (thanks to bump_cpu_timer above).
*/
unlock_task_sighand(p, &flags);
goto out;
return ret;
}
if (new_expires != 0 && !(timer_flags & TIMER_ABSTIME)) {
new_expires += val;
}
/* Convert relative expiry time to absolute */
if (new_expires && !(timer_flags & TIMER_ABSTIME))
new_expires += now;
/* Set the new expiry time (might be 0) */
cpu_timer_setexpires(ctmr, new_expires);
/*
* Install the new expiry time (or zero).
* For a timer with no notification action, we don't actually
* arm the timer (we'll just fake it for timer_gettime).
* Arm the timer if it is not disabled, the new expiry value has
* not yet expired and the timer requires signal delivery.
* SIGEV_NONE timers are never armed. In case the timer is not
* armed, enforce the reevaluation of the timer base so that the
* process wide cputime counter can be disabled eventually.
*/
cpu_timer_setexpires(ctmr, new_expires);
if (new_expires != 0 && val < new_expires) {
arm_timer(timer, p);
if (likely(!sigev_none)) {
if (new_expires && now < new_expires)
arm_timer(timer, p);
else
trigger_base_recalc_expires(timer, p);
}
unlock_task_sighand(p, &flags);
@ -755,76 +798,70 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags,
timer->it_overrun_last = 0;
timer->it_overrun = -1;
if (val >= new_expires) {
if (new_expires != 0) {
/*
* The designated time already passed, so we notify
* immediately, even if the thread never runs to
* accumulate more time on this clock.
*/
cpu_timer_fire(timer);
}
/*
* Make sure we don't keep around the process wide cputime
* counter or the tick dependency if they are not necessary.
*/
sighand = lock_task_sighand(p, &flags);
if (!sighand)
goto out;
if (!cpu_timer_queued(ctmr))
trigger_base_recalc_expires(timer, p);
unlock_task_sighand(p, &flags);
}
out:
rcu_read_unlock();
if (old)
old->it_interval = ns_to_timespec64(old_incr);
/*
* If the new expiry time was already in the past the timer was not
* queued. Fire it immediately even if the thread never runs to
* accumulate more time on this clock.
*/
if (!sigev_none && new_expires && now >= new_expires)
cpu_timer_fire(timer);
return ret;
}
static void __posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp, u64 now)
{
bool sigev_none = timer->it_sigev_notify == SIGEV_NONE;
u64 expires, iv = timer->it_interval;
/*
* Make sure that interval timers are moved forward for the
* following cases:
* - SIGEV_NONE timers which are never armed
* - Timers which expired, but the signal has not yet been
* delivered
*/
if (iv && ((timer->it_requeue_pending & REQUEUE_PENDING) || sigev_none))
expires = bump_cpu_timer(timer, now);
else
expires = cpu_timer_getexpires(&timer->it.cpu);
/*
* Expired interval timers cannot have a remaining time <= 0.
* The kernel has to move them forward so that the next
* timer expiry is > @now.
*/
if (now < expires) {
itp->it_value = ns_to_timespec64(expires - now);
} else {
/*
* A single shot SIGEV_NONE timer must return 0, when it is
* expired! Timers which have a real signal delivery mode
* must return a remaining time greater than 0 because the
* signal has not yet been delivered.
*/
if (!sigev_none)
itp->it_value.tv_nsec = 1;
}
}
static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp)
{
clockid_t clkid = CPUCLOCK_WHICH(timer->it_clock);
struct cpu_timer *ctmr = &timer->it.cpu;
u64 now, expires = cpu_timer_getexpires(ctmr);
struct task_struct *p;
u64 now;
rcu_read_lock();
p = cpu_timer_task_rcu(timer);
if (!p)
goto out;
if (p && cpu_timer_getexpires(&timer->it.cpu)) {
itp->it_interval = ktime_to_timespec64(timer->it_interval);
/*
* Easy part: convert the reload time.
*/
itp->it_interval = ktime_to_timespec64(timer->it_interval);
if (CPUCLOCK_PERTHREAD(timer->it_clock))
now = cpu_clock_sample(clkid, p);
else
now = cpu_clock_sample_group(clkid, p, false);
if (!expires)
goto out;
/*
* Sample the clock to take the difference with the expiry time.
*/
if (CPUCLOCK_PERTHREAD(timer->it_clock))
now = cpu_clock_sample(clkid, p);
else
now = cpu_clock_sample_group(clkid, p, false);
if (now < expires) {
itp->it_value = ns_to_timespec64(expires - now);
} else {
/*
* The timer should have expired already, but the firing
* hasn't taken place yet. Say it's just about to expire.
*/
itp->it_value.tv_nsec = 1;
itp->it_value.tv_sec = 0;
__posix_cpu_timer_get(timer, itp, now);
}
out:
rcu_read_unlock();
}
@ -1047,19 +1084,12 @@ static void posix_cpu_timer_rearm(struct k_itimer *timer)
{
clockid_t clkid = CPUCLOCK_WHICH(timer->it_clock);
struct task_struct *p;
struct sighand_struct *sighand;
unsigned long flags;
u64 now;
rcu_read_lock();
p = cpu_timer_task_rcu(timer);
if (!p)
goto out;
/* Protect timer list r/w in arm_timer() */
sighand = lock_task_sighand(p, &flags);
if (unlikely(sighand == NULL))
goto out;
p = timer_lock_sighand(timer, &flags);
if (unlikely(!p))
return;
/*
* Fetch the current sample and update the timer's expiry time.
@ -1076,8 +1106,6 @@ static void posix_cpu_timer_rearm(struct k_itimer *timer)
*/
arm_timer(timer, p);
unlock_task_sighand(p, &flags);
out:
rcu_read_unlock();
}
/**
@ -1477,6 +1505,7 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags,
spin_lock_irq(&timer.it_lock);
error = posix_cpu_timer_set(&timer, flags, &it, NULL);
if (error) {
posix_cpu_timer_del(&timer);
spin_unlock_irq(&timer.it_lock);
return error;
}

View File

@ -902,7 +902,7 @@ static int do_timer_settime(timer_t timer_id, int tmr_flags,
const struct k_clock *kc;
struct k_itimer *timr;
unsigned long flags;
int error = 0;
int error;
if (!timespec64_valid(&new_spec64->it_interval) ||
!timespec64_valid(&new_spec64->it_value))
@ -916,6 +916,9 @@ retry:
if (!timr)
return -EINVAL;
if (old_spec64)
old_spec64->it_interval = ktime_to_timespec64(timr->it_interval);
kc = timr->kclock;
if (WARN_ON_ONCE(!kc || !kc->timer_set))
error = -EINVAL;

View File

@ -2145,7 +2145,9 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
if (!PageReferenced(page) && pmd_young(old_pmd))
SetPageReferenced(page);
page_remove_rmap(page, vma, true);
add_mm_counter(mm, mm_counter_file(page), -HPAGE_PMD_NR);
put_page(page);
return;
}
add_mm_counter(mm, mm_counter_file(page), -HPAGE_PMD_NR);
return;

View File

@ -257,6 +257,12 @@ static int memfd_add_seals(struct file *file, unsigned int seals)
goto unlock;
}
/*
* SEAL_EXEC implies SEAL_WRITE, making W^X from the start.
*/
if (seals & F_SEAL_EXEC && inode->i_mode & 0111)
seals |= F_SEAL_SHRINK|F_SEAL_GROW|F_SEAL_WRITE|F_SEAL_FUTURE_WRITE;
if ((seals & F_SEAL_WRITE) && !(*file_seals & F_SEAL_WRITE)) {
error = mapping_deny_writable(file->f_mapping);
if (error)
@ -269,12 +275,6 @@ static int memfd_add_seals(struct file *file, unsigned int seals)
}
}
/*
* SEAL_EXEC implys SEAL_WRITE, making W^X from the start.
*/
if (seals & F_SEAL_EXEC && inode->i_mode & 0111)
seals |= F_SEAL_SHRINK|F_SEAL_GROW|F_SEAL_WRITE|F_SEAL_FUTURE_WRITE;
*file_seals |= seals;
error = 0;

View File

@ -2327,10 +2327,11 @@ static int ip6erspan_changelink(struct net_device *dev, struct nlattr *tb[],
struct nlattr *data[],
struct netlink_ext_ack *extack)
{
struct ip6gre_net *ign = net_generic(dev_net(dev), ip6gre_net_id);
struct ip6_tnl *t = netdev_priv(dev);
struct __ip6_tnl_parm p;
struct ip6_tnl *t;
struct ip6gre_net *ign;
ign = net_generic(t->net, ip6gre_net_id);
t = ip6gre_changelink_common(dev, tb, data, &p, extack);
if (IS_ERR(t))
return PTR_ERR(t);

View File

@ -515,7 +515,7 @@ int drv_set_key(struct ieee80211_local *local,
!(sdata->vif.active_links & BIT(key->link_id))))
return -ENOLINK;
if (fips_enabled)
if (!fips_allows(FIPS_EXCEPTION_WIFI_MFP))
return -EOPNOTSUPP;
trace_drv_set_key(local, cmd, sdata, sta, key);

View File

@ -903,7 +903,7 @@ static inline void drv_set_rekey_data(struct ieee80211_local *local,
if (!check_sdata_in_driver(sdata))
return;
if (fips_enabled)
if (!fips_allows(FIPS_EXCEPTION_WIFI_MFP))
return;
trace_drv_set_rekey_data(local, sdata, data);

View File

@ -796,7 +796,7 @@ static int decode_choice(struct bitstr *bs, const struct field_t *f,
if (ext || (son->attr & OPEN)) {
BYTE_ALIGN(bs);
if (nf_h323_error_boundary(bs, len, 0))
if (nf_h323_error_boundary(bs, 2, 0))
return H323_ERROR_BOUND;
len = get_len(bs);
if (nf_h323_error_boundary(bs, len, 0))

View File

@ -199,6 +199,8 @@ synproxy_tstamp_adjust(struct sk_buff *skb, unsigned int protoff,
if (skb_ensure_writable(skb, optend))
return 0;
th = (struct tcphdr *)(skb->data + protoff);
while (optoff < optend) {
unsigned char *op = skb->data + optoff;

View File

@ -1380,7 +1380,8 @@ smc_v2_determine_accepted_chid(struct smc_clc_msg_accept_confirm *aclc,
int i;
for (i = 0; i < ini->ism_offered_cnt + 1; i++) {
if (ini->ism_chid[i] == ntohs(aclc->d1.chid)) {
if (ini->ism_dev[i] &&
ini->ism_chid[i] == ntohs(aclc->d1.chid)) {
ini->ism_selected = i;
return 0;
}

View File

@ -1,3 +1,57 @@
* Wed Aug 19 2026 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [5.14.0-687.41.1.el9_8]
- smb: client: validate DFS referral PathConsumed (CKI Backport Bot) [RHEL-237668] {CVE-2026-68343}
- posix-cpu-timers: Prevent UAF caused by non-leader exec() race (Waiman Long) [RHEL-227844] {CVE-2026-64560}
- posix-cpu-timers: Fix pid refcount leak in do_cpu_nanosleep() error path (Waiman Long) [RHEL-227844] {CVE-2026-64370}
- posix-timers: Retrieve interval in common timer_settime() code (Waiman Long) [RHEL-227844]
- posix-cpu-timers: Simplify posix_cpu_timer_set() (Waiman Long) [RHEL-227844]
- posix-cpu-timers: Remove incorrect comment in posix_cpu_timer_set() (Waiman Long) [RHEL-227844]
- posix-cpu-timers: Use @now instead of @val for clarity (Waiman Long) [RHEL-227844]
- posix-cpu-timers: Do not arm SIGEV_NONE timers (Waiman Long) [RHEL-227844]
- posix-cpu-timers: Replace old expiry retrieval in posix_cpu_timer_set() (Waiman Long) [RHEL-227844]
- posix-cpu-timers: Handle SIGEV_NONE timers correctly in timer_set() (Waiman Long) [RHEL-227844]
- posix-cpu-timers: Handle SIGEV_NONE timers correctly in timer_get() (Waiman Long) [RHEL-227844]
- posix-cpu-timers: Handle interval timers correctly in timer_get() (Waiman Long) [RHEL-227844]
- posix-cpu-timers: Save interval only for armed timers (Waiman Long) [RHEL-227844]
- posix-cpu-timers: Split up posix_cpu_timer_get() (Waiman Long) [RHEL-227844]
- smb/client: handle overlapping allocated ranges in fallocate (CKI Backport Bot) [RHEL-236207] {CVE-2026-68388}
- smb: client: mask server-provided mode to 07777 in modefromsid (CKI Backport Bot) [RHEL-234528] {CVE-2026-64379}
- cgroup/psi: Set of->priv to NULL upon file release (Waiman Long) [RHEL-232554]
- sched/psi: Create the psimon kthread outside of cgroup_mutex (Waiman Long) [RHEL-232554]
- sched/psi: fix race between file release and pressure write (Waiman Long) [RHEL-232554] {CVE-2026-52991}
- smb: client: fix query_info() replay double-free (CKI Backport Bot) [RHEL-234121] {CVE-2026-64386}
- smb: client: fix double-free in SMB2_open() replay (CKI Backport Bot) [RHEL-234107] {CVE-2026-64382}
- mm/huge_memory: update file PMD counter before folio_put() (Luiz Capitulino) [RHEL-231225] {CVE-2026-53189}
- net/smc: reject CHID-0 ACCEPT that matches an empty ism_dev slot (CKI Backport Bot) [RHEL-230090] {CVE-2026-64048}
- ip6_gre: Use cached t->net in ip6erspan_changelink(). (CKI Backport Bot) [RHEL-180144] {CVE-2026-46120}
Resolves: RHEL-180144, RHEL-227844, RHEL-230090, RHEL-231225, RHEL-232554, RHEL-234107, RHEL-234121, RHEL-234528, RHEL-236207, RHEL-237668
* Mon Aug 17 2026 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [5.14.0-687.40.1.el9_8]
- scsi: target: iscsi: Fix CRC overread and double-free in iscsit_handle_text_cmd() (Maurizio Lombardi) [RHEL-213222] {CVE-2026-63888}
- smb: client: fix SMB1 TRANS2 multi-response truncation in SendReceive() (Paulo Alcantara) [RHEL-235811]
- drm/amdgpu: fix amdgpu_hmm_range_get_pages (José Expósito) [RHEL-222614] {CVE-2026-63879}
- drm/amd/display: Use krealloc_array() in dal_vector_reserve() (CKI Backport Bot) [RHEL-222668] {CVE-2026-53329}
- drm/amd/display: Clamp VBIOS HDMI retimer register count to array size (CKI Backport Bot) [RHEL-222683] {CVE-2026-53136}
- drm/amdkfd: Fix buffer overflow in SDMA queue checkpoint/restore on GFX11 (CKI Backport Bot) [RHEL-222703] {CVE-2026-53143}
- drm/amdkfd: Fix watch_id bounds checking in debug address watch v2 (CKI Backport Bot) [RHEL-222718] {CVE-2026-45878}
- drm/i915: Fix potential UAF in TTM object purge (CKI Backport Bot) [RHEL-222742] {CVE-2026-63884}
- drm/i915/gem: Fix phys BO pread/pwrite with offset (CKI Backport Bot) [RHEL-222748] {CVE-2026-53356}
- drm/amd/display: Validate payload length and link_index in dc_process_dmub_aux_transfer_async (CKI Backport Bot) [RHEL-222571] {CVE-2026-64219}
- drm/amdgpu: zero-initialize GART table on allocation (CKI Backport Bot) [RHEL-222647] {CVE-2026-53374}
- drm/amdkfd: Fix out-of-bounds write in kfd_event_page_set() (CKI Backport Bot) [RHEL-221333] {CVE-2026-43206}
- drm/amdgpu: Refactor amdgpu_gem_va_ioctl for Handling Last Fence Update and Timeline Management v7 (CKI Backport Bot) [RHEL-221368] {CVE-2026-43237}
- drm/amdgpu: Refactor amdgpu_gem_va_ioctl for Handling Last Fence Update and Timeline Management v4 (CKI Backport Bot) [RHEL-221368] {CVE-2026-43237}
- wifi: iwlwifi: reduce encryption error message to debug level in FIPS mode (Jose Ignacio Tornos Martinez) [RHEL-181065]
- wifi: iwlwifi: restore FIPS-disabled features with fips exception (Jose Ignacio Tornos Martinez) [RHEL-181065]
- wifi: mac80211: allow keys to driver with fips exception (Jose Ignacio Tornos Martinez) [RHEL-181065]
- crypto: fips: add rh_fips_exception kernel boot parameter and fips_allows() helper (Jose Ignacio Tornos Martinez) [RHEL-181065]
- netfilter: nf_conntrack_h323: fix OOB read in decode_choice() (CKI Backport Bot) [RHEL-230625] {CVE-2026-43233}
- netfilter: synproxy: refresh tcphdr after skb_ensure_writable (CKI Backport Bot) [RHEL-228909] {CVE-2026-64007}
- memfd: deny writeable mappings when implying SEAL_WRITE (Luiz Capitulino) [RHEL-228523] {CVE-2026-63952}
- mm/memfd: fix spelling in memfd_add_seals() (Luiz Capitulino) [RHEL-228523]
- vhost: reset the vring metadata cache on vring reconfiguration (CKI Backport Bot) [RHEL-224549]
- udf: fix partition descriptor append bookkeeping (CKI Backport Bot) [RHEL-179581] {CVE-2026-45991}
Resolves: RHEL-179581, RHEL-181065, RHEL-213222, RHEL-221333, RHEL-221368, RHEL-222571, RHEL-222614, RHEL-222647, RHEL-222668, RHEL-222683, RHEL-222703, RHEL-222718, RHEL-222742, RHEL-222748, RHEL-224549, RHEL-228523, RHEL-228909, RHEL-230625, RHEL-235811
* Wed Aug 12 2026 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [5.14.0-687.39.1.el9_8]
- x86/mm: Add missing saved dirty bit to page protection change mask (Luiz Capitulino) [RHEL-220787]
- net/sched: act_api: use RCU with deferred freeing for action lifecycle (CKI Backport Bot) [RHEL-218181] {CVE-2026-53264}