2105 lines
65 KiB
Diff
2105 lines
65 KiB
Diff
diff --git a/Makefile b/Makefile
|
|
index 52a41396680c..7d7bda23db8f 100644
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -1,6 +1,6 @@
|
|
VERSION = 4
|
|
PATCHLEVEL = 9
|
|
-SUBLEVEL = 100
|
|
+SUBLEVEL = 101
|
|
EXTRAVERSION =
|
|
NAME = Roaring Lionus
|
|
|
|
diff --git a/arch/alpha/include/asm/futex.h b/arch/alpha/include/asm/futex.h
|
|
index f939794363ac..56474690e685 100644
|
|
--- a/arch/alpha/include/asm/futex.h
|
|
+++ b/arch/alpha/include/asm/futex.h
|
|
@@ -29,18 +29,10 @@
|
|
: "r" (uaddr), "r"(oparg) \
|
|
: "memory")
|
|
|
|
-static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
|
|
+static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
|
|
+ u32 __user *uaddr)
|
|
{
|
|
- int op = (encoded_op >> 28) & 7;
|
|
- int cmp = (encoded_op >> 24) & 15;
|
|
- int oparg = (encoded_op << 8) >> 20;
|
|
- int cmparg = (encoded_op << 20) >> 20;
|
|
int oldval = 0, ret;
|
|
- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
|
|
- oparg = 1 << oparg;
|
|
-
|
|
- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
|
|
- return -EFAULT;
|
|
|
|
pagefault_disable();
|
|
|
|
@@ -66,17 +58,9 @@ static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
|
|
|
|
pagefault_enable();
|
|
|
|
- if (!ret) {
|
|
- switch (cmp) {
|
|
- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
|
|
- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
|
|
- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
|
|
- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
|
|
- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
|
|
- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
|
|
- default: ret = -ENOSYS;
|
|
- }
|
|
- }
|
|
+ if (!ret)
|
|
+ *oval = oldval;
|
|
+
|
|
return ret;
|
|
}
|
|
|
|
diff --git a/arch/arc/include/asm/futex.h b/arch/arc/include/asm/futex.h
|
|
index 11e1b1f3acda..eb887dd13e74 100644
|
|
--- a/arch/arc/include/asm/futex.h
|
|
+++ b/arch/arc/include/asm/futex.h
|
|
@@ -73,20 +73,11 @@
|
|
|
|
#endif
|
|
|
|
-static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
|
|
+static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
|
|
+ u32 __user *uaddr)
|
|
{
|
|
- int op = (encoded_op >> 28) & 7;
|
|
- int cmp = (encoded_op >> 24) & 15;
|
|
- int oparg = (encoded_op << 8) >> 20;
|
|
- int cmparg = (encoded_op << 20) >> 20;
|
|
int oldval = 0, ret;
|
|
|
|
- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
|
|
- oparg = 1 << oparg;
|
|
-
|
|
- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
|
|
- return -EFAULT;
|
|
-
|
|
#ifndef CONFIG_ARC_HAS_LLSC
|
|
preempt_disable(); /* to guarantee atomic r-m-w of futex op */
|
|
#endif
|
|
@@ -118,30 +109,9 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
|
|
preempt_enable();
|
|
#endif
|
|
|
|
- if (!ret) {
|
|
- switch (cmp) {
|
|
- case FUTEX_OP_CMP_EQ:
|
|
- ret = (oldval == cmparg);
|
|
- break;
|
|
- case FUTEX_OP_CMP_NE:
|
|
- ret = (oldval != cmparg);
|
|
- break;
|
|
- case FUTEX_OP_CMP_LT:
|
|
- ret = (oldval < cmparg);
|
|
- break;
|
|
- case FUTEX_OP_CMP_GE:
|
|
- ret = (oldval >= cmparg);
|
|
- break;
|
|
- case FUTEX_OP_CMP_LE:
|
|
- ret = (oldval <= cmparg);
|
|
- break;
|
|
- case FUTEX_OP_CMP_GT:
|
|
- ret = (oldval > cmparg);
|
|
- break;
|
|
- default:
|
|
- ret = -ENOSYS;
|
|
- }
|
|
- }
|
|
+ if (!ret)
|
|
+ *oval = oldval;
|
|
+
|
|
return ret;
|
|
}
|
|
|
|
diff --git a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi
|
|
index 47c955458a77..2b9c2be436f9 100644
|
|
--- a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi
|
|
+++ b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi
|
|
@@ -88,7 +88,6 @@
|
|
clocks = <&clks IMX6QDL_CLK_CKO>;
|
|
VDDA-supply = <®_2p5v>;
|
|
VDDIO-supply = <®_3p3v>;
|
|
- lrclk-strength = <3>;
|
|
};
|
|
};
|
|
|
|
diff --git a/arch/arm/include/asm/futex.h b/arch/arm/include/asm/futex.h
|
|
index 6795368ad023..cc414382dab4 100644
|
|
--- a/arch/arm/include/asm/futex.h
|
|
+++ b/arch/arm/include/asm/futex.h
|
|
@@ -128,20 +128,10 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
|
|
#endif /* !SMP */
|
|
|
|
static inline int
|
|
-futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
|
|
+arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
|
|
{
|
|
- int op = (encoded_op >> 28) & 7;
|
|
- int cmp = (encoded_op >> 24) & 15;
|
|
- int oparg = (encoded_op << 8) >> 20;
|
|
- int cmparg = (encoded_op << 20) >> 20;
|
|
int oldval = 0, ret, tmp;
|
|
|
|
- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
|
|
- oparg = 1 << oparg;
|
|
-
|
|
- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
|
|
- return -EFAULT;
|
|
-
|
|
#ifndef CONFIG_SMP
|
|
preempt_disable();
|
|
#endif
|
|
@@ -172,17 +162,9 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
|
|
preempt_enable();
|
|
#endif
|
|
|
|
- if (!ret) {
|
|
- switch (cmp) {
|
|
- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
|
|
- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
|
|
- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
|
|
- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
|
|
- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
|
|
- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
|
|
- default: ret = -ENOSYS;
|
|
- }
|
|
- }
|
|
+ if (!ret)
|
|
+ *oval = oldval;
|
|
+
|
|
return ret;
|
|
}
|
|
|
|
diff --git a/arch/arm64/include/asm/futex.h b/arch/arm64/include/asm/futex.h
|
|
index 4e5f36a804b4..2a5090fb9113 100644
|
|
--- a/arch/arm64/include/asm/futex.h
|
|
+++ b/arch/arm64/include/asm/futex.h
|
|
@@ -51,20 +51,9 @@
|
|
: "memory")
|
|
|
|
static inline int
|
|
-futex_atomic_op_inuser(unsigned int encoded_op, u32 __user *_uaddr)
|
|
+arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
|
|
{
|
|
- int op = (encoded_op >> 28) & 7;
|
|
- int cmp = (encoded_op >> 24) & 15;
|
|
- int oparg = (int)(encoded_op << 8) >> 20;
|
|
- int cmparg = (int)(encoded_op << 20) >> 20;
|
|
int oldval = 0, ret, tmp;
|
|
- u32 __user *uaddr = __uaccess_mask_ptr(_uaddr);
|
|
-
|
|
- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
|
|
- oparg = 1U << (oparg & 0x1f);
|
|
-
|
|
- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
|
|
- return -EFAULT;
|
|
|
|
pagefault_disable();
|
|
|
|
@@ -95,17 +84,9 @@ futex_atomic_op_inuser(unsigned int encoded_op, u32 __user *_uaddr)
|
|
|
|
pagefault_enable();
|
|
|
|
- if (!ret) {
|
|
- switch (cmp) {
|
|
- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
|
|
- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
|
|
- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
|
|
- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
|
|
- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
|
|
- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
|
|
- default: ret = -ENOSYS;
|
|
- }
|
|
- }
|
|
+ if (!ret)
|
|
+ *oval = oldval;
|
|
+
|
|
return ret;
|
|
}
|
|
|
|
diff --git a/arch/frv/include/asm/futex.h b/arch/frv/include/asm/futex.h
|
|
index 4bea27f50a7a..2702bd802d44 100644
|
|
--- a/arch/frv/include/asm/futex.h
|
|
+++ b/arch/frv/include/asm/futex.h
|
|
@@ -7,7 +7,8 @@
|
|
#include <asm/errno.h>
|
|
#include <asm/uaccess.h>
|
|
|
|
-extern int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr);
|
|
+extern int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
|
|
+ u32 __user *uaddr);
|
|
|
|
static inline int
|
|
futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
|
|
diff --git a/arch/frv/kernel/futex.c b/arch/frv/kernel/futex.c
|
|
index d155ca9e5098..37f7b2bf7f73 100644
|
|
--- a/arch/frv/kernel/futex.c
|
|
+++ b/arch/frv/kernel/futex.c
|
|
@@ -186,20 +186,10 @@ static inline int atomic_futex_op_xchg_xor(int oparg, u32 __user *uaddr, int *_o
|
|
/*
|
|
* do the futex operations
|
|
*/
|
|
-int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
|
|
+int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
|
|
{
|
|
- int op = (encoded_op >> 28) & 7;
|
|
- int cmp = (encoded_op >> 24) & 15;
|
|
- int oparg = (encoded_op << 8) >> 20;
|
|
- int cmparg = (encoded_op << 20) >> 20;
|
|
int oldval = 0, ret;
|
|
|
|
- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
|
|
- oparg = 1 << oparg;
|
|
-
|
|
- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
|
|
- return -EFAULT;
|
|
-
|
|
pagefault_disable();
|
|
|
|
switch (op) {
|
|
@@ -225,18 +215,9 @@ int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
|
|
|
|
pagefault_enable();
|
|
|
|
- if (!ret) {
|
|
- switch (cmp) {
|
|
- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
|
|
- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
|
|
- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
|
|
- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
|
|
- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
|
|
- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
|
|
- default: ret = -ENOSYS; break;
|
|
- }
|
|
- }
|
|
+ if (!ret)
|
|
+ *oval = oldval;
|
|
|
|
return ret;
|
|
|
|
-} /* end futex_atomic_op_inuser() */
|
|
+} /* end arch_futex_atomic_op_inuser() */
|
|
diff --git a/arch/hexagon/include/asm/futex.h b/arch/hexagon/include/asm/futex.h
|
|
index 7e597f8434da..c607b77c8215 100644
|
|
--- a/arch/hexagon/include/asm/futex.h
|
|
+++ b/arch/hexagon/include/asm/futex.h
|
|
@@ -31,18 +31,9 @@
|
|
|
|
|
|
static inline int
|
|
-futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
|
|
+arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
|
|
{
|
|
- int op = (encoded_op >> 28) & 7;
|
|
- int cmp = (encoded_op >> 24) & 15;
|
|
- int oparg = (encoded_op << 8) >> 20;
|
|
- int cmparg = (encoded_op << 20) >> 20;
|
|
int oldval = 0, ret;
|
|
- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
|
|
- oparg = 1 << oparg;
|
|
-
|
|
- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
|
|
- return -EFAULT;
|
|
|
|
pagefault_disable();
|
|
|
|
@@ -72,30 +63,9 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
|
|
|
|
pagefault_enable();
|
|
|
|
- if (!ret) {
|
|
- switch (cmp) {
|
|
- case FUTEX_OP_CMP_EQ:
|
|
- ret = (oldval == cmparg);
|
|
- break;
|
|
- case FUTEX_OP_CMP_NE:
|
|
- ret = (oldval != cmparg);
|
|
- break;
|
|
- case FUTEX_OP_CMP_LT:
|
|
- ret = (oldval < cmparg);
|
|
- break;
|
|
- case FUTEX_OP_CMP_GE:
|
|
- ret = (oldval >= cmparg);
|
|
- break;
|
|
- case FUTEX_OP_CMP_LE:
|
|
- ret = (oldval <= cmparg);
|
|
- break;
|
|
- case FUTEX_OP_CMP_GT:
|
|
- ret = (oldval > cmparg);
|
|
- break;
|
|
- default:
|
|
- ret = -ENOSYS;
|
|
- }
|
|
- }
|
|
+ if (!ret)
|
|
+ *oval = oldval;
|
|
+
|
|
return ret;
|
|
}
|
|
|
|
diff --git a/arch/ia64/include/asm/futex.h b/arch/ia64/include/asm/futex.h
|
|
index 76acbcd5c060..6d67dc1eaf2b 100644
|
|
--- a/arch/ia64/include/asm/futex.h
|
|
+++ b/arch/ia64/include/asm/futex.h
|
|
@@ -45,18 +45,9 @@ do { \
|
|
} while (0)
|
|
|
|
static inline int
|
|
-futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
|
|
+arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
|
|
{
|
|
- int op = (encoded_op >> 28) & 7;
|
|
- int cmp = (encoded_op >> 24) & 15;
|
|
- int oparg = (encoded_op << 8) >> 20;
|
|
- int cmparg = (encoded_op << 20) >> 20;
|
|
int oldval = 0, ret;
|
|
- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
|
|
- oparg = 1 << oparg;
|
|
-
|
|
- if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
|
|
- return -EFAULT;
|
|
|
|
pagefault_disable();
|
|
|
|
@@ -84,17 +75,9 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
|
|
|
|
pagefault_enable();
|
|
|
|
- if (!ret) {
|
|
- switch (cmp) {
|
|
- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
|
|
- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
|
|
- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
|
|
- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
|
|
- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
|
|
- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
|
|
- default: ret = -ENOSYS;
|
|
- }
|
|
- }
|
|
+ if (!ret)
|
|
+ *oval = oldval;
|
|
+
|
|
return ret;
|
|
}
|
|
|
|
diff --git a/arch/microblaze/include/asm/futex.h b/arch/microblaze/include/asm/futex.h
|
|
index 01848f056f43..a9dad9e5e132 100644
|
|
--- a/arch/microblaze/include/asm/futex.h
|
|
+++ b/arch/microblaze/include/asm/futex.h
|
|
@@ -29,18 +29,9 @@
|
|
})
|
|
|
|
static inline int
|
|
-futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
|
|
+arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
|
|
{
|
|
- int op = (encoded_op >> 28) & 7;
|
|
- int cmp = (encoded_op >> 24) & 15;
|
|
- int oparg = (encoded_op << 8) >> 20;
|
|
- int cmparg = (encoded_op << 20) >> 20;
|
|
int oldval = 0, ret;
|
|
- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
|
|
- oparg = 1 << oparg;
|
|
-
|
|
- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
|
|
- return -EFAULT;
|
|
|
|
pagefault_disable();
|
|
|
|
@@ -66,30 +57,9 @@ futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
|
|
|
|
pagefault_enable();
|
|
|
|
- if (!ret) {
|
|
- switch (cmp) {
|
|
- case FUTEX_OP_CMP_EQ:
|
|
- ret = (oldval == cmparg);
|
|
- break;
|
|
- case FUTEX_OP_CMP_NE:
|
|
- ret = (oldval != cmparg);
|
|
- break;
|
|
- case FUTEX_OP_CMP_LT:
|
|
- ret = (oldval < cmparg);
|
|
- break;
|
|
- case FUTEX_OP_CMP_GE:
|
|
- ret = (oldval >= cmparg);
|
|
- break;
|
|
- case FUTEX_OP_CMP_LE:
|
|
- ret = (oldval <= cmparg);
|
|
- break;
|
|
- case FUTEX_OP_CMP_GT:
|
|
- ret = (oldval > cmparg);
|
|
- break;
|
|
- default:
|
|
- ret = -ENOSYS;
|
|
- }
|
|
- }
|
|
+ if (!ret)
|
|
+ *oval = oldval;
|
|
+
|
|
return ret;
|
|
}
|
|
|
|
diff --git a/arch/mips/include/asm/futex.h b/arch/mips/include/asm/futex.h
|
|
index 1de190bdfb9c..a9e61ea54ca9 100644
|
|
--- a/arch/mips/include/asm/futex.h
|
|
+++ b/arch/mips/include/asm/futex.h
|
|
@@ -83,18 +83,9 @@
|
|
}
|
|
|
|
static inline int
|
|
-futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
|
|
+arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
|
|
{
|
|
- int op = (encoded_op >> 28) & 7;
|
|
- int cmp = (encoded_op >> 24) & 15;
|
|
- int oparg = (encoded_op << 8) >> 20;
|
|
- int cmparg = (encoded_op << 20) >> 20;
|
|
int oldval = 0, ret;
|
|
- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
|
|
- oparg = 1 << oparg;
|
|
-
|
|
- if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
|
|
- return -EFAULT;
|
|
|
|
pagefault_disable();
|
|
|
|
@@ -125,17 +116,9 @@ futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
|
|
|
|
pagefault_enable();
|
|
|
|
- if (!ret) {
|
|
- switch (cmp) {
|
|
- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
|
|
- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
|
|
- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
|
|
- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
|
|
- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
|
|
- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
|
|
- default: ret = -ENOSYS;
|
|
- }
|
|
- }
|
|
+ if (!ret)
|
|
+ *oval = oldval;
|
|
+
|
|
return ret;
|
|
}
|
|
|
|
diff --git a/arch/parisc/include/asm/futex.h b/arch/parisc/include/asm/futex.h
|
|
index ac8bd586ace8..06a1a883c72f 100644
|
|
--- a/arch/parisc/include/asm/futex.h
|
|
+++ b/arch/parisc/include/asm/futex.h
|
|
@@ -32,22 +32,12 @@ _futex_spin_unlock_irqrestore(u32 __user *uaddr, unsigned long int *flags)
|
|
}
|
|
|
|
static inline int
|
|
-futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
|
|
+arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
|
|
{
|
|
unsigned long int flags;
|
|
- int op = (encoded_op >> 28) & 7;
|
|
- int cmp = (encoded_op >> 24) & 15;
|
|
- int oparg = (encoded_op << 8) >> 20;
|
|
- int cmparg = (encoded_op << 20) >> 20;
|
|
int oldval, ret;
|
|
u32 tmp;
|
|
|
|
- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
|
|
- oparg = 1 << oparg;
|
|
-
|
|
- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(*uaddr)))
|
|
- return -EFAULT;
|
|
-
|
|
_futex_spin_lock_irqsave(uaddr, &flags);
|
|
pagefault_disable();
|
|
|
|
@@ -85,17 +75,9 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
|
|
pagefault_enable();
|
|
_futex_spin_unlock_irqrestore(uaddr, &flags);
|
|
|
|
- if (ret == 0) {
|
|
- switch (cmp) {
|
|
- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
|
|
- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
|
|
- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
|
|
- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
|
|
- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
|
|
- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
|
|
- default: ret = -ENOSYS;
|
|
- }
|
|
- }
|
|
+ if (!ret)
|
|
+ *oval = oldval;
|
|
+
|
|
return ret;
|
|
}
|
|
|
|
diff --git a/arch/powerpc/include/asm/futex.h b/arch/powerpc/include/asm/futex.h
|
|
index 2a9cf845473b..f4c7467f7465 100644
|
|
--- a/arch/powerpc/include/asm/futex.h
|
|
+++ b/arch/powerpc/include/asm/futex.h
|
|
@@ -31,18 +31,10 @@
|
|
: "b" (uaddr), "i" (-EFAULT), "r" (oparg) \
|
|
: "cr0", "memory")
|
|
|
|
-static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
|
|
+static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
|
|
+ u32 __user *uaddr)
|
|
{
|
|
- int op = (encoded_op >> 28) & 7;
|
|
- int cmp = (encoded_op >> 24) & 15;
|
|
- int oparg = (encoded_op << 8) >> 20;
|
|
- int cmparg = (encoded_op << 20) >> 20;
|
|
int oldval = 0, ret;
|
|
- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
|
|
- oparg = 1 << oparg;
|
|
-
|
|
- if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
|
|
- return -EFAULT;
|
|
|
|
pagefault_disable();
|
|
|
|
@@ -68,17 +60,9 @@ static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
|
|
|
|
pagefault_enable();
|
|
|
|
- if (!ret) {
|
|
- switch (cmp) {
|
|
- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
|
|
- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
|
|
- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
|
|
- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
|
|
- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
|
|
- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
|
|
- default: ret = -ENOSYS;
|
|
- }
|
|
- }
|
|
+ if (!ret)
|
|
+ *oval = oldval;
|
|
+
|
|
return ret;
|
|
}
|
|
|
|
diff --git a/arch/s390/include/asm/futex.h b/arch/s390/include/asm/futex.h
|
|
index a4811aa0304d..8f8eec9e1198 100644
|
|
--- a/arch/s390/include/asm/futex.h
|
|
+++ b/arch/s390/include/asm/futex.h
|
|
@@ -21,17 +21,12 @@
|
|
: "0" (-EFAULT), "d" (oparg), "a" (uaddr), \
|
|
"m" (*uaddr) : "cc");
|
|
|
|
-static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
|
|
+static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
|
|
+ u32 __user *uaddr)
|
|
{
|
|
- int op = (encoded_op >> 28) & 7;
|
|
- int cmp = (encoded_op >> 24) & 15;
|
|
- int oparg = (encoded_op << 8) >> 20;
|
|
- int cmparg = (encoded_op << 20) >> 20;
|
|
int oldval = 0, newval, ret;
|
|
|
|
load_kernel_asce();
|
|
- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
|
|
- oparg = 1 << oparg;
|
|
|
|
pagefault_disable();
|
|
switch (op) {
|
|
@@ -60,17 +55,9 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
|
|
}
|
|
pagefault_enable();
|
|
|
|
- if (!ret) {
|
|
- switch (cmp) {
|
|
- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
|
|
- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
|
|
- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
|
|
- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
|
|
- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
|
|
- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
|
|
- default: ret = -ENOSYS;
|
|
- }
|
|
- }
|
|
+ if (!ret)
|
|
+ *oval = oldval;
|
|
+
|
|
return ret;
|
|
}
|
|
|
|
diff --git a/arch/sh/include/asm/futex.h b/arch/sh/include/asm/futex.h
|
|
index d0078747d308..8f8cf941a8cd 100644
|
|
--- a/arch/sh/include/asm/futex.h
|
|
+++ b/arch/sh/include/asm/futex.h
|
|
@@ -27,21 +27,12 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
|
|
return atomic_futex_op_cmpxchg_inatomic(uval, uaddr, oldval, newval);
|
|
}
|
|
|
|
-static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
|
|
+static inline int arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval,
|
|
+ u32 __user *uaddr)
|
|
{
|
|
- int op = (encoded_op >> 28) & 7;
|
|
- int cmp = (encoded_op >> 24) & 15;
|
|
- u32 oparg = (encoded_op << 8) >> 20;
|
|
- u32 cmparg = (encoded_op << 20) >> 20;
|
|
u32 oldval, newval, prev;
|
|
int ret;
|
|
|
|
- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
|
|
- oparg = 1 << oparg;
|
|
-
|
|
- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
|
|
- return -EFAULT;
|
|
-
|
|
pagefault_disable();
|
|
|
|
do {
|
|
@@ -80,17 +71,8 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
|
|
|
|
pagefault_enable();
|
|
|
|
- if (!ret) {
|
|
- switch (cmp) {
|
|
- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
|
|
- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
|
|
- case FUTEX_OP_CMP_LT: ret = ((int)oldval < (int)cmparg); break;
|
|
- case FUTEX_OP_CMP_GE: ret = ((int)oldval >= (int)cmparg); break;
|
|
- case FUTEX_OP_CMP_LE: ret = ((int)oldval <= (int)cmparg); break;
|
|
- case FUTEX_OP_CMP_GT: ret = ((int)oldval > (int)cmparg); break;
|
|
- default: ret = -ENOSYS;
|
|
- }
|
|
- }
|
|
+ if (!ret)
|
|
+ *oval = oldval;
|
|
|
|
return ret;
|
|
}
|
|
diff --git a/arch/sparc/include/asm/futex_64.h b/arch/sparc/include/asm/futex_64.h
|
|
index 4e899b0dabf7..1cfd89d92208 100644
|
|
--- a/arch/sparc/include/asm/futex_64.h
|
|
+++ b/arch/sparc/include/asm/futex_64.h
|
|
@@ -29,22 +29,14 @@
|
|
: "r" (uaddr), "r" (oparg), "i" (-EFAULT) \
|
|
: "memory")
|
|
|
|
-static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
|
|
+static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
|
|
+ u32 __user *uaddr)
|
|
{
|
|
- int op = (encoded_op >> 28) & 7;
|
|
- int cmp = (encoded_op >> 24) & 15;
|
|
- int oparg = (encoded_op << 8) >> 20;
|
|
- int cmparg = (encoded_op << 20) >> 20;
|
|
int oldval = 0, ret, tem;
|
|
|
|
- if (unlikely(!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))))
|
|
- return -EFAULT;
|
|
if (unlikely((((unsigned long) uaddr) & 0x3UL)))
|
|
return -EINVAL;
|
|
|
|
- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
|
|
- oparg = 1 << oparg;
|
|
-
|
|
pagefault_disable();
|
|
|
|
switch (op) {
|
|
@@ -69,17 +61,9 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
|
|
|
|
pagefault_enable();
|
|
|
|
- if (!ret) {
|
|
- switch (cmp) {
|
|
- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
|
|
- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
|
|
- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
|
|
- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
|
|
- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
|
|
- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
|
|
- default: ret = -ENOSYS;
|
|
- }
|
|
- }
|
|
+ if (!ret)
|
|
+ *oval = oldval;
|
|
+
|
|
return ret;
|
|
}
|
|
|
|
diff --git a/arch/tile/include/asm/futex.h b/arch/tile/include/asm/futex.h
|
|
index e64a1b75fc38..83c1e639b411 100644
|
|
--- a/arch/tile/include/asm/futex.h
|
|
+++ b/arch/tile/include/asm/futex.h
|
|
@@ -106,12 +106,9 @@
|
|
lock = __atomic_hashed_lock((int __force *)uaddr)
|
|
#endif
|
|
|
|
-static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
|
|
+static inline int arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval,
|
|
+ u32 __user *uaddr)
|
|
{
|
|
- int op = (encoded_op >> 28) & 7;
|
|
- int cmp = (encoded_op >> 24) & 15;
|
|
- int oparg = (encoded_op << 8) >> 20;
|
|
- int cmparg = (encoded_op << 20) >> 20;
|
|
int uninitialized_var(val), ret;
|
|
|
|
__futex_prolog();
|
|
@@ -119,12 +116,6 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
|
|
/* The 32-bit futex code makes this assumption, so validate it here. */
|
|
BUILD_BUG_ON(sizeof(atomic_t) != sizeof(int));
|
|
|
|
- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
|
|
- oparg = 1 << oparg;
|
|
-
|
|
- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
|
|
- return -EFAULT;
|
|
-
|
|
pagefault_disable();
|
|
switch (op) {
|
|
case FUTEX_OP_SET:
|
|
@@ -148,30 +139,9 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
|
|
}
|
|
pagefault_enable();
|
|
|
|
- if (!ret) {
|
|
- switch (cmp) {
|
|
- case FUTEX_OP_CMP_EQ:
|
|
- ret = (val == cmparg);
|
|
- break;
|
|
- case FUTEX_OP_CMP_NE:
|
|
- ret = (val != cmparg);
|
|
- break;
|
|
- case FUTEX_OP_CMP_LT:
|
|
- ret = (val < cmparg);
|
|
- break;
|
|
- case FUTEX_OP_CMP_GE:
|
|
- ret = (val >= cmparg);
|
|
- break;
|
|
- case FUTEX_OP_CMP_LE:
|
|
- ret = (val <= cmparg);
|
|
- break;
|
|
- case FUTEX_OP_CMP_GT:
|
|
- ret = (val > cmparg);
|
|
- break;
|
|
- default:
|
|
- ret = -ENOSYS;
|
|
- }
|
|
- }
|
|
+ if (!ret)
|
|
+ *oval = val;
|
|
+
|
|
return ret;
|
|
}
|
|
|
|
diff --git a/arch/x86/include/asm/futex.h b/arch/x86/include/asm/futex.h
|
|
index b4c1f5453436..f4dc9b63bdda 100644
|
|
--- a/arch/x86/include/asm/futex.h
|
|
+++ b/arch/x86/include/asm/futex.h
|
|
@@ -41,20 +41,11 @@
|
|
"+m" (*uaddr), "=&r" (tem) \
|
|
: "r" (oparg), "i" (-EFAULT), "1" (0))
|
|
|
|
-static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
|
|
+static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
|
|
+ u32 __user *uaddr)
|
|
{
|
|
- int op = (encoded_op >> 28) & 7;
|
|
- int cmp = (encoded_op >> 24) & 15;
|
|
- int oparg = (encoded_op << 8) >> 20;
|
|
- int cmparg = (encoded_op << 20) >> 20;
|
|
int oldval = 0, ret, tem;
|
|
|
|
- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
|
|
- oparg = 1 << oparg;
|
|
-
|
|
- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
|
|
- return -EFAULT;
|
|
-
|
|
pagefault_disable();
|
|
|
|
switch (op) {
|
|
@@ -80,30 +71,9 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
|
|
|
|
pagefault_enable();
|
|
|
|
- if (!ret) {
|
|
- switch (cmp) {
|
|
- case FUTEX_OP_CMP_EQ:
|
|
- ret = (oldval == cmparg);
|
|
- break;
|
|
- case FUTEX_OP_CMP_NE:
|
|
- ret = (oldval != cmparg);
|
|
- break;
|
|
- case FUTEX_OP_CMP_LT:
|
|
- ret = (oldval < cmparg);
|
|
- break;
|
|
- case FUTEX_OP_CMP_GE:
|
|
- ret = (oldval >= cmparg);
|
|
- break;
|
|
- case FUTEX_OP_CMP_LE:
|
|
- ret = (oldval <= cmparg);
|
|
- break;
|
|
- case FUTEX_OP_CMP_GT:
|
|
- ret = (oldval > cmparg);
|
|
- break;
|
|
- default:
|
|
- ret = -ENOSYS;
|
|
- }
|
|
- }
|
|
+ if (!ret)
|
|
+ *oval = oldval;
|
|
+
|
|
return ret;
|
|
}
|
|
|
|
diff --git a/arch/xtensa/include/asm/futex.h b/arch/xtensa/include/asm/futex.h
|
|
index 72bfc1cbc2b5..5bfbc1c401d4 100644
|
|
--- a/arch/xtensa/include/asm/futex.h
|
|
+++ b/arch/xtensa/include/asm/futex.h
|
|
@@ -44,18 +44,10 @@
|
|
: "r" (uaddr), "I" (-EFAULT), "r" (oparg) \
|
|
: "memory")
|
|
|
|
-static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
|
|
+static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
|
|
+ u32 __user *uaddr)
|
|
{
|
|
- int op = (encoded_op >> 28) & 7;
|
|
- int cmp = (encoded_op >> 24) & 15;
|
|
- int oparg = (encoded_op << 8) >> 20;
|
|
- int cmparg = (encoded_op << 20) >> 20;
|
|
int oldval = 0, ret;
|
|
- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
|
|
- oparg = 1 << oparg;
|
|
-
|
|
- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
|
|
- return -EFAULT;
|
|
|
|
#if !XCHAL_HAVE_S32C1I
|
|
return -ENOSYS;
|
|
@@ -89,19 +81,10 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
|
|
|
|
pagefault_enable();
|
|
|
|
- if (ret)
|
|
- return ret;
|
|
+ if (!ret)
|
|
+ *oval = oldval;
|
|
|
|
- switch (cmp) {
|
|
- case FUTEX_OP_CMP_EQ: return (oldval == cmparg);
|
|
- case FUTEX_OP_CMP_NE: return (oldval != cmparg);
|
|
- case FUTEX_OP_CMP_LT: return (oldval < cmparg);
|
|
- case FUTEX_OP_CMP_GE: return (oldval >= cmparg);
|
|
- case FUTEX_OP_CMP_LE: return (oldval <= cmparg);
|
|
- case FUTEX_OP_CMP_GT: return (oldval > cmparg);
|
|
- }
|
|
-
|
|
- return -ENOSYS;
|
|
+ return ret;
|
|
}
|
|
|
|
static inline int
|
|
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
|
|
index 551f0f8dead3..91d8a48e53c3 100644
|
|
--- a/drivers/net/bonding/bond_alb.c
|
|
+++ b/drivers/net/bonding/bond_alb.c
|
|
@@ -450,7 +450,7 @@ static void rlb_update_client(struct rlb_client_info *client_info)
|
|
{
|
|
int i;
|
|
|
|
- if (!client_info->slave)
|
|
+ if (!client_info->slave || !is_valid_ether_addr(client_info->mac_dst))
|
|
return;
|
|
|
|
for (i = 0; i < RLB_ARP_BURST_SIZE; i++) {
|
|
@@ -944,6 +944,10 @@ static void alb_send_lp_vid(struct slave *slave, u8 mac_addr[],
|
|
skb->priority = TC_PRIO_CONTROL;
|
|
skb->dev = slave->dev;
|
|
|
|
+ netdev_dbg(slave->bond->dev,
|
|
+ "Send learning packet: dev %s mac %pM vlan %d\n",
|
|
+ slave->dev->name, mac_addr, vid);
|
|
+
|
|
if (vid)
|
|
__vlan_hwaccel_put_tag(skb, vlan_proto, vid);
|
|
|
|
@@ -966,14 +970,13 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[],
|
|
*/
|
|
rcu_read_lock();
|
|
netdev_for_each_all_upper_dev_rcu(bond->dev, upper, iter) {
|
|
- if (is_vlan_dev(upper) && vlan_get_encap_level(upper) == 0) {
|
|
- if (strict_match &&
|
|
- ether_addr_equal_64bits(mac_addr,
|
|
- upper->dev_addr)) {
|
|
+ if (is_vlan_dev(upper) &&
|
|
+ bond->nest_level == vlan_get_encap_level(upper) - 1) {
|
|
+ if (upper->addr_assign_type == NET_ADDR_STOLEN) {
|
|
alb_send_lp_vid(slave, mac_addr,
|
|
vlan_dev_vlan_proto(upper),
|
|
vlan_dev_vlan_id(upper));
|
|
- } else if (!strict_match) {
|
|
+ } else {
|
|
alb_send_lp_vid(slave, upper->dev_addr,
|
|
vlan_dev_vlan_proto(upper),
|
|
vlan_dev_vlan_id(upper));
|
|
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
|
|
index 13a015b8052b..1a139d0f2232 100644
|
|
--- a/drivers/net/bonding/bond_main.c
|
|
+++ b/drivers/net/bonding/bond_main.c
|
|
@@ -1732,6 +1732,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
|
|
if (bond_mode_uses_xmit_hash(bond))
|
|
bond_update_slave_arr(bond, NULL);
|
|
|
|
+ bond->nest_level = dev_get_nest_level(bond_dev);
|
|
+
|
|
netdev_info(bond_dev, "Enslaving %s as %s interface with %s link\n",
|
|
slave_dev->name,
|
|
bond_is_active_slave(new_slave) ? "an active" : "a backup",
|
|
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
|
|
index 795a133fb074..4ffbe850d746 100644
|
|
--- a/drivers/net/ethernet/broadcom/tg3.c
|
|
+++ b/drivers/net/ethernet/broadcom/tg3.c
|
|
@@ -8720,14 +8720,15 @@ static void tg3_free_consistent(struct tg3 *tp)
|
|
tg3_mem_rx_release(tp);
|
|
tg3_mem_tx_release(tp);
|
|
|
|
- /* Protect tg3_get_stats64() from reading freed tp->hw_stats. */
|
|
- tg3_full_lock(tp, 0);
|
|
+ /* tp->hw_stats can be referenced safely:
|
|
+ * 1. under rtnl_lock
|
|
+ * 2. or under tp->lock if TG3_FLAG_INIT_COMPLETE is set.
|
|
+ */
|
|
if (tp->hw_stats) {
|
|
dma_free_coherent(&tp->pdev->dev, sizeof(struct tg3_hw_stats),
|
|
tp->hw_stats, tp->stats_mapping);
|
|
tp->hw_stats = NULL;
|
|
}
|
|
- tg3_full_unlock(tp);
|
|
}
|
|
|
|
/*
|
|
@@ -14161,7 +14162,7 @@ static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *dev,
|
|
struct tg3 *tp = netdev_priv(dev);
|
|
|
|
spin_lock_bh(&tp->lock);
|
|
- if (!tp->hw_stats) {
|
|
+ if (!tp->hw_stats || !tg3_flag(tp, INIT_COMPLETE)) {
|
|
*stats = tp->net_stats_prev;
|
|
spin_unlock_bh(&tp->lock);
|
|
return stats;
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
|
|
index 24977cc881d2..9a4c4f8281bd 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
|
|
+++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
|
|
@@ -970,6 +970,22 @@ static int mlx4_en_set_coalesce(struct net_device *dev,
|
|
if (!coal->tx_max_coalesced_frames_irq)
|
|
return -EINVAL;
|
|
|
|
+ if (coal->tx_coalesce_usecs > MLX4_EN_MAX_COAL_TIME ||
|
|
+ coal->rx_coalesce_usecs > MLX4_EN_MAX_COAL_TIME ||
|
|
+ coal->rx_coalesce_usecs_low > MLX4_EN_MAX_COAL_TIME ||
|
|
+ coal->rx_coalesce_usecs_high > MLX4_EN_MAX_COAL_TIME) {
|
|
+ netdev_info(dev, "%s: maximum coalesce time supported is %d usecs\n",
|
|
+ __func__, MLX4_EN_MAX_COAL_TIME);
|
|
+ return -ERANGE;
|
|
+ }
|
|
+
|
|
+ if (coal->tx_max_coalesced_frames > MLX4_EN_MAX_COAL_PKTS ||
|
|
+ coal->rx_max_coalesced_frames > MLX4_EN_MAX_COAL_PKTS) {
|
|
+ netdev_info(dev, "%s: maximum coalesced frames supported is %d\n",
|
|
+ __func__, MLX4_EN_MAX_COAL_PKTS);
|
|
+ return -ERANGE;
|
|
+ }
|
|
+
|
|
priv->rx_frames = (coal->rx_max_coalesced_frames ==
|
|
MLX4_EN_AUTO_CONF) ?
|
|
MLX4_EN_RX_COAL_TARGET :
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
|
|
index 18f221d8a04d..247d340be743 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
|
|
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
|
|
@@ -141,6 +141,9 @@ enum {
|
|
#define MLX4_EN_TX_COAL_PKTS 16
|
|
#define MLX4_EN_TX_COAL_TIME 0x10
|
|
|
|
+#define MLX4_EN_MAX_COAL_PKTS U16_MAX
|
|
+#define MLX4_EN_MAX_COAL_TIME U16_MAX
|
|
+
|
|
#define MLX4_EN_RX_RATE_LOW 400000
|
|
#define MLX4_EN_RX_COAL_TIME_LOW 0
|
|
#define MLX4_EN_RX_RATE_HIGH 450000
|
|
@@ -543,8 +546,8 @@ struct mlx4_en_priv {
|
|
u16 rx_usecs_low;
|
|
u32 pkt_rate_high;
|
|
u16 rx_usecs_high;
|
|
- u16 sample_interval;
|
|
- u16 adaptive_rx_coal;
|
|
+ u32 sample_interval;
|
|
+ u32 adaptive_rx_coal;
|
|
u32 msg_enable;
|
|
u32 loopback_ok;
|
|
u32 validate_loopback;
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
|
|
index a8966e6dbe1b..5d6eab19a9d8 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
|
|
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
|
|
@@ -1924,26 +1924,35 @@ int mlx5_eswitch_get_vport_stats(struct mlx5_eswitch *esw,
|
|
memset(vf_stats, 0, sizeof(*vf_stats));
|
|
vf_stats->rx_packets =
|
|
MLX5_GET_CTR(out, received_eth_unicast.packets) +
|
|
+ MLX5_GET_CTR(out, received_ib_unicast.packets) +
|
|
MLX5_GET_CTR(out, received_eth_multicast.packets) +
|
|
+ MLX5_GET_CTR(out, received_ib_multicast.packets) +
|
|
MLX5_GET_CTR(out, received_eth_broadcast.packets);
|
|
|
|
vf_stats->rx_bytes =
|
|
MLX5_GET_CTR(out, received_eth_unicast.octets) +
|
|
+ MLX5_GET_CTR(out, received_ib_unicast.octets) +
|
|
MLX5_GET_CTR(out, received_eth_multicast.octets) +
|
|
+ MLX5_GET_CTR(out, received_ib_multicast.octets) +
|
|
MLX5_GET_CTR(out, received_eth_broadcast.octets);
|
|
|
|
vf_stats->tx_packets =
|
|
MLX5_GET_CTR(out, transmitted_eth_unicast.packets) +
|
|
+ MLX5_GET_CTR(out, transmitted_ib_unicast.packets) +
|
|
MLX5_GET_CTR(out, transmitted_eth_multicast.packets) +
|
|
+ MLX5_GET_CTR(out, transmitted_ib_multicast.packets) +
|
|
MLX5_GET_CTR(out, transmitted_eth_broadcast.packets);
|
|
|
|
vf_stats->tx_bytes =
|
|
MLX5_GET_CTR(out, transmitted_eth_unicast.octets) +
|
|
+ MLX5_GET_CTR(out, transmitted_ib_unicast.octets) +
|
|
MLX5_GET_CTR(out, transmitted_eth_multicast.octets) +
|
|
+ MLX5_GET_CTR(out, transmitted_ib_multicast.octets) +
|
|
MLX5_GET_CTR(out, transmitted_eth_broadcast.octets);
|
|
|
|
vf_stats->multicast =
|
|
- MLX5_GET_CTR(out, received_eth_multicast.packets);
|
|
+ MLX5_GET_CTR(out, received_eth_multicast.packets) +
|
|
+ MLX5_GET_CTR(out, received_ib_multicast.packets);
|
|
|
|
vf_stats->broadcast =
|
|
MLX5_GET_CTR(out, received_eth_broadcast.packets);
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
|
|
index 331a6ca4856d..5f3402ba9916 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
|
|
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
|
|
@@ -153,6 +153,7 @@ static void del_rule(struct fs_node *node);
|
|
static void del_flow_table(struct fs_node *node);
|
|
static void del_flow_group(struct fs_node *node);
|
|
static void del_fte(struct fs_node *node);
|
|
+static void cleanup_root_ns(struct mlx5_flow_root_namespace *root_ns);
|
|
|
|
static void tree_init_node(struct fs_node *node,
|
|
unsigned int refcount,
|
|
@@ -1690,24 +1691,28 @@ static int create_anchor_flow_table(struct mlx5_flow_steering *steering)
|
|
|
|
static int init_root_ns(struct mlx5_flow_steering *steering)
|
|
{
|
|
+ int err;
|
|
|
|
steering->root_ns = create_root_ns(steering, FS_FT_NIC_RX);
|
|
if (!steering->root_ns)
|
|
- goto cleanup;
|
|
+ return -ENOMEM;
|
|
|
|
- if (init_root_tree(steering, &root_fs, &steering->root_ns->ns.node))
|
|
- goto cleanup;
|
|
+ err = init_root_tree(steering, &root_fs, &steering->root_ns->ns.node);
|
|
+ if (err)
|
|
+ goto out_err;
|
|
|
|
set_prio_attrs(steering->root_ns);
|
|
|
|
- if (create_anchor_flow_table(steering))
|
|
- goto cleanup;
|
|
+ err = create_anchor_flow_table(steering);
|
|
+ if (err)
|
|
+ goto out_err;
|
|
|
|
return 0;
|
|
|
|
-cleanup:
|
|
- mlx5_cleanup_fs(steering->dev);
|
|
- return -ENOMEM;
|
|
+out_err:
|
|
+ cleanup_root_ns(steering->root_ns);
|
|
+ steering->root_ns = NULL;
|
|
+ return err;
|
|
}
|
|
|
|
static void clean_tree(struct fs_node *node)
|
|
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
|
|
index 4ca82bd8c4f0..eee6e59e6cf3 100644
|
|
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
|
|
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
|
|
@@ -854,6 +854,8 @@ static int nfp_net_tx(struct sk_buff *skb, struct net_device *netdev)
|
|
|
|
netdev_tx_sent_queue(nd_q, txbuf->real_len);
|
|
|
|
+ skb_tx_timestamp(skb);
|
|
+
|
|
tx_ring->wr_p += nr_frags + 1;
|
|
if (nfp_net_tx_ring_should_stop(tx_ring))
|
|
nfp_net_tx_ring_stop(nd_q, tx_ring);
|
|
@@ -866,8 +868,6 @@ static int nfp_net_tx(struct sk_buff *skb, struct net_device *netdev)
|
|
tx_ring->wr_ptr_add = 0;
|
|
}
|
|
|
|
- skb_tx_timestamp(skb);
|
|
-
|
|
return NETDEV_TX_OK;
|
|
|
|
err_unmap:
|
|
diff --git a/drivers/net/ethernet/realtek/8139too.c b/drivers/net/ethernet/realtek/8139too.c
|
|
index da4c2d8a4173..1420dfb56bac 100644
|
|
--- a/drivers/net/ethernet/realtek/8139too.c
|
|
+++ b/drivers/net/ethernet/realtek/8139too.c
|
|
@@ -2233,7 +2233,7 @@ static void rtl8139_poll_controller(struct net_device *dev)
|
|
struct rtl8139_private *tp = netdev_priv(dev);
|
|
const int irq = tp->pci_dev->irq;
|
|
|
|
- disable_irq(irq);
|
|
+ disable_irq_nosync(irq);
|
|
rtl8139_interrupt(irq, dev);
|
|
enable_irq(irq);
|
|
}
|
|
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
|
|
index dbb63640bc6e..59b932db0d42 100644
|
|
--- a/drivers/net/ethernet/realtek/r8169.c
|
|
+++ b/drivers/net/ethernet/realtek/r8169.c
|
|
@@ -4861,6 +4861,9 @@ static void rtl_pll_power_down(struct rtl8169_private *tp)
|
|
static void rtl_pll_power_up(struct rtl8169_private *tp)
|
|
{
|
|
rtl_generic_op(tp, tp->pll_power_ops.up);
|
|
+
|
|
+ /* give MAC/PHY some time to resume */
|
|
+ msleep(20);
|
|
}
|
|
|
|
static void rtl_init_pll_power_ops(struct rtl8169_private *tp)
|
|
diff --git a/drivers/net/ethernet/sun/niu.c b/drivers/net/ethernet/sun/niu.c
|
|
index a2371aa14a49..e45e2f14fb94 100644
|
|
--- a/drivers/net/ethernet/sun/niu.c
|
|
+++ b/drivers/net/ethernet/sun/niu.c
|
|
@@ -3442,7 +3442,7 @@ static int niu_process_rx_pkt(struct napi_struct *napi, struct niu *np,
|
|
|
|
len = (val & RCR_ENTRY_L2_LEN) >>
|
|
RCR_ENTRY_L2_LEN_SHIFT;
|
|
- len -= ETH_FCS_LEN;
|
|
+ append_size = len + ETH_HLEN + ETH_FCS_LEN;
|
|
|
|
addr = (val & RCR_ENTRY_PKT_BUF_ADDR) <<
|
|
RCR_ENTRY_PKT_BUF_ADDR_SHIFT;
|
|
@@ -3452,7 +3452,6 @@ static int niu_process_rx_pkt(struct napi_struct *napi, struct niu *np,
|
|
RCR_ENTRY_PKTBUFSZ_SHIFT];
|
|
|
|
off = addr & ~PAGE_MASK;
|
|
- append_size = rcr_size;
|
|
if (num_rcr == 1) {
|
|
int ptype;
|
|
|
|
@@ -3465,7 +3464,7 @@ static int niu_process_rx_pkt(struct napi_struct *napi, struct niu *np,
|
|
else
|
|
skb_checksum_none_assert(skb);
|
|
} else if (!(val & RCR_ENTRY_MULTI))
|
|
- append_size = len - skb->len;
|
|
+ append_size = append_size - skb->len;
|
|
|
|
niu_rx_skb_append(skb, page, off, append_size, rcr_size);
|
|
if ((page->index + rp->rbr_block_size) - rcr_size == addr) {
|
|
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
|
|
index de336897a28a..d7cb205fe7e2 100644
|
|
--- a/drivers/net/ethernet/ti/cpsw.c
|
|
+++ b/drivers/net/ethernet/ti/cpsw.c
|
|
@@ -1141,6 +1141,8 @@ static inline void cpsw_add_dual_emac_def_ale_entries(
|
|
cpsw_ale_add_ucast(cpsw->ale, priv->mac_addr,
|
|
HOST_PORT_NUM, ALE_VLAN |
|
|
ALE_SECURE, slave->port_vlan);
|
|
+ cpsw_ale_control_set(cpsw->ale, slave_port,
|
|
+ ALE_PORT_DROP_UNKNOWN_VLAN, 1);
|
|
}
|
|
|
|
static void soft_reset_slave(struct cpsw_slave *slave)
|
|
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
|
|
index 1029bd234c22..3e893fe890a0 100644
|
|
--- a/drivers/net/usb/qmi_wwan.c
|
|
+++ b/drivers/net/usb/qmi_wwan.c
|
|
@@ -1039,6 +1039,18 @@ static int qmi_wwan_probe(struct usb_interface *intf,
|
|
id->driver_info = (unsigned long)&qmi_wwan_info;
|
|
}
|
|
|
|
+ /* There are devices where the same interface number can be
|
|
+ * configured as different functions. We should only bind to
|
|
+ * vendor specific functions when matching on interface number
|
|
+ */
|
|
+ if (id->match_flags & USB_DEVICE_ID_MATCH_INT_NUMBER &&
|
|
+ desc->bInterfaceClass != USB_CLASS_VENDOR_SPEC) {
|
|
+ dev_dbg(&intf->dev,
|
|
+ "Rejecting interface number match for class %02x\n",
|
|
+ desc->bInterfaceClass);
|
|
+ return -ENODEV;
|
|
+ }
|
|
+
|
|
/* Quectel EC20 quirk where we've QMI on interface 4 instead of 0 */
|
|
if (quectel_ec20_detected(intf) && desc->bInterfaceNumber == 0) {
|
|
dev_dbg(&intf->dev, "Quectel EC20 quirk, skipping interface 0\n");
|
|
diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c
|
|
index cdd2f942317c..b9c7a904c1ea 100644
|
|
--- a/drivers/tty/serial/sccnxp.c
|
|
+++ b/drivers/tty/serial/sccnxp.c
|
|
@@ -889,7 +889,16 @@ static int sccnxp_probe(struct platform_device *pdev)
|
|
goto err_out;
|
|
uartclk = 0;
|
|
} else {
|
|
- clk_prepare_enable(clk);
|
|
+ ret = clk_prepare_enable(clk);
|
|
+ if (ret)
|
|
+ goto err_out;
|
|
+
|
|
+ ret = devm_add_action_or_reset(&pdev->dev,
|
|
+ (void(*)(void *))clk_disable_unprepare,
|
|
+ clk);
|
|
+ if (ret)
|
|
+ goto err_out;
|
|
+
|
|
uartclk = clk_get_rate(clk);
|
|
}
|
|
|
|
@@ -988,7 +997,7 @@ static int sccnxp_probe(struct platform_device *pdev)
|
|
uart_unregister_driver(&s->uart);
|
|
err_out:
|
|
if (!IS_ERR(s->regulator))
|
|
- return regulator_disable(s->regulator);
|
|
+ regulator_disable(s->regulator);
|
|
|
|
return ret;
|
|
}
|
|
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
|
|
index 85135df0eb34..c19123dcd1a4 100644
|
|
--- a/fs/lockd/svc.c
|
|
+++ b/fs/lockd/svc.c
|
|
@@ -274,6 +274,8 @@ static void lockd_down_net(struct svc_serv *serv, struct net *net)
|
|
if (ln->nlmsvc_users) {
|
|
if (--ln->nlmsvc_users == 0) {
|
|
nlm_shutdown_hosts_net(net);
|
|
+ cancel_delayed_work_sync(&ln->grace_period_end);
|
|
+ locks_end_grace(&ln->lockd_manager);
|
|
svc_shutdown_net(serv, net);
|
|
dprintk("lockd_down_net: per-net data destroyed; net=%p\n", net);
|
|
}
|
|
diff --git a/fs/proc/base.c b/fs/proc/base.c
|
|
index e67fec3c9856..3fec83ba75fa 100644
|
|
--- a/fs/proc/base.c
|
|
+++ b/fs/proc/base.c
|
|
@@ -252,7 +252,7 @@ static ssize_t proc_pid_cmdline_read(struct file *file, char __user *buf,
|
|
* Inherently racy -- command line shares address space
|
|
* with code and data.
|
|
*/
|
|
- rv = access_remote_vm(mm, arg_end - 1, &c, 1, 0);
|
|
+ rv = access_remote_vm(mm, arg_end - 1, &c, 1, FOLL_ANON);
|
|
if (rv <= 0)
|
|
goto out_free_page;
|
|
|
|
@@ -270,7 +270,7 @@ static ssize_t proc_pid_cmdline_read(struct file *file, char __user *buf,
|
|
int nr_read;
|
|
|
|
_count = min3(count, len, PAGE_SIZE);
|
|
- nr_read = access_remote_vm(mm, p, page, _count, 0);
|
|
+ nr_read = access_remote_vm(mm, p, page, _count, FOLL_ANON);
|
|
if (nr_read < 0)
|
|
rv = nr_read;
|
|
if (nr_read <= 0)
|
|
@@ -305,7 +305,7 @@ static ssize_t proc_pid_cmdline_read(struct file *file, char __user *buf,
|
|
bool final;
|
|
|
|
_count = min3(count, len, PAGE_SIZE);
|
|
- nr_read = access_remote_vm(mm, p, page, _count, 0);
|
|
+ nr_read = access_remote_vm(mm, p, page, _count, FOLL_ANON);
|
|
if (nr_read < 0)
|
|
rv = nr_read;
|
|
if (nr_read <= 0)
|
|
@@ -354,7 +354,7 @@ static ssize_t proc_pid_cmdline_read(struct file *file, char __user *buf,
|
|
bool final;
|
|
|
|
_count = min3(count, len, PAGE_SIZE);
|
|
- nr_read = access_remote_vm(mm, p, page, _count, 0);
|
|
+ nr_read = access_remote_vm(mm, p, page, _count, FOLL_ANON);
|
|
if (nr_read < 0)
|
|
rv = nr_read;
|
|
if (nr_read <= 0)
|
|
@@ -970,7 +970,7 @@ static ssize_t environ_read(struct file *file, char __user *buf,
|
|
max_len = min_t(size_t, PAGE_SIZE, count);
|
|
this_len = min(max_len, this_len);
|
|
|
|
- retval = access_remote_vm(mm, (env_start + src), page, this_len, 0);
|
|
+ retval = access_remote_vm(mm, (env_start + src), page, this_len, FOLL_ANON);
|
|
|
|
if (retval <= 0) {
|
|
ret = retval;
|
|
diff --git a/include/asm-generic/futex.h b/include/asm-generic/futex.h
|
|
index bf2d34c9d804..f0d8b1c51343 100644
|
|
--- a/include/asm-generic/futex.h
|
|
+++ b/include/asm-generic/futex.h
|
|
@@ -13,7 +13,7 @@
|
|
*/
|
|
|
|
/**
|
|
- * futex_atomic_op_inuser() - Atomic arithmetic operation with constant
|
|
+ * arch_futex_atomic_op_inuser() - Atomic arithmetic operation with constant
|
|
* argument and comparison of the previous
|
|
* futex value with another constant.
|
|
*
|
|
@@ -25,18 +25,11 @@
|
|
* <0 - On error
|
|
*/
|
|
static inline int
|
|
-futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
|
|
+arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr)
|
|
{
|
|
- int op = (encoded_op >> 28) & 7;
|
|
- int cmp = (encoded_op >> 24) & 15;
|
|
- int oparg = (encoded_op << 8) >> 20;
|
|
- int cmparg = (encoded_op << 20) >> 20;
|
|
int oldval, ret;
|
|
u32 tmp;
|
|
|
|
- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
|
|
- oparg = 1 << oparg;
|
|
-
|
|
preempt_disable();
|
|
pagefault_disable();
|
|
|
|
@@ -74,17 +67,9 @@ futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
|
|
pagefault_enable();
|
|
preempt_enable();
|
|
|
|
- if (ret == 0) {
|
|
- switch (cmp) {
|
|
- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
|
|
- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
|
|
- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
|
|
- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
|
|
- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
|
|
- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
|
|
- default: ret = -ENOSYS;
|
|
- }
|
|
- }
|
|
+ if (ret == 0)
|
|
+ *oval = oldval;
|
|
+
|
|
return ret;
|
|
}
|
|
|
|
@@ -126,18 +111,9 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
|
|
|
|
#else
|
|
static inline int
|
|
-futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
|
|
+arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr)
|
|
{
|
|
- int op = (encoded_op >> 28) & 7;
|
|
- int cmp = (encoded_op >> 24) & 15;
|
|
- int oparg = (encoded_op << 8) >> 20;
|
|
- int cmparg = (encoded_op << 20) >> 20;
|
|
int oldval = 0, ret;
|
|
- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
|
|
- oparg = 1 << oparg;
|
|
-
|
|
- if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
|
|
- return -EFAULT;
|
|
|
|
pagefault_disable();
|
|
|
|
@@ -153,17 +129,9 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
|
|
|
|
pagefault_enable();
|
|
|
|
- if (!ret) {
|
|
- switch (cmp) {
|
|
- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
|
|
- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
|
|
- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
|
|
- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
|
|
- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
|
|
- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
|
|
- default: ret = -ENOSYS;
|
|
- }
|
|
- }
|
|
+ if (!ret)
|
|
+ *oval = oldval;
|
|
+
|
|
return ret;
|
|
}
|
|
|
|
diff --git a/include/linux/mm.h b/include/linux/mm.h
|
|
index 4a07ff4f38e1..493d07931ea5 100644
|
|
--- a/include/linux/mm.h
|
|
+++ b/include/linux/mm.h
|
|
@@ -2246,6 +2246,7 @@ static inline struct page *follow_page(struct vm_area_struct *vma,
|
|
#define FOLL_MLOCK 0x1000 /* lock present pages */
|
|
#define FOLL_REMOTE 0x2000 /* we are working on non-current tsk/mm */
|
|
#define FOLL_COW 0x4000 /* internal GUP flag */
|
|
+#define FOLL_ANON 0x8000 /* don't do file mappings */
|
|
|
|
typedef int (*pte_fn_t)(pte_t *pte, pgtable_t token, unsigned long addr,
|
|
void *data);
|
|
diff --git a/include/net/bonding.h b/include/net/bonding.h
|
|
index f32f7ef8a23a..7734cc9c7d29 100644
|
|
--- a/include/net/bonding.h
|
|
+++ b/include/net/bonding.h
|
|
@@ -197,6 +197,7 @@ struct bonding {
|
|
struct slave __rcu *primary_slave;
|
|
struct bond_up_slave __rcu *slave_arr; /* Array of usable slaves */
|
|
bool force_primary;
|
|
+ u32 nest_level;
|
|
s32 slave_cnt; /* never change this value outside the attach/detach wrappers */
|
|
int (*recv_probe)(const struct sk_buff *, struct bonding *,
|
|
struct slave *);
|
|
diff --git a/kernel/exit.c b/kernel/exit.c
|
|
index 3076f3089919..6dd7ff4b337a 100644
|
|
--- a/kernel/exit.c
|
|
+++ b/kernel/exit.c
|
|
@@ -1662,6 +1662,10 @@ SYSCALL_DEFINE4(wait4, pid_t, upid, int __user *, stat_addr,
|
|
__WNOTHREAD|__WCLONE|__WALL))
|
|
return -EINVAL;
|
|
|
|
+ /* -INT_MIN is not defined */
|
|
+ if (upid == INT_MIN)
|
|
+ return -ESRCH;
|
|
+
|
|
if (upid == -1)
|
|
type = PIDTYPE_MAX;
|
|
else if (upid < 0) {
|
|
diff --git a/kernel/futex.c b/kernel/futex.c
|
|
index bb2265ae5cbc..c3ea6f2a6997 100644
|
|
--- a/kernel/futex.c
|
|
+++ b/kernel/futex.c
|
|
@@ -1458,6 +1458,45 @@ futex_wake(u32 __user *uaddr, unsigned int flags, int nr_wake, u32 bitset)
|
|
return ret;
|
|
}
|
|
|
|
+static int futex_atomic_op_inuser(unsigned int encoded_op, u32 __user *uaddr)
|
|
+{
|
|
+ unsigned int op = (encoded_op & 0x70000000) >> 28;
|
|
+ unsigned int cmp = (encoded_op & 0x0f000000) >> 24;
|
|
+ int oparg = sign_extend32((encoded_op & 0x00fff000) >> 12, 11);
|
|
+ int cmparg = sign_extend32(encoded_op & 0x00000fff, 11);
|
|
+ int oldval, ret;
|
|
+
|
|
+ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) {
|
|
+ if (oparg < 0 || oparg > 31)
|
|
+ return -EINVAL;
|
|
+ oparg = 1 << oparg;
|
|
+ }
|
|
+
|
|
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
|
|
+ return -EFAULT;
|
|
+
|
|
+ ret = arch_futex_atomic_op_inuser(op, oparg, &oldval, uaddr);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ switch (cmp) {
|
|
+ case FUTEX_OP_CMP_EQ:
|
|
+ return oldval == cmparg;
|
|
+ case FUTEX_OP_CMP_NE:
|
|
+ return oldval != cmparg;
|
|
+ case FUTEX_OP_CMP_LT:
|
|
+ return oldval < cmparg;
|
|
+ case FUTEX_OP_CMP_GE:
|
|
+ return oldval >= cmparg;
|
|
+ case FUTEX_OP_CMP_LE:
|
|
+ return oldval <= cmparg;
|
|
+ case FUTEX_OP_CMP_GT:
|
|
+ return oldval > cmparg;
|
|
+ default:
|
|
+ return -ENOSYS;
|
|
+ }
|
|
+}
|
|
+
|
|
/*
|
|
* Wake up all waiters hashed on the physical page that is mapped
|
|
* to this virtual address:
|
|
diff --git a/mm/gup.c b/mm/gup.c
|
|
index 6c3b4e822946..be4ccddac26f 100644
|
|
--- a/mm/gup.c
|
|
+++ b/mm/gup.c
|
|
@@ -430,6 +430,9 @@ static int check_vma_flags(struct vm_area_struct *vma, unsigned long gup_flags)
|
|
if (vm_flags & (VM_IO | VM_PFNMAP))
|
|
return -EFAULT;
|
|
|
|
+ if (gup_flags & FOLL_ANON && !vma_is_anonymous(vma))
|
|
+ return -EFAULT;
|
|
+
|
|
if (write) {
|
|
if (!(vm_flags & VM_WRITE)) {
|
|
if (!(gup_flags & FOLL_FORCE))
|
|
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
|
|
index ed0dd3340084..8e173324693d 100644
|
|
--- a/net/bridge/br_if.c
|
|
+++ b/net/bridge/br_if.c
|
|
@@ -504,8 +504,8 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
|
|
if (dev->netdev_ops->ndo_start_xmit == br_dev_xmit)
|
|
return -ELOOP;
|
|
|
|
- /* Device is already being bridged */
|
|
- if (br_port_exists(dev))
|
|
+ /* Device has master upper dev */
|
|
+ if (netdev_master_upper_dev_get(dev))
|
|
return -EBUSY;
|
|
|
|
/* No bridging devices that dislike that (e.g. wireless) */
|
|
diff --git a/net/compat.c b/net/compat.c
|
|
index a96fd2f3507b..73671e6ec6eb 100644
|
|
--- a/net/compat.c
|
|
+++ b/net/compat.c
|
|
@@ -372,7 +372,8 @@ static int compat_sock_setsockopt(struct socket *sock, int level, int optname,
|
|
optname == SO_ATTACH_REUSEPORT_CBPF)
|
|
return do_set_attach_filter(sock, level, optname,
|
|
optval, optlen);
|
|
- if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)
|
|
+ if (!COMPAT_USE_64BIT_TIME &&
|
|
+ (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO))
|
|
return do_set_sock_timeout(sock, level, optname, optval, optlen);
|
|
|
|
return sock_setsockopt(sock, level, optname, optval, optlen);
|
|
@@ -437,7 +438,8 @@ static int do_get_sock_timeout(struct socket *sock, int level, int optname,
|
|
static int compat_sock_getsockopt(struct socket *sock, int level, int optname,
|
|
char __user *optval, int __user *optlen)
|
|
{
|
|
- if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)
|
|
+ if (!COMPAT_USE_64BIT_TIME &&
|
|
+ (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO))
|
|
return do_get_sock_timeout(sock, level, optname, optval, optlen);
|
|
return sock_getsockopt(sock, level, optname, optval, optlen);
|
|
}
|
|
diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c
|
|
index 7753681195c1..86a2ed0fb219 100644
|
|
--- a/net/dccp/ccids/ccid2.c
|
|
+++ b/net/dccp/ccids/ccid2.c
|
|
@@ -126,6 +126,16 @@ static void ccid2_change_l_seq_window(struct sock *sk, u64 val)
|
|
DCCPF_SEQ_WMAX));
|
|
}
|
|
|
|
+static void dccp_tasklet_schedule(struct sock *sk)
|
|
+{
|
|
+ struct tasklet_struct *t = &dccp_sk(sk)->dccps_xmitlet;
|
|
+
|
|
+ if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {
|
|
+ sock_hold(sk);
|
|
+ __tasklet_schedule(t);
|
|
+ }
|
|
+}
|
|
+
|
|
static void ccid2_hc_tx_rto_expire(unsigned long data)
|
|
{
|
|
struct sock *sk = (struct sock *)data;
|
|
@@ -166,7 +176,7 @@ static void ccid2_hc_tx_rto_expire(unsigned long data)
|
|
|
|
/* if we were blocked before, we may now send cwnd=1 packet */
|
|
if (sender_was_blocked)
|
|
- tasklet_schedule(&dccp_sk(sk)->dccps_xmitlet);
|
|
+ dccp_tasklet_schedule(sk);
|
|
/* restart backed-off timer */
|
|
sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto);
|
|
out:
|
|
@@ -706,7 +716,7 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
|
|
done:
|
|
/* check if incoming Acks allow pending packets to be sent */
|
|
if (sender_was_blocked && !ccid2_cwnd_network_limited(hc))
|
|
- tasklet_schedule(&dccp_sk(sk)->dccps_xmitlet);
|
|
+ dccp_tasklet_schedule(sk);
|
|
dccp_ackvec_parsed_cleanup(&hc->tx_av_chunks);
|
|
}
|
|
|
|
diff --git a/net/dccp/timer.c b/net/dccp/timer.c
|
|
index 3a2c34027758..2a952cbd6efa 100644
|
|
--- a/net/dccp/timer.c
|
|
+++ b/net/dccp/timer.c
|
|
@@ -230,12 +230,12 @@ static void dccp_write_xmitlet(unsigned long data)
|
|
else
|
|
dccp_write_xmit(sk);
|
|
bh_unlock_sock(sk);
|
|
+ sock_put(sk);
|
|
}
|
|
|
|
static void dccp_write_xmit_timer(unsigned long data)
|
|
{
|
|
dccp_write_xmitlet(data);
|
|
- sock_put((struct sock *)data);
|
|
}
|
|
|
|
void dccp_init_xmit_timers(struct sock *sk)
|
|
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
|
|
index e612991c9185..9adcd4b1b3fd 100644
|
|
--- a/net/ipv4/ping.c
|
|
+++ b/net/ipv4/ping.c
|
|
@@ -775,8 +775,10 @@ static int ping_v4_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
|
|
ipc.addr = faddr = daddr;
|
|
|
|
if (ipc.opt && ipc.opt->opt.srr) {
|
|
- if (!daddr)
|
|
- return -EINVAL;
|
|
+ if (!daddr) {
|
|
+ err = -EINVAL;
|
|
+ goto out_free;
|
|
+ }
|
|
faddr = ipc.opt->opt.faddr;
|
|
}
|
|
tos = get_rttos(&ipc, inet);
|
|
@@ -841,6 +843,7 @@ static int ping_v4_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
|
|
|
|
out:
|
|
ip_rt_put(rt);
|
|
+out_free:
|
|
if (free)
|
|
kfree(ipc.opt);
|
|
if (!err) {
|
|
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
|
|
index 6f501c9deaae..84ffebf0192d 100644
|
|
--- a/net/ipv4/tcp.c
|
|
+++ b/net/ipv4/tcp.c
|
|
@@ -1118,7 +1118,7 @@ int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
|
|
lock_sock(sk);
|
|
|
|
flags = msg->msg_flags;
|
|
- if (flags & MSG_FASTOPEN) {
|
|
+ if ((flags & MSG_FASTOPEN) && !tp->repair) {
|
|
err = tcp_sendmsg_fastopen(sk, msg, &copied_syn, size);
|
|
if (err == -EINPROGRESS && copied_syn > 0)
|
|
goto out;
|
|
diff --git a/net/ipv4/tcp_bbr.c b/net/ipv4/tcp_bbr.c
|
|
index 8ec60532be2b..9169859506b7 100644
|
|
--- a/net/ipv4/tcp_bbr.c
|
|
+++ b/net/ipv4/tcp_bbr.c
|
|
@@ -773,7 +773,9 @@ static void bbr_update_min_rtt(struct sock *sk, const struct rate_sample *rs)
|
|
}
|
|
}
|
|
}
|
|
- bbr->idle_restart = 0;
|
|
+ /* Restart after idle ends only once we process a new S/ACK for data */
|
|
+ if (rs->delivered > 0)
|
|
+ bbr->idle_restart = 0;
|
|
}
|
|
|
|
static void bbr_update_model(struct sock *sk, const struct rate_sample *rs)
|
|
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
|
|
index 4cd943096afa..aa2a20e918fd 100644
|
|
--- a/net/ipv4/udp.c
|
|
+++ b/net/ipv4/udp.c
|
|
@@ -982,8 +982,10 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
|
|
sock_tx_timestamp(sk, ipc.sockc.tsflags, &ipc.tx_flags);
|
|
|
|
if (ipc.opt && ipc.opt->opt.srr) {
|
|
- if (!daddr)
|
|
- return -EINVAL;
|
|
+ if (!daddr) {
|
|
+ err = -EINVAL;
|
|
+ goto out_free;
|
|
+ }
|
|
faddr = ipc.opt->opt.faddr;
|
|
connected = 0;
|
|
}
|
|
@@ -1090,6 +1092,7 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
|
|
|
|
out:
|
|
ip_rt_put(rt);
|
|
+out_free:
|
|
if (free)
|
|
kfree(ipc.opt);
|
|
if (!err)
|
|
diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c
|
|
index ce1238492c0f..ee03bc866d1b 100644
|
|
--- a/net/l2tp/l2tp_netlink.c
|
|
+++ b/net/l2tp/l2tp_netlink.c
|
|
@@ -750,8 +750,6 @@ static int l2tp_nl_session_send(struct sk_buff *skb, u32 portid, u32 seq, int fl
|
|
|
|
if ((session->ifname[0] &&
|
|
nla_put_string(skb, L2TP_ATTR_IFNAME, session->ifname)) ||
|
|
- (session->offset &&
|
|
- nla_put_u16(skb, L2TP_ATTR_OFFSET, session->offset)) ||
|
|
(session->cookie_len &&
|
|
nla_put(skb, L2TP_ATTR_COOKIE, session->cookie_len,
|
|
&session->cookie[0])) ||
|
|
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
|
|
index d6bc5f2a1175..85aae8c84aeb 100644
|
|
--- a/net/llc/af_llc.c
|
|
+++ b/net/llc/af_llc.c
|
|
@@ -926,6 +926,9 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
|
|
if (size > llc->dev->mtu)
|
|
size = llc->dev->mtu;
|
|
copied = size - hdrlen;
|
|
+ rc = -EINVAL;
|
|
+ if (copied < 0)
|
|
+ goto release;
|
|
release_sock(sk);
|
|
skb = sock_alloc_send_skb(sk, size, noblock, &rc);
|
|
lock_sock(sk);
|
|
diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c
|
|
index 1668916bdbde..326945d9be5f 100644
|
|
--- a/net/openvswitch/flow_netlink.c
|
|
+++ b/net/openvswitch/flow_netlink.c
|
|
@@ -1296,13 +1296,10 @@ static void nlattr_set(struct nlattr *attr, u8 val,
|
|
|
|
/* The nlattr stream should already have been validated */
|
|
nla_for_each_nested(nla, attr, rem) {
|
|
- if (tbl[nla_type(nla)].len == OVS_ATTR_NESTED) {
|
|
- if (tbl[nla_type(nla)].next)
|
|
- tbl = tbl[nla_type(nla)].next;
|
|
- nlattr_set(nla, val, tbl);
|
|
- } else {
|
|
+ if (tbl[nla_type(nla)].len == OVS_ATTR_NESTED)
|
|
+ nlattr_set(nla, val, tbl[nla_type(nla)].next ? : tbl);
|
|
+ else
|
|
memset(nla_data(nla), val, nla_len(nla));
|
|
- }
|
|
|
|
if (nla_type(nla) == OVS_KEY_ATTR_CT_STATE)
|
|
*(u32 *)nla_data(nla) &= CT_SUPPORTED_MASK;
|
|
diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c
|
|
index 18e752439f6f..b57b4de73038 100644
|
|
--- a/net/sched/sch_fq.c
|
|
+++ b/net/sched/sch_fq.c
|
|
@@ -128,6 +128,28 @@ static bool fq_flow_is_detached(const struct fq_flow *f)
|
|
return f->next == &detached;
|
|
}
|
|
|
|
+static bool fq_flow_is_throttled(const struct fq_flow *f)
|
|
+{
|
|
+ return f->next == &throttled;
|
|
+}
|
|
+
|
|
+static void fq_flow_add_tail(struct fq_flow_head *head, struct fq_flow *flow)
|
|
+{
|
|
+ if (head->first)
|
|
+ head->last->next = flow;
|
|
+ else
|
|
+ head->first = flow;
|
|
+ head->last = flow;
|
|
+ flow->next = NULL;
|
|
+}
|
|
+
|
|
+static void fq_flow_unset_throttled(struct fq_sched_data *q, struct fq_flow *f)
|
|
+{
|
|
+ rb_erase(&f->rate_node, &q->delayed);
|
|
+ q->throttled_flows--;
|
|
+ fq_flow_add_tail(&q->old_flows, f);
|
|
+}
|
|
+
|
|
static void fq_flow_set_throttled(struct fq_sched_data *q, struct fq_flow *f)
|
|
{
|
|
struct rb_node **p = &q->delayed.rb_node, *parent = NULL;
|
|
@@ -155,15 +177,6 @@ static void fq_flow_set_throttled(struct fq_sched_data *q, struct fq_flow *f)
|
|
|
|
static struct kmem_cache *fq_flow_cachep __read_mostly;
|
|
|
|
-static void fq_flow_add_tail(struct fq_flow_head *head, struct fq_flow *flow)
|
|
-{
|
|
- if (head->first)
|
|
- head->last->next = flow;
|
|
- else
|
|
- head->first = flow;
|
|
- head->last = flow;
|
|
- flow->next = NULL;
|
|
-}
|
|
|
|
/* limit number of collected flows per round */
|
|
#define FQ_GC_MAX 8
|
|
@@ -267,6 +280,8 @@ static struct fq_flow *fq_classify(struct sk_buff *skb, struct fq_sched_data *q)
|
|
f->socket_hash != sk->sk_hash)) {
|
|
f->credit = q->initial_quantum;
|
|
f->socket_hash = sk->sk_hash;
|
|
+ if (fq_flow_is_throttled(f))
|
|
+ fq_flow_unset_throttled(q, f);
|
|
f->time_next_packet = 0ULL;
|
|
}
|
|
return f;
|
|
@@ -430,9 +445,7 @@ static void fq_check_throttled(struct fq_sched_data *q, u64 now)
|
|
q->time_next_delayed_flow = f->time_next_packet;
|
|
break;
|
|
}
|
|
- rb_erase(p, &q->delayed);
|
|
- q->throttled_flows--;
|
|
- fq_flow_add_tail(&q->old_flows, f);
|
|
+ fq_flow_unset_throttled(q, f);
|
|
}
|
|
}
|
|
|
|
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
|
|
index f10d3397f917..738c55e994c4 100644
|
|
--- a/net/sctp/associola.c
|
|
+++ b/net/sctp/associola.c
|
|
@@ -1006,9 +1006,10 @@ static void sctp_assoc_bh_rcv(struct work_struct *work)
|
|
struct sctp_endpoint *ep;
|
|
struct sctp_chunk *chunk;
|
|
struct sctp_inq *inqueue;
|
|
- int state;
|
|
sctp_subtype_t subtype;
|
|
+ int first_time = 1; /* is this the first time through the loop */
|
|
int error = 0;
|
|
+ int state;
|
|
|
|
/* The association should be held so we should be safe. */
|
|
ep = asoc->ep;
|
|
@@ -1019,6 +1020,30 @@ static void sctp_assoc_bh_rcv(struct work_struct *work)
|
|
state = asoc->state;
|
|
subtype = SCTP_ST_CHUNK(chunk->chunk_hdr->type);
|
|
|
|
+ /* If the first chunk in the packet is AUTH, do special
|
|
+ * processing specified in Section 6.3 of SCTP-AUTH spec
|
|
+ */
|
|
+ if (first_time && subtype.chunk == SCTP_CID_AUTH) {
|
|
+ struct sctp_chunkhdr *next_hdr;
|
|
+
|
|
+ next_hdr = sctp_inq_peek(inqueue);
|
|
+ if (!next_hdr)
|
|
+ goto normal;
|
|
+
|
|
+ /* If the next chunk is COOKIE-ECHO, skip the AUTH
|
|
+ * chunk while saving a pointer to it so we can do
|
|
+ * Authentication later (during cookie-echo
|
|
+ * processing).
|
|
+ */
|
|
+ if (next_hdr->type == SCTP_CID_COOKIE_ECHO) {
|
|
+ chunk->auth_chunk = skb_clone(chunk->skb,
|
|
+ GFP_ATOMIC);
|
|
+ chunk->auth = 1;
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
+
|
|
+normal:
|
|
/* SCTP-AUTH, Section 6.3:
|
|
* The receiver has a list of chunk types which it expects
|
|
* to be received only after an AUTH-chunk. This list has
|
|
@@ -1057,6 +1082,9 @@ static void sctp_assoc_bh_rcv(struct work_struct *work)
|
|
/* If there is an error on chunk, discard this packet. */
|
|
if (error && chunk)
|
|
chunk->pdiscard = 1;
|
|
+
|
|
+ if (first_time)
|
|
+ first_time = 0;
|
|
}
|
|
sctp_association_put(asoc);
|
|
}
|
|
diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c
|
|
index f731de3e8428..e06083c53f57 100644
|
|
--- a/net/sctp/inqueue.c
|
|
+++ b/net/sctp/inqueue.c
|
|
@@ -217,7 +217,7 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue)
|
|
skb_pull(chunk->skb, sizeof(sctp_chunkhdr_t));
|
|
chunk->subh.v = NULL; /* Subheader is no longer valid. */
|
|
|
|
- if (chunk->chunk_end + sizeof(sctp_chunkhdr_t) <
|
|
+ if (chunk->chunk_end + sizeof(sctp_chunkhdr_t) <=
|
|
skb_tail_pointer(chunk->skb)) {
|
|
/* This is not a singleton */
|
|
chunk->singleton = 0;
|
|
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
|
|
index e031797ad311..f4d5efb1d231 100644
|
|
--- a/net/sctp/ipv6.c
|
|
+++ b/net/sctp/ipv6.c
|
|
@@ -864,6 +864,9 @@ static int sctp_inet6_cmp_addr(const union sctp_addr *addr1,
|
|
if (sctp_is_any(sk, addr1) || sctp_is_any(sk, addr2))
|
|
return 1;
|
|
|
|
+ if (addr1->sa.sa_family == AF_INET && addr2->sa.sa_family == AF_INET)
|
|
+ return addr1->v4.sin_addr.s_addr == addr2->v4.sin_addr.s_addr;
|
|
+
|
|
return __sctp_v6_cmp_addr(addr1, addr2);
|
|
}
|
|
|
|
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
|
|
index 8ec20a64a3f8..bfd068679710 100644
|
|
--- a/net/sctp/sm_statefuns.c
|
|
+++ b/net/sctp/sm_statefuns.c
|
|
@@ -144,10 +144,8 @@ static sctp_disposition_t sctp_sf_violation_chunk(
|
|
void *arg,
|
|
sctp_cmd_seq_t *commands);
|
|
|
|
-static sctp_ierror_t sctp_sf_authenticate(struct net *net,
|
|
- const struct sctp_endpoint *ep,
|
|
+static sctp_ierror_t sctp_sf_authenticate(
|
|
const struct sctp_association *asoc,
|
|
- const sctp_subtype_t type,
|
|
struct sctp_chunk *chunk);
|
|
|
|
static sctp_disposition_t __sctp_sf_do_9_1_abort(struct net *net,
|
|
@@ -615,6 +613,38 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(struct net *net,
|
|
return SCTP_DISPOSITION_CONSUME;
|
|
}
|
|
|
|
+static bool sctp_auth_chunk_verify(struct net *net, struct sctp_chunk *chunk,
|
|
+ const struct sctp_association *asoc)
|
|
+{
|
|
+ struct sctp_chunk auth;
|
|
+
|
|
+ if (!chunk->auth_chunk)
|
|
+ return true;
|
|
+
|
|
+ /* SCTP-AUTH: auth_chunk pointer is only set when the cookie-echo
|
|
+ * is supposed to be authenticated and we have to do delayed
|
|
+ * authentication. We've just recreated the association using
|
|
+ * the information in the cookie and now it's much easier to
|
|
+ * do the authentication.
|
|
+ */
|
|
+
|
|
+ /* Make sure that we and the peer are AUTH capable */
|
|
+ if (!net->sctp.auth_enable || !asoc->peer.auth_capable)
|
|
+ return false;
|
|
+
|
|
+ /* set-up our fake chunk so that we can process it */
|
|
+ auth.skb = chunk->auth_chunk;
|
|
+ auth.asoc = chunk->asoc;
|
|
+ auth.sctp_hdr = chunk->sctp_hdr;
|
|
+ auth.chunk_hdr = (struct sctp_chunkhdr *)
|
|
+ skb_push(chunk->auth_chunk,
|
|
+ sizeof(struct sctp_chunkhdr));
|
|
+ skb_pull(chunk->auth_chunk, sizeof(struct sctp_chunkhdr));
|
|
+ auth.transport = chunk->transport;
|
|
+
|
|
+ return sctp_sf_authenticate(asoc, &auth) == SCTP_IERROR_NO_ERROR;
|
|
+}
|
|
+
|
|
/*
|
|
* Respond to a normal COOKIE ECHO chunk.
|
|
* We are the side that is being asked for an association.
|
|
@@ -751,36 +781,9 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(struct net *net,
|
|
if (error)
|
|
goto nomem_init;
|
|
|
|
- /* SCTP-AUTH: auth_chunk pointer is only set when the cookie-echo
|
|
- * is supposed to be authenticated and we have to do delayed
|
|
- * authentication. We've just recreated the association using
|
|
- * the information in the cookie and now it's much easier to
|
|
- * do the authentication.
|
|
- */
|
|
- if (chunk->auth_chunk) {
|
|
- struct sctp_chunk auth;
|
|
- sctp_ierror_t ret;
|
|
-
|
|
- /* Make sure that we and the peer are AUTH capable */
|
|
- if (!net->sctp.auth_enable || !new_asoc->peer.auth_capable) {
|
|
- sctp_association_free(new_asoc);
|
|
- return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
|
|
- }
|
|
-
|
|
- /* set-up our fake chunk so that we can process it */
|
|
- auth.skb = chunk->auth_chunk;
|
|
- auth.asoc = chunk->asoc;
|
|
- auth.sctp_hdr = chunk->sctp_hdr;
|
|
- auth.chunk_hdr = (sctp_chunkhdr_t *)skb_push(chunk->auth_chunk,
|
|
- sizeof(sctp_chunkhdr_t));
|
|
- skb_pull(chunk->auth_chunk, sizeof(sctp_chunkhdr_t));
|
|
- auth.transport = chunk->transport;
|
|
-
|
|
- ret = sctp_sf_authenticate(net, ep, new_asoc, type, &auth);
|
|
- if (ret != SCTP_IERROR_NO_ERROR) {
|
|
- sctp_association_free(new_asoc);
|
|
- return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
|
|
- }
|
|
+ if (!sctp_auth_chunk_verify(net, chunk, new_asoc)) {
|
|
+ sctp_association_free(new_asoc);
|
|
+ return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
|
|
}
|
|
|
|
repl = sctp_make_cookie_ack(new_asoc, chunk);
|
|
@@ -1717,13 +1720,15 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(struct net *net,
|
|
GFP_ATOMIC))
|
|
goto nomem;
|
|
|
|
+ if (!sctp_auth_chunk_verify(net, chunk, new_asoc))
|
|
+ return SCTP_DISPOSITION_DISCARD;
|
|
+
|
|
/* Make sure no new addresses are being added during the
|
|
* restart. Though this is a pretty complicated attack
|
|
* since you'd have to get inside the cookie.
|
|
*/
|
|
- if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk, commands)) {
|
|
+ if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk, commands))
|
|
return SCTP_DISPOSITION_CONSUME;
|
|
- }
|
|
|
|
/* If the endpoint is in the SHUTDOWN-ACK-SENT state and recognizes
|
|
* the peer has restarted (Action A), it MUST NOT setup a new
|
|
@@ -1828,6 +1833,9 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(struct net *net,
|
|
GFP_ATOMIC))
|
|
goto nomem;
|
|
|
|
+ if (!sctp_auth_chunk_verify(net, chunk, new_asoc))
|
|
+ return SCTP_DISPOSITION_DISCARD;
|
|
+
|
|
/* Update the content of current association. */
|
|
sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc));
|
|
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
|
|
@@ -1920,6 +1928,9 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(struct net *net,
|
|
* a COOKIE ACK.
|
|
*/
|
|
|
|
+ if (!sctp_auth_chunk_verify(net, chunk, asoc))
|
|
+ return SCTP_DISPOSITION_DISCARD;
|
|
+
|
|
/* Don't accidentally move back into established state. */
|
|
if (asoc->state < SCTP_STATE_ESTABLISHED) {
|
|
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
|
|
@@ -1959,7 +1970,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(struct net *net,
|
|
}
|
|
}
|
|
|
|
- repl = sctp_make_cookie_ack(new_asoc, chunk);
|
|
+ repl = sctp_make_cookie_ack(asoc, chunk);
|
|
if (!repl)
|
|
goto nomem;
|
|
|
|
@@ -3981,10 +3992,8 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn_fast(
|
|
*
|
|
* The return value is the disposition of the chunk.
|
|
*/
|
|
-static sctp_ierror_t sctp_sf_authenticate(struct net *net,
|
|
- const struct sctp_endpoint *ep,
|
|
+static sctp_ierror_t sctp_sf_authenticate(
|
|
const struct sctp_association *asoc,
|
|
- const sctp_subtype_t type,
|
|
struct sctp_chunk *chunk)
|
|
{
|
|
struct sctp_authhdr *auth_hdr;
|
|
@@ -4083,7 +4092,7 @@ sctp_disposition_t sctp_sf_eat_auth(struct net *net,
|
|
commands);
|
|
|
|
auth_hdr = (struct sctp_authhdr *)chunk->skb->data;
|
|
- error = sctp_sf_authenticate(net, ep, asoc, type, chunk);
|
|
+ error = sctp_sf_authenticate(asoc, chunk);
|
|
switch (error) {
|
|
case SCTP_IERROR_AUTH_BAD_HMAC:
|
|
/* Generate the ERROR chunk and discard the rest
|
|
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
|
|
index bea00058ce35..6825e05a68b2 100644
|
|
--- a/net/sctp/ulpevent.c
|
|
+++ b/net/sctp/ulpevent.c
|
|
@@ -723,7 +723,6 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
|
|
return event;
|
|
|
|
fail_mark:
|
|
- sctp_chunk_put(chunk);
|
|
kfree_skb(skb);
|
|
fail:
|
|
return NULL;
|
|
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
|
|
index 6f5635770d6a..71a94e549301 100644
|
|
--- a/net/xfrm/xfrm_state.c
|
|
+++ b/net/xfrm/xfrm_state.c
|
|
@@ -1197,6 +1197,7 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig)
|
|
|
|
if (orig->aead) {
|
|
x->aead = xfrm_algo_aead_clone(orig->aead);
|
|
+ x->geniv = orig->geniv;
|
|
if (!x->aead)
|
|
goto error;
|
|
}
|