Re: Linux 6.18.46

From: Greg Kroah-Hartman

Date: Sun Aug 23 2026 - 08:48:53 EST


diff --git a/Makefile b/Makefile
index 7f6474d36c70..3c9141925807 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
VERSION = 6
PATCHLEVEL = 18
-SUBLEVEL = 45
+SUBLEVEL = 46
EXTRAVERSION =
NAME = Baby Opossum Posse

diff --git a/arch/arm64/boot/dts/nvidia/tegra194.dtsi b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
index 1399342f23e1..def60103179f 100644
--- a/arch/arm64/boot/dts/nvidia/tegra194.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
@@ -3177,6 +3177,8 @@ timer {
<GIC_PPI 11
(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
<GIC_PPI 10
+ (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 15
(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
interrupt-parent = <&gic>;
always-on;
diff --git a/arch/m68k/Kconfig.cpu b/arch/m68k/Kconfig.cpu
index c9a7e602d8a4..83f46fd6b97c 100644
--- a/arch/m68k/Kconfig.cpu
+++ b/arch/m68k/Kconfig.cpu
@@ -548,6 +548,10 @@ config CACHE_COPYBACK
endchoice
endif # HAVE_CACHE_CB

+config NR_CPUS
+ int
+ default "1"
+
# Coldfire cores that do not have a data cache configured can do coherent DMA.
config COLDFIRE_COHERENT_DMA
bool
diff --git a/arch/openrisc/include/asm/processor.h b/arch/openrisc/include/asm/processor.h
index 3ff893a67c13..ae43fe79b2b5 100644
--- a/arch/openrisc/include/asm/processor.h
+++ b/arch/openrisc/include/asm/processor.h
@@ -26,6 +26,8 @@
| SPR_SR_DCE | SPR_SR_SM)
#define USER_SR (SPR_SR_DME | SPR_SR_IME | SPR_SR_ICE \
| SPR_SR_DCE | SPR_SR_IEE | SPR_SR_TEE)
+/* SR bits user space may change via sigreturn, the rest stay kernel owned */
+#define SPR_SR_USER_MASK (SPR_SR_F | SPR_SR_CY | SPR_SR_OV)

/*
* User space process size. This is hardcoded into a few places,
diff --git a/arch/openrisc/kernel/signal.c b/arch/openrisc/kernel/signal.c
index f70a13ee0593..2be5af3b9832 100644
--- a/arch/openrisc/kernel/signal.c
+++ b/arch/openrisc/kernel/signal.c
@@ -74,6 +74,7 @@ static long save_fp_state(struct sigcontext __user *sc)
static int restore_sigcontext(struct pt_regs *regs,
struct sigcontext __user *sc)
{
+ unsigned long old_sr = regs->sr;
int err = 0;

/* Always make any pending restarted system calls return -EINTR */
@@ -89,8 +90,8 @@ static int restore_sigcontext(struct pt_regs *regs,
err |= __copy_from_user(&regs->sr, &sc->regs.sr, sizeof(unsigned long));
err |= restore_fp_state(sc);

- /* make sure the SM-bit is cleared so user-mode cannot fool us */
- regs->sr &= ~SPR_SR_SM;
+ /* keep the privileged SR bits kernel owned, restore only user flags */
+ regs->sr = (old_sr & ~SPR_SR_USER_MASK) | (regs->sr & SPR_SR_USER_MASK);

regs->orig_gpr11 = -1; /* Avoid syscall restart checks */

diff --git a/arch/powerpc/platforms/pseries/lparcfg.c b/arch/powerpc/platforms/pseries/lparcfg.c
index cc22924f159f..cc775293d710 100644
--- a/arch/powerpc/platforms/pseries/lparcfg.c
+++ b/arch/powerpc/platforms/pseries/lparcfg.c
@@ -686,7 +686,7 @@ static ssize_t lparcfg_write(struct file *file, const char __user * buf,
if (!firmware_has_feature(FW_FEATURE_SPLPAR))
return -EINVAL;

- if (count > sizeof(kbuf))
+ if (count == 0 || count > sizeof(kbuf))
return -EINVAL;

if (copy_from_user(kbuf, buf, count))
diff --git a/arch/powerpc/platforms/pseries/papr-phy-attest.c b/arch/powerpc/platforms/pseries/papr-phy-attest.c
index 1907f2411567..d661e6f96188 100644
--- a/arch/powerpc/platforms/pseries/papr-phy-attest.c
+++ b/arch/powerpc/platforms/pseries/papr-phy-attest.c
@@ -230,10 +230,17 @@ static long papr_phy_attest_create_handle(struct papr_phy_attest_io_block __user
return -ENOMEM;

if (copy_from_user(&params->cmd, ulc,
- sizeof(struct papr_phy_attest_io_block)))
+ sizeof(struct papr_phy_attest_io_block))) {
+ kfree(params);
return -EFAULT;
+ }

params->cmd_len = be32_to_cpu(params->cmd.length);
+ if (params->cmd_len == 0 || params->cmd_len > sizeof(params->cmd)) {
+ kfree(params);
+ return -EINVAL;
+ }
+
seq = (struct papr_rtas_sequence) {
.begin = phy_attest_sequence_begin,
.end = phy_attest_sequence_end,
@@ -246,6 +253,9 @@ static long papr_phy_attest_create_handle(struct papr_phy_attest_io_block __user
&papr_phy_attest_handle_ops,
"[papr-physical-attestation]");

+ if (fd < 0)
+ kfree(params);
+
return fd;
}

diff --git a/arch/powerpc/platforms/pseries/pci.c b/arch/powerpc/platforms/pseries/pci.c
index 6dbc73eb2ca2..82dc1ad52ac9 100644
--- a/arch/powerpc/platforms/pseries/pci.c
+++ b/arch/powerpc/platforms/pseries/pci.c
@@ -132,7 +132,7 @@ static int pseries_pci_sriov_enable(struct pci_dev *pdev, u16 num_vfs)

/* First integer stores max config */
max_config_vfs = of_read_number(&max_vfs[0], 1);
- if (max_config_vfs < num_vfs && num_vfs > MAX_VFS_FOR_MAP_PE) {
+ if (max_config_vfs < num_vfs || num_vfs > MAX_VFS_FOR_MAP_PE) {
dev_err(&pdev->dev,
"Num VFs %x > %x Configurable VFs\n",
num_vfs, (num_vfs > MAX_VFS_FOR_MAP_PE) ?
diff --git a/arch/riscv/kernel/ftrace.c b/arch/riscv/kernel/ftrace.c
index 8d18d6727f0f..c201c6bac1dd 100644
--- a/arch/riscv/kernel/ftrace.c
+++ b/arch/riscv/kernel/ftrace.c
@@ -12,6 +12,7 @@
#include <linux/stop_machine.h>
#include <asm/cacheflush.h>
#include <asm/text-patching.h>
+#include <asm/insn.h>

#ifdef CONFIG_DYNAMIC_FTRACE
void ftrace_arch_code_modify_prepare(void)
@@ -63,7 +64,9 @@ static int __ftrace_modify_call(unsigned long source, unsigned long target, bool
if (copy_from_kernel_nofault(replaced, (void *)source, 2 * MCOUNT_INSN_SIZE))
return -EFAULT;

- if (replaced[0] != call[0]) {
+ /* Bypass the check if the auipc insn is a kprobe breakpoint */
+ if (replaced[0] != call[0] &&
+ !(riscv_insn_is_ebreak(replaced[0]) || riscv_insn_is_c_ebreak(replaced[0]))) {
pr_err("%p: expected (%08x) but got (%08x)\n",
(void *)source, call[0], replaced[0]);
return -EINVAL;
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index f2708419f787..f0707f0e1ec0 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -13320,12 +13320,18 @@ void kvm_arch_pre_destroy_vm(struct kvm *kvm)
* iterating over vCPUs in a different task while vCPUs are being freed
* is unsafe, i.e. will lead to use-after-free. The PIT also needs to
* be stopped before IRQ routing is freed.
+ *
+ * Do NOT free the in-kernel PIC or I/O APIC here (but as above, make
+ * sure to flush any background work), as KVM expects interrupt routing
+ * structures to be valid until vCPUs are destroyed.
*/
cancel_delayed_work_sync(&kvm->arch.kvmclock_sync_work);
cancel_delayed_work_sync(&kvm->arch.kvmclock_update_work);

#ifdef CONFIG_KVM_IOAPIC
kvm_free_pit(kvm);
+ if (kvm->arch.vioapic)
+ cancel_delayed_work_sync(&kvm->arch.vioapic->eoi_inject);
#endif

kvm_mmu_pre_destroy_vm(kvm);
diff --git a/block/genhd.c b/block/genhd.c
index d23cb33ea127..b00fa6baf4ff 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -1281,14 +1281,18 @@ static void disk_release(struct device *dev)
/*
* To undo the all initialization from blk_mq_init_allocated_queue in
* case of a probe failure where add_disk is never called we have to
- * call blk_mq_exit_queue here. We can't do this for the more common
- * teardown case (yet) as the tagset can be gone by the time the disk
- * is released once it was added.
+ * call blk_mq_exit_queue here, after stopping the timer and work items
+ * that I/O issued before add_disk may have left pending. We can't do
+ * this for the more common teardown case (yet) as the tagset can be
+ * gone by the time the disk is released once it was added.
*/
if (queue_is_mq(disk->queue) &&
test_bit(GD_OWNS_QUEUE, &disk->state) &&
- !test_bit(GD_ADDED, &disk->state))
+ !test_bit(GD_ADDED, &disk->state)) {
+ blk_sync_queue(disk->queue);
+ blk_mq_cancel_work_sync(disk->queue);
blk_mq_exit_queue(disk->queue);
+ }

blkcg_exit_disk(disk);

diff --git a/crypto/ccm.c b/crypto/ccm.c
index 2ae929ffdef8..916441e4f2b8 100644
--- a/crypto/ccm.c
+++ b/crypto/ccm.c
@@ -747,7 +747,7 @@ static int crypto_rfc4309_create(struct crypto_template *tmpl,

inst->alg.ivsize = 8;
inst->alg.chunksize = crypto_aead_alg_chunksize(alg);
- inst->alg.maxauthsize = 16;
+ inst->alg.maxauthsize = crypto_aead_alg_maxauthsize(alg);

inst->alg.base.cra_ctxsize = sizeof(struct crypto_rfc4309_ctx);

diff --git a/drivers/accel/amdxdna/aie2_ctx.c b/drivers/accel/amdxdna/aie2_ctx.c
index 612ad6302622..9ec3d90c2d20 100644
--- a/drivers/accel/amdxdna/aie2_ctx.c
+++ b/drivers/accel/amdxdna/aie2_ctx.c
@@ -794,6 +794,16 @@ static int aie2_populate_range(struct amdxdna_gem_obj *abo)
found = false;
down_write(&xdna->notifier_lock);
list_for_each_entry(mapp, &abo->mem.umap_list, node) {
+ /*
+ * Skip entries that have already been unmapped.
+ *
+ * If userspace unmaps the address and later submits I/O using
+ * it, the IOMMU will reject the access and report a fault.
+ * Ignore such entries here.
+ */
+ if (mapp->unmapped)
+ continue;
+
if (mapp->invalid && kref_get_unless_zero(&mapp->refcnt)) {
found = true;
break;
@@ -801,6 +811,12 @@ static int aie2_populate_range(struct amdxdna_gem_obj *abo)
}

if (!found) {
+ /*
+ * This also covers the case where all mappings have been
+ * removed. There are no invalid mappings left to process.
+ * Any subsequent I/O using the unmapped address will be
+ * rejected by the IOMMU.
+ */
abo->mem.map_invalid = false;
up_write(&xdna->notifier_lock);
return 0;
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 44daae8f378a..f21efb0f6419 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -648,29 +648,12 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap,
set_host_byte(scmd, DID_OK);

ata_qc_for_each_raw(ap, qc, i) {
- if (qc->scsicmd != scmd)
- continue;
- if ((qc->flags & ATA_QCFLAG_ACTIVE) ||
- qc == qc->dev->link->deferred_qc)
+ if (qc->scsicmd == scmd &&
+ qc->flags & ATA_QCFLAG_ACTIVE)
break;
}

- if (i < ATA_MAX_QUEUE && qc == qc->dev->link->deferred_qc) {
- /*
- * This is a deferred command that timed out while
- * waiting for the command queue to drain. Since the qc
- * is not active yet (deferred_qc is still set, so the
- * deferred qc work has not issued the command yet),
- * simply signal the timeout by finishing the SCSI
- * command and clear the deferred qc to prevent the
- * deferred qc work from issuing this qc.
- */
- WARN_ON_ONCE(qc->flags & ATA_QCFLAG_ACTIVE);
- qc->dev->link->deferred_qc = NULL;
- cancel_work(&qc->dev->link->deferred_qc_work);
- set_host_byte(scmd, DID_TIME_OUT);
- scsi_eh_finish_cmd(scmd, &ap->eh_done_q);
- } else if (i < ATA_MAX_QUEUE) {
+ if (i < ATA_MAX_QUEUE) {
/* the scmd has an associated qc */
if (!(qc->flags & ATA_QCFLAG_EH)) {
/* which hasn't failed yet, timeout */
@@ -944,10 +927,10 @@ static void ata_eh_set_pending(struct ata_port *ap, bool fastdrain)
ap->pflags |= ATA_PFLAG_EH_PENDING;

/*
- * If we have a deferred qc, requeue it so that it is retried once EH
- * completes.
+ * If we have deferred QCs, requeue them so that the SCSI EH task can
+ * run.
*/
- ata_scsi_requeue_deferred_qc(ap);
+ ata_scsi_requeue_deferred_qc(ap, NULL);

if (!fastdrain)
return;
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index a7916b50cbfc..55299f28b123 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -1680,30 +1680,81 @@ void ata_scsi_deferred_qc_work(struct work_struct *work)
spin_unlock_irqrestore(ap->lock, flags);
}

-void ata_scsi_requeue_deferred_qc(struct ata_port *ap)
+enum scsi_timeout_action ata_scsi_requeue_deferred_qc(struct ata_port *ap,
+ struct scsi_cmnd *timedout_scmd)
{
+ enum scsi_timeout_action action = SCSI_EH_NOT_HANDLED;
+ struct ata_queued_cmd *qc;
struct ata_link *link;
+ u32 host_byte;

lockdep_assert_held(ap->lock);

/*
- * If we have a deferred qc when a reset occurs or NCQ commands fail,
- * do not try to be smart about what to do with this deferred command
- * and simply requeue it by completing it with DID_REQUEUE.
+ * If we have deferred QCs when a reset, a timeout or an NCQ command
+ * fails, do not try to be smart about what to do with the deferred
+ * commands and simply terminate them and let the SCSI layer decide
+ * what to do.
*/
ata_for_each_link(link, ap, PMP_FIRST) {
- struct ata_queued_cmd *qc = link->deferred_qc;
- struct scsi_cmnd *scmd;
-
- if (qc) {
- scmd = qc->scsicmd;
- link->deferred_qc = NULL;
- cancel_work(&link->deferred_qc_work);
- ata_qc_free(qc);
- scmd->result = (DID_REQUEUE << 16);
- scsi_done(scmd);
+ qc = link->deferred_qc;
+ if (!qc)
+ continue;
+
+ /*
+ * Clear the deferred QC so that the deferred work does not try
+ * to issue it.
+ */
+ link->deferred_qc = NULL;
+ cancel_work(&link->deferred_qc_work);
+
+ /*
+ * We are going to complete some scsi command, either with
+ * DID_TIME_OUT if the command timed out while waiting for being
+ * issued, or with DID_REQUEUE if another command timed out or
+ * we had a failed command. However, the block layer may re-issue
+ * these commands immediately, keeping the scsi host busy and
+ * thus preventing the SCSI EH task from running.
+ * So schedule EH on the port to prevent accepting new commands
+ * until everything is sorted out with the error or timeout that
+ * got us here in the first place. Note that we set EH pending
+ * on the port before calling ata_port_schedule_eh() so that we
+ * do not reenter this function from ata_eh_set_pending() with
+ * timedout_scmd being NULL and erroneously retry deferred QCs
+ * that have timed out on other links.
+ */
+ if (!ata_port_eh_scheduled(ap)) {
+ ap->pflags |= ATA_PFLAG_EH_PENDING;
+ ata_port_schedule_eh(ap);
}
+
+ /*
+ * If we are being called from scsi_timeout(), then we have a
+ * non-NULL timedout_scmd. If the timed out command is for a
+ * deferred QC, terminate that deferred QC with DID_TIME_OUT and
+ * requeue all other deferred QCs. In this case we need to
+ * return SCSI_EH_DONE, because the timed out command was
+ * handled.
+ * If the timed out command is not for a deferred QC, we need to
+ * requeue all deferred QCs, and return SCSI_EH_NOT_HANDLED so
+ * that the timed out command gets added to the EH work queue
+ * with scsi_eh_scmd_add(), for later handling with libata EH
+ * ata_scsi_cmd_error_handler().
+ * If timedout_scmd is NULL, we simply need to requeue all
+ * deferred QCs and the return value does not matter as we were
+ * not called from scsi_timeout().
+ */
+ if (timedout_scmd && qc->scsicmd == timedout_scmd) {
+ host_byte = DID_TIME_OUT;
+ action = SCSI_EH_DONE;
+ } else {
+ host_byte = DID_REQUEUE;
+ }
+ qc->scsicmd->result = host_byte << 16;
+ ata_qc_done(qc);
}
+
+ return action;
}

static void ata_scsi_schedule_deferred_qc(struct ata_link *link)
@@ -1722,13 +1773,41 @@ static void ata_scsi_schedule_deferred_qc(struct ata_link *link)
return;

if (ata_port_eh_scheduled(ap)) {
- ata_scsi_requeue_deferred_qc(ap);
+ ata_scsi_requeue_deferred_qc(ap, NULL);
return;
}
if (!ap->ops->qc_defer(qc))
queue_work(system_highpri_wq, &link->deferred_qc_work);
}

+static enum scsi_timeout_action
+ata_scsi_retry_deferred_qc(struct ata_port *ap, struct scsi_cmnd *scmd)
+{
+ enum scsi_timeout_action action;
+ unsigned long flags;
+
+ spin_lock_irqsave(ap->lock, flags);
+ action = ata_scsi_requeue_deferred_qc(ap, scmd);
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ return action;
+}
+
+enum scsi_timeout_action ata_scsi_eh_timed_out(struct scsi_cmnd *scmd)
+{
+ struct ata_port *ap = ata_shost_to_port(scmd->device->host);
+
+ /*
+ * ata_scsi_cmd_error_handler() takes care of commands that timed out
+ * while executing. However, if we have deferred QCs while a timeout
+ * triggers, we must requeue these commands for retry so that we do not
+ * unnecessarily delay starting the SCSI EH task until these deferred
+ * commands also time out.
+ */
+ return ata_scsi_retry_deferred_qc(ap, scmd);
+}
+EXPORT_SYMBOL_GPL(ata_scsi_eh_timed_out);
+
static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
{
struct ata_link *link = qc->dev->link;
@@ -2933,7 +3012,13 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc)
if (qc->cdb[0] == ALLOW_MEDIUM_REMOVAL && qc->dev->sdev)
qc->dev->sdev->locked = 0;

- qc->scsicmd->result = SAM_STAT_CHECK_CONDITION;
+ if (!cmd->result)
+ cmd->result = SAM_STAT_CHECK_CONDITION;
+ ata_qc_done(qc);
+ return;
+ }
+
+ if (cmd->result) {
ata_qc_done(qc);
return;
}
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 56c4136b7417..9f96ca2acfd9 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -172,7 +172,8 @@ int ata_scsi_dev_config(struct scsi_device *sdev, struct queue_limits *lim,
struct ata_device *dev);
int __ata_scsi_queuecmd(struct scsi_cmnd *scmd, struct ata_device *dev);
void ata_scsi_deferred_qc_work(struct work_struct *work);
-void ata_scsi_requeue_deferred_qc(struct ata_port *ap);
+enum scsi_timeout_action ata_scsi_requeue_deferred_qc(struct ata_port *ap,
+ struct scsi_cmnd *scmd);

/* libata-eh.c */
extern unsigned int ata_internal_cmd_timeout(struct ata_device *dev, u8 cmd);
diff --git a/drivers/base/regmap/regmap-sdw-mbq.c b/drivers/base/regmap/regmap-sdw-mbq.c
index 86644bbd0710..fe1a8c442034 100644
--- a/drivers/base/regmap/regmap-sdw-mbq.c
+++ b/drivers/base/regmap/regmap-sdw-mbq.c
@@ -54,10 +54,10 @@ static int regmap_sdw_mbq_poll_busy(struct sdw_slave *slave, unsigned int reg,
reg = SDW_SDCA_CTL(SDW_SDCA_CTL_FUNC(reg), 0,
SDCA_CTL_ENTITY_0_FUNCTION_STATUS, 0);

- if (ctx->readable_reg(dev, reg)) {
+ if (!ctx->readable_reg || ctx->readable_reg(dev, reg)) {
ret = read_poll_timeout(sdw_read_no_pm, val,
val < 0 || !(val & SDCA_CTL_ENTITY_0_FUNCTION_BUSY),
- ctx->cfg.timeout_us, ctx->cfg.retry_us,
+ ctx->cfg.retry_us, ctx->cfg.timeout_us,
false, slave, reg);
if (val < 0)
return val;
diff --git a/drivers/crypto/qce/core.c b/drivers/crypto/qce/core.c
index e95e84486d9a..f5bccb345374 100644
--- a/drivers/crypto/qce/core.c
+++ b/drivers/crypto/qce/core.c
@@ -60,7 +60,7 @@ static int devm_qce_register_algs(struct qce_device *qce)
ret = ops->register_algs(qce);
if (ret) {
for (j = i - 1; j >= 0; j--)
- ops->unregister_algs(qce);
+ qce_ops[j]->unregister_algs(qce);
return ret;
}
}
diff --git a/drivers/crypto/starfive/jh7110-aes.c b/drivers/crypto/starfive/jh7110-aes.c
index 01195664cc7c..8e02275a7079 100644
--- a/drivers/crypto/starfive/jh7110-aes.c
+++ b/drivers/crypto/starfive/jh7110-aes.c
@@ -677,7 +677,7 @@ static int starfive_aes_aead_do_one_req(struct crypto_engine *engine, void *areq

if (cryp->total_in)
sg_zero_buffer(rctx->in_sg, sg_nents(rctx->in_sg),
- sg_dma_len(rctx->in_sg) - cryp->total_in,
+ rctx->in_sg->length - cryp->total_in,
cryp->total_in);

ctx->rctx = rctx;
diff --git a/drivers/crypto/tegra/tegra-se-aes.c b/drivers/crypto/tegra/tegra-se-aes.c
index 9094c03e991f..0fd1d7035899 100644
--- a/drivers/crypto/tegra/tegra-se-aes.c
+++ b/drivers/crypto/tegra/tegra-se-aes.c
@@ -45,7 +45,6 @@ struct tegra_aes_reqctx {

struct tegra_aead_ctx {
struct tegra_se *se;
- unsigned int authsize;
u32 alg;
u32 key_id;
u32 keylen;
@@ -1290,7 +1289,7 @@ static int tegra_gcm_do_one_req(struct crypto_engine *engine, void *areq)
if (rctx->encrypt)
rctx->cryptlen = req->cryptlen;
else
- rctx->cryptlen = req->cryptlen - ctx->authsize;
+ rctx->cryptlen = req->cryptlen - rctx->authsize;

memcpy(rctx->iv, req->iv, GCM_AES_IV_SIZE);
rctx->iv[3] = (1 << 24);
@@ -1394,8 +1393,6 @@ static int tegra_aead_cra_init(struct crypto_aead *tfm)

static int tegra_ccm_setauthsize(struct crypto_aead *tfm, unsigned int authsize)
{
- struct tegra_aead_ctx *ctx = crypto_aead_ctx(tfm);
-
switch (authsize) {
case 4:
case 6:
@@ -1404,28 +1401,15 @@ static int tegra_ccm_setauthsize(struct crypto_aead *tfm, unsigned int authsize
case 12:
case 14:
case 16:
- break;
+ return 0;
default:
return -EINVAL;
}
-
- ctx->authsize = authsize;
-
- return 0;
}

static int tegra_gcm_setauthsize(struct crypto_aead *tfm, unsigned int authsize)
{
- struct tegra_aead_ctx *ctx = crypto_aead_ctx(tfm);
- int ret;
-
- ret = crypto_gcm_check_authsize(authsize);
- if (ret)
- return ret;
-
- ctx->authsize = authsize;
-
- return 0;
+ return crypto_gcm_check_authsize(authsize);
}

static void tegra_aead_cra_exit(struct crypto_aead *tfm)
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index 030aed5453a1..a72b0dad6c3f 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -538,19 +538,25 @@ static void ar_context_link_page(struct ar_context *ctx, unsigned int index)

static void ar_context_release(struct ar_context *ctx)
{
- struct device *dev = ctx->ohci->card.device;
- unsigned int i;
+ struct device *dev;

if (!ctx->buffer)
return;

- vunmap(ctx->buffer);
+ dev = ctx->ohci->card.device;

- for (i = 0; i < AR_BUFFERS; i++) {
- if (ctx->pages[i])
- dma_free_pages(dev, PAGE_SIZE, ctx->pages[i],
- ar_buffer_bus(ctx, i), DMA_FROM_DEVICE);
+ for (int i = 0; i < AR_BUFFERS; ++i) {
+ dma_addr_t dma_addr = page_private(ctx->pages[i]);
+
+ dma_unmap_page(dev, dma_addr, PAGE_SIZE, DMA_FROM_DEVICE);
+ set_page_private(ctx->pages[i], 0);
}
+
+ vunmap(ctx->buffer);
+ ctx->buffer = NULL;
+
+ release_pages(ctx->pages, AR_BUFFERS);
+ memset(ctx->pages, 0, sizeof(ctx->pages));
}

static void ar_context_abort(struct ar_context *ctx, const char *error_msg)
@@ -845,31 +851,57 @@ static int ar_context_init(struct ar_context *ctx, struct fw_ohci *ohci,
{
struct device *dev = ohci->card.device;
unsigned int i;
- dma_addr_t dma_addr;
- struct page *pages[AR_BUFFERS + AR_WRAPAROUND_PAGES];
+ struct page *pages[AR_BUFFERS + AR_WRAPAROUND_PAGES] = { NULL };
+ void *vaddr;
struct descriptor *d;

ctx->regs = regs;
ctx->ohci = ohci;
INIT_WORK(&ctx->work, ohci_ar_context_work);

- for (i = 0; i < AR_BUFFERS; i++) {
- ctx->pages[i] = dma_alloc_pages(dev, PAGE_SIZE, &dma_addr,
- DMA_FROM_DEVICE, GFP_KERNEL);
- if (!ctx->pages[i])
- goto out_of_memory;
- set_page_private(ctx->pages[i], dma_addr);
- dma_sync_single_for_device(dev, dma_addr, PAGE_SIZE,
- DMA_FROM_DEVICE);
+ // Retrieve noncontiguous pages. The descriptors for 1394 OHCI AR DMA contexts have a set
+ // of address and length per each. The reason to use pages is to construct contiguous
+ // address range in kernel virtual address space.
+ unsigned long nr_populated = alloc_pages_bulk(GFP_KERNEL | GFP_DMA32, AR_BUFFERS, pages);
+
+ if (nr_populated != AR_BUFFERS) {
+ release_pages(pages, nr_populated);
+ return -ENOMEM;
}

- for (i = 0; i < AR_BUFFERS; i++)
- pages[i] = ctx->pages[i];
+ // Map the pages into contiguous kernel virtual addresses so that the packet data
+ // across the pages can be referred as being contiguous, especially across the last
+ // and first pages.
for (i = 0; i < AR_WRAPAROUND_PAGES; i++)
- pages[AR_BUFFERS + i] = ctx->pages[i];
- ctx->buffer = vmap(pages, ARRAY_SIZE(pages), VM_MAP, PAGE_KERNEL);
- if (!ctx->buffer)
- goto out_of_memory;
+ pages[AR_BUFFERS + i] = pages[i];
+ vaddr = vmap(pages, ARRAY_SIZE(pages), VM_MAP, PAGE_KERNEL);
+ if (!vaddr) {
+ release_pages(pages, nr_populated);
+ return -ENOMEM;
+ }
+
+ // Retrieve DMA mapping addresses for the pages. They are not contiguous. Maintain the cache
+ // coherency for the pages by hand.
+ for (i = 0; i < AR_BUFFERS; i++) {
+ // The dma_map_phys() with a physical address per page is available here, instead.
+ dma_addr_t dma_addr = dma_map_page(dev, pages[i], 0, PAGE_SIZE, DMA_FROM_DEVICE);
+ if (dma_mapping_error(dev, dma_addr))
+ break;
+ set_page_private(pages[i], dma_addr);
+ dma_sync_single_for_device(dev, dma_addr, PAGE_SIZE, DMA_FROM_DEVICE);
+ }
+ if (i < AR_BUFFERS) {
+ while (i-- > 0) {
+ dma_addr_t dma_addr = page_private(pages[i]);
+ dma_unmap_page(dev, dma_addr, PAGE_SIZE, DMA_FROM_DEVICE);
+ }
+ vunmap(vaddr);
+ release_pages(pages, nr_populated);
+ return -ENOMEM;
+ }
+
+ ctx->buffer = vaddr;
+ memcpy(ctx->pages, pages, sizeof(ctx->pages));

ctx->descriptors = ohci->misc_buffer + descriptors_offset;
ctx->descriptors_bus = ohci->misc_buffer_bus + descriptors_offset;
@@ -886,11 +918,6 @@ static int ar_context_init(struct ar_context *ctx, struct fw_ohci *ohci,
}

return 0;
-
-out_of_memory:
- ar_context_release(ctx);
-
- return -ENOMEM;
}

static void ar_context_run(struct ar_context *ctx)
diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c
index f6af81bf2b13..031ddf29539c 100644
--- a/drivers/gpio/gpio-ml-ioh.c
+++ b/drivers/gpio/gpio-ml-ioh.c
@@ -73,7 +73,7 @@ struct ioh_gpio_reg_data {
* @gpio_use_sel: Save GPIO_USE_SEL1~4 register for PM
* @ch: Indicate GPIO channel
* @irq_base: Save base of IRQ number for interrupt
- * @spinlock: Used for register access protection
+ * @spinlock: Shared register access lock
*/
struct ioh_gpio {
void __iomem *base;
@@ -84,7 +84,12 @@ struct ioh_gpio {
u32 gpio_use_sel;
int ch;
int irq_base;
- spinlock_t spinlock;
+ raw_spinlock_t *spinlock;
+};
+
+struct ioh_gpio_device {
+ raw_spinlock_t spinlock;
+ struct ioh_gpio chip[8];
};

static const int num_ports[] = {6, 12, 16, 16, 15, 16, 16, 12};
@@ -95,7 +100,7 @@ static int ioh_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
struct ioh_gpio *chip = gpiochip_get_data(gpio);
unsigned long flags;

- spin_lock_irqsave(&chip->spinlock, flags);
+ raw_spin_lock_irqsave(chip->spinlock, flags);
reg_val = ioread32(&chip->reg->regs[chip->ch].po);
if (val)
reg_val |= BIT(nr);
@@ -103,7 +108,7 @@ static int ioh_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val)
reg_val &= ~BIT(nr);

iowrite32(reg_val, &chip->reg->regs[chip->ch].po);
- spin_unlock_irqrestore(&chip->spinlock, flags);
+ raw_spin_unlock_irqrestore(chip->spinlock, flags);

return 0;
}
@@ -123,7 +128,7 @@ static int ioh_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
u32 reg_val;
unsigned long flags;

- spin_lock_irqsave(&chip->spinlock, flags);
+ raw_spin_lock_irqsave(chip->spinlock, flags);
pm = ioread32(&chip->reg->regs[chip->ch].pm);
pm &= BIT(num_ports[chip->ch]) - 1;
pm |= BIT(nr);
@@ -136,7 +141,7 @@ static int ioh_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
reg_val &= ~BIT(nr);
iowrite32(reg_val, &chip->reg->regs[chip->ch].po);

- spin_unlock_irqrestore(&chip->spinlock, flags);
+ raw_spin_unlock_irqrestore(chip->spinlock, flags);

return 0;
}
@@ -147,12 +152,12 @@ static int ioh_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
u32 pm;
unsigned long flags;

- spin_lock_irqsave(&chip->spinlock, flags);
+ raw_spin_lock_irqsave(chip->spinlock, flags);
pm = ioread32(&chip->reg->regs[chip->ch].pm);
pm &= BIT(num_ports[chip->ch]) - 1;
pm &= ~BIT(nr);
iowrite32(pm, &chip->reg->regs[chip->ch].pm);
- spin_unlock_irqrestore(&chip->spinlock, flags);
+ raw_spin_unlock_irqrestore(chip->spinlock, flags);

return 0;
}
@@ -256,7 +261,7 @@ static int ioh_irq_type(struct irq_data *d, unsigned int type)
dev_dbg(chip->dev, "%s:irq=%d type=%d ch=%d pos=%d type=%d\n",
__func__, irq, type, ch, im_pos, type);

- spin_lock_irqsave(&chip->spinlock, flags);
+ raw_spin_lock_irqsave(chip->spinlock, flags);

switch (type) {
case IRQ_TYPE_EDGE_RISING:
@@ -296,7 +301,7 @@ static int ioh_irq_type(struct irq_data *d, unsigned int type)
ien = ioread32(&chip->reg->regs[chip->ch].ien);
iowrite32(ien | BIT(ch), &chip->reg->regs[chip->ch].ien);
end:
- spin_unlock_irqrestore(&chip->spinlock, flags);
+ raw_spin_unlock_irqrestore(chip->spinlock, flags);

return 0;
}
@@ -326,11 +331,11 @@ static void ioh_irq_disable(struct irq_data *d)
unsigned long flags;
u32 ien;

- spin_lock_irqsave(&chip->spinlock, flags);
+ raw_spin_lock_irqsave(chip->spinlock, flags);
ien = ioread32(&chip->reg->regs[chip->ch].ien);
ien &= ~BIT(d->irq - chip->irq_base);
iowrite32(ien, &chip->reg->regs[chip->ch].ien);
- spin_unlock_irqrestore(&chip->spinlock, flags);
+ raw_spin_unlock_irqrestore(chip->spinlock, flags);
}

static void ioh_irq_enable(struct irq_data *d)
@@ -340,11 +345,11 @@ static void ioh_irq_enable(struct irq_data *d)
unsigned long flags;
u32 ien;

- spin_lock_irqsave(&chip->spinlock, flags);
+ raw_spin_lock_irqsave(chip->spinlock, flags);
ien = ioread32(&chip->reg->regs[chip->ch].ien);
ien |= BIT(d->irq - chip->irq_base);
iowrite32(ien, &chip->reg->regs[chip->ch].ien);
- spin_unlock_irqrestore(&chip->spinlock, flags);
+ raw_spin_unlock_irqrestore(chip->spinlock, flags);
}

static irqreturn_t ioh_gpio_handler(int irq, void *dev_id)
@@ -407,8 +412,8 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
int ret;
int i, j;
struct ioh_gpio *chip;
+ struct ioh_gpio_device *priv;
void __iomem *base;
- void *chip_save;
int irq_base;

ret = pcim_enable_device(pdev);
@@ -429,18 +434,18 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
return -ENOMEM;
}

- chip_save = devm_kcalloc(dev, 8, sizeof(*chip), GFP_KERNEL);
- if (chip_save == NULL) {
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
return -ENOMEM;
- }

- chip = chip_save;
+ raw_spin_lock_init(&priv->spinlock);
+ chip = priv->chip;
for (i = 0; i < 8; i++, chip++) {
chip->dev = dev;
chip->base = base;
chip->reg = chip->base;
chip->ch = i;
- spin_lock_init(&chip->spinlock);
+ chip->spinlock = &priv->spinlock;
ioh_gpio_setup(chip, num_ports[i]);
ret = devm_gpiochip_add_data(dev, &chip->gpio, chip);
if (ret) {
@@ -449,7 +454,7 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
}
}

- chip = chip_save;
+ chip = priv->chip;
for (j = 0; j < 8; j++, chip++) {
irq_base = devm_irq_alloc_descs(dev, -1, IOH_IRQ_BASE,
num_ports[j], NUMA_NO_NODE);
@@ -466,7 +471,7 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
return ret;
}

- chip = chip_save;
+ chip = priv->chip;
ret = devm_request_irq(dev, pdev->irq, ioh_gpio_handler,
IRQF_SHARED, KBUILD_MODNAME, chip);
if (ret != 0) {
@@ -474,33 +479,33 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
return ret;
}

- pci_set_drvdata(pdev, chip);
+ pci_set_drvdata(pdev, priv);

return 0;
}

static int __maybe_unused ioh_gpio_suspend(struct device *dev)
{
- struct ioh_gpio *chip = dev_get_drvdata(dev);
+ struct ioh_gpio_device *priv = dev_get_drvdata(dev);
unsigned long flags;

- spin_lock_irqsave(&chip->spinlock, flags);
- ioh_gpio_save_reg_conf(chip);
- spin_unlock_irqrestore(&chip->spinlock, flags);
+ raw_spin_lock_irqsave(&priv->spinlock, flags);
+ ioh_gpio_save_reg_conf(priv->chip);
+ raw_spin_unlock_irqrestore(&priv->spinlock, flags);

return 0;
}

static int __maybe_unused ioh_gpio_resume(struct device *dev)
{
- struct ioh_gpio *chip = dev_get_drvdata(dev);
+ struct ioh_gpio_device *priv = dev_get_drvdata(dev);
unsigned long flags;

- spin_lock_irqsave(&chip->spinlock, flags);
- iowrite32(0x01, &chip->reg->srst);
- iowrite32(0x00, &chip->reg->srst);
- ioh_gpio_restore_reg_conf(chip);
- spin_unlock_irqrestore(&chip->spinlock, flags);
+ raw_spin_lock_irqsave(&priv->spinlock, flags);
+ iowrite32(0x01, &priv->chip->reg->srst);
+ iowrite32(0x00, &priv->chip->reg->srst);
+ ioh_gpio_restore_reg_conf(priv->chip);
+ raw_spin_unlock_irqrestore(&priv->spinlock, flags);

return 0;
}
diff --git a/drivers/gpio/gpio-sloppy-logic-analyzer.c b/drivers/gpio/gpio-sloppy-logic-analyzer.c
index 0f4a6228a748..3b6825b0f2f9 100644
--- a/drivers/gpio/gpio-sloppy-logic-analyzer.c
+++ b/drivers/gpio/gpio-sloppy-logic-analyzer.c
@@ -301,7 +301,7 @@ static int gpio_la_poll_probe(struct platform_device *pdev)
debugfs_create_ulong("delay_ns_acquisition", 0400, priv->debug_dir, &priv->acq_delay);
debugfs_create_file_unsafe("buf_size", 0600, priv->debug_dir, priv, &fops_buf_size);
debugfs_create_file_unsafe("capture", 0200, priv->debug_dir, priv, &fops_capture);
- debugfs_create_file_unsafe("trigger", 0200, priv->debug_dir, priv, &fops_trigger);
+ debugfs_create_file("trigger", 0200, priv->debug_dir, priv, &fops_trigger);

return 0;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
index 752b34cffdc5..38ce4d7c86f0 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
@@ -42,6 +42,26 @@
#include "amdgpu_gem.h"
#include "amdgpu_ras.h"

+/*
+ * Maximum IB length (dwords) for rings whose emit_ib packet format
+ * documents a 20-bit size field.
+ */
+#define AMDGPU_GFX_SDMA_IB_PACKET_SIZE_MAX_DW 0xFFFFF
+#define AMDGPU_MM_IB_PACKET_SIZE_MAX_DW 0x7FFFF0
+
+static u32 amdgpu_cs_ib_packet_size_max_dw(enum amdgpu_ring_type type)
+{
+ switch (type) {
+ case AMDGPU_RING_TYPE_GFX:
+ case AMDGPU_RING_TYPE_COMPUTE:
+ case AMDGPU_RING_TYPE_SDMA:
+ case AMDGPU_RING_TYPE_VPE:
+ return AMDGPU_GFX_SDMA_IB_PACKET_SIZE_MAX_DW;
+ default:
+ return AMDGPU_MM_IB_PACKET_SIZE_MAX_DW;
+ }
+}
+
static int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p,
struct amdgpu_device *adev,
struct drm_file *filp,
@@ -241,6 +261,10 @@ static int amdgpu_cs_pass1(struct amdgpu_cs_parser *p,
if (size < sizeof(struct drm_amdgpu_cs_chunk_fence))
goto free_partial_kdata;

+ /* Only a single user fence is allowed to simplify handling. */
+ if (p->uf_bo)
+ goto free_partial_kdata;
+
ret = amdgpu_cs_p1_user_fence(p, p->chunks[i].kdata,
&uf_offset);
if (ret)
@@ -358,7 +382,6 @@ static int amdgpu_cs_p2_ib(struct amdgpu_cs_parser *p,

job = p->jobs[r];
ring = amdgpu_job_ring(job);
- ib = &job->ibs[job->num_ibs++];

/* submissions to kernel queues are disabled */
if (ring->no_user_submission)
@@ -387,6 +410,12 @@ static int amdgpu_cs_p2_ib(struct amdgpu_cs_parser *p,
return -EINVAL;
}

+ if (chunk_ib->ib_bytes / 4 >
+ amdgpu_cs_ib_packet_size_max_dw(ring->funcs->type))
+ return -EINVAL;
+
+ ib = &job->ibs[job->num_ibs++];
+
if (chunk_ib->flags & AMDGPU_IB_FLAG_PREAMBLE)
job->preamble_status |= AMDGPU_PREAMBLE_IB_PRESENT;

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index c3e9b916f08f..d35efc7fd80e 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -1928,6 +1928,31 @@ static bool amdgpu_device_aspm_support_quirk(struct amdgpu_device *adev)
#endif
}

+/*
+ * Some dGPUs expose their display endpoint below an internal PCIe switch.
+ * Use the switch upstream port to query the host-facing link.
+ */
+static struct pci_dev *amdgpu_device_get_aspm_pdev(struct amdgpu_device *adev)
+{
+ struct pci_dev *swds, *swus;
+
+ swds = pci_upstream_bridge(adev->pdev);
+ if (!swds ||
+ (swds->vendor != PCI_VENDOR_ID_ATI &&
+ swds->vendor != PCI_VENDOR_ID_AMD) ||
+ pci_pcie_type(swds) != PCI_EXP_TYPE_DOWNSTREAM)
+ return adev->pdev;
+
+ swus = pci_upstream_bridge(swds);
+ if (!swus ||
+ (swus->vendor != PCI_VENDOR_ID_ATI &&
+ swus->vendor != PCI_VENDOR_ID_AMD) ||
+ pci_pcie_type(swus) != PCI_EXP_TYPE_UPSTREAM)
+ return adev->pdev;
+
+ return swus;
+}
+
/**
* amdgpu_device_should_use_aspm - check if the device should program ASPM
*
@@ -1940,6 +1965,9 @@ static bool amdgpu_device_aspm_support_quirk(struct amdgpu_device *adev)
*/
bool amdgpu_device_should_use_aspm(struct amdgpu_device *adev)
{
+ struct pci_dev *aspm_pdev, *parent;
+ bool enabled;
+
switch (amdgpu_aspm) {
case -1:
break;
@@ -1954,7 +1982,27 @@ bool amdgpu_device_should_use_aspm(struct amdgpu_device *adev)
return false;
if (amdgpu_device_aspm_support_quirk(adev))
return false;
- return pcie_aspm_enabled(adev->pdev);
+
+ /*
+ * pcie_aspm_enabled() checks the link between its argument and
+ * the immediate upstream bridge. Use SWUS for dGPUs with an
+ * internal switch so that this is the host-facing link.
+ */
+ aspm_pdev = amdgpu_device_get_aspm_pdev(adev);
+ parent = pci_upstream_bridge(aspm_pdev);
+ if (!parent) {
+ dev_dbg(adev->dev, "ASPM: no upstream PCIe link for %s\n",
+ pci_name(aspm_pdev));
+ return false;
+ }
+
+ enabled = pcie_aspm_enabled(aspm_pdev);
+ /* Report the exact link used for the automatic ASPM decision. */
+ dev_dbg(adev->dev, "ASPM: link %s <-> %s is %s\n",
+ pci_name(parent), pci_name(aspm_pdev),
+ enabled ? "enabled" : "disabled");
+
+ return enabled;
}

/* if we get transitioned to only one device, take VGA back */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
index 5fc9a6b1ec72..d3f2aa8cbdbc 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
@@ -385,6 +385,25 @@ const struct drm_gem_object_funcs amdgpu_gem_object_funcs = {
.vm_ops = &amdgpu_gem_vm_ops,
};

+static bool amdgpu_gem_are_domains_valid(u32 domains)
+{
+ u32 normal = AMDGPU_GEM_DOMAIN_CPU |
+ AMDGPU_GEM_DOMAIN_GTT |
+ AMDGPU_GEM_DOMAIN_VRAM;
+ /* Treat all non CPU/GTT/VRAM domains as special domains. */
+ u32 special = AMDGPU_GEM_DOMAIN_MASK & ~normal;
+ u32 normal_mask = domains & normal;
+ u32 special_mask = domains & special;
+
+ if (!special_mask)
+ return true;
+
+ if (normal_mask)
+ return false;
+
+ return !(special_mask & (special_mask - 1));
+}
+
/*
* GEM ioctls.
*/
@@ -409,6 +428,8 @@ int amdgpu_gem_create_ioctl(struct drm_device *dev, void *data,
/* reject invalid gem domains */
if (args->in.domains & ~AMDGPU_GEM_DOMAIN_MASK)
return -EINVAL;
+ if (!amdgpu_gem_are_domains_valid(args->in.domains))
+ return -EINVAL;

if (!amdgpu_is_tmz(adev) && (flags & AMDGPU_GEM_CREATE_ENCRYPTED)) {
DRM_NOTE_ONCE("Cannot allocate secure buffer since TMZ is disabled\n");
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
index 387a3358ffda..c48c266cc7a7 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
@@ -2163,8 +2163,6 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
*/
void amdgpu_ttm_fini(struct amdgpu_device *adev)
{
- int idx;
-
if (!adev->mman.initialized)
return;

@@ -2191,13 +2189,9 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev)
amdgpu_ttm_fw_reserve_vram_fini(adev);
amdgpu_ttm_drv_reserve_vram_fini(adev);

- if (drm_dev_enter(adev_to_drm(adev), &idx)) {
-
- if (adev->mman.aper_base_kaddr)
- iounmap(adev->mman.aper_base_kaddr);
+ if (adev->mman.aper_base_kaddr) {
+ iounmap(adev->mman.aper_base_kaddr);
adev->mman.aper_base_kaddr = NULL;
-
- drm_dev_exit(idx);
}

if (!adev->gmc.is_app_apu)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
index 5f1199b592b0..fb8d879193c9 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
@@ -645,17 +645,15 @@ static int amdgpu_uvd_cs_msg_decode(struct amdgpu_device *adev, uint32_t *msg,
unsigned int height = msg[7];
unsigned int dpb_size = msg[9];
unsigned int pitch = msg[28];
- unsigned int level = msg[57];

unsigned int width_in_mb = width / 16;
unsigned int height_in_mb = ALIGN(height / 16, 2);
- unsigned int fs_in_mb = width_in_mb * height_in_mb;

unsigned int image_size, tmp, min_dpb_size, num_dpb_buffer;
unsigned int min_ctx_size = ~0;

- /* Reject invalid dimensions to prevent division by zero */
- if (width < 16 || height < 16) {
+ /* Reject invalid dimensions */
+ if (width < 16 || height < 16 || width > 4096 || height > 4096) {
dev_WARN_ONCE(adev->dev, 1,
"Invalid UVD decoding dimensions (%dx%d)!\n",
width, height);
@@ -668,35 +666,9 @@ static int amdgpu_uvd_cs_msg_decode(struct amdgpu_device *adev, uint32_t *msg,

switch (stream_type) {
case 0: /* H264 */
- switch (level) {
- case 30:
- num_dpb_buffer = 8100 / fs_in_mb;
- break;
- case 31:
- num_dpb_buffer = 18000 / fs_in_mb;
- break;
- case 32:
- num_dpb_buffer = 20480 / fs_in_mb;
- break;
- case 41:
- num_dpb_buffer = 32768 / fs_in_mb;
- break;
- case 42:
- num_dpb_buffer = 34816 / fs_in_mb;
- break;
- case 50:
- num_dpb_buffer = 110400 / fs_in_mb;
- break;
- case 51:
- num_dpb_buffer = 184320 / fs_in_mb;
- break;
- default:
- num_dpb_buffer = 184320 / fs_in_mb;
- break;
- }
- num_dpb_buffer++;
+ num_dpb_buffer = ((msg[61] >> 16) & 0xff) + 1;
if (num_dpb_buffer > 17)
- num_dpb_buffer = 17;
+ return -EINVAL;

/* reference picture buffer */
min_dpb_size = image_size * num_dpb_buffer;
@@ -746,35 +718,9 @@ static int amdgpu_uvd_cs_msg_decode(struct amdgpu_device *adev, uint32_t *msg,
break;

case 7: /* H264 Perf */
- switch (level) {
- case 30:
- num_dpb_buffer = 8100 / fs_in_mb;
- break;
- case 31:
- num_dpb_buffer = 18000 / fs_in_mb;
- break;
- case 32:
- num_dpb_buffer = 20480 / fs_in_mb;
- break;
- case 41:
- num_dpb_buffer = 32768 / fs_in_mb;
- break;
- case 42:
- num_dpb_buffer = 34816 / fs_in_mb;
- break;
- case 50:
- num_dpb_buffer = 110400 / fs_in_mb;
- break;
- case 51:
- num_dpb_buffer = 184320 / fs_in_mb;
- break;
- default:
- num_dpb_buffer = 184320 / fs_in_mb;
- break;
- }
- num_dpb_buffer++;
+ num_dpb_buffer = ((msg[61] >> 16) & 0xff) + 1;
if (num_dpb_buffer > 17)
- num_dpb_buffer = 17;
+ return -EINVAL;

/* reference picture buffer */
min_dpb_size = image_size * num_dpb_buffer;
@@ -802,6 +748,9 @@ static int amdgpu_uvd_cs_msg_decode(struct amdgpu_device *adev, uint32_t *msg,
image_size = ALIGN(image_size, 256);

num_dpb_buffer = (le32_to_cpu(msg[59]) & 0xff) + 2;
+ if (num_dpb_buffer > 17)
+ return -EINVAL;
+
min_dpb_size = image_size * num_dpb_buffer;
min_ctx_size = ((width + 255) / 16) * ((height + 255) / 16)
* 16 * num_dpb_buffer + 52 * 1024;
@@ -812,7 +761,7 @@ static int amdgpu_uvd_cs_msg_decode(struct amdgpu_device *adev, uint32_t *msg,
return -EINVAL;
}

- if (width > pitch) {
+ if (width > pitch || pitch > 4096) {
DRM_ERROR("Invalid UVD decoding target pitch!\n");
return -EINVAL;
}
@@ -824,7 +773,7 @@ static int amdgpu_uvd_cs_msg_decode(struct amdgpu_device *adev, uint32_t *msg,
}

buf_sizes[0x1] = dpb_size;
- buf_sizes[0x2] = image_size;
+ buf_sizes[0x2] = (pitch * height) * 3 / 2;
buf_sizes[0x4] = min_ctx_size;
/* store image width to adjust nb memory pstate */
adev->uvd.decode_image_width = width;
@@ -971,15 +920,16 @@ static int amdgpu_uvd_cs_pass2(struct amdgpu_uvd_cs_ctx *ctx)
ctx->buf_sizes[cmd]);
return -EINVAL;
}
+ } else if (cmd == 0x204 || cmd == 0x206) {
+ unsigned int min_size = ctx->buf_sizes[cmd == 0x204 ? 5 : 4];

- } else if (cmd == 0x206) {
- if ((end - start) < ctx->buf_sizes[4]) {
+ if ((end - start) < min_size) {
DRM_ERROR("buffer (%d) to small (%d / %d)!\n", cmd,
(unsigned int)(end - start),
- ctx->buf_sizes[4]);
+ min_size);
return -EINVAL;
}
- } else if ((cmd != 0x100) && (cmd != 0x204)) {
+ } else if ((cmd != 0x100)) {
DRM_ERROR("invalid UVD command %X!\n", cmd);
return -EINVAL;
}
@@ -1109,11 +1059,12 @@ int amdgpu_uvd_ring_parse_cs(struct amdgpu_cs_parser *parser,
{
struct amdgpu_uvd_cs_ctx ctx = {};
unsigned int buf_sizes[] = {
- [0x00000000] = 2048,
+ [0x00000000] = 3556,
[0x00000001] = 0xFFFFFFFF,
[0x00000002] = 0xFFFFFFFF,
[0x00000003] = 2048,
[0x00000004] = 0xFFFFFFFF,
+ [0x00000005] = 992,
};
int r;

diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
index b91e81276877..ea72c334a3e7 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
@@ -1810,6 +1810,11 @@ static void gfx_v12_0_constants_init(struct amdgpu_device *adev)
gfx_v12_0_get_tcc_info(adev);
adev->gfx.config.pa_sc_tile_steering_override = 0;

+ /* Set whether texture coordinate truncation is conformant. */
+ tmp = RREG32_SOC15(GC, 0, regTA_CNTL2);
+ adev->gfx.config.ta_cntl2_truncate_coord_mode =
+ REG_GET_FIELD(tmp, TA_CNTL2, TRUNCATE_COORD_MODE);
+
/* XXX SH_MEM regs */
/* where to put LDS, scratch, GPUVM in FSA64 space */
mutex_lock(&adev->srbm_mutex);
diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c
index a43582b9c876..3f61d5367d94 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c
@@ -772,15 +772,28 @@ static int jpeg_v4_0_5_ring_reset(struct amdgpu_ring *ring,
unsigned int vmid,
struct amdgpu_fence *timedout_fence)
{
+ struct amdgpu_device *adev = ring->adev;
+ u32 pg_flags = adev->pg_flags;
int r;

amdgpu_ring_reset_helper_begin(ring, timedout_fence);
- r = jpeg_v4_0_5_stop(ring->adev);
- if (r)
- return r;
- r = jpeg_v4_0_5_start(ring->adev);
+
+ /*
+ * The DPG stop path only clears the JPEG_PG_MODE bit and never resets a
+ * hung JRBC, so the post-reset ring test times out and the driver falls
+ * back to a full MODE1 reset. Temporarily force the static power-gating
+ * path so the stop/start sequence actually power-cycles the JPEG block
+ * (JMI soft reset + static power off/on), matching the working jpeg_v4_0
+ * reset.
+ */
+ adev->pg_flags &= ~AMD_PG_SUPPORT_JPEG_DPG;
+ r = jpeg_v4_0_5_stop(adev);
+ if (!r)
+ r = jpeg_v4_0_5_start(adev);
+ adev->pg_flags = pg_flags;
if (r)
return r;
+
return amdgpu_ring_reset_helper_end(ring, timedout_fence);
}

diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c
index 72a4b2d0676f..c696a0dea32c 100644
--- a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c
@@ -648,15 +648,28 @@ static int jpeg_v5_0_0_ring_reset(struct amdgpu_ring *ring,
unsigned int vmid,
struct amdgpu_fence *timedout_fence)
{
+ struct amdgpu_device *adev = ring->adev;
+ u32 pg_flags = adev->pg_flags;
int r;

amdgpu_ring_reset_helper_begin(ring, timedout_fence);
- r = jpeg_v5_0_0_stop(ring->adev);
- if (r)
- return r;
- r = jpeg_v5_0_0_start(ring->adev);
+
+ /*
+ * The DPG stop path only clears the JPEG_PG_MODE bit and never resets a
+ * hung JRBC, so the post-reset ring test times out and the driver falls
+ * back to a full MODE1 reset. Temporarily force the static power-gating
+ * path so the stop/start sequence actually power-cycles the JPEG block
+ * (JMI soft reset + ONO1 power off/on), matching the working jpeg_v4_0
+ * reset.
+ */
+ adev->pg_flags &= ~AMD_PG_SUPPORT_JPEG_DPG;
+ r = jpeg_v5_0_0_stop(adev);
+ if (!r)
+ r = jpeg_v5_0_0_start(adev);
+ adev->pg_flags = pg_flags;
if (r)
return r;
+
return amdgpu_ring_reset_helper_end(ring, timedout_fence);
}

diff --git a/drivers/gpu/drm/amd/amdgpu/nbif_v6_3_1.c b/drivers/gpu/drm/amd/amdgpu/nbif_v6_3_1.c
index 9b4025c39e44..13c7f09fb951 100644
--- a/drivers/gpu/drm/amd/amdgpu/nbif_v6_3_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/nbif_v6_3_1.c
@@ -315,7 +315,6 @@ static u32 nbif_v6_3_1_get_rom_offset(struct amdgpu_device *adev)
static void nbif_v6_3_1_program_ltr(struct amdgpu_device *adev)
{
uint32_t def, data;
- u16 devctl2;

def = RREG32_SOC15(NBIO, 0, regRCC_EP_DEV0_0_EP_PCIE_TX_LTR_CNTL);
data = 0x35EB;
@@ -329,15 +328,8 @@ static void nbif_v6_3_1_program_ltr(struct amdgpu_device *adev)
if (def != data)
WREG32_SOC15(NBIO, 0, regRCC_STRAP0_RCC_BIF_STRAP2, data);

- pcie_capability_read_word(adev->pdev, PCI_EXP_DEVCTL2, &devctl2);
-
- if (adev->pdev->ltr_path == (devctl2 & PCI_EXP_DEVCTL2_LTR_EN))
- return;
-
- if (adev->pdev->ltr_path)
- pcie_capability_set_word(adev->pdev, PCI_EXP_DEVCTL2, PCI_EXP_DEVCTL2_LTR_EN);
- else
- pcie_capability_clear_word(adev->pdev, PCI_EXP_DEVCTL2, PCI_EXP_DEVCTL2_LTR_EN);
+ pcie_capability_set_word(adev->pdev, PCI_EXP_DEVCTL2,
+ PCI_EXP_DEVCTL2_LTR_EN);
}
#endif

@@ -345,7 +337,7 @@ static void nbif_v6_3_1_program_aspm(struct amdgpu_device *adev)
{
#ifdef CONFIG_PCIEASPM
uint32_t def, data;
- u16 devctl2, ltr;
+ u16 ltr;

def = data = RREG32_SOC15(PCIE, 0, regPCIE_LC_CNTL);
data &= ~PCIE_LC_CNTL__LC_L1_INACTIVITY_MASK;
@@ -375,11 +367,8 @@ static void nbif_v6_3_1_program_aspm(struct amdgpu_device *adev)
if (def != data)
WREG32_SOC15(NBIO, 0, regRCC_STRAP0_RCC_BIF_STRAP5, data);

- pcie_capability_read_word(adev->pdev, PCI_EXP_DEVCTL2, &devctl2);
- data = def = devctl2;
- data &= ~PCI_EXP_DEVCTL2_LTR_EN;
- if (def != data)
- pcie_capability_set_word(adev->pdev, PCI_EXP_DEVCTL2, (u16)data);
+ pcie_capability_clear_word(adev->pdev, PCI_EXP_DEVCTL2,
+ PCI_EXP_DEVCTL2_LTR_EN);

ltr = pci_find_ext_capability(adev->pdev, PCI_EXT_CAP_ID_LTR);

@@ -387,15 +376,13 @@ static void nbif_v6_3_1_program_aspm(struct amdgpu_device *adev)
pci_write_config_dword(adev->pdev, ltr + PCI_LTR_MAX_SNOOP_LAT, 0x10011001);
}

-#if 0
- /* regPSWUSP0_PCIE_LC_CNTL2 should be replace by PCIE_LC_CNTL2 or someone else ? */
- def = data = RREG32_SOC15(NBIO, 0, regPSWUSP0_PCIE_LC_CNTL2);
- data |= PSWUSP0_PCIE_LC_CNTL2__LC_ALLOW_PDWN_IN_L1_MASK |
- PSWUSP0_PCIE_LC_CNTL2__LC_ALLOW_PDWN_IN_L23_MASK;
- data &= ~PSWUSP0_PCIE_LC_CNTL2__LC_RCV_L0_TO_RCV_L0S_DIS_MASK;
+ def = data = RREG32_SOC15(PCIE, 0, regPCIE_LC_CNTL2);
+ data |= PCIE_LC_CNTL2__LC_ALLOW_PDWN_IN_L1_MASK |
+ PCIE_LC_CNTL2__LC_ALLOW_PDWN_IN_L23_MASK;
+ data &= ~PCIE_LC_CNTL2__LC_RCV_L0_TO_RCV_L0S_DIS_MASK;
if (def != data)
- WREG32_SOC15(NBIO, 0, regPSWUSP0_PCIE_LC_CNTL2, data);
-#endif
+ WREG32_SOC15(PCIE, 0, regPCIE_LC_CNTL2, data);
+
def = data = RREG32_SOC15(PCIE, 0, regPCIE_LC_CNTL4);
data |= PCIE_LC_CNTL4__LC_L1_POWERDOWN_MASK;
if (def != data)
@@ -406,7 +393,12 @@ static void nbif_v6_3_1_program_aspm(struct amdgpu_device *adev)
if (def != data)
WREG32_SOC15(PCIE, 0, regPCIE_LC_RXRECOVER_RXSTANDBY_CNTL, data);

- nbif_v6_3_1_program_ltr(adev);
+ /*
+ * Do not enable endpoint LTR unless the Root Complex and every
+ * upstream switch support it.
+ */
+ if (adev->pdev->ltr_path)
+ nbif_v6_3_1_program_ltr(adev);

def = data = RREG32_SOC15(NBIO, 0, regRCC_STRAP0_RCC_BIF_STRAP3);
data |= 0x5DE0 << RCC_STRAP0_RCC_BIF_STRAP3__STRAP_VLINK_ASPM_IDLE_TIMER__SHIFT;
diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
index 708123899c41..b54359efac06 100644
--- a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
@@ -870,6 +870,23 @@ static void vce_v3_0_ring_emit_ib(struct amdgpu_ring *ring,
amdgpu_ring_write(ring, ib->length_dw);
}

+static void vce_v3_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr,
+ u64 seq, unsigned flags)
+{
+ WARN_ON(flags & AMDGPU_FENCE_FLAG_64BIT);
+
+ amdgpu_ring_write(ring, VCE_CMD_FENCE);
+ amdgpu_ring_write(ring, addr);
+ amdgpu_ring_write(ring, upper_32_bits(addr));
+ amdgpu_ring_write(ring, seq);
+ amdgpu_ring_write(ring, VCE_CMD_TRAP);
+}
+
+static void vce_v3_0_ring_insert_end(struct amdgpu_ring *ring)
+{
+ amdgpu_ring_write(ring, VCE_CMD_END);
+}
+
static void vce_v3_0_emit_vm_flush(struct amdgpu_ring *ring,
unsigned int vmid, uint64_t pd_addr)
{
@@ -879,7 +896,6 @@ static void vce_v3_0_emit_vm_flush(struct amdgpu_ring *ring,

amdgpu_ring_write(ring, VCE_CMD_FLUSH_TLB);
amdgpu_ring_write(ring, vmid);
- amdgpu_ring_write(ring, VCE_CMD_END);
}

static void vce_v3_0_emit_pipeline_sync(struct amdgpu_ring *ring)
@@ -948,17 +964,19 @@ static const struct amdgpu_ring_funcs vce_v3_0_ring_vm_funcs = {
.set_wptr = vce_v3_0_ring_set_wptr,
.patch_cs_in_place = amdgpu_vce_ring_parse_cs_vm,
.emit_frame_size =
- 6 + /* vce_v3_0_emit_vm_flush */
+ 5 + /* vce_v3_0_emit_vm_flush */
4 + /* vce_v3_0_emit_pipeline_sync */
- 6 + 6, /* amdgpu_vce_ring_emit_fence x2 vm fence */
+ 5 + 5 + /* vce_v3_0_ring_emit_fence x2 vm fence */
+ 1, /* vce_v3_0_ring_insert_end */
.emit_ib_size = 5, /* vce_v3_0_ring_emit_ib */
.emit_ib = vce_v3_0_ring_emit_ib,
.emit_vm_flush = vce_v3_0_emit_vm_flush,
.emit_pipeline_sync = vce_v3_0_emit_pipeline_sync,
- .emit_fence = amdgpu_vce_ring_emit_fence,
+ .emit_fence = vce_v3_0_ring_emit_fence,
.test_ring = amdgpu_vce_ring_test_ring,
.test_ib = amdgpu_vce_ring_test_ib,
.insert_nop = amdgpu_ring_insert_nop,
+ .insert_end = vce_v3_0_ring_insert_end,
.pad_ib = amdgpu_ring_generic_pad_ib,
.begin_use = amdgpu_vce_ring_begin_use,
.end_use = amdgpu_vce_ring_end_use,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
index cc23d45815c3..788068303152 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
@@ -306,7 +306,7 @@ static inline int amdgpu_dm_crtc_set_vblank(struct drm_crtc *crtc, bool enable)

irq_type = amdgpu_display_crtc_idx_to_irq_type(adev, acrtc->crtc_id);

- if (enable) {
+ if (enable && acrtc_state->stream) {
struct dc *dc = adev->dm.dc;
struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc);
struct psr_settings *psr = &acrtc_state->stream->link->psr_settings;
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
index d82b1cb467f4..f56d1ae879ee 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
@@ -51,7 +51,8 @@ enum dc_color_space_type {
COLOR_SPACE_RGB_LIMITED_TYPE,
COLOR_SPACE_YCBCR601_TYPE,
COLOR_SPACE_YCBCR709_TYPE,
- COLOR_SPACE_YCBCR2020_TYPE,
+ COLOR_SPACE_YCBCR2020_LIMITED_TYPE,
+ COLOR_SPACE_YCBCR2020_FULL_TYPE,
COLOR_SPACE_YCBCR601_LIMITED_TYPE,
COLOR_SPACE_YCBCR709_LIMITED_TYPE,
COLOR_SPACE_YCBCR709_BLACK_TYPE,
@@ -103,9 +104,15 @@ static const struct out_csc_color_matrix_type output_csc_matrix[] = {
{ 0xE00, 0xF349, 0xFEB7, 0x1000,
0x6CE, 0x16E3, 0x24F, 0x200,
0xFCCB, 0xF535, 0xE00, 0x1000} },
- { COLOR_SPACE_YCBCR2020_TYPE,
+ /* Corrected. Not included in the TODO above. */
+ { COLOR_SPACE_YCBCR2020_LIMITED_TYPE,
+ { 0x0E04, 0xF31D, 0xFEDF, 0x1004,
+ 0x0733, 0x1294, 0x01A0, 0x0201,
+ 0xFC16, 0xF5E6, 0x0E04, 0x1004} },
+ /* Corrected. Not included in the TODO above. */
+ { COLOR_SPACE_YCBCR2020_FULL_TYPE,
{ 0x1000, 0xF149, 0xFEB7, 0x1004,
- 0x0868, 0x15B2, 0x01E6, 0x201,
+ 0x0868, 0x15B2, 0x01E6, 0,
0xFB88, 0xF478, 0x1000, 0x1004} },
{ COLOR_SPACE_YCBCR709_BLACK_TYPE,
{ 0x0000, 0x0000, 0x0000, 0x1000,
@@ -172,14 +179,14 @@ static bool is_ycbcr709_type(
return ret;
}

-static bool is_ycbcr2020_type(
- enum dc_color_space color_space)
+static bool is_ycbcr2020_limited_type(enum dc_color_space color_space)
{
- bool ret = false;
+ return color_space == COLOR_SPACE_2020_YCBCR_LIMITED;
+}

- if (color_space == COLOR_SPACE_2020_YCBCR_LIMITED || color_space == COLOR_SPACE_2020_YCBCR_FULL)
- ret = true;
- return ret;
+static bool is_ycbcr2020_full_type(enum dc_color_space color_space)
+{
+ return color_space == COLOR_SPACE_2020_YCBCR_FULL;
}

static bool is_ycbcr709_limited_type(
@@ -208,8 +215,10 @@ static enum dc_color_space_type get_color_space_type(enum dc_color_space color_s
type = COLOR_SPACE_YCBCR601_LIMITED_TYPE;
else if (is_ycbcr709_limited_type(color_space))
type = COLOR_SPACE_YCBCR709_LIMITED_TYPE;
- else if (is_ycbcr2020_type(color_space))
- type = COLOR_SPACE_YCBCR2020_TYPE;
+ else if (is_ycbcr2020_limited_type(color_space))
+ type = COLOR_SPACE_YCBCR2020_LIMITED_TYPE;
+ else if (is_ycbcr2020_full_type(color_space))
+ type = COLOR_SPACE_YCBCR2020_FULL_TYPE;
else if (color_space == COLOR_SPACE_YCBCR709)
type = COLOR_SPACE_YCBCR709_BLACK_TYPE;
else if (color_space == COLOR_SPACE_YCBCR709_BLACK)
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c b/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c
index 23b35393bf42..351cc84e146b 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_transform.c
@@ -115,10 +115,11 @@ static const struct out_csc_color_matrix global_color_matrix[] = {
{ 0x2000, 0, 0, 0, 0, 0x2000, 0, 0, 0, 0, 0x2000, 0} },
{ COLOR_SPACE_2020_RGB_LIMITEDRANGE,
{ 0x1B67, 0, 0, 0x201, 0, 0x1B67, 0, 0x201, 0, 0, 0x1B67, 0x201} },
-{ COLOR_SPACE_2020_YCBCR_LIMITED, { 0x1000, 0xF149, 0xFEB7, 0x1004, 0x0868,
- 0x15B2, 0x01E6, 0x201, 0xFB88, 0xF478, 0x1000, 0x1004} },
+/* COLOR_SPACE_2020_YCBCR_* values corrected. Not included in the TODO above. */
+{ COLOR_SPACE_2020_YCBCR_LIMITED, { 0x0E04, 0xF31D, 0xFEDF, 0x1004, 0x0733,
+ 0x1294, 0x01A0, 0x201, 0xFC16, 0xF5E6, 0x0E04, 0x1004} },
{ COLOR_SPACE_2020_YCBCR_FULL, { 0x1000, 0xF149, 0xFEB7, 0x1004, 0x0868, 0x15B2,
- 0x01E6, 0x201, 0xFB88, 0xF478, 0x1000, 0x1004} }
+ 0x01E6, 0, 0xFB88, 0xF478, 0x1000, 0x1004} }
};

static bool setup_scaling_configuration(
diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_csc_v.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_csc_v.c
index f7b2be02333c..870ae2e3c1b1 100644
--- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_csc_v.c
+++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_csc_v.c
@@ -93,10 +93,11 @@ static const struct out_csc_color_matrix global_color_matrix[] = {
{ 0x2000, 0, 0, 0, 0, 0x2000, 0, 0, 0, 0, 0x2000, 0} },
{ COLOR_SPACE_2020_RGB_LIMITEDRANGE,
{ 0x1B67, 0, 0, 0x201, 0, 0x1B67, 0, 0x201, 0, 0, 0x1B67, 0x201} },
-{ COLOR_SPACE_2020_YCBCR_LIMITED, { 0x1000, 0xF149, 0xFEB7, 0x1004, 0x0868,
- 0x15B2, 0x01E6, 0x201, 0xFB88, 0xF478, 0x1000, 0x1004} },
+/* COLOR_SPACE_2020_YCBCR_* values corrected. Not included in the TODO above. */
+{ COLOR_SPACE_2020_YCBCR_LIMITED, { 0x0E04, 0xF31D, 0xFEDF, 0x1004, 0x0733,
+ 0x1294, 0x01A0, 0x201, 0xFC16, 0xF5E6, 0x0E04, 0x1004} },
{ COLOR_SPACE_2020_YCBCR_FULL, { 0x1000, 0xF149, 0xFEB7, 0x1004, 0x0868, 0x15B2,
- 0x01E6, 0x201, 0xFB88, 0xF478, 0x1000, 0x1004} }
+ 0x01E6, 0, 0xFB88, 0xF478, 0x1000, 0x1004} }
};

enum csc_color_mode {
diff --git a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
index caf2cabeca6d..3830c3b72d4b 100644
--- a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
+++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c
@@ -1183,17 +1183,28 @@ int amdgpu_dpm_dispatch_task(struct amdgpu_device *adev,
return ret;
}

-int amdgpu_dpm_get_pp_table(struct amdgpu_device *adev, char **table)
+int amdgpu_dpm_get_pp_table(struct amdgpu_device *adev, char *table,
+ size_t size)
{
const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
+ char *pptable = NULL;
int ret = 0;

- if (!pp_funcs->get_pp_table)
- return 0;
+ if ((!table && size) || (table && !size))
+ return -EINVAL;
+
+ if (amdgpu_sriov_vf(adev) || !pp_funcs->get_pp_table || adev->scpm_enabled)
+ return -EOPNOTSUPP;

mutex_lock(&adev->pm.mutex);
ret = pp_funcs->get_pp_table(adev->powerplay.pp_handle,
- table);
+ &pptable);
+ if (ret > 0 && !pptable) {
+ ret = -EINVAL;
+ } else if (ret > 0 && table) {
+ ret = min_t(size_t, ret, size);
+ memcpy(table, pptable, ret);
+ }
mutex_unlock(&adev->pm.mutex);

return ret;
@@ -1721,7 +1732,10 @@ int amdgpu_dpm_set_pp_table(struct amdgpu_device *adev,
const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
int ret = 0;

- if (!pp_funcs->set_pp_table)
+ if (!buf || !size)
+ return -EINVAL;
+
+ if (amdgpu_sriov_vf(adev) || !pp_funcs->set_pp_table || adev->scpm_enabled)
return -EOPNOTSUPP;

mutex_lock(&adev->pm.mutex);
diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c
index 94c534c1d0be..db7296567c85 100644
--- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c
+++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c
@@ -556,25 +556,19 @@ static ssize_t amdgpu_get_pp_table(struct device *dev,
{
struct drm_device *ddev = dev_get_drvdata(dev);
struct amdgpu_device *adev = drm_to_adev(ddev);
- char *table = NULL;
int size, ret;

ret = amdgpu_pm_get_access_if_active(adev);
if (ret)
return ret;

- size = amdgpu_dpm_get_pp_table(adev, &table);
+ size = amdgpu_dpm_get_pp_table(adev, buf, PAGE_SIZE - 1);

amdgpu_pm_put_access(adev);

if (size <= 0)
return size;

- if (size >= PAGE_SIZE)
- size = PAGE_SIZE - 1;
-
- memcpy(buf, table, size);
-
return size;
}

@@ -2502,7 +2496,7 @@ static struct amdgpu_device_attr amdgpu_device_attrs[] = {
AMDGPU_DEVICE_ATTR_RO(pp_num_states, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF),
AMDGPU_DEVICE_ATTR_RO(pp_cur_state, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF),
AMDGPU_DEVICE_ATTR_RW(pp_force_state, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF),
- AMDGPU_DEVICE_ATTR_RW(pp_table, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF),
+ AMDGPU_DEVICE_ATTR_RW(pp_table, ATTR_FLAG_BASIC),
AMDGPU_DEVICE_ATTR_RW(pp_dpm_sclk, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF,
.attr_update = pp_dpm_clk_default_attr_update),
AMDGPU_DEVICE_ATTR_RW(pp_dpm_mclk, ATTR_FLAG_BASIC|ATTR_FLAG_ONEVF,
@@ -2639,6 +2633,14 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_
if (amdgpu_dpm_get_apu_thermal_limit(adev, &limit) ==
-EOPNOTSUPP)
*states = ATTR_STATE_UNSUPPORTED;
+ } else if (DEVICE_ATTR_IS(pp_table)) {
+ int ret;
+
+ ret = amdgpu_dpm_get_pp_table(adev, NULL, 0);
+ if (ret <= 0)
+ *states = ATTR_STATE_UNSUPPORTED;
+ else
+ *states = ATTR_STATE_SUPPORTED;
}

switch (gc_ver) {
diff --git a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
index b0bbb23929bf..13a834575ed7 100644
--- a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
+++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h
@@ -487,7 +487,8 @@ int amdgpu_dpm_get_pp_num_states(struct amdgpu_device *adev,
int amdgpu_dpm_dispatch_task(struct amdgpu_device *adev,
enum amd_pp_task task_id,
enum amd_pm_state_type *user_state);
-int amdgpu_dpm_get_pp_table(struct amdgpu_device *adev, char **table);
+int amdgpu_dpm_get_pp_table(struct amdgpu_device *adev, char *table,
+ size_t size);
int amdgpu_dpm_set_fine_grain_clk_vol(struct amdgpu_device *adev,
uint32_t type,
long *input,
diff --git a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c
index 554492dfa3c0..a16fcca3576c 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c
@@ -634,9 +634,12 @@ static int pp_dpm_get_pp_table(void *handle, char **table)
{
struct pp_hwmgr *hwmgr = handle;

- if (!hwmgr || !hwmgr->pm_en || !hwmgr->soft_pp_table)
+ if (!hwmgr || !hwmgr->pm_en || !table)
return -EINVAL;

+ if (!hwmgr->soft_pp_table)
+ return -EOPNOTSUPP;
+
*table = (char *)hwmgr->soft_pp_table;
return hwmgr->soft_pp_table_size;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
index cfa4ff5d21b2..53d071eddbf4 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
@@ -620,7 +620,7 @@ static int smu_sys_get_pp_table(void *handle,
return -EOPNOTSUPP;

if (!smu_table->power_play_table && !smu_table->hardcode_pptable)
- return -EINVAL;
+ return -EOPNOTSUPP;

if (smu_table->hardcode_pptable)
*table = smu_table->hardcode_pptable;
diff --git a/drivers/gpu/drm/clients/drm_log.c b/drivers/gpu/drm/clients/drm_log.c
index d239f1e3c456..1e137786b36a 100644
--- a/drivers/gpu/drm/clients/drm_log.c
+++ b/drivers/gpu/drm/clients/drm_log.c
@@ -160,6 +160,9 @@ static void drm_log_draw_kmsg_record(struct drm_log_scanout *scanout,
{
u32 prefix_len = 0;

+ if (!len)
+ return;
+
if (len > TS_PREFIX_LEN && s[0] == '[' && s[6] == '.' && s[TS_PREFIX_LEN] == ']')
prefix_len = TS_PREFIX_LEN + 1;

@@ -215,6 +218,12 @@ static int drm_log_setup_modeset(struct drm_client_dev *client,
scanout->scaled_font_w = scanout->font->width * scale;
scanout->rows = height / scanout->scaled_font_h;
scanout->columns = width / scanout->scaled_font_w;
+ if (!scanout->rows || !scanout->columns) {
+ drm_client_buffer_delete(scanout->buffer);
+ scanout->buffer = NULL;
+ mode_set->fb = NULL;
+ return -EINVAL;
+ }
scanout->front_color = drm_draw_color_from_xrgb8888(0xffffff, format);
scanout->prefix_color = drm_draw_color_from_xrgb8888(0x4e9a06, format);
return 0;
@@ -272,7 +281,7 @@ static void drm_log_init_client(struct drm_log *dlog)

err_failed_commit:
for (i = 0; i < n_modeset; i++)
- drm_client_framebuffer_delete(dlog->scanout[i].buffer);
+ drm_client_buffer_delete(dlog->scanout[i].buffer);

err_nomodeset:
kfree(dlog->scanout);
@@ -286,7 +295,7 @@ static void drm_log_free_scanout(struct drm_client_dev *client)

if (dlog->n_scanout) {
for (i = 0; i < dlog->n_scanout; i++)
- drm_client_framebuffer_delete(dlog->scanout[i].buffer);
+ drm_client_buffer_delete(dlog->scanout[i].buffer);
dlog->n_scanout = 0;
kfree(dlog->scanout);
dlog->scanout = NULL;
diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index a561f124be99..ce71f5c19af1 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -1072,7 +1072,8 @@ drm_atomic_helper_connector_hdmi_update_audio_infoframe(struct drm_connector *co

mutex_lock(&connector->hdmi.infoframes.lock);

- memcpy(&infoframe->data, frame, sizeof(infoframe->data));
+ BUILD_BUG_ON(sizeof(*frame) > sizeof(infoframe->data));
+ memcpy(&infoframe->data, frame, sizeof(*frame));
infoframe->set = true;

ret = write_infoframe(connector, infoframe);
diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c
index 3fa38d4ac70b..6a6ba50e6928 100644
--- a/drivers/gpu/drm/drm_client.c
+++ b/drivers/gpu/drm/drm_client.c
@@ -17,6 +17,7 @@
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem.h>
+#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_mode.h>
#include <drm/drm_print.h>

@@ -172,25 +173,51 @@ void drm_client_release(struct drm_client_dev *client)
}
EXPORT_SYMBOL(drm_client_release);

-static void drm_client_buffer_delete(struct drm_client_buffer *buffer)
+/**
+ * drm_client_buffer_delete - Delete a client buffer
+ * @buffer: DRM client buffer
+ */
+void drm_client_buffer_delete(struct drm_client_buffer *buffer)
{
- if (buffer->gem) {
- drm_gem_vunmap(buffer->gem, &buffer->map);
- drm_gem_object_put(buffer->gem);
- }
+ struct drm_gem_object *gem;
+ int ret;
+
+ if (!buffer)
+ return;
+
+ gem = buffer->fb->obj[0];
+ drm_gem_vunmap(gem, &buffer->map);
+
+ ret = drm_mode_rmfb(buffer->client->dev, buffer->fb->base.id, buffer->client->file);
+ if (ret)
+ drm_err(buffer->client->dev,
+ "Error removing FB:%u (%d)\n", buffer->fb->base.id, ret);
+
+ drm_gem_object_put(buffer->gem);

kfree(buffer);
}
+EXPORT_SYMBOL(drm_client_buffer_delete);

static struct drm_client_buffer *
drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height,
- u32 format, u32 *handle)
+ u32 format, u32 handle, u32 pitch)
{
- const struct drm_format_info *info = drm_format_info(format);
- struct drm_mode_create_dumb dumb_args = { };
+ struct drm_mode_fb_cmd2 fb_req = {
+ .width = width,
+ .height = height,
+ .pixel_format = format,
+ .handles = {
+ handle,
+ },
+ .pitches = {
+ pitch,
+ },
+ };
struct drm_device *dev = client->dev;
struct drm_client_buffer *buffer;
struct drm_gem_object *obj;
+ struct drm_framebuffer *fb;
int ret;

buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
@@ -199,28 +226,38 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height,

buffer->client = client;

- dumb_args.width = width;
- dumb_args.height = height;
- dumb_args.bpp = drm_format_info_bpp(info, 0);
- ret = drm_mode_create_dumb(dev, &dumb_args, client->file);
- if (ret)
- goto err_delete;
-
- obj = drm_gem_object_lookup(client->file, dumb_args.handle);
+ obj = drm_gem_object_lookup(client->file, handle);
if (!obj) {
ret = -ENOENT;
goto err_delete;
}

- buffer->pitch = dumb_args.pitch;
+ ret = drm_mode_addfb2(dev, &fb_req, client->file);
+ if (ret)
+ goto err_drm_gem_object_put;
+
+ fb = drm_framebuffer_lookup(dev, client->file, fb_req.fb_id);
+ if (drm_WARN_ON(dev, !fb)) {
+ ret = -ENOENT;
+ goto err_drm_mode_rmfb;
+ }
+
+ /* drop the reference we picked up in framebuffer lookup */
+ drm_framebuffer_put(fb);
+
+ strscpy(fb->comm, client->name, TASK_COMM_LEN);
+
buffer->gem = obj;
- *handle = dumb_args.handle;
+ buffer->fb = fb;

return buffer;

+err_drm_mode_rmfb:
+ drm_mode_rmfb(dev, fb_req.fb_id, client->file);
+err_drm_gem_object_put:
+ drm_gem_object_put(obj);
err_delete:
- drm_client_buffer_delete(buffer);
-
+ kfree(buffer);
return ERR_PTR(ret);
}

@@ -247,7 +284,7 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height,
int drm_client_buffer_vmap_local(struct drm_client_buffer *buffer,
struct iosys_map *map_copy)
{
- struct drm_gem_object *gem = buffer->gem;
+ struct drm_gem_object *gem = buffer->fb->obj[0];
struct iosys_map *map = &buffer->map;
int ret;

@@ -276,7 +313,7 @@ EXPORT_SYMBOL(drm_client_buffer_vmap_local);
*/
void drm_client_buffer_vunmap_local(struct drm_client_buffer *buffer)
{
- struct drm_gem_object *gem = buffer->gem;
+ struct drm_gem_object *gem = buffer->fb->obj[0];
struct iosys_map *map = &buffer->map;

drm_gem_vunmap_locked(gem, map);
@@ -307,9 +344,10 @@ EXPORT_SYMBOL(drm_client_buffer_vunmap_local);
int drm_client_buffer_vmap(struct drm_client_buffer *buffer,
struct iosys_map *map_copy)
{
+ struct drm_gem_object *gem = buffer->fb->obj[0];
int ret;

- ret = drm_gem_vmap(buffer->gem, &buffer->map);
+ ret = drm_gem_vmap(gem, &buffer->map);
if (ret)
return ret;
*map_copy = buffer->map;
@@ -328,54 +366,11 @@ EXPORT_SYMBOL(drm_client_buffer_vmap);
*/
void drm_client_buffer_vunmap(struct drm_client_buffer *buffer)
{
- drm_gem_vunmap(buffer->gem, &buffer->map);
-}
-EXPORT_SYMBOL(drm_client_buffer_vunmap);
-
-static void drm_client_buffer_rmfb(struct drm_client_buffer *buffer)
-{
- int ret;
+ struct drm_gem_object *gem = buffer->fb->obj[0];

- if (!buffer->fb)
- return;
-
- ret = drm_mode_rmfb(buffer->client->dev, buffer->fb->base.id, buffer->client->file);
- if (ret)
- drm_err(buffer->client->dev,
- "Error removing FB:%u (%d)\n", buffer->fb->base.id, ret);
-
- buffer->fb = NULL;
-}
-
-static int drm_client_buffer_addfb(struct drm_client_buffer *buffer,
- u32 width, u32 height, u32 format,
- u32 handle)
-{
- struct drm_client_dev *client = buffer->client;
- struct drm_mode_fb_cmd2 fb_req = { };
- int ret;
-
- fb_req.width = width;
- fb_req.height = height;
- fb_req.pixel_format = format;
- fb_req.handles[0] = handle;
- fb_req.pitches[0] = buffer->pitch;
-
- ret = drm_mode_addfb2(client->dev, &fb_req, client->file);
- if (ret)
- return ret;
-
- buffer->fb = drm_framebuffer_lookup(client->dev, buffer->client->file, fb_req.fb_id);
- if (WARN_ON(!buffer->fb))
- return -ENOENT;
-
- /* drop the reference we picked up in framebuffer lookup */
- drm_framebuffer_put(buffer->fb);
-
- strscpy(buffer->fb->comm, client->name, TASK_COMM_LEN);
-
- return 0;
+ drm_gem_vunmap(gem, &buffer->map);
}
+EXPORT_SYMBOL(drm_client_buffer_vunmap);

/**
* drm_client_framebuffer_create - Create a client framebuffer
@@ -386,7 +381,7 @@ static int drm_client_buffer_addfb(struct drm_client_buffer *buffer,
*
* This function creates a &drm_client_buffer which consists of a
* &drm_framebuffer backed by a dumb buffer.
- * Call drm_client_framebuffer_delete() to free the buffer.
+ * Call drm_client_buffer_delete() to free the buffer.
*
* Returns:
* Pointer to a client buffer or an error pointer on failure.
@@ -394,16 +389,25 @@ static int drm_client_buffer_addfb(struct drm_client_buffer *buffer,
struct drm_client_buffer *
drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format)
{
+ const struct drm_format_info *info = drm_format_info(format);
+ struct drm_device *dev = client->dev;
+ struct drm_mode_create_dumb dumb_args = { };
struct drm_client_buffer *buffer;
- u32 handle;
int ret;

- buffer = drm_client_buffer_create(client, width, height, format,
- &handle);
- if (IS_ERR(buffer))
- return buffer;
+ dumb_args.width = width;
+ dumb_args.height = height;
+ dumb_args.bpp = drm_format_info_bpp(info, 0);
+ ret = drm_mode_create_dumb(dev, &dumb_args, client->file);
+ if (ret)
+ return ERR_PTR(ret);

- ret = drm_client_buffer_addfb(buffer, width, height, format, handle);
+ buffer = drm_client_buffer_create(client, width, height, format,
+ dumb_args.handle, dumb_args.pitch);
+ if (IS_ERR(buffer)) {
+ ret = PTR_ERR(buffer);
+ goto err_drm_mode_destroy_dumb;
+ }

/*
* The handle is only needed for creating the framebuffer, destroy it
@@ -411,30 +415,15 @@ drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 heig
* object as DMA-buf. The framebuffer and our buffer structure are still
* holding references to the GEM object to prevent its destruction.
*/
- drm_mode_destroy_dumb(client->dev, handle, client->file);
-
- if (ret) {
- drm_client_buffer_delete(buffer);
- return ERR_PTR(ret);
- }
+ drm_mode_destroy_dumb(client->dev, dumb_args.handle, client->file);

return buffer;
-}
-EXPORT_SYMBOL(drm_client_framebuffer_create);
-
-/**
- * drm_client_framebuffer_delete - Delete a client framebuffer
- * @buffer: DRM client buffer (can be NULL)
- */
-void drm_client_framebuffer_delete(struct drm_client_buffer *buffer)
-{
- if (!buffer)
- return;

- drm_client_buffer_rmfb(buffer);
- drm_client_buffer_delete(buffer);
+err_drm_mode_destroy_dumb:
+ drm_mode_destroy_dumb(client->dev, dumb_args.handle, client->file);
+ return ERR_PTR(ret);
}
-EXPORT_SYMBOL(drm_client_framebuffer_delete);
+EXPORT_SYMBOL(drm_client_framebuffer_create);

/**
* drm_client_framebuffer_flush - Manually flush client framebuffer
diff --git a/drivers/gpu/drm/drm_fbdev_dma.c b/drivers/gpu/drm/drm_fbdev_dma.c
index 7b77c801a63a..feecd44e91eb 100644
--- a/drivers/gpu/drm/drm_fbdev_dma.c
+++ b/drivers/gpu/drm/drm_fbdev_dma.c
@@ -55,7 +55,7 @@ static void drm_fbdev_dma_fb_destroy(struct fb_info *info)
drm_fb_helper_fini(fb_helper);

drm_client_buffer_vunmap(fb_helper->buffer);
- drm_client_framebuffer_delete(fb_helper->buffer);
+ drm_client_buffer_delete(fb_helper->buffer);
drm_client_release(&fb_helper->client);
drm_fb_helper_unprepare(fb_helper);
kfree(fb_helper);
@@ -90,7 +90,7 @@ static void drm_fbdev_dma_shadowed_fb_destroy(struct fb_info *info)
vfree(shadow);

drm_client_buffer_vunmap(fb_helper->buffer);
- drm_client_framebuffer_delete(fb_helper->buffer);
+ drm_client_buffer_delete(fb_helper->buffer);
drm_client_release(&fb_helper->client);
drm_fb_helper_unprepare(fb_helper);
kfree(fb_helper);
@@ -320,7 +320,7 @@ int drm_fbdev_dma_driver_fbdev_probe(struct drm_fb_helper *fb_helper,
fb_helper->buffer = NULL;
drm_client_buffer_vunmap(buffer);
err_drm_client_buffer_delete:
- drm_client_framebuffer_delete(buffer);
+ drm_client_buffer_delete(buffer);
return ret;
}
EXPORT_SYMBOL(drm_fbdev_dma_driver_fbdev_probe);
diff --git a/drivers/gpu/drm/drm_fbdev_shmem.c b/drivers/gpu/drm/drm_fbdev_shmem.c
index 77f350700818..d435caed7002 100644
--- a/drivers/gpu/drm/drm_fbdev_shmem.c
+++ b/drivers/gpu/drm/drm_fbdev_shmem.c
@@ -63,7 +63,7 @@ static void drm_fbdev_shmem_fb_destroy(struct fb_info *info)
drm_fb_helper_fini(fb_helper);

drm_client_buffer_vunmap(fb_helper->buffer);
- drm_client_framebuffer_delete(fb_helper->buffer);
+ drm_client_buffer_delete(fb_helper->buffer);
drm_client_release(&fb_helper->client);
drm_fb_helper_unprepare(fb_helper);
kfree(fb_helper);
@@ -198,7 +198,7 @@ int drm_fbdev_shmem_driver_fbdev_probe(struct drm_fb_helper *fb_helper,
fb_helper->buffer = NULL;
drm_client_buffer_vunmap(buffer);
err_drm_client_buffer_delete:
- drm_client_framebuffer_delete(buffer);
+ drm_client_buffer_delete(buffer);
return ret;
}
EXPORT_SYMBOL(drm_fbdev_shmem_driver_fbdev_probe);
diff --git a/drivers/gpu/drm/drm_fbdev_ttm.c b/drivers/gpu/drm/drm_fbdev_ttm.c
index 1ba258f3c854..c2aa65b2384f 100644
--- a/drivers/gpu/drm/drm_fbdev_ttm.c
+++ b/drivers/gpu/drm/drm_fbdev_ttm.c
@@ -50,7 +50,7 @@ static void drm_fbdev_ttm_fb_destroy(struct fb_info *info)
fb_deferred_io_cleanup(info);
drm_fb_helper_fini(fb_helper);
vfree(shadow);
- drm_client_framebuffer_delete(fb_helper->buffer);
+ drm_client_buffer_delete(fb_helper->buffer);

drm_client_release(&fb_helper->client);
drm_fb_helper_unprepare(fb_helper);
@@ -202,7 +202,7 @@ int drm_fbdev_ttm_driver_fbdev_probe(struct drm_fb_helper *fb_helper,
screen_buffer = vzalloc(screen_size);
if (!screen_buffer) {
ret = -ENOMEM;
- goto err_drm_client_framebuffer_delete;
+ goto err_drm_client_buffer_delete;
}

drm_fb_helper_fill_info(info, fb_helper, sizes);
@@ -227,10 +227,10 @@ int drm_fbdev_ttm_driver_fbdev_probe(struct drm_fb_helper *fb_helper,

err_vfree:
vfree(screen_buffer);
-err_drm_client_framebuffer_delete:
+err_drm_client_buffer_delete:
fb_helper->fb = NULL;
fb_helper->buffer = NULL;
- drm_client_framebuffer_delete(buffer);
+ drm_client_buffer_delete(buffer);
return ret;
}
EXPORT_SYMBOL(drm_fbdev_ttm_driver_fbdev_probe);
diff --git a/drivers/gpu/drm/panthor/panthor_fw.c b/drivers/gpu/drm/panthor/panthor_fw.c
index 470e41297764..a299b746ee2e 100644
--- a/drivers/gpu/drm/panthor/panthor_fw.c
+++ b/drivers/gpu/drm/panthor/panthor_fw.c
@@ -553,6 +553,9 @@ static int panthor_fw_load_section_entry(struct panthor_device *ptdev,
return -EINVAL;
}

+ if (!section_size)
+ return 0;
+
name_len = iter->size - iter->offset;

section = drmm_kzalloc(&ptdev->base, sizeof(*section), GFP_KERNEL);
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c
index ba1446acd703..16adc5d5f67b 100644
--- a/drivers/gpu/drm/radeon/radeon_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_kms.c
@@ -71,6 +71,7 @@ void radeon_driver_unload_kms(struct drm_device *dev)
if (radeon_is_px(dev)) {
pm_runtime_get_sync(dev->dev);
pm_runtime_forbid(dev->dev);
+ pm_runtime_dont_use_autosuspend(dev->dev);
}

radeon_acpi_fini(rdev);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 3e8a2f4a907d..35c7277521a9 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -553,6 +553,9 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
memcpy(&vfbs->uo, uo, sizeof(vfbs->uo));
vmw_user_object_ref(&vfbs->uo);

+ if (vfbs->uo.buffer)
+ vfbs->base.base.obj[0] = &vfbs->uo.buffer->tbo.base;
+
*out = &vfbs->base;

ret = drm_framebuffer_init(dev, &vfbs->base.base,
diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
index 0d69cd0e4e79..05a84ea6bd6a 100644
--- a/drivers/gpu/drm/xe/xe_device.c
+++ b/drivers/gpu/drm/xe/xe_device.c
@@ -962,7 +962,11 @@ int xe_device_probe(struct xe_device *xe)
if (err)
goto err_unregister_display;

- return devm_add_action_or_reset(xe->drm.dev, xe_device_sanitize, xe);
+ err = devm_add_action_or_reset(xe->drm.dev, xe_device_sanitize, xe);
+ if (err)
+ goto err_unregister_display;
+
+ return 0;

err_unregister_display:
xe_display_unregister(xe);
diff --git a/drivers/gpu/drm/xe/xe_lrc.c b/drivers/gpu/drm/xe/xe_lrc.c
index 9f29dbe890f6..53eadea8ab38 100644
--- a/drivers/gpu/drm/xe/xe_lrc.c
+++ b/drivers/gpu/drm/xe/xe_lrc.c
@@ -1692,6 +1692,13 @@ void xe_lrc_write_ring(struct xe_lrc *lrc, const void *data, size_t size)

__xe_lrc_write_ring(lrc, ring, &noop, sizeof(noop));
}
+
+ /*
+ * The ring and the LRC context image are both WC, so the ring tail
+ * update which publishes these writes can become visible to the device
+ * first. Ensure the ring contents are visible before returning.
+ */
+ xe_device_wmb(xe);
}

u64 xe_lrc_descriptor(struct xe_lrc *lrc)
diff --git a/drivers/gpu/drm/xe/xe_oa.c b/drivers/gpu/drm/xe/xe_oa.c
index 98df9ee1cac3..ff19553e8843 100644
--- a/drivers/gpu/drm/xe/xe_oa.c
+++ b/drivers/gpu/drm/xe/xe_oa.c
@@ -1567,6 +1567,10 @@ static long xe_oa_config_locked(struct xe_oa_stream *stream, u64 arg)
config = xchg(&stream->oa_config, config);
drm_dbg(&stream->oa->xe->drm, "changed to oa config uuid=%s\n",
stream->oa_config->uuid);
+ } else {
+ while (param.num_syncs--)
+ xe_sync_entry_cleanup(&param.syncs[param.num_syncs]);
+ kfree(param.syncs);
}

err_config_put:
diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c
index effa76bfd8f9..01fee14054fb 100644
--- a/drivers/input/joystick/iforce/iforce-packets.c
+++ b/drivers/input/joystick/iforce/iforce-packets.c
@@ -155,6 +155,9 @@ void iforce_process_packet(struct iforce *iforce,
switch (packet_id) {

case 0x01: /* joystick position data */
+ if (len < 7)
+ break;
+
input_report_abs(dev, ABS_X,
(__s16) get_unaligned_le16(data));
input_report_abs(dev, ABS_Y,
@@ -170,6 +173,9 @@ void iforce_process_packet(struct iforce *iforce,
break;

case 0x03: /* wheel position data */
+ if (len < 7)
+ break;
+
input_report_abs(dev, ABS_WHEEL,
(__s16) get_unaligned_le16(data));
input_report_abs(dev, ABS_GAS, 255 - data[2]);
@@ -181,6 +187,9 @@ void iforce_process_packet(struct iforce *iforce,
break;

case 0x02: /* status report */
+ if (len < 2)
+ break;
+
input_report_key(dev, BTN_DEAD, data[0] & 0x02);
input_sync(dev);

@@ -200,7 +209,7 @@ void iforce_process_packet(struct iforce *iforce,
}
}

- for (j = 3; j < len; j += 2)
+ for (j = 3; j + sizeof(u16) <= len; j += sizeof(u16))
mark_core_as_ready(iforce, get_unaligned_le16(data + j));

break;
diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c
index 1f00f76b0174..5e3a8dbe6c6f 100644
--- a/drivers/input/joystick/iforce/iforce-usb.c
+++ b/drivers/input/joystick/iforce/iforce-usb.c
@@ -158,6 +158,9 @@ static void iforce_usb_irq(struct urb *urb)
goto exit;
}

+ if (!urb->actual_length)
+ goto exit;
+
iforce_process_packet(iforce, iforce_usb->data_in[0],
iforce_usb->data_in + 1, urb->actual_length - 1);

diff --git a/drivers/input/joystick/psxpad-spi.c b/drivers/input/joystick/psxpad-spi.c
index f902a56d011f..aac77a2cfe46 100644
--- a/drivers/input/joystick/psxpad-spi.c
+++ b/drivers/input/joystick/psxpad-spi.c
@@ -373,6 +373,7 @@ static int psxpad_spi_probe(struct spi_device *spi)
return err;
}

+ spi_set_drvdata(spi, pad);
pm_runtime_enable(&spi->dev);

return 0;
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index ebfb841aafee..1b6f38f62905 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -428,6 +428,7 @@ static const struct xpad_device {
{ 0x3285, 0x0646, "Nacon Pro Compact", 0, XTYPE_XBOXONE },
{ 0x3285, 0x0662, "Nacon Revolution5 Pro", 0, XTYPE_XBOX360 },
{ 0x3285, 0x0663, "Nacon Evol-X", 0, XTYPE_XBOXONE },
+ { 0x3507, 0x000b, "ZENAIM LEVERLESS", 0, XTYPE_XBOX360 },
{ 0x3537, 0x1004, "GameSir T4 Kaleid", 0, XTYPE_XBOX360 },
{ 0x3537, 0x100f, "GameSir Nova 2 Lite", 0, XTYPE_XBOX360 },
{ 0x3537, 0x1010, "GameSir G7 SE", 0, XTYPE_XBOXONE },
@@ -591,6 +592,7 @@ static const struct usb_device_id xpad_table[] = {
XPAD_XBOX360_VENDOR(0x31e3), /* Wooting Keyboards */
XPAD_XBOX360_VENDOR(0x3285), /* Nacon GC-100 */
XPAD_XBOXONE_VENDOR(0x3285), /* Nacon Evol-X */
+ XPAD_XBOX360_VENDOR(0x3507), /* ZENAIM Controllers */
XPAD_XBOX360_VENDOR(0x3537), /* GameSir Controllers */
XPAD_XBOXONE_VENDOR(0x3537), /* GameSir Controllers */
XPAD_XBOX360_VENDOR(0x3651), /* CRKD Controllers */
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index 8eeac27dec54..ea88bcfdb4b6 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -1952,6 +1952,14 @@ static const struct dmi_system_id atkbd_dmi_quirk_table[] __initconst = {
},
.callback = atkbd_deactivate_fixup,
},
+ {
+ /* Xiaomi Book Pro 14 (TM2424) */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "XIAOMI"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Xiaomi Book Pro 14"),
+ },
+ .callback = atkbd_deactivate_fixup,
+ },
{ }
};

diff --git a/drivers/input/misc/cs40l50-vibra.c b/drivers/input/misc/cs40l50-vibra.c
index 7aa7d577e01b..f4c605eafd11 100644
--- a/drivers/input/misc/cs40l50-vibra.c
+++ b/drivers/input/misc/cs40l50-vibra.c
@@ -139,10 +139,10 @@ static struct cs40l50_effect *cs40l50_find_effect(int id, struct list_head *effe
static int cs40l50_effect_bank_set(struct cs40l50_work *work_data,
struct cs40l50_effect *effect)
{
- s16 bank_type = work_data->custom_data[0] & CS40L50_CUSTOM_DATA_MASK;
+ u32 bank_type = work_data->custom_data[0] & CS40L50_CUSTOM_DATA_MASK;

if (bank_type >= CS40L50_WVFRM_BANK_NUM) {
- dev_err(work_data->vib->dev, "Invalid bank (%d)\n", bank_type);
+ dev_err(work_data->vib->dev, "Invalid bank (%u)\n", bank_type);
return -EINVAL;
}

@@ -327,6 +327,12 @@ static int cs40l50_add(struct input_dev *dev, struct ff_effect *effect,
return -EINVAL;
}

+ if (periodic->custom_len < CS40L50_OWT_CUSTOM_DATA_SIZE) {
+ dev_err(vib->dev, "Invalid custom data length (%u)\n",
+ periodic->custom_len);
+ return -EINVAL;
+ }
+
work_data.custom_data = memdup_array_user(effect->u.periodic.custom_data,
effect->u.periodic.custom_len,
sizeof(s16));
diff --git a/drivers/input/mouse/byd.c b/drivers/input/mouse/byd.c
index 71aa23dd7d8d..91bcff433898 100644
--- a/drivers/input/mouse/byd.c
+++ b/drivers/input/mouse/byd.c
@@ -425,7 +425,7 @@ static void byd_disconnect(struct psmouse *psmouse)
struct byd_data *priv = psmouse->private;

if (priv) {
- timer_delete(&priv->timer);
+ timer_shutdown_sync(&priv->timer);
kfree(psmouse->private);
psmouse->private = NULL;
}
diff --git a/drivers/input/mouse/focaltech.c b/drivers/input/mouse/focaltech.c
index 356b99d48544..d1a3b48ee891 100644
--- a/drivers/input/mouse/focaltech.c
+++ b/drivers/input/mouse/focaltech.c
@@ -197,7 +197,7 @@ static void focaltech_process_rel_packet(struct psmouse *psmouse,
{
struct focaltech_data *priv = psmouse->private;
struct focaltech_hw_state *state = &priv->state;
- int finger1, finger2;
+ unsigned int finger1, finger2;

state->pressed = packet[0] >> 7;
finger1 = ((packet[0] >> 4) & 0x7) - 1;
diff --git a/drivers/input/rmi4/rmi_f54.c b/drivers/input/rmi4/rmi_f54.c
index 61909e1a39e2..6c6cdec7da9e 100644
--- a/drivers/input/rmi4/rmi_f54.c
+++ b/drivers/input/rmi4/rmi_f54.c
@@ -104,7 +104,9 @@ struct f54_data {

enum rmi_f54_report_type report_type;
u8 *report_data;
+ size_t max_report_size;
int report_size;
+ int report_error;

bool is_busy;
struct mutex status_mutex;
@@ -339,6 +341,12 @@ static void rmi_f54_buffer_queue(struct vb2_buffer *vb)
mutex_lock(&f54->data_mutex);
}

+ if (f54->report_error) {
+ dev_err(&f54->fn->dev, "Error acquiring report: %d\n", f54->report_error);
+ state = VB2_BUF_STATE_ERROR;
+ goto data_done;
+ }
+
ptr = vb2_plane_vaddr(vb, 0);
if (!ptr) {
dev_err(&f54->fn->dev, "Error acquiring frame ptr\n");
@@ -444,7 +452,12 @@ static int rmi_f54_set_input(struct f54_data *f54, unsigned int i)

static int rmi_f54_vidioc_s_input(struct file *file, void *priv, unsigned int i)
{
- return rmi_f54_set_input(video_drvdata(file), i);
+ struct f54_data *f54 = video_drvdata(file);
+
+ if (vb2_is_busy(&f54->queue))
+ return -EBUSY;
+
+ return rmi_f54_set_input(f54, i);
}

static int rmi_f54_vidioc_g_input(struct file *file, void *priv,
@@ -545,7 +558,14 @@ static void rmi_f54_work(struct work_struct *work)
dev_err(&fn->dev, "Bad report size, report type=%d\n",
f54->report_type);
error = -EINVAL;
- goto error; /* retry won't help */
+ goto out; /* retry won't help */
+ }
+
+ if (report_size > f54->max_report_size) {
+ dev_err(&fn->dev, "Report size %d exceeds buffer size %zu\n",
+ report_size, f54->max_report_size);
+ error = -EINVAL;
+ goto out;
}

/*
@@ -556,7 +576,7 @@ static void rmi_f54_work(struct work_struct *work)
&command);
if (error) {
dev_err(&fn->dev, "Failed to read back command\n");
- goto error;
+ goto out;
}
if (command & F54_GET_REPORT) {
if (time_after(jiffies, f54->timeout)) {
@@ -564,7 +584,7 @@ static void rmi_f54_work(struct work_struct *work)
error = -ETIMEDOUT;
}
report_size = 0;
- goto error;
+ goto out;
}

rmi_dbg(RMI_DEBUG_FN, &fn->dev, "Get report command completed, reading data\n");
@@ -579,7 +599,7 @@ static void rmi_f54_work(struct work_struct *work)
fifo, sizeof(fifo));
if (error) {
dev_err(&fn->dev, "Failed to set fifo start offset\n");
- goto abort;
+ goto out;
}

error = rmi_read_block(fn->rmi_dev, fn->fd.data_base_addr +
@@ -588,16 +608,17 @@ static void rmi_f54_work(struct work_struct *work)
if (error) {
dev_err(&fn->dev, "%s: read [%d bytes] returned %d\n",
__func__, size, error);
- goto abort;
+ goto out;
}
}

-abort:
- f54->report_size = error ? 0 : report_size;
-error:
+out:
if (error)
report_size = 0;

+ f54->report_size = report_size;
+ f54->report_error = error;
+
if (report_size == 0 && !error) {
queue_delayed_work(f54->workqueue, &f54->work,
msecs_to_jiffies(1));
@@ -678,8 +699,8 @@ static int rmi_f54_probe(struct rmi_function *fn)

rx = f54->num_rx_electrodes;
tx = f54->num_tx_electrodes;
- f54->report_data = devm_kzalloc(&fn->dev,
- array3_size(tx, rx, sizeof(u16)),
+ f54->max_report_size = array3_size(tx, rx, sizeof(u16));
+ f54->report_data = devm_kzalloc(&fn->dev, f54->max_report_size,
GFP_KERNEL);
if (f54->report_data == NULL)
return -ENOMEM;
diff --git a/drivers/input/rmi4/rmi_f55.c b/drivers/input/rmi4/rmi_f55.c
index 488adaca4dd0..a0877d32a914 100644
--- a/drivers/input/rmi4/rmi_f55.c
+++ b/drivers/input/rmi4/rmi_f55.c
@@ -54,10 +54,10 @@ static int rmi_f55_detect(struct rmi_function *fn)
f55->num_tx_electrodes = f55->qry[F55_NUM_TX_OFFSET];

f55->cfg_num_rx_electrodes = f55->num_rx_electrodes;
- f55->cfg_num_tx_electrodes = f55->num_rx_electrodes;
+ f55->cfg_num_tx_electrodes = f55->num_tx_electrodes;

drv_data->num_rx_electrodes = f55->cfg_num_rx_electrodes;
- drv_data->num_tx_electrodes = f55->cfg_num_rx_electrodes;
+ drv_data->num_tx_electrodes = f55->cfg_num_tx_electrodes;

if (f55->qry[F55_PHYS_CHAR_OFFSET] & F55_CAP_SENSOR_ASSIGN) {
int i, total;
diff --git a/drivers/input/touchscreen/hynitron_cstxxx.c b/drivers/input/touchscreen/hynitron_cstxxx.c
index 1d8ca90dcda6..af66d91848b3 100644
--- a/drivers/input/touchscreen/hynitron_cstxxx.c
+++ b/drivers/input/touchscreen/hynitron_cstxxx.c
@@ -313,6 +313,12 @@ static void cst3xx_touch_report(struct i2c_client *client)
return;

touch_cnt = buf[5] & CST3XX_TOUCH_COUNT_MASK;
+ if (touch_cnt > ts_data->chip->max_touch_num) {
+ dev_err(&client->dev, "cst3xx invalid touch count (%d vs %d max)\n",
+ touch_cnt, ts_data->chip->max_touch_num);
+ return;
+ }
+
/*
* Check the check bit of the last touch slot. The check bit is
* always present after touch point 1 for valid data, and then
@@ -335,9 +341,10 @@ static void cst3xx_touch_report(struct i2c_client *client)
finger_id = (buf[idx] >> 4) & 0x0f;

/* Sanity check we don't have more fingers than we expect */
- if (ts_data->chip->max_touch_num < finger_id) {
- dev_err(&client->dev, "cst3xx touch read failure\n");
- break;
+ if (finger_id >= ts_data->chip->max_touch_num) {
+ dev_err(&client->dev,
+ "cst3xx invalid finger id %d\n", finger_id);
+ return;
}

/* sw value of 0 means no touch, 0x03 means touch */
diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c
index 7b3b10cbfcfc..0a4e40b85ab8 100644
--- a/drivers/input/touchscreen/sur40.c
+++ b/drivers/input/touchscreen/sur40.c
@@ -725,21 +725,13 @@ static int sur40_probe(struct usb_interface *interface,
goto err_free_input;
}

- /* register the polled input device */
- error = input_register_device(input);
- if (error) {
- dev_err(&interface->dev,
- "Unable to register polled input device.");
- goto err_free_buffer;
- }
-
/* register the video master device */
snprintf(sur40->v4l2.name, sizeof(sur40->v4l2.name), "%s", DRIVER_LONG);
error = v4l2_device_register(sur40->dev, &sur40->v4l2);
if (error) {
dev_err(&interface->dev,
"Unable to register video master device.");
- goto err_unreg_v4l2;
+ goto err_free_buffer;
}

/* initialize the lock and subdevice */
@@ -795,6 +787,14 @@ static int sur40_probe(struct usb_interface *interface,
if (error) {
dev_err(&interface->dev,
"Unable to register video subdevice.");
+ goto err_free_ctrl;
+ }
+
+ /* register the polled input device */
+ error = input_register_device(input);
+ if (error) {
+ dev_err(&interface->dev,
+ "Unable to register polled input device.");
goto err_unreg_video;
}

@@ -806,6 +806,8 @@ static int sur40_probe(struct usb_interface *interface,

err_unreg_video:
video_unregister_device(&sur40->vdev);
+err_free_ctrl:
+ v4l2_ctrl_handler_free(&sur40->hdl);
err_unreg_v4l2:
v4l2_device_unregister(&sur40->v4l2);
err_free_buffer:
@@ -823,11 +825,12 @@ static void sur40_disconnect(struct usb_interface *interface)
{
struct sur40_state *sur40 = usb_get_intfdata(interface);

+ input_unregister_device(sur40->input);
+
v4l2_ctrl_handler_free(&sur40->hdl);
video_unregister_device(&sur40->vdev);
v4l2_device_unregister(&sur40->v4l2);

- input_unregister_device(sur40->input);
kfree(sur40->bulk_in_buffer);
kfree(sur40);

diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index d1fbc6811563..d631a6ea2eab 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -2616,6 +2616,8 @@ static void atmci_remove(struct platform_device *pdev)

free_irq(platform_get_irq(pdev, 0), host);

+ cancel_work_sync(&host->bh_work);
+
clk_disable_unprepare(host->mck);

pm_runtime_disable(dev);
diff --git a/drivers/mmc/host/loongson2-mmc.c b/drivers/mmc/host/loongson2-mmc.c
index da3daab5f3d6..7e5c6f00badd 100644
--- a/drivers/mmc/host/loongson2-mmc.c
+++ b/drivers/mmc/host/loongson2-mmc.c
@@ -628,8 +628,8 @@ static void ls2k0500_mmc_reorder_cmd_data(struct loongson2_mmc_host *host,
return;

for_each_sg(cmd->data->sg, sg, cmd->data->sg_len, i) {
- data = sg_virt(&sg[i]);
- for (j = 0; j < (sg_dma_len(&sg[i]) / 4); j++)
+ data = sg_virt(sg);
+ for (j = 0; j < (sg_dma_len(sg) / 4); j++)
if (cmd->opcode == SD_SWITCH)
data[j] = bitrev8x4(data[j]);
else
@@ -761,8 +761,8 @@ static void ls2k2000_mmc_reorder_cmd_data(struct loongson2_mmc_host *host,
return;

for_each_sg(cmd->data->sg, sg, cmd->data->sg_len, i) {
- data = sg_virt(&sg[i]);
- for (j = 0; j < (sg_dma_len(&sg[i]) / 4); j++)
+ data = sg_virt(sg);
+ for (j = 0; j < (sg_dma_len(sg) / 4); j++)
data[j] = bitrev8x4(data[j]);
}
}
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 09e4354d1f1d..e09bdf690064 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -1357,7 +1357,7 @@ omap_hsmmc_prepare_data(struct omap_hsmmc_host *host, struct mmc_request *req)
if (req->data == NULL) {
OMAP_HSMMC_WRITE(host->base, BLK, 0);
if (req->cmd->flags & MMC_RSP_BUSY) {
- timeout = req->cmd->busy_timeout * NSEC_PER_MSEC;
+ timeout = (u64)req->cmd->busy_timeout * NSEC_PER_MSEC;

/*
* Set an arbitrary 100ms data timeout for commands with
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index d06c5a13ef91..3b6cd685f7bd 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -4187,6 +4187,14 @@ void __sdhci_read_caps(struct sdhci_host *host, const u16 *ver,
}
EXPORT_SYMBOL_GPL(__sdhci_read_caps);

+static void sdhci_unmap_bounce_buffer(void *data)
+{
+ struct sdhci_host *host = data;
+
+ dma_unmap_single(mmc_dev(host->mmc), host->bounce_addr,
+ host->bounce_buffer_size, DMA_BIDIRECTIONAL);
+}
+
static void sdhci_allocate_bounce_buffer(struct sdhci_host *host)
{
struct mmc_host *mmc = host->mmc;
@@ -4241,6 +4249,14 @@ static void sdhci_allocate_bounce_buffer(struct sdhci_host *host)
}

host->bounce_buffer_size = bounce_size;
+ ret = devm_add_action_or_reset(mmc_dev(mmc),
+ sdhci_unmap_bounce_buffer, host);
+ if (ret) {
+ devm_kfree(mmc_dev(mmc), host->bounce_buffer);
+ host->bounce_buffer = NULL;
+ host->bounce_buffer_size = 0;
+ return;
+ }

/* Lie about this since we're bouncing */
mmc->max_segs = max_blocks;
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index b6a571d866fa..f0fd81409a86 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -659,7 +659,7 @@ struct sdhci_host {

unsigned int tuning_count; /* Timer count for re-tuning */
unsigned int tuning_mode; /* Re-tuning mode supported by host */
- unsigned int tuning_err; /* Error code for re-tuning */
+ int tuning_err; /* Error code for re-tuning */
#define SDHCI_TUNING_MODE_1 0
#define SDHCI_TUNING_MODE_2 1
#define SDHCI_TUNING_MODE_3 2
diff --git a/drivers/mtd/ubi/attach.c b/drivers/mtd/ubi/attach.c
index adc47b87b38a..884171871d0e 100644
--- a/drivers/mtd/ubi/attach.c
+++ b/drivers/mtd/ubi/attach.c
@@ -1600,7 +1600,7 @@ int ubi_attach(struct ubi_device *ubi, int force_scan)

err = ubi_read_volume_table(ubi, ai);
if (err)
- goto out_ai;
+ goto out_fm;

err = ubi_wl_init(ubi, ai);
if (err)
@@ -1642,6 +1642,8 @@ int ubi_attach(struct ubi_device *ubi, int force_scan)
out_vtbl:
ubi_free_all_volumes(ubi);
vfree(ubi->vtbl);
+out_fm:
+ ubi_free_fastmap(ubi);
out_ai:
destroy_ai(ai);
return err;
diff --git a/drivers/mtd/ubi/fastmap-wl.c b/drivers/mtd/ubi/fastmap-wl.c
index 9bdb6525f128..e2bc1122bfd3 100644
--- a/drivers/mtd/ubi/fastmap-wl.c
+++ b/drivers/mtd/ubi/fastmap-wl.c
@@ -530,8 +530,6 @@ int ubi_is_erase_work(struct ubi_work *wrk)

static void ubi_fastmap_close(struct ubi_device *ubi)
{
- int i;
-
return_unused_pool_pebs(ubi, &ubi->fm_pool);
return_unused_pool_pebs(ubi, &ubi->fm_wl_pool);

@@ -540,11 +538,7 @@ static void ubi_fastmap_close(struct ubi_device *ubi)
ubi->fm_anchor = NULL;
}

- if (ubi->fm) {
- for (i = 0; i < ubi->fm->used_blocks; i++)
- kfree(ubi->fm->e[i]);
- }
- kfree(ubi->fm);
+ ubi_free_fastmap(ubi);
}

/**
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index a4999bce435f..915eb64cb001 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -868,6 +868,8 @@ int ubi_io_write_ec_hdr(struct ubi_device *ubi, int pnum,
return -EROFS;
}

+ memset((char *)ec_hdr + UBI_EC_HDR_SIZE, 0xFF, ubi->ec_hdr_alsize - UBI_EC_HDR_SIZE);
+
err = ubi_io_write(ubi, ec_hdr, pnum, 0, ubi->ec_hdr_alsize);
return err;
}
@@ -1150,6 +1152,14 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
return -EROFS;
}

+ if (ubi->vid_hdr_shift) {
+ memset((char *)p, 0xFF, ubi->vid_hdr_shift);
+ memset((char *)p + ubi->vid_hdr_shift + UBI_VID_HDR_SIZE, 0xFF,
+ ubi->vid_hdr_alsize - (ubi->vid_hdr_shift + UBI_VID_HDR_SIZE));
+ } else {
+ memset((char *)p + UBI_VID_HDR_SIZE, 0xFF, ubi->vid_hdr_alsize - UBI_VID_HDR_SIZE);
+ }
+
err = ubi_io_write(ubi, p, pnum, ubi->vid_hdr_aloffset,
ubi->vid_hdr_alsize);
return err;
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index c792b9bcab9b..44803d3329f4 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -969,10 +969,22 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai,
struct ubi_attach_info *scan_ai);
int ubi_fastmap_init_checkmap(struct ubi_volume *vol, int leb_count);
void ubi_fastmap_destroy_checkmap(struct ubi_volume *vol);
+static inline void ubi_free_fastmap(struct ubi_device *ubi)
+{
+ if (ubi->fm) {
+ int i;
+
+ for (i = 0; i < ubi->fm->used_blocks; i++)
+ kmem_cache_free(ubi_wl_entry_slab, ubi->fm->e[i]);
+ kfree(ubi->fm);
+ ubi->fm = NULL;
+ }
+}
#else
static inline int ubi_update_fastmap(struct ubi_device *ubi) { return 0; }
static inline int ubi_fastmap_init_checkmap(struct ubi_volume *vol, int leb_count) { return 0; }
static inline void ubi_fastmap_destroy_checkmap(struct ubi_volume *vol) {}
+static inline void ubi_free_fastmap(struct ubi_device *ubi) { }
#endif

/* block.c */
diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c
index 4c0d7d26df9f..45af1d121a84 100644
--- a/drivers/net/can/rcar/rcar_canfd.c
+++ b/drivers/net/can/rcar/rcar_canfd.c
@@ -468,6 +468,7 @@ struct rcar_canfd_global {
struct platform_device *pdev; /* Respective platform device */
struct clk *clkp; /* Peripheral clock */
struct clk *can_clk; /* fCAN clock */
+ struct clk *clk_ram; /* Clock RAM */
unsigned long channels_mask; /* Enabled channels mask */
bool extclk; /* CANFD or Ext clock */
bool fdmode; /* CAN FD or Classical CAN only mode */
@@ -1970,22 +1971,120 @@ static void rcar_canfd_channel_remove(struct rcar_canfd_global *gpriv, u32 ch)
}
}

+static int rcar_canfd_global_init(struct rcar_canfd_global *gpriv)
+{
+ struct device *dev = &gpriv->pdev->dev;
+ u32 rule_entry = 0;
+ u32 ch, sts;
+ int err;
+
+ /* Enable peripheral clock for register access */
+ err = clk_prepare_enable(gpriv->clkp);
+ if (err) {
+ dev_err(dev, "failed to enable peripheral clock: %pe\n",
+ ERR_PTR(err));
+ return err;
+ }
+
+ /* Enable RAM clock */
+ err = clk_prepare_enable(gpriv->clk_ram);
+ if (err) {
+ dev_err(dev,
+ "failed to enable RAM clock, error %d\n", err);
+ goto fail_clk;
+ }
+
+ err = reset_control_reset(gpriv->rstc1);
+ if (err)
+ goto fail_ram_clk;
+
+ err = reset_control_reset(gpriv->rstc2);
+ if (err)
+ goto fail_reset1;
+
+ err = rcar_canfd_reset_controller(gpriv);
+ if (err) {
+ dev_err(dev, "reset controller failed: %pe\n", ERR_PTR(err));
+ goto fail_reset2;
+ }
+
+ /* Controller in Global reset & Channel reset mode */
+ rcar_canfd_configure_controller(gpriv);
+
+ /* Configure per channel attributes */
+ for_each_set_bit(ch, &gpriv->channels_mask, gpriv->info->max_channels) {
+ /* Configure Channel's Rx fifo */
+ rcar_canfd_configure_rx(gpriv, ch);
+
+ /* Configure Channel's Tx (Common) fifo */
+ rcar_canfd_configure_tx(gpriv, ch);
+
+ /* Configure receive rules */
+ rcar_canfd_configure_afl_rules(gpriv, ch, rule_entry);
+ rule_entry += RCANFD_CHANNEL_NUMRULES;
+ }
+
+ /* Configure common interrupts */
+ rcar_canfd_enable_global_interrupts(gpriv);
+
+ /* Start Global operation mode */
+ rcar_canfd_update_bit(gpriv->base, RCANFD_GCTR, RCANFD_GCTR_GMDC_MASK,
+ RCANFD_GCTR_GMDC_GOPM);
+
+ /* Verify mode change */
+ err = readl_poll_timeout((gpriv->base + RCANFD_GSTS), sts,
+ !(sts & RCANFD_GSTS_GNOPM), 2, 500000);
+ if (err) {
+ dev_err(dev, "global operational mode failed\n");
+ goto fail_mode;
+ }
+
+ return 0;
+
+fail_mode:
+ rcar_canfd_disable_global_interrupts(gpriv);
+fail_reset2:
+ reset_control_assert(gpriv->rstc2);
+fail_reset1:
+ reset_control_assert(gpriv->rstc1);
+fail_ram_clk:
+ clk_disable_unprepare(gpriv->clk_ram);
+fail_clk:
+ clk_disable_unprepare(gpriv->clkp);
+ return err;
+}
+
+static void rcar_canfd_global_deinit(struct rcar_canfd_global *gpriv, bool full)
+{
+ rcar_canfd_disable_global_interrupts(gpriv);
+
+ if (full) {
+ rcar_canfd_reset_controller(gpriv);
+
+ /* Enter global sleep mode */
+ rcar_canfd_set_bit(gpriv->base, RCANFD_GCTR, RCANFD_GCTR_GSLPR);
+ }
+
+ reset_control_assert(gpriv->rstc2);
+ reset_control_assert(gpriv->rstc1);
+ clk_disable_unprepare(gpriv->clk_ram);
+ clk_disable_unprepare(gpriv->clkp);
+}
+
static int rcar_canfd_probe(struct platform_device *pdev)
{
struct phy *transceivers[RCANFD_NUM_CHANNELS] = { NULL, };
const struct rcar_canfd_hw_info *info;
struct device *dev = &pdev->dev;
void __iomem *addr;
- u32 sts, ch, fcan_freq;
struct rcar_canfd_global *gpriv;
struct device_node *of_child;
unsigned long channels_mask = 0;
int err, ch_irq, g_irq;
int g_err_irq, g_recc_irq;
- u32 rule_entry = 0;
bool fdmode = true; /* CAN FD only mode - default */
char name[9] = "channelX";
- struct clk *clk_ram;
+ u32 ch, fcan_freq;
int i;

info = of_device_get_match_data(dev);
@@ -2075,10 +2174,10 @@ static int rcar_canfd_probe(struct platform_device *pdev)
gpriv->extclk = gpriv->info->external_clk;
}

- clk_ram = devm_clk_get_optional_enabled(dev, "ram_clk");
- if (IS_ERR(clk_ram))
- return dev_err_probe(dev, PTR_ERR(clk_ram),
- "cannot get enabled ram clock\n");
+ gpriv->clk_ram = devm_clk_get_optional(dev, "ram_clk");
+ if (IS_ERR(gpriv->clk_ram))
+ return dev_err_probe(dev, PTR_ERR(gpriv->clk_ram),
+ "cannot get ram clock\n");

addr = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(addr)) {
@@ -2127,59 +2226,9 @@ static int rcar_canfd_probe(struct platform_device *pdev)
}
}

- err = reset_control_reset(gpriv->rstc1);
+ err = rcar_canfd_global_init(gpriv);
if (err)
- goto fail_dev;
- err = reset_control_reset(gpriv->rstc2);
- if (err) {
- reset_control_assert(gpriv->rstc1);
- goto fail_dev;
- }
-
- /* Enable peripheral clock for register access */
- err = clk_prepare_enable(gpriv->clkp);
- if (err) {
- dev_err(dev, "failed to enable peripheral clock: %pe\n",
- ERR_PTR(err));
- goto fail_reset;
- }
-
- err = rcar_canfd_reset_controller(gpriv);
- if (err) {
- dev_err(dev, "reset controller failed: %pe\n", ERR_PTR(err));
- goto fail_clk;
- }
-
- /* Controller in Global reset & Channel reset mode */
- rcar_canfd_configure_controller(gpriv);
-
- /* Configure per channel attributes */
- for_each_set_bit(ch, &gpriv->channels_mask, info->max_channels) {
- /* Configure Channel's Rx fifo */
- rcar_canfd_configure_rx(gpriv, ch);
-
- /* Configure Channel's Tx (Common) fifo */
- rcar_canfd_configure_tx(gpriv, ch);
-
- /* Configure receive rules */
- rcar_canfd_configure_afl_rules(gpriv, ch, rule_entry);
- rule_entry += RCANFD_CHANNEL_NUMRULES;
- }
-
- /* Configure common interrupts */
- rcar_canfd_enable_global_interrupts(gpriv);
-
- /* Start Global operation mode */
- rcar_canfd_update_bit(gpriv->base, RCANFD_GCTR, RCANFD_GCTR_GMDC_MASK,
- RCANFD_GCTR_GMDC_GOPM);
-
- /* Verify mode change */
- err = readl_poll_timeout((gpriv->base + RCANFD_GSTS), sts,
- !(sts & RCANFD_GSTS_GNOPM), 2, 500000);
- if (err) {
- dev_err(dev, "global operational mode failed\n");
goto fail_mode;
- }

for_each_set_bit(ch, &gpriv->channels_mask, info->max_channels) {
err = rcar_canfd_channel_probe(gpriv, ch, fcan_freq,
@@ -2198,12 +2247,7 @@ static int rcar_canfd_probe(struct platform_device *pdev)
for_each_set_bit(ch, &gpriv->channels_mask, info->max_channels)
rcar_canfd_channel_remove(gpriv, ch);
fail_mode:
- rcar_canfd_disable_global_interrupts(gpriv);
-fail_clk:
- clk_disable_unprepare(gpriv->clkp);
-fail_reset:
- reset_control_assert(gpriv->rstc1);
- reset_control_assert(gpriv->rstc2);
+ rcar_canfd_global_deinit(gpriv, false);
fail_dev:
return err;
}
@@ -2213,19 +2257,12 @@ static void rcar_canfd_remove(struct platform_device *pdev)
struct rcar_canfd_global *gpriv = platform_get_drvdata(pdev);
u32 ch;

- rcar_canfd_reset_controller(gpriv);
- rcar_canfd_disable_global_interrupts(gpriv);
-
for_each_set_bit(ch, &gpriv->channels_mask, gpriv->info->max_channels) {
rcar_canfd_disable_channel_interrupts(gpriv->ch[ch]);
rcar_canfd_channel_remove(gpriv, ch);
}

- /* Enter global sleep mode */
- rcar_canfd_set_bit(gpriv->base, RCANFD_GCTR, RCANFD_GCTR_GSLPR);
- clk_disable_unprepare(gpriv->clkp);
- reset_control_assert(gpriv->rstc1);
- reset_control_assert(gpriv->rstc2);
+ rcar_canfd_global_deinit(gpriv, true);
}

static int __maybe_unused rcar_canfd_suspend(struct device *dev)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index 83ddf753b8c9..29e52df2502e 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -11643,6 +11643,16 @@ static void bnxt_irq_affinity_notify(struct irq_affinity_notify *notify,

irq = container_of(notify, struct bnxt_irq, affinity_notify);

+#ifdef CONFIG_RFS_ACCEL
+ if (irq->bp->dev->rx_cpu_rmap && irq->ring_nr < irq->bp->rx_nr_rings) {
+ err = cpu_rmap_update(irq->bp->dev->rx_cpu_rmap, irq->ring_nr,
+ mask);
+ if (err)
+ netdev_warn(irq->bp->dev,
+ "aRFS rmap update failed: %d\n", err);
+ }
+#endif
+
if (!irq->bp->tph_mode)
return;

@@ -11716,10 +11726,6 @@ static void bnxt_free_irq(struct bnxt *bp)
struct bnxt_irq *irq;
int i;

-#ifdef CONFIG_RFS_ACCEL
- free_irq_cpu_rmap(bp->dev->rx_cpu_rmap);
- bp->dev->rx_cpu_rmap = NULL;
-#endif
if (!bp->irq_tbl || !bp->bnapi)
return;

@@ -11728,14 +11734,14 @@ static void bnxt_free_irq(struct bnxt *bp)

irq = &bp->irq_tbl[map_idx];
if (irq->requested) {
+ bnxt_release_irq_notifier(irq);
+
if (irq->have_cpumask) {
irq_update_affinity_hint(irq->vector, NULL);
free_cpumask_var(irq->cpu_mask);
irq->have_cpumask = 0;
}

- bnxt_release_irq_notifier(irq);
-
free_irq(irq->vector, bp->bnapi[i]);
}

@@ -11745,6 +11751,11 @@ static void bnxt_free_irq(struct bnxt *bp)
/* Disable TPH support */
pcie_disable_tph(bp->pdev);
bp->tph_mode = 0;
+
+#ifdef CONFIG_RFS_ACCEL
+ free_irq_cpu_rmap(bp->dev->rx_cpu_rmap);
+ bp->dev->rx_cpu_rmap = NULL;
+#endif
}

static int bnxt_request_irq(struct bnxt *bp)
@@ -16325,6 +16336,10 @@ static const struct netdev_queue_mgmt_ops bnxt_queue_mgmt_ops = {
.supported_params = QCFG_RX_PAGE_SIZE,
};

+static const struct netdev_queue_mgmt_ops bnxt_queue_mgmt_ops_unsupp = {
+ .ndo_default_qcfg = bnxt_queue_default_qcfg,
+};
+
static void bnxt_remove_one(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
@@ -16977,9 +16992,10 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)

if (BNXT_SUPPORTS_NTUPLE_VNIC(bp))
bp->rss_cap |= BNXT_RSS_CAP_MULTI_RSS_CTX;
+
+ dev->queue_mgmt_ops = &bnxt_queue_mgmt_ops_unsupp;
if (BNXT_SUPPORTS_QUEUE_API(bp))
dev->queue_mgmt_ops = &bnxt_queue_mgmt_ops;
- dev->request_ops_lock = true;
dev->netmem_tx = true;

rc = register_netdev(dev);
diff --git a/drivers/net/ethernet/google/gve/gve_ptp.c b/drivers/net/ethernet/google/gve/gve_ptp.c
index a384a9ed4914..1a46e4a9a3cb 100644
--- a/drivers/net/ethernet/google/gve/gve_ptp.c
+++ b/drivers/net/ethernet/google/gve/gve_ptp.c
@@ -26,6 +26,11 @@ int gve_clock_nic_ts_read(struct gve_priv *priv)
return 0;
}

+static int gve_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
+{
+ return -EOPNOTSUPP;
+}
+
static int gve_ptp_gettimex64(struct ptp_clock_info *info,
struct timespec64 *ts,
struct ptp_system_timestamp *sts)
@@ -60,6 +65,7 @@ static long gve_ptp_do_aux_work(struct ptp_clock_info *info)
static const struct ptp_clock_info gve_ptp_caps = {
.owner = THIS_MODULE,
.name = "gve clock",
+ .adjfine = gve_ptp_adjfine,
.gettimex64 = gve_ptp_gettimex64,
.settime64 = gve_ptp_settime64,
.do_aux_work = gve_ptp_do_aux_work,
diff --git a/drivers/net/ethernet/google/gve/gve_rx_dqo.c b/drivers/net/ethernet/google/gve/gve_rx_dqo.c
index fc0c7991c3a2..0c7ab6f4a540 100644
--- a/drivers/net/ethernet/google/gve/gve_rx_dqo.c
+++ b/drivers/net/ethernet/google/gve/gve_rx_dqo.c
@@ -859,6 +859,11 @@ static int gve_rx_dqo(struct napi_struct *napi, struct gve_rx_ring *rx,
rx->rx_hsplit_unsplit_pkt += unsplit;
rx->rx_hsplit_bytes += hdr_len;
u64_stats_update_end(&rx->statss);
+
+ if (!buf_len) {
+ gve_free_buffer(rx, buf_state);
+ return 0;
+ }
} else if (!rx->ctx.skb_head && rx->dqo.page_pool &&
netmem_is_net_iov(buf_state->page_info.netmem)) {
/* when header split is disabled, the header went to the packet
diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
index 31d436cdceb7..5bcf1126d627 100644
--- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c
+++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
@@ -1312,6 +1312,8 @@ static int am65_cpsw_nuss_rx_packets(struct am65_cpsw_rx_flow *flow,
k3_udma_glue_rx_cppi5_to_dma_addr(rx_chn->rx_chn, &buf_dma);
pkt_len = cppi5_hdesc_get_pktlen(desc_rx);
cppi5_desc_get_tags_ids(&desc_rx->hdr, &port_id, NULL);
+ /* Port ID is contained in the lower 8-bits of the 16-bit Source Tag */
+ port_id &= 0xFF;
dev_dbg(dev, "%s rx port_id:%d\n", __func__, port_id);
port = am65_common_get_port(common, port_id);
ndev = port->ndev;
diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
index 58488e138beb..e80962d40f7e 100644
--- a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
+++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
@@ -160,8 +160,10 @@ static void ngbe_irq_enable(struct wx *wx, bool queues)
/* mask interrupt */
if (queues)
wx_intr_enable(wx, NGBE_INTR_ALL);
- else
+ else if (wx->pdev->msix_enabled)
wx_intr_enable(wx, NGBE_INTR_MISC(wx));
+ else
+ wx_intr_enable(wx, BIT(0));
}

/**
diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c
index baccdad695fd..93a8a7c91fb0 100644
--- a/drivers/net/ipvlan/ipvlan_main.c
+++ b/drivers/net/ipvlan/ipvlan_main.c
@@ -146,6 +146,8 @@ static int ipvlan_init(struct net_device *dev)
dev->lltx = true;
netif_inherit_tso_max(dev, phy_dev);
dev->hard_header_len = phy_dev->hard_header_len;
+ dev->needed_headroom = phy_dev->needed_headroom;
+ dev->needed_tailroom = phy_dev->needed_tailroom;

netdev_lockdep_set_classes(dev);

@@ -773,6 +775,8 @@ static int ipvlan_device_event(struct notifier_block *unused,
case NETDEV_FEAT_CHANGE:
list_for_each_entry(ipvlan, &port->ipvlans, pnode) {
netif_inherit_tso_max(ipvlan->dev, dev);
+ ipvlan->dev->needed_headroom = dev->needed_headroom;
+ ipvlan->dev->needed_tailroom = dev->needed_tailroom;
netdev_update_features(ipvlan->dev);
}
break;
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 35dcaa985cfd..7151ae883136 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -943,6 +943,8 @@ static int macvlan_init(struct net_device *dev)
dev->lltx = true;
netif_inherit_tso_max(dev, lowerdev);
dev->hard_header_len = lowerdev->hard_header_len;
+ dev->needed_headroom = lowerdev->needed_headroom;
+ dev->needed_tailroom = lowerdev->needed_tailroom;
macvlan_set_lockdep_class(dev);

vlan->pcpu_stats = netdev_alloc_pcpu_stats(struct vlan_pcpu_stats);
@@ -1817,6 +1819,8 @@ static int macvlan_device_event(struct notifier_block *unused,
case NETDEV_FEAT_CHANGE:
list_for_each_entry(vlan, &port->vlans, list) {
netif_inherit_tso_max(vlan->dev, dev);
+ vlan->dev->needed_headroom = dev->needed_headroom;
+ vlan->dev->needed_tailroom = dev->needed_tailroom;
netdev_update_features(vlan->dev);
}
break;
diff --git a/drivers/net/ntb_netdev.c b/drivers/net/ntb_netdev.c
index fbeae05817e9..b72d0bfd7c2a 100644
--- a/drivers/net/ntb_netdev.c
+++ b/drivers/net/ntb_netdev.c
@@ -53,6 +53,7 @@
#include <linux/pci.h>
#include <linux/ntb.h>
#include <linux/ntb_transport.h>
+#include <linux/slab.h>

#define NTB_NETDEV_VER "0.7"

@@ -70,11 +71,24 @@ static unsigned int tx_start = 10;
/* Number of descriptors still available before stop upper layer tx */
static unsigned int tx_stop = 5;

+#define NTB_NETDEV_MAX_QUEUES 64
+#define NTB_NETDEV_DEFAULT_QUEUES 1
+
+struct ntb_netdev;
+
+struct ntb_netdev_queue {
+ struct ntb_netdev *ntdev;
+ struct ntb_transport_qp *qp;
+ struct timer_list tx_timer;
+ u16 qid;
+};
+
struct ntb_netdev {
struct pci_dev *pdev;
+ struct device *client_dev;
struct net_device *ndev;
- struct ntb_transport_qp *qp;
- struct timer_list tx_timer;
+ unsigned int num_queues;
+ struct ntb_netdev_queue *queues;
};

#define NTB_TX_TIMEOUT_MS 1000
@@ -82,14 +96,17 @@ struct ntb_netdev {

static void ntb_netdev_event_handler(void *data, int link_is_up)
{
- struct net_device *ndev = data;
- struct ntb_netdev *dev = netdev_priv(ndev);
+ struct ntb_netdev_queue *q = data;
+ struct ntb_netdev *dev = q->ntdev;
+ struct net_device *ndev;

- netdev_dbg(ndev, "Event %x, Link %x\n", link_is_up,
- ntb_transport_link_query(dev->qp));
+ ndev = dev->ndev;
+
+ netdev_dbg(ndev, "Event %x, Link %x, qp %u\n", link_is_up,
+ ntb_transport_link_query(q->qp), q->qid);

if (link_is_up) {
- if (ntb_transport_link_query(dev->qp))
+ if (ntb_transport_link_query(q->qp))
netif_carrier_on(ndev);
} else {
netif_carrier_off(ndev);
@@ -99,10 +116,13 @@ static void ntb_netdev_event_handler(void *data, int link_is_up)
static void ntb_netdev_rx_handler(struct ntb_transport_qp *qp, void *qp_data,
void *data, int len)
{
- struct net_device *ndev = qp_data;
- struct sk_buff *skb;
+ struct ntb_netdev_queue *q = qp_data;
+ struct ntb_netdev *dev = q->ntdev;
+ struct sk_buff *skb, *new_skb;
+ struct net_device *ndev;
int rc;

+ ndev = dev->ndev;
skb = data;
if (!skb)
return;
@@ -115,9 +135,16 @@ static void ntb_netdev_rx_handler(struct ntb_transport_qp *qp, void *qp_data,
goto enqueue_again;
}

+ new_skb = netdev_alloc_skb(ndev, ndev->mtu + ETH_HLEN);
+ if (!new_skb) {
+ ndev->stats.rx_dropped++;
+ goto enqueue_again;
+ }
+
skb_put(skb, len);
skb->protocol = eth_type_trans(skb, ndev);
skb->ip_summed = CHECKSUM_NONE;
+ skb_record_rx_queue(skb, q->qid);

if (netif_rx(skb) == NET_RX_DROP) {
ndev->stats.rx_errors++;
@@ -127,12 +154,7 @@ static void ntb_netdev_rx_handler(struct ntb_transport_qp *qp, void *qp_data,
ndev->stats.rx_bytes += len;
}

- skb = netdev_alloc_skb(ndev, ndev->mtu + ETH_HLEN);
- if (!skb) {
- ndev->stats.rx_errors++;
- ndev->stats.rx_frame_errors++;
- return;
- }
+ skb = new_skb;

enqueue_again:
rc = ntb_transport_rx_enqueue(qp, skb, skb->data, ndev->mtu + ETH_HLEN);
@@ -144,42 +166,43 @@ static void ntb_netdev_rx_handler(struct ntb_transport_qp *qp, void *qp_data,
}

static int __ntb_netdev_maybe_stop_tx(struct net_device *netdev,
- struct ntb_transport_qp *qp, int size)
+ struct ntb_netdev_queue *q, int size)
{
- struct ntb_netdev *dev = netdev_priv(netdev);
+ netif_stop_subqueue(netdev, q->qid);

- netif_stop_queue(netdev);
/* Make sure to see the latest value of ntb_transport_tx_free_entry()
* since the queue was last started.
*/
smp_mb();

- if (likely(ntb_transport_tx_free_entry(qp) < size)) {
- mod_timer(&dev->tx_timer, jiffies + usecs_to_jiffies(tx_time));
+ if (likely(ntb_transport_tx_free_entry(q->qp) < size)) {
+ mod_timer(&q->tx_timer, jiffies + usecs_to_jiffies(tx_time));
return -EBUSY;
}

- netif_start_queue(netdev);
+ netif_start_subqueue(netdev, q->qid);
return 0;
}

static int ntb_netdev_maybe_stop_tx(struct net_device *ndev,
- struct ntb_transport_qp *qp, int size)
+ struct ntb_netdev_queue *q, int size)
{
- if (netif_queue_stopped(ndev) ||
- (ntb_transport_tx_free_entry(qp) >= size))
+ if (__netif_subqueue_stopped(ndev, q->qid) ||
+ (ntb_transport_tx_free_entry(q->qp) >= size))
return 0;

- return __ntb_netdev_maybe_stop_tx(ndev, qp, size);
+ return __ntb_netdev_maybe_stop_tx(ndev, q, size);
}

static void ntb_netdev_tx_handler(struct ntb_transport_qp *qp, void *qp_data,
void *data, int len)
{
- struct net_device *ndev = qp_data;
+ struct ntb_netdev_queue *q = qp_data;
+ struct ntb_netdev *dev = q->ntdev;
+ struct net_device *ndev;
struct sk_buff *skb;
- struct ntb_netdev *dev = netdev_priv(ndev);

+ ndev = dev->ndev;
skb = data;
if (!skb || !ndev)
return;
@@ -194,13 +217,13 @@ static void ntb_netdev_tx_handler(struct ntb_transport_qp *qp, void *qp_data,

dev_kfree_skb_any(skb);

- if (ntb_transport_tx_free_entry(dev->qp) >= tx_start) {
+ if (ntb_transport_tx_free_entry(qp) >= tx_start) {
/* Make sure anybody stopping the queue after this sees the new
* value of ntb_transport_tx_free_entry()
*/
smp_mb();
- if (netif_queue_stopped(ndev))
- netif_wake_queue(ndev);
+ if (__netif_subqueue_stopped(ndev, q->qid))
+ netif_wake_subqueue(ndev, q->qid);
}
}

@@ -208,16 +231,20 @@ static netdev_tx_t ntb_netdev_start_xmit(struct sk_buff *skb,
struct net_device *ndev)
{
struct ntb_netdev *dev = netdev_priv(ndev);
+ u16 qid = skb_get_queue_mapping(skb);
+ struct ntb_netdev_queue *q;
int rc;

- ntb_netdev_maybe_stop_tx(ndev, dev->qp, tx_stop);
+ q = &dev->queues[qid];

- rc = ntb_transport_tx_enqueue(dev->qp, skb, skb->data, skb->len);
+ ntb_netdev_maybe_stop_tx(ndev, q, tx_stop);
+
+ rc = ntb_transport_tx_enqueue(q->qp, skb, skb->data, skb->len);
if (rc)
goto err;

/* check for next submit */
- ntb_netdev_maybe_stop_tx(ndev, dev->qp, tx_stop);
+ ntb_netdev_maybe_stop_tx(ndev, q, tx_stop);

return NETDEV_TX_OK;

@@ -229,80 +256,104 @@ static netdev_tx_t ntb_netdev_start_xmit(struct sk_buff *skb,

static void ntb_netdev_tx_timer(struct timer_list *t)
{
- struct ntb_netdev *dev = timer_container_of(dev, t, tx_timer);
- struct net_device *ndev = dev->ndev;
+ struct ntb_netdev_queue *q = timer_container_of(q, t, tx_timer);
+ struct ntb_netdev *dev = q->ntdev;
+ struct net_device *ndev;

- if (ntb_transport_tx_free_entry(dev->qp) < tx_stop) {
- mod_timer(&dev->tx_timer, jiffies + usecs_to_jiffies(tx_time));
+ ndev = dev->ndev;
+
+ if (ntb_transport_tx_free_entry(q->qp) < tx_stop) {
+ mod_timer(&q->tx_timer, jiffies + usecs_to_jiffies(tx_time));
} else {
/* Make sure anybody stopping the queue after this sees the new
* value of ntb_transport_tx_free_entry()
*/
smp_mb();
- if (netif_queue_stopped(ndev))
- netif_wake_queue(ndev);
+ if (__netif_subqueue_stopped(ndev, q->qid))
+ netif_wake_subqueue(ndev, q->qid);
}
}

static int ntb_netdev_open(struct net_device *ndev)
{
struct ntb_netdev *dev = netdev_priv(ndev);
+ struct ntb_netdev_queue *queue;
struct sk_buff *skb;
- int rc, i, len;
-
- /* Add some empty rx bufs */
- for (i = 0; i < NTB_RXQ_SIZE; i++) {
- skb = netdev_alloc_skb(ndev, ndev->mtu + ETH_HLEN);
- if (!skb) {
- rc = -ENOMEM;
- goto err;
- }
+ int rc = 0, i, len;
+ unsigned int q;

- rc = ntb_transport_rx_enqueue(dev->qp, skb, skb->data,
- ndev->mtu + ETH_HLEN);
- if (rc) {
- dev_kfree_skb(skb);
- goto err;
+ /* Add some empty rx bufs for each queue */
+ for (q = 0; q < dev->num_queues; q++) {
+ queue = &dev->queues[q];
+
+ for (i = 0; i < NTB_RXQ_SIZE; i++) {
+ skb = netdev_alloc_skb(ndev, ndev->mtu + ETH_HLEN);
+ if (!skb) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ rc = ntb_transport_rx_enqueue(queue->qp, skb, skb->data,
+ ndev->mtu + ETH_HLEN);
+ if (rc) {
+ dev_kfree_skb(skb);
+ goto err;
+ }
}
- }

- timer_setup(&dev->tx_timer, ntb_netdev_tx_timer, 0);
+ timer_setup(&queue->tx_timer, ntb_netdev_tx_timer, 0);
+ }

netif_carrier_off(ndev);
- ntb_transport_link_up(dev->qp);
+
+ for (q = 0; q < dev->num_queues; q++)
+ ntb_transport_link_up(dev->queues[q].qp);
+
netif_start_queue(ndev);

return 0;

err:
- while ((skb = ntb_transport_rx_remove(dev->qp, &len)))
- dev_kfree_skb(skb);
+ for (q = 0; q < dev->num_queues; q++) {
+ queue = &dev->queues[q];
+
+ while ((skb = ntb_transport_rx_remove(queue->qp, &len)))
+ dev_kfree_skb(skb);
+ }
return rc;
}

static int ntb_netdev_close(struct net_device *ndev)
{
struct ntb_netdev *dev = netdev_priv(ndev);
+ struct ntb_netdev_queue *queue;
struct sk_buff *skb;
+ unsigned int q;
int len;

- ntb_transport_link_down(dev->qp);

- while ((skb = ntb_transport_rx_remove(dev->qp, &len)))
- dev_kfree_skb(skb);
+ for (q = 0; q < dev->num_queues; q++) {
+ queue = &dev->queues[q];

- timer_delete_sync(&dev->tx_timer);
+ ntb_transport_link_down(queue->qp);
+
+ while ((skb = ntb_transport_rx_remove(queue->qp, &len)))
+ dev_kfree_skb(skb);

+ timer_delete_sync(&queue->tx_timer);
+ }
return 0;
}

static int ntb_netdev_change_mtu(struct net_device *ndev, int new_mtu)
{
struct ntb_netdev *dev = netdev_priv(ndev);
+ struct ntb_netdev_queue *queue;
struct sk_buff *skb;
- int len, rc;
+ unsigned int q, i;
+ int len, rc = 0;

- if (new_mtu > ntb_transport_max_size(dev->qp) - ETH_HLEN)
+ if (new_mtu > ntb_transport_max_size(dev->queues[0].qp) - ETH_HLEN)
return -EINVAL;

if (!netif_running(ndev)) {
@@ -311,41 +362,54 @@ static int ntb_netdev_change_mtu(struct net_device *ndev, int new_mtu)
}

/* Bring down the link and dispose of posted rx entries */
- ntb_transport_link_down(dev->qp);
+ for (q = 0; q < dev->num_queues; q++)
+ ntb_transport_link_down(dev->queues[q].qp);

if (ndev->mtu < new_mtu) {
- int i;
-
- for (i = 0; (skb = ntb_transport_rx_remove(dev->qp, &len)); i++)
- dev_kfree_skb(skb);
+ for (q = 0; q < dev->num_queues; q++) {
+ queue = &dev->queues[q];

- for (; i; i--) {
- skb = netdev_alloc_skb(ndev, new_mtu + ETH_HLEN);
- if (!skb) {
- rc = -ENOMEM;
- goto err;
- }
-
- rc = ntb_transport_rx_enqueue(dev->qp, skb, skb->data,
- new_mtu + ETH_HLEN);
- if (rc) {
+ for (i = 0;
+ (skb = ntb_transport_rx_remove(queue->qp, &len));
+ i++)
dev_kfree_skb(skb);
- goto err;
+
+ for (; i; i--) {
+ skb = netdev_alloc_skb(ndev,
+ new_mtu + ETH_HLEN);
+ if (!skb) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ rc = ntb_transport_rx_enqueue(queue->qp, skb,
+ skb->data,
+ new_mtu +
+ ETH_HLEN);
+ if (rc) {
+ dev_kfree_skb(skb);
+ goto err;
+ }
}
}
}

WRITE_ONCE(ndev->mtu, new_mtu);

- ntb_transport_link_up(dev->qp);
+ for (q = 0; q < dev->num_queues; q++)
+ ntb_transport_link_up(dev->queues[q].qp);

return 0;

err:
- ntb_transport_link_down(dev->qp);
+ for (q = 0; q < dev->num_queues; q++) {
+ struct ntb_netdev_queue *queue = &dev->queues[q];
+
+ ntb_transport_link_down(queue->qp);

- while ((skb = ntb_transport_rx_remove(dev->qp, &len)))
- dev_kfree_skb(skb);
+ while ((skb = ntb_transport_rx_remove(queue->qp, &len)))
+ dev_kfree_skb(skb);
+ }

netdev_err(ndev, "Error changing MTU, device inoperable\n");
return rc;
@@ -404,6 +468,7 @@ static int ntb_netdev_probe(struct device *client_dev)
struct net_device *ndev;
struct pci_dev *pdev;
struct ntb_netdev *dev;
+ unsigned int q;
int rc;

ntb = dev_ntb(client_dev->parent);
@@ -411,7 +476,7 @@ static int ntb_netdev_probe(struct device *client_dev)
if (!pdev)
return -ENODEV;

- ndev = alloc_etherdev(sizeof(*dev));
+ ndev = alloc_etherdev_mq(sizeof(*dev), NTB_NETDEV_MAX_QUEUES);
if (!ndev)
return -ENOMEM;

@@ -420,6 +485,16 @@ static int ntb_netdev_probe(struct device *client_dev)
dev = netdev_priv(ndev);
dev->ndev = ndev;
dev->pdev = pdev;
+ dev->client_dev = client_dev;
+ dev->num_queues = 0;
+
+ dev->queues = kzalloc_objs(*dev->queues, NTB_NETDEV_MAX_QUEUES,
+ GFP_KERNEL);
+ if (!dev->queues) {
+ rc = -ENOMEM;
+ goto err_free_netdev;
+ }
+
ndev->features = NETIF_F_HIGHDMA;

ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
@@ -436,26 +511,47 @@ static int ntb_netdev_probe(struct device *client_dev)
ndev->min_mtu = 0;
ndev->max_mtu = ETH_MAX_MTU;

- dev->qp = ntb_transport_create_queue(ndev, client_dev,
- &ntb_netdev_handlers);
- if (!dev->qp) {
+ for (q = 0; q < NTB_NETDEV_DEFAULT_QUEUES; q++) {
+ struct ntb_netdev_queue *queue = &dev->queues[q];
+
+ queue->ntdev = dev;
+ queue->qid = q;
+ queue->qp = ntb_transport_create_queue(queue, client_dev,
+ &ntb_netdev_handlers);
+ if (!queue->qp)
+ break;
+
+ dev->num_queues++;
+ }
+
+ if (!dev->num_queues) {
rc = -EIO;
- goto err;
+ goto err_free_queues;
}

- ndev->mtu = ntb_transport_max_size(dev->qp) - ETH_HLEN;
+ rc = netif_set_real_num_queues(ndev, dev->num_queues, dev->num_queues);
+ if (rc)
+ goto err_free_qps;
+
+ ndev->mtu = ntb_transport_max_size(dev->queues[0].qp) - ETH_HLEN;

rc = register_netdev(ndev);
if (rc)
- goto err1;
+ goto err_free_qps;

dev_set_drvdata(client_dev, ndev);
- dev_info(&pdev->dev, "%s created\n", ndev->name);
+ dev_info(&pdev->dev, "%s created with %u queue pairs\n",
+ ndev->name, dev->num_queues);
return 0;

-err1:
- ntb_transport_free_queue(dev->qp);
-err:
+err_free_qps:
+ for (q = 0; q < dev->num_queues; q++)
+ ntb_transport_free_queue(dev->queues[q].qp);
+
+err_free_queues:
+ kfree(dev->queues);
+
+err_free_netdev:
free_netdev(ndev);
return rc;
}
@@ -464,9 +560,13 @@ static void ntb_netdev_remove(struct device *client_dev)
{
struct net_device *ndev = dev_get_drvdata(client_dev);
struct ntb_netdev *dev = netdev_priv(ndev);
+ unsigned int q;

unregister_netdev(ndev);
- ntb_transport_free_queue(dev->qp);
+ for (q = 0; q < dev->num_queues; q++)
+ ntb_transport_free_queue(dev->queues[q].qp);
+
+ kfree(dev->queues);
free_netdev(ndev);
}

diff --git a/drivers/net/ovpn/crypto.c b/drivers/net/ovpn/crypto.c
index 90580e32052f..2e95f29514fc 100644
--- a/drivers/net/ovpn/crypto.c
+++ b/drivers/net/ovpn/crypto.c
@@ -58,15 +58,19 @@ void ovpn_crypto_state_release(struct ovpn_crypto_state *cs)
bool ovpn_crypto_kill_key(struct ovpn_crypto_state *cs, u8 key_id)
{
struct ovpn_crypto_key_slot *ks = NULL;
+ struct ovpn_crypto_key_slot *tmp;
+ int slot = 0;

spin_lock_bh(&cs->lock);
- if (rcu_access_pointer(cs->slots[0])->key_id == key_id) {
- ks = rcu_replace_pointer(cs->slots[0], NULL,
- lockdep_is_held(&cs->lock));
- } else if (rcu_access_pointer(cs->slots[1])->key_id == key_id) {
- ks = rcu_replace_pointer(cs->slots[1], NULL,
- lockdep_is_held(&cs->lock));
+ tmp = rcu_access_pointer(cs->slots[slot]);
+ if (!tmp || tmp->key_id != key_id) {
+ slot = 1;
+ tmp = rcu_access_pointer(cs->slots[slot]);
}
+
+ if (tmp && tmp->key_id == key_id)
+ ks = rcu_replace_pointer(cs->slots[slot], NULL,
+ lockdep_is_held(&cs->lock));
spin_unlock_bh(&cs->lock);

if (ks)
diff --git a/drivers/net/ovpn/io.c b/drivers/net/ovpn/io.c
index 0008a3d30c19..65a904c64e05 100644
--- a/drivers/net/ovpn/io.c
+++ b/drivers/net/ovpn/io.c
@@ -199,10 +199,10 @@ void ovpn_decrypt_post(void *data, int ret)
ovpn_dev_dstats_rx_dropped(peer->ovpn->dev);
kfree_skb(skb);
drop_nocount:
- if (likely(peer))
- ovpn_peer_put(peer);
if (likely(ks))
ovpn_crypto_key_slot_put(ks);
+ if (likely(peer))
+ ovpn_peer_put(peer);
}

/* RX path entry point: decrypt packet and forward it to the device */
@@ -299,11 +299,11 @@ void ovpn_encrypt_post(void *data, int ret)
err:
if (unlikely(skb))
ovpn_dev_dstats_tx_dropped(peer->ovpn->dev);
- if (likely(peer))
- ovpn_peer_put(peer);
+ kfree_skb(skb);
if (likely(ks))
ovpn_crypto_key_slot_put(ks);
- kfree_skb(skb);
+ if (likely(peer))
+ ovpn_peer_put(peer);
}

static bool ovpn_encrypt_one(struct ovpn_peer *peer, struct sk_buff *skb)
diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c
index 05df1a33b0e2..ef8c3b23bee8 100644
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -1164,7 +1164,7 @@ static int rtlgen_write_mmd(struct phy_device *phydev, int devnum, u16 regnum,
if (devnum == MDIO_MMD_VEND2)
ret = rtlgen_write_vend2(phydev, regnum, val);
else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV)
- ret = rtlgen_write_vend2(phydev, regnum, RTL_MDIO_AN_EEE_ADV);
+ ret = rtlgen_write_vend2(phydev, RTL_MDIO_AN_EEE_ADV, val);
else
ret = -EOPNOTSUPP;

diff --git a/drivers/net/tap.c b/drivers/net/tap.c
index bb62faad5b5c..1aeaecd4030f 100644
--- a/drivers/net/tap.c
+++ b/drivers/net/tap.c
@@ -1091,12 +1091,13 @@ static int tap_get_user_xdp(struct tap_queue *q, struct xdp_buff *xdp)
}
}

+ skb_probe_transport_header(skb);
+
/* Move network header to the right position for VLAN tagged packets */
if (eth_type_vlan(skb->protocol) &&
vlan_get_protocol_and_depth(skb, skb->protocol, &depth) != 0)
skb_set_network_header(skb, depth);

- skb_probe_transport_header(skb);
dev_queue_xmit(skb);
rcu_read_unlock();

diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index ffe05e331224..df276a646c45 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -967,7 +967,7 @@ static int veth_poll(struct napi_struct *napi, int budget)
struct veth_rq *rq =
container_of(napi, struct veth_rq, xdp_napi);
struct veth_priv *priv = netdev_priv(rq->dev);
- int queue_idx = rq->xdp_rxq.queue_index;
+ int queue_idx = rq - priv->rq;
struct netdev_queue *peer_txq;
struct veth_stats stats = {};
struct net_device *peer_dev;
diff --git a/drivers/pmdomain/arm/scmi_perf_domain.c b/drivers/pmdomain/arm/scmi_perf_domain.c
index 3693423459c9..e390f902a444 100644
--- a/drivers/pmdomain/arm/scmi_perf_domain.c
+++ b/drivers/pmdomain/arm/scmi_perf_domain.c
@@ -33,7 +33,7 @@ scmi_pd_set_perf_state(struct generic_pm_domain *genpd, unsigned int state)
return 0;

if (!state)
- return -EINVAL;
+ return 0;

ret = pd->perf_ops->level_set(pd->ph, pd->domain_id, state, false);
if (ret)
diff --git a/drivers/pmdomain/mediatek/mt8183-pm-domains.h b/drivers/pmdomain/mediatek/mt8183-pm-domains.h
index 3742782a2702..5e33b8628e85 100644
--- a/drivers/pmdomain/mediatek/mt8183-pm-domains.h
+++ b/drivers/pmdomain/mediatek/mt8183-pm-domains.h
@@ -47,7 +47,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = {
.pwr_sta2nd_offs = 0x0184,
.sram_pdn_bits = 0,
.sram_pdn_ack_bits = 0,
- .caps = MTK_SCPD_DOMAIN_SUPPLY,
+ .caps = MTK_SCPD_DOMAIN_SUPPLY | MTK_SCPD_KEEP_DEFAULT_OFF,
},
[MT8183_POWER_DOMAIN_MFG] = {
.name = "mfg",
@@ -57,7 +57,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = {
.pwr_sta2nd_offs = 0x0184,
.sram_pdn_bits = GENMASK(8, 8),
.sram_pdn_ack_bits = GENMASK(12, 12),
- .caps = MTK_SCPD_DOMAIN_SUPPLY,
+ .caps = MTK_SCPD_DOMAIN_SUPPLY | MTK_SCPD_KEEP_DEFAULT_OFF,
},
[MT8183_POWER_DOMAIN_MFG_CORE0] = {
.name = "mfg_core0",
@@ -67,6 +67,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = {
.pwr_sta2nd_offs = 0x0184,
.sram_pdn_bits = GENMASK(8, 8),
.sram_pdn_ack_bits = GENMASK(12, 12),
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
},
[MT8183_POWER_DOMAIN_MFG_CORE1] = {
.name = "mfg_core1",
@@ -76,6 +77,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = {
.pwr_sta2nd_offs = 0x0184,
.sram_pdn_bits = GENMASK(8, 8),
.sram_pdn_ack_bits = GENMASK(12, 12),
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
},
[MT8183_POWER_DOMAIN_MFG_2D] = {
.name = "mfg_2d",
@@ -85,6 +87,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = {
.pwr_sta2nd_offs = 0x0184,
.sram_pdn_bits = GENMASK(8, 8),
.sram_pdn_ack_bits = GENMASK(12, 12),
+ .caps = MTK_SCPD_KEEP_DEFAULT_OFF,
.bp_cfg = {
BUS_PROT_WR(INFRA,
MT8183_TOP_AXI_PROT_EN_1_MFG,
diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.c b/drivers/pmdomain/mediatek/mtk-pm-domains.c
index 1716d726b8cc..5b3752043d8a 100644
--- a/drivers/pmdomain/mediatek/mtk-pm-domains.c
+++ b/drivers/pmdomain/mediatek/mtk-pm-domains.c
@@ -266,16 +266,8 @@ static int scpsys_ctl_pwrseq_on(struct scpsys_domain *pd)
if (ret < 0)
return ret;

- if (pd->data->rtff_type == SCPSYS_RTFF_TYPE_PCIE_PHY)
- regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_CLK_DIS);
-
regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_CLK_DIS_BIT);
regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ISO_BIT);
-
- /* Wait for RTFF HW to sync buck isolation state if this is PCIe PHY RTFF */
- if (pd->data->rtff_type == SCPSYS_RTFF_TYPE_PCIE_PHY)
- udelay(5);
-
regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT);

/*
@@ -774,12 +766,15 @@ static int scpsys_get_bus_protection_legacy(struct device *dev, struct scpsys *s
node = of_find_node_with_property(np, "mediatek,infracfg");
if (node) {
regmap[0] = syscon_regmap_lookup_by_phandle(node, "mediatek,infracfg");
- of_node_put(node);
num_regmaps++;
- if (IS_ERR(regmap[0]))
- return dev_err_probe(dev, PTR_ERR(regmap[0]),
+ if (IS_ERR(regmap[0])) {
+ ret = dev_err_probe(dev, PTR_ERR(regmap[0]),
"%pOF: failed to get infracfg regmap\n",
node);
+ of_node_put(node);
+ return ret;
+ }
+ of_node_put(node);
} else {
regmap[0] = NULL;
}
@@ -788,17 +783,22 @@ static int scpsys_get_bus_protection_legacy(struct device *dev, struct scpsys *s
node = of_find_node_with_property(np, "mediatek,smi");
if (node) {
smi_np = of_parse_phandle(node, "mediatek,smi", 0);
- of_node_put(node);
- if (!smi_np)
+ if (!smi_np) {
+ of_node_put(node);
return -ENODEV;
+ }

regmap[1] = device_node_to_regmap(smi_np);
num_regmaps++;
of_node_put(smi_np);
- if (IS_ERR(regmap[1]))
- return dev_err_probe(dev, PTR_ERR(regmap[1]),
+ if (IS_ERR(regmap[1])) {
+ ret = dev_err_probe(dev, PTR_ERR(regmap[1]),
"%pOF: failed to get SMI regmap\n",
node);
+ of_node_put(node);
+ return ret;
+ }
+ of_node_put(node);
} else {
regmap[1] = NULL;
}
diff --git a/drivers/s390/cio/vfio_ccw_async.c b/drivers/s390/cio/vfio_ccw_async.c
index 420d89ba7f83..4aff0b58fa5d 100644
--- a/drivers/s390/cio/vfio_ccw_async.c
+++ b/drivers/s390/cio/vfio_ccw_async.c
@@ -8,6 +8,7 @@
*/

#include <linux/vfio.h>
+#include <linux/nospec.h>

#include "vfio_ccw_private.h"

@@ -24,11 +25,20 @@ static ssize_t vfio_ccw_async_region_read(struct vfio_ccw_private *private,
return -EINVAL;

mutex_lock(&private->io_mutex);
+
+ if (i >= private->num_regions) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ i = array_index_nospec(i, private->num_regions);
region = private->region[i].data;
if (copy_to_user(buf, (void *)region + pos, count))
ret = -EFAULT;
else
ret = count;
+
+out_unlock:
mutex_unlock(&private->io_mutex);
return ret;
}
@@ -48,6 +58,12 @@ static ssize_t vfio_ccw_async_region_write(struct vfio_ccw_private *private,
if (!mutex_trylock(&private->io_mutex))
return -EAGAIN;

+ if (i >= private->num_regions) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ i = array_index_nospec(i, private->num_regions);
region = private->region[i].data;
if (copy_from_user((void *)region + pos, buf, count)) {
ret = -EFAULT;
diff --git a/drivers/s390/cio/vfio_ccw_chp.c b/drivers/s390/cio/vfio_ccw_chp.c
index 38c176cf6295..7708eb4d6de0 100644
--- a/drivers/s390/cio/vfio_ccw_chp.c
+++ b/drivers/s390/cio/vfio_ccw_chp.c
@@ -9,6 +9,7 @@
*/

#include <linux/slab.h>
+#include <linux/nospec.h>
#include <linux/vfio.h>
#include "vfio_ccw_private.h"

@@ -26,6 +27,13 @@ static ssize_t vfio_ccw_schib_region_read(struct vfio_ccw_private *private,
return -EINVAL;

mutex_lock(&private->io_mutex);
+
+ if (i >= private->num_regions) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ i = array_index_nospec(i, private->num_regions);
region = private->region[i].data;

if (cio_update_schib(sch)) {
@@ -85,19 +93,30 @@ static ssize_t vfio_ccw_crw_region_read(struct vfio_ccw_private *private,
loff_t pos = *ppos & VFIO_CCW_OFFSET_MASK;
struct ccw_crw_region *region;
struct vfio_ccw_crw *crw;
+ unsigned long flags;
int ret;

if (pos + count > sizeof(*region))
return -EINVAL;

+ mutex_lock(&private->io_mutex);
+ if (i >= private->num_regions) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ i = array_index_nospec(i, private->num_regions);
+ region = private->region[i].data;
+
+ spin_lock_irqsave(&private->crw_lock, flags);
crw = list_first_entry_or_null(&private->crw,
struct vfio_ccw_crw, next);

if (crw)
list_del(&crw->next);

- mutex_lock(&private->io_mutex);
- region = private->region[i].data;
+ /* Drop CRW lock while copying to userspace */
+ spin_unlock_irqrestore(&private->crw_lock, flags);

if (crw)
memcpy(&region->crw, &crw->crw, sizeof(region->crw));
@@ -108,14 +127,16 @@ static ssize_t vfio_ccw_crw_region_read(struct vfio_ccw_private *private,
ret = count;

region->crw = 0;
-
- mutex_unlock(&private->io_mutex);
-
kfree(crw);

/* Notify the guest if more CRWs are on our queue */
+ spin_lock_irqsave(&private->crw_lock, flags);
if (!list_empty(&private->crw) && private->crw_trigger)
eventfd_signal(private->crw_trigger);
+ spin_unlock_irqrestore(&private->crw_lock, flags);
+
+out:
+ mutex_unlock(&private->io_mutex);

return ret;
}
diff --git a/drivers/s390/cio/vfio_ccw_cp.c b/drivers/s390/cio/vfio_ccw_cp.c
index 5f6e10225627..36985aed125c 100644
--- a/drivers/s390/cio/vfio_ccw_cp.c
+++ b/drivers/s390/cio/vfio_ccw_cp.c
@@ -233,6 +233,7 @@ static void convert_ccw0_to_ccw1(struct ccw1 *source, unsigned long len)
}

#define idal_is_2k(_cp) (!(_cp)->orb.cmd.c64 || (_cp)->orb.cmd.i2k)
+#define get_idaw_size(_cp) ((_cp)->orb.cmd.c64 ? sizeof(u64) : sizeof(u32))

/*
* Helpers to operate ccwchain.
@@ -332,6 +333,7 @@ static struct ccwchain *ccwchain_alloc(struct channel_program *cp, int len)
goto out_err;

list_add_tail(&chain->next, &cp->ccwchain_list);
+ cp->ccwchain_count++;

return chain;

@@ -376,11 +378,9 @@ static void ccwchain_cda_free(struct ccwchain *chain, int idx)
static int ccwchain_calc_length(u64 iova, struct channel_program *cp)
{
struct ccw1 *ccw = cp->guest_cp;
- int cnt = 0;
-
- do {
- cnt++;
+ int cnt;

+ for (cnt = 1; cnt <= CCWCHAIN_LEN_MAX; cnt++, ccw++) {
/*
* We want to keep counting if the current CCW has the
* command-chaining flag enabled, or if it is a TIC CCW
@@ -390,15 +390,10 @@ static int ccwchain_calc_length(u64 iova, struct channel_program *cp)
* after the TIC, depending on the results of its operation.
*/
if (!ccw_is_chain(ccw) && !is_tic_within_range(ccw, iova, cnt))
- break;
-
- ccw++;
- } while (cnt < CCWCHAIN_LEN_MAX + 1);
-
- if (cnt == CCWCHAIN_LEN_MAX + 1)
- cnt = -EINVAL;
+ return cnt;
+ }

- return cnt;
+ return -EINVAL;
}

static int tic_target_chain_exists(struct ccw1 *tic, struct channel_program *cp)
@@ -441,6 +436,10 @@ static int ccwchain_handle_ccw(dma32_t cda, struct channel_program *cp)
if (len < 0)
return len;

+ /* Limit number of chains in a single channel program */
+ if (cp->ccwchain_count >= CCWCHAIN_COUNT_MAX)
+ return -EINVAL;
+
/* Need alloc a new chain for this one. */
chain = ccwchain_alloc(cp, len);
if (!chain)
@@ -455,9 +454,6 @@ static int ccwchain_handle_ccw(dma32_t cda, struct channel_program *cp)
/* Loop for tics on this new chain. */
ret = ccwchain_loop_tic(chain, cp);

- if (ret)
- ccwchain_free(chain);
-
return ret;
}

@@ -486,6 +482,23 @@ static int ccwchain_loop_tic(struct ccwchain *chain, struct channel_program *cp)
return 0;
}

+static int ccwchain_build_ccws(dma32_t cda, struct channel_program *cp)
+{
+ struct ccwchain *chain, *temp;
+ int ret;
+
+ ret = ccwchain_handle_ccw(cda, cp);
+
+ if (ret) {
+ /* Cleanup if an error occurred */
+ list_for_each_entry_safe(chain, temp, &cp->ccwchain_list, next) {
+ ccwchain_free(chain);
+ }
+ }
+
+ return ret;
+}
+
static int ccwchain_fetch_tic(struct ccw1 *ccw,
struct channel_program *cp)
{
@@ -511,7 +524,8 @@ static dma64_t *get_guest_idal(struct ccw1 *ccw, struct channel_program *cp, int
&container_of(cp, struct vfio_ccw_private, cp)->vdev;
dma64_t *idaws;
dma32_t *idaws_f1;
- int idal_len = idaw_nr * sizeof(*idaws);
+ u64 first_idaw;
+ int idal_len = idaw_nr * get_idaw_size(cp);
int idaw_size = idal_is_2k(cp) ? PAGE_SIZE / 2 : PAGE_SIZE;
int idaw_mask = ~(idaw_size - 1);
int i, ret;
@@ -527,6 +541,18 @@ static dma64_t *get_guest_idal(struct ccw1 *ccw, struct channel_program *cp, int
kfree(idaws);
return ERR_PTR(ret);
}
+
+ idaws_f1 = (dma32_t *)idaws;
+ if (cp->orb.cmd.c64)
+ first_idaw = dma64_to_u64(idaws[0]);
+ else
+ first_idaw = dma32_to_u32(idaws_f1[0]);
+
+ /* Unexpected mismatch from earlier read */
+ if (first_idaw != cp->guest_iova) {
+ kfree(idaws);
+ return ERR_PTR(-EINVAL);
+ }
} else {
/* Fabricate an IDAL based off CCW data address */
if (cp->orb.cmd.c64) {
@@ -568,7 +594,7 @@ static int ccw_count_idaws(struct ccw1 *ccw,
struct vfio_device *vdev =
&container_of(cp, struct vfio_ccw_private, cp)->vdev;
u64 iova;
- int size = cp->orb.cmd.c64 ? sizeof(u64) : sizeof(u32);
+ int size = get_idaw_size(cp);
int ret;
int bytes = 1;

@@ -592,6 +618,9 @@ static int ccw_count_idaws(struct ccw1 *ccw,
iova = dma32_to_u32(ccw->cda);
}

+ /* Save the read address for later */
+ cp->guest_iova = iova;
+
/* Format-1 IDAWs operate on 2K each */
if (!cp->orb.cmd.c64)
return idal_2k_nr_words((void *)iova, bytes);
@@ -731,11 +760,12 @@ int cp_init(struct channel_program *cp, union orb *orb)
vdev->dev,
"Prefetching channel program even though prefetch not specified in ORB");

+ cp->ccwchain_count = 0;
INIT_LIST_HEAD(&cp->ccwchain_list);
memcpy(&cp->orb, orb, sizeof(*orb));

/* Build a ccwchain for the first CCW segment */
- ret = ccwchain_handle_ccw(orb->cmd.cpa, cp);
+ ret = ccwchain_build_ccws(orb->cmd.cpa, cp);

if (!ret)
cp->initialized = true;
@@ -947,17 +977,23 @@ void cp_update_scsw(struct channel_program *cp, union scsw *scsw)
*/
bool cp_iova_pinned(struct channel_program *cp, u64 iova, u64 length)
{
+ struct vfio_ccw_private *private =
+ container_of(cp, struct vfio_ccw_private, cp);
struct ccwchain *chain;
int i;

if (!cp->initialized)
return false;

+ mutex_lock(&private->io_mutex);
list_for_each_entry(chain, &cp->ccwchain_list, next) {
for (i = 0; i < chain->ch_len; i++)
- if (page_array_iova_pinned(&chain->ch_pa[i], iova, length))
+ if (page_array_iova_pinned(&chain->ch_pa[i], iova, length)) {
+ mutex_unlock(&private->io_mutex);
return true;
+ }
}
+ mutex_unlock(&private->io_mutex);

return false;
}
diff --git a/drivers/s390/cio/vfio_ccw_cp.h b/drivers/s390/cio/vfio_ccw_cp.h
index fc31eb699807..9af98ff12d67 100644
--- a/drivers/s390/cio/vfio_ccw_cp.h
+++ b/drivers/s390/cio/vfio_ccw_cp.h
@@ -23,11 +23,19 @@
*/
#define CCWCHAIN_LEN_MAX 256

+/*
+ * Maximum number of chains
+ */
+#define CCWCHAIN_COUNT_MAX 16
+
/**
* struct channel_program - manage information for channel program
* @ccwchain_list: list head of ccwchains
* @orb: orb for the currently processed ssch request
* @initialized: whether this instance is actually initialized
+ * @guest_cp: copy of guest channel program
+ * @ccwchain_count: number of channel program segments (linked by TIC)
+ * @guest_iova: first data address of a guest channel program
*
* @ccwchain_list is the head of a ccwchain list, that contents the
* translated result of the guest channel program that pointed out by
@@ -38,6 +46,8 @@ struct channel_program {
union orb orb;
bool initialized;
struct ccw1 *guest_cp;
+ unsigned int ccwchain_count;
+ u64 guest_iova;
};

int cp_init(struct channel_program *cp, union orb *orb);
diff --git a/drivers/s390/cio/vfio_ccw_drv.c b/drivers/s390/cio/vfio_ccw_drv.c
index 6ff5c9cfb7ed..cf5b92a63d06 100644
--- a/drivers/s390/cio/vfio_ccw_drv.c
+++ b/drivers/s390/cio/vfio_ccw_drv.c
@@ -91,6 +91,7 @@ void vfio_ccw_sch_io_todo(struct work_struct *work)

is_final = !(scsw_actl(&irb->scsw) &
(SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT));
+ mutex_lock(&private->io_mutex);
if (scsw_is_solicited(&irb->scsw)) {
cp_update_scsw(&private->cp, &irb->scsw);
if (is_final && private->state == VFIO_CCW_STATE_CP_PENDING) {
@@ -98,9 +99,7 @@ void vfio_ccw_sch_io_todo(struct work_struct *work)
cp_is_finished = true;
}
}
- mutex_lock(&private->io_mutex);
memcpy(private->io_region->irb_area, irb, sizeof(*irb));
- mutex_unlock(&private->io_mutex);

/*
* Reset to IDLE only if processing of a channel program
@@ -110,6 +109,7 @@ void vfio_ccw_sch_io_todo(struct work_struct *work)
*/
if (cp_is_finished)
private->state = VFIO_CCW_STATE_IDLE;
+ mutex_unlock(&private->io_mutex);

if (private->io_trigger)
eventfd_signal(private->io_trigger);
@@ -118,11 +118,25 @@ void vfio_ccw_sch_io_todo(struct work_struct *work)
void vfio_ccw_crw_todo(struct work_struct *work)
{
struct vfio_ccw_private *private;
+ unsigned long flags;

private = container_of(work, struct vfio_ccw_private, crw_work);

+ spin_lock_irqsave(&private->crw_lock, flags);
if (!list_empty(&private->crw) && private->crw_trigger)
eventfd_signal(private->crw_trigger);
+ spin_unlock_irqrestore(&private->crw_lock, flags);
+}
+
+void vfio_ccw_notoper_todo(struct work_struct *work)
+{
+ struct vfio_ccw_private *private;
+
+ private = container_of(work, struct vfio_ccw_private, notoper_work);
+
+ mutex_lock(&private->io_mutex);
+ cp_free(&private->cp);
+ mutex_unlock(&private->io_mutex);
}

/*
@@ -275,6 +289,7 @@ static void vfio_ccw_queue_crw(struct vfio_ccw_private *private,
unsigned int rsid)
{
struct vfio_ccw_crw *crw;
+ unsigned long flags;

/*
* If unable to allocate a CRW, just drop the event and
@@ -292,7 +307,9 @@ static void vfio_ccw_queue_crw(struct vfio_ccw_private *private,
crw->crw.erc = erc;
crw->crw.rsid = rsid;

+ spin_lock_irqsave(&private->crw_lock, flags);
list_add_tail(&crw->next, &private->crw);
+ spin_unlock_irqrestore(&private->crw_lock, flags);
queue_work(vfio_ccw_work_q, &private->crw_work);
}

diff --git a/drivers/s390/cio/vfio_ccw_fsm.c b/drivers/s390/cio/vfio_ccw_fsm.c
index 4d7988ea47ef..5fd94e9d5c61 100644
--- a/drivers/s390/cio/vfio_ccw_fsm.c
+++ b/drivers/s390/cio/vfio_ccw_fsm.c
@@ -170,8 +170,8 @@ static void fsm_notoper(struct vfio_ccw_private *private,
css_sched_sch_todo(sch, SCH_TODO_UNREG);
private->state = VFIO_CCW_STATE_NOT_OPER;

- /* This is usually handled during CLOSE event */
- cp_free(&private->cp);
+ /* This routine could be called from IRQ context, so defer */
+ queue_work(vfio_ccw_work_q, &private->notoper_work);
}

/*
@@ -410,7 +410,11 @@ static void fsm_close(struct vfio_ccw_private *private,

private->state = VFIO_CCW_STATE_STANDBY;
spin_unlock_irq(&sch->lock);
+
+ mutex_lock(&private->io_mutex);
cp_free(&private->cp);
+ mutex_unlock(&private->io_mutex);
+
return;

err_unlock:
diff --git a/drivers/s390/cio/vfio_ccw_ops.c b/drivers/s390/cio/vfio_ccw_ops.c
index ea532a8a4a0c..b7acc2532096 100644
--- a/drivers/s390/cio/vfio_ccw_ops.c
+++ b/drivers/s390/cio/vfio_ccw_ops.c
@@ -54,6 +54,8 @@ static int vfio_ccw_mdev_init_dev(struct vfio_device *vdev)
INIT_LIST_HEAD(&private->crw);
INIT_WORK(&private->io_work, vfio_ccw_sch_io_todo);
INIT_WORK(&private->crw_work, vfio_ccw_crw_todo);
+ INIT_WORK(&private->notoper_work, vfio_ccw_notoper_todo);
+ spin_lock_init(&private->crw_lock);

private->cp.guest_cp = kcalloc(CCWCHAIN_LEN_MAX, sizeof(struct ccw1),
GFP_KERNEL);
@@ -131,11 +133,28 @@ static void vfio_ccw_mdev_release_dev(struct vfio_device *vdev)
struct vfio_ccw_private *private =
container_of(vdev, struct vfio_ccw_private, vdev);
struct vfio_ccw_crw *crw, *temp;
+ unsigned long flags;

+ /*
+ * Ensure these work items are fully drained, so none can
+ * fire after being released.
+ *
+ * notoper_work should have nothing to do here, because only
+ * open devices could have channel_program resources in use
+ * and those would be released during close. Nevertheless,
+ * call flush here as well to be certain anything that was
+ * allocated is freed.
+ */
+ cancel_work_sync(&private->io_work);
+ cancel_work_sync(&private->crw_work);
+ flush_work(&private->notoper_work);
+
+ spin_lock_irqsave(&private->crw_lock, flags);
list_for_each_entry_safe(crw, temp, &private->crw, next) {
list_del(&crw->next);
kfree(crw);
}
+ spin_unlock_irqrestore(&private->crw_lock, flags);

kmem_cache_free(vfio_ccw_crw_region, private->crw_region);
kmem_cache_free(vfio_ccw_schib_region, private->schib_region);
@@ -203,6 +222,19 @@ static void vfio_ccw_mdev_close_device(struct vfio_device *vdev)
container_of(vdev, struct vfio_ccw_private, vdev);

vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_CLOSE);
+
+ /*
+ * Ensure these work items are drained, in the event the
+ * device is re-opened instead of released.
+ *
+ * notoper_work needs to be given a chance to run if it
+ * is queued, so any memory associated with the channel
+ * program can be returned.
+ */
+ cancel_work_sync(&private->io_work);
+ cancel_work_sync(&private->crw_work);
+ flush_work(&private->notoper_work);
+
vfio_ccw_unregister_dev_regions(private);
}

@@ -244,6 +276,7 @@ static ssize_t vfio_ccw_mdev_read(struct vfio_device *vdev,
return vfio_ccw_mdev_read_io_region(private, buf, count, ppos);
default:
index -= VFIO_CCW_NUM_REGIONS;
+ index = array_index_nospec(index, private->num_regions);
return private->region[index].ops->read(private, buf, count,
ppos);
}
@@ -296,6 +329,7 @@ static ssize_t vfio_ccw_mdev_write(struct vfio_device *vdev,
return vfio_ccw_mdev_write_io_region(private, buf, count, ppos);
default:
index -= VFIO_CCW_NUM_REGIONS;
+ index = array_index_nospec(index, private->num_regions);
return private->region[index].ops->write(private, buf, count,
ppos);
}
@@ -338,11 +372,8 @@ static int vfio_ccw_mdev_get_region_info(struct vfio_ccw_private *private,
VFIO_CCW_NUM_REGIONS + private->num_regions)
return -EINVAL;

- info->index = array_index_nospec(info->index,
- VFIO_CCW_NUM_REGIONS +
- private->num_regions);
-
i = info->index - VFIO_CCW_NUM_REGIONS;
+ i = array_index_nospec(i, private->num_regions);

info->offset = VFIO_CCW_INDEX_TO_OFFSET(info->index);
info->size = private->region[i].size;
diff --git a/drivers/s390/cio/vfio_ccw_private.h b/drivers/s390/cio/vfio_ccw_private.h
index 0501d4bbcdbd..3bd0171d38d0 100644
--- a/drivers/s390/cio/vfio_ccw_private.h
+++ b/drivers/s390/cio/vfio_ccw_private.h
@@ -88,7 +88,8 @@ struct vfio_ccw_parent {
* @state: internal state of the device
* @completion: synchronization helper of the I/O completion
* @io_region: MMIO region to input/output I/O arguments/results
- * @io_mutex: protect against concurrent update of I/O regions
+ * @io_mutex: protect against concurrent update of I/O resources
+ * and @cp lifecycle
* @region: additional regions for other subchannel operations
* @cmd_region: MMIO region for asynchronous I/O commands other than START
* @schib_region: MMIO region for SCHIB information
@@ -97,11 +98,14 @@ struct vfio_ccw_parent {
* @cp: channel program for the current I/O operation
* @irb: irb info received from interrupt
* @scsw: scsw info
+ * @crw_lock: serialization of CRW list information
+ * @crw: list of Channel Report Word elements
* @io_trigger: eventfd ctx for signaling userspace I/O results
* @crw_trigger: eventfd ctx for signaling userspace CRW information
* @req_trigger: eventfd ctx for signaling userspace to return device
* @io_work: work for deferral process of I/O handling
* @crw_work: work for deferral process of CRW handling
+ * @notoper_work: work for deferred processing in not-operational state
*/
struct vfio_ccw_private {
struct vfio_device vdev;
@@ -118,6 +122,8 @@ struct vfio_ccw_private {
struct channel_program cp;
struct irb irb;
union scsw scsw;
+
+ spinlock_t crw_lock;
struct list_head crw;

struct eventfd_ctx *io_trigger;
@@ -125,11 +131,13 @@ struct vfio_ccw_private {
struct eventfd_ctx *req_trigger;
struct work_struct io_work;
struct work_struct crw_work;
+ struct work_struct notoper_work;
} __aligned(8);

int vfio_ccw_sch_quiesce(struct subchannel *sch);
void vfio_ccw_sch_io_todo(struct work_struct *work);
void vfio_ccw_crw_todo(struct work_struct *work);
+void vfio_ccw_notoper_todo(struct work_struct *work);

extern struct mdev_driver vfio_ccw_mdev_driver;

diff --git a/drivers/s390/crypto/zcrypt_ccamisc.c b/drivers/s390/crypto/zcrypt_ccamisc.c
index 1de67038d164..700c2d902b79 100644
--- a/drivers/s390/crypto/zcrypt_ccamisc.c
+++ b/drivers/s390/crypto/zcrypt_ccamisc.c
@@ -16,6 +16,7 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/random.h>
+#include <linux/align.h>
#include <asm/zcrypt.h>
#include <asm/pkey.h>

@@ -268,6 +269,10 @@ EXPORT_SYMBOL(cca_check_sececckeytoken);
* block, reply CPRB and reply param block and fill in values
* for the common fields. Returns 0 on success or errno value
* on failure.
+ * It is guaranteed that request and a possible param block
+ * are aligned to a 4 byte boundary. Furthermore if a param
+ * block is used, the memory allocated for this is rounded up to
+ * the next multiple of 4 bytes.
*/
static int alloc_and_prep_cprbmem(size_t paramblen,
u8 **p_cprb_mem,
@@ -276,7 +281,8 @@ static int alloc_and_prep_cprbmem(size_t paramblen,
u32 xflags)
{
u8 *cprbmem = NULL;
- size_t cprbplusparamblen = sizeof(struct CPRBX) + paramblen;
+ size_t cprbplusparamblen =
+ ALIGN(sizeof(struct CPRBX), 4) + ALIGN(paramblen, 4);
size_t len = 2 * cprbplusparamblen;
struct CPRBX *preqcblk, *prepcblk;

@@ -303,10 +309,10 @@ static int alloc_and_prep_cprbmem(size_t paramblen,
memcpy(preqcblk->func_id, "T2", 2);
preqcblk->rpl_msgbl = cprbplusparamblen;
if (paramblen) {
- preqcblk->req_parmb =
- ((u8 __user *)preqcblk) + sizeof(struct CPRBX);
- preqcblk->rpl_parmb =
- ((u8 __user *)prepcblk) + sizeof(struct CPRBX);
+ preqcblk->req_parmb = ((u8 __user *)preqcblk) +
+ ALIGN(sizeof(struct CPRBX), 4);
+ preqcblk->rpl_parmb = ((u8 __user *)prepcblk) +
+ ALIGN(sizeof(struct CPRBX), 4);
}

*p_cprb_mem = cprbmem;
@@ -324,8 +330,10 @@ static int alloc_and_prep_cprbmem(size_t paramblen,
*/
static void free_cprbmem(void *mem, size_t paramblen, bool scrub, u32 xflags)
{
+ size_t cprblen = ALIGN(sizeof(struct CPRBX), 4) + ALIGN(paramblen, 4);
+
if (mem && scrub)
- memzero_explicit(mem, 2 * (sizeof(struct CPRBX) + paramblen));
+ memzero_explicit(mem, 2 * cprblen);

if (xflags & ZCRYPT_XFLAG_NOMEMALLOC)
mempool_free(mem, cprb_mempool);
diff --git a/drivers/s390/crypto/zcrypt_ep11misc.c b/drivers/s390/crypto/zcrypt_ep11misc.c
index e92e2fd8ce5d..6d2064555e1a 100644
--- a/drivers/s390/crypto/zcrypt_ep11misc.c
+++ b/drivers/s390/crypto/zcrypt_ep11misc.c
@@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/random.h>
#include <linux/slab.h>
+#include <linux/align.h>
#include <asm/zcrypt.h>
#include <asm/pkey.h>
#include <crypto/aes.h>
@@ -356,21 +357,24 @@ EXPORT_SYMBOL(ep11_check_aes_key);

/*
* Allocate and prepare ep11 cprb plus additional payload.
+ * It is guaranteed that the memory is aligned to a 4 byte boundary.
+ * Furthermore the memory allocation is rounded up to the next
+ * multiple of 4 bytes (with taking the payload_len into account).
*/
static void *alloc_cprbmem(size_t payload_len, u32 xflags)
{
- size_t len = sizeof(struct ep11_cprb) + payload_len;
+ size_t memlen = ALIGN(sizeof(struct ep11_cprb) + payload_len, 4);
struct ep11_cprb *cprb = NULL;

if (xflags & ZCRYPT_XFLAG_NOMEMALLOC) {
- if (len <= CPRB_MEMPOOL_ITEM_SIZE)
+ if (memlen <= CPRB_MEMPOOL_ITEM_SIZE)
cprb = mempool_alloc_preallocated(cprb_mempool);
} else {
- cprb = kmalloc(len, GFP_KERNEL);
+ cprb = kmalloc(memlen, GFP_KERNEL);
}
if (!cprb)
return NULL;
- memset(cprb, 0, len);
+ memset(cprb, 0, memlen);

cprb->cprb_len = sizeof(struct ep11_cprb);
cprb->cprb_ver_id = 0x04;
@@ -386,8 +390,10 @@ static void *alloc_cprbmem(size_t payload_len, u32 xflags)
*/
static void free_cprbmem(void *mem, size_t payload_len, bool scrub, u32 xflags)
{
+ size_t memlen = ALIGN(sizeof(struct ep11_cprb) + payload_len, 4);
+
if (mem && scrub)
- memzero_explicit(mem, sizeof(struct ep11_cprb) + payload_len);
+ memzero_explicit(mem, memlen);

if (xflags & ZCRYPT_XFLAG_NOMEMALLOC)
mempool_free(mem, cprb_mempool);
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index 64ca42ca78c4..c524b4b0a328 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -4712,6 +4712,9 @@ static int qeth_snmp_command(struct qeth_card *card, char __user *udata)
if (req_len > QETH_BUFSIZE)
return -EINVAL;

+ if (qinfo.udata_len < sizeof(struct qeth_snmp_ureq_hdr))
+ return -EINVAL;
+
iob = qeth_get_adapter_cmd(card, IPA_SETADP_SET_SNMP_CONTROL, req_len);
if (!iob)
return -ENOMEM;
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index 3525be819362..2621839fb8c3 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -1416,6 +1416,11 @@ static int qeth_l3_arp_query(struct qeth_card *card, char __user *udata)
rc = -EFAULT;
goto out;
}
+
+ if (qinfo.udata_len < QETH_QARP_ENTRIES_OFFSET) {
+ rc = -EINVAL;
+ goto out;
+ }
qinfo.udata = kzalloc(qinfo.udata_len, GFP_KERNEL);
if (!qinfo.udata) {
rc = -ENOMEM;
diff --git a/drivers/spi/spi-virtio.c b/drivers/spi/spi-virtio.c
index 2acb929b2c69..fb30c9207a4b 100644
--- a/drivers/spi/spi-virtio.c
+++ b/drivers/spi/spi-virtio.c
@@ -361,6 +361,8 @@ static int virtio_spi_probe(struct virtio_device *vdev)
if (ret)
return dev_err_probe(&vdev->dev, ret, "Cannot register virtqueue cleanup\n");

+ virtio_device_ready(vdev);
+
/* Use devm version to register controller */
ret = devm_spi_register_controller(&vdev->dev, ctrl);
if (ret)
diff --git a/drivers/video/fbdev/core/fb_io_fops.c b/drivers/video/fbdev/core/fb_io_fops.c
index 6ab60fcd0050..0798e88799eb 100644
--- a/drivers/video/fbdev/core/fb_io_fops.c
+++ b/drivers/video/fbdev/core/fb_io_fops.c
@@ -61,6 +61,14 @@ ssize_t fb_io_read(struct fb_info *info, char __user *buf, size_t count, loff_t
buf += c;
cnt += c;
count -= c;
+
+ /*
+ * If there was a partial copy, the user buffer is faulty.
+ * Break out to avoid over-advancing the src pointer and
+ * reading out of bounds in the next iteration.
+ */
+ if (trailing)
+ break;
}

kfree(buffer);
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index a4d2cd787f83..9dadd2c14ab5 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -928,18 +928,9 @@ static const struct file_operations bm_status_operations = {

/* Superblock handling */

-static void bm_put_super(struct super_block *sb)
-{
- struct user_namespace *user_ns = sb->s_fs_info;
-
- sb->s_fs_info = NULL;
- put_user_ns(user_ns);
-}
-
static const struct super_operations s_ops = {
.statfs = simple_statfs,
.evict_inode = bm_evict_inode,
- .put_super = bm_put_super,
};

static int bm_fill_super(struct super_block *sb, struct fs_context *fc)
@@ -998,13 +989,12 @@ static int bm_fill_super(struct super_block *sb, struct fs_context *fc)
/*
* When the binfmt_misc superblock for this userns is shutdown
* ->enabled might have been set to false and we don't reinitialize
- * ->enabled again in put_super() as someone might already be mounting
- * binfmt_misc again. It also would be pointless since by the time
- * ->put_super() is called we know that the binary type list for this
- * bintfmt_misc mount is empty making load_misc_binary() return
- * -ENOEXEC independent of whether ->enabled is true. Instead, if
- * someone mounts binfmt_misc for the first time or again we simply
- * reset ->enabled to true.
+ * ->enabled again during shutdown as someone might already be mounting
+ * binfmt_misc again. It also would be pointless since by then we know
+ * that the binary type list for this binfmt_misc mount is empty making
+ * load_misc_binary() return -ENOEXEC independent of whether ->enabled
+ * is true. Instead, if someone mounts binfmt_misc for the first time or
+ * again we simply reset ->enabled to true.
*/
misc->enabled = true;

@@ -1030,6 +1020,14 @@ static const struct fs_context_operations bm_context_ops = {
.get_tree = bm_get_tree,
};

+static void bm_kill_sb(struct super_block *sb)
+{
+ struct user_namespace *user_ns = sb->s_fs_info;
+
+ kill_litter_super(sb);
+ put_user_ns(user_ns);
+}
+
static int bm_init_fs_context(struct fs_context *fc)
{
fc->ops = &bm_context_ops;
@@ -1046,7 +1044,7 @@ static struct file_system_type bm_fs_type = {
.name = "binfmt_misc",
.init_fs_context = bm_init_fs_context,
.fs_flags = FS_USERNS_MOUNT,
- .kill_sb = kill_litter_super,
+ .kill_sb = bm_kill_sb,
};
MODULE_ALIAS_FS("binfmt_misc");

diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c
index e6bac34ebe83..93e0063bb1fa 100644
--- a/fs/btrfs/block-group.c
+++ b/fs/btrfs/block-group.c
@@ -3073,7 +3073,7 @@ int btrfs_inc_block_group_ro(struct btrfs_block_group *cache,
* We have allocated a new chunk. We also need to activate that chunk to
* grant metadata tickets for zoned filesystem.
*/
- ret = btrfs_zoned_activate_one_bg(fs_info, space_info, true);
+ ret = btrfs_zoned_activate_one_bg(space_info, true);
if (ret < 0)
goto out;

@@ -4350,25 +4350,29 @@ static void reserve_chunk_space(struct btrfs_trans_handle *trans,
if (IS_ERR(bg)) {
ret = PTR_ERR(bg);
} else {
+ int activate_ret;
+
/*
* We have a new chunk. We also need to activate it for
* zoned filesystem.
*/
- ret = btrfs_zoned_activate_one_bg(fs_info, info, true);
- if (ret < 0)
- return;
-
- /*
- * If we fail to add the chunk item here, we end up
- * trying again at phase 2 of chunk allocation, at
- * btrfs_create_pending_block_groups(). So ignore
- * any error here. An ENOSPC here could happen, due to
- * the cases described at do_chunk_alloc() - the system
- * block group we just created was just turned into RO
- * mode by a scrub for example, or a running discard
- * temporarily removed its free space entries, etc.
- */
- btrfs_chunk_alloc_add_chunk_item(trans, bg);
+ activate_ret = btrfs_zoned_activate_one_bg(info, true);
+ if (activate_ret < 0) {
+ ret = activate_ret;
+ } else {
+ /*
+ * If we fail to add the chunk item here, we end
+ * up trying again at phase 2 of chunk allocation,
+ * at btrfs_create_pending_block_groups(). So
+ * ignore any error here. An ENOSPC here could
+ * happen, due to the cases described at
+ * do_chunk_alloc() - the system block group we
+ * just created was just turned into RO mode by a
+ * scrub for example, or a running discard
+ * temporarily removed its free space entries, etc.
+ */
+ btrfs_chunk_alloc_add_chunk_item(trans, bg);
+ }
}
}

diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c
index 0dfbb28b7445..548cfc0fe28e 100644
--- a/fs/btrfs/zoned.c
+++ b/fs/btrfs/zoned.c
@@ -2963,10 +2963,9 @@ int btrfs_zone_finish_one_bg(struct btrfs_fs_info *fs_info)
return ret < 0 ? ret : 1;
}

-int btrfs_zoned_activate_one_bg(struct btrfs_fs_info *fs_info,
- struct btrfs_space_info *space_info,
- bool do_finish)
+int btrfs_zoned_activate_one_bg(struct btrfs_space_info *space_info, bool do_finish)
{
+ struct btrfs_fs_info *fs_info = space_info->fs_info;
struct btrfs_block_group *bg;
int index;

diff --git a/fs/btrfs/zoned.h b/fs/btrfs/zoned.h
index 2b807a02d1a8..5cefdeb08b7b 100644
--- a/fs/btrfs/zoned.h
+++ b/fs/btrfs/zoned.h
@@ -93,8 +93,7 @@ bool btrfs_zoned_should_reclaim(const struct btrfs_fs_info *fs_info);
void btrfs_zoned_release_data_reloc_bg(struct btrfs_fs_info *fs_info, u64 logical,
u64 length);
int btrfs_zone_finish_one_bg(struct btrfs_fs_info *fs_info);
-int btrfs_zoned_activate_one_bg(struct btrfs_fs_info *fs_info,
- struct btrfs_space_info *space_info, bool do_finish);
+int btrfs_zoned_activate_one_bg(struct btrfs_space_info *space_info, bool do_finish);
void btrfs_check_active_zone_reservation(struct btrfs_fs_info *fs_info);
int btrfs_reset_unused_block_groups(struct btrfs_space_info *space_info, u64 num_bytes);
#else /* CONFIG_BLK_DEV_ZONED */
@@ -261,8 +260,7 @@ static inline int btrfs_zone_finish_one_bg(struct btrfs_fs_info *fs_info)
return 1;
}

-static inline int btrfs_zoned_activate_one_bg(struct btrfs_fs_info *fs_info,
- struct btrfs_space_info *space_info,
+static inline int btrfs_zoned_activate_one_bg(struct btrfs_space_info *space_info,
bool do_finish)
{
/* Consider all the block groups are active */
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c
index d9924ef55f4a..07e3236e0f97 100644
--- a/fs/ceph/caps.c
+++ b/fs/ceph/caps.c
@@ -3090,7 +3090,19 @@ int __ceph_get_caps(struct inode *inode, struct ceph_file_info *fi, int need,
ret = -ERESTARTSYS;
break;
}
- wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
+
+ /*
+ * If a cap update is lost after
+ * mds_wanted was raised, waiting
+ * forever will never make progress.
+ * Retry the renew path periodically
+ * so we can resend synchronously.
+ */
+ if (!wait_woken(&wait, TASK_INTERRUPTIBLE,
+ CEPH_GET_CAPS_WAIT_TIMEOUT)) {
+ ret = -EUCLEAN;
+ break;
+ }
}

remove_wait_queue(&ci->i_cap_wq, &wait);
@@ -3124,7 +3136,8 @@ int __ceph_get_caps(struct inode *inode, struct ceph_file_info *fi, int need,
continue;
}
if (ret == -EUCLEAN) {
- /* session was killed, try renew caps */
+ /* session was killed or a waited cap
+ * request needs a retry */
ret = ceph_renew_caps(inode, flags);
if (ret == 0)
continue;
diff --git a/fs/ceph/file.c b/fs/ceph/file.c
index ceb5706fe366..f640aff749ed 100644
--- a/fs/ceph/file.c
+++ b/fs/ceph/file.c
@@ -295,7 +295,7 @@ static int ceph_init_file(struct inode *inode, struct file *file, int fmode)
}

/*
- * try renew caps after session gets killed.
+ * Retry cap acquisition after a stale session or a lost cap update.
*/
int ceph_renew_caps(struct inode *inode, int fmode)
{
@@ -303,14 +303,15 @@ int ceph_renew_caps(struct inode *inode, int fmode)
struct ceph_client *cl = mdsc->fsc->client;
struct ceph_inode_info *ci = ceph_inode(inode);
struct ceph_mds_request *req;
- int err, flags, wanted;
+ int err, flags, wanted, issued;

spin_lock(&ci->i_ceph_lock);
__ceph_touch_fmode(ci, mdsc, fmode);
wanted = __ceph_caps_file_wanted(ci);
+ issued = __ceph_caps_issued(ci, NULL);
if (__ceph_is_any_real_caps(ci) &&
- (!(wanted & CEPH_CAP_ANY_WR) || ci->i_auth_cap)) {
- int issued = __ceph_caps_issued(ci, NULL);
+ (!(wanted & CEPH_CAP_ANY_WR) || ci->i_auth_cap) &&
+ (issued & wanted) == wanted) {
spin_unlock(&ci->i_ceph_lock);
doutc(cl, "%p %llx.%llx want %s issued %s updating mds_wanted\n",
inode, ceph_vinop(inode), ceph_cap_string(wanted),
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index ba9f96efc8ee..049b2d414fe9 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -6,6 +6,7 @@
#include <linux/slab.h>
#include <linux/gfp.h>
#include <linux/sched.h>
+#include <linux/sched/mm.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/ratelimit.h>
@@ -3843,6 +3844,7 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg)
struct ceph_mds_reply_head *head = msg->front.iov_base;
struct ceph_mds_reply_info_parsed *rinfo; /* parsed reply info */
struct ceph_snap_realm *realm;
+ unsigned int nofs_flags;
u64 tid;
int err, result;
int mds = session->s_mds;
@@ -3985,6 +3987,14 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg)

/* insert trace into our cache */
mutex_lock(&req->r_fill_mutex);
+
+ /* disable fs reclaim while we are using current->journal_info
+ * for our own purposes, or else shrinkers of other
+ * filesystems might dereference this pointer as a different
+ * type
+ */
+ nofs_flags = memalloc_nofs_save();
+
current->journal_info = req;
err = ceph_fill_trace(mdsc->fsc->sb, req);
if (err == 0) {
@@ -3993,6 +4003,7 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg)
err = ceph_readdir_prepopulate(req, req->r_session);
}
current->journal_info = NULL;
+ memalloc_nofs_restore(nofs_flags);
mutex_unlock(&req->r_fill_mutex);

up_read(&mdsc->snap_rwsem);
diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h
index 0428a5eaf28c..3720d5f16e06 100644
--- a/fs/ceph/mds_client.h
+++ b/fs/ceph/mds_client.h
@@ -74,6 +74,7 @@ struct ceph_fs_client;
struct ceph_cap;

#define MDS_AUTH_UID_ANY -1
+#define CEPH_GET_CAPS_WAIT_TIMEOUT (5 * HZ)

struct ceph_mds_cap_match {
s64 uid; /* default to MDS_AUTH_UID_ANY */
diff --git a/fs/ceph/mdsmap.c b/fs/ceph/mdsmap.c
index b228e5ecfb92..97ecf272a37d 100644
--- a/fs/ceph/mdsmap.c
+++ b/fs/ceph/mdsmap.c
@@ -15,7 +15,7 @@
#include "super.h"

#define CEPH_MDS_IS_READY(i, ignore_laggy) \
- (m->m_info[i].state > 0 && ignore_laggy ? true : !m->m_info[i].laggy)
+ (m->m_info[i].state > 0 && (ignore_laggy ? true : !m->m_info[i].laggy))

static int __mdsmap_get_random_mds(struct ceph_mdsmap *m, bool ignore_laggy)
{
diff --git a/fs/erofs/Kconfig b/fs/erofs/Kconfig
index 0d199f6698ff..0be8a38cfb11 100644
--- a/fs/erofs/Kconfig
+++ b/fs/erofs/Kconfig
@@ -123,7 +123,8 @@ config EROFS_FS_ZIP_LZMA
config EROFS_FS_ZIP_LZMA_DEFAULT_MAX_STREAMS
int "EROFS LZMA default maximum decompression streams"
depends on EROFS_FS_ZIP_LZMA
- range 1 NR_CPUS
+ range 1 NR_CPUS if SMP
+ range 1 1 if !SMP
default 16
help
By default EROFS allocates one LZMA decompression stream per CPU.
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 48455e2a66a1..6dc16295e307 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -1989,90 +1989,98 @@ static pagemap_entry_t pte_to_pagemap_entry(struct pagemapread *pm,
return make_pme(frame, flags);
}

-static int pagemap_pmd_range(pmd_t *pmdp, unsigned long addr, unsigned long end,
- struct mm_walk *walk)
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+static int pagemap_pmd_range_thp(pmd_t *pmdp, unsigned long addr,
+ unsigned long end, struct vm_area_struct *vma,
+ struct pagemapread *pm)
{
- struct vm_area_struct *vma = walk->vma;
- struct pagemapread *pm = walk->private;
- spinlock_t *ptl;
- pte_t *pte, *orig_pte;
+ unsigned int idx = (addr & ~PMD_MASK) >> PAGE_SHIFT;
+ u64 flags = 0, frame = 0;
+ pmd_t pmd = *pmdp;
+ struct page *page = NULL;
+ struct folio *folio = NULL;
int err = 0;
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE

- ptl = pmd_trans_huge_lock(pmdp, vma);
- if (ptl) {
- unsigned int idx = (addr & ~PMD_MASK) >> PAGE_SHIFT;
- u64 flags = 0, frame = 0;
- pmd_t pmd = *pmdp;
- struct page *page = NULL;
- struct folio *folio = NULL;
+ if (vma->vm_flags & VM_SOFTDIRTY)
+ flags |= PM_SOFT_DIRTY;

- if (vma->vm_flags & VM_SOFTDIRTY)
- flags |= PM_SOFT_DIRTY;
+ if (pmd_present(pmd)) {
+ page = pmd_page(pmd);

- if (pmd_present(pmd)) {
- page = pmd_page(pmd);
+ flags |= PM_PRESENT;
+ if (pmd_soft_dirty(pmd))
+ flags |= PM_SOFT_DIRTY;
+ if (pmd_uffd_wp(pmd))
+ flags |= PM_UFFD_WP;
+ if (pm->show_pfn)
+ frame = pmd_pfn(pmd) + idx;
+ } else if (thp_migration_supported() && is_swap_pmd(pmd)) {
+ swp_entry_t entry = pmd_to_swp_entry(pmd);
+ unsigned long offset;

- flags |= PM_PRESENT;
- if (pmd_soft_dirty(pmd))
- flags |= PM_SOFT_DIRTY;
- if (pmd_uffd_wp(pmd))
- flags |= PM_UFFD_WP;
- if (pm->show_pfn)
- frame = pmd_pfn(pmd) + idx;
- }
-#ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION
- else if (is_swap_pmd(pmd)) {
- swp_entry_t entry = pmd_to_swp_entry(pmd);
- unsigned long offset;
-
- if (pm->show_pfn) {
- if (is_pfn_swap_entry(entry))
- offset = swp_offset_pfn(entry) + idx;
- else
- offset = swp_offset(entry) + idx;
- frame = swp_type(entry) |
- (offset << MAX_SWAPFILES_SHIFT);
- }
- flags |= PM_SWAP;
- if (pmd_swp_soft_dirty(pmd))
- flags |= PM_SOFT_DIRTY;
- if (pmd_swp_uffd_wp(pmd))
- flags |= PM_UFFD_WP;
- VM_BUG_ON(!is_pmd_migration_entry(pmd));
- page = pfn_swap_entry_to_page(entry);
+ if (pm->show_pfn) {
+ if (is_pfn_swap_entry(entry))
+ offset = swp_offset_pfn(entry) + idx;
+ else
+ offset = swp_offset(entry) + idx;
+ frame = swp_type(entry) |
+ (offset << MAX_SWAPFILES_SHIFT);
}
-#endif
+ flags |= PM_SWAP;
+ if (pmd_swp_soft_dirty(pmd))
+ flags |= PM_SOFT_DIRTY;
+ if (pmd_swp_uffd_wp(pmd))
+ flags |= PM_UFFD_WP;
+ VM_WARN_ON_ONCE(!pmd_is_migration_entry(pmd));
+ page = pfn_swap_entry_to_page(entry);
+ }

- if (page) {
- folio = page_folio(page);
- if (!folio_test_anon(folio))
- flags |= PM_FILE;
- }
+ if (page) {
+ folio = page_folio(page);
+ if (!folio_test_anon(folio))
+ flags |= PM_FILE;
+ }

- for (; addr != end; addr += PAGE_SIZE, idx++) {
- u64 cur_flags = flags;
- pagemap_entry_t pme;
+ for (; addr != end; addr += PAGE_SIZE, idx++) {
+ u64 cur_flags = flags;
+ pagemap_entry_t pme;

- if (folio && (flags & PM_PRESENT) &&
- __folio_page_mapped_exclusively(folio, page))
- cur_flags |= PM_MMAP_EXCLUSIVE;
+ if (folio && (flags & PM_PRESENT) &&
+ __folio_page_mapped_exclusively(folio, page))
+ cur_flags |= PM_MMAP_EXCLUSIVE;

- pme = make_pme(frame, cur_flags);
- err = add_to_pagemap(&pme, pm);
- if (err)
- break;
- if (pm->show_pfn) {
- if (flags & PM_PRESENT)
- frame++;
- else if (flags & PM_SWAP)
- frame += (1 << MAX_SWAPFILES_SHIFT);
- }
+ pme = make_pme(frame, cur_flags);
+ err = add_to_pagemap(&pme, pm);
+ if (err)
+ break;
+ if (pm->show_pfn) {
+ if (flags & PM_PRESENT)
+ frame++;
+ else if (flags & PM_SWAP)
+ frame += (1 << MAX_SWAPFILES_SHIFT);
}
+ }
+ return err;
+}
+#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
+
+static int pagemap_pmd_range(pmd_t *pmdp, unsigned long addr, unsigned long end,
+ struct mm_walk *walk)
+{
+ struct vm_area_struct *vma = walk->vma;
+ struct pagemapread *pm = walk->private;
+ spinlock_t *ptl;
+ pte_t *pte, *orig_pte;
+ int err = 0;
+
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+ ptl = pmd_trans_huge_lock(pmdp, vma);
+ if (ptl) {
+ err = pagemap_pmd_range_thp(pmdp, addr, end, vma, pm);
spin_unlock(ptl);
return err;
}
-#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
+#endif

/*
* We can assume that @vma always points to a valid one and @end never
diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 69deb29502a8..38b4053d9791 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -671,12 +671,6 @@ struct cifs_mnt_data {
int flags;
};

-static inline unsigned int
-get_rfc1002_length(void *buf)
-{
- return be32_to_cpu(*((__be32 *)buf)) & 0xffffff;
-}
-
struct TCP_Server_Info {
struct list_head tcp_ses_list;
struct list_head smb_ses_list;
diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c
index db9d9a1983c7..3f5975503202 100644
--- a/fs/smb/client/cifssmb.c
+++ b/fs/smb/client/cifssmb.c
@@ -615,7 +615,7 @@ CIFSSMBEcho(struct TCP_Server_Info *server)

iov[0].iov_len = 4;
iov[0].iov_base = smb;
- iov[1].iov_len = get_rfc1002_length(smb);
+ iov[1].iov_len = get_rfc1002_len(smb);
iov[1].iov_base = (char *)smb + 4;

rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL,
@@ -1459,7 +1459,7 @@ cifs_async_readv(struct cifs_io_subrequest *rdata)
rdata->iov[0].iov_base = smb;
rdata->iov[0].iov_len = 4;
rdata->iov[1].iov_base = (char *)smb + 4;
- rdata->iov[1].iov_len = get_rfc1002_length(smb);
+ rdata->iov[1].iov_len = get_rfc1002_len(smb);

trace_smb3_read_enter(rdata->rreq->debug_id,
rdata->subreq.debug_index,
@@ -1835,7 +1835,7 @@ cifs_async_writev(struct cifs_io_subrequest *wdata)
/* 4 for RFC1001 length + 1 for BCC */
iov[0].iov_len = 4;
iov[0].iov_base = smb;
- iov[1].iov_len = get_rfc1002_length(smb) + 1;
+ iov[1].iov_len = get_rfc1002_len(smb) + 1;
iov[1].iov_base = (char *)smb + 4;

rqst.rq_iov = iov;
diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
index 2ee2199d2a6a..3e06c0eddb3a 100644
--- a/fs/smb/client/connect.c
+++ b/fs/smb/client/connect.c
@@ -1295,7 +1295,7 @@ cifs_demultiplex_thread(void *p)
* The right amount was read from socket - 4 bytes,
* so we can now interpret the length field.
*/
- pdu_length = get_rfc1002_length(buf);
+ pdu_length = get_rfc1002_len(buf);

cifs_dbg(FYI, "RFC1002 header 0x%x\n", pdu_length);
if (!is_smb_response(server, buf[0]))
diff --git a/fs/smb/client/smb1transport.c b/fs/smb/client/smb1transport.c
index 518f764dedcc..bafc5181e029 100644
--- a/fs/smb/client/smb1transport.c
+++ b/fs/smb/client/smb1transport.c
@@ -165,7 +165,7 @@ SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
int resp_buf_type;

iov[0].iov_base = in_buf;
- iov[0].iov_len = get_rfc1002_length(in_buf) + 4;
+ iov[0].iov_len = get_rfc1002_len(in_buf) + 4;
flags |= CIFS_NO_RSP_BUF;
rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags, &rsp_iov);
cifs_dbg(NOISY, "SendRcvNoRsp flags %d rc %d\n", flags, rc);
@@ -177,7 +177,7 @@ int
cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
bool log_error)
{
- unsigned int len = get_rfc1002_length(mid->resp_buf) + 4;
+ unsigned int len = get_rfc1002_len(mid->resp_buf) + 4;

dump_smb(mid->resp_buf, min_t(u32, 92, len));

@@ -370,7 +370,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
goto out;
}

- *pbytes_returned = get_rfc1002_length(midQ->resp_buf);
+ *pbytes_returned = get_rfc1002_len(midQ->resp_buf);
memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
rc = cifs_check_receive(midQ, server, 0);
out:
@@ -554,7 +554,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
goto out;
}

- *pbytes_returned = get_rfc1002_length(midQ->resp_buf);
+ *pbytes_returned = get_rfc1002_len(midQ->resp_buf);
memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
rc = cifs_check_receive(midQ, server, 0);
out:
diff --git a/fs/smb/common/cifsglob.h b/fs/smb/common/cifsglob.h
index eda5e666a761..371160fec1cd 100644
--- a/fs/smb/common/cifsglob.h
+++ b/fs/smb/common/cifsglob.h
@@ -40,6 +40,11 @@ struct smb_version_values {
size_t create_posix_size;
};

+static inline unsigned int get_rfc1002_len(void *buf)
+{
+ return be32_to_cpu(*((__be32 *)buf)) & 0xffffff;
+}
+
static inline void inc_rfc1001_len(void *buf, int count)
{
be32_add_cpu((__be32 *)buf, count);
diff --git a/fs/smb/server/auth.c b/fs/smb/server/auth.c
index a778275207fe..3f8258954901 100644
--- a/fs/smb/server/auth.c
+++ b/fs/smb/server/auth.c
@@ -710,7 +710,7 @@ void ksmbd_gen_smb311_encryptionkey(struct ksmbd_conn *conn,
int ksmbd_gen_preauth_integrity_hash(struct ksmbd_conn *conn, char *buf,
__u8 *pi_hash)
{
- struct smb2_hdr *rcv_hdr = smb2_get_msg(buf);
+ struct smb2_hdr *rcv_hdr = smb_get_msg(buf);
char *all_bytes_msg = (char *)&rcv_hdr->ProtocolId;
int msg_size = get_rfc1002_len(buf);
struct sha512_ctx sha_ctx;
@@ -837,7 +837,7 @@ int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov,
unsigned int nvec, int enc)
{
struct ksmbd_conn *conn = work->conn;
- struct smb2_transform_hdr *tr_hdr = smb2_get_msg(iov[0].iov_base);
+ struct smb2_transform_hdr *tr_hdr = smb_get_msg(iov[0].iov_base);
unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20;
int rc;
DECLARE_CRYPTO_WAIT(wait);
diff --git a/fs/smb/server/connection.c b/fs/smb/server/connection.c
index 9274953eb064..c193b87cfa75 100644
--- a/fs/smb/server/connection.c
+++ b/fs/smb/server/connection.c
@@ -376,8 +376,11 @@ bool ksmbd_conn_alive(struct ksmbd_conn *conn)
return true;
}

-#define SMB1_MIN_SUPPORTED_HEADER_SIZE (sizeof(struct smb_hdr))
-#define SMB2_MIN_SUPPORTED_HEADER_SIZE (sizeof(struct smb2_hdr) + 4)
+/* "+2" for BCC field (ByteCount, 2 bytes) */
+#define SMB1_MIN_SUPPORTED_PDU_SIZE (sizeof(struct smb_hdr) + 2)
+#define SMB2_MIN_SUPPORTED_PDU_SIZE (sizeof(struct smb2_pdu))
+#define SMB2_TRANSFORM_MIN_SUPPORTED_PDU_SIZE \
+ (sizeof(struct smb2_transform_hdr) + sizeof(struct smb2_hdr))

/**
* ksmbd_conn_handler_loop() - session thread to listen on new smb requests
@@ -392,6 +395,7 @@ int ksmbd_conn_handler_loop(void *p)
struct ksmbd_conn *conn = (struct ksmbd_conn *)p;
struct ksmbd_transport *t = conn->transport;
unsigned int pdu_size, max_allowed_pdu_size, max_req;
+ __le32 proto;
char hdr_buf[4] = {0,};
int size;

@@ -444,7 +448,7 @@ int ksmbd_conn_handler_loop(void *p)
if (pdu_size > MAX_STREAM_PROT_LEN)
break;

- if (pdu_size < SMB1_MIN_SUPPORTED_HEADER_SIZE)
+ if (pdu_size < SMB1_MIN_SUPPORTED_PDU_SIZE)
break;

/* 4 for rfc1002 length field */
@@ -475,11 +479,14 @@ int ksmbd_conn_handler_loop(void *p)
if (!ksmbd_smb_request(conn))
break;

- if (((struct smb2_hdr *)smb2_get_msg(conn->request_buf))->ProtocolId ==
- SMB2_PROTO_NUMBER) {
- if (pdu_size < SMB2_MIN_SUPPORTED_HEADER_SIZE)
- break;
- }
+ proto = *(__le32 *)smb_get_msg(conn->request_buf);
+ if (proto == SMB2_PROTO_NUMBER &&
+ pdu_size < SMB2_MIN_SUPPORTED_PDU_SIZE)
+ break;
+
+ if (proto == SMB2_TRANSFORM_PROTO_NUM &&
+ pdu_size < SMB2_TRANSFORM_MIN_SUPPORTED_PDU_SIZE)
+ break;

if (!default_conn_ops.process_fn) {
pr_err("No connection request callback\n");
diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c
index ff0dbf3f8cbf..d83370f53d6f 100644
--- a/fs/smb/server/oplock.c
+++ b/fs/smb/server/oplock.c
@@ -663,7 +663,7 @@ static void __smb2_oplock_break_noti(struct work_struct *wk)
goto out;
}

- rsp_hdr = smb2_get_msg(work->response_buf);
+ rsp_hdr = smb_get_msg(work->response_buf);
memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2);
rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER;
rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE;
@@ -677,7 +677,7 @@ static void __smb2_oplock_break_noti(struct work_struct *wk)
rsp_hdr->SessionId = 0;
memset(rsp_hdr->Signature, 0, 16);

- rsp = smb2_get_msg(work->response_buf);
+ rsp = smb_get_msg(work->response_buf);

rsp->StructureSize = cpu_to_le16(24);
if (!br_info->open_trunc &&
@@ -776,7 +776,7 @@ static void __smb2_lease_break_noti(struct work_struct *wk)
goto out;
}

- rsp_hdr = smb2_get_msg(work->response_buf);
+ rsp_hdr = smb_get_msg(work->response_buf);
memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2);
rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER;
rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE;
@@ -790,7 +790,7 @@ static void __smb2_lease_break_noti(struct work_struct *wk)
rsp_hdr->SessionId = 0;
memset(rsp_hdr->Signature, 0, 16);

- rsp = smb2_get_msg(work->response_buf);
+ rsp = smb_get_msg(work->response_buf);
rsp->StructureSize = cpu_to_le16(44);
rsp->Epoch = br_info->epoch;
rsp->Flags = 0;
diff --git a/fs/smb/server/server.c b/fs/smb/server/server.c
index b78126bb2371..9da4525010cc 100644
--- a/fs/smb/server/server.c
+++ b/fs/smb/server/server.c
@@ -95,7 +95,7 @@ static inline int check_conn_state(struct ksmbd_work *work)

if (ksmbd_conn_exiting(work->conn) ||
ksmbd_conn_need_reconnect(work->conn)) {
- rsp_hdr = work->response_buf;
+ rsp_hdr = smb_get_msg(work->response_buf);
rsp_hdr->Status.CifsError = STATUS_CONNECTION_DISCONNECTED;
return 1;
}
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index b610cad470ea..7374422bfaf2 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -48,8 +48,8 @@ static void __wbuf(struct ksmbd_work *work, void **req, void **rsp)
*req = ksmbd_req_buf_next(work);
*rsp = ksmbd_resp_buf_next(work);
} else {
- *req = smb2_get_msg(work->request_buf);
- *rsp = smb2_get_msg(work->response_buf);
+ *req = smb_get_msg(work->request_buf);
+ *rsp = smb_get_msg(work->response_buf);
}
}

@@ -155,7 +155,7 @@ void smb2_set_err_rsp(struct ksmbd_work *work)
if (work->next_smb2_rcv_hdr_off)
err_rsp = ksmbd_resp_buf_next(work);
else
- err_rsp = smb2_get_msg(work->response_buf);
+ err_rsp = smb_get_msg(work->response_buf);

if (err_rsp->hdr.Status != STATUS_STOPPED_ON_SYMLINK) {
int err;
@@ -181,7 +181,7 @@ void smb2_set_err_rsp(struct ksmbd_work *work)
*/
bool is_smb2_neg_cmd(struct ksmbd_work *work)
{
- struct smb2_hdr *hdr = smb2_get_msg(work->request_buf);
+ struct smb2_hdr *hdr = smb_get_msg(work->request_buf);

/* is it SMB2 header ? */
if (hdr->ProtocolId != SMB2_PROTO_NUMBER)
@@ -205,7 +205,7 @@ bool is_smb2_neg_cmd(struct ksmbd_work *work)
*/
bool is_smb2_rsp(struct ksmbd_work *work)
{
- struct smb2_hdr *hdr = smb2_get_msg(work->response_buf);
+ struct smb2_hdr *hdr = smb_get_msg(work->response_buf);

/* is it SMB2 header ? */
if (hdr->ProtocolId != SMB2_PROTO_NUMBER)
@@ -231,7 +231,7 @@ u16 get_smb2_cmd_val(struct ksmbd_work *work)
if (work->next_smb2_rcv_hdr_off)
rcv_hdr = ksmbd_req_buf_next(work);
else
- rcv_hdr = smb2_get_msg(work->request_buf);
+ rcv_hdr = smb_get_msg(work->request_buf);
return le16_to_cpu(rcv_hdr->Command);
}

@@ -244,7 +244,7 @@ void set_smb2_rsp_status(struct ksmbd_work *work, __le32 err)
{
struct smb2_hdr *rsp_hdr;

- rsp_hdr = smb2_get_msg(work->response_buf);
+ rsp_hdr = smb_get_msg(work->response_buf);
rsp_hdr->Status = err;

work->iov_idx = 0;
@@ -267,7 +267,7 @@ int init_smb2_neg_rsp(struct ksmbd_work *work)
struct ksmbd_conn *conn = work->conn;
int err;

- rsp_hdr = smb2_get_msg(work->response_buf);
+ rsp_hdr = smb_get_msg(work->response_buf);
memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2);
rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER;
rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE;
@@ -281,7 +281,7 @@ int init_smb2_neg_rsp(struct ksmbd_work *work)
rsp_hdr->SessionId = 0;
memset(rsp_hdr->Signature, 0, 16);

- rsp = smb2_get_msg(work->response_buf);
+ rsp = smb_get_msg(work->response_buf);

WARN_ON(ksmbd_conn_good(conn));

@@ -455,7 +455,7 @@ static void init_chained_smb2_rsp(struct ksmbd_work *work)
*/
bool is_chained_smb2_message(struct ksmbd_work *work)
{
- struct smb2_hdr *hdr = smb2_get_msg(work->request_buf);
+ struct smb2_hdr *hdr = smb_get_msg(work->request_buf);
unsigned int len, next_cmd;

if (hdr->ProtocolId != SMB2_PROTO_NUMBER)
@@ -506,8 +506,8 @@ bool is_chained_smb2_message(struct ksmbd_work *work)
*/
int init_smb2_rsp_hdr(struct ksmbd_work *work)
{
- struct smb2_hdr *rsp_hdr = smb2_get_msg(work->response_buf);
- struct smb2_hdr *rcv_hdr = smb2_get_msg(work->request_buf);
+ struct smb2_hdr *rsp_hdr = smb_get_msg(work->response_buf);
+ struct smb2_hdr *rcv_hdr = smb_get_msg(work->request_buf);

memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2);
rsp_hdr->ProtocolId = rcv_hdr->ProtocolId;
@@ -536,7 +536,7 @@ int init_smb2_rsp_hdr(struct ksmbd_work *work)
*/
int smb2_allocate_rsp_buf(struct ksmbd_work *work)
{
- struct smb2_hdr *hdr = smb2_get_msg(work->request_buf);
+ struct smb2_hdr *hdr = smb_get_msg(work->request_buf);
size_t small_sz = MAX_CIFS_SMALL_BUFFER_SIZE;
size_t large_sz = small_sz + work->conn->vals->max_trans_size;
size_t sz = small_sz;
@@ -552,7 +552,7 @@ int smb2_allocate_rsp_buf(struct ksmbd_work *work)
offsetof(struct smb2_query_info_req, OutputBufferLength))
return -EINVAL;

- req = smb2_get_msg(work->request_buf);
+ req = smb_get_msg(work->request_buf);
if ((req->InfoType == SMB2_O_INFO_FILE &&
(req->FileInfoClass == FILE_FULL_EA_INFORMATION ||
req->FileInfoClass == FILE_ALL_INFORMATION)) ||
@@ -726,10 +726,10 @@ void smb2_send_interim_resp(struct ksmbd_work *work, __le32 status)
}

in_work->conn = work->conn;
- memcpy(smb2_get_msg(in_work->response_buf), ksmbd_resp_buf_next(work),
+ memcpy(smb_get_msg(in_work->response_buf), ksmbd_resp_buf_next(work),
__SMB2_HEADER_STRUCTURE_SIZE);

- rsp_hdr = smb2_get_msg(in_work->response_buf);
+ rsp_hdr = smb_get_msg(in_work->response_buf);
rsp_hdr->Flags |= SMB2_FLAGS_ASYNC_COMMAND;
rsp_hdr->Id.AsyncId = cpu_to_le64(work->async_id);
smb2_set_err_rsp(in_work);
@@ -1109,8 +1109,8 @@ static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn,
int smb2_handle_negotiate(struct ksmbd_work *work)
{
struct ksmbd_conn *conn = work->conn;
- struct smb2_negotiate_req *req = smb2_get_msg(work->request_buf);
- struct smb2_negotiate_rsp *rsp = smb2_get_msg(work->response_buf);
+ struct smb2_negotiate_req *req = smb_get_msg(work->request_buf);
+ struct smb2_negotiate_rsp *rsp = smb_get_msg(work->response_buf);
int rc = 0;
unsigned int smb2_buf_len, smb2_neg_size, neg_ctxt_len = 0;
__le32 status;
@@ -6088,7 +6088,7 @@ int smb2_close(struct ksmbd_work *work)
*/
int smb2_echo(struct ksmbd_work *work)
{
- struct smb2_echo_rsp *rsp = smb2_get_msg(work->response_buf);
+ struct smb2_echo_rsp *rsp = smb_get_msg(work->response_buf);

ksmbd_debug(SMB, "Received smb2 echo request\n");

@@ -6666,8 +6666,8 @@ int smb2_set_info(struct ksmbd_work *work)
pid = work->compound_pfid;
}
} else {
- req = smb2_get_msg(work->request_buf);
- rsp = smb2_get_msg(work->response_buf);
+ req = smb_get_msg(work->request_buf);
+ rsp = smb_get_msg(work->response_buf);
}

if (!test_tree_conn_flag(work->tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) {
@@ -6895,8 +6895,8 @@ int smb2_read(struct ksmbd_work *work)
pid = work->compound_pfid;
}
} else {
- req = smb2_get_msg(work->request_buf);
- rsp = smb2_get_msg(work->response_buf);
+ req = smb_get_msg(work->request_buf);
+ rsp = smb_get_msg(work->response_buf);
}

if (!has_file_id(id)) {
@@ -7324,7 +7324,7 @@ int smb2_flush(struct ksmbd_work *work)
int smb2_cancel(struct ksmbd_work *work)
{
struct ksmbd_conn *conn = work->conn;
- struct smb2_hdr *hdr = smb2_get_msg(work->request_buf);
+ struct smb2_hdr *hdr = smb_get_msg(work->request_buf);
struct smb2_hdr *chdr;
struct ksmbd_work *iter;
struct list_head *command_list;
@@ -7341,7 +7341,7 @@ int smb2_cancel(struct ksmbd_work *work)
spin_lock(&conn->request_lock);
list_for_each_entry(iter, command_list,
async_request_entry) {
- chdr = smb2_get_msg(iter->request_buf);
+ chdr = smb_get_msg(iter->request_buf);

if (iter->async_id !=
le64_to_cpu(hdr->Id.AsyncId))
@@ -7373,7 +7373,7 @@ int smb2_cancel(struct ksmbd_work *work)

spin_lock(&conn->request_lock);
list_for_each_entry(iter, command_list, request_entry) {
- chdr = smb2_get_msg(iter->request_buf);
+ chdr = smb_get_msg(iter->request_buf);

if (chdr->MessageId != hdr->MessageId ||
iter == work)
@@ -8330,8 +8330,8 @@ int smb2_ioctl(struct ksmbd_work *work)
id = work->compound_fid;
}
} else {
- req = smb2_get_msg(work->request_buf);
- rsp = smb2_get_msg(work->response_buf);
+ req = smb_get_msg(work->request_buf);
+ rsp = smb_get_msg(work->response_buf);
}

if (!has_file_id(id))
@@ -9017,7 +9017,7 @@ int smb2_notify(struct ksmbd_work *work)
*/
bool smb2_is_sign_req(struct ksmbd_work *work, unsigned int command)
{
- struct smb2_hdr *rcv_hdr2 = smb2_get_msg(work->request_buf);
+ struct smb2_hdr *rcv_hdr2 = smb_get_msg(work->request_buf);

if ((rcv_hdr2->Flags & SMB2_FLAGS_SIGNED) &&
command != SMB2_NEGOTIATE_HE &&
@@ -9042,7 +9042,7 @@ int smb2_check_sign_req(struct ksmbd_work *work)
struct kvec iov[1];
size_t len;

- hdr = smb2_get_msg(work->request_buf);
+ hdr = smb_get_msg(work->request_buf);
if (work->next_smb2_rcv_hdr_off)
hdr = ksmbd_req_buf_next(work);

@@ -9116,7 +9116,7 @@ int smb3_check_sign_req(struct ksmbd_work *work)
struct kvec iov[1];
size_t len;

- hdr = smb2_get_msg(work->request_buf);
+ hdr = smb_get_msg(work->request_buf);
if (work->next_smb2_rcv_hdr_off)
hdr = ksmbd_req_buf_next(work);

@@ -9252,7 +9252,7 @@ void smb3_preauth_hash_rsp(struct ksmbd_work *work)
static void fill_transform_hdr(void *tr_buf, char *old_buf, __le16 cipher_type)
{
struct smb2_transform_hdr *tr_hdr = tr_buf + 4;
- struct smb2_hdr *hdr = smb2_get_msg(old_buf);
+ struct smb2_hdr *hdr = smb_get_msg(old_buf);
unsigned int orig_len = get_rfc1002_len(old_buf);

/* tr_buf must be cleared by the caller */
@@ -9291,7 +9291,7 @@ int smb3_encrypt_resp(struct ksmbd_work *work)

bool smb3_is_transform_hdr(void *buf)
{
- struct smb2_transform_hdr *trhdr = smb2_get_msg(buf);
+ struct smb2_transform_hdr *trhdr = smb_get_msg(buf);

return trhdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM;
}
@@ -9303,7 +9303,7 @@ int smb3_decrypt_req(struct ksmbd_work *work)
unsigned int pdu_length = get_rfc1002_len(buf);
struct kvec iov[2];
int buf_data_size = pdu_length - sizeof(struct smb2_transform_hdr);
- struct smb2_transform_hdr *tr_hdr = smb2_get_msg(buf);
+ struct smb2_transform_hdr *tr_hdr = smb_get_msg(buf);
int rc = 0;

if (pdu_length < sizeof(struct smb2_transform_hdr) ||
@@ -9344,7 +9344,7 @@ bool smb3_11_final_sess_setup_resp(struct ksmbd_work *work)
{
struct ksmbd_conn *conn = work->conn;
struct ksmbd_session *sess = work->sess;
- struct smb2_hdr *rsp = smb2_get_msg(work->response_buf);
+ struct smb2_hdr *rsp = smb_get_msg(work->response_buf);

if (conn->dialect < SMB30_PROT_ID)
return false;
diff --git a/fs/smb/server/smb2pdu.h b/fs/smb/server/smb2pdu.h
index 5163d5241b90..9d4c01c453b2 100644
--- a/fs/smb/server/smb2pdu.h
+++ b/fs/smb/server/smb2pdu.h
@@ -490,15 +490,6 @@ int smb2_ioctl(struct ksmbd_work *work);
int smb2_oplock_break(struct ksmbd_work *work);
int smb2_notify(struct ksmbd_work *ksmbd_work);

-/*
- * Get the body of the smb2 message excluding the 4 byte rfc1002 headers
- * from request/response buffer.
- */
-static inline void *smb2_get_msg(void *buf)
-{
- return buf + 4;
-}
-
#define POSIX_TYPE_FILE 0
#define POSIX_TYPE_DIR 1
#define POSIX_TYPE_SYMLINK 2
diff --git a/fs/smb/server/smb_common.c b/fs/smb/server/smb_common.c
index 4ad01a0fa1cf..3e3758f5ed42 100644
--- a/fs/smb/server/smb_common.c
+++ b/fs/smb/server/smb_common.c
@@ -140,7 +140,7 @@ int ksmbd_verify_smb_message(struct ksmbd_work *work)
if (smb2_hdr->ProtocolId == SMB2_PROTO_NUMBER)
return ksmbd_smb2_check_message(work);

- hdr = work->request_buf;
+ hdr = smb_get_msg(work->request_buf);
if (*(__le32 *)hdr->Protocol == SMB1_PROTO_NUMBER &&
hdr->Command == SMB_COM_NEGOTIATE) {
work->conn->outstanding_credits++;
@@ -163,7 +163,7 @@ bool ksmbd_smb_request(struct ksmbd_conn *conn)
if (conn->request_buf[0] != 0)
return false;

- proto = (__le32 *)smb2_get_msg(conn->request_buf);
+ proto = (__le32 *)smb_get_msg(conn->request_buf);
if (*proto == SMB2_COMPRESSION_TRANSFORM_ID) {
pr_err_ratelimited("smb2 compression not support yet");
return false;
@@ -259,14 +259,14 @@ int ksmbd_lookup_dialect_by_id(__le16 *cli_dialects, __le16 dialects_count)
static int ksmbd_negotiate_smb_dialect(void *buf)
{
int smb_buf_length = get_rfc1002_len(buf);
- __le32 proto = ((struct smb2_hdr *)smb2_get_msg(buf))->ProtocolId;
+ __le32 proto = ((struct smb2_hdr *)smb_get_msg(buf))->ProtocolId;

if (proto == SMB2_PROTO_NUMBER) {
struct smb2_negotiate_req *req;
int smb2_neg_size =
offsetof(struct smb2_negotiate_req, Dialects);

- req = (struct smb2_negotiate_req *)smb2_get_msg(buf);
+ req = (struct smb2_negotiate_req *)smb_get_msg(buf);
if (smb2_neg_size > smb_buf_length)
goto err_out;

@@ -278,15 +278,14 @@ static int ksmbd_negotiate_smb_dialect(void *buf)
req->DialectCount);
}

- proto = *(__le32 *)((struct smb_hdr *)buf)->Protocol;
if (proto == SMB1_PROTO_NUMBER) {
struct smb_negotiate_req *req;

- req = (struct smb_negotiate_req *)buf;
+ req = (struct smb_negotiate_req *)smb_get_msg(buf);
if (le16_to_cpu(req->ByteCount) < 2)
goto err_out;

- if (offsetof(struct smb_negotiate_req, DialectsArray) - 4 +
+ if (offsetof(struct smb_negotiate_req, DialectsArray) +
le16_to_cpu(req->ByteCount) > smb_buf_length) {
goto err_out;
}
@@ -320,8 +319,8 @@ static u16 get_smb1_cmd_val(struct ksmbd_work *work)
*/
static int init_smb1_rsp_hdr(struct ksmbd_work *work)
{
- struct smb_hdr *rsp_hdr = (struct smb_hdr *)work->response_buf;
- struct smb_hdr *rcv_hdr = (struct smb_hdr *)work->request_buf;
+ struct smb_hdr *rsp_hdr = (struct smb_hdr *)smb_get_msg(work->response_buf);
+ struct smb_hdr *rcv_hdr = (struct smb_hdr *)smb_get_msg(work->request_buf);

rsp_hdr->Command = SMB_COM_NEGOTIATE;
*(__le32 *)rsp_hdr->Protocol = SMB1_PROTO_NUMBER;
@@ -412,9 +411,10 @@ static int init_smb1_server(struct ksmbd_conn *conn)

int ksmbd_init_smb_server(struct ksmbd_conn *conn)
{
+ struct smb_hdr *rcv_hdr = (struct smb_hdr *)smb_get_msg(conn->request_buf);
__le32 proto;

- proto = *(__le32 *)((struct smb_hdr *)conn->request_buf)->Protocol;
+ proto = *(__le32 *)rcv_hdr->Protocol;
if (conn->need_neg == false) {
if (proto == SMB1_PROTO_NUMBER)
return -EINVAL;
@@ -572,12 +572,12 @@ static int __smb2_negotiate(struct ksmbd_conn *conn)

static int smb_handle_negotiate(struct ksmbd_work *work)
{
- struct smb_negotiate_rsp *neg_rsp = work->response_buf;
+ struct smb_negotiate_rsp *neg_rsp = smb_get_msg(work->response_buf);

ksmbd_debug(SMB, "Unsupported SMB1 protocol\n");

- if (ksmbd_iov_pin_rsp(work, (void *)neg_rsp + 4,
- sizeof(struct smb_negotiate_rsp) - 4))
+ if (ksmbd_iov_pin_rsp(work, (void *)neg_rsp,
+ sizeof(struct smb_negotiate_rsp)))
return -ENOMEM;

neg_rsp->hdr.Status.CifsError = STATUS_SUCCESS;
diff --git a/fs/smb/server/smb_common.h b/fs/smb/server/smb_common.h
index e3be583e803d..95062e922de9 100644
--- a/fs/smb/server/smb_common.h
+++ b/fs/smb/server/smb_common.h
@@ -3,8 +3,8 @@
* Copyright (C) 2018 Samsung Electronics Co., Ltd.
*/

-#ifndef __SMB_COMMON_H__
-#define __SMB_COMMON_H__
+#ifndef __SMB_SERVER_COMMON_H__
+#define __SMB_SERVER_COMMON_H__

#include <linux/kernel.h>

@@ -424,8 +424,12 @@ unsigned int ksmbd_server_side_copy_max_total_size(void);
bool is_asterisk(char *p);
__le32 smb_map_generic_desired_access(__le32 daccess);

-static inline unsigned int get_rfc1002_len(void *buf)
+/*
+ * Get the body of the smb message excluding the 4 byte rfc1002 headers
+ * from request/response buffer.
+ */
+static inline void *smb_get_msg(void *buf)
{
- return be32_to_cpu(*((__be32 *)buf)) & 0xffffff;
+ return buf + 4;
}
-#endif /* __SMB_COMMON_H__ */
+#endif /* __SMB_SERVER_COMMON_H__ */
diff --git a/fs/xfs/libxfs/xfs_exchmaps.c b/fs/xfs/libxfs/xfs_exchmaps.c
index f021fe3c9cb6..85d651e1c1fc 100644
--- a/fs/xfs/libxfs/xfs_exchmaps.c
+++ b/fs/xfs/libxfs/xfs_exchmaps.c
@@ -959,6 +959,16 @@ xmi_can_exchange_reflink_flags(
{
struct xfs_mount *mp = req->ip1->i_mount;

+ /*
+ * The INO1_WRITTEN optimization can skip exchanging hole and
+ * unwritten mappings, which means we cannot guarantee that all
+ * shared extents actually moved to the other file. Clearing the
+ * reflink flag of an inode that still holds shared extents breaks
+ * the CoW write path, so refuse to exchange the flags in that case.
+ */
+ if (req->flags & XFS_EXCHMAPS_INO1_WRITTEN)
+ return false;
+
if (hweight32(reflink_state) != 1)
return false;
if (req->startoff1 != 0 || req->startoff2 != 0)
diff --git a/fs/xfs/libxfs/xfs_rtrefcount_btree.c b/fs/xfs/libxfs/xfs_rtrefcount_btree.c
index ac11e94b42ae..743d6eada560 100644
--- a/fs/xfs/libxfs/xfs_rtrefcount_btree.c
+++ b/fs/xfs/libxfs/xfs_rtrefcount_btree.c
@@ -201,7 +201,7 @@ xfs_rtrefcountbt_verify(
if (fa)
return fa;
level = be16_to_cpu(block->bb_level);
- if (level > mp->m_rtrefc_maxlevels)
+ if (level >= mp->m_rtrefc_maxlevels)
return __this_address;

return xfs_btree_fsblock_verify(bp, mp->m_rtrefc_mxr[level != 0]);
@@ -651,7 +651,7 @@ xfs_iformat_rtrefcount(
numrecs = be16_to_cpu(dfp->bb_numrecs);
level = be16_to_cpu(dfp->bb_level);

- if (level > mp->m_rtrefc_maxlevels ||
+ if (level >= mp->m_rtrefc_maxlevels ||
xfs_rtrefcount_droot_space_calc(level, numrecs) > dsize) {
xfs_inode_mark_sick(ip, XFS_SICK_INO_CORE);
return -EFSCORRUPTED;
diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c
index 94c272a2ae26..823ff59ba711 100644
--- a/fs/xfs/libxfs/xfs_sb.c
+++ b/fs/xfs/libxfs/xfs_sb.c
@@ -1118,10 +1118,10 @@ xfs_sb_read_verify(
* because _verify_common checks the on-disk values.
*/
__xfs_sb_from_disk(&sb, dsb, false);
- error = xfs_validate_sb_common(mp, bp, &sb);
+ error = xfs_validate_sb_read(mp, &sb);
if (error)
goto out_error;
- error = xfs_validate_sb_read(mp, &sb);
+ error = xfs_validate_sb_common(mp, bp, &sb);

out_error:
if (error == -EFSCORRUPTED || error == -EFSBADCRC)
diff --git a/fs/xfs/scrub/agheader.c b/fs/xfs/scrub/agheader.c
index 303374df44bd..2ac2125b8317 100644
--- a/fs/xfs/scrub/agheader.c
+++ b/fs/xfs/scrub/agheader.c
@@ -266,7 +266,7 @@ xchk_superblock(
xchk_block_set_corrupt(sc, bp);

if (sb->sb_gquotino != cpu_to_be64(0))
- xchk_block_set_preen(sc, bp);
+ xchk_block_set_corrupt(sc, bp);
} else {
if (sb->sb_uquotino != cpu_to_be64(mp->m_sb.sb_uquotino))
xchk_block_set_preen(sc, bp);
diff --git a/fs/xfs/scrub/agheader_repair.c b/fs/xfs/scrub/agheader_repair.c
index 6e3fef36d661..d18944449b3a 100644
--- a/fs/xfs/scrub/agheader_repair.c
+++ b/fs/xfs/scrub/agheader_repair.c
@@ -979,6 +979,13 @@ xrep_agi_calc_from_btrees(
return error;
}

+/*
+ * Magic value that means "not unlinked" because xfarrays don't support storing
+ * totally zeroed elements. There can't be a cluster that starts in daddr 0 so
+ * there can't be an inode #1 either.
+ */
+#define LINKED_AGINO (0x1)
+
/*
* Record a forwards unlinked chain pointer from agino -> next_agino in our
* staging information.
@@ -1034,31 +1041,40 @@ xrep_iunlink_next(
* the chain or if we should stop walking the chain due to corruption; or a
* per-AG inode number.
*/
-STATIC xfs_agino_t
+STATIC int
xrep_iunlink_reload_next(
struct xrep_agi *ragi,
xfs_agino_t prev_agino,
- xfs_agino_t agino)
+ xfs_agino_t agino,
+ xfs_agino_t *next_agino)
{
struct xfs_scrub *sc = ragi->sc;
struct xfs_inode *ip;
- xfs_agino_t ret = NULLAGINO;
int error;

+ *next_agino = NULLAGINO;
+
error = xchk_iget(ragi->sc, xfs_agino_to_ino(sc->sa.pag, agino), &ip);
if (error)
- return ret;
+ return 0;

trace_xrep_iunlink_reload_next(ip, prev_agino);

/* If this is a linked inode, stop processing the chain. */
if (VFS_I(ip)->i_nlink != 0) {
- xrep_iunlink_store_next(ragi, agino, NULLAGINO);
+ error = xrep_iunlink_store_next(ragi, agino, NULLAGINO);
+ if (error)
+ return error;
+
+ error = xrep_iunlink_store_prev(ragi, agino, LINKED_AGINO);
+ if (error)
+ return error;
+
goto rele;
}

ip->i_prev_unlinked = prev_agino;
- ret = ip->i_next_unlinked;
+ *next_agino = ip->i_next_unlinked;

/*
* Drop the inode reference that we just took. We hold the AGI, so
@@ -1067,7 +1083,7 @@ xrep_iunlink_reload_next(
*/
rele:
xchk_irele(sc, ip);
- return ret;
+ return 0;
}

/*
@@ -1081,7 +1097,7 @@ xrep_iunlink_walk_ondisk_bucket(
unsigned int bucket)
{
struct xfs_scrub *sc = ragi->sc;
- struct xfs_agi *agi = sc->sa.agi_bp->b_addr;
+ struct xfs_agi *agi = ragi->agi_bp->b_addr;
xfs_agino_t prev_agino = NULLAGINO;
xfs_agino_t next_agino;
int error = 0;
@@ -1100,9 +1116,12 @@ xrep_iunlink_walk_ondisk_bucket(
break;

next_agino = xrep_iunlink_next(sc, agino);
- if (!next_agino)
- next_agino = xrep_iunlink_reload_next(ragi, prev_agino,
- agino);
+ if (!next_agino) {
+ error = xrep_iunlink_reload_next(ragi, prev_agino,
+ agino, &next_agino);
+ if (error)
+ break;
+ }

prev_agino = agino;
}
@@ -1302,7 +1321,7 @@ xrep_iunlink_mark_ondisk_rec(
* iunlink_bmp. We haven't checked the inobt yet, so we don't error out if
* the btree is corrupt.
*/
-STATIC void
+STATIC int
xrep_iunlink_mark_ondisk(
struct xrep_agi *ragi)
{
@@ -1314,6 +1333,14 @@ xrep_iunlink_mark_ondisk(
cur = xfs_inobt_init_cursor(sc->sa.pag, sc->tp, agi_bp);
error = xfs_btree_query_all(cur, xrep_iunlink_mark_ondisk_rec, ragi);
xfs_btree_del_cursor(cur, error);
+
+ /*
+ * Don't proceed if we couldn't set a bit in the bitmap. All other
+ * errors we ignore because we haven't actually checked the inobt yet.
+ */
+ if (error == -ENOMEM)
+ return -ENOMEM;
+ return 0;
}

/*
@@ -1326,15 +1353,32 @@ xrep_iunlink_resolve_bucket(
struct xrep_agi *ragi,
unsigned int bucket)
{
+ struct xagino_bitmap seen;
struct xfs_scrub *sc = ragi->sc;
struct xfs_inode *ip;
xfs_agino_t prev_agino = NULLAGINO;
xfs_agino_t next_agino = ragi->iunlink_heads[bucket];
int error = 0;

+ xagino_bitmap_init(&seen);
+
while (next_agino != NULLAGINO) {
+ unsigned int len = 1;
+
if (xchk_should_terminate(ragi->sc, &error))
- return error;
+ goto out_bitmap;
+
+ /* Inode already seen? We're stuck in a loop */
+ if (xagino_bitmap_test(&seen, next_agino, &len)) {
+ trace_xrep_iunlink_resolve_infinite_loop(sc->sa.pag,
+ bucket, prev_agino, next_agino);
+ next_agino = NULLAGINO;
+ break;
+ }
+
+ error = xagino_bitmap_set(&seen, next_agino, 1);
+ if (error)
+ goto out_bitmap;

/* Find the next inode in the chain. */
ip = xfs_iunlink_lookup(sc->sa.pag, next_agino);
@@ -1347,6 +1391,35 @@ xrep_iunlink_resolve_bucket(
break;
}

+ if (VFS_I(ip)->i_nlink != 0) {
+ /*
+ * Inode is linked somewhere! Blow out both unlinked
+ * list pointers, advance the list, and pretend we
+ * didn't see this inode. Clear it from iunlink_bmp
+ * because it's linked.
+ */
+ trace_xrep_iunlink_resolve_allocated(sc->sa.pag,
+ bucket, prev_agino, next_agino);
+
+ error = xrep_iunlink_store_next(ragi, next_agino,
+ NULLAGINO);
+ if (error)
+ goto out_bitmap;
+
+ error = xrep_iunlink_store_prev(ragi, next_agino,
+ LINKED_AGINO);
+ if (error)
+ goto out_bitmap;
+
+ error = xagino_bitmap_clear(&ragi->iunlink_bmp,
+ next_agino, 1);
+ if (error)
+ goto out_bitmap;
+
+ next_agino = ip->i_next_unlinked;
+ continue;
+ }
+
if (next_agino % XFS_AGI_UNLINKED_BUCKETS != bucket) {
/*
* Inode is in the wrong bucket. Advance the list,
@@ -1382,20 +1455,20 @@ xrep_iunlink_resolve_bucket(
*/
error = xagino_bitmap_clear(&ragi->iunlink_bmp, next_agino, 1);
if (error)
- return error;
+ goto out_bitmap;

/* Remember the previous inode's next pointer. */
if (prev_agino != NULLAGINO) {
error = xrep_iunlink_store_next(ragi, prev_agino,
next_agino);
if (error)
- return error;
+ goto out_bitmap;
}

/* Remember this inode's previous pointer. */
error = xrep_iunlink_store_prev(ragi, next_agino, prev_agino);
if (error)
- return error;
+ goto out_bitmap;

/* Advance the list and remember this inode. */
prev_agino = next_agino;
@@ -1406,10 +1479,12 @@ xrep_iunlink_resolve_bucket(
if (prev_agino != NULLAGINO) {
error = xrep_iunlink_store_next(ragi, prev_agino, next_agino);
if (error)
- return error;
+ goto out_bitmap;
}

- return 0;
+out_bitmap:
+ xagino_bitmap_destroy(&seen);
+ return error;
}

/* Reinsert this unlinked inode into the head of the staged bucket list. */
@@ -1434,6 +1509,10 @@ xrep_iunlink_add_to_bucket(
if (error)
return error;

+ error = xrep_iunlink_store_prev(ragi, agino, NULLAGINO);
+ if (error)
+ return error;
+
/* Remember the head inode's previous pointer. */
if (current_head != NULLAGINO) {
error = xrep_iunlink_store_prev(ragi, current_head, agino);
@@ -1501,7 +1580,9 @@ xrep_iunlink_rebuild_buckets(
* If there are ondisk inodes that are unlinked and are not been loaded
* into cache, record them in iunlink_bmp.
*/
- xrep_iunlink_mark_ondisk(ragi);
+ error = xrep_iunlink_mark_ondisk(ragi);
+ if (error)
+ return error;

/*
* Walk each iunlink bucket to (re)construct as much of the incore list
@@ -1523,6 +1604,24 @@ xrep_iunlink_rebuild_buckets(
xrep_iunlink_add_lost_inodes, ragi);
}

+static inline void
+set_inode_prev_unlinked(
+ struct xfs_inode *ip,
+ xfs_agino_t prev_agino)
+{
+ /*
+ * Magic value that means "not unlinked" because xfarrays don't support
+ * storing totally zeroed elements.
+ */
+ if (prev_agino == LINKED_AGINO)
+ prev_agino = 0;
+
+ if (ip->i_prev_unlinked != prev_agino) {
+ trace_xrep_iunlink_relink_prev(ip, prev_agino);
+ ip->i_prev_unlinked = prev_agino;
+ }
+}
+
/* Update i_next_iunlinked for the inode @agino. */
STATIC int
xrep_iunlink_relink_next(
@@ -1556,8 +1655,7 @@ xrep_iunlink_relink_next(
if (error)
goto out_rele;

- trace_xrep_iunlink_relink_prev(ip, prev_agino);
- ip->i_prev_unlinked = prev_agino;
+ set_inode_prev_unlinked(ip, prev_agino);
}

/* Update the forward pointer. */
@@ -1612,7 +1710,7 @@ xrep_iunlink_relink_prev(
want_rele = true;

/* Set the forward pointer since this just came off disk. */
- error = xfarray_load(ragi->iunlink_prev, agino, &next_agino);
+ error = xfarray_load(ragi->iunlink_next, agino, &next_agino);
if (error)
goto out_rele;

@@ -1624,11 +1722,7 @@ xrep_iunlink_relink_prev(
ip->i_next_unlinked = next_agino;
}

- /* Update the backward pointer. */
- if (ip->i_prev_unlinked != prev_agino) {
- trace_xrep_iunlink_relink_prev(ip, prev_agino);
- ip->i_prev_unlinked = prev_agino;
- }
+ set_inode_prev_unlinked(ip, prev_agino);

out_rele:
/*
@@ -1658,6 +1752,8 @@ xrep_iunlink_commit(
if (error)
return error;
}
+ if (error < 0)
+ return error;

/* Fix all the back links */
idx = XFARRAY_CURSOR_INIT;
@@ -1666,6 +1762,8 @@ xrep_iunlink_commit(
if (error)
return error;
}
+ if (error < 0)
+ return error;

/* Copy the staged iunlink buckets to the new AGI. */
for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) {
diff --git a/fs/xfs/scrub/alloc.c b/fs/xfs/scrub/alloc.c
index 8b282138097f..c77934f5b724 100644
--- a/fs/xfs/scrub/alloc.c
+++ b/fs/xfs/scrub/alloc.c
@@ -136,7 +136,7 @@ xchk_allocbt_rec(
const union xfs_btree_rec *rec)
{
struct xfs_alloc_rec_incore irec;
- struct xchk_alloc *ca = bs->private;
+ struct xchk_alloc *ca = bs->private;

xfs_alloc_btrec_to_irec(rec, &irec);
if (xfs_alloc_check_irec(to_perag(bs->cur->bc_group), &irec) != NULL) {
@@ -144,7 +144,8 @@ xchk_allocbt_rec(
return 0;
}

- xchk_allocbt_mergeable(bs, ca, &irec);
+ if (bs->sc->sm->sm_type == XFS_SCRUB_TYPE_BNOBT)
+ xchk_allocbt_mergeable(bs, ca, &irec);
xchk_allocbt_xref(bs->sc, &irec);

return 0;
diff --git a/fs/xfs/scrub/attr_repair.c b/fs/xfs/scrub/attr_repair.c
index dd24044c44ef..fa68ecabd983 100644
--- a/fs/xfs/scrub/attr_repair.c
+++ b/fs/xfs/scrub/attr_repair.c
@@ -1427,7 +1427,8 @@ xrep_xattr_rebuild_tree(
* If we didn't find any attributes to salvage, repair the file by
* zapping its attr fork.
*/
- if (rx->attrs_found == 0) {
+ if (rx->attrs_found == 0 &&
+ (!xfs_has_parent(sc->mp) || xfarray_length(rx->pptr_recs) == 0)) {
xfs_trans_ijoin(sc->tp, sc->ip, 0);
error = xrep_xattr_reset_fork(sc);
if (error)
diff --git a/fs/xfs/scrub/bmap.c b/fs/xfs/scrub/bmap.c
index 4f1e2574660d..aa9351e544cf 100644
--- a/fs/xfs/scrub/bmap.c
+++ b/fs/xfs/scrub/bmap.c
@@ -1170,6 +1170,11 @@ xchk_bmap_attr(
}

error = xchk_bmap(sc, XFS_ATTR_FORK);
+ /* A repaired, empty attr fork no longer has mappings to check. */
+ if (error == -ENOENT && (sc->flags & XREP_ALREADY_FIXED)) {
+ xchk_mark_healthy_if_clean(sc, XFS_SICK_INO_BMBTA_ZAPPED);
+ return 0;
+ }
if (error)
return error;

diff --git a/fs/xfs/scrub/dirtree_repair.c b/fs/xfs/scrub/dirtree_repair.c
index 5c04e70ba951..d6d07798903e 100644
--- a/fs/xfs/scrub/dirtree_repair.c
+++ b/fs/xfs/scrub/dirtree_repair.c
@@ -349,6 +349,8 @@ xrep_dirtree_unlink_iolock(

ASSERT(sc->ilock_flags & XFS_IOLOCK_EXCL);

+ if (sc->ip == dp)
+ return 0;
if (xfs_ilock_nowait(dp, XFS_IOLOCK_EXCL))
return 0;

@@ -400,8 +402,18 @@ xrep_dirtree_unlink(
* directory code can handle a reservationless update.
*/
resblks = xfs_remove_space_res(mp, step->name_len);
- error = xfs_trans_alloc_dir(dp, &M_RES(mp)->tr_remove, sc->ip,
- &resblks, &sc->tp, &dontcare);
+ if (sc->ip == dp) {
+again:
+ error = xfs_trans_alloc_inode(dp, &M_RES(mp)->tr_remove,
+ resblks, 0, false, &sc->tp);
+ if ((error == -ENOSPC || error == -EDQUOT) && resblks > 0) {
+ resblks = 0;
+ goto again;
+ }
+ } else {
+ error = xfs_trans_alloc_dir(dp, &M_RES(mp)->tr_remove, sc->ip,
+ &resblks, &sc->tp, &dontcare);
+ }
if (error)
goto out_iolock;

@@ -489,9 +501,11 @@ xrep_dirtree_unlink(
xchk_trans_cancel(sc);
out_ilock:
xfs_iunlock(sc->ip, XFS_ILOCK_EXCL);
- xfs_iunlock(dp, XFS_ILOCK_EXCL);
+ if (dp != sc->ip)
+ xfs_iunlock(dp, XFS_ILOCK_EXCL);
out_iolock:
- xfs_iunlock(dp, XFS_IOLOCK_EXCL);
+ if (dp != sc->ip)
+ xfs_iunlock(dp, XFS_IOLOCK_EXCL);
return error;
}

diff --git a/fs/xfs/scrub/inode_repair.c b/fs/xfs/scrub/inode_repair.c
index 5c45a68793d0..fdb227dcfd21 100644
--- a/fs/xfs/scrub/inode_repair.c
+++ b/fs/xfs/scrub/inode_repair.c
@@ -1956,7 +1956,7 @@ xrep_inode_cowextsize(
/* Fix misaligned CoW extent size hints on a directory. */
if ((sc->ip->i_diflags & XFS_DIFLAG_RTINHERIT) &&
(sc->ip->i_diflags2 & XFS_DIFLAG2_COWEXTSIZE) &&
- sc->ip->i_extsize % sc->mp->m_sb.sb_rextsize > 0) {
+ xfs_extlen_to_rtxmod(sc->mp, sc->ip->i_cowextsize) > 0) {
sc->ip->i_cowextsize = 0;
sc->ip->i_diflags2 &= ~XFS_DIFLAG2_COWEXTSIZE;
}
diff --git a/fs/xfs/scrub/nlinks.c b/fs/xfs/scrub/nlinks.c
index dec3b9b47453..04c44d25e58a 100644
--- a/fs/xfs/scrub/nlinks.c
+++ b/fs/xfs/scrub/nlinks.c
@@ -382,6 +382,12 @@ xchk_nlinks_ilock_dir(
{
uint lock_mode = XFS_ILOCK_SHARED;

+ /*
+ * Take the IOLOCK so that other threads cannot start a directory
+ * update while we're scanning.
+ */
+ xfs_ilock(ip, XFS_IOLOCK_SHARED);
+
/*
* We're going to scan the directory entries, so we must be ready to
* pull the data fork mappings into memory if they aren't already.
@@ -397,13 +403,8 @@ xchk_nlinks_ilock_dir(
xfs_need_iread_extents(&ip->i_af))
lock_mode = XFS_ILOCK_EXCL;

- /*
- * Take the IOLOCK so that other threads cannot start a directory
- * update while we're scanning.
- */
- lock_mode |= XFS_IOLOCK_SHARED;
xfs_ilock(ip, lock_mode);
- return lock_mode;
+ return lock_mode | XFS_IOLOCK_SHARED;
}

/* Walk a directory to bump the observed link counts of the children. */
diff --git a/fs/xfs/scrub/nlinks_repair.c b/fs/xfs/scrub/nlinks_repair.c
index 6ef2ee9c3814..c3540f3dd2c7 100644
--- a/fs/xfs/scrub/nlinks_repair.c
+++ b/fs/xfs/scrub/nlinks_repair.c
@@ -232,9 +232,14 @@ xrep_nlinks_repair_inode(
* unlinked list, put it on the unlinked list.
*/
if (total_links == 0 && !xfs_inode_on_unlinked_list(ip)) {
+ if (actual_nlink)
+ clear_nlink(VFS_I(ip));
error = xfs_iunlink(sc->tp, ip);
- if (error)
+ if (error) {
+ if (actual_nlink)
+ set_nlink(VFS_I(ip), actual_nlink);
goto out_trans;
+ }
dirty = true;
}

diff --git a/fs/xfs/scrub/parent.c b/fs/xfs/scrub/parent.c
index f2ee520cc942..a1b15358a731 100644
--- a/fs/xfs/scrub/parent.c
+++ b/fs/xfs/scrub/parent.c
@@ -486,7 +486,7 @@ xchk_parent_scan_attr(
valuelen, &parent_ino, NULL);
if (error) {
xchk_fblock_set_corrupt(sc, XFS_ATTR_FORK, 0);
- return error;
+ return -ECANCELED;
}

/* No self-referential parent pointers. */
diff --git a/fs/xfs/scrub/rtbitmap_repair.c b/fs/xfs/scrub/rtbitmap_repair.c
index 41d6736a529d..d2669082d093 100644
--- a/fs/xfs/scrub/rtbitmap_repair.c
+++ b/fs/xfs/scrub/rtbitmap_repair.c
@@ -36,6 +36,24 @@

/* rt bitmap content repairs */

+/*
+ * Reserve enough blocks to write out a completely new bitmap file, plus twice
+ * as many blocks as we would need if we can only allocate one block per data
+ * fork mapping. This should cover the preallocation of the temporary file and
+ * exchanging the extent mappings.
+ *
+ * We cannot use xfs_exchmaps_estimate because we have not yet constructed the
+ * replacement bitmap and therefore do not know how many extents it will use.
+ * By the time we do, we will have a dirty transaction (which we cannot drop
+ * because we cannot drop the rtbitmap ILOCK) and cannot ask for more
+ * reservation.
+ */
+static inline unsigned long long
+xrep_rtbitmap_calc_blocks(struct xfs_mount *mp, unsigned long long blocks)
+{
+ return blocks + (xfs_bmbt_calc_size(mp, blocks) * 2);
+}
+
/* Set up to repair the realtime bitmap for this group. */
int
xrep_setup_rtbitmap(
@@ -56,20 +74,7 @@ xrep_setup_rtbitmap(
if (error)
return error;

- /*
- * Reserve enough blocks to write out a completely new bitmap file,
- * plus twice as many blocks as we would need if we can only allocate
- * one block per data fork mapping. This should cover the
- * preallocation of the temporary file and exchanging the extent
- * mappings.
- *
- * We cannot use xfs_exchmaps_estimate because we have not yet
- * constructed the replacement bitmap and therefore do not know how
- * many extents it will use. By the time we do, we will have a dirty
- * transaction (which we cannot drop because we cannot drop the
- * rtbitmap ILOCK) and cannot ask for more reservation.
- */
- blocks += xfs_bmbt_calc_size(mp, blocks) * 2;
+ blocks = xrep_rtbitmap_calc_blocks(mp, mp->m_sb.sb_rbmblocks);
if (blocks > UINT_MAX)
return -EOPNOTSUPP;

@@ -512,7 +517,7 @@ xrep_rtbitmap(
struct xchk_rtbitmap *rtb = sc->buf;
struct xfs_mount *mp = sc->mp;
struct xfs_group *xg = rtg_group(sc->sr.rtg);
- unsigned long long blocks = 0;
+ unsigned long long blocks;
unsigned int busy_gen;
int error;

@@ -532,15 +537,20 @@ xrep_rtbitmap(
* figure out if we need to adjust the block reservation in the
* transaction.
*/
- blocks = xfs_bmbt_calc_size(mp, rtb->rbmblocks);
+ blocks = xrep_rtbitmap_calc_blocks(mp, rtb->rbmblocks);
if (blocks > UINT_MAX)
return -EOPNOTSUPP;
if (blocks > rtb->resblks) {
- error = xfs_trans_reserve_more(sc->tp, blocks, 0);
+ uint64_t delta = blocks - rtb->resblks;
+
+ if (delta > UINT_MAX)
+ return -EOPNOTSUPP;
+
+ error = xfs_trans_reserve_more(sc->tp, delta, 0);
if (error)
return error;

- rtb->resblks += blocks;
+ rtb->resblks += delta;
}

/* Fix inode core and forks. */
diff --git a/fs/xfs/scrub/tempfile.c b/fs/xfs/scrub/tempfile.c
index cf99e0ca51b0..fabf6ae2e512 100644
--- a/fs/xfs/scrub/tempfile.c
+++ b/fs/xfs/scrub/tempfile.c
@@ -174,6 +174,7 @@ xrep_tempfile_create(
xfs_iunlock(sc->tempip, XFS_ILOCK_EXCL);
xfs_finish_inode_setup(sc->tempip);
xchk_irele(sc, sc->tempip);
+ sc->tempip = NULL;
}
out_release_dquots:
xfs_qm_dqrele(udqp);
diff --git a/fs/xfs/scrub/trace.h b/fs/xfs/scrub/trace.h
index fab3ce323e4c..90a7c8cad9b9 100644
--- a/fs/xfs/scrub/trace.h
+++ b/fs/xfs/scrub/trace.h
@@ -3579,10 +3579,12 @@ DEFINE_EVENT(xrep_iunlink_resolve_class, name, \
TP_PROTO(const struct xfs_perag *pag, unsigned int bucket, \
xfs_agino_t prev_agino, xfs_agino_t next_agino), \
TP_ARGS(pag, bucket, prev_agino, next_agino))
+DEFINE_REPAIR_IUNLINK_RESOLVE_EVENT(xrep_iunlink_resolve_infinite_loop);
DEFINE_REPAIR_IUNLINK_RESOLVE_EVENT(xrep_iunlink_resolve_uncached);
DEFINE_REPAIR_IUNLINK_RESOLVE_EVENT(xrep_iunlink_resolve_wronglist);
DEFINE_REPAIR_IUNLINK_RESOLVE_EVENT(xrep_iunlink_resolve_nolist);
DEFINE_REPAIR_IUNLINK_RESOLVE_EVENT(xrep_iunlink_resolve_ok);
+DEFINE_REPAIR_IUNLINK_RESOLVE_EVENT(xrep_iunlink_resolve_allocated);

TRACE_EVENT(xrep_iunlink_relink_next,
TP_PROTO(struct xfs_inode *ip, xfs_agino_t next_agino),
diff --git a/fs/xfs/xfs_buf_item_recover.c b/fs/xfs/xfs_buf_item_recover.c
index e4c8af873632..54cf93b2a196 100644
--- a/fs/xfs/xfs_buf_item_recover.c
+++ b/fs/xfs/xfs_buf_item_recover.c
@@ -461,7 +461,7 @@ xlog_recover_validate_buf_type(
* given buffer. The bitmap in the buf log format structure indicates
* where to place the logged data.
*/
-STATIC void
+STATIC int
xlog_recover_do_reg_buffer(
struct xfs_mount *mp,
struct xlog_recover_item *item,
@@ -489,8 +489,24 @@ xlog_recover_do_reg_buffer(
ASSERT(nbits > 0);
ASSERT(item->ri_buf[i].iov_base != NULL);
ASSERT(item->ri_buf[i].iov_len % XFS_BLF_CHUNK == 0);
- ASSERT(BBTOB(bp->b_length) >=
- ((uint)bit << XFS_BLF_SHIFT) + (nbits << XFS_BLF_SHIFT));
+ /*
+ * The bitmap is only trustworthy to the extent that it
+ * describes a region that actually fits inside the buffer we
+ * read in based on the (attacker-controlled) blf_len. Do not
+ * rely on an ASSERT() for this -- it compiles away entirely on
+ * non-DEBUG kernels, which is exactly where this matters, so
+ * validate it for real and abort recovery of this buffer rather
+ * than copying past the end of it.
+ */
+ if (XFS_IS_CORRUPT(mp, BBTOB(bp->b_length) <
+ ((uint)bit << XFS_BLF_SHIFT) +
+ (nbits << XFS_BLF_SHIFT))) {
+ xfs_alert(mp,
+ "Bad buffer log item dirty bitmap (bit %d, nbits %d) for %d-byte buffer at daddr 0x%llx.",
+ bit, nbits, BBTOB(bp->b_length),
+ xfs_buf_daddr(bp));
+ return -EFSCORRUPTED;
+ }

/*
* The dirty regions logged in the buffer, even though
@@ -544,6 +560,7 @@ xlog_recover_do_reg_buffer(
ASSERT(i == item->ri_total);

xlog_recover_validate_buf_type(mp, bp, buf_f, current_lsn);
+ return 0;
}

/*
@@ -552,10 +569,10 @@ xlog_recover_do_reg_buffer(
* (ie. USR or GRP), then just toss this buffer away; don't recover it.
* Else, treat it as a regular buffer and do recovery.
*
- * Return false if the buffer was tossed and true if we recovered the buffer to
- * indicate to the caller if the buffer needs writing.
+ * Return 0 if the buffer was not recovered (tossed), 1 if it was recovered and
+ * needs writing, or a negative errno if recovery of the buffer failed.
*/
-STATIC bool
+STATIC int
xlog_recover_do_dquot_buffer(
struct xfs_mount *mp,
struct xlog *log,
@@ -564,6 +581,7 @@ xlog_recover_do_dquot_buffer(
struct xfs_buf_log_format *buf_f)
{
uint type;
+ int error;

trace_xfs_log_recover_buf_dquot_buf(log, buf_f);

@@ -571,7 +589,7 @@ xlog_recover_do_dquot_buffer(
* Filesystems are required to send in quota flags at mount time.
*/
if (!mp->m_qflags)
- return false;
+ return 0;

type = 0;
if (buf_f->blf_flags & XFS_BLF_UDQUOT_BUF)
@@ -584,10 +602,12 @@ xlog_recover_do_dquot_buffer(
* This type of quotas was turned off, so ignore this buffer
*/
if (log->l_quotaoffs_flag & type)
- return false;
+ return 0;

- xlog_recover_do_reg_buffer(mp, item, bp, buf_f, NULLCOMMITLSN);
- return true;
+ error = xlog_recover_do_reg_buffer(mp, item, bp, buf_f, NULLCOMMITLSN);
+ if (error)
+ return error;
+ return 1;
}

/*
@@ -724,7 +744,9 @@ xlog_recover_do_primary_sb_buffer(
xfs_rgnumber_t orig_rgcount = mp->m_sb.sb_rgcount;
int error;

- xlog_recover_do_reg_buffer(mp, item, bp, buf_f, current_lsn);
+ error = xlog_recover_do_reg_buffer(mp, item, bp, buf_f, current_lsn);
+ if (error)
+ return error;

if (orig_agcount == 0) {
xfs_alert(mp, "Trying to grow file system without AGs");
@@ -1081,11 +1103,11 @@ xlog_recover_buf_commit_pass2(
goto out_release;
} else if (buf_f->blf_flags &
(XFS_BLF_UDQUOT_BUF|XFS_BLF_PDQUOT_BUF|XFS_BLF_GDQUOT_BUF)) {
- bool dirty;
-
- dirty = xlog_recover_do_dquot_buffer(mp, log, item, bp, buf_f);
- if (!dirty)
+ error = xlog_recover_do_dquot_buffer(mp, log, item, bp, buf_f);
+ if (error <= 0)
goto out_release;
+ /* write dirty buffer */
+ error = 0;
} else if ((xfs_blft_from_flags(buf_f) & XFS_BLFT_SB_BUF) &&
xfs_buf_daddr(bp) == 0) {
error = xlog_recover_do_primary_sb_buffer(mp, item, bp, buf_f,
@@ -1105,7 +1127,10 @@ xlog_recover_buf_commit_pass2(
xfs_buf_relse(rtsb_bp);
}
} else {
- xlog_recover_do_reg_buffer(mp, item, bp, buf_f, current_lsn);
+ error = xlog_recover_do_reg_buffer(mp, item, bp, buf_f,
+ current_lsn);
+ if (error)
+ goto out_release;
}

/*
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index 896ff8080b75..8c89f701537f 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -778,7 +778,7 @@ xfs_dq_get_next_id(
lock_flags = xfs_ilock_data_map_shared(quotip);
error = xfs_iread_extents(NULL, quotip, XFS_DATA_FORK);
if (error)
- return error;
+ goto out_unlock;

if (xfs_iext_lookup_extent(quotip, &quotip->i_df, start, &cur, &got)) {
/* contiguous chunk, bump startoff for the id calculation */
@@ -789,6 +789,7 @@ xfs_dq_get_next_id(
error = -ENOENT;
}

+out_unlock:
xfs_iunlock(quotip, lock_flags);

return error;
diff --git a/fs/xfs/xfs_dquot_item_recover.c b/fs/xfs/xfs_dquot_item_recover.c
index 89bc9bcaf51e..590412c8e615 100644
--- a/fs/xfs/xfs_dquot_item_recover.c
+++ b/fs/xfs/xfs_dquot_item_recover.c
@@ -173,7 +173,7 @@ xlog_recover_dquot_commit_pass2(

out_release:
xfs_buf_relse(bp);
- return 0;
+ return error;
}

const struct xlog_recover_item_ops xlog_dquot_item_ops = {
diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c
index 907c88034c8d..365cfe22c0eb 100644
--- a/fs/xfs/xfs_rtalloc.c
+++ b/fs/xfs/xfs_rtalloc.c
@@ -734,7 +734,7 @@ xfs_rtginode_ensure(
xfs_trans_cancel(tp);

if (error != -ENOENT)
- return 0;
+ return error;
return xfs_rtginode_create(rtg, type, true);
}

diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h
index 146ca80e35db..8e2e51f98430 100644
--- a/include/drm/drm_client.h
+++ b/include/drm/drm_client.h
@@ -173,20 +173,12 @@ struct drm_client_buffer {
*/
struct drm_client_dev *client;

- /**
- * @pitch: Buffer pitch
- */
- u32 pitch;
-
/**
* @gem: GEM object backing this buffer
*
- * FIXME: The dependency on GEM here isn't required, we could
- * convert the driver handle to a dma-buf instead and use the
- * backend-agnostic dma-buf vmap support instead. This would
- * require that the handle2fd prime ioctl is reworked to pull the
- * fd_install step out of the driver backend hooks, to make that
- * final step optional for internal users.
+ * FIXME: The DRM framebuffer holds a reference on its GEM
+ * buffer objects. Do not use this field in new code and
+ * update existing users.
*/
struct drm_gem_object *gem;

@@ -203,7 +195,7 @@ struct drm_client_buffer {

struct drm_client_buffer *
drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format);
-void drm_client_framebuffer_delete(struct drm_client_buffer *buffer);
+void drm_client_buffer_delete(struct drm_client_buffer *buffer);
int drm_client_framebuffer_flush(struct drm_client_buffer *buffer, struct drm_rect *rect);
int drm_client_buffer_vmap_local(struct drm_client_buffer *buffer,
struct iosys_map *map_copy);
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 7244d8e15536..868af0a08f52 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -1151,6 +1151,7 @@ extern int ata_scsi_ioctl(struct scsi_device *dev, unsigned int cmd,
#define ATA_SCSI_COMPAT_IOCTL /* empty */
#endif
extern int ata_scsi_queuecmd(struct Scsi_Host *h, struct scsi_cmnd *cmd);
+enum scsi_timeout_action ata_scsi_eh_timed_out(struct scsi_cmnd *cmd);
#if IS_REACHABLE(CONFIG_ATA)
bool ata_scsi_dma_need_drain(struct request *rq);
#else
@@ -1460,6 +1461,7 @@ extern const struct attribute_group *ata_common_sdev_groups[];
.ioctl = ata_scsi_ioctl, \
ATA_SCSI_COMPAT_IOCTL \
.queuecommand = ata_scsi_queuecmd, \
+ .eh_timed_out = ata_scsi_eh_timed_out, \
.dma_need_drain = ata_scsi_dma_need_drain, \
.this_id = ATA_SHT_THIS_ID, \
.emulated = ATA_SHT_EMULATED, \
diff --git a/include/linux/swapops.h b/include/linux/swapops.h
index a73c5f14b591..57aad87e46a6 100644
--- a/include/linux/swapops.h
+++ b/include/linux/swapops.h
@@ -570,7 +570,7 @@ static inline pmd_t swp_entry_to_pmd(swp_entry_t entry)
return __swp_entry_to_pmd(arch_entry);
}

-static inline int is_pmd_migration_entry(pmd_t pmd)
+static inline int pmd_is_migration_entry(pmd_t pmd)
{
return is_swap_pmd(pmd) && is_migration_entry(pmd_to_swp_entry(pmd));
}
@@ -599,7 +599,7 @@ static inline pmd_t swp_entry_to_pmd(swp_entry_t entry)
return __pmd(0);
}

-static inline int is_pmd_migration_entry(pmd_t pmd)
+static inline int pmd_is_migration_entry(pmd_t pmd)
{
return 0;
}
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index b65009a226e0..94dfc3a265ee 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -34,6 +34,12 @@
#define IP_VS_HDR_INVERSE 1
#define IP_VS_HDR_ICMP 2

+/* Destination Server Flags */
+#define IP_VS_DEST_F_OVERLOAD 0x0002 /* server is overloaded */
+
+/* Destination Server Config Flags */
+#define IP_VS_DEST_CF_AVAILABLE 0x0001 /* server is available */
+
/* Generic access of ipvs struct */
static inline struct netns_ipvs *net_ipvs(struct net* net)
{
@@ -725,6 +731,7 @@ struct ip_vs_dest {
volatile unsigned int flags; /* dest status flags */
atomic_t conn_flags; /* flags to copy to conn */
atomic_t weight; /* server weight */
+ unsigned long cflags; /* config flags */
atomic_t last_weight; /* server latest weight */
__u16 tun_type; /* tunnel type */
__be16 tun_port; /* tunnel port */
diff --git a/include/uapi/linux/ip_vs.h b/include/uapi/linux/ip_vs.h
index 1ed234e7f251..2c37c6ac7525 100644
--- a/include/uapi/linux/ip_vs.h
+++ b/include/uapi/linux/ip_vs.h
@@ -28,12 +28,6 @@
#define IP_VS_SVC_F_SCHED_SH_FALLBACK IP_VS_SVC_F_SCHED1 /* SH fallback */
#define IP_VS_SVC_F_SCHED_SH_PORT IP_VS_SVC_F_SCHED2 /* SH use port */

-/*
- * Destination Server Flags
- */
-#define IP_VS_DEST_F_AVAILABLE 0x0001 /* server is available */
-#define IP_VS_DEST_F_OVERLOAD 0x0002 /* server is overloaded */
-
/*
* IPVS sync daemon states
*/
diff --git a/kernel/events/core.c b/kernel/events/core.c
index d64f8edeaf8b..04c9d4915093 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -13549,7 +13549,7 @@ SYSCALL_DEFINE5(perf_event_open,
goto err_fd;
}
group_leader = fd_file(group)->private_data;
- if (group_leader->state <= PERF_EVENT_STATE_REVOKED) {
+ if (group_leader->state <= PERF_EVENT_STATE_EXIT) {
err = -ENODEV;
goto err_fd;
}
@@ -13680,6 +13680,12 @@ SYSCALL_DEFINE5(perf_event_open,
if (group_leader->ctx != ctx)
goto err_locked;

+ /* Recheck under ctx::mutex to serialize against remove-on-exec. */
+ if (group_leader->state <= PERF_EVENT_STATE_EXIT) {
+ err = -ENODEV;
+ goto err_locked;
+ }
+
/*
* Only a group leader can be exclusive or pinned
*/
diff --git a/kernel/futex/core.c b/kernel/futex/core.c
index 4f5d7d042f8e..fde558fd2bd6 100644
--- a/kernel/futex/core.c
+++ b/kernel/futex/core.c
@@ -1774,12 +1774,12 @@ static bool futex_pivot_pending(struct mm_struct *mm)
{
struct futex_private_hash *fph;

- guard(rcu)();
+ guard(mutex)(&mm->futex_hash_lock);

if (!mm->futex_phash_new)
return true;

- fph = rcu_dereference(mm->futex_phash);
+ fph = rcu_dereference_raw(mm->futex_phash);
return futex_ref_is_dead(fph);
}

diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
index 83baf2708888..b5f95b379ea6 100644
--- a/kernel/sched/ext.c
+++ b/kernel/sched/ext.c
@@ -2841,7 +2841,10 @@ static int scx_init_task(struct task_struct *p, struct task_group *tg, bool fork
scx_set_task_state(p, SCX_TASK_INIT);

if (p->scx.disallow) {
- if (!fork) {
+ if (unlikely(fork)) {
+ scx_error(sch, "ops.init_task() set task->scx.disallow for %s[%d] during fork",
+ p->comm, p->pid);
+ } else {
struct rq *rq;
struct rq_flags rf;

@@ -2860,9 +2863,6 @@ static int scx_init_task(struct task_struct *p, struct task_group *tg, bool fork
}

task_rq_unlock(rq, p, &rf);
- } else if (p->policy == SCHED_EXT) {
- scx_error(sch, "ops.init_task() set task->scx.disallow for %s[%d] during fork",
- p->comm, p->pid);
}
}

@@ -3029,8 +3029,8 @@ void sched_ext_free(struct task_struct *p)
raw_spin_unlock_irqrestore(&scx_tasks_lock, flags);

/*
- * @p is off scx_tasks and wholly ours. scx_enable()'s READY -> ENABLED
- * transitions can't race us. Disable ops for @p.
+ * @p is off scx_tasks and wholly ours. scx_root_enable()'s READY ->
+ * ENABLED transitions can't race us. Disable ops for @p.
*/
if (scx_get_task_state(p) != SCX_TASK_NONE) {
struct rq_flags rf;
@@ -3313,16 +3313,21 @@ void scx_group_set_bandwidth(struct task_group *tg,
percpu_up_read(&scx_cgroup_ops_rwsem);
}

+/*
+ * cgroup_lock() must nest outside the rwsem write side: a writer waiting
+ * for cgroup_mutex deadlocks with cgroup teardown, which holds it while
+ * draining a set_* file write blocked on the rwsem behind the writer.
+ */
static void scx_cgroup_lock(void)
{
- percpu_down_write(&scx_cgroup_ops_rwsem);
cgroup_lock();
+ percpu_down_write(&scx_cgroup_ops_rwsem);
}

static void scx_cgroup_unlock(void)
{
- cgroup_unlock();
percpu_up_write(&scx_cgroup_ops_rwsem);
+ cgroup_unlock();
}

#else /* CONFIG_EXT_GROUP_SCHED */
@@ -3962,24 +3967,12 @@ static void free_kick_pseqs(void)
}
}

-static void scx_disable_workfn(struct kthread_work *work)
+static void scx_root_disable(struct scx_sched *sch)
{
- struct scx_sched *sch = container_of(work, struct scx_sched, disable_work);
struct scx_exit_info *ei = sch->exit_info;
struct scx_task_iter sti;
struct task_struct *p;
- int kind, cpu;
-
- kind = atomic_read(&sch->exit_kind);
- while (true) {
- if (kind == SCX_EXIT_DONE) /* already disabled? */
- return;
- WARN_ON_ONCE(kind == SCX_EXIT_NONE);
- if (atomic_try_cmpxchg(&sch->exit_kind, &kind, SCX_EXIT_DONE))
- break;
- }
- ei->kind = kind;
- ei->reason = scx_exit_reason(ei->kind);
+ int cpu;

/* guarantee forward progress by bypassing scx_ops */
scx_bypass(true);
@@ -4124,6 +4117,9 @@ static bool scx_claim_exit(struct scx_sched *sch, enum scx_exit_kind kind)

lockdep_assert_preemption_disabled();

+ if (WARN_ON_ONCE(kind == SCX_EXIT_NONE || kind == SCX_EXIT_DONE))
+ kind = SCX_EXIT_ERROR;
+
if (!atomic_try_cmpxchg(&sch->exit_kind, &none, kind))
return false;

@@ -4136,21 +4132,31 @@ static bool scx_claim_exit(struct scx_sched *sch, enum scx_exit_kind kind)
return true;
}

-static void scx_disable(enum scx_exit_kind kind)
+static void scx_disable_workfn(struct kthread_work *work)
{
- struct scx_sched *sch;
+ struct scx_sched *sch = container_of(work, struct scx_sched, disable_work);
+ struct scx_exit_info *ei = sch->exit_info;
+ int kind;

- if (WARN_ON_ONCE(kind == SCX_EXIT_NONE || kind == SCX_EXIT_DONE))
- kind = SCX_EXIT_ERROR;
+ kind = atomic_read(&sch->exit_kind);
+ while (true) {
+ if (kind == SCX_EXIT_DONE) /* already disabled? */
+ return;
+ WARN_ON_ONCE(kind == SCX_EXIT_NONE);
+ if (atomic_try_cmpxchg(&sch->exit_kind, &kind, SCX_EXIT_DONE))
+ break;
+ }
+ ei->kind = kind;
+ ei->reason = scx_exit_reason(ei->kind);

- rcu_read_lock();
- sch = rcu_dereference(scx_root);
- if (sch) {
- guard(preempt)();
- scx_claim_exit(sch, kind);
+ scx_root_disable(sch);
+}
+
+static void scx_disable(struct scx_sched *sch, enum scx_exit_kind kind)
+{
+ guard(preempt)();
+ if (scx_claim_exit(sch, kind))
kthread_queue_work(sch->helper, &sch->disable_work);
- }
- rcu_read_unlock();
}

static void dump_newline(struct seq_buf *s)
@@ -4662,10 +4668,9 @@ struct scx_enable_cmd {
int ret;
};

-static void scx_enable_workfn(struct kthread_work *work)
+static void scx_root_enable_workfn(struct kthread_work *work)
{
- struct scx_enable_cmd *cmd =
- container_of(work, struct scx_enable_cmd, work);
+ struct scx_enable_cmd *cmd = container_of(work, struct scx_enable_cmd, work);
struct sched_ext_ops *ops = cmd->ops;
struct scx_sched *sch;
struct scx_task_iter sti;
@@ -4915,12 +4920,12 @@ static void scx_enable_workfn(struct kthread_work *work)
* Flush scx_disable_work to ensure that error is reported before init
* completion. sch's base reference will be put by bpf_scx_unreg().
*/
- scx_error(sch, "scx_enable() failed (%d)", ret);
+ scx_error(sch, "scx_root_enable() failed (%d)", ret);
kthread_flush_work(&sch->disable_work);
cmd->ret = 0;
}

-static int scx_enable(struct sched_ext_ops *ops, struct bpf_link *link)
+static s32 scx_enable(struct sched_ext_ops *ops, struct bpf_link *link)
{
static struct kthread_worker *helper;
static DEFINE_MUTEX(helper_mutex);
@@ -4946,7 +4951,7 @@ static int scx_enable(struct sched_ext_ops *ops, struct bpf_link *link)
mutex_unlock(&helper_mutex);
}

- kthread_init_work(&cmd.work, scx_enable_workfn);
+ kthread_init_work(&cmd.work, scx_root_enable_workfn);
cmd.ops = ops;

kthread_queue_work(READ_ONCE(helper), &cmd.work);
@@ -5089,7 +5094,7 @@ static void bpf_scx_unreg(void *kdata, struct bpf_link *link)
struct sched_ext_ops *ops = kdata;
struct scx_sched *sch = ops->priv;

- scx_disable(SCX_EXIT_UNREG);
+ scx_disable(sch, SCX_EXIT_UNREG);
kthread_flush_work(&sch->disable_work);
kobject_put(&sch->kobj);
}
@@ -5217,7 +5222,15 @@ static struct bpf_struct_ops bpf_sched_ext_ops = {

static void sysrq_handle_sched_ext_reset(u8 key)
{
- scx_disable(SCX_EXIT_SYSRQ);
+ struct scx_sched *sch;
+
+ rcu_read_lock();
+ sch = rcu_dereference(scx_root);
+ if (likely(sch))
+ scx_disable(sch, SCX_EXIT_SYSRQ);
+ else
+ pr_info("sched_ext: BPF schedulers not loaded\n");
+ rcu_read_unlock();
}

static const struct sysrq_key_op sysrq_sched_ext_reset_op = {
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index d451926bc55d..f643ae98e4d1 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -2594,7 +2594,8 @@ unsigned long ftrace_find_rec_direct(unsigned long ip)
{
struct ftrace_func_entry *entry;

- entry = __ftrace_lookup_ip(direct_functions, ip);
+ guard(preempt_notrace)();
+ entry = __ftrace_lookup_ip(rcu_dereference_sched(direct_functions), ip);
if (!entry)
return 0;

@@ -7863,7 +7864,8 @@ static void add_to_clear_hash_list(struct list_head *clear_list,
void ftrace_free_mem(struct module *mod, void *start_ptr, void *end_ptr)
{
unsigned long start = (unsigned long)(start_ptr);
- unsigned long end = (unsigned long)(end_ptr);
+ /* end is inclusive and end_ptr is exclusive */
+ unsigned long end = (unsigned long)(end_ptr) - 1;
struct ftrace_page **last_pg = &ftrace_pages_start;
struct ftrace_page *tmp_page = NULL;
struct ftrace_page *pg;
@@ -7873,6 +7875,9 @@ void ftrace_free_mem(struct module *mod, void *start_ptr, void *end_ptr)
struct ftrace_init_func *func, *func_next;
LIST_HEAD(clear_hash);

+ if (start_ptr >= end_ptr)
+ return;
+
key.ip = start;
key.flags = end; /* overload flags, as it is unsigned long */

diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index 9c2dfff126b1..9ea034b55158 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -404,6 +404,41 @@ static void free_buffer_page(struct buffer_page *bpage)
kfree(bpage);
}

+/*
+ * For best performance, allocate cpu buffer data cache line sized
+ * and per CPU.
+ */
+#define alloc_cpu_buffer(cpu) (struct ring_buffer_per_cpu *) \
+ kzalloc_node(ALIGN(sizeof(struct ring_buffer_per_cpu), \
+ cache_line_size()), GFP_KERNEL, cpu_to_node(cpu));
+
+#define alloc_cpu_page(cpu) (struct buffer_page *) \
+ kzalloc_node(ALIGN(sizeof(struct buffer_page), \
+ cache_line_size()), GFP_KERNEL, cpu_to_node(cpu));
+
+static struct buffer_data_page *alloc_cpu_data(int cpu, int order)
+{
+ struct buffer_data_page *dpage;
+ struct page *page;
+ gfp_t mflags;
+
+ /*
+ * __GFP_RETRY_MAYFAIL flag makes sure that the allocation fails
+ * gracefully without invoking oom-killer and the system is not
+ * destabilized.
+ */
+ mflags = GFP_KERNEL | __GFP_RETRY_MAYFAIL | __GFP_COMP | __GFP_ZERO;
+
+ page = alloc_pages_node(cpu_to_node(cpu), mflags, order);
+ if (!page)
+ return NULL;
+
+ dpage = page_address(page);
+ rb_init_page(dpage);
+
+ return dpage;
+}
+
/*
* We need to fit the time_stamp delta into 27 bits.
*/
@@ -522,7 +557,7 @@ struct ring_buffer_per_cpu {
unsigned int mapped;
unsigned int user_mapped; /* user space mapping */
struct mutex mapping_lock;
- unsigned long *subbuf_ids; /* ID to subbuf VA */
+ struct buffer_page **subbuf_ids; /* ID to subbuf VA */
struct trace_buffer_meta *meta_page;
struct ring_buffer_cpu_meta *ring_meta;

@@ -2214,7 +2249,6 @@ static int __rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
struct ring_buffer_cpu_meta *meta = NULL;
struct buffer_page *bpage, *tmp;
bool user_thread = current->mm != NULL;
- gfp_t mflags;
long i;

/*
@@ -2228,13 +2262,6 @@ static int __rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
if (i < nr_pages)
return -ENOMEM;

- /*
- * __GFP_RETRY_MAYFAIL flag makes sure that the allocation fails
- * gracefully without invoking oom-killer and the system is not
- * destabilized.
- */
- mflags = GFP_KERNEL | __GFP_RETRY_MAYFAIL;
-
/*
* If a user thread allocates too much, and si_mem_available()
* reports there's enough memory, even though there is not.
@@ -2251,10 +2278,8 @@ static int __rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
meta = rb_range_meta(buffer, nr_pages, cpu_buffer->cpu);

for (i = 0; i < nr_pages; i++) {
- struct page *page;

- bpage = kzalloc_node(ALIGN(sizeof(*bpage), cache_line_size()),
- mflags, cpu_to_node(cpu_buffer->cpu));
+ bpage = alloc_cpu_page(cpu_buffer->cpu);
if (!bpage)
goto free_pages;

@@ -2277,13 +2302,10 @@ static int __rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
bpage->range = 1;
bpage->id = i + 1;
} else {
- page = alloc_pages_node(cpu_to_node(cpu_buffer->cpu),
- mflags | __GFP_COMP | __GFP_ZERO,
- cpu_buffer->buffer->subbuf_order);
- if (!page)
+ int order = cpu_buffer->buffer->subbuf_order;
+ bpage->page = alloc_cpu_data(cpu_buffer->cpu, order);
+ if (!bpage->page)
goto free_pages;
- bpage->page = page_address(page);
- rb_init_page(bpage->page);
}
bpage->order = cpu_buffer->buffer->subbuf_order;

@@ -2334,14 +2356,12 @@ static int rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
static struct ring_buffer_per_cpu *
rb_allocate_cpu_buffer(struct trace_buffer *buffer, long nr_pages, int cpu)
{
- struct ring_buffer_per_cpu *cpu_buffer __free(kfree) = NULL;
+ struct ring_buffer_per_cpu *cpu_buffer __free(kfree) =
+ alloc_cpu_buffer(cpu);
struct ring_buffer_cpu_meta *meta;
struct buffer_page *bpage;
- struct page *page;
int ret;

- cpu_buffer = kzalloc_node(ALIGN(sizeof(*cpu_buffer), cache_line_size()),
- GFP_KERNEL, cpu_to_node(cpu));
if (!cpu_buffer)
return NULL;

@@ -2357,8 +2377,7 @@ rb_allocate_cpu_buffer(struct trace_buffer *buffer, long nr_pages, int cpu)
init_waitqueue_head(&cpu_buffer->irq_work.full_waiters);
mutex_init(&cpu_buffer->mapping_lock);

- bpage = kzalloc_node(ALIGN(sizeof(*bpage), cache_line_size()),
- GFP_KERNEL, cpu_to_node(cpu));
+ bpage = alloc_cpu_page(cpu);
if (!bpage)
return NULL;
bpage->order = cpu_buffer->buffer->subbuf_order;
@@ -2380,14 +2399,13 @@ rb_allocate_cpu_buffer(struct trace_buffer *buffer, long nr_pages, int cpu)
if (cpu_buffer->ring_meta->head_buffer)
rb_meta_buffer_update(cpu_buffer, bpage);
bpage->range = 1;
+
+ atomic_inc(&cpu_buffer->resize_disabled);
} else {
- page = alloc_pages_node(cpu_to_node(cpu),
- GFP_KERNEL | __GFP_COMP | __GFP_ZERO,
- cpu_buffer->buffer->subbuf_order);
- if (!page)
+ int order = cpu_buffer->buffer->subbuf_order;
+ bpage->page = alloc_cpu_data(cpu, order);
+ if (!bpage->page)
goto fail_free_reader;
- bpage->page = page_address(page);
- rb_init_page(bpage->page);
}

INIT_LIST_HEAD(&cpu_buffer->reader_page->list);
@@ -6494,7 +6512,6 @@ ring_buffer_alloc_read_page(struct trace_buffer *buffer, int cpu)
struct ring_buffer_per_cpu *cpu_buffer;
struct buffer_data_read_page *bpage = NULL;
unsigned long flags;
- struct page *page;

if (!cpumask_test_cpu(cpu, buffer->cpumask))
return ERR_PTR(-ENODEV);
@@ -6516,22 +6533,16 @@ ring_buffer_alloc_read_page(struct trace_buffer *buffer, int cpu)
arch_spin_unlock(&cpu_buffer->lock);
local_irq_restore(flags);

- if (bpage->data)
- goto out;
-
- page = alloc_pages_node(cpu_to_node(cpu),
- GFP_KERNEL | __GFP_NORETRY | __GFP_COMP | __GFP_ZERO,
- cpu_buffer->buffer->subbuf_order);
- if (!page) {
- kfree(bpage);
- return ERR_PTR(-ENOMEM);
+ if (bpage->data) {
+ rb_init_page(bpage->data);
+ } else {
+ bpage->data = alloc_cpu_data(cpu, cpu_buffer->buffer->subbuf_order);
+ if (!bpage->data) {
+ kfree(bpage);
+ return ERR_PTR(-ENOMEM);
+ }
}

- bpage->data = page_address(page);
-
- out:
- rb_init_page(bpage->data);
-
return bpage;
}
EXPORT_SYMBOL_GPL(ring_buffer_alloc_read_page);
@@ -7030,7 +7041,7 @@ static void rb_free_meta_page(struct ring_buffer_per_cpu *cpu_buffer)
}

static void rb_setup_ids_meta_page(struct ring_buffer_per_cpu *cpu_buffer,
- unsigned long *subbuf_ids)
+ struct buffer_page **subbuf_ids)
{
struct trace_buffer_meta *meta = cpu_buffer->meta_page;
unsigned int nr_subbufs = cpu_buffer->nr_pages + 1;
@@ -7039,7 +7050,7 @@ static void rb_setup_ids_meta_page(struct ring_buffer_per_cpu *cpu_buffer,
int id = 0;

id = rb_page_id(cpu_buffer, cpu_buffer->reader_page, id);
- subbuf_ids[id++] = (unsigned long)cpu_buffer->reader_page->page;
+ subbuf_ids[id++] = cpu_buffer->reader_page;
cnt++;

first_subbuf = subbuf = rb_set_head_page(cpu_buffer);
@@ -7049,7 +7060,7 @@ static void rb_setup_ids_meta_page(struct ring_buffer_per_cpu *cpu_buffer,
if (WARN_ON(id >= nr_subbufs))
break;

- subbuf_ids[id] = (unsigned long)subbuf->page;
+ subbuf_ids[id] = subbuf;

rb_inc_page(&subbuf);
id++;
@@ -7058,7 +7069,7 @@ static void rb_setup_ids_meta_page(struct ring_buffer_per_cpu *cpu_buffer,

WARN_ON(cnt != nr_subbufs);

- /* install subbuf ID to kern VA translation */
+ /* install subbuf ID to bpage translation */
cpu_buffer->subbuf_ids = subbuf_ids;

meta->meta_struct_len = sizeof(*meta);
@@ -7214,13 +7225,15 @@ static int __rb_map_vma(struct ring_buffer_per_cpu *cpu_buffer,
}

while (p < nr_pages) {
+ struct buffer_page *subbuf;
struct page *page;
int off = 0;

if (WARN_ON_ONCE(s >= nr_subbufs))
return -EINVAL;

- page = virt_to_page((void *)cpu_buffer->subbuf_ids[s]);
+ subbuf = cpu_buffer->subbuf_ids[s];
+ page = virt_to_page((void *)subbuf->page);

for (; off < (1 << (subbuf_order)); off++, page++) {
if (p >= nr_pages)
@@ -7247,7 +7260,8 @@ int ring_buffer_map(struct trace_buffer *buffer, int cpu,
struct vm_area_struct *vma)
{
struct ring_buffer_per_cpu *cpu_buffer;
- unsigned long flags, *subbuf_ids;
+ struct buffer_page **subbuf_ids;
+ unsigned long flags;
int err;

if (!cpumask_test_cpu(cpu, buffer->cpumask))
@@ -7271,7 +7285,7 @@ int ring_buffer_map(struct trace_buffer *buffer, int cpu,
if (err)
return err;

- /* subbuf_ids include the reader while nr_pages does not */
+ /* subbuf_ids includes the reader while nr_pages does not */
subbuf_ids = kcalloc(cpu_buffer->nr_pages + 1, sizeof(*subbuf_ids), GFP_KERNEL);
if (!subbuf_ids) {
rb_free_meta_page(cpu_buffer);
diff --git a/mm/hmm.c b/mm/hmm.c
index a56081d67ad6..df9b11e1d8ed 100644
--- a/mm/hmm.c
+++ b/mm/hmm.c
@@ -407,7 +407,7 @@ static int hmm_vma_walk_pmd(pmd_t *pmdp,
if (pmd_none(pmd))
return hmm_vma_walk_hole(start, end, -1, walk);

- if (thp_migration_supported() && is_pmd_migration_entry(pmd)) {
+ if (thp_migration_supported() && pmd_is_migration_entry(pmd)) {
if (hmm_range_need_fault(hmm_vma_walk, hmm_pfns, npages, 0)) {
hmm_vma_walk->last = addr;
pmd_migration_entry_wait(walk->mm, pmdp);
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 94f95ac8b760..227aeffae8ee 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -1722,7 +1722,7 @@ int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm,
if (unlikely(is_swap_pmd(pmd))) {
swp_entry_t entry = pmd_to_swp_entry(pmd);

- VM_BUG_ON(!is_pmd_migration_entry(pmd));
+ VM_BUG_ON(!pmd_is_migration_entry(pmd));
if (!is_readable_migration_entry(entry)) {
entry = make_readable_migration_entry(
swp_offset(entry));
@@ -2132,7 +2132,7 @@ bool madvise_free_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,

if (unlikely(!pmd_present(orig_pmd))) {
VM_BUG_ON(thp_migration_supported() &&
- !is_pmd_migration_entry(orig_pmd));
+ !pmd_is_migration_entry(orig_pmd));
goto out;
}

@@ -2233,7 +2233,7 @@ int zap_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,
} else if (thp_migration_supported()) {
swp_entry_t entry;

- VM_BUG_ON(!is_pmd_migration_entry(orig_pmd));
+ VM_BUG_ON(!pmd_is_migration_entry(orig_pmd));
entry = pmd_to_swp_entry(orig_pmd);
folio = pfn_swap_entry_folio(entry);
flush_needed = 0;
@@ -2283,7 +2283,7 @@ static inline int pmd_move_must_withdraw(spinlock_t *new_pmd_ptl,
static pmd_t move_soft_dirty_pmd(pmd_t pmd)
{
#ifdef CONFIG_MEM_SOFT_DIRTY
- if (unlikely(is_pmd_migration_entry(pmd)))
+ if (unlikely(pmd_is_migration_entry(pmd)))
pmd = pmd_swp_mksoft_dirty(pmd);
else if (pmd_present(pmd))
pmd = pmd_mksoft_dirty(pmd);
@@ -2386,7 +2386,7 @@ int change_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma,
struct folio *folio = pfn_swap_entry_folio(entry);
pmd_t newpmd;

- VM_BUG_ON(!is_pmd_migration_entry(*pmd));
+ VM_BUG_ON(!pmd_is_migration_entry(*pmd));
if (is_writable_migration_entry(entry)) {
/*
* A protection check is difficult so
@@ -2574,8 +2574,8 @@ int move_pages_huge_pmd(struct mm_struct *mm, pmd_t *dst_pmd, pmd_t *src_pmd, pm

if (!pmd_trans_huge(src_pmdval)) {
spin_unlock(src_ptl);
- if (is_pmd_migration_entry(src_pmdval)) {
- pmd_migration_entry_wait(mm, &src_pmdval);
+ if (pmd_is_migration_entry(src_pmdval)) {
+ pmd_migration_entry_wait(mm, src_pmd);
return -EAGAIN;
}
return -ENOENT;
@@ -2863,7 +2863,7 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
VM_BUG_ON(haddr & ~HPAGE_PMD_MASK);
VM_BUG_ON_VMA(vma->vm_start > haddr, vma);
VM_BUG_ON_VMA(vma->vm_end < haddr + HPAGE_PMD_SIZE, vma);
- VM_BUG_ON(!is_pmd_migration_entry(*pmd) && !pmd_trans_huge(*pmd));
+ VM_BUG_ON(!pmd_is_migration_entry(*pmd) && !pmd_trans_huge(*pmd));

count_vm_event(THP_SPLIT_PMD);

@@ -2877,7 +2877,7 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
zap_deposited_table(mm, pmd);
if (!vma_is_dax(vma) && vma_is_special_huge(vma))
return;
- if (unlikely(is_pmd_migration_entry(old_pmd))) {
+ if (unlikely(pmd_is_migration_entry(old_pmd))) {
swp_entry_t entry;

entry = pmd_to_swp_entry(old_pmd);
@@ -2913,7 +2913,7 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
return __split_huge_zero_page_pmd(vma, haddr, pmd);
}

- pmd_migration = is_pmd_migration_entry(*pmd);
+ pmd_migration = pmd_is_migration_entry(*pmd);
if (unlikely(pmd_migration)) {
swp_entry_t entry;

@@ -3073,7 +3073,7 @@ void split_huge_pmd_locked(struct vm_area_struct *vma, unsigned long address,
pmd_t *pmd, bool freeze)
{
VM_WARN_ON_ONCE(!IS_ALIGNED(address, HPAGE_PMD_SIZE));
- if (pmd_trans_huge(*pmd) || is_pmd_migration_entry(*pmd))
+ if (pmd_trans_huge(*pmd) || pmd_is_migration_entry(*pmd))
__split_huge_pmd_locked(vma, pmd, address, freeze);
}

diff --git a/mm/khugepaged.c b/mm/khugepaged.c
index 01a5d443ffc5..6b3ba903ba39 100644
--- a/mm/khugepaged.c
+++ b/mm/khugepaged.c
@@ -939,7 +939,7 @@ static inline int check_pmd_state(pmd_t *pmd)
* collapse it. Migration success or failure will eventually end
* up with a present PMD mapping a folio again.
*/
- if (is_pmd_migration_entry(pmde))
+ if (pmd_is_migration_entry(pmde))
return SCAN_PMD_MAPPED;
if (!pmd_present(pmde))
return SCAN_PMD_NULL;
diff --git a/mm/madvise.c b/mm/madvise.c
index 588a809dac11..73f56b18c337 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -391,7 +391,7 @@ static int madvise_cold_or_pageout_pte_range(pmd_t *pmd,

if (unlikely(!pmd_present(orig_pmd))) {
VM_BUG_ON(thp_migration_supported() &&
- !is_pmd_migration_entry(orig_pmd));
+ !pmd_is_migration_entry(orig_pmd));
goto huge_unlock;
}

diff --git a/mm/memory.c b/mm/memory.c
index 9b071e269d1e..6b4cdb8bd8db 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -6327,8 +6327,8 @@ static vm_fault_t __handle_mm_fault(struct vm_area_struct *vma,

if (unlikely(is_swap_pmd(vmf.orig_pmd))) {
VM_BUG_ON(thp_migration_supported() &&
- !is_pmd_migration_entry(vmf.orig_pmd));
- if (is_pmd_migration_entry(vmf.orig_pmd))
+ !pmd_is_migration_entry(vmf.orig_pmd));
+ if (pmd_is_migration_entry(vmf.orig_pmd))
pmd_migration_entry_wait(mm, vmf.pmd);
return 0;
}
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index 779a8cc17a83..b4aa4f2cb8ec 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -651,7 +651,7 @@ static void queue_folios_pmd(pmd_t *pmd, struct mm_walk *walk)
struct folio *folio;
struct queue_pages *qp = walk->private;

- if (unlikely(is_pmd_migration_entry(*pmd))) {
+ if (unlikely(pmd_is_migration_entry(*pmd))) {
qp->nr_failed++;
return;
}
diff --git a/mm/migrate.c b/mm/migrate.c
index ad7af66a4450..e66d9cc67dda 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -542,7 +542,7 @@ void pmd_migration_entry_wait(struct mm_struct *mm, pmd_t *pmd)
spinlock_t *ptl;

ptl = pmd_lock(mm, pmd);
- if (!is_pmd_migration_entry(*pmd))
+ if (!pmd_is_migration_entry(*pmd))
goto unlock;
migration_entry_wait_on_locked(pmd_to_swp_entry(*pmd), ptl);
return;
diff --git a/mm/page_table_check.c b/mm/page_table_check.c
index 4eeca782b888..0a5ab62c9c59 100644
--- a/mm/page_table_check.c
+++ b/mm/page_table_check.c
@@ -150,18 +150,29 @@ void __page_table_check_pte_clear(struct mm_struct *mm, pte_t pte)
if (&init_mm == mm)
return;

- if (pte_user_accessible_page(pte)) {
+ if (pte_user_accessible_page(pte) && !pte_special(pte)) {
page_table_check_clear(pte_pfn(pte), PAGE_SIZE >> PAGE_SHIFT);
}
}
EXPORT_SYMBOL(__page_table_check_pte_clear);

+static inline bool page_table_check_huge_zero_pmd(pmd_t pmd)
+{
+ unsigned long pfn = pmd_pfn(pmd);
+
+ if (!pfn_valid(pfn))
+ return false;
+
+ return is_huge_zero_folio(page_folio(pfn_to_page(pfn)));
+}
+
void __page_table_check_pmd_clear(struct mm_struct *mm, pmd_t pmd)
{
if (&init_mm == mm)
return;

- if (pmd_user_accessible_page(pmd)) {
+ if (pmd_user_accessible_page(pmd) &&
+ !page_table_check_huge_zero_pmd(pmd)) {
page_table_check_clear(pmd_pfn(pmd), PMD_SIZE >> PAGE_SHIFT);
}
}
@@ -205,7 +216,7 @@ void __page_table_check_ptes_set(struct mm_struct *mm, pte_t *ptep, pte_t pte,

for (i = 0; i < nr; i++)
__page_table_check_pte_clear(mm, ptep_get(ptep + i));
- if (pte_user_accessible_page(pte))
+ if (pte_user_accessible_page(pte) && !pte_special(pte))
page_table_check_set(pte_pfn(pte), nr, pte_write(pte));
}
EXPORT_SYMBOL(__page_table_check_ptes_set);
@@ -231,7 +242,8 @@ void __page_table_check_pmds_set(struct mm_struct *mm, pmd_t *pmdp, pmd_t pmd,

for (i = 0; i < nr; i++)
__page_table_check_pmd_clear(mm, *(pmdp + i));
- if (pmd_user_accessible_page(pmd))
+ if (pmd_user_accessible_page(pmd) &&
+ !page_table_check_huge_zero_pmd(pmd))
page_table_check_set(pmd_pfn(pmd), stride * nr, pmd_write(pmd));
}
EXPORT_SYMBOL(__page_table_check_pmds_set);
diff --git a/mm/page_vma_mapped.c b/mm/page_vma_mapped.c
index c498a91b6706..2fdd31a5a48f 100644
--- a/mm/page_vma_mapped.c
+++ b/mm/page_vma_mapped.c
@@ -246,7 +246,7 @@ bool page_vma_mapped_walk(struct page_vma_mapped_walk *pvmw)
*/
pmde = pmdp_get_lockless(pvmw->pmd);

- if (pmd_trans_huge(pmde) || is_pmd_migration_entry(pmde)) {
+ if (pmd_trans_huge(pmde) || pmd_is_migration_entry(pmde)) {
pvmw->ptl = pmd_lock(mm, pvmw->pmd);
pmde = *pvmw->pmd;
if (!pmd_present(pmde)) {
diff --git a/mm/pagewalk.c b/mm/pagewalk.c
index fdce9ad67aad..ca6c51598aed 100644
--- a/mm/pagewalk.c
+++ b/mm/pagewalk.c
@@ -991,7 +991,7 @@ struct folio *folio_walk_start(struct folio_walk *fw,
goto found;
}
} else if ((flags & FW_MIGRATION) &&
- is_pmd_migration_entry(pmd)) {
+ pmd_is_migration_entry(pmd)) {
swp_entry_t entry = pmd_to_swp_entry(pmd);

page = pfn_swap_entry_to_page(entry);
diff --git a/mm/pgtable-generic.c b/mm/pgtable-generic.c
index 8c22be79b734..b7f347ed786e 100644
--- a/mm/pgtable-generic.c
+++ b/mm/pgtable-generic.c
@@ -291,7 +291,7 @@ pte_t *___pte_offset_map(pmd_t *pmd, unsigned long addr, pmd_t *pmdvalp)

if (pmdvalp)
*pmdvalp = pmdval;
- if (unlikely(pmd_none(pmdval) || is_pmd_migration_entry(pmdval)))
+ if (unlikely(pmd_none(pmdval) || pmd_is_migration_entry(pmdval)))
goto nomap;
if (unlikely(pmd_trans_huge(pmdval)))
goto nomap;
diff --git a/net/ceph/cls_lock_client.c b/net/ceph/cls_lock_client.c
index 66136a4c1ce7..a9655678be6f 100644
--- a/net/ceph/cls_lock_client.c
+++ b/net/ceph/cls_lock_client.c
@@ -259,7 +259,8 @@ static int decode_locker(void **p, void *end, struct ceph_locker *locker)
if (ret)
return ret;

- ceph_decode_copy(p, &locker->id.name, sizeof(locker->id.name));
+ ceph_decode_copy_safe(p, end, &locker->id.name,
+ sizeof(locker->id.name), bad);
s = ceph_extract_encoded_string(p, end, NULL, GFP_NOIO);
if (IS_ERR(s))
return PTR_ERR(s);
@@ -270,19 +271,23 @@ static int decode_locker(void **p, void *end, struct ceph_locker *locker)
if (ret)
return ret;

- *p += sizeof(struct ceph_timespec); /* skip expiration */
+ /* skip expiration */
+ ceph_decode_skip_n(p, end, sizeof(struct ceph_timespec), bad);

ret = ceph_decode_entity_addr(p, end, &locker->info.addr);
if (ret)
return ret;

- len = ceph_decode_32(p);
- *p += len; /* skip description */
+ /* skip description */
+ ceph_decode_skip_string(p, end, bad);

dout("%s %s%llu cookie %s addr %s\n", __func__,
ENTITY_NAME(locker->id.name), locker->id.cookie,
ceph_pr_addr(&locker->info.addr));
return 0;
+
+bad:
+ return -EINVAL;
}

static int decode_lockers(void **p, void *end, u8 *type, char **tag,
@@ -299,7 +304,7 @@ static int decode_lockers(void **p, void *end, u8 *type, char **tag,
if (ret)
return ret;

- *num_lockers = ceph_decode_32(p);
+ ceph_decode_32_safe(p, end, *num_lockers, err_inval);
*lockers = kcalloc(*num_lockers, sizeof(**lockers), GFP_NOIO);
if (!*lockers)
return -ENOMEM;
@@ -310,7 +315,8 @@ static int decode_lockers(void **p, void *end, u8 *type, char **tag,
goto err_free_lockers;
}

- *type = ceph_decode_8(p);
+ ret = -EINVAL;
+ ceph_decode_8_safe(p, end, *type, err_free_lockers);
s = ceph_extract_encoded_string(p, end, NULL, GFP_NOIO);
if (IS_ERR(s)) {
ret = PTR_ERR(s);
@@ -320,6 +326,9 @@ static int decode_lockers(void **p, void *end, u8 *type, char **tag,
*tag = s;
return 0;

+err_inval:
+ return -EINVAL;
+
err_free_lockers:
ceph_free_lockers(*lockers, *num_lockers);
return ret;
diff --git a/net/ceph/decode.c b/net/ceph/decode.c
index bc109a1a4616..2f21af38cd9a 100644
--- a/net/ceph/decode.c
+++ b/net/ceph/decode.c
@@ -87,8 +87,9 @@ ceph_decode_entity_addr(void **p, void *end, struct ceph_entity_addr *addr)
EXPORT_SYMBOL(ceph_decode_entity_addr);

/*
- * Return addr of desired type (MSGR2 or LEGACY) or error.
- * Make sure there is only one match.
+ * Return addr of desired type (MSGR2 or LEGACY) or error. In case of
+ * multiple matches, use the first one for compatibility with userspace
+ * messenger.
*
* Assume encoding with MSG_ADDR2.
*/
@@ -121,14 +122,13 @@ int ceph_decode_entity_addrvec(void **p, void *end, bool msgr2,

dout("%s i %d addr %s\n", __func__, i, ceph_pr_addr(&tmp_addr));
if (tmp_addr.type == my_type) {
- if (found) {
- pr_err("another match of type %d in addrvec\n",
- le32_to_cpu(my_type));
- return -EINVAL;
+ if (!found) {
+ memcpy(addr, &tmp_addr, sizeof(*addr));
+ found = true;
+ } else {
+ dout("%s skipping extra match of type %d in addrvec\n",
+ __func__, le32_to_cpu(my_type));
}
-
- memcpy(addr, &tmp_addr, sizeof(*addr));
- found = true;
}
}

diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c
index 30d75970be44..ff06ba2965cf 100644
--- a/net/ceph/osdmap.c
+++ b/net/ceph/osdmap.c
@@ -1440,7 +1440,7 @@ static struct ceph_pg_mapping *__decode_pg_temp(void **p, void *end,
ceph_decode_32_safe(p, end, len, e_inval);
if (len == 0 && incremental)
return NULL; /* new_pg_temp: [] to remove */
- if (len > (SIZE_MAX - sizeof(*pg)) / sizeof(u32))
+ if (len > CEPH_PG_MAX_SIZE)
return ERR_PTR(-EINVAL);

ceph_decode_need(p, end, len * sizeof(u32), e_inval);
@@ -1621,7 +1621,7 @@ static struct ceph_pg_mapping *__decode_pg_upmap_items(void **p, void *end,
u32 len, i;

ceph_decode_32_safe(p, end, len, e_inval);
- if (len > (SIZE_MAX - sizeof(*pg)) / (2 * sizeof(u32)))
+ if (len > CEPH_PG_MAX_SIZE)
return ERR_PTR(-EINVAL);

ceph_decode_need(p, end, 2 * len * sizeof(u32), e_inval);
@@ -2811,9 +2811,10 @@ static void get_temp_osds(struct ceph_osdmap *osdmap,
}
}

- /* primary_temp? */
+ /* primary_temp? (shouldn't ever be a nonexistent or down OSD) */
pg = lookup_pg_mapping(&osdmap->primary_temp, pgid);
- if (pg)
+ if (pg && !WARN_ON_ONCE(ceph_osd_is_down(osdmap,
+ pg->primary_temp.osd)))
temp->primary = pg->primary_temp.osd;
}

diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index c1769031a9e9..05521a3509a9 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1006,9 +1006,9 @@ static void tcp_event_data_recv(struct sock *sk, struct sk_buff *skb)
/* The fastest case is the first. */
icsk->icsk_ack.ato = (icsk->icsk_ack.ato >> 1) + TCP_ATO_MIN / 2;
} else if (m < icsk->icsk_ack.ato) {
- icsk->icsk_ack.ato = (icsk->icsk_ack.ato >> 1) + m;
- if (icsk->icsk_ack.ato > icsk->icsk_rto)
- icsk->icsk_ack.ato = icsk->icsk_rto;
+ icsk->icsk_ack.ato = min3((icsk->icsk_ack.ato >> 1) + (u32)m,
+ icsk->icsk_rto,
+ (u32)TCP_DELACK_MAX);
} else if (m > icsk->icsk_rto) {
/* Too long gap. Apparently sender failed to
* restart window, so that we send ACKs quickly.
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index 1e6d7d90371a..9ebce13fa8ad 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -333,7 +333,9 @@ void tcp_delack_timer_handler(struct sock *sk)
if (inet_csk_ack_scheduled(sk)) {
if (!inet_csk_in_pingpong_mode(sk)) {
/* Delayed ACK missed: inflate ATO. */
- icsk->icsk_ack.ato = min_t(u32, icsk->icsk_ack.ato << 1, icsk->icsk_rto);
+ icsk->icsk_ack.ato = min3((u32)icsk->icsk_ack.ato << 1,
+ icsk->icsk_rto,
+ (u32)TCP_DELACK_MAX);
} else {
/* Delayed ACK missed: leave pingpong mode and
* deflate ATO.
diff --git a/net/mptcp/fastopen.c b/net/mptcp/fastopen.c
index 082c46c0f50e..f717750906ff 100644
--- a/net/mptcp/fastopen.c
+++ b/net/mptcp/fastopen.c
@@ -24,12 +24,13 @@ void mptcp_fastopen_subflow_synack_set_params(struct mptcp_subflow_context *subf
sk = subflow->conn;
tp = tcp_sk(ssk);

- subflow->is_mptfo = 1;
-
+ /* A valid TFO cookie does not guarantee SYN data. */
skb = skb_peek(&ssk->sk_receive_queue);
- if (WARN_ON_ONCE(!skb))
+ if (!skb)
return;

+ subflow->is_mptfo = 1;
+
/* dequeue the skb from sk receive queue */
__skb_unlink(skb, &ssk->sk_receive_queue);
skb_ext_reset(skb);
diff --git a/net/mptcp/options.c b/net/mptcp/options.c
index cbece69dc5f0..14a6d7265530 100644
--- a/net/mptcp/options.c
+++ b/net/mptcp/options.c
@@ -50,6 +50,14 @@ static void mptcp_parse_option(const struct sk_buff *skb,
}
}

+ /* Only the MPC + ACK can be used with a RM_ADDR */
+ if (subopt == OPTION_MPTCP_MPC_ACK) {
+ if ((mp_opt->suboptions & ~OPTION_MPTCP_RM_ADDR) != 0)
+ break;
+ } else if (mp_opt->suboptions != 0) {
+ break;
+ }
+
/* Cfr RFC 8684 Section 3.3.0:
* If a checksum is present but its use had
* not been negotiated in the MP_CAPABLE handshake, the receiver MUST
@@ -122,6 +130,11 @@ static void mptcp_parse_option(const struct sk_buff *skb,
break;

case MPTCPOPT_MP_JOIN:
+ /* Can be used with a restricted number of other options */
+ if ((mp_opt->suboptions & ~(OPTION_MPTCP_RM_ADDR |
+ OPTION_MPTCP_PRIO)) != 0)
+ break;
+
if (opsize == TCPOLEN_MPTCP_MPJ_SYN) {
mp_opt->suboptions |= OPTION_MPTCP_MPJ_SYN;
mp_opt->backup = *ptr++ & MPTCPOPT_BACKUP;
@@ -153,6 +166,14 @@ static void mptcp_parse_option(const struct sk_buff *skb,
break;

case MPTCPOPT_DSS:
+ /* Can be used with a restricted number of other options */
+ if ((mp_opt->suboptions & ~(OPTION_MPTCP_ADD_ADDR |
+ OPTION_MPTCP_RM_ADDR |
+ OPTION_MPTCP_PRIO |
+ OPTION_MPTCP_FASTCLOSE |
+ OPTION_MPTCP_FAIL)) != 0)
+ break;
+
pr_debug("DSS\n");
ptr++;

@@ -188,8 +209,14 @@ static void mptcp_parse_option(const struct sk_buff *skb,
* RFC 8684 Section 3.3.0 checks later in subflow_data_ready
*/
if (opsize != expected_opsize &&
- opsize != expected_opsize + TCPOLEN_MPTCP_DSS_CHECKSUM)
+ opsize != expected_opsize + TCPOLEN_MPTCP_DSS_CHECKSUM) {
+ mp_opt->dsn64 = 0;
+ mp_opt->use_map = 0;
+ mp_opt->ack64 = 0;
+ mp_opt->use_ack = 0;
+ mp_opt->data_fin = 0;
break;
+ }

mp_opt->suboptions |= OPTION_MPTCP_DSS;
if (mp_opt->use_ack) {
@@ -234,6 +261,12 @@ static void mptcp_parse_option(const struct sk_buff *skb,
break;

case MPTCPOPT_ADD_ADDR:
+ /* Can be used with a restricted number of other options */
+ if ((mp_opt->suboptions & ~(OPTIONS_MPTCP_DSS |
+ OPTION_MPTCP_RM_ADDR |
+ OPTION_MPTCP_PRIO)) != 0)
+ break;
+
mp_opt->echo = (*ptr++) & MPTCP_ADDR_ECHO;
if (!mp_opt->echo) {
if (opsize == TCPOLEN_MPTCP_ADD_ADDR ||
@@ -293,6 +326,14 @@ static void mptcp_parse_option(const struct sk_buff *skb,
break;

case MPTCPOPT_RM_ADDR:
+ /* Can be used with a restricted number of other options */
+ if ((mp_opt->suboptions & ~(OPTION_MPTCP_MPC_ACK |
+ OPTIONS_MPTCP_MPJ |
+ OPTIONS_MPTCP_DSS |
+ OPTION_MPTCP_ADD_ADDR |
+ OPTION_MPTCP_PRIO)) != 0)
+ break;
+
if (opsize < TCPOLEN_MPTCP_RM_ADDR_BASE + 1 ||
opsize > TCPOLEN_MPTCP_RM_ADDR_BASE + MPTCP_RM_IDS_MAX)
break;
@@ -307,6 +348,13 @@ static void mptcp_parse_option(const struct sk_buff *skb,
break;

case MPTCPOPT_MP_PRIO:
+ /* Can be used with a restricted number of other options */
+ if ((mp_opt->suboptions & ~(OPTIONS_MPTCP_MPJ |
+ OPTIONS_MPTCP_DSS |
+ OPTION_MPTCP_ADD_ADDR |
+ OPTION_MPTCP_RM_ADDR)) != 0)
+ break;
+
if (opsize != TCPOLEN_MPTCP_PRIO)
break;

@@ -316,6 +364,11 @@ static void mptcp_parse_option(const struct sk_buff *skb,
break;

case MPTCPOPT_MP_FASTCLOSE:
+ /* Can be used with a restricted number of other options */
+ if ((mp_opt->suboptions & ~(OPTIONS_MPTCP_DSS |
+ OPTION_MPTCP_RST)) != 0)
+ break;
+
if (opsize != TCPOLEN_MPTCP_FASTCLOSE)
break;

@@ -327,6 +380,11 @@ static void mptcp_parse_option(const struct sk_buff *skb,
break;

case MPTCPOPT_RST:
+ /* Can be used with a restricted number of other options */
+ if ((mp_opt->suboptions & ~(OPTION_MPTCP_FAIL |
+ OPTION_MPTCP_FASTCLOSE)) != 0)
+ break;
+
if (opsize != TCPOLEN_MPTCP_RST)
break;

@@ -342,6 +400,11 @@ static void mptcp_parse_option(const struct sk_buff *skb,
break;

case MPTCPOPT_MP_FAIL:
+ /* Can be used with a restricted number of other options */
+ if ((mp_opt->suboptions & ~(OPTIONS_MPTCP_DSS |
+ OPTION_MPTCP_RST)) != 0)
+ break;
+
if (opsize != TCPOLEN_MPTCP_FAIL)
break;

@@ -1416,7 +1479,7 @@ void mptcp_write_options(struct tcphdr *th, __be32 *ptr, struct tcp_sock *tp,
* RM | C | C | C | P |------|------|------|------|
* PRIO | X | C | C | C | C |------|------|------|
* FAIL | X | X | C | X | X | X |------|------|
- * FC | X | X | X | X | X | X | X |------|
+ * FC | X | X | P | X | X | X | X |------|
* RST | X | X | X | X | X | X | O | O |
* ------|------|------|------|------|------|------|------|------|
*
diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c
index 72a8f6a0d058..4f2c173d9d75 100644
--- a/net/mptcp/pm.c
+++ b/net/mptcp/pm.c
@@ -345,6 +345,7 @@ static void mptcp_pm_add_timer(struct timer_list *timer)
struct mptcp_sock *msk = entry->sock;
struct sock *sk = (struct sock *)msk;
unsigned int timeout = 0;
+ bool retransmit;

pr_debug("msk=%p\n", msk);

@@ -377,14 +378,15 @@ static void mptcp_pm_add_timer(struct timer_list *timer)
entry->retrans_times++;
}

- if (entry->retrans_times < ADD_ADDR_RETRANS_MAX)
+ retransmit = entry->retrans_times < ADD_ADDR_RETRANS_MAX;
+ if (retransmit)
timeout <<= entry->retrans_times;
else
timeout = 0;

spin_unlock_bh(&msk->pm.lock);

- if (entry->retrans_times == ADD_ADDR_RETRANS_MAX)
+ if (!retransmit)
mptcp_pm_subflow_established(msk);

out:
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index 9e381408d58a..1bf9b1dfc431 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -147,6 +147,12 @@ struct sock *__mptcp_nmpc_sk(struct mptcp_sock *msk)

static void mptcp_drop(struct sock *sk, struct sk_buff *skb)
{
+ /* The skb forward memory was already transferred to sk by
+ * mptcp_borrow_fwdmem(), even before setting the destructor.
+ */
+ if (!skb->destructor)
+ sk_mem_reclaim(sk);
+
sk_drops_skbadd(sk, skb);
__kfree_skb(skb);
}
diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
index 3b8edd9b658b..a03c8b04ee9b 100644
--- a/net/mptcp/protocol.h
+++ b/net/mptcp/protocol.h
@@ -37,6 +37,7 @@
OPTION_MPTCP_MPC_ACK)
#define OPTIONS_MPTCP_MPJ (OPTION_MPTCP_MPJ_SYN | OPTION_MPTCP_MPJ_SYNACK | \
OPTION_MPTCP_MPJ_ACK)
+#define OPTIONS_MPTCP_DSS (OPTION_MPTCP_DSS | OPTION_MPTCP_CSUMREQD)

/* MPTCP option subtypes */
#define MPTCPOPT_MP_CAPABLE 0
diff --git a/net/netfilter/ipset/ip_set_bitmap_gen.h b/net/netfilter/ipset/ip_set_bitmap_gen.h
index d99e2e2e5855..ca1119f651ef 100644
--- a/net/netfilter/ipset/ip_set_bitmap_gen.h
+++ b/net/netfilter/ipset/ip_set_bitmap_gen.h
@@ -77,7 +77,7 @@ mtype_flush(struct ip_set *set)
mtype_ext_cleanup(set);
bitmap_zero(map->members, map->elements);
set->elements = 0;
- atomic64_set(&set->ext_size, 0);
+ DEBUG_NET_WARN_ON_ONCE(atomic64_read(&set->ext_size) > 0);
}

/* Calculate the actual memory size of the set data */
diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c
index 29bf5ee74fe3..e7c85b0af729 100644
--- a/net/netfilter/ipset/ip_set_core.c
+++ b/net/netfilter/ipset/ip_set_core.c
@@ -679,11 +679,18 @@ __ip_set_get(struct ip_set *set)
}

static void
-__ip_set_put(struct ip_set *set)
+__ip_set_put_locked(struct ip_set *set)
{
- write_lock_bh(&ip_set_ref_lock);
+ lockdep_assert_held(&ip_set_ref_lock);
BUG_ON(set->ref == 0);
set->ref--;
+}
+
+static void
+__ip_set_put(struct ip_set *set)
+{
+ write_lock_bh(&ip_set_ref_lock);
+ __ip_set_put_locked(set);
write_unlock_bh(&ip_set_ref_lock);
}

@@ -854,11 +861,11 @@ __ip_set_put_byindex(struct ip_set_net *inst, ip_set_id_t index)
{
struct ip_set *set;

- rcu_read_lock();
- set = rcu_dereference(inst->ip_set_list)[index];
+ write_lock_bh(&ip_set_ref_lock);
+ set = ip_set(inst, index);
if (set)
- __ip_set_put(set);
- rcu_read_unlock();
+ __ip_set_put_locked(set);
+ write_unlock_bh(&ip_set_ref_lock);
}

void
diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c
index 7bb807b3c628..2f11814bd512 100644
--- a/net/netfilter/ipset/ip_set_list_set.c
+++ b/net/netfilter/ipset/ip_set_list_set.c
@@ -301,9 +301,12 @@ list_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext,
e->set = set;
INIT_LIST_HEAD(&e->list);
list_set_init_extensions(set, ext, e);
- if (n)
+ if (n) {
list_set_replace(set, e, n);
- else if (next)
+ return 0;
+ }
+
+ if (next)
list_add_tail_rcu(&e->list, &next->list);
else if (prev)
list_add_rcu(&e->list, &prev->list);
@@ -420,8 +423,7 @@ list_set_flush(struct ip_set *set)

list_for_each_entry_safe(e, n, &map->members, list)
list_set_del(set, e);
- set->elements = 0;
- atomic64_set(&set->ext_size, 0);
+ DEBUG_NET_WARN_ON_ONCE(set->elements > 0);
}

static void
diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c
index e42fed876596..7da11628073b 100644
--- a/net/netfilter/ipvs/ip_vs_conn.c
+++ b/net/netfilter/ipvs/ip_vs_conn.c
@@ -759,7 +759,7 @@ int ip_vs_check_template(struct ip_vs_conn *ct, struct ip_vs_dest *cdest)
* Checking the dest server status.
*/
if ((dest == NULL) ||
- !(dest->flags & IP_VS_DEST_F_AVAILABLE) ||
+ !(dest->cflags & IP_VS_DEST_CF_AVAILABLE) ||
expire_quiescent_template(ipvs, dest) ||
(cdest && (dest != cdest))) {
IP_VS_DBG_BUF(9, "check_template: dest not available for "
@@ -1408,7 +1408,7 @@ void ip_vs_expire_nodest_conn_flush(struct netns_ipvs *ipvs)
continue;

dest = cp->dest;
- if (!dest || (dest->flags & IP_VS_DEST_F_AVAILABLE))
+ if (!dest || (dest->cflags & IP_VS_DEST_CF_AVAILABLE))
continue;

if (atomic_read(&cp->n_control))
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index d121ea3d16bc..1f62ca2f7330 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -124,7 +124,7 @@ ip_vs_in_stats(struct ip_vs_conn *cp, struct sk_buff *skb)
struct ip_vs_dest *dest = cp->dest;
struct netns_ipvs *ipvs = cp->ipvs;

- if (dest && (dest->flags & IP_VS_DEST_F_AVAILABLE)) {
+ if (dest && (dest->cflags & IP_VS_DEST_CF_AVAILABLE)) {
struct ip_vs_cpu_stats *s;
struct ip_vs_service *svc;

@@ -160,7 +160,7 @@ ip_vs_out_stats(struct ip_vs_conn *cp, struct sk_buff *skb)
struct ip_vs_dest *dest = cp->dest;
struct netns_ipvs *ipvs = cp->ipvs;

- if (dest && (dest->flags & IP_VS_DEST_F_AVAILABLE)) {
+ if (dest && (dest->cflags & IP_VS_DEST_CF_AVAILABLE)) {
struct ip_vs_cpu_stats *s;
struct ip_vs_service *svc;

@@ -2030,7 +2030,7 @@ ip_vs_in_hook(void *priv, struct sk_buff *skb, const struct nf_hook_state *state
}

/* Check the server status */
- if (cp && cp->dest && !(cp->dest->flags & IP_VS_DEST_F_AVAILABLE)) {
+ if (cp && cp->dest && !(cp->dest->cflags & IP_VS_DEST_CF_AVAILABLE)) {
/* the destination server is not available */
if (sysctl_expire_nodest_conn(ipvs)) {
bool old_ct = ip_vs_conn_uses_old_conntrack(cp, skb);
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
index 5dea5a14e85f..c0257ef4d8b0 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -1058,7 +1058,7 @@ __ip_vs_update_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest,
}

/* set the dest status flags */
- dest->flags |= IP_VS_DEST_F_AVAILABLE;
+ dest->cflags |= IP_VS_DEST_CF_AVAILABLE;

if (READ_ONCE(dest->u_threshold) != udest->u_threshold ||
READ_ONCE(dest->l_threshold) != udest->l_threshold) {
@@ -1325,7 +1325,7 @@ static void __ip_vs_unlink_dest(struct ip_vs_service *svc,
struct ip_vs_dest *dest,
int svcupd)
{
- dest->flags &= ~IP_VS_DEST_F_AVAILABLE;
+ dest->cflags &= ~IP_VS_DEST_CF_AVAILABLE;

/*
* Remove it from the d-linked destination list.
diff --git a/net/netfilter/ipvs/ip_vs_dh.c b/net/netfilter/ipvs/ip_vs_dh.c
index 75f4c231f4a0..f04d2530a093 100644
--- a/net/netfilter/ipvs/ip_vs_dh.c
+++ b/net/netfilter/ipvs/ip_vs_dh.c
@@ -220,8 +220,8 @@ ip_vs_dh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,

s = (struct ip_vs_dh_state *) svc->sched_data;
dest = ip_vs_dh_get(svc->af, s, &iph->daddr);
- if (!dest
- || !(dest->flags & IP_VS_DEST_F_AVAILABLE)
+ if (!dest ||
+ !(dest->cflags & IP_VS_DEST_CF_AVAILABLE)
|| atomic_read(&dest->weight) <= 0
|| is_overloaded(dest)) {
ip_vs_scheduler_err(svc, "no destination available");
diff --git a/net/netfilter/ipvs/ip_vs_lblc.c b/net/netfilter/ipvs/ip_vs_lblc.c
index 156181a3bacd..9bb1e05063dc 100644
--- a/net/netfilter/ipvs/ip_vs_lblc.c
+++ b/net/netfilter/ipvs/ip_vs_lblc.c
@@ -503,7 +503,7 @@ ip_vs_lblc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
*/

dest = en->dest;
- if ((dest->flags & IP_VS_DEST_F_AVAILABLE) &&
+ if ((dest->cflags & IP_VS_DEST_CF_AVAILABLE) &&
atomic_read(&dest->weight) > 0 && !is_overloaded(dest, svc))
goto out;
}
diff --git a/net/netfilter/ipvs/ip_vs_lblcr.c b/net/netfilter/ipvs/ip_vs_lblcr.c
index a021e6aba3d7..1a53c1254fe5 100644
--- a/net/netfilter/ipvs/ip_vs_lblcr.c
+++ b/net/netfilter/ipvs/ip_vs_lblcr.c
@@ -170,8 +170,8 @@ static inline struct ip_vs_dest *ip_vs_dest_set_min(struct ip_vs_dest_set *set)
if (least->flags & IP_VS_DEST_F_OVERLOAD)
continue;

- if ((atomic_read(&least->weight) > 0)
- && (least->flags & IP_VS_DEST_F_AVAILABLE)) {
+ if ((atomic_read(&least->weight) > 0) &&
+ (least->cflags & IP_VS_DEST_CF_AVAILABLE)) {
loh = ip_vs_dest_conn_overhead(least);
goto nextstage;
}
@@ -187,8 +187,8 @@ static inline struct ip_vs_dest *ip_vs_dest_set_min(struct ip_vs_dest_set *set)

doh = ip_vs_dest_conn_overhead(dest);
if (((__s64)loh * atomic_read(&dest->weight) >
- (__s64)doh * atomic_read(&least->weight))
- && (dest->flags & IP_VS_DEST_F_AVAILABLE)) {
+ (__s64)doh * atomic_read(&least->weight)) &&
+ (dest->cflags & IP_VS_DEST_CF_AVAILABLE)) {
least = dest;
loh = doh;
}
diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c
index 595a0f19d15e..7a93e22d049d 100644
--- a/net/netfilter/nf_flow_table_core.c
+++ b/net/netfilter/nf_flow_table_core.c
@@ -324,17 +324,18 @@ int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow)
flow->timeout = nf_flowtable_time_stamp + flow_offload_get_timeout(flow);

err = rhashtable_insert_fast(&flow_table->rhashtable,
- &flow->tuplehash[0].node,
+ &flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].node,
nf_flow_offload_rhash_params);
if (err < 0)
return err;

+ /* GC only iterates original-direction entries; publish original last. */
err = rhashtable_insert_fast(&flow_table->rhashtable,
- &flow->tuplehash[1].node,
+ &flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].node,
nf_flow_offload_rhash_params);
if (err < 0) {
rhashtable_remove_fast(&flow_table->rhashtable,
- &flow->tuplehash[0].node,
+ &flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].node,
nf_flow_offload_rhash_params);
return err;
}
diff --git a/net/netfilter/nf_tables_offload.c b/net/netfilter/nf_tables_offload.c
index fd30e205de84..933a17d0f251 100644
--- a/net/netfilter/nf_tables_offload.c
+++ b/net/netfilter/nf_tables_offload.c
@@ -558,7 +558,7 @@ static void nft_flow_rule_offload_abort(struct net *net,
break;
}

- if (WARN_ON_ONCE(err))
+ if (WARN_ON_ONCE(err && err != -ENOMEM))
break;
}
}
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index a557f4dd2ebb..99212023b119 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1942,13 +1942,13 @@ static void packet_parse_headers(struct sk_buff *skb, struct socket *sock)
sock->type == SOCK_RAW)
skb->protocol = dev_parse_header_protocol(skb);

+ skb_probe_transport_header(skb);
+
/* Move network header to the right position for VLAN tagged packets */
if (likely(skb->dev->type == ARPHRD_ETHER) &&
eth_type_vlan(skb->protocol) &&
vlan_get_protocol_and_depth(skb, skb->protocol, &depth) != 0)
skb_set_network_header(skb, depth);
-
- skb_probe_transport_header(skb);
}

/*
@@ -2659,6 +2659,9 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
len = ((to_write > len_max) ? len_max : to_write);
}

+ if (unlikely(!skb->len))
+ return -EINVAL;
+
packet_parse_headers(skb, sock);

return tp_len;
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index f948646985dd..3578fd5ac4fb 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -41,11 +41,9 @@ int tcf_dev_queue_xmit(struct sk_buff *skb, int (*xmit)(struct sk_buff *skb))
}
EXPORT_SYMBOL_GPL(tcf_dev_queue_xmit);

-static void tcf_action_goto_chain_exec(const struct tc_action *a,
+static void tcf_action_goto_chain_exec(const struct tcf_chain *chain,
struct tcf_result *res)
{
- const struct tcf_chain *chain = rcu_dereference_bh(a->goto_chain);
-
res->goto_tp = rcu_dereference_bh(chain->filter_chain);
}

@@ -1170,12 +1168,14 @@ int tcf_action_exec(struct sk_buff *skb, struct tc_action **actions,
return TC_ACT_OK;
}
} else if (TC_ACT_EXT_CMP(ret, TC_ACT_GOTO_CHAIN)) {
- if (unlikely(!rcu_access_pointer(a->goto_chain))) {
+ struct tcf_chain *chain = rcu_dereference_bh(a->goto_chain);
+
+ if (unlikely(!chain)) {
tcf_set_drop_reason(skb,
SKB_DROP_REASON_TC_CHAIN_NOTFOUND);
return TC_ACT_SHOT;
}
- tcf_action_goto_chain_exec(a, res);
+ tcf_action_goto_chain_exec(chain, res);
}

if (ret != TC_ACT_PIPE)
diff --git a/net/sched/cls_bpf.c b/net/sched/cls_bpf.c
index e888d0aa9f21..a6003fa35c7c 100644
--- a/net/sched/cls_bpf.c
+++ b/net/sched/cls_bpf.c
@@ -374,7 +374,8 @@ static int cls_bpf_prog_from_ops(struct nlattr **tb, struct cls_bpf_prog *prog)
}

static int cls_bpf_prog_from_efd(struct nlattr **tb, struct cls_bpf_prog *prog,
- u32 gen_flags, const struct tcf_proto *tp)
+ u32 gen_flags, const struct tcf_proto *tp,
+ struct netlink_ext_ack *extack)
{
struct bpf_prog *fp;
char *name = NULL;
@@ -388,6 +389,19 @@ static int cls_bpf_prog_from_efd(struct nlattr **tb, struct cls_bpf_prog *prog,
if (IS_ERR(fp))
return PTR_ERR(fp);

+ if (bpf_prog_is_dev_bound(fp->aux)) {
+ struct tcf_block *block = tp->chain->block;
+ struct net_device *dev;
+
+ dev = block->q ? qdisc_dev(block->q) : NULL;
+ if (!dev || !bpf_offload_dev_match(fp, dev)) {
+ NL_SET_ERR_MSG(extack,
+ "Program is bound to a different device");
+ bpf_prog_put(fp);
+ return -EINVAL;
+ }
+ }
+
if (tb[TCA_BPF_NAME]) {
name = nla_memdup(tb[TCA_BPF_NAME], GFP_KERNEL);
if (!name) {
@@ -492,7 +506,7 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
prog->gen_flags = gen_flags;

ret = is_bpf ? cls_bpf_prog_from_ops(tb, prog) :
- cls_bpf_prog_from_efd(tb, prog, gen_flags, tp);
+ cls_bpf_prog_from_efd(tb, prog, gen_flags, tp, extack);
if (ret < 0)
goto errout_idr;

diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
index 58e849c0acf4..a90de52e1ac8 100644
--- a/net/sched/cls_u32.c
+++ b/net/sched/cls_u32.c
@@ -1336,6 +1336,9 @@ static void u32_bind_class(void *fh, u32 classid, unsigned long cl, void *q,
{
struct tc_u_knode *n = fh;

+ if (TC_U32_KEY(n->handle) == 0)
+ return;
+
tc_cls_bind_class(classid, cl, q, &n->res, base);
}

diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index 2d54f7200cd0..08decb95648c 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -415,12 +415,13 @@ static __u8 __detect_linklayer(struct tc_ratespec *r, __u32 *rtab)
}

static struct qdisc_rate_table *qdisc_rtab_list;
+static DEFINE_SPINLOCK(qdisc_rtab_lock);

struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r,
struct nlattr *tab,
struct netlink_ext_ack *extack)
{
- struct qdisc_rate_table *rtab;
+ struct qdisc_rate_table *rtab, *new_rtab;

if (tab == NULL || r->rate == 0 ||
r->cell_log == 0 || r->cell_log >= 32 ||
@@ -429,15 +430,20 @@ struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r,
return NULL;
}

+ new_rtab = kmalloc_obj(*new_rtab);
+
+ spin_lock(&qdisc_rtab_lock);
for (rtab = qdisc_rtab_list; rtab; rtab = rtab->next) {
if (!memcmp(&rtab->rate, r, sizeof(struct tc_ratespec)) &&
!memcmp(&rtab->data, nla_data(tab), TC_RTAB_SIZE)) {
rtab->refcnt++;
+ spin_unlock(&qdisc_rtab_lock);
+ kfree(new_rtab);
return rtab;
}
}

- rtab = kmalloc(sizeof(*rtab), GFP_KERNEL);
+ rtab = new_rtab;
if (rtab) {
rtab->rate = *r;
rtab->refcnt = 1;
@@ -449,6 +455,7 @@ struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r,
} else {
NL_SET_ERR_MSG(extack, "Failed to allocate new qdisc rate table");
}
+ spin_unlock(&qdisc_rtab_lock);
return rtab;
}
EXPORT_SYMBOL(qdisc_get_rtab);
@@ -457,18 +464,25 @@ void qdisc_put_rtab(struct qdisc_rate_table *tab)
{
struct qdisc_rate_table *rtab, **rtabp;

- if (!tab || --tab->refcnt)
+ if (!tab)
return;

+ spin_lock(&qdisc_rtab_lock);
+ if (--tab->refcnt) {
+ spin_unlock(&qdisc_rtab_lock);
+ return;
+ }
+
for (rtabp = &qdisc_rtab_list;
(rtab = *rtabp) != NULL;
rtabp = &rtab->next) {
if (rtab == tab) {
*rtabp = rtab->next;
- kfree(rtab);
- return;
+ break;
}
}
+ spin_unlock(&qdisc_rtab_lock);
+ kfree(tab);
}
EXPORT_SYMBOL(qdisc_put_rtab);

diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
index 7c3582b3eea9..4c77036da071 100644
--- a/net/tls/tls_sw.c
+++ b/net/tls/tls_sw.c
@@ -2319,6 +2319,11 @@ ssize_t tls_sw_splice_read(struct socket *sock, loff_t *ppos,
if (err < 0)
return err;

+ /* If crypto failed the connection is broken */
+ err = ctx->async_wait.err;
+ if (err)
+ goto splice_read_end;
+
if (!skb_queue_empty(&ctx->rx_list)) {
skb = __skb_dequeue(&ctx->rx_list);
} else {
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index 91df3db6a88c..fdb8a62da04a 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -721,6 +721,7 @@ static inline void symtab_hash_eval(struct symtab *s)
static int policydb_index(struct policydb *p)
{
int i, rc;
+ u32 v;

if (p->mls_enabled)
pr_debug(
@@ -773,6 +774,24 @@ static int policydb_index(struct policydb *p)
if (rc)
goto out;
}
+
+ /*
+ * A sparse class value is absorbed by policydb_class_isvalid() and
+ * its siblings, but no such predicate exists for booleans: every
+ * user of bool_val_to_struct[] walks it by index and dereferences
+ * each entry -- cond_evaluate_expr(), the two getters and
+ * security_set_bools() -- so an unclaimed one has no consumer that
+ * can tolerate it.
+ */
+ for (v = 0; v < p->p_bools.nprim; v++) {
+ if (!p->bool_val_to_struct[v]) {
+ pr_err("SELinux: boolean %u is declared but not defined\n",
+ v + 1);
+ rc = -EINVAL;
+ goto out;
+ }
+ }
+
rc = 0;
out:
return rc;
@@ -1149,6 +1168,9 @@ static int perm_read(struct policydb *p, struct symtab *s, struct policy_file *f
rc = symtab_insert(s, key, perdatum);
if (rc)
goto bad;
+ /* indexes an nprim-sized array in security_get_permissions() */
+ if (perdatum->value > s->nprim)
+ goto bad;

return 0;
bad:
@@ -1366,6 +1388,18 @@ static int class_read(struct policydb *p, struct symtab *s, struct policy_file *
cladatum->comkey);
goto bad;
}
+
+ /*
+ * security_get_permissions() maps the common's permissions
+ * into an array sized by this class's nprim, so a class must
+ * declare at least as many as the common it inherits.
+ */
+ if (cladatum->permissions.nprim <
+ cladatum->comdatum->permissions.nprim) {
+ pr_err("SELinux: class %s has fewer permissions than common %s\n",
+ key, cladatum->comkey);
+ goto bad;
+ }
}
for (i = 0; i < nel; i++) {
rc = perm_read(p, &cladatum->permissions, fp);
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 1f5b05a59f84..82608b34260f 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -2220,7 +2220,9 @@ void selinux_policy_cancel(struct selinux_load_state *load_state)
oldpolicy = rcu_dereference_protected(state->policy,
lockdep_is_held(&state->policy_mutex));

- sidtab_cancel_convert(oldpolicy->sidtab);
+ /* a first load has no outgoing policy and converted nothing */
+ if (oldpolicy)
+ sidtab_cancel_convert(oldpolicy->sidtab);
selinux_policy_free(load_state->policy);
kfree(load_state->convert_data);
}
@@ -3301,6 +3303,7 @@ int security_get_classes(struct selinux_policy *policy,
char ***classes, u32 *nclasses)
{
struct policydb *policydb;
+ u32 i;
int rc;

policydb = &policy->policydb;
@@ -3313,16 +3316,29 @@ int security_get_classes(struct selinux_policy *policy,

rc = hashtab_map(&policydb->p_classes.table, get_classes_callback,
*classes);
- if (rc) {
- u32 i;
+ if (rc)
+ goto err;

- for (i = 0; i < *nclasses; i++)
- kfree((*classes)[i]);
- kfree(*classes);
+ /*
+ * The class symtab may be sparse, which policydb_class_isvalid() exists
+ * to absorb; the callback fills this array by value, so an unclaimed
+ * one leaves a NULL that sel_make_classes() hands to sel_make_dir().
+ */
+ for (i = 0; i < *nclasses; i++) {
+ if (!(*classes)[i]) {
+ rc = -EINVAL;
+ goto err;
+ }
}

out:
return rc;
+
+err:
+ for (i = 0; i < *nclasses; i++)
+ kfree((*classes)[i]);
+ kfree(*classes);
+ return rc;
}

static int get_permissions_callback(void *k, void *d, void *args)
diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c
index 7a047bdbae46..e79997b34302 100644
--- a/sound/hda/codecs/realtek/alc269.c
+++ b/sound/hda/codecs/realtek/alc269.c
@@ -6839,6 +6839,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x89d3, "HP EliteBook 645 G9 (MB 89D2)", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x89da, "HP Spectre x360 14t-ea100", ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX),
SND_PCI_QUIRK(0x103c, 0x89e7, "HP Elite x2 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8a05, "HP Dragonfly Folio G3 2-in-1", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8a06, "HP Dragonfly Folio G3 2-in-1", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8a0f, "HP Pavilion 14-ec1xxx", ALC287_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8a1f, "HP Laptop 14s-dr5xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
diff --git a/sound/hda/codecs/realtek/alc662.c b/sound/hda/codecs/realtek/alc662.c
index 5073165d1f3c..5678063ac057 100644
--- a/sound/hda/codecs/realtek/alc662.c
+++ b/sound/hda/codecs/realtek/alc662.c
@@ -835,6 +835,7 @@ static const struct hda_quirk alc662_fixup_tbl[] = {
SND_PCI_QUIRK(0x1b35, 0x1234, "CZC ET26", ALC662_FIXUP_CZC_ET26),
SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T),
SND_PCI_QUIRK(0x1c6c, 0x1239, "Compaq N14JP6-V2", ALC897_FIXUP_HP_HSMIC_VERB),
+ SND_PCI_QUIRK(0x1e63, 0x6d9a, "F+ FLAPTOP r", ALC897_FIXUP_HP_HSMIC_VERB),

#if 0
/* Below is a quirk table taken from the old code.
diff --git a/sound/soc/codecs/cs35l41-lib.c b/sound/soc/codecs/cs35l41-lib.c
index 1702f26049d3..b0fa80705be7 100644
--- a/sound/soc/codecs/cs35l41-lib.c
+++ b/sound/soc/codecs/cs35l41-lib.c
@@ -25,9 +25,9 @@ static const struct reg_default cs35l41_reg[] = {
{ CS35L41_GPIO_PAD_CONTROL, 0x00000000 },
{ CS35L41_GLOBAL_CLK_CTRL, 0x00000003 },
{ CS35L41_TST_FS_MON0, 0x00020016 },
+ { CS35L41_BSTCVRT_PEAK_CUR, 0x0000004A },
{ CS35L41_BSTCVRT_COEFF, 0x00002424 },
{ CS35L41_BSTCVRT_SLOPE_LBST, 0x00007500 },
- { CS35L41_BSTCVRT_PEAK_CUR, 0x0000004A },
{ CS35L41_SP_ENABLES, 0x00000000 },
{ CS35L41_SP_RATE_CTRL, 0x00000028 },
{ CS35L41_SP_FORMAT, 0x18180200 },
diff --git a/sound/soc/codecs/cs35l45-tables.c b/sound/soc/codecs/cs35l45-tables.c
index d2ecc7b3f619..764dbaa35042 100644
--- a/sound/soc/codecs/cs35l45-tables.c
+++ b/sound/soc/codecs/cs35l45-tables.c
@@ -66,22 +66,6 @@ static const struct reg_default cs35l45_defaults[] = {
{ CS35L45_ASPTX3_INPUT, 0x00000020 },
{ CS35L45_ASPTX4_INPUT, 0x00000028 },
{ CS35L45_ASPTX5_INPUT, 0x00000048 },
- { CS35L45_DSP1_RX1_RATE, 0x00000001 },
- { CS35L45_DSP1_RX2_RATE, 0x00000001 },
- { CS35L45_DSP1_RX3_RATE, 0x00000001 },
- { CS35L45_DSP1_RX4_RATE, 0x00000001 },
- { CS35L45_DSP1_RX5_RATE, 0x00000001 },
- { CS35L45_DSP1_RX6_RATE, 0x00000001 },
- { CS35L45_DSP1_RX7_RATE, 0x00000001 },
- { CS35L45_DSP1_RX8_RATE, 0x00000001 },
- { CS35L45_DSP1_TX1_RATE, 0x00000001 },
- { CS35L45_DSP1_TX2_RATE, 0x00000001 },
- { CS35L45_DSP1_TX3_RATE, 0x00000001 },
- { CS35L45_DSP1_TX4_RATE, 0x00000001 },
- { CS35L45_DSP1_TX5_RATE, 0x00000001 },
- { CS35L45_DSP1_TX6_RATE, 0x00000001 },
- { CS35L45_DSP1_TX7_RATE, 0x00000001 },
- { CS35L45_DSP1_TX8_RATE, 0x00000001 },
{ CS35L45_DSP1RX1_INPUT, 0x00000008 },
{ CS35L45_DSP1RX2_INPUT, 0x00000009 },
{ CS35L45_DSP1RX3_INPUT, 0x00000018 },
@@ -114,6 +98,22 @@ static const struct reg_default cs35l45_defaults[] = {
{ CS35L45_GPIO1_CTRL1, 0x81000001 },
{ CS35L45_GPIO2_CTRL1, 0x81000001 },
{ CS35L45_GPIO3_CTRL1, 0x81000001 },
+ { CS35L45_DSP1_RX1_RATE, 0x00000001 },
+ { CS35L45_DSP1_RX2_RATE, 0x00000001 },
+ { CS35L45_DSP1_RX3_RATE, 0x00000001 },
+ { CS35L45_DSP1_RX4_RATE, 0x00000001 },
+ { CS35L45_DSP1_RX5_RATE, 0x00000001 },
+ { CS35L45_DSP1_RX6_RATE, 0x00000001 },
+ { CS35L45_DSP1_RX7_RATE, 0x00000001 },
+ { CS35L45_DSP1_RX8_RATE, 0x00000001 },
+ { CS35L45_DSP1_TX1_RATE, 0x00000001 },
+ { CS35L45_DSP1_TX2_RATE, 0x00000001 },
+ { CS35L45_DSP1_TX3_RATE, 0x00000001 },
+ { CS35L45_DSP1_TX4_RATE, 0x00000001 },
+ { CS35L45_DSP1_TX5_RATE, 0x00000001 },
+ { CS35L45_DSP1_TX6_RATE, 0x00000001 },
+ { CS35L45_DSP1_TX7_RATE, 0x00000001 },
+ { CS35L45_DSP1_TX8_RATE, 0x00000001 },
};

static bool cs35l45_readable_reg(struct device *dev, unsigned int reg)
diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c
index 3f759c13d6d1..0bb1aa0c6cd0 100644
--- a/sound/soc/codecs/cs4265.c
+++ b/sound/soc/codecs/cs4265.c
@@ -46,11 +46,11 @@ static const struct reg_default cs4265_reg_defaults[] = {
{ CS4265_DAC_CHA_VOL, 0x00 },
{ CS4265_DAC_CHB_VOL, 0x00 },
{ CS4265_DAC_CTL2, 0xC0 },
- { CS4265_SPDIF_CTL1, 0x00 },
- { CS4265_SPDIF_CTL2, 0x00 },
{ CS4265_INT_MASK, 0x00 },
{ CS4265_STATUS_MODE_MSB, 0x00 },
{ CS4265_STATUS_MODE_LSB, 0x00 },
+ { CS4265_SPDIF_CTL1, 0x00 },
+ { CS4265_SPDIF_CTL2, 0x00 },
};

static bool cs4265_readable_register(struct device *dev, unsigned int reg)
diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c
index 38faa9074ca3..8350b02b575f 100644
--- a/sound/soc/codecs/lpass-wsa-macro.c
+++ b/sound/soc/codecs/lpass-wsa-macro.c
@@ -2167,7 +2167,7 @@ static int wsa_macro_ear_spkr_pa_gain_get(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);

- ucontrol->value.integer.value[0] = wsa->ear_spkr_gain;
+ ucontrol->value.enumerated.item[0] = wsa->ear_spkr_gain;

return 0;
}
@@ -2178,7 +2178,7 @@ static int wsa_macro_ear_spkr_pa_gain_put(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);

- wsa->ear_spkr_gain = ucontrol->value.integer.value[0];
+ wsa->ear_spkr_gain = ucontrol->value.enumerated.item[0];

return 0;
}
@@ -2192,7 +2192,7 @@ static int wsa_macro_rx_mux_get(struct snd_kcontrol *kcontrol,
snd_soc_dapm_to_component(widget->dapm);
struct wsa_macro *wsa = snd_soc_component_get_drvdata(component);

- ucontrol->value.integer.value[0] =
+ ucontrol->value.enumerated.item[0] =
wsa->rx_port_value[widget->shift];
return 0;
}
@@ -2206,7 +2206,7 @@ static int wsa_macro_rx_mux_put(struct snd_kcontrol *kcontrol,
snd_soc_dapm_to_component(widget->dapm);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
struct snd_soc_dapm_update *update = NULL;
- u32 rx_port_value = ucontrol->value.integer.value[0];
+ u32 rx_port_value = ucontrol->value.enumerated.item[0];
u32 bit_input;
u32 aif_rst;
unsigned int dai_id;
diff --git a/sound/soc/codecs/tas2562.c b/sound/soc/codecs/tas2562.c
index ec1c8d077efc..118984e30d7b 100644
--- a/sound/soc/codecs/tas2562.c
+++ b/sound/soc/codecs/tas2562.c
@@ -472,10 +472,15 @@ static int tas2562_volume_control_put(struct snd_kcontrol *kcontrol,
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component);
- int ret;
+ int ret, index;
u32 reg_val;

- reg_val = float_vol_db_lookup[ucontrol->value.integer.value[0]/2];
+ index = ucontrol->value.integer.value[0] / 2;
+ if (index < 0 || index >= ARRAY_SIZE(float_vol_db_lookup))
+ return -EINVAL;
+
+ reg_val = float_vol_db_lookup[index];
+
/*
* The device applies the 32-bit coefficient to the playback path on
* the write to DVC_CFG4 (the LSB, book 0 page 2 reg 0x0F), so the
diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c
index 0b83446da45e..58f8ae016dac 100644
--- a/sound/soc/codecs/tas2781-i2c.c
+++ b/sound/soc/codecs/tas2781-i2c.c
@@ -1533,8 +1533,8 @@ static ssize_t acoustic_ctl_write(struct file *file,
if (src[0] > max_pkg_len && src[0] != count) {
dev_err(priv->dev, "pkg(%u), max(%u), count(%u) mismatch.\n",
src[0], max_pkg_len, (unsigned int)count);
- ret = 0;
- goto exit;
+ kfree(src);
+ return 0;
}

switch (src[1]) {
@@ -1548,14 +1548,14 @@ static ssize_t acoustic_ctl_write(struct file *file,
break;
default:
dev_err(priv->dev, "%s Wrong code %02x.\n", __func__, src[1]);
- ret = 0;
- goto exit;
+ kfree(src);
+ return 0;
}

if (len < 1) {
dev_err(priv->dev, "pkg fmt invalid %02x.\n", len);
- ret = 0;
- goto exit;
+ kfree(src);
+ return 0;
}

for (j = 0; j < priv->ndev; j++)
@@ -1565,8 +1565,8 @@ static ssize_t acoustic_ctl_write(struct file *file,
}
if (j >= priv->ndev) {
dev_err(priv->dev, "no such device 0x%02x.\n", src[2]);
- ret = 0;
- goto exit;
+ kfree(src);
+ return 0;
}

reg = TASDEVICE_REG(src[3], src[4], src[5]);
@@ -1597,7 +1597,7 @@ static ssize_t acoustic_ctl_write(struct file *file,
dev_err(priv->dev, "i2c communication error.\n");
else
ret = count;
-exit:
+
kfree(src);
return ret;
}
diff --git a/sound/soc/intel/common/sof-function-topology-lib.c b/sound/soc/intel/common/sof-function-topology-lib.c
index 3cc81dcf047e..7940280bf448 100644
--- a/sound/soc/intel/common/sof-function-topology-lib.c
+++ b/sound/soc/intel/common/sof-function-topology-lib.c
@@ -30,7 +30,12 @@ enum tplg_device_id {
int sof_sdw_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_mach *mach,
const char *prefix, const char ***tplg_files)
{
- struct snd_soc_acpi_mach_params mach_params = mach->mach_params;
+ struct snd_soc_acpi_mach *card_mach = dev_get_platdata(card->dev);
+ /*
+ * Use the acpi mach from the machine driver because the machine driver
+ * may change the dmic_num based on the machine driver quirk.
+ */
+ struct snd_soc_acpi_mach_params mach_params = card_mach->mach_params;
struct snd_soc_dai_link *dai_link;
const struct firmware *fw;
char platform[SOF_INTEL_PLATFORM_NAME_MAX];
diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c
index 6d81969e181c..0c1d229c7bcb 100644
--- a/sound/soc/sof/ipc4-pcm.c
+++ b/sound/soc/sof/ipc4-pcm.c
@@ -528,7 +528,19 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
ret = sof_ipc4_set_multi_pipeline_state(sdev, SOF_IPC4_PIPE_PAUSED, trigger_list);
if (ret < 0) {
spcm_err(spcm, substream->stream, "failed to pause all pipelines\n");
- goto free;
+ /*
+ * workaround: if the firmware is crashed or the IPC timed out
+ * while setting the pipeline state we must ignore the error
+ * code and proceed to set adjust the local pipeline states.
+ *
+ * If the firmware is crashed we will not send IPC messages
+ * and we are going to see errors printed, but the state of the
+ * widgets will be correct for the next boot.
+ */
+ if (sdev->fw_state != SOF_FW_CRASHED && ret != -ETIMEDOUT)
+ goto free;
+
+ ret = 0;
}

/* update PAUSED state for all pipelines just triggered */
@@ -560,14 +572,15 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
"failed to set final state %d for all pipelines\n",
state);
/*
- * workaround: if the firmware is crashed while setting the
- * pipelines to reset state we must ignore the error code and
- * reset it to 0.
- * Since the firmware is crashed we will not send IPC messages
+ * workaround: if the firmware is crashed or the IPC timed out
+ * while setting the pipeline state we must ignore the error
+ * code and proceed to set adjust the local pipeline states.
+ *
+ * If the firmware is crashed we will not send IPC messages
* and we are going to see errors printed, but the state of the
* widgets will be correct for the next boot.
*/
- if (sdev->fw_state != SOF_FW_CRASHED || state != SOF_IPC4_PIPE_RESET)
+ if (sdev->fw_state != SOF_FW_CRASHED && ret != -ETIMEDOUT)
goto free;

ret = 0;
diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index d74567d6afc4..5701e4d1ac13 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -3007,6 +3007,15 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
ipc_size = ipc4_copier->ipc_config_size;
ipc_data = ipc4_copier->ipc_config_data;

+ /*
+ * Refresh copier_data in ipc_config_data for host copiers.
+ * The node_id may have been updated by host_config after
+ * ipc_prepare, e.g. when host stream tags change after a
+ * suspend/resume cycle.
+ */
+ if (swidget->id != snd_soc_dapm_buffer)
+ memcpy(ipc_data, &ipc4_copier->data, sizeof(ipc4_copier->data));
+
msg = &ipc4_copier->msg;
break;
}
@@ -3015,6 +3024,9 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
{
struct snd_sof_dai *dai = swidget->private;
struct sof_ipc4_copier *ipc4_copier = dai->private;
+ struct sof_ipc4_copier_data *copier_data;
+ u32 gtw_cfg_config_length;
+ u32 tlv_size;

pipeline = pipe_widget->private;
if (pipeline->use_chain_dma)
@@ -3023,6 +3035,27 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
ipc_size = ipc4_copier->ipc_config_size;
ipc_data = ipc4_copier->ipc_config_data;

+ /*
+ * Refresh copier_data and dma_config_tlv in ipc_config_data.
+ * These may have been updated after ipc_prepare, e.g. when
+ * link DMA stream tags change after a suspend/resume cycle.
+ *
+ * copier_data->gtw_cfg.config_length does not include the
+ * TLV size (it was restored after sof_ipc4_prepare_copier_module),
+ * so temporarily inflate it to match the ipc_config_data layout.
+ */
+ copier_data = &ipc4_copier->data;
+ gtw_cfg_config_length = copier_data->gtw_cfg.config_length * 4;
+ tlv_size = ipc_size - sizeof(*copier_data) - gtw_cfg_config_length;
+
+ copier_data->gtw_cfg.config_length += tlv_size / 4;
+ memcpy(ipc_data, copier_data, sizeof(*copier_data));
+ copier_data->gtw_cfg.config_length = gtw_cfg_config_length / 4;
+
+ if (tlv_size)
+ memcpy(ipc_data + sizeof(*copier_data) + gtw_cfg_config_length,
+ &ipc4_copier->dma_config_tlv, tlv_size);
+
msg = &ipc4_copier->msg;
break;
}
diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c
index a9664b4cf43f..ef7d2f4b31c8 100644
--- a/sound/soc/sof/sof-audio.c
+++ b/sound/soc/sof/sof-audio.c
@@ -136,7 +136,6 @@ static int sof_widget_setup_unlocked(struct snd_sof_dev *sdev,
{
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
struct snd_sof_pipeline *spipe = swidget->spipe;
- bool use_count_decremented = false;
int ret;
int i;

@@ -215,9 +214,10 @@ static int sof_widget_setup_unlocked(struct snd_sof_dev *sdev,
return 0;

widget_free:
- /* widget use_count will be decremented by sof_widget_free() */
+ /* widget use_count and core_put handled by sof_widget_free() */
sof_widget_free_unlocked(sdev, swidget);
- use_count_decremented = true;
+ return ret;
+
pipe_widget_free:
if (swidget->id != snd_soc_dapm_scheduler) {
sof_widget_free_unlocked(sdev, swidget->spipe->pipe_widget);
@@ -232,8 +232,7 @@ static int sof_widget_setup_unlocked(struct snd_sof_dev *sdev,
}
}
use_count_dec:
- if (!use_count_decremented)
- swidget->use_count--;
+ swidget->use_count--;

return ret;
}
diff --git a/sound/soc/xilinx/xlnx_formatter_pcm.c b/sound/soc/xilinx/xlnx_formatter_pcm.c
index 17ef05309469..45b178148b98 100644
--- a/sound/soc/xilinx/xlnx_formatter_pcm.c
+++ b/sound/soc/xilinx/xlnx_formatter_pcm.c
@@ -281,8 +281,7 @@ static irqreturn_t xlnx_mm2s_irq_handler(int irq, void *arg)
{
u32 val;
void __iomem *reg;
- struct device *dev = arg;
- struct xlnx_pcm_drv_data *adata = dev_get_drvdata(dev);
+ struct xlnx_pcm_drv_data *adata = arg;

reg = adata->mmio + XLNX_MM2S_OFFSET + XLNX_AUD_STS;
val = readl(reg);
@@ -300,8 +299,7 @@ static irqreturn_t xlnx_s2mm_irq_handler(int irq, void *arg)
{
u32 val;
void __iomem *reg;
- struct device *dev = arg;
- struct xlnx_pcm_drv_data *adata = dev_get_drvdata(dev);
+ struct xlnx_pcm_drv_data *adata = arg;

reg = adata->mmio + XLNX_S2MM_OFFSET + XLNX_AUD_STS;
val = readl(reg);
@@ -637,7 +635,7 @@ static int xlnx_formatter_pcm_probe(struct platform_device *pdev)
}
ret = devm_request_irq(dev, aud_drv_data->mm2s_irq,
xlnx_mm2s_irq_handler, 0,
- "xlnx_formatter_pcm_mm2s_irq", dev);
+ "xlnx_formatter_pcm_mm2s_irq", aud_drv_data);
if (ret) {
dev_err(dev, "xlnx audio mm2s irq request failed\n");
goto clk_err;
@@ -664,7 +662,7 @@ static int xlnx_formatter_pcm_probe(struct platform_device *pdev)
ret = devm_request_irq(dev, aud_drv_data->s2mm_irq,
xlnx_s2mm_irq_handler, 0,
"xlnx_formatter_pcm_s2mm_irq",
- dev);
+ aud_drv_data);
if (ret) {
dev_err(dev, "xlnx audio s2mm irq request failed\n");
goto clk_err;
diff --git a/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_uprobe.tc b/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_uprobe.tc
index f2048c244526..19430bd5864c 100644
--- a/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_uprobe.tc
+++ b/tools/testing/selftests/ftrace/test.d/dynevent/add_remove_uprobe.tc
@@ -12,9 +12,32 @@ echo 0 > events/enable
echo > dynamic_events

REALBIN=`readlink -f /bin/sh`
-ENTRYPOINT=`readelf -h ${REALBIN} | grep Entry | sed -e 's/[^0]*//'`

-echo "p:myevent ${REALBIN}:${ENTRYPOINT}" >> uprobe_events
+# Get the entry point virtual address from ELF header
+ENTRY=`readelf -hW ${REALBIN} | grep "Entry point" | awk '{print $NF}'`
+
+# Convert virtual address to file offset: find the LOAD segment containing
+# the entry point, then compute file_offset = e_entry - p_vaddr + p_offset.
+# For PIE binaries this is a no-op (vaddr == file offset), but for non-PIE
+# executables the virtual address is much larger than the file size and
+# must be converted, otherwise uprobe_register() rejects it with -EINVAL.
+ENTRY_DEC=$(printf '%d' "$ENTRY")
+OFFSET=$ENTRY
+while IFS= read -r line; do
+ set -- $line
+ [ "$1" = "LOAD" ] || continue
+ VA_DEC=$(printf '%d' "$3")
+ OFF_DEC=$(printf '%d' "$2")
+ FSZ_DEC=$(printf '%d' "$5")
+ if [ "$ENTRY_DEC" -ge "$VA_DEC" ] && [ "$ENTRY_DEC" -lt "$((VA_DEC + FSZ_DEC))" ]; then
+ OFFSET=$(printf '0x%x' "$((ENTRY_DEC - VA_DEC + OFF_DEC))")
+ break
+ fi
+done << EOF
+$(readelf -lW ${REALBIN} | grep LOAD)
+EOF
+
+echo "p:myevent ${REALBIN}:${OFFSET}" >> uprobe_events

grep -q myevent uprobe_events
test -d events/uprobes/myevent
diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh
index 11b603742d8f..c3e158bf347d 100755
--- a/tools/testing/selftests/net/mptcp/mptcp_join.sh
+++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh
@@ -565,7 +565,7 @@ check_transfer()
mv "$tmpfile" "$out"
tmpfile=""
fi
- cmp -l "$in" "$out" | while read -r i a b; do
+ while read -r i a b; do
local sum=$((0${a} + 0${b}))
if [ $check_invert -eq 0 ] || [ $sum -ne $((0xff)) ]; then
fail_test "$what does not match (in, out):"
@@ -576,7 +576,7 @@ check_transfer()
else
print_info "$what has inverted byte at ${i}"
fi
- done
+ done < <(cmp -l "$in" "$out")

return 0
}