mirror of
https://github.com/Fishwaldo/build.git
synced 2025-03-22 14:51:41 +00:00
8602 lines
266 KiB
Diff
8602 lines
266 KiB
Diff
|
diff --git a/Documentation/devicetree/bindings/clock/imx31-clock.txt b/Documentation/devicetree/bindings/clock/imx31-clock.txt
|
||
|
index 19df842c694f..8163d565f697 100644
|
||
|
--- a/Documentation/devicetree/bindings/clock/imx31-clock.txt
|
||
|
+++ b/Documentation/devicetree/bindings/clock/imx31-clock.txt
|
||
|
@@ -77,7 +77,7 @@ Examples:
|
||
|
clks: ccm@53f80000{
|
||
|
compatible = "fsl,imx31-ccm";
|
||
|
reg = <0x53f80000 0x4000>;
|
||
|
- interrupts = <0 31 0x04 0 53 0x04>;
|
||
|
+ interrupts = <31>, <53>;
|
||
|
#clock-cells = <1>;
|
||
|
};
|
||
|
|
||
|
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
|
||
|
index 98da831a14ba..daf83824fda5 100644
|
||
|
--- a/Documentation/kernel-parameters.txt
|
||
|
+++ b/Documentation/kernel-parameters.txt
|
||
|
@@ -955,6 +955,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
||
|
When zero, profiling data is discarded and associated
|
||
|
debugfs files are removed at module unload time.
|
||
|
|
||
|
+ goldfish [X86] Enable the goldfish android emulator platform.
|
||
|
+ Don't use this when you are not running on the
|
||
|
+ android emulator
|
||
|
+
|
||
|
gpt [EFI] Forces disk with valid GPT signature but
|
||
|
invalid Protective MBR to be treated as GPT.
|
||
|
|
||
|
diff --git a/Makefile b/Makefile
|
||
|
index 80e180e1e4a2..2f87f67fb9f7 100644
|
||
|
--- a/Makefile
|
||
|
+++ b/Makefile
|
||
|
@@ -1,6 +1,6 @@
|
||
|
VERSION = 3
|
||
|
PATCHLEVEL = 10
|
||
|
-SUBLEVEL = 105
|
||
|
+SUBLEVEL = 106
|
||
|
EXTRAVERSION = -bsp-1.2
|
||
|
NAME = TOSSUG Baby Fish
|
||
|
|
||
|
diff --git a/arch/arm/boot/dts/imx31.dtsi b/arch/arm/boot/dts/imx31.dtsi
|
||
|
index c5449257ad9a..b73190d08baa 100644
|
||
|
--- a/arch/arm/boot/dts/imx31.dtsi
|
||
|
+++ b/arch/arm/boot/dts/imx31.dtsi
|
||
|
@@ -20,11 +20,11 @@
|
||
|
serial4 = &uart5;
|
||
|
};
|
||
|
|
||
|
- avic: avic-interrupt-controller@60000000 {
|
||
|
+ avic: interrupt-controller@68000000 {
|
||
|
compatible = "fsl,imx31-avic", "fsl,avic";
|
||
|
interrupt-controller;
|
||
|
#interrupt-cells = <1>;
|
||
|
- reg = <0x60000000 0x100000>;
|
||
|
+ reg = <0x68000000 0x100000>;
|
||
|
};
|
||
|
|
||
|
soc {
|
||
|
@@ -93,13 +93,6 @@
|
||
|
clock-names = "ipg", "per";
|
||
|
status = "disabled";
|
||
|
};
|
||
|
-
|
||
|
- clks: ccm@53f80000{
|
||
|
- compatible = "fsl,imx31-ccm";
|
||
|
- reg = <0x53f80000 0x4000>;
|
||
|
- interrupts = <0 31 0x04 0 53 0x04>;
|
||
|
- #clock-cells = <1>;
|
||
|
- };
|
||
|
};
|
||
|
|
||
|
aips@53f00000 { /* AIPS2 */
|
||
|
@@ -109,6 +102,13 @@
|
||
|
reg = <0x53f00000 0x100000>;
|
||
|
ranges;
|
||
|
|
||
|
+ clks: ccm@53f80000{
|
||
|
+ compatible = "fsl,imx31-ccm";
|
||
|
+ reg = <0x53f80000 0x4000>;
|
||
|
+ interrupts = <31>, <53>;
|
||
|
+ #clock-cells = <1>;
|
||
|
+ };
|
||
|
+
|
||
|
gpt: timer@53f90000 {
|
||
|
compatible = "fsl,imx31-gpt";
|
||
|
reg = <0x53f90000 0x4000>;
|
||
|
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
|
||
|
index 4e2110d48c41..dfdd683d373e 100644
|
||
|
--- a/arch/arm/kernel/ptrace.c
|
||
|
+++ b/arch/arm/kernel/ptrace.c
|
||
|
@@ -600,7 +600,7 @@ static int gpr_set(struct task_struct *target,
|
||
|
const void *kbuf, const void __user *ubuf)
|
||
|
{
|
||
|
int ret;
|
||
|
- struct pt_regs newregs;
|
||
|
+ struct pt_regs newregs = *task_pt_regs(target);
|
||
|
|
||
|
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||
|
&newregs,
|
||
|
diff --git a/arch/arm/mach-ux500/pm.c b/arch/arm/mach-ux500/pm.c
|
||
|
index 1a468f0fd22e..9d532568b8b3 100644
|
||
|
--- a/arch/arm/mach-ux500/pm.c
|
||
|
+++ b/arch/arm/mach-ux500/pm.c
|
||
|
@@ -128,8 +128,8 @@ bool prcmu_pending_irq(void)
|
||
|
*/
|
||
|
bool prcmu_is_cpu_in_wfi(int cpu)
|
||
|
{
|
||
|
- return readl(PRCM_ARM_WFI_STANDBY) & cpu ? PRCM_ARM_WFI_STANDBY_WFI1 :
|
||
|
- PRCM_ARM_WFI_STANDBY_WFI0;
|
||
|
+ return readl(PRCM_ARM_WFI_STANDBY) &
|
||
|
+ (cpu ? PRCM_ARM_WFI_STANDBY_WFI1 : PRCM_ARM_WFI_STANDBY_WFI0);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h
|
||
|
index 6913643bbe54..c136fd53c847 100644
|
||
|
--- a/arch/arm64/include/uapi/asm/ptrace.h
|
||
|
+++ b/arch/arm64/include/uapi/asm/ptrace.h
|
||
|
@@ -75,6 +75,7 @@ struct user_fpsimd_state {
|
||
|
__uint128_t vregs[32];
|
||
|
__u32 fpsr;
|
||
|
__u32 fpcr;
|
||
|
+ __u32 __reserved[2];
|
||
|
};
|
||
|
|
||
|
struct user_hwdebug_state {
|
||
|
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
|
||
|
index dfad98fda4f8..015775ad7604 100644
|
||
|
--- a/arch/arm64/kernel/ptrace.c
|
||
|
+++ b/arch/arm64/kernel/ptrace.c
|
||
|
@@ -464,6 +464,8 @@ static int hw_break_set(struct task_struct *target,
|
||
|
/* (address, ctrl) registers */
|
||
|
limit = regset->n * regset->size;
|
||
|
while (count && offset < limit) {
|
||
|
+ if (count < PTRACE_HBP_ADDR_SZ)
|
||
|
+ return -EINVAL;
|
||
|
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &addr,
|
||
|
offset, offset + PTRACE_HBP_ADDR_SZ);
|
||
|
if (ret)
|
||
|
@@ -473,6 +475,8 @@ static int hw_break_set(struct task_struct *target,
|
||
|
return ret;
|
||
|
offset += PTRACE_HBP_ADDR_SZ;
|
||
|
|
||
|
+ if (!count)
|
||
|
+ break;
|
||
|
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &ctrl,
|
||
|
offset, offset + PTRACE_HBP_CTRL_SZ);
|
||
|
if (ret)
|
||
|
@@ -509,7 +513,7 @@ static int gpr_set(struct task_struct *target, const struct user_regset *regset,
|
||
|
const void *kbuf, const void __user *ubuf)
|
||
|
{
|
||
|
int ret;
|
||
|
- struct user_pt_regs newregs;
|
||
|
+ struct user_pt_regs newregs = task_pt_regs(target)->user_regs;
|
||
|
|
||
|
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newregs, 0, -1);
|
||
|
if (ret)
|
||
|
@@ -539,7 +543,8 @@ static int fpr_set(struct task_struct *target, const struct user_regset *regset,
|
||
|
const void *kbuf, const void __user *ubuf)
|
||
|
{
|
||
|
int ret;
|
||
|
- struct user_fpsimd_state newstate;
|
||
|
+ struct user_fpsimd_state newstate =
|
||
|
+ target->thread.fpsimd_state.user_fpsimd;
|
||
|
|
||
|
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newstate, 0, -1);
|
||
|
if (ret)
|
||
|
@@ -562,7 +567,7 @@ static int tls_set(struct task_struct *target, const struct user_regset *regset,
|
||
|
const void *kbuf, const void __user *ubuf)
|
||
|
{
|
||
|
int ret;
|
||
|
- unsigned long tls;
|
||
|
+ unsigned long tls = target->thread.tp_value;
|
||
|
|
||
|
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &tls, 0, -1);
|
||
|
if (ret)
|
||
|
diff --git a/arch/cris/boot/rescue/Makefile b/arch/cris/boot/rescue/Makefile
|
||
|
index 52bd0bd1dd22..d98edbb30a18 100644
|
||
|
--- a/arch/cris/boot/rescue/Makefile
|
||
|
+++ b/arch/cris/boot/rescue/Makefile
|
||
|
@@ -10,6 +10,9 @@
|
||
|
|
||
|
asflags-y += $(LINUXINCLUDE)
|
||
|
ccflags-y += -O2 $(LINUXINCLUDE)
|
||
|
+
|
||
|
+ifdef CONFIG_ETRAX_AXISFLASHMAP
|
||
|
+
|
||
|
arch-$(CONFIG_ETRAX_ARCH_V10) = v10
|
||
|
arch-$(CONFIG_ETRAX_ARCH_V32) = v32
|
||
|
|
||
|
@@ -28,6 +31,11 @@ $(obj)/rescue.bin: $(obj)/rescue.o FORCE
|
||
|
$(call if_changed,objcopy)
|
||
|
cp -p $(obj)/rescue.bin $(objtree)
|
||
|
|
||
|
+else
|
||
|
+$(obj)/rescue.bin:
|
||
|
+
|
||
|
+endif
|
||
|
+
|
||
|
$(obj)/testrescue.bin: $(obj)/testrescue.o
|
||
|
$(OBJCOPY) $(OBJCOPYFLAGS) $(obj)/testrescue.o tr.bin
|
||
|
# Pad it to 784 bytes
|
||
|
diff --git a/arch/m68k/include/asm/delay.h b/arch/m68k/include/asm/delay.h
|
||
|
index d28fa8fe26fe..c598d847d56b 100644
|
||
|
--- a/arch/m68k/include/asm/delay.h
|
||
|
+++ b/arch/m68k/include/asm/delay.h
|
||
|
@@ -114,6 +114,6 @@ static inline void __udelay(unsigned long usecs)
|
||
|
*/
|
||
|
#define HZSCALE (268435456 / (1000000 / HZ))
|
||
|
|
||
|
-#define ndelay(n) __delay(DIV_ROUND_UP((n) * ((((HZSCALE) >> 11) * (loops_per_jiffy >> 11)) >> 6), 1000));
|
||
|
+#define ndelay(n) __delay(DIV_ROUND_UP((n) * ((((HZSCALE) >> 11) * (loops_per_jiffy >> 11)) >> 6), 1000))
|
||
|
|
||
|
#endif /* defined(_M68K_DELAY_H) */
|
||
|
diff --git a/arch/metag/lib/usercopy.c b/arch/metag/lib/usercopy.c
|
||
|
index b3ebfe9c8e88..dfe77b26beaa 100644
|
||
|
--- a/arch/metag/lib/usercopy.c
|
||
|
+++ b/arch/metag/lib/usercopy.c
|
||
|
@@ -260,27 +260,31 @@
|
||
|
"MGETL D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \
|
||
|
"22:\n" \
|
||
|
"MSETL [%0++], D0FrT, D0.5, D0.6, D0.7\n" \
|
||
|
- "SUB %3, %3, #32\n" \
|
||
|
"23:\n" \
|
||
|
- "MGETL D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \
|
||
|
+ "SUB %3, %3, #32\n" \
|
||
|
"24:\n" \
|
||
|
+ "MGETL D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \
|
||
|
+ "25:\n" \
|
||
|
"MSETL [%0++], D0FrT, D0.5, D0.6, D0.7\n" \
|
||
|
+ "26:\n" \
|
||
|
"SUB %3, %3, #32\n" \
|
||
|
"DCACHE [%1+#-64], D0Ar6\n" \
|
||
|
"BR $Lloop"id"\n" \
|
||
|
\
|
||
|
"MOV RAPF, %1\n" \
|
||
|
- "25:\n" \
|
||
|
+ "27:\n" \
|
||
|
"MGETL D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \
|
||
|
- "26:\n" \
|
||
|
+ "28:\n" \
|
||
|
"MSETL [%0++], D0FrT, D0.5, D0.6, D0.7\n" \
|
||
|
+ "29:\n" \
|
||
|
"SUB %3, %3, #32\n" \
|
||
|
- "27:\n" \
|
||
|
+ "30:\n" \
|
||
|
"MGETL D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \
|
||
|
- "28:\n" \
|
||
|
+ "31:\n" \
|
||
|
"MSETL [%0++], D0FrT, D0.5, D0.6, D0.7\n" \
|
||
|
+ "32:\n" \
|
||
|
"SUB %0, %0, #8\n" \
|
||
|
- "29:\n" \
|
||
|
+ "33:\n" \
|
||
|
"SETL [%0++], D0.7, D1.7\n" \
|
||
|
"SUB %3, %3, #32\n" \
|
||
|
"1:" \
|
||
|
@@ -312,11 +316,15 @@
|
||
|
" .long 26b,3b\n" \
|
||
|
" .long 27b,3b\n" \
|
||
|
" .long 28b,3b\n" \
|
||
|
- " .long 29b,4b\n" \
|
||
|
+ " .long 29b,3b\n" \
|
||
|
+ " .long 30b,3b\n" \
|
||
|
+ " .long 31b,3b\n" \
|
||
|
+ " .long 32b,3b\n" \
|
||
|
+ " .long 33b,4b\n" \
|
||
|
" .previous\n" \
|
||
|
: "=r" (to), "=r" (from), "=r" (ret), "=d" (n) \
|
||
|
: "0" (to), "1" (from), "2" (ret), "3" (n) \
|
||
|
- : "D1Ar1", "D0Ar2", "memory")
|
||
|
+ : "D1Ar1", "D0Ar2", "cc", "memory")
|
||
|
|
||
|
/* rewind 'to' and 'from' pointers when a fault occurs
|
||
|
*
|
||
|
@@ -342,7 +350,7 @@
|
||
|
#define __asm_copy_to_user_64bit_rapf_loop(to, from, ret, n, id)\
|
||
|
__asm_copy_user_64bit_rapf_loop(to, from, ret, n, id, \
|
||
|
"LSR D0Ar2, D0Ar2, #8\n" \
|
||
|
- "AND D0Ar2, D0Ar2, #0x7\n" \
|
||
|
+ "ANDS D0Ar2, D0Ar2, #0x7\n" \
|
||
|
"ADDZ D0Ar2, D0Ar2, #4\n" \
|
||
|
"SUB D0Ar2, D0Ar2, #1\n" \
|
||
|
"MOV D1Ar1, #4\n" \
|
||
|
@@ -403,47 +411,55 @@
|
||
|
"MGETD D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \
|
||
|
"22:\n" \
|
||
|
"MSETD [%0++], D0FrT, D0.5, D0.6, D0.7\n" \
|
||
|
- "SUB %3, %3, #16\n" \
|
||
|
"23:\n" \
|
||
|
- "MGETD D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \
|
||
|
- "24:\n" \
|
||
|
- "MSETD [%0++], D0FrT, D0.5, D0.6, D0.7\n" \
|
||
|
"SUB %3, %3, #16\n" \
|
||
|
- "25:\n" \
|
||
|
+ "24:\n" \
|
||
|
"MGETD D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \
|
||
|
- "26:\n" \
|
||
|
+ "25:\n" \
|
||
|
"MSETD [%0++], D0FrT, D0.5, D0.6, D0.7\n" \
|
||
|
+ "26:\n" \
|
||
|
"SUB %3, %3, #16\n" \
|
||
|
"27:\n" \
|
||
|
"MGETD D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \
|
||
|
"28:\n" \
|
||
|
"MSETD [%0++], D0FrT, D0.5, D0.6, D0.7\n" \
|
||
|
+ "29:\n" \
|
||
|
+ "SUB %3, %3, #16\n" \
|
||
|
+ "30:\n" \
|
||
|
+ "MGETD D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \
|
||
|
+ "31:\n" \
|
||
|
+ "MSETD [%0++], D0FrT, D0.5, D0.6, D0.7\n" \
|
||
|
+ "32:\n" \
|
||
|
"SUB %3, %3, #16\n" \
|
||
|
"DCACHE [%1+#-64], D0Ar6\n" \
|
||
|
"BR $Lloop"id"\n" \
|
||
|
\
|
||
|
"MOV RAPF, %1\n" \
|
||
|
- "29:\n" \
|
||
|
+ "33:\n" \
|
||
|
"MGETD D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \
|
||
|
- "30:\n" \
|
||
|
+ "34:\n" \
|
||
|
"MSETD [%0++], D0FrT, D0.5, D0.6, D0.7\n" \
|
||
|
+ "35:\n" \
|
||
|
"SUB %3, %3, #16\n" \
|
||
|
- "31:\n" \
|
||
|
+ "36:\n" \
|
||
|
"MGETD D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \
|
||
|
- "32:\n" \
|
||
|
+ "37:\n" \
|
||
|
"MSETD [%0++], D0FrT, D0.5, D0.6, D0.7\n" \
|
||
|
+ "38:\n" \
|
||
|
"SUB %3, %3, #16\n" \
|
||
|
- "33:\n" \
|
||
|
+ "39:\n" \
|
||
|
"MGETD D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \
|
||
|
- "34:\n" \
|
||
|
+ "40:\n" \
|
||
|
"MSETD [%0++], D0FrT, D0.5, D0.6, D0.7\n" \
|
||
|
+ "41:\n" \
|
||
|
"SUB %3, %3, #16\n" \
|
||
|
- "35:\n" \
|
||
|
+ "42:\n" \
|
||
|
"MGETD D0FrT, D0.5, D0.6, D0.7, [%1++]\n" \
|
||
|
- "36:\n" \
|
||
|
+ "43:\n" \
|
||
|
"MSETD [%0++], D0FrT, D0.5, D0.6, D0.7\n" \
|
||
|
+ "44:\n" \
|
||
|
"SUB %0, %0, #4\n" \
|
||
|
- "37:\n" \
|
||
|
+ "45:\n" \
|
||
|
"SETD [%0++], D0.7\n" \
|
||
|
"SUB %3, %3, #16\n" \
|
||
|
"1:" \
|
||
|
@@ -483,11 +499,19 @@
|
||
|
" .long 34b,3b\n" \
|
||
|
" .long 35b,3b\n" \
|
||
|
" .long 36b,3b\n" \
|
||
|
- " .long 37b,4b\n" \
|
||
|
+ " .long 37b,3b\n" \
|
||
|
+ " .long 38b,3b\n" \
|
||
|
+ " .long 39b,3b\n" \
|
||
|
+ " .long 40b,3b\n" \
|
||
|
+ " .long 41b,3b\n" \
|
||
|
+ " .long 42b,3b\n" \
|
||
|
+ " .long 43b,3b\n" \
|
||
|
+ " .long 44b,3b\n" \
|
||
|
+ " .long 45b,4b\n" \
|
||
|
" .previous\n" \
|
||
|
: "=r" (to), "=r" (from), "=r" (ret), "=d" (n) \
|
||
|
: "0" (to), "1" (from), "2" (ret), "3" (n) \
|
||
|
- : "D1Ar1", "D0Ar2", "memory")
|
||
|
+ : "D1Ar1", "D0Ar2", "cc", "memory")
|
||
|
|
||
|
/* rewind 'to' and 'from' pointers when a fault occurs
|
||
|
*
|
||
|
@@ -513,7 +537,7 @@
|
||
|
#define __asm_copy_to_user_32bit_rapf_loop(to, from, ret, n, id)\
|
||
|
__asm_copy_user_32bit_rapf_loop(to, from, ret, n, id, \
|
||
|
"LSR D0Ar2, D0Ar2, #8\n" \
|
||
|
- "AND D0Ar2, D0Ar2, #0x7\n" \
|
||
|
+ "ANDS D0Ar2, D0Ar2, #0x7\n" \
|
||
|
"ADDZ D0Ar2, D0Ar2, #4\n" \
|
||
|
"SUB D0Ar2, D0Ar2, #1\n" \
|
||
|
"MOV D1Ar1, #4\n" \
|
||
|
@@ -538,23 +562,31 @@ unsigned long __copy_user(void __user *pdst, const void *psrc,
|
||
|
if ((unsigned long) src & 1) {
|
||
|
__asm_copy_to_user_1(dst, src, retn);
|
||
|
n--;
|
||
|
+ if (retn)
|
||
|
+ return retn + n;
|
||
|
}
|
||
|
if ((unsigned long) dst & 1) {
|
||
|
/* Worst case - byte copy */
|
||
|
while (n > 0) {
|
||
|
__asm_copy_to_user_1(dst, src, retn);
|
||
|
n--;
|
||
|
+ if (retn)
|
||
|
+ return retn + n;
|
||
|
}
|
||
|
}
|
||
|
if (((unsigned long) src & 2) && n >= 2) {
|
||
|
__asm_copy_to_user_2(dst, src, retn);
|
||
|
n -= 2;
|
||
|
+ if (retn)
|
||
|
+ return retn + n;
|
||
|
}
|
||
|
if ((unsigned long) dst & 2) {
|
||
|
/* Second worst case - word copy */
|
||
|
while (n >= 2) {
|
||
|
__asm_copy_to_user_2(dst, src, retn);
|
||
|
n -= 2;
|
||
|
+ if (retn)
|
||
|
+ return retn + n;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@@ -569,6 +601,8 @@ unsigned long __copy_user(void __user *pdst, const void *psrc,
|
||
|
while (n >= 8) {
|
||
|
__asm_copy_to_user_8x64(dst, src, retn);
|
||
|
n -= 8;
|
||
|
+ if (retn)
|
||
|
+ return retn + n;
|
||
|
}
|
||
|
}
|
||
|
if (n >= RAPF_MIN_BUF_SIZE) {
|
||
|
@@ -581,6 +615,8 @@ unsigned long __copy_user(void __user *pdst, const void *psrc,
|
||
|
while (n >= 8) {
|
||
|
__asm_copy_to_user_8x64(dst, src, retn);
|
||
|
n -= 8;
|
||
|
+ if (retn)
|
||
|
+ return retn + n;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
@@ -588,11 +624,15 @@ unsigned long __copy_user(void __user *pdst, const void *psrc,
|
||
|
while (n >= 16) {
|
||
|
__asm_copy_to_user_16(dst, src, retn);
|
||
|
n -= 16;
|
||
|
+ if (retn)
|
||
|
+ return retn + n;
|
||
|
}
|
||
|
|
||
|
while (n >= 4) {
|
||
|
__asm_copy_to_user_4(dst, src, retn);
|
||
|
n -= 4;
|
||
|
+ if (retn)
|
||
|
+ return retn + n;
|
||
|
}
|
||
|
|
||
|
switch (n) {
|
||
|
@@ -609,6 +649,10 @@ unsigned long __copy_user(void __user *pdst, const void *psrc,
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
+ /*
|
||
|
+ * If we get here, retn correctly reflects the number of failing
|
||
|
+ * bytes.
|
||
|
+ */
|
||
|
return retn;
|
||
|
}
|
||
|
EXPORT_SYMBOL(__copy_user);
|
||
|
@@ -789,29 +833,49 @@ EXPORT_SYMBOL(__copy_user);
|
||
|
*
|
||
|
* Rationale:
|
||
|
* A fault occurs while reading from user buffer, which is the
|
||
|
- * source. Since the fault is at a single address, we only
|
||
|
- * need to rewind by 8 bytes.
|
||
|
+ * source.
|
||
|
* Since we don't write to kernel buffer until we read first,
|
||
|
* the kernel buffer is at the right state and needn't be
|
||
|
- * corrected.
|
||
|
+ * corrected, but the source must be rewound to the beginning of
|
||
|
+ * the block, which is LSM_STEP*8 bytes.
|
||
|
+ * LSM_STEP is bits 10:8 in TXSTATUS which is already read
|
||
|
+ * and stored in D0Ar2
|
||
|
+ *
|
||
|
+ * NOTE: If a fault occurs at the last operation in M{G,S}ETL
|
||
|
+ * LSM_STEP will be 0. ie: we do 4 writes in our case, if
|
||
|
+ * a fault happens at the 4th write, LSM_STEP will be 0
|
||
|
+ * instead of 4. The code copes with that.
|
||
|
*/
|
||
|
#define __asm_copy_from_user_64bit_rapf_loop(to, from, ret, n, id) \
|
||
|
__asm_copy_user_64bit_rapf_loop(to, from, ret, n, id, \
|
||
|
- "SUB %1, %1, #8\n")
|
||
|
+ "LSR D0Ar2, D0Ar2, #5\n" \
|
||
|
+ "ANDS D0Ar2, D0Ar2, #0x38\n" \
|
||
|
+ "ADDZ D0Ar2, D0Ar2, #32\n" \
|
||
|
+ "SUB %1, %1, D0Ar2\n")
|
||
|
|
||
|
/* rewind 'from' pointer when a fault occurs
|
||
|
*
|
||
|
* Rationale:
|
||
|
* A fault occurs while reading from user buffer, which is the
|
||
|
- * source. Since the fault is at a single address, we only
|
||
|
- * need to rewind by 4 bytes.
|
||
|
+ * source.
|
||
|
* Since we don't write to kernel buffer until we read first,
|
||
|
* the kernel buffer is at the right state and needn't be
|
||
|
- * corrected.
|
||
|
+ * corrected, but the source must be rewound to the beginning of
|
||
|
+ * the block, which is LSM_STEP*4 bytes.
|
||
|
+ * LSM_STEP is bits 10:8 in TXSTATUS which is already read
|
||
|
+ * and stored in D0Ar2
|
||
|
+ *
|
||
|
+ * NOTE: If a fault occurs at the last operation in M{G,S}ETL
|
||
|
+ * LSM_STEP will be 0. ie: we do 4 writes in our case, if
|
||
|
+ * a fault happens at the 4th write, LSM_STEP will be 0
|
||
|
+ * instead of 4. The code copes with that.
|
||
|
*/
|
||
|
#define __asm_copy_from_user_32bit_rapf_loop(to, from, ret, n, id) \
|
||
|
__asm_copy_user_32bit_rapf_loop(to, from, ret, n, id, \
|
||
|
- "SUB %1, %1, #4\n")
|
||
|
+ "LSR D0Ar2, D0Ar2, #6\n" \
|
||
|
+ "ANDS D0Ar2, D0Ar2, #0x1c\n" \
|
||
|
+ "ADDZ D0Ar2, D0Ar2, #16\n" \
|
||
|
+ "SUB %1, %1, D0Ar2\n")
|
||
|
|
||
|
|
||
|
/* Copy from user to kernel, zeroing the bytes that were inaccessible in
|
||
|
@@ -830,6 +894,8 @@ unsigned long __copy_user_zeroing(void *pdst, const void __user *psrc,
|
||
|
if ((unsigned long) src & 1) {
|
||
|
__asm_copy_from_user_1(dst, src, retn);
|
||
|
n--;
|
||
|
+ if (retn)
|
||
|
+ goto copy_exception_bytes;
|
||
|
}
|
||
|
if ((unsigned long) dst & 1) {
|
||
|
/* Worst case - byte copy */
|
||
|
@@ -843,6 +909,8 @@ unsigned long __copy_user_zeroing(void *pdst, const void __user *psrc,
|
||
|
if (((unsigned long) src & 2) && n >= 2) {
|
||
|
__asm_copy_from_user_2(dst, src, retn);
|
||
|
n -= 2;
|
||
|
+ if (retn)
|
||
|
+ goto copy_exception_bytes;
|
||
|
}
|
||
|
if ((unsigned long) dst & 2) {
|
||
|
/* Second worst case - word copy */
|
||
|
@@ -854,12 +922,6 @@ unsigned long __copy_user_zeroing(void *pdst, const void __user *psrc,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- /* We only need one check after the unalignment-adjustments,
|
||
|
- because if both adjustments were done, either both or
|
||
|
- neither reference had an exception. */
|
||
|
- if (retn != 0)
|
||
|
- goto copy_exception_bytes;
|
||
|
-
|
||
|
#ifdef USE_RAPF
|
||
|
/* 64 bit copy loop */
|
||
|
if (!(((unsigned long) src | (unsigned long) dst) & 7)) {
|
||
|
diff --git a/arch/mips/cavium-octeon/octeon-memcpy.S b/arch/mips/cavium-octeon/octeon-memcpy.S
|
||
|
index 64e08df51d65..8b7004132491 100644
|
||
|
--- a/arch/mips/cavium-octeon/octeon-memcpy.S
|
||
|
+++ b/arch/mips/cavium-octeon/octeon-memcpy.S
|
||
|
@@ -208,18 +208,18 @@ EXC( STORE t2, UNIT(6)(dst), s_exc_p10u)
|
||
|
ADD src, src, 16*NBYTES
|
||
|
EXC( STORE t3, UNIT(7)(dst), s_exc_p9u)
|
||
|
ADD dst, dst, 16*NBYTES
|
||
|
-EXC( LOAD t0, UNIT(-8)(src), l_exc_copy)
|
||
|
-EXC( LOAD t1, UNIT(-7)(src), l_exc_copy)
|
||
|
-EXC( LOAD t2, UNIT(-6)(src), l_exc_copy)
|
||
|
-EXC( LOAD t3, UNIT(-5)(src), l_exc_copy)
|
||
|
+EXC( LOAD t0, UNIT(-8)(src), l_exc_copy_rewind16)
|
||
|
+EXC( LOAD t1, UNIT(-7)(src), l_exc_copy_rewind16)
|
||
|
+EXC( LOAD t2, UNIT(-6)(src), l_exc_copy_rewind16)
|
||
|
+EXC( LOAD t3, UNIT(-5)(src), l_exc_copy_rewind16)
|
||
|
EXC( STORE t0, UNIT(-8)(dst), s_exc_p8u)
|
||
|
EXC( STORE t1, UNIT(-7)(dst), s_exc_p7u)
|
||
|
EXC( STORE t2, UNIT(-6)(dst), s_exc_p6u)
|
||
|
EXC( STORE t3, UNIT(-5)(dst), s_exc_p5u)
|
||
|
-EXC( LOAD t0, UNIT(-4)(src), l_exc_copy)
|
||
|
-EXC( LOAD t1, UNIT(-3)(src), l_exc_copy)
|
||
|
-EXC( LOAD t2, UNIT(-2)(src), l_exc_copy)
|
||
|
-EXC( LOAD t3, UNIT(-1)(src), l_exc_copy)
|
||
|
+EXC( LOAD t0, UNIT(-4)(src), l_exc_copy_rewind16)
|
||
|
+EXC( LOAD t1, UNIT(-3)(src), l_exc_copy_rewind16)
|
||
|
+EXC( LOAD t2, UNIT(-2)(src), l_exc_copy_rewind16)
|
||
|
+EXC( LOAD t3, UNIT(-1)(src), l_exc_copy_rewind16)
|
||
|
EXC( STORE t0, UNIT(-4)(dst), s_exc_p4u)
|
||
|
EXC( STORE t1, UNIT(-3)(dst), s_exc_p3u)
|
||
|
EXC( STORE t2, UNIT(-2)(dst), s_exc_p2u)
|
||
|
@@ -383,6 +383,10 @@ done:
|
||
|
nop
|
||
|
END(memcpy)
|
||
|
|
||
|
+l_exc_copy_rewind16:
|
||
|
+ /* Rewind src and dst by 16*NBYTES for l_exc_copy */
|
||
|
+ SUB src, src, 16*NBYTES
|
||
|
+ SUB dst, dst, 16*NBYTES
|
||
|
l_exc_copy:
|
||
|
/*
|
||
|
* Copy bytes from src until faulting load address (or until a
|
||
|
diff --git a/arch/mips/configs/ip27_defconfig b/arch/mips/configs/ip27_defconfig
|
||
|
index 0e36abcd39cc..7446284dd7b3 100644
|
||
|
--- a/arch/mips/configs/ip27_defconfig
|
||
|
+++ b/arch/mips/configs/ip27_defconfig
|
||
|
@@ -206,7 +206,6 @@ CONFIG_MLX4_EN=m
|
||
|
# CONFIG_MLX4_DEBUG is not set
|
||
|
CONFIG_TEHUTI=m
|
||
|
CONFIG_BNX2X=m
|
||
|
-CONFIG_QLGE=m
|
||
|
CONFIG_SFC=m
|
||
|
CONFIG_BE2NET=m
|
||
|
CONFIG_LIBERTAS_THINFIRM=m
|
||
|
diff --git a/arch/mips/kernel/kgdb.c b/arch/mips/kernel/kgdb.c
|
||
|
index fcaac2f132f0..910db386d9ef 100644
|
||
|
--- a/arch/mips/kernel/kgdb.c
|
||
|
+++ b/arch/mips/kernel/kgdb.c
|
||
|
@@ -236,9 +236,6 @@ static int compute_signal(int tt)
|
||
|
void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
|
||
|
{
|
||
|
int reg;
|
||
|
- struct thread_info *ti = task_thread_info(p);
|
||
|
- unsigned long ksp = (unsigned long)ti + THREAD_SIZE - 32;
|
||
|
- struct pt_regs *regs = (struct pt_regs *)ksp - 1;
|
||
|
#if (KGDB_GDB_REG_SIZE == 32)
|
||
|
u32 *ptr = (u32 *)gdb_regs;
|
||
|
#else
|
||
|
@@ -246,25 +243,46 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
|
||
|
#endif
|
||
|
|
||
|
for (reg = 0; reg < 16; reg++)
|
||
|
- *(ptr++) = regs->regs[reg];
|
||
|
+ *(ptr++) = 0;
|
||
|
|
||
|
/* S0 - S7 */
|
||
|
- for (reg = 16; reg < 24; reg++)
|
||
|
- *(ptr++) = regs->regs[reg];
|
||
|
+ *(ptr++) = p->thread.reg16;
|
||
|
+ *(ptr++) = p->thread.reg17;
|
||
|
+ *(ptr++) = p->thread.reg18;
|
||
|
+ *(ptr++) = p->thread.reg19;
|
||
|
+ *(ptr++) = p->thread.reg20;
|
||
|
+ *(ptr++) = p->thread.reg21;
|
||
|
+ *(ptr++) = p->thread.reg22;
|
||
|
+ *(ptr++) = p->thread.reg23;
|
||
|
|
||
|
for (reg = 24; reg < 28; reg++)
|
||
|
*(ptr++) = 0;
|
||
|
|
||
|
/* GP, SP, FP, RA */
|
||
|
- for (reg = 28; reg < 32; reg++)
|
||
|
- *(ptr++) = regs->regs[reg];
|
||
|
-
|
||
|
- *(ptr++) = regs->cp0_status;
|
||
|
- *(ptr++) = regs->lo;
|
||
|
- *(ptr++) = regs->hi;
|
||
|
- *(ptr++) = regs->cp0_badvaddr;
|
||
|
- *(ptr++) = regs->cp0_cause;
|
||
|
- *(ptr++) = regs->cp0_epc;
|
||
|
+ *(ptr++) = (long)p;
|
||
|
+ *(ptr++) = p->thread.reg29;
|
||
|
+ *(ptr++) = p->thread.reg30;
|
||
|
+ *(ptr++) = p->thread.reg31;
|
||
|
+
|
||
|
+ *(ptr++) = p->thread.cp0_status;
|
||
|
+
|
||
|
+ /* lo, hi */
|
||
|
+ *(ptr++) = 0;
|
||
|
+ *(ptr++) = 0;
|
||
|
+
|
||
|
+ /*
|
||
|
+ * BadVAddr, Cause
|
||
|
+ * Ideally these would come from the last exception frame up the stack
|
||
|
+ * but that requires unwinding, otherwise we can't know much for sure.
|
||
|
+ */
|
||
|
+ *(ptr++) = 0;
|
||
|
+ *(ptr++) = 0;
|
||
|
+
|
||
|
+ /*
|
||
|
+ * PC
|
||
|
+ * use return address (RA), i.e. the moment after return from resume()
|
||
|
+ */
|
||
|
+ *(ptr++) = p->thread.reg31;
|
||
|
}
|
||
|
|
||
|
void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
|
||
|
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
|
||
|
index c6a041d9d05d..3cfa3bc288fd 100644
|
||
|
--- a/arch/mips/kernel/process.c
|
||
|
+++ b/arch/mips/kernel/process.c
|
||
|
@@ -214,11 +214,9 @@ struct mips_frame_info {
|
||
|
#define J_TARGET(pc,target) \
|
||
|
(((unsigned long)(pc) & 0xf0000000) | ((target) << 2))
|
||
|
|
||
|
-static inline int is_ra_save_ins(union mips_instruction *ip)
|
||
|
+static inline int is_ra_save_ins(union mips_instruction *ip, int *poff)
|
||
|
{
|
||
|
#ifdef CONFIG_CPU_MICROMIPS
|
||
|
- union mips_instruction mmi;
|
||
|
-
|
||
|
/*
|
||
|
* swsp ra,offset
|
||
|
* swm16 reglist,offset(sp)
|
||
|
@@ -228,29 +226,71 @@ static inline int is_ra_save_ins(union mips_instruction *ip)
|
||
|
*
|
||
|
* microMIPS is way more fun...
|
||
|
*/
|
||
|
- if (mm_insn_16bit(ip->halfword[0])) {
|
||
|
- mmi.word = (ip->halfword[0] << 16);
|
||
|
- return ((mmi.mm16_r5_format.opcode == mm_swsp16_op &&
|
||
|
- mmi.mm16_r5_format.rt == 31) ||
|
||
|
- (mmi.mm16_m_format.opcode == mm_pool16c_op &&
|
||
|
- mmi.mm16_m_format.func == mm_swm16_op));
|
||
|
+ if (mm_insn_16bit(ip->halfword[1])) {
|
||
|
+ switch (ip->mm16_r5_format.opcode) {
|
||
|
+ case mm_swsp16_op:
|
||
|
+ if (ip->mm16_r5_format.rt != 31)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ *poff = ip->mm16_r5_format.simmediate;
|
||
|
+ *poff = (*poff << 2) / sizeof(ulong);
|
||
|
+ return 1;
|
||
|
+
|
||
|
+ case mm_pool16c_op:
|
||
|
+ switch (ip->mm16_m_format.func) {
|
||
|
+ case mm_swm16_op:
|
||
|
+ *poff = ip->mm16_m_format.imm;
|
||
|
+ *poff += 1 + ip->mm16_m_format.rlist;
|
||
|
+ *poff = (*poff << 2) / sizeof(ulong);
|
||
|
+ return 1;
|
||
|
+
|
||
|
+ default:
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ default:
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
}
|
||
|
- else {
|
||
|
- mmi.halfword[0] = ip->halfword[1];
|
||
|
- mmi.halfword[1] = ip->halfword[0];
|
||
|
- return ((mmi.mm_m_format.opcode == mm_pool32b_op &&
|
||
|
- mmi.mm_m_format.rd > 9 &&
|
||
|
- mmi.mm_m_format.base == 29 &&
|
||
|
- mmi.mm_m_format.func == mm_swm32_func) ||
|
||
|
- (mmi.i_format.opcode == mm_sw32_op &&
|
||
|
- mmi.i_format.rs == 29 &&
|
||
|
- mmi.i_format.rt == 31));
|
||
|
+
|
||
|
+ switch (ip->i_format.opcode) {
|
||
|
+ case mm_sw32_op:
|
||
|
+ if (ip->i_format.rs != 29)
|
||
|
+ return 0;
|
||
|
+ if (ip->i_format.rt != 31)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ *poff = ip->i_format.simmediate / sizeof(ulong);
|
||
|
+ return 1;
|
||
|
+
|
||
|
+ case mm_pool32b_op:
|
||
|
+ switch (ip->mm_m_format.func) {
|
||
|
+ case mm_swm32_func:
|
||
|
+ if (ip->mm_m_format.rd < 0x10)
|
||
|
+ return 0;
|
||
|
+ if (ip->mm_m_format.base != 29)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ *poff = ip->mm_m_format.simmediate;
|
||
|
+ *poff += (ip->mm_m_format.rd & 0xf) * sizeof(u32);
|
||
|
+ *poff /= sizeof(ulong);
|
||
|
+ return 1;
|
||
|
+ default:
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ default:
|
||
|
+ return 0;
|
||
|
}
|
||
|
#else
|
||
|
/* sw / sd $ra, offset($sp) */
|
||
|
- return (ip->i_format.opcode == sw_op || ip->i_format.opcode == sd_op) &&
|
||
|
- ip->i_format.rs == 29 &&
|
||
|
- ip->i_format.rt == 31;
|
||
|
+ if ((ip->i_format.opcode == sw_op || ip->i_format.opcode == sd_op) &&
|
||
|
+ ip->i_format.rs == 29 && ip->i_format.rt == 31) {
|
||
|
+ *poff = ip->i_format.simmediate / sizeof(ulong);
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+
|
||
|
+ return 0;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
@@ -265,13 +305,16 @@ static inline int is_jump_ins(union mips_instruction *ip)
|
||
|
*
|
||
|
* microMIPS is kind of more fun...
|
||
|
*/
|
||
|
- union mips_instruction mmi;
|
||
|
-
|
||
|
- mmi.word = (ip->halfword[0] << 16);
|
||
|
+ if (mm_insn_16bit(ip->halfword[1])) {
|
||
|
+ if ((ip->mm16_r5_format.opcode == mm_pool16c_op &&
|
||
|
+ (ip->mm16_r5_format.rt & mm_jr16_op) == mm_jr16_op))
|
||
|
+ return 1;
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
|
||
|
- if ((mmi.mm16_r5_format.opcode == mm_pool16c_op &&
|
||
|
- (mmi.mm16_r5_format.rt & mm_jr16_op) == mm_jr16_op) ||
|
||
|
- ip->j_format.opcode == mm_jal32_op)
|
||
|
+ if (ip->j_format.opcode == mm_j32_op)
|
||
|
+ return 1;
|
||
|
+ if (ip->j_format.opcode == mm_jal32_op)
|
||
|
return 1;
|
||
|
if (ip->r_format.opcode != mm_pool32a_op ||
|
||
|
ip->r_format.func != mm_pool32axf_op)
|
||
|
@@ -299,15 +342,13 @@ static inline int is_sp_move_ins(union mips_instruction *ip)
|
||
|
*
|
||
|
* microMIPS is not more fun...
|
||
|
*/
|
||
|
- if (mm_insn_16bit(ip->halfword[0])) {
|
||
|
- union mips_instruction mmi;
|
||
|
-
|
||
|
- mmi.word = (ip->halfword[0] << 16);
|
||
|
- return ((mmi.mm16_r3_format.opcode == mm_pool16d_op &&
|
||
|
- mmi.mm16_r3_format.simmediate && mm_addiusp_func) ||
|
||
|
- (mmi.mm16_r5_format.opcode == mm_pool16d_op &&
|
||
|
- mmi.mm16_r5_format.rt == 29));
|
||
|
+ if (mm_insn_16bit(ip->halfword[1])) {
|
||
|
+ return (ip->mm16_r3_format.opcode == mm_pool16d_op &&
|
||
|
+ ip->mm16_r3_format.simmediate && mm_addiusp_func) ||
|
||
|
+ (ip->mm16_r5_format.opcode == mm_pool16d_op &&
|
||
|
+ ip->mm16_r5_format.rt == 29);
|
||
|
}
|
||
|
+
|
||
|
return (ip->mm_i_format.opcode == mm_addiu32_op &&
|
||
|
ip->mm_i_format.rt == 29 && ip->mm_i_format.rs == 29);
|
||
|
#else
|
||
|
@@ -322,30 +363,36 @@ static inline int is_sp_move_ins(union mips_instruction *ip)
|
||
|
|
||
|
static int get_frame_info(struct mips_frame_info *info)
|
||
|
{
|
||
|
-#ifdef CONFIG_CPU_MICROMIPS
|
||
|
- union mips_instruction *ip = (void *) (((char *) info->func) - 1);
|
||
|
-#else
|
||
|
- union mips_instruction *ip = info->func;
|
||
|
-#endif
|
||
|
- unsigned max_insns = info->func_size / sizeof(union mips_instruction);
|
||
|
- unsigned i;
|
||
|
+ bool is_mmips = IS_ENABLED(CONFIG_CPU_MICROMIPS);
|
||
|
+ union mips_instruction insn, *ip, *ip_end;
|
||
|
+ const unsigned int max_insns = 128;
|
||
|
+ unsigned int i;
|
||
|
|
||
|
info->pc_offset = -1;
|
||
|
info->frame_size = 0;
|
||
|
|
||
|
+ ip = (void *)msk_isa16_mode((ulong)info->func);
|
||
|
if (!ip)
|
||
|
goto err;
|
||
|
|
||
|
- if (max_insns == 0)
|
||
|
- max_insns = 128U; /* unknown function size */
|
||
|
- max_insns = min(128U, max_insns);
|
||
|
-
|
||
|
- for (i = 0; i < max_insns; i++, ip++) {
|
||
|
+ ip_end = (void *)ip + info->func_size;
|
||
|
+
|
||
|
+ for (i = 0; i < max_insns && ip < ip_end; i++, ip++) {
|
||
|
+ if (is_mmips && mm_insn_16bit(ip->halfword[0])) {
|
||
|
+ insn.halfword[0] = 0;
|
||
|
+ insn.halfword[1] = ip->halfword[0];
|
||
|
+ } else if (is_mmips) {
|
||
|
+ insn.halfword[0] = ip->halfword[1];
|
||
|
+ insn.halfword[1] = ip->halfword[0];
|
||
|
+ } else {
|
||
|
+ insn.word = ip->word;
|
||
|
+ }
|
||
|
|
||
|
- if (is_jump_ins(ip))
|
||
|
+ if (is_jump_ins(&insn))
|
||
|
break;
|
||
|
+
|
||
|
if (!info->frame_size) {
|
||
|
- if (is_sp_move_ins(ip))
|
||
|
+ if (is_sp_move_ins(&insn))
|
||
|
{
|
||
|
#ifdef CONFIG_CPU_MICROMIPS
|
||
|
if (mm_insn_16bit(ip->halfword[0]))
|
||
|
@@ -368,11 +415,9 @@ static int get_frame_info(struct mips_frame_info *info)
|
||
|
}
|
||
|
continue;
|
||
|
}
|
||
|
- if (info->pc_offset == -1 && is_ra_save_ins(ip)) {
|
||
|
- info->pc_offset =
|
||
|
- ip->i_format.simmediate / sizeof(long);
|
||
|
+ if (info->pc_offset == -1 &&
|
||
|
+ is_ra_save_ins(&insn, &info->pc_offset))
|
||
|
break;
|
||
|
- }
|
||
|
}
|
||
|
if (info->frame_size && info->pc_offset >= 0) /* nested */
|
||
|
return 0;
|
||
|
diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c
|
||
|
index 8220baa46faf..a1812fbc2648 100644
|
||
|
--- a/arch/powerpc/kernel/ibmebus.c
|
||
|
+++ b/arch/powerpc/kernel/ibmebus.c
|
||
|
@@ -180,6 +180,7 @@ static int ibmebus_create_device(struct device_node *dn)
|
||
|
static int ibmebus_create_devices(const struct of_device_id *matches)
|
||
|
{
|
||
|
struct device_node *root, *child;
|
||
|
+ struct device *dev;
|
||
|
int ret = 0;
|
||
|
|
||
|
root = of_find_node_by_path("/");
|
||
|
@@ -188,9 +189,12 @@ static int ibmebus_create_devices(const struct of_device_id *matches)
|
||
|
if (!of_match_node(matches, child))
|
||
|
continue;
|
||
|
|
||
|
- if (bus_find_device(&ibmebus_bus_type, NULL, child,
|
||
|
- ibmebus_match_node))
|
||
|
+ dev = bus_find_device(&ibmebus_bus_type, NULL, child,
|
||
|
+ ibmebus_match_node);
|
||
|
+ if (dev) {
|
||
|
+ put_device(dev);
|
||
|
continue;
|
||
|
+ }
|
||
|
|
||
|
ret = ibmebus_create_device(child);
|
||
|
if (ret) {
|
||
|
@@ -262,6 +266,7 @@ static ssize_t ibmebus_store_probe(struct bus_type *bus,
|
||
|
const char *buf, size_t count)
|
||
|
{
|
||
|
struct device_node *dn = NULL;
|
||
|
+ struct device *dev;
|
||
|
char *path;
|
||
|
ssize_t rc = 0;
|
||
|
|
||
|
@@ -269,8 +274,10 @@ static ssize_t ibmebus_store_probe(struct bus_type *bus,
|
||
|
if (!path)
|
||
|
return -ENOMEM;
|
||
|
|
||
|
- if (bus_find_device(&ibmebus_bus_type, NULL, path,
|
||
|
- ibmebus_match_path)) {
|
||
|
+ dev = bus_find_device(&ibmebus_bus_type, NULL, path,
|
||
|
+ ibmebus_match_path);
|
||
|
+ if (dev) {
|
||
|
+ put_device(dev);
|
||
|
printk(KERN_WARNING "%s: %s has already been probed\n",
|
||
|
__func__, path);
|
||
|
rc = -EEXIST;
|
||
|
@@ -306,6 +313,7 @@ static ssize_t ibmebus_store_remove(struct bus_type *bus,
|
||
|
if ((dev = bus_find_device(&ibmebus_bus_type, NULL, path,
|
||
|
ibmebus_match_path))) {
|
||
|
of_device_unregister(to_platform_device(dev));
|
||
|
+ put_device(dev);
|
||
|
|
||
|
kfree(path);
|
||
|
return count;
|
||
|
diff --git a/arch/powerpc/kernel/idle_power7.S b/arch/powerpc/kernel/idle_power7.S
|
||
|
index e11863f4e595..ccef1728a4c9 100644
|
||
|
--- a/arch/powerpc/kernel/idle_power7.S
|
||
|
+++ b/arch/powerpc/kernel/idle_power7.S
|
||
|
@@ -94,7 +94,7 @@ _GLOBAL(power7_nap)
|
||
|
std r0,0(r1)
|
||
|
ptesync
|
||
|
ld r0,0(r1)
|
||
|
-1: cmp cr0,r0,r0
|
||
|
+1: cmpd cr0,r0,r0
|
||
|
bne 1b
|
||
|
PPC_NAP
|
||
|
b .
|
||
|
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
|
||
|
index e469f30e6eeb..ad8573f053d5 100644
|
||
|
--- a/arch/powerpc/kernel/misc_32.S
|
||
|
+++ b/arch/powerpc/kernel/misc_32.S
|
||
|
@@ -295,7 +295,7 @@ _GLOBAL(flush_instruction_cache)
|
||
|
lis r3, KERNELBASE@h
|
||
|
iccci 0,r3
|
||
|
#endif
|
||
|
-#elif CONFIG_FSL_BOOKE
|
||
|
+#elif defined(CONFIG_FSL_BOOKE)
|
||
|
BEGIN_FTR_SECTION
|
||
|
mfspr r3,SPRN_L1CSR0
|
||
|
ori r3,r3,L1CSR0_CFI|L1CSR0_CLFC
|
||
|
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
|
||
|
index 389fb8077cc9..1d3d3d653675 100644
|
||
|
--- a/arch/powerpc/kernel/setup_64.c
|
||
|
+++ b/arch/powerpc/kernel/setup_64.c
|
||
|
@@ -142,6 +142,15 @@ static void check_smt_enabled(void)
|
||
|
of_node_put(dn);
|
||
|
}
|
||
|
}
|
||
|
+
|
||
|
+ /*
|
||
|
+ * Fixup HFSCR:TM based on CPU features. The bit is set by our
|
||
|
+ * early asm init because at that point we haven't updated our
|
||
|
+ * CPU features from firmware and device-tree. Here we have,
|
||
|
+ * so let's do it.
|
||
|
+ */
|
||
|
+ if (cpu_has_feature(CPU_FTR_HVMODE) && !cpu_has_feature(CPU_FTR_TM_COMP))
|
||
|
+ mtspr(SPRN_HFSCR, mfspr(SPRN_HFSCR) & ~HFSCR_TM);
|
||
|
}
|
||
|
|
||
|
/* Look for smt-enabled= cmdline option */
|
||
|
diff --git a/arch/s390/boot/compressed/misc.c b/arch/s390/boot/compressed/misc.c
|
||
|
index c4c6a1cf221b..05ab88249251 100644
|
||
|
--- a/arch/s390/boot/compressed/misc.c
|
||
|
+++ b/arch/s390/boot/compressed/misc.c
|
||
|
@@ -138,31 +138,34 @@ static void check_ipl_parmblock(void *start, unsigned long size)
|
||
|
|
||
|
unsigned long decompress_kernel(void)
|
||
|
{
|
||
|
- unsigned long output_addr;
|
||
|
- unsigned char *output;
|
||
|
+ void *output, *kernel_end;
|
||
|
|
||
|
- output_addr = ((unsigned long) &_end + HEAP_SIZE + 4095UL) & -4096UL;
|
||
|
- check_ipl_parmblock((void *) 0, output_addr + SZ__bss_start);
|
||
|
- memset(&_bss, 0, &_ebss - &_bss);
|
||
|
- free_mem_ptr = (unsigned long)&_end;
|
||
|
- free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
|
||
|
- output = (unsigned char *) output_addr;
|
||
|
+ output = (void *) ALIGN((unsigned long) &_end + HEAP_SIZE, PAGE_SIZE);
|
||
|
+ kernel_end = output + SZ__bss_start;
|
||
|
+ check_ipl_parmblock((void *) 0, (unsigned long) kernel_end);
|
||
|
|
||
|
#ifdef CONFIG_BLK_DEV_INITRD
|
||
|
/*
|
||
|
* Move the initrd right behind the end of the decompressed
|
||
|
- * kernel image.
|
||
|
+ * kernel image. This also prevents initrd corruption caused by
|
||
|
+ * bss clearing since kernel_end will always be located behind the
|
||
|
+ * current bss section..
|
||
|
*/
|
||
|
- if (INITRD_START && INITRD_SIZE &&
|
||
|
- INITRD_START < (unsigned long) output + SZ__bss_start) {
|
||
|
- check_ipl_parmblock(output + SZ__bss_start,
|
||
|
- INITRD_START + INITRD_SIZE);
|
||
|
- memmove(output + SZ__bss_start,
|
||
|
- (void *) INITRD_START, INITRD_SIZE);
|
||
|
- INITRD_START = (unsigned long) output + SZ__bss_start;
|
||
|
+ if (INITRD_START && INITRD_SIZE && kernel_end > (void *) INITRD_START) {
|
||
|
+ check_ipl_parmblock(kernel_end, INITRD_SIZE);
|
||
|
+ memmove(kernel_end, (void *) INITRD_START, INITRD_SIZE);
|
||
|
+ INITRD_START = (unsigned long) kernel_end;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
+ /*
|
||
|
+ * Clear bss section. free_mem_ptr and free_mem_end_ptr need to be
|
||
|
+ * initialized afterwards since they reside in bss.
|
||
|
+ */
|
||
|
+ memset(&_bss, 0, &_ebss - &_bss);
|
||
|
+ free_mem_ptr = (unsigned long) &_end;
|
||
|
+ free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
|
||
|
+
|
||
|
puts("Uncompressing Linux... ");
|
||
|
decompress(input_data, input_len, NULL, NULL, output, NULL, error);
|
||
|
puts("Ok, booting the kernel.\n");
|
||
|
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
|
||
|
index 81e0fe48b9b0..7e09789d2cf3 100644
|
||
|
--- a/arch/x86/kernel/cpu/common.c
|
||
|
+++ b/arch/x86/kernel/cpu/common.c
|
||
|
@@ -1066,7 +1066,7 @@ static __init int setup_disablecpuid(char *arg)
|
||
|
{
|
||
|
int bit;
|
||
|
|
||
|
- if (get_option(&arg, &bit) && bit < NCAPINTS*32)
|
||
|
+ if (get_option(&arg, &bit) && bit >= 0 && bit < NCAPINTS * 32)
|
||
|
setup_clear_cpu_cap(bit);
|
||
|
else
|
||
|
return 0;
|
||
|
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
|
||
|
index 5c38e2b298cd..c502340ef270 100644
|
||
|
--- a/arch/x86/kernel/entry_32.S
|
||
|
+++ b/arch/x86/kernel/entry_32.S
|
||
|
@@ -1103,8 +1103,8 @@ ftrace_graph_call:
|
||
|
jmp ftrace_stub
|
||
|
#endif
|
||
|
|
||
|
-.globl ftrace_stub
|
||
|
-ftrace_stub:
|
||
|
+/* This is weak to keep gas from relaxing the jumps */
|
||
|
+WEAK(ftrace_stub)
|
||
|
ret
|
||
|
END(ftrace_caller)
|
||
|
|
||
|
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
|
||
|
index ddad189e596e..c96485054f6b 100644
|
||
|
--- a/arch/x86/kvm/emulate.c
|
||
|
+++ b/arch/x86/kvm/emulate.c
|
||
|
@@ -906,6 +906,20 @@ static int segmented_read_std(struct x86_emulate_ctxt *ctxt,
|
||
|
return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception);
|
||
|
}
|
||
|
|
||
|
+static int segmented_write_std(struct x86_emulate_ctxt *ctxt,
|
||
|
+ struct segmented_address addr,
|
||
|
+ void *data,
|
||
|
+ unsigned int size)
|
||
|
+{
|
||
|
+ int rc;
|
||
|
+ ulong linear;
|
||
|
+
|
||
|
+ rc = linearize(ctxt, addr, size, true, &linear);
|
||
|
+ if (rc != X86EMUL_CONTINUE)
|
||
|
+ return rc;
|
||
|
+ return ctxt->ops->write_std(ctxt, linear, data, size, &ctxt->exception);
|
||
|
+}
|
||
|
+
|
||
|
/*
|
||
|
* Fetch the next byte of the instruction being emulated which is pointed to
|
||
|
* by ctxt->_eip, then increment ctxt->_eip.
|
||
|
@@ -1599,7 +1613,6 @@ static int write_segment_descriptor(struct x86_emulate_ctxt *ctxt,
|
||
|
&ctxt->exception);
|
||
|
}
|
||
|
|
||
|
-/* Does not support long mode */
|
||
|
static int load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
|
||
|
u16 selector, int seg)
|
||
|
{
|
||
|
@@ -1612,6 +1625,21 @@ static int load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
|
||
|
int ret;
|
||
|
u16 dummy;
|
||
|
|
||
|
+
|
||
|
+ /*
|
||
|
+ * None of MOV, POP and LSS can load a NULL selector in CPL=3, but
|
||
|
+ * they can load it at CPL<3 (Intel's manual says only LSS can,
|
||
|
+ * but it's wrong).
|
||
|
+ *
|
||
|
+ * However, the Intel manual says that putting IST=1/DPL=3 in
|
||
|
+ * an interrupt gate will result in SS=3 (the AMD manual instead
|
||
|
+ * says it doesn't), so allow SS=3 in __load_segment_descriptor
|
||
|
+ * and only forbid it here.
|
||
|
+ */
|
||
|
+ if (seg == VCPU_SREG_SS && selector == 3 &&
|
||
|
+ ctxt->mode == X86EMUL_MODE_PROT64)
|
||
|
+ return emulate_exception(ctxt, GP_VECTOR, 0, true);
|
||
|
+
|
||
|
memset(&seg_desc, 0, sizeof seg_desc);
|
||
|
|
||
|
if (ctxt->mode == X86EMUL_MODE_REAL) {
|
||
|
@@ -1634,20 +1662,34 @@ static int load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
|
||
|
rpl = selector & 3;
|
||
|
cpl = ctxt->ops->cpl(ctxt);
|
||
|
|
||
|
- /* NULL selector is not valid for TR, CS and SS (except for long mode) */
|
||
|
- if ((seg == VCPU_SREG_CS
|
||
|
- || (seg == VCPU_SREG_SS
|
||
|
- && (ctxt->mode != X86EMUL_MODE_PROT64 || rpl != cpl))
|
||
|
- || seg == VCPU_SREG_TR)
|
||
|
- && null_selector)
|
||
|
- goto exception;
|
||
|
-
|
||
|
/* TR should be in GDT only */
|
||
|
if (seg == VCPU_SREG_TR && (selector & (1 << 2)))
|
||
|
goto exception;
|
||
|
|
||
|
- if (null_selector) /* for NULL selector skip all following checks */
|
||
|
+ /* NULL selector is not valid for TR, CS and (except for long mode) SS */
|
||
|
+ if (null_selector) {
|
||
|
+ if (seg == VCPU_SREG_CS || seg == VCPU_SREG_TR)
|
||
|
+ goto exception;
|
||
|
+
|
||
|
+ if (seg == VCPU_SREG_SS) {
|
||
|
+ if (ctxt->mode != X86EMUL_MODE_PROT64 || rpl != cpl)
|
||
|
+ goto exception;
|
||
|
+
|
||
|
+ /*
|
||
|
+ * ctxt->ops->set_segment expects the CPL to be in
|
||
|
+ * SS.DPL, so fake an expand-up 32-bit data segment.
|
||
|
+ */
|
||
|
+ seg_desc.type = 3;
|
||
|
+ seg_desc.p = 1;
|
||
|
+ seg_desc.s = 1;
|
||
|
+ seg_desc.dpl = cpl;
|
||
|
+ seg_desc.d = 1;
|
||
|
+ seg_desc.g = 1;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Skip all following checks */
|
||
|
goto load;
|
||
|
+ }
|
||
|
|
||
|
ret = read_segment_descriptor(ctxt, selector, &seg_desc, &desc_addr);
|
||
|
if (ret != X86EMUL_CONTINUE)
|
||
|
@@ -3333,8 +3375,8 @@ static int emulate_store_desc_ptr(struct x86_emulate_ctxt *ctxt,
|
||
|
}
|
||
|
/* Disable writeback. */
|
||
|
ctxt->dst.type = OP_NONE;
|
||
|
- return segmented_write(ctxt, ctxt->dst.addr.mem,
|
||
|
- &desc_ptr, 2 + ctxt->op_bytes);
|
||
|
+ return segmented_write_std(ctxt, ctxt->dst.addr.mem,
|
||
|
+ &desc_ptr, 2 + ctxt->op_bytes);
|
||
|
}
|
||
|
|
||
|
static int em_sgdt(struct x86_emulate_ctxt *ctxt)
|
||
|
diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
|
||
|
index 48e8461057ba..6e4580b87600 100644
|
||
|
--- a/arch/x86/pci/xen.c
|
||
|
+++ b/arch/x86/pci/xen.c
|
||
|
@@ -227,23 +227,14 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
|
||
|
return 1;
|
||
|
|
||
|
list_for_each_entry(msidesc, &dev->msi_list, list) {
|
||
|
- __read_msi_msg(msidesc, &msg);
|
||
|
- pirq = MSI_ADDR_EXT_DEST_ID(msg.address_hi) |
|
||
|
- ((msg.address_lo >> MSI_ADDR_DEST_ID_SHIFT) & 0xff);
|
||
|
- if (msg.data != XEN_PIRQ_MSI_DATA ||
|
||
|
- xen_irq_from_pirq(pirq) < 0) {
|
||
|
- pirq = xen_allocate_pirq_msi(dev, msidesc);
|
||
|
- if (pirq < 0) {
|
||
|
- irq = -ENODEV;
|
||
|
- goto error;
|
||
|
- }
|
||
|
- xen_msi_compose_msg(dev, pirq, &msg);
|
||
|
- __write_msi_msg(msidesc, &msg);
|
||
|
- dev_dbg(&dev->dev, "xen: msi bound to pirq=%d\n", pirq);
|
||
|
- } else {
|
||
|
- dev_dbg(&dev->dev,
|
||
|
- "xen: msi already bound to pirq=%d\n", pirq);
|
||
|
+ pirq = xen_allocate_pirq_msi(dev, msidesc);
|
||
|
+ if (pirq < 0) {
|
||
|
+ irq = -ENODEV;
|
||
|
+ goto error;
|
||
|
}
|
||
|
+ xen_msi_compose_msg(dev, pirq, &msg);
|
||
|
+ __write_msi_msg(msidesc, &msg);
|
||
|
+ dev_dbg(&dev->dev, "xen: msi bound to pirq=%d\n", pirq);
|
||
|
irq = xen_bind_pirq_msi_to_irq(dev, msidesc, pirq,
|
||
|
(type == PCI_CAP_ID_MSIX) ?
|
||
|
"msi-x" : "msi",
|
||
|
diff --git a/arch/x86/platform/goldfish/goldfish.c b/arch/x86/platform/goldfish/goldfish.c
|
||
|
index 1693107a518e..0d17c0aafeb1 100644
|
||
|
--- a/arch/x86/platform/goldfish/goldfish.c
|
||
|
+++ b/arch/x86/platform/goldfish/goldfish.c
|
||
|
@@ -42,10 +42,22 @@ static struct resource goldfish_pdev_bus_resources[] = {
|
||
|
}
|
||
|
};
|
||
|
|
||
|
+static bool goldfish_enable __initdata;
|
||
|
+
|
||
|
+static int __init goldfish_setup(char *str)
|
||
|
+{
|
||
|
+ goldfish_enable = true;
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+__setup("goldfish", goldfish_setup);
|
||
|
+
|
||
|
static int __init goldfish_init(void)
|
||
|
{
|
||
|
+ if (!goldfish_enable)
|
||
|
+ return -ENODEV;
|
||
|
+
|
||
|
platform_device_register_simple("goldfish_pdev_bus", -1,
|
||
|
- goldfish_pdev_bus_resources, 2);
|
||
|
+ goldfish_pdev_bus_resources, 2);
|
||
|
return 0;
|
||
|
}
|
||
|
device_initcall(goldfish_init);
|
||
|
diff --git a/crypto/Makefile b/crypto/Makefile
|
||
|
index a8e9b0fefbe9..b54916590d3a 100644
|
||
|
--- a/crypto/Makefile
|
||
|
+++ b/crypto/Makefile
|
||
|
@@ -2,8 +2,13 @@
|
||
|
# Cryptographic API
|
||
|
#
|
||
|
|
||
|
+# memneq MUST be built with -Os or -O0 to prevent early-return optimizations
|
||
|
+# that will defeat memneq's actual purpose to prevent timing attacks.
|
||
|
+CFLAGS_REMOVE_memneq.o := -O1 -O2 -O3
|
||
|
+CFLAGS_memneq.o := -Os
|
||
|
+
|
||
|
obj-$(CONFIG_CRYPTO) += crypto.o
|
||
|
-crypto-y := api.o cipher.o compress.o
|
||
|
+crypto-y := api.o cipher.o compress.o memneq.o
|
||
|
|
||
|
obj-$(CONFIG_CRYPTO_WORKQUEUE) += crypto_wq.o
|
||
|
|
||
|
diff --git a/crypto/asymmetric_keys/rsa.c b/crypto/asymmetric_keys/rsa.c
|
||
|
index 4a6a0696f8a3..1912b9be5043 100644
|
||
|
--- a/crypto/asymmetric_keys/rsa.c
|
||
|
+++ b/crypto/asymmetric_keys/rsa.c
|
||
|
@@ -13,6 +13,7 @@
|
||
|
#include <linux/module.h>
|
||
|
#include <linux/kernel.h>
|
||
|
#include <linux/slab.h>
|
||
|
+#include <crypto/algapi.h>
|
||
|
#include "public_key.h"
|
||
|
|
||
|
MODULE_LICENSE("GPL");
|
||
|
@@ -189,12 +190,12 @@ static int RSA_verify(const u8 *H, const u8 *EM, size_t k, size_t hash_size,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- if (memcmp(asn1_template, EM + T_offset, asn1_size) != 0) {
|
||
|
+ if (crypto_memneq(asn1_template, EM + T_offset, asn1_size) != 0) {
|
||
|
kleave(" = -EBADMSG [EM[T] ASN.1 mismatch]");
|
||
|
return -EBADMSG;
|
||
|
}
|
||
|
|
||
|
- if (memcmp(H, EM + T_offset + asn1_size, hash_size) != 0) {
|
||
|
+ if (crypto_memneq(H, EM + T_offset + asn1_size, hash_size) != 0) {
|
||
|
kleave(" = -EKEYREJECTED [EM[T] hash mismatch]");
|
||
|
return -EKEYREJECTED;
|
||
|
}
|
||
|
diff --git a/crypto/authenc.c b/crypto/authenc.c
|
||
|
index a2cfae251dd5..65bcd076b18b 100644
|
||
|
--- a/crypto/authenc.c
|
||
|
+++ b/crypto/authenc.c
|
||
|
@@ -188,7 +188,7 @@ static void authenc_verify_ahash_update_done(struct crypto_async_request *areq,
|
||
|
scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen,
|
||
|
authsize, 0);
|
||
|
|
||
|
- err = memcmp(ihash, ahreq->result, authsize) ? -EBADMSG : 0;
|
||
|
+ err = crypto_memneq(ihash, ahreq->result, authsize) ? -EBADMSG : 0;
|
||
|
if (err)
|
||
|
goto out;
|
||
|
|
||
|
@@ -227,7 +227,7 @@ static void authenc_verify_ahash_done(struct crypto_async_request *areq,
|
||
|
scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen,
|
||
|
authsize, 0);
|
||
|
|
||
|
- err = memcmp(ihash, ahreq->result, authsize) ? -EBADMSG : 0;
|
||
|
+ err = crypto_memneq(ihash, ahreq->result, authsize) ? -EBADMSG : 0;
|
||
|
if (err)
|
||
|
goto out;
|
||
|
|
||
|
@@ -463,7 +463,7 @@ static int crypto_authenc_verify(struct aead_request *req,
|
||
|
ihash = ohash + authsize;
|
||
|
scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen,
|
||
|
authsize, 0);
|
||
|
- return memcmp(ihash, ohash, authsize) ? -EBADMSG : 0;
|
||
|
+ return crypto_memneq(ihash, ohash, authsize) ? -EBADMSG : 0;
|
||
|
}
|
||
|
|
||
|
static int crypto_authenc_iverify(struct aead_request *req, u8 *iv,
|
||
|
diff --git a/crypto/authencesn.c b/crypto/authencesn.c
|
||
|
index 16c225cb28c2..a3ef98be2064 100644
|
||
|
--- a/crypto/authencesn.c
|
||
|
+++ b/crypto/authencesn.c
|
||
|
@@ -247,7 +247,7 @@ static void authenc_esn_verify_ahash_update_done(struct crypto_async_request *ar
|
||
|
scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen,
|
||
|
authsize, 0);
|
||
|
|
||
|
- err = memcmp(ihash, ahreq->result, authsize) ? -EBADMSG : 0;
|
||
|
+ err = crypto_memneq(ihash, ahreq->result, authsize) ? -EBADMSG : 0;
|
||
|
if (err)
|
||
|
goto out;
|
||
|
|
||
|
@@ -296,7 +296,7 @@ static void authenc_esn_verify_ahash_update_done2(struct crypto_async_request *a
|
||
|
scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen,
|
||
|
authsize, 0);
|
||
|
|
||
|
- err = memcmp(ihash, ahreq->result, authsize) ? -EBADMSG : 0;
|
||
|
+ err = crypto_memneq(ihash, ahreq->result, authsize) ? -EBADMSG : 0;
|
||
|
if (err)
|
||
|
goto out;
|
||
|
|
||
|
@@ -336,7 +336,7 @@ static void authenc_esn_verify_ahash_done(struct crypto_async_request *areq,
|
||
|
scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen,
|
||
|
authsize, 0);
|
||
|
|
||
|
- err = memcmp(ihash, ahreq->result, authsize) ? -EBADMSG : 0;
|
||
|
+ err = crypto_memneq(ihash, ahreq->result, authsize) ? -EBADMSG : 0;
|
||
|
if (err)
|
||
|
goto out;
|
||
|
|
||
|
@@ -568,7 +568,7 @@ static int crypto_authenc_esn_verify(struct aead_request *req)
|
||
|
ihash = ohash + authsize;
|
||
|
scatterwalk_map_and_copy(ihash, areq_ctx->sg, areq_ctx->cryptlen,
|
||
|
authsize, 0);
|
||
|
- return memcmp(ihash, ohash, authsize) ? -EBADMSG : 0;
|
||
|
+ return crypto_memneq(ihash, ohash, authsize) ? -EBADMSG : 0;
|
||
|
}
|
||
|
|
||
|
static int crypto_authenc_esn_iverify(struct aead_request *req, u8 *iv,
|
||
|
diff --git a/crypto/ccm.c b/crypto/ccm.c
|
||
|
index c569c9c6afe3..003bbbd21a2b 100644
|
||
|
--- a/crypto/ccm.c
|
||
|
+++ b/crypto/ccm.c
|
||
|
@@ -364,7 +364,7 @@ static void crypto_ccm_decrypt_done(struct crypto_async_request *areq,
|
||
|
|
||
|
if (!err) {
|
||
|
err = crypto_ccm_auth(req, req->dst, cryptlen);
|
||
|
- if (!err && memcmp(pctx->auth_tag, pctx->odata, authsize))
|
||
|
+ if (!err && crypto_memneq(pctx->auth_tag, pctx->odata, authsize))
|
||
|
err = -EBADMSG;
|
||
|
}
|
||
|
aead_request_complete(req, err);
|
||
|
@@ -423,7 +423,7 @@ static int crypto_ccm_decrypt(struct aead_request *req)
|
||
|
return err;
|
||
|
|
||
|
/* verify */
|
||
|
- if (memcmp(authtag, odata, authsize))
|
||
|
+ if (crypto_memneq(authtag, odata, authsize))
|
||
|
return -EBADMSG;
|
||
|
|
||
|
return err;
|
||
|
diff --git a/crypto/gcm.c b/crypto/gcm.c
|
||
|
index a1ec756b8438..49b6fb20cceb 100644
|
||
|
--- a/crypto/gcm.c
|
||
|
+++ b/crypto/gcm.c
|
||
|
@@ -582,7 +582,7 @@ static int crypto_gcm_verify(struct aead_request *req,
|
||
|
|
||
|
crypto_xor(auth_tag, iauth_tag, 16);
|
||
|
scatterwalk_map_and_copy(iauth_tag, req->src, cryptlen, authsize, 0);
|
||
|
- return memcmp(iauth_tag, auth_tag, authsize) ? -EBADMSG : 0;
|
||
|
+ return crypto_memneq(iauth_tag, auth_tag, authsize) ? -EBADMSG : 0;
|
||
|
}
|
||
|
|
||
|
static void gcm_decrypt_done(struct crypto_async_request *areq, int err)
|
||
|
diff --git a/crypto/memneq.c b/crypto/memneq.c
|
||
|
new file mode 100644
|
||
|
index 000000000000..cd0162221c14
|
||
|
--- /dev/null
|
||
|
+++ b/crypto/memneq.c
|
||
|
@@ -0,0 +1,138 @@
|
||
|
+/*
|
||
|
+ * Constant-time equality testing of memory regions.
|
||
|
+ *
|
||
|
+ * Authors:
|
||
|
+ *
|
||
|
+ * James Yonan <james@openvpn.net>
|
||
|
+ * Daniel Borkmann <dborkman@redhat.com>
|
||
|
+ *
|
||
|
+ * This file is provided under a dual BSD/GPLv2 license. When using or
|
||
|
+ * redistributing this file, you may do so under either license.
|
||
|
+ *
|
||
|
+ * GPL LICENSE SUMMARY
|
||
|
+ *
|
||
|
+ * Copyright(c) 2013 OpenVPN Technologies, Inc. All rights reserved.
|
||
|
+ *
|
||
|
+ * This program is free software; you can redistribute it and/or modify
|
||
|
+ * it under the terms of version 2 of the GNU General Public License as
|
||
|
+ * published by the Free Software Foundation.
|
||
|
+ *
|
||
|
+ * This program is distributed in the hope that it will be useful, but
|
||
|
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
+ * General Public License for more details.
|
||
|
+ *
|
||
|
+ * You should have received a copy of the GNU General Public License
|
||
|
+ * along with this program; if not, write to the Free Software
|
||
|
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||
|
+ * The full GNU General Public License is included in this distribution
|
||
|
+ * in the file called LICENSE.GPL.
|
||
|
+ *
|
||
|
+ * BSD LICENSE
|
||
|
+ *
|
||
|
+ * Copyright(c) 2013 OpenVPN Technologies, Inc. All rights reserved.
|
||
|
+ *
|
||
|
+ * Redistribution and use in source and binary forms, with or without
|
||
|
+ * modification, are permitted provided that the following conditions
|
||
|
+ * are met:
|
||
|
+ *
|
||
|
+ * * Redistributions of source code must retain the above copyright
|
||
|
+ * notice, this list of conditions and the following disclaimer.
|
||
|
+ * * Redistributions in binary form must reproduce the above copyright
|
||
|
+ * notice, this list of conditions and the following disclaimer in
|
||
|
+ * the documentation and/or other materials provided with the
|
||
|
+ * distribution.
|
||
|
+ * * Neither the name of OpenVPN Technologies nor the names of its
|
||
|
+ * contributors may be used to endorse or promote products derived
|
||
|
+ * from this software without specific prior written permission.
|
||
|
+ *
|
||
|
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||
|
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||
|
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||
|
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||
|
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||
|
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||
|
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||
|
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||
|
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||
|
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||
|
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||
|
+ */
|
||
|
+
|
||
|
+#include <crypto/algapi.h>
|
||
|
+
|
||
|
+#ifndef __HAVE_ARCH_CRYPTO_MEMNEQ
|
||
|
+
|
||
|
+/* Generic path for arbitrary size */
|
||
|
+static inline unsigned long
|
||
|
+__crypto_memneq_generic(const void *a, const void *b, size_t size)
|
||
|
+{
|
||
|
+ unsigned long neq = 0;
|
||
|
+
|
||
|
+#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
|
||
|
+ while (size >= sizeof(unsigned long)) {
|
||
|
+ neq |= *(unsigned long *)a ^ *(unsigned long *)b;
|
||
|
+ a += sizeof(unsigned long);
|
||
|
+ b += sizeof(unsigned long);
|
||
|
+ size -= sizeof(unsigned long);
|
||
|
+ }
|
||
|
+#endif /* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS */
|
||
|
+ while (size > 0) {
|
||
|
+ neq |= *(unsigned char *)a ^ *(unsigned char *)b;
|
||
|
+ a += 1;
|
||
|
+ b += 1;
|
||
|
+ size -= 1;
|
||
|
+ }
|
||
|
+ return neq;
|
||
|
+}
|
||
|
+
|
||
|
+/* Loop-free fast-path for frequently used 16-byte size */
|
||
|
+static inline unsigned long __crypto_memneq_16(const void *a, const void *b)
|
||
|
+{
|
||
|
+#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
|
||
|
+ if (sizeof(unsigned long) == 8)
|
||
|
+ return ((*(unsigned long *)(a) ^ *(unsigned long *)(b))
|
||
|
+ | (*(unsigned long *)(a+8) ^ *(unsigned long *)(b+8)));
|
||
|
+ else if (sizeof(unsigned int) == 4)
|
||
|
+ return ((*(unsigned int *)(a) ^ *(unsigned int *)(b))
|
||
|
+ | (*(unsigned int *)(a+4) ^ *(unsigned int *)(b+4))
|
||
|
+ | (*(unsigned int *)(a+8) ^ *(unsigned int *)(b+8))
|
||
|
+ | (*(unsigned int *)(a+12) ^ *(unsigned int *)(b+12)));
|
||
|
+ else
|
||
|
+#endif /* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS */
|
||
|
+ return ((*(unsigned char *)(a) ^ *(unsigned char *)(b))
|
||
|
+ | (*(unsigned char *)(a+1) ^ *(unsigned char *)(b+1))
|
||
|
+ | (*(unsigned char *)(a+2) ^ *(unsigned char *)(b+2))
|
||
|
+ | (*(unsigned char *)(a+3) ^ *(unsigned char *)(b+3))
|
||
|
+ | (*(unsigned char *)(a+4) ^ *(unsigned char *)(b+4))
|
||
|
+ | (*(unsigned char *)(a+5) ^ *(unsigned char *)(b+5))
|
||
|
+ | (*(unsigned char *)(a+6) ^ *(unsigned char *)(b+6))
|
||
|
+ | (*(unsigned char *)(a+7) ^ *(unsigned char *)(b+7))
|
||
|
+ | (*(unsigned char *)(a+8) ^ *(unsigned char *)(b+8))
|
||
|
+ | (*(unsigned char *)(a+9) ^ *(unsigned char *)(b+9))
|
||
|
+ | (*(unsigned char *)(a+10) ^ *(unsigned char *)(b+10))
|
||
|
+ | (*(unsigned char *)(a+11) ^ *(unsigned char *)(b+11))
|
||
|
+ | (*(unsigned char *)(a+12) ^ *(unsigned char *)(b+12))
|
||
|
+ | (*(unsigned char *)(a+13) ^ *(unsigned char *)(b+13))
|
||
|
+ | (*(unsigned char *)(a+14) ^ *(unsigned char *)(b+14))
|
||
|
+ | (*(unsigned char *)(a+15) ^ *(unsigned char *)(b+15)));
|
||
|
+}
|
||
|
+
|
||
|
+/* Compare two areas of memory without leaking timing information,
|
||
|
+ * and with special optimizations for common sizes. Users should
|
||
|
+ * not call this function directly, but should instead use
|
||
|
+ * crypto_memneq defined in crypto/algapi.h.
|
||
|
+ */
|
||
|
+noinline unsigned long __crypto_memneq(const void *a, const void *b,
|
||
|
+ size_t size)
|
||
|
+{
|
||
|
+ switch (size) {
|
||
|
+ case 16:
|
||
|
+ return __crypto_memneq_16(a, b);
|
||
|
+ default:
|
||
|
+ return __crypto_memneq_generic(a, b, size);
|
||
|
+ }
|
||
|
+}
|
||
|
+EXPORT_SYMBOL(__crypto_memneq);
|
||
|
+
|
||
|
+#endif /* __HAVE_ARCH_CRYPTO_MEMNEQ */
|
||
|
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
|
||
|
index 11441ad69de3..276ea4727ad2 100644
|
||
|
--- a/drivers/acpi/osl.c
|
||
|
+++ b/drivers/acpi/osl.c
|
||
|
@@ -173,7 +173,7 @@ static void __init acpi_request_region (struct acpi_generic_address *gas,
|
||
|
request_mem_region(addr, length, desc);
|
||
|
}
|
||
|
|
||
|
-static void __init acpi_reserve_resources(void)
|
||
|
+static int __init acpi_reserve_resources(void)
|
||
|
{
|
||
|
acpi_request_region(&acpi_gbl_FADT.xpm1a_event_block, acpi_gbl_FADT.pm1_event_length,
|
||
|
"ACPI PM1a_EVT_BLK");
|
||
|
@@ -202,7 +202,10 @@ static void __init acpi_reserve_resources(void)
|
||
|
if (!(acpi_gbl_FADT.gpe1_block_length & 0x1))
|
||
|
acpi_request_region(&acpi_gbl_FADT.xgpe1_block,
|
||
|
acpi_gbl_FADT.gpe1_block_length, "ACPI GPE1_BLK");
|
||
|
+
|
||
|
+ return 0;
|
||
|
}
|
||
|
+fs_initcall_sync(acpi_reserve_resources);
|
||
|
|
||
|
void acpi_os_printf(const char *fmt, ...)
|
||
|
{
|
||
|
@@ -1724,7 +1727,6 @@ acpi_status __init acpi_os_initialize(void)
|
||
|
|
||
|
acpi_status __init acpi_os_initialize1(void)
|
||
|
{
|
||
|
- acpi_reserve_resources();
|
||
|
kacpid_wq = alloc_workqueue("kacpid", 0, 1);
|
||
|
kacpi_notify_wq = alloc_workqueue("kacpi_notify", 0, 1);
|
||
|
kacpi_hotplug_wq = alloc_workqueue("kacpi_hotplug", 0, 1);
|
||
|
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
|
||
|
index 3bb6fa3930be..30878924e65b 100644
|
||
|
--- a/drivers/char/Kconfig
|
||
|
+++ b/drivers/char/Kconfig
|
||
|
@@ -580,7 +580,6 @@ config TELCLOCK
|
||
|
|
||
|
config DEVPORT
|
||
|
bool
|
||
|
- depends on !M68K
|
||
|
depends on ISA || PCI
|
||
|
default y
|
||
|
|
||
|
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
|
||
|
index 0913d79424d3..6b619105dea8 100644
|
||
|
--- a/drivers/char/lp.c
|
||
|
+++ b/drivers/char/lp.c
|
||
|
@@ -857,7 +857,11 @@ static int __init lp_setup (char *str)
|
||
|
} else if (!strcmp(str, "auto")) {
|
||
|
parport_nr[0] = LP_PARPORT_AUTO;
|
||
|
} else if (!strcmp(str, "none")) {
|
||
|
- parport_nr[parport_ptr++] = LP_PARPORT_NONE;
|
||
|
+ if (parport_ptr < LP_NO)
|
||
|
+ parport_nr[parport_ptr++] = LP_PARPORT_NONE;
|
||
|
+ else
|
||
|
+ printk(KERN_INFO "lp: too many ports, %s ignored.\n",
|
||
|
+ str);
|
||
|
} else if (!strcmp(str, "reset")) {
|
||
|
reset = 1;
|
||
|
}
|
||
|
diff --git a/drivers/clk/clk-wm831x.c b/drivers/clk/clk-wm831x.c
|
||
|
index 917a3ab482f9..e2e5e76e9805 100644
|
||
|
--- a/drivers/clk/clk-wm831x.c
|
||
|
+++ b/drivers/clk/clk-wm831x.c
|
||
|
@@ -248,7 +248,7 @@ static int wm831x_clkout_is_enabled(struct clk_hw *hw)
|
||
|
if (ret < 0) {
|
||
|
dev_err(wm831x->dev, "Unable to read CLOCK_CONTROL_1: %d\n",
|
||
|
ret);
|
||
|
- return true;
|
||
|
+ return false;
|
||
|
}
|
||
|
|
||
|
return (ret & WM831X_CLKOUT_ENA) != 0;
|
||
|
diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c
|
||
|
index bf416a8391a7..0cba9273e6c9 100644
|
||
|
--- a/drivers/crypto/caam/caamalg.c
|
||
|
+++ b/drivers/crypto/caam/caamalg.c
|
||
|
@@ -422,7 +422,9 @@ static int aead_set_sh_desc(struct crypto_aead *aead)
|
||
|
|
||
|
/* Will read cryptlen */
|
||
|
append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ);
|
||
|
- aead_append_src_dst(desc, FIFOLD_TYPE_MSG1OUT2);
|
||
|
+ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_BOTH | KEY_VLF |
|
||
|
+ FIFOLD_TYPE_MSG1OUT2 | FIFOLD_TYPE_LASTBOTH);
|
||
|
+ append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | KEY_VLF);
|
||
|
|
||
|
/* Write ICV */
|
||
|
append_seq_store(desc, ctx->authsize, LDST_CLASS_2_CCB |
|
||
|
diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c
|
||
|
index dda43cc4b6cd..e9d8b235f68d 100644
|
||
|
--- a/drivers/crypto/caam/caamhash.c
|
||
|
+++ b/drivers/crypto/caam/caamhash.c
|
||
|
@@ -1793,6 +1793,7 @@ caam_hash_alloc(struct device *ctrldev, struct caam_hash_template *template,
|
||
|
template->name);
|
||
|
snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
|
||
|
template->driver_name);
|
||
|
+ t_alg->ahash_alg.setkey = NULL;
|
||
|
}
|
||
|
alg->cra_module = THIS_MODULE;
|
||
|
alg->cra_init = caam_hash_cra_init;
|
||
|
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
|
||
|
index 53435a9d847e..93c80d7143ef 100644
|
||
|
--- a/drivers/gpu/drm/i915/intel_crt.c
|
||
|
+++ b/drivers/gpu/drm/i915/intel_crt.c
|
||
|
@@ -428,6 +428,7 @@ static bool intel_crt_detect_ddc(struct drm_connector *connector)
|
||
|
struct drm_i915_private *dev_priv = crt->base.base.dev->dev_private;
|
||
|
struct edid *edid;
|
||
|
struct i2c_adapter *i2c;
|
||
|
+ bool ret = false;
|
||
|
|
||
|
BUG_ON(crt->base.type != INTEL_OUTPUT_ANALOG);
|
||
|
|
||
|
@@ -444,17 +445,17 @@ static bool intel_crt_detect_ddc(struct drm_connector *connector)
|
||
|
*/
|
||
|
if (!is_digital) {
|
||
|
DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n");
|
||
|
- return true;
|
||
|
+ ret = true;
|
||
|
+ } else {
|
||
|
+ DRM_DEBUG_KMS("CRT not detected via DDC:0x50 [EDID reports a digital panel]\n");
|
||
|
}
|
||
|
-
|
||
|
- DRM_DEBUG_KMS("CRT not detected via DDC:0x50 [EDID reports a digital panel]\n");
|
||
|
} else {
|
||
|
DRM_DEBUG_KMS("CRT not detected via DDC:0x50 [no valid EDID found]\n");
|
||
|
}
|
||
|
|
||
|
kfree(edid);
|
||
|
|
||
|
- return false;
|
||
|
+ return ret;
|
||
|
}
|
||
|
|
||
|
static enum drm_connector_status
|
||
|
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
|
||
|
index 8814b0dbfc4f..a7dbdec68994 100644
|
||
|
--- a/drivers/gpu/drm/i915/intel_display.c
|
||
|
+++ b/drivers/gpu/drm/i915/intel_display.c
|
||
|
@@ -7052,9 +7052,9 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
|
||
|
|
||
|
wake_up_all(&dev_priv->pending_flip_queue);
|
||
|
|
||
|
- queue_work(dev_priv->wq, &work->work);
|
||
|
-
|
||
|
trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj);
|
||
|
+
|
||
|
+ queue_work(dev_priv->wq, &work->work);
|
||
|
}
|
||
|
|
||
|
void intel_finish_page_flip(struct drm_device *dev, int pipe)
|
||
|
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
|
||
|
index dd5e01f89f28..969acd36c409 100644
|
||
|
--- a/drivers/gpu/drm/nouveau/nv50_display.c
|
||
|
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
|
||
|
@@ -1253,7 +1253,7 @@ nv50_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
|
||
|
uint32_t start, uint32_t size)
|
||
|
{
|
||
|
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
|
||
|
- u32 end = max(start + size, (u32)256);
|
||
|
+ u32 end = min_t(u32, start + size, 256);
|
||
|
u32 i;
|
||
|
|
||
|
for (i = start; i < end; i++) {
|
||
|
diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c
|
||
|
index ae4923756d98..b1039552b623 100644
|
||
|
--- a/drivers/hv/hv.c
|
||
|
+++ b/drivers/hv/hv.c
|
||
|
@@ -193,7 +193,7 @@ cleanup:
|
||
|
*
|
||
|
* This routine is called normally during driver unloading or exiting.
|
||
|
*/
|
||
|
-void hv_cleanup(void)
|
||
|
+void hv_cleanup(bool crash)
|
||
|
{
|
||
|
union hv_x64_msr_hypercall_contents hypercall_msr;
|
||
|
|
||
|
@@ -203,7 +203,8 @@ void hv_cleanup(void)
|
||
|
if (hv_context.hypercall_page) {
|
||
|
hypercall_msr.as_uint64 = 0;
|
||
|
wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
|
||
|
- vfree(hv_context.hypercall_page);
|
||
|
+ if (!crash)
|
||
|
+ vfree(hv_context.hypercall_page);
|
||
|
hv_context.hypercall_page = NULL;
|
||
|
}
|
||
|
}
|
||
|
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
|
||
|
index 12f2f9e989f7..11d4e6222f52 100644
|
||
|
--- a/drivers/hv/hyperv_vmbus.h
|
||
|
+++ b/drivers/hv/hyperv_vmbus.h
|
||
|
@@ -519,7 +519,7 @@ extern struct hv_context hv_context;
|
||
|
|
||
|
extern int hv_init(void);
|
||
|
|
||
|
-extern void hv_cleanup(void);
|
||
|
+extern void hv_cleanup(bool crash);
|
||
|
|
||
|
extern int hv_post_message(union hv_connection_id connection_id,
|
||
|
enum hv_message_type message_type,
|
||
|
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
|
||
|
index 80754e2d8086..3190a1fc7bc8 100644
|
||
|
--- a/drivers/hv/vmbus_drv.c
|
||
|
+++ b/drivers/hv/vmbus_drv.c
|
||
|
@@ -618,7 +618,7 @@ err_unregister:
|
||
|
bus_unregister(&hv_bus);
|
||
|
|
||
|
err_cleanup:
|
||
|
- hv_cleanup();
|
||
|
+ hv_cleanup(false);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
@@ -841,7 +841,7 @@ static void __exit vmbus_exit(void)
|
||
|
free_irq(irq, hv_acpi_dev);
|
||
|
vmbus_free_channels();
|
||
|
bus_unregister(&hv_bus);
|
||
|
- hv_cleanup();
|
||
|
+ hv_cleanup(false);
|
||
|
acpi_bus_unregister_driver(&vmbus_acpi_driver);
|
||
|
hv_cpu_hotplug_quirk(false);
|
||
|
}
|
||
|
diff --git a/drivers/hwmon/ds620.c b/drivers/hwmon/ds620.c
|
||
|
index f1d6b422cf06..c25700f7db93 100644
|
||
|
--- a/drivers/hwmon/ds620.c
|
||
|
+++ b/drivers/hwmon/ds620.c
|
||
|
@@ -166,7 +166,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da,
|
||
|
if (res)
|
||
|
return res;
|
||
|
|
||
|
- val = (val * 10 / 625) * 8;
|
||
|
+ val = (clamp_val(val, -128000, 128000) * 10 / 625) * 8;
|
||
|
|
||
|
mutex_lock(&data->update_lock);
|
||
|
data->temp[attr->index] = val;
|
||
|
diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
|
||
|
index c880d13f5405..f079877bd4ea 100644
|
||
|
--- a/drivers/i2c/busses/i2c-at91.c
|
||
|
+++ b/drivers/i2c/busses/i2c-at91.c
|
||
|
@@ -273,8 +273,14 @@ error:
|
||
|
|
||
|
static void at91_twi_read_next_byte(struct at91_twi_dev *dev)
|
||
|
{
|
||
|
- if (dev->buf_len <= 0)
|
||
|
+ /*
|
||
|
+ * If we are in this case, it means there is garbage data in RHR, so
|
||
|
+ * delete them.
|
||
|
+ */
|
||
|
+ if (!dev->buf_len) {
|
||
|
+ at91_twi_read(dev, AT91_TWI_RHR);
|
||
|
return;
|
||
|
+ }
|
||
|
|
||
|
*dev->buf = at91_twi_read(dev, AT91_TWI_RHR) & 0xff;
|
||
|
--dev->buf_len;
|
||
|
@@ -371,6 +377,24 @@ static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id)
|
||
|
|
||
|
if (!irqstatus)
|
||
|
return IRQ_NONE;
|
||
|
+ /*
|
||
|
+ * In reception, the behavior of the twi device (before sama5d2) is
|
||
|
+ * weird. There is some magic about RXRDY flag! When a data has been
|
||
|
+ * almost received, the reception of a new one is anticipated if there
|
||
|
+ * is no stop command to send. That is the reason why ask for sending
|
||
|
+ * the stop command not on the last data but on the second last one.
|
||
|
+ *
|
||
|
+ * Unfortunately, we could still have the RXRDY flag set even if the
|
||
|
+ * transfer is done and we have read the last data. It might happen
|
||
|
+ * when the i2c slave device sends too quickly data after receiving the
|
||
|
+ * ack from the master. The data has been almost received before having
|
||
|
+ * the order to send stop. In this case, sending the stop command could
|
||
|
+ * cause a RXRDY interrupt with a TXCOMP one. It is better to manage
|
||
|
+ * the RXRDY interrupt first in order to not keep garbage data in the
|
||
|
+ * Receive Holding Register for the next transfer.
|
||
|
+ */
|
||
|
+ if (irqstatus & AT91_TWI_RXRDY)
|
||
|
+ at91_twi_read_next_byte(dev);
|
||
|
|
||
|
/*
|
||
|
* When a NACK condition is detected, the I2C controller sets the NACK,
|
||
|
@@ -413,8 +437,6 @@ static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id)
|
||
|
if (irqstatus & (AT91_TWI_TXCOMP | AT91_TWI_NACK)) {
|
||
|
at91_disable_twi_interrupts(dev);
|
||
|
complete(&dev->cmd_complete);
|
||
|
- } else if (irqstatus & AT91_TWI_RXRDY) {
|
||
|
- at91_twi_read_next_byte(dev);
|
||
|
} else if (irqstatus & AT91_TWI_TXRDY) {
|
||
|
at91_twi_write_next_byte(dev);
|
||
|
}
|
||
|
@@ -429,7 +451,6 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
|
||
|
{
|
||
|
int ret;
|
||
|
bool has_unre_flag = dev->pdata->has_unre_flag;
|
||
|
- unsigned sr;
|
||
|
|
||
|
/*
|
||
|
* WARNING: the TXCOMP bit in the Status Register is NOT a clear on
|
||
|
@@ -466,7 +487,7 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
|
||
|
dev->transfer_status = 0;
|
||
|
|
||
|
/* Clear pending interrupts, such as NACK. */
|
||
|
- sr = at91_twi_read(dev, AT91_TWI_SR);
|
||
|
+ at91_twi_read(dev, AT91_TWI_SR);
|
||
|
|
||
|
if (!dev->buf_len) {
|
||
|
at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_QUICK);
|
||
|
@@ -474,11 +495,6 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
|
||
|
} else if (dev->msg->flags & I2C_M_RD) {
|
||
|
unsigned start_flags = AT91_TWI_START;
|
||
|
|
||
|
- if (sr & AT91_TWI_RXRDY) {
|
||
|
- dev_err(dev->dev, "RXRDY still set!");
|
||
|
- at91_twi_read(dev, AT91_TWI_RHR);
|
||
|
- }
|
||
|
-
|
||
|
/* if only one byte is to be read, immediately stop transfer */
|
||
|
if (dev->buf_len <= 1 && !(dev->msg->flags & I2C_M_RECV_LEN))
|
||
|
start_flags |= AT91_TWI_STOP;
|
||
|
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
|
||
|
index dc3fd1e8af07..200f6c10eee5 100644
|
||
|
--- a/drivers/infiniband/core/mad.c
|
||
|
+++ b/drivers/infiniband/core/mad.c
|
||
|
@@ -1598,7 +1598,7 @@ find_mad_agent(struct ib_mad_port_private *port_priv,
|
||
|
if (!class)
|
||
|
goto out;
|
||
|
if (convert_mgmt_class(mad->mad_hdr.mgmt_class) >=
|
||
|
- IB_MGMT_MAX_METHODS)
|
||
|
+ ARRAY_SIZE(class->method_table))
|
||
|
goto out;
|
||
|
method = class->method_table[convert_mgmt_class(
|
||
|
mad->mad_hdr.mgmt_class)];
|
||
|
diff --git a/drivers/infiniband/core/multicast.c b/drivers/infiniband/core/multicast.c
|
||
|
index 180d7f436ed5..2f861b59cbc1 100644
|
||
|
--- a/drivers/infiniband/core/multicast.c
|
||
|
+++ b/drivers/infiniband/core/multicast.c
|
||
|
@@ -516,8 +516,11 @@ static void join_handler(int status, struct ib_sa_mcmember_rec *rec,
|
||
|
if (status)
|
||
|
process_join_error(group, status);
|
||
|
else {
|
||
|
- ib_find_pkey(group->port->dev->device, group->port->port_num,
|
||
|
- be16_to_cpu(rec->pkey), &pkey_index);
|
||
|
+
|
||
|
+ if (ib_find_pkey(group->port->dev->device,
|
||
|
+ group->port->port_num, be16_to_cpu(rec->pkey),
|
||
|
+ &pkey_index))
|
||
|
+ pkey_index = MCAST_INVALID_PKEY_INDEX;
|
||
|
|
||
|
spin_lock_irq(&group->port->lock);
|
||
|
group->rec = *rec;
|
||
|
diff --git a/drivers/infiniband/hw/mlx4/ah.c b/drivers/infiniband/hw/mlx4/ah.c
|
||
|
index f55d69500a5f..3a85e7669068 100644
|
||
|
--- a/drivers/infiniband/hw/mlx4/ah.c
|
||
|
+++ b/drivers/infiniband/hw/mlx4/ah.c
|
||
|
@@ -118,7 +118,9 @@ static struct ib_ah *create_iboe_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr
|
||
|
!(1 << ah->av.eth.stat_rate & dev->caps.stat_rate_support))
|
||
|
--ah->av.eth.stat_rate;
|
||
|
}
|
||
|
-
|
||
|
+ ah->av.eth.sl_tclass_flowlabel |=
|
||
|
+ cpu_to_be32((ah_attr->grh.traffic_class << 20) |
|
||
|
+ ah_attr->grh.flow_label);
|
||
|
/*
|
||
|
* HW requires multicast LID so we just choose one.
|
||
|
*/
|
||
|
@@ -126,7 +128,7 @@ static struct ib_ah *create_iboe_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr
|
||
|
ah->av.ib.dlid = cpu_to_be16(0xc000);
|
||
|
|
||
|
memcpy(ah->av.eth.dgid, ah_attr->grh.dgid.raw, 16);
|
||
|
- ah->av.eth.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 29);
|
||
|
+ ah->av.eth.sl_tclass_flowlabel |= cpu_to_be32(ah_attr->sl << 29);
|
||
|
|
||
|
return &ah->ibah;
|
||
|
}
|
||
|
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
|
||
|
index 23d734349d8e..6b810b12433d 100644
|
||
|
--- a/drivers/infiniband/hw/mlx4/main.c
|
||
|
+++ b/drivers/infiniband/hw/mlx4/main.c
|
||
|
@@ -312,9 +312,11 @@ static int eth_link_query_port(struct ib_device *ibdev, u8 port,
|
||
|
if (err)
|
||
|
goto out;
|
||
|
|
||
|
- props->active_width = (((u8 *)mailbox->buf)[5] == 0x40) ?
|
||
|
- IB_WIDTH_4X : IB_WIDTH_1X;
|
||
|
- props->active_speed = IB_SPEED_QDR;
|
||
|
+ props->active_width = (((u8 *)mailbox->buf)[5] == 0x40) ||
|
||
|
+ (((u8 *)mailbox->buf)[5] == 0x20 /*56Gb*/) ?
|
||
|
+ IB_WIDTH_4X : IB_WIDTH_1X;
|
||
|
+ props->active_speed = (((u8 *)mailbox->buf)[5] == 0x20 /*56Gb*/) ?
|
||
|
+ IB_SPEED_FDR : IB_SPEED_QDR;
|
||
|
props->port_cap_flags = IB_PORT_CM_SUP;
|
||
|
props->gid_tbl_len = mdev->dev->caps.gid_table_len[port];
|
||
|
props->max_msg_sz = mdev->dev->caps.max_msg_sz;
|
||
|
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
|
||
|
index aa9ad2d70ddd..c781c7c633fd 100644
|
||
|
--- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c
|
||
|
+++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
|
||
|
@@ -1482,12 +1482,14 @@ static ssize_t set_mode(struct device *d, struct device_attribute *attr,
|
||
|
|
||
|
ret = ipoib_set_mode(dev, buf);
|
||
|
|
||
|
- rtnl_unlock();
|
||
|
-
|
||
|
- if (!ret)
|
||
|
- return count;
|
||
|
+ /* The assumption is that the function ipoib_set_mode returned
|
||
|
+ * with the rtnl held by it, if not the value -EBUSY returned,
|
||
|
+ * then no need to rtnl_unlock
|
||
|
+ */
|
||
|
+ if (ret != -EBUSY)
|
||
|
+ rtnl_unlock();
|
||
|
|
||
|
- return ret;
|
||
|
+ return (!ret || ret == -EBUSY) ? count : ret;
|
||
|
}
|
||
|
|
||
|
static DEVICE_ATTR(mode, S_IWUSR | S_IRUGO, show_mode, set_mode);
|
||
|
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
|
||
|
index 375f9edd4027..b022d7108101 100644
|
||
|
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
|
||
|
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
|
||
|
@@ -234,8 +234,7 @@ int ipoib_set_mode(struct net_device *dev, const char *buf)
|
||
|
priv->tx_wr.send_flags &= ~IB_SEND_IP_CSUM;
|
||
|
|
||
|
ipoib_flush_paths(dev);
|
||
|
- rtnl_lock();
|
||
|
- return 0;
|
||
|
+ return (!rtnl_trylock()) ? -EBUSY : 0;
|
||
|
}
|
||
|
|
||
|
if (!strcmp(buf, "datagram\n")) {
|
||
|
@@ -244,8 +243,7 @@ int ipoib_set_mode(struct net_device *dev, const char *buf)
|
||
|
dev_set_mtu(dev, min(priv->mcast_mtu, dev->mtu));
|
||
|
rtnl_unlock();
|
||
|
ipoib_flush_paths(dev);
|
||
|
- rtnl_lock();
|
||
|
- return 0;
|
||
|
+ return (!rtnl_trylock()) ? -EBUSY : 0;
|
||
|
}
|
||
|
|
||
|
return -EINVAL;
|
||
|
diff --git a/drivers/input/misc/cm109.c b/drivers/input/misc/cm109.c
|
||
|
index 082684e7f390..d6a35a713856 100644
|
||
|
--- a/drivers/input/misc/cm109.c
|
||
|
+++ b/drivers/input/misc/cm109.c
|
||
|
@@ -669,6 +669,10 @@ static int cm109_usb_probe(struct usb_interface *intf,
|
||
|
int error = -ENOMEM;
|
||
|
|
||
|
interface = intf->cur_altsetting;
|
||
|
+
|
||
|
+ if (interface->desc.bNumEndpoints < 1)
|
||
|
+ return -ENODEV;
|
||
|
+
|
||
|
endpoint = &interface->endpoint[0].desc;
|
||
|
|
||
|
if (!usb_endpoint_is_int_in(endpoint))
|
||
|
diff --git a/drivers/input/misc/ims-pcu.c b/drivers/input/misc/ims-pcu.c
|
||
|
index 77164dc1bedd..8fb814ccfd7a 100644
|
||
|
--- a/drivers/input/misc/ims-pcu.c
|
||
|
+++ b/drivers/input/misc/ims-pcu.c
|
||
|
@@ -1437,6 +1437,10 @@ static int ims_pcu_parse_cdc_data(struct usb_interface *intf, struct ims_pcu *pc
|
||
|
return -EINVAL;
|
||
|
|
||
|
alt = pcu->ctrl_intf->cur_altsetting;
|
||
|
+
|
||
|
+ if (alt->desc.bNumEndpoints < 1)
|
||
|
+ return -ENODEV;
|
||
|
+
|
||
|
pcu->ep_ctrl = &alt->endpoint[0].desc;
|
||
|
pcu->max_ctrl_size = usb_endpoint_maxp(pcu->ep_ctrl);
|
||
|
|
||
|
diff --git a/drivers/input/misc/yealink.c b/drivers/input/misc/yealink.c
|
||
|
index 285a5bd6cbc9..3b6fdb389a2d 100644
|
||
|
--- a/drivers/input/misc/yealink.c
|
||
|
+++ b/drivers/input/misc/yealink.c
|
||
|
@@ -876,6 +876,10 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||
|
int ret, pipe, i;
|
||
|
|
||
|
interface = intf->cur_altsetting;
|
||
|
+
|
||
|
+ if (interface->desc.bNumEndpoints < 1)
|
||
|
+ return -ENODEV;
|
||
|
+
|
||
|
endpoint = &interface->endpoint[0].desc;
|
||
|
if (!usb_endpoint_is_int_in(endpoint))
|
||
|
return -ENODEV;
|
||
|
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
|
||
|
index 5102b4f68f18..875e680e90c2 100644
|
||
|
--- a/drivers/input/serio/i8042-x86ia64io.h
|
||
|
+++ b/drivers/input/serio/i8042-x86ia64io.h
|
||
|
@@ -211,6 +211,12 @@ static const struct dmi_system_id __initconst i8042_dmi_noloop_table[] = {
|
||
|
DMI_MATCH(DMI_PRODUCT_VERSION, "Rev 1"),
|
||
|
},
|
||
|
},
|
||
|
+ {
|
||
|
+ .matches = {
|
||
|
+ DMI_MATCH(DMI_SYS_VENDOR, "PEGATRON CORPORATION"),
|
||
|
+ DMI_MATCH(DMI_PRODUCT_NAME, "C15B"),
|
||
|
+ },
|
||
|
+ },
|
||
|
{ }
|
||
|
};
|
||
|
|
||
|
diff --git a/drivers/input/tablet/hanwang.c b/drivers/input/tablet/hanwang.c
|
||
|
index 5cc04124995c..263c85e72e14 100644
|
||
|
--- a/drivers/input/tablet/hanwang.c
|
||
|
+++ b/drivers/input/tablet/hanwang.c
|
||
|
@@ -341,6 +341,9 @@ static int hanwang_probe(struct usb_interface *intf, const struct usb_device_id
|
||
|
int error;
|
||
|
int i;
|
||
|
|
||
|
+ if (intf->cur_altsetting->desc.bNumEndpoints < 1)
|
||
|
+ return -ENODEV;
|
||
|
+
|
||
|
hanwang = kzalloc(sizeof(struct hanwang), GFP_KERNEL);
|
||
|
input_dev = input_allocate_device();
|
||
|
if (!hanwang || !input_dev) {
|
||
|
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
|
||
|
index 1c62c248da6a..0e7cd14bf7bb 100644
|
||
|
--- a/drivers/iommu/amd_iommu.c
|
||
|
+++ b/drivers/iommu/amd_iommu.c
|
||
|
@@ -1029,7 +1029,7 @@ again:
|
||
|
next_tail = (tail + sizeof(*cmd)) % iommu->cmd_buf_size;
|
||
|
left = (head - next_tail) % iommu->cmd_buf_size;
|
||
|
|
||
|
- if (left <= 2) {
|
||
|
+ if (left <= 0x20) {
|
||
|
struct iommu_cmd sync_cmd;
|
||
|
volatile u64 sem = 0;
|
||
|
int ret;
|
||
|
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c
|
||
|
index c44950d3eb7b..6d4d9c1c2cf0 100644
|
||
|
--- a/drivers/isdn/gigaset/bas-gigaset.c
|
||
|
+++ b/drivers/isdn/gigaset/bas-gigaset.c
|
||
|
@@ -2317,6 +2317,9 @@ static int gigaset_probe(struct usb_interface *interface,
|
||
|
return -ENODEV;
|
||
|
}
|
||
|
|
||
|
+ if (hostif->desc.bNumEndpoints < 1)
|
||
|
+ return -ENODEV;
|
||
|
+
|
||
|
dev_info(&udev->dev,
|
||
|
"%s: Device matched (Vendor: 0x%x, Product: 0x%x)\n",
|
||
|
__func__, le16_to_cpu(udev->descriptor.idVendor),
|
||
|
diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c
|
||
|
index 3ac9c4194814..53dfe1693e50 100644
|
||
|
--- a/drivers/isdn/gigaset/ser-gigaset.c
|
||
|
+++ b/drivers/isdn/gigaset/ser-gigaset.c
|
||
|
@@ -787,8 +787,10 @@ static int __init ser_gigaset_init(void)
|
||
|
driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS,
|
||
|
GIGASET_MODULENAME, GIGASET_DEVNAME,
|
||
|
&ops, THIS_MODULE);
|
||
|
- if (!driver)
|
||
|
+ if (!driver) {
|
||
|
+ rc = -ENOMEM;
|
||
|
goto error;
|
||
|
+ }
|
||
|
|
||
|
rc = tty_register_ldisc(N_GIGASET_M101, &gigaset_ldisc);
|
||
|
if (rc != 0) {
|
||
|
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
|
||
|
index a77ef6cac62d..975bb316a552 100644
|
||
|
--- a/drivers/md/dm.c
|
||
|
+++ b/drivers/md/dm.c
|
||
|
@@ -976,11 +976,62 @@ int dm_set_target_max_io_len(struct dm_target *ti, sector_t len)
|
||
|
}
|
||
|
EXPORT_SYMBOL_GPL(dm_set_target_max_io_len);
|
||
|
|
||
|
+/*
|
||
|
+ * Flush current->bio_list when the target map method blocks.
|
||
|
+ * This fixes deadlocks in snapshot and possibly in other targets.
|
||
|
+ */
|
||
|
+struct dm_offload {
|
||
|
+ struct blk_plug plug;
|
||
|
+ struct blk_plug_cb cb;
|
||
|
+};
|
||
|
+
|
||
|
+static void flush_current_bio_list(struct blk_plug_cb *cb, bool from_schedule)
|
||
|
+{
|
||
|
+ struct dm_offload *o = container_of(cb, struct dm_offload, cb);
|
||
|
+ struct bio_list list;
|
||
|
+ struct bio *bio;
|
||
|
+
|
||
|
+ INIT_LIST_HEAD(&o->cb.list);
|
||
|
+
|
||
|
+ if (unlikely(!current->bio_list))
|
||
|
+ return;
|
||
|
+
|
||
|
+ list = *current->bio_list;
|
||
|
+ bio_list_init(current->bio_list);
|
||
|
+
|
||
|
+ while ((bio = bio_list_pop(&list))) {
|
||
|
+ struct bio_set *bs = bio->bi_pool;
|
||
|
+ if (unlikely(!bs) || bs == fs_bio_set) {
|
||
|
+ bio_list_add(current->bio_list, bio);
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+
|
||
|
+ spin_lock(&bs->rescue_lock);
|
||
|
+ bio_list_add(&bs->rescue_list, bio);
|
||
|
+ queue_work(bs->rescue_workqueue, &bs->rescue_work);
|
||
|
+ spin_unlock(&bs->rescue_lock);
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+static void dm_offload_start(struct dm_offload *o)
|
||
|
+{
|
||
|
+ blk_start_plug(&o->plug);
|
||
|
+ o->cb.callback = flush_current_bio_list;
|
||
|
+ list_add(&o->cb.list, ¤t->plug->cb_list);
|
||
|
+}
|
||
|
+
|
||
|
+static void dm_offload_end(struct dm_offload *o)
|
||
|
+{
|
||
|
+ list_del(&o->cb.list);
|
||
|
+ blk_finish_plug(&o->plug);
|
||
|
+}
|
||
|
+
|
||
|
static void __map_bio(struct dm_target_io *tio)
|
||
|
{
|
||
|
int r;
|
||
|
sector_t sector;
|
||
|
struct mapped_device *md;
|
||
|
+ struct dm_offload o;
|
||
|
struct bio *clone = &tio->clone;
|
||
|
struct dm_target *ti = tio->ti;
|
||
|
|
||
|
@@ -994,7 +1045,11 @@ static void __map_bio(struct dm_target_io *tio)
|
||
|
*/
|
||
|
atomic_inc(&tio->io->io_count);
|
||
|
sector = clone->bi_sector;
|
||
|
+
|
||
|
+ dm_offload_start(&o);
|
||
|
r = ti->type->map(ti, clone);
|
||
|
+ dm_offload_end(&o);
|
||
|
+
|
||
|
if (r == DM_MAPIO_REMAPPED) {
|
||
|
/* the bio has been remapped so dispatch it */
|
||
|
|
||
|
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
|
||
|
index f981d50a2a8c..936ef2f881f0 100644
|
||
|
--- a/drivers/media/i2c/Kconfig
|
||
|
+++ b/drivers/media/i2c/Kconfig
|
||
|
@@ -549,6 +549,7 @@ config VIDEO_S5K6AA
|
||
|
config VIDEO_S5K4ECGX
|
||
|
tristate "Samsung S5K4ECGX sensor support"
|
||
|
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
|
||
|
+ select CRC32
|
||
|
---help---
|
||
|
This is a V4L2 sensor-level driver for Samsung S5K4ECGX 5M
|
||
|
camera sensor with an embedded SoC image signal processor.
|
||
|
diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c
|
||
|
index 63b42252166a..7a754ec826ac 100644
|
||
|
--- a/drivers/media/rc/ite-cir.c
|
||
|
+++ b/drivers/media/rc/ite-cir.c
|
||
|
@@ -263,6 +263,8 @@ static void ite_set_carrier_params(struct ite_dev *dev)
|
||
|
|
||
|
if (allowance > ITE_RXDCR_MAX)
|
||
|
allowance = ITE_RXDCR_MAX;
|
||
|
+
|
||
|
+ use_demodulator = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
diff --git a/drivers/media/tuners/tuner-xc2028.c b/drivers/media/tuners/tuner-xc2028.c
|
||
|
index 9771cd83c06e..3a615e4c4991 100644
|
||
|
--- a/drivers/media/tuners/tuner-xc2028.c
|
||
|
+++ b/drivers/media/tuners/tuner-xc2028.c
|
||
|
@@ -289,6 +289,14 @@ static void free_firmware(struct xc2028_data *priv)
|
||
|
int i;
|
||
|
tuner_dbg("%s called\n", __func__);
|
||
|
|
||
|
+ /* free allocated f/w string */
|
||
|
+ if (priv->fname != firmware_name)
|
||
|
+ kfree(priv->fname);
|
||
|
+ priv->fname = NULL;
|
||
|
+
|
||
|
+ priv->state = XC2028_NO_FIRMWARE;
|
||
|
+ memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
|
||
|
+
|
||
|
if (!priv->firm)
|
||
|
return;
|
||
|
|
||
|
@@ -299,9 +307,6 @@ static void free_firmware(struct xc2028_data *priv)
|
||
|
|
||
|
priv->firm = NULL;
|
||
|
priv->firm_size = 0;
|
||
|
- priv->state = XC2028_NO_FIRMWARE;
|
||
|
-
|
||
|
- memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
|
||
|
}
|
||
|
|
||
|
static int load_all_firmwares(struct dvb_frontend *fe,
|
||
|
@@ -890,9 +895,9 @@ read_not_reliable:
|
||
|
return 0;
|
||
|
|
||
|
fail:
|
||
|
+ free_firmware(priv);
|
||
|
priv->state = XC2028_SLEEP;
|
||
|
|
||
|
- memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
|
||
|
if (retry_count < 8) {
|
||
|
msleep(50);
|
||
|
retry_count++;
|
||
|
@@ -1314,11 +1319,8 @@ static int xc2028_dvb_release(struct dvb_frontend *fe)
|
||
|
mutex_lock(&xc2028_list_mutex);
|
||
|
|
||
|
/* only perform final cleanup if this is the last instance */
|
||
|
- if (hybrid_tuner_report_instance_count(priv) == 1) {
|
||
|
+ if (hybrid_tuner_report_instance_count(priv) == 1)
|
||
|
free_firmware(priv);
|
||
|
- kfree(priv->ctrl.fname);
|
||
|
- priv->ctrl.fname = NULL;
|
||
|
- }
|
||
|
|
||
|
if (priv)
|
||
|
hybrid_tuner_release_state(priv);
|
||
|
@@ -1381,16 +1383,8 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg)
|
||
|
|
||
|
/*
|
||
|
* Copy the config data.
|
||
|
- * For the firmware name, keep a local copy of the string,
|
||
|
- * in order to avoid troubles during device release.
|
||
|
*/
|
||
|
- kfree(priv->ctrl.fname);
|
||
|
memcpy(&priv->ctrl, p, sizeof(priv->ctrl));
|
||
|
- if (p->fname) {
|
||
|
- priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL);
|
||
|
- if (priv->ctrl.fname == NULL)
|
||
|
- rc = -ENOMEM;
|
||
|
- }
|
||
|
|
||
|
/*
|
||
|
* If firmware name changed, frees firmware. As free_firmware will
|
||
|
@@ -1405,10 +1399,15 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg)
|
||
|
|
||
|
if (priv->state == XC2028_NO_FIRMWARE) {
|
||
|
if (!firmware_name[0])
|
||
|
- priv->fname = priv->ctrl.fname;
|
||
|
+ priv->fname = kstrdup(p->fname, GFP_KERNEL);
|
||
|
else
|
||
|
priv->fname = firmware_name;
|
||
|
|
||
|
+ if (!priv->fname) {
|
||
|
+ rc = -ENOMEM;
|
||
|
+ goto unlock;
|
||
|
+ }
|
||
|
+
|
||
|
rc = request_firmware_nowait(THIS_MODULE, 1,
|
||
|
priv->fname,
|
||
|
priv->i2c_props.adap->dev.parent,
|
||
|
@@ -1421,6 +1420,7 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg)
|
||
|
} else
|
||
|
priv->state = XC2028_WAITING_FIRMWARE;
|
||
|
}
|
||
|
+unlock:
|
||
|
mutex_unlock(&priv->lock);
|
||
|
|
||
|
return rc;
|
||
|
diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c
|
||
|
index cd962be860ca..7e743958dbce 100644
|
||
|
--- a/drivers/media/usb/uvc/uvc_queue.c
|
||
|
+++ b/drivers/media/usb/uvc/uvc_queue.c
|
||
|
@@ -375,7 +375,7 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
|
||
|
nextbuf = NULL;
|
||
|
spin_unlock_irqrestore(&queue->irqlock, flags);
|
||
|
|
||
|
- buf->state = buf->error ? VB2_BUF_STATE_ERROR : UVC_BUF_STATE_DONE;
|
||
|
+ buf->state = buf->error ? UVC_BUF_STATE_ERROR : UVC_BUF_STATE_DONE;
|
||
|
vb2_set_plane_payload(&buf->buf, 0, buf->bytesused);
|
||
|
vb2_buffer_done(&buf->buf, VB2_BUF_STATE_DONE);
|
||
|
|
||
|
diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c
|
||
|
index ecc137ffa8c3..a28f434147fe 100644
|
||
|
--- a/drivers/mfd/pm8921-core.c
|
||
|
+++ b/drivers/mfd/pm8921-core.c
|
||
|
@@ -173,11 +173,12 @@ static int pm8921_remove(struct platform_device *pdev)
|
||
|
drvdata = platform_get_drvdata(pdev);
|
||
|
if (drvdata)
|
||
|
pmic = drvdata->pm_chip_data;
|
||
|
- if (pmic)
|
||
|
+ if (pmic) {
|
||
|
mfd_remove_devices(pmic->dev);
|
||
|
- if (pmic->irq_chip) {
|
||
|
- pm8xxx_irq_exit(pmic->irq_chip);
|
||
|
- pmic->irq_chip = NULL;
|
||
|
+ if (pmic->irq_chip) {
|
||
|
+ pm8xxx_irq_exit(pmic->irq_chip);
|
||
|
+ pmic->irq_chip = NULL;
|
||
|
+ }
|
||
|
}
|
||
|
platform_set_drvdata(pdev, NULL);
|
||
|
kfree(pmic);
|
||
|
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c
|
||
|
index 759714ed6bee..abad0b49bd7a 100644
|
||
|
--- a/drivers/mmc/card/mmc_test.c
|
||
|
+++ b/drivers/mmc/card/mmc_test.c
|
||
|
@@ -795,7 +795,7 @@ static int mmc_test_nonblock_transfer(struct mmc_test_card *test,
|
||
|
struct mmc_async_req *cur_areq = &test_areq[0].areq;
|
||
|
struct mmc_async_req *other_areq = &test_areq[1].areq;
|
||
|
int i;
|
||
|
- int ret;
|
||
|
+ int ret = RESULT_OK;
|
||
|
|
||
|
test_areq[0].test = test;
|
||
|
test_areq[1].test = test;
|
||
|
diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c
|
||
|
index f3a423213108..01951cd6599c 100644
|
||
|
--- a/drivers/mmc/host/mxs-mmc.c
|
||
|
+++ b/drivers/mmc/host/mxs-mmc.c
|
||
|
@@ -312,6 +312,9 @@ static void mxs_mmc_ac(struct mxs_mmc_host *host)
|
||
|
cmd0 = BF_SSP(cmd->opcode, CMD0_CMD);
|
||
|
cmd1 = cmd->arg;
|
||
|
|
||
|
+ if (cmd->opcode == MMC_STOP_TRANSMISSION)
|
||
|
+ cmd0 |= BM_SSP_CMD0_APPEND_8CYC;
|
||
|
+
|
||
|
if (host->sdio_irq_en) {
|
||
|
ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK;
|
||
|
cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN | BM_SSP_CMD0_SLOW_CLKING_EN;
|
||
|
@@ -420,8 +423,7 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host)
|
||
|
ssp->base + HW_SSP_BLOCK_SIZE);
|
||
|
}
|
||
|
|
||
|
- if ((cmd->opcode == MMC_STOP_TRANSMISSION) ||
|
||
|
- (cmd->opcode == SD_IO_RW_EXTENDED))
|
||
|
+ if (cmd->opcode == SD_IO_RW_EXTENDED)
|
||
|
cmd0 |= BM_SSP_CMD0_APPEND_8CYC;
|
||
|
|
||
|
cmd1 = cmd->arg;
|
||
|
diff --git a/drivers/mmc/host/ushc.c b/drivers/mmc/host/ushc.c
|
||
|
index c0105a2e269a..d5493a5a7e7c 100644
|
||
|
--- a/drivers/mmc/host/ushc.c
|
||
|
+++ b/drivers/mmc/host/ushc.c
|
||
|
@@ -426,6 +426,9 @@ static int ushc_probe(struct usb_interface *intf, const struct usb_device_id *id
|
||
|
struct ushc_data *ushc;
|
||
|
int ret;
|
||
|
|
||
|
+ if (intf->cur_altsetting->desc.bNumEndpoints < 1)
|
||
|
+ return -ENODEV;
|
||
|
+
|
||
|
mmc = mmc_alloc_host(sizeof(struct ushc_data), &intf->dev);
|
||
|
if (mmc == NULL)
|
||
|
return -ENOMEM;
|
||
|
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
|
||
|
index 50543f166215..faab8cdc1c9b 100644
|
||
|
--- a/drivers/mtd/nand/Kconfig
|
||
|
+++ b/drivers/mtd/nand/Kconfig
|
||
|
@@ -537,7 +537,7 @@ config MTD_NAND_FSMC
|
||
|
Flexible Static Memory Controller (FSMC)
|
||
|
|
||
|
config MTD_NAND_XWAY
|
||
|
- tristate "Support for NAND on Lantiq XWAY SoC"
|
||
|
+ bool "Support for NAND on Lantiq XWAY SoC"
|
||
|
depends on LANTIQ && SOC_TYPE_XWAY
|
||
|
select MTD_NAND_PLATFORM
|
||
|
help
|
||
|
diff --git a/drivers/net/ethernet/mellanox/mlx4/cq.c b/drivers/net/ethernet/mellanox/mlx4/cq.c
|
||
|
index 004e4231af67..528597f65937 100644
|
||
|
--- a/drivers/net/ethernet/mellanox/mlx4/cq.c
|
||
|
+++ b/drivers/net/ethernet/mellanox/mlx4/cq.c
|
||
|
@@ -57,13 +57,19 @@ void mlx4_cq_completion(struct mlx4_dev *dev, u32 cqn)
|
||
|
{
|
||
|
struct mlx4_cq *cq;
|
||
|
|
||
|
+ rcu_read_lock();
|
||
|
cq = radix_tree_lookup(&mlx4_priv(dev)->cq_table.tree,
|
||
|
cqn & (dev->caps.num_cqs - 1));
|
||
|
+ rcu_read_unlock();
|
||
|
+
|
||
|
if (!cq) {
|
||
|
mlx4_dbg(dev, "Completion event for bogus CQ %08x\n", cqn);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
+ /* Acessing the CQ outside of rcu_read_lock is safe, because
|
||
|
+ * the CQ is freed only after interrupt handling is completed.
|
||
|
+ */
|
||
|
++cq->arm_sn;
|
||
|
|
||
|
cq->comp(cq);
|
||
|
@@ -74,23 +80,19 @@ void mlx4_cq_event(struct mlx4_dev *dev, u32 cqn, int event_type)
|
||
|
struct mlx4_cq_table *cq_table = &mlx4_priv(dev)->cq_table;
|
||
|
struct mlx4_cq *cq;
|
||
|
|
||
|
- spin_lock(&cq_table->lock);
|
||
|
-
|
||
|
+ rcu_read_lock();
|
||
|
cq = radix_tree_lookup(&cq_table->tree, cqn & (dev->caps.num_cqs - 1));
|
||
|
- if (cq)
|
||
|
- atomic_inc(&cq->refcount);
|
||
|
-
|
||
|
- spin_unlock(&cq_table->lock);
|
||
|
+ rcu_read_unlock();
|
||
|
|
||
|
if (!cq) {
|
||
|
- mlx4_warn(dev, "Async event for bogus CQ %08x\n", cqn);
|
||
|
+ mlx4_dbg(dev, "Async event for bogus CQ %08x\n", cqn);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
+ /* Acessing the CQ outside of rcu_read_lock is safe, because
|
||
|
+ * the CQ is freed only after interrupt handling is completed.
|
||
|
+ */
|
||
|
cq->event(cq, event_type);
|
||
|
-
|
||
|
- if (atomic_dec_and_test(&cq->refcount))
|
||
|
- complete(&cq->free);
|
||
|
}
|
||
|
|
||
|
static int mlx4_SW2HW_CQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
|
||
|
@@ -261,9 +263,9 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent,
|
||
|
if (err)
|
||
|
return err;
|
||
|
|
||
|
- spin_lock_irq(&cq_table->lock);
|
||
|
+ spin_lock(&cq_table->lock);
|
||
|
err = radix_tree_insert(&cq_table->tree, cq->cqn, cq);
|
||
|
- spin_unlock_irq(&cq_table->lock);
|
||
|
+ spin_unlock(&cq_table->lock);
|
||
|
if (err)
|
||
|
goto err_icm;
|
||
|
|
||
|
@@ -303,9 +305,9 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent,
|
||
|
return 0;
|
||
|
|
||
|
err_radix:
|
||
|
- spin_lock_irq(&cq_table->lock);
|
||
|
+ spin_lock(&cq_table->lock);
|
||
|
radix_tree_delete(&cq_table->tree, cq->cqn);
|
||
|
- spin_unlock_irq(&cq_table->lock);
|
||
|
+ spin_unlock(&cq_table->lock);
|
||
|
|
||
|
err_icm:
|
||
|
mlx4_cq_free_icm(dev, cq->cqn);
|
||
|
@@ -324,11 +326,11 @@ void mlx4_cq_free(struct mlx4_dev *dev, struct mlx4_cq *cq)
|
||
|
if (err)
|
||
|
mlx4_warn(dev, "HW2SW_CQ failed (%d) for CQN %06x\n", err, cq->cqn);
|
||
|
|
||
|
- synchronize_irq(priv->eq_table.eq[cq->vector].irq);
|
||
|
-
|
||
|
- spin_lock_irq(&cq_table->lock);
|
||
|
+ spin_lock(&cq_table->lock);
|
||
|
radix_tree_delete(&cq_table->tree, cq->cqn);
|
||
|
- spin_unlock_irq(&cq_table->lock);
|
||
|
+ spin_unlock(&cq_table->lock);
|
||
|
+
|
||
|
+ synchronize_irq(priv->eq_table.eq[cq->vector].irq);
|
||
|
|
||
|
if (atomic_dec_and_test(&cq->refcount))
|
||
|
complete(&cq->free);
|
||
|
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
|
||
|
index 02aee1ebd203..2a541500ad2e 100644
|
||
|
--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
|
||
|
+++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
|
||
|
@@ -350,8 +350,14 @@ int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv)
|
||
|
ring->cqn = priv->rx_cq[ring_ind].mcq.cqn;
|
||
|
|
||
|
ring->stride = stride;
|
||
|
- if (ring->stride <= TXBB_SIZE)
|
||
|
+ if (ring->stride <= TXBB_SIZE) {
|
||
|
+ /* Stamp first unused send wqe */
|
||
|
+ __be32 *ptr = (__be32 *)ring->buf;
|
||
|
+ __be32 stamp = cpu_to_be32(1 << STAMP_SHIFT);
|
||
|
+ *ptr = stamp;
|
||
|
+ /* Move pointer to start of rx section */
|
||
|
ring->buf += TXBB_SIZE;
|
||
|
+ }
|
||
|
|
||
|
ring->log_stride = ffs(ring->stride) - 1;
|
||
|
ring->buf_size = ring->size * ring->stride;
|
||
|
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
|
||
|
index e9eab29db7be..5cb09ecfd75f 100644
|
||
|
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
|
||
|
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
|
||
|
@@ -2697,12 +2697,6 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
|
||
|
spin_lock_init(&priv->lock);
|
||
|
spin_lock_init(&priv->tx_lock);
|
||
|
|
||
|
- ret = register_netdev(ndev);
|
||
|
- if (ret) {
|
||
|
- pr_err("%s: ERROR %i registering the device\n", __func__, ret);
|
||
|
- goto error_netdev_register;
|
||
|
- }
|
||
|
-
|
||
|
priv->stmmac_clk = clk_get(priv->device, STMMAC_RESOURCE_NAME);
|
||
|
if (IS_ERR(priv->stmmac_clk)) {
|
||
|
pr_warn("%s: warning: cannot get CSR clock\n", __func__);
|
||
|
@@ -2733,13 +2727,23 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+ ret = register_netdev(ndev);
|
||
|
+ if (ret) {
|
||
|
+ netdev_err(priv->dev, "%s: ERROR %i registering the device\n",
|
||
|
+ __func__, ret);
|
||
|
+ goto error_netdev_register;
|
||
|
+ }
|
||
|
+
|
||
|
return priv;
|
||
|
|
||
|
+error_netdev_register:
|
||
|
+ if (priv->pcs != STMMAC_PCS_RGMII &&
|
||
|
+ priv->pcs != STMMAC_PCS_TBI &&
|
||
|
+ priv->pcs != STMMAC_PCS_RTBI)
|
||
|
+ stmmac_mdio_unregister(ndev);
|
||
|
error_mdio_register:
|
||
|
clk_put(priv->stmmac_clk);
|
||
|
error_clk_get:
|
||
|
- unregister_netdev(ndev);
|
||
|
-error_netdev_register:
|
||
|
netif_napi_del(&priv->napi);
|
||
|
error_free_netdev:
|
||
|
free_netdev(ndev);
|
||
|
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
|
||
|
index 299d35552a3e..bd245c3039ec 100644
|
||
|
--- a/drivers/net/phy/phy.c
|
||
|
+++ b/drivers/net/phy/phy.c
|
||
|
@@ -474,7 +474,7 @@ void phy_stop_machine(struct phy_device *phydev)
|
||
|
cancel_delayed_work_sync(&phydev->state_queue);
|
||
|
|
||
|
mutex_lock(&phydev->lock);
|
||
|
- if (phydev->state > PHY_UP)
|
||
|
+ if (phydev->state > PHY_UP && phydev->state != PHY_HALTED)
|
||
|
phydev->state = PHY_UP;
|
||
|
mutex_unlock(&phydev->lock);
|
||
|
|
||
|
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
|
||
|
index 582497103fe8..ea6ada39db15 100644
|
||
|
--- a/drivers/net/tun.c
|
||
|
+++ b/drivers/net/tun.c
|
||
|
@@ -1272,12 +1272,16 @@ static ssize_t tun_put_user(struct tun_struct *tun,
|
||
|
{
|
||
|
struct tun_pi pi = { 0, skb->protocol };
|
||
|
ssize_t total = 0;
|
||
|
+ int vnet_hdr_sz = 0;
|
||
|
+
|
||
|
+ if (tun->flags & TUN_VNET_HDR)
|
||
|
+ vnet_hdr_sz = tun->vnet_hdr_sz;
|
||
|
|
||
|
if (!(tun->flags & TUN_NO_PI)) {
|
||
|
if ((len -= sizeof(pi)) < 0)
|
||
|
return -EINVAL;
|
||
|
|
||
|
- if (len < skb->len) {
|
||
|
+ if (len < skb->len + vnet_hdr_sz) {
|
||
|
/* Packet will be striped */
|
||
|
pi.flags |= TUN_PKT_STRIP;
|
||
|
}
|
||
|
@@ -1287,9 +1291,9 @@ static ssize_t tun_put_user(struct tun_struct *tun,
|
||
|
total += sizeof(pi);
|
||
|
}
|
||
|
|
||
|
- if (tun->flags & TUN_VNET_HDR) {
|
||
|
+ if (vnet_hdr_sz) {
|
||
|
struct virtio_net_hdr gso = { 0 }; /* no info leak */
|
||
|
- if ((len -= tun->vnet_hdr_sz) < 0)
|
||
|
+ if ((len -= vnet_hdr_sz) < 0)
|
||
|
return -EINVAL;
|
||
|
|
||
|
if (skb_is_gso(skb)) {
|
||
|
@@ -1332,7 +1336,7 @@ static ssize_t tun_put_user(struct tun_struct *tun,
|
||
|
if (unlikely(memcpy_toiovecend(iv, (void *)&gso, total,
|
||
|
sizeof(gso))))
|
||
|
return -EFAULT;
|
||
|
- total += tun->vnet_hdr_sz;
|
||
|
+ total += vnet_hdr_sz;
|
||
|
}
|
||
|
|
||
|
len = min_t(int, skb->len, len);
|
||
|
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
|
||
|
index 03e8a15d7deb..f32a57ed1d13 100644
|
||
|
--- a/drivers/net/usb/pegasus.c
|
||
|
+++ b/drivers/net/usb/pegasus.c
|
||
|
@@ -126,40 +126,61 @@ static void async_ctrl_callback(struct urb *urb)
|
||
|
|
||
|
static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
|
||
|
{
|
||
|
+ u8 *buf;
|
||
|
int ret;
|
||
|
|
||
|
+ buf = kmalloc(size, GFP_NOIO);
|
||
|
+ if (!buf)
|
||
|
+ return -ENOMEM;
|
||
|
+
|
||
|
ret = usb_control_msg(pegasus->usb, usb_rcvctrlpipe(pegasus->usb, 0),
|
||
|
PEGASUS_REQ_GET_REGS, PEGASUS_REQT_READ, 0,
|
||
|
- indx, data, size, 1000);
|
||
|
+ indx, buf, size, 1000);
|
||
|
if (ret < 0)
|
||
|
netif_dbg(pegasus, drv, pegasus->net,
|
||
|
"%s returned %d\n", __func__, ret);
|
||
|
+ else if (ret <= size)
|
||
|
+ memcpy(data, buf, ret);
|
||
|
+ kfree(buf);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
-static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
|
||
|
+static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size,
|
||
|
+ const void *data)
|
||
|
{
|
||
|
+ u8 *buf;
|
||
|
int ret;
|
||
|
|
||
|
+ buf = kmemdup(data, size, GFP_NOIO);
|
||
|
+ if (!buf)
|
||
|
+ return -ENOMEM;
|
||
|
+
|
||
|
ret = usb_control_msg(pegasus->usb, usb_sndctrlpipe(pegasus->usb, 0),
|
||
|
PEGASUS_REQ_SET_REGS, PEGASUS_REQT_WRITE, 0,
|
||
|
- indx, data, size, 100);
|
||
|
+ indx, buf, size, 100);
|
||
|
if (ret < 0)
|
||
|
netif_dbg(pegasus, drv, pegasus->net,
|
||
|
"%s returned %d\n", __func__, ret);
|
||
|
+ kfree(buf);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static int set_register(pegasus_t *pegasus, __u16 indx, __u8 data)
|
||
|
{
|
||
|
+ u8 *buf;
|
||
|
int ret;
|
||
|
|
||
|
+ buf = kmemdup(&data, 1, GFP_NOIO);
|
||
|
+ if (!buf)
|
||
|
+ return -ENOMEM;
|
||
|
+
|
||
|
ret = usb_control_msg(pegasus->usb, usb_sndctrlpipe(pegasus->usb, 0),
|
||
|
PEGASUS_REQ_SET_REG, PEGASUS_REQT_WRITE, data,
|
||
|
- indx, &data, 1, 1000);
|
||
|
+ indx, buf, 1, 1000);
|
||
|
if (ret < 0)
|
||
|
netif_dbg(pegasus, drv, pegasus->net,
|
||
|
"%s returned %d\n", __func__, ret);
|
||
|
+ kfree(buf);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c
|
||
|
index 6cbdac67f3a0..59d6a3a5830a 100644
|
||
|
--- a/drivers/net/usb/rtl8150.c
|
||
|
+++ b/drivers/net/usb/rtl8150.c
|
||
|
@@ -156,16 +156,36 @@ static const char driver_name [] = "rtl8150";
|
||
|
*/
|
||
|
static int get_registers(rtl8150_t * dev, u16 indx, u16 size, void *data)
|
||
|
{
|
||
|
- return usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
|
||
|
- RTL8150_REQ_GET_REGS, RTL8150_REQT_READ,
|
||
|
- indx, 0, data, size, 500);
|
||
|
+ void *buf;
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ buf = kmalloc(size, GFP_NOIO);
|
||
|
+ if (!buf)
|
||
|
+ return -ENOMEM;
|
||
|
+
|
||
|
+ ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
|
||
|
+ RTL8150_REQ_GET_REGS, RTL8150_REQT_READ,
|
||
|
+ indx, 0, buf, size, 500);
|
||
|
+ if (ret > 0 && ret <= size)
|
||
|
+ memcpy(data, buf, ret);
|
||
|
+ kfree(buf);
|
||
|
+ return ret;
|
||
|
}
|
||
|
|
||
|
-static int set_registers(rtl8150_t * dev, u16 indx, u16 size, void *data)
|
||
|
+static int set_registers(rtl8150_t * dev, u16 indx, u16 size, const void *data)
|
||
|
{
|
||
|
- return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
|
||
|
- RTL8150_REQ_SET_REGS, RTL8150_REQT_WRITE,
|
||
|
- indx, 0, data, size, 500);
|
||
|
+ void *buf;
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ buf = kmemdup(data, size, GFP_NOIO);
|
||
|
+ if (!buf)
|
||
|
+ return -ENOMEM;
|
||
|
+
|
||
|
+ ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
|
||
|
+ RTL8150_REQ_SET_REGS, RTL8150_REQT_WRITE,
|
||
|
+ indx, 0, buf, size, 500);
|
||
|
+ kfree(buf);
|
||
|
+ return ret;
|
||
|
}
|
||
|
|
||
|
static void async_set_reg_cb(struct urb *urb)
|
||
|
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
|
||
|
index a1dc186c6f66..8912ba83fd77 100644
|
||
|
--- a/drivers/net/vxlan.c
|
||
|
+++ b/drivers/net/vxlan.c
|
||
|
@@ -1386,7 +1386,7 @@ static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[])
|
||
|
|
||
|
if (data[IFLA_VXLAN_ID]) {
|
||
|
__u32 id = nla_get_u32(data[IFLA_VXLAN_ID]);
|
||
|
- if (id >= VXLAN_VID_MASK)
|
||
|
+ if (id >= VXLAN_N_VID)
|
||
|
return -ERANGE;
|
||
|
}
|
||
|
|
||
|
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
|
||
|
index 874f6570bd1c..d83ad9df6603 100644
|
||
|
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
|
||
|
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
|
||
|
@@ -71,13 +71,13 @@
|
||
|
#define AR9300_OTP_BASE \
|
||
|
((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x30000 : 0x14000)
|
||
|
#define AR9300_OTP_STATUS \
|
||
|
- ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x30018 : 0x15f18)
|
||
|
+ ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x31018 : 0x15f18)
|
||
|
#define AR9300_OTP_STATUS_TYPE 0x7
|
||
|
#define AR9300_OTP_STATUS_VALID 0x4
|
||
|
#define AR9300_OTP_STATUS_ACCESS_BUSY 0x2
|
||
|
#define AR9300_OTP_STATUS_SM_BUSY 0x1
|
||
|
#define AR9300_OTP_READ_DATA \
|
||
|
- ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x3001c : 0x15f1c)
|
||
|
+ ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x3101c : 0x15f1c)
|
||
|
|
||
|
enum targetPowerHTRates {
|
||
|
HT_TARGET_RATE_0_8_16,
|
||
|
diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c
|
||
|
index b29e20b7862f..ffb2de5c4d50 100644
|
||
|
--- a/drivers/pci/hotplug/rpadlpar_core.c
|
||
|
+++ b/drivers/pci/hotplug/rpadlpar_core.c
|
||
|
@@ -259,8 +259,13 @@ static int dlpar_add_phb(char *drc_name, struct device_node *dn)
|
||
|
|
||
|
static int dlpar_add_vio_slot(char *drc_name, struct device_node *dn)
|
||
|
{
|
||
|
- if (vio_find_node(dn))
|
||
|
+ struct vio_dev *vio_dev;
|
||
|
+
|
||
|
+ vio_dev = vio_find_node(dn);
|
||
|
+ if (vio_dev) {
|
||
|
+ put_device(&vio_dev->dev);
|
||
|
return -EINVAL;
|
||
|
+ }
|
||
|
|
||
|
if (!vio_register_device_node(dn)) {
|
||
|
printk(KERN_ERR
|
||
|
@@ -336,6 +341,9 @@ static int dlpar_remove_vio_slot(char *drc_name, struct device_node *dn)
|
||
|
return -EINVAL;
|
||
|
|
||
|
vio_unregister_device(vio_dev);
|
||
|
+
|
||
|
+ put_device(&vio_dev->dev);
|
||
|
+
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
diff --git a/drivers/platform/goldfish/pdev_bus.c b/drivers/platform/goldfish/pdev_bus.c
|
||
|
index 92cc4cfafde5..6bcd57cb2f75 100644
|
||
|
--- a/drivers/platform/goldfish/pdev_bus.c
|
||
|
+++ b/drivers/platform/goldfish/pdev_bus.c
|
||
|
@@ -153,23 +153,26 @@ static int goldfish_new_pdev(void)
|
||
|
static irqreturn_t goldfish_pdev_bus_interrupt(int irq, void *dev_id)
|
||
|
{
|
||
|
irqreturn_t ret = IRQ_NONE;
|
||
|
+
|
||
|
while (1) {
|
||
|
u32 op = readl(pdev_bus_base + PDEV_BUS_OP);
|
||
|
- switch (op) {
|
||
|
- case PDEV_BUS_OP_DONE:
|
||
|
- return IRQ_NONE;
|
||
|
|
||
|
+ switch (op) {
|
||
|
case PDEV_BUS_OP_REMOVE_DEV:
|
||
|
goldfish_pdev_remove();
|
||
|
+ ret = IRQ_HANDLED;
|
||
|
break;
|
||
|
|
||
|
case PDEV_BUS_OP_ADD_DEV:
|
||
|
goldfish_new_pdev();
|
||
|
+ ret = IRQ_HANDLED;
|
||
|
break;
|
||
|
+
|
||
|
+ case PDEV_BUS_OP_DONE:
|
||
|
+ default:
|
||
|
+ return ret;
|
||
|
}
|
||
|
- ret = IRQ_HANDLED;
|
||
|
}
|
||
|
- return ret;
|
||
|
}
|
||
|
|
||
|
static int goldfish_pdev_bus_probe(struct platform_device *pdev)
|
||
|
diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c
|
||
|
index f59683aa13d5..fc6d84e202e8 100644
|
||
|
--- a/drivers/platform/x86/intel_mid_powerbtn.c
|
||
|
+++ b/drivers/platform/x86/intel_mid_powerbtn.c
|
||
|
@@ -78,8 +78,8 @@ static int mfld_pb_probe(struct platform_device *pdev)
|
||
|
|
||
|
input_set_capability(input, EV_KEY, KEY_POWER);
|
||
|
|
||
|
- error = request_threaded_irq(irq, NULL, mfld_pb_isr, IRQF_NO_SUSPEND,
|
||
|
- DRIVER_NAME, input);
|
||
|
+ error = request_threaded_irq(irq, NULL, mfld_pb_isr, IRQF_NO_SUSPEND |
|
||
|
+ IRQF_ONESHOT, DRIVER_NAME, input);
|
||
|
if (error) {
|
||
|
dev_err(&pdev->dev, "Unable to request irq %d for mfld power"
|
||
|
"button\n", irq);
|
||
|
diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c
|
||
|
index bde5255200dc..1d1e585bd034 100644
|
||
|
--- a/drivers/s390/cio/qdio_thinint.c
|
||
|
+++ b/drivers/s390/cio/qdio_thinint.c
|
||
|
@@ -142,11 +142,11 @@ static inline void tiqdio_call_inq_handlers(struct qdio_irq *irq)
|
||
|
struct qdio_q *q;
|
||
|
int i;
|
||
|
|
||
|
- for_each_input_queue(irq, q, i) {
|
||
|
- if (!references_shared_dsci(irq) &&
|
||
|
- has_multiple_inq_on_dsci(irq))
|
||
|
- xchg(q->irq_ptr->dsci, 0);
|
||
|
+ if (!references_shared_dsci(irq) &&
|
||
|
+ has_multiple_inq_on_dsci(irq))
|
||
|
+ xchg(irq->dsci, 0);
|
||
|
|
||
|
+ for_each_input_queue(irq, q, i) {
|
||
|
if (q->u.in.queue_start_poll) {
|
||
|
/* skip if polling is enabled or already in work */
|
||
|
if (test_and_set_bit(QDIO_QUEUE_IRQS_DISABLED,
|
||
|
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
|
||
|
index c846a63ea672..bf13e73ecabc 100644
|
||
|
--- a/drivers/s390/scsi/zfcp_dbf.c
|
||
|
+++ b/drivers/s390/scsi/zfcp_dbf.c
|
||
|
@@ -282,11 +282,12 @@ void zfcp_dbf_rec_trig(char *tag, struct zfcp_adapter *adapter,
|
||
|
|
||
|
|
||
|
/**
|
||
|
- * zfcp_dbf_rec_run - trace event related to running recovery
|
||
|
+ * zfcp_dbf_rec_run_lvl - trace event related to running recovery
|
||
|
+ * @level: trace level to be used for event
|
||
|
* @tag: identifier for event
|
||
|
* @erp: erp_action running
|
||
|
*/
|
||
|
-void zfcp_dbf_rec_run(char *tag, struct zfcp_erp_action *erp)
|
||
|
+void zfcp_dbf_rec_run_lvl(int level, char *tag, struct zfcp_erp_action *erp)
|
||
|
{
|
||
|
struct zfcp_dbf *dbf = erp->adapter->dbf;
|
||
|
struct zfcp_dbf_rec *rec = &dbf->rec_buf;
|
||
|
@@ -312,11 +313,21 @@ void zfcp_dbf_rec_run(char *tag, struct zfcp_erp_action *erp)
|
||
|
else
|
||
|
rec->u.run.rec_count = atomic_read(&erp->adapter->erp_counter);
|
||
|
|
||
|
- debug_event(dbf->rec, 1, rec, sizeof(*rec));
|
||
|
+ debug_event(dbf->rec, level, rec, sizeof(*rec));
|
||
|
spin_unlock_irqrestore(&dbf->rec_lock, flags);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
+ * zfcp_dbf_rec_run - trace event related to running recovery
|
||
|
+ * @tag: identifier for event
|
||
|
+ * @erp: erp_action running
|
||
|
+ */
|
||
|
+void zfcp_dbf_rec_run(char *tag, struct zfcp_erp_action *erp)
|
||
|
+{
|
||
|
+ zfcp_dbf_rec_run_lvl(1, tag, erp);
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
* zfcp_dbf_rec_run_wka - trace wka port event with info like running recovery
|
||
|
* @tag: identifier for event
|
||
|
* @wka_port: well known address port
|
||
|
diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h
|
||
|
index 440aa619da1d..a8165f142550 100644
|
||
|
--- a/drivers/s390/scsi/zfcp_dbf.h
|
||
|
+++ b/drivers/s390/scsi/zfcp_dbf.h
|
||
|
@@ -2,7 +2,7 @@
|
||
|
* zfcp device driver
|
||
|
* debug feature declarations
|
||
|
*
|
||
|
- * Copyright IBM Corp. 2008, 2015
|
||
|
+ * Copyright IBM Corp. 2008, 2016
|
||
|
*/
|
||
|
|
||
|
#ifndef ZFCP_DBF_H
|
||
|
@@ -283,6 +283,30 @@ struct zfcp_dbf {
|
||
|
struct zfcp_dbf_scsi scsi_buf;
|
||
|
};
|
||
|
|
||
|
+/**
|
||
|
+ * zfcp_dbf_hba_fsf_resp_suppress - true if we should not trace by default
|
||
|
+ * @req: request that has been completed
|
||
|
+ *
|
||
|
+ * Returns true if FCP response with only benign residual under count.
|
||
|
+ */
|
||
|
+static inline
|
||
|
+bool zfcp_dbf_hba_fsf_resp_suppress(struct zfcp_fsf_req *req)
|
||
|
+{
|
||
|
+ struct fsf_qtcb *qtcb = req->qtcb;
|
||
|
+ u32 fsf_stat = qtcb->header.fsf_status;
|
||
|
+ struct fcp_resp *fcp_rsp;
|
||
|
+ u8 rsp_flags, fr_status;
|
||
|
+
|
||
|
+ if (qtcb->prefix.qtcb_type != FSF_IO_COMMAND)
|
||
|
+ return false; /* not an FCP response */
|
||
|
+ fcp_rsp = (struct fcp_resp *)&qtcb->bottom.io.fcp_rsp;
|
||
|
+ rsp_flags = fcp_rsp->fr_flags;
|
||
|
+ fr_status = fcp_rsp->fr_status;
|
||
|
+ return (fsf_stat == FSF_FCP_RSP_AVAILABLE) &&
|
||
|
+ (rsp_flags == FCP_RESID_UNDER) &&
|
||
|
+ (fr_status == SAM_STAT_GOOD);
|
||
|
+}
|
||
|
+
|
||
|
static inline
|
||
|
void zfcp_dbf_hba_fsf_resp(char *tag, int level, struct zfcp_fsf_req *req)
|
||
|
{
|
||
|
@@ -304,7 +328,9 @@ void zfcp_dbf_hba_fsf_response(struct zfcp_fsf_req *req)
|
||
|
zfcp_dbf_hba_fsf_resp("fs_perr", 1, req);
|
||
|
|
||
|
} else if (qtcb->header.fsf_status != FSF_GOOD) {
|
||
|
- zfcp_dbf_hba_fsf_resp("fs_ferr", 1, req);
|
||
|
+ zfcp_dbf_hba_fsf_resp("fs_ferr",
|
||
|
+ zfcp_dbf_hba_fsf_resp_suppress(req)
|
||
|
+ ? 5 : 1, req);
|
||
|
|
||
|
} else if ((req->fsf_command == FSF_QTCB_OPEN_PORT_WITH_DID) ||
|
||
|
(req->fsf_command == FSF_QTCB_OPEN_LUN)) {
|
||
|
@@ -388,4 +414,15 @@ void zfcp_dbf_scsi_devreset(char *tag, struct scsi_cmnd *scmnd, u8 flag)
|
||
|
_zfcp_dbf_scsi(tmp_tag, 1, scmnd, NULL);
|
||
|
}
|
||
|
|
||
|
+/**
|
||
|
+ * zfcp_dbf_scsi_nullcmnd() - trace NULLify of SCSI command in dev/tgt-reset.
|
||
|
+ * @scmnd: SCSI command that was NULLified.
|
||
|
+ * @fsf_req: request that owned @scmnd.
|
||
|
+ */
|
||
|
+static inline void zfcp_dbf_scsi_nullcmnd(struct scsi_cmnd *scmnd,
|
||
|
+ struct zfcp_fsf_req *fsf_req)
|
||
|
+{
|
||
|
+ _zfcp_dbf_scsi("scfc__1", 3, scmnd, fsf_req);
|
||
|
+}
|
||
|
+
|
||
|
#endif /* ZFCP_DBF_H */
|
||
|
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
|
||
|
index b4cd26d24152..f7e720e11093 100644
|
||
|
--- a/drivers/s390/scsi/zfcp_erp.c
|
||
|
+++ b/drivers/s390/scsi/zfcp_erp.c
|
||
|
@@ -3,7 +3,7 @@
|
||
|
*
|
||
|
* Error Recovery Procedures (ERP).
|
||
|
*
|
||
|
- * Copyright IBM Corp. 2002, 2015
|
||
|
+ * Copyright IBM Corp. 2002, 2016
|
||
|
*/
|
||
|
|
||
|
#define KMSG_COMPONENT "zfcp"
|
||
|
@@ -1212,6 +1212,62 @@ static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+/**
|
||
|
+ * zfcp_erp_try_rport_unblock - unblock rport if no more/new recovery
|
||
|
+ * @port: zfcp_port whose fc_rport we should try to unblock
|
||
|
+ */
|
||
|
+static void zfcp_erp_try_rport_unblock(struct zfcp_port *port)
|
||
|
+{
|
||
|
+ unsigned long flags;
|
||
|
+ struct zfcp_adapter *adapter = port->adapter;
|
||
|
+ int port_status;
|
||
|
+ struct Scsi_Host *shost = adapter->scsi_host;
|
||
|
+ struct scsi_device *sdev;
|
||
|
+
|
||
|
+ write_lock_irqsave(&adapter->erp_lock, flags);
|
||
|
+ port_status = atomic_read(&port->status);
|
||
|
+ if ((port_status & ZFCP_STATUS_COMMON_UNBLOCKED) == 0 ||
|
||
|
+ (port_status & (ZFCP_STATUS_COMMON_ERP_INUSE |
|
||
|
+ ZFCP_STATUS_COMMON_ERP_FAILED)) != 0) {
|
||
|
+ /* new ERP of severity >= port triggered elsewhere meanwhile or
|
||
|
+ * local link down (adapter erp_failed but not clear unblock)
|
||
|
+ */
|
||
|
+ zfcp_dbf_rec_run_lvl(4, "ertru_p", &port->erp_action);
|
||
|
+ write_unlock_irqrestore(&adapter->erp_lock, flags);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+ spin_lock(shost->host_lock);
|
||
|
+ __shost_for_each_device(sdev, shost) {
|
||
|
+ struct zfcp_scsi_dev *zsdev = sdev_to_zfcp(sdev);
|
||
|
+ int lun_status;
|
||
|
+
|
||
|
+ if (zsdev->port != port)
|
||
|
+ continue;
|
||
|
+ /* LUN under port of interest */
|
||
|
+ lun_status = atomic_read(&zsdev->status);
|
||
|
+ if ((lun_status & ZFCP_STATUS_COMMON_ERP_FAILED) != 0)
|
||
|
+ continue; /* unblock rport despite failed LUNs */
|
||
|
+ /* LUN recovery not given up yet [maybe follow-up pending] */
|
||
|
+ if ((lun_status & ZFCP_STATUS_COMMON_UNBLOCKED) == 0 ||
|
||
|
+ (lun_status & ZFCP_STATUS_COMMON_ERP_INUSE) != 0) {
|
||
|
+ /* LUN blocked:
|
||
|
+ * not yet unblocked [LUN recovery pending]
|
||
|
+ * or meanwhile blocked [new LUN recovery triggered]
|
||
|
+ */
|
||
|
+ zfcp_dbf_rec_run_lvl(4, "ertru_l", &zsdev->erp_action);
|
||
|
+ spin_unlock(shost->host_lock);
|
||
|
+ write_unlock_irqrestore(&adapter->erp_lock, flags);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ /* now port has no child or all children have completed recovery,
|
||
|
+ * and no ERP of severity >= port was meanwhile triggered elsewhere
|
||
|
+ */
|
||
|
+ zfcp_scsi_schedule_rport_register(port);
|
||
|
+ spin_unlock(shost->host_lock);
|
||
|
+ write_unlock_irqrestore(&adapter->erp_lock, flags);
|
||
|
+}
|
||
|
+
|
||
|
static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
|
||
|
{
|
||
|
struct zfcp_adapter *adapter = act->adapter;
|
||
|
@@ -1222,6 +1278,7 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
|
||
|
case ZFCP_ERP_ACTION_REOPEN_LUN:
|
||
|
if (!(act->status & ZFCP_STATUS_ERP_NO_REF))
|
||
|
scsi_device_put(sdev);
|
||
|
+ zfcp_erp_try_rport_unblock(port);
|
||
|
break;
|
||
|
|
||
|
case ZFCP_ERP_ACTION_REOPEN_PORT:
|
||
|
@@ -1232,7 +1289,7 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result)
|
||
|
*/
|
||
|
if (act->step != ZFCP_ERP_STEP_UNINITIALIZED)
|
||
|
if (result == ZFCP_ERP_SUCCEEDED)
|
||
|
- zfcp_scsi_schedule_rport_register(port);
|
||
|
+ zfcp_erp_try_rport_unblock(port);
|
||
|
/* fall through */
|
||
|
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
|
||
|
put_device(&port->dev);
|
||
|
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
|
||
|
index 01527c31d1da..fdef6a6fe06b 100644
|
||
|
--- a/drivers/s390/scsi/zfcp_ext.h
|
||
|
+++ b/drivers/s390/scsi/zfcp_ext.h
|
||
|
@@ -3,7 +3,7 @@
|
||
|
*
|
||
|
* External function declarations.
|
||
|
*
|
||
|
- * Copyright IBM Corp. 2002, 2015
|
||
|
+ * Copyright IBM Corp. 2002, 2016
|
||
|
*/
|
||
|
|
||
|
#ifndef ZFCP_EXT_H
|
||
|
@@ -49,6 +49,8 @@ extern void zfcp_dbf_adapter_unregister(struct zfcp_adapter *);
|
||
|
extern void zfcp_dbf_rec_trig(char *, struct zfcp_adapter *,
|
||
|
struct zfcp_port *, struct scsi_device *, u8, u8);
|
||
|
extern void zfcp_dbf_rec_run(char *, struct zfcp_erp_action *);
|
||
|
+extern void zfcp_dbf_rec_run_lvl(int level, char *tag,
|
||
|
+ struct zfcp_erp_action *erp);
|
||
|
extern void zfcp_dbf_rec_run_wka(char *, struct zfcp_fc_wka_port *, u64);
|
||
|
extern void zfcp_dbf_hba_fsf_uss(char *, struct zfcp_fsf_req *);
|
||
|
extern void zfcp_dbf_hba_fsf_res(char *, int, struct zfcp_fsf_req *);
|
||
|
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
|
||
|
index f246097b7c6d..ad5718401eab 100644
|
||
|
--- a/drivers/s390/scsi/zfcp_fsf.c
|
||
|
+++ b/drivers/s390/scsi/zfcp_fsf.c
|
||
|
@@ -1607,7 +1607,7 @@ out:
|
||
|
int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port)
|
||
|
{
|
||
|
struct zfcp_qdio *qdio = wka_port->adapter->qdio;
|
||
|
- struct zfcp_fsf_req *req = NULL;
|
||
|
+ struct zfcp_fsf_req *req;
|
||
|
int retval = -EIO;
|
||
|
|
||
|
spin_lock_irq(&qdio->req_q_lock);
|
||
|
@@ -1636,7 +1636,7 @@ int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port)
|
||
|
zfcp_fsf_req_free(req);
|
||
|
out:
|
||
|
spin_unlock_irq(&qdio->req_q_lock);
|
||
|
- if (req && !IS_ERR(req))
|
||
|
+ if (!retval)
|
||
|
zfcp_dbf_rec_run_wka("fsowp_1", wka_port, req->req_id);
|
||
|
return retval;
|
||
|
}
|
||
|
@@ -1662,7 +1662,7 @@ static void zfcp_fsf_close_wka_port_handler(struct zfcp_fsf_req *req)
|
||
|
int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port)
|
||
|
{
|
||
|
struct zfcp_qdio *qdio = wka_port->adapter->qdio;
|
||
|
- struct zfcp_fsf_req *req = NULL;
|
||
|
+ struct zfcp_fsf_req *req;
|
||
|
int retval = -EIO;
|
||
|
|
||
|
spin_lock_irq(&qdio->req_q_lock);
|
||
|
@@ -1691,7 +1691,7 @@ int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port)
|
||
|
zfcp_fsf_req_free(req);
|
||
|
out:
|
||
|
spin_unlock_irq(&qdio->req_q_lock);
|
||
|
- if (req && !IS_ERR(req))
|
||
|
+ if (!retval)
|
||
|
zfcp_dbf_rec_run_wka("fscwp_1", wka_port, req->req_id);
|
||
|
return retval;
|
||
|
}
|
||
|
diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h
|
||
|
index 8cad41ffb6b8..358b92ece8d0 100644
|
||
|
--- a/drivers/s390/scsi/zfcp_fsf.h
|
||
|
+++ b/drivers/s390/scsi/zfcp_fsf.h
|
||
|
@@ -3,7 +3,7 @@
|
||
|
*
|
||
|
* Interface to the FSF support functions.
|
||
|
*
|
||
|
- * Copyright IBM Corp. 2002, 2015
|
||
|
+ * Copyright IBM Corp. 2002, 2016
|
||
|
*/
|
||
|
|
||
|
#ifndef FSF_H
|
||
|
@@ -86,6 +86,7 @@
|
||
|
#define FSF_APP_TAG_CHECK_FAILURE 0x00000082
|
||
|
#define FSF_REF_TAG_CHECK_FAILURE 0x00000083
|
||
|
#define FSF_ADAPTER_STATUS_AVAILABLE 0x000000AD
|
||
|
+#define FSF_FCP_RSP_AVAILABLE 0x000000AF
|
||
|
#define FSF_UNKNOWN_COMMAND 0x000000E2
|
||
|
#define FSF_UNKNOWN_OP_SUBTYPE 0x000000E3
|
||
|
#define FSF_INVALID_COMMAND_OPTION 0x000000E5
|
||
|
diff --git a/drivers/s390/scsi/zfcp_reqlist.h b/drivers/s390/scsi/zfcp_reqlist.h
|
||
|
index 7c2c6194dfca..703fce59befe 100644
|
||
|
--- a/drivers/s390/scsi/zfcp_reqlist.h
|
||
|
+++ b/drivers/s390/scsi/zfcp_reqlist.h
|
||
|
@@ -4,7 +4,7 @@
|
||
|
* Data structure and helper functions for tracking pending FSF
|
||
|
* requests.
|
||
|
*
|
||
|
- * Copyright IBM Corp. 2009
|
||
|
+ * Copyright IBM Corp. 2009, 2016
|
||
|
*/
|
||
|
|
||
|
#ifndef ZFCP_REQLIST_H
|
||
|
@@ -180,4 +180,32 @@ static inline void zfcp_reqlist_move(struct zfcp_reqlist *rl,
|
||
|
spin_unlock_irqrestore(&rl->lock, flags);
|
||
|
}
|
||
|
|
||
|
+/**
|
||
|
+ * zfcp_reqlist_apply_for_all() - apply a function to every request.
|
||
|
+ * @rl: the requestlist that contains the target requests.
|
||
|
+ * @f: the function to apply to each request; the first parameter of the
|
||
|
+ * function will be the target-request; the second parameter is the same
|
||
|
+ * pointer as given with the argument @data.
|
||
|
+ * @data: freely chosen argument; passed through to @f as second parameter.
|
||
|
+ *
|
||
|
+ * Uses :c:macro:`list_for_each_entry` to iterate over the lists in the hash-
|
||
|
+ * table (not a 'safe' variant, so don't modify the list).
|
||
|
+ *
|
||
|
+ * Holds @rl->lock over the entire request-iteration.
|
||
|
+ */
|
||
|
+static inline void
|
||
|
+zfcp_reqlist_apply_for_all(struct zfcp_reqlist *rl,
|
||
|
+ void (*f)(struct zfcp_fsf_req *, void *), void *data)
|
||
|
+{
|
||
|
+ struct zfcp_fsf_req *req;
|
||
|
+ unsigned long flags;
|
||
|
+ unsigned int i;
|
||
|
+
|
||
|
+ spin_lock_irqsave(&rl->lock, flags);
|
||
|
+ for (i = 0; i < ZFCP_REQ_LIST_BUCKETS; i++)
|
||
|
+ list_for_each_entry(req, &rl->buckets[i], list)
|
||
|
+ f(req, data);
|
||
|
+ spin_unlock_irqrestore(&rl->lock, flags);
|
||
|
+}
|
||
|
+
|
||
|
#endif /* ZFCP_REQLIST_H */
|
||
|
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
|
||
|
index 38ee0df633a3..66c37e77ac7c 100644
|
||
|
--- a/drivers/s390/scsi/zfcp_scsi.c
|
||
|
+++ b/drivers/s390/scsi/zfcp_scsi.c
|
||
|
@@ -3,7 +3,7 @@
|
||
|
*
|
||
|
* Interface to Linux SCSI midlayer.
|
||
|
*
|
||
|
- * Copyright IBM Corp. 2002, 2015
|
||
|
+ * Copyright IBM Corp. 2002, 2016
|
||
|
*/
|
||
|
|
||
|
#define KMSG_COMPONENT "zfcp"
|
||
|
@@ -109,9 +109,7 @@ int zfcp_scsi_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scpnt)
|
||
|
}
|
||
|
|
||
|
if (unlikely(!(status & ZFCP_STATUS_COMMON_UNBLOCKED))) {
|
||
|
- /* This could be either
|
||
|
- * open LUN pending: this is temporary, will result in
|
||
|
- * open LUN or ERP_FAILED, so retry command
|
||
|
+ /* This could be
|
||
|
* call to rport_delete pending: mimic retry from
|
||
|
* fc_remote_port_chkready until rport is BLOCKED
|
||
|
*/
|
||
|
@@ -230,6 +228,57 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
+struct zfcp_scsi_req_filter {
|
||
|
+ u8 tmf_scope;
|
||
|
+ u32 lun_handle;
|
||
|
+ u32 port_handle;
|
||
|
+};
|
||
|
+
|
||
|
+static void zfcp_scsi_forget_cmnd(struct zfcp_fsf_req *old_req, void *data)
|
||
|
+{
|
||
|
+ struct zfcp_scsi_req_filter *filter =
|
||
|
+ (struct zfcp_scsi_req_filter *)data;
|
||
|
+
|
||
|
+ /* already aborted - prevent side-effects - or not a SCSI command */
|
||
|
+ if (old_req->data == NULL || old_req->fsf_command != FSF_QTCB_FCP_CMND)
|
||
|
+ return;
|
||
|
+
|
||
|
+ /* (tmf_scope == FCP_TMF_TGT_RESET || tmf_scope == FCP_TMF_LUN_RESET) */
|
||
|
+ if (old_req->qtcb->header.port_handle != filter->port_handle)
|
||
|
+ return;
|
||
|
+
|
||
|
+ if (filter->tmf_scope == FCP_TMF_LUN_RESET &&
|
||
|
+ old_req->qtcb->header.lun_handle != filter->lun_handle)
|
||
|
+ return;
|
||
|
+
|
||
|
+ zfcp_dbf_scsi_nullcmnd((struct scsi_cmnd *)old_req->data, old_req);
|
||
|
+ old_req->data = NULL;
|
||
|
+}
|
||
|
+
|
||
|
+static void zfcp_scsi_forget_cmnds(struct zfcp_scsi_dev *zsdev, u8 tm_flags)
|
||
|
+{
|
||
|
+ struct zfcp_adapter *adapter = zsdev->port->adapter;
|
||
|
+ struct zfcp_scsi_req_filter filter = {
|
||
|
+ .tmf_scope = FCP_TMF_TGT_RESET,
|
||
|
+ .port_handle = zsdev->port->handle,
|
||
|
+ };
|
||
|
+ unsigned long flags;
|
||
|
+
|
||
|
+ if (tm_flags == FCP_TMF_LUN_RESET) {
|
||
|
+ filter.tmf_scope = FCP_TMF_LUN_RESET;
|
||
|
+ filter.lun_handle = zsdev->lun_handle;
|
||
|
+ }
|
||
|
+
|
||
|
+ /*
|
||
|
+ * abort_lock secures against other processings - in the abort-function
|
||
|
+ * and normal cmnd-handler - of (struct zfcp_fsf_req *)->data
|
||
|
+ */
|
||
|
+ write_lock_irqsave(&adapter->abort_lock, flags);
|
||
|
+ zfcp_reqlist_apply_for_all(adapter->req_list, zfcp_scsi_forget_cmnd,
|
||
|
+ &filter);
|
||
|
+ write_unlock_irqrestore(&adapter->abort_lock, flags);
|
||
|
+}
|
||
|
+
|
||
|
static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags)
|
||
|
{
|
||
|
struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scpnt->device);
|
||
|
@@ -262,8 +311,10 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags)
|
||
|
if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) {
|
||
|
zfcp_dbf_scsi_devreset("fail", scpnt, tm_flags);
|
||
|
retval = FAILED;
|
||
|
- } else
|
||
|
+ } else {
|
||
|
zfcp_dbf_scsi_devreset("okay", scpnt, tm_flags);
|
||
|
+ zfcp_scsi_forget_cmnds(zfcp_sdev, tm_flags);
|
||
|
+ }
|
||
|
|
||
|
zfcp_fsf_req_free(fsf_req);
|
||
|
return retval;
|
||
|
diff --git a/drivers/scsi/aacraid/src.c b/drivers/scsi/aacraid/src.c
|
||
|
index 7e17107643d4..05c999429ffe 100644
|
||
|
--- a/drivers/scsi/aacraid/src.c
|
||
|
+++ b/drivers/scsi/aacraid/src.c
|
||
|
@@ -359,16 +359,23 @@ static int aac_src_check_health(struct aac_dev *dev)
|
||
|
u32 status = src_readl(dev, MUnit.OMR);
|
||
|
|
||
|
/*
|
||
|
+ * Check to see if the board panic'd.
|
||
|
+ */
|
||
|
+ if (unlikely(status & KERNEL_PANIC))
|
||
|
+ goto err_blink;
|
||
|
+
|
||
|
+ /*
|
||
|
* Check to see if the board failed any self tests.
|
||
|
*/
|
||
|
if (unlikely(status & SELF_TEST_FAILED))
|
||
|
- return -1;
|
||
|
+ goto err_out;
|
||
|
|
||
|
/*
|
||
|
- * Check to see if the board panic'd.
|
||
|
+ * Check to see if the board failed any self tests.
|
||
|
*/
|
||
|
- if (unlikely(status & KERNEL_PANIC))
|
||
|
- return (status >> 16) & 0xFF;
|
||
|
+ if (unlikely(status & MONITOR_PANIC))
|
||
|
+ goto err_out;
|
||
|
+
|
||
|
/*
|
||
|
* Wait for the adapter to be up and running.
|
||
|
*/
|
||
|
@@ -378,6 +385,12 @@ static int aac_src_check_health(struct aac_dev *dev)
|
||
|
* Everything is OK
|
||
|
*/
|
||
|
return 0;
|
||
|
+
|
||
|
+err_out:
|
||
|
+ return -1;
|
||
|
+
|
||
|
+err_blink:
|
||
|
+ return (status > 16) & 0xFF;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
|
||
|
index d2895836f9fa..83e3ca703cd1 100644
|
||
|
--- a/drivers/scsi/libsas/sas_ata.c
|
||
|
+++ b/drivers/scsi/libsas/sas_ata.c
|
||
|
@@ -219,7 +219,7 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
|
||
|
task->num_scatter = qc->n_elem;
|
||
|
} else {
|
||
|
for_each_sg(qc->sg, sg, qc->n_elem, si)
|
||
|
- xfer += sg->length;
|
||
|
+ xfer += sg_dma_len(sg);
|
||
|
|
||
|
task->total_xfer_len = xfer;
|
||
|
task->num_scatter = si;
|
||
|
diff --git a/drivers/scsi/mvsas/mv_94xx.c b/drivers/scsi/mvsas/mv_94xx.c
|
||
|
index 1e4479f3331a..55716c5184f7 100644
|
||
|
--- a/drivers/scsi/mvsas/mv_94xx.c
|
||
|
+++ b/drivers/scsi/mvsas/mv_94xx.c
|
||
|
@@ -621,7 +621,7 @@ static void mvs_94xx_command_active(struct mvs_info *mvi, u32 slot_idx)
|
||
|
{
|
||
|
u32 tmp;
|
||
|
tmp = mvs_cr32(mvi, MVS_COMMAND_ACTIVE+(slot_idx >> 3));
|
||
|
- if (tmp && 1 << (slot_idx % 32)) {
|
||
|
+ if (tmp & 1 << (slot_idx % 32)) {
|
||
|
mv_printk("command active %08X, slot [%x].\n", tmp, slot_idx);
|
||
|
mvs_cw32(mvi, MVS_COMMAND_ACTIVE + (slot_idx >> 3),
|
||
|
1 << (slot_idx % 32));
|
||
|
diff --git a/drivers/staging/iio/adc/ad7606_core.c b/drivers/staging/iio/adc/ad7606_core.c
|
||
|
index d104b4378424..fa763dd9a4b7 100644
|
||
|
--- a/drivers/staging/iio/adc/ad7606_core.c
|
||
|
+++ b/drivers/staging/iio/adc/ad7606_core.c
|
||
|
@@ -185,7 +185,7 @@ static ssize_t ad7606_store_oversampling_ratio(struct device *dev,
|
||
|
mutex_lock(&indio_dev->mlock);
|
||
|
gpio_set_value(st->pdata->gpio_os0, (ret >> 0) & 1);
|
||
|
gpio_set_value(st->pdata->gpio_os1, (ret >> 1) & 1);
|
||
|
- gpio_set_value(st->pdata->gpio_os1, (ret >> 2) & 1);
|
||
|
+ gpio_set_value(st->pdata->gpio_os2, (ret >> 2) & 1);
|
||
|
st->oversampling = lval;
|
||
|
mutex_unlock(&indio_dev->mlock);
|
||
|
|
||
|
diff --git a/drivers/staging/vt6656/hostap.c b/drivers/staging/vt6656/hostap.c
|
||
|
index c699a3058b39..cfffdd20e435 100644
|
||
|
--- a/drivers/staging/vt6656/hostap.c
|
||
|
+++ b/drivers/staging/vt6656/hostap.c
|
||
|
@@ -133,7 +133,8 @@ static int hostap_disable_hostapd(struct vnt_private *pDevice, int rtnl_locked)
|
||
|
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: Netdevice %s unregistered\n",
|
||
|
pDevice->dev->name, pDevice->apdev->name);
|
||
|
}
|
||
|
- free_netdev(pDevice->apdev);
|
||
|
+ if (pDevice->apdev)
|
||
|
+ free_netdev(pDevice->apdev);
|
||
|
pDevice->apdev = NULL;
|
||
|
pDevice->bEnable8021x = false;
|
||
|
pDevice->bEnableHostWEP = false;
|
||
|
diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c
|
||
|
index 75a4e83842c2..a6801e8a8116 100644
|
||
|
--- a/drivers/target/iscsi/iscsi_target_tpg.c
|
||
|
+++ b/drivers/target/iscsi/iscsi_target_tpg.c
|
||
|
@@ -256,7 +256,6 @@ err_out:
|
||
|
iscsi_release_param_list(tpg->param_list);
|
||
|
tpg->param_list = NULL;
|
||
|
}
|
||
|
- kfree(tpg);
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
|
||
|
diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c
|
||
|
index 1b2db9a3038c..66fb07684133 100644
|
||
|
--- a/drivers/tty/n_hdlc.c
|
||
|
+++ b/drivers/tty/n_hdlc.c
|
||
|
@@ -114,7 +114,7 @@
|
||
|
#define DEFAULT_TX_BUF_COUNT 3
|
||
|
|
||
|
struct n_hdlc_buf {
|
||
|
- struct n_hdlc_buf *link;
|
||
|
+ struct list_head list_item;
|
||
|
int count;
|
||
|
char buf[1];
|
||
|
};
|
||
|
@@ -122,8 +122,7 @@ struct n_hdlc_buf {
|
||
|
#define N_HDLC_BUF_SIZE (sizeof(struct n_hdlc_buf) + maxframe)
|
||
|
|
||
|
struct n_hdlc_buf_list {
|
||
|
- struct n_hdlc_buf *head;
|
||
|
- struct n_hdlc_buf *tail;
|
||
|
+ struct list_head list;
|
||
|
int count;
|
||
|
spinlock_t spinlock;
|
||
|
};
|
||
|
@@ -136,7 +135,6 @@ struct n_hdlc_buf_list {
|
||
|
* @backup_tty - TTY to use if tty gets closed
|
||
|
* @tbusy - reentrancy flag for tx wakeup code
|
||
|
* @woke_up - FIXME: describe this field
|
||
|
- * @tbuf - currently transmitting tx buffer
|
||
|
* @tx_buf_list - list of pending transmit frame buffers
|
||
|
* @rx_buf_list - list of received frame buffers
|
||
|
* @tx_free_buf_list - list unused transmit frame buffers
|
||
|
@@ -149,7 +147,6 @@ struct n_hdlc {
|
||
|
struct tty_struct *backup_tty;
|
||
|
int tbusy;
|
||
|
int woke_up;
|
||
|
- struct n_hdlc_buf *tbuf;
|
||
|
struct n_hdlc_buf_list tx_buf_list;
|
||
|
struct n_hdlc_buf_list rx_buf_list;
|
||
|
struct n_hdlc_buf_list tx_free_buf_list;
|
||
|
@@ -159,7 +156,8 @@ struct n_hdlc {
|
||
|
/*
|
||
|
* HDLC buffer list manipulation functions
|
||
|
*/
|
||
|
-static void n_hdlc_buf_list_init(struct n_hdlc_buf_list *list);
|
||
|
+static void n_hdlc_buf_return(struct n_hdlc_buf_list *buf_list,
|
||
|
+ struct n_hdlc_buf *buf);
|
||
|
static void n_hdlc_buf_put(struct n_hdlc_buf_list *list,
|
||
|
struct n_hdlc_buf *buf);
|
||
|
static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *list);
|
||
|
@@ -209,16 +207,9 @@ static void flush_tx_queue(struct tty_struct *tty)
|
||
|
{
|
||
|
struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
|
||
|
struct n_hdlc_buf *buf;
|
||
|
- unsigned long flags;
|
||
|
|
||
|
while ((buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list)))
|
||
|
n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, buf);
|
||
|
- spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
|
||
|
- if (n_hdlc->tbuf) {
|
||
|
- n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, n_hdlc->tbuf);
|
||
|
- n_hdlc->tbuf = NULL;
|
||
|
- }
|
||
|
- spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
|
||
|
}
|
||
|
|
||
|
static struct tty_ldisc_ops n_hdlc_ldisc = {
|
||
|
@@ -284,7 +275,6 @@ static void n_hdlc_release(struct n_hdlc *n_hdlc)
|
||
|
} else
|
||
|
break;
|
||
|
}
|
||
|
- kfree(n_hdlc->tbuf);
|
||
|
kfree(n_hdlc);
|
||
|
|
||
|
} /* end of n_hdlc_release() */
|
||
|
@@ -403,13 +393,7 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
|
||
|
n_hdlc->woke_up = 0;
|
||
|
spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
|
||
|
|
||
|
- /* get current transmit buffer or get new transmit */
|
||
|
- /* buffer from list of pending transmit buffers */
|
||
|
-
|
||
|
- tbuf = n_hdlc->tbuf;
|
||
|
- if (!tbuf)
|
||
|
- tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
|
||
|
-
|
||
|
+ tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
|
||
|
while (tbuf) {
|
||
|
if (debuglevel >= DEBUG_LEVEL_INFO)
|
||
|
printk("%s(%d)sending frame %p, count=%d\n",
|
||
|
@@ -421,7 +405,7 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
|
||
|
|
||
|
/* rollback was possible and has been done */
|
||
|
if (actual == -ERESTARTSYS) {
|
||
|
- n_hdlc->tbuf = tbuf;
|
||
|
+ n_hdlc_buf_return(&n_hdlc->tx_buf_list, tbuf);
|
||
|
break;
|
||
|
}
|
||
|
/* if transmit error, throw frame away by */
|
||
|
@@ -436,10 +420,7 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
|
||
|
|
||
|
/* free current transmit buffer */
|
||
|
n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, tbuf);
|
||
|
-
|
||
|
- /* this tx buffer is done */
|
||
|
- n_hdlc->tbuf = NULL;
|
||
|
-
|
||
|
+
|
||
|
/* wait up sleeping writers */
|
||
|
wake_up_interruptible(&tty->write_wait);
|
||
|
|
||
|
@@ -449,10 +430,12 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
|
||
|
if (debuglevel >= DEBUG_LEVEL_INFO)
|
||
|
printk("%s(%d)frame %p pending\n",
|
||
|
__FILE__,__LINE__,tbuf);
|
||
|
-
|
||
|
- /* buffer not accepted by driver */
|
||
|
- /* set this buffer as pending buffer */
|
||
|
- n_hdlc->tbuf = tbuf;
|
||
|
+
|
||
|
+ /*
|
||
|
+ * the buffer was not accepted by driver,
|
||
|
+ * return it back into tx queue
|
||
|
+ */
|
||
|
+ n_hdlc_buf_return(&n_hdlc->tx_buf_list, tbuf);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
@@ -750,7 +733,8 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
|
||
|
int error = 0;
|
||
|
int count;
|
||
|
unsigned long flags;
|
||
|
-
|
||
|
+ struct n_hdlc_buf *buf = NULL;
|
||
|
+
|
||
|
if (debuglevel >= DEBUG_LEVEL_INFO)
|
||
|
printk("%s(%d)n_hdlc_tty_ioctl() called %d\n",
|
||
|
__FILE__,__LINE__,cmd);
|
||
|
@@ -764,8 +748,10 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
|
||
|
/* report count of read data available */
|
||
|
/* in next available frame (if any) */
|
||
|
spin_lock_irqsave(&n_hdlc->rx_buf_list.spinlock,flags);
|
||
|
- if (n_hdlc->rx_buf_list.head)
|
||
|
- count = n_hdlc->rx_buf_list.head->count;
|
||
|
+ buf = list_first_entry_or_null(&n_hdlc->rx_buf_list.list,
|
||
|
+ struct n_hdlc_buf, list_item);
|
||
|
+ if (buf)
|
||
|
+ count = buf->count;
|
||
|
else
|
||
|
count = 0;
|
||
|
spin_unlock_irqrestore(&n_hdlc->rx_buf_list.spinlock,flags);
|
||
|
@@ -777,8 +763,10 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
|
||
|
count = tty_chars_in_buffer(tty);
|
||
|
/* add size of next output frame in queue */
|
||
|
spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock,flags);
|
||
|
- if (n_hdlc->tx_buf_list.head)
|
||
|
- count += n_hdlc->tx_buf_list.head->count;
|
||
|
+ buf = list_first_entry_or_null(&n_hdlc->tx_buf_list.list,
|
||
|
+ struct n_hdlc_buf, list_item);
|
||
|
+ if (buf)
|
||
|
+ count += buf->count;
|
||
|
spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock,flags);
|
||
|
error = put_user(count, (int __user *)arg);
|
||
|
break;
|
||
|
@@ -826,14 +814,14 @@ static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,
|
||
|
poll_wait(filp, &tty->write_wait, wait);
|
||
|
|
||
|
/* set bits for operations that won't block */
|
||
|
- if (n_hdlc->rx_buf_list.head)
|
||
|
+ if (!list_empty(&n_hdlc->rx_buf_list.list))
|
||
|
mask |= POLLIN | POLLRDNORM; /* readable */
|
||
|
if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
|
||
|
mask |= POLLHUP;
|
||
|
if (tty_hung_up_p(filp))
|
||
|
mask |= POLLHUP;
|
||
|
if (!tty_is_writelocked(tty) &&
|
||
|
- n_hdlc->tx_free_buf_list.head)
|
||
|
+ !list_empty(&n_hdlc->tx_free_buf_list.list))
|
||
|
mask |= POLLOUT | POLLWRNORM; /* writable */
|
||
|
}
|
||
|
return mask;
|
||
|
@@ -855,11 +843,16 @@ static struct n_hdlc *n_hdlc_alloc(void)
|
||
|
|
||
|
memset(n_hdlc, 0, sizeof(*n_hdlc));
|
||
|
|
||
|
- n_hdlc_buf_list_init(&n_hdlc->rx_free_buf_list);
|
||
|
- n_hdlc_buf_list_init(&n_hdlc->tx_free_buf_list);
|
||
|
- n_hdlc_buf_list_init(&n_hdlc->rx_buf_list);
|
||
|
- n_hdlc_buf_list_init(&n_hdlc->tx_buf_list);
|
||
|
-
|
||
|
+ spin_lock_init(&n_hdlc->rx_free_buf_list.spinlock);
|
||
|
+ spin_lock_init(&n_hdlc->tx_free_buf_list.spinlock);
|
||
|
+ spin_lock_init(&n_hdlc->rx_buf_list.spinlock);
|
||
|
+ spin_lock_init(&n_hdlc->tx_buf_list.spinlock);
|
||
|
+
|
||
|
+ INIT_LIST_HEAD(&n_hdlc->rx_free_buf_list.list);
|
||
|
+ INIT_LIST_HEAD(&n_hdlc->tx_free_buf_list.list);
|
||
|
+ INIT_LIST_HEAD(&n_hdlc->rx_buf_list.list);
|
||
|
+ INIT_LIST_HEAD(&n_hdlc->tx_buf_list.list);
|
||
|
+
|
||
|
/* allocate free rx buffer list */
|
||
|
for(i=0;i<DEFAULT_RX_BUF_COUNT;i++) {
|
||
|
buf = kmalloc(N_HDLC_BUF_SIZE, GFP_KERNEL);
|
||
|
@@ -887,63 +880,65 @@ static struct n_hdlc *n_hdlc_alloc(void)
|
||
|
} /* end of n_hdlc_alloc() */
|
||
|
|
||
|
/**
|
||
|
- * n_hdlc_buf_list_init - initialize specified HDLC buffer list
|
||
|
- * @list - pointer to buffer list
|
||
|
+ * n_hdlc_buf_return - put the HDLC buffer after the head of the specified list
|
||
|
+ * @buf_list - pointer to the buffer list
|
||
|
+ * @buf - pointer to the buffer
|
||
|
*/
|
||
|
-static void n_hdlc_buf_list_init(struct n_hdlc_buf_list *list)
|
||
|
+static void n_hdlc_buf_return(struct n_hdlc_buf_list *buf_list,
|
||
|
+ struct n_hdlc_buf *buf)
|
||
|
{
|
||
|
- memset(list, 0, sizeof(*list));
|
||
|
- spin_lock_init(&list->spinlock);
|
||
|
-} /* end of n_hdlc_buf_list_init() */
|
||
|
+ unsigned long flags;
|
||
|
+
|
||
|
+ spin_lock_irqsave(&buf_list->spinlock, flags);
|
||
|
+
|
||
|
+ list_add(&buf->list_item, &buf_list->list);
|
||
|
+ buf_list->count++;
|
||
|
+
|
||
|
+ spin_unlock_irqrestore(&buf_list->spinlock, flags);
|
||
|
+}
|
||
|
|
||
|
/**
|
||
|
* n_hdlc_buf_put - add specified HDLC buffer to tail of specified list
|
||
|
- * @list - pointer to buffer list
|
||
|
+ * @buf_list - pointer to buffer list
|
||
|
* @buf - pointer to buffer
|
||
|
*/
|
||
|
-static void n_hdlc_buf_put(struct n_hdlc_buf_list *list,
|
||
|
+static void n_hdlc_buf_put(struct n_hdlc_buf_list *buf_list,
|
||
|
struct n_hdlc_buf *buf)
|
||
|
{
|
||
|
unsigned long flags;
|
||
|
- spin_lock_irqsave(&list->spinlock,flags);
|
||
|
-
|
||
|
- buf->link=NULL;
|
||
|
- if (list->tail)
|
||
|
- list->tail->link = buf;
|
||
|
- else
|
||
|
- list->head = buf;
|
||
|
- list->tail = buf;
|
||
|
- (list->count)++;
|
||
|
-
|
||
|
- spin_unlock_irqrestore(&list->spinlock,flags);
|
||
|
-
|
||
|
+
|
||
|
+ spin_lock_irqsave(&buf_list->spinlock, flags);
|
||
|
+
|
||
|
+ list_add_tail(&buf->list_item, &buf_list->list);
|
||
|
+ buf_list->count++;
|
||
|
+
|
||
|
+ spin_unlock_irqrestore(&buf_list->spinlock, flags);
|
||
|
} /* end of n_hdlc_buf_put() */
|
||
|
|
||
|
/**
|
||
|
* n_hdlc_buf_get - remove and return an HDLC buffer from list
|
||
|
- * @list - pointer to HDLC buffer list
|
||
|
+ * @buf_list - pointer to HDLC buffer list
|
||
|
*
|
||
|
* Remove and return an HDLC buffer from the head of the specified HDLC buffer
|
||
|
* list.
|
||
|
* Returns a pointer to HDLC buffer if available, otherwise %NULL.
|
||
|
*/
|
||
|
-static struct n_hdlc_buf* n_hdlc_buf_get(struct n_hdlc_buf_list *list)
|
||
|
+static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *buf_list)
|
||
|
{
|
||
|
unsigned long flags;
|
||
|
struct n_hdlc_buf *buf;
|
||
|
- spin_lock_irqsave(&list->spinlock,flags);
|
||
|
-
|
||
|
- buf = list->head;
|
||
|
+
|
||
|
+ spin_lock_irqsave(&buf_list->spinlock, flags);
|
||
|
+
|
||
|
+ buf = list_first_entry_or_null(&buf_list->list,
|
||
|
+ struct n_hdlc_buf, list_item);
|
||
|
if (buf) {
|
||
|
- list->head = buf->link;
|
||
|
- (list->count)--;
|
||
|
+ list_del(&buf->list_item);
|
||
|
+ buf_list->count--;
|
||
|
}
|
||
|
- if (!list->head)
|
||
|
- list->tail = NULL;
|
||
|
-
|
||
|
- spin_unlock_irqrestore(&list->spinlock,flags);
|
||
|
+
|
||
|
+ spin_unlock_irqrestore(&buf_list->spinlock, flags);
|
||
|
return buf;
|
||
|
-
|
||
|
} /* end of n_hdlc_buf_get() */
|
||
|
|
||
|
static char hdlc_banner[] __initdata =
|
||
|
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
|
||
|
index 4c5506ae5e45..64317898a7cb 100644
|
||
|
--- a/drivers/usb/class/usbtmc.c
|
||
|
+++ b/drivers/usb/class/usbtmc.c
|
||
|
@@ -989,7 +989,7 @@ static int usbtmc_probe(struct usb_interface *intf,
|
||
|
|
||
|
dev_dbg(&intf->dev, "%s called\n", __func__);
|
||
|
|
||
|
- data = kmalloc(sizeof(struct usbtmc_device_data), GFP_KERNEL);
|
||
|
+ data = kzalloc(sizeof(struct usbtmc_device_data), GFP_KERNEL);
|
||
|
if (!data) {
|
||
|
dev_err(&intf->dev, "Unable to allocate kernel memory\n");
|
||
|
return -ENOMEM;
|
||
|
@@ -1035,6 +1035,12 @@ static int usbtmc_probe(struct usb_interface *intf,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+ if (!data->bulk_out || !data->bulk_in) {
|
||
|
+ dev_err(&intf->dev, "bulk endpoints not found\n");
|
||
|
+ retcode = -ENODEV;
|
||
|
+ goto err_put;
|
||
|
+ }
|
||
|
+
|
||
|
retcode = get_capabilities(data);
|
||
|
if (retcode)
|
||
|
dev_err(&intf->dev, "can't read capabilities\n");
|
||
|
@@ -1058,6 +1064,7 @@ static int usbtmc_probe(struct usb_interface *intf,
|
||
|
error_register:
|
||
|
sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp);
|
||
|
sysfs_remove_group(&intf->dev.kobj, &data_attr_grp);
|
||
|
+err_put:
|
||
|
kref_put(&data->kref, usbtmc_delete);
|
||
|
return retcode;
|
||
|
}
|
||
|
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
|
||
|
index 3252bb2dcb80..d6481cb469c3 100644
|
||
|
--- a/drivers/usb/core/config.c
|
||
|
+++ b/drivers/usb/core/config.c
|
||
|
@@ -207,6 +207,16 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
|
||
|
if (ifp->desc.bNumEndpoints >= num_ep)
|
||
|
goto skip_to_next_endpoint_or_interface_descriptor;
|
||
|
|
||
|
+ /* Check for duplicate endpoint addresses */
|
||
|
+ for (i = 0; i < ifp->desc.bNumEndpoints; ++i) {
|
||
|
+ if (ifp->endpoint[i].desc.bEndpointAddress ==
|
||
|
+ d->bEndpointAddress) {
|
||
|
+ dev_warn(ddev, "config %d interface %d altsetting %d has a duplicate endpoint with address 0x%X, skipping\n",
|
||
|
+ cfgno, inum, asnum, d->bEndpointAddress);
|
||
|
+ goto skip_to_next_endpoint_or_interface_descriptor;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
endpoint = &ifp->endpoint[ifp->desc.bNumEndpoints];
|
||
|
++ifp->desc.bNumEndpoints;
|
||
|
|
||
|
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
|
||
|
index 0dfee61f7878..5a2eaf401b00 100644
|
||
|
--- a/drivers/usb/dwc3/gadget.c
|
||
|
+++ b/drivers/usb/dwc3/gadget.c
|
||
|
@@ -265,11 +265,11 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
|
||
|
if (req->request.status == -EINPROGRESS)
|
||
|
req->request.status = status;
|
||
|
|
||
|
- if (dwc->ep0_bounced && dep->number == 0)
|
||
|
+ if (dwc->ep0_bounced && dep->number <= 1)
|
||
|
dwc->ep0_bounced = false;
|
||
|
- else
|
||
|
- usb_gadget_unmap_request(&dwc->gadget, &req->request,
|
||
|
- req->direction);
|
||
|
+
|
||
|
+ usb_gadget_unmap_request(&dwc->gadget, &req->request,
|
||
|
+ req->direction);
|
||
|
|
||
|
dev_dbg(dwc->dev, "request %p from %s completed %d/%d ===> %d\n",
|
||
|
req, dep->name, req->request.actual,
|
||
|
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
|
||
|
index a660716f9331..584e43c9748f 100644
|
||
|
--- a/drivers/usb/gadget/composite.c
|
||
|
+++ b/drivers/usb/gadget/composite.c
|
||
|
@@ -1320,9 +1320,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
||
|
value = min(w_length, (u16) 1);
|
||
|
break;
|
||
|
|
||
|
- /* function drivers must handle get/set altsetting; if there's
|
||
|
- * no get() method, we know only altsetting zero works.
|
||
|
- */
|
||
|
+ /* function drivers must handle get/set altsetting */
|
||
|
case USB_REQ_SET_INTERFACE:
|
||
|
if (ctrl->bRequestType != USB_RECIP_INTERFACE)
|
||
|
goto unknown;
|
||
|
@@ -1331,7 +1329,13 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
||
|
f = cdev->config->interface[intf];
|
||
|
if (!f)
|
||
|
break;
|
||
|
- if (w_value && !f->set_alt)
|
||
|
+
|
||
|
+ /*
|
||
|
+ * If there's no get_alt() method, we know only altsetting zero
|
||
|
+ * works. There is no need to check if set_alt() is not NULL
|
||
|
+ * as we check this in usb_add_function().
|
||
|
+ */
|
||
|
+ if (w_value && !f->get_alt)
|
||
|
break;
|
||
|
value = f->set_alt(f, w_index, w_value);
|
||
|
if (value == USB_GADGET_DELAYED_STATUS) {
|
||
|
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
|
||
|
index ac0e79e2c2e9..644c1053d650 100644
|
||
|
--- a/drivers/usb/gadget/dummy_hcd.c
|
||
|
+++ b/drivers/usb/gadget/dummy_hcd.c
|
||
|
@@ -266,7 +266,7 @@ static void nuke(struct dummy *dum, struct dummy_ep *ep)
|
||
|
/* caller must hold lock */
|
||
|
static void stop_activity(struct dummy *dum)
|
||
|
{
|
||
|
- struct dummy_ep *ep;
|
||
|
+ int i;
|
||
|
|
||
|
/* prevent any more requests */
|
||
|
dum->address = 0;
|
||
|
@@ -274,8 +274,8 @@ static void stop_activity(struct dummy *dum)
|
||
|
/* The timer is left running so that outstanding URBs can fail */
|
||
|
|
||
|
/* nuke any pending requests first, so driver i/o is quiesced */
|
||
|
- list_for_each_entry(ep, &dum->gadget.ep_list, ep.ep_list)
|
||
|
- nuke(dum, ep);
|
||
|
+ for (i = 0; i < DUMMY_ENDPOINTS; ++i)
|
||
|
+ nuke(dum, &dum->ep[i]);
|
||
|
|
||
|
/* driver now does any non-usb quiescing necessary */
|
||
|
}
|
||
|
diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
|
||
|
index 1e1563da1812..7f93dc26fb15 100644
|
||
|
--- a/drivers/usb/host/ohci-q.c
|
||
|
+++ b/drivers/usb/host/ohci-q.c
|
||
|
@@ -927,10 +927,6 @@ rescan_all:
|
||
|
int completed, modified;
|
||
|
__hc32 *prev;
|
||
|
|
||
|
- /* Is this ED already invisible to the hardware? */
|
||
|
- if (ed->state == ED_IDLE)
|
||
|
- goto ed_idle;
|
||
|
-
|
||
|
/* only take off EDs that the HC isn't using, accounting for
|
||
|
* frame counter wraps and EDs with partially retired TDs
|
||
|
*/
|
||
|
@@ -961,14 +957,12 @@ skip_ed:
|
||
|
}
|
||
|
|
||
|
/* ED's now officially unlinked, hc doesn't see */
|
||
|
- ed->state = ED_IDLE;
|
||
|
if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT)
|
||
|
ohci->eds_scheduled--;
|
||
|
ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H);
|
||
|
ed->hwNextED = 0;
|
||
|
wmb();
|
||
|
ed->hwINFO &= ~cpu_to_hc32(ohci, ED_SKIP | ED_DEQUEUE);
|
||
|
-ed_idle:
|
||
|
|
||
|
/* reentrancy: if we drop the schedule lock, someone might
|
||
|
* have modified this list. normally it's just prepending
|
||
|
@@ -1039,6 +1033,7 @@ rescan_this:
|
||
|
if (list_empty(&ed->td_list)) {
|
||
|
*last = ed->ed_next;
|
||
|
ed->ed_next = NULL;
|
||
|
+ ed->state = ED_IDLE;
|
||
|
} else if (ohci->rh_state == OHCI_RH_RUNNING) {
|
||
|
*last = ed->ed_next;
|
||
|
ed->ed_next = NULL;
|
||
|
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
|
||
|
index af9e4e8c9064..b07e0754d784 100644
|
||
|
--- a/drivers/usb/host/xhci-mem.c
|
||
|
+++ b/drivers/usb/host/xhci-mem.c
|
||
|
@@ -2306,7 +2306,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
|
||
|
* "physically contiguous and 64-byte (cache line) aligned".
|
||
|
*/
|
||
|
xhci->dcbaa = dma_alloc_coherent(dev, sizeof(*xhci->dcbaa), &dma,
|
||
|
- GFP_KERNEL);
|
||
|
+ flags);
|
||
|
if (!xhci->dcbaa)
|
||
|
goto fail;
|
||
|
memset(xhci->dcbaa, 0, sizeof *(xhci->dcbaa));
|
||
|
@@ -2397,7 +2397,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
|
||
|
|
||
|
xhci->erst.entries = dma_alloc_coherent(dev,
|
||
|
sizeof(struct xhci_erst_entry) * ERST_NUM_SEGS, &dma,
|
||
|
- GFP_KERNEL);
|
||
|
+ flags);
|
||
|
if (!xhci->erst.entries)
|
||
|
goto fail;
|
||
|
xhci_dbg(xhci, "// Allocated event ring segment table at 0x%llx\n",
|
||
|
diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c
|
||
|
index ce978384fda1..3b885c61b73e 100644
|
||
|
--- a/drivers/usb/misc/idmouse.c
|
||
|
+++ b/drivers/usb/misc/idmouse.c
|
||
|
@@ -347,6 +347,9 @@ static int idmouse_probe(struct usb_interface *interface,
|
||
|
if (iface_desc->desc.bInterfaceClass != 0x0A)
|
||
|
return -ENODEV;
|
||
|
|
||
|
+ if (iface_desc->desc.bNumEndpoints < 1)
|
||
|
+ return -ENODEV;
|
||
|
+
|
||
|
/* allocate memory for our device state and initialize it */
|
||
|
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||
|
if (dev == NULL)
|
||
|
diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
|
||
|
index 4c24ba0a6574..05aa716cf6b5 100644
|
||
|
--- a/drivers/usb/misc/iowarrior.c
|
||
|
+++ b/drivers/usb/misc/iowarrior.c
|
||
|
@@ -792,12 +792,6 @@ static int iowarrior_probe(struct usb_interface *interface,
|
||
|
iface_desc = interface->cur_altsetting;
|
||
|
dev->product_id = le16_to_cpu(udev->descriptor.idProduct);
|
||
|
|
||
|
- if (iface_desc->desc.bNumEndpoints < 1) {
|
||
|
- dev_err(&interface->dev, "Invalid number of endpoints\n");
|
||
|
- retval = -EINVAL;
|
||
|
- goto error;
|
||
|
- }
|
||
|
-
|
||
|
/* set up the endpoint information */
|
||
|
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
|
||
|
endpoint = &iface_desc->endpoint[i].desc;
|
||
|
@@ -808,6 +802,21 @@ static int iowarrior_probe(struct usb_interface *interface,
|
||
|
/* this one will match for the IOWarrior56 only */
|
||
|
dev->int_out_endpoint = endpoint;
|
||
|
}
|
||
|
+
|
||
|
+ if (!dev->int_in_endpoint) {
|
||
|
+ dev_err(&interface->dev, "no interrupt-in endpoint found\n");
|
||
|
+ retval = -ENODEV;
|
||
|
+ goto error;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56) {
|
||
|
+ if (!dev->int_out_endpoint) {
|
||
|
+ dev_err(&interface->dev, "no interrupt-out endpoint found\n");
|
||
|
+ retval = -ENODEV;
|
||
|
+ goto error;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
/* we have to check the report_size often, so remember it in the endianness suitable for our machine */
|
||
|
dev->report_size = usb_endpoint_maxp(dev->int_in_endpoint);
|
||
|
if ((dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) &&
|
||
|
diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
|
||
|
index e129cf661223..20d7e5312f0e 100644
|
||
|
--- a/drivers/usb/misc/uss720.c
|
||
|
+++ b/drivers/usb/misc/uss720.c
|
||
|
@@ -709,6 +709,11 @@ static int uss720_probe(struct usb_interface *intf,
|
||
|
|
||
|
interface = intf->cur_altsetting;
|
||
|
|
||
|
+ if (interface->desc.bNumEndpoints < 3) {
|
||
|
+ usb_put_dev(usbdev);
|
||
|
+ return -ENODEV;
|
||
|
+ }
|
||
|
+
|
||
|
/*
|
||
|
* Allocate parport interface
|
||
|
*/
|
||
|
diff --git a/drivers/usb/musb/musbhsdma.h b/drivers/usb/musb/musbhsdma.h
|
||
|
index f7b13fd25257..a3dcbd55e436 100644
|
||
|
--- a/drivers/usb/musb/musbhsdma.h
|
||
|
+++ b/drivers/usb/musb/musbhsdma.h
|
||
|
@@ -157,5 +157,5 @@ struct musb_dma_controller {
|
||
|
void __iomem *base;
|
||
|
u8 channel_count;
|
||
|
u8 used_channels;
|
||
|
- u8 irq;
|
||
|
+ int irq;
|
||
|
};
|
||
|
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
|
||
|
index 40e7fd94646f..62fb2553c771 100644
|
||
|
--- a/drivers/usb/serial/ark3116.c
|
||
|
+++ b/drivers/usb/serial/ark3116.c
|
||
|
@@ -100,10 +100,17 @@ static int ark3116_read_reg(struct usb_serial *serial,
|
||
|
usb_rcvctrlpipe(serial->dev, 0),
|
||
|
0xfe, 0xc0, 0, reg,
|
||
|
buf, 1, ARK_TIMEOUT);
|
||
|
- if (result < 0)
|
||
|
+ if (result < 1) {
|
||
|
+ dev_err(&serial->interface->dev,
|
||
|
+ "failed to read register %u: %d\n",
|
||
|
+ reg, result);
|
||
|
+ if (result >= 0)
|
||
|
+ result = -EIO;
|
||
|
+
|
||
|
return result;
|
||
|
- else
|
||
|
- return buf[0];
|
||
|
+ }
|
||
|
+
|
||
|
+ return buf[0];
|
||
|
}
|
||
|
|
||
|
static inline int calc_divisor(int bps)
|
||
|
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
|
||
|
index c2a4171ab9cb..a4e5be5aea46 100644
|
||
|
--- a/drivers/usb/serial/ch341.c
|
||
|
+++ b/drivers/usb/serial/ch341.c
|
||
|
@@ -97,6 +97,8 @@ static int ch341_control_out(struct usb_device *dev, u8 request,
|
||
|
r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request,
|
||
|
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
|
||
|
value, index, NULL, 0, DEFAULT_TIMEOUT);
|
||
|
+ if (r < 0)
|
||
|
+ dev_err(&dev->dev, "failed to send control message: %d\n", r);
|
||
|
|
||
|
return r;
|
||
|
}
|
||
|
@@ -114,7 +116,20 @@ static int ch341_control_in(struct usb_device *dev,
|
||
|
r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request,
|
||
|
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
|
||
|
value, index, buf, bufsize, DEFAULT_TIMEOUT);
|
||
|
- return r;
|
||
|
+ if (r < bufsize) {
|
||
|
+ if (r >= 0) {
|
||
|
+ dev_err(&dev->dev,
|
||
|
+ "short control message received (%d < %u)\n",
|
||
|
+ r, bufsize);
|
||
|
+ r = -EIO;
|
||
|
+ }
|
||
|
+
|
||
|
+ dev_err(&dev->dev, "failed to receive control message: %d\n",
|
||
|
+ r);
|
||
|
+ return r;
|
||
|
+ }
|
||
|
+
|
||
|
+ return 0;
|
||
|
}
|
||
|
|
||
|
static int ch341_set_baudrate(struct usb_device *dev,
|
||
|
@@ -156,9 +171,9 @@ static int ch341_set_handshake(struct usb_device *dev, u8 control)
|
||
|
|
||
|
static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv)
|
||
|
{
|
||
|
+ const unsigned int size = 2;
|
||
|
char *buffer;
|
||
|
int r;
|
||
|
- const unsigned size = 8;
|
||
|
unsigned long flags;
|
||
|
|
||
|
buffer = kmalloc(size, GFP_KERNEL);
|
||
|
@@ -169,15 +184,10 @@ static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv)
|
||
|
if (r < 0)
|
||
|
goto out;
|
||
|
|
||
|
- /* setup the private status if available */
|
||
|
- if (r == 2) {
|
||
|
- r = 0;
|
||
|
- spin_lock_irqsave(&priv->lock, flags);
|
||
|
- priv->line_status = (~(*buffer)) & CH341_BITS_MODEM_STAT;
|
||
|
- priv->multi_status_change = 0;
|
||
|
- spin_unlock_irqrestore(&priv->lock, flags);
|
||
|
- } else
|
||
|
- r = -EPROTO;
|
||
|
+ spin_lock_irqsave(&priv->lock, flags);
|
||
|
+ priv->line_status = (~(*buffer)) & CH341_BITS_MODEM_STAT;
|
||
|
+ priv->multi_status_change = 0;
|
||
|
+ spin_unlock_irqrestore(&priv->lock, flags);
|
||
|
|
||
|
out: kfree(buffer);
|
||
|
return r;
|
||
|
@@ -187,9 +197,9 @@ out: kfree(buffer);
|
||
|
|
||
|
static int ch341_configure(struct usb_device *dev, struct ch341_private *priv)
|
||
|
{
|
||
|
+ const unsigned int size = 2;
|
||
|
char *buffer;
|
||
|
int r;
|
||
|
- const unsigned size = 8;
|
||
|
|
||
|
buffer = kmalloc(size, GFP_KERNEL);
|
||
|
if (!buffer)
|
||
|
@@ -252,7 +262,6 @@ static int ch341_port_probe(struct usb_serial_port *port)
|
||
|
|
||
|
spin_lock_init(&priv->lock);
|
||
|
priv->baud_rate = DEFAULT_BAUD_RATE;
|
||
|
- priv->line_control = CH341_BIT_RTS | CH341_BIT_DTR;
|
||
|
|
||
|
r = ch341_configure(port->serial->dev, priv);
|
||
|
if (r < 0)
|
||
|
@@ -316,15 +325,15 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||
|
|
||
|
r = ch341_configure(serial->dev, priv);
|
||
|
if (r)
|
||
|
- goto out;
|
||
|
+ return r;
|
||
|
|
||
|
r = ch341_set_handshake(serial->dev, priv->line_control);
|
||
|
if (r)
|
||
|
- goto out;
|
||
|
+ return r;
|
||
|
|
||
|
r = ch341_set_baudrate(serial->dev, priv);
|
||
|
if (r)
|
||
|
- goto out;
|
||
|
+ return r;
|
||
|
|
||
|
dev_dbg(&port->dev, "%s - submitting interrupt urb", __func__);
|
||
|
r = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
|
||
|
@@ -332,12 +341,19 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||
|
dev_err(&port->dev, "%s - failed submitting interrupt urb,"
|
||
|
" error %d\n", __func__, r);
|
||
|
ch341_close(port);
|
||
|
- goto out;
|
||
|
+ return r;
|
||
|
}
|
||
|
|
||
|
r = usb_serial_generic_open(tty, port);
|
||
|
+ if (r)
|
||
|
+ goto err_kill_interrupt_urb;
|
||
|
|
||
|
-out: return r;
|
||
|
+ return 0;
|
||
|
+
|
||
|
+err_kill_interrupt_urb:
|
||
|
+ usb_kill_urb(port->interrupt_in_urb);
|
||
|
+
|
||
|
+ return r;
|
||
|
}
|
||
|
|
||
|
/* Old_termios contains the original termios settings and
|
||
|
@@ -352,26 +368,25 @@ static void ch341_set_termios(struct tty_struct *tty,
|
||
|
|
||
|
baud_rate = tty_get_baud_rate(tty);
|
||
|
|
||
|
- priv->baud_rate = baud_rate;
|
||
|
-
|
||
|
if (baud_rate) {
|
||
|
- spin_lock_irqsave(&priv->lock, flags);
|
||
|
- priv->line_control |= (CH341_BIT_DTR | CH341_BIT_RTS);
|
||
|
- spin_unlock_irqrestore(&priv->lock, flags);
|
||
|
+ priv->baud_rate = baud_rate;
|
||
|
ch341_set_baudrate(port->serial->dev, priv);
|
||
|
- } else {
|
||
|
- spin_lock_irqsave(&priv->lock, flags);
|
||
|
- priv->line_control &= ~(CH341_BIT_DTR | CH341_BIT_RTS);
|
||
|
- spin_unlock_irqrestore(&priv->lock, flags);
|
||
|
}
|
||
|
|
||
|
- ch341_set_handshake(port->serial->dev, priv->line_control);
|
||
|
-
|
||
|
/* Unimplemented:
|
||
|
* (cflag & CSIZE) : data bits [5, 8]
|
||
|
* (cflag & PARENB) : parity {NONE, EVEN, ODD}
|
||
|
* (cflag & CSTOPB) : stop bits [1, 2]
|
||
|
*/
|
||
|
+
|
||
|
+ spin_lock_irqsave(&priv->lock, flags);
|
||
|
+ if (C_BAUD(tty) == B0)
|
||
|
+ priv->line_control &= ~(CH341_BIT_DTR | CH341_BIT_RTS);
|
||
|
+ else if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
|
||
|
+ priv->line_control |= (CH341_BIT_DTR | CH341_BIT_RTS);
|
||
|
+ spin_unlock_irqrestore(&priv->lock, flags);
|
||
|
+
|
||
|
+ ch341_set_handshake(port->serial->dev, priv->line_control);
|
||
|
}
|
||
|
|
||
|
static void ch341_break_ctl(struct tty_struct *tty, int break_state)
|
||
|
@@ -570,14 +585,23 @@ static int ch341_tiocmget(struct tty_struct *tty)
|
||
|
|
||
|
static int ch341_reset_resume(struct usb_serial *serial)
|
||
|
{
|
||
|
- struct ch341_private *priv;
|
||
|
-
|
||
|
- priv = usb_get_serial_port_data(serial->port[0]);
|
||
|
+ struct usb_serial_port *port = serial->port[0];
|
||
|
+ struct ch341_private *priv = usb_get_serial_port_data(port);
|
||
|
+ int ret;
|
||
|
|
||
|
/* reconfigure ch341 serial port after bus-reset */
|
||
|
ch341_configure(serial->dev, priv);
|
||
|
|
||
|
- return 0;
|
||
|
+ if (test_bit(ASYNCB_INITIALIZED, &port->port.flags)) {
|
||
|
+ ret = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
|
||
|
+ if (ret) {
|
||
|
+ dev_err(&port->dev, "failed to submit interrupt urb: %d\n",
|
||
|
+ ret);
|
||
|
+ return ret;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ return usb_serial_generic_resume(serial);
|
||
|
}
|
||
|
|
||
|
static struct usb_serial_driver ch341_device = {
|
||
|
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
|
||
|
index 781426230d69..bb3c7f09f059 100644
|
||
|
--- a/drivers/usb/serial/cyberjack.c
|
||
|
+++ b/drivers/usb/serial/cyberjack.c
|
||
|
@@ -51,6 +51,7 @@
|
||
|
#define CYBERJACK_PRODUCT_ID 0x0100
|
||
|
|
||
|
/* Function prototypes */
|
||
|
+static int cyberjack_attach(struct usb_serial *serial);
|
||
|
static int cyberjack_port_probe(struct usb_serial_port *port);
|
||
|
static int cyberjack_port_remove(struct usb_serial_port *port);
|
||
|
static int cyberjack_open(struct tty_struct *tty,
|
||
|
@@ -78,6 +79,7 @@ static struct usb_serial_driver cyberjack_device = {
|
||
|
.description = "Reiner SCT Cyberjack USB card reader",
|
||
|
.id_table = id_table,
|
||
|
.num_ports = 1,
|
||
|
+ .attach = cyberjack_attach,
|
||
|
.port_probe = cyberjack_port_probe,
|
||
|
.port_remove = cyberjack_port_remove,
|
||
|
.open = cyberjack_open,
|
||
|
@@ -101,6 +103,14 @@ struct cyberjack_private {
|
||
|
short wrsent; /* Data already sent */
|
||
|
};
|
||
|
|
||
|
+static int cyberjack_attach(struct usb_serial *serial)
|
||
|
+{
|
||
|
+ if (serial->num_bulk_out < serial->num_ports)
|
||
|
+ return -ENODEV;
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
static int cyberjack_port_probe(struct usb_serial_port *port)
|
||
|
{
|
||
|
struct cyberjack_private *priv;
|
||
|
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
|
||
|
index 8c34d9cfb226..e8d7c1beae83 100644
|
||
|
--- a/drivers/usb/serial/digi_acceleport.c
|
||
|
+++ b/drivers/usb/serial/digi_acceleport.c
|
||
|
@@ -1489,16 +1489,20 @@ static int digi_read_oob_callback(struct urb *urb)
|
||
|
struct usb_serial *serial = port->serial;
|
||
|
struct tty_struct *tty;
|
||
|
struct digi_port *priv = usb_get_serial_port_data(port);
|
||
|
+ unsigned char *buf = urb->transfer_buffer;
|
||
|
int opcode, line, status, val;
|
||
|
int i;
|
||
|
unsigned int rts;
|
||
|
|
||
|
+ if (urb->actual_length < 4)
|
||
|
+ return -1;
|
||
|
+
|
||
|
/* handle each oob command */
|
||
|
- for (i = 0; i < urb->actual_length - 3;) {
|
||
|
- opcode = ((unsigned char *)urb->transfer_buffer)[i++];
|
||
|
- line = ((unsigned char *)urb->transfer_buffer)[i++];
|
||
|
- status = ((unsigned char *)urb->transfer_buffer)[i++];
|
||
|
- val = ((unsigned char *)urb->transfer_buffer)[i++];
|
||
|
+ for (i = 0; i < urb->actual_length - 3; i += 4) {
|
||
|
+ opcode = buf[i];
|
||
|
+ line = buf[i + 1];
|
||
|
+ status = buf[i + 2];
|
||
|
+ val = buf[i + 3];
|
||
|
|
||
|
dev_dbg(&port->dev, "digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d\n",
|
||
|
opcode, line, status, val);
|
||
|
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
|
||
|
index 4e865664699b..ce884f7434b8 100644
|
||
|
--- a/drivers/usb/serial/ftdi_sio.c
|
||
|
+++ b/drivers/usb/serial/ftdi_sio.c
|
||
|
@@ -1813,8 +1813,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
|
||
|
|
||
|
mutex_init(&priv->cfg_lock);
|
||
|
|
||
|
- priv->flags = ASYNC_LOW_LATENCY;
|
||
|
-
|
||
|
if (quirk && quirk->port_probe)
|
||
|
quirk->port_probe(priv);
|
||
|
|
||
|
@@ -2091,6 +2089,20 @@ static int ftdi_process_packet(struct usb_serial_port *port,
|
||
|
priv->prev_status = status;
|
||
|
}
|
||
|
|
||
|
+ /* save if the transmitter is empty or not */
|
||
|
+ if (packet[1] & FTDI_RS_TEMT)
|
||
|
+ priv->transmit_empty = 1;
|
||
|
+ else
|
||
|
+ priv->transmit_empty = 0;
|
||
|
+
|
||
|
+ len -= 2;
|
||
|
+ if (!len)
|
||
|
+ return 0; /* status only */
|
||
|
+
|
||
|
+ /*
|
||
|
+ * Break and error status must only be processed for packets with
|
||
|
+ * data payload to avoid over-reporting.
|
||
|
+ */
|
||
|
flag = TTY_NORMAL;
|
||
|
if (packet[1] & FTDI_RS_ERR_MASK) {
|
||
|
/* Break takes precedence over parity, which takes precedence
|
||
|
@@ -2113,15 +2125,6 @@ static int ftdi_process_packet(struct usb_serial_port *port,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- /* save if the transmitter is empty or not */
|
||
|
- if (packet[1] & FTDI_RS_TEMT)
|
||
|
- priv->transmit_empty = 1;
|
||
|
- else
|
||
|
- priv->transmit_empty = 0;
|
||
|
-
|
||
|
- len -= 2;
|
||
|
- if (!len)
|
||
|
- return 0; /* status only */
|
||
|
port->icount.rx += len;
|
||
|
ch = packet + 2;
|
||
|
|
||
|
@@ -2452,8 +2455,12 @@ static int ftdi_get_modem_status(struct usb_serial_port *port,
|
||
|
FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
|
||
|
0, priv->interface,
|
||
|
buf, len, WDR_TIMEOUT);
|
||
|
- if (ret < 0) {
|
||
|
+
|
||
|
+ /* NOTE: We allow short responses and handle that below. */
|
||
|
+ if (ret < 1) {
|
||
|
dev_err(&port->dev, "failed to get modem status: %d\n", ret);
|
||
|
+ if (ret >= 0)
|
||
|
+ ret = -EIO;
|
||
|
ret = usb_translate_errors(ret);
|
||
|
goto out;
|
||
|
}
|
||
|
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
|
||
|
index b110c573ea85..ea9c4f4aea32 100644
|
||
|
--- a/drivers/usb/serial/garmin_gps.c
|
||
|
+++ b/drivers/usb/serial/garmin_gps.c
|
||
|
@@ -1049,6 +1049,7 @@ static int garmin_write_bulk(struct usb_serial_port *port,
|
||
|
"%s - usb_submit_urb(write bulk) failed with status = %d\n",
|
||
|
__func__, status);
|
||
|
count = status;
|
||
|
+ kfree(buffer);
|
||
|
}
|
||
|
|
||
|
/* we are done with this urb, so let the host driver
|
||
|
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
|
||
|
index c574d312f1f5..9f24fd776ec0 100644
|
||
|
--- a/drivers/usb/serial/io_edgeport.c
|
||
|
+++ b/drivers/usb/serial/io_edgeport.c
|
||
|
@@ -2795,6 +2795,11 @@ static int edge_startup(struct usb_serial *serial)
|
||
|
EDGE_COMPATIBILITY_MASK1,
|
||
|
EDGE_COMPATIBILITY_MASK2 };
|
||
|
|
||
|
+ if (serial->num_bulk_in < 1 || serial->num_interrupt_in < 1) {
|
||
|
+ dev_err(&serial->interface->dev, "missing endpoints\n");
|
||
|
+ return -ENODEV;
|
||
|
+ }
|
||
|
+
|
||
|
dev = serial->dev;
|
||
|
|
||
|
/* create our private serial structure */
|
||
|
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
|
||
|
index 8cd6479a8b43..20814d528c15 100644
|
||
|
--- a/drivers/usb/serial/io_ti.c
|
||
|
+++ b/drivers/usb/serial/io_ti.c
|
||
|
@@ -1402,7 +1402,7 @@ stayinbootmode:
|
||
|
dev_dbg(dev, "%s - STAYING IN BOOT MODE\n", __func__);
|
||
|
serial->product_info.TiMode = TI_MODE_BOOT;
|
||
|
|
||
|
- return 0;
|
||
|
+ return 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
@@ -1575,6 +1575,12 @@ static void edge_interrupt_callback(struct urb *urb)
|
||
|
function = TIUMP_GET_FUNC_FROM_CODE(data[0]);
|
||
|
dev_dbg(dev, "%s - port_number %d, function %d, info 0x%x\n", __func__,
|
||
|
port_number, function, data[1]);
|
||
|
+
|
||
|
+ if (port_number >= edge_serial->serial->num_ports) {
|
||
|
+ dev_err(dev, "bad port number %d\n", port_number);
|
||
|
+ goto exit;
|
||
|
+ }
|
||
|
+
|
||
|
port = edge_serial->serial->port[port_number];
|
||
|
edge_port = usb_get_serial_port_data(port);
|
||
|
if (!edge_port) {
|
||
|
@@ -1655,7 +1661,7 @@ static void edge_bulk_in_callback(struct urb *urb)
|
||
|
|
||
|
port_number = edge_port->port->number - edge_port->port->serial->minor;
|
||
|
|
||
|
- if (edge_port->lsr_event) {
|
||
|
+ if (urb->actual_length > 0 && edge_port->lsr_event) {
|
||
|
edge_port->lsr_event = 0;
|
||
|
dev_dbg(dev, "%s ===== Port %u LSR Status = %02x, Data = %02x ======\n",
|
||
|
__func__, port_number, edge_port->lsr_mask, *data);
|
||
|
@@ -2433,6 +2439,13 @@ static int edge_startup(struct usb_serial *serial)
|
||
|
struct edgeport_serial *edge_serial;
|
||
|
int status;
|
||
|
|
||
|
+ /* Make sure we have the required endpoints when in download mode. */
|
||
|
+ if (serial->interface->cur_altsetting->desc.bNumEndpoints > 1) {
|
||
|
+ if (serial->num_bulk_in < serial->num_ports ||
|
||
|
+ serial->num_bulk_out < serial->num_ports)
|
||
|
+ return -ENODEV;
|
||
|
+ }
|
||
|
+
|
||
|
/* create our private serial structure */
|
||
|
edge_serial = kzalloc(sizeof(struct edgeport_serial), GFP_KERNEL);
|
||
|
if (edge_serial == NULL) {
|
||
|
@@ -2444,11 +2457,14 @@ static int edge_startup(struct usb_serial *serial)
|
||
|
usb_set_serial_data(serial, edge_serial);
|
||
|
|
||
|
status = download_fw(edge_serial);
|
||
|
- if (status) {
|
||
|
+ if (status < 0) {
|
||
|
kfree(edge_serial);
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
+ if (status > 0)
|
||
|
+ return 1; /* bind but do not register any ports */
|
||
|
+
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
|
||
|
index 790673e5faa7..eadab621361a 100644
|
||
|
--- a/drivers/usb/serial/iuu_phoenix.c
|
||
|
+++ b/drivers/usb/serial/iuu_phoenix.c
|
||
|
@@ -69,6 +69,16 @@ struct iuu_private {
|
||
|
u32 clk;
|
||
|
};
|
||
|
|
||
|
+static int iuu_attach(struct usb_serial *serial)
|
||
|
+{
|
||
|
+ unsigned char num_ports = serial->num_ports;
|
||
|
+
|
||
|
+ if (serial->num_bulk_in < num_ports || serial->num_bulk_out < num_ports)
|
||
|
+ return -ENODEV;
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
static int iuu_port_probe(struct usb_serial_port *port)
|
||
|
{
|
||
|
struct iuu_private *priv;
|
||
|
@@ -1199,6 +1209,7 @@ static struct usb_serial_driver iuu_device = {
|
||
|
.tiocmset = iuu_tiocmset,
|
||
|
.set_termios = iuu_set_termios,
|
||
|
.init_termios = iuu_init_termios,
|
||
|
+ .attach = iuu_attach,
|
||
|
.port_probe = iuu_port_probe,
|
||
|
.port_remove = iuu_port_remove,
|
||
|
};
|
||
|
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
|
||
|
index 5f1d382e55cf..05c567bf5cfa 100644
|
||
|
--- a/drivers/usb/serial/keyspan_pda.c
|
||
|
+++ b/drivers/usb/serial/keyspan_pda.c
|
||
|
@@ -697,6 +697,19 @@ MODULE_FIRMWARE("keyspan_pda/keyspan_pda.fw");
|
||
|
MODULE_FIRMWARE("keyspan_pda/xircom_pgs.fw");
|
||
|
#endif
|
||
|
|
||
|
+static int keyspan_pda_attach(struct usb_serial *serial)
|
||
|
+{
|
||
|
+ unsigned char num_ports = serial->num_ports;
|
||
|
+
|
||
|
+ if (serial->num_bulk_out < num_ports ||
|
||
|
+ serial->num_interrupt_in < num_ports) {
|
||
|
+ dev_err(&serial->interface->dev, "missing endpoints\n");
|
||
|
+ return -ENODEV;
|
||
|
+ }
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
static int keyspan_pda_port_probe(struct usb_serial_port *port)
|
||
|
{
|
||
|
|
||
|
@@ -774,6 +787,7 @@ static struct usb_serial_driver keyspan_pda_device = {
|
||
|
.break_ctl = keyspan_pda_break_ctl,
|
||
|
.tiocmget = keyspan_pda_tiocmget,
|
||
|
.tiocmset = keyspan_pda_tiocmset,
|
||
|
+ .attach = keyspan_pda_attach,
|
||
|
.port_probe = keyspan_pda_port_probe,
|
||
|
.port_remove = keyspan_pda_port_remove,
|
||
|
};
|
||
|
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
|
||
|
index 1b4054fe52a5..b6794baf0a3b 100644
|
||
|
--- a/drivers/usb/serial/kl5kusb105.c
|
||
|
+++ b/drivers/usb/serial/kl5kusb105.c
|
||
|
@@ -198,10 +198,11 @@ static int klsi_105_get_line_state(struct usb_serial_port *port,
|
||
|
status_buf, KLSI_STATUSBUF_LEN,
|
||
|
10000
|
||
|
);
|
||
|
- if (rc < 0)
|
||
|
- dev_err(&port->dev, "Reading line status failed (error = %d)\n",
|
||
|
- rc);
|
||
|
- else {
|
||
|
+ if (rc != KLSI_STATUSBUF_LEN) {
|
||
|
+ dev_err(&port->dev, "reading line status failed: %d\n", rc);
|
||
|
+ if (rc >= 0)
|
||
|
+ rc = -EIO;
|
||
|
+ } else {
|
||
|
status = get_unaligned_le16(status_buf);
|
||
|
|
||
|
dev_info(&port->serial->dev->dev, "read status %x %x",
|
||
|
@@ -304,7 +305,7 @@ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||
|
rc = usb_serial_generic_open(tty, port);
|
||
|
if (rc) {
|
||
|
retval = rc;
|
||
|
- goto exit;
|
||
|
+ goto err_free_cfg;
|
||
|
}
|
||
|
|
||
|
rc = usb_control_msg(port->serial->dev,
|
||
|
@@ -319,21 +320,38 @@ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||
|
if (rc < 0) {
|
||
|
dev_err(&port->dev, "Enabling read failed (error = %d)\n", rc);
|
||
|
retval = rc;
|
||
|
+ goto err_generic_close;
|
||
|
} else
|
||
|
dev_dbg(&port->dev, "%s - enabled reading\n", __func__);
|
||
|
|
||
|
rc = klsi_105_get_line_state(port, &line_state);
|
||
|
- if (rc >= 0) {
|
||
|
- spin_lock_irqsave(&priv->lock, flags);
|
||
|
- priv->line_state = line_state;
|
||
|
- spin_unlock_irqrestore(&priv->lock, flags);
|
||
|
- dev_dbg(&port->dev, "%s - read line state 0x%lx\n", __func__, line_state);
|
||
|
- retval = 0;
|
||
|
- } else
|
||
|
+ if (rc < 0) {
|
||
|
retval = rc;
|
||
|
+ goto err_disable_read;
|
||
|
+ }
|
||
|
+
|
||
|
+ spin_lock_irqsave(&priv->lock, flags);
|
||
|
+ priv->line_state = line_state;
|
||
|
+ spin_unlock_irqrestore(&priv->lock, flags);
|
||
|
+ dev_dbg(&port->dev, "%s - read line state 0x%lx\n", __func__,
|
||
|
+ line_state);
|
||
|
+
|
||
|
+ return 0;
|
||
|
|
||
|
-exit:
|
||
|
+err_disable_read:
|
||
|
+ usb_control_msg(port->serial->dev,
|
||
|
+ usb_sndctrlpipe(port->serial->dev, 0),
|
||
|
+ KL5KUSB105A_SIO_CONFIGURE,
|
||
|
+ USB_TYPE_VENDOR | USB_DIR_OUT,
|
||
|
+ KL5KUSB105A_SIO_CONFIGURE_READ_OFF,
|
||
|
+ 0, /* index */
|
||
|
+ NULL, 0,
|
||
|
+ KLSI_TIMEOUT);
|
||
|
+err_generic_close:
|
||
|
+ usb_serial_generic_close(port);
|
||
|
+err_free_cfg:
|
||
|
kfree(cfg);
|
||
|
+
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
|
||
|
index efa75b4e51f2..63fa400a822f 100644
|
||
|
--- a/drivers/usb/serial/kobil_sct.c
|
||
|
+++ b/drivers/usb/serial/kobil_sct.c
|
||
|
@@ -52,6 +52,7 @@
|
||
|
|
||
|
|
||
|
/* Function prototypes */
|
||
|
+static int kobil_attach(struct usb_serial *serial);
|
||
|
static int kobil_port_probe(struct usb_serial_port *probe);
|
||
|
static int kobil_port_remove(struct usb_serial_port *probe);
|
||
|
static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port);
|
||
|
@@ -87,6 +88,7 @@ static struct usb_serial_driver kobil_device = {
|
||
|
.description = "KOBIL USB smart card terminal",
|
||
|
.id_table = id_table,
|
||
|
.num_ports = 1,
|
||
|
+ .attach = kobil_attach,
|
||
|
.port_probe = kobil_port_probe,
|
||
|
.port_remove = kobil_port_remove,
|
||
|
.ioctl = kobil_ioctl,
|
||
|
@@ -114,6 +116,16 @@ struct kobil_private {
|
||
|
};
|
||
|
|
||
|
|
||
|
+static int kobil_attach(struct usb_serial *serial)
|
||
|
+{
|
||
|
+ if (serial->num_interrupt_out < serial->num_ports) {
|
||
|
+ dev_err(&serial->interface->dev, "missing interrupt-out endpoint\n");
|
||
|
+ return -ENODEV;
|
||
|
+ }
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
static int kobil_port_probe(struct usb_serial_port *port)
|
||
|
{
|
||
|
struct usb_serial *serial = port->serial;
|
||
|
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
|
||
|
index ddc71d706ac6..2d1ad823b1ab 100644
|
||
|
--- a/drivers/usb/serial/mos7720.c
|
||
|
+++ b/drivers/usb/serial/mos7720.c
|
||
|
@@ -66,8 +66,6 @@ struct moschip_port {
|
||
|
struct urb *write_urb_pool[NUM_URBS];
|
||
|
};
|
||
|
|
||
|
-static struct usb_serial_driver moschip7720_2port_driver;
|
||
|
-
|
||
|
#define USB_VENDOR_ID_MOSCHIP 0x9710
|
||
|
#define MOSCHIP_DEVICE_ID_7720 0x7720
|
||
|
#define MOSCHIP_DEVICE_ID_7715 0x7715
|
||
|
@@ -966,25 +964,6 @@ static void mos7720_bulk_out_data_callback(struct urb *urb)
|
||
|
tty_port_tty_wakeup(&mos7720_port->port->port);
|
||
|
}
|
||
|
|
||
|
-/*
|
||
|
- * mos77xx_probe
|
||
|
- * this function installs the appropriate read interrupt endpoint callback
|
||
|
- * depending on whether the device is a 7720 or 7715, thus avoiding costly
|
||
|
- * run-time checks in the high-frequency callback routine itself.
|
||
|
- */
|
||
|
-static int mos77xx_probe(struct usb_serial *serial,
|
||
|
- const struct usb_device_id *id)
|
||
|
-{
|
||
|
- if (id->idProduct == MOSCHIP_DEVICE_ID_7715)
|
||
|
- moschip7720_2port_driver.read_int_callback =
|
||
|
- mos7715_interrupt_callback;
|
||
|
- else
|
||
|
- moschip7720_2port_driver.read_int_callback =
|
||
|
- mos7720_interrupt_callback;
|
||
|
-
|
||
|
- return 0;
|
||
|
-}
|
||
|
-
|
||
|
static int mos77xx_calc_num_ports(struct usb_serial *serial)
|
||
|
{
|
||
|
u16 product = le16_to_cpu(serial->dev->descriptor.idProduct);
|
||
|
@@ -1917,6 +1896,11 @@ static int mos7720_startup(struct usb_serial *serial)
|
||
|
u16 product;
|
||
|
int ret_val;
|
||
|
|
||
|
+ if (serial->num_bulk_in < 2 || serial->num_bulk_out < 2) {
|
||
|
+ dev_err(&serial->interface->dev, "missing bulk endpoints\n");
|
||
|
+ return -ENODEV;
|
||
|
+ }
|
||
|
+
|
||
|
product = le16_to_cpu(serial->dev->descriptor.idProduct);
|
||
|
dev = serial->dev;
|
||
|
|
||
|
@@ -1941,19 +1925,18 @@ static int mos7720_startup(struct usb_serial *serial)
|
||
|
tmp->interrupt_in_endpointAddress;
|
||
|
serial->port[1]->interrupt_in_urb = NULL;
|
||
|
serial->port[1]->interrupt_in_buffer = NULL;
|
||
|
+
|
||
|
+ if (serial->port[0]->interrupt_in_urb) {
|
||
|
+ struct urb *urb = serial->port[0]->interrupt_in_urb;
|
||
|
+
|
||
|
+ urb->complete = mos7715_interrupt_callback;
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
/* setting configuration feature to one */
|
||
|
usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
|
||
|
(__u8)0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5000);
|
||
|
|
||
|
- /* start the interrupt urb */
|
||
|
- ret_val = usb_submit_urb(serial->port[0]->interrupt_in_urb, GFP_KERNEL);
|
||
|
- if (ret_val)
|
||
|
- dev_err(&dev->dev,
|
||
|
- "%s - Error %d submitting control urb\n",
|
||
|
- __func__, ret_val);
|
||
|
-
|
||
|
#ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT
|
||
|
if (product == MOSCHIP_DEVICE_ID_7715) {
|
||
|
ret_val = mos7715_parport_init(serial);
|
||
|
@@ -1961,6 +1944,13 @@ static int mos7720_startup(struct usb_serial *serial)
|
||
|
return ret_val;
|
||
|
}
|
||
|
#endif
|
||
|
+ /* start the interrupt urb */
|
||
|
+ ret_val = usb_submit_urb(serial->port[0]->interrupt_in_urb, GFP_KERNEL);
|
||
|
+ if (ret_val) {
|
||
|
+ dev_err(&dev->dev, "failed to submit interrupt urb: %d\n",
|
||
|
+ ret_val);
|
||
|
+ }
|
||
|
+
|
||
|
/* LSR For Port 1 */
|
||
|
read_mos_reg(serial, 0, LSR, &data);
|
||
|
dev_dbg(&dev->dev, "LSR:%x\n", data);
|
||
|
@@ -1970,6 +1960,8 @@ static int mos7720_startup(struct usb_serial *serial)
|
||
|
|
||
|
static void mos7720_release(struct usb_serial *serial)
|
||
|
{
|
||
|
+ usb_kill_urb(serial->port[0]->interrupt_in_urb);
|
||
|
+
|
||
|
#ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT
|
||
|
/* close the parallel port */
|
||
|
|
||
|
@@ -2052,7 +2044,6 @@ static struct usb_serial_driver moschip7720_2port_driver = {
|
||
|
.close = mos7720_close,
|
||
|
.throttle = mos7720_throttle,
|
||
|
.unthrottle = mos7720_unthrottle,
|
||
|
- .probe = mos77xx_probe,
|
||
|
.attach = mos7720_startup,
|
||
|
.release = mos7720_release,
|
||
|
.port_probe = mos7720_port_probe,
|
||
|
@@ -2066,7 +2057,7 @@ static struct usb_serial_driver moschip7720_2port_driver = {
|
||
|
.chars_in_buffer = mos7720_chars_in_buffer,
|
||
|
.break_ctl = mos7720_break,
|
||
|
.read_bulk_callback = mos7720_bulk_in_callback,
|
||
|
- .read_int_callback = NULL /* dynamically assigned in probe() */
|
||
|
+ .read_int_callback = mos7720_interrupt_callback,
|
||
|
};
|
||
|
|
||
|
static struct usb_serial_driver * const serial_drivers[] = {
|
||
|
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
|
||
|
index 7df7df62e177..3308c43d2313 100644
|
||
|
--- a/drivers/usb/serial/mos7840.c
|
||
|
+++ b/drivers/usb/serial/mos7840.c
|
||
|
@@ -1041,6 +1041,7 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||
|
* (can't set it up in mos7840_startup as the structures *
|
||
|
* were not set up at that time.) */
|
||
|
if (port0->open_ports == 1) {
|
||
|
+ /* FIXME: Buffer never NULL, so URB is not submitted. */
|
||
|
if (serial->port[0]->interrupt_in_buffer == NULL) {
|
||
|
/* set up interrupt urb */
|
||
|
usb_fill_int_urb(serial->port[0]->interrupt_in_urb,
|
||
|
@@ -2255,6 +2256,18 @@ static int mos7840_calc_num_ports(struct usb_serial *serial)
|
||
|
return mos7840_num_ports;
|
||
|
}
|
||
|
|
||
|
+static int mos7840_attach(struct usb_serial *serial)
|
||
|
+{
|
||
|
+ if (serial->num_bulk_in < serial->num_ports ||
|
||
|
+ serial->num_bulk_out < serial->num_ports ||
|
||
|
+ serial->num_interrupt_in < 1) {
|
||
|
+ dev_err(&serial->interface->dev, "missing endpoints\n");
|
||
|
+ return -ENODEV;
|
||
|
+ }
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
static int mos7840_port_probe(struct usb_serial_port *port)
|
||
|
{
|
||
|
struct usb_serial *serial = port->serial;
|
||
|
@@ -2537,6 +2550,7 @@ static struct usb_serial_driver moschip7840_4port_device = {
|
||
|
.tiocmset = mos7840_tiocmset,
|
||
|
.tiocmiwait = usb_serial_generic_tiocmiwait,
|
||
|
.get_icount = usb_serial_generic_get_icount,
|
||
|
+ .attach = mos7840_attach,
|
||
|
.port_probe = mos7840_port_probe,
|
||
|
.port_remove = mos7840_port_remove,
|
||
|
.read_bulk_callback = mos7840_bulk_in_callback,
|
||
|
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
|
||
|
index 5739bf6f7200..8028e5ffe80d 100644
|
||
|
--- a/drivers/usb/serial/omninet.c
|
||
|
+++ b/drivers/usb/serial/omninet.c
|
||
|
@@ -39,6 +39,7 @@ static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port,
|
||
|
const unsigned char *buf, int count);
|
||
|
static int omninet_write_room(struct tty_struct *tty);
|
||
|
static void omninet_disconnect(struct usb_serial *serial);
|
||
|
+static int omninet_attach(struct usb_serial *serial);
|
||
|
static int omninet_port_probe(struct usb_serial_port *port);
|
||
|
static int omninet_port_remove(struct usb_serial_port *port);
|
||
|
|
||
|
@@ -57,6 +58,7 @@ static struct usb_serial_driver zyxel_omninet_device = {
|
||
|
.description = "ZyXEL - omni.net lcd plus usb",
|
||
|
.id_table = id_table,
|
||
|
.num_ports = 1,
|
||
|
+ .attach = omninet_attach,
|
||
|
.port_probe = omninet_port_probe,
|
||
|
.port_remove = omninet_port_remove,
|
||
|
.open = omninet_open,
|
||
|
@@ -105,6 +107,17 @@ struct omninet_data {
|
||
|
__u8 od_outseq; /* Sequence number for bulk_out URBs */
|
||
|
};
|
||
|
|
||
|
+static int omninet_attach(struct usb_serial *serial)
|
||
|
+{
|
||
|
+ /* The second bulk-out endpoint is used for writing. */
|
||
|
+ if (serial->num_bulk_out < 2) {
|
||
|
+ dev_err(&serial->interface->dev, "missing endpoints\n");
|
||
|
+ return -ENODEV;
|
||
|
+ }
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
static int omninet_port_probe(struct usb_serial_port *port)
|
||
|
{
|
||
|
struct omninet_data *od;
|
||
|
@@ -130,12 +143,6 @@ static int omninet_port_remove(struct usb_serial_port *port)
|
||
|
|
||
|
static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||
|
{
|
||
|
- struct usb_serial *serial = port->serial;
|
||
|
- struct usb_serial_port *wport;
|
||
|
-
|
||
|
- wport = serial->port[1];
|
||
|
- tty_port_tty_set(&wport->port, tty);
|
||
|
-
|
||
|
return usb_serial_generic_open(tty, port);
|
||
|
}
|
||
|
|
||
|
diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c
|
||
|
index b0eb1dfc601a..b93ab96573ef 100644
|
||
|
--- a/drivers/usb/serial/opticon.c
|
||
|
+++ b/drivers/usb/serial/opticon.c
|
||
|
@@ -143,7 +143,7 @@ static int opticon_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||
|
usb_clear_halt(port->serial->dev, port->read_urb->pipe);
|
||
|
|
||
|
res = usb_serial_generic_open(tty, port);
|
||
|
- if (!res)
|
||
|
+ if (res)
|
||
|
return res;
|
||
|
|
||
|
/* Request CTS line state, sometimes during opening the current
|
||
|
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
|
||
|
index 7e3e0782e51f..ff83d87ed921 100644
|
||
|
--- a/drivers/usb/serial/oti6858.c
|
||
|
+++ b/drivers/usb/serial/oti6858.c
|
||
|
@@ -135,6 +135,7 @@ static int oti6858_tiocmget(struct tty_struct *tty);
|
||
|
static int oti6858_tiocmset(struct tty_struct *tty,
|
||
|
unsigned int set, unsigned int clear);
|
||
|
static int oti6858_tiocmiwait(struct tty_struct *tty, unsigned long arg);
|
||
|
+static int oti6858_attach(struct usb_serial *serial);
|
||
|
static int oti6858_port_probe(struct usb_serial_port *port);
|
||
|
static int oti6858_port_remove(struct usb_serial_port *port);
|
||
|
|
||
|
@@ -159,6 +160,7 @@ static struct usb_serial_driver oti6858_device = {
|
||
|
.write_bulk_callback = oti6858_write_bulk_callback,
|
||
|
.write_room = oti6858_write_room,
|
||
|
.chars_in_buffer = oti6858_chars_in_buffer,
|
||
|
+ .attach = oti6858_attach,
|
||
|
.port_probe = oti6858_port_probe,
|
||
|
.port_remove = oti6858_port_remove,
|
||
|
};
|
||
|
@@ -328,6 +330,20 @@ static void send_data(struct work_struct *work)
|
||
|
usb_serial_port_softint(port);
|
||
|
}
|
||
|
|
||
|
+static int oti6858_attach(struct usb_serial *serial)
|
||
|
+{
|
||
|
+ unsigned char num_ports = serial->num_ports;
|
||
|
+
|
||
|
+ if (serial->num_bulk_in < num_ports ||
|
||
|
+ serial->num_bulk_out < num_ports ||
|
||
|
+ serial->num_interrupt_in < num_ports) {
|
||
|
+ dev_err(&serial->interface->dev, "missing endpoints\n");
|
||
|
+ return -ENODEV;
|
||
|
+ }
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
static int oti6858_port_probe(struct usb_serial_port *port)
|
||
|
{
|
||
|
struct oti6858_private *priv;
|
||
|
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
|
||
|
index 33313caed504..f496c38d5395 100644
|
||
|
--- a/drivers/usb/serial/pl2303.c
|
||
|
+++ b/drivers/usb/serial/pl2303.c
|
||
|
@@ -175,9 +175,17 @@ static int pl2303_vendor_write(__u16 value, __u16 index,
|
||
|
static int pl2303_startup(struct usb_serial *serial)
|
||
|
{
|
||
|
struct pl2303_serial_private *spriv;
|
||
|
+ unsigned char num_ports = serial->num_ports;
|
||
|
enum pl2303_type type = type_0;
|
||
|
unsigned char *buf;
|
||
|
|
||
|
+ if (serial->num_bulk_in < num_ports ||
|
||
|
+ serial->num_bulk_out < num_ports ||
|
||
|
+ serial->num_interrupt_in < num_ports) {
|
||
|
+ dev_err(&serial->interface->dev, "missing endpoints\n");
|
||
|
+ return -ENODEV;
|
||
|
+ }
|
||
|
+
|
||
|
spriv = kzalloc(sizeof(*spriv), GFP_KERNEL);
|
||
|
if (!spriv)
|
||
|
return -ENOMEM;
|
||
|
diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c
|
||
|
index 13824b5ca343..ecd0a84ffc0d 100644
|
||
|
--- a/drivers/usb/serial/quatech2.c
|
||
|
+++ b/drivers/usb/serial/quatech2.c
|
||
|
@@ -408,16 +408,12 @@ static void qt2_close(struct usb_serial_port *port)
|
||
|
{
|
||
|
struct usb_serial *serial;
|
||
|
struct qt2_port_private *port_priv;
|
||
|
- unsigned long flags;
|
||
|
int i;
|
||
|
|
||
|
serial = port->serial;
|
||
|
port_priv = usb_get_serial_port_data(port);
|
||
|
|
||
|
- spin_lock_irqsave(&port_priv->urb_lock, flags);
|
||
|
usb_kill_urb(port_priv->write_urb);
|
||
|
- port_priv->urb_in_use = false;
|
||
|
- spin_unlock_irqrestore(&port_priv->urb_lock, flags);
|
||
|
|
||
|
/* flush the port transmit buffer */
|
||
|
i = usb_control_msg(serial->dev,
|
||
|
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
|
||
|
index 21cd7bf2a8cc..8e24f8ff2fc6 100644
|
||
|
--- a/drivers/usb/serial/safe_serial.c
|
||
|
+++ b/drivers/usb/serial/safe_serial.c
|
||
|
@@ -215,6 +215,11 @@ static void safe_process_read_urb(struct urb *urb)
|
||
|
if (!safe)
|
||
|
goto out;
|
||
|
|
||
|
+ if (length < 2) {
|
||
|
+ dev_err(&port->dev, "malformed packet\n");
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
fcs = fcs_compute10(data, length, CRC10_INITFCS);
|
||
|
if (fcs) {
|
||
|
dev_err(&port->dev, "%s - bad CRC %x\n", __func__, fcs);
|
||
|
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
|
||
|
index 1694d4ff1639..595a3f0b021e 100644
|
||
|
--- a/drivers/usb/serial/spcp8x5.c
|
||
|
+++ b/drivers/usb/serial/spcp8x5.c
|
||
|
@@ -155,6 +155,19 @@ static int spcp8x5_probe(struct usb_serial *serial,
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
+static int spcp8x5_attach(struct usb_serial *serial)
|
||
|
+{
|
||
|
+ unsigned char num_ports = serial->num_ports;
|
||
|
+
|
||
|
+ if (serial->num_bulk_in < num_ports ||
|
||
|
+ serial->num_bulk_out < num_ports) {
|
||
|
+ dev_err(&serial->interface->dev, "missing endpoints\n");
|
||
|
+ return -ENODEV;
|
||
|
+ }
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
static int spcp8x5_port_probe(struct usb_serial_port *port)
|
||
|
{
|
||
|
const struct usb_device_id *id = usb_get_serial_data(port->serial);
|
||
|
@@ -218,11 +231,17 @@ static int spcp8x5_get_msr(struct usb_serial_port *port, u8 *status)
|
||
|
ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
|
||
|
GET_UART_STATUS, GET_UART_STATUS_TYPE,
|
||
|
0, GET_UART_STATUS_MSR, buf, 1, 100);
|
||
|
- if (ret < 0)
|
||
|
+ if (ret < 1) {
|
||
|
dev_err(&port->dev, "failed to get modem status: %d", ret);
|
||
|
+ if (ret >= 0)
|
||
|
+ ret = -EIO;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
|
||
|
dev_dbg(&port->dev, "0xc0:0x22:0:6 %d - 0x02%x", ret, *buf);
|
||
|
*status = *buf;
|
||
|
+ ret = 0;
|
||
|
+out:
|
||
|
kfree(buf);
|
||
|
|
||
|
return ret;
|
||
|
@@ -479,6 +498,7 @@ static struct usb_serial_driver spcp8x5_device = {
|
||
|
.tiocmget = spcp8x5_tiocmget,
|
||
|
.tiocmset = spcp8x5_tiocmset,
|
||
|
.probe = spcp8x5_probe,
|
||
|
+ .attach = spcp8x5_attach,
|
||
|
.port_probe = spcp8x5_port_probe,
|
||
|
.port_remove = spcp8x5_port_remove,
|
||
|
};
|
||
|
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
|
||
|
index 0a7c68fa5e5e..1ccf221d842b 100644
|
||
|
--- a/drivers/usb/serial/ti_usb_3410_5052.c
|
||
|
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
|
||
|
@@ -401,6 +401,13 @@ static int ti_startup(struct usb_serial *serial)
|
||
|
goto free_tdev;
|
||
|
}
|
||
|
|
||
|
+ if (serial->num_bulk_in < serial->num_ports ||
|
||
|
+ serial->num_bulk_out < serial->num_ports) {
|
||
|
+ dev_err(&serial->interface->dev, "missing endpoints\n");
|
||
|
+ status = -ENODEV;
|
||
|
+ goto free_tdev;
|
||
|
+ }
|
||
|
+
|
||
|
return 0;
|
||
|
|
||
|
free_tdev:
|
||
|
diff --git a/drivers/usb/wusbcore/wa-hc.c b/drivers/usb/wusbcore/wa-hc.c
|
||
|
index a09b65ebd9bb..2bb0fd3f3423 100644
|
||
|
--- a/drivers/usb/wusbcore/wa-hc.c
|
||
|
+++ b/drivers/usb/wusbcore/wa-hc.c
|
||
|
@@ -38,6 +38,9 @@ int wa_create(struct wahc *wa, struct usb_interface *iface)
|
||
|
int result;
|
||
|
struct device *dev = &iface->dev;
|
||
|
|
||
|
+ if (iface->cur_altsetting->desc.bNumEndpoints < 3)
|
||
|
+ return -ENODEV;
|
||
|
+
|
||
|
result = wa_rpipes_create(wa);
|
||
|
if (result < 0)
|
||
|
goto error_rpipes_create;
|
||
|
diff --git a/drivers/uwb/hwa-rc.c b/drivers/uwb/hwa-rc.c
|
||
|
index 810c90ae2c55..cd8bf69aa691 100644
|
||
|
--- a/drivers/uwb/hwa-rc.c
|
||
|
+++ b/drivers/uwb/hwa-rc.c
|
||
|
@@ -811,6 +811,9 @@ static int hwarc_probe(struct usb_interface *iface,
|
||
|
struct hwarc *hwarc;
|
||
|
struct device *dev = &iface->dev;
|
||
|
|
||
|
+ if (iface->cur_altsetting->desc.bNumEndpoints < 1)
|
||
|
+ return -ENODEV;
|
||
|
+
|
||
|
result = -ENOMEM;
|
||
|
uwb_rc = uwb_rc_alloc();
|
||
|
if (uwb_rc == NULL) {
|
||
|
diff --git a/drivers/uwb/i1480/dfu/usb.c b/drivers/uwb/i1480/dfu/usb.c
|
||
|
index 2bfc846ac071..6345e85822a4 100644
|
||
|
--- a/drivers/uwb/i1480/dfu/usb.c
|
||
|
+++ b/drivers/uwb/i1480/dfu/usb.c
|
||
|
@@ -362,6 +362,9 @@ int i1480_usb_probe(struct usb_interface *iface, const struct usb_device_id *id)
|
||
|
result);
|
||
|
}
|
||
|
|
||
|
+ if (iface->cur_altsetting->desc.bNumEndpoints < 1)
|
||
|
+ return -ENODEV;
|
||
|
+
|
||
|
result = -ENOMEM;
|
||
|
i1480_usb = kzalloc(sizeof(*i1480_usb), GFP_KERNEL);
|
||
|
if (i1480_usb == NULL) {
|
||
|
diff --git a/drivers/video/fbcmap.c b/drivers/video/fbcmap.c
|
||
|
index 5c3960da755a..71666c02dea8 100644
|
||
|
--- a/drivers/video/fbcmap.c
|
||
|
+++ b/drivers/video/fbcmap.c
|
||
|
@@ -163,17 +163,18 @@ void fb_dealloc_cmap(struct fb_cmap *cmap)
|
||
|
|
||
|
int fb_copy_cmap(const struct fb_cmap *from, struct fb_cmap *to)
|
||
|
{
|
||
|
- int tooff = 0, fromoff = 0;
|
||
|
- int size;
|
||
|
+ unsigned int tooff = 0, fromoff = 0;
|
||
|
+ size_t size;
|
||
|
|
||
|
if (to->start > from->start)
|
||
|
fromoff = to->start - from->start;
|
||
|
else
|
||
|
tooff = from->start - to->start;
|
||
|
- size = to->len - tooff;
|
||
|
- if (size > (int) (from->len - fromoff))
|
||
|
- size = from->len - fromoff;
|
||
|
- if (size <= 0)
|
||
|
+ if (fromoff >= from->len || tooff >= to->len)
|
||
|
+ return -EINVAL;
|
||
|
+
|
||
|
+ size = min_t(size_t, to->len - tooff, from->len - fromoff);
|
||
|
+ if (size == 0)
|
||
|
return -EINVAL;
|
||
|
size *= sizeof(u16);
|
||
|
|
||
|
@@ -187,17 +188,18 @@ int fb_copy_cmap(const struct fb_cmap *from, struct fb_cmap *to)
|
||
|
|
||
|
int fb_cmap_to_user(const struct fb_cmap *from, struct fb_cmap_user *to)
|
||
|
{
|
||
|
- int tooff = 0, fromoff = 0;
|
||
|
- int size;
|
||
|
+ unsigned int tooff = 0, fromoff = 0;
|
||
|
+ size_t size;
|
||
|
|
||
|
if (to->start > from->start)
|
||
|
fromoff = to->start - from->start;
|
||
|
else
|
||
|
tooff = from->start - to->start;
|
||
|
- size = to->len - tooff;
|
||
|
- if (size > (int) (from->len - fromoff))
|
||
|
- size = from->len - fromoff;
|
||
|
- if (size <= 0)
|
||
|
+ if (fromoff >= from->len || tooff >= to->len)
|
||
|
+ return -EINVAL;
|
||
|
+
|
||
|
+ size = min_t(size_t, to->len - tooff, from->len - fromoff);
|
||
|
+ if (size == 0)
|
||
|
return -EINVAL;
|
||
|
size *= sizeof(u16);
|
||
|
|
||
|
diff --git a/fs/9p/acl.c b/fs/9p/acl.c
|
||
|
index 7af425f53bee..9686c1f17653 100644
|
||
|
--- a/fs/9p/acl.c
|
||
|
+++ b/fs/9p/acl.c
|
||
|
@@ -320,32 +320,26 @@ static int v9fs_xattr_set_acl(struct dentry *dentry, const char *name,
|
||
|
case ACL_TYPE_ACCESS:
|
||
|
name = POSIX_ACL_XATTR_ACCESS;
|
||
|
if (acl) {
|
||
|
- umode_t mode = inode->i_mode;
|
||
|
- retval = posix_acl_equiv_mode(acl, &mode);
|
||
|
- if (retval < 0)
|
||
|
+ struct iattr iattr;
|
||
|
+
|
||
|
+ retval = posix_acl_update_mode(inode, &iattr.ia_mode, &acl);
|
||
|
+ if (retval)
|
||
|
goto err_out;
|
||
|
- else {
|
||
|
- struct iattr iattr;
|
||
|
- if (retval == 0) {
|
||
|
- /*
|
||
|
- * ACL can be represented
|
||
|
- * by the mode bits. So don't
|
||
|
- * update ACL.
|
||
|
- */
|
||
|
- acl = NULL;
|
||
|
- value = NULL;
|
||
|
- size = 0;
|
||
|
- }
|
||
|
- /* Updte the mode bits */
|
||
|
- iattr.ia_mode = ((mode & S_IALLUGO) |
|
||
|
- (inode->i_mode & ~S_IALLUGO));
|
||
|
- iattr.ia_valid = ATTR_MODE;
|
||
|
- /* FIXME should we update ctime ?
|
||
|
- * What is the following setxattr update the
|
||
|
- * mode ?
|
||
|
+ if (!acl) {
|
||
|
+ /*
|
||
|
+ * ACL can be represented
|
||
|
+ * by the mode bits. So don't
|
||
|
+ * update ACL.
|
||
|
*/
|
||
|
- v9fs_vfs_setattr_dotl(dentry, &iattr);
|
||
|
+ value = NULL;
|
||
|
+ size = 0;
|
||
|
}
|
||
|
+ iattr.ia_valid = ATTR_MODE;
|
||
|
+ /* FIXME should we update ctime ?
|
||
|
+ * What is the following setxattr update the
|
||
|
+ * mode ?
|
||
|
+ */
|
||
|
+ v9fs_vfs_setattr_dotl(dentry, &iattr);
|
||
|
}
|
||
|
break;
|
||
|
case ACL_TYPE_DEFAULT:
|
||
|
diff --git a/fs/block_dev.c b/fs/block_dev.c
|
||
|
index 85f5c85ec91c..8f0267e81e8d 100644
|
||
|
--- a/fs/block_dev.c
|
||
|
+++ b/fs/block_dev.c
|
||
|
@@ -655,7 +655,7 @@ static bool bd_may_claim(struct block_device *bdev, struct block_device *whole,
|
||
|
return true; /* already a holder */
|
||
|
else if (bdev->bd_holder != NULL)
|
||
|
return false; /* held by someone else */
|
||
|
- else if (bdev->bd_contains == bdev)
|
||
|
+ else if (whole == bdev)
|
||
|
return true; /* is a whole device which isn't held */
|
||
|
|
||
|
else if (whole->bd_holder == bd_may_claim)
|
||
|
@@ -1692,6 +1692,7 @@ void iterate_bdevs(void (*func)(struct block_device *, void *), void *arg)
|
||
|
spin_lock(&inode_sb_list_lock);
|
||
|
list_for_each_entry(inode, &blockdev_superblock->s_inodes, i_sb_list) {
|
||
|
struct address_space *mapping = inode->i_mapping;
|
||
|
+ struct block_device *bdev;
|
||
|
|
||
|
spin_lock(&inode->i_lock);
|
||
|
if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW) ||
|
||
|
@@ -1712,8 +1713,12 @@ void iterate_bdevs(void (*func)(struct block_device *, void *), void *arg)
|
||
|
*/
|
||
|
iput(old_inode);
|
||
|
old_inode = inode;
|
||
|
+ bdev = I_BDEV(inode);
|
||
|
|
||
|
- func(I_BDEV(inode), arg);
|
||
|
+ mutex_lock(&bdev->bd_mutex);
|
||
|
+ if (bdev->bd_openers)
|
||
|
+ func(bdev, arg);
|
||
|
+ mutex_unlock(&bdev->bd_mutex);
|
||
|
|
||
|
spin_lock(&inode_sb_list_lock);
|
||
|
}
|
||
|
diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c
|
||
|
index 0890c83643e9..d6d53e5e7945 100644
|
||
|
--- a/fs/btrfs/acl.c
|
||
|
+++ b/fs/btrfs/acl.c
|
||
|
@@ -118,11 +118,9 @@ static int btrfs_set_acl(struct btrfs_trans_handle *trans,
|
||
|
case ACL_TYPE_ACCESS:
|
||
|
name = POSIX_ACL_XATTR_ACCESS;
|
||
|
if (acl) {
|
||
|
- ret = posix_acl_equiv_mode(acl, &inode->i_mode);
|
||
|
- if (ret < 0)
|
||
|
+ ret = posix_acl_update_mode(inode, &inode->i_mode, &acl);
|
||
|
+ if (ret)
|
||
|
return ret;
|
||
|
- if (ret == 0)
|
||
|
- acl = NULL;
|
||
|
}
|
||
|
ret = 0;
|
||
|
break;
|
||
|
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
|
||
|
index 7d3331cbccba..681782d00b1f 100644
|
||
|
--- a/fs/btrfs/tree-log.c
|
||
|
+++ b/fs/btrfs/tree-log.c
|
||
|
@@ -1691,12 +1691,11 @@ static noinline int find_dir_range(struct btrfs_root *root,
|
||
|
next:
|
||
|
/* check the next slot in the tree to see if it is a valid item */
|
||
|
nritems = btrfs_header_nritems(path->nodes[0]);
|
||
|
+ path->slots[0]++;
|
||
|
if (path->slots[0] >= nritems) {
|
||
|
ret = btrfs_next_leaf(root, path);
|
||
|
if (ret)
|
||
|
goto out;
|
||
|
- } else {
|
||
|
- path->slots[0]++;
|
||
|
}
|
||
|
|
||
|
btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
|
||
|
diff --git a/fs/exec.c b/fs/exec.c
|
||
|
index acbd7ac2deda..c945a555eb25 100644
|
||
|
--- a/fs/exec.c
|
||
|
+++ b/fs/exec.c
|
||
|
@@ -19,7 +19,7 @@
|
||
|
* current->executable is only used by the procfs. This allows a dispatch
|
||
|
* table to check for several different types of binary formats. We keep
|
||
|
* trying until we recognize the file or we run out of supported binary
|
||
|
- * formats.
|
||
|
+ * formats.
|
||
|
*/
|
||
|
|
||
|
#include <linux/slab.h>
|
||
|
@@ -1091,6 +1091,13 @@ int flush_old_exec(struct linux_binprm * bprm)
|
||
|
flush_thread();
|
||
|
current->personality &= ~bprm->per_clear;
|
||
|
|
||
|
+ /*
|
||
|
+ * We have to apply CLOEXEC before we change whether the process is
|
||
|
+ * dumpable (in setup_new_exec) to avoid a race with a process in userspace
|
||
|
+ * trying to access the should-be-closed file descriptors of a process
|
||
|
+ * undergoing exec(2).
|
||
|
+ */
|
||
|
+ do_close_on_exec(current->files);
|
||
|
return 0;
|
||
|
|
||
|
out:
|
||
|
@@ -1141,7 +1148,6 @@ void setup_new_exec(struct linux_binprm * bprm)
|
||
|
current->self_exec_id++;
|
||
|
|
||
|
flush_signal_handlers(current, 0);
|
||
|
- do_close_on_exec(current->files);
|
||
|
}
|
||
|
EXPORT_SYMBOL(setup_new_exec);
|
||
|
|
||
|
diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c
|
||
|
index 110b6b371a4e..48c3c2d7d261 100644
|
||
|
--- a/fs/ext2/acl.c
|
||
|
+++ b/fs/ext2/acl.c
|
||
|
@@ -206,15 +206,11 @@ ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
|
||
|
case ACL_TYPE_ACCESS:
|
||
|
name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS;
|
||
|
if (acl) {
|
||
|
- error = posix_acl_equiv_mode(acl, &inode->i_mode);
|
||
|
- if (error < 0)
|
||
|
+ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
|
||
|
+ if (error)
|
||
|
return error;
|
||
|
- else {
|
||
|
- inode->i_ctime = CURRENT_TIME_SEC;
|
||
|
- mark_inode_dirty(inode);
|
||
|
- if (error == 0)
|
||
|
- acl = NULL;
|
||
|
- }
|
||
|
+ inode->i_ctime = CURRENT_TIME_SEC;
|
||
|
+ mark_inode_dirty(inode);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c
|
||
|
index dbb5ad59a7fc..2f994bbf73a7 100644
|
||
|
--- a/fs/ext3/acl.c
|
||
|
+++ b/fs/ext3/acl.c
|
||
|
@@ -205,15 +205,11 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type,
|
||
|
case ACL_TYPE_ACCESS:
|
||
|
name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS;
|
||
|
if (acl) {
|
||
|
- error = posix_acl_equiv_mode(acl, &inode->i_mode);
|
||
|
+ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
|
||
|
if (error < 0)
|
||
|
return error;
|
||
|
- else {
|
||
|
- inode->i_ctime = CURRENT_TIME_SEC;
|
||
|
- ext3_mark_inode_dirty(handle, inode);
|
||
|
- if (error == 0)
|
||
|
- acl = NULL;
|
||
|
- }
|
||
|
+ inode->i_ctime = CURRENT_TIME_SEC;
|
||
|
+ ext3_mark_inode_dirty(handle, inode);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c
|
||
|
index 39a54a0e9fe4..c844f1bfb451 100644
|
||
|
--- a/fs/ext4/acl.c
|
||
|
+++ b/fs/ext4/acl.c
|
||
|
@@ -211,15 +211,11 @@ ext4_set_acl(handle_t *handle, struct inode *inode, int type,
|
||
|
case ACL_TYPE_ACCESS:
|
||
|
name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS;
|
||
|
if (acl) {
|
||
|
- error = posix_acl_equiv_mode(acl, &inode->i_mode);
|
||
|
- if (error < 0)
|
||
|
+ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
|
||
|
+ if (error)
|
||
|
return error;
|
||
|
- else {
|
||
|
- inode->i_ctime = ext4_current_time(inode);
|
||
|
- ext4_mark_inode_dirty(handle, inode);
|
||
|
- if (error == 0)
|
||
|
- acl = NULL;
|
||
|
- }
|
||
|
+ inode->i_ctime = ext4_current_time(inode);
|
||
|
+ ext4_mark_inode_dirty(handle, inode);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
|
||
|
index e350be6c7ac6..55af0d98d968 100644
|
||
|
--- a/fs/ext4/inline.c
|
||
|
+++ b/fs/ext4/inline.c
|
||
|
@@ -339,8 +339,10 @@ static int ext4_update_inline_data(handle_t *handle, struct inode *inode,
|
||
|
|
||
|
len -= EXT4_MIN_INLINE_DATA_SIZE;
|
||
|
value = kzalloc(len, GFP_NOFS);
|
||
|
- if (!value)
|
||
|
+ if (!value) {
|
||
|
+ error = -ENOMEM;
|
||
|
goto out;
|
||
|
+ }
|
||
|
|
||
|
error = ext4_xattr_ibody_get(inode, i.name_index, i.name,
|
||
|
value, len);
|
||
|
@@ -1145,10 +1147,9 @@ static int ext4_finish_convert_inline_dir(handle_t *handle,
|
||
|
set_buffer_uptodate(dir_block);
|
||
|
err = ext4_handle_dirty_dirent_node(handle, inode, dir_block);
|
||
|
if (err)
|
||
|
- goto out;
|
||
|
+ return err;
|
||
|
set_buffer_verified(dir_block);
|
||
|
-out:
|
||
|
- return err;
|
||
|
+ return ext4_mark_inode_dirty(handle, inode);
|
||
|
}
|
||
|
|
||
|
static int ext4_convert_inline_data_nolock(handle_t *handle,
|
||
|
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
|
||
|
index 31179ba2072c..5fb975495c2d 100644
|
||
|
--- a/fs/ext4/inode.c
|
||
|
+++ b/fs/ext4/inode.c
|
||
|
@@ -759,6 +759,20 @@ has_zeroout:
|
||
|
int ret = check_block_validity(inode, map);
|
||
|
if (ret != 0)
|
||
|
return ret;
|
||
|
+
|
||
|
+ /*
|
||
|
+ * Inodes with freshly allocated blocks where contents will be
|
||
|
+ * visible after transaction commit must be on transaction's
|
||
|
+ * ordered data list.
|
||
|
+ */
|
||
|
+ if (map->m_flags & EXT4_MAP_NEW &&
|
||
|
+ !(map->m_flags & EXT4_MAP_UNWRITTEN) &&
|
||
|
+ !IS_NOQUOTA(inode) &&
|
||
|
+ ext4_should_order_data(inode)) {
|
||
|
+ ret = ext4_jbd2_file_inode(handle, inode);
|
||
|
+ if (ret)
|
||
|
+ return ret;
|
||
|
+ }
|
||
|
}
|
||
|
return retval;
|
||
|
}
|
||
|
@@ -1119,15 +1133,6 @@ static int ext4_write_end(struct file *file,
|
||
|
int i_size_changed = 0;
|
||
|
|
||
|
trace_ext4_write_end(inode, pos, len, copied);
|
||
|
- if (ext4_test_inode_state(inode, EXT4_STATE_ORDERED_MODE)) {
|
||
|
- ret = ext4_jbd2_file_inode(handle, inode);
|
||
|
- if (ret) {
|
||
|
- unlock_page(page);
|
||
|
- page_cache_release(page);
|
||
|
- goto errout;
|
||
|
- }
|
||
|
- }
|
||
|
-
|
||
|
if (ext4_has_inline_data(inode)) {
|
||
|
ret = ext4_write_inline_data_end(inode, pos, len,
|
||
|
copied, page);
|
||
|
@@ -4178,6 +4183,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
|
||
|
struct inode *inode;
|
||
|
journal_t *journal = EXT4_SB(sb)->s_journal;
|
||
|
long ret;
|
||
|
+ loff_t size;
|
||
|
int block;
|
||
|
uid_t i_uid;
|
||
|
gid_t i_gid;
|
||
|
@@ -4270,6 +4276,11 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
|
||
|
ei->i_file_acl |=
|
||
|
((__u64)le16_to_cpu(raw_inode->i_file_acl_high)) << 32;
|
||
|
inode->i_size = ext4_isize(raw_inode);
|
||
|
+ if ((size = i_size_read(inode)) < 0) {
|
||
|
+ EXT4_ERROR_INODE(inode, "bad i_size value: %lld", size);
|
||
|
+ ret = -EIO;
|
||
|
+ goto bad_inode;
|
||
|
+ }
|
||
|
ei->i_disksize = inode->i_size;
|
||
|
#ifdef CONFIG_QUOTA
|
||
|
ei->i_reserved_quota = 0;
|
||
|
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
|
||
|
index cb9eec025ba8..83ed61a6cfcb 100644
|
||
|
--- a/fs/ext4/mballoc.c
|
||
|
+++ b/fs/ext4/mballoc.c
|
||
|
@@ -668,7 +668,7 @@ static void ext4_mb_mark_free_simple(struct super_block *sb,
|
||
|
ext4_grpblk_t min;
|
||
|
ext4_grpblk_t max;
|
||
|
ext4_grpblk_t chunk;
|
||
|
- unsigned short border;
|
||
|
+ unsigned int border;
|
||
|
|
||
|
BUG_ON(len > EXT4_CLUSTERS_PER_GROUP(sb));
|
||
|
|
||
|
@@ -2222,7 +2222,7 @@ static int ext4_mb_seq_groups_show(struct seq_file *seq, void *v)
|
||
|
struct ext4_group_info *grinfo;
|
||
|
struct sg {
|
||
|
struct ext4_group_info info;
|
||
|
- ext4_grpblk_t counters[16];
|
||
|
+ ext4_grpblk_t counters[EXT4_MAX_BLOCK_LOG_SIZE + 2];
|
||
|
} sg;
|
||
|
|
||
|
group--;
|
||
|
diff --git a/fs/f2fs/acl.c b/fs/f2fs/acl.c
|
||
|
index 44abc2f286e0..9c4f3c732bce 100644
|
||
|
--- a/fs/f2fs/acl.c
|
||
|
+++ b/fs/f2fs/acl.c
|
||
|
@@ -223,12 +223,10 @@ static int f2fs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
|
||
|
case ACL_TYPE_ACCESS:
|
||
|
name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS;
|
||
|
if (acl) {
|
||
|
- error = posix_acl_equiv_mode(acl, &inode->i_mode);
|
||
|
- if (error < 0)
|
||
|
+ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
|
||
|
+ if (error)
|
||
|
return error;
|
||
|
set_acl_inode(fi, inode->i_mode);
|
||
|
- if (error == 0)
|
||
|
- acl = NULL;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c
|
||
|
index 8d9943786c31..a73dddedc803 100644
|
||
|
--- a/fs/f2fs/debug.c
|
||
|
+++ b/fs/f2fs/debug.c
|
||
|
@@ -294,6 +294,7 @@ static int stat_open(struct inode *inode, struct file *file)
|
||
|
}
|
||
|
|
||
|
static const struct file_operations stat_fops = {
|
||
|
+ .owner = THIS_MODULE,
|
||
|
.open = stat_open,
|
||
|
.read = seq_read,
|
||
|
.llseek = seq_lseek,
|
||
|
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
|
||
|
index 35f604b5f408..1dce93041012 100644
|
||
|
--- a/fs/fuse/file.c
|
||
|
+++ b/fs/fuse/file.c
|
||
|
@@ -128,6 +128,7 @@ static void fuse_file_put(struct fuse_file *ff, bool sync)
|
||
|
struct fuse_req *req = ff->reserved_req;
|
||
|
|
||
|
if (sync) {
|
||
|
+ req->force = 1;
|
||
|
req->background = 0;
|
||
|
fuse_request_send(ff->fc, req);
|
||
|
path_put(&req->misc.release.path);
|
||
|
@@ -2398,6 +2399,7 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
|
||
|
loff_t i_size;
|
||
|
size_t count = iov_length(iov, nr_segs);
|
||
|
struct fuse_io_priv *io;
|
||
|
+ bool is_sync = is_sync_kiocb(iocb);
|
||
|
|
||
|
pos = offset;
|
||
|
inode = file->f_mapping->host;
|
||
|
@@ -2433,7 +2435,7 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
|
||
|
* to wait on real async I/O requests, so we must submit this request
|
||
|
* synchronously.
|
||
|
*/
|
||
|
- if (!is_sync_kiocb(iocb) && (offset + count > i_size) && rw == WRITE)
|
||
|
+ if (!is_sync && (offset + count > i_size) && rw == WRITE)
|
||
|
io->async = false;
|
||
|
|
||
|
if (rw == WRITE)
|
||
|
@@ -2445,7 +2447,7 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
|
||
|
fuse_aio_complete(io, ret < 0 ? ret : 0, -1);
|
||
|
|
||
|
/* we have a non-extending, async request, so return */
|
||
|
- if (!is_sync_kiocb(iocb))
|
||
|
+ if (!is_sync)
|
||
|
return -EIOCBQUEUED;
|
||
|
|
||
|
ret = wait_on_sync_kiocb(iocb);
|
||
|
diff --git a/fs/generic_acl.c b/fs/generic_acl.c
|
||
|
index b3f3676796d3..7855cfb938f6 100644
|
||
|
--- a/fs/generic_acl.c
|
||
|
+++ b/fs/generic_acl.c
|
||
|
@@ -82,19 +82,21 @@ generic_acl_set(struct dentry *dentry, const char *name, const void *value,
|
||
|
return PTR_ERR(acl);
|
||
|
}
|
||
|
if (acl) {
|
||
|
+ struct posix_acl *old_acl;
|
||
|
+
|
||
|
error = posix_acl_valid(acl);
|
||
|
if (error)
|
||
|
goto failed;
|
||
|
switch (type) {
|
||
|
case ACL_TYPE_ACCESS:
|
||
|
- error = posix_acl_equiv_mode(acl, &inode->i_mode);
|
||
|
+ old_acl = acl;
|
||
|
+ error = posix_acl_update_mode(inode, &inode->i_mode,
|
||
|
+ &acl);
|
||
|
if (error < 0)
|
||
|
goto failed;
|
||
|
+ if (!acl)
|
||
|
+ posix_acl_release(old_acl);
|
||
|
inode->i_ctime = CURRENT_TIME;
|
||
|
- if (error == 0) {
|
||
|
- posix_acl_release(acl);
|
||
|
- acl = NULL;
|
||
|
- }
|
||
|
break;
|
||
|
case ACL_TYPE_DEFAULT:
|
||
|
if (!S_ISDIR(inode->i_mode)) {
|
||
|
diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c
|
||
|
index f69ac0af5496..a61b0c2b57ab 100644
|
||
|
--- a/fs/gfs2/acl.c
|
||
|
+++ b/fs/gfs2/acl.c
|
||
|
@@ -268,15 +268,13 @@ static int gfs2_xattr_system_set(struct dentry *dentry, const char *name,
|
||
|
|
||
|
if (type == ACL_TYPE_ACCESS) {
|
||
|
umode_t mode = inode->i_mode;
|
||
|
- error = posix_acl_equiv_mode(acl, &mode);
|
||
|
+ struct posix_acl *old_acl = acl;
|
||
|
|
||
|
- if (error <= 0) {
|
||
|
- posix_acl_release(acl);
|
||
|
- acl = NULL;
|
||
|
-
|
||
|
- if (error < 0)
|
||
|
- return error;
|
||
|
- }
|
||
|
+ error = posix_acl_update_mode(inode, &mode, &acl);
|
||
|
+ if (error < 0)
|
||
|
+ goto out_release;
|
||
|
+ if (!acl)
|
||
|
+ posix_acl_release(old_acl);
|
||
|
|
||
|
error = gfs2_set_mode(inode, mode);
|
||
|
if (error)
|
||
|
diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c
|
||
|
index 223283c30111..9335b8d3cf52 100644
|
||
|
--- a/fs/jffs2/acl.c
|
||
|
+++ b/fs/jffs2/acl.c
|
||
|
@@ -243,9 +243,10 @@ static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
|
||
|
case ACL_TYPE_ACCESS:
|
||
|
xprefix = JFFS2_XPREFIX_ACL_ACCESS;
|
||
|
if (acl) {
|
||
|
- umode_t mode = inode->i_mode;
|
||
|
- rc = posix_acl_equiv_mode(acl, &mode);
|
||
|
- if (rc < 0)
|
||
|
+ umode_t mode;
|
||
|
+
|
||
|
+ rc = posix_acl_update_mode(inode, &mode, &acl);
|
||
|
+ if (rc)
|
||
|
return rc;
|
||
|
if (inode->i_mode != mode) {
|
||
|
struct iattr attr;
|
||
|
@@ -257,8 +258,6 @@ static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
|
||
|
if (rc < 0)
|
||
|
return rc;
|
||
|
}
|
||
|
- if (rc == 0)
|
||
|
- acl = NULL;
|
||
|
}
|
||
|
break;
|
||
|
case ACL_TYPE_DEFAULT:
|
||
|
diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c
|
||
|
index 42d67f9757bf..29a28601cb93 100644
|
||
|
--- a/fs/jfs/xattr.c
|
||
|
+++ b/fs/jfs/xattr.c
|
||
|
@@ -693,8 +693,9 @@ static int can_set_system_xattr(struct inode *inode, const char *name,
|
||
|
return rc;
|
||
|
}
|
||
|
if (acl) {
|
||
|
- rc = posix_acl_equiv_mode(acl, &inode->i_mode);
|
||
|
- posix_acl_release(acl);
|
||
|
+ struct posix_acl *old_acl = acl;
|
||
|
+ rc = posix_acl_update_mode(inode, &inode->i_mode, &acl);
|
||
|
+ posix_acl_release(old_acl);
|
||
|
if (rc < 0) {
|
||
|
printk(KERN_ERR
|
||
|
"posix_acl_equiv_mode returned %d\n",
|
||
|
diff --git a/fs/nfs/nfs4filelayoutdev.c b/fs/nfs/nfs4filelayoutdev.c
|
||
|
index 678cb8964532..b906d8e55d83 100644
|
||
|
--- a/fs/nfs/nfs4filelayoutdev.c
|
||
|
+++ b/fs/nfs/nfs4filelayoutdev.c
|
||
|
@@ -821,7 +821,8 @@ nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx)
|
||
|
nfs4_wait_ds_connect(ds);
|
||
|
}
|
||
|
out_test_devid:
|
||
|
- if (filelayout_test_devid_unavailable(devid))
|
||
|
+ if (ret->ds_clp == NULL ||
|
||
|
+ filelayout_test_devid_unavailable(devid))
|
||
|
ret = NULL;
|
||
|
out:
|
||
|
return ret;
|
||
|
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
|
||
|
index 988efb4caac0..f5d27ca10146 100644
|
||
|
--- a/fs/nfs/nfs4xdr.c
|
||
|
+++ b/fs/nfs/nfs4xdr.c
|
||
|
@@ -2435,7 +2435,7 @@ static void nfs4_xdr_enc_getacl(struct rpc_rqst *req, struct xdr_stream *xdr,
|
||
|
encode_compound_hdr(xdr, req, &hdr);
|
||
|
encode_sequence(xdr, &args->seq_args, &hdr);
|
||
|
encode_putfh(xdr, args->fh, &hdr);
|
||
|
- replen = hdr.replen + op_decode_hdr_maxsz + 1;
|
||
|
+ replen = hdr.replen + op_decode_hdr_maxsz;
|
||
|
encode_getattr_two(xdr, FATTR4_WORD0_ACL, 0, &hdr);
|
||
|
|
||
|
xdr_inline_pages(&req->rq_rcv_buf, replen << 2,
|
||
|
diff --git a/fs/ocfs2/acl.c b/fs/ocfs2/acl.c
|
||
|
index 8a404576fb26..51ff9506cb0f 100644
|
||
|
--- a/fs/ocfs2/acl.c
|
||
|
+++ b/fs/ocfs2/acl.c
|
||
|
@@ -274,20 +274,14 @@ static int ocfs2_set_acl(handle_t *handle,
|
||
|
case ACL_TYPE_ACCESS:
|
||
|
name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS;
|
||
|
if (acl) {
|
||
|
- umode_t mode = inode->i_mode;
|
||
|
- ret = posix_acl_equiv_mode(acl, &mode);
|
||
|
- if (ret < 0)
|
||
|
+ umode_t mode;
|
||
|
+ ret = posix_acl_update_mode(inode, &mode, &acl);
|
||
|
+ if (ret)
|
||
|
+ return ret;
|
||
|
+ ret = ocfs2_acl_set_mode(inode, di_bh,
|
||
|
+ handle, mode);
|
||
|
+ if (ret)
|
||
|
return ret;
|
||
|
- else {
|
||
|
- if (ret == 0)
|
||
|
- acl = NULL;
|
||
|
-
|
||
|
- ret = ocfs2_acl_set_mode(inode, di_bh,
|
||
|
- handle, mode);
|
||
|
- if (ret)
|
||
|
- return ret;
|
||
|
-
|
||
|
- }
|
||
|
}
|
||
|
break;
|
||
|
case ACL_TYPE_DEFAULT:
|
||
|
diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c
|
||
|
index 0c60ef2d8056..b9d16098ede3 100644
|
||
|
--- a/fs/ocfs2/ioctl.c
|
||
|
+++ b/fs/ocfs2/ioctl.c
|
||
|
@@ -34,9 +34,8 @@
|
||
|
copy_to_user((typeof(a) __user *)b, &(a), sizeof(a))
|
||
|
|
||
|
/*
|
||
|
- * This call is void because we are already reporting an error that may
|
||
|
- * be -EFAULT. The error will be returned from the ioctl(2) call. It's
|
||
|
- * just a best-effort to tell userspace that this request caused the error.
|
||
|
+ * This is just a best-effort to tell userspace that this request
|
||
|
+ * caused the error.
|
||
|
*/
|
||
|
static inline void o2info_set_request_error(struct ocfs2_info_request *kreq,
|
||
|
struct ocfs2_info_request __user *req)
|
||
|
@@ -145,136 +144,105 @@ bail:
|
||
|
int ocfs2_info_handle_blocksize(struct inode *inode,
|
||
|
struct ocfs2_info_request __user *req)
|
||
|
{
|
||
|
- int status = -EFAULT;
|
||
|
struct ocfs2_info_blocksize oib;
|
||
|
|
||
|
if (o2info_from_user(oib, req))
|
||
|
- goto bail;
|
||
|
+ return -EFAULT;
|
||
|
|
||
|
oib.ib_blocksize = inode->i_sb->s_blocksize;
|
||
|
|
||
|
o2info_set_request_filled(&oib.ib_req);
|
||
|
|
||
|
if (o2info_to_user(oib, req))
|
||
|
- goto bail;
|
||
|
-
|
||
|
- status = 0;
|
||
|
-bail:
|
||
|
- if (status)
|
||
|
- o2info_set_request_error(&oib.ib_req, req);
|
||
|
+ return -EFAULT;
|
||
|
|
||
|
- return status;
|
||
|
+ return 0;
|
||
|
}
|
||
|
|
||
|
int ocfs2_info_handle_clustersize(struct inode *inode,
|
||
|
struct ocfs2_info_request __user *req)
|
||
|
{
|
||
|
- int status = -EFAULT;
|
||
|
struct ocfs2_info_clustersize oic;
|
||
|
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
|
||
|
|
||
|
if (o2info_from_user(oic, req))
|
||
|
- goto bail;
|
||
|
+ return -EFAULT;
|
||
|
|
||
|
oic.ic_clustersize = osb->s_clustersize;
|
||
|
|
||
|
o2info_set_request_filled(&oic.ic_req);
|
||
|
|
||
|
if (o2info_to_user(oic, req))
|
||
|
- goto bail;
|
||
|
-
|
||
|
- status = 0;
|
||
|
-bail:
|
||
|
- if (status)
|
||
|
- o2info_set_request_error(&oic.ic_req, req);
|
||
|
+ return -EFAULT;
|
||
|
|
||
|
- return status;
|
||
|
+ return 0;
|
||
|
}
|
||
|
|
||
|
int ocfs2_info_handle_maxslots(struct inode *inode,
|
||
|
struct ocfs2_info_request __user *req)
|
||
|
{
|
||
|
- int status = -EFAULT;
|
||
|
struct ocfs2_info_maxslots oim;
|
||
|
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
|
||
|
|
||
|
if (o2info_from_user(oim, req))
|
||
|
- goto bail;
|
||
|
+ return -EFAULT;
|
||
|
|
||
|
oim.im_max_slots = osb->max_slots;
|
||
|
|
||
|
o2info_set_request_filled(&oim.im_req);
|
||
|
|
||
|
if (o2info_to_user(oim, req))
|
||
|
- goto bail;
|
||
|
+ return -EFAULT;
|
||
|
|
||
|
- status = 0;
|
||
|
-bail:
|
||
|
- if (status)
|
||
|
- o2info_set_request_error(&oim.im_req, req);
|
||
|
-
|
||
|
- return status;
|
||
|
+ return 0;
|
||
|
}
|
||
|
|
||
|
int ocfs2_info_handle_label(struct inode *inode,
|
||
|
struct ocfs2_info_request __user *req)
|
||
|
{
|
||
|
- int status = -EFAULT;
|
||
|
struct ocfs2_info_label oil;
|
||
|
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
|
||
|
|
||
|
if (o2info_from_user(oil, req))
|
||
|
- goto bail;
|
||
|
+ return -EFAULT;
|
||
|
|
||
|
memcpy(oil.il_label, osb->vol_label, OCFS2_MAX_VOL_LABEL_LEN);
|
||
|
|
||
|
o2info_set_request_filled(&oil.il_req);
|
||
|
|
||
|
if (o2info_to_user(oil, req))
|
||
|
- goto bail;
|
||
|
+ return -EFAULT;
|
||
|
|
||
|
- status = 0;
|
||
|
-bail:
|
||
|
- if (status)
|
||
|
- o2info_set_request_error(&oil.il_req, req);
|
||
|
-
|
||
|
- return status;
|
||
|
+ return 0;
|
||
|
}
|
||
|
|
||
|
int ocfs2_info_handle_uuid(struct inode *inode,
|
||
|
struct ocfs2_info_request __user *req)
|
||
|
{
|
||
|
- int status = -EFAULT;
|
||
|
struct ocfs2_info_uuid oiu;
|
||
|
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
|
||
|
|
||
|
if (o2info_from_user(oiu, req))
|
||
|
- goto bail;
|
||
|
+ return -EFAULT;
|
||
|
|
||
|
memcpy(oiu.iu_uuid_str, osb->uuid_str, OCFS2_TEXT_UUID_LEN + 1);
|
||
|
|
||
|
o2info_set_request_filled(&oiu.iu_req);
|
||
|
|
||
|
if (o2info_to_user(oiu, req))
|
||
|
- goto bail;
|
||
|
-
|
||
|
- status = 0;
|
||
|
-bail:
|
||
|
- if (status)
|
||
|
- o2info_set_request_error(&oiu.iu_req, req);
|
||
|
+ return -EFAULT;
|
||
|
|
||
|
- return status;
|
||
|
+ return 0;
|
||
|
}
|
||
|
|
||
|
int ocfs2_info_handle_fs_features(struct inode *inode,
|
||
|
struct ocfs2_info_request __user *req)
|
||
|
{
|
||
|
- int status = -EFAULT;
|
||
|
struct ocfs2_info_fs_features oif;
|
||
|
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
|
||
|
|
||
|
if (o2info_from_user(oif, req))
|
||
|
- goto bail;
|
||
|
+ return -EFAULT;
|
||
|
|
||
|
oif.if_compat_features = osb->s_feature_compat;
|
||
|
oif.if_incompat_features = osb->s_feature_incompat;
|
||
|
@@ -283,39 +251,28 @@ int ocfs2_info_handle_fs_features(struct inode *inode,
|
||
|
o2info_set_request_filled(&oif.if_req);
|
||
|
|
||
|
if (o2info_to_user(oif, req))
|
||
|
- goto bail;
|
||
|
+ return -EFAULT;
|
||
|
|
||
|
- status = 0;
|
||
|
-bail:
|
||
|
- if (status)
|
||
|
- o2info_set_request_error(&oif.if_req, req);
|
||
|
-
|
||
|
- return status;
|
||
|
+ return 0;
|
||
|
}
|
||
|
|
||
|
int ocfs2_info_handle_journal_size(struct inode *inode,
|
||
|
struct ocfs2_info_request __user *req)
|
||
|
{
|
||
|
- int status = -EFAULT;
|
||
|
struct ocfs2_info_journal_size oij;
|
||
|
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
|
||
|
|
||
|
if (o2info_from_user(oij, req))
|
||
|
- goto bail;
|
||
|
+ return -EFAULT;
|
||
|
|
||
|
oij.ij_journal_size = osb->journal->j_inode->i_size;
|
||
|
|
||
|
o2info_set_request_filled(&oij.ij_req);
|
||
|
|
||
|
if (o2info_to_user(oij, req))
|
||
|
- goto bail;
|
||
|
+ return -EFAULT;
|
||
|
|
||
|
- status = 0;
|
||
|
-bail:
|
||
|
- if (status)
|
||
|
- o2info_set_request_error(&oij.ij_req, req);
|
||
|
-
|
||
|
- return status;
|
||
|
+ return 0;
|
||
|
}
|
||
|
|
||
|
int ocfs2_info_scan_inode_alloc(struct ocfs2_super *osb,
|
||
|
@@ -371,7 +328,7 @@ int ocfs2_info_handle_freeinode(struct inode *inode,
|
||
|
u32 i;
|
||
|
u64 blkno = -1;
|
||
|
char namebuf[40];
|
||
|
- int status = -EFAULT, type = INODE_ALLOC_SYSTEM_INODE;
|
||
|
+ int status, type = INODE_ALLOC_SYSTEM_INODE;
|
||
|
struct ocfs2_info_freeinode *oifi = NULL;
|
||
|
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
|
||
|
struct inode *inode_alloc = NULL;
|
||
|
@@ -383,8 +340,10 @@ int ocfs2_info_handle_freeinode(struct inode *inode,
|
||
|
goto out_err;
|
||
|
}
|
||
|
|
||
|
- if (o2info_from_user(*oifi, req))
|
||
|
- goto bail;
|
||
|
+ if (o2info_from_user(*oifi, req)) {
|
||
|
+ status = -EFAULT;
|
||
|
+ goto out_free;
|
||
|
+ }
|
||
|
|
||
|
oifi->ifi_slotnum = osb->max_slots;
|
||
|
|
||
|
@@ -421,14 +380,16 @@ int ocfs2_info_handle_freeinode(struct inode *inode,
|
||
|
|
||
|
o2info_set_request_filled(&oifi->ifi_req);
|
||
|
|
||
|
- if (o2info_to_user(*oifi, req))
|
||
|
- goto bail;
|
||
|
+ if (o2info_to_user(*oifi, req)) {
|
||
|
+ status = -EFAULT;
|
||
|
+ goto out_free;
|
||
|
+ }
|
||
|
|
||
|
status = 0;
|
||
|
bail:
|
||
|
if (status)
|
||
|
o2info_set_request_error(&oifi->ifi_req, req);
|
||
|
-
|
||
|
+out_free:
|
||
|
kfree(oifi);
|
||
|
out_err:
|
||
|
return status;
|
||
|
@@ -655,7 +616,7 @@ int ocfs2_info_handle_freefrag(struct inode *inode,
|
||
|
{
|
||
|
u64 blkno = -1;
|
||
|
char namebuf[40];
|
||
|
- int status = -EFAULT, type = GLOBAL_BITMAP_SYSTEM_INODE;
|
||
|
+ int status, type = GLOBAL_BITMAP_SYSTEM_INODE;
|
||
|
|
||
|
struct ocfs2_info_freefrag *oiff;
|
||
|
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
|
||
|
@@ -668,8 +629,10 @@ int ocfs2_info_handle_freefrag(struct inode *inode,
|
||
|
goto out_err;
|
||
|
}
|
||
|
|
||
|
- if (o2info_from_user(*oiff, req))
|
||
|
- goto bail;
|
||
|
+ if (o2info_from_user(*oiff, req)) {
|
||
|
+ status = -EFAULT;
|
||
|
+ goto out_free;
|
||
|
+ }
|
||
|
/*
|
||
|
* chunksize from userspace should be power of 2.
|
||
|
*/
|
||
|
@@ -708,14 +671,14 @@ int ocfs2_info_handle_freefrag(struct inode *inode,
|
||
|
|
||
|
if (o2info_to_user(*oiff, req)) {
|
||
|
status = -EFAULT;
|
||
|
- goto bail;
|
||
|
+ goto out_free;
|
||
|
}
|
||
|
|
||
|
status = 0;
|
||
|
bail:
|
||
|
if (status)
|
||
|
o2info_set_request_error(&oiff->iff_req, req);
|
||
|
-
|
||
|
+out_free:
|
||
|
kfree(oiff);
|
||
|
out_err:
|
||
|
return status;
|
||
|
@@ -724,23 +687,17 @@ out_err:
|
||
|
int ocfs2_info_handle_unknown(struct inode *inode,
|
||
|
struct ocfs2_info_request __user *req)
|
||
|
{
|
||
|
- int status = -EFAULT;
|
||
|
struct ocfs2_info_request oir;
|
||
|
|
||
|
if (o2info_from_user(oir, req))
|
||
|
- goto bail;
|
||
|
+ return -EFAULT;
|
||
|
|
||
|
o2info_clear_request_filled(&oir);
|
||
|
|
||
|
if (o2info_to_user(oir, req))
|
||
|
- goto bail;
|
||
|
+ return -EFAULT;
|
||
|
|
||
|
- status = 0;
|
||
|
-bail:
|
||
|
- if (status)
|
||
|
- o2info_set_request_error(&oir, req);
|
||
|
-
|
||
|
- return status;
|
||
|
+ return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
diff --git a/fs/posix_acl.c b/fs/posix_acl.c
|
||
|
index 3542f1f814e2..1da000aabb08 100644
|
||
|
--- a/fs/posix_acl.c
|
||
|
+++ b/fs/posix_acl.c
|
||
|
@@ -407,6 +407,37 @@ posix_acl_create(struct posix_acl **acl, gfp_t gfp, umode_t *mode_p)
|
||
|
}
|
||
|
EXPORT_SYMBOL(posix_acl_create);
|
||
|
|
||
|
+/**
|
||
|
+ * posix_acl_update_mode - update mode in set_acl
|
||
|
+ *
|
||
|
+ * Update the file mode when setting an ACL: compute the new file permission
|
||
|
+ * bits based on the ACL. In addition, if the ACL is equivalent to the new
|
||
|
+ * file mode, set *acl to NULL to indicate that no ACL should be set.
|
||
|
+ *
|
||
|
+ * As with chmod, clear the setgit bit if the caller is not in the owning group
|
||
|
+ * or capable of CAP_FSETID (see inode_change_ok).
|
||
|
+ *
|
||
|
+ * Called from set_acl inode operations.
|
||
|
+ */
|
||
|
+int posix_acl_update_mode(struct inode *inode, umode_t *mode_p,
|
||
|
+ struct posix_acl **acl)
|
||
|
+{
|
||
|
+ umode_t mode = inode->i_mode;
|
||
|
+ int error;
|
||
|
+
|
||
|
+ error = posix_acl_equiv_mode(*acl, &mode);
|
||
|
+ if (error < 0)
|
||
|
+ return error;
|
||
|
+ if (error == 0)
|
||
|
+ *acl = NULL;
|
||
|
+ if (!in_group_p(inode->i_gid) &&
|
||
|
+ !capable_wrt_inode_uidgid(inode, CAP_FSETID))
|
||
|
+ mode &= ~S_ISGID;
|
||
|
+ *mode_p = mode;
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+EXPORT_SYMBOL(posix_acl_update_mode);
|
||
|
+
|
||
|
int
|
||
|
posix_acl_chmod(struct posix_acl **acl, gfp_t gfp, umode_t mode)
|
||
|
{
|
||
|
diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c
|
||
|
index 6c8767fdfc6a..2d73589f37d6 100644
|
||
|
--- a/fs/reiserfs/xattr_acl.c
|
||
|
+++ b/fs/reiserfs/xattr_acl.c
|
||
|
@@ -286,13 +286,9 @@ reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
|
||
|
case ACL_TYPE_ACCESS:
|
||
|
name = POSIX_ACL_XATTR_ACCESS;
|
||
|
if (acl) {
|
||
|
- error = posix_acl_equiv_mode(acl, &inode->i_mode);
|
||
|
- if (error < 0)
|
||
|
+ error = posix_acl_update_mode(inode, &inode->i_mode, &acl);
|
||
|
+ if (error)
|
||
|
return error;
|
||
|
- else {
|
||
|
- if (error == 0)
|
||
|
- acl = NULL;
|
||
|
- }
|
||
|
}
|
||
|
break;
|
||
|
case ACL_TYPE_DEFAULT:
|
||
|
diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c
|
||
|
index 349f31a30f40..fdf2ca1dd771 100644
|
||
|
--- a/fs/ubifs/tnc.c
|
||
|
+++ b/fs/ubifs/tnc.c
|
||
|
@@ -34,6 +34,11 @@
|
||
|
#include <linux/slab.h>
|
||
|
#include "ubifs.h"
|
||
|
|
||
|
+static int try_read_node(const struct ubifs_info *c, void *buf, int type,
|
||
|
+ int len, int lnum, int offs);
|
||
|
+static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key,
|
||
|
+ struct ubifs_zbranch *zbr, void *node);
|
||
|
+
|
||
|
/*
|
||
|
* Returned codes of 'matches_name()' and 'fallible_matches_name()' functions.
|
||
|
* @NAME_LESS: name corresponding to the first argument is less than second
|
||
|
@@ -419,7 +424,19 @@ static int tnc_read_node_nm(struct ubifs_info *c, struct ubifs_zbranch *zbr,
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
- err = ubifs_tnc_read_node(c, zbr, node);
|
||
|
+ if (c->replaying) {
|
||
|
+ err = fallible_read_node(c, &zbr->key, zbr, node);
|
||
|
+ /*
|
||
|
+ * When the node was not found, return -ENOENT, 0 otherwise.
|
||
|
+ * Negative return codes stay as-is.
|
||
|
+ */
|
||
|
+ if (err == 0)
|
||
|
+ err = -ENOENT;
|
||
|
+ else if (err == 1)
|
||
|
+ err = 0;
|
||
|
+ } else {
|
||
|
+ err = ubifs_tnc_read_node(c, zbr, node);
|
||
|
+ }
|
||
|
if (err)
|
||
|
return err;
|
||
|
|
||
|
@@ -2783,7 +2800,11 @@ struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
|
||
|
if (nm->name) {
|
||
|
if (err) {
|
||
|
/* Handle collisions */
|
||
|
- err = resolve_collision(c, key, &znode, &n, nm);
|
||
|
+ if (c->replaying)
|
||
|
+ err = fallible_resolve_collision(c, key, &znode, &n,
|
||
|
+ nm, 0);
|
||
|
+ else
|
||
|
+ err = resolve_collision(c, key, &znode, &n, nm);
|
||
|
dbg_tnc("rc returned %d, znode %p, n %d",
|
||
|
err, znode, n);
|
||
|
if (unlikely(err < 0))
|
||
|
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
|
||
|
index 306d883d89bc..5e9a9a62a45c 100644
|
||
|
--- a/fs/xfs/xfs_acl.c
|
||
|
+++ b/fs/xfs/xfs_acl.c
|
||
|
@@ -388,16 +388,15 @@ xfs_xattr_acl_set(struct dentry *dentry, const char *name,
|
||
|
goto out_release;
|
||
|
|
||
|
if (type == ACL_TYPE_ACCESS) {
|
||
|
- umode_t mode = inode->i_mode;
|
||
|
- error = posix_acl_equiv_mode(acl, &mode);
|
||
|
+ umode_t mode;
|
||
|
+ struct posix_acl *old_acl = acl;
|
||
|
|
||
|
- if (error <= 0) {
|
||
|
- posix_acl_release(acl);
|
||
|
- acl = NULL;
|
||
|
+ error = posix_acl_update_mode(inode, &mode, &acl);
|
||
|
|
||
|
- if (error < 0)
|
||
|
- return error;
|
||
|
- }
|
||
|
+ if (error)
|
||
|
+ goto out_release;
|
||
|
+ if (!acl)
|
||
|
+ posix_acl_release(old_acl);
|
||
|
|
||
|
error = xfs_set_mode(inode, mode);
|
||
|
if (error)
|
||
|
diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h
|
||
|
index 418d270e1806..e73c19e90e38 100644
|
||
|
--- a/include/crypto/algapi.h
|
||
|
+++ b/include/crypto/algapi.h
|
||
|
@@ -386,5 +386,21 @@ static inline int crypto_requires_sync(u32 type, u32 mask)
|
||
|
return (type ^ CRYPTO_ALG_ASYNC) & mask & CRYPTO_ALG_ASYNC;
|
||
|
}
|
||
|
|
||
|
-#endif /* _CRYPTO_ALGAPI_H */
|
||
|
+noinline unsigned long __crypto_memneq(const void *a, const void *b, size_t size);
|
||
|
+
|
||
|
+/**
|
||
|
+ * crypto_memneq - Compare two areas of memory without leaking
|
||
|
+ * timing information.
|
||
|
+ *
|
||
|
+ * @a: One area of memory
|
||
|
+ * @b: Another area of memory
|
||
|
+ * @size: The size of the area.
|
||
|
+ *
|
||
|
+ * Returns 0 when data is equal, 1 otherwise.
|
||
|
+ */
|
||
|
+static inline int crypto_memneq(const void *a, const void *b, size_t size)
|
||
|
+{
|
||
|
+ return __crypto_memneq(a, b, size) != 0UL ? 1 : 0;
|
||
|
+}
|
||
|
|
||
|
+#endif /* _CRYPTO_ALGAPI_H */
|
||
|
diff --git a/include/linux/can/core.h b/include/linux/can/core.h
|
||
|
index 78c6c52073ad..6bdc00b6df01 100644
|
||
|
--- a/include/linux/can/core.h
|
||
|
+++ b/include/linux/can/core.h
|
||
|
@@ -45,10 +45,9 @@ struct can_proto {
|
||
|
extern int can_proto_register(const struct can_proto *cp);
|
||
|
extern void can_proto_unregister(const struct can_proto *cp);
|
||
|
|
||
|
-extern int can_rx_register(struct net_device *dev, canid_t can_id,
|
||
|
- canid_t mask,
|
||
|
- void (*func)(struct sk_buff *, void *),
|
||
|
- void *data, char *ident);
|
||
|
+int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask,
|
||
|
+ void (*func)(struct sk_buff *, void *),
|
||
|
+ void *data, char *ident, struct sock *sk);
|
||
|
|
||
|
extern void can_rx_unregister(struct net_device *dev, canid_t can_id,
|
||
|
canid_t mask,
|
||
|
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
|
||
|
index 9f3c7e81270a..d0d5946b6ee9 100644
|
||
|
--- a/include/linux/cpu.h
|
||
|
+++ b/include/linux/cpu.h
|
||
|
@@ -119,22 +119,16 @@ enum {
|
||
|
{ .notifier_call = fn, .priority = pri }; \
|
||
|
register_cpu_notifier(&fn##_nb); \
|
||
|
}
|
||
|
-#else /* #if defined(CONFIG_HOTPLUG_CPU) || !defined(MODULE) */
|
||
|
-#define cpu_notifier(fn, pri) do { (void)(fn); } while (0)
|
||
|
-#endif /* #else #if defined(CONFIG_HOTPLUG_CPU) || !defined(MODULE) */
|
||
|
-#ifdef CONFIG_HOTPLUG_CPU
|
||
|
extern int register_cpu_notifier(struct notifier_block *nb);
|
||
|
extern void unregister_cpu_notifier(struct notifier_block *nb);
|
||
|
-#else
|
||
|
|
||
|
-#ifndef MODULE
|
||
|
-extern int register_cpu_notifier(struct notifier_block *nb);
|
||
|
-#else
|
||
|
+#else /* #if defined(CONFIG_HOTPLUG_CPU) || !defined(MODULE) */
|
||
|
+#define cpu_notifier(fn, pri) do { (void)(fn); } while (0)
|
||
|
+
|
||
|
static inline int register_cpu_notifier(struct notifier_block *nb)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
-#endif
|
||
|
|
||
|
static inline void unregister_cpu_notifier(struct notifier_block *nb)
|
||
|
{
|
||
|
diff --git a/include/linux/jump_label.h b/include/linux/jump_label.h
|
||
|
index 0976fc46d1e0..7f831b28ee68 100644
|
||
|
--- a/include/linux/jump_label.h
|
||
|
+++ b/include/linux/jump_label.h
|
||
|
@@ -208,4 +208,20 @@ static inline bool static_key_enabled(struct static_key *key)
|
||
|
return (atomic_read(&key->enabled) > 0);
|
||
|
}
|
||
|
|
||
|
+static inline void static_key_enable(struct static_key *key)
|
||
|
+{
|
||
|
+ int count = atomic_read(&key->enabled);
|
||
|
+
|
||
|
+ if (!count)
|
||
|
+ static_key_slow_inc(key);
|
||
|
+}
|
||
|
+
|
||
|
+static inline void static_key_disable(struct static_key *key)
|
||
|
+{
|
||
|
+ int count = atomic_read(&key->enabled);
|
||
|
+
|
||
|
+ if (count)
|
||
|
+ static_key_slow_dec(key);
|
||
|
+}
|
||
|
+
|
||
|
#endif /* _LINUX_JUMP_LABEL_H */
|
||
|
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
|
||
|
index 8db53cfaccdb..71bcaf585edd 100644
|
||
|
--- a/include/linux/kvm_host.h
|
||
|
+++ b/include/linux/kvm_host.h
|
||
|
@@ -145,7 +145,8 @@ struct kvm_io_range {
|
||
|
#define NR_IOBUS_DEVS 1000
|
||
|
|
||
|
struct kvm_io_bus {
|
||
|
- int dev_count;
|
||
|
+ int dev_count;
|
||
|
+ int ioeventfd_count;
|
||
|
struct kvm_io_range range[];
|
||
|
};
|
||
|
|
||
|
@@ -162,8 +163,8 @@ int kvm_io_bus_read(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr, int len,
|
||
|
void *val);
|
||
|
int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
|
||
|
int len, struct kvm_io_device *dev);
|
||
|
-int kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx,
|
||
|
- struct kvm_io_device *dev);
|
||
|
+void kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx,
|
||
|
+ struct kvm_io_device *dev);
|
||
|
|
||
|
#ifdef CONFIG_KVM_ASYNC_PF
|
||
|
struct kvm_async_pf {
|
||
|
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
|
||
|
index 0adf073f13b3..669af5eaa898 100644
|
||
|
--- a/include/linux/lockd/lockd.h
|
||
|
+++ b/include/linux/lockd/lockd.h
|
||
|
@@ -355,7 +355,8 @@ static inline int nlm_privileged_requester(const struct svc_rqst *rqstp)
|
||
|
static inline int nlm_compare_locks(const struct file_lock *fl1,
|
||
|
const struct file_lock *fl2)
|
||
|
{
|
||
|
- return fl1->fl_pid == fl2->fl_pid
|
||
|
+ return file_inode(fl1->fl_file) == file_inode(fl2->fl_file)
|
||
|
+ && fl1->fl_pid == fl2->fl_pid
|
||
|
&& fl1->fl_owner == fl2->fl_owner
|
||
|
&& fl1->fl_start == fl2->fl_start
|
||
|
&& fl1->fl_end == fl2->fl_end
|
||
|
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
|
||
|
index 45a618b58864..157a47c998e5 100644
|
||
|
--- a/include/linux/netdevice.h
|
||
|
+++ b/include/linux/netdevice.h
|
||
|
@@ -1729,14 +1729,19 @@ static inline int skb_gro_header_hard(struct sk_buff *skb, unsigned int hlen)
|
||
|
return NAPI_GRO_CB(skb)->frag0_len < hlen;
|
||
|
}
|
||
|
|
||
|
+static inline void skb_gro_frag0_invalidate(struct sk_buff *skb)
|
||
|
+{
|
||
|
+ NAPI_GRO_CB(skb)->frag0 = NULL;
|
||
|
+ NAPI_GRO_CB(skb)->frag0_len = 0;
|
||
|
+}
|
||
|
+
|
||
|
static inline void *skb_gro_header_slow(struct sk_buff *skb, unsigned int hlen,
|
||
|
unsigned int offset)
|
||
|
{
|
||
|
if (!pskb_may_pull(skb, hlen))
|
||
|
return NULL;
|
||
|
|
||
|
- NAPI_GRO_CB(skb)->frag0 = NULL;
|
||
|
- NAPI_GRO_CB(skb)->frag0_len = 0;
|
||
|
+ skb_gro_frag0_invalidate(skb);
|
||
|
return skb->data + offset;
|
||
|
}
|
||
|
|
||
|
diff --git a/include/linux/posix_acl.h b/include/linux/posix_acl.h
|
||
|
index 7931efe71175..43cb8d59d0a7 100644
|
||
|
--- a/include/linux/posix_acl.h
|
||
|
+++ b/include/linux/posix_acl.h
|
||
|
@@ -89,6 +89,7 @@ extern int posix_acl_permission(struct inode *, const struct posix_acl *, int);
|
||
|
extern struct posix_acl *posix_acl_from_mode(umode_t, gfp_t);
|
||
|
extern int posix_acl_equiv_mode(const struct posix_acl *, umode_t *);
|
||
|
extern int posix_acl_create(struct posix_acl **, gfp_t, umode_t *);
|
||
|
+extern int posix_acl_update_mode(struct inode *, umode_t *, struct posix_acl **);
|
||
|
extern int posix_acl_chmod(struct posix_acl **, gfp_t, umode_t);
|
||
|
|
||
|
extern struct posix_acl *get_posix_acl(struct inode *, int);
|
||
|
diff --git a/include/net/cipso_ipv4.h b/include/net/cipso_ipv4.h
|
||
|
index a8c2ef6d3b93..9078b31d336f 100644
|
||
|
--- a/include/net/cipso_ipv4.h
|
||
|
+++ b/include/net/cipso_ipv4.h
|
||
|
@@ -303,6 +303,10 @@ static inline int cipso_v4_validate(const struct sk_buff *skb,
|
||
|
}
|
||
|
|
||
|
for (opt_iter = 6; opt_iter < opt_len;) {
|
||
|
+ if (opt_iter + 1 == opt_len) {
|
||
|
+ err_offset = opt_iter;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
tag_len = opt[opt_iter + 1];
|
||
|
if ((tag_len == 0) || (opt[opt_iter + 1] > (opt_len - opt_iter))) {
|
||
|
err_offset = opt_iter + 1;
|
||
|
diff --git a/include/rdma/ib_sa.h b/include/rdma/ib_sa.h
|
||
|
index 8275e539bace..969aff6f657e 100644
|
||
|
--- a/include/rdma/ib_sa.h
|
||
|
+++ b/include/rdma/ib_sa.h
|
||
|
@@ -137,12 +137,12 @@ struct ib_sa_path_rec {
|
||
|
union ib_gid sgid;
|
||
|
__be16 dlid;
|
||
|
__be16 slid;
|
||
|
- int raw_traffic;
|
||
|
+ u8 raw_traffic;
|
||
|
/* reserved */
|
||
|
__be32 flow_label;
|
||
|
u8 hop_limit;
|
||
|
u8 traffic_class;
|
||
|
- int reversible;
|
||
|
+ u8 reversible;
|
||
|
u8 numb_path;
|
||
|
__be16 pkey;
|
||
|
__be16 qos_class;
|
||
|
@@ -193,7 +193,7 @@ struct ib_sa_mcmember_rec {
|
||
|
u8 hop_limit;
|
||
|
u8 scope;
|
||
|
u8 join_state;
|
||
|
- int proxy_join;
|
||
|
+ u8 proxy_join;
|
||
|
};
|
||
|
|
||
|
/* Service Record Component Mask Sec 15.2.5.14 Ver 1.1 */
|
||
|
diff --git a/include/trace/events/syscalls.h b/include/trace/events/syscalls.h
|
||
|
index 5a4c04a75b3d..55c9b99ff9a6 100644
|
||
|
--- a/include/trace/events/syscalls.h
|
||
|
+++ b/include/trace/events/syscalls.h
|
||
|
@@ -1,5 +1,6 @@
|
||
|
#undef TRACE_SYSTEM
|
||
|
#define TRACE_SYSTEM raw_syscalls
|
||
|
+#undef TRACE_INCLUDE_FILE
|
||
|
#define TRACE_INCLUDE_FILE syscalls
|
||
|
|
||
|
#if !defined(_TRACE_EVENTS_SYSCALLS_H) || defined(TRACE_HEADER_MULTI_READ)
|
||
|
diff --git a/kernel/cpu.c b/kernel/cpu.c
|
||
|
index bc255e25d5dd..a6c242489861 100644
|
||
|
--- a/kernel/cpu.c
|
||
|
+++ b/kernel/cpu.c
|
||
|
@@ -185,8 +185,6 @@ static int cpu_notify(unsigned long val, void *v)
|
||
|
return __cpu_notify(val, v, -1, NULL);
|
||
|
}
|
||
|
|
||
|
-#ifdef CONFIG_HOTPLUG_CPU
|
||
|
-
|
||
|
static void cpu_notify_nofail(unsigned long val, void *v)
|
||
|
{
|
||
|
BUG_ON(cpu_notify(val, v));
|
||
|
@@ -201,6 +199,7 @@ void __ref unregister_cpu_notifier(struct notifier_block *nb)
|
||
|
}
|
||
|
EXPORT_SYMBOL(unregister_cpu_notifier);
|
||
|
|
||
|
+#ifdef CONFIG_HOTPLUG_CPU
|
||
|
/**
|
||
|
* clear_tasks_mm_cpumask - Safely clear tasks' mm_cpumask for a CPU
|
||
|
* @cpu: a CPU id
|
||
|
diff --git a/kernel/events/core.c b/kernel/events/core.c
|
||
|
index 76e26b8e4e41..5a550f2e37f2 100644
|
||
|
--- a/kernel/events/core.c
|
||
|
+++ b/kernel/events/core.c
|
||
|
@@ -7470,7 +7470,7 @@ int perf_event_init_context(struct task_struct *child, int ctxn)
|
||
|
ret = inherit_task_group(event, parent, parent_ctx,
|
||
|
child, ctxn, &inherited_all);
|
||
|
if (ret)
|
||
|
- break;
|
||
|
+ goto out_unlock;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
@@ -7486,7 +7486,7 @@ int perf_event_init_context(struct task_struct *child, int ctxn)
|
||
|
ret = inherit_task_group(event, parent, parent_ctx,
|
||
|
child, ctxn, &inherited_all);
|
||
|
if (ret)
|
||
|
- break;
|
||
|
+ goto out_unlock;
|
||
|
}
|
||
|
|
||
|
raw_spin_lock_irqsave(&parent_ctx->lock, flags);
|
||
|
@@ -7514,6 +7514,7 @@ int perf_event_init_context(struct task_struct *child, int ctxn)
|
||
|
}
|
||
|
|
||
|
raw_spin_unlock_irqrestore(&parent_ctx->lock, flags);
|
||
|
+out_unlock:
|
||
|
mutex_unlock(&parent_ctx->mutex);
|
||
|
|
||
|
perf_unpin_context(parent_ctx);
|
||
|
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
|
||
|
index 72b0b3e0e065..d34c05ac6f99 100644
|
||
|
--- a/kernel/ptrace.c
|
||
|
+++ b/kernel/ptrace.c
|
||
|
@@ -150,11 +150,17 @@ static void ptrace_unfreeze_traced(struct task_struct *task)
|
||
|
|
||
|
WARN_ON(!task->ptrace || task->parent != current);
|
||
|
|
||
|
+ /*
|
||
|
+ * PTRACE_LISTEN can allow ptrace_trap_notify to wake us up remotely.
|
||
|
+ * Recheck state under the lock to close this race.
|
||
|
+ */
|
||
|
spin_lock_irq(&task->sighand->siglock);
|
||
|
- if (__fatal_signal_pending(task))
|
||
|
- wake_up_state(task, __TASK_TRACED);
|
||
|
- else
|
||
|
- task->state = TASK_TRACED;
|
||
|
+ if (task->state == __TASK_TRACED) {
|
||
|
+ if (__fatal_signal_pending(task))
|
||
|
+ wake_up_state(task, __TASK_TRACED);
|
||
|
+ else
|
||
|
+ task->state = TASK_TRACED;
|
||
|
+ }
|
||
|
spin_unlock_irq(&task->sighand->siglock);
|
||
|
}
|
||
|
|
||
|
diff --git a/kernel/rtmutex.c b/kernel/rtmutex.c
|
||
|
index d9ca207cec0c..286c92f5573c 100644
|
||
|
--- a/kernel/rtmutex.c
|
||
|
+++ b/kernel/rtmutex.c
|
||
|
@@ -64,8 +64,72 @@ static inline void clear_rt_mutex_waiters(struct rt_mutex *lock)
|
||
|
|
||
|
static void fixup_rt_mutex_waiters(struct rt_mutex *lock)
|
||
|
{
|
||
|
- if (!rt_mutex_has_waiters(lock))
|
||
|
- clear_rt_mutex_waiters(lock);
|
||
|
+ unsigned long owner, *p = (unsigned long *) &lock->owner;
|
||
|
+
|
||
|
+ if (rt_mutex_has_waiters(lock))
|
||
|
+ return;
|
||
|
+
|
||
|
+ /*
|
||
|
+ * The rbtree has no waiters enqueued, now make sure that the
|
||
|
+ * lock->owner still has the waiters bit set, otherwise the
|
||
|
+ * following can happen:
|
||
|
+ *
|
||
|
+ * CPU 0 CPU 1 CPU2
|
||
|
+ * l->owner=T1
|
||
|
+ * rt_mutex_lock(l)
|
||
|
+ * lock(l->lock)
|
||
|
+ * l->owner = T1 | HAS_WAITERS;
|
||
|
+ * enqueue(T2)
|
||
|
+ * boost()
|
||
|
+ * unlock(l->lock)
|
||
|
+ * block()
|
||
|
+ *
|
||
|
+ * rt_mutex_lock(l)
|
||
|
+ * lock(l->lock)
|
||
|
+ * l->owner = T1 | HAS_WAITERS;
|
||
|
+ * enqueue(T3)
|
||
|
+ * boost()
|
||
|
+ * unlock(l->lock)
|
||
|
+ * block()
|
||
|
+ * signal(->T2) signal(->T3)
|
||
|
+ * lock(l->lock)
|
||
|
+ * dequeue(T2)
|
||
|
+ * deboost()
|
||
|
+ * unlock(l->lock)
|
||
|
+ * lock(l->lock)
|
||
|
+ * dequeue(T3)
|
||
|
+ * ==> wait list is empty
|
||
|
+ * deboost()
|
||
|
+ * unlock(l->lock)
|
||
|
+ * lock(l->lock)
|
||
|
+ * fixup_rt_mutex_waiters()
|
||
|
+ * if (wait_list_empty(l) {
|
||
|
+ * l->owner = owner
|
||
|
+ * owner = l->owner & ~HAS_WAITERS;
|
||
|
+ * ==> l->owner = T1
|
||
|
+ * }
|
||
|
+ * lock(l->lock)
|
||
|
+ * rt_mutex_unlock(l) fixup_rt_mutex_waiters()
|
||
|
+ * if (wait_list_empty(l) {
|
||
|
+ * owner = l->owner & ~HAS_WAITERS;
|
||
|
+ * cmpxchg(l->owner, T1, NULL)
|
||
|
+ * ===> Success (l->owner = NULL)
|
||
|
+ *
|
||
|
+ * l->owner = owner
|
||
|
+ * ==> l->owner = T1
|
||
|
+ * }
|
||
|
+ *
|
||
|
+ * With the check for the waiter bit in place T3 on CPU2 will not
|
||
|
+ * overwrite. All tasks fiddling with the waiters bit are
|
||
|
+ * serialized by l->lock, so nothing else can modify the waiters
|
||
|
+ * bit. If the bit is set then nothing can change l->owner either
|
||
|
+ * so the simple RMW is safe. The cmpxchg() will simply fail if it
|
||
|
+ * happens in the middle of the RMW because the waiters bit is
|
||
|
+ * still set.
|
||
|
+ */
|
||
|
+ owner = ACCESS_ONCE(*p);
|
||
|
+ if (owner & RT_MUTEX_HAS_WAITERS)
|
||
|
+ ACCESS_ONCE(*p) = owner & ~RT_MUTEX_HAS_WAITERS;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
|
||
|
index 6a366f9d08db..506e56ec56a9 100644
|
||
|
--- a/kernel/sched/core.c
|
||
|
+++ b/kernel/sched/core.c
|
||
|
@@ -179,14 +179,12 @@ struct static_key sched_feat_keys[__SCHED_FEAT_NR] = {
|
||
|
|
||
|
static void sched_feat_disable(int i)
|
||
|
{
|
||
|
- if (static_key_enabled(&sched_feat_keys[i]))
|
||
|
- static_key_slow_dec(&sched_feat_keys[i]);
|
||
|
+ static_key_disable(&sched_feat_keys[i]);
|
||
|
}
|
||
|
|
||
|
static void sched_feat_enable(int i)
|
||
|
{
|
||
|
- if (!static_key_enabled(&sched_feat_keys[i]))
|
||
|
- static_key_slow_inc(&sched_feat_keys[i]);
|
||
|
+ static_key_enable(&sched_feat_keys[i]);
|
||
|
}
|
||
|
#else
|
||
|
static void sched_feat_disable(int i) { };
|
||
|
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
|
||
|
index c4ce3a951a1c..1caa75585fa0 100644
|
||
|
--- a/kernel/trace/ring_buffer.c
|
||
|
+++ b/kernel/trace/ring_buffer.c
|
||
|
@@ -3402,11 +3402,23 @@ EXPORT_SYMBOL_GPL(ring_buffer_iter_reset);
|
||
|
int ring_buffer_iter_empty(struct ring_buffer_iter *iter)
|
||
|
{
|
||
|
struct ring_buffer_per_cpu *cpu_buffer;
|
||
|
+ struct buffer_page *reader;
|
||
|
+ struct buffer_page *head_page;
|
||
|
+ struct buffer_page *commit_page;
|
||
|
+ unsigned commit;
|
||
|
|
||
|
cpu_buffer = iter->cpu_buffer;
|
||
|
|
||
|
- return iter->head_page == cpu_buffer->commit_page &&
|
||
|
- iter->head == rb_commit_index(cpu_buffer);
|
||
|
+ /* Remember, trace recording is off when iterator is in use */
|
||
|
+ reader = cpu_buffer->reader_page;
|
||
|
+ head_page = cpu_buffer->head_page;
|
||
|
+ commit_page = cpu_buffer->commit_page;
|
||
|
+ commit = rb_page_commit(commit_page);
|
||
|
+
|
||
|
+ return ((iter->head_page == commit_page && iter->head == commit) ||
|
||
|
+ (iter->head_page == reader && commit_page == head_page &&
|
||
|
+ head_page->read == commit &&
|
||
|
+ iter->head == rb_page_commit(cpu_buffer->reader_page)));
|
||
|
}
|
||
|
EXPORT_SYMBOL_GPL(ring_buffer_iter_empty);
|
||
|
|
||
|
@@ -4837,9 +4849,9 @@ static __init int test_ringbuffer(void)
|
||
|
rb_data[cpu].cnt = cpu;
|
||
|
rb_threads[cpu] = kthread_create(rb_test, &rb_data[cpu],
|
||
|
"rbtester/%d", cpu);
|
||
|
- if (WARN_ON(!rb_threads[cpu])) {
|
||
|
+ if (WARN_ON(IS_ERR(rb_threads[cpu]))) {
|
||
|
pr_cont("FAILED\n");
|
||
|
- ret = -1;
|
||
|
+ ret = PTR_ERR(rb_threads[cpu]);
|
||
|
goto out_free;
|
||
|
}
|
||
|
|
||
|
@@ -4849,9 +4861,9 @@ static __init int test_ringbuffer(void)
|
||
|
|
||
|
/* Now create the rb hammer! */
|
||
|
rb_hammer = kthread_run(rb_hammer_test, NULL, "rbhammer");
|
||
|
- if (WARN_ON(!rb_hammer)) {
|
||
|
+ if (WARN_ON(IS_ERR(rb_hammer))) {
|
||
|
pr_cont("FAILED\n");
|
||
|
- ret = -1;
|
||
|
+ ret = PTR_ERR(rb_hammer);
|
||
|
goto out_free;
|
||
|
}
|
||
|
|
||
|
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
|
||
|
index d6e72522fc4e..edffb6781c0e 100644
|
||
|
--- a/kernel/trace/trace.c
|
||
|
+++ b/kernel/trace/trace.c
|
||
|
@@ -5468,11 +5468,13 @@ ftrace_trace_snapshot_callback(struct ftrace_hash *hash,
|
||
|
return ret;
|
||
|
|
||
|
out_reg:
|
||
|
- ret = register_ftrace_function_probe(glob, ops, count);
|
||
|
+ ret = alloc_snapshot(&global_trace);
|
||
|
+ if (ret < 0)
|
||
|
+ goto out;
|
||
|
|
||
|
- if (ret >= 0)
|
||
|
- alloc_snapshot(&global_trace);
|
||
|
+ ret = register_ftrace_function_probe(glob, ops, count);
|
||
|
|
||
|
+ out:
|
||
|
return ret < 0 ? ret : 0;
|
||
|
}
|
||
|
|
||
|
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
|
||
|
index d21c9ef0943c..3877483a20fd 100644
|
||
|
--- a/mm/huge_memory.c
|
||
|
+++ b/mm/huge_memory.c
|
||
|
@@ -1235,6 +1235,18 @@ out_unlock:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
+/*
|
||
|
+ * foll_force can write to even unwritable pmd's, but only
|
||
|
+ * after we've gone through a cow cycle and they are dirty.
|
||
|
+ */
|
||
|
+static inline bool can_follow_write_pmd(pmd_t pmd, struct page *page,
|
||
|
+ unsigned int flags)
|
||
|
+{
|
||
|
+ return pmd_write(pmd) ||
|
||
|
+ ((flags & FOLL_FORCE) && (flags & FOLL_COW) &&
|
||
|
+ page && PageAnon(page));
|
||
|
+}
|
||
|
+
|
||
|
struct page *follow_trans_huge_pmd(struct vm_area_struct *vma,
|
||
|
unsigned long addr,
|
||
|
pmd_t *pmd,
|
||
|
@@ -1245,15 +1257,16 @@ struct page *follow_trans_huge_pmd(struct vm_area_struct *vma,
|
||
|
|
||
|
assert_spin_locked(&mm->page_table_lock);
|
||
|
|
||
|
- if (flags & FOLL_WRITE && !pmd_write(*pmd))
|
||
|
- goto out;
|
||
|
-
|
||
|
/* Avoid dumping huge zero page */
|
||
|
if ((flags & FOLL_DUMP) && is_huge_zero_pmd(*pmd))
|
||
|
return ERR_PTR(-EFAULT);
|
||
|
|
||
|
page = pmd_page(*pmd);
|
||
|
VM_BUG_ON(!PageHead(page));
|
||
|
+
|
||
|
+ if (flags & FOLL_WRITE && !can_follow_write_pmd(*pmd, page, flags))
|
||
|
+ return NULL;
|
||
|
+
|
||
|
if (flags & FOLL_TOUCH) {
|
||
|
pmd_t _pmd;
|
||
|
/*
|
||
|
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
|
||
|
index e9fd382bf25a..69832290015f 100644
|
||
|
--- a/mm/hugetlb.c
|
||
|
+++ b/mm/hugetlb.c
|
||
|
@@ -1070,23 +1070,32 @@ free:
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
- * When releasing a hugetlb pool reservation, any surplus pages that were
|
||
|
- * allocated to satisfy the reservation must be explicitly freed if they were
|
||
|
- * never used.
|
||
|
- * Called with hugetlb_lock held.
|
||
|
+ * This routine has two main purposes:
|
||
|
+ * 1) Decrement the reservation count (resv_huge_pages) by the value passed
|
||
|
+ * in unused_resv_pages. This corresponds to the prior adjustments made
|
||
|
+ * to the associated reservation map.
|
||
|
+ * 2) Free any unused surplus pages that may have been allocated to satisfy
|
||
|
+ * the reservation. As many as unused_resv_pages may be freed.
|
||
|
+ *
|
||
|
+ * Called with hugetlb_lock held. However, the lock could be dropped (and
|
||
|
+ * reacquired) during calls to cond_resched_lock. Whenever dropping the lock,
|
||
|
+ * we must make sure nobody else can claim pages we are in the process of
|
||
|
+ * freeing. Do this by ensuring resv_huge_page always is greater than the
|
||
|
+ * number of huge pages we plan to free when dropping the lock.
|
||
|
*/
|
||
|
static void return_unused_surplus_pages(struct hstate *h,
|
||
|
unsigned long unused_resv_pages)
|
||
|
{
|
||
|
unsigned long nr_pages;
|
||
|
|
||
|
- /* Uncommit the reservation */
|
||
|
- h->resv_huge_pages -= unused_resv_pages;
|
||
|
-
|
||
|
/* Cannot return gigantic pages currently */
|
||
|
if (h->order >= MAX_ORDER)
|
||
|
- return;
|
||
|
+ goto out;
|
||
|
|
||
|
+ /*
|
||
|
+ * Part (or even all) of the reservation could have been backed
|
||
|
+ * by pre-allocated pages. Only free surplus pages.
|
||
|
+ */
|
||
|
nr_pages = min(unused_resv_pages, h->surplus_huge_pages);
|
||
|
|
||
|
/*
|
||
|
@@ -1096,12 +1105,22 @@ static void return_unused_surplus_pages(struct hstate *h,
|
||
|
* when the nodes with surplus pages have no free pages.
|
||
|
* free_pool_huge_page() will balance the the freed pages across the
|
||
|
* on-line nodes with memory and will handle the hstate accounting.
|
||
|
+ *
|
||
|
+ * Note that we decrement resv_huge_pages as we free the pages. If
|
||
|
+ * we drop the lock, resv_huge_pages will still be sufficiently large
|
||
|
+ * to cover subsequent pages we may free.
|
||
|
*/
|
||
|
while (nr_pages--) {
|
||
|
+ h->resv_huge_pages--;
|
||
|
+ unused_resv_pages--;
|
||
|
if (!free_pool_huge_page(h, &node_states[N_MEMORY], 1))
|
||
|
- break;
|
||
|
+ goto out;
|
||
|
cond_resched_lock(&hugetlb_lock);
|
||
|
}
|
||
|
+
|
||
|
+out:
|
||
|
+ /* Fully uncommit the reservation */
|
||
|
+ h->resv_huge_pages -= unused_resv_pages;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
|
||
|
index 494a081ec5e4..4e8927539299 100644
|
||
|
--- a/mm/page_alloc.c
|
||
|
+++ b/mm/page_alloc.c
|
||
|
@@ -5060,15 +5060,18 @@ void __init free_area_init_nodes(unsigned long *max_zone_pfn)
|
||
|
sizeof(arch_zone_lowest_possible_pfn));
|
||
|
memset(arch_zone_highest_possible_pfn, 0,
|
||
|
sizeof(arch_zone_highest_possible_pfn));
|
||
|
- arch_zone_lowest_possible_pfn[0] = find_min_pfn_with_active_regions();
|
||
|
- arch_zone_highest_possible_pfn[0] = max_zone_pfn[0];
|
||
|
- for (i = 1; i < MAX_NR_ZONES; i++) {
|
||
|
+
|
||
|
+ start_pfn = find_min_pfn_with_active_regions();
|
||
|
+
|
||
|
+ for (i = 0; i < MAX_NR_ZONES; i++) {
|
||
|
if (i == ZONE_MOVABLE)
|
||
|
continue;
|
||
|
- arch_zone_lowest_possible_pfn[i] =
|
||
|
- arch_zone_highest_possible_pfn[i-1];
|
||
|
- arch_zone_highest_possible_pfn[i] =
|
||
|
- max(max_zone_pfn[i], arch_zone_lowest_possible_pfn[i]);
|
||
|
+
|
||
|
+ end_pfn = max(max_zone_pfn[i], start_pfn);
|
||
|
+ arch_zone_lowest_possible_pfn[i] = start_pfn;
|
||
|
+ arch_zone_highest_possible_pfn[i] = end_pfn;
|
||
|
+
|
||
|
+ start_pfn = end_pfn;
|
||
|
}
|
||
|
arch_zone_lowest_possible_pfn[ZONE_MOVABLE] = 0;
|
||
|
arch_zone_highest_possible_pfn[ZONE_MOVABLE] = 0;
|
||
|
diff --git a/net/can/af_can.c b/net/can/af_can.c
|
||
|
index d3668c55b088..34064aa88f02 100644
|
||
|
--- a/net/can/af_can.c
|
||
|
+++ b/net/can/af_can.c
|
||
|
@@ -425,6 +425,7 @@ static struct hlist_head *find_rcv_list(canid_t *can_id, canid_t *mask,
|
||
|
* @func: callback function on filter match
|
||
|
* @data: returned parameter for callback function
|
||
|
* @ident: string for calling module indentification
|
||
|
+ * @sk: socket pointer (might be NULL)
|
||
|
*
|
||
|
* Description:
|
||
|
* Invokes the callback function with the received sk_buff and the given
|
||
|
@@ -448,7 +449,7 @@ static struct hlist_head *find_rcv_list(canid_t *can_id, canid_t *mask,
|
||
|
*/
|
||
|
int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask,
|
||
|
void (*func)(struct sk_buff *, void *), void *data,
|
||
|
- char *ident)
|
||
|
+ char *ident, struct sock *sk)
|
||
|
{
|
||
|
struct receiver *r;
|
||
|
struct hlist_head *rl;
|
||
|
@@ -476,6 +477,7 @@ int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask,
|
||
|
r->func = func;
|
||
|
r->data = data;
|
||
|
r->ident = ident;
|
||
|
+ r->sk = sk;
|
||
|
|
||
|
hlist_add_head_rcu(&r->list, rl);
|
||
|
d->entries++;
|
||
|
@@ -500,8 +502,11 @@ EXPORT_SYMBOL(can_rx_register);
|
||
|
static void can_rx_delete_receiver(struct rcu_head *rp)
|
||
|
{
|
||
|
struct receiver *r = container_of(rp, struct receiver, rcu);
|
||
|
+ struct sock *sk = r->sk;
|
||
|
|
||
|
kmem_cache_free(rcv_cache, r);
|
||
|
+ if (sk)
|
||
|
+ sock_put(sk);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@@ -576,8 +581,11 @@ void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask,
|
||
|
spin_unlock(&can_rcvlists_lock);
|
||
|
|
||
|
/* schedule the receiver item for deletion */
|
||
|
- if (r)
|
||
|
+ if (r) {
|
||
|
+ if (r->sk)
|
||
|
+ sock_hold(r->sk);
|
||
|
call_rcu(&r->rcu, can_rx_delete_receiver);
|
||
|
+ }
|
||
|
}
|
||
|
EXPORT_SYMBOL(can_rx_unregister);
|
||
|
|
||
|
diff --git a/net/can/af_can.h b/net/can/af_can.h
|
||
|
index 1dccb4c33894..0e95be423587 100644
|
||
|
--- a/net/can/af_can.h
|
||
|
+++ b/net/can/af_can.h
|
||
|
@@ -50,13 +50,14 @@
|
||
|
|
||
|
struct receiver {
|
||
|
struct hlist_node list;
|
||
|
- struct rcu_head rcu;
|
||
|
canid_t can_id;
|
||
|
canid_t mask;
|
||
|
unsigned long matches;
|
||
|
void (*func)(struct sk_buff *, void *);
|
||
|
void *data;
|
||
|
char *ident;
|
||
|
+ struct sock *sk;
|
||
|
+ struct rcu_head rcu;
|
||
|
};
|
||
|
|
||
|
enum { RX_ERR, RX_ALL, RX_FIL, RX_INV, RX_EFF, RX_MAX };
|
||
|
diff --git a/net/can/bcm.c b/net/can/bcm.c
|
||
|
index dd0781c49ebb..725ce812cfbc 100644
|
||
|
--- a/net/can/bcm.c
|
||
|
+++ b/net/can/bcm.c
|
||
|
@@ -1169,7 +1169,7 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
|
||
|
err = can_rx_register(dev, op->can_id,
|
||
|
REGMASK(op->can_id),
|
||
|
bcm_rx_handler, op,
|
||
|
- "bcm");
|
||
|
+ "bcm", sk);
|
||
|
|
||
|
op->rx_reg_dev = dev;
|
||
|
dev_put(dev);
|
||
|
@@ -1178,7 +1178,7 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
|
||
|
} else
|
||
|
err = can_rx_register(NULL, op->can_id,
|
||
|
REGMASK(op->can_id),
|
||
|
- bcm_rx_handler, op, "bcm");
|
||
|
+ bcm_rx_handler, op, "bcm", sk);
|
||
|
if (err) {
|
||
|
/* this bcm rx op is broken -> remove it */
|
||
|
list_del(&op->list);
|
||
|
diff --git a/net/can/gw.c b/net/can/gw.c
|
||
|
index de25455b4e3e..2ad8aa4f9f0b 100644
|
||
|
--- a/net/can/gw.c
|
||
|
+++ b/net/can/gw.c
|
||
|
@@ -435,7 +435,7 @@ static inline int cgw_register_filter(struct cgw_job *gwj)
|
||
|
{
|
||
|
return can_rx_register(gwj->src.dev, gwj->ccgw.filter.can_id,
|
||
|
gwj->ccgw.filter.can_mask, can_can_gw_rcv,
|
||
|
- gwj, "gw");
|
||
|
+ gwj, "gw", NULL);
|
||
|
}
|
||
|
|
||
|
static inline void cgw_unregister_filter(struct cgw_job *gwj)
|
||
|
diff --git a/net/can/raw.c b/net/can/raw.c
|
||
|
index 1085e65f848e..f4d86485571f 100644
|
||
|
--- a/net/can/raw.c
|
||
|
+++ b/net/can/raw.c
|
||
|
@@ -168,7 +168,7 @@ static int raw_enable_filters(struct net_device *dev, struct sock *sk,
|
||
|
for (i = 0; i < count; i++) {
|
||
|
err = can_rx_register(dev, filter[i].can_id,
|
||
|
filter[i].can_mask,
|
||
|
- raw_rcv, sk, "raw");
|
||
|
+ raw_rcv, sk, "raw", sk);
|
||
|
if (err) {
|
||
|
/* clean up successfully registered filters */
|
||
|
while (--i >= 0)
|
||
|
@@ -189,7 +189,7 @@ static int raw_enable_errfilter(struct net_device *dev, struct sock *sk,
|
||
|
|
||
|
if (err_mask)
|
||
|
err = can_rx_register(dev, 0, err_mask | CAN_ERR_FLAG,
|
||
|
- raw_rcv, sk, "raw");
|
||
|
+ raw_rcv, sk, "raw", sk);
|
||
|
|
||
|
return err;
|
||
|
}
|
||
|
diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c
|
||
|
index c1de8d404c47..26e2235356c5 100644
|
||
|
--- a/net/ceph/osdmap.c
|
||
|
+++ b/net/ceph/osdmap.c
|
||
|
@@ -870,7 +870,6 @@ static int decode_new_up_state_weight(void **p, void *end,
|
||
|
if ((map->osd_state[osd] & CEPH_OSD_EXISTS) &&
|
||
|
(xorstate & CEPH_OSD_EXISTS)) {
|
||
|
pr_info("osd%d does not exist\n", osd);
|
||
|
- map->osd_weight[osd] = CEPH_OSD_IN;
|
||
|
memset(map->osd_addr + osd, 0, sizeof(*map->osd_addr));
|
||
|
map->osd_state[osd] = 0;
|
||
|
} else {
|
||
|
diff --git a/net/core/dev.c b/net/core/dev.c
|
||
|
index 6494918b3eaa..682bf5ad63a0 100644
|
||
|
--- a/net/core/dev.c
|
||
|
+++ b/net/core/dev.c
|
||
|
@@ -1559,37 +1559,59 @@ EXPORT_SYMBOL(call_netdevice_notifiers);
|
||
|
|
||
|
static struct static_key netstamp_needed __read_mostly;
|
||
|
#ifdef HAVE_JUMP_LABEL
|
||
|
-/* We are not allowed to call static_key_slow_dec() from irq context
|
||
|
- * If net_disable_timestamp() is called from irq context, defer the
|
||
|
- * static_key_slow_dec() calls.
|
||
|
- */
|
||
|
static atomic_t netstamp_needed_deferred;
|
||
|
+static atomic_t netstamp_wanted;
|
||
|
+static void netstamp_clear(struct work_struct *work)
|
||
|
+{
|
||
|
+ int deferred = atomic_xchg(&netstamp_needed_deferred, 0);
|
||
|
+ int wanted;
|
||
|
+
|
||
|
+ wanted = atomic_add_return(deferred, &netstamp_wanted);
|
||
|
+ if (wanted > 0)
|
||
|
+ static_key_enable(&netstamp_needed);
|
||
|
+ else
|
||
|
+ static_key_disable(&netstamp_needed);
|
||
|
+}
|
||
|
+static DECLARE_WORK(netstamp_work, netstamp_clear);
|
||
|
#endif
|
||
|
|
||
|
void net_enable_timestamp(void)
|
||
|
{
|
||
|
#ifdef HAVE_JUMP_LABEL
|
||
|
- int deferred = atomic_xchg(&netstamp_needed_deferred, 0);
|
||
|
+ int wanted;
|
||
|
|
||
|
- if (deferred) {
|
||
|
- while (--deferred)
|
||
|
- static_key_slow_dec(&netstamp_needed);
|
||
|
- return;
|
||
|
+ while (1) {
|
||
|
+ wanted = atomic_read(&netstamp_wanted);
|
||
|
+ if (wanted <= 0)
|
||
|
+ break;
|
||
|
+ if (atomic_cmpxchg(&netstamp_wanted, wanted, wanted + 1) == wanted)
|
||
|
+ return;
|
||
|
}
|
||
|
-#endif
|
||
|
+ atomic_inc(&netstamp_needed_deferred);
|
||
|
+ schedule_work(&netstamp_work);
|
||
|
+#else
|
||
|
static_key_slow_inc(&netstamp_needed);
|
||
|
+#endif
|
||
|
}
|
||
|
EXPORT_SYMBOL(net_enable_timestamp);
|
||
|
|
||
|
void net_disable_timestamp(void)
|
||
|
{
|
||
|
#ifdef HAVE_JUMP_LABEL
|
||
|
- if (in_interrupt()) {
|
||
|
- atomic_inc(&netstamp_needed_deferred);
|
||
|
- return;
|
||
|
+ int wanted;
|
||
|
+
|
||
|
+ while (1) {
|
||
|
+ wanted = atomic_read(&netstamp_wanted);
|
||
|
+ if (wanted <= 1)
|
||
|
+ break;
|
||
|
+ if (atomic_cmpxchg(&netstamp_wanted, wanted, wanted - 1) == wanted)
|
||
|
+ return;
|
||
|
}
|
||
|
-#endif
|
||
|
+ atomic_dec(&netstamp_needed_deferred);
|
||
|
+ schedule_work(&netstamp_work);
|
||
|
+#else
|
||
|
static_key_slow_dec(&netstamp_needed);
|
||
|
+#endif
|
||
|
}
|
||
|
EXPORT_SYMBOL(net_disable_timestamp);
|
||
|
|
||
|
@@ -2461,9 +2483,9 @@ static netdev_features_t harmonize_features(struct sk_buff *skb,
|
||
|
if (skb->ip_summed != CHECKSUM_NONE &&
|
||
|
!can_checksum_protocol(features, protocol)) {
|
||
|
features &= ~NETIF_F_ALL_CSUM;
|
||
|
- } else if (illegal_highdma(dev, skb)) {
|
||
|
- features &= ~NETIF_F_SG;
|
||
|
}
|
||
|
+ if (illegal_highdma(dev, skb))
|
||
|
+ features &= ~NETIF_F_SG;
|
||
|
|
||
|
return features;
|
||
|
}
|
||
|
@@ -3891,7 +3913,9 @@ static void skb_gro_reset_offset(struct sk_buff *skb)
|
||
|
pinfo->nr_frags &&
|
||
|
!PageHighMem(skb_frag_page(frag0))) {
|
||
|
NAPI_GRO_CB(skb)->frag0 = skb_frag_address(frag0);
|
||
|
- NAPI_GRO_CB(skb)->frag0_len = skb_frag_size(frag0);
|
||
|
+ NAPI_GRO_CB(skb)->frag0_len = min_t(unsigned int,
|
||
|
+ skb_frag_size(frag0),
|
||
|
+ skb->end - skb->tail);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
diff --git a/net/core/sock.c b/net/core/sock.c
|
||
|
index e3cb45411f34..96e125919324 100644
|
||
|
--- a/net/core/sock.c
|
||
|
+++ b/net/core/sock.c
|
||
|
@@ -1403,6 +1403,11 @@ static void __sk_free(struct sock *sk)
|
||
|
pr_debug("%s: optmem leakage (%d bytes) detected\n",
|
||
|
__func__, atomic_read(&sk->sk_omem_alloc));
|
||
|
|
||
|
+ if (sk->sk_frag.page) {
|
||
|
+ put_page(sk->sk_frag.page);
|
||
|
+ sk->sk_frag.page = NULL;
|
||
|
+ }
|
||
|
+
|
||
|
if (sk->sk_peer_cred)
|
||
|
put_cred(sk->sk_peer_cred);
|
||
|
put_pid(sk->sk_peer_pid);
|
||
|
@@ -2556,11 +2561,6 @@ void sk_common_release(struct sock *sk)
|
||
|
|
||
|
sk_refcnt_debug_release(sk);
|
||
|
|
||
|
- if (sk->sk_frag.page) {
|
||
|
- put_page(sk->sk_frag.page);
|
||
|
- sk->sk_frag.page = NULL;
|
||
|
- }
|
||
|
-
|
||
|
sock_put(sk);
|
||
|
}
|
||
|
EXPORT_SYMBOL(sk_common_release);
|
||
|
diff --git a/net/dccp/input.c b/net/dccp/input.c
|
||
|
index 14cdafad7a90..e511ccc74a07 100644
|
||
|
--- a/net/dccp/input.c
|
||
|
+++ b/net/dccp/input.c
|
||
|
@@ -606,7 +606,8 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
|
||
|
if (inet_csk(sk)->icsk_af_ops->conn_request(sk,
|
||
|
skb) < 0)
|
||
|
return 1;
|
||
|
- goto discard;
|
||
|
+ consume_skb(skb);
|
||
|
+ return 0;
|
||
|
}
|
||
|
if (dh->dccph_type == DCCP_PKT_RESET)
|
||
|
goto discard;
|
||
|
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
|
||
|
index 294c642fbebb..3bb5ff9e14a2 100644
|
||
|
--- a/net/dccp/ipv4.c
|
||
|
+++ b/net/dccp/ipv4.c
|
||
|
@@ -263,7 +263,8 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info)
|
||
|
|
||
|
switch (type) {
|
||
|
case ICMP_REDIRECT:
|
||
|
- dccp_do_redirect(skb, sk);
|
||
|
+ if (!sock_owned_by_user(sk))
|
||
|
+ dccp_do_redirect(skb, sk);
|
||
|
goto out;
|
||
|
case ICMP_SOURCE_QUENCH:
|
||
|
/* Just silently ignore these. */
|
||
|
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
|
||
|
index 94f8224d543e..9ad2416f8e33 100644
|
||
|
--- a/net/dccp/ipv6.c
|
||
|
+++ b/net/dccp/ipv6.c
|
||
|
@@ -132,10 +132,12 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
|
||
|
np = inet6_sk(sk);
|
||
|
|
||
|
if (type == NDISC_REDIRECT) {
|
||
|
- struct dst_entry *dst = __sk_dst_check(sk, np->dst_cookie);
|
||
|
+ if (!sock_owned_by_user(sk)) {
|
||
|
+ struct dst_entry *dst = __sk_dst_check(sk, np->dst_cookie);
|
||
|
|
||
|
- if (dst)
|
||
|
- dst->ops->redirect(dst, sk, skb);
|
||
|
+ if (dst)
|
||
|
+ dst->ops->redirect(dst, sk, skb);
|
||
|
+ }
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c
|
||
|
index ca118e8cb141..9d06b37acc4c 100644
|
||
|
--- a/net/ieee802154/6lowpan.c
|
||
|
+++ b/net/ieee802154/6lowpan.c
|
||
|
@@ -459,7 +459,7 @@ static int lowpan_header_create(struct sk_buff *skb,
|
||
|
hc06_ptr += 3;
|
||
|
} else {
|
||
|
/* compress nothing */
|
||
|
- memcpy(hc06_ptr, &hdr, 4);
|
||
|
+ memcpy(hc06_ptr, hdr, 4);
|
||
|
/* replace the top byte with new ECN | DSCP format */
|
||
|
*hc06_ptr = tmp;
|
||
|
hc06_ptr += 4;
|
||
|
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
|
||
|
index 667c1d4ca984..4322372dddbe 100644
|
||
|
--- a/net/ipv4/cipso_ipv4.c
|
||
|
+++ b/net/ipv4/cipso_ipv4.c
|
||
|
@@ -1649,6 +1649,10 @@ int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option)
|
||
|
goto validate_return_locked;
|
||
|
}
|
||
|
|
||
|
+ if (opt_iter + 1 == opt_len) {
|
||
|
+ err_offset = opt_iter;
|
||
|
+ goto validate_return_locked;
|
||
|
+ }
|
||
|
tag_len = tag[1];
|
||
|
if (tag_len > (opt_len - opt_iter)) {
|
||
|
err_offset = opt_iter + 1;
|
||
|
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
|
||
|
index 155adf8729c2..b0178b04bd81 100644
|
||
|
--- a/net/ipv4/igmp.c
|
||
|
+++ b/net/ipv4/igmp.c
|
||
|
@@ -1874,7 +1874,7 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr)
|
||
|
|
||
|
rtnl_lock();
|
||
|
in_dev = ip_mc_find_dev(net, imr);
|
||
|
- if (!in_dev) {
|
||
|
+ if (!imr->imr_ifindex && !imr->imr_address.s_addr && !in_dev) {
|
||
|
ret = -ENODEV;
|
||
|
goto out;
|
||
|
}
|
||
|
@@ -1895,8 +1895,10 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr)
|
||
|
|
||
|
*imlp = iml->next_rcu;
|
||
|
|
||
|
- ip_mc_dec_group(in_dev, group);
|
||
|
+ if (in_dev)
|
||
|
+ ip_mc_dec_group(in_dev, group);
|
||
|
rtnl_unlock();
|
||
|
+
|
||
|
/* decrease mem now to avoid the memleak warning */
|
||
|
atomic_sub(sizeof(*iml), &sk->sk_omem_alloc);
|
||
|
kfree_rcu(iml, rcu);
|
||
|
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
|
||
|
index 6acb541c9091..40ac1e2cbb34 100644
|
||
|
--- a/net/ipv4/inet_connection_sock.c
|
||
|
+++ b/net/ipv4/inet_connection_sock.c
|
||
|
@@ -688,6 +688,8 @@ struct sock *inet_csk_clone_lock(const struct sock *sk,
|
||
|
inet_sk(newsk)->inet_sport = inet_rsk(req)->loc_port;
|
||
|
newsk->sk_write_space = sk_stream_write_space;
|
||
|
|
||
|
+ inet_sk(newsk)->mc_list = NULL;
|
||
|
+
|
||
|
newicsk->icsk_retransmits = 0;
|
||
|
newicsk->icsk_backoff = 0;
|
||
|
newicsk->icsk_probes_out = 0;
|
||
|
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
|
||
|
index f6603142cb33..3d009e174166 100644
|
||
|
--- a/net/ipv4/ip_sockglue.c
|
||
|
+++ b/net/ipv4/ip_sockglue.c
|
||
|
@@ -1042,7 +1042,14 @@ void ipv4_pktinfo_prepare(struct sk_buff *skb)
|
||
|
pktinfo->ipi_ifindex = 0;
|
||
|
pktinfo->ipi_spec_dst.s_addr = 0;
|
||
|
}
|
||
|
- skb_dst_drop(skb);
|
||
|
+ /* We need to keep the dst for __ip_options_echo()
|
||
|
+ * We could restrict the test to opt.ts_needtime || opt.srr,
|
||
|
+ * but the following is good enough as IP options are not often used.
|
||
|
+ */
|
||
|
+ if (unlikely(IPCB(skb)->opt.optlen))
|
||
|
+ skb_dst_force(skb);
|
||
|
+ else
|
||
|
+ skb_dst_drop(skb);
|
||
|
}
|
||
|
|
||
|
int ip_setsockopt(struct sock *sk, int level,
|
||
|
diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c
|
||
|
index 4ec34275160b..eadafac6f461 100644
|
||
|
--- a/net/ipv4/ip_vti.c
|
||
|
+++ b/net/ipv4/ip_vti.c
|
||
|
@@ -582,7 +582,6 @@ static void vti_tunnel_setup(struct net_device *dev)
|
||
|
dev->type = ARPHRD_TUNNEL;
|
||
|
dev->destructor = vti_dev_free;
|
||
|
|
||
|
- dev->hard_header_len = LL_MAX_HEADER + sizeof(struct iphdr);
|
||
|
dev->mtu = ETH_DATA_LEN;
|
||
|
dev->flags = IFF_NOARP;
|
||
|
dev->iflink = 0;
|
||
|
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
|
||
|
index 95a5f261fe8a..f8f0518772d6 100644
|
||
|
--- a/net/ipv4/netfilter/arp_tables.c
|
||
|
+++ b/net/ipv4/netfilter/arp_tables.c
|
||
|
@@ -1309,8 +1309,8 @@ static int translate_compat_table(struct xt_table_info **pinfo,
|
||
|
|
||
|
newinfo->number = compatr->num_entries;
|
||
|
for (i = 0; i < NF_ARP_NUMHOOKS; i++) {
|
||
|
- newinfo->hook_entry[i] = info->hook_entry[i];
|
||
|
- newinfo->underflow[i] = info->underflow[i];
|
||
|
+ newinfo->hook_entry[i] = compatr->hook_entry[i];
|
||
|
+ newinfo->underflow[i] = compatr->underflow[i];
|
||
|
}
|
||
|
entry1 = newinfo->entries[raw_smp_processor_id()];
|
||
|
pos = entry1;
|
||
|
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
|
||
|
index e59d6332458b..d9c791343638 100644
|
||
|
--- a/net/ipv4/route.c
|
||
|
+++ b/net/ipv4/route.c
|
||
|
@@ -1789,6 +1789,7 @@ int ip_route_input_noref(struct sk_buff *skb, __be32 daddr, __be32 saddr,
|
||
|
{
|
||
|
int res;
|
||
|
|
||
|
+ tos &= IPTOS_RT_MASK;
|
||
|
rcu_read_lock();
|
||
|
|
||
|
/* Multicast recognition logic is moved from route cache to here.
|
||
|
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
|
||
|
index 5d4bd6ca3ab1..d1e04221c275 100644
|
||
|
--- a/net/ipv4/tcp.c
|
||
|
+++ b/net/ipv4/tcp.c
|
||
|
@@ -723,6 +723,12 @@ ssize_t tcp_splice_read(struct socket *sock, loff_t *ppos,
|
||
|
ret = -EAGAIN;
|
||
|
break;
|
||
|
}
|
||
|
+ /* if __tcp_splice_read() got nothing while we have
|
||
|
+ * an skb in receive queue, we do not want to loop.
|
||
|
+ * This might happen with URG data.
|
||
|
+ */
|
||
|
+ if (!skb_queue_empty(&sk->sk_receive_queue))
|
||
|
+ break;
|
||
|
sk_wait_data(sk, &timeo);
|
||
|
if (signal_pending(current)) {
|
||
|
ret = sock_intr_errno(timeo);
|
||
|
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
|
||
|
index 6504a085ca60..195c618aba6c 100644
|
||
|
--- a/net/ipv4/tcp_ipv4.c
|
||
|
+++ b/net/ipv4/tcp_ipv4.c
|
||
|
@@ -389,7 +389,8 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
|
||
|
|
||
|
switch (type) {
|
||
|
case ICMP_REDIRECT:
|
||
|
- do_redirect(icmp_skb, sk);
|
||
|
+ if (!sock_owned_by_user(sk))
|
||
|
+ do_redirect(icmp_skb, sk);
|
||
|
goto out;
|
||
|
case ICMP_SOURCE_QUENCH:
|
||
|
/* Just silently ignore these. */
|
||
|
@@ -1422,6 +1423,7 @@ static int tcp_v4_conn_req_fastopen(struct sock *sk,
|
||
|
* scaled. So correct it appropriately.
|
||
|
*/
|
||
|
tp->snd_wnd = ntohs(tcp_hdr(skb)->window);
|
||
|
+ tp->max_window = tp->snd_wnd;
|
||
|
|
||
|
/* Activate the retrans timer so that SYNACK can be retransmitted.
|
||
|
* The request socket is not added to the SYN table of the parent
|
||
|
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
|
||
|
index 603f251b6ca2..ae88e17f5c72 100644
|
||
|
--- a/net/ipv6/ip6_gre.c
|
||
|
+++ b/net/ipv6/ip6_gre.c
|
||
|
@@ -55,6 +55,7 @@
|
||
|
#include <net/ip6_fib.h>
|
||
|
#include <net/ip6_route.h>
|
||
|
#include <net/ip6_tunnel.h>
|
||
|
+#include <net/gre.h>
|
||
|
|
||
|
|
||
|
static bool log_ecn_error = true;
|
||
|
@@ -365,35 +366,37 @@ static void ip6gre_tunnel_uninit(struct net_device *dev)
|
||
|
|
||
|
|
||
|
static void ip6gre_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
|
||
|
- u8 type, u8 code, int offset, __be32 info)
|
||
|
+ u8 type, u8 code, int offset, __be32 info)
|
||
|
{
|
||
|
- const struct ipv6hdr *ipv6h = (const struct ipv6hdr *)skb->data;
|
||
|
- __be16 *p = (__be16 *)(skb->data + offset);
|
||
|
- int grehlen = offset + 4;
|
||
|
+ const struct gre_base_hdr *greh;
|
||
|
+ const struct ipv6hdr *ipv6h;
|
||
|
+ int grehlen = sizeof(*greh);
|
||
|
struct ip6_tnl *t;
|
||
|
+ int key_off = 0;
|
||
|
__be16 flags;
|
||
|
+ __be32 key;
|
||
|
|
||
|
- flags = p[0];
|
||
|
- if (flags&(GRE_CSUM|GRE_KEY|GRE_SEQ|GRE_ROUTING|GRE_VERSION)) {
|
||
|
- if (flags&(GRE_VERSION|GRE_ROUTING))
|
||
|
- return;
|
||
|
- if (flags&GRE_KEY) {
|
||
|
- grehlen += 4;
|
||
|
- if (flags&GRE_CSUM)
|
||
|
- grehlen += 4;
|
||
|
- }
|
||
|
+ if (!pskb_may_pull(skb, offset + grehlen))
|
||
|
+ return;
|
||
|
+ greh = (const struct gre_base_hdr *)(skb->data + offset);
|
||
|
+ flags = greh->flags;
|
||
|
+ if (flags & (GRE_VERSION | GRE_ROUTING))
|
||
|
+ return;
|
||
|
+ if (flags & GRE_CSUM)
|
||
|
+ grehlen += 4;
|
||
|
+ if (flags & GRE_KEY) {
|
||
|
+ key_off = grehlen + offset;
|
||
|
+ grehlen += 4;
|
||
|
}
|
||
|
|
||
|
- /* If only 8 bytes returned, keyed message will be dropped here */
|
||
|
- if (!pskb_may_pull(skb, grehlen))
|
||
|
+ if (!pskb_may_pull(skb, offset + grehlen))
|
||
|
return;
|
||
|
ipv6h = (const struct ipv6hdr *)skb->data;
|
||
|
- p = (__be16 *)(skb->data + offset);
|
||
|
+ greh = (const struct gre_base_hdr *)(skb->data + offset);
|
||
|
+ key = key_off ? *(__be32 *)(skb->data + key_off) : 0;
|
||
|
|
||
|
t = ip6gre_tunnel_lookup(skb->dev, &ipv6h->daddr, &ipv6h->saddr,
|
||
|
- flags & GRE_KEY ?
|
||
|
- *(((__be32 *)p) + (grehlen / 4) - 1) : 0,
|
||
|
- p[1]);
|
||
|
+ key, greh->protocol);
|
||
|
if (t == NULL)
|
||
|
return;
|
||
|
|
||
|
diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c
|
||
|
index 71b766ee821d..88a2e8827ef7 100644
|
||
|
--- a/net/ipv6/ip6_offload.c
|
||
|
+++ b/net/ipv6/ip6_offload.c
|
||
|
@@ -174,6 +174,7 @@ static struct sk_buff **ipv6_gro_receive(struct sk_buff **head,
|
||
|
ops = rcu_dereference(inet6_offloads[proto]);
|
||
|
if (!ops || !ops->callbacks.gro_receive) {
|
||
|
__pskb_pull(skb, skb_gro_offset(skb));
|
||
|
+ skb_gro_frag0_invalidate(skb);
|
||
|
proto = ipv6_gso_pull_exthdrs(skb, proto);
|
||
|
skb_gro_pull(skb, -skb_transport_offset(skb));
|
||
|
skb_reset_transport_header(skb);
|
||
|
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
|
||
|
index 12984e6794b9..efc77acbe9e1 100644
|
||
|
--- a/net/ipv6/ip6_tunnel.c
|
||
|
+++ b/net/ipv6/ip6_tunnel.c
|
||
|
@@ -103,16 +103,25 @@ struct ip6_tnl_net {
|
||
|
|
||
|
static struct net_device_stats *ip6_get_stats(struct net_device *dev)
|
||
|
{
|
||
|
- struct pcpu_tstats sum = { 0 };
|
||
|
+ struct pcpu_tstats tmp, sum = { 0 };
|
||
|
int i;
|
||
|
|
||
|
for_each_possible_cpu(i) {
|
||
|
+ unsigned int start;
|
||
|
const struct pcpu_tstats *tstats = per_cpu_ptr(dev->tstats, i);
|
||
|
|
||
|
- sum.rx_packets += tstats->rx_packets;
|
||
|
- sum.rx_bytes += tstats->rx_bytes;
|
||
|
- sum.tx_packets += tstats->tx_packets;
|
||
|
- sum.tx_bytes += tstats->tx_bytes;
|
||
|
+ do {
|
||
|
+ start = u64_stats_fetch_begin_bh(&tstats->syncp);
|
||
|
+ tmp.rx_packets = tstats->rx_packets;
|
||
|
+ tmp.rx_bytes = tstats->rx_bytes;
|
||
|
+ tmp.tx_packets = tstats->tx_packets;
|
||
|
+ tmp.tx_bytes = tstats->tx_bytes;
|
||
|
+ } while (u64_stats_fetch_retry_bh(&tstats->syncp, start));
|
||
|
+
|
||
|
+ sum.rx_packets += tmp.rx_packets;
|
||
|
+ sum.rx_bytes += tmp.rx_bytes;
|
||
|
+ sum.tx_packets += tmp.tx_packets;
|
||
|
+ sum.tx_bytes += tmp.tx_bytes;
|
||
|
}
|
||
|
dev->stats.rx_packets = sum.rx_packets;
|
||
|
dev->stats.rx_bytes = sum.rx_bytes;
|
||
|
@@ -394,18 +403,19 @@ ip6_tnl_dev_uninit(struct net_device *dev)
|
||
|
|
||
|
__u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw)
|
||
|
{
|
||
|
- const struct ipv6hdr *ipv6h = (const struct ipv6hdr *) raw;
|
||
|
- __u8 nexthdr = ipv6h->nexthdr;
|
||
|
- __u16 off = sizeof (*ipv6h);
|
||
|
+ const struct ipv6hdr *ipv6h = (const struct ipv6hdr *)raw;
|
||
|
+ unsigned int nhoff = raw - skb->data;
|
||
|
+ unsigned int off = nhoff + sizeof(*ipv6h);
|
||
|
+ u8 next, nexthdr = ipv6h->nexthdr;
|
||
|
|
||
|
while (ipv6_ext_hdr(nexthdr) && nexthdr != NEXTHDR_NONE) {
|
||
|
- __u16 optlen = 0;
|
||
|
struct ipv6_opt_hdr *hdr;
|
||
|
- if (raw + off + sizeof (*hdr) > skb->data &&
|
||
|
- !pskb_may_pull(skb, raw - skb->data + off + sizeof (*hdr)))
|
||
|
+ u16 optlen;
|
||
|
+
|
||
|
+ if (!pskb_may_pull(skb, off + sizeof(*hdr)))
|
||
|
break;
|
||
|
|
||
|
- hdr = (struct ipv6_opt_hdr *) (raw + off);
|
||
|
+ hdr = (struct ipv6_opt_hdr *)(skb->data + off);
|
||
|
if (nexthdr == NEXTHDR_FRAGMENT) {
|
||
|
struct frag_hdr *frag_hdr = (struct frag_hdr *) hdr;
|
||
|
if (frag_hdr->frag_off)
|
||
|
@@ -416,20 +426,29 @@ __u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw)
|
||
|
} else {
|
||
|
optlen = ipv6_optlen(hdr);
|
||
|
}
|
||
|
+ /* cache hdr->nexthdr, since pskb_may_pull() might
|
||
|
+ * invalidate hdr
|
||
|
+ */
|
||
|
+ next = hdr->nexthdr;
|
||
|
if (nexthdr == NEXTHDR_DEST) {
|
||
|
- __u16 i = off + 2;
|
||
|
+ u16 i = 2;
|
||
|
+
|
||
|
+ /* Remember : hdr is no longer valid at this point. */
|
||
|
+ if (!pskb_may_pull(skb, off + optlen))
|
||
|
+ break;
|
||
|
+
|
||
|
while (1) {
|
||
|
struct ipv6_tlv_tnl_enc_lim *tel;
|
||
|
|
||
|
/* No more room for encapsulation limit */
|
||
|
- if (i + sizeof (*tel) > off + optlen)
|
||
|
+ if (i + sizeof(*tel) > optlen)
|
||
|
break;
|
||
|
|
||
|
- tel = (struct ipv6_tlv_tnl_enc_lim *) &raw[i];
|
||
|
+ tel = (struct ipv6_tlv_tnl_enc_lim *)(skb->data + off + i);
|
||
|
/* return index of option if found and valid */
|
||
|
if (tel->type == IPV6_TLV_TNL_ENCAP_LIMIT &&
|
||
|
tel->length == 1)
|
||
|
- return i;
|
||
|
+ return i + off - nhoff;
|
||
|
/* else jump to next option */
|
||
|
if (tel->type)
|
||
|
i += tel->length + 2;
|
||
|
@@ -437,7 +456,7 @@ __u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw)
|
||
|
i++;
|
||
|
}
|
||
|
}
|
||
|
- nexthdr = hdr->nexthdr;
|
||
|
+ nexthdr = next;
|
||
|
off += optlen;
|
||
|
}
|
||
|
return 0;
|
||
|
@@ -822,8 +841,10 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
|
||
|
}
|
||
|
|
||
|
tstats = this_cpu_ptr(t->dev->tstats);
|
||
|
+ u64_stats_update_begin(&tstats->syncp);
|
||
|
tstats->rx_packets++;
|
||
|
tstats->rx_bytes += skb->len;
|
||
|
+ u64_stats_update_end(&tstats->syncp);
|
||
|
|
||
|
netif_rx(skb);
|
||
|
|
||
|
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
|
||
|
index 464b1c9c08e4..989bd7987985 100644
|
||
|
--- a/net/ipv6/raw.c
|
||
|
+++ b/net/ipv6/raw.c
|
||
|
@@ -578,8 +578,11 @@ static int rawv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6,
|
||
|
}
|
||
|
|
||
|
offset += skb_transport_offset(skb);
|
||
|
- if (skb_copy_bits(skb, offset, &csum, 2))
|
||
|
- BUG();
|
||
|
+ err = skb_copy_bits(skb, offset, &csum, 2);
|
||
|
+ if (err < 0) {
|
||
|
+ ip6_flush_pending_frames(sk);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
|
||
|
/* in case cksum was not initialized */
|
||
|
if (unlikely(csum))
|
||
|
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
|
||
|
index 70b10ed169ae..ecbdc4b29f29 100644
|
||
|
--- a/net/ipv6/tcp_ipv6.c
|
||
|
+++ b/net/ipv6/tcp_ipv6.c
|
||
|
@@ -382,10 +382,12 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
|
||
|
np = inet6_sk(sk);
|
||
|
|
||
|
if (type == NDISC_REDIRECT) {
|
||
|
- struct dst_entry *dst = __sk_dst_check(sk, np->dst_cookie);
|
||
|
+ if (!sock_owned_by_user(sk)) {
|
||
|
+ struct dst_entry *dst = __sk_dst_check(sk, np->dst_cookie);
|
||
|
|
||
|
- if (dst)
|
||
|
- dst->ops->redirect(dst, sk, skb);
|
||
|
+ if (dst)
|
||
|
+ dst->ops->redirect(dst, sk, skb);
|
||
|
+ }
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
|
||
|
index 797ff373e486..787ac0ef1823 100644
|
||
|
--- a/net/l2tp/l2tp_core.c
|
||
|
+++ b/net/l2tp/l2tp_core.c
|
||
|
@@ -280,7 +280,8 @@ struct l2tp_session *l2tp_session_find(struct net *net, struct l2tp_tunnel *tunn
|
||
|
}
|
||
|
EXPORT_SYMBOL_GPL(l2tp_session_find);
|
||
|
|
||
|
-struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth)
|
||
|
+struct l2tp_session *l2tp_session_get_nth(struct l2tp_tunnel *tunnel, int nth,
|
||
|
+ bool do_ref)
|
||
|
{
|
||
|
int hash;
|
||
|
struct l2tp_session *session;
|
||
|
@@ -290,6 +291,9 @@ struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth)
|
||
|
for (hash = 0; hash < L2TP_HASH_SIZE; hash++) {
|
||
|
hlist_for_each_entry(session, &tunnel->session_hlist[hash], hlist) {
|
||
|
if (++count > nth) {
|
||
|
+ l2tp_session_inc_refcount(session);
|
||
|
+ if (do_ref && session->ref)
|
||
|
+ session->ref(session);
|
||
|
read_unlock_bh(&tunnel->hlist_lock);
|
||
|
return session;
|
||
|
}
|
||
|
@@ -300,7 +304,7 @@ struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth)
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
-EXPORT_SYMBOL_GPL(l2tp_session_find_nth);
|
||
|
+EXPORT_SYMBOL_GPL(l2tp_session_get_nth);
|
||
|
|
||
|
/* Lookup a session by interface name.
|
||
|
* This is very inefficient but is only used by management interfaces.
|
||
|
diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h
|
||
|
index 2f89d43877d7..54f89f38386e 100644
|
||
|
--- a/net/l2tp/l2tp_core.h
|
||
|
+++ b/net/l2tp/l2tp_core.h
|
||
|
@@ -236,7 +236,8 @@ out:
|
||
|
extern struct sock *l2tp_tunnel_sock_lookup(struct l2tp_tunnel *tunnel);
|
||
|
extern void l2tp_tunnel_sock_put(struct sock *sk);
|
||
|
extern struct l2tp_session *l2tp_session_find(struct net *net, struct l2tp_tunnel *tunnel, u32 session_id);
|
||
|
-extern struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth);
|
||
|
+extern struct l2tp_session *l2tp_session_get_nth(struct l2tp_tunnel *tunnel, int nth,
|
||
|
+ bool do_ref);
|
||
|
extern struct l2tp_session *l2tp_session_find_by_ifname(struct net *net, char *ifname);
|
||
|
extern struct l2tp_tunnel *l2tp_tunnel_find(struct net *net, u32 tunnel_id);
|
||
|
extern struct l2tp_tunnel *l2tp_tunnel_find_nth(struct net *net, int nth);
|
||
|
@@ -256,6 +257,7 @@ extern int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int
|
||
|
|
||
|
extern int l2tp_nl_register_ops(enum l2tp_pwtype pw_type, const struct l2tp_nl_cmd_ops *ops);
|
||
|
extern void l2tp_nl_unregister_ops(enum l2tp_pwtype pw_type);
|
||
|
+int l2tp_ioctl(struct sock *sk, int cmd, unsigned long arg);
|
||
|
|
||
|
/* Session reference counts. Incremented when code obtains a reference
|
||
|
* to a session.
|
||
|
diff --git a/net/l2tp/l2tp_debugfs.c b/net/l2tp/l2tp_debugfs.c
|
||
|
index 072d7202e182..c6bd783cfb1b 100644
|
||
|
--- a/net/l2tp/l2tp_debugfs.c
|
||
|
+++ b/net/l2tp/l2tp_debugfs.c
|
||
|
@@ -53,7 +53,7 @@ static void l2tp_dfs_next_tunnel(struct l2tp_dfs_seq_data *pd)
|
||
|
|
||
|
static void l2tp_dfs_next_session(struct l2tp_dfs_seq_data *pd)
|
||
|
{
|
||
|
- pd->session = l2tp_session_find_nth(pd->tunnel, pd->session_idx);
|
||
|
+ pd->session = l2tp_session_get_nth(pd->tunnel, pd->session_idx, true);
|
||
|
pd->session_idx++;
|
||
|
|
||
|
if (pd->session == NULL) {
|
||
|
@@ -237,10 +237,14 @@ static int l2tp_dfs_seq_show(struct seq_file *m, void *v)
|
||
|
}
|
||
|
|
||
|
/* Show the tunnel or session context */
|
||
|
- if (pd->session == NULL)
|
||
|
+ if (!pd->session) {
|
||
|
l2tp_dfs_seq_tunnel_show(m, pd->tunnel);
|
||
|
- else
|
||
|
+ } else {
|
||
|
l2tp_dfs_seq_session_show(m, pd->session);
|
||
|
+ if (pd->session->deref)
|
||
|
+ pd->session->deref(pd->session);
|
||
|
+ l2tp_session_dec_refcount(pd->session);
|
||
|
+ }
|
||
|
|
||
|
out:
|
||
|
return 0;
|
||
|
diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c
|
||
|
index 07f8b97f9ae9..f4d30b509cdf 100644
|
||
|
--- a/net/l2tp/l2tp_ip.c
|
||
|
+++ b/net/l2tp/l2tp_ip.c
|
||
|
@@ -11,6 +11,7 @@
|
||
|
|
||
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||
|
|
||
|
+#include <asm/ioctls.h>
|
||
|
#include <linux/icmp.h>
|
||
|
#include <linux/module.h>
|
||
|
#include <linux/skbuff.h>
|
||
|
@@ -554,6 +555,30 @@ out:
|
||
|
return err ? err : copied;
|
||
|
}
|
||
|
|
||
|
+int l2tp_ioctl(struct sock *sk, int cmd, unsigned long arg)
|
||
|
+{
|
||
|
+ struct sk_buff *skb;
|
||
|
+ int amount;
|
||
|
+
|
||
|
+ switch (cmd) {
|
||
|
+ case SIOCOUTQ:
|
||
|
+ amount = sk_wmem_alloc_get(sk);
|
||
|
+ break;
|
||
|
+ case SIOCINQ:
|
||
|
+ spin_lock_bh(&sk->sk_receive_queue.lock);
|
||
|
+ skb = skb_peek(&sk->sk_receive_queue);
|
||
|
+ amount = skb ? skb->len : 0;
|
||
|
+ spin_unlock_bh(&sk->sk_receive_queue.lock);
|
||
|
+ break;
|
||
|
+
|
||
|
+ default:
|
||
|
+ return -ENOIOCTLCMD;
|
||
|
+ }
|
||
|
+
|
||
|
+ return put_user(amount, (int __user *)arg);
|
||
|
+}
|
||
|
+EXPORT_SYMBOL(l2tp_ioctl);
|
||
|
+
|
||
|
static struct proto l2tp_ip_prot = {
|
||
|
.name = "L2TP/IP",
|
||
|
.owner = THIS_MODULE,
|
||
|
@@ -562,7 +587,7 @@ static struct proto l2tp_ip_prot = {
|
||
|
.bind = l2tp_ip_bind,
|
||
|
.connect = l2tp_ip_connect,
|
||
|
.disconnect = l2tp_ip_disconnect,
|
||
|
- .ioctl = udp_ioctl,
|
||
|
+ .ioctl = l2tp_ioctl,
|
||
|
.destroy = l2tp_ip_destroy_sock,
|
||
|
.setsockopt = ip_setsockopt,
|
||
|
.getsockopt = ip_getsockopt,
|
||
|
diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c
|
||
|
index db96af978da5..15367918413c 100644
|
||
|
--- a/net/l2tp/l2tp_ip6.c
|
||
|
+++ b/net/l2tp/l2tp_ip6.c
|
||
|
@@ -716,7 +716,7 @@ static struct proto l2tp_ip6_prot = {
|
||
|
.bind = l2tp_ip6_bind,
|
||
|
.connect = l2tp_ip6_connect,
|
||
|
.disconnect = l2tp_ip6_disconnect,
|
||
|
- .ioctl = udp_ioctl,
|
||
|
+ .ioctl = l2tp_ioctl,
|
||
|
.destroy = l2tp_ip6_destroy_sock,
|
||
|
.setsockopt = ipv6_setsockopt,
|
||
|
.getsockopt = ipv6_getsockopt,
|
||
|
diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c
|
||
|
index 0825ff26e113..490024eaece8 100644
|
||
|
--- a/net/l2tp/l2tp_netlink.c
|
||
|
+++ b/net/l2tp/l2tp_netlink.c
|
||
|
@@ -719,7 +719,7 @@ static int l2tp_nl_cmd_session_dump(struct sk_buff *skb, struct netlink_callback
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
- session = l2tp_session_find_nth(tunnel, si);
|
||
|
+ session = l2tp_session_get_nth(tunnel, si, false);
|
||
|
if (session == NULL) {
|
||
|
ti++;
|
||
|
tunnel = NULL;
|
||
|
@@ -729,8 +729,11 @@ static int l2tp_nl_cmd_session_dump(struct sk_buff *skb, struct netlink_callback
|
||
|
|
||
|
if (l2tp_nl_session_send(skb, NETLINK_CB(cb->skb).portid,
|
||
|
cb->nlh->nlmsg_seq, NLM_F_MULTI,
|
||
|
- session) <= 0)
|
||
|
+ session) <= 0) {
|
||
|
+ l2tp_session_dec_refcount(session);
|
||
|
break;
|
||
|
+ }
|
||
|
+ l2tp_session_dec_refcount(session);
|
||
|
|
||
|
si++;
|
||
|
}
|
||
|
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
|
||
|
index c3ae2411650c..c06c7ed47b69 100644
|
||
|
--- a/net/l2tp/l2tp_ppp.c
|
||
|
+++ b/net/l2tp/l2tp_ppp.c
|
||
|
@@ -1576,7 +1576,7 @@ static void pppol2tp_next_tunnel(struct net *net, struct pppol2tp_seq_data *pd)
|
||
|
|
||
|
static void pppol2tp_next_session(struct net *net, struct pppol2tp_seq_data *pd)
|
||
|
{
|
||
|
- pd->session = l2tp_session_find_nth(pd->tunnel, pd->session_idx);
|
||
|
+ pd->session = l2tp_session_get_nth(pd->tunnel, pd->session_idx, true);
|
||
|
pd->session_idx++;
|
||
|
|
||
|
if (pd->session == NULL) {
|
||
|
@@ -1703,10 +1703,14 @@ static int pppol2tp_seq_show(struct seq_file *m, void *v)
|
||
|
|
||
|
/* Show the tunnel or session context.
|
||
|
*/
|
||
|
- if (pd->session == NULL)
|
||
|
+ if (!pd->session) {
|
||
|
pppol2tp_seq_tunnel_show(m, pd->tunnel);
|
||
|
- else
|
||
|
+ } else {
|
||
|
pppol2tp_seq_session_show(m, pd->session);
|
||
|
+ if (pd->session->deref)
|
||
|
+ pd->session->deref(pd->session);
|
||
|
+ l2tp_session_dec_refcount(pd->session);
|
||
|
+ }
|
||
|
|
||
|
out:
|
||
|
return 0;
|
||
|
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
|
||
|
index f8765cc84e47..ddc63f92fa2a 100644
|
||
|
--- a/net/mac80211/mesh.c
|
||
|
+++ b/net/mac80211/mesh.c
|
||
|
@@ -345,7 +345,7 @@ int mesh_add_vendor_ies(struct ieee80211_sub_if_data *sdata,
|
||
|
/* fast-forward to vendor IEs */
|
||
|
offset = ieee80211_ie_split_vendor(ifmsh->ie, ifmsh->ie_len, 0);
|
||
|
|
||
|
- if (offset) {
|
||
|
+ if (offset < ifmsh->ie_len) {
|
||
|
len = ifmsh->ie_len - offset;
|
||
|
data = ifmsh->ie + offset;
|
||
|
if (skb_tailroom(skb) < len)
|
||
|
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
|
||
|
index 24f006623f7c..4b1734a14ff9 100644
|
||
|
--- a/net/packet/af_packet.c
|
||
|
+++ b/net/packet/af_packet.c
|
||
|
@@ -1257,6 +1257,8 @@ static void __fanout_link(struct sock *sk, struct packet_sock *po)
|
||
|
f->arr[f->num_members] = sk;
|
||
|
smp_wmb();
|
||
|
f->num_members++;
|
||
|
+ if (f->num_members == 1)
|
||
|
+ dev_add_pack(&f->prot_hook);
|
||
|
spin_unlock(&f->lock);
|
||
|
}
|
||
|
|
||
|
@@ -1273,6 +1275,8 @@ static void __fanout_unlink(struct sock *sk, struct packet_sock *po)
|
||
|
BUG_ON(i >= f->num_members);
|
||
|
f->arr[i] = f->arr[f->num_members - 1];
|
||
|
f->num_members--;
|
||
|
+ if (f->num_members == 0)
|
||
|
+ __dev_remove_pack(&f->prot_hook);
|
||
|
spin_unlock(&f->lock);
|
||
|
}
|
||
|
|
||
|
@@ -1304,13 +1308,16 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags)
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
+ mutex_lock(&fanout_mutex);
|
||
|
+
|
||
|
+ err = -EINVAL;
|
||
|
if (!po->running)
|
||
|
- return -EINVAL;
|
||
|
+ goto out;
|
||
|
|
||
|
+ err = -EALREADY;
|
||
|
if (po->fanout)
|
||
|
- return -EALREADY;
|
||
|
+ goto out;
|
||
|
|
||
|
- mutex_lock(&fanout_mutex);
|
||
|
match = NULL;
|
||
|
list_for_each_entry(f, &fanout_list, list) {
|
||
|
if (f->id == id &&
|
||
|
@@ -1340,7 +1347,6 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags)
|
||
|
match->prot_hook.func = packet_rcv_fanout;
|
||
|
match->prot_hook.af_packet_priv = match;
|
||
|
match->prot_hook.id_match = match_fanout_group;
|
||
|
- dev_add_pack(&match->prot_hook);
|
||
|
list_add(&match->list, &fanout_list);
|
||
|
}
|
||
|
err = -EINVAL;
|
||
|
@@ -1361,24 +1367,29 @@ out:
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
-static void fanout_release(struct sock *sk)
|
||
|
+/* If pkt_sk(sk)->fanout->sk_ref is zero, this function removes
|
||
|
+ * pkt_sk(sk)->fanout from fanout_list and returns pkt_sk(sk)->fanout.
|
||
|
+ * It is the responsibility of the caller to call fanout_release_data() and
|
||
|
+ * free the returned packet_fanout (after synchronize_net())
|
||
|
+ */
|
||
|
+static struct packet_fanout *fanout_release(struct sock *sk)
|
||
|
{
|
||
|
struct packet_sock *po = pkt_sk(sk);
|
||
|
struct packet_fanout *f;
|
||
|
|
||
|
- f = po->fanout;
|
||
|
- if (!f)
|
||
|
- return;
|
||
|
-
|
||
|
mutex_lock(&fanout_mutex);
|
||
|
- po->fanout = NULL;
|
||
|
+ f = po->fanout;
|
||
|
+ if (f) {
|
||
|
+ po->fanout = NULL;
|
||
|
|
||
|
- if (atomic_dec_and_test(&f->sk_ref)) {
|
||
|
- list_del(&f->list);
|
||
|
- dev_remove_pack(&f->prot_hook);
|
||
|
- kfree(f);
|
||
|
+ if (atomic_dec_and_test(&f->sk_ref))
|
||
|
+ list_del(&f->list);
|
||
|
+ else
|
||
|
+ f = NULL;
|
||
|
}
|
||
|
mutex_unlock(&fanout_mutex);
|
||
|
+
|
||
|
+ return f;
|
||
|
}
|
||
|
|
||
|
static const struct proto_ops packet_ops;
|
||
|
@@ -2428,6 +2439,7 @@ static int packet_release(struct socket *sock)
|
||
|
{
|
||
|
struct sock *sk = sock->sk;
|
||
|
struct packet_sock *po;
|
||
|
+ struct packet_fanout *f;
|
||
|
struct net *net;
|
||
|
union tpacket_req_u req_u;
|
||
|
|
||
|
@@ -2467,9 +2479,13 @@ static int packet_release(struct socket *sock)
|
||
|
packet_set_ring(sk, &req_u, 1, 1);
|
||
|
}
|
||
|
|
||
|
- fanout_release(sk);
|
||
|
+ f = fanout_release(sk);
|
||
|
|
||
|
synchronize_net();
|
||
|
+
|
||
|
+ if (f) {
|
||
|
+ kfree(f);
|
||
|
+ }
|
||
|
/*
|
||
|
* Now the socket is dead. No more input will appear.
|
||
|
*/
|
||
|
diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c
|
||
|
index 7c3de6ffa516..eba9d1e49faf 100644
|
||
|
--- a/net/sched/em_meta.c
|
||
|
+++ b/net/sched/em_meta.c
|
||
|
@@ -176,11 +176,12 @@ META_COLLECTOR(int_vlan_tag)
|
||
|
{
|
||
|
unsigned short tag;
|
||
|
|
||
|
- tag = vlan_tx_tag_get(skb);
|
||
|
- if (!tag && __vlan_get_tag(skb, &tag))
|
||
|
- *err = -1;
|
||
|
- else
|
||
|
+ if (vlan_tx_tag_present(skb))
|
||
|
+ dst->value = vlan_tx_tag_get(skb);
|
||
|
+ else if (!__vlan_get_tag(skb, &tag))
|
||
|
dst->value = tag;
|
||
|
+ else
|
||
|
+ *err = -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
|
||
|
index 6360a14edeab..59ab0c40e15c 100644
|
||
|
--- a/net/sctp/associola.c
|
||
|
+++ b/net/sctp/associola.c
|
||
|
@@ -1301,82 +1301,111 @@ void sctp_assoc_update(struct sctp_association *asoc,
|
||
|
}
|
||
|
|
||
|
/* Update the retran path for sending a retransmitted packet.
|
||
|
- * Round-robin through the active transports, else round-robin
|
||
|
- * through the inactive transports as this is the next best thing
|
||
|
- * we can try.
|
||
|
+ * See also RFC4960, 6.4. Multi-Homed SCTP Endpoints:
|
||
|
+ *
|
||
|
+ * When there is outbound data to send and the primary path
|
||
|
+ * becomes inactive (e.g., due to failures), or where the
|
||
|
+ * SCTP user explicitly requests to send data to an
|
||
|
+ * inactive destination transport address, before reporting
|
||
|
+ * an error to its ULP, the SCTP endpoint should try to send
|
||
|
+ * the data to an alternate active destination transport
|
||
|
+ * address if one exists.
|
||
|
+ *
|
||
|
+ * When retransmitting data that timed out, if the endpoint
|
||
|
+ * is multihomed, it should consider each source-destination
|
||
|
+ * address pair in its retransmission selection policy.
|
||
|
+ * When retransmitting timed-out data, the endpoint should
|
||
|
+ * attempt to pick the most divergent source-destination
|
||
|
+ * pair from the original source-destination pair to which
|
||
|
+ * the packet was transmitted.
|
||
|
+ *
|
||
|
+ * Note: Rules for picking the most divergent source-destination
|
||
|
+ * pair are an implementation decision and are not specified
|
||
|
+ * within this document.
|
||
|
+ *
|
||
|
+ * Our basic strategy is to round-robin transports in priorities
|
||
|
+ * according to sctp_state_prio_map[] e.g., if no such
|
||
|
+ * transport with state SCTP_ACTIVE exists, round-robin through
|
||
|
+ * SCTP_UNKNOWN, etc. You get the picture.
|
||
|
*/
|
||
|
-void sctp_assoc_update_retran_path(struct sctp_association *asoc)
|
||
|
+static const u8 sctp_trans_state_to_prio_map[] = {
|
||
|
+ [SCTP_ACTIVE] = 3, /* best case */
|
||
|
+ [SCTP_UNKNOWN] = 2,
|
||
|
+ [SCTP_PF] = 1,
|
||
|
+ [SCTP_INACTIVE] = 0, /* worst case */
|
||
|
+};
|
||
|
+
|
||
|
+static u8 sctp_trans_score(const struct sctp_transport *trans)
|
||
|
{
|
||
|
- struct sctp_transport *t, *next;
|
||
|
- struct list_head *head = &asoc->peer.transport_addr_list;
|
||
|
- struct list_head *pos;
|
||
|
+ return sctp_trans_state_to_prio_map[trans->state];
|
||
|
+}
|
||
|
|
||
|
- if (asoc->peer.transport_count == 1)
|
||
|
- return;
|
||
|
+static struct sctp_transport *sctp_trans_elect_best(struct sctp_transport *curr,
|
||
|
+ struct sctp_transport *best)
|
||
|
+{
|
||
|
+ if (best == NULL)
|
||
|
+ return curr;
|
||
|
|
||
|
- /* Find the next transport in a round-robin fashion. */
|
||
|
- t = asoc->peer.retran_path;
|
||
|
- pos = &t->transports;
|
||
|
- next = NULL;
|
||
|
+ return sctp_trans_score(curr) > sctp_trans_score(best) ? curr : best;
|
||
|
+}
|
||
|
|
||
|
- while (1) {
|
||
|
- /* Skip the head. */
|
||
|
- if (pos->next == head)
|
||
|
- pos = head->next;
|
||
|
- else
|
||
|
- pos = pos->next;
|
||
|
+void sctp_assoc_update_retran_path(struct sctp_association *asoc)
|
||
|
+{
|
||
|
+ struct sctp_transport *trans = asoc->peer.retran_path;
|
||
|
+ struct sctp_transport *trans_next = NULL;
|
||
|
|
||
|
- t = list_entry(pos, struct sctp_transport, transports);
|
||
|
+ /* We're done as we only have the one and only path. */
|
||
|
+ if (asoc->peer.transport_count == 1)
|
||
|
+ return;
|
||
|
+ /* If active_path and retran_path are the same and active,
|
||
|
+ * then this is the only active path. Use it.
|
||
|
+ */
|
||
|
+ if (asoc->peer.active_path == asoc->peer.retran_path &&
|
||
|
+ asoc->peer.active_path->state == SCTP_ACTIVE)
|
||
|
+ return;
|
||
|
|
||
|
- /* We have exhausted the list, but didn't find any
|
||
|
- * other active transports. If so, use the next
|
||
|
- * transport.
|
||
|
- */
|
||
|
- if (t == asoc->peer.retran_path) {
|
||
|
- t = next;
|
||
|
+ /* Iterate from retran_path's successor back to retran_path. */
|
||
|
+ for (trans = list_next_entry(trans, transports); 1;
|
||
|
+ trans = list_next_entry(trans, transports)) {
|
||
|
+ /* Manually skip the head element. */
|
||
|
+ if (&trans->transports == &asoc->peer.transport_addr_list)
|
||
|
+ continue;
|
||
|
+ if (trans->state == SCTP_UNCONFIRMED)
|
||
|
+ continue;
|
||
|
+ trans_next = sctp_trans_elect_best(trans, trans_next);
|
||
|
+ /* Active is good enough for immediate return. */
|
||
|
+ if (trans_next->state == SCTP_ACTIVE)
|
||
|
break;
|
||
|
- }
|
||
|
-
|
||
|
- /* Try to find an active transport. */
|
||
|
-
|
||
|
- if ((t->state == SCTP_ACTIVE) ||
|
||
|
- (t->state == SCTP_UNKNOWN)) {
|
||
|
+ /* We've reached the end, time to update path. */
|
||
|
+ if (trans == asoc->peer.retran_path)
|
||
|
break;
|
||
|
- } else {
|
||
|
- /* Keep track of the next transport in case
|
||
|
- * we don't find any active transport.
|
||
|
- */
|
||
|
- if (t->state != SCTP_UNCONFIRMED && !next)
|
||
|
- next = t;
|
||
|
- }
|
||
|
}
|
||
|
|
||
|
- if (t)
|
||
|
- asoc->peer.retran_path = t;
|
||
|
- else
|
||
|
- t = asoc->peer.retran_path;
|
||
|
+ if (trans_next != NULL)
|
||
|
+ asoc->peer.retran_path = trans_next;
|
||
|
|
||
|
SCTP_DEBUG_PRINTK_IPADDR("sctp_assoc_update_retran_path:association"
|
||
|
- " %p addr: ",
|
||
|
+ " %p updated new path to addr: ",
|
||
|
" port: %d\n",
|
||
|
asoc,
|
||
|
- (&t->ipaddr),
|
||
|
- ntohs(t->ipaddr.v4.sin_port));
|
||
|
+ (&asoc->peer.retran_path->ipaddr),
|
||
|
+ ntohs(asoc->peer.retran_path->ipaddr.v4.sin_port));
|
||
|
}
|
||
|
|
||
|
-/* Choose the transport for sending retransmit packet. */
|
||
|
-struct sctp_transport *sctp_assoc_choose_alter_transport(
|
||
|
- struct sctp_association *asoc, struct sctp_transport *last_sent_to)
|
||
|
+struct sctp_transport *
|
||
|
+sctp_assoc_choose_alter_transport(struct sctp_association *asoc,
|
||
|
+ struct sctp_transport *last_sent_to)
|
||
|
{
|
||
|
/* If this is the first time packet is sent, use the active path,
|
||
|
* else use the retran path. If the last packet was sent over the
|
||
|
* retran path, update the retran path and use it.
|
||
|
*/
|
||
|
- if (!last_sent_to)
|
||
|
+ if (last_sent_to == NULL) {
|
||
|
return asoc->peer.active_path;
|
||
|
- else {
|
||
|
+ } else {
|
||
|
if (last_sent_to == asoc->peer.retran_path)
|
||
|
sctp_assoc_update_retran_path(asoc);
|
||
|
+
|
||
|
return asoc->peer.retran_path;
|
||
|
}
|
||
|
}
|
||
|
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
|
||
|
index ede7c540ea24..4178cf387d21 100644
|
||
|
--- a/net/sctp/socket.c
|
||
|
+++ b/net/sctp/socket.c
|
||
|
@@ -4310,6 +4310,12 @@ int sctp_do_peeloff(struct sock *sk, sctp_assoc_t id, struct socket **sockp)
|
||
|
if (!asoc)
|
||
|
return -EINVAL;
|
||
|
|
||
|
+ /* If there is a thread waiting on more sndbuf space for
|
||
|
+ * sending on this asoc, it cannot be peeled.
|
||
|
+ */
|
||
|
+ if (waitqueue_active(&asoc->wait))
|
||
|
+ return -EBUSY;
|
||
|
+
|
||
|
/* An association cannot be branched off from an already peeled-off
|
||
|
* socket, nor is this supported for tcp style sockets.
|
||
|
*/
|
||
|
@@ -6724,7 +6730,6 @@ static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p,
|
||
|
*/
|
||
|
sctp_release_sock(sk);
|
||
|
current_timeo = schedule_timeout(current_timeo);
|
||
|
- BUG_ON(sk != asoc->base.sk);
|
||
|
sctp_lock_sock(sk);
|
||
|
|
||
|
*timeo_p = current_timeo;
|
||
|
diff --git a/net/socket.c b/net/socket.c
|
||
|
index e91e8ed1b8df..773ba3abb10b 100644
|
||
|
--- a/net/socket.c
|
||
|
+++ b/net/socket.c
|
||
|
@@ -2326,8 +2326,10 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
|
||
|
return err;
|
||
|
|
||
|
err = sock_error(sock->sk);
|
||
|
- if (err)
|
||
|
+ if (err) {
|
||
|
+ datagrams = err;
|
||
|
goto out_put;
|
||
|
+ }
|
||
|
|
||
|
entry = mmsg;
|
||
|
compat_entry = (struct compat_mmsghdr __user *)mmsg;
|
||
|
diff --git a/net/sunrpc/auth_gss/gss_rpc_xdr.c b/net/sunrpc/auth_gss/gss_rpc_xdr.c
|
||
|
index e0062c544ac8..a9ca70579eb9 100644
|
||
|
--- a/net/sunrpc/auth_gss/gss_rpc_xdr.c
|
||
|
+++ b/net/sunrpc/auth_gss/gss_rpc_xdr.c
|
||
|
@@ -260,7 +260,7 @@ static int gssx_dec_option_array(struct xdr_stream *xdr,
|
||
|
if (!oa->data)
|
||
|
return -ENOMEM;
|
||
|
|
||
|
- creds = kmalloc(sizeof(struct svc_cred), GFP_KERNEL);
|
||
|
+ creds = kzalloc(sizeof(struct svc_cred), GFP_KERNEL);
|
||
|
if (!creds) {
|
||
|
kfree(oa->data);
|
||
|
return -ENOMEM;
|
||
|
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
|
||
|
index 62663a08ffbd..e625efe0e035 100644
|
||
|
--- a/net/sunrpc/auth_gss/svcauth_gss.c
|
||
|
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
|
||
|
@@ -1518,7 +1518,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
|
||
|
case RPC_GSS_PROC_DESTROY:
|
||
|
if (gss_write_verf(rqstp, rsci->mechctx, gc->gc_seq))
|
||
|
goto auth_err;
|
||
|
- rsci->h.expiry_time = get_seconds();
|
||
|
+ rsci->h.expiry_time = seconds_since_boot();
|
||
|
set_bit(CACHE_NEGATIVE, &rsci->h.flags);
|
||
|
if (resv->iov_len + 4 > PAGE_SIZE)
|
||
|
goto drop;
|
||
|
diff --git a/net/unix/garbage.c b/net/unix/garbage.c
|
||
|
index a72182d6750f..58ba0e5f147b 100644
|
||
|
--- a/net/unix/garbage.c
|
||
|
+++ b/net/unix/garbage.c
|
||
|
@@ -152,6 +152,7 @@ void unix_notinflight(struct user_struct *user, struct file *fp)
|
||
|
if (s) {
|
||
|
struct unix_sock *u = unix_sk(s);
|
||
|
|
||
|
+ BUG_ON(!atomic_long_read(&u->inflight));
|
||
|
BUG_ON(list_empty(&u->link));
|
||
|
if (atomic_long_dec_and_test(&u->inflight))
|
||
|
list_del_init(&u->link);
|
||
|
@@ -358,6 +359,14 @@ void unix_gc(void)
|
||
|
}
|
||
|
list_del(&cursor);
|
||
|
|
||
|
+ /* Now gc_candidates contains only garbage. Restore original
|
||
|
+ * inflight counters for these as well, and remove the skbuffs
|
||
|
+ * which are creating the cycle(s).
|
||
|
+ */
|
||
|
+ skb_queue_head_init(&hitlist);
|
||
|
+ list_for_each_entry(u, &gc_candidates, link)
|
||
|
+ scan_children(&u->sk, inc_inflight, &hitlist);
|
||
|
+
|
||
|
/*
|
||
|
* not_cycle_list contains those sockets which do not make up a
|
||
|
* cycle. Restore these to the inflight list.
|
||
|
@@ -368,15 +377,6 @@ void unix_gc(void)
|
||
|
list_move_tail(&u->link, &gc_inflight_list);
|
||
|
}
|
||
|
|
||
|
- /*
|
||
|
- * Now gc_candidates contains only garbage. Restore original
|
||
|
- * inflight counters for these as well, and remove the skbuffs
|
||
|
- * which are creating the cycle(s).
|
||
|
- */
|
||
|
- skb_queue_head_init(&hitlist);
|
||
|
- list_for_each_entry(u, &gc_candidates, link)
|
||
|
- scan_children(&u->sk, inc_inflight, &hitlist);
|
||
|
-
|
||
|
spin_unlock(&unix_gc_lock);
|
||
|
|
||
|
/* Here we are. Hitlist is filled. Die. */
|
||
|
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
|
||
|
index 7a70a5a5671a..91a6a2903e8d 100644
|
||
|
--- a/net/xfrm/xfrm_user.c
|
||
|
+++ b/net/xfrm/xfrm_user.c
|
||
|
@@ -390,7 +390,14 @@ static inline int xfrm_replay_verify_len(struct xfrm_replay_state_esn *replay_es
|
||
|
up = nla_data(rp);
|
||
|
ulen = xfrm_replay_state_esn_len(up);
|
||
|
|
||
|
- if (nla_len(rp) < ulen || xfrm_replay_state_esn_len(replay_esn) != ulen)
|
||
|
+ /* Check the overall length and the internal bitmap length to avoid
|
||
|
+ * potential overflow. */
|
||
|
+ if (nla_len(rp) < ulen ||
|
||
|
+ xfrm_replay_state_esn_len(replay_esn) != ulen ||
|
||
|
+ replay_esn->bmp_len != up->bmp_len)
|
||
|
+ return -EINVAL;
|
||
|
+
|
||
|
+ if (up->replay_window > up->bmp_len * sizeof(__u32) * 8)
|
||
|
return -EINVAL;
|
||
|
|
||
|
return 0;
|
||
|
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
|
||
|
index b980a6ce5c79..3db2bf1f0a6c 100644
|
||
|
--- a/security/integrity/evm/evm_main.c
|
||
|
+++ b/security/integrity/evm/evm_main.c
|
||
|
@@ -20,6 +20,7 @@
|
||
|
#include <linux/integrity.h>
|
||
|
#include <linux/evm.h>
|
||
|
#include <crypto/hash.h>
|
||
|
+#include <crypto/algapi.h>
|
||
|
#include "evm.h"
|
||
|
|
||
|
int evm_initialized;
|
||
|
@@ -128,7 +129,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
|
||
|
xattr_value_len, calc.digest);
|
||
|
if (rc)
|
||
|
break;
|
||
|
- rc = memcmp(xattr_data->digest, calc.digest,
|
||
|
+ rc = crypto_memneq(xattr_data->digest, calc.digest,
|
||
|
sizeof(calc.digest));
|
||
|
if (rc)
|
||
|
rc = -EINVAL;
|
||
|
diff --git a/security/keys/gc.c b/security/keys/gc.c
|
||
|
index de34c290bd6f..2e01e23295aa 100644
|
||
|
--- a/security/keys/gc.c
|
||
|
+++ b/security/keys/gc.c
|
||
|
@@ -46,7 +46,7 @@ static unsigned long key_gc_flags;
|
||
|
* immediately unlinked.
|
||
|
*/
|
||
|
struct key_type key_type_dead = {
|
||
|
- .name = "dead",
|
||
|
+ .name = ".dead",
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
|
||
|
index 3242195bfa95..066baa1926bb 100644
|
||
|
--- a/security/keys/keyctl.c
|
||
|
+++ b/security/keys/keyctl.c
|
||
|
@@ -271,7 +271,8 @@ error:
|
||
|
* Create and join an anonymous session keyring or join a named session
|
||
|
* keyring, creating it if necessary. A named session keyring must have Search
|
||
|
* permission for it to be joined. Session keyrings without this permit will
|
||
|
- * be skipped over.
|
||
|
+ * be skipped over. It is not permitted for userspace to create or join
|
||
|
+ * keyrings whose name begin with a dot.
|
||
|
*
|
||
|
* If successful, the ID of the joined session keyring will be returned.
|
||
|
*/
|
||
|
@@ -288,12 +289,16 @@ long keyctl_join_session_keyring(const char __user *_name)
|
||
|
ret = PTR_ERR(name);
|
||
|
goto error;
|
||
|
}
|
||
|
+
|
||
|
+ ret = -EPERM;
|
||
|
+ if (name[0] == '.')
|
||
|
+ goto error_name;
|
||
|
}
|
||
|
|
||
|
/* join the session */
|
||
|
ret = join_session_keyring(name);
|
||
|
+error_name:
|
||
|
kfree(name);
|
||
|
-
|
||
|
error:
|
||
|
return ret;
|
||
|
}
|
||
|
@@ -1240,8 +1245,8 @@ error:
|
||
|
* Read or set the default keyring in which request_key() will cache keys and
|
||
|
* return the old setting.
|
||
|
*
|
||
|
- * If a process keyring is specified then this will be created if it doesn't
|
||
|
- * yet exist. The old setting will be returned if successful.
|
||
|
+ * If a thread or process keyring is specified then it will be created if it
|
||
|
+ * doesn't yet exist. The old setting will be returned if successful.
|
||
|
*/
|
||
|
long keyctl_set_reqkey_keyring(int reqkey_defl)
|
||
|
{
|
||
|
@@ -1266,11 +1271,8 @@ long keyctl_set_reqkey_keyring(int reqkey_defl)
|
||
|
|
||
|
case KEY_REQKEY_DEFL_PROCESS_KEYRING:
|
||
|
ret = install_process_keyring_to_cred(new);
|
||
|
- if (ret < 0) {
|
||
|
- if (ret != -EEXIST)
|
||
|
- goto error;
|
||
|
- ret = 0;
|
||
|
- }
|
||
|
+ if (ret < 0)
|
||
|
+ goto error;
|
||
|
goto set;
|
||
|
|
||
|
case KEY_REQKEY_DEFL_DEFAULT:
|
||
|
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
|
||
|
index cd871dc8b7c0..33384662fc82 100644
|
||
|
--- a/security/keys/process_keys.c
|
||
|
+++ b/security/keys/process_keys.c
|
||
|
@@ -125,13 +125,18 @@ error:
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
- * Install a fresh thread keyring directly to new credentials. This keyring is
|
||
|
- * allowed to overrun the quota.
|
||
|
+ * Install a thread keyring to the given credentials struct if it didn't have
|
||
|
+ * one already. This is allowed to overrun the quota.
|
||
|
+ *
|
||
|
+ * Return: 0 if a thread keyring is now present; -errno on failure.
|
||
|
*/
|
||
|
int install_thread_keyring_to_cred(struct cred *new)
|
||
|
{
|
||
|
struct key *keyring;
|
||
|
|
||
|
+ if (new->thread_keyring)
|
||
|
+ return 0;
|
||
|
+
|
||
|
keyring = keyring_alloc("_tid", new->uid, new->gid, new,
|
||
|
KEY_POS_ALL | KEY_USR_VIEW,
|
||
|
KEY_ALLOC_QUOTA_OVERRUN, NULL);
|
||
|
@@ -143,7 +148,9 @@ int install_thread_keyring_to_cred(struct cred *new)
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
- * Install a fresh thread keyring, discarding the old one.
|
||
|
+ * Install a thread keyring to the current task if it didn't have one already.
|
||
|
+ *
|
||
|
+ * Return: 0 if a thread keyring is now present; -errno on failure.
|
||
|
*/
|
||
|
static int install_thread_keyring(void)
|
||
|
{
|
||
|
@@ -154,8 +161,6 @@ static int install_thread_keyring(void)
|
||
|
if (!new)
|
||
|
return -ENOMEM;
|
||
|
|
||
|
- BUG_ON(new->thread_keyring);
|
||
|
-
|
||
|
ret = install_thread_keyring_to_cred(new);
|
||
|
if (ret < 0) {
|
||
|
abort_creds(new);
|
||
|
@@ -166,17 +171,17 @@ static int install_thread_keyring(void)
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
- * Install a process keyring directly to a credentials struct.
|
||
|
+ * Install a process keyring to the given credentials struct if it didn't have
|
||
|
+ * one already. This is allowed to overrun the quota.
|
||
|
*
|
||
|
- * Returns -EEXIST if there was already a process keyring, 0 if one installed,
|
||
|
- * and other value on any other error
|
||
|
+ * Return: 0 if a process keyring is now present; -errno on failure.
|
||
|
*/
|
||
|
int install_process_keyring_to_cred(struct cred *new)
|
||
|
{
|
||
|
struct key *keyring;
|
||
|
|
||
|
if (new->process_keyring)
|
||
|
- return -EEXIST;
|
||
|
+ return 0;
|
||
|
|
||
|
keyring = keyring_alloc("_pid", new->uid, new->gid, new,
|
||
|
KEY_POS_ALL | KEY_USR_VIEW,
|
||
|
@@ -189,11 +194,9 @@ int install_process_keyring_to_cred(struct cred *new)
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
- * Make sure a process keyring is installed for the current process. The
|
||
|
- * existing process keyring is not replaced.
|
||
|
+ * Install a process keyring to the current task if it didn't have one already.
|
||
|
*
|
||
|
- * Returns 0 if there is a process keyring by the end of this function, some
|
||
|
- * error otherwise.
|
||
|
+ * Return: 0 if a process keyring is now present; -errno on failure.
|
||
|
*/
|
||
|
static int install_process_keyring(void)
|
||
|
{
|
||
|
@@ -207,14 +210,18 @@ static int install_process_keyring(void)
|
||
|
ret = install_process_keyring_to_cred(new);
|
||
|
if (ret < 0) {
|
||
|
abort_creds(new);
|
||
|
- return ret != -EEXIST ? ret : 0;
|
||
|
+ return ret;
|
||
|
}
|
||
|
|
||
|
return commit_creds(new);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
- * Install a session keyring directly to a credentials struct.
|
||
|
+ * Install the given keyring as the session keyring of the given credentials
|
||
|
+ * struct, replacing the existing one if any. If the given keyring is NULL,
|
||
|
+ * then install a new anonymous session keyring.
|
||
|
+ *
|
||
|
+ * Return: 0 on success; -errno on failure.
|
||
|
*/
|
||
|
int install_session_keyring_to_cred(struct cred *cred, struct key *keyring)
|
||
|
{
|
||
|
@@ -249,8 +256,11 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring)
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
- * Install a session keyring, discarding the old one. If a keyring is not
|
||
|
- * supplied, an empty one is invented.
|
||
|
+ * Install the given keyring as the session keyring of the current task,
|
||
|
+ * replacing the existing one if any. If the given keyring is NULL, then
|
||
|
+ * install a new anonymous session keyring.
|
||
|
+ *
|
||
|
+ * Return: 0 on success; -errno on failure.
|
||
|
*/
|
||
|
static int install_session_keyring(struct key *keyring)
|
||
|
{
|
||
|
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
|
||
|
index fdd6e4f8be39..c08d4a10b07e 100644
|
||
|
--- a/security/selinux/hooks.c
|
||
|
+++ b/security/selinux/hooks.c
|
||
|
@@ -5442,7 +5442,7 @@ static int selinux_setprocattr(struct task_struct *p,
|
||
|
return error;
|
||
|
|
||
|
/* Obtain a SID for the context, if one was specified. */
|
||
|
- if (size && str[1] && str[1] != '\n') {
|
||
|
+ if (size && str[0] && str[0] != '\n') {
|
||
|
if (str[size-1] == '\n') {
|
||
|
str[size-1] = 0;
|
||
|
size--;
|
||
|
diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c
|
||
|
index 6ac40beb49da..7f414b05644b 100644
|
||
|
--- a/sound/pci/ctxfi/cthw20k1.c
|
||
|
+++ b/sound/pci/ctxfi/cthw20k1.c
|
||
|
@@ -27,12 +27,6 @@
|
||
|
#include "cthw20k1.h"
|
||
|
#include "ct20k1reg.h"
|
||
|
|
||
|
-#if BITS_PER_LONG == 32
|
||
|
-#define CT_XFI_DMA_MASK DMA_BIT_MASK(32) /* 32 bit PTE */
|
||
|
-#else
|
||
|
-#define CT_XFI_DMA_MASK DMA_BIT_MASK(64) /* 64 bit PTE */
|
||
|
-#endif
|
||
|
-
|
||
|
struct hw20k1 {
|
||
|
struct hw hw;
|
||
|
spinlock_t reg_20k1_lock;
|
||
|
@@ -1903,19 +1897,18 @@ static int hw_card_start(struct hw *hw)
|
||
|
{
|
||
|
int err;
|
||
|
struct pci_dev *pci = hw->pci;
|
||
|
+ const unsigned int dma_bits = BITS_PER_LONG;
|
||
|
|
||
|
err = pci_enable_device(pci);
|
||
|
if (err < 0)
|
||
|
return err;
|
||
|
|
||
|
/* Set DMA transfer mask */
|
||
|
- if (pci_set_dma_mask(pci, CT_XFI_DMA_MASK) < 0 ||
|
||
|
- pci_set_consistent_dma_mask(pci, CT_XFI_DMA_MASK) < 0) {
|
||
|
- printk(KERN_ERR "architecture does not support PCI "
|
||
|
- "busmaster DMA with mask 0x%llx\n",
|
||
|
- CT_XFI_DMA_MASK);
|
||
|
- err = -ENXIO;
|
||
|
- goto error1;
|
||
|
+ if (!dma_set_mask(&pci->dev, DMA_BIT_MASK(dma_bits))) {
|
||
|
+ dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(dma_bits));
|
||
|
+ } else {
|
||
|
+ dma_set_mask(&pci->dev, DMA_BIT_MASK(32));
|
||
|
+ dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(32));
|
||
|
}
|
||
|
|
||
|
if (!hw->io_base) {
|
||
|
diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c
|
||
|
index b1438861d38a..5828a3ec58bb 100644
|
||
|
--- a/sound/pci/ctxfi/cthw20k2.c
|
||
|
+++ b/sound/pci/ctxfi/cthw20k2.c
|
||
|
@@ -26,12 +26,6 @@
|
||
|
#include "cthw20k2.h"
|
||
|
#include "ct20k2reg.h"
|
||
|
|
||
|
-#if BITS_PER_LONG == 32
|
||
|
-#define CT_XFI_DMA_MASK DMA_BIT_MASK(32) /* 32 bit PTE */
|
||
|
-#else
|
||
|
-#define CT_XFI_DMA_MASK DMA_BIT_MASK(64) /* 64 bit PTE */
|
||
|
-#endif
|
||
|
-
|
||
|
struct hw20k2 {
|
||
|
struct hw hw;
|
||
|
/* for i2c */
|
||
|
@@ -2026,18 +2020,18 @@ static int hw_card_start(struct hw *hw)
|
||
|
int err = 0;
|
||
|
struct pci_dev *pci = hw->pci;
|
||
|
unsigned int gctl;
|
||
|
+ const unsigned int dma_bits = BITS_PER_LONG;
|
||
|
|
||
|
err = pci_enable_device(pci);
|
||
|
if (err < 0)
|
||
|
return err;
|
||
|
|
||
|
/* Set DMA transfer mask */
|
||
|
- if (pci_set_dma_mask(pci, CT_XFI_DMA_MASK) < 0 ||
|
||
|
- pci_set_consistent_dma_mask(pci, CT_XFI_DMA_MASK) < 0) {
|
||
|
- printk(KERN_ERR "ctxfi: architecture does not support PCI "
|
||
|
- "busmaster DMA with mask 0x%llx\n", CT_XFI_DMA_MASK);
|
||
|
- err = -ENXIO;
|
||
|
- goto error1;
|
||
|
+ if (!dma_set_mask(&pci->dev, DMA_BIT_MASK(dma_bits))) {
|
||
|
+ dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(dma_bits));
|
||
|
+ } else {
|
||
|
+ dma_set_mask(&pci->dev, DMA_BIT_MASK(32));
|
||
|
+ dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(32));
|
||
|
}
|
||
|
|
||
|
if (!hw->io_base) {
|
||
|
diff --git a/sound/usb/card.c b/sound/usb/card.c
|
||
|
index 64952e2d3ed1..7344ac083263 100644
|
||
|
--- a/sound/usb/card.c
|
||
|
+++ b/sound/usb/card.c
|
||
|
@@ -205,7 +205,6 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int
|
||
|
if (! snd_usb_parse_audio_interface(chip, interface)) {
|
||
|
usb_set_interface(dev, interface, 0); /* reset the current interface */
|
||
|
usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L);
|
||
|
- return -EINVAL;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
|
||
|
index ab3ed4af1466..9f2afbd33702 100644
|
||
|
--- a/tools/perf/builtin-trace.c
|
||
|
+++ b/tools/perf/builtin-trace.c
|
||
|
@@ -330,7 +330,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
|
||
|
|
||
|
if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
|
||
|
if (!trace->duration_filter) {
|
||
|
- trace__fprintf_entry_head(trace, thread, 1, sample->time, stdout);
|
||
|
+ trace__fprintf_entry_head(trace, thread, 1, ttrace->entry_time, stdout);
|
||
|
printf("%-70s\n", ttrace->entry_str);
|
||
|
}
|
||
|
} else
|
||
|
@@ -364,7 +364,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
|
||
|
} else if (trace->duration_filter)
|
||
|
goto out;
|
||
|
|
||
|
- trace__fprintf_entry_head(trace, thread, duration, sample->time, stdout);
|
||
|
+ trace__fprintf_entry_head(trace, thread, duration, ttrace->entry_time, stdout);
|
||
|
|
||
|
if (ttrace->entry_pending) {
|
||
|
printf("%-70s", ttrace->entry_str);
|
||
|
diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c
|
||
|
index 8715a1006d00..ae061a45fa04 100644
|
||
|
--- a/tools/perf/util/trace-event-scripting.c
|
||
|
+++ b/tools/perf/util/trace-event-scripting.c
|
||
|
@@ -90,7 +90,8 @@ static void register_python_scripting(struct scripting_ops *scripting_ops)
|
||
|
if (err)
|
||
|
die("error registering py script extension");
|
||
|
|
||
|
- scripting_context = malloc(sizeof(struct scripting_context));
|
||
|
+ if (scripting_context == NULL)
|
||
|
+ scripting_context = malloc(sizeof(*scripting_context));
|
||
|
}
|
||
|
|
||
|
#ifdef NO_LIBPYTHON
|
||
|
@@ -153,7 +154,8 @@ static void register_perl_scripting(struct scripting_ops *scripting_ops)
|
||
|
if (err)
|
||
|
die("error registering pl script extension");
|
||
|
|
||
|
- scripting_context = malloc(sizeof(struct scripting_context));
|
||
|
+ if (scripting_context == NULL)
|
||
|
+ scripting_context = malloc(sizeof(*scripting_context));
|
||
|
}
|
||
|
|
||
|
#ifdef NO_LIBPERL
|
||
|
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
|
||
|
index 0d7fd8b51544..a0a8314df4b9 100755
|
||
|
--- a/tools/testing/ktest/ktest.pl
|
||
|
+++ b/tools/testing/ktest/ktest.pl
|
||
|
@@ -2375,7 +2375,7 @@ sub do_run_test {
|
||
|
}
|
||
|
|
||
|
waitpid $child_pid, 0;
|
||
|
- $child_exit = $?;
|
||
|
+ $child_exit = $? >> 8;
|
||
|
|
||
|
if (!$bug && $in_bisect) {
|
||
|
if (defined($bisect_ret_good)) {
|
||
|
diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c
|
||
|
index 64ee720b75c7..362908c5f6c3 100644
|
||
|
--- a/virt/kvm/eventfd.c
|
||
|
+++ b/virt/kvm/eventfd.c
|
||
|
@@ -753,6 +753,7 @@ kvm_assign_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args)
|
||
|
if (ret < 0)
|
||
|
goto unlock_fail;
|
||
|
|
||
|
+ kvm->buses[bus_idx]->ioeventfd_count++;
|
||
|
list_add_tail(&p->list, &kvm->ioeventfds);
|
||
|
|
||
|
mutex_unlock(&kvm->slots_lock);
|
||
|
@@ -798,6 +799,8 @@ kvm_deassign_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args)
|
||
|
continue;
|
||
|
|
||
|
kvm_io_bus_unregister_dev(kvm, bus_idx, &p->dev);
|
||
|
+ if (kvm->buses[bus_idx])
|
||
|
+ kvm->buses[bus_idx]->ioeventfd_count--;
|
||
|
ioeventfd_release(p);
|
||
|
ret = 0;
|
||
|
break;
|
||
|
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
|
||
|
index f71c4ad425c6..0715673b6965 100644
|
||
|
--- a/virt/kvm/kvm_main.c
|
||
|
+++ b/virt/kvm/kvm_main.c
|
||
|
@@ -607,8 +607,11 @@ static void kvm_destroy_vm(struct kvm *kvm)
|
||
|
list_del(&kvm->vm_list);
|
||
|
raw_spin_unlock(&kvm_lock);
|
||
|
kvm_free_irq_routing(kvm);
|
||
|
- for (i = 0; i < KVM_NR_BUSES; i++)
|
||
|
- kvm_io_bus_destroy(kvm->buses[i]);
|
||
|
+ for (i = 0; i < KVM_NR_BUSES; i++) {
|
||
|
+ if (kvm->buses[i])
|
||
|
+ kvm_io_bus_destroy(kvm->buses[i]);
|
||
|
+ kvm->buses[i] = NULL;
|
||
|
+ }
|
||
|
kvm_coalesced_mmio_free(kvm);
|
||
|
#if defined(CONFIG_MMU_NOTIFIER) && defined(KVM_ARCH_WANT_MMU_NOTIFIER)
|
||
|
mmu_notifier_unregister(&kvm->mmu_notifier, kvm->mm);
|
||
|
@@ -2885,6 +2888,8 @@ int kvm_io_bus_write(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
|
||
|
};
|
||
|
|
||
|
bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu);
|
||
|
+ if (!bus)
|
||
|
+ return -ENOMEM;
|
||
|
idx = kvm_io_bus_get_first_dev(bus, addr, len);
|
||
|
if (idx < 0)
|
||
|
return -EOPNOTSUPP;
|
||
|
@@ -2913,6 +2918,8 @@ int kvm_io_bus_read(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
|
||
|
};
|
||
|
|
||
|
bus = srcu_dereference(kvm->buses[bus_idx], &kvm->srcu);
|
||
|
+ if (!bus)
|
||
|
+ return -ENOMEM;
|
||
|
idx = kvm_io_bus_get_first_dev(bus, addr, len);
|
||
|
if (idx < 0)
|
||
|
return -EOPNOTSUPP;
|
||
|
@@ -2934,7 +2941,11 @@ int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
|
||
|
struct kvm_io_bus *new_bus, *bus;
|
||
|
|
||
|
bus = kvm->buses[bus_idx];
|
||
|
- if (bus->dev_count > NR_IOBUS_DEVS - 1)
|
||
|
+ if (!bus)
|
||
|
+ return -ENOMEM;
|
||
|
+
|
||
|
+ /* exclude ioeventfd which is limited by maximum fd */
|
||
|
+ if (bus->dev_count - bus->ioeventfd_count > NR_IOBUS_DEVS - 1)
|
||
|
return -ENOSPC;
|
||
|
|
||
|
new_bus = kzalloc(sizeof(*bus) + ((bus->dev_count + 1) *
|
||
|
@@ -2952,37 +2963,41 @@ int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
|
||
|
}
|
||
|
|
||
|
/* Caller must hold slots_lock. */
|
||
|
-int kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx,
|
||
|
- struct kvm_io_device *dev)
|
||
|
+void kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx,
|
||
|
+ struct kvm_io_device *dev)
|
||
|
{
|
||
|
- int i, r;
|
||
|
+ int i;
|
||
|
struct kvm_io_bus *new_bus, *bus;
|
||
|
|
||
|
bus = kvm->buses[bus_idx];
|
||
|
- r = -ENOENT;
|
||
|
+ if (!bus)
|
||
|
+ return;
|
||
|
+
|
||
|
for (i = 0; i < bus->dev_count; i++)
|
||
|
if (bus->range[i].dev == dev) {
|
||
|
- r = 0;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
- if (r)
|
||
|
- return r;
|
||
|
+ if (i == bus->dev_count)
|
||
|
+ return;
|
||
|
|
||
|
new_bus = kzalloc(sizeof(*bus) + ((bus->dev_count - 1) *
|
||
|
sizeof(struct kvm_io_range)), GFP_KERNEL);
|
||
|
- if (!new_bus)
|
||
|
- return -ENOMEM;
|
||
|
+ if (!new_bus) {
|
||
|
+ pr_err("kvm: failed to shrink bus, removing it completely\n");
|
||
|
+ goto broken;
|
||
|
+ }
|
||
|
|
||
|
memcpy(new_bus, bus, sizeof(*bus) + i * sizeof(struct kvm_io_range));
|
||
|
new_bus->dev_count--;
|
||
|
memcpy(new_bus->range + i, bus->range + i + 1,
|
||
|
(new_bus->dev_count - i) * sizeof(struct kvm_io_range));
|
||
|
|
||
|
+broken:
|
||
|
rcu_assign_pointer(kvm->buses[bus_idx], new_bus);
|
||
|
synchronize_srcu_expedited(&kvm->srcu);
|
||
|
kfree(bus);
|
||
|
- return r;
|
||
|
+ return;
|
||
|
}
|
||
|
|
||
|
static struct notifier_block kvm_cpu_notifier = {
|