mirror of
https://github.com/Fishwaldo/build.git
synced 2025-03-27 09:11:49 +00:00
2770 lines
85 KiB
Diff
2770 lines
85 KiB
Diff
diff --git a/Makefile b/Makefile
|
|
index 788d90a0051b..7e4c46b375b3 100644
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -1,6 +1,6 @@
|
|
VERSION = 4
|
|
PATCHLEVEL = 4
|
|
-SUBLEVEL = 88
|
|
+SUBLEVEL = 89
|
|
EXTRAVERSION =
|
|
NAME = Blurry Fish Butt
|
|
|
|
diff --git a/arch/arc/kernel/entry.S b/arch/arc/kernel/entry.S
|
|
index 2efb0625331d..db1eee5fe502 100644
|
|
--- a/arch/arc/kernel/entry.S
|
|
+++ b/arch/arc/kernel/entry.S
|
|
@@ -104,6 +104,12 @@ ENTRY(EV_MachineCheck)
|
|
lr r0, [efa]
|
|
mov r1, sp
|
|
|
|
+ ; hardware auto-disables MMU, re-enable it to allow kernel vaddr
|
|
+ ; access for say stack unwinding of modules for crash dumps
|
|
+ lr r3, [ARC_REG_PID]
|
|
+ or r3, r3, MMU_ENABLE
|
|
+ sr r3, [ARC_REG_PID]
|
|
+
|
|
lsr r3, r2, 8
|
|
bmsk r3, r3, 7
|
|
brne r3, ECR_C_MCHK_DUP_TLB, 1f
|
|
diff --git a/arch/arc/mm/tlb.c b/arch/arc/mm/tlb.c
|
|
index daf2bf52b984..97e9582dcf99 100644
|
|
--- a/arch/arc/mm/tlb.c
|
|
+++ b/arch/arc/mm/tlb.c
|
|
@@ -885,9 +885,6 @@ void do_tlb_overlap_fault(unsigned long cause, unsigned long address,
|
|
|
|
local_irq_save(flags);
|
|
|
|
- /* re-enable the MMU */
|
|
- write_aux_reg(ARC_REG_PID, MMU_ENABLE | read_aux_reg(ARC_REG_PID));
|
|
-
|
|
/* loop thru all sets of TLB */
|
|
for (set = 0; set < mmu->sets; set++) {
|
|
|
|
diff --git a/arch/mips/math-emu/dp_fmax.c b/arch/mips/math-emu/dp_fmax.c
|
|
index fd71b8daaaf2..5bec64f2884e 100644
|
|
--- a/arch/mips/math-emu/dp_fmax.c
|
|
+++ b/arch/mips/math-emu/dp_fmax.c
|
|
@@ -47,14 +47,26 @@ union ieee754dp ieee754dp_fmax(union ieee754dp x, union ieee754dp y)
|
|
case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
|
|
return ieee754dp_nanxcpt(x);
|
|
|
|
- /* numbers are preferred to NaNs */
|
|
+ /*
|
|
+ * Quiet NaN handling
|
|
+ */
|
|
+
|
|
+ /*
|
|
+ * The case of both inputs quiet NaNs
|
|
+ */
|
|
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
|
|
+ return x;
|
|
+
|
|
+ /*
|
|
+ * The cases of exactly one input quiet NaN (numbers
|
|
+ * are here preferred as returned values to NaNs)
|
|
+ */
|
|
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
|
|
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
|
|
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
|
|
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
|
|
return x;
|
|
|
|
- case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
|
|
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
|
|
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
|
|
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
|
|
@@ -80,9 +92,7 @@ union ieee754dp ieee754dp_fmax(union ieee754dp x, union ieee754dp y)
|
|
return ys ? x : y;
|
|
|
|
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
|
|
- if (xs == ys)
|
|
- return x;
|
|
- return ieee754dp_zero(1);
|
|
+ return ieee754dp_zero(xs & ys);
|
|
|
|
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
|
|
DPDNORMX;
|
|
@@ -106,16 +116,32 @@ union ieee754dp ieee754dp_fmax(union ieee754dp x, union ieee754dp y)
|
|
else if (xs < ys)
|
|
return x;
|
|
|
|
- /* Compare exponent */
|
|
- if (xe > ye)
|
|
- return x;
|
|
- else if (xe < ye)
|
|
- return y;
|
|
+ /* Signs of inputs are equal, let's compare exponents */
|
|
+ if (xs == 0) {
|
|
+ /* Inputs are both positive */
|
|
+ if (xe > ye)
|
|
+ return x;
|
|
+ else if (xe < ye)
|
|
+ return y;
|
|
+ } else {
|
|
+ /* Inputs are both negative */
|
|
+ if (xe > ye)
|
|
+ return y;
|
|
+ else if (xe < ye)
|
|
+ return x;
|
|
+ }
|
|
|
|
- /* Compare mantissa */
|
|
+ /* Signs and exponents of inputs are equal, let's compare mantissas */
|
|
+ if (xs == 0) {
|
|
+ /* Inputs are both positive, with equal signs and exponents */
|
|
+ if (xm <= ym)
|
|
+ return y;
|
|
+ return x;
|
|
+ }
|
|
+ /* Inputs are both negative, with equal signs and exponents */
|
|
if (xm <= ym)
|
|
- return y;
|
|
- return x;
|
|
+ return x;
|
|
+ return y;
|
|
}
|
|
|
|
union ieee754dp ieee754dp_fmaxa(union ieee754dp x, union ieee754dp y)
|
|
@@ -147,14 +173,26 @@ union ieee754dp ieee754dp_fmaxa(union ieee754dp x, union ieee754dp y)
|
|
case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
|
|
return ieee754dp_nanxcpt(x);
|
|
|
|
- /* numbers are preferred to NaNs */
|
|
+ /*
|
|
+ * Quiet NaN handling
|
|
+ */
|
|
+
|
|
+ /*
|
|
+ * The case of both inputs quiet NaNs
|
|
+ */
|
|
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
|
|
+ return x;
|
|
+
|
|
+ /*
|
|
+ * The cases of exactly one input quiet NaN (numbers
|
|
+ * are here preferred as returned values to NaNs)
|
|
+ */
|
|
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
|
|
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
|
|
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
|
|
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
|
|
return x;
|
|
|
|
- case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
|
|
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
|
|
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
|
|
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
|
|
@@ -164,6 +202,9 @@ union ieee754dp ieee754dp_fmaxa(union ieee754dp x, union ieee754dp y)
|
|
/*
|
|
* Infinity and zero handling
|
|
*/
|
|
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
|
|
+ return ieee754dp_inf(xs & ys);
|
|
+
|
|
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
|
|
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
|
|
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
|
|
@@ -171,7 +212,6 @@ union ieee754dp ieee754dp_fmaxa(union ieee754dp x, union ieee754dp y)
|
|
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
|
|
return x;
|
|
|
|
- case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
|
|
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
|
|
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
|
|
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
|
|
@@ -180,9 +220,7 @@ union ieee754dp ieee754dp_fmaxa(union ieee754dp x, union ieee754dp y)
|
|
return y;
|
|
|
|
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
|
|
- if (xs == ys)
|
|
- return x;
|
|
- return ieee754dp_zero(1);
|
|
+ return ieee754dp_zero(xs & ys);
|
|
|
|
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
|
|
DPDNORMX;
|
|
@@ -207,7 +245,11 @@ union ieee754dp ieee754dp_fmaxa(union ieee754dp x, union ieee754dp y)
|
|
return y;
|
|
|
|
/* Compare mantissa */
|
|
- if (xm <= ym)
|
|
+ if (xm < ym)
|
|
return y;
|
|
- return x;
|
|
+ else if (xm > ym)
|
|
+ return x;
|
|
+ else if (xs == 0)
|
|
+ return x;
|
|
+ return y;
|
|
}
|
|
diff --git a/arch/mips/math-emu/dp_fmin.c b/arch/mips/math-emu/dp_fmin.c
|
|
index c1072b0dfb95..a287b23818d8 100644
|
|
--- a/arch/mips/math-emu/dp_fmin.c
|
|
+++ b/arch/mips/math-emu/dp_fmin.c
|
|
@@ -47,14 +47,26 @@ union ieee754dp ieee754dp_fmin(union ieee754dp x, union ieee754dp y)
|
|
case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
|
|
return ieee754dp_nanxcpt(x);
|
|
|
|
- /* numbers are preferred to NaNs */
|
|
+ /*
|
|
+ * Quiet NaN handling
|
|
+ */
|
|
+
|
|
+ /*
|
|
+ * The case of both inputs quiet NaNs
|
|
+ */
|
|
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
|
|
+ return x;
|
|
+
|
|
+ /*
|
|
+ * The cases of exactly one input quiet NaN (numbers
|
|
+ * are here preferred as returned values to NaNs)
|
|
+ */
|
|
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
|
|
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
|
|
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
|
|
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
|
|
return x;
|
|
|
|
- case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
|
|
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
|
|
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
|
|
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
|
|
@@ -80,9 +92,7 @@ union ieee754dp ieee754dp_fmin(union ieee754dp x, union ieee754dp y)
|
|
return ys ? y : x;
|
|
|
|
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
|
|
- if (xs == ys)
|
|
- return x;
|
|
- return ieee754dp_zero(1);
|
|
+ return ieee754dp_zero(xs | ys);
|
|
|
|
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
|
|
DPDNORMX;
|
|
@@ -106,16 +116,32 @@ union ieee754dp ieee754dp_fmin(union ieee754dp x, union ieee754dp y)
|
|
else if (xs < ys)
|
|
return y;
|
|
|
|
- /* Compare exponent */
|
|
- if (xe > ye)
|
|
- return y;
|
|
- else if (xe < ye)
|
|
- return x;
|
|
+ /* Signs of inputs are the same, let's compare exponents */
|
|
+ if (xs == 0) {
|
|
+ /* Inputs are both positive */
|
|
+ if (xe > ye)
|
|
+ return y;
|
|
+ else if (xe < ye)
|
|
+ return x;
|
|
+ } else {
|
|
+ /* Inputs are both negative */
|
|
+ if (xe > ye)
|
|
+ return x;
|
|
+ else if (xe < ye)
|
|
+ return y;
|
|
+ }
|
|
|
|
- /* Compare mantissa */
|
|
+ /* Signs and exponents of inputs are equal, let's compare mantissas */
|
|
+ if (xs == 0) {
|
|
+ /* Inputs are both positive, with equal signs and exponents */
|
|
+ if (xm <= ym)
|
|
+ return x;
|
|
+ return y;
|
|
+ }
|
|
+ /* Inputs are both negative, with equal signs and exponents */
|
|
if (xm <= ym)
|
|
- return x;
|
|
- return y;
|
|
+ return y;
|
|
+ return x;
|
|
}
|
|
|
|
union ieee754dp ieee754dp_fmina(union ieee754dp x, union ieee754dp y)
|
|
@@ -147,14 +173,26 @@ union ieee754dp ieee754dp_fmina(union ieee754dp x, union ieee754dp y)
|
|
case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
|
|
return ieee754dp_nanxcpt(x);
|
|
|
|
- /* numbers are preferred to NaNs */
|
|
+ /*
|
|
+ * Quiet NaN handling
|
|
+ */
|
|
+
|
|
+ /*
|
|
+ * The case of both inputs quiet NaNs
|
|
+ */
|
|
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
|
|
+ return x;
|
|
+
|
|
+ /*
|
|
+ * The cases of exactly one input quiet NaN (numbers
|
|
+ * are here preferred as returned values to NaNs)
|
|
+ */
|
|
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
|
|
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
|
|
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
|
|
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
|
|
return x;
|
|
|
|
- case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
|
|
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
|
|
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
|
|
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
|
|
@@ -164,25 +202,25 @@ union ieee754dp ieee754dp_fmina(union ieee754dp x, union ieee754dp y)
|
|
/*
|
|
* Infinity and zero handling
|
|
*/
|
|
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
|
|
+ return ieee754dp_inf(xs | ys);
|
|
+
|
|
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
|
|
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
|
|
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
|
|
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
|
|
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
|
|
- return x;
|
|
+ return y;
|
|
|
|
- case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
|
|
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
|
|
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
|
|
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
|
|
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
|
|
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
|
|
- return y;
|
|
+ return x;
|
|
|
|
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
|
|
- if (xs == ys)
|
|
- return x;
|
|
- return ieee754dp_zero(1);
|
|
+ return ieee754dp_zero(xs | ys);
|
|
|
|
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
|
|
DPDNORMX;
|
|
@@ -207,7 +245,11 @@ union ieee754dp ieee754dp_fmina(union ieee754dp x, union ieee754dp y)
|
|
return x;
|
|
|
|
/* Compare mantissa */
|
|
- if (xm <= ym)
|
|
+ if (xm < ym)
|
|
+ return x;
|
|
+ else if (xm > ym)
|
|
+ return y;
|
|
+ else if (xs == 1)
|
|
return x;
|
|
return y;
|
|
}
|
|
diff --git a/arch/mips/math-emu/sp_fmax.c b/arch/mips/math-emu/sp_fmax.c
|
|
index 4d000844e48e..74a5a00d2f22 100644
|
|
--- a/arch/mips/math-emu/sp_fmax.c
|
|
+++ b/arch/mips/math-emu/sp_fmax.c
|
|
@@ -47,14 +47,26 @@ union ieee754sp ieee754sp_fmax(union ieee754sp x, union ieee754sp y)
|
|
case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
|
|
return ieee754sp_nanxcpt(x);
|
|
|
|
- /* numbers are preferred to NaNs */
|
|
+ /*
|
|
+ * Quiet NaN handling
|
|
+ */
|
|
+
|
|
+ /*
|
|
+ * The case of both inputs quiet NaNs
|
|
+ */
|
|
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
|
|
+ return x;
|
|
+
|
|
+ /*
|
|
+ * The cases of exactly one input quiet NaN (numbers
|
|
+ * are here preferred as returned values to NaNs)
|
|
+ */
|
|
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
|
|
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
|
|
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
|
|
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
|
|
return x;
|
|
|
|
- case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
|
|
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
|
|
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
|
|
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
|
|
@@ -80,9 +92,7 @@ union ieee754sp ieee754sp_fmax(union ieee754sp x, union ieee754sp y)
|
|
return ys ? x : y;
|
|
|
|
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
|
|
- if (xs == ys)
|
|
- return x;
|
|
- return ieee754sp_zero(1);
|
|
+ return ieee754sp_zero(xs & ys);
|
|
|
|
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
|
|
SPDNORMX;
|
|
@@ -106,16 +116,32 @@ union ieee754sp ieee754sp_fmax(union ieee754sp x, union ieee754sp y)
|
|
else if (xs < ys)
|
|
return x;
|
|
|
|
- /* Compare exponent */
|
|
- if (xe > ye)
|
|
- return x;
|
|
- else if (xe < ye)
|
|
- return y;
|
|
+ /* Signs of inputs are equal, let's compare exponents */
|
|
+ if (xs == 0) {
|
|
+ /* Inputs are both positive */
|
|
+ if (xe > ye)
|
|
+ return x;
|
|
+ else if (xe < ye)
|
|
+ return y;
|
|
+ } else {
|
|
+ /* Inputs are both negative */
|
|
+ if (xe > ye)
|
|
+ return y;
|
|
+ else if (xe < ye)
|
|
+ return x;
|
|
+ }
|
|
|
|
- /* Compare mantissa */
|
|
+ /* Signs and exponents of inputs are equal, let's compare mantissas */
|
|
+ if (xs == 0) {
|
|
+ /* Inputs are both positive, with equal signs and exponents */
|
|
+ if (xm <= ym)
|
|
+ return y;
|
|
+ return x;
|
|
+ }
|
|
+ /* Inputs are both negative, with equal signs and exponents */
|
|
if (xm <= ym)
|
|
- return y;
|
|
- return x;
|
|
+ return x;
|
|
+ return y;
|
|
}
|
|
|
|
union ieee754sp ieee754sp_fmaxa(union ieee754sp x, union ieee754sp y)
|
|
@@ -147,14 +173,26 @@ union ieee754sp ieee754sp_fmaxa(union ieee754sp x, union ieee754sp y)
|
|
case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
|
|
return ieee754sp_nanxcpt(x);
|
|
|
|
- /* numbers are preferred to NaNs */
|
|
+ /*
|
|
+ * Quiet NaN handling
|
|
+ */
|
|
+
|
|
+ /*
|
|
+ * The case of both inputs quiet NaNs
|
|
+ */
|
|
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
|
|
+ return x;
|
|
+
|
|
+ /*
|
|
+ * The cases of exactly one input quiet NaN (numbers
|
|
+ * are here preferred as returned values to NaNs)
|
|
+ */
|
|
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
|
|
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
|
|
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
|
|
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
|
|
return x;
|
|
|
|
- case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
|
|
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
|
|
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
|
|
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
|
|
@@ -164,6 +202,9 @@ union ieee754sp ieee754sp_fmaxa(union ieee754sp x, union ieee754sp y)
|
|
/*
|
|
* Infinity and zero handling
|
|
*/
|
|
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
|
|
+ return ieee754sp_inf(xs & ys);
|
|
+
|
|
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
|
|
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
|
|
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
|
|
@@ -171,7 +212,6 @@ union ieee754sp ieee754sp_fmaxa(union ieee754sp x, union ieee754sp y)
|
|
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
|
|
return x;
|
|
|
|
- case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
|
|
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
|
|
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
|
|
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
|
|
@@ -180,9 +220,7 @@ union ieee754sp ieee754sp_fmaxa(union ieee754sp x, union ieee754sp y)
|
|
return y;
|
|
|
|
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
|
|
- if (xs == ys)
|
|
- return x;
|
|
- return ieee754sp_zero(1);
|
|
+ return ieee754sp_zero(xs & ys);
|
|
|
|
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
|
|
SPDNORMX;
|
|
@@ -207,7 +245,11 @@ union ieee754sp ieee754sp_fmaxa(union ieee754sp x, union ieee754sp y)
|
|
return y;
|
|
|
|
/* Compare mantissa */
|
|
- if (xm <= ym)
|
|
+ if (xm < ym)
|
|
return y;
|
|
- return x;
|
|
+ else if (xm > ym)
|
|
+ return x;
|
|
+ else if (xs == 0)
|
|
+ return x;
|
|
+ return y;
|
|
}
|
|
diff --git a/arch/mips/math-emu/sp_fmin.c b/arch/mips/math-emu/sp_fmin.c
|
|
index 4eb1bb9e9dec..c51385f46b09 100644
|
|
--- a/arch/mips/math-emu/sp_fmin.c
|
|
+++ b/arch/mips/math-emu/sp_fmin.c
|
|
@@ -47,14 +47,26 @@ union ieee754sp ieee754sp_fmin(union ieee754sp x, union ieee754sp y)
|
|
case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
|
|
return ieee754sp_nanxcpt(x);
|
|
|
|
- /* numbers are preferred to NaNs */
|
|
+ /*
|
|
+ * Quiet NaN handling
|
|
+ */
|
|
+
|
|
+ /*
|
|
+ * The case of both inputs quiet NaNs
|
|
+ */
|
|
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
|
|
+ return x;
|
|
+
|
|
+ /*
|
|
+ * The cases of exactly one input quiet NaN (numbers
|
|
+ * are here preferred as returned values to NaNs)
|
|
+ */
|
|
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
|
|
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
|
|
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
|
|
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
|
|
return x;
|
|
|
|
- case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
|
|
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
|
|
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
|
|
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
|
|
@@ -80,9 +92,7 @@ union ieee754sp ieee754sp_fmin(union ieee754sp x, union ieee754sp y)
|
|
return ys ? y : x;
|
|
|
|
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
|
|
- if (xs == ys)
|
|
- return x;
|
|
- return ieee754sp_zero(1);
|
|
+ return ieee754sp_zero(xs | ys);
|
|
|
|
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
|
|
SPDNORMX;
|
|
@@ -106,16 +116,32 @@ union ieee754sp ieee754sp_fmin(union ieee754sp x, union ieee754sp y)
|
|
else if (xs < ys)
|
|
return y;
|
|
|
|
- /* Compare exponent */
|
|
- if (xe > ye)
|
|
- return y;
|
|
- else if (xe < ye)
|
|
- return x;
|
|
+ /* Signs of inputs are the same, let's compare exponents */
|
|
+ if (xs == 0) {
|
|
+ /* Inputs are both positive */
|
|
+ if (xe > ye)
|
|
+ return y;
|
|
+ else if (xe < ye)
|
|
+ return x;
|
|
+ } else {
|
|
+ /* Inputs are both negative */
|
|
+ if (xe > ye)
|
|
+ return x;
|
|
+ else if (xe < ye)
|
|
+ return y;
|
|
+ }
|
|
|
|
- /* Compare mantissa */
|
|
+ /* Signs and exponents of inputs are equal, let's compare mantissas */
|
|
+ if (xs == 0) {
|
|
+ /* Inputs are both positive, with equal signs and exponents */
|
|
+ if (xm <= ym)
|
|
+ return x;
|
|
+ return y;
|
|
+ }
|
|
+ /* Inputs are both negative, with equal signs and exponents */
|
|
if (xm <= ym)
|
|
- return x;
|
|
- return y;
|
|
+ return y;
|
|
+ return x;
|
|
}
|
|
|
|
union ieee754sp ieee754sp_fmina(union ieee754sp x, union ieee754sp y)
|
|
@@ -147,14 +173,26 @@ union ieee754sp ieee754sp_fmina(union ieee754sp x, union ieee754sp y)
|
|
case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
|
|
return ieee754sp_nanxcpt(x);
|
|
|
|
- /* numbers are preferred to NaNs */
|
|
+ /*
|
|
+ * Quiet NaN handling
|
|
+ */
|
|
+
|
|
+ /*
|
|
+ * The case of both inputs quiet NaNs
|
|
+ */
|
|
+ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
|
|
+ return x;
|
|
+
|
|
+ /*
|
|
+ * The cases of exactly one input quiet NaN (numbers
|
|
+ * are here preferred as returned values to NaNs)
|
|
+ */
|
|
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN):
|
|
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN):
|
|
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN):
|
|
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN):
|
|
return x;
|
|
|
|
- case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN):
|
|
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO):
|
|
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM):
|
|
case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM):
|
|
@@ -164,25 +202,25 @@ union ieee754sp ieee754sp_fmina(union ieee754sp x, union ieee754sp y)
|
|
/*
|
|
* Infinity and zero handling
|
|
*/
|
|
+ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
|
|
+ return ieee754sp_inf(xs | ys);
|
|
+
|
|
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
|
|
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
|
|
case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
|
|
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO):
|
|
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
|
|
- return x;
|
|
+ return y;
|
|
|
|
- case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
|
|
case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF):
|
|
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF):
|
|
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
|
|
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
|
|
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM):
|
|
- return y;
|
|
+ return x;
|
|
|
|
case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
|
|
- if (xs == ys)
|
|
- return x;
|
|
- return ieee754sp_zero(1);
|
|
+ return ieee754sp_zero(xs | ys);
|
|
|
|
case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
|
|
SPDNORMX;
|
|
@@ -207,7 +245,11 @@ union ieee754sp ieee754sp_fmina(union ieee754sp x, union ieee754sp y)
|
|
return x;
|
|
|
|
/* Compare mantissa */
|
|
- if (xm <= ym)
|
|
+ if (xm < ym)
|
|
+ return x;
|
|
+ else if (xm > ym)
|
|
+ return y;
|
|
+ else if (xs == 1)
|
|
return x;
|
|
return y;
|
|
}
|
|
diff --git a/arch/powerpc/kernel/align.c b/arch/powerpc/kernel/align.c
|
|
index 91e5c1758b5c..64e016abb2a5 100644
|
|
--- a/arch/powerpc/kernel/align.c
|
|
+++ b/arch/powerpc/kernel/align.c
|
|
@@ -236,6 +236,28 @@ static int emulate_dcbz(struct pt_regs *regs, unsigned char __user *addr)
|
|
|
|
#define SWIZ_PTR(p) ((unsigned char __user *)((p) ^ swiz))
|
|
|
|
+#define __get_user_or_set_dar(_regs, _dest, _addr) \
|
|
+ ({ \
|
|
+ int rc = 0; \
|
|
+ typeof(_addr) __addr = (_addr); \
|
|
+ if (__get_user_inatomic(_dest, __addr)) { \
|
|
+ _regs->dar = (unsigned long)__addr; \
|
|
+ rc = -EFAULT; \
|
|
+ } \
|
|
+ rc; \
|
|
+ })
|
|
+
|
|
+#define __put_user_or_set_dar(_regs, _src, _addr) \
|
|
+ ({ \
|
|
+ int rc = 0; \
|
|
+ typeof(_addr) __addr = (_addr); \
|
|
+ if (__put_user_inatomic(_src, __addr)) { \
|
|
+ _regs->dar = (unsigned long)__addr; \
|
|
+ rc = -EFAULT; \
|
|
+ } \
|
|
+ rc; \
|
|
+ })
|
|
+
|
|
static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr,
|
|
unsigned int reg, unsigned int nb,
|
|
unsigned int flags, unsigned int instr,
|
|
@@ -264,9 +286,10 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr,
|
|
} else {
|
|
unsigned long pc = regs->nip ^ (swiz & 4);
|
|
|
|
- if (__get_user_inatomic(instr,
|
|
- (unsigned int __user *)pc))
|
|
+ if (__get_user_or_set_dar(regs, instr,
|
|
+ (unsigned int __user *)pc))
|
|
return -EFAULT;
|
|
+
|
|
if (swiz == 0 && (flags & SW))
|
|
instr = cpu_to_le32(instr);
|
|
nb = (instr >> 11) & 0x1f;
|
|
@@ -310,31 +333,31 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr,
|
|
((nb0 + 3) / 4) * sizeof(unsigned long));
|
|
|
|
for (i = 0; i < nb; ++i, ++p)
|
|
- if (__get_user_inatomic(REG_BYTE(rptr, i ^ bswiz),
|
|
- SWIZ_PTR(p)))
|
|
+ if (__get_user_or_set_dar(regs, REG_BYTE(rptr, i ^ bswiz),
|
|
+ SWIZ_PTR(p)))
|
|
return -EFAULT;
|
|
if (nb0 > 0) {
|
|
rptr = ®s->gpr[0];
|
|
addr += nb;
|
|
for (i = 0; i < nb0; ++i, ++p)
|
|
- if (__get_user_inatomic(REG_BYTE(rptr,
|
|
- i ^ bswiz),
|
|
- SWIZ_PTR(p)))
|
|
+ if (__get_user_or_set_dar(regs,
|
|
+ REG_BYTE(rptr, i ^ bswiz),
|
|
+ SWIZ_PTR(p)))
|
|
return -EFAULT;
|
|
}
|
|
|
|
} else {
|
|
for (i = 0; i < nb; ++i, ++p)
|
|
- if (__put_user_inatomic(REG_BYTE(rptr, i ^ bswiz),
|
|
- SWIZ_PTR(p)))
|
|
+ if (__put_user_or_set_dar(regs, REG_BYTE(rptr, i ^ bswiz),
|
|
+ SWIZ_PTR(p)))
|
|
return -EFAULT;
|
|
if (nb0 > 0) {
|
|
rptr = ®s->gpr[0];
|
|
addr += nb;
|
|
for (i = 0; i < nb0; ++i, ++p)
|
|
- if (__put_user_inatomic(REG_BYTE(rptr,
|
|
- i ^ bswiz),
|
|
- SWIZ_PTR(p)))
|
|
+ if (__put_user_or_set_dar(regs,
|
|
+ REG_BYTE(rptr, i ^ bswiz),
|
|
+ SWIZ_PTR(p)))
|
|
return -EFAULT;
|
|
}
|
|
}
|
|
@@ -346,29 +369,32 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr,
|
|
* Only POWER6 has these instructions, and it does true little-endian,
|
|
* so we don't need the address swizzling.
|
|
*/
|
|
-static int emulate_fp_pair(unsigned char __user *addr, unsigned int reg,
|
|
- unsigned int flags)
|
|
+static int emulate_fp_pair(struct pt_regs *regs, unsigned char __user *addr,
|
|
+ unsigned int reg, unsigned int flags)
|
|
{
|
|
char *ptr0 = (char *) ¤t->thread.TS_FPR(reg);
|
|
char *ptr1 = (char *) ¤t->thread.TS_FPR(reg+1);
|
|
- int i, ret, sw = 0;
|
|
+ int i, sw = 0;
|
|
|
|
if (reg & 1)
|
|
return 0; /* invalid form: FRS/FRT must be even */
|
|
if (flags & SW)
|
|
sw = 7;
|
|
- ret = 0;
|
|
+
|
|
for (i = 0; i < 8; ++i) {
|
|
if (!(flags & ST)) {
|
|
- ret |= __get_user(ptr0[i^sw], addr + i);
|
|
- ret |= __get_user(ptr1[i^sw], addr + i + 8);
|
|
+ if (__get_user_or_set_dar(regs, ptr0[i^sw], addr + i))
|
|
+ return -EFAULT;
|
|
+ if (__get_user_or_set_dar(regs, ptr1[i^sw], addr + i + 8))
|
|
+ return -EFAULT;
|
|
} else {
|
|
- ret |= __put_user(ptr0[i^sw], addr + i);
|
|
- ret |= __put_user(ptr1[i^sw], addr + i + 8);
|
|
+ if (__put_user_or_set_dar(regs, ptr0[i^sw], addr + i))
|
|
+ return -EFAULT;
|
|
+ if (__put_user_or_set_dar(regs, ptr1[i^sw], addr + i + 8))
|
|
+ return -EFAULT;
|
|
}
|
|
}
|
|
- if (ret)
|
|
- return -EFAULT;
|
|
+
|
|
return 1; /* exception handled and fixed up */
|
|
}
|
|
|
|
@@ -378,24 +404,27 @@ static int emulate_lq_stq(struct pt_regs *regs, unsigned char __user *addr,
|
|
{
|
|
char *ptr0 = (char *)®s->gpr[reg];
|
|
char *ptr1 = (char *)®s->gpr[reg+1];
|
|
- int i, ret, sw = 0;
|
|
+ int i, sw = 0;
|
|
|
|
if (reg & 1)
|
|
return 0; /* invalid form: GPR must be even */
|
|
if (flags & SW)
|
|
sw = 7;
|
|
- ret = 0;
|
|
+
|
|
for (i = 0; i < 8; ++i) {
|
|
if (!(flags & ST)) {
|
|
- ret |= __get_user(ptr0[i^sw], addr + i);
|
|
- ret |= __get_user(ptr1[i^sw], addr + i + 8);
|
|
+ if (__get_user_or_set_dar(regs, ptr0[i^sw], addr + i))
|
|
+ return -EFAULT;
|
|
+ if (__get_user_or_set_dar(regs, ptr1[i^sw], addr + i + 8))
|
|
+ return -EFAULT;
|
|
} else {
|
|
- ret |= __put_user(ptr0[i^sw], addr + i);
|
|
- ret |= __put_user(ptr1[i^sw], addr + i + 8);
|
|
+ if (__put_user_or_set_dar(regs, ptr0[i^sw], addr + i))
|
|
+ return -EFAULT;
|
|
+ if (__put_user_or_set_dar(regs, ptr1[i^sw], addr + i + 8))
|
|
+ return -EFAULT;
|
|
}
|
|
}
|
|
- if (ret)
|
|
- return -EFAULT;
|
|
+
|
|
return 1; /* exception handled and fixed up */
|
|
}
|
|
#endif /* CONFIG_PPC64 */
|
|
@@ -688,9 +717,14 @@ static int emulate_vsx(unsigned char __user *addr, unsigned int reg,
|
|
for (j = 0; j < length; j += elsize) {
|
|
for (i = 0; i < elsize; ++i) {
|
|
if (flags & ST)
|
|
- ret |= __put_user(ptr[i^sw], addr + i);
|
|
+ ret = __put_user_or_set_dar(regs, ptr[i^sw],
|
|
+ addr + i);
|
|
else
|
|
- ret |= __get_user(ptr[i^sw], addr + i);
|
|
+ ret = __get_user_or_set_dar(regs, ptr[i^sw],
|
|
+ addr + i);
|
|
+
|
|
+ if (ret)
|
|
+ return ret;
|
|
}
|
|
ptr += elsize;
|
|
#ifdef __LITTLE_ENDIAN__
|
|
@@ -740,7 +774,7 @@ int fix_alignment(struct pt_regs *regs)
|
|
unsigned int dsisr;
|
|
unsigned char __user *addr;
|
|
unsigned long p, swiz;
|
|
- int ret, i;
|
|
+ int i;
|
|
union data {
|
|
u64 ll;
|
|
double dd;
|
|
@@ -923,7 +957,7 @@ int fix_alignment(struct pt_regs *regs)
|
|
if (flags & F) {
|
|
/* Special case for 16-byte FP loads and stores */
|
|
PPC_WARN_ALIGNMENT(fp_pair, regs);
|
|
- return emulate_fp_pair(addr, reg, flags);
|
|
+ return emulate_fp_pair(regs, addr, reg, flags);
|
|
} else {
|
|
#ifdef CONFIG_PPC64
|
|
/* Special case for 16-byte loads and stores */
|
|
@@ -953,15 +987,12 @@ int fix_alignment(struct pt_regs *regs)
|
|
}
|
|
|
|
data.ll = 0;
|
|
- ret = 0;
|
|
p = (unsigned long)addr;
|
|
|
|
for (i = 0; i < nb; i++)
|
|
- ret |= __get_user_inatomic(data.v[start + i],
|
|
- SWIZ_PTR(p++));
|
|
-
|
|
- if (unlikely(ret))
|
|
- return -EFAULT;
|
|
+ if (__get_user_or_set_dar(regs, data.v[start + i],
|
|
+ SWIZ_PTR(p++)))
|
|
+ return -EFAULT;
|
|
|
|
} else if (flags & F) {
|
|
data.ll = current->thread.TS_FPR(reg);
|
|
@@ -1031,15 +1062,13 @@ int fix_alignment(struct pt_regs *regs)
|
|
break;
|
|
}
|
|
|
|
- ret = 0;
|
|
p = (unsigned long)addr;
|
|
|
|
for (i = 0; i < nb; i++)
|
|
- ret |= __put_user_inatomic(data.v[start + i],
|
|
- SWIZ_PTR(p++));
|
|
+ if (__put_user_or_set_dar(regs, data.v[start + i],
|
|
+ SWIZ_PTR(p++)))
|
|
+ return -EFAULT;
|
|
|
|
- if (unlikely(ret))
|
|
- return -EFAULT;
|
|
} else if (flags & F)
|
|
current->thread.TS_FPR(reg) = data.ll;
|
|
else
|
|
diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h
|
|
index bcd3d6199464..bb16a58cf7e4 100644
|
|
--- a/arch/x86/include/asm/elf.h
|
|
+++ b/arch/x86/include/asm/elf.h
|
|
@@ -204,6 +204,7 @@ void set_personality_ia32(bool);
|
|
|
|
#define ELF_CORE_COPY_REGS(pr_reg, regs) \
|
|
do { \
|
|
+ unsigned long base; \
|
|
unsigned v; \
|
|
(pr_reg)[0] = (regs)->r15; \
|
|
(pr_reg)[1] = (regs)->r14; \
|
|
@@ -226,8 +227,8 @@ do { \
|
|
(pr_reg)[18] = (regs)->flags; \
|
|
(pr_reg)[19] = (regs)->sp; \
|
|
(pr_reg)[20] = (regs)->ss; \
|
|
- (pr_reg)[21] = current->thread.fs; \
|
|
- (pr_reg)[22] = current->thread.gs; \
|
|
+ rdmsrl(MSR_FS_BASE, base); (pr_reg)[21] = base; \
|
|
+ rdmsrl(MSR_KERNEL_GS_BASE, base); (pr_reg)[22] = base; \
|
|
asm("movl %%ds,%0" : "=r" (v)); (pr_reg)[23] = v; \
|
|
asm("movl %%es,%0" : "=r" (v)); (pr_reg)[24] = v; \
|
|
asm("movl %%fs,%0" : "=r" (v)); (pr_reg)[25] = v; \
|
|
diff --git a/block/blk-core.c b/block/blk-core.c
|
|
index ef083e7a37c5..119658534dfd 100644
|
|
--- a/block/blk-core.c
|
|
+++ b/block/blk-core.c
|
|
@@ -233,7 +233,7 @@ EXPORT_SYMBOL(blk_start_queue_async);
|
|
**/
|
|
void blk_start_queue(struct request_queue *q)
|
|
{
|
|
- WARN_ON(!irqs_disabled());
|
|
+ WARN_ON(!in_interrupt() && !irqs_disabled());
|
|
|
|
queue_flag_clear(QUEUE_FLAG_STOPPED, q);
|
|
__blk_run_queue(q);
|
|
diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c
|
|
index b3b0004ea8ac..d12782dc9683 100644
|
|
--- a/crypto/algif_skcipher.c
|
|
+++ b/crypto/algif_skcipher.c
|
|
@@ -143,8 +143,10 @@ static int skcipher_alloc_sgl(struct sock *sk)
|
|
sg_init_table(sgl->sg, MAX_SGL_ENTS + 1);
|
|
sgl->cur = 0;
|
|
|
|
- if (sg)
|
|
+ if (sg) {
|
|
sg_chain(sg, MAX_SGL_ENTS + 1, sgl->sg);
|
|
+ sg_unmark_end(sg + (MAX_SGL_ENTS - 1));
|
|
+ }
|
|
|
|
list_add_tail(&sgl->list, &ctx->tsgl);
|
|
}
|
|
diff --git a/drivers/block/skd_main.c b/drivers/block/skd_main.c
|
|
index 586f9168ffa4..47d1e834f3f4 100644
|
|
--- a/drivers/block/skd_main.c
|
|
+++ b/drivers/block/skd_main.c
|
|
@@ -2214,6 +2214,9 @@ static void skd_send_fitmsg(struct skd_device *skdev,
|
|
*/
|
|
qcmd |= FIT_QCMD_MSGSIZE_64;
|
|
|
|
+ /* Make sure skd_msg_buf is written before the doorbell is triggered. */
|
|
+ smp_wmb();
|
|
+
|
|
SKD_WRITEQ(skdev, qcmd, FIT_Q_COMMAND);
|
|
|
|
}
|
|
@@ -2260,6 +2263,9 @@ static void skd_send_special_fitmsg(struct skd_device *skdev,
|
|
qcmd = skspcl->mb_dma_address;
|
|
qcmd |= FIT_QCMD_QID_NORMAL + FIT_QCMD_MSGSIZE_128;
|
|
|
|
+ /* Make sure skd_msg_buf is written before the doorbell is triggered. */
|
|
+ smp_wmb();
|
|
+
|
|
SKD_WRITEQ(skdev, qcmd, FIT_Q_COMMAND);
|
|
}
|
|
|
|
@@ -4679,15 +4685,16 @@ static void skd_free_disk(struct skd_device *skdev)
|
|
{
|
|
struct gendisk *disk = skdev->disk;
|
|
|
|
- if (disk != NULL) {
|
|
- struct request_queue *q = disk->queue;
|
|
+ if (disk && (disk->flags & GENHD_FL_UP))
|
|
+ del_gendisk(disk);
|
|
|
|
- if (disk->flags & GENHD_FL_UP)
|
|
- del_gendisk(disk);
|
|
- if (q)
|
|
- blk_cleanup_queue(q);
|
|
- put_disk(disk);
|
|
+ if (skdev->queue) {
|
|
+ blk_cleanup_queue(skdev->queue);
|
|
+ skdev->queue = NULL;
|
|
+ disk->queue = NULL;
|
|
}
|
|
+
|
|
+ put_disk(disk);
|
|
skdev->disk = NULL;
|
|
}
|
|
|
|
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
|
|
index 5be14ad29d46..dbf09836ff30 100644
|
|
--- a/drivers/input/serio/i8042-x86ia64io.h
|
|
+++ b/drivers/input/serio/i8042-x86ia64io.h
|
|
@@ -904,6 +904,13 @@ static const struct dmi_system_id __initconst i8042_dmi_kbdreset_table[] = {
|
|
DMI_MATCH(DMI_PRODUCT_NAME, "P34"),
|
|
},
|
|
},
|
|
+ {
|
|
+ /* Gigabyte P57 - Elantech touchpad */
|
|
+ .matches = {
|
|
+ DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
|
|
+ DMI_MATCH(DMI_PRODUCT_NAME, "P57"),
|
|
+ },
|
|
+ },
|
|
{
|
|
/* Schenker XMG C504 - Elantech touchpad */
|
|
.matches = {
|
|
diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h
|
|
index c3ea03c9a1a8..02619cabda8b 100644
|
|
--- a/drivers/md/bcache/bcache.h
|
|
+++ b/drivers/md/bcache/bcache.h
|
|
@@ -333,6 +333,7 @@ struct cached_dev {
|
|
/* Limit number of writeback bios in flight */
|
|
struct semaphore in_flight;
|
|
struct task_struct *writeback_thread;
|
|
+ struct workqueue_struct *writeback_write_wq;
|
|
|
|
struct keybuf writeback_keys;
|
|
|
|
diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c
|
|
index 2410df1c2a05..6c4c7caea693 100644
|
|
--- a/drivers/md/bcache/request.c
|
|
+++ b/drivers/md/bcache/request.c
|
|
@@ -196,12 +196,12 @@ static void bch_data_insert_start(struct closure *cl)
|
|
struct data_insert_op *op = container_of(cl, struct data_insert_op, cl);
|
|
struct bio *bio = op->bio, *n;
|
|
|
|
- if (atomic_sub_return(bio_sectors(bio), &op->c->sectors_to_gc) < 0)
|
|
- wake_up_gc(op->c);
|
|
-
|
|
if (op->bypass)
|
|
return bch_data_invalidate(cl);
|
|
|
|
+ if (atomic_sub_return(bio_sectors(bio), &op->c->sectors_to_gc) < 0)
|
|
+ wake_up_gc(op->c);
|
|
+
|
|
/*
|
|
* Journal writes are marked REQ_FLUSH; if the original write was a
|
|
* flush, it'll wait on the journal write.
|
|
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
|
|
index 7b5880b8874c..c5ceea9222ff 100644
|
|
--- a/drivers/md/bcache/super.c
|
|
+++ b/drivers/md/bcache/super.c
|
|
@@ -1023,7 +1023,7 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c)
|
|
}
|
|
|
|
if (BDEV_STATE(&dc->sb) == BDEV_STATE_DIRTY) {
|
|
- bch_sectors_dirty_init(dc);
|
|
+ bch_sectors_dirty_init(&dc->disk);
|
|
atomic_set(&dc->has_dirty, 1);
|
|
atomic_inc(&dc->count);
|
|
bch_writeback_queue(dc);
|
|
@@ -1056,6 +1056,8 @@ static void cached_dev_free(struct closure *cl)
|
|
cancel_delayed_work_sync(&dc->writeback_rate_update);
|
|
if (!IS_ERR_OR_NULL(dc->writeback_thread))
|
|
kthread_stop(dc->writeback_thread);
|
|
+ if (dc->writeback_write_wq)
|
|
+ destroy_workqueue(dc->writeback_write_wq);
|
|
|
|
mutex_lock(&bch_register_lock);
|
|
|
|
@@ -1227,6 +1229,7 @@ static int flash_dev_run(struct cache_set *c, struct uuid_entry *u)
|
|
goto err;
|
|
|
|
bcache_device_attach(d, c, u - c->uuids);
|
|
+ bch_sectors_dirty_init(d);
|
|
bch_flash_dev_request_init(d);
|
|
add_disk(d->disk);
|
|
|
|
@@ -1959,6 +1962,8 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr,
|
|
else
|
|
err = "device busy";
|
|
mutex_unlock(&bch_register_lock);
|
|
+ if (!IS_ERR(bdev))
|
|
+ bdput(bdev);
|
|
if (attr == &ksysfs_register_quiet)
|
|
goto out;
|
|
}
|
|
diff --git a/drivers/md/bcache/sysfs.c b/drivers/md/bcache/sysfs.c
|
|
index b3ff57d61dde..4fbb5532f24c 100644
|
|
--- a/drivers/md/bcache/sysfs.c
|
|
+++ b/drivers/md/bcache/sysfs.c
|
|
@@ -191,7 +191,7 @@ STORE(__cached_dev)
|
|
{
|
|
struct cached_dev *dc = container_of(kobj, struct cached_dev,
|
|
disk.kobj);
|
|
- unsigned v = size;
|
|
+ ssize_t v = size;
|
|
struct cache_set *c;
|
|
struct kobj_uevent_env *env;
|
|
|
|
@@ -226,7 +226,7 @@ STORE(__cached_dev)
|
|
bch_cached_dev_run(dc);
|
|
|
|
if (attr == &sysfs_cache_mode) {
|
|
- ssize_t v = bch_read_string_list(buf, bch_cache_modes + 1);
|
|
+ v = bch_read_string_list(buf, bch_cache_modes + 1);
|
|
|
|
if (v < 0)
|
|
return v;
|
|
diff --git a/drivers/md/bcache/util.c b/drivers/md/bcache/util.c
|
|
index db3ae4c2b223..6c18e3ec3e48 100644
|
|
--- a/drivers/md/bcache/util.c
|
|
+++ b/drivers/md/bcache/util.c
|
|
@@ -73,24 +73,44 @@ STRTO_H(strtouint, unsigned int)
|
|
STRTO_H(strtoll, long long)
|
|
STRTO_H(strtoull, unsigned long long)
|
|
|
|
+/**
|
|
+ * bch_hprint() - formats @v to human readable string for sysfs.
|
|
+ *
|
|
+ * @v - signed 64 bit integer
|
|
+ * @buf - the (at least 8 byte) buffer to format the result into.
|
|
+ *
|
|
+ * Returns the number of bytes used by format.
|
|
+ */
|
|
ssize_t bch_hprint(char *buf, int64_t v)
|
|
{
|
|
static const char units[] = "?kMGTPEZY";
|
|
- char dec[4] = "";
|
|
- int u, t = 0;
|
|
-
|
|
- for (u = 0; v >= 1024 || v <= -1024; u++) {
|
|
- t = v & ~(~0 << 10);
|
|
- v >>= 10;
|
|
- }
|
|
-
|
|
- if (!u)
|
|
- return sprintf(buf, "%llu", v);
|
|
-
|
|
- if (v < 100 && v > -100)
|
|
- snprintf(dec, sizeof(dec), ".%i", t / 100);
|
|
-
|
|
- return sprintf(buf, "%lli%s%c", v, dec, units[u]);
|
|
+ int u = 0, t;
|
|
+
|
|
+ uint64_t q;
|
|
+
|
|
+ if (v < 0)
|
|
+ q = -v;
|
|
+ else
|
|
+ q = v;
|
|
+
|
|
+ /* For as long as the number is more than 3 digits, but at least
|
|
+ * once, shift right / divide by 1024. Keep the remainder for
|
|
+ * a digit after the decimal point.
|
|
+ */
|
|
+ do {
|
|
+ u++;
|
|
+
|
|
+ t = q & ~(~0 << 10);
|
|
+ q >>= 10;
|
|
+ } while (q >= 1000);
|
|
+
|
|
+ if (v < 0)
|
|
+ /* '-', up to 3 digits, '.', 1 digit, 1 character, null;
|
|
+ * yields 8 bytes.
|
|
+ */
|
|
+ return sprintf(buf, "-%llu.%i%c", q, t * 10 / 1024, units[u]);
|
|
+ else
|
|
+ return sprintf(buf, "%llu.%i%c", q, t * 10 / 1024, units[u]);
|
|
}
|
|
|
|
ssize_t bch_snprint_string_list(char *buf, size_t size, const char * const list[],
|
|
diff --git a/drivers/md/bcache/writeback.c b/drivers/md/bcache/writeback.c
|
|
index b9346cd9cda1..bbb1dc9e1639 100644
|
|
--- a/drivers/md/bcache/writeback.c
|
|
+++ b/drivers/md/bcache/writeback.c
|
|
@@ -21,7 +21,8 @@
|
|
static void __update_writeback_rate(struct cached_dev *dc)
|
|
{
|
|
struct cache_set *c = dc->disk.c;
|
|
- uint64_t cache_sectors = c->nbuckets * c->sb.bucket_size;
|
|
+ uint64_t cache_sectors = c->nbuckets * c->sb.bucket_size -
|
|
+ bcache_flash_devs_sectors_dirty(c);
|
|
uint64_t cache_dirty_target =
|
|
div_u64(cache_sectors * dc->writeback_percent, 100);
|
|
|
|
@@ -190,7 +191,7 @@ static void write_dirty(struct closure *cl)
|
|
|
|
closure_bio_submit(&io->bio, cl);
|
|
|
|
- continue_at(cl, write_dirty_finish, system_wq);
|
|
+ continue_at(cl, write_dirty_finish, io->dc->writeback_write_wq);
|
|
}
|
|
|
|
static void read_dirty_endio(struct bio *bio)
|
|
@@ -210,7 +211,7 @@ static void read_dirty_submit(struct closure *cl)
|
|
|
|
closure_bio_submit(&io->bio, cl);
|
|
|
|
- continue_at(cl, write_dirty, system_wq);
|
|
+ continue_at(cl, write_dirty, io->dc->writeback_write_wq);
|
|
}
|
|
|
|
static void read_dirty(struct cached_dev *dc)
|
|
@@ -488,17 +489,17 @@ static int sectors_dirty_init_fn(struct btree_op *_op, struct btree *b,
|
|
return MAP_CONTINUE;
|
|
}
|
|
|
|
-void bch_sectors_dirty_init(struct cached_dev *dc)
|
|
+void bch_sectors_dirty_init(struct bcache_device *d)
|
|
{
|
|
struct sectors_dirty_init op;
|
|
|
|
bch_btree_op_init(&op.op, -1);
|
|
- op.inode = dc->disk.id;
|
|
+ op.inode = d->id;
|
|
|
|
- bch_btree_map_keys(&op.op, dc->disk.c, &KEY(op.inode, 0, 0),
|
|
+ bch_btree_map_keys(&op.op, d->c, &KEY(op.inode, 0, 0),
|
|
sectors_dirty_init_fn, 0);
|
|
|
|
- dc->disk.sectors_dirty_last = bcache_dev_sectors_dirty(&dc->disk);
|
|
+ d->sectors_dirty_last = bcache_dev_sectors_dirty(d);
|
|
}
|
|
|
|
void bch_cached_dev_writeback_init(struct cached_dev *dc)
|
|
@@ -522,6 +523,11 @@ void bch_cached_dev_writeback_init(struct cached_dev *dc)
|
|
|
|
int bch_cached_dev_writeback_start(struct cached_dev *dc)
|
|
{
|
|
+ dc->writeback_write_wq = alloc_workqueue("bcache_writeback_wq",
|
|
+ WQ_MEM_RECLAIM, 0);
|
|
+ if (!dc->writeback_write_wq)
|
|
+ return -ENOMEM;
|
|
+
|
|
dc->writeback_thread = kthread_create(bch_writeback_thread, dc,
|
|
"bcache_writeback");
|
|
if (IS_ERR(dc->writeback_thread))
|
|
diff --git a/drivers/md/bcache/writeback.h b/drivers/md/bcache/writeback.h
|
|
index 073a042aed24..daec4fd782ea 100644
|
|
--- a/drivers/md/bcache/writeback.h
|
|
+++ b/drivers/md/bcache/writeback.h
|
|
@@ -14,6 +14,25 @@ static inline uint64_t bcache_dev_sectors_dirty(struct bcache_device *d)
|
|
return ret;
|
|
}
|
|
|
|
+static inline uint64_t bcache_flash_devs_sectors_dirty(struct cache_set *c)
|
|
+{
|
|
+ uint64_t i, ret = 0;
|
|
+
|
|
+ mutex_lock(&bch_register_lock);
|
|
+
|
|
+ for (i = 0; i < c->nr_uuids; i++) {
|
|
+ struct bcache_device *d = c->devices[i];
|
|
+
|
|
+ if (!d || !UUID_FLASH_ONLY(&c->uuids[i]))
|
|
+ continue;
|
|
+ ret += bcache_dev_sectors_dirty(d);
|
|
+ }
|
|
+
|
|
+ mutex_unlock(&bch_register_lock);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
static inline unsigned offset_to_stripe(struct bcache_device *d,
|
|
uint64_t offset)
|
|
{
|
|
@@ -85,7 +104,7 @@ static inline void bch_writeback_add(struct cached_dev *dc)
|
|
|
|
void bcache_dev_sectors_dirty_add(struct cache_set *, unsigned, uint64_t, int);
|
|
|
|
-void bch_sectors_dirty_init(struct cached_dev *dc);
|
|
+void bch_sectors_dirty_init(struct bcache_device *);
|
|
void bch_cached_dev_writeback_init(struct cached_dev *);
|
|
int bch_cached_dev_writeback_start(struct cached_dev *);
|
|
|
|
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
|
|
index 4f22e919787a..7a50728b9389 100644
|
|
--- a/drivers/md/bitmap.c
|
|
+++ b/drivers/md/bitmap.c
|
|
@@ -1960,6 +1960,11 @@ int bitmap_resize(struct bitmap *bitmap, sector_t blocks,
|
|
long pages;
|
|
struct bitmap_page *new_bp;
|
|
|
|
+ if (bitmap->storage.file && !init) {
|
|
+ pr_info("md: cannot resize file-based bitmap\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
if (chunksize == 0) {
|
|
/* If there is enough space, leave the chunk size unchanged,
|
|
* else increase by factor of two until there is enough space.
|
|
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
|
|
index 8f60520c8392..5eac08ffc697 100644
|
|
--- a/drivers/md/raid5.c
|
|
+++ b/drivers/md/raid5.c
|
|
@@ -5822,6 +5822,8 @@ static void raid5_do_work(struct work_struct *work)
|
|
|
|
spin_unlock_irq(&conf->device_lock);
|
|
|
|
+ r5l_flush_stripe_to_raid(conf->log);
|
|
+
|
|
async_tx_issue_pending_all();
|
|
blk_finish_plug(&plug);
|
|
|
|
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
|
|
index 3e59b288b8a8..618e4e2b4207 100644
|
|
--- a/drivers/media/usb/uvc/uvc_ctrl.c
|
|
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
|
|
@@ -2001,6 +2001,13 @@ int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
|
|
goto done;
|
|
}
|
|
|
|
+ /* Validate the user-provided bit-size and offset */
|
|
+ if (mapping->size > 32 ||
|
|
+ mapping->offset + mapping->size > ctrl->info.size * 8) {
|
|
+ ret = -EINVAL;
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
list_for_each_entry(map, &ctrl->info.mappings, list) {
|
|
if (mapping->id == map->id) {
|
|
uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s', "
|
|
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
|
|
index 109f687d1cbd..4379b949bb93 100644
|
|
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
|
|
+++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
|
|
@@ -773,7 +773,8 @@ static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *u
|
|
copy_to_user(&up->u, &kp->u, sizeof(kp->u)) ||
|
|
put_user(kp->pending, &up->pending) ||
|
|
put_user(kp->sequence, &up->sequence) ||
|
|
- compat_put_timespec(&kp->timestamp, &up->timestamp) ||
|
|
+ put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
|
|
+ put_user(kp->timestamp.tv_nsec, &up->timestamp.tv_nsec) ||
|
|
put_user(kp->id, &up->id) ||
|
|
copy_to_user(up->reserved, kp->reserved, 8 * sizeof(__u32)))
|
|
return -EFAULT;
|
|
diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
|
|
index 4cd2a7d0124f..7923bfdc9b30 100644
|
|
--- a/drivers/net/ethernet/freescale/gianfar.c
|
|
+++ b/drivers/net/ethernet/freescale/gianfar.c
|
|
@@ -3676,7 +3676,7 @@ static noinline void gfar_update_link_state(struct gfar_private *priv)
|
|
u32 tempval1 = gfar_read(®s->maccfg1);
|
|
u32 tempval = gfar_read(®s->maccfg2);
|
|
u32 ecntrl = gfar_read(®s->ecntrl);
|
|
- u32 tx_flow_oldval = (tempval & MACCFG1_TX_FLOW);
|
|
+ u32 tx_flow_oldval = (tempval1 & MACCFG1_TX_FLOW);
|
|
|
|
if (phydev->duplex != priv->oldduplex) {
|
|
if (!(phydev->duplex))
|
|
diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c b/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c
|
|
index 829be21f97b2..be258d90de9e 100644
|
|
--- a/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c
|
|
+++ b/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c
|
|
@@ -724,7 +724,7 @@ static void ql_build_coredump_seg_header(
|
|
seg_hdr->cookie = MPI_COREDUMP_COOKIE;
|
|
seg_hdr->segNum = seg_number;
|
|
seg_hdr->segSize = seg_size;
|
|
- memcpy(seg_hdr->description, desc, (sizeof(seg_hdr->description)) - 1);
|
|
+ strncpy(seg_hdr->description, desc, (sizeof(seg_hdr->description)) - 1);
|
|
}
|
|
|
|
/*
|
|
diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c
|
|
index 7d223e9080ef..77dddee2753a 100644
|
|
--- a/drivers/pci/hotplug/shpchp_hpc.c
|
|
+++ b/drivers/pci/hotplug/shpchp_hpc.c
|
|
@@ -1062,6 +1062,8 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev)
|
|
if (rc) {
|
|
ctrl_info(ctrl, "Can't get msi for the hotplug controller\n");
|
|
ctrl_info(ctrl, "Use INTx for the hotplug controller\n");
|
|
+ } else {
|
|
+ pci_set_master(pdev);
|
|
}
|
|
|
|
rc = request_irq(ctrl->pci_dev->irq, shpc_isr, IRQF_SHARED,
|
|
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
|
|
index d5bf36ec8a75..34367d172961 100644
|
|
--- a/drivers/s390/scsi/zfcp_dbf.c
|
|
+++ b/drivers/s390/scsi/zfcp_dbf.c
|
|
@@ -3,7 +3,7 @@
|
|
*
|
|
* Debug traces for zfcp.
|
|
*
|
|
- * Copyright IBM Corp. 2002, 2016
|
|
+ * Copyright IBM Corp. 2002, 2017
|
|
*/
|
|
|
|
#define KMSG_COMPONENT "zfcp"
|
|
@@ -447,6 +447,7 @@ static u16 zfcp_dbf_san_res_cap_len_if_gpn_ft(char *tag,
|
|
struct fc_ct_hdr *reqh = sg_virt(ct_els->req);
|
|
struct fc_ns_gid_ft *reqn = (struct fc_ns_gid_ft *)(reqh + 1);
|
|
struct scatterlist *resp_entry = ct_els->resp;
|
|
+ struct fc_ct_hdr *resph;
|
|
struct fc_gpn_ft_resp *acc;
|
|
int max_entries, x, last = 0;
|
|
|
|
@@ -473,6 +474,13 @@ static u16 zfcp_dbf_san_res_cap_len_if_gpn_ft(char *tag,
|
|
return len; /* not GPN_FT response so do not cap */
|
|
|
|
acc = sg_virt(resp_entry);
|
|
+
|
|
+ /* cap all but accept CT responses to at least the CT header */
|
|
+ resph = (struct fc_ct_hdr *)acc;
|
|
+ if ((ct_els->status) ||
|
|
+ (resph->ct_cmd != cpu_to_be16(FC_FS_ACC)))
|
|
+ return max(FC_CT_HDR_LEN, ZFCP_DBF_SAN_MAX_PAYLOAD);
|
|
+
|
|
max_entries = (reqh->ct_mr_size * 4 / sizeof(struct fc_gpn_ft_resp))
|
|
+ 1 /* zfcp_fc_scan_ports: bytes correct, entries off-by-one
|
|
* to account for header as 1st pseudo "entry" */;
|
|
@@ -555,8 +563,8 @@ void zfcp_dbf_scsi(char *tag, int level, struct scsi_cmnd *sc,
|
|
rec->scsi_retries = sc->retries;
|
|
rec->scsi_allowed = sc->allowed;
|
|
rec->scsi_id = sc->device->id;
|
|
- /* struct zfcp_dbf_scsi needs to be updated to handle 64bit LUNs */
|
|
rec->scsi_lun = (u32)sc->device->lun;
|
|
+ rec->scsi_lun_64_hi = (u32)(sc->device->lun >> 32);
|
|
rec->host_scribble = (unsigned long)sc->host_scribble;
|
|
|
|
memcpy(rec->scsi_opcode, sc->cmnd,
|
|
@@ -564,19 +572,32 @@ void zfcp_dbf_scsi(char *tag, int level, struct scsi_cmnd *sc,
|
|
|
|
if (fsf) {
|
|
rec->fsf_req_id = fsf->req_id;
|
|
+ rec->pl_len = FCP_RESP_WITH_EXT;
|
|
fcp_rsp = (struct fcp_resp_with_ext *)
|
|
&(fsf->qtcb->bottom.io.fcp_rsp);
|
|
+ /* mandatory parts of FCP_RSP IU in this SCSI record */
|
|
memcpy(&rec->fcp_rsp, fcp_rsp, FCP_RESP_WITH_EXT);
|
|
if (fcp_rsp->resp.fr_flags & FCP_RSP_LEN_VAL) {
|
|
fcp_rsp_info = (struct fcp_resp_rsp_info *) &fcp_rsp[1];
|
|
rec->fcp_rsp_info = fcp_rsp_info->rsp_code;
|
|
+ rec->pl_len += be32_to_cpu(fcp_rsp->ext.fr_rsp_len);
|
|
}
|
|
if (fcp_rsp->resp.fr_flags & FCP_SNS_LEN_VAL) {
|
|
- rec->pl_len = min((u16)SCSI_SENSE_BUFFERSIZE,
|
|
- (u16)ZFCP_DBF_PAY_MAX_REC);
|
|
- zfcp_dbf_pl_write(dbf, sc->sense_buffer, rec->pl_len,
|
|
- "fcp_sns", fsf->req_id);
|
|
+ rec->pl_len += be32_to_cpu(fcp_rsp->ext.fr_sns_len);
|
|
}
|
|
+ /* complete FCP_RSP IU in associated PAYload record
|
|
+ * but only if there are optional parts
|
|
+ */
|
|
+ if (fcp_rsp->resp.fr_flags != 0)
|
|
+ zfcp_dbf_pl_write(
|
|
+ dbf, fcp_rsp,
|
|
+ /* at least one full PAY record
|
|
+ * but not beyond hardware response field
|
|
+ */
|
|
+ min_t(u16, max_t(u16, rec->pl_len,
|
|
+ ZFCP_DBF_PAY_MAX_REC),
|
|
+ FSF_FCP_RSP_SIZE),
|
|
+ "fcp_riu", fsf->req_id);
|
|
}
|
|
|
|
debug_event(dbf->scsi, level, rec, sizeof(*rec));
|
|
diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h
|
|
index db186d44cfaf..b60667c145fd 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, 2016
|
|
+ * Copyright IBM Corp. 2008, 2017
|
|
*/
|
|
|
|
#ifndef ZFCP_DBF_H
|
|
@@ -204,7 +204,7 @@ enum zfcp_dbf_scsi_id {
|
|
* @id: unique number of recovery record type
|
|
* @tag: identifier string specifying the location of initiation
|
|
* @scsi_id: scsi device id
|
|
- * @scsi_lun: scsi device logical unit number
|
|
+ * @scsi_lun: scsi device logical unit number, low part of 64 bit, old 32 bit
|
|
* @scsi_result: scsi result
|
|
* @scsi_retries: current retry number of scsi request
|
|
* @scsi_allowed: allowed retries
|
|
@@ -214,6 +214,7 @@ enum zfcp_dbf_scsi_id {
|
|
* @host_scribble: LLD specific data attached to SCSI request
|
|
* @pl_len: length of paload stored as zfcp_dbf_pay
|
|
* @fsf_rsp: response for fsf request
|
|
+ * @scsi_lun_64_hi: scsi device logical unit number, high part of 64 bit
|
|
*/
|
|
struct zfcp_dbf_scsi {
|
|
u8 id;
|
|
@@ -230,6 +231,7 @@ struct zfcp_dbf_scsi {
|
|
u64 host_scribble;
|
|
u16 pl_len;
|
|
struct fcp_resp_with_ext fcp_rsp;
|
|
+ u32 scsi_lun_64_hi;
|
|
} __packed;
|
|
|
|
/**
|
|
@@ -323,7 +325,11 @@ void zfcp_dbf_hba_fsf_response(struct zfcp_fsf_req *req)
|
|
{
|
|
struct fsf_qtcb *qtcb = req->qtcb;
|
|
|
|
- if ((qtcb->prefix.prot_status != FSF_PROT_GOOD) &&
|
|
+ if (unlikely(req->status & (ZFCP_STATUS_FSFREQ_DISMISSED |
|
|
+ ZFCP_STATUS_FSFREQ_ERROR))) {
|
|
+ zfcp_dbf_hba_fsf_resp("fs_rerr", 3, req);
|
|
+
|
|
+ } else if ((qtcb->prefix.prot_status != FSF_PROT_GOOD) &&
|
|
(qtcb->prefix.prot_status != FSF_PROT_FSF_STATUS_PRESENTED)) {
|
|
zfcp_dbf_hba_fsf_resp("fs_perr", 1, req);
|
|
|
|
@@ -401,7 +407,8 @@ void zfcp_dbf_scsi_abort(char *tag, struct scsi_cmnd *scmd,
|
|
* @flag: indicates type of reset (Target Reset, Logical Unit Reset)
|
|
*/
|
|
static inline
|
|
-void zfcp_dbf_scsi_devreset(char *tag, struct scsi_cmnd *scmnd, u8 flag)
|
|
+void zfcp_dbf_scsi_devreset(char *tag, struct scsi_cmnd *scmnd, u8 flag,
|
|
+ struct zfcp_fsf_req *fsf_req)
|
|
{
|
|
char tmp_tag[ZFCP_DBF_TAG_LEN];
|
|
|
|
@@ -411,7 +418,7 @@ void zfcp_dbf_scsi_devreset(char *tag, struct scsi_cmnd *scmnd, u8 flag)
|
|
memcpy(tmp_tag, "lr_", 3);
|
|
|
|
memcpy(&tmp_tag[3], tag, 4);
|
|
- _zfcp_dbf_scsi(tmp_tag, 1, scmnd, NULL);
|
|
+ _zfcp_dbf_scsi(tmp_tag, 1, scmnd, fsf_req);
|
|
}
|
|
|
|
/**
|
|
diff --git a/drivers/s390/scsi/zfcp_fc.h b/drivers/s390/scsi/zfcp_fc.h
|
|
index df2b541c8287..a2275825186f 100644
|
|
--- a/drivers/s390/scsi/zfcp_fc.h
|
|
+++ b/drivers/s390/scsi/zfcp_fc.h
|
|
@@ -4,7 +4,7 @@
|
|
* Fibre Channel related definitions and inline functions for the zfcp
|
|
* device driver
|
|
*
|
|
- * Copyright IBM Corp. 2009
|
|
+ * Copyright IBM Corp. 2009, 2017
|
|
*/
|
|
|
|
#ifndef ZFCP_FC_H
|
|
@@ -279,6 +279,10 @@ void zfcp_fc_eval_fcp_rsp(struct fcp_resp_with_ext *fcp_rsp,
|
|
!(rsp_flags & FCP_SNS_LEN_VAL) &&
|
|
fcp_rsp->resp.fr_status == SAM_STAT_GOOD)
|
|
set_host_byte(scsi, DID_ERROR);
|
|
+ } else if (unlikely(rsp_flags & FCP_RESID_OVER)) {
|
|
+ /* FCP_DL was not sufficient for SCSI data length */
|
|
+ if (fcp_rsp->resp.fr_status == SAM_STAT_GOOD)
|
|
+ set_host_byte(scsi, DID_ERROR);
|
|
}
|
|
}
|
|
|
|
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
|
|
index 27ff38f839fc..1964391db904 100644
|
|
--- a/drivers/s390/scsi/zfcp_fsf.c
|
|
+++ b/drivers/s390/scsi/zfcp_fsf.c
|
|
@@ -928,8 +928,8 @@ static void zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *req)
|
|
|
|
switch (header->fsf_status) {
|
|
case FSF_GOOD:
|
|
- zfcp_dbf_san_res("fsscth2", req);
|
|
ct->status = 0;
|
|
+ zfcp_dbf_san_res("fsscth2", req);
|
|
break;
|
|
case FSF_SERVICE_CLASS_NOT_SUPPORTED:
|
|
zfcp_fsf_class_not_supp(req);
|
|
@@ -1109,8 +1109,8 @@ static void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req)
|
|
|
|
switch (header->fsf_status) {
|
|
case FSF_GOOD:
|
|
- zfcp_dbf_san_res("fsselh1", req);
|
|
send_els->status = 0;
|
|
+ zfcp_dbf_san_res("fsselh1", req);
|
|
break;
|
|
case FSF_SERVICE_CLASS_NOT_SUPPORTED:
|
|
zfcp_fsf_class_not_supp(req);
|
|
@@ -2258,7 +2258,8 @@ int zfcp_fsf_fcp_cmnd(struct scsi_cmnd *scsi_cmnd)
|
|
fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd;
|
|
zfcp_fc_scsi_to_fcp(fcp_cmnd, scsi_cmnd, 0);
|
|
|
|
- if (scsi_prot_sg_count(scsi_cmnd)) {
|
|
+ if ((scsi_get_prot_op(scsi_cmnd) != SCSI_PROT_NORMAL) &&
|
|
+ scsi_prot_sg_count(scsi_cmnd)) {
|
|
zfcp_qdio_set_data_div(qdio, &req->qdio_req,
|
|
scsi_prot_sg_count(scsi_cmnd));
|
|
retval = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req,
|
|
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
|
|
index 07ffdbb5107f..9bd9b9a29dfc 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, 2016
|
|
+ * Copyright IBM Corp. 2002, 2017
|
|
*/
|
|
|
|
#define KMSG_COMPONENT "zfcp"
|
|
@@ -273,25 +273,29 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags)
|
|
|
|
zfcp_erp_wait(adapter);
|
|
ret = fc_block_scsi_eh(scpnt);
|
|
- if (ret)
|
|
+ if (ret) {
|
|
+ zfcp_dbf_scsi_devreset("fiof", scpnt, tm_flags, NULL);
|
|
return ret;
|
|
+ }
|
|
|
|
if (!(atomic_read(&adapter->status) &
|
|
ZFCP_STATUS_COMMON_RUNNING)) {
|
|
- zfcp_dbf_scsi_devreset("nres", scpnt, tm_flags);
|
|
+ zfcp_dbf_scsi_devreset("nres", scpnt, tm_flags, NULL);
|
|
return SUCCESS;
|
|
}
|
|
}
|
|
- if (!fsf_req)
|
|
+ if (!fsf_req) {
|
|
+ zfcp_dbf_scsi_devreset("reqf", scpnt, tm_flags, NULL);
|
|
return FAILED;
|
|
+ }
|
|
|
|
wait_for_completion(&fsf_req->completion);
|
|
|
|
if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) {
|
|
- zfcp_dbf_scsi_devreset("fail", scpnt, tm_flags);
|
|
+ zfcp_dbf_scsi_devreset("fail", scpnt, tm_flags, fsf_req);
|
|
retval = FAILED;
|
|
} else {
|
|
- zfcp_dbf_scsi_devreset("okay", scpnt, tm_flags);
|
|
+ zfcp_dbf_scsi_devreset("okay", scpnt, tm_flags, fsf_req);
|
|
zfcp_scsi_forget_cmnds(zfcp_sdev, tm_flags);
|
|
}
|
|
|
|
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
|
|
index 17c440b9d086..6835bae33ec4 100644
|
|
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
|
|
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
|
|
@@ -1824,9 +1824,12 @@ static void megasas_complete_outstanding_ioctls(struct megasas_instance *instanc
|
|
if (cmd_fusion->sync_cmd_idx != (u32)ULONG_MAX) {
|
|
cmd_mfi = instance->cmd_list[cmd_fusion->sync_cmd_idx];
|
|
if (cmd_mfi->sync_cmd &&
|
|
- cmd_mfi->frame->hdr.cmd != MFI_CMD_ABORT)
|
|
+ (cmd_mfi->frame->hdr.cmd != MFI_CMD_ABORT)) {
|
|
+ cmd_mfi->frame->hdr.cmd_status =
|
|
+ MFI_STAT_WRONG_STATE;
|
|
megasas_complete_cmd(instance,
|
|
cmd_mfi, DID_OK);
|
|
+ }
|
|
}
|
|
}
|
|
} else {
|
|
@@ -5094,6 +5097,14 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num,
|
|
prev_aen.word =
|
|
le32_to_cpu(instance->aen_cmd->frame->dcmd.mbox.w[1]);
|
|
|
|
+ if ((curr_aen.members.class < MFI_EVT_CLASS_DEBUG) ||
|
|
+ (curr_aen.members.class > MFI_EVT_CLASS_DEAD)) {
|
|
+ dev_info(&instance->pdev->dev,
|
|
+ "%s %d out of range class %d send by application\n",
|
|
+ __func__, __LINE__, curr_aen.members.class);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
/*
|
|
* A class whose enum value is smaller is inclusive of all
|
|
* higher values. If a PROGRESS (= -1) was previously
|
|
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
|
|
index 1ed85dfc008d..ac12ee844bfc 100644
|
|
--- a/drivers/scsi/qla2xxx/qla_attr.c
|
|
+++ b/drivers/scsi/qla2xxx/qla_attr.c
|
|
@@ -404,6 +404,8 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
|
|
return -EINVAL;
|
|
if (start > ha->optrom_size)
|
|
return -EINVAL;
|
|
+ if (size > ha->optrom_size - start)
|
|
+ size = ha->optrom_size - start;
|
|
|
|
mutex_lock(&ha->optrom_mutex);
|
|
switch (val) {
|
|
@@ -429,8 +431,7 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
|
|
}
|
|
|
|
ha->optrom_region_start = start;
|
|
- ha->optrom_region_size = start + size > ha->optrom_size ?
|
|
- ha->optrom_size - start : size;
|
|
+ ha->optrom_region_size = start + size;
|
|
|
|
ha->optrom_state = QLA_SREADING;
|
|
ha->optrom_buffer = vmalloc(ha->optrom_region_size);
|
|
@@ -503,8 +504,7 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
|
|
}
|
|
|
|
ha->optrom_region_start = start;
|
|
- ha->optrom_region_size = start + size > ha->optrom_size ?
|
|
- ha->optrom_size - start : size;
|
|
+ ha->optrom_region_size = start + size;
|
|
|
|
ha->optrom_state = QLA_SWRITING;
|
|
ha->optrom_buffer = vmalloc(ha->optrom_region_size);
|
|
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
|
|
index 71325972e503..39e8b5dc23fa 100644
|
|
--- a/drivers/scsi/sg.c
|
|
+++ b/drivers/scsi/sg.c
|
|
@@ -133,7 +133,7 @@ struct sg_device; /* forward declarations */
|
|
struct sg_fd;
|
|
|
|
typedef struct sg_request { /* SG_MAX_QUEUE requests outstanding per file */
|
|
- struct sg_request *nextrp; /* NULL -> tail request (slist) */
|
|
+ struct list_head entry; /* list entry */
|
|
struct sg_fd *parentfp; /* NULL -> not in use */
|
|
Sg_scatter_hold data; /* hold buffer, perhaps scatter list */
|
|
sg_io_hdr_t header; /* scsi command+info, see <scsi/sg.h> */
|
|
@@ -157,8 +157,7 @@ typedef struct sg_fd { /* holds the state of a file descriptor */
|
|
int timeout; /* defaults to SG_DEFAULT_TIMEOUT */
|
|
int timeout_user; /* defaults to SG_DEFAULT_TIMEOUT_USER */
|
|
Sg_scatter_hold reserve; /* buffer held for this file descriptor */
|
|
- unsigned save_scat_len; /* original length of trunc. scat. element */
|
|
- Sg_request *headrp; /* head of request slist, NULL->empty */
|
|
+ struct list_head rq_list; /* head of request list */
|
|
struct fasync_struct *async_qp; /* used by asynchronous notification */
|
|
Sg_request req_arr[SG_MAX_QUEUE]; /* used as singly-linked list */
|
|
char low_dma; /* as in parent but possibly overridden to 1 */
|
|
@@ -840,6 +839,39 @@ static int max_sectors_bytes(struct request_queue *q)
|
|
return max_sectors << 9;
|
|
}
|
|
|
|
+static void
|
|
+sg_fill_request_table(Sg_fd *sfp, sg_req_info_t *rinfo)
|
|
+{
|
|
+ Sg_request *srp;
|
|
+ int val;
|
|
+ unsigned int ms;
|
|
+
|
|
+ val = 0;
|
|
+ list_for_each_entry(srp, &sfp->rq_list, entry) {
|
|
+ if (val > SG_MAX_QUEUE)
|
|
+ break;
|
|
+ rinfo[val].req_state = srp->done + 1;
|
|
+ rinfo[val].problem =
|
|
+ srp->header.masked_status &
|
|
+ srp->header.host_status &
|
|
+ srp->header.driver_status;
|
|
+ if (srp->done)
|
|
+ rinfo[val].duration =
|
|
+ srp->header.duration;
|
|
+ else {
|
|
+ ms = jiffies_to_msecs(jiffies);
|
|
+ rinfo[val].duration =
|
|
+ (ms > srp->header.duration) ?
|
|
+ (ms - srp->header.duration) : 0;
|
|
+ }
|
|
+ rinfo[val].orphan = srp->orphan;
|
|
+ rinfo[val].sg_io_owned = srp->sg_io_owned;
|
|
+ rinfo[val].pack_id = srp->header.pack_id;
|
|
+ rinfo[val].usr_ptr = srp->header.usr_ptr;
|
|
+ val++;
|
|
+ }
|
|
+}
|
|
+
|
|
static long
|
|
sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
|
|
{
|
|
@@ -951,7 +983,7 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
|
|
if (!access_ok(VERIFY_WRITE, ip, sizeof (int)))
|
|
return -EFAULT;
|
|
read_lock_irqsave(&sfp->rq_list_lock, iflags);
|
|
- for (srp = sfp->headrp; srp; srp = srp->nextrp) {
|
|
+ list_for_each_entry(srp, &sfp->rq_list, entry) {
|
|
if ((1 == srp->done) && (!srp->sg_io_owned)) {
|
|
read_unlock_irqrestore(&sfp->rq_list_lock,
|
|
iflags);
|
|
@@ -964,7 +996,8 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
|
|
return 0;
|
|
case SG_GET_NUM_WAITING:
|
|
read_lock_irqsave(&sfp->rq_list_lock, iflags);
|
|
- for (val = 0, srp = sfp->headrp; srp; srp = srp->nextrp) {
|
|
+ val = 0;
|
|
+ list_for_each_entry(srp, &sfp->rq_list, entry) {
|
|
if ((1 == srp->done) && (!srp->sg_io_owned))
|
|
++val;
|
|
}
|
|
@@ -1032,42 +1065,15 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
|
|
return -EFAULT;
|
|
else {
|
|
sg_req_info_t *rinfo;
|
|
- unsigned int ms;
|
|
|
|
- rinfo = kmalloc(SZ_SG_REQ_INFO * SG_MAX_QUEUE,
|
|
- GFP_KERNEL);
|
|
+ rinfo = kzalloc(SZ_SG_REQ_INFO * SG_MAX_QUEUE,
|
|
+ GFP_KERNEL);
|
|
if (!rinfo)
|
|
return -ENOMEM;
|
|
read_lock_irqsave(&sfp->rq_list_lock, iflags);
|
|
- for (srp = sfp->headrp, val = 0; val < SG_MAX_QUEUE;
|
|
- ++val, srp = srp ? srp->nextrp : srp) {
|
|
- memset(&rinfo[val], 0, SZ_SG_REQ_INFO);
|
|
- if (srp) {
|
|
- rinfo[val].req_state = srp->done + 1;
|
|
- rinfo[val].problem =
|
|
- srp->header.masked_status &
|
|
- srp->header.host_status &
|
|
- srp->header.driver_status;
|
|
- if (srp->done)
|
|
- rinfo[val].duration =
|
|
- srp->header.duration;
|
|
- else {
|
|
- ms = jiffies_to_msecs(jiffies);
|
|
- rinfo[val].duration =
|
|
- (ms > srp->header.duration) ?
|
|
- (ms - srp->header.duration) : 0;
|
|
- }
|
|
- rinfo[val].orphan = srp->orphan;
|
|
- rinfo[val].sg_io_owned =
|
|
- srp->sg_io_owned;
|
|
- rinfo[val].pack_id =
|
|
- srp->header.pack_id;
|
|
- rinfo[val].usr_ptr =
|
|
- srp->header.usr_ptr;
|
|
- }
|
|
- }
|
|
+ sg_fill_request_table(sfp, rinfo);
|
|
read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
|
|
- result = __copy_to_user(p, rinfo,
|
|
+ result = __copy_to_user(p, rinfo,
|
|
SZ_SG_REQ_INFO * SG_MAX_QUEUE);
|
|
result = result ? -EFAULT : 0;
|
|
kfree(rinfo);
|
|
@@ -1173,7 +1179,7 @@ sg_poll(struct file *filp, poll_table * wait)
|
|
return POLLERR;
|
|
poll_wait(filp, &sfp->read_wait, wait);
|
|
read_lock_irqsave(&sfp->rq_list_lock, iflags);
|
|
- for (srp = sfp->headrp; srp; srp = srp->nextrp) {
|
|
+ list_for_each_entry(srp, &sfp->rq_list, entry) {
|
|
/* if any read waiting, flag it */
|
|
if ((0 == res) && (1 == srp->done) && (!srp->sg_io_owned))
|
|
res = POLLIN | POLLRDNORM;
|
|
@@ -2059,7 +2065,6 @@ sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp)
|
|
req_schp->pages = NULL;
|
|
req_schp->page_order = 0;
|
|
req_schp->sglist_len = 0;
|
|
- sfp->save_scat_len = 0;
|
|
srp->res_used = 0;
|
|
/* Called without mutex lock to avoid deadlock */
|
|
sfp->res_in_use = 0;
|
|
@@ -2072,7 +2077,7 @@ sg_get_rq_mark(Sg_fd * sfp, int pack_id)
|
|
unsigned long iflags;
|
|
|
|
write_lock_irqsave(&sfp->rq_list_lock, iflags);
|
|
- for (resp = sfp->headrp; resp; resp = resp->nextrp) {
|
|
+ list_for_each_entry(resp, &sfp->rq_list, entry) {
|
|
/* look for requests that are ready + not SG_IO owned */
|
|
if ((1 == resp->done) && (!resp->sg_io_owned) &&
|
|
((-1 == pack_id) || (resp->header.pack_id == pack_id))) {
|
|
@@ -2090,70 +2095,45 @@ sg_add_request(Sg_fd * sfp)
|
|
{
|
|
int k;
|
|
unsigned long iflags;
|
|
- Sg_request *resp;
|
|
Sg_request *rp = sfp->req_arr;
|
|
|
|
write_lock_irqsave(&sfp->rq_list_lock, iflags);
|
|
- resp = sfp->headrp;
|
|
- if (!resp) {
|
|
- memset(rp, 0, sizeof (Sg_request));
|
|
- rp->parentfp = sfp;
|
|
- resp = rp;
|
|
- sfp->headrp = resp;
|
|
- } else {
|
|
- if (0 == sfp->cmd_q)
|
|
- resp = NULL; /* command queuing disallowed */
|
|
- else {
|
|
- for (k = 0; k < SG_MAX_QUEUE; ++k, ++rp) {
|
|
- if (!rp->parentfp)
|
|
- break;
|
|
- }
|
|
- if (k < SG_MAX_QUEUE) {
|
|
- memset(rp, 0, sizeof (Sg_request));
|
|
- rp->parentfp = sfp;
|
|
- while (resp->nextrp)
|
|
- resp = resp->nextrp;
|
|
- resp->nextrp = rp;
|
|
- resp = rp;
|
|
- } else
|
|
- resp = NULL;
|
|
+ if (!list_empty(&sfp->rq_list)) {
|
|
+ if (!sfp->cmd_q)
|
|
+ goto out_unlock;
|
|
+
|
|
+ for (k = 0; k < SG_MAX_QUEUE; ++k, ++rp) {
|
|
+ if (!rp->parentfp)
|
|
+ break;
|
|
}
|
|
+ if (k >= SG_MAX_QUEUE)
|
|
+ goto out_unlock;
|
|
}
|
|
- if (resp) {
|
|
- resp->nextrp = NULL;
|
|
- resp->header.duration = jiffies_to_msecs(jiffies);
|
|
- }
|
|
+ memset(rp, 0, sizeof (Sg_request));
|
|
+ rp->parentfp = sfp;
|
|
+ rp->header.duration = jiffies_to_msecs(jiffies);
|
|
+ list_add_tail(&rp->entry, &sfp->rq_list);
|
|
write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
|
|
- return resp;
|
|
+ return rp;
|
|
+out_unlock:
|
|
+ write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
|
|
+ return NULL;
|
|
}
|
|
|
|
/* Return of 1 for found; 0 for not found */
|
|
static int
|
|
sg_remove_request(Sg_fd * sfp, Sg_request * srp)
|
|
{
|
|
- Sg_request *prev_rp;
|
|
- Sg_request *rp;
|
|
unsigned long iflags;
|
|
int res = 0;
|
|
|
|
- if ((!sfp) || (!srp) || (!sfp->headrp))
|
|
+ if (!sfp || !srp || list_empty(&sfp->rq_list))
|
|
return res;
|
|
write_lock_irqsave(&sfp->rq_list_lock, iflags);
|
|
- prev_rp = sfp->headrp;
|
|
- if (srp == prev_rp) {
|
|
- sfp->headrp = prev_rp->nextrp;
|
|
- prev_rp->parentfp = NULL;
|
|
+ if (!list_empty(&srp->entry)) {
|
|
+ list_del(&srp->entry);
|
|
+ srp->parentfp = NULL;
|
|
res = 1;
|
|
- } else {
|
|
- while ((rp = prev_rp->nextrp)) {
|
|
- if (srp == rp) {
|
|
- prev_rp->nextrp = rp->nextrp;
|
|
- rp->parentfp = NULL;
|
|
- res = 1;
|
|
- break;
|
|
- }
|
|
- prev_rp = rp;
|
|
- }
|
|
}
|
|
write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
|
|
return res;
|
|
@@ -2172,7 +2152,7 @@ sg_add_sfp(Sg_device * sdp)
|
|
|
|
init_waitqueue_head(&sfp->read_wait);
|
|
rwlock_init(&sfp->rq_list_lock);
|
|
-
|
|
+ INIT_LIST_HEAD(&sfp->rq_list);
|
|
kref_init(&sfp->f_ref);
|
|
mutex_init(&sfp->f_mutex);
|
|
sfp->timeout = SG_DEFAULT_TIMEOUT;
|
|
@@ -2213,10 +2193,13 @@ sg_remove_sfp_usercontext(struct work_struct *work)
|
|
{
|
|
struct sg_fd *sfp = container_of(work, struct sg_fd, ew.work);
|
|
struct sg_device *sdp = sfp->parentdp;
|
|
+ Sg_request *srp;
|
|
|
|
/* Cleanup any responses which were never read(). */
|
|
- while (sfp->headrp)
|
|
- sg_finish_rem_req(sfp->headrp);
|
|
+ while (!list_empty(&sfp->rq_list)) {
|
|
+ srp = list_first_entry(&sfp->rq_list, Sg_request, entry);
|
|
+ sg_finish_rem_req(srp);
|
|
+ }
|
|
|
|
if (sfp->reserve.bufflen > 0) {
|
|
SCSI_LOG_TIMEOUT(6, sg_printk(KERN_INFO, sdp,
|
|
@@ -2619,7 +2602,7 @@ static int sg_proc_seq_show_devstrs(struct seq_file *s, void *v)
|
|
/* must be called while holding sg_index_lock */
|
|
static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp)
|
|
{
|
|
- int k, m, new_interface, blen, usg;
|
|
+ int k, new_interface, blen, usg;
|
|
Sg_request *srp;
|
|
Sg_fd *fp;
|
|
const sg_io_hdr_t *hp;
|
|
@@ -2639,13 +2622,11 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp)
|
|
seq_printf(s, " cmd_q=%d f_packid=%d k_orphan=%d closed=0\n",
|
|
(int) fp->cmd_q, (int) fp->force_packid,
|
|
(int) fp->keep_orphan);
|
|
- for (m = 0, srp = fp->headrp;
|
|
- srp != NULL;
|
|
- ++m, srp = srp->nextrp) {
|
|
+ list_for_each_entry(srp, &fp->rq_list, entry) {
|
|
hp = &srp->header;
|
|
new_interface = (hp->interface_id == '\0') ? 0 : 1;
|
|
if (srp->res_used) {
|
|
- if (new_interface &&
|
|
+ if (new_interface &&
|
|
(SG_FLAG_MMAP_IO & hp->flags))
|
|
cp = " mmap>> ";
|
|
else
|
|
@@ -2676,7 +2657,7 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp)
|
|
seq_printf(s, "ms sgat=%d op=0x%02x\n", usg,
|
|
(int) srp->data.cmd_opcode);
|
|
}
|
|
- if (0 == m)
|
|
+ if (list_empty(&fp->rq_list))
|
|
seq_puts(s, " No requests active\n");
|
|
read_unlock(&fp->rq_list_lock);
|
|
}
|
|
diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
|
|
index cd5c1c060481..6df2841cb7f9 100644
|
|
--- a/drivers/scsi/storvsc_drv.c
|
|
+++ b/drivers/scsi/storvsc_drv.c
|
|
@@ -1511,6 +1511,8 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
|
|
ret = storvsc_do_io(dev, cmd_request);
|
|
|
|
if (ret == -EAGAIN) {
|
|
+ if (payload_sz > sizeof(cmd_request->mpb))
|
|
+ kfree(payload);
|
|
/* no more space */
|
|
return SCSI_MLQUEUE_DEVICE_BUSY;
|
|
}
|
|
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
|
|
index fb31eecb708d..8f3566cde3eb 100644
|
|
--- a/drivers/tty/tty_buffer.c
|
|
+++ b/drivers/tty/tty_buffer.c
|
|
@@ -361,6 +361,32 @@ int tty_insert_flip_string_flags(struct tty_port *port,
|
|
}
|
|
EXPORT_SYMBOL(tty_insert_flip_string_flags);
|
|
|
|
+/**
|
|
+ * __tty_insert_flip_char - Add one character to the tty buffer
|
|
+ * @port: tty port
|
|
+ * @ch: character
|
|
+ * @flag: flag byte
|
|
+ *
|
|
+ * Queue a single byte to the tty buffering, with an optional flag.
|
|
+ * This is the slow path of tty_insert_flip_char.
|
|
+ */
|
|
+int __tty_insert_flip_char(struct tty_port *port, unsigned char ch, char flag)
|
|
+{
|
|
+ struct tty_buffer *tb;
|
|
+ int flags = (flag == TTY_NORMAL) ? TTYB_NORMAL : 0;
|
|
+
|
|
+ if (!__tty_buffer_request_room(port, 1, flags))
|
|
+ return 0;
|
|
+
|
|
+ tb = port->buf.tail;
|
|
+ if (~tb->flags & TTYB_NORMAL)
|
|
+ *flag_buf_ptr(tb, tb->used) = flag;
|
|
+ *char_buf_ptr(tb, tb->used++) = ch;
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+EXPORT_SYMBOL(__tty_insert_flip_char);
|
|
+
|
|
/**
|
|
* tty_schedule_flip - push characters to ldisc
|
|
* @port: tty port to push from
|
|
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
|
|
index 68345a9e59b8..32941cd6d34b 100644
|
|
--- a/fs/ext4/super.c
|
|
+++ b/fs/ext4/super.c
|
|
@@ -2205,6 +2205,7 @@ static void ext4_orphan_cleanup(struct super_block *sb,
|
|
unsigned int s_flags = sb->s_flags;
|
|
int nr_orphans = 0, nr_truncates = 0;
|
|
#ifdef CONFIG_QUOTA
|
|
+ int quota_update = 0;
|
|
int i;
|
|
#endif
|
|
if (!es->s_last_orphan) {
|
|
@@ -2243,14 +2244,32 @@ static void ext4_orphan_cleanup(struct super_block *sb,
|
|
#ifdef CONFIG_QUOTA
|
|
/* Needed for iput() to work correctly and not trash data */
|
|
sb->s_flags |= MS_ACTIVE;
|
|
- /* Turn on quotas so that they are updated correctly */
|
|
+
|
|
+ /*
|
|
+ * Turn on quotas which were not enabled for read-only mounts if
|
|
+ * filesystem has quota feature, so that they are updated correctly.
|
|
+ */
|
|
+ if (ext4_has_feature_quota(sb) && (s_flags & MS_RDONLY)) {
|
|
+ int ret = ext4_enable_quotas(sb);
|
|
+
|
|
+ if (!ret)
|
|
+ quota_update = 1;
|
|
+ else
|
|
+ ext4_msg(sb, KERN_ERR,
|
|
+ "Cannot turn on quotas: error %d", ret);
|
|
+ }
|
|
+
|
|
+ /* Turn on journaled quotas used for old sytle */
|
|
for (i = 0; i < EXT4_MAXQUOTAS; i++) {
|
|
if (EXT4_SB(sb)->s_qf_names[i]) {
|
|
int ret = ext4_quota_on_mount(sb, i);
|
|
- if (ret < 0)
|
|
+
|
|
+ if (!ret)
|
|
+ quota_update = 1;
|
|
+ else
|
|
ext4_msg(sb, KERN_ERR,
|
|
"Cannot turn on journaled "
|
|
- "quota: error %d", ret);
|
|
+ "quota: type %d: error %d", i, ret);
|
|
}
|
|
}
|
|
#endif
|
|
@@ -2309,10 +2328,12 @@ static void ext4_orphan_cleanup(struct super_block *sb,
|
|
ext4_msg(sb, KERN_INFO, "%d truncate%s cleaned up",
|
|
PLURAL(nr_truncates));
|
|
#ifdef CONFIG_QUOTA
|
|
- /* Turn quotas off */
|
|
- for (i = 0; i < EXT4_MAXQUOTAS; i++) {
|
|
- if (sb_dqopt(sb)->files[i])
|
|
- dquot_quota_off(sb, i);
|
|
+ /* Turn off quotas if they were enabled for orphan cleanup */
|
|
+ if (quota_update) {
|
|
+ for (i = 0; i < EXT4_MAXQUOTAS; i++) {
|
|
+ if (sb_dqopt(sb)->files[i])
|
|
+ dquot_quota_off(sb, i);
|
|
+ }
|
|
}
|
|
#endif
|
|
sb->s_flags = s_flags; /* Restore MS_RDONLY status */
|
|
@@ -5120,6 +5141,9 @@ static int ext4_enable_quotas(struct super_block *sb)
|
|
err = ext4_quota_enable(sb, type, QFMT_VFS_V1,
|
|
DQUOT_USAGE_ENABLED);
|
|
if (err) {
|
|
+ for (type--; type >= 0; type--)
|
|
+ dquot_quota_off(sb, type);
|
|
+
|
|
ext4_warning(sb,
|
|
"Failed to enable quota tracking "
|
|
"(type=%d, err=%d). Please run "
|
|
diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c
|
|
index cbf74f47cce8..e32f349f341b 100644
|
|
--- a/fs/f2fs/recovery.c
|
|
+++ b/fs/f2fs/recovery.c
|
|
@@ -276,7 +276,7 @@ static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi,
|
|
return 0;
|
|
|
|
/* Get the previous summary */
|
|
- for (i = CURSEG_WARM_DATA; i <= CURSEG_COLD_DATA; i++) {
|
|
+ for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) {
|
|
struct curseg_info *curseg = CURSEG_I(sbi, i);
|
|
if (curseg->segno == segno) {
|
|
sum = curseg->sum_blk->entries[blkoff];
|
|
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
|
|
index c7f1ce41442a..9e5a6842346e 100644
|
|
--- a/fs/nfsd/nfs4state.c
|
|
+++ b/fs/nfsd/nfs4state.c
|
|
@@ -1145,9 +1145,7 @@ static void put_ol_stateid_locked(struct nfs4_ol_stateid *stp,
|
|
|
|
static bool unhash_lock_stateid(struct nfs4_ol_stateid *stp)
|
|
{
|
|
- struct nfs4_openowner *oo = openowner(stp->st_openstp->st_stateowner);
|
|
-
|
|
- lockdep_assert_held(&oo->oo_owner.so_client->cl_lock);
|
|
+ lockdep_assert_held(&stp->st_stid.sc_client->cl_lock);
|
|
|
|
list_del_init(&stp->st_locks);
|
|
nfs4_unhash_stid(&stp->st_stid);
|
|
@@ -1156,12 +1154,12 @@ static bool unhash_lock_stateid(struct nfs4_ol_stateid *stp)
|
|
|
|
static void release_lock_stateid(struct nfs4_ol_stateid *stp)
|
|
{
|
|
- struct nfs4_openowner *oo = openowner(stp->st_openstp->st_stateowner);
|
|
+ struct nfs4_client *clp = stp->st_stid.sc_client;
|
|
bool unhashed;
|
|
|
|
- spin_lock(&oo->oo_owner.so_client->cl_lock);
|
|
+ spin_lock(&clp->cl_lock);
|
|
unhashed = unhash_lock_stateid(stp);
|
|
- spin_unlock(&oo->oo_owner.so_client->cl_lock);
|
|
+ spin_unlock(&clp->cl_lock);
|
|
if (unhashed)
|
|
nfs4_put_stid(&stp->st_stid);
|
|
}
|
|
diff --git a/include/linux/tty_flip.h b/include/linux/tty_flip.h
|
|
index c28dd523f96e..d43837f2ce3a 100644
|
|
--- a/include/linux/tty_flip.h
|
|
+++ b/include/linux/tty_flip.h
|
|
@@ -12,6 +12,7 @@ extern int tty_prepare_flip_string(struct tty_port *port,
|
|
unsigned char **chars, size_t size);
|
|
extern void tty_flip_buffer_push(struct tty_port *port);
|
|
void tty_schedule_flip(struct tty_port *port);
|
|
+int __tty_insert_flip_char(struct tty_port *port, unsigned char ch, char flag);
|
|
|
|
static inline int tty_insert_flip_char(struct tty_port *port,
|
|
unsigned char ch, char flag)
|
|
@@ -26,7 +27,7 @@ static inline int tty_insert_flip_char(struct tty_port *port,
|
|
*char_buf_ptr(tb, tb->used++) = ch;
|
|
return 1;
|
|
}
|
|
- return tty_insert_flip_string_flags(port, &ch, &flag, 1);
|
|
+ return __tty_insert_flip_char(port, ch, flag);
|
|
}
|
|
|
|
static inline int tty_insert_flip_string(struct tty_port *port,
|
|
diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h
|
|
index ac42bbb37b2d..c26a6e4dc306 100644
|
|
--- a/include/net/inet_frag.h
|
|
+++ b/include/net/inet_frag.h
|
|
@@ -1,14 +1,9 @@
|
|
#ifndef __NET_FRAG_H__
|
|
#define __NET_FRAG_H__
|
|
|
|
-#include <linux/percpu_counter.h>
|
|
-
|
|
struct netns_frags {
|
|
- /* The percpu_counter "mem" need to be cacheline aligned.
|
|
- * mem.count must not share cacheline with other writers
|
|
- */
|
|
- struct percpu_counter mem ____cacheline_aligned_in_smp;
|
|
-
|
|
+ /* Keep atomic mem on separate cachelines in structs that include it */
|
|
+ atomic_t mem ____cacheline_aligned_in_smp;
|
|
/* sysctls */
|
|
int timeout;
|
|
int high_thresh;
|
|
@@ -108,15 +103,10 @@ struct inet_frags {
|
|
int inet_frags_init(struct inet_frags *);
|
|
void inet_frags_fini(struct inet_frags *);
|
|
|
|
-static inline int inet_frags_init_net(struct netns_frags *nf)
|
|
-{
|
|
- return percpu_counter_init(&nf->mem, 0, GFP_KERNEL);
|
|
-}
|
|
-static inline void inet_frags_uninit_net(struct netns_frags *nf)
|
|
+static inline void inet_frags_init_net(struct netns_frags *nf)
|
|
{
|
|
- percpu_counter_destroy(&nf->mem);
|
|
+ atomic_set(&nf->mem, 0);
|
|
}
|
|
-
|
|
void inet_frags_exit_net(struct netns_frags *nf, struct inet_frags *f);
|
|
|
|
void inet_frag_kill(struct inet_frag_queue *q, struct inet_frags *f);
|
|
@@ -140,37 +130,24 @@ static inline bool inet_frag_evicting(struct inet_frag_queue *q)
|
|
|
|
/* Memory Tracking Functions. */
|
|
|
|
-/* The default percpu_counter batch size is not big enough to scale to
|
|
- * fragmentation mem acct sizes.
|
|
- * The mem size of a 64K fragment is approx:
|
|
- * (44 fragments * 2944 truesize) + frag_queue struct(200) = 129736 bytes
|
|
- */
|
|
-static unsigned int frag_percpu_counter_batch = 130000;
|
|
-
|
|
static inline int frag_mem_limit(struct netns_frags *nf)
|
|
{
|
|
- return percpu_counter_read(&nf->mem);
|
|
+ return atomic_read(&nf->mem);
|
|
}
|
|
|
|
static inline void sub_frag_mem_limit(struct netns_frags *nf, int i)
|
|
{
|
|
- __percpu_counter_add(&nf->mem, -i, frag_percpu_counter_batch);
|
|
+ atomic_sub(i, &nf->mem);
|
|
}
|
|
|
|
static inline void add_frag_mem_limit(struct netns_frags *nf, int i)
|
|
{
|
|
- __percpu_counter_add(&nf->mem, i, frag_percpu_counter_batch);
|
|
+ atomic_add(i, &nf->mem);
|
|
}
|
|
|
|
-static inline unsigned int sum_frag_mem_limit(struct netns_frags *nf)
|
|
+static inline int sum_frag_mem_limit(struct netns_frags *nf)
|
|
{
|
|
- unsigned int res;
|
|
-
|
|
- local_bh_disable();
|
|
- res = percpu_counter_sum_positive(&nf->mem);
|
|
- local_bh_enable();
|
|
-
|
|
- return res;
|
|
+ return atomic_read(&nf->mem);
|
|
}
|
|
|
|
/* RFC 3168 support :
|
|
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
|
|
index fb961a576abe..fa5e703a14ed 100644
|
|
--- a/include/net/ip6_fib.h
|
|
+++ b/include/net/ip6_fib.h
|
|
@@ -68,6 +68,7 @@ struct fib6_node {
|
|
__u16 fn_flags;
|
|
int fn_sernum;
|
|
struct rt6_info *rr_ptr;
|
|
+ struct rcu_head rcu;
|
|
};
|
|
|
|
#ifndef CONFIG_IPV6_SUBTREES
|
|
@@ -102,7 +103,7 @@ struct rt6_info {
|
|
* the same cache line.
|
|
*/
|
|
struct fib6_table *rt6i_table;
|
|
- struct fib6_node *rt6i_node;
|
|
+ struct fib6_node __rcu *rt6i_node;
|
|
|
|
struct in6_addr rt6i_gateway;
|
|
|
|
@@ -165,13 +166,40 @@ static inline void rt6_update_expires(struct rt6_info *rt0, int timeout)
|
|
rt0->rt6i_flags |= RTF_EXPIRES;
|
|
}
|
|
|
|
+/* Function to safely get fn->sernum for passed in rt
|
|
+ * and store result in passed in cookie.
|
|
+ * Return true if we can get cookie safely
|
|
+ * Return false if not
|
|
+ */
|
|
+static inline bool rt6_get_cookie_safe(const struct rt6_info *rt,
|
|
+ u32 *cookie)
|
|
+{
|
|
+ struct fib6_node *fn;
|
|
+ bool status = false;
|
|
+
|
|
+ rcu_read_lock();
|
|
+ fn = rcu_dereference(rt->rt6i_node);
|
|
+
|
|
+ if (fn) {
|
|
+ *cookie = fn->fn_sernum;
|
|
+ status = true;
|
|
+ }
|
|
+
|
|
+ rcu_read_unlock();
|
|
+ return status;
|
|
+}
|
|
+
|
|
static inline u32 rt6_get_cookie(const struct rt6_info *rt)
|
|
{
|
|
+ u32 cookie = 0;
|
|
+
|
|
if (rt->rt6i_flags & RTF_PCPU ||
|
|
(unlikely(rt->dst.flags & DST_NOCACHE) && rt->dst.from))
|
|
rt = (struct rt6_info *)(rt->dst.from);
|
|
|
|
- return rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0;
|
|
+ rt6_get_cookie_safe(rt, &cookie);
|
|
+
|
|
+ return cookie;
|
|
}
|
|
|
|
static inline void ip6_rt_put(struct rt6_info *rt)
|
|
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
|
|
index eba904bae48c..38d73a6e2857 100644
|
|
--- a/kernel/trace/ftrace.c
|
|
+++ b/kernel/trace/ftrace.c
|
|
@@ -2667,13 +2667,14 @@ static int ftrace_shutdown(struct ftrace_ops *ops, int command)
|
|
|
|
if (!command || !ftrace_enabled) {
|
|
/*
|
|
- * If these are control ops, they still need their
|
|
- * per_cpu field freed. Since, function tracing is
|
|
+ * If these are dynamic or control ops, they still
|
|
+ * need their data freed. Since, function tracing is
|
|
* not currently active, we can just free them
|
|
* without synchronizing all CPUs.
|
|
*/
|
|
- if (ops->flags & FTRACE_OPS_FL_CONTROL)
|
|
- control_ops_free(ops);
|
|
+ if (ops->flags & (FTRACE_OPS_FL_DYNAMIC | FTRACE_OPS_FL_CONTROL))
|
|
+ goto free_ops;
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -2728,6 +2729,7 @@ static int ftrace_shutdown(struct ftrace_ops *ops, int command)
|
|
if (ops->flags & (FTRACE_OPS_FL_DYNAMIC | FTRACE_OPS_FL_CONTROL)) {
|
|
schedule_on_each_cpu(ftrace_sync);
|
|
|
|
+ free_ops:
|
|
arch_ftrace_trampoline_free(ops);
|
|
|
|
if (ops->flags & FTRACE_OPS_FL_CONTROL)
|
|
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
|
|
index d59ebd9d21df..4743066010c4 100644
|
|
--- a/kernel/trace/trace.c
|
|
+++ b/kernel/trace/trace.c
|
|
@@ -5237,7 +5237,7 @@ static int tracing_set_clock(struct trace_array *tr, const char *clockstr)
|
|
tracing_reset_online_cpus(&tr->trace_buffer);
|
|
|
|
#ifdef CONFIG_TRACER_MAX_TRACE
|
|
- if (tr->flags & TRACE_ARRAY_FL_GLOBAL && tr->max_buffer.buffer)
|
|
+ if (tr->max_buffer.buffer)
|
|
ring_buffer_set_clock(tr->max_buffer.buffer, trace_clocks[i].func);
|
|
tracing_reset_online_cpus(&tr->max_buffer);
|
|
#endif
|
|
diff --git a/kernel/trace/trace_selftest.c b/kernel/trace/trace_selftest.c
|
|
index b0f86ea77881..ca70d11b8aa7 100644
|
|
--- a/kernel/trace/trace_selftest.c
|
|
+++ b/kernel/trace/trace_selftest.c
|
|
@@ -272,7 +272,7 @@ static int trace_selftest_ops(struct trace_array *tr, int cnt)
|
|
goto out_free;
|
|
if (cnt > 1) {
|
|
if (trace_selftest_test_global_cnt == 0)
|
|
- goto out;
|
|
+ goto out_free;
|
|
}
|
|
if (trace_selftest_test_dyn_cnt == 0)
|
|
goto out_free;
|
|
diff --git a/net/ieee802154/6lowpan/reassembly.c b/net/ieee802154/6lowpan/reassembly.c
|
|
index 6b437e8760d3..12e8cf4bda9f 100644
|
|
--- a/net/ieee802154/6lowpan/reassembly.c
|
|
+++ b/net/ieee802154/6lowpan/reassembly.c
|
|
@@ -580,19 +580,14 @@ static int __net_init lowpan_frags_init_net(struct net *net)
|
|
{
|
|
struct netns_ieee802154_lowpan *ieee802154_lowpan =
|
|
net_ieee802154_lowpan(net);
|
|
- int res;
|
|
|
|
ieee802154_lowpan->frags.high_thresh = IPV6_FRAG_HIGH_THRESH;
|
|
ieee802154_lowpan->frags.low_thresh = IPV6_FRAG_LOW_THRESH;
|
|
ieee802154_lowpan->frags.timeout = IPV6_FRAG_TIMEOUT;
|
|
|
|
- res = inet_frags_init_net(&ieee802154_lowpan->frags);
|
|
- if (res)
|
|
- return res;
|
|
- res = lowpan_frags_ns_sysctl_register(net);
|
|
- if (res)
|
|
- inet_frags_uninit_net(&ieee802154_lowpan->frags);
|
|
- return res;
|
|
+ inet_frags_init_net(&ieee802154_lowpan->frags);
|
|
+
|
|
+ return lowpan_frags_ns_sysctl_register(net);
|
|
}
|
|
|
|
static void __net_exit lowpan_frags_exit_net(struct net *net)
|
|
diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c
|
|
index fe144dae7372..c5fb2f694ed0 100644
|
|
--- a/net/ipv4/inet_fragment.c
|
|
+++ b/net/ipv4/inet_fragment.c
|
|
@@ -234,10 +234,8 @@ evict_again:
|
|
cond_resched();
|
|
|
|
if (read_seqretry(&f->rnd_seqlock, seq) ||
|
|
- percpu_counter_sum(&nf->mem))
|
|
+ sum_frag_mem_limit(nf))
|
|
goto evict_again;
|
|
-
|
|
- percpu_counter_destroy(&nf->mem);
|
|
}
|
|
EXPORT_SYMBOL(inet_frags_exit_net);
|
|
|
|
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
|
|
index b8a0607dab96..e2e162432aa3 100644
|
|
--- a/net/ipv4/ip_fragment.c
|
|
+++ b/net/ipv4/ip_fragment.c
|
|
@@ -840,8 +840,6 @@ static void __init ip4_frags_ctl_register(void)
|
|
|
|
static int __net_init ipv4_frags_init_net(struct net *net)
|
|
{
|
|
- int res;
|
|
-
|
|
/* Fragment cache limits.
|
|
*
|
|
* The fragment memory accounting code, (tries to) account for
|
|
@@ -865,13 +863,9 @@ static int __net_init ipv4_frags_init_net(struct net *net)
|
|
*/
|
|
net->ipv4.frags.timeout = IP_FRAG_TIME;
|
|
|
|
- res = inet_frags_init_net(&net->ipv4.frags);
|
|
- if (res)
|
|
- return res;
|
|
- res = ip4_frags_ns_ctl_register(net);
|
|
- if (res)
|
|
- inet_frags_uninit_net(&net->ipv4.frags);
|
|
- return res;
|
|
+ inet_frags_init_net(&net->ipv4.frags);
|
|
+
|
|
+ return ip4_frags_ns_ctl_register(net);
|
|
}
|
|
|
|
static void __net_exit ipv4_frags_exit_net(struct net *net)
|
|
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
|
|
index 0870a86e9d96..5597120c8ffd 100644
|
|
--- a/net/ipv4/tcp.c
|
|
+++ b/net/ipv4/tcp.c
|
|
@@ -2260,6 +2260,10 @@ int tcp_disconnect(struct sock *sk, int flags)
|
|
tcp_set_ca_state(sk, TCP_CA_Open);
|
|
tcp_clear_retrans(tp);
|
|
inet_csk_delack_init(sk);
|
|
+ /* Initialize rcv_mss to TCP_MIN_MSS to avoid division by 0
|
|
+ * issue in __tcp_select_window()
|
|
+ */
|
|
+ icsk->icsk_ack.rcv_mss = TCP_MIN_MSS;
|
|
tcp_init_send_head(sk);
|
|
memset(&tp->rx_opt, 0, sizeof(tp->rx_opt));
|
|
__sk_dst_reset(sk);
|
|
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
|
|
index 735b22b1b4ea..92174881844d 100644
|
|
--- a/net/ipv6/addrconf.c
|
|
+++ b/net/ipv6/addrconf.c
|
|
@@ -5152,7 +5152,7 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
|
|
* our DAD process, so we don't need
|
|
* to do it again
|
|
*/
|
|
- if (!(ifp->rt->rt6i_node))
|
|
+ if (!rcu_access_pointer(ifp->rt->rt6i_node))
|
|
ip6_ins_rt(ifp->rt);
|
|
if (ifp->idev->cnf.forwarding)
|
|
addrconf_join_anycast(ifp);
|
|
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
|
|
index aad8cdf15472..c23e02a7ccb0 100644
|
|
--- a/net/ipv6/ip6_fib.c
|
|
+++ b/net/ipv6/ip6_fib.c
|
|
@@ -150,11 +150,23 @@ static struct fib6_node *node_alloc(void)
|
|
return fn;
|
|
}
|
|
|
|
-static void node_free(struct fib6_node *fn)
|
|
+static void node_free_immediate(struct fib6_node *fn)
|
|
+{
|
|
+ kmem_cache_free(fib6_node_kmem, fn);
|
|
+}
|
|
+
|
|
+static void node_free_rcu(struct rcu_head *head)
|
|
{
|
|
+ struct fib6_node *fn = container_of(head, struct fib6_node, rcu);
|
|
+
|
|
kmem_cache_free(fib6_node_kmem, fn);
|
|
}
|
|
|
|
+static void node_free(struct fib6_node *fn)
|
|
+{
|
|
+ call_rcu(&fn->rcu, node_free_rcu);
|
|
+}
|
|
+
|
|
static void rt6_rcu_free(struct rt6_info *rt)
|
|
{
|
|
call_rcu(&rt->dst.rcu_head, dst_rcu_free);
|
|
@@ -191,6 +203,12 @@ static void rt6_release(struct rt6_info *rt)
|
|
}
|
|
}
|
|
|
|
+static void fib6_free_table(struct fib6_table *table)
|
|
+{
|
|
+ inetpeer_invalidate_tree(&table->tb6_peers);
|
|
+ kfree(table);
|
|
+}
|
|
+
|
|
static void fib6_link_table(struct net *net, struct fib6_table *tb)
|
|
{
|
|
unsigned int h;
|
|
@@ -588,9 +606,9 @@ insert_above:
|
|
|
|
if (!in || !ln) {
|
|
if (in)
|
|
- node_free(in);
|
|
+ node_free_immediate(in);
|
|
if (ln)
|
|
- node_free(ln);
|
|
+ node_free_immediate(ln);
|
|
return ERR_PTR(-ENOMEM);
|
|
}
|
|
|
|
@@ -857,7 +875,7 @@ add:
|
|
|
|
rt->dst.rt6_next = iter;
|
|
*ins = rt;
|
|
- rt->rt6i_node = fn;
|
|
+ rcu_assign_pointer(rt->rt6i_node, fn);
|
|
atomic_inc(&rt->rt6i_ref);
|
|
inet6_rt_notify(RTM_NEWROUTE, rt, info, 0);
|
|
info->nl_net->ipv6.rt6_stats->fib_rt_entries++;
|
|
@@ -882,7 +900,7 @@ add:
|
|
return err;
|
|
|
|
*ins = rt;
|
|
- rt->rt6i_node = fn;
|
|
+ rcu_assign_pointer(rt->rt6i_node, fn);
|
|
rt->dst.rt6_next = iter->dst.rt6_next;
|
|
atomic_inc(&rt->rt6i_ref);
|
|
inet6_rt_notify(RTM_NEWROUTE, rt, info, NLM_F_REPLACE);
|
|
@@ -1015,7 +1033,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt,
|
|
root, and then (in failure) stale node
|
|
in main tree.
|
|
*/
|
|
- node_free(sfn);
|
|
+ node_free_immediate(sfn);
|
|
err = PTR_ERR(sn);
|
|
goto failure;
|
|
}
|
|
@@ -1442,8 +1460,9 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
|
|
|
|
int fib6_del(struct rt6_info *rt, struct nl_info *info)
|
|
{
|
|
+ struct fib6_node *fn = rcu_dereference_protected(rt->rt6i_node,
|
|
+ lockdep_is_held(&rt->rt6i_table->tb6_lock));
|
|
struct net *net = info->nl_net;
|
|
- struct fib6_node *fn = rt->rt6i_node;
|
|
struct rt6_info **rtp;
|
|
|
|
#if RT6_DEBUG >= 2
|
|
@@ -1632,7 +1651,9 @@ static int fib6_clean_node(struct fib6_walker *w)
|
|
if (res) {
|
|
#if RT6_DEBUG >= 2
|
|
pr_debug("%s: del failed: rt=%p@%p err=%d\n",
|
|
- __func__, rt, rt->rt6i_node, res);
|
|
+ __func__, rt,
|
|
+ rcu_access_pointer(rt->rt6i_node),
|
|
+ res);
|
|
#endif
|
|
continue;
|
|
}
|
|
@@ -1870,15 +1891,22 @@ out_timer:
|
|
|
|
static void fib6_net_exit(struct net *net)
|
|
{
|
|
+ unsigned int i;
|
|
+
|
|
rt6_ifdown(net, NULL);
|
|
del_timer_sync(&net->ipv6.ip6_fib_timer);
|
|
|
|
-#ifdef CONFIG_IPV6_MULTIPLE_TABLES
|
|
- inetpeer_invalidate_tree(&net->ipv6.fib6_local_tbl->tb6_peers);
|
|
- kfree(net->ipv6.fib6_local_tbl);
|
|
-#endif
|
|
- inetpeer_invalidate_tree(&net->ipv6.fib6_main_tbl->tb6_peers);
|
|
- kfree(net->ipv6.fib6_main_tbl);
|
|
+ for (i = 0; i < FIB6_TABLE_HASHSZ; i++) {
|
|
+ struct hlist_head *head = &net->ipv6.fib_table_hash[i];
|
|
+ struct hlist_node *tmp;
|
|
+ struct fib6_table *tb;
|
|
+
|
|
+ hlist_for_each_entry_safe(tb, tmp, head, tb6_hlist) {
|
|
+ hlist_del(&tb->tb6_hlist);
|
|
+ fib6_free_table(tb);
|
|
+ }
|
|
+ }
|
|
+
|
|
kfree(net->ipv6.fib_table_hash);
|
|
kfree(net->ipv6.rt6_stats);
|
|
}
|
|
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
|
|
index bab4441ed4e4..eb2dc39f7066 100644
|
|
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
|
|
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
|
|
@@ -649,18 +649,12 @@ EXPORT_SYMBOL_GPL(nf_ct_frag6_consume_orig);
|
|
|
|
static int nf_ct_net_init(struct net *net)
|
|
{
|
|
- int res;
|
|
-
|
|
net->nf_frag.frags.high_thresh = IPV6_FRAG_HIGH_THRESH;
|
|
net->nf_frag.frags.low_thresh = IPV6_FRAG_LOW_THRESH;
|
|
net->nf_frag.frags.timeout = IPV6_FRAG_TIMEOUT;
|
|
- res = inet_frags_init_net(&net->nf_frag.frags);
|
|
- if (res)
|
|
- return res;
|
|
- res = nf_ct_frag6_sysctl_register(net);
|
|
- if (res)
|
|
- inet_frags_uninit_net(&net->nf_frag.frags);
|
|
- return res;
|
|
+ inet_frags_init_net(&net->nf_frag.frags);
|
|
+
|
|
+ return nf_ct_frag6_sysctl_register(net);
|
|
}
|
|
|
|
static void nf_ct_net_exit(struct net *net)
|
|
diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c
|
|
index f9f02581c4ca..f99a04674419 100644
|
|
--- a/net/ipv6/output_core.c
|
|
+++ b/net/ipv6/output_core.c
|
|
@@ -86,7 +86,6 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
|
|
|
|
while (offset <= packet_len) {
|
|
struct ipv6_opt_hdr *exthdr;
|
|
- unsigned int len;
|
|
|
|
switch (**nexthdr) {
|
|
|
|
@@ -112,10 +111,9 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
|
|
|
|
exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) +
|
|
offset);
|
|
- len = ipv6_optlen(exthdr);
|
|
- if (len + offset >= IPV6_MAXPLEN)
|
|
+ offset += ipv6_optlen(exthdr);
|
|
+ if (offset > IPV6_MAXPLEN)
|
|
return -EINVAL;
|
|
- offset += len;
|
|
*nexthdr = &exthdr->nexthdr;
|
|
}
|
|
|
|
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
|
|
index a234552a7e3d..58f2139ebb5e 100644
|
|
--- a/net/ipv6/reassembly.c
|
|
+++ b/net/ipv6/reassembly.c
|
|
@@ -708,19 +708,13 @@ static void ip6_frags_sysctl_unregister(void)
|
|
|
|
static int __net_init ipv6_frags_init_net(struct net *net)
|
|
{
|
|
- int res;
|
|
-
|
|
net->ipv6.frags.high_thresh = IPV6_FRAG_HIGH_THRESH;
|
|
net->ipv6.frags.low_thresh = IPV6_FRAG_LOW_THRESH;
|
|
net->ipv6.frags.timeout = IPV6_FRAG_TIMEOUT;
|
|
|
|
- res = inet_frags_init_net(&net->ipv6.frags);
|
|
- if (res)
|
|
- return res;
|
|
- res = ip6_frags_ns_sysctl_register(net);
|
|
- if (res)
|
|
- inet_frags_uninit_net(&net->ipv6.frags);
|
|
- return res;
|
|
+ inet_frags_init_net(&net->ipv6.frags);
|
|
+
|
|
+ return ip6_frags_ns_sysctl_register(net);
|
|
}
|
|
|
|
static void __net_exit ipv6_frags_exit_net(struct net *net)
|
|
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
|
|
index ef335070e98a..48917437550e 100644
|
|
--- a/net/ipv6/route.c
|
|
+++ b/net/ipv6/route.c
|
|
@@ -1248,7 +1248,9 @@ static void rt6_dst_from_metrics_check(struct rt6_info *rt)
|
|
|
|
static struct dst_entry *rt6_check(struct rt6_info *rt, u32 cookie)
|
|
{
|
|
- if (!rt->rt6i_node || (rt->rt6i_node->fn_sernum != cookie))
|
|
+ u32 rt_cookie;
|
|
+
|
|
+ if (!rt6_get_cookie_safe(rt, &rt_cookie) || rt_cookie != cookie)
|
|
return NULL;
|
|
|
|
if (rt6_check_expired(rt))
|
|
@@ -1316,8 +1318,14 @@ static void ip6_link_failure(struct sk_buff *skb)
|
|
if (rt->rt6i_flags & RTF_CACHE) {
|
|
dst_hold(&rt->dst);
|
|
ip6_del_rt(rt);
|
|
- } else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT)) {
|
|
- rt->rt6i_node->fn_sernum = -1;
|
|
+ } else {
|
|
+ struct fib6_node *fn;
|
|
+
|
|
+ rcu_read_lock();
|
|
+ fn = rcu_dereference(rt->rt6i_node);
|
|
+ if (fn && (rt->rt6i_flags & RTF_DEFAULT))
|
|
+ fn->fn_sernum = -1;
|
|
+ rcu_read_unlock();
|
|
}
|
|
}
|
|
}
|
|
@@ -1334,7 +1342,8 @@ static void rt6_do_update_pmtu(struct rt6_info *rt, u32 mtu)
|
|
static bool rt6_cache_allowed_for_pmtu(const struct rt6_info *rt)
|
|
{
|
|
return !(rt->rt6i_flags & RTF_CACHE) &&
|
|
- (rt->rt6i_flags & RTF_PCPU || rt->rt6i_node);
|
|
+ (rt->rt6i_flags & RTF_PCPU ||
|
|
+ rcu_access_pointer(rt->rt6i_node));
|
|
}
|
|
|
|
static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
|