]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.10-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 5 Mar 2021 08:32:39 +0000 (09:32 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 5 Mar 2021 08:32:39 +0000 (09:32 +0100)
added patches:
powerpc-sstep-check-instruction-validity-against-isa-version-before-emulation.patch
powerpc-sstep-fix-incorrect-return-from-analyze_instr.patch
remoteproc-mediatek-fix-kernel-test-robot-warning.patch
scsi-iscsi-ensure-sysfs-attributes-are-limited-to-page_size.patch
scsi-iscsi-restrict-sessions-and-handles-to-admin-capabilities.patch
scsi-iscsi-verify-lengths-on-passthrough-pdus.patch
swap-fix-swapfile-read-write-offset.patch
xen-fix-p2m-size-in-dom0-for-disabled-memory-hotplug-case.patch
xen-gnttab-handle-p2m-update-errors-on-a-per-slot-basis.patch
xen-netback-respect-gnttab_map_refs-s-return-value.patch
zsmalloc-account-the-number-of-compacted-pages-correctly.patch

12 files changed:
queue-5.10/powerpc-sstep-check-instruction-validity-against-isa-version-before-emulation.patch [new file with mode: 0644]
queue-5.10/powerpc-sstep-fix-incorrect-return-from-analyze_instr.patch [new file with mode: 0644]
queue-5.10/remoteproc-mediatek-fix-kernel-test-robot-warning.patch [new file with mode: 0644]
queue-5.10/scsi-iscsi-ensure-sysfs-attributes-are-limited-to-page_size.patch [new file with mode: 0644]
queue-5.10/scsi-iscsi-restrict-sessions-and-handles-to-admin-capabilities.patch [new file with mode: 0644]
queue-5.10/scsi-iscsi-verify-lengths-on-passthrough-pdus.patch [new file with mode: 0644]
queue-5.10/series
queue-5.10/swap-fix-swapfile-read-write-offset.patch [new file with mode: 0644]
queue-5.10/xen-fix-p2m-size-in-dom0-for-disabled-memory-hotplug-case.patch [new file with mode: 0644]
queue-5.10/xen-gnttab-handle-p2m-update-errors-on-a-per-slot-basis.patch [new file with mode: 0644]
queue-5.10/xen-netback-respect-gnttab_map_refs-s-return-value.patch [new file with mode: 0644]
queue-5.10/zsmalloc-account-the-number-of-compacted-pages-correctly.patch [new file with mode: 0644]

diff --git a/queue-5.10/powerpc-sstep-check-instruction-validity-against-isa-version-before-emulation.patch b/queue-5.10/powerpc-sstep-check-instruction-validity-against-isa-version-before-emulation.patch
new file mode 100644 (file)
index 0000000..d62b1a0
--- /dev/null
@@ -0,0 +1,326 @@
+From 8813ff49607eab3caaf40fe8929b0ce7dc68e85f Mon Sep 17 00:00:00 2001
+From: Ananth N Mavinakayanahalli <ananth@linux.ibm.com>
+Date: Mon, 25 Jan 2021 18:36:22 +0530
+Subject: powerpc/sstep: Check instruction validity against ISA version before emulation
+
+From: Ananth N Mavinakayanahalli <ananth@linux.ibm.com>
+
+commit 8813ff49607eab3caaf40fe8929b0ce7dc68e85f upstream.
+
+We currently unconditionally try to emulate newer instructions on older
+Power versions that could cause issues. Gate it.
+
+Fixes: 350779a29f11 ("powerpc: Handle most loads and stores in instruction emulation code")
+Signed-off-by: Ananth N Mavinakayanahalli <ananth@linux.ibm.com>
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+Link: https://lore.kernel.org/r/161157995977.64773.13794501093457185080.stgit@thinktux.local
+[Dropped a few missing hunks for the backport to v5.10]
+Signed-off-by: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/powerpc/lib/sstep.c |   72 ++++++++++++++++++++++++++++++++++++++---------
+ 1 file changed, 59 insertions(+), 13 deletions(-)
+
+--- a/arch/powerpc/lib/sstep.c
++++ b/arch/powerpc/lib/sstep.c
+@@ -1241,9 +1241,11 @@ int analyse_instr(struct instruction_op
+               if ((word & 0xfe2) == 2)
+                       op->type = SYSCALL;
+               else if (IS_ENABLED(CONFIG_PPC_BOOK3S_64) &&
+-                              (word & 0xfe3) == 1)
++                              (word & 0xfe3) == 1) {  /* scv */
+                       op->type = SYSCALL_VECTORED_0;
+-              else
++                      if (!cpu_has_feature(CPU_FTR_ARCH_300))
++                              goto unknown_opcode;
++              } else
+                       op->type = UNKNOWN;
+               return 0;
+ #endif
+@@ -1347,7 +1349,7 @@ int analyse_instr(struct instruction_op
+ #ifdef __powerpc64__
+       case 1:
+               if (!cpu_has_feature(CPU_FTR_ARCH_31))
+-                      return -1;
++                      goto unknown_opcode;
+               prefix_r = GET_PREFIX_R(word);
+               ra = GET_PREFIX_RA(suffix);
+@@ -1381,7 +1383,7 @@ int analyse_instr(struct instruction_op
+ #ifdef __powerpc64__
+       case 4:
+               if (!cpu_has_feature(CPU_FTR_ARCH_300))
+-                      return -1;
++                      goto unknown_opcode;
+               switch (word & 0x3f) {
+               case 48:        /* maddhd */
+@@ -1467,6 +1469,8 @@ int analyse_instr(struct instruction_op
+       case 19:
+               if (((word >> 1) & 0x1f) == 2) {
+                       /* addpcis */
++                      if (!cpu_has_feature(CPU_FTR_ARCH_300))
++                              goto unknown_opcode;
+                       imm = (short) (word & 0xffc1);  /* d0 + d2 fields */
+                       imm |= (word >> 15) & 0x3e;     /* d1 field */
+                       op->val = regs->nip + (imm << 16) + 4;
+@@ -1779,7 +1783,7 @@ int analyse_instr(struct instruction_op
+ #ifdef __powerpc64__
+               case 265:       /* modud */
+                       if (!cpu_has_feature(CPU_FTR_ARCH_300))
+-                              return -1;
++                              goto unknown_opcode;
+                       op->val = regs->gpr[ra] % regs->gpr[rb];
+                       goto compute_done;
+ #endif
+@@ -1789,7 +1793,7 @@ int analyse_instr(struct instruction_op
+               case 267:       /* moduw */
+                       if (!cpu_has_feature(CPU_FTR_ARCH_300))
+-                              return -1;
++                              goto unknown_opcode;
+                       op->val = (unsigned int) regs->gpr[ra] %
+                               (unsigned int) regs->gpr[rb];
+                       goto compute_done;
+@@ -1826,7 +1830,7 @@ int analyse_instr(struct instruction_op
+ #endif
+               case 755:       /* darn */
+                       if (!cpu_has_feature(CPU_FTR_ARCH_300))
+-                              return -1;
++                              goto unknown_opcode;
+                       switch (ra & 0x3) {
+                       case 0:
+                               /* 32-bit conditioned */
+@@ -1848,14 +1852,14 @@ int analyse_instr(struct instruction_op
+ #ifdef __powerpc64__
+               case 777:       /* modsd */
+                       if (!cpu_has_feature(CPU_FTR_ARCH_300))
+-                              return -1;
++                              goto unknown_opcode;
+                       op->val = (long int) regs->gpr[ra] %
+                               (long int) regs->gpr[rb];
+                       goto compute_done;
+ #endif
+               case 779:       /* modsw */
+                       if (!cpu_has_feature(CPU_FTR_ARCH_300))
+-                              return -1;
++                              goto unknown_opcode;
+                       op->val = (int) regs->gpr[ra] %
+                               (int) regs->gpr[rb];
+                       goto compute_done;
+@@ -1932,14 +1936,14 @@ int analyse_instr(struct instruction_op
+ #endif
+               case 538:       /* cnttzw */
+                       if (!cpu_has_feature(CPU_FTR_ARCH_300))
+-                              return -1;
++                              goto unknown_opcode;
+                       val = (unsigned int) regs->gpr[rd];
+                       op->val = (val ? __builtin_ctz(val) : 32);
+                       goto logical_done;
+ #ifdef __powerpc64__
+               case 570:       /* cnttzd */
+                       if (!cpu_has_feature(CPU_FTR_ARCH_300))
+-                              return -1;
++                              goto unknown_opcode;
+                       val = regs->gpr[rd];
+                       op->val = (val ? __builtin_ctzl(val) : 64);
+                       goto logical_done;
+@@ -2049,7 +2053,7 @@ int analyse_instr(struct instruction_op
+               case 890:       /* extswsli with sh_5 = 0 */
+               case 891:       /* extswsli with sh_5 = 1 */
+                       if (!cpu_has_feature(CPU_FTR_ARCH_300))
+-                              return -1;
++                              goto unknown_opcode;
+                       op->type = COMPUTE + SETREG;
+                       sh = rb | ((word & 2) << 4);
+                       val = (signed int) regs->gpr[rd];
+@@ -2376,6 +2380,8 @@ int analyse_instr(struct instruction_op
+                       break;
+               case 268:       /* lxvx */
++                      if (!cpu_has_feature(CPU_FTR_ARCH_300))
++                              goto unknown_opcode;
+                       op->reg = rd | ((word & 1) << 5);
+                       op->type = MKOP(LOAD_VSX, 0, 16);
+                       op->element_size = 16;
+@@ -2385,6 +2391,8 @@ int analyse_instr(struct instruction_op
+               case 269:       /* lxvl */
+               case 301: {     /* lxvll */
+                       int nb;
++                      if (!cpu_has_feature(CPU_FTR_ARCH_300))
++                              goto unknown_opcode;
+                       op->reg = rd | ((word & 1) << 5);
+                       op->ea = ra ? regs->gpr[ra] : 0;
+                       nb = regs->gpr[rb] & 0xff;
+@@ -2404,6 +2412,8 @@ int analyse_instr(struct instruction_op
+                       break;
+               case 364:       /* lxvwsx */
++                      if (!cpu_has_feature(CPU_FTR_ARCH_300))
++                              goto unknown_opcode;
+                       op->reg = rd | ((word & 1) << 5);
+                       op->type = MKOP(LOAD_VSX, 0, 4);
+                       op->element_size = 4;
+@@ -2411,6 +2421,8 @@ int analyse_instr(struct instruction_op
+                       break;
+               case 396:       /* stxvx */
++                      if (!cpu_has_feature(CPU_FTR_ARCH_300))
++                              goto unknown_opcode;
+                       op->reg = rd | ((word & 1) << 5);
+                       op->type = MKOP(STORE_VSX, 0, 16);
+                       op->element_size = 16;
+@@ -2420,6 +2432,8 @@ int analyse_instr(struct instruction_op
+               case 397:       /* stxvl */
+               case 429: {     /* stxvll */
+                       int nb;
++                      if (!cpu_has_feature(CPU_FTR_ARCH_300))
++                              goto unknown_opcode;
+                       op->reg = rd | ((word & 1) << 5);
+                       op->ea = ra ? regs->gpr[ra] : 0;
+                       nb = regs->gpr[rb] & 0xff;
+@@ -2464,6 +2478,8 @@ int analyse_instr(struct instruction_op
+                       break;
+               case 781:       /* lxsibzx */
++                      if (!cpu_has_feature(CPU_FTR_ARCH_300))
++                              goto unknown_opcode;
+                       op->reg = rd | ((word & 1) << 5);
+                       op->type = MKOP(LOAD_VSX, 0, 1);
+                       op->element_size = 8;
+@@ -2471,6 +2487,8 @@ int analyse_instr(struct instruction_op
+                       break;
+               case 812:       /* lxvh8x */
++                      if (!cpu_has_feature(CPU_FTR_ARCH_300))
++                              goto unknown_opcode;
+                       op->reg = rd | ((word & 1) << 5);
+                       op->type = MKOP(LOAD_VSX, 0, 16);
+                       op->element_size = 2;
+@@ -2478,6 +2496,8 @@ int analyse_instr(struct instruction_op
+                       break;
+               case 813:       /* lxsihzx */
++                      if (!cpu_has_feature(CPU_FTR_ARCH_300))
++                              goto unknown_opcode;
+                       op->reg = rd | ((word & 1) << 5);
+                       op->type = MKOP(LOAD_VSX, 0, 2);
+                       op->element_size = 8;
+@@ -2491,6 +2511,8 @@ int analyse_instr(struct instruction_op
+                       break;
+               case 876:       /* lxvb16x */
++                      if (!cpu_has_feature(CPU_FTR_ARCH_300))
++                              goto unknown_opcode;
+                       op->reg = rd | ((word & 1) << 5);
+                       op->type = MKOP(LOAD_VSX, 0, 16);
+                       op->element_size = 1;
+@@ -2504,6 +2526,8 @@ int analyse_instr(struct instruction_op
+                       break;
+               case 909:       /* stxsibx */
++                      if (!cpu_has_feature(CPU_FTR_ARCH_300))
++                              goto unknown_opcode;
+                       op->reg = rd | ((word & 1) << 5);
+                       op->type = MKOP(STORE_VSX, 0, 1);
+                       op->element_size = 8;
+@@ -2511,6 +2535,8 @@ int analyse_instr(struct instruction_op
+                       break;
+               case 940:       /* stxvh8x */
++                      if (!cpu_has_feature(CPU_FTR_ARCH_300))
++                              goto unknown_opcode;
+                       op->reg = rd | ((word & 1) << 5);
+                       op->type = MKOP(STORE_VSX, 0, 16);
+                       op->element_size = 2;
+@@ -2518,6 +2544,8 @@ int analyse_instr(struct instruction_op
+                       break;
+               case 941:       /* stxsihx */
++                      if (!cpu_has_feature(CPU_FTR_ARCH_300))
++                              goto unknown_opcode;
+                       op->reg = rd | ((word & 1) << 5);
+                       op->type = MKOP(STORE_VSX, 0, 2);
+                       op->element_size = 8;
+@@ -2531,6 +2559,8 @@ int analyse_instr(struct instruction_op
+                       break;
+               case 1004:      /* stxvb16x */
++                      if (!cpu_has_feature(CPU_FTR_ARCH_300))
++                              goto unknown_opcode;
+                       op->reg = rd | ((word & 1) << 5);
+                       op->type = MKOP(STORE_VSX, 0, 16);
+                       op->element_size = 1;
+@@ -2639,12 +2669,16 @@ int analyse_instr(struct instruction_op
+                       op->type = MKOP(LOAD_FP, 0, 16);
+                       break;
+               case 2:         /* lxsd */
++                      if (!cpu_has_feature(CPU_FTR_ARCH_300))
++                              goto unknown_opcode;
+                       op->reg = rd + 32;
+                       op->type = MKOP(LOAD_VSX, 0, 8);
+                       op->element_size = 8;
+                       op->vsx_flags = VSX_CHECK_VEC;
+                       break;
+               case 3:         /* lxssp */
++                      if (!cpu_has_feature(CPU_FTR_ARCH_300))
++                              goto unknown_opcode;
+                       op->reg = rd + 32;
+                       op->type = MKOP(LOAD_VSX, 0, 4);
+                       op->element_size = 8;
+@@ -2681,6 +2715,8 @@ int analyse_instr(struct instruction_op
+                       break;
+               case 1:         /* lxv */
++                      if (!cpu_has_feature(CPU_FTR_ARCH_300))
++                              goto unknown_opcode;
+                       op->ea = dqform_ea(word, regs);
+                       if (word & 8)
+                               op->reg = rd + 32;
+@@ -2691,6 +2727,8 @@ int analyse_instr(struct instruction_op
+               case 2:         /* stxsd with LSB of DS field = 0 */
+               case 6:         /* stxsd with LSB of DS field = 1 */
++                      if (!cpu_has_feature(CPU_FTR_ARCH_300))
++                              goto unknown_opcode;
+                       op->ea = dsform_ea(word, regs);
+                       op->reg = rd + 32;
+                       op->type = MKOP(STORE_VSX, 0, 8);
+@@ -2700,6 +2738,8 @@ int analyse_instr(struct instruction_op
+               case 3:         /* stxssp with LSB of DS field = 0 */
+               case 7:         /* stxssp with LSB of DS field = 1 */
++                      if (!cpu_has_feature(CPU_FTR_ARCH_300))
++                              goto unknown_opcode;
+                       op->ea = dsform_ea(word, regs);
+                       op->reg = rd + 32;
+                       op->type = MKOP(STORE_VSX, 0, 4);
+@@ -2708,6 +2748,8 @@ int analyse_instr(struct instruction_op
+                       break;
+               case 5:         /* stxv */
++                      if (!cpu_has_feature(CPU_FTR_ARCH_300))
++                              goto unknown_opcode;
+                       op->ea = dqform_ea(word, regs);
+                       if (word & 8)
+                               op->reg = rd + 32;
+@@ -2737,7 +2779,7 @@ int analyse_instr(struct instruction_op
+               break;
+       case 1: /* Prefixed instructions */
+               if (!cpu_has_feature(CPU_FTR_ARCH_31))
+-                      return -1;
++                      goto unknown_opcode;
+               prefix_r = GET_PREFIX_R(word);
+               ra = GET_PREFIX_RA(suffix);
+@@ -2872,6 +2914,10 @@ int analyse_instr(struct instruction_op
+       return 0;
++ unknown_opcode:
++      op->type = UNKNOWN;
++      return 0;
++
+  logical_done:
+       if (word & 1)
+               set_cr0(regs, op);
diff --git a/queue-5.10/powerpc-sstep-fix-incorrect-return-from-analyze_instr.patch b/queue-5.10/powerpc-sstep-fix-incorrect-return-from-analyze_instr.patch
new file mode 100644 (file)
index 0000000..e1190dc
--- /dev/null
@@ -0,0 +1,53 @@
+From 718aae916fa6619c57c348beaedd675835cf1aa1 Mon Sep 17 00:00:00 2001
+From: Ananth N Mavinakayanahalli <ananth@linux.ibm.com>
+Date: Mon, 25 Jan 2021 18:36:43 +0530
+Subject: powerpc/sstep: Fix incorrect return from analyze_instr()
+
+From: Ananth N Mavinakayanahalli <ananth@linux.ibm.com>
+
+commit 718aae916fa6619c57c348beaedd675835cf1aa1 upstream.
+
+We currently just percolate the return value from analyze_instr()
+to the caller of emulate_step(), especially if it is a -1.
+
+For one particular case (opcode = 4) for instructions that aren't
+currently emulated, we are returning 'should not be single-stepped'
+while we should have returned 0 which says 'did not emulate, may
+have to single-step'.
+
+Fixes: 930d6288a26787 ("powerpc: sstep: Add support for maddhd, maddhdu, maddld instructions")
+Signed-off-by: Ananth N Mavinakayanahalli <ananth@linux.ibm.com>
+Suggested-by: Michael Ellerman <mpe@ellerman.id.au>
+Tested-by: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
+Reviewed-by: Sandipan Das <sandipan@linux.ibm.com>
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+Link: https://lore.kernel.org/r/161157999039.64773.14950289716779364766.stgit@thinktux.local
+Signed-off-by: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/powerpc/lib/sstep.c |    7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/arch/powerpc/lib/sstep.c
++++ b/arch/powerpc/lib/sstep.c
+@@ -1382,6 +1382,11 @@ int analyse_instr(struct instruction_op
+ #ifdef __powerpc64__
+       case 4:
++              /*
++               * There are very many instructions with this primary opcode
++               * introduced in the ISA as early as v2.03. However, the ones
++               * we currently emulate were all introduced with ISA 3.0
++               */
+               if (!cpu_has_feature(CPU_FTR_ARCH_300))
+                       goto unknown_opcode;
+@@ -1409,7 +1414,7 @@ int analyse_instr(struct instruction_op
+                * There are other instructions from ISA 3.0 with the same
+                * primary opcode which do not have emulation support yet.
+                */
+-              return -1;
++              goto unknown_opcode;
+ #endif
+       case 7:         /* mulli */
diff --git a/queue-5.10/remoteproc-mediatek-fix-kernel-test-robot-warning.patch b/queue-5.10/remoteproc-mediatek-fix-kernel-test-robot-warning.patch
new file mode 100644 (file)
index 0000000..7f0666e
--- /dev/null
@@ -0,0 +1,58 @@
+From cca21000261b2364991ecdb0d9e66b26ad9c4b4e Mon Sep 17 00:00:00 2001
+From: Souptick Joarder <jrdr.linux@gmail.com>
+Date: Sat, 28 Nov 2020 03:20:55 +0530
+Subject: remoteproc/mediatek: Fix kernel test robot warning
+
+From: Souptick Joarder <jrdr.linux@gmail.com>
+
+commit cca21000261b2364991ecdb0d9e66b26ad9c4b4e upstream.
+
+Kernel test robot throws below warning ->
+
+>> drivers/remoteproc/mtk_scp.c:755:37: warning: unused variable
+>> 'mt8183_of_data' [-Wunused-const-variable]
+   static const struct mtk_scp_of_data mt8183_of_data = {
+                                       ^
+>> drivers/remoteproc/mtk_scp.c:765:37: warning: unused variable
+>> 'mt8192_of_data' [-Wunused-const-variable]
+   static const struct mtk_scp_of_data mt8192_of_data = {
+                                       ^
+As suggested by Bjorn, there's no harm in just dropping the
+of_match_ptr() wrapping of mtk_scp_of_match in the definition of
+mtk_scp_driver and we avoid this whole problem.
+
+Reported-by: kernel test robot <lkp@intel.com>
+Suggested-by: Bjorn Andersson <bjorn.andersson@linaro.org>
+Signed-off-by: Souptick Joarder <jrdr.linux@gmail.com>
+Link: https://lore.kernel.org/r/1606513855-21130-1-git-send-email-jrdr.linux@gmail.com
+Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/remoteproc/mtk_scp.c |    4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+--- a/drivers/remoteproc/mtk_scp.c
++++ b/drivers/remoteproc/mtk_scp.c
+@@ -775,21 +775,19 @@ static const struct mtk_scp_of_data mt81
+       .host_to_scp_int_bit = MT8192_HOST_IPC_INT_BIT,
+ };
+-#if defined(CONFIG_OF)
+ static const struct of_device_id mtk_scp_of_match[] = {
+       { .compatible = "mediatek,mt8183-scp", .data = &mt8183_of_data },
+       { .compatible = "mediatek,mt8192-scp", .data = &mt8192_of_data },
+       {},
+ };
+ MODULE_DEVICE_TABLE(of, mtk_scp_of_match);
+-#endif
+ static struct platform_driver mtk_scp_driver = {
+       .probe = scp_probe,
+       .remove = scp_remove,
+       .driver = {
+               .name = "mtk-scp",
+-              .of_match_table = of_match_ptr(mtk_scp_of_match),
++              .of_match_table = mtk_scp_of_match,
+       },
+ };
diff --git a/queue-5.10/scsi-iscsi-ensure-sysfs-attributes-are-limited-to-page_size.patch b/queue-5.10/scsi-iscsi-ensure-sysfs-attributes-are-limited-to-page_size.patch
new file mode 100644 (file)
index 0000000..b4df659
--- /dev/null
@@ -0,0 +1,447 @@
+From ec98ea7070e94cc25a422ec97d1421e28d97b7ee Mon Sep 17 00:00:00 2001
+From: Chris Leech <cleech@redhat.com>
+Date: Tue, 23 Feb 2021 18:00:17 -0800
+Subject: scsi: iscsi: Ensure sysfs attributes are limited to PAGE_SIZE
+
+From: Chris Leech <cleech@redhat.com>
+
+commit ec98ea7070e94cc25a422ec97d1421e28d97b7ee upstream.
+
+As the iSCSI parameters are exported back through sysfs, it should be
+enforcing that they never are more than PAGE_SIZE (which should be more
+than enough) before accepting updates through netlink.
+
+Change all iSCSI sysfs attributes to use sysfs_emit().
+
+Cc: stable@vger.kernel.org
+Reported-by: Adam Nichols <adam@grimm-co.com>
+Reviewed-by: Lee Duncan <lduncan@suse.com>
+Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Reviewed-by: Mike Christie <michael.christie@oracle.com>
+Signed-off-by: Chris Leech <cleech@redhat.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/scsi/libiscsi.c             |  148 ++++++++++++++++++------------------
+ drivers/scsi/scsi_transport_iscsi.c |   25 +++---
+ 2 files changed, 90 insertions(+), 83 deletions(-)
+
+--- a/drivers/scsi/libiscsi.c
++++ b/drivers/scsi/libiscsi.c
+@@ -3338,125 +3338,125 @@ int iscsi_session_get_param(struct iscsi
+       switch(param) {
+       case ISCSI_PARAM_FAST_ABORT:
+-              len = sprintf(buf, "%d\n", session->fast_abort);
++              len = sysfs_emit(buf, "%d\n", session->fast_abort);
+               break;
+       case ISCSI_PARAM_ABORT_TMO:
+-              len = sprintf(buf, "%d\n", session->abort_timeout);
++              len = sysfs_emit(buf, "%d\n", session->abort_timeout);
+               break;
+       case ISCSI_PARAM_LU_RESET_TMO:
+-              len = sprintf(buf, "%d\n", session->lu_reset_timeout);
++              len = sysfs_emit(buf, "%d\n", session->lu_reset_timeout);
+               break;
+       case ISCSI_PARAM_TGT_RESET_TMO:
+-              len = sprintf(buf, "%d\n", session->tgt_reset_timeout);
++              len = sysfs_emit(buf, "%d\n", session->tgt_reset_timeout);
+               break;
+       case ISCSI_PARAM_INITIAL_R2T_EN:
+-              len = sprintf(buf, "%d\n", session->initial_r2t_en);
++              len = sysfs_emit(buf, "%d\n", session->initial_r2t_en);
+               break;
+       case ISCSI_PARAM_MAX_R2T:
+-              len = sprintf(buf, "%hu\n", session->max_r2t);
++              len = sysfs_emit(buf, "%hu\n", session->max_r2t);
+               break;
+       case ISCSI_PARAM_IMM_DATA_EN:
+-              len = sprintf(buf, "%d\n", session->imm_data_en);
++              len = sysfs_emit(buf, "%d\n", session->imm_data_en);
+               break;
+       case ISCSI_PARAM_FIRST_BURST:
+-              len = sprintf(buf, "%u\n", session->first_burst);
++              len = sysfs_emit(buf, "%u\n", session->first_burst);
+               break;
+       case ISCSI_PARAM_MAX_BURST:
+-              len = sprintf(buf, "%u\n", session->max_burst);
++              len = sysfs_emit(buf, "%u\n", session->max_burst);
+               break;
+       case ISCSI_PARAM_PDU_INORDER_EN:
+-              len = sprintf(buf, "%d\n", session->pdu_inorder_en);
++              len = sysfs_emit(buf, "%d\n", session->pdu_inorder_en);
+               break;
+       case ISCSI_PARAM_DATASEQ_INORDER_EN:
+-              len = sprintf(buf, "%d\n", session->dataseq_inorder_en);
++              len = sysfs_emit(buf, "%d\n", session->dataseq_inorder_en);
+               break;
+       case ISCSI_PARAM_DEF_TASKMGMT_TMO:
+-              len = sprintf(buf, "%d\n", session->def_taskmgmt_tmo);
++              len = sysfs_emit(buf, "%d\n", session->def_taskmgmt_tmo);
+               break;
+       case ISCSI_PARAM_ERL:
+-              len = sprintf(buf, "%d\n", session->erl);
++              len = sysfs_emit(buf, "%d\n", session->erl);
+               break;
+       case ISCSI_PARAM_TARGET_NAME:
+-              len = sprintf(buf, "%s\n", session->targetname);
++              len = sysfs_emit(buf, "%s\n", session->targetname);
+               break;
+       case ISCSI_PARAM_TARGET_ALIAS:
+-              len = sprintf(buf, "%s\n", session->targetalias);
++              len = sysfs_emit(buf, "%s\n", session->targetalias);
+               break;
+       case ISCSI_PARAM_TPGT:
+-              len = sprintf(buf, "%d\n", session->tpgt);
++              len = sysfs_emit(buf, "%d\n", session->tpgt);
+               break;
+       case ISCSI_PARAM_USERNAME:
+-              len = sprintf(buf, "%s\n", session->username);
++              len = sysfs_emit(buf, "%s\n", session->username);
+               break;
+       case ISCSI_PARAM_USERNAME_IN:
+-              len = sprintf(buf, "%s\n", session->username_in);
++              len = sysfs_emit(buf, "%s\n", session->username_in);
+               break;
+       case ISCSI_PARAM_PASSWORD:
+-              len = sprintf(buf, "%s\n", session->password);
++              len = sysfs_emit(buf, "%s\n", session->password);
+               break;
+       case ISCSI_PARAM_PASSWORD_IN:
+-              len = sprintf(buf, "%s\n", session->password_in);
++              len = sysfs_emit(buf, "%s\n", session->password_in);
+               break;
+       case ISCSI_PARAM_IFACE_NAME:
+-              len = sprintf(buf, "%s\n", session->ifacename);
++              len = sysfs_emit(buf, "%s\n", session->ifacename);
+               break;
+       case ISCSI_PARAM_INITIATOR_NAME:
+-              len = sprintf(buf, "%s\n", session->initiatorname);
++              len = sysfs_emit(buf, "%s\n", session->initiatorname);
+               break;
+       case ISCSI_PARAM_BOOT_ROOT:
+-              len = sprintf(buf, "%s\n", session->boot_root);
++              len = sysfs_emit(buf, "%s\n", session->boot_root);
+               break;
+       case ISCSI_PARAM_BOOT_NIC:
+-              len = sprintf(buf, "%s\n", session->boot_nic);
++              len = sysfs_emit(buf, "%s\n", session->boot_nic);
+               break;
+       case ISCSI_PARAM_BOOT_TARGET:
+-              len = sprintf(buf, "%s\n", session->boot_target);
++              len = sysfs_emit(buf, "%s\n", session->boot_target);
+               break;
+       case ISCSI_PARAM_AUTO_SND_TGT_DISABLE:
+-              len = sprintf(buf, "%u\n", session->auto_snd_tgt_disable);
++              len = sysfs_emit(buf, "%u\n", session->auto_snd_tgt_disable);
+               break;
+       case ISCSI_PARAM_DISCOVERY_SESS:
+-              len = sprintf(buf, "%u\n", session->discovery_sess);
++              len = sysfs_emit(buf, "%u\n", session->discovery_sess);
+               break;
+       case ISCSI_PARAM_PORTAL_TYPE:
+-              len = sprintf(buf, "%s\n", session->portal_type);
++              len = sysfs_emit(buf, "%s\n", session->portal_type);
+               break;
+       case ISCSI_PARAM_CHAP_AUTH_EN:
+-              len = sprintf(buf, "%u\n", session->chap_auth_en);
++              len = sysfs_emit(buf, "%u\n", session->chap_auth_en);
+               break;
+       case ISCSI_PARAM_DISCOVERY_LOGOUT_EN:
+-              len = sprintf(buf, "%u\n", session->discovery_logout_en);
++              len = sysfs_emit(buf, "%u\n", session->discovery_logout_en);
+               break;
+       case ISCSI_PARAM_BIDI_CHAP_EN:
+-              len = sprintf(buf, "%u\n", session->bidi_chap_en);
++              len = sysfs_emit(buf, "%u\n", session->bidi_chap_en);
+               break;
+       case ISCSI_PARAM_DISCOVERY_AUTH_OPTIONAL:
+-              len = sprintf(buf, "%u\n", session->discovery_auth_optional);
++              len = sysfs_emit(buf, "%u\n", session->discovery_auth_optional);
+               break;
+       case ISCSI_PARAM_DEF_TIME2WAIT:
+-              len = sprintf(buf, "%d\n", session->time2wait);
++              len = sysfs_emit(buf, "%d\n", session->time2wait);
+               break;
+       case ISCSI_PARAM_DEF_TIME2RETAIN:
+-              len = sprintf(buf, "%d\n", session->time2retain);
++              len = sysfs_emit(buf, "%d\n", session->time2retain);
+               break;
+       case ISCSI_PARAM_TSID:
+-              len = sprintf(buf, "%u\n", session->tsid);
++              len = sysfs_emit(buf, "%u\n", session->tsid);
+               break;
+       case ISCSI_PARAM_ISID:
+-              len = sprintf(buf, "%02x%02x%02x%02x%02x%02x\n",
++              len = sysfs_emit(buf, "%02x%02x%02x%02x%02x%02x\n",
+                             session->isid[0], session->isid[1],
+                             session->isid[2], session->isid[3],
+                             session->isid[4], session->isid[5]);
+               break;
+       case ISCSI_PARAM_DISCOVERY_PARENT_IDX:
+-              len = sprintf(buf, "%u\n", session->discovery_parent_idx);
++              len = sysfs_emit(buf, "%u\n", session->discovery_parent_idx);
+               break;
+       case ISCSI_PARAM_DISCOVERY_PARENT_TYPE:
+               if (session->discovery_parent_type)
+-                      len = sprintf(buf, "%s\n",
++                      len = sysfs_emit(buf, "%s\n",
+                                     session->discovery_parent_type);
+               else
+-                      len = sprintf(buf, "\n");
++                      len = sysfs_emit(buf, "\n");
+               break;
+       default:
+               return -ENOSYS;
+@@ -3488,16 +3488,16 @@ int iscsi_conn_get_addr_param(struct soc
+       case ISCSI_PARAM_CONN_ADDRESS:
+       case ISCSI_HOST_PARAM_IPADDRESS:
+               if (sin)
+-                      len = sprintf(buf, "%pI4\n", &sin->sin_addr.s_addr);
++                      len = sysfs_emit(buf, "%pI4\n", &sin->sin_addr.s_addr);
+               else
+-                      len = sprintf(buf, "%pI6\n", &sin6->sin6_addr);
++                      len = sysfs_emit(buf, "%pI6\n", &sin6->sin6_addr);
+               break;
+       case ISCSI_PARAM_CONN_PORT:
+       case ISCSI_PARAM_LOCAL_PORT:
+               if (sin)
+-                      len = sprintf(buf, "%hu\n", be16_to_cpu(sin->sin_port));
++                      len = sysfs_emit(buf, "%hu\n", be16_to_cpu(sin->sin_port));
+               else
+-                      len = sprintf(buf, "%hu\n",
++                      len = sysfs_emit(buf, "%hu\n",
+                                     be16_to_cpu(sin6->sin6_port));
+               break;
+       default:
+@@ -3516,88 +3516,88 @@ int iscsi_conn_get_param(struct iscsi_cl
+       switch(param) {
+       case ISCSI_PARAM_PING_TMO:
+-              len = sprintf(buf, "%u\n", conn->ping_timeout);
++              len = sysfs_emit(buf, "%u\n", conn->ping_timeout);
+               break;
+       case ISCSI_PARAM_RECV_TMO:
+-              len = sprintf(buf, "%u\n", conn->recv_timeout);
++              len = sysfs_emit(buf, "%u\n", conn->recv_timeout);
+               break;
+       case ISCSI_PARAM_MAX_RECV_DLENGTH:
+-              len = sprintf(buf, "%u\n", conn->max_recv_dlength);
++              len = sysfs_emit(buf, "%u\n", conn->max_recv_dlength);
+               break;
+       case ISCSI_PARAM_MAX_XMIT_DLENGTH:
+-              len = sprintf(buf, "%u\n", conn->max_xmit_dlength);
++              len = sysfs_emit(buf, "%u\n", conn->max_xmit_dlength);
+               break;
+       case ISCSI_PARAM_HDRDGST_EN:
+-              len = sprintf(buf, "%d\n", conn->hdrdgst_en);
++              len = sysfs_emit(buf, "%d\n", conn->hdrdgst_en);
+               break;
+       case ISCSI_PARAM_DATADGST_EN:
+-              len = sprintf(buf, "%d\n", conn->datadgst_en);
++              len = sysfs_emit(buf, "%d\n", conn->datadgst_en);
+               break;
+       case ISCSI_PARAM_IFMARKER_EN:
+-              len = sprintf(buf, "%d\n", conn->ifmarker_en);
++              len = sysfs_emit(buf, "%d\n", conn->ifmarker_en);
+               break;
+       case ISCSI_PARAM_OFMARKER_EN:
+-              len = sprintf(buf, "%d\n", conn->ofmarker_en);
++              len = sysfs_emit(buf, "%d\n", conn->ofmarker_en);
+               break;
+       case ISCSI_PARAM_EXP_STATSN:
+-              len = sprintf(buf, "%u\n", conn->exp_statsn);
++              len = sysfs_emit(buf, "%u\n", conn->exp_statsn);
+               break;
+       case ISCSI_PARAM_PERSISTENT_PORT:
+-              len = sprintf(buf, "%d\n", conn->persistent_port);
++              len = sysfs_emit(buf, "%d\n", conn->persistent_port);
+               break;
+       case ISCSI_PARAM_PERSISTENT_ADDRESS:
+-              len = sprintf(buf, "%s\n", conn->persistent_address);
++              len = sysfs_emit(buf, "%s\n", conn->persistent_address);
+               break;
+       case ISCSI_PARAM_STATSN:
+-              len = sprintf(buf, "%u\n", conn->statsn);
++              len = sysfs_emit(buf, "%u\n", conn->statsn);
+               break;
+       case ISCSI_PARAM_MAX_SEGMENT_SIZE:
+-              len = sprintf(buf, "%u\n", conn->max_segment_size);
++              len = sysfs_emit(buf, "%u\n", conn->max_segment_size);
+               break;
+       case ISCSI_PARAM_KEEPALIVE_TMO:
+-              len = sprintf(buf, "%u\n", conn->keepalive_tmo);
++              len = sysfs_emit(buf, "%u\n", conn->keepalive_tmo);
+               break;
+       case ISCSI_PARAM_LOCAL_PORT:
+-              len = sprintf(buf, "%u\n", conn->local_port);
++              len = sysfs_emit(buf, "%u\n", conn->local_port);
+               break;
+       case ISCSI_PARAM_TCP_TIMESTAMP_STAT:
+-              len = sprintf(buf, "%u\n", conn->tcp_timestamp_stat);
++              len = sysfs_emit(buf, "%u\n", conn->tcp_timestamp_stat);
+               break;
+       case ISCSI_PARAM_TCP_NAGLE_DISABLE:
+-              len = sprintf(buf, "%u\n", conn->tcp_nagle_disable);
++              len = sysfs_emit(buf, "%u\n", conn->tcp_nagle_disable);
+               break;
+       case ISCSI_PARAM_TCP_WSF_DISABLE:
+-              len = sprintf(buf, "%u\n", conn->tcp_wsf_disable);
++              len = sysfs_emit(buf, "%u\n", conn->tcp_wsf_disable);
+               break;
+       case ISCSI_PARAM_TCP_TIMER_SCALE:
+-              len = sprintf(buf, "%u\n", conn->tcp_timer_scale);
++              len = sysfs_emit(buf, "%u\n", conn->tcp_timer_scale);
+               break;
+       case ISCSI_PARAM_TCP_TIMESTAMP_EN:
+-              len = sprintf(buf, "%u\n", conn->tcp_timestamp_en);
++              len = sysfs_emit(buf, "%u\n", conn->tcp_timestamp_en);
+               break;
+       case ISCSI_PARAM_IP_FRAGMENT_DISABLE:
+-              len = sprintf(buf, "%u\n", conn->fragment_disable);
++              len = sysfs_emit(buf, "%u\n", conn->fragment_disable);
+               break;
+       case ISCSI_PARAM_IPV4_TOS:
+-              len = sprintf(buf, "%u\n", conn->ipv4_tos);
++              len = sysfs_emit(buf, "%u\n", conn->ipv4_tos);
+               break;
+       case ISCSI_PARAM_IPV6_TC:
+-              len = sprintf(buf, "%u\n", conn->ipv6_traffic_class);
++              len = sysfs_emit(buf, "%u\n", conn->ipv6_traffic_class);
+               break;
+       case ISCSI_PARAM_IPV6_FLOW_LABEL:
+-              len = sprintf(buf, "%u\n", conn->ipv6_flow_label);
++              len = sysfs_emit(buf, "%u\n", conn->ipv6_flow_label);
+               break;
+       case ISCSI_PARAM_IS_FW_ASSIGNED_IPV6:
+-              len = sprintf(buf, "%u\n", conn->is_fw_assigned_ipv6);
++              len = sysfs_emit(buf, "%u\n", conn->is_fw_assigned_ipv6);
+               break;
+       case ISCSI_PARAM_TCP_XMIT_WSF:
+-              len = sprintf(buf, "%u\n", conn->tcp_xmit_wsf);
++              len = sysfs_emit(buf, "%u\n", conn->tcp_xmit_wsf);
+               break;
+       case ISCSI_PARAM_TCP_RECV_WSF:
+-              len = sprintf(buf, "%u\n", conn->tcp_recv_wsf);
++              len = sysfs_emit(buf, "%u\n", conn->tcp_recv_wsf);
+               break;
+       case ISCSI_PARAM_LOCAL_IPADDR:
+-              len = sprintf(buf, "%s\n", conn->local_ipaddr);
++              len = sysfs_emit(buf, "%s\n", conn->local_ipaddr);
+               break;
+       default:
+               return -ENOSYS;
+@@ -3615,13 +3615,13 @@ int iscsi_host_get_param(struct Scsi_Hos
+       switch (param) {
+       case ISCSI_HOST_PARAM_NETDEV_NAME:
+-              len = sprintf(buf, "%s\n", ihost->netdev);
++              len = sysfs_emit(buf, "%s\n", ihost->netdev);
+               break;
+       case ISCSI_HOST_PARAM_HWADDRESS:
+-              len = sprintf(buf, "%s\n", ihost->hwaddress);
++              len = sysfs_emit(buf, "%s\n", ihost->hwaddress);
+               break;
+       case ISCSI_HOST_PARAM_INITIATOR_NAME:
+-              len = sprintf(buf, "%s\n", ihost->initiatorname);
++              len = sysfs_emit(buf, "%s\n", ihost->initiatorname);
+               break;
+       default:
+               return -ENOSYS;
+--- a/drivers/scsi/scsi_transport_iscsi.c
++++ b/drivers/scsi/scsi_transport_iscsi.c
+@@ -135,7 +135,8 @@ show_transport_handle(struct device *dev
+       if (!capable(CAP_SYS_ADMIN))
+               return -EACCES;
+-      return sprintf(buf, "%llu\n", (unsigned long long)iscsi_handle(priv->iscsi_transport));
++      return sysfs_emit(buf, "%llu\n",
++                (unsigned long long)iscsi_handle(priv->iscsi_transport));
+ }
+ static DEVICE_ATTR(handle, S_IRUGO, show_transport_handle, NULL);
+@@ -145,7 +146,7 @@ show_transport_##name(struct device *dev
+                     struct device_attribute *attr,char *buf)          \
+ {                                                                     \
+       struct iscsi_internal *priv = dev_to_iscsi_internal(dev);       \
+-      return sprintf(buf, format"\n", priv->iscsi_transport->name);   \
++      return sysfs_emit(buf, format"\n", priv->iscsi_transport->name);\
+ }                                                                     \
+ static DEVICE_ATTR(name, S_IRUGO, show_transport_##name, NULL);
+@@ -186,7 +187,7 @@ static ssize_t
+ show_ep_handle(struct device *dev, struct device_attribute *attr, char *buf)
+ {
+       struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev);
+-      return sprintf(buf, "%llu\n", (unsigned long long) ep->id);
++      return sysfs_emit(buf, "%llu\n", (unsigned long long) ep->id);
+ }
+ static ISCSI_ATTR(ep, handle, S_IRUGO, show_ep_handle, NULL);
+@@ -2886,6 +2887,9 @@ iscsi_set_param(struct iscsi_transport *
+       struct iscsi_cls_session *session;
+       int err = 0, value = 0;
++      if (ev->u.set_param.len > PAGE_SIZE)
++              return -EINVAL;
++
+       session = iscsi_session_lookup(ev->u.set_param.sid);
+       conn = iscsi_conn_lookup(ev->u.set_param.sid, ev->u.set_param.cid);
+       if (!conn || !session)
+@@ -3033,6 +3037,9 @@ iscsi_set_host_param(struct iscsi_transp
+       if (!transport->set_host_param)
+               return -ENOSYS;
++      if (ev->u.set_host_param.len > PAGE_SIZE)
++              return -EINVAL;
++
+       shost = scsi_host_lookup(ev->u.set_host_param.host_no);
+       if (!shost) {
+               printk(KERN_ERR "set_host_param could not find host no %u\n",
+@@ -3966,7 +3973,7 @@ static ssize_t show_conn_state(struct de
+           conn->state < ARRAY_SIZE(connection_state_names))
+               state = connection_state_names[conn->state];
+-      return sprintf(buf, "%s\n", state);
++      return sysfs_emit(buf, "%s\n", state);
+ }
+ static ISCSI_CLASS_ATTR(conn, state, S_IRUGO, show_conn_state,
+                       NULL);
+@@ -4194,7 +4201,7 @@ show_priv_session_state(struct device *d
+                       char *buf)
+ {
+       struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent);
+-      return sprintf(buf, "%s\n", iscsi_session_state_name(session->state));
++      return sysfs_emit(buf, "%s\n", iscsi_session_state_name(session->state));
+ }
+ static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state,
+                       NULL);
+@@ -4203,7 +4210,7 @@ show_priv_session_creator(struct device
+                       char *buf)
+ {
+       struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent);
+-      return sprintf(buf, "%d\n", session->creator);
++      return sysfs_emit(buf, "%d\n", session->creator);
+ }
+ static ISCSI_CLASS_ATTR(priv_sess, creator, S_IRUGO, show_priv_session_creator,
+                       NULL);
+@@ -4212,7 +4219,7 @@ show_priv_session_target_id(struct devic
+                           char *buf)
+ {
+       struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent);
+-      return sprintf(buf, "%d\n", session->target_id);
++      return sysfs_emit(buf, "%d\n", session->target_id);
+ }
+ static ISCSI_CLASS_ATTR(priv_sess, target_id, S_IRUGO,
+                       show_priv_session_target_id, NULL);
+@@ -4225,8 +4232,8 @@ show_priv_session_##field(struct device
+       struct iscsi_cls_session *session =                             \
+                       iscsi_dev_to_session(dev->parent);              \
+       if (session->field == -1)                                       \
+-              return sprintf(buf, "off\n");                           \
+-      return sprintf(buf, format"\n", session->field);                \
++              return sysfs_emit(buf, "off\n");                        \
++      return sysfs_emit(buf, format"\n", session->field);             \
+ }
+ #define iscsi_priv_session_attr_store(field)                          \
diff --git a/queue-5.10/scsi-iscsi-restrict-sessions-and-handles-to-admin-capabilities.patch b/queue-5.10/scsi-iscsi-restrict-sessions-and-handles-to-admin-capabilities.patch
new file mode 100644 (file)
index 0000000..b89a402
--- /dev/null
@@ -0,0 +1,47 @@
+From 688e8128b7a92df982709a4137ea4588d16f24aa Mon Sep 17 00:00:00 2001
+From: Lee Duncan <lduncan@suse.com>
+Date: Tue, 23 Feb 2021 13:06:24 -0800
+Subject: scsi: iscsi: Restrict sessions and handles to admin capabilities
+
+From: Lee Duncan <lduncan@suse.com>
+
+commit 688e8128b7a92df982709a4137ea4588d16f24aa upstream.
+
+Protect the iSCSI transport handle, available in sysfs, by requiring
+CAP_SYS_ADMIN to read it. Also protect the netlink socket by restricting
+reception of messages to ones sent with CAP_SYS_ADMIN. This disables
+normal users from being able to end arbitrary iSCSI sessions.
+
+Cc: stable@vger.kernel.org
+Reported-by: Adam Nichols <adam@grimm-co.com>
+Reviewed-by: Chris Leech <cleech@redhat.com>
+Reviewed-by: Mike Christie <michael.christie@oracle.com>
+Signed-off-by: Lee Duncan <lduncan@suse.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/scsi/scsi_transport_iscsi.c |    6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/scsi/scsi_transport_iscsi.c
++++ b/drivers/scsi/scsi_transport_iscsi.c
+@@ -132,6 +132,9 @@ show_transport_handle(struct device *dev
+                     char *buf)
+ {
+       struct iscsi_internal *priv = dev_to_iscsi_internal(dev);
++
++      if (!capable(CAP_SYS_ADMIN))
++              return -EACCES;
+       return sprintf(buf, "%llu\n", (unsigned long long)iscsi_handle(priv->iscsi_transport));
+ }
+ static DEVICE_ATTR(handle, S_IRUGO, show_transport_handle, NULL);
+@@ -3624,6 +3627,9 @@ iscsi_if_recv_msg(struct sk_buff *skb, s
+       struct iscsi_cls_conn *conn;
+       struct iscsi_endpoint *ep = NULL;
++      if (!netlink_capable(skb, CAP_SYS_ADMIN))
++              return -EPERM;
++
+       if (nlh->nlmsg_type == ISCSI_UEVENT_PATH_UPDATE)
+               *group = ISCSI_NL_GRP_UIP;
+       else
diff --git a/queue-5.10/scsi-iscsi-verify-lengths-on-passthrough-pdus.patch b/queue-5.10/scsi-iscsi-verify-lengths-on-passthrough-pdus.patch
new file mode 100644 (file)
index 0000000..2dacdd5
--- /dev/null
@@ -0,0 +1,49 @@
+From f9dbdf97a5bd92b1a49cee3d591b55b11fd7a6d5 Mon Sep 17 00:00:00 2001
+From: Chris Leech <cleech@redhat.com>
+Date: Tue, 23 Feb 2021 21:39:01 -0800
+Subject: scsi: iscsi: Verify lengths on passthrough PDUs
+
+From: Chris Leech <cleech@redhat.com>
+
+commit f9dbdf97a5bd92b1a49cee3d591b55b11fd7a6d5 upstream.
+
+Open-iSCSI sends passthrough PDUs over netlink, but the kernel should be
+verifying that the provided PDU header and data lengths fall within the
+netlink message to prevent accessing beyond that in memory.
+
+Cc: stable@vger.kernel.org
+Reported-by: Adam Nichols <adam@grimm-co.com>
+Reviewed-by: Lee Duncan <lduncan@suse.com>
+Reviewed-by: Mike Christie <michael.christie@oracle.com>
+Signed-off-by: Chris Leech <cleech@redhat.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/scsi/scsi_transport_iscsi.c |    9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/drivers/scsi/scsi_transport_iscsi.c
++++ b/drivers/scsi/scsi_transport_iscsi.c
+@@ -3627,6 +3627,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, s
+ {
+       int err = 0;
+       u32 portid;
++      u32 pdu_len;
+       struct iscsi_uevent *ev = nlmsg_data(nlh);
+       struct iscsi_transport *transport = NULL;
+       struct iscsi_internal *priv;
+@@ -3769,6 +3770,14 @@ iscsi_if_recv_msg(struct sk_buff *skb, s
+                       err = -EINVAL;
+               break;
+       case ISCSI_UEVENT_SEND_PDU:
++              pdu_len = nlh->nlmsg_len - sizeof(*nlh) - sizeof(*ev);
++
++              if ((ev->u.send_pdu.hdr_size > pdu_len) ||
++                  (ev->u.send_pdu.data_size > (pdu_len - ev->u.send_pdu.hdr_size))) {
++                      err = -EINVAL;
++                      break;
++              }
++
+               conn = iscsi_conn_lookup(ev->u.send_pdu.sid, ev->u.send_pdu.cid);
+               if (conn) {
+                       mutex_lock(&conn_mutex);
index c52b5b058371093b4f0b00b8cb4432b66cacc0bc..dcb00b5132271be2553b6cfb5991ff593baf2d5a 100644 (file)
@@ -80,3 +80,14 @@ asoc-intel-bytcr_rt5640-add-quirk-for-the-estar-beau.patch
 asoc-intel-bytcr_rt5640-add-quirk-for-the-voyo-winpa.patch
 asoc-intel-bytcr_rt5651-add-quirk-for-the-jumper-ezp.patch
 asoc-intel-bytcr_rt5640-add-quirk-for-the-acer-one-s.patch
+scsi-iscsi-restrict-sessions-and-handles-to-admin-capabilities.patch
+scsi-iscsi-ensure-sysfs-attributes-are-limited-to-page_size.patch
+scsi-iscsi-verify-lengths-on-passthrough-pdus.patch
+xen-gnttab-handle-p2m-update-errors-on-a-per-slot-basis.patch
+xen-netback-respect-gnttab_map_refs-s-return-value.patch
+xen-fix-p2m-size-in-dom0-for-disabled-memory-hotplug-case.patch
+zsmalloc-account-the-number-of-compacted-pages-correctly.patch
+remoteproc-mediatek-fix-kernel-test-robot-warning.patch
+swap-fix-swapfile-read-write-offset.patch
+powerpc-sstep-check-instruction-validity-against-isa-version-before-emulation.patch
+powerpc-sstep-fix-incorrect-return-from-analyze_instr.patch
diff --git a/queue-5.10/swap-fix-swapfile-read-write-offset.patch b/queue-5.10/swap-fix-swapfile-read-write-offset.patch
new file mode 100644 (file)
index 0000000..b2f7ba5
--- /dev/null
@@ -0,0 +1,69 @@
+From caf6912f3f4af7232340d500a4a2008f81b93f14 Mon Sep 17 00:00:00 2001
+From: Jens Axboe <axboe@kernel.dk>
+Date: Tue, 2 Mar 2021 14:53:21 -0700
+Subject: swap: fix swapfile read/write offset
+
+From: Jens Axboe <axboe@kernel.dk>
+
+commit caf6912f3f4af7232340d500a4a2008f81b93f14 upstream.
+
+We're not factoring in the start of the file for where to write and
+read the swapfile, which leads to very unfortunate side effects of
+writing where we should not be...
+
+Fixes: dd6bd0d9c7db ("swap: use bdev_read_page() / bdev_write_page()")
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Cc: Anthony Iliopoulos <ailiop@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/swap.h |    1 +
+ mm/page_io.c         |    5 -----
+ mm/swapfile.c        |   13 +++++++++++++
+ 3 files changed, 14 insertions(+), 5 deletions(-)
+
+--- a/include/linux/swap.h
++++ b/include/linux/swap.h
+@@ -484,6 +484,7 @@ struct backing_dev_info;
+ extern int init_swap_address_space(unsigned int type, unsigned long nr_pages);
+ extern void exit_swap_address_space(unsigned int type);
+ extern struct swap_info_struct *get_swap_device(swp_entry_t entry);
++sector_t swap_page_sector(struct page *page);
+ static inline void put_swap_device(struct swap_info_struct *si)
+ {
+--- a/mm/page_io.c
++++ b/mm/page_io.c
+@@ -273,11 +273,6 @@ out:
+       return ret;
+ }
+-static sector_t swap_page_sector(struct page *page)
+-{
+-      return (sector_t)__page_file_index(page) << (PAGE_SHIFT - 9);
+-}
+-
+ static inline void count_swpout_vm_event(struct page *page)
+ {
+ #ifdef CONFIG_TRANSPARENT_HUGEPAGE
+--- a/mm/swapfile.c
++++ b/mm/swapfile.c
+@@ -220,6 +220,19 @@ offset_to_swap_extent(struct swap_info_s
+       BUG();
+ }
++sector_t swap_page_sector(struct page *page)
++{
++      struct swap_info_struct *sis = page_swap_info(page);
++      struct swap_extent *se;
++      sector_t sector;
++      pgoff_t offset;
++
++      offset = __page_file_index(page);
++      se = offset_to_swap_extent(sis, offset);
++      sector = se->start_block + (offset - se->start_page);
++      return sector << (PAGE_SHIFT - 9);
++}
++
+ /*
+  * swap allocation tell device that a cluster of swap can now be discarded,
+  * to allow the swap device to optimize its wear-levelling.
diff --git a/queue-5.10/xen-fix-p2m-size-in-dom0-for-disabled-memory-hotplug-case.patch b/queue-5.10/xen-fix-p2m-size-in-dom0-for-disabled-memory-hotplug-case.patch
new file mode 100644 (file)
index 0000000..16df4ba
--- /dev/null
@@ -0,0 +1,135 @@
+From 882213990d32fd224340a4533f6318dd152be4b2 Mon Sep 17 00:00:00 2001
+From: Juergen Gross <jgross@suse.com>
+Date: Wed, 24 Feb 2021 16:03:08 +0100
+Subject: xen: fix p2m size in dom0 for disabled memory hotplug case
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Juergen Gross <jgross@suse.com>
+
+commit 882213990d32fd224340a4533f6318dd152be4b2 upstream.
+
+Since commit 9e2369c06c8a18 ("xen: add helpers to allocate unpopulated
+memory") foreign mappings are using guest physical addresses allocated
+via ZONE_DEVICE functionality.
+
+This will result in problems for the case of no balloon memory hotplug
+being configured, as the p2m list will only cover the initial memory
+size of the domain. Any ZONE_DEVICE allocated address will be outside
+the p2m range and thus a mapping can't be established with that memory
+address.
+
+Fix that by extending the p2m size for that case. At the same time add
+a check for a to be created mapping to be within the p2m limits in
+order to detect errors early.
+
+While changing a comment, remove some 32-bit leftovers.
+
+This is XSA-369.
+
+Fixes: 9e2369c06c8a18 ("xen: add helpers to allocate unpopulated memory")
+Cc: <stable@vger.kernel.org> # 5.9
+Reported-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
+Signed-off-by: Juergen Gross <jgross@suse.com>
+Reviewed-by: Jan Beulich <jbeulich@suse.com>
+Signed-off-by: Juergen Gross <jgross@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/include/asm/xen/page.h |   12 ++++++++++++
+ arch/x86/xen/p2m.c              |   10 ++++++----
+ arch/x86/xen/setup.c            |   25 +++----------------------
+ 3 files changed, 21 insertions(+), 26 deletions(-)
+
+--- a/arch/x86/include/asm/xen/page.h
++++ b/arch/x86/include/asm/xen/page.h
+@@ -87,6 +87,18 @@ clear_foreign_p2m_mapping(struct gnttab_
+ #endif
+ /*
++ * The maximum amount of extra memory compared to the base size.  The
++ * main scaling factor is the size of struct page.  At extreme ratios
++ * of base:extra, all the base memory can be filled with page
++ * structures for the extra memory, leaving no space for anything
++ * else.
++ *
++ * 10x seems like a reasonable balance between scaling flexibility and
++ * leaving a practically usable system.
++ */
++#define XEN_EXTRA_MEM_RATIO   (10)
++
++/*
+  * Helper functions to write or read unsigned long values to/from
+  * memory, when the access may fault.
+  */
+--- a/arch/x86/xen/p2m.c
++++ b/arch/x86/xen/p2m.c
+@@ -416,6 +416,9 @@ void __init xen_vmalloc_p2m_tree(void)
+       xen_p2m_last_pfn = xen_max_p2m_pfn;
+       p2m_limit = (phys_addr_t)P2M_LIMIT * 1024 * 1024 * 1024 / PAGE_SIZE;
++      if (!p2m_limit && IS_ENABLED(CONFIG_XEN_UNPOPULATED_ALLOC))
++              p2m_limit = xen_start_info->nr_pages * XEN_EXTRA_MEM_RATIO;
++
+       vm.flags = VM_ALLOC;
+       vm.size = ALIGN(sizeof(unsigned long) * max(xen_max_p2m_pfn, p2m_limit),
+                       PMD_SIZE * PMDS_PER_MID_PAGE);
+@@ -652,10 +655,9 @@ bool __set_phys_to_machine(unsigned long
+       pte_t *ptep;
+       unsigned int level;
+-      if (unlikely(pfn >= xen_p2m_size)) {
+-              BUG_ON(mfn != INVALID_P2M_ENTRY);
+-              return true;
+-      }
++      /* Only invalid entries allowed above the highest p2m covered frame. */
++      if (unlikely(pfn >= xen_p2m_size))
++              return mfn == INVALID_P2M_ENTRY;
+       /*
+        * The interface requires atomic updates on p2m elements.
+--- a/arch/x86/xen/setup.c
++++ b/arch/x86/xen/setup.c
+@@ -59,18 +59,6 @@ static struct {
+ } xen_remap_buf __initdata __aligned(PAGE_SIZE);
+ static unsigned long xen_remap_mfn __initdata = INVALID_P2M_ENTRY;
+-/* 
+- * The maximum amount of extra memory compared to the base size.  The
+- * main scaling factor is the size of struct page.  At extreme ratios
+- * of base:extra, all the base memory can be filled with page
+- * structures for the extra memory, leaving no space for anything
+- * else.
+- * 
+- * 10x seems like a reasonable balance between scaling flexibility and
+- * leaving a practically usable system.
+- */
+-#define EXTRA_MEM_RATIO               (10)
+-
+ static bool xen_512gb_limit __initdata = IS_ENABLED(CONFIG_XEN_512GB);
+ static void __init xen_parse_512gb(void)
+@@ -790,20 +778,13 @@ char * __init xen_memory_setup(void)
+               extra_pages += max_pages - max_pfn;
+       /*
+-       * Clamp the amount of extra memory to a EXTRA_MEM_RATIO
+-       * factor the base size.  On non-highmem systems, the base
+-       * size is the full initial memory allocation; on highmem it
+-       * is limited to the max size of lowmem, so that it doesn't
+-       * get completely filled.
++       * Clamp the amount of extra memory to a XEN_EXTRA_MEM_RATIO
++       * factor the base size.
+        *
+        * Make sure we have no memory above max_pages, as this area
+        * isn't handled by the p2m management.
+-       *
+-       * In principle there could be a problem in lowmem systems if
+-       * the initial memory is also very large with respect to
+-       * lowmem, but we won't try to deal with that here.
+        */
+-      extra_pages = min3(EXTRA_MEM_RATIO * min(max_pfn, PFN_DOWN(MAXMEM)),
++      extra_pages = min3(XEN_EXTRA_MEM_RATIO * min(max_pfn, PFN_DOWN(MAXMEM)),
+                          extra_pages, max_pages - max_pfn);
+       i = 0;
+       addr = xen_e820_table.entries[0].addr;
diff --git a/queue-5.10/xen-gnttab-handle-p2m-update-errors-on-a-per-slot-basis.patch b/queue-5.10/xen-gnttab-handle-p2m-update-errors-on-a-per-slot-basis.patch
new file mode 100644 (file)
index 0000000..c674e02
--- /dev/null
@@ -0,0 +1,143 @@
+From 8310b77b48c5558c140e7a57a702e7819e62f04e Mon Sep 17 00:00:00 2001
+From: Jan Beulich <jbeulich@suse.com>
+Date: Thu, 25 Feb 2021 16:34:43 +0100
+Subject: Xen/gnttab: handle p2m update errors on a per-slot basis
+
+From: Jan Beulich <jbeulich@suse.com>
+
+commit 8310b77b48c5558c140e7a57a702e7819e62f04e upstream.
+
+Bailing immediately from set_foreign_p2m_mapping() upon a p2m updating
+error leaves the full batch in an ambiguous state as far as the caller
+is concerned. Instead flags respective slots as bad, unmapping what
+was mapped there right away.
+
+HYPERVISOR_grant_table_op()'s return value and the individual unmap
+slots' status fields get used only for a one-time - there's not much we
+can do in case of a failure.
+
+Note that there's no GNTST_enomem or alike, so GNTST_general_error gets
+used.
+
+The map ops' handle fields get overwritten just to be on the safe side.
+
+This is part of XSA-367.
+
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Jan Beulich <jbeulich@suse.com>
+Reviewed-by: Juergen Gross <jgross@suse.com>
+Link: https://lore.kernel.org/r/96cccf5d-e756-5f53-b91a-ea269bfb9be0@suse.com
+Signed-off-by: Juergen Gross <jgross@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/arm/xen/p2m.c |   35 +++++++++++++++++++++++++++++++----
+ arch/x86/xen/p2m.c |   44 +++++++++++++++++++++++++++++++++++++++++---
+ 2 files changed, 72 insertions(+), 7 deletions(-)
+
+--- a/arch/arm/xen/p2m.c
++++ b/arch/arm/xen/p2m.c
+@@ -93,12 +93,39 @@ int set_foreign_p2m_mapping(struct gntta
+       int i;
+       for (i = 0; i < count; i++) {
++              struct gnttab_unmap_grant_ref unmap;
++              int rc;
++
+               if (map_ops[i].status)
+                       continue;
+-              if (unlikely(!set_phys_to_machine(map_ops[i].host_addr >> XEN_PAGE_SHIFT,
+-                                  map_ops[i].dev_bus_addr >> XEN_PAGE_SHIFT))) {
+-                      return -ENOMEM;
+-              }
++              if (likely(set_phys_to_machine(map_ops[i].host_addr >> XEN_PAGE_SHIFT,
++                                  map_ops[i].dev_bus_addr >> XEN_PAGE_SHIFT)))
++                      continue;
++
++              /*
++               * Signal an error for this slot. This in turn requires
++               * immediate unmapping.
++               */
++              map_ops[i].status = GNTST_general_error;
++              unmap.host_addr = map_ops[i].host_addr,
++              unmap.handle = map_ops[i].handle;
++              map_ops[i].handle = ~0;
++              if (map_ops[i].flags & GNTMAP_device_map)
++                      unmap.dev_bus_addr = map_ops[i].dev_bus_addr;
++              else
++                      unmap.dev_bus_addr = 0;
++
++              /*
++               * Pre-populate the status field, to be recognizable in
++               * the log message below.
++               */
++              unmap.status = 1;
++
++              rc = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref,
++                                             &unmap, 1);
++              if (rc || unmap.status != GNTST_okay)
++                      pr_err_once("gnttab unmap failed: rc=%d st=%d\n",
++                                  rc, unmap.status);
+       }
+       return 0;
+--- a/arch/x86/xen/p2m.c
++++ b/arch/x86/xen/p2m.c
+@@ -710,6 +710,8 @@ int set_foreign_p2m_mapping(struct gntta
+       for (i = 0; i < count; i++) {
+               unsigned long mfn, pfn;
++              struct gnttab_unmap_grant_ref unmap[2];
++              int rc;
+               /* Do not add to override if the map failed. */
+               if (map_ops[i].status != GNTST_okay ||
+@@ -727,10 +729,46 @@ int set_foreign_p2m_mapping(struct gntta
+               WARN(pfn_to_mfn(pfn) != INVALID_P2M_ENTRY, "page must be ballooned");
+-              if (unlikely(!set_phys_to_machine(pfn, FOREIGN_FRAME(mfn)))) {
+-                      ret = -ENOMEM;
+-                      goto out;
++              if (likely(set_phys_to_machine(pfn, FOREIGN_FRAME(mfn))))
++                      continue;
++
++              /*
++               * Signal an error for this slot. This in turn requires
++               * immediate unmapping.
++               */
++              map_ops[i].status = GNTST_general_error;
++              unmap[0].host_addr = map_ops[i].host_addr,
++              unmap[0].handle = map_ops[i].handle;
++              map_ops[i].handle = ~0;
++              if (map_ops[i].flags & GNTMAP_device_map)
++                      unmap[0].dev_bus_addr = map_ops[i].dev_bus_addr;
++              else
++                      unmap[0].dev_bus_addr = 0;
++
++              if (kmap_ops) {
++                      kmap_ops[i].status = GNTST_general_error;
++                      unmap[1].host_addr = kmap_ops[i].host_addr,
++                      unmap[1].handle = kmap_ops[i].handle;
++                      kmap_ops[i].handle = ~0;
++                      if (kmap_ops[i].flags & GNTMAP_device_map)
++                              unmap[1].dev_bus_addr = kmap_ops[i].dev_bus_addr;
++                      else
++                              unmap[1].dev_bus_addr = 0;
+               }
++
++              /*
++               * Pre-populate both status fields, to be recognizable in
++               * the log message below.
++               */
++              unmap[0].status = 1;
++              unmap[1].status = 1;
++
++              rc = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref,
++                                             unmap, 1 + !!kmap_ops);
++              if (rc || unmap[0].status != GNTST_okay ||
++                  unmap[1].status != GNTST_okay)
++                      pr_err_once("gnttab unmap failed: rc=%d st0=%d st1=%d\n",
++                                  rc, unmap[0].status, unmap[1].status);
+       }
+ out:
diff --git a/queue-5.10/xen-netback-respect-gnttab_map_refs-s-return-value.patch b/queue-5.10/xen-netback-respect-gnttab_map_refs-s-return-value.patch
new file mode 100644 (file)
index 0000000..2789cf3
--- /dev/null
@@ -0,0 +1,53 @@
+From 2991397d23ec597405b116d96de3813420bdcbc3 Mon Sep 17 00:00:00 2001
+From: Jan Beulich <jbeulich@suse.com>
+Date: Thu, 25 Feb 2021 16:35:15 +0100
+Subject: xen-netback: respect gnttab_map_refs()'s return value
+
+From: Jan Beulich <jbeulich@suse.com>
+
+commit 2991397d23ec597405b116d96de3813420bdcbc3 upstream.
+
+Commit 3194a1746e8a ("xen-netback: don't "handle" error by BUG()")
+dropped respective a BUG_ON() without noticing that with this the
+variable's value wouldn't be consumed anymore. With gnttab_set_map_op()
+setting all status fields to a non-zero value, in case of an error no
+slot should have a status of GNTST_okay (zero).
+
+This is part of XSA-367.
+
+Cc: <stable@vger.kernel.org>
+Reported-by: kernel test robot <lkp@intel.com>
+Signed-off-by: Jan Beulich <jbeulich@suse.com>
+Reviewed-by: Juergen Gross <jgross@suse.com>
+Link: https://lore.kernel.org/r/d933f495-619a-0086-5fb4-1ec3cf81a8fc@suse.com
+Signed-off-by: Juergen Gross <jgross@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/xen-netback/netback.c |   12 +++++++++++-
+ 1 file changed, 11 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/xen-netback/netback.c
++++ b/drivers/net/xen-netback/netback.c
+@@ -1342,11 +1342,21 @@ int xenvif_tx_action(struct xenvif_queue
+               return 0;
+       gnttab_batch_copy(queue->tx_copy_ops, nr_cops);
+-      if (nr_mops != 0)
++      if (nr_mops != 0) {
+               ret = gnttab_map_refs(queue->tx_map_ops,
+                                     NULL,
+                                     queue->pages_to_map,
+                                     nr_mops);
++              if (ret) {
++                      unsigned int i;
++
++                      netdev_err(queue->vif->dev, "Map fail: nr %u ret %d\n",
++                                 nr_mops, ret);
++                      for (i = 0; i < nr_mops; ++i)
++                              WARN_ON_ONCE(queue->tx_map_ops[i].status ==
++                                           GNTST_okay);
++              }
++      }
+       work_done = xenvif_tx_submit(queue);
diff --git a/queue-5.10/zsmalloc-account-the-number-of-compacted-pages-correctly.patch b/queue-5.10/zsmalloc-account-the-number-of-compacted-pages-correctly.patch
new file mode 100644 (file)
index 0000000..7fd3d68
--- /dev/null
@@ -0,0 +1,135 @@
+From 2395928158059b8f9858365fce7713ce7fef62e4 Mon Sep 17 00:00:00 2001
+From: Rokudo Yan <wu-yan@tcl.com>
+Date: Thu, 25 Feb 2021 17:18:31 -0800
+Subject: zsmalloc: account the number of compacted pages correctly
+
+From: Rokudo Yan <wu-yan@tcl.com>
+
+commit 2395928158059b8f9858365fce7713ce7fef62e4 upstream.
+
+There exists multiple path may do zram compaction concurrently.
+1. auto-compaction triggered during memory reclaim
+2. userspace utils write zram<id>/compaction node
+
+So, multiple threads may call zs_shrinker_scan/zs_compact concurrently.
+But pages_compacted is a per zsmalloc pool variable and modification
+of the variable is not serialized(through under class->lock).
+There are two issues here:
+1. the pages_compacted may not equal to total number of pages
+freed(due to concurrently add).
+2. zs_shrinker_scan may not return the correct number of pages
+freed(issued by current shrinker).
+
+The fix is simple:
+1. account the number of pages freed in zs_compact locally.
+2. use actomic variable pages_compacted to accumulate total number.
+
+Link: https://lkml.kernel.org/r/20210202122235.26885-1-wu-yan@tcl.com
+Fixes: 860c707dca155a56 ("zsmalloc: account the number of compacted pages")
+Signed-off-by: Rokudo Yan <wu-yan@tcl.com>
+Cc: Minchan Kim <minchan@kernel.org>
+Cc: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/block/zram/zram_drv.c |    2 +-
+ include/linux/zsmalloc.h      |    2 +-
+ mm/zsmalloc.c                 |   17 +++++++++++------
+ 3 files changed, 13 insertions(+), 8 deletions(-)
+
+--- a/drivers/block/zram/zram_drv.c
++++ b/drivers/block/zram/zram_drv.c
+@@ -1078,7 +1078,7 @@ static ssize_t mm_stat_show(struct devic
+                       zram->limit_pages << PAGE_SHIFT,
+                       max_used << PAGE_SHIFT,
+                       (u64)atomic64_read(&zram->stats.same_pages),
+-                      pool_stats.pages_compacted,
++                      atomic_long_read(&pool_stats.pages_compacted),
+                       (u64)atomic64_read(&zram->stats.huge_pages));
+       up_read(&zram->init_lock);
+--- a/include/linux/zsmalloc.h
++++ b/include/linux/zsmalloc.h
+@@ -35,7 +35,7 @@ enum zs_mapmode {
+ struct zs_pool_stats {
+       /* How many pages were migrated (freed) */
+-      unsigned long pages_compacted;
++      atomic_long_t pages_compacted;
+ };
+ struct zs_pool;
+--- a/mm/zsmalloc.c
++++ b/mm/zsmalloc.c
+@@ -2216,11 +2216,13 @@ static unsigned long zs_can_compact(stru
+       return obj_wasted * class->pages_per_zspage;
+ }
+-static void __zs_compact(struct zs_pool *pool, struct size_class *class)
++static unsigned long __zs_compact(struct zs_pool *pool,
++                                struct size_class *class)
+ {
+       struct zs_compact_control cc;
+       struct zspage *src_zspage;
+       struct zspage *dst_zspage = NULL;
++      unsigned long pages_freed = 0;
+       spin_lock(&class->lock);
+       while ((src_zspage = isolate_zspage(class, true))) {
+@@ -2250,7 +2252,7 @@ static void __zs_compact(struct zs_pool
+               putback_zspage(class, dst_zspage);
+               if (putback_zspage(class, src_zspage) == ZS_EMPTY) {
+                       free_zspage(pool, class, src_zspage);
+-                      pool->stats.pages_compacted += class->pages_per_zspage;
++                      pages_freed += class->pages_per_zspage;
+               }
+               spin_unlock(&class->lock);
+               cond_resched();
+@@ -2261,12 +2263,15 @@ static void __zs_compact(struct zs_pool
+               putback_zspage(class, src_zspage);
+       spin_unlock(&class->lock);
++
++      return pages_freed;
+ }
+ unsigned long zs_compact(struct zs_pool *pool)
+ {
+       int i;
+       struct size_class *class;
++      unsigned long pages_freed = 0;
+       for (i = ZS_SIZE_CLASSES - 1; i >= 0; i--) {
+               class = pool->size_class[i];
+@@ -2274,10 +2279,11 @@ unsigned long zs_compact(struct zs_pool
+                       continue;
+               if (class->index != i)
+                       continue;
+-              __zs_compact(pool, class);
++              pages_freed += __zs_compact(pool, class);
+       }
++      atomic_long_add(pages_freed, &pool->stats.pages_compacted);
+-      return pool->stats.pages_compacted;
++      return pages_freed;
+ }
+ EXPORT_SYMBOL_GPL(zs_compact);
+@@ -2294,13 +2300,12 @@ static unsigned long zs_shrinker_scan(st
+       struct zs_pool *pool = container_of(shrinker, struct zs_pool,
+                       shrinker);
+-      pages_freed = pool->stats.pages_compacted;
+       /*
+        * Compact classes and calculate compaction delta.
+        * Can run concurrently with a manually triggered
+        * (by user) compaction.
+        */
+-      pages_freed = zs_compact(pool) - pages_freed;
++      pages_freed = zs_compact(pool);
+       return pages_freed ? pages_freed : SHRINK_STOP;
+ }