diff --git a/Makefile b/Makefile
index b48aebbe187f..c53de1e38c6a 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 4
 PATCHLEVEL = 9
-SUBLEVEL = 51
+SUBLEVEL = 52
 EXTRAVERSION =
 NAME = Roaring Lionus
 
diff --git a/arch/arc/kernel/entry.S b/arch/arc/kernel/entry.S
index 1eea99beecc3..85d9ea4a0acc 100644
--- a/arch/arc/kernel/entry.S
+++ b/arch/arc/kernel/entry.S
@@ -92,6 +92,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 bdb295e09160..a4dc881da277 100644
--- a/arch/arc/mm/tlb.c
+++ b/arch/arc/mm/tlb.c
@@ -896,9 +896,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/dp_maddf.c b/arch/mips/math-emu/dp_maddf.c
index 4a2d03c72959..e0d9be5fbf4c 100644
--- a/arch/mips/math-emu/dp_maddf.c
+++ b/arch/mips/math-emu/dp_maddf.c
@@ -14,22 +14,45 @@
 
 #include "ieee754dp.h"
 
-enum maddf_flags {
-       maddf_negate_product    = 1 << 0,
-};
+
+/* 128 bits shift right logical with rounding. */
+void srl128(u64 *hptr, u64 *lptr, int count)
+{
+       u64 low;
+
+       if (count >= 128) {
+               *lptr = *hptr != 0 || *lptr != 0;
+               *hptr = 0;
+       } else if (count >= 64) {
+               if (count == 64) {
+                       *lptr = *hptr | (*lptr != 0);
+               } else {
+                       low = *lptr;
+                       *lptr = *hptr >> (count - 64);
+                       *lptr |= (*hptr << (128 - count)) != 0 || low != 0;
+               }
+               *hptr = 0;
+       } else {
+               low = *lptr;
+               *lptr = low >> count | *hptr << (64 - count);
+               *lptr |= (low << (64 - count)) != 0;
+               *hptr = *hptr >> count;
+       }
+}
 
 static union ieee754dp _dp_maddf(union ieee754dp z, union ieee754dp x,
                                 union ieee754dp y, enum maddf_flags flags)
 {
        int re;
        int rs;
-       u64 rm;
        unsigned lxm;
        unsigned hxm;
        unsigned lym;
        unsigned hym;
        u64 lrm;
        u64 hrm;
+       u64 lzm;
+       u64 hzm;
        u64 t;
        u64 at;
        int s;
@@ -48,52 +71,34 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union 
ieee754dp x,
 
        ieee754_clearcx();
 
-       switch (zc) {
-       case IEEE754_CLASS_SNAN:
-               ieee754_setcx(IEEE754_INVALID_OPERATION);
+       /*
+        * Handle the cases when at least one of x, y or z is a NaN.
+        * Order of precedence is sNaN, qNaN and z, x, y.
+        */
+       if (zc == IEEE754_CLASS_SNAN)
                return ieee754dp_nanxcpt(z);
-       case IEEE754_CLASS_DNORM:
-               DPDNORMZ;
-       /* QNAN is handled separately below */
-       }
-
-       switch (CLPAIR(xc, yc)) {
-       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
-       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
-       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
-       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
-       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
-               return ieee754dp_nanxcpt(y);
-
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
+       if (xc == IEEE754_CLASS_SNAN)
                return ieee754dp_nanxcpt(x);
-
-       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):
+       if (yc == IEEE754_CLASS_SNAN)
+               return ieee754dp_nanxcpt(y);
+       if (zc == IEEE754_CLASS_QNAN)
+               return z;
+       if (xc == IEEE754_CLASS_QNAN)
+               return x;
+       if (yc == IEEE754_CLASS_QNAN)
                return y;
 
-       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):
-       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
-               return x;
+       if (zc == IEEE754_CLASS_DNORM)
+               DPDNORMZ;
+       /* ZERO z cases are handled separately below */
 
+       switch (CLPAIR(xc, yc)) {
 
        /*
         * Infinity handling
         */
        case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
-               if (zc == IEEE754_CLASS_QNAN)
-                       return z;
                ieee754_setcx(IEEE754_INVALID_OPERATION);
                return ieee754dp_indef();
 
@@ -102,9 +107,27 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union 
ieee754dp x,
        case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
        case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
        case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
-               if (zc == IEEE754_CLASS_QNAN)
-                       return z;
-               return ieee754dp_inf(xs ^ ys);
+               if ((zc == IEEE754_CLASS_INF) &&
+                   ((!(flags & MADDF_NEGATE_PRODUCT) && (zs != (xs ^ ys))) ||
+                    ((flags & MADDF_NEGATE_PRODUCT) && (zs == (xs ^ ys))))) {
+                       /*
+                        * Cases of addition of infinities with opposite signs
+                        * or subtraction of infinities with same signs.
+                        */
+                       ieee754_setcx(IEEE754_INVALID_OPERATION);
+                       return ieee754dp_indef();
+               }
+               /*
+                * z is here either not an infinity, or an infinity having the
+                * same sign as product (x*y) (in case of MADDF.D instruction)
+                * or product -(x*y) (in MSUBF.D case). The result must be an
+                * infinity, and its sign is determined only by the value of
+                * (flags & MADDF_NEGATE_PRODUCT) and the signs of x and y.
+                */
+               if (flags & MADDF_NEGATE_PRODUCT)
+                       return ieee754dp_inf(1 ^ (xs ^ ys));
+               else
+                       return ieee754dp_inf(xs ^ ys);
 
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
@@ -113,32 +136,42 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union 
ieee754dp x,
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
                if (zc == IEEE754_CLASS_INF)
                        return ieee754dp_inf(zs);
-               /* Multiplication is 0 so just return z */
+               if (zc == IEEE754_CLASS_ZERO) {
+                       /* Handle cases +0 + (-0) and similar ones. */
+                       if ((!(flags & MADDF_NEGATE_PRODUCT)
+                                       && (zs == (xs ^ ys))) ||
+                           ((flags & MADDF_NEGATE_PRODUCT)
+                                       && (zs != (xs ^ ys))))
+                               /*
+                                * Cases of addition of zeros of equal signs
+                                * or subtraction of zeroes of opposite signs.
+                                * The sign of the resulting zero is in any
+                                * such case determined only by the sign of z.
+                                */
+                               return z;
+
+                       return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD);
+               }
+               /* x*y is here 0, and z is not 0, so just return z */
                return z;
 
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
                DPDNORMX;
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
-               if (zc == IEEE754_CLASS_QNAN)
-                       return z;
-               else if (zc == IEEE754_CLASS_INF)
+               if (zc == IEEE754_CLASS_INF)
                        return ieee754dp_inf(zs);
                DPDNORMY;
                break;
 
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
-               if (zc == IEEE754_CLASS_QNAN)
-                       return z;
-               else if (zc == IEEE754_CLASS_INF)
+               if (zc == IEEE754_CLASS_INF)
                        return ieee754dp_inf(zs);
                DPDNORMX;
                break;
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
-               if (zc == IEEE754_CLASS_QNAN)
-                       return z;
-               else if (zc == IEEE754_CLASS_INF)
+               if (zc == IEEE754_CLASS_INF)
                        return ieee754dp_inf(zs);
                /* fall through to real computations */
        }
@@ -157,7 +190,7 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union 
ieee754dp x,
 
        re = xe + ye;
        rs = xs ^ ys;
-       if (flags & maddf_negate_product)
+       if (flags & MADDF_NEGATE_PRODUCT)
                rs ^= 1;
 
        /* shunt to top of word */
@@ -165,7 +198,7 @@ static union ieee754dp _dp_maddf(union ieee754dp z, union 
ieee754dp x,
        ym <<= 64 - (DP_FBITS + 1);
 
        /*
-        * Multiply 64 bits xm, ym to give high 64 bits rm with stickness.
+        * Multiply 64 bits xm and ym to give 128 bits result in hrm:lrm.
         */
 
        /* 32 * 32 => 64 */
@@ -195,78 +228,110 @@ static union ieee754dp _dp_maddf(union ieee754dp z, 
union ieee754dp x,
 
        hrm = hrm + (t >> 32);
 
-       rm = hrm | (lrm != 0);
-
-       /*
-        * Sticky shift down to normal rounding precision.
-        */
-       if ((s64) rm < 0) {
-               rm = (rm >> (64 - (DP_FBITS + 1 + 3))) |
-                    ((rm << (DP_FBITS + 1 + 3)) != 0);
+       /* Put explicit bit at bit 126 if necessary */
+       if ((int64_t)hrm < 0) {
+               lrm = (hrm << 63) | (lrm >> 1);
+               hrm = hrm >> 1;
                re++;
-       } else {
-               rm = (rm >> (64 - (DP_FBITS + 1 + 3 + 1))) |
-                    ((rm << (DP_FBITS + 1 + 3 + 1)) != 0);
        }
-       assert(rm & (DP_HIDDEN_BIT << 3));
 
-       /* And now the addition */
-       assert(zm & DP_HIDDEN_BIT);
+       assert(hrm & (1 << 62));
 
-       /*
-        * Provide guard,round and stick bit space.
-        */
-       zm <<= 3;
+       if (zc == IEEE754_CLASS_ZERO) {
+               /*
+                * Move explicit bit from bit 126 to bit 55 since the
+                * ieee754dp_format code expects the mantissa to be
+                * 56 bits wide (53 + 3 rounding bits).
+                */
+               srl128(&hrm, &lrm, (126 - 55));
+               return ieee754dp_format(rs, re, lrm);
+       }
+
+       /* Move explicit bit from bit 52 to bit 126 */
+       lzm = 0;
+       hzm = zm << 10;
+       assert(hzm & (1 << 62));
 
+       /* Make the exponents the same */
        if (ze > re) {
                /*
                 * Have to shift y fraction right to align.
                 */
                s = ze - re;
-               rm = XDPSRS(rm, s);
+               srl128(&hrm, &lrm, s);
                re += s;
        } else if (re > ze) {
                /*
                 * Have to shift x fraction right to align.
                 */
                s = re - ze;
-               zm = XDPSRS(zm, s);
+               srl128(&hzm, &lzm, s);
                ze += s;
        }
        assert(ze == re);
        assert(ze <= DP_EMAX);
 
+       /* Do the addition */
        if (zs == rs) {
                /*
-                * Generate 28 bit result of adding two 27 bit numbers
-                * leaving result in xm, xs and xe.
+                * Generate 128 bit result by adding two 127 bit numbers
+                * leaving result in hzm:lzm, zs and ze.
                 */
-               zm = zm + rm;
-
-               if (zm >> (DP_FBITS + 1 + 3)) { /* carry out */
-                       zm = XDPSRS1(zm);
+               hzm = hzm + hrm + (lzm > (lzm + lrm));
+               lzm = lzm + lrm;
+               if ((int64_t)hzm < 0) {        /* carry out */
+                       srl128(&hzm, &lzm, 1);
                        ze++;
                }
        } else {
-               if (zm >= rm) {
-                       zm = zm - rm;
+               if (hzm > hrm || (hzm == hrm && lzm >= lrm)) {
+                       hzm = hzm - hrm - (lzm < lrm);
+                       lzm = lzm - lrm;
                } else {
-                       zm = rm - zm;
+                       hzm = hrm - hzm - (lrm < lzm);
+                       lzm = lrm - lzm;
                        zs = rs;
                }
-               if (zm == 0)
+               if (lzm == 0 && hzm == 0)
                        return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD);
 
                /*
-                * Normalize to rounding precision.
+                * Put explicit bit at bit 126 if necessary.
                 */
-               while ((zm >> (DP_FBITS + 3)) == 0) {
-                       zm <<= 1;
-                       ze--;
+               if (hzm == 0) {
+                       /* left shift by 63 or 64 bits */
+                       if ((int64_t)lzm < 0) {
+                               /* MSB of lzm is the explicit bit */
+                               hzm = lzm >> 1;
+                               lzm = lzm << 63;
+                               ze -= 63;
+                       } else {
+                               hzm = lzm;
+                               lzm = 0;
+                               ze -= 64;
+                       }
+               }
+
+               t = 0;
+               while ((hzm >> (62 - t)) == 0)
+                       t++;
+
+               assert(t <= 62);
+               if (t) {
+                       hzm = hzm << t | lzm >> (64 - t);
+                       lzm = lzm << t;
+                       ze -= t;
                }
        }
 
-       return ieee754dp_format(zs, ze, zm);
+       /*
+        * Move explicit bit from bit 126 to bit 55 since the
+        * ieee754dp_format code expects the mantissa to be
+        * 56 bits wide (53 + 3 rounding bits).
+        */
+       srl128(&hzm, &lzm, (126 - 55));
+
+       return ieee754dp_format(zs, ze, lzm);
 }
 
 union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x,
@@ -278,5 +343,5 @@ union ieee754dp ieee754dp_maddf(union ieee754dp z, union 
ieee754dp x,
 union ieee754dp ieee754dp_msubf(union ieee754dp z, union ieee754dp x,
                                union ieee754dp y)
 {
-       return _dp_maddf(z, x, y, maddf_negate_product);
+       return _dp_maddf(z, x, y, MADDF_NEGATE_PRODUCT);
 }
diff --git a/arch/mips/math-emu/ieee754int.h b/arch/mips/math-emu/ieee754int.h
index 8bc2f6963324..dd2071f430e0 100644
--- a/arch/mips/math-emu/ieee754int.h
+++ b/arch/mips/math-emu/ieee754int.h
@@ -26,6 +26,10 @@
 
 #define CLPAIR(x, y)   ((x)*6+(y))
 
+enum maddf_flags {
+       MADDF_NEGATE_PRODUCT    = 1 << 0,
+};
+
 static inline void ieee754_clearcx(void)
 {
        ieee754_csr.cx = 0;
diff --git a/arch/mips/math-emu/ieee754sp.h b/arch/mips/math-emu/ieee754sp.h
index 8476067075fe..0f63e4202cff 100644
--- a/arch/mips/math-emu/ieee754sp.h
+++ b/arch/mips/math-emu/ieee754sp.h
@@ -45,6 +45,10 @@ static inline int ieee754sp_finite(union ieee754sp x)
        return SPBEXP(x) != SP_EMAX + 1 + SP_EBIAS;
 }
 
+/* 64 bit right shift with rounding */
+#define XSPSRS64(v, rs)                                                \
+       (((rs) >= 64) ? ((v) != 0) : ((v) >> (rs)) | ((v) << (64-(rs)) != 0))
+
 /* 3bit extended single precision sticky right shift */
 #define XSPSRS(v, rs)                                          \
        ((rs > (SP_FBITS+3))?1:((v) >> (rs)) | ((v) << (32-(rs)) != 0))
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/mips/math-emu/sp_maddf.c b/arch/mips/math-emu/sp_maddf.c
index a8cd8b4f235e..7195fe785d81 100644
--- a/arch/mips/math-emu/sp_maddf.c
+++ b/arch/mips/math-emu/sp_maddf.c
@@ -14,9 +14,6 @@
 
 #include "ieee754sp.h"
 
-enum maddf_flags {
-       maddf_negate_product    = 1 << 0,
-};
 
 static union ieee754sp _sp_maddf(union ieee754sp z, union ieee754sp x,
                                 union ieee754sp y, enum maddf_flags flags)
@@ -24,14 +21,8 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union 
ieee754sp x,
        int re;
        int rs;
        unsigned rm;
-       unsigned short lxm;
-       unsigned short hxm;
-       unsigned short lym;
-       unsigned short hym;
-       unsigned lrm;
-       unsigned hrm;
-       unsigned t;
-       unsigned at;
+       uint64_t rm64;
+       uint64_t zm64;
        int s;
 
        COMPXSP;
@@ -48,51 +39,35 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union 
ieee754sp x,
 
        ieee754_clearcx();
 
-       switch (zc) {
-       case IEEE754_CLASS_SNAN:
-               ieee754_setcx(IEEE754_INVALID_OPERATION);
+       /*
+        * Handle the cases when at least one of x, y or z is a NaN.
+        * Order of precedence is sNaN, qNaN and z, x, y.
+        */
+       if (zc == IEEE754_CLASS_SNAN)
                return ieee754sp_nanxcpt(z);
-       case IEEE754_CLASS_DNORM:
-               SPDNORMZ;
-       /* QNAN is handled separately below */
-       }
-
-       switch (CLPAIR(xc, yc)) {
-       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN):
-       case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN):
-       case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN):
-       case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN):
-       case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN):
+       if (xc == IEEE754_CLASS_SNAN)
+               return ieee754sp_nanxcpt(x);
+       if (yc == IEEE754_CLASS_SNAN)
                return ieee754sp_nanxcpt(y);
+       if (zc == IEEE754_CLASS_QNAN)
+               return z;
+       if (xc == IEEE754_CLASS_QNAN)
+               return x;
+       if (yc == IEEE754_CLASS_QNAN)
+               return y;
 
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN):
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN):
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO):
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM):
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM):
-       case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF):
-               return ieee754sp_nanxcpt(x);
+       if (zc == IEEE754_CLASS_DNORM)
+               SPDNORMZ;
+       /* ZERO z cases are handled separately below */
 
-       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 y;
+       switch (CLPAIR(xc, yc)) {
 
-       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):
-       case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF):
-               return x;
 
        /*
         * Infinity handling
         */
        case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO):
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF):
-               if (zc == IEEE754_CLASS_QNAN)
-                       return z;
                ieee754_setcx(IEEE754_INVALID_OPERATION);
                return ieee754sp_indef();
 
@@ -101,9 +76,27 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union 
ieee754sp x,
        case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM):
        case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM):
        case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF):
-               if (zc == IEEE754_CLASS_QNAN)
-                       return z;
-               return ieee754sp_inf(xs ^ ys);
+               if ((zc == IEEE754_CLASS_INF) &&
+                   ((!(flags & MADDF_NEGATE_PRODUCT) && (zs != (xs ^ ys))) ||
+                    ((flags & MADDF_NEGATE_PRODUCT) && (zs == (xs ^ ys))))) {
+                       /*
+                        * Cases of addition of infinities with opposite signs
+                        * or subtraction of infinities with same signs.
+                        */
+                       ieee754_setcx(IEEE754_INVALID_OPERATION);
+                       return ieee754sp_indef();
+               }
+               /*
+                * z is here either not an infinity, or an infinity having the
+                * same sign as product (x*y) (in case of MADDF.D instruction)
+                * or product -(x*y) (in MSUBF.D case). The result must be an
+                * infinity, and its sign is determined only by the value of
+                * (flags & MADDF_NEGATE_PRODUCT) and the signs of x and y.
+                */
+               if (flags & MADDF_NEGATE_PRODUCT)
+                       return ieee754sp_inf(1 ^ (xs ^ ys));
+               else
+                       return ieee754sp_inf(xs ^ ys);
 
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO):
        case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM):
@@ -112,32 +105,42 @@ static union ieee754sp _sp_maddf(union ieee754sp z, union 
ieee754sp x,
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO):
                if (zc == IEEE754_CLASS_INF)
                        return ieee754sp_inf(zs);
-               /* Multiplication is 0 so just return z */
+               if (zc == IEEE754_CLASS_ZERO) {
+                       /* Handle cases +0 + (-0) and similar ones. */
+                       if ((!(flags & MADDF_NEGATE_PRODUCT)
+                                       && (zs == (xs ^ ys))) ||
+                           ((flags & MADDF_NEGATE_PRODUCT)
+                                       && (zs != (xs ^ ys))))
+                               /*
+                                * Cases of addition of zeros of equal signs
+                                * or subtraction of zeroes of opposite signs.
+                                * The sign of the resulting zero is in any
+                                * such case determined only by the sign of z.
+                                */
+                               return z;
+
+                       return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD);
+               }
+               /* x*y is here 0, and z is not 0, so just return z */
                return z;
 
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM):
                SPDNORMX;
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM):
-               if (zc == IEEE754_CLASS_QNAN)
-                       return z;
-               else if (zc == IEEE754_CLASS_INF)
+               if (zc == IEEE754_CLASS_INF)
                        return ieee754sp_inf(zs);
                SPDNORMY;
                break;
 
        case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM):
-               if (zc == IEEE754_CLASS_QNAN)
-                       return z;
-               else if (zc == IEEE754_CLASS_INF)
+               if (zc == IEEE754_CLASS_INF)
                        return ieee754sp_inf(zs);
                SPDNORMX;
                break;
 
        case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM):
-               if (zc == IEEE754_CLASS_QNAN)
-                       return z;
-               else if (zc == IEEE754_CLASS_INF)
+               if (zc == IEEE754_CLASS_INF)
                        return ieee754sp_inf(zs);
                /* fall through to real computations */
        }
@@ -158,108 +161,93 @@ static union ieee754sp _sp_maddf(union ieee754sp z, 
union ieee754sp x,
 
        re = xe + ye;
        rs = xs ^ ys;
-       if (flags & maddf_negate_product)
+       if (flags & MADDF_NEGATE_PRODUCT)
                rs ^= 1;
 
-       /* shunt to top of word */
-       xm <<= 32 - (SP_FBITS + 1);
-       ym <<= 32 - (SP_FBITS + 1);
-
-       /*
-        * Multiply 32 bits xm, ym to give high 32 bits rm with stickness.
-        */
-       lxm = xm & 0xffff;
-       hxm = xm >> 16;
-       lym = ym & 0xffff;
-       hym = ym >> 16;
-
-       lrm = lxm * lym;        /* 16 * 16 => 32 */
-       hrm = hxm * hym;        /* 16 * 16 => 32 */
+       /* Multiple 24 bit xm and ym to give 48 bit results */
+       rm64 = (uint64_t)xm * ym;
 
-       t = lxm * hym; /* 16 * 16 => 32 */
-       at = lrm + (t << 16);
-       hrm += at < lrm;
-       lrm = at;
-       hrm = hrm + (t >> 16);
+       /* Shunt to top of word */
+       rm64 = rm64 << 16;
 
-       t = hxm * lym; /* 16 * 16 => 32 */
-       at = lrm + (t << 16);
-       hrm += at < lrm;
-       lrm = at;
-       hrm = hrm + (t >> 16);
-
-       rm = hrm | (lrm != 0);
-
-       /*
-        * Sticky shift down to normal rounding precision.
-        */
-       if ((int) rm < 0) {
-               rm = (rm >> (32 - (SP_FBITS + 1 + 3))) |
-                   ((rm << (SP_FBITS + 1 + 3)) != 0);
+       /* Put explicit bit at bit 62 if necessary */
+       if ((int64_t) rm64 < 0) {
+               rm64 = rm64 >> 1;
                re++;
-       } else {
-               rm = (rm >> (32 - (SP_FBITS + 1 + 3 + 1))) |
-                    ((rm << (SP_FBITS + 1 + 3 + 1)) != 0);
        }
-       assert(rm & (SP_HIDDEN_BIT << 3));
 
-       /* And now the addition */
+       assert(rm64 & (1 << 62));
 
-       assert(zm & SP_HIDDEN_BIT);
+       if (zc == IEEE754_CLASS_ZERO) {
+               /*
+                * Move explicit bit from bit 62 to bit 26 since the
+                * ieee754sp_format code expects the mantissa to be
+                * 27 bits wide (24 + 3 rounding bits).
+                */
+               rm = XSPSRS64(rm64, (62 - 26));
+               return ieee754sp_format(rs, re, rm);
+       }
 
-       /*
-        * Provide guard,round and stick bit space.
-        */
-       zm <<= 3;
+       /* Move explicit bit from bit 23 to bit 62 */
+       zm64 = (uint64_t)zm << (62 - 23);
+       assert(zm64 & (1 << 62));
 
+       /* Make the exponents the same */
        if (ze > re) {
                /*
                 * Have to shift r fraction right to align.
                 */
                s = ze - re;
-               rm = XSPSRS(rm, s);
+               rm64 = XSPSRS64(rm64, s);
                re += s;
        } else if (re > ze) {
                /*
                 * Have to shift z fraction right to align.
                 */
                s = re - ze;
-               zm = XSPSRS(zm, s);
+               zm64 = XSPSRS64(zm64, s);
                ze += s;
        }
        assert(ze == re);
        assert(ze <= SP_EMAX);
 
+       /* Do the addition */
        if (zs == rs) {
                /*
-                * Generate 28 bit result of adding two 27 bit numbers
-                * leaving result in zm, zs and ze.
+                * Generate 64 bit result by adding two 63 bit numbers
+                * leaving result in zm64, zs and ze.
                 */
-               zm = zm + rm;
-
-               if (zm >> (SP_FBITS + 1 + 3)) { /* carry out */
-                       zm = XSPSRS1(zm);
+               zm64 = zm64 + rm64;
+               if ((int64_t)zm64 < 0) {        /* carry out */
+                       zm64 = XSPSRS1(zm64);
                        ze++;
                }
        } else {
-               if (zm >= rm) {
-                       zm = zm - rm;
+               if (zm64 >= rm64) {
+                       zm64 = zm64 - rm64;
                } else {
-                       zm = rm - zm;
+                       zm64 = rm64 - zm64;
                        zs = rs;
                }
-               if (zm == 0)
+               if (zm64 == 0)
                        return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD);
 
                /*
-                * Normalize in extended single precision
+                * Put explicit bit at bit 62 if necessary.
                 */
-               while ((zm >> (SP_MBITS + 3)) == 0) {
-                       zm <<= 1;
+               while ((zm64 >> 62) == 0) {
+                       zm64 <<= 1;
                        ze--;
                }
-
        }
+
+       /*
+        * Move explicit bit from bit 62 to bit 26 since the
+        * ieee754sp_format code expects the mantissa to be
+        * 27 bits wide (24 + 3 rounding bits).
+        */
+       zm = XSPSRS64(zm64, (62 - 26));
+
        return ieee754sp_format(zs, ze, zm);
 }
 
@@ -272,5 +260,5 @@ union ieee754sp ieee754sp_maddf(union ieee754sp z, union 
ieee754sp x,
 union ieee754sp ieee754sp_msubf(union ieee754sp z, union ieee754sp x,
                                union ieee754sp y)
 {
-       return _sp_maddf(z, x, y, maddf_negate_product);
+       return _sp_maddf(z, x, y, MADDF_NEGATE_PRODUCT);
 }
diff --git a/arch/powerpc/kernel/align.c b/arch/powerpc/kernel/align.c
index b2da7c8baed7..292458b694fb 100644
--- a/arch/powerpc/kernel/align.c
+++ b/arch/powerpc/kernel/align.c
@@ -235,6 +235,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,
@@ -263,9 +285,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;
@@ -309,31 +332,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 = &regs->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 = &regs->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;
                }
        }
@@ -345,29 +368,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 *) &current->thread.TS_FPR(reg);
        char *ptr1 = (char *) &current->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 */
 }
 
@@ -377,24 +403,27 @@ static int emulate_lq_stq(struct pt_regs *regs, unsigned 
char __user *addr,
 {
        char *ptr0 = (char *)&regs->gpr[reg];
        char *ptr1 = (char *)&regs->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 */
@@ -687,9 +716,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__
@@ -739,7 +773,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;
@@ -936,7 +970,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 */
@@ -966,15 +1000,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);
@@ -1046,15 +1077,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/s390/include/asm/mmu.h b/arch/s390/include/asm/mmu.h
index bea785d7f853..af85d6b12028 100644
--- a/arch/s390/include/asm/mmu.h
+++ b/arch/s390/include/asm/mmu.h
@@ -5,6 +5,7 @@
 #include <linux/errno.h>
 
 typedef struct {
+       spinlock_t lock;
        cpumask_t cpu_attach_mask;
        atomic_t flush_count;
        unsigned int flush_mm;
@@ -25,6 +26,7 @@ typedef struct {
 } mm_context_t;
 
 #define INIT_MM_CONTEXT(name)                                             \
+       .context.lock = __SPIN_LOCK_UNLOCKED(name.context.lock),           \
        .context.pgtable_lock =                                            \
                        __SPIN_LOCK_UNLOCKED(name.context.pgtable_lock),   \
        .context.pgtable_list = LIST_HEAD_INIT(name.context.pgtable_list), \
diff --git a/arch/s390/include/asm/mmu_context.h 
b/arch/s390/include/asm/mmu_context.h
index 515fea5a3fc4..f65a708ac395 100644
--- a/arch/s390/include/asm/mmu_context.h
+++ b/arch/s390/include/asm/mmu_context.h
@@ -15,6 +15,7 @@
 static inline int init_new_context(struct task_struct *tsk,
                                   struct mm_struct *mm)
 {
+       spin_lock_init(&mm->context.lock);
        spin_lock_init(&mm->context.pgtable_lock);
        INIT_LIST_HEAD(&mm->context.pgtable_list);
        spin_lock_init(&mm->context.gmap_lock);
@@ -93,7 +94,6 @@ static inline void switch_mm(struct mm_struct *prev, struct 
mm_struct *next,
        if (prev == next)
                return;
        cpumask_set_cpu(cpu, &next->context.cpu_attach_mask);
-       cpumask_set_cpu(cpu, mm_cpumask(next));
        /* Clear old ASCE by loading the kernel ASCE. */
        __ctl_load(S390_lowcore.kernel_asce, 1, 1);
        __ctl_load(S390_lowcore.kernel_asce, 7, 7);
@@ -111,9 +111,8 @@ static inline void finish_arch_post_lock_switch(void)
                preempt_disable();
                while (atomic_read(&mm->context.flush_count))
                        cpu_relax();
-
-               if (mm->context.flush_mm)
-                       __tlb_flush_mm(mm);
+               cpumask_set_cpu(smp_processor_id(), mm_cpumask(mm));
+               __tlb_flush_mm_lazy(mm);
                preempt_enable();
        }
        set_fs(current->thread.mm_segment);
@@ -126,6 +125,7 @@ static inline void activate_mm(struct mm_struct *prev,
                                struct mm_struct *next)
 {
        switch_mm(prev, next, current);
+       cpumask_set_cpu(smp_processor_id(), mm_cpumask(next));
        set_user_asce(next);
 }
 
diff --git a/arch/s390/include/asm/tlbflush.h b/arch/s390/include/asm/tlbflush.h
index 39846100682a..eed927aeb08f 100644
--- a/arch/s390/include/asm/tlbflush.h
+++ b/arch/s390/include/asm/tlbflush.h
@@ -43,23 +43,6 @@ static inline void __tlb_flush_global(void)
  * Flush TLB entries for a specific mm on all CPUs (in case gmap is used
  * this implicates multiple ASCEs!).
  */
-static inline void __tlb_flush_full(struct mm_struct *mm)
-{
-       preempt_disable();
-       atomic_inc(&mm->context.flush_count);
-       if (cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) {
-               /* Local TLB flush */
-               __tlb_flush_local();
-       } else {
-               /* Global TLB flush */
-               __tlb_flush_global();
-               /* Reset TLB flush mask */
-               cpumask_copy(mm_cpumask(mm), &mm->context.cpu_attach_mask);
-       }
-       atomic_dec(&mm->context.flush_count);
-       preempt_enable();
-}
-
 static inline void __tlb_flush_mm(struct mm_struct *mm)
 {
        unsigned long gmap_asce;
@@ -71,16 +54,18 @@ static inline void __tlb_flush_mm(struct mm_struct *mm)
         */
        preempt_disable();
        atomic_inc(&mm->context.flush_count);
+       /* Reset TLB flush mask */
+       cpumask_copy(mm_cpumask(mm), &mm->context.cpu_attach_mask);
+       barrier();
        gmap_asce = READ_ONCE(mm->context.gmap_asce);
        if (MACHINE_HAS_IDTE && gmap_asce != -1UL) {
                if (gmap_asce)
                        __tlb_flush_idte(gmap_asce);
                __tlb_flush_idte(mm->context.asce);
        } else {
-               __tlb_flush_full(mm);
+               /* Global TLB flush */
+               __tlb_flush_global();
        }
-       /* Reset TLB flush mask */
-       cpumask_copy(mm_cpumask(mm), &mm->context.cpu_attach_mask);
        atomic_dec(&mm->context.flush_count);
        preempt_enable();
 }
@@ -94,7 +79,6 @@ static inline void __tlb_flush_kernel(void)
 }
 #else
 #define __tlb_flush_global()   __tlb_flush_local()
-#define __tlb_flush_full(mm)   __tlb_flush_local()
 
 /*
  * Flush TLB entries for a specific ASCE on all CPUs.
@@ -112,10 +96,12 @@ static inline void __tlb_flush_kernel(void)
 
 static inline void __tlb_flush_mm_lazy(struct mm_struct * mm)
 {
+       spin_lock(&mm->context.lock);
        if (mm->context.flush_mm) {
-               __tlb_flush_mm(mm);
                mm->context.flush_mm = 0;
+               __tlb_flush_mm(mm);
        }
+       spin_unlock(&mm->context.lock);
 }
 
 /*
diff --git a/block/blk-core.c b/block/blk-core.c
index d1f2801ce836..95379fc83805 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 45af0fe00f33..aaf2f810d170 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 3822eae102db..6f78cea75103 100644
--- a/drivers/block/skd_main.c
+++ b/drivers/block/skd_main.c
@@ -2163,6 +2163,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);
 
 }
@@ -2209,6 +2212,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);
 }
 
@@ -4622,15 +4628,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/crypto/ccp/ccp-crypto-aes-xts.c 
b/drivers/crypto/ccp/ccp-crypto-aes-xts.c
index 58a4244b4752..3f26a415ef44 100644
--- a/drivers/crypto/ccp/ccp-crypto-aes-xts.c
+++ b/drivers/crypto/ccp/ccp-crypto-aes-xts.c
@@ -1,8 +1,9 @@
 /*
  * AMD Cryptographic Coprocessor (CCP) AES XTS crypto API support
  *
- * Copyright (C) 2013 Advanced Micro Devices, Inc.
+ * Copyright (C) 2013,2017 Advanced Micro Devices, Inc.
  *
+ * Author: Gary R Hook <gary.h...@amd.com>
  * Author: Tom Lendacky <thomas.lenda...@amd.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -164,6 +165,7 @@ static int ccp_aes_xts_crypt(struct ablkcipher_request *req,
        memset(&rctx->cmd, 0, sizeof(rctx->cmd));
        INIT_LIST_HEAD(&rctx->cmd.entry);
        rctx->cmd.engine = CCP_ENGINE_XTS_AES_128;
+       rctx->cmd.u.xts.type = CCP_AES_TYPE_128;
        rctx->cmd.u.xts.action = (encrypt) ? CCP_AES_ACTION_ENCRYPT
                                           : CCP_AES_ACTION_DECRYPT;
        rctx->cmd.u.xts.unit_size = unit_size;
diff --git a/drivers/crypto/ccp/ccp-dev-v5.c b/drivers/crypto/ccp/ccp-dev-v5.c
index 2c0ce5f605b3..17b19a68e269 100644
--- a/drivers/crypto/ccp/ccp-dev-v5.c
+++ b/drivers/crypto/ccp/ccp-dev-v5.c
@@ -131,6 +131,7 @@ union ccp_function {
 #define        CCP_AES_MODE(p)         ((p)->aes.mode)
 #define        CCP_AES_TYPE(p)         ((p)->aes.type)
 #define        CCP_XTS_SIZE(p)         ((p)->aes_xts.size)
+#define        CCP_XTS_TYPE(p)         ((p)->aes_xts.type)
 #define        CCP_XTS_ENCRYPT(p)      ((p)->aes_xts.encrypt)
 #define        CCP_SHA_TYPE(p)         ((p)->sha.type)
 #define        CCP_RSA_SIZE(p)         ((p)->rsa.size)
@@ -318,6 +319,7 @@ static int ccp5_perform_xts_aes(struct ccp_op *op)
        CCP5_CMD_PROT(&desc) = 0;
 
        function.raw = 0;
+       CCP_XTS_TYPE(&function) = op->u.xts.type;
        CCP_XTS_ENCRYPT(&function) = op->u.xts.action;
        CCP_XTS_SIZE(&function) = op->u.xts.unit_size;
        CCP5_CMD_FUNCTION(&desc) = function.raw;
diff --git a/drivers/crypto/ccp/ccp-dev.h b/drivers/crypto/ccp/ccp-dev.h
index 8ac7ae17e1f4..e23c36c7691c 100644
--- a/drivers/crypto/ccp/ccp-dev.h
+++ b/drivers/crypto/ccp/ccp-dev.h
@@ -187,6 +187,7 @@
 #define CCP_AES_CTX_SB_COUNT           1
 
 #define CCP_XTS_AES_KEY_SB_COUNT       1
+#define CCP5_XTS_AES_KEY_SB_COUNT      2
 #define CCP_XTS_AES_CTX_SB_COUNT       1
 
 #define CCP_SHA_SB_COUNT               1
@@ -472,6 +473,7 @@ struct ccp_aes_op {
 };
 
 struct ccp_xts_aes_op {
+       enum ccp_aes_type type;
        enum ccp_aes_action action;
        enum ccp_xts_aes_unit_size unit_size;
 };
diff --git a/drivers/crypto/ccp/ccp-ops.c b/drivers/crypto/ccp/ccp-ops.c
index 50fae4442801..64deb006c3be 100644
--- a/drivers/crypto/ccp/ccp-ops.c
+++ b/drivers/crypto/ccp/ccp-ops.c
@@ -779,6 +779,8 @@ static int ccp_run_xts_aes_cmd(struct ccp_cmd_queue *cmd_q,
        struct ccp_op op;
        unsigned int unit_size, dm_offset;
        bool in_place = false;
+       unsigned int sb_count;
+       enum ccp_aes_type aestype;
        int ret;
 
        switch (xts->unit_size) {
@@ -802,7 +804,9 @@ static int ccp_run_xts_aes_cmd(struct ccp_cmd_queue *cmd_q,
                return -EINVAL;
        }
 
-       if (xts->key_len != AES_KEYSIZE_128)
+       if (xts->key_len == AES_KEYSIZE_128)
+               aestype = CCP_AES_TYPE_128;
+       else
                return -EINVAL;
 
        if (!xts->final && (xts->src_len & (AES_BLOCK_SIZE - 1)))
@@ -824,23 +828,44 @@ static int ccp_run_xts_aes_cmd(struct ccp_cmd_queue 
*cmd_q,
        op.sb_key = cmd_q->sb_key;
        op.sb_ctx = cmd_q->sb_ctx;
        op.init = 1;
+       op.u.xts.type = aestype;
        op.u.xts.action = xts->action;
        op.u.xts.unit_size = xts->unit_size;
 
-       /* All supported key sizes fit in a single (32-byte) SB entry
-        * and must be in little endian format. Use the 256-bit byte
-        * swap passthru option to convert from big endian to little
-        * endian.
+       /* A version 3 device only supports 128-bit keys, which fits into a
+        * single SB entry. A version 5 device uses a 512-bit vector, so two
+        * SB entries.
         */
+       if (cmd_q->ccp->vdata->version == CCP_VERSION(3, 0))
+               sb_count = CCP_XTS_AES_KEY_SB_COUNT;
+       else
+               sb_count = CCP5_XTS_AES_KEY_SB_COUNT;
        ret = ccp_init_dm_workarea(&key, cmd_q,
-                                  CCP_XTS_AES_KEY_SB_COUNT * CCP_SB_BYTES,
+                                  sb_count * CCP_SB_BYTES,
                                   DMA_TO_DEVICE);
        if (ret)
                return ret;
 
-       dm_offset = CCP_SB_BYTES - AES_KEYSIZE_128;
-       ccp_set_dm_area(&key, dm_offset, xts->key, 0, xts->key_len);
-       ccp_set_dm_area(&key, 0, xts->key, dm_offset, xts->key_len);
+       if (cmd_q->ccp->vdata->version == CCP_VERSION(3, 0)) {
+               /* All supported key sizes must be in little endian format.
+                * Use the 256-bit byte swap passthru option to convert from
+                * big endian to little endian.
+                */
+               dm_offset = CCP_SB_BYTES - AES_KEYSIZE_128;
+               ccp_set_dm_area(&key, dm_offset, xts->key, 0, xts->key_len);
+               ccp_set_dm_area(&key, 0, xts->key, xts->key_len, xts->key_len);
+       } else {
+               /* Version 5 CCPs use a 512-bit space for the key: each portion
+                * occupies 256 bits, or one entire slot, and is zero-padded.
+                */
+               unsigned int pad;
+
+               dm_offset = CCP_SB_BYTES;
+               pad = dm_offset - xts->key_len;
+               ccp_set_dm_area(&key, pad, xts->key, 0, xts->key_len);
+               ccp_set_dm_area(&key, dm_offset + pad, xts->key, xts->key_len,
+                               xts->key_len);
+       }
        ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
                             CCP_PASSTHRU_BYTESWAP_256BIT);
        if (ret) {
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 7309c0824887..a2449d77af07 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -574,7 +574,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
        err = device_register(&devfreq->dev);
        if (err) {
                mutex_unlock(&devfreq->lock);
-               goto err_out;
+               goto err_dev;
        }
 
        devfreq->trans_table =  devm_kzalloc(&devfreq->dev, sizeof(unsigned 
int) *
@@ -618,6 +618,9 @@ struct devfreq *devfreq_add_device(struct device *dev,
        mutex_unlock(&devfreq_list_lock);
 
        device_unregister(&devfreq->dev);
+err_dev:
+       if (devfreq)
+               kfree(devfreq);
 err_out:
        return ERR_PTR(err);
 }
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c 
b/drivers/gpu/drm/sun4i/sun4i_drv.c
index c3b21865443e..1feec34ca9dd 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -47,6 +47,13 @@ static void sun4i_drv_disable_vblank(struct drm_device *drm, 
unsigned int pipe)
        sun4i_tcon_enable_vblank(tcon, false);
 }
 
+static void sun4i_drv_lastclose(struct drm_device *dev)
+{
+       struct sun4i_drv *drv = dev->dev_private;
+
+       drm_fbdev_cma_restore_mode(drv->fbdev);
+}
+
 static const struct file_operations sun4i_drv_fops = {
        .owner          = THIS_MODULE,
        .open           = drm_open,
@@ -65,6 +72,7 @@ static struct drm_driver sun4i_drv_driver = {
        .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | 
DRIVER_ATOMIC,
 
        /* Generic Operations */
+       .lastclose              = sun4i_drv_lastclose,
        .fops                   = &sun4i_drv_fops,
        .name                   = "sun4i-drm",
        .desc                   = "Allwinner sun4i Display Engine",
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index 63e82f8e8308..fb4ce0394ac7 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -446,15 +446,10 @@ static int addr6_resolve(struct sockaddr_in6 *src_in,
 
        ret = ipv6_stub->ipv6_dst_lookup(addr->net, NULL, &dst, &fl6);
        if (ret < 0)
-               goto put;
+               return ret;
 
        rt = (struct rt6_info *)dst;
-       if (ipv6_addr_any(&fl6.saddr)) {
-               ret = ipv6_dev_get_saddr(addr->net, ip6_dst_idev(dst)->dev,
-                                        &fl6.daddr, 0, &fl6.saddr);
-               if (ret)
-                       goto put;
-
+       if (ipv6_addr_any(&src_in->sin6_addr)) {
                src_in->sin6_family = AF_INET6;
                src_in->sin6_addr = fl6.saddr;
        }
@@ -471,9 +466,6 @@ static int addr6_resolve(struct sockaddr_in6 *src_in,
 
        *pdst = dst;
        return 0;
-put:
-       dst_release(dst);
-       return ret;
 }
 #else
 static int addr6_resolve(struct sockaddr_in6 *src_in,
diff --git a/drivers/infiniband/hw/hfi1/rc.c b/drivers/infiniband/hw/hfi1/rc.c
index 4bd5b5caa243..613074e963bb 100644
--- a/drivers/infiniband/hw/hfi1/rc.c
+++ b/drivers/infiniband/hw/hfi1/rc.c
@@ -551,7 +551,7 @@ int hfi1_make_rc_req(struct rvt_qp *qp, struct 
hfi1_pkt_state *ps)
                case IB_WR_RDMA_WRITE:
                        if (newreq && !(qp->s_flags & RVT_S_UNLIMITED_CREDIT))
                                qp->s_lsn++;
-                       /* FALLTHROUGH */
+                       goto no_flow_control;
                case IB_WR_RDMA_WRITE_WITH_IMM:
                        /* If no credit, return. */
                        if (!(qp->s_flags & RVT_S_UNLIMITED_CREDIT) &&
@@ -559,6 +559,7 @@ int hfi1_make_rc_req(struct rvt_qp *qp, struct 
hfi1_pkt_state *ps)
                                qp->s_flags |= RVT_S_WAIT_SSN_CREDIT;
                                goto bail;
                        }
+no_flow_control:
                        put_ib_reth_vaddr(
                                wqe->rdma_wr.remote_addr,
                                &ohdr->u.rc.reth);
diff --git a/drivers/infiniband/hw/qib/qib_rc.c 
b/drivers/infiniband/hw/qib/qib_rc.c
index f3fe787c9426..c1523f9a3c12 100644
--- a/drivers/infiniband/hw/qib/qib_rc.c
+++ b/drivers/infiniband/hw/qib/qib_rc.c
@@ -357,7 +357,7 @@ int qib_make_rc_req(struct rvt_qp *qp, unsigned long *flags)
                case IB_WR_RDMA_WRITE:
                        if (newreq && !(qp->s_flags & RVT_S_UNLIMITED_CREDIT))
                                qp->s_lsn++;
-                       /* FALLTHROUGH */
+                       goto no_flow_control;
                case IB_WR_RDMA_WRITE_WITH_IMM:
                        /* If no credit, return. */
                        if (!(qp->s_flags & RVT_S_UNLIMITED_CREDIT) &&
@@ -365,7 +365,7 @@ int qib_make_rc_req(struct rvt_qp *qp, unsigned long *flags)
                                qp->s_flags |= RVT_S_WAIT_SSN_CREDIT;
                                goto bail;
                        }
-
+no_flow_control:
                        ohdr->u.rc.reth.vaddr =
                                cpu_to_be64(wqe->rdma_wr.remote_addr);
                        ohdr->u.rc.reth.rkey =
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 a37c1776f2e3..e0f1c6d534fe 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_PREFLUSH; 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 66669c8f4161..f4557f558b24 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -1025,7 +1025,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);
@@ -1058,6 +1058,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);
 
@@ -1229,6 +1231,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);
 
@@ -1967,6 +1970,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 dde6172f3f10..eb70f6894f05 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 e51644e503a5..4ce2b19fe120 100644
--- a/drivers/md/bcache/writeback.c
+++ b/drivers/md/bcache/writeback.c
@@ -20,7 +20,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);
 
@@ -186,7 +187,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)
@@ -206,7 +207,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)
@@ -482,17 +483,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)
@@ -516,6 +517,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 301eaf565167..cdf8d253209e 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 2d826927a3bf..fb02c3979bf4 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -1992,6 +1992,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/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index c2ee6e39fd0c..20397aba6849 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -2002,6 +2002,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 bacecbd68a6d..dc51dd86377d 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/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index b57fc6d6e28a..d08dfc8b9ba9 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -586,6 +586,14 @@ static irqreturn_t pciehp_isr(int irq, void *dev_id)
        events = status & (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD |
                           PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_CC |
                           PCI_EXP_SLTSTA_DLLSC);
+
+       /*
+        * If we've already reported a power fault, don't report it again
+        * until we've done something to handle it.
+        */
+       if (ctrl->power_fault_detected)
+               events &= ~PCI_EXP_SLTSTA_PFD;
+
        if (!events)
                return IRQ_NONE;
 
diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c
index de0ea474fb73..e5824c7b7b6b 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/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c
index c9a146948192..a5b7bd3c9bac 100644
--- a/drivers/pinctrl/pinctrl-amd.c
+++ b/drivers/pinctrl/pinctrl-amd.c
@@ -32,6 +32,7 @@
 #include <linux/pinctrl/pinconf.h>
 #include <linux/pinctrl/pinconf-generic.h>
 
+#include "core.h"
 #include "pinctrl-utils.h"
 #include "pinctrl-amd.h"
 
@@ -712,6 +713,69 @@ static const struct pinconf_ops amd_pinconf_ops = {
        .pin_config_group_set = amd_pinconf_group_set,
 };
 
+#ifdef CONFIG_PM_SLEEP
+static bool amd_gpio_should_save(struct amd_gpio *gpio_dev, unsigned int pin)
+{
+       const struct pin_desc *pd = pin_desc_get(gpio_dev->pctrl, pin);
+
+       if (!pd)
+               return false;
+
+       /*
+        * Only restore the pin if it is actually in use by the kernel (or
+        * by userspace).
+        */
+       if (pd->mux_owner || pd->gpio_owner ||
+           gpiochip_line_is_irq(&gpio_dev->gc, pin))
+               return true;
+
+       return false;
+}
+
+int amd_gpio_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct amd_gpio *gpio_dev = platform_get_drvdata(pdev);
+       struct pinctrl_desc *desc = gpio_dev->pctrl->desc;
+       int i;
+
+       for (i = 0; i < desc->npins; i++) {
+               int pin = desc->pins[i].number;
+
+               if (!amd_gpio_should_save(gpio_dev, pin))
+                       continue;
+
+               gpio_dev->saved_regs[i] = readl(gpio_dev->base + pin*4);
+       }
+
+       return 0;
+}
+
+int amd_gpio_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct amd_gpio *gpio_dev = platform_get_drvdata(pdev);
+       struct pinctrl_desc *desc = gpio_dev->pctrl->desc;
+       int i;
+
+       for (i = 0; i < desc->npins; i++) {
+               int pin = desc->pins[i].number;
+
+               if (!amd_gpio_should_save(gpio_dev, pin))
+                       continue;
+
+               writel(gpio_dev->saved_regs[i], gpio_dev->base + pin*4);
+       }
+
+       return 0;
+}
+
+static const struct dev_pm_ops amd_gpio_pm_ops = {
+       SET_LATE_SYSTEM_SLEEP_PM_OPS(amd_gpio_suspend,
+                                    amd_gpio_resume)
+};
+#endif
+
 static struct pinctrl_desc amd_pinctrl_desc = {
        .pins   = kerncz_pins,
        .npins = ARRAY_SIZE(kerncz_pins),
@@ -751,6 +815,14 @@ static int amd_gpio_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
+#ifdef CONFIG_PM_SLEEP
+       gpio_dev->saved_regs = devm_kcalloc(&pdev->dev, amd_pinctrl_desc.npins,
+                                           sizeof(*gpio_dev->saved_regs),
+                                           GFP_KERNEL);
+       if (!gpio_dev->saved_regs)
+               return -ENOMEM;
+#endif
+
        gpio_dev->pdev = pdev;
        gpio_dev->gc.direction_input    = amd_gpio_direction_input;
        gpio_dev->gc.direction_output   = amd_gpio_direction_output;
@@ -839,6 +911,9 @@ static struct platform_driver amd_gpio_driver = {
        .driver         = {
                .name   = "amd_gpio",
                .acpi_match_table = ACPI_PTR(amd_gpio_acpi_match),
+#ifdef CONFIG_PM_SLEEP
+               .pm     = &amd_gpio_pm_ops,
+#endif
        },
        .probe          = amd_gpio_probe,
        .remove         = amd_gpio_remove,
diff --git a/drivers/pinctrl/pinctrl-amd.h b/drivers/pinctrl/pinctrl-amd.h
index 7bfea47dbb47..e8bbb20779d0 100644
--- a/drivers/pinctrl/pinctrl-amd.h
+++ b/drivers/pinctrl/pinctrl-amd.h
@@ -95,6 +95,7 @@ struct amd_gpio {
        struct gpio_chip        gc;
        struct resource         *res;
        struct platform_device  *pdev;
+       u32                     *saved_regs;
 };
 
 /*  KERNCZ configuration*/
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 d8b1fbd4c8aa..35cbd36f8d3b 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -1901,9 +1901,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 {
@@ -5290,7 +5293,8 @@ static int megasas_init_fw(struct megasas_instance 
*instance)
                instance->throttlequeuedepth =
                                MEGASAS_THROTTLE_QUEUE_DEPTH;
 
-       if (resetwaittime > MEGASAS_RESET_WAIT_TIME)
+       if ((resetwaittime < 1) ||
+           (resetwaittime > MEGASAS_RESET_WAIT_TIME))
                resetwaittime = MEGASAS_RESET_WAIT_TIME;
 
        if ((scmd_timeout < 10) || (scmd_timeout > MEGASAS_DEFAULT_CMD_TIMEOUT))
@@ -5459,6 +5463,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 8c4641b518b5..9a34afcb1c4c 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -318,6 +318,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) {
@@ -343,8 +345,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);
@@ -417,8 +418,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/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
index 3dfb54abc874..f8ae70476b3a 100644
--- a/drivers/scsi/qla2xxx/qla_mid.c
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -74,7 +74,7 @@ qla24xx_deallocate_vp_id(scsi_qla_host_t *vha)
         * ensures no active vp_list traversal while the vport is removed
         * from the queue)
         */
-       wait_event_timeout(vha->vref_waitq, atomic_read(&vha->vref_count),
+       wait_event_timeout(vha->vref_waitq, !atomic_read(&vha->vref_count),
            10*HZ);
 
        spin_lock_irqsave(&ha->vport_slock, flags);
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 9236a13d5d2a..02dfbc1373e3 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -122,7 +122,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> */
@@ -146,8 +146,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 */
@@ -829,6 +828,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)
 {
@@ -941,7 +973,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);
@@ -954,7 +986,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;
                }
@@ -1022,42 +1055,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);
@@ -1163,7 +1169,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;
@@ -2049,7 +2055,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;
@@ -2062,7 +2067,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))) {
@@ -2080,70 +2085,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;
@@ -2162,7 +2142,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;
@@ -2203,10 +2183,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,
@@ -2609,7 +2592,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;
@@ -2629,13 +2612,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
@@ -2666,7 +2647,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 c5ab1b0037fc..2bf96d33428a 100644
--- a/drivers/scsi/storvsc_drv.c
+++ b/drivers/scsi/storvsc_drv.c
@@ -1559,6 +1559,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 aa80dc94ddc2..c220c2c0893f 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 5fa9ba1de429..f72535e1898f 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -2334,6 +2334,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) {
@@ -2372,14 +2373,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
@@ -2438,10 +2457,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 */
@@ -5365,6 +5386,9 @@ static int ext4_enable_quotas(struct super_block *sb)
                                DQUOT_USAGE_ENABLED |
                                (quota_mopt[type] ? DQUOT_LIMITS_ENABLED : 0));
                        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/nfs/callback.c b/fs/nfs/callback.c
index 0a2115084c3f..582bfee40345 100644
--- a/fs/nfs/callback.c
+++ b/fs/nfs/callback.c
@@ -75,7 +75,10 @@ nfs4_callback_svc(void *vrqstp)
 
        set_freezable();
 
-       while (!kthread_should_stop()) {
+       while (!kthread_freezable_should_stop(NULL)) {
+
+               if (signal_pending(current))
+                       flush_signals(current);
                /*
                 * Listen for a request on the socket
                 */
@@ -84,6 +87,8 @@ nfs4_callback_svc(void *vrqstp)
                        continue;
                svc_process(rqstp);
        }
+       svc_exit_thread(rqstp);
+       module_put_and_exit(0);
        return 0;
 }
 
@@ -102,9 +107,10 @@ nfs41_callback_svc(void *vrqstp)
 
        set_freezable();
 
-       while (!kthread_should_stop()) {
-               if (try_to_freeze())
-                       continue;
+       while (!kthread_freezable_should_stop(NULL)) {
+
+               if (signal_pending(current))
+                       flush_signals(current);
 
                prepare_to_wait(&serv->sv_cb_waitq, &wq, TASK_INTERRUPTIBLE);
                spin_lock_bh(&serv->sv_cb_lock);
@@ -120,11 +126,13 @@ nfs41_callback_svc(void *vrqstp)
                                error);
                } else {
                        spin_unlock_bh(&serv->sv_cb_lock);
-                       schedule();
+                       if (!kthread_should_stop())
+                               schedule();
                        finish_wait(&serv->sv_cb_waitq, &wq);
                }
-               flush_signals(current);
        }
+       svc_exit_thread(rqstp);
+       module_put_and_exit(0);
        return 0;
 }
 
@@ -220,14 +228,14 @@ static int nfs_callback_up_net(int minorversion, struct 
svc_serv *serv,
 static struct svc_serv_ops nfs40_cb_sv_ops = {
        .svo_function           = nfs4_callback_svc,
        .svo_enqueue_xprt       = svc_xprt_do_enqueue,
-       .svo_setup              = svc_set_num_threads,
+       .svo_setup              = svc_set_num_threads_sync,
        .svo_module             = THIS_MODULE,
 };
 #if defined(CONFIG_NFS_V4_1)
 static struct svc_serv_ops nfs41_cb_sv_ops = {
        .svo_function           = nfs41_callback_svc,
        .svo_enqueue_xprt       = svc_xprt_do_enqueue,
-       .svo_setup              = svc_set_num_threads,
+       .svo_setup              = svc_set_num_threads_sync,
        .svo_module             = THIS_MODULE,
 };
 
diff --git a/fs/orangefs/acl.c b/fs/orangefs/acl.c
index 7a3754488312..9409aac232f7 100644
--- a/fs/orangefs/acl.c
+++ b/fs/orangefs/acl.c
@@ -61,9 +61,9 @@ struct posix_acl *orangefs_get_acl(struct inode *inode, int 
type)
        return acl;
 }
 
-int orangefs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
+static int __orangefs_set_acl(struct inode *inode, struct posix_acl *acl,
+                             int type)
 {
-       struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
        int error = 0;
        void *value = NULL;
        size_t size = 0;
@@ -72,22 +72,6 @@ int orangefs_set_acl(struct inode *inode, struct posix_acl 
*acl, int type)
        switch (type) {
        case ACL_TYPE_ACCESS:
                name = XATTR_NAME_POSIX_ACL_ACCESS;
-               if (acl) {
-                       umode_t mode;
-
-                       error = posix_acl_update_mode(inode, &mode, &acl);
-                       if (error) {
-                               gossip_err("%s: posix_acl_update_mode err: 
%d\n",
-                                          __func__,
-                                          error);
-                               return error;
-                       }
-
-                       if (inode->i_mode != mode)
-                               SetModeFlag(orangefs_inode);
-                       inode->i_mode = mode;
-                       mark_inode_dirty_sync(inode);
-               }
                break;
        case ACL_TYPE_DEFAULT:
                name = XATTR_NAME_POSIX_ACL_DEFAULT;
@@ -132,6 +116,29 @@ int orangefs_set_acl(struct inode *inode, struct posix_acl 
*acl, int type)
        return error;
 }
 
+int orangefs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
+{
+       int error;
+
+       if (type == ACL_TYPE_ACCESS && acl) {
+               umode_t mode;
+
+               error = posix_acl_update_mode(inode, &mode, &acl);
+               if (error) {
+                       gossip_err("%s: posix_acl_update_mode err: %d\n",
+                                  __func__,
+                                  error);
+                       return error;
+               }
+
+               if (inode->i_mode != mode)
+                       SetModeFlag(ORANGEFS_I(inode));
+               inode->i_mode = mode;
+               mark_inode_dirty_sync(inode);
+       }
+       return __orangefs_set_acl(inode, acl, type);
+}
+
 int orangefs_init_acl(struct inode *inode, struct inode *dir)
 {
        struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
@@ -146,13 +153,14 @@ int orangefs_init_acl(struct inode *inode, struct inode 
*dir)
                return error;
 
        if (default_acl) {
-               error = orangefs_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
+               error = __orangefs_set_acl(inode, default_acl,
+                                          ACL_TYPE_DEFAULT);
                posix_acl_release(default_acl);
        }
 
        if (acl) {
                if (!error)
-                       error = orangefs_set_acl(inode, acl, ACL_TYPE_ACCESS);
+                       error = __orangefs_set_acl(inode, acl, ACL_TYPE_ACCESS);
                posix_acl_release(acl);
        }
 
diff --git a/include/linux/ccp.h b/include/linux/ccp.h
index edc5d04b9632..1cfe5ef3060b 100644
--- a/include/linux/ccp.h
+++ b/include/linux/ccp.h
@@ -1,7 +1,7 @@
 /*
  * AMD Cryptographic Coprocessor (CCP) driver
  *
- * Copyright (C) 2013,2016 Advanced Micro Devices, Inc.
+ * Copyright (C) 2013,2017 Advanced Micro Devices, Inc.
  *
  * Author: Tom Lendacky <thomas.lenda...@amd.com>
  * Author: Gary R Hook <gary.h...@amd.com>
@@ -222,6 +222,7 @@ enum ccp_xts_aes_unit_size {
  * AES operation the new IV overwrites the old IV.
  */
 struct ccp_xts_aes_engine {
+       enum ccp_aes_type type;
        enum ccp_aes_action action;
        enum ccp_xts_aes_unit_size unit_size;
 
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 7321ae933867..102c84dcc11a 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -470,6 +470,7 @@ void                   svc_pool_map_put(void);
 struct svc_serv *  svc_create_pooled(struct svc_program *, unsigned int,
                        struct svc_serv_ops *);
 int               svc_set_num_threads(struct svc_serv *, struct svc_pool *, 
int);
+int               svc_set_num_threads_sync(struct svc_serv *, struct svc_pool 
*, int);
 int               svc_pool_stats_open(struct svc_serv *serv, struct file 
*file);
 void              svc_destroy(struct svc_serv *);
 void              svc_shutdown_net(struct svc_serv *, struct net *);
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/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 6e432ed7d0fe..53ed8ae5de1c 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -2747,13 +2747,14 @@ static int ftrace_shutdown(struct ftrace_ops *ops, int 
command)
 
        if (!command || !ftrace_enabled) {
                /*
-                * If these are per_cpu ops, they still need their
-                * per_cpu field freed. Since, function tracing is
+                * If these are dynamic or per_cpu 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_PER_CPU)
-                       per_cpu_ops_free(ops);
+               if (ops->flags & (FTRACE_OPS_FL_DYNAMIC | 
FTRACE_OPS_FL_PER_CPU))
+                       goto free_ops;
+
                return 0;
        }
 
@@ -2808,6 +2809,7 @@ static int ftrace_shutdown(struct ftrace_ops *ops, int 
command)
        if (ops->flags & (FTRACE_OPS_FL_DYNAMIC | FTRACE_OPS_FL_PER_CPU)) {
                schedule_on_each_cpu(ftrace_sync);
 
+ free_ops:
                arch_ftrace_trampoline_free(ops);
 
                if (ops->flags & FTRACE_OPS_FL_PER_CPU)
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 7379f735a9f4..f95bf81529f5 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -2369,11 +2369,17 @@ static char *get_trace_buf(void)
        if (!buffer || buffer->nesting >= 4)
                return NULL;
 
-       return &buffer->buffer[buffer->nesting++][0];
+       buffer->nesting++;
+
+       /* Interrupts must see nesting incremented before we use the buffer */
+       barrier();
+       return &buffer->buffer[buffer->nesting][0];
 }
 
 static void put_trace_buf(void)
 {
+       /* Don't let the decrement of nesting leak before this */
+       barrier();
        this_cpu_dec(trace_percpu_buffer->nesting);
 }
 
@@ -5658,7 +5664,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/mm/page_alloc.c b/mm/page_alloc.c
index 2abf8d5f0ad4..7064aae8ded7 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -2100,13 +2100,25 @@ static void unreserve_highatomic_pageblock(const struct 
alloc_context *ac)
                                continue;
 
                        /*
-                        * It should never happen but changes to locking could
-                        * inadvertently allow a per-cpu drain to add pages
-                        * to MIGRATE_HIGHATOMIC while unreserving so be safe
-                        * and watch for underflows.
+                        * In page freeing path, migratetype change is racy so
+                        * we can counter several free pages in a pageblock
+                        * in this loop althoug we changed the pageblock type
+                        * from highatomic to ac->migratetype. So we should
+                        * adjust the count once.
                         */
-                       zone->nr_reserved_highatomic -= min(pageblock_nr_pages,
-                               zone->nr_reserved_highatomic);
+                       if (get_pageblock_migratetype(page) ==
+                                                       MIGRATE_HIGHATOMIC) {
+                               /*
+                                * It should never happen but changes to
+                                * locking could inadvertently allow a per-cpu
+                                * drain to add pages to MIGRATE_HIGHATOMIC
+                                * while unreserving so be safe and watch for
+                                * underflows.
+                                */
+                               zone->nr_reserved_highatomic -= min(
+                                               pageblock_nr_pages,
+                                               zone->nr_reserved_highatomic);
+                       }
 
                        /*
                         * Convert to ac->migratetype and avoid the normal
diff --git a/net/netfilter/nf_conntrack_core.c 
b/net/netfilter/nf_conntrack_core.c
index 6bd150882ba4..ed9ce7c63252 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -95,19 +95,26 @@ static struct conntrack_gc_work conntrack_gc_work;
 
 void nf_conntrack_lock(spinlock_t *lock) __acquires(lock)
 {
+       /* 1) Acquire the lock */
        spin_lock(lock);
-       while (unlikely(nf_conntrack_locks_all)) {
-               spin_unlock(lock);
 
-               /*
-                * Order the 'nf_conntrack_locks_all' load vs. the
-                * spin_unlock_wait() loads below, to ensure
-                * that 'nf_conntrack_locks_all_lock' is indeed held:
-                */
-               smp_rmb(); /* spin_lock(&nf_conntrack_locks_all_lock) */
-               spin_unlock_wait(&nf_conntrack_locks_all_lock);
-               spin_lock(lock);
-       }
+       /* 2) read nf_conntrack_locks_all, with ACQUIRE semantics
+        * It pairs with the smp_store_release() in nf_conntrack_all_unlock()
+        */
+       if (likely(smp_load_acquire(&nf_conntrack_locks_all) == false))
+               return;
+
+       /* fast path failed, unlock */
+       spin_unlock(lock);
+
+       /* Slow path 1) get global lock */
+       spin_lock(&nf_conntrack_locks_all_lock);
+
+       /* Slow path 2) get the lock we want */
+       spin_lock(lock);
+
+       /* Slow path 3) release the global lock */
+       spin_unlock(&nf_conntrack_locks_all_lock);
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_lock);
 
@@ -148,28 +155,27 @@ static void nf_conntrack_all_lock(void)
        int i;
 
        spin_lock(&nf_conntrack_locks_all_lock);
-       nf_conntrack_locks_all = true;
 
-       /*
-        * Order the above store of 'nf_conntrack_locks_all' against
-        * the spin_unlock_wait() loads below, such that if
-        * nf_conntrack_lock() observes 'nf_conntrack_locks_all'
-        * we must observe nf_conntrack_locks[] held:
-        */
-       smp_mb(); /* spin_lock(&nf_conntrack_locks_all_lock) */
+       nf_conntrack_locks_all = true;
 
        for (i = 0; i < CONNTRACK_LOCKS; i++) {
-               spin_unlock_wait(&nf_conntrack_locks[i]);
+               spin_lock(&nf_conntrack_locks[i]);
+
+               /* This spin_unlock provides the "release" to ensure that
+                * nf_conntrack_locks_all==true is visible to everyone that
+                * acquired spin_lock(&nf_conntrack_locks[]).
+                */
+               spin_unlock(&nf_conntrack_locks[i]);
        }
 }
 
 static void nf_conntrack_all_unlock(void)
 {
-       /*
-        * All prior stores must be complete before we clear
+       /* All prior stores must be complete before we clear
         * 'nf_conntrack_locks_all'. Otherwise nf_conntrack_lock()
         * might observe the false value but not the entire
-        * critical section:
+        * critical section.
+        * It pairs with the smp_load_acquire() in nf_conntrack_lock()
         */
        smp_store_release(&nf_conntrack_locks_all, false);
        spin_unlock(&nf_conntrack_locks_all_lock);
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 75f290bddca1..272c34551979 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -702,59 +702,32 @@ choose_victim(struct svc_serv *serv, struct svc_pool 
*pool, unsigned int *state)
        return task;
 }
 
-/*
- * Create or destroy enough new threads to make the number
- * of threads the given number.  If `pool' is non-NULL, applies
- * only to threads in that pool, otherwise round-robins between
- * all pools.  Caller must ensure that mutual exclusion between this and
- * server startup or shutdown.
- *
- * Destroying threads relies on the service threads filling in
- * rqstp->rq_task, which only the nfs ones do.  Assumes the serv
- * has been created using svc_create_pooled().
- *
- * Based on code that used to be in nfsd_svc() but tweaked
- * to be pool-aware.
- */
-int
-svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
+/* create new threads */
+static int
+svc_start_kthreads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
 {
        struct svc_rqst *rqstp;
        struct task_struct *task;
        struct svc_pool *chosen_pool;
-       int error = 0;
        unsigned int state = serv->sv_nrthreads-1;
        int node;
 
-       if (pool == NULL) {
-               /* The -1 assumes caller has done a svc_get() */
-               nrservs -= (serv->sv_nrthreads-1);
-       } else {
-               spin_lock_bh(&pool->sp_lock);
-               nrservs -= pool->sp_nrthreads;
-               spin_unlock_bh(&pool->sp_lock);
-       }
-
-       /* create new threads */
-       while (nrservs > 0) {
+       do {
                nrservs--;
                chosen_pool = choose_pool(serv, pool, &state);
 
                node = svc_pool_map_get_node(chosen_pool->sp_id);
                rqstp = svc_prepare_thread(serv, chosen_pool, node);
-               if (IS_ERR(rqstp)) {
-                       error = PTR_ERR(rqstp);
-                       break;
-               }
+               if (IS_ERR(rqstp))
+                       return PTR_ERR(rqstp);
 
                __module_get(serv->sv_ops->svo_module);
                task = kthread_create_on_node(serv->sv_ops->svo_function, rqstp,
                                              node, "%s", serv->sv_name);
                if (IS_ERR(task)) {
-                       error = PTR_ERR(task);
                        module_put(serv->sv_ops->svo_module);
                        svc_exit_thread(rqstp);
-                       break;
+                       return PTR_ERR(task);
                }
 
                rqstp->rq_task = task;
@@ -763,18 +736,103 @@ svc_set_num_threads(struct svc_serv *serv, struct 
svc_pool *pool, int nrservs)
 
                svc_sock_update_bufs(serv);
                wake_up_process(task);
-       }
+       } while (nrservs > 0);
+
+       return 0;
+}
+
+
+/* destroy old threads */
+static int
+svc_signal_kthreads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
+{
+       struct task_struct *task;
+       unsigned int state = serv->sv_nrthreads-1;
+
        /* destroy old threads */
-       while (nrservs < 0 &&
-              (task = choose_victim(serv, pool, &state)) != NULL) {
+       do {
+               task = choose_victim(serv, pool, &state);
+               if (task == NULL)
+                       break;
                send_sig(SIGINT, task, 1);
                nrservs++;
+       } while (nrservs < 0);
+
+       return 0;
+}
+
+/*
+ * Create or destroy enough new threads to make the number
+ * of threads the given number.  If `pool' is non-NULL, applies
+ * only to threads in that pool, otherwise round-robins between
+ * all pools.  Caller must ensure that mutual exclusion between this and
+ * server startup or shutdown.
+ *
+ * Destroying threads relies on the service threads filling in
+ * rqstp->rq_task, which only the nfs ones do.  Assumes the serv
+ * has been created using svc_create_pooled().
+ *
+ * Based on code that used to be in nfsd_svc() but tweaked
+ * to be pool-aware.
+ */
+int
+svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
+{
+       if (pool == NULL) {
+               /* The -1 assumes caller has done a svc_get() */
+               nrservs -= (serv->sv_nrthreads-1);
+       } else {
+               spin_lock_bh(&pool->sp_lock);
+               nrservs -= pool->sp_nrthreads;
+               spin_unlock_bh(&pool->sp_lock);
        }
 
-       return error;
+       if (nrservs > 0)
+               return svc_start_kthreads(serv, pool, nrservs);
+       if (nrservs < 0)
+               return svc_signal_kthreads(serv, pool, nrservs);
+       return 0;
 }
 EXPORT_SYMBOL_GPL(svc_set_num_threads);
 
+/* destroy old threads */
+static int
+svc_stop_kthreads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
+{
+       struct task_struct *task;
+       unsigned int state = serv->sv_nrthreads-1;
+
+       /* destroy old threads */
+       do {
+               task = choose_victim(serv, pool, &state);
+               if (task == NULL)
+                       break;
+               kthread_stop(task);
+               nrservs++;
+       } while (nrservs < 0);
+       return 0;
+}
+
+int
+svc_set_num_threads_sync(struct svc_serv *serv, struct svc_pool *pool, int 
nrservs)
+{
+       if (pool == NULL) {
+               /* The -1 assumes caller has done a svc_get() */
+               nrservs -= (serv->sv_nrthreads-1);
+       } else {
+               spin_lock_bh(&pool->sp_lock);
+               nrservs -= pool->sp_nrthreads;
+               spin_unlock_bh(&pool->sp_lock);
+       }
+
+       if (nrservs > 0)
+               return svc_start_kthreads(serv, pool, nrservs);
+       if (nrservs < 0)
+               return svc_stop_kthreads(serv, pool, nrservs);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(svc_set_num_threads_sync);
+
 /*
  * Called from a server thread as it's exiting. Caller must hold the "service
  * mutex" for the service.

Reply via email to