Merge "Merge android-4.9.160 (fd5657a) into msm-4.9"
diff --git a/Documentation/devicetree/bindings/eeprom/eeprom.txt b/Documentation/devicetree/bindings/eeprom/eeprom.txt
index 735bc94..4dcce8e 100644
--- a/Documentation/devicetree/bindings/eeprom/eeprom.txt
+++ b/Documentation/devicetree/bindings/eeprom/eeprom.txt
@@ -6,7 +6,8 @@
"atmel,24c00", "atmel,24c01", "atmel,24c02", "atmel,24c04",
"atmel,24c08", "atmel,24c16", "atmel,24c32", "atmel,24c64",
- "atmel,24c128", "atmel,24c256", "atmel,24c512", "atmel,24c1024"
+ "atmel,24c128", "atmel,24c256", "atmel,24c512", "atmel,24c1024",
+ "atmel,24c2048"
"catalyst,24c32"
@@ -17,7 +18,7 @@
If there is no specific driver for <manufacturer>, a generic
driver based on <type> is selected. Possible types are:
"24c00", "24c01", "24c02", "24c04", "24c08", "24c16", "24c32", "24c64",
- "24c128", "24c256", "24c512", "24c1024", "spd"
+ "24c128", "24c256", "24c512", "24c1024", "24c2048", "spd"
- reg : the I2C address of the EEPROM
diff --git a/Makefile b/Makefile
index 5d26ede..a9858ca 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
VERSION = 4
PATCHLEVEL = 9
-SUBLEVEL = 155
+SUBLEVEL = 160
EXTRAVERSION =
NAME = Roaring Lionus
diff --git a/arch/alpha/include/asm/irq.h b/arch/alpha/include/asm/irq.h
index 0637740..4696428 100644
--- a/arch/alpha/include/asm/irq.h
+++ b/arch/alpha/include/asm/irq.h
@@ -55,15 +55,15 @@
#elif defined(CONFIG_ALPHA_DP264) || \
defined(CONFIG_ALPHA_LYNX) || \
- defined(CONFIG_ALPHA_SHARK) || \
- defined(CONFIG_ALPHA_EIGER)
+ defined(CONFIG_ALPHA_SHARK)
# define NR_IRQS 64
#elif defined(CONFIG_ALPHA_TITAN)
#define NR_IRQS 80
#elif defined(CONFIG_ALPHA_RAWHIDE) || \
- defined(CONFIG_ALPHA_TAKARA)
+ defined(CONFIG_ALPHA_TAKARA) || \
+ defined(CONFIG_ALPHA_EIGER)
# define NR_IRQS 128
#elif defined(CONFIG_ALPHA_WILDFIRE)
diff --git a/arch/alpha/mm/fault.c b/arch/alpha/mm/fault.c
index 83e9eee..f706631 100644
--- a/arch/alpha/mm/fault.c
+++ b/arch/alpha/mm/fault.c
@@ -77,7 +77,7 @@
/* Macro for exception fixup code to access integer registers. */
#define dpf_reg(r) \
(((unsigned long *)regs)[(r) <= 8 ? (r) : (r) <= 15 ? (r)-16 : \
- (r) <= 18 ? (r)+8 : (r)-10])
+ (r) <= 18 ? (r)+10 : (r)-10])
asmlinkage void
do_page_fault(unsigned long address, unsigned long mmcsr,
diff --git a/arch/arm/boot/dts/da850-evm.dts b/arch/arm/boot/dts/da850-evm.dts
index 78492a0..3c58ec7 100644
--- a/arch/arm/boot/dts/da850-evm.dts
+++ b/arch/arm/boot/dts/da850-evm.dts
@@ -156,7 +156,7 @@
sound {
compatible = "simple-audio-card";
- simple-audio-card,name = "DA850/OMAP-L138 EVM";
+ simple-audio-card,name = "DA850-OMAPL138 EVM";
simple-audio-card,widgets =
"Line", "Line In",
"Line", "Line Out";
diff --git a/arch/arm/boot/dts/da850-lcdk.dts b/arch/arm/boot/dts/da850-lcdk.dts
index 7b8ab21..920e64c 100644
--- a/arch/arm/boot/dts/da850-lcdk.dts
+++ b/arch/arm/boot/dts/da850-lcdk.dts
@@ -26,7 +26,7 @@
sound {
compatible = "simple-audio-card";
- simple-audio-card,name = "DA850/OMAP-L138 LCDK";
+ simple-audio-card,name = "DA850-OMAPL138 LCDK";
simple-audio-card,widgets =
"Line", "Line In",
"Line", "Line Out";
diff --git a/arch/arm/boot/dts/kirkwood-dnskw.dtsi b/arch/arm/boot/dts/kirkwood-dnskw.dtsi
index d8fca9d..dddbc0d 100644
--- a/arch/arm/boot/dts/kirkwood-dnskw.dtsi
+++ b/arch/arm/boot/dts/kirkwood-dnskw.dtsi
@@ -35,8 +35,8 @@
compatible = "gpio-fan";
pinctrl-0 = <&pmx_fan_high_speed &pmx_fan_low_speed>;
pinctrl-names = "default";
- gpios = <&gpio1 14 GPIO_ACTIVE_LOW
- &gpio1 13 GPIO_ACTIVE_LOW>;
+ gpios = <&gpio1 14 GPIO_ACTIVE_HIGH
+ &gpio1 13 GPIO_ACTIVE_HIGH>;
gpio-fan,speed-map = <0 0
3000 1
6000 2>;
diff --git a/arch/arm/boot/dts/mmp2.dtsi b/arch/arm/boot/dts/mmp2.dtsi
index 766bbb8..47e5b63 100644
--- a/arch/arm/boot/dts/mmp2.dtsi
+++ b/arch/arm/boot/dts/mmp2.dtsi
@@ -220,12 +220,15 @@
status = "disabled";
};
- twsi2: i2c@d4025000 {
+ twsi2: i2c@d4031000 {
compatible = "mrvl,mmp-twsi";
- reg = <0xd4025000 0x1000>;
- interrupts = <58>;
+ reg = <0xd4031000 0x1000>;
+ interrupt-parent = <&intcmux17>;
+ interrupts = <0>;
clocks = <&soc_clocks MMP2_CLK_TWSI1>;
resets = <&soc_clocks MMP2_CLK_TWSI1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/omap4-sdp.dts b/arch/arm/boot/dts/omap4-sdp.dts
index d728ec9..891ba75 100644
--- a/arch/arm/boot/dts/omap4-sdp.dts
+++ b/arch/arm/boot/dts/omap4-sdp.dts
@@ -33,6 +33,7 @@
gpio = <&gpio2 16 GPIO_ACTIVE_HIGH>; /* gpio line 48 */
enable-active-high;
regulator-boot-on;
+ startup-delay-us = <25000>;
};
vbat: fixedregulator-vbat {
diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig
old mode 100644
new mode 100755
index ade0f45..5c68a44
--- a/arch/arm/configs/msm8909-perf_defconfig
+++ b/arch/arm/configs/msm8909-perf_defconfig
@@ -140,9 +140,9 @@
CONFIG_NETFILTER_XT_MATCH_MAC=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_OWNER=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
diff --git a/arch/arm/configs/msm8909_defconfig b/arch/arm/configs/msm8909_defconfig
old mode 100644
new mode 100755
index 7fba408..b903f85
--- a/arch/arm/configs/msm8909_defconfig
+++ b/arch/arm/configs/msm8909_defconfig
@@ -140,9 +140,9 @@
CONFIG_NETFILTER_XT_MATCH_MAC=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_OWNER=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
diff --git a/arch/arm/configs/msm8909w-perf_defconfig b/arch/arm/configs/msm8909w-perf_defconfig
old mode 100644
new mode 100755
index c9157c4..557e5c3
--- a/arch/arm/configs/msm8909w-perf_defconfig
+++ b/arch/arm/configs/msm8909w-perf_defconfig
@@ -138,9 +138,9 @@
CONFIG_NETFILTER_XT_MATCH_MAC=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_OWNER=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
diff --git a/arch/arm/configs/msm8909w_defconfig b/arch/arm/configs/msm8909w_defconfig
old mode 100644
new mode 100755
index 7a02588..07a287e
--- a/arch/arm/configs/msm8909w_defconfig
+++ b/arch/arm/configs/msm8909w_defconfig
@@ -141,9 +141,9 @@
CONFIG_NETFILTER_XT_MATCH_MAC=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_OWNER=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
diff --git a/arch/arm/configs/msm8937-perf_defconfig b/arch/arm/configs/msm8937-perf_defconfig
old mode 100644
new mode 100755
index 73e3c87..84bc290
--- a/arch/arm/configs/msm8937-perf_defconfig
+++ b/arch/arm/configs/msm8937-perf_defconfig
@@ -169,9 +169,9 @@
CONFIG_NETFILTER_XT_MATCH_MAC=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_OWNER=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
diff --git a/arch/arm/configs/msm8937_defconfig b/arch/arm/configs/msm8937_defconfig
old mode 100644
new mode 100755
index a74358c..184df09
--- a/arch/arm/configs/msm8937_defconfig
+++ b/arch/arm/configs/msm8937_defconfig
@@ -172,9 +172,9 @@
CONFIG_NETFILTER_XT_MATCH_MAC=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_OWNER=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
diff --git a/arch/arm/configs/msm8937go-perf_defconfig b/arch/arm/configs/msm8937go-perf_defconfig
old mode 100644
new mode 100755
index 3a38886..cbb3cdc
--- a/arch/arm/configs/msm8937go-perf_defconfig
+++ b/arch/arm/configs/msm8937go-perf_defconfig
@@ -169,9 +169,9 @@
CONFIG_NETFILTER_XT_MATCH_MAC=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_OWNER=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
diff --git a/arch/arm/configs/msm8937go_defconfig b/arch/arm/configs/msm8937go_defconfig
old mode 100644
new mode 100755
index 0f7c823..6e2d7db
--- a/arch/arm/configs/msm8937go_defconfig
+++ b/arch/arm/configs/msm8937go_defconfig
@@ -172,9 +172,9 @@
CONFIG_NETFILTER_XT_MATCH_MAC=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_OWNER=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
diff --git a/arch/arm/configs/msm8953-perf_defconfig b/arch/arm/configs/msm8953-perf_defconfig
old mode 100644
new mode 100755
index b7fbe29..ec351e3
--- a/arch/arm/configs/msm8953-perf_defconfig
+++ b/arch/arm/configs/msm8953-perf_defconfig
@@ -164,9 +164,9 @@
CONFIG_NETFILTER_XT_MATCH_MAC=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_OWNER=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
diff --git a/arch/arm/configs/msm8953_defconfig b/arch/arm/configs/msm8953_defconfig
old mode 100644
new mode 100755
index 528cb27..1d27286
--- a/arch/arm/configs/msm8953_defconfig
+++ b/arch/arm/configs/msm8953_defconfig
@@ -168,9 +168,9 @@
CONFIG_NETFILTER_XT_MATCH_MAC=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_OWNER=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
diff --git a/arch/arm/configs/ranchu_defconfig b/arch/arm/configs/ranchu_defconfig
index 49e7bbd..e217631 100644
--- a/arch/arm/configs/ranchu_defconfig
+++ b/arch/arm/configs/ranchu_defconfig
@@ -103,9 +103,9 @@
CONFIG_NETFILTER_XT_MATCH_LIMIT=y
CONFIG_NETFILTER_XT_MATCH_MAC=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_OWNER=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
diff --git a/arch/arm/configs/sdm670-perf_defconfig b/arch/arm/configs/sdm670-perf_defconfig
old mode 100644
new mode 100755
index 71bc390..d597ff0
--- a/arch/arm/configs/sdm670-perf_defconfig
+++ b/arch/arm/configs/sdm670-perf_defconfig
@@ -158,9 +158,9 @@
CONFIG_NETFILTER_XT_MATCH_MAC=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_OWNER=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
diff --git a/arch/arm/configs/sdm670_defconfig b/arch/arm/configs/sdm670_defconfig
old mode 100644
new mode 100755
index a2bbb68..83aaf9b
--- a/arch/arm/configs/sdm670_defconfig
+++ b/arch/arm/configs/sdm670_defconfig
@@ -161,9 +161,9 @@
CONFIG_NETFILTER_XT_MATCH_MAC=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_OWNER=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h
index e616f61..7d72750 100644
--- a/arch/arm/include/asm/assembler.h
+++ b/arch/arm/include/asm/assembler.h
@@ -465,6 +465,17 @@
#endif
.endm
+ .macro uaccess_mask_range_ptr, addr:req, size:req, limit:req, tmp:req
+#ifdef CONFIG_CPU_SPECTRE
+ sub \tmp, \limit, #1
+ subs \tmp, \tmp, \addr @ tmp = limit - 1 - addr
+ addhs \tmp, \tmp, #1 @ if (tmp >= 0) {
+ subhss \tmp, \tmp, \size @ tmp = limit - (addr + size) }
+ movlo \addr, #0 @ if (tmp < 0) addr = NULL
+ csdb
+#endif
+ .endm
+
.macro uaccess_disable, tmp, isb=1
#ifdef CONFIG_CPU_SW_DOMAIN_PAN
/*
diff --git a/arch/arm/include/asm/cputype.h b/arch/arm/include/asm/cputype.h
index ba78e5a..48512ba 100755
--- a/arch/arm/include/asm/cputype.h
+++ b/arch/arm/include/asm/cputype.h
@@ -107,6 +107,7 @@
#define ARM_CPU_PART_SCORPION 0x510002d0
extern unsigned int processor_id;
+struct proc_info_list *lookup_processor(u32 midr);
#ifdef CONFIG_CPU_CP15
#define read_cpuid(reg) \
diff --git a/arch/arm/include/asm/proc-fns.h b/arch/arm/include/asm/proc-fns.h
index f379f5f..1bfcc3b 100644
--- a/arch/arm/include/asm/proc-fns.h
+++ b/arch/arm/include/asm/proc-fns.h
@@ -23,7 +23,7 @@
/*
* Don't change this structure - ASM code relies on it.
*/
-extern struct processor {
+struct processor {
/* MISC
* get data abort address/flags
*/
@@ -79,9 +79,13 @@
unsigned int suspend_size;
void (*do_suspend)(void *);
void (*do_resume)(void *);
-} processor;
+};
#ifndef MULTI_CPU
+static inline void init_proc_vtable(const struct processor *p)
+{
+}
+
extern void cpu_proc_init(void);
extern void cpu_proc_fin(void);
extern int cpu_do_idle(void);
@@ -98,17 +102,50 @@
extern void cpu_do_suspend(void *);
extern void cpu_do_resume(void *);
#else
-#define cpu_proc_init processor._proc_init
-#define cpu_proc_fin processor._proc_fin
-#define cpu_reset processor.reset
-#define cpu_do_idle processor._do_idle
-#define cpu_dcache_clean_area processor.dcache_clean_area
-#define cpu_set_pte_ext processor.set_pte_ext
-#define cpu_do_switch_mm processor.switch_mm
-/* These three are private to arch/arm/kernel/suspend.c */
-#define cpu_do_suspend processor.do_suspend
-#define cpu_do_resume processor.do_resume
+extern struct processor processor;
+#if defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR)
+#include <linux/smp.h>
+/*
+ * This can't be a per-cpu variable because we need to access it before
+ * per-cpu has been initialised. We have a couple of functions that are
+ * called in a pre-emptible context, and so can't use smp_processor_id()
+ * there, hence PROC_TABLE(). We insist in init_proc_vtable() that the
+ * function pointers for these are identical across all CPUs.
+ */
+extern struct processor *cpu_vtable[];
+#define PROC_VTABLE(f) cpu_vtable[smp_processor_id()]->f
+#define PROC_TABLE(f) cpu_vtable[0]->f
+static inline void init_proc_vtable(const struct processor *p)
+{
+ unsigned int cpu = smp_processor_id();
+ *cpu_vtable[cpu] = *p;
+ WARN_ON_ONCE(cpu_vtable[cpu]->dcache_clean_area !=
+ cpu_vtable[0]->dcache_clean_area);
+ WARN_ON_ONCE(cpu_vtable[cpu]->set_pte_ext !=
+ cpu_vtable[0]->set_pte_ext);
+}
+#else
+#define PROC_VTABLE(f) processor.f
+#define PROC_TABLE(f) processor.f
+static inline void init_proc_vtable(const struct processor *p)
+{
+ processor = *p;
+}
+#endif
+
+#define cpu_proc_init PROC_VTABLE(_proc_init)
+#define cpu_check_bugs PROC_VTABLE(check_bugs)
+#define cpu_proc_fin PROC_VTABLE(_proc_fin)
+#define cpu_reset PROC_VTABLE(reset)
+#define cpu_do_idle PROC_VTABLE(_do_idle)
+#define cpu_dcache_clean_area PROC_TABLE(dcache_clean_area)
+#define cpu_set_pte_ext PROC_TABLE(set_pte_ext)
+#define cpu_do_switch_mm PROC_VTABLE(switch_mm)
+
+/* These two are private to arch/arm/kernel/suspend.c */
+#define cpu_do_suspend PROC_VTABLE(do_suspend)
+#define cpu_do_resume PROC_VTABLE(do_resume)
#endif
extern void cpu_resume(void);
diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h
index a0e42ca..cfbf32b 100644
--- a/arch/arm/include/asm/thread_info.h
+++ b/arch/arm/include/asm/thread_info.h
@@ -124,8 +124,8 @@
struct user_vfp;
struct user_vfp_exc;
-extern int vfp_preserve_user_clear_hwstate(struct user_vfp __user *,
- struct user_vfp_exc __user *);
+extern int vfp_preserve_user_clear_hwstate(struct user_vfp *,
+ struct user_vfp_exc *);
extern int vfp_restore_user_hwstate(struct user_vfp *,
struct user_vfp_exc *);
#endif
diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h
index 7b17460..0f6c6b87 100644
--- a/arch/arm/include/asm/uaccess.h
+++ b/arch/arm/include/asm/uaccess.h
@@ -99,6 +99,14 @@
static inline void set_fs(mm_segment_t fs)
{
current_thread_info()->addr_limit = fs;
+
+ /*
+ * Prevent a mispredicted conditional call to set_fs from forwarding
+ * the wrong address limit to access_ok under speculation.
+ */
+ dsb(nsh);
+ isb();
+
modify_domain(DOMAIN_KERNEL, fs ? DOMAIN_CLIENT : DOMAIN_MANAGER);
}
@@ -122,6 +130,32 @@
__typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL))
/*
+ * Sanitise a uaccess pointer such that it becomes NULL if addr+size
+ * is above the current addr_limit.
+ */
+#define uaccess_mask_range_ptr(ptr, size) \
+ ((__typeof__(ptr))__uaccess_mask_range_ptr(ptr, size))
+static inline void __user *__uaccess_mask_range_ptr(const void __user *ptr,
+ size_t size)
+{
+ void __user *safe_ptr = (void __user *)ptr;
+ unsigned long tmp;
+
+ asm volatile(
+ " sub %1, %3, #1\n"
+ " subs %1, %1, %0\n"
+ " addhs %1, %1, #1\n"
+ " subhss %1, %1, %2\n"
+ " movlo %0, #0\n"
+ : "+r" (safe_ptr), "=&r" (tmp)
+ : "r" (size), "r" (current_thread_info()->addr_limit)
+ : "cc");
+
+ csdb();
+ return safe_ptr;
+}
+
+/*
* Single-value transfer routines. They automatically use the right
* size if we just have the right pointer type. Note that the functions
* which read from user space (*get_*) need to take care not to leak
@@ -392,6 +426,14 @@
__pu_err; \
})
+#ifdef CONFIG_CPU_SPECTRE
+/*
+ * When mitigating Spectre variant 1.1, all accessors need to include
+ * verification of the address space.
+ */
+#define __put_user(x, ptr) put_user(x, ptr)
+
+#else
#define __put_user(x, ptr) \
({ \
long __pu_err = 0; \
@@ -399,12 +441,6 @@
__pu_err; \
})
-#define __put_user_error(x, ptr, err) \
-({ \
- __put_user_switch((x), (ptr), (err), __put_user_nocheck); \
- (void) 0; \
-})
-
#define __put_user_nocheck(x, __pu_ptr, __err, __size) \
do { \
unsigned long __pu_addr = (unsigned long)__pu_ptr; \
@@ -484,6 +520,7 @@
: "r" (x), "i" (-EFAULT) \
: "cc")
+#endif /* !CONFIG_CPU_SPECTRE */
#ifdef CONFIG_MMU
extern unsigned long __must_check
diff --git a/arch/arm/kernel/bugs.c b/arch/arm/kernel/bugs.c
index 7be5113..d41d359 100644
--- a/arch/arm/kernel/bugs.c
+++ b/arch/arm/kernel/bugs.c
@@ -6,8 +6,8 @@
void check_other_bugs(void)
{
#ifdef MULTI_CPU
- if (processor.check_bugs)
- processor.check_bugs();
+ if (cpu_check_bugs)
+ cpu_check_bugs();
#endif
}
diff --git a/arch/arm/kernel/head-common.S b/arch/arm/kernel/head-common.S
index 8733012..7e662bd 100644
--- a/arch/arm/kernel/head-common.S
+++ b/arch/arm/kernel/head-common.S
@@ -122,6 +122,9 @@
.long init_thread_union + THREAD_START_SP @ sp
.size __mmap_switched_data, . - __mmap_switched_data
+ __FINIT
+ .text
+
/*
* This provides a C-API version of __lookup_processor_type
*/
@@ -133,9 +136,6 @@
ldmfd sp!, {r4 - r6, r9, pc}
ENDPROC(lookup_processor_type)
- __FINIT
- .text
-
/*
* Read processor ID register (CP#15, CR0), and look up in the linker-built
* supported processor list. Note that we can't use the absolute addresses
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
old mode 100644
new mode 100755
index 4f451ce..775d70c
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -124,6 +124,11 @@
#ifdef MULTI_CPU
struct processor processor __ro_after_init;
+#if defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR)
+struct processor *cpu_vtable[NR_CPUS] = {
+ [0] = &processor,
+};
+#endif
#endif
#ifdef MULTI_TLB
struct cpu_tlb_fns cpu_tlb __ro_after_init;
@@ -710,29 +715,36 @@
}
#endif
-static void __init setup_processor(void)
+/*
+ * locate processor in the list of supported processor types. The linker
+ * builds this table for us from the entries in arch/arm/mm/proc-*.S
+ */
+struct proc_info_list *lookup_processor(u32 midr)
{
- struct proc_info_list *list;
+ struct proc_info_list *list = lookup_processor_type(midr);
- /*
- * locate processor in the list of supported processor
- * types. The linker builds this table for us from the
- * entries in arch/arm/mm/proc-*.S
- */
- arm_init_bp_hardening();
- list = lookup_processor_type(read_cpuid_id());
if (!list) {
- pr_err("CPU configuration botched (ID %08x), unable to continue.\n",
- read_cpuid_id());
- while (1);
+ pr_err("CPU%u: configuration botched (ID %08x), CPU halted\n",
+ smp_processor_id(), midr);
+ while (1)
+ /* can't use cpu_relax() here as it may require MMU setup */;
}
+ return list;
+}
+
+static void __init setup_processor(void)
+{
+ unsigned int midr;
+ struct proc_info_list *list;
+
+ arm_init_bp_hardening();
+ midr = read_cpuid_id();
+ list = lookup_processor(midr);
cpu_name = list->cpu_name;
__cpu_architecture = __get_cpu_architecture();
-#ifdef MULTI_CPU
- processor = *list->proc;
-#endif
+ init_proc_vtable(list->proc);
#ifdef MULTI_TLB
cpu_tlb = *list->tlb;
#endif
@@ -744,7 +756,7 @@
#endif
pr_info("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n",
- cpu_name, read_cpuid_id(), read_cpuid_id() & 15,
+ list->cpu_name, midr, midr & 15,
proc_arch[cpu_architecture()], get_cr());
snprintf(init_utsname()->machine, __NEW_UTS_LEN + 1, "%s%c",
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index a53e2b8..7abc908 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -95,17 +95,18 @@
static int preserve_vfp_context(struct vfp_sigframe __user *frame)
{
- const unsigned long magic = VFP_MAGIC;
- const unsigned long size = VFP_STORAGE_SIZE;
+ struct vfp_sigframe kframe;
int err = 0;
- __put_user_error(magic, &frame->magic, err);
- __put_user_error(size, &frame->size, err);
+ memset(&kframe, 0, sizeof(kframe));
+ kframe.magic = VFP_MAGIC;
+ kframe.size = VFP_STORAGE_SIZE;
+ err = vfp_preserve_user_clear_hwstate(&kframe.ufp, &kframe.ufp_exc);
if (err)
- return -EFAULT;
+ return err;
- return vfp_preserve_user_clear_hwstate(&frame->ufp, &frame->ufp_exc);
+ return __copy_to_user(frame, &kframe, sizeof(kframe));
}
static int restore_vfp_context(struct vfp_sigframe __user *auxp)
@@ -257,30 +258,35 @@
setup_sigframe(struct sigframe __user *sf, struct pt_regs *regs, sigset_t *set)
{
struct aux_sigframe __user *aux;
+ struct sigcontext context;
int err = 0;
- __put_user_error(regs->ARM_r0, &sf->uc.uc_mcontext.arm_r0, err);
- __put_user_error(regs->ARM_r1, &sf->uc.uc_mcontext.arm_r1, err);
- __put_user_error(regs->ARM_r2, &sf->uc.uc_mcontext.arm_r2, err);
- __put_user_error(regs->ARM_r3, &sf->uc.uc_mcontext.arm_r3, err);
- __put_user_error(regs->ARM_r4, &sf->uc.uc_mcontext.arm_r4, err);
- __put_user_error(regs->ARM_r5, &sf->uc.uc_mcontext.arm_r5, err);
- __put_user_error(regs->ARM_r6, &sf->uc.uc_mcontext.arm_r6, err);
- __put_user_error(regs->ARM_r7, &sf->uc.uc_mcontext.arm_r7, err);
- __put_user_error(regs->ARM_r8, &sf->uc.uc_mcontext.arm_r8, err);
- __put_user_error(regs->ARM_r9, &sf->uc.uc_mcontext.arm_r9, err);
- __put_user_error(regs->ARM_r10, &sf->uc.uc_mcontext.arm_r10, err);
- __put_user_error(regs->ARM_fp, &sf->uc.uc_mcontext.arm_fp, err);
- __put_user_error(regs->ARM_ip, &sf->uc.uc_mcontext.arm_ip, err);
- __put_user_error(regs->ARM_sp, &sf->uc.uc_mcontext.arm_sp, err);
- __put_user_error(regs->ARM_lr, &sf->uc.uc_mcontext.arm_lr, err);
- __put_user_error(regs->ARM_pc, &sf->uc.uc_mcontext.arm_pc, err);
- __put_user_error(regs->ARM_cpsr, &sf->uc.uc_mcontext.arm_cpsr, err);
+ context = (struct sigcontext) {
+ .arm_r0 = regs->ARM_r0,
+ .arm_r1 = regs->ARM_r1,
+ .arm_r2 = regs->ARM_r2,
+ .arm_r3 = regs->ARM_r3,
+ .arm_r4 = regs->ARM_r4,
+ .arm_r5 = regs->ARM_r5,
+ .arm_r6 = regs->ARM_r6,
+ .arm_r7 = regs->ARM_r7,
+ .arm_r8 = regs->ARM_r8,
+ .arm_r9 = regs->ARM_r9,
+ .arm_r10 = regs->ARM_r10,
+ .arm_fp = regs->ARM_fp,
+ .arm_ip = regs->ARM_ip,
+ .arm_sp = regs->ARM_sp,
+ .arm_lr = regs->ARM_lr,
+ .arm_pc = regs->ARM_pc,
+ .arm_cpsr = regs->ARM_cpsr,
- __put_user_error(current->thread.trap_no, &sf->uc.uc_mcontext.trap_no, err);
- __put_user_error(current->thread.error_code, &sf->uc.uc_mcontext.error_code, err);
- __put_user_error(current->thread.address, &sf->uc.uc_mcontext.fault_address, err);
- __put_user_error(set->sig[0], &sf->uc.uc_mcontext.oldmask, err);
+ .trap_no = current->thread.trap_no,
+ .error_code = current->thread.error_code,
+ .fault_address = current->thread.address,
+ .oldmask = set->sig[0],
+ };
+
+ err |= __copy_to_user(&sf->uc.uc_mcontext, &context, sizeof(context));
err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set));
@@ -297,7 +303,7 @@
if (err == 0)
err |= preserve_vfp_context(&aux->vfp);
#endif
- __put_user_error(0, &aux->end_magic, err);
+ err |= __put_user(0, &aux->end_magic);
return err;
}
@@ -429,7 +435,7 @@
/*
* Set uc.uc_flags to a value which sc.trap_no would never have.
*/
- __put_user_error(0x5ac3c35a, &frame->uc.uc_flags, err);
+ err = __put_user(0x5ac3c35a, &frame->uc.uc_flags);
err |= setup_sigframe(frame, regs, set);
if (err == 0)
@@ -449,8 +455,8 @@
err |= copy_siginfo_to_user(&frame->info, &ksig->info);
- __put_user_error(0, &frame->sig.uc.uc_flags, err);
- __put_user_error(NULL, &frame->sig.uc.uc_link, err);
+ err |= __put_user(0, &frame->sig.uc.uc_flags);
+ err |= __put_user(NULL, &frame->sig.uc.uc_link);
err |= __save_altstack(&frame->sig.uc.uc_stack, regs->ARM_sp);
err |= setup_sigframe(&frame->sig, regs, set);
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index ff86d6c..b7a75a0 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -27,6 +27,7 @@
#include <linux/completion.h>
#include <linux/cpufreq.h>
#include <linux/irq_work.h>
+#include <linux/slab.h>
#include <linux/atomic.h>
#include <asm/bugs.h>
@@ -40,6 +41,7 @@
#include <asm/mmu_context.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
+#include <asm/procinfo.h>
#include <asm/processor.h>
#include <asm/sections.h>
#include <asm/tlbflush.h>
@@ -101,6 +103,30 @@
#endif
}
+#if defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR)
+static int secondary_biglittle_prepare(unsigned int cpu)
+{
+ if (!cpu_vtable[cpu])
+ cpu_vtable[cpu] = kzalloc(sizeof(*cpu_vtable[cpu]), GFP_KERNEL);
+
+ return cpu_vtable[cpu] ? 0 : -ENOMEM;
+}
+
+static void secondary_biglittle_init(void)
+{
+ init_proc_vtable(lookup_processor(read_cpuid_id())->proc);
+}
+#else
+static int secondary_biglittle_prepare(unsigned int cpu)
+{
+ return 0;
+}
+
+static void secondary_biglittle_init(void)
+{
+}
+#endif
+
int __cpu_up(unsigned int cpu, struct task_struct *idle)
{
int ret;
@@ -108,6 +134,10 @@
if (!smp_ops.smp_boot_secondary)
return -ENOSYS;
+ ret = secondary_biglittle_prepare(cpu);
+ if (ret)
+ return ret;
+
/*
* We need to tell the secondary core where to find
* its stack and the page tables.
@@ -357,6 +387,8 @@
struct mm_struct *mm = &init_mm;
unsigned int cpu;
+ secondary_biglittle_init();
+
/*
* The identity mapping is uncached (strongly ordered), so
* switch away from it before attempting any exclusive accesses.
@@ -705,6 +737,21 @@
pr_warn("SMP: failed to stop secondary CPUs\n");
}
+/* In case panic() and panic() called at the same time on CPU1 and CPU2,
+ * and CPU 1 calls panic_smp_self_stop() before crash_smp_send_stop()
+ * CPU1 can't receive the ipi irqs from CPU2, CPU1 will be always online,
+ * kdump fails. So split out the panic_smp_self_stop() and add
+ * set_cpu_online(smp_processor_id(), false).
+ */
+void panic_smp_self_stop(void)
+{
+ pr_debug("CPU %u will stop doing anything useful since another CPU has paniced\n",
+ smp_processor_id());
+ set_cpu_online(smp_processor_id(), false);
+ while (1)
+ cpu_relax();
+}
+
/*
* not supported here
*/
diff --git a/arch/arm/kernel/sys_oabi-compat.c b/arch/arm/kernel/sys_oabi-compat.c
index 640748e..d844c5c 100644
--- a/arch/arm/kernel/sys_oabi-compat.c
+++ b/arch/arm/kernel/sys_oabi-compat.c
@@ -276,6 +276,7 @@
int maxevents, int timeout)
{
struct epoll_event *kbuf;
+ struct oabi_epoll_event e;
mm_segment_t fs;
long ret, err, i;
@@ -294,8 +295,11 @@
set_fs(fs);
err = 0;
for (i = 0; i < ret; i++) {
- __put_user_error(kbuf[i].events, &events->events, err);
- __put_user_error(kbuf[i].data, &events->data, err);
+ e.events = kbuf[i].events;
+ e.data = kbuf[i].data;
+ err = __copy_to_user(events, &e, sizeof(e));
+ if (err)
+ break;
events++;
}
kfree(kbuf);
diff --git a/arch/arm/kvm/mmio.c b/arch/arm/kvm/mmio.c
index dac7ceb..08443a1 100644
--- a/arch/arm/kvm/mmio.c
+++ b/arch/arm/kvm/mmio.c
@@ -117,6 +117,12 @@
vcpu_set_reg(vcpu, vcpu->arch.mmio_decode.rt, data);
}
+ /*
+ * The MMIO instruction is emulated and should not be re-executed
+ * in the guest.
+ */
+ kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
+
return 0;
}
@@ -144,11 +150,6 @@
vcpu->arch.mmio_decode.sign_extend = sign_extend;
vcpu->arch.mmio_decode.rt = rt;
- /*
- * The MMIO instruction is emulated and should not be re-executed
- * in the guest.
- */
- kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
return 0;
}
diff --git a/arch/arm/lib/copy_from_user.S b/arch/arm/lib/copy_from_user.S
index a826df3..6709a8d 100644
--- a/arch/arm/lib/copy_from_user.S
+++ b/arch/arm/lib/copy_from_user.S
@@ -93,11 +93,7 @@
#ifdef CONFIG_CPU_SPECTRE
get_thread_info r3
ldr r3, [r3, #TI_ADDR_LIMIT]
- adds ip, r1, r2 @ ip=addr+size
- sub r3, r3, #1 @ addr_limit - 1
- cmpcc ip, r3 @ if (addr+size > addr_limit - 1)
- movcs r1, #0 @ addr = NULL
- csdb
+ uaccess_mask_range_ptr r1, r2, r3, ip
#endif
#include "copy_template.S"
diff --git a/arch/arm/lib/copy_to_user.S b/arch/arm/lib/copy_to_user.S
index caf5019..970abe5 100644
--- a/arch/arm/lib/copy_to_user.S
+++ b/arch/arm/lib/copy_to_user.S
@@ -94,6 +94,11 @@
ENTRY(__copy_to_user_std)
WEAK(arm_copy_to_user)
+#ifdef CONFIG_CPU_SPECTRE
+ get_thread_info r3
+ ldr r3, [r3, #TI_ADDR_LIMIT]
+ uaccess_mask_range_ptr r0, r2, r3, ip
+#endif
#include "copy_template.S"
@@ -108,4 +113,3 @@
rsb r0, r0, r2
copy_abort_end
.popsection
-
diff --git a/arch/arm/lib/uaccess_with_memcpy.c b/arch/arm/lib/uaccess_with_memcpy.c
index 6bd1089..f598d79 100644
--- a/arch/arm/lib/uaccess_with_memcpy.c
+++ b/arch/arm/lib/uaccess_with_memcpy.c
@@ -152,7 +152,8 @@
n = __copy_to_user_std(to, from, n);
uaccess_restore(ua_flags);
} else {
- n = __copy_to_user_memcpy(to, from, n);
+ n = __copy_to_user_memcpy(uaccess_mask_range_ptr(to, n),
+ from, n);
}
return n;
}
diff --git a/arch/arm/mach-integrator/impd1.c b/arch/arm/mach-integrator/impd1.c
index ed9a014..a52fe87 100644
--- a/arch/arm/mach-integrator/impd1.c
+++ b/arch/arm/mach-integrator/impd1.c
@@ -394,7 +394,11 @@
sizeof(*lookup) + 3 * sizeof(struct gpiod_lookup),
GFP_KERNEL);
chipname = devm_kstrdup(&dev->dev, devname, GFP_KERNEL);
- mmciname = kasprintf(GFP_KERNEL, "lm%x:00700", dev->id);
+ mmciname = devm_kasprintf(&dev->dev, GFP_KERNEL,
+ "lm%x:00700", dev->id);
+ if (!lookup || !chipname || !mmciname)
+ return -ENOMEM;
+
lookup->dev_id = mmciname;
/*
* Offsets on GPIO block 1:
diff --git a/arch/arm/mach-iop32x/n2100.c b/arch/arm/mach-iop32x/n2100.c
index c1cd80e..a904244 100644
--- a/arch/arm/mach-iop32x/n2100.c
+++ b/arch/arm/mach-iop32x/n2100.c
@@ -75,8 +75,7 @@
/*
* N2100 PCI.
*/
-static int __init
-n2100_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+static int n2100_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
int irq;
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index b5c1714..bfc7495 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -2551,7 +2551,7 @@
* a stub; implementing this properly requires iclk autoidle usecounting in
* the clock code. No return value.
*/
-static void __init _setup_iclk_autoidle(struct omap_hwmod *oh)
+static void _setup_iclk_autoidle(struct omap_hwmod *oh)
{
struct omap_hwmod_ocp_if *os;
struct list_head *p;
@@ -2586,7 +2586,7 @@
* reset. Returns 0 upon success or a negative error code upon
* failure.
*/
-static int __init _setup_reset(struct omap_hwmod *oh)
+static int _setup_reset(struct omap_hwmod *oh)
{
int r;
@@ -2647,7 +2647,7 @@
*
* No return value.
*/
-static void __init _setup_postsetup(struct omap_hwmod *oh)
+static void _setup_postsetup(struct omap_hwmod *oh)
{
u8 postsetup_state;
diff --git a/arch/arm/mach-pxa/cm-x300.c b/arch/arm/mach-pxa/cm-x300.c
index 868448d..38ab308 100644
--- a/arch/arm/mach-pxa/cm-x300.c
+++ b/arch/arm/mach-pxa/cm-x300.c
@@ -547,7 +547,7 @@
.exit = cm_x300_u2d_exit,
};
-static void cm_x300_init_u2d(void)
+static void __init cm_x300_init_u2d(void)
{
pxa3xx_set_u2d_info(&cm_x300_u2d_platform_data);
}
diff --git a/arch/arm/mach-pxa/littleton.c b/arch/arm/mach-pxa/littleton.c
index 051c554..ebdef66 100644
--- a/arch/arm/mach-pxa/littleton.c
+++ b/arch/arm/mach-pxa/littleton.c
@@ -183,7 +183,7 @@
.lcd_conn = LCD_COLOR_TFT_16BPP,
};
-static void littleton_init_lcd(void)
+static void __init littleton_init_lcd(void)
{
pxa_set_fb_info(NULL, &littleton_lcd_info);
}
diff --git a/arch/arm/mach-pxa/zeus.c b/arch/arm/mach-pxa/zeus.c
index 3b94ecf..3fcd585 100644
--- a/arch/arm/mach-pxa/zeus.c
+++ b/arch/arm/mach-pxa/zeus.c
@@ -557,7 +557,7 @@
.flags = ENABLE_PORT_ALL | POWER_SENSE_LOW,
};
-static void zeus_register_ohci(void)
+static void __init zeus_register_ohci(void)
{
/* Port 2 is shared between host and client interface. */
UP2OCR = UP2OCR_HXOE | UP2OCR_HXS | UP2OCR_DMPDE | UP2OCR_DPPDE;
diff --git a/arch/arm/mach-tango/pm.c b/arch/arm/mach-tango/pm.c
index b05c6d6..08d8132 100644
--- a/arch/arm/mach-tango/pm.c
+++ b/arch/arm/mach-tango/pm.c
@@ -2,6 +2,7 @@
#include <linux/suspend.h>
#include <asm/suspend.h>
#include "smc.h"
+#include "pm.h"
static int tango_pm_powerdown(unsigned long arg)
{
@@ -23,10 +24,7 @@
.valid = suspend_valid_only_mem,
};
-static int __init tango_pm_init(void)
+void __init tango_pm_init(void)
{
suspend_set_ops(&tango_pm_ops);
- return 0;
}
-
-late_initcall(tango_pm_init);
diff --git a/arch/arm/mach-tango/pm.h b/arch/arm/mach-tango/pm.h
new file mode 100644
index 0000000..35ea705
--- /dev/null
+++ b/arch/arm/mach-tango/pm.h
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifdef CONFIG_SUSPEND
+void __init tango_pm_init(void);
+#else
+#define tango_pm_init NULL
+#endif
diff --git a/arch/arm/mach-tango/setup.c b/arch/arm/mach-tango/setup.c
index f14b6c7..2b48e10 100644
--- a/arch/arm/mach-tango/setup.c
+++ b/arch/arm/mach-tango/setup.c
@@ -1,6 +1,7 @@
#include <asm/mach/arch.h>
#include <asm/hardware/cache-l2x0.h>
#include "smc.h"
+#include "pm.h"
static void tango_l2c_write(unsigned long val, unsigned int reg)
{
@@ -14,4 +15,5 @@
.dt_compat = tango_dt_compat,
.l2c_aux_mask = ~0,
.l2c_write_sec = tango_l2c_write,
+ .init_late = tango_pm_init,
MACHINE_END
diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S
index 53bf9ed..cb41b18 100644
--- a/arch/arm/mm/proc-macros.S
+++ b/arch/arm/mm/proc-macros.S
@@ -275,6 +275,13 @@
.endm
.macro define_processor_functions name:req, dabort:req, pabort:req, nommu=0, suspend=0, bugs=0
+/*
+ * If we are building for big.Little with branch predictor hardening,
+ * we need the processor function tables to remain available after boot.
+ */
+#if defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR)
+ .section ".rodata"
+#endif
.type \name\()_processor_functions, #object
.align 2
ENTRY(\name\()_processor_functions)
@@ -310,6 +317,9 @@
.endif
.size \name\()_processor_functions, . - \name\()_processor_functions
+#if defined(CONFIG_BIG_LITTLE) && defined(CONFIG_HARDEN_BRANCH_PREDICTOR)
+ .previous
+#endif
.endm
.macro define_cache_functions name:req
diff --git a/arch/arm/mm/proc-v7-bugs.c b/arch/arm/mm/proc-v7-bugs.c
index 5544b82..9a07916 100644
--- a/arch/arm/mm/proc-v7-bugs.c
+++ b/arch/arm/mm/proc-v7-bugs.c
@@ -52,8 +52,6 @@
case ARM_CPU_PART_CORTEX_A17:
case ARM_CPU_PART_CORTEX_A73:
case ARM_CPU_PART_CORTEX_A75:
- if (processor.switch_mm != cpu_v7_bpiall_switch_mm)
- goto bl_error;
per_cpu(harden_branch_predictor_fn, cpu) =
harden_branch_predictor_bpiall;
spectre_v2_method = "BPIALL";
@@ -61,8 +59,6 @@
case ARM_CPU_PART_CORTEX_A15:
case ARM_CPU_PART_BRAHMA_B15:
- if (processor.switch_mm != cpu_v7_iciallu_switch_mm)
- goto bl_error;
per_cpu(harden_branch_predictor_fn, cpu) =
harden_branch_predictor_iciallu;
spectre_v2_method = "ICIALLU";
@@ -88,11 +84,9 @@
ARM_SMCCC_ARCH_WORKAROUND_1, &res);
if ((int)res.a0 != 0)
break;
- if (processor.switch_mm != cpu_v7_hvc_switch_mm && cpu)
- goto bl_error;
per_cpu(harden_branch_predictor_fn, cpu) =
call_hvc_arch_workaround_1;
- processor.switch_mm = cpu_v7_hvc_switch_mm;
+ cpu_do_switch_mm = cpu_v7_hvc_switch_mm;
spectre_v2_method = "hypervisor";
break;
@@ -101,11 +95,9 @@
ARM_SMCCC_ARCH_WORKAROUND_1, &res);
if ((int)res.a0 != 0)
break;
- if (processor.switch_mm != cpu_v7_smc_switch_mm && cpu)
- goto bl_error;
per_cpu(harden_branch_predictor_fn, cpu) =
call_smc_arch_workaround_1;
- processor.switch_mm = cpu_v7_smc_switch_mm;
+ cpu_do_switch_mm = cpu_v7_smc_switch_mm;
spectre_v2_method = "firmware";
break;
@@ -119,11 +111,6 @@
if (spectre_v2_method)
pr_info("CPU%u: Spectre v2: using %s workaround\n",
smp_processor_id(), spectre_v2_method);
- return;
-
-bl_error:
- pr_err("CPU%u: Spectre v2: incorrect context switching function, system vulnerable\n",
- cpu);
}
#else
static void cpu_v7_spectre_init(void)
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index 8e5e979..00dd8cf 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -554,12 +554,11 @@
* Save the current VFP state into the provided structures and prepare
* for entry into a new function (signal handler).
*/
-int vfp_preserve_user_clear_hwstate(struct user_vfp __user *ufp,
- struct user_vfp_exc __user *ufp_exc)
+int vfp_preserve_user_clear_hwstate(struct user_vfp *ufp,
+ struct user_vfp_exc *ufp_exc)
{
struct thread_info *thread = current_thread_info();
struct vfp_hard_struct *hwstate = &thread->vfpstate.hard;
- int err = 0;
/* Ensure that the saved hwstate is up-to-date. */
vfp_sync_hwstate(thread);
@@ -568,22 +567,19 @@
* Copy the floating point registers. There can be unused
* registers see asm/hwcap.h for details.
*/
- err |= __copy_to_user(&ufp->fpregs, &hwstate->fpregs,
- sizeof(hwstate->fpregs));
+ memcpy(&ufp->fpregs, &hwstate->fpregs, sizeof(hwstate->fpregs));
+
/*
* Copy the status and control register.
*/
- __put_user_error(hwstate->fpscr, &ufp->fpscr, err);
+ ufp->fpscr = hwstate->fpscr;
/*
* Copy the exception registers.
*/
- __put_user_error(hwstate->fpexc, &ufp_exc->fpexc, err);
- __put_user_error(hwstate->fpinst, &ufp_exc->fpinst, err);
- __put_user_error(hwstate->fpinst2, &ufp_exc->fpinst2, err);
-
- if (err)
- return -EFAULT;
+ ufp_exc->fpexc = hwstate->fpexc;
+ ufp_exc->fpinst = hwstate->fpinst;
+ ufp_exc->fpinst2 = hwstate->fpinst2;
/* Ensure that VFP is disabled. */
vfp_flush_hwstate(thread);
diff --git a/arch/arm64/configs/cuttlefish_defconfig b/arch/arm64/configs/cuttlefish_defconfig
index a16f315..8afaa52 100644
--- a/arch/arm64/configs/cuttlefish_defconfig
+++ b/arch/arm64/configs/cuttlefish_defconfig
@@ -80,6 +80,7 @@
CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_XFRM_USER=y
+CONFIG_XFRM_INTERFACE=y
CONFIG_NET_KEY=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
@@ -142,6 +143,7 @@
CONFIG_NETFILTER_XT_MATCH_LIMIT=y
CONFIG_NETFILTER_XT_MATCH_MAC=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_OWNER=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
@@ -178,6 +180,7 @@
CONFIG_L2TP=y
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_NETEM=y
CONFIG_NET_CLS_U32=y
CONFIG_NET_CLS_BPF=y
CONFIG_NET_EMATCH=y
diff --git a/arch/arm64/configs/msm8937-perf_defconfig b/arch/arm64/configs/msm8937-perf_defconfig
old mode 100644
new mode 100755
index 094b842..cc52953a
--- a/arch/arm64/configs/msm8937-perf_defconfig
+++ b/arch/arm64/configs/msm8937-perf_defconfig
@@ -170,9 +170,9 @@
CONFIG_NETFILTER_XT_MATCH_MAC=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_OWNER=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
diff --git a/arch/arm64/configs/msm8937_defconfig b/arch/arm64/configs/msm8937_defconfig
old mode 100644
new mode 100755
index bb41b2a..f3ed5a7
--- a/arch/arm64/configs/msm8937_defconfig
+++ b/arch/arm64/configs/msm8937_defconfig
@@ -174,9 +174,9 @@
CONFIG_NETFILTER_XT_MATCH_MAC=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_OWNER=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
diff --git a/arch/arm64/configs/msm8953-perf_defconfig b/arch/arm64/configs/msm8953-perf_defconfig
old mode 100644
new mode 100755
index 6264bc3..4099bd0
--- a/arch/arm64/configs/msm8953-perf_defconfig
+++ b/arch/arm64/configs/msm8953-perf_defconfig
@@ -169,9 +169,9 @@
CONFIG_NETFILTER_XT_MATCH_MAC=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_OWNER=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
diff --git a/arch/arm64/configs/msm8953_defconfig b/arch/arm64/configs/msm8953_defconfig
old mode 100644
new mode 100755
index 4149825..c7441f4
--- a/arch/arm64/configs/msm8953_defconfig
+++ b/arch/arm64/configs/msm8953_defconfig
@@ -173,9 +173,9 @@
CONFIG_NETFILTER_XT_MATCH_MAC=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_OWNER=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
diff --git a/arch/arm64/configs/ranchu64_defconfig b/arch/arm64/configs/ranchu64_defconfig
index fc55008..704d9b5 100644
--- a/arch/arm64/configs/ranchu64_defconfig
+++ b/arch/arm64/configs/ranchu64_defconfig
@@ -105,9 +105,9 @@
CONFIG_NETFILTER_XT_MATCH_LIMIT=y
CONFIG_NETFILTER_XT_MATCH_MAC=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_OWNER=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
diff --git a/arch/arm64/configs/sdm670-perf_defconfig b/arch/arm64/configs/sdm670-perf_defconfig
old mode 100644
new mode 100755
index e5ebc0c..4112115
--- a/arch/arm64/configs/sdm670-perf_defconfig
+++ b/arch/arm64/configs/sdm670-perf_defconfig
@@ -168,9 +168,9 @@
CONFIG_NETFILTER_XT_MATCH_MAC=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_OWNER=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
diff --git a/arch/arm64/configs/sdm670_defconfig b/arch/arm64/configs/sdm670_defconfig
old mode 100644
new mode 100755
index d495175..9316ac0
--- a/arch/arm64/configs/sdm670_defconfig
+++ b/arch/arm64/configs/sdm670_defconfig
@@ -173,9 +173,9 @@
CONFIG_NETFILTER_XT_MATCH_MAC=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_OWNER=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig
old mode 100644
new mode 100755
index 492b72e..ca073a7
--- a/arch/arm64/configs/sdm845-perf_defconfig
+++ b/arch/arm64/configs/sdm845-perf_defconfig
@@ -168,9 +168,9 @@
CONFIG_NETFILTER_XT_MATCH_MAC=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_OWNER=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig
old mode 100644
new mode 100755
index 8d44296..9bea57c
--- a/arch/arm64/configs/sdm845_defconfig
+++ b/arch/arm64/configs/sdm845_defconfig
@@ -171,9 +171,9 @@
CONFIG_NETFILTER_XT_MATCH_MAC=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_OWNER=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
diff --git a/arch/arm64/include/asm/lse.h b/arch/arm64/include/asm/lse.h
index fc756e2..c5a0d2e 100644
--- a/arch/arm64/include/asm/lse.h
+++ b/arch/arm64/include/asm/lse.h
@@ -16,7 +16,12 @@
#else /* __ASSEMBLER__ */
+#ifdef CONFIG_LTO_CLANG
+#define __LSE_PREAMBLE ".arch armv8-a+lse\n"
+#else
__asm__(".arch_extension lse");
+#define __LSE_PREAMBLE
+#endif
/* Move the ll/sc atomics out-of-line */
#define __LL_SC_INLINE
@@ -29,7 +34,7 @@
/* In-line patching at runtime */
#define ARM64_LSE_ATOMIC_INSN(llsc, lse) \
- ALTERNATIVE(llsc, lse, ARM64_HAS_LSE_ATOMICS)
+ ALTERNATIVE(llsc, __LSE_PREAMBLE lse, ARM64_HAS_LSE_ATOMICS)
#endif /* __ASSEMBLER__ */
#else /* CONFIG_AS_LSE && CONFIG_ARM64_LSE_ATOMICS */
diff --git a/arch/arm64/kernel/entry-ftrace.S b/arch/arm64/kernel/entry-ftrace.S
index aef02d2..7a87d32 100644
--- a/arch/arm64/kernel/entry-ftrace.S
+++ b/arch/arm64/kernel/entry-ftrace.S
@@ -78,7 +78,6 @@
.macro mcount_get_lr reg
ldr \reg, [x29]
ldr \reg, [\reg, #8]
- mcount_adjust_addr \reg, \reg
.endm
.macro mcount_get_lr_addr reg
diff --git a/arch/mips/include/uapi/asm/inst.h b/arch/mips/include/uapi/asm/inst.h
index 711d9b8..377d517 100644
--- a/arch/mips/include/uapi/asm/inst.h
+++ b/arch/mips/include/uapi/asm/inst.h
@@ -361,8 +361,8 @@
mm_ext_op = 0x02c,
mm_pool32axf_op = 0x03c,
mm_srl32_op = 0x040,
+ mm_srlv32_op = 0x050,
mm_sra_op = 0x080,
- mm_srlv32_op = 0x090,
mm_rotr_op = 0x0c0,
mm_lwxs_op = 0x118,
mm_addu32_op = 0x150,
diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c
index 659e6d3..60177a6 100644
--- a/arch/mips/kernel/mips-cm.c
+++ b/arch/mips/kernel/mips-cm.c
@@ -424,5 +424,5 @@
}
/* reprime cause register */
- write_gcr_error_cause(0);
+ write_gcr_error_cause(cm_error);
}
diff --git a/arch/mips/pci/pci-octeon.c b/arch/mips/pci/pci-octeon.c
index 308d051..7c51283 100644
--- a/arch/mips/pci/pci-octeon.c
+++ b/arch/mips/pci/pci-octeon.c
@@ -573,6 +573,11 @@
if (octeon_has_feature(OCTEON_FEATURE_PCIE))
return 0;
+ if (!octeon_is_pci_host()) {
+ pr_notice("Not in host mode, PCI Controller not initialized\n");
+ return 0;
+ }
+
/* Point pcibios_map_irq() to the PCI version of it */
octeon_pcibios_map_irq = octeon_pci_pcibios_map_irq;
@@ -584,11 +589,6 @@
else
octeon_dma_bar_type = OCTEON_DMA_BAR_TYPE_BIG;
- if (!octeon_is_pci_host()) {
- pr_notice("Not in host mode, PCI Controller not initialized\n");
- return 0;
- }
-
/* PCI I/O and PCI MEM values */
set_io_port_base(OCTEON_PCI_IOSPACE_BASE);
ioport_resource.start = 0;
diff --git a/arch/mips/ralink/Kconfig b/arch/mips/ralink/Kconfig
index 813826a..55a5fee 100644
--- a/arch/mips/ralink/Kconfig
+++ b/arch/mips/ralink/Kconfig
@@ -38,6 +38,7 @@
config SOC_MT7620
bool "MT7620/8"
+ select CPU_MIPSR2_IRQ_VI
select HW_HAS_PCI
config SOC_MT7621
diff --git a/arch/mips/vdso/Makefile b/arch/mips/vdso/Makefile
index c3dc12a..0b845cc 100644
--- a/arch/mips/vdso/Makefile
+++ b/arch/mips/vdso/Makefile
@@ -116,7 +116,7 @@
$(call cmd,force_checksrc)
$(call if_changed_rule,cc_o_c)
-$(obj)/vdso-o32.lds: KBUILD_CPPFLAGS := -mabi=32
+$(obj)/vdso-o32.lds: KBUILD_CPPFLAGS := $(ccflags-vdso) -mabi=32
$(obj)/vdso-o32.lds: $(src)/vdso.lds.S FORCE
$(call if_changed_dep,cpp_lds_S)
@@ -156,7 +156,7 @@
$(call cmd,force_checksrc)
$(call if_changed_rule,cc_o_c)
-$(obj)/vdso-n32.lds: KBUILD_CPPFLAGS := -mabi=n32
+$(obj)/vdso-n32.lds: KBUILD_CPPFLAGS := $(ccflags-vdso) -mabi=n32
$(obj)/vdso-n32.lds: $(src)/vdso.lds.S FORCE
$(call if_changed_dep,cpp_lds_S)
diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h
index c266227..31913b3 100644
--- a/arch/powerpc/include/asm/uaccess.h
+++ b/arch/powerpc/include/asm/uaccess.h
@@ -59,7 +59,7 @@
#endif
#define access_ok(type, addr, size) \
- (__chk_user_ptr(addr), \
+ (__chk_user_ptr(addr), (void)(type), \
__access_ok((__force unsigned long)(addr), (size), get_fs()))
/*
diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c
index 72ae2cd..999b048 100644
--- a/arch/powerpc/platforms/pseries/dlpar.c
+++ b/arch/powerpc/platforms/pseries/dlpar.c
@@ -288,6 +288,8 @@
if (rc)
return rc;
+ of_node_put(dn);
+
return 0;
}
diff --git a/arch/um/include/asm/pgtable.h b/arch/um/include/asm/pgtable.h
index 7485398..9c04562 100644
--- a/arch/um/include/asm/pgtable.h
+++ b/arch/um/include/asm/pgtable.h
@@ -197,12 +197,17 @@
static inline pte_t pte_wrprotect(pte_t pte)
{
- pte_clear_bits(pte, _PAGE_RW);
+ if (likely(pte_get_bits(pte, _PAGE_RW)))
+ pte_clear_bits(pte, _PAGE_RW);
+ else
+ return pte;
return(pte_mknewprot(pte));
}
static inline pte_t pte_mkread(pte_t pte)
{
+ if (unlikely(pte_get_bits(pte, _PAGE_USER)))
+ return pte;
pte_set_bits(pte, _PAGE_USER);
return(pte_mknewprot(pte));
}
@@ -221,6 +226,8 @@
static inline pte_t pte_mkwrite(pte_t pte)
{
+ if (unlikely(pte_get_bits(pte, _PAGE_RW)))
+ return pte;
pte_set_bits(pte, _PAGE_RW);
return(pte_mknewprot(pte));
}
diff --git a/arch/x86/configs/i386_ranchu_defconfig b/arch/x86/configs/i386_ranchu_defconfig
index a1c83c4..c679e2d 100644
--- a/arch/x86/configs/i386_ranchu_defconfig
+++ b/arch/x86/configs/i386_ranchu_defconfig
@@ -137,9 +137,9 @@
CONFIG_NETFILTER_XT_MATCH_LIMIT=y
CONFIG_NETFILTER_XT_MATCH_MAC=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_OWNER=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig
index bdc5c66..a22ed6a 100644
--- a/arch/x86/configs/x86_64_cuttlefish_defconfig
+++ b/arch/x86/configs/x86_64_cuttlefish_defconfig
@@ -84,6 +84,7 @@
CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_XFRM_USER=y
+CONFIG_XFRM_INTERFACE=y
CONFIG_NET_KEY=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
@@ -153,9 +154,9 @@
CONFIG_NETFILTER_XT_MATCH_LIMIT=y
CONFIG_NETFILTER_XT_MATCH_MAC=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_OWNER=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
@@ -191,6 +192,7 @@
CONFIG_IP6_NF_RAW=y
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_NETEM=y
CONFIG_NET_CLS_U32=y
CONFIG_NET_CLS_BPF=y
CONFIG_NET_EMATCH=y
@@ -456,6 +458,7 @@
CONFIG_RCU_CPU_STALL_TIMEOUT=60
CONFIG_ENABLE_DEFAULT_TRACERS=y
CONFIG_UPROBE_EVENT=y
+CONFIG_DEBUG_SET_MODULE_RONX=y
CONFIG_IO_DELAY_NONE=y
CONFIG_DEBUG_BOOT_PARAMS=y
CONFIG_OPTIMIZE_INLINING=y
diff --git a/arch/x86/configs/x86_64_ranchu_defconfig b/arch/x86/configs/x86_64_ranchu_defconfig
index d50434f..f094365 100644
--- a/arch/x86/configs/x86_64_ranchu_defconfig
+++ b/arch/x86/configs/x86_64_ranchu_defconfig
@@ -135,9 +135,9 @@
CONFIG_NETFILTER_XT_MATCH_LIMIT=y
CONFIG_NETFILTER_XT_MATCH_MAC=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_OWNER=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
index cadf999..ab04751 100644
--- a/arch/x86/events/core.c
+++ b/arch/x86/events/core.c
@@ -2196,6 +2196,19 @@
}
EXPORT_SYMBOL_GPL(perf_check_microcode);
+static int x86_pmu_check_period(struct perf_event *event, u64 value)
+{
+ if (x86_pmu.check_period && x86_pmu.check_period(event, value))
+ return -EINVAL;
+
+ if (value && x86_pmu.limit_period) {
+ if (x86_pmu.limit_period(event, value) > value)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static struct pmu pmu = {
.pmu_enable = x86_pmu_enable,
.pmu_disable = x86_pmu_disable,
@@ -2220,6 +2233,7 @@
.event_idx = x86_pmu_event_idx,
.sched_task = x86_pmu_sched_task,
.task_ctx_size = sizeof(struct x86_perf_task_context),
+ .check_period = x86_pmu_check_period,
};
void arch_perf_update_userpage(struct perf_event *event,
diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c
index 4f85607..f0639c8 100644
--- a/arch/x86/events/intel/core.c
+++ b/arch/x86/events/intel/core.c
@@ -3235,6 +3235,11 @@
static void intel_pmu_cpu_dying(int cpu)
{
+ fini_debug_store_on_cpu(cpu);
+}
+
+static void intel_pmu_cpu_dead(int cpu)
+{
struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu);
struct intel_shared_regs *pc;
@@ -3246,8 +3251,6 @@
}
free_excl_cntrs(cpu);
-
- fini_debug_store_on_cpu(cpu);
}
static void intel_pmu_sched_task(struct perf_event_context *ctx,
@@ -3259,6 +3262,11 @@
intel_pmu_lbr_sched_task(ctx, sched_in);
}
+static int intel_pmu_check_period(struct perf_event *event, u64 value)
+{
+ return intel_pmu_has_bts_period(event, value) ? -EINVAL : 0;
+}
+
PMU_FORMAT_ATTR(offcore_rsp, "config1:0-63");
PMU_FORMAT_ATTR(ldlat, "config1:0-15");
@@ -3324,6 +3332,9 @@
.cpu_prepare = intel_pmu_cpu_prepare,
.cpu_starting = intel_pmu_cpu_starting,
.cpu_dying = intel_pmu_cpu_dying,
+ .cpu_dead = intel_pmu_cpu_dead,
+
+ .check_period = intel_pmu_check_period,
};
static __initconst const struct x86_pmu intel_pmu = {
@@ -3359,8 +3370,12 @@
.cpu_prepare = intel_pmu_cpu_prepare,
.cpu_starting = intel_pmu_cpu_starting,
.cpu_dying = intel_pmu_cpu_dying,
+ .cpu_dead = intel_pmu_cpu_dead,
+
.guest_get_msrs = intel_guest_get_msrs,
.sched_task = intel_pmu_sched_task,
+
+ .check_period = intel_pmu_check_period,
};
static __init void intel_clovertown_quirk(void)
diff --git a/arch/x86/events/intel/uncore_snbep.c b/arch/x86/events/intel/uncore_snbep.c
index 8c2a9fa..686dd43 100644
--- a/arch/x86/events/intel/uncore_snbep.c
+++ b/arch/x86/events/intel/uncore_snbep.c
@@ -1221,6 +1221,8 @@
.id_table = snbep_uncore_pci_ids,
};
+#define NODE_ID_MASK 0x7
+
/*
* build pci bus to socket mapping
*/
@@ -1242,7 +1244,7 @@
err = pci_read_config_dword(ubox_dev, nodeid_loc, &config);
if (err)
break;
- nodeid = config;
+ nodeid = config & NODE_ID_MASK;
/* get the Node ID mapping */
err = pci_read_config_dword(ubox_dev, idmap_loc, &config);
if (err)
diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h
index 7ace39c..5c21680 100644
--- a/arch/x86/events/perf_event.h
+++ b/arch/x86/events/perf_event.h
@@ -626,6 +626,11 @@
* Intel host/guest support (KVM)
*/
struct perf_guest_switch_msr *(*guest_get_msrs)(int *nr);
+
+ /*
+ * Check period value for PERF_EVENT_IOC_PERIOD ioctl.
+ */
+ int (*check_period) (struct perf_event *event, u64 period);
};
struct x86_perf_task_context {
@@ -833,7 +838,7 @@
#ifdef CONFIG_CPU_SUP_INTEL
-static inline bool intel_pmu_has_bts(struct perf_event *event)
+static inline bool intel_pmu_has_bts_period(struct perf_event *event, u64 period)
{
struct hw_perf_event *hwc = &event->hw;
unsigned int hw_event, bts_event;
@@ -844,7 +849,14 @@
hw_event = hwc->config & INTEL_ARCH_EVENT_MASK;
bts_event = x86_pmu.event_map(PERF_COUNT_HW_BRANCH_INSTRUCTIONS);
- return hw_event == bts_event && hwc->sample_period == 1;
+ return hw_event == bts_event && period == 1;
+}
+
+static inline bool intel_pmu_has_bts(struct perf_event *event)
+{
+ struct hw_perf_event *hwc = &event->hw;
+
+ return intel_pmu_has_bts_period(event, hwc->sample_period);
}
int intel_pmu_save_and_restart(struct perf_event *event);
diff --git a/arch/x86/ia32/ia32_aout.c b/arch/x86/ia32/ia32_aout.c
index cb26f18..555c002 100644
--- a/arch/x86/ia32/ia32_aout.c
+++ b/arch/x86/ia32/ia32_aout.c
@@ -50,7 +50,7 @@
/*
* fill in the user structure for a core dump..
*/
-static void dump_thread32(struct pt_regs *regs, struct user32 *dump)
+static void fill_dump(struct pt_regs *regs, struct user32 *dump)
{
u32 fs, gs;
memset(dump, 0, sizeof(*dump));
@@ -156,10 +156,12 @@
fs = get_fs();
set_fs(KERNEL_DS);
has_dumped = 1;
+
+ fill_dump(cprm->regs, &dump);
+
strncpy(dump.u_comm, current->comm, sizeof(current->comm));
dump.u_ar0 = offsetof(struct user32, regs);
dump.signal = cprm->siginfo->si_signo;
- dump_thread32(cprm->regs, &dump);
/*
* If the size of the dump file exceeds the rlimit, then see
diff --git a/arch/x86/include/asm/fpu/internal.h b/arch/x86/include/asm/fpu/internal.h
index 499d6ed..21d6fa2 100644
--- a/arch/x86/include/asm/fpu/internal.h
+++ b/arch/x86/include/asm/fpu/internal.h
@@ -97,6 +97,9 @@
#define user_insn(insn, output, input...) \
({ \
int err; \
+ \
+ might_fault(); \
+ \
asm volatile(ASM_STAC "\n" \
"1:" #insn "\n\t" \
"2: " ASM_CLAC "\n" \
diff --git a/arch/x86/include/asm/uv/bios.h b/arch/x86/include/asm/uv/bios.h
index e652a7c..3f697a9 100644
--- a/arch/x86/include/asm/uv/bios.h
+++ b/arch/x86/include/asm/uv/bios.h
@@ -48,7 +48,8 @@
BIOS_STATUS_SUCCESS = 0,
BIOS_STATUS_UNIMPLEMENTED = -ENOSYS,
BIOS_STATUS_EINVAL = -EINVAL,
- BIOS_STATUS_UNAVAIL = -EBUSY
+ BIOS_STATUS_UNAVAIL = -EBUSY,
+ BIOS_STATUS_ABORT = -EINTR,
};
/* Address map parameters */
@@ -167,4 +168,9 @@
extern struct kobject *sgi_uv_kobj; /* /sys/firmware/sgi_uv */
+/*
+ * EFI runtime lock; cf. firmware/efi/runtime-wrappers.c for details
+ */
+extern struct semaphore __efi_uv_runtime_lock;
+
#endif /* _ASM_X86_UV_BIOS_H */
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index 7e6163c..25310d2 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -751,6 +751,7 @@
quirk_no_way_out(i, m, regs);
if (mce_severity(m, mca_cfg.tolerant, &tmp, true) >= MCE_PANIC_SEVERITY) {
+ m->bank = i;
mce_read_aux(m, i);
*msg = tmp;
return 1;
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index fa1b0e3..c8efacf 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -5223,6 +5223,13 @@
static bool svm_has_emulated_msr(int index)
{
+ switch (index) {
+ case MSR_IA32_MCG_EXT_CTL:
+ return false;
+ default:
+ break;
+ }
+
return true;
}
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 726cc44..a24d080 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -2178,7 +2178,8 @@
if (!entry_only)
j = find_msr(&m->host, msr);
- if (i == NR_AUTOLOAD_MSRS || j == NR_AUTOLOAD_MSRS) {
+ if ((i < 0 && m->guest.nr == NR_AUTOLOAD_MSRS) ||
+ (j < 0 && m->host.nr == NR_AUTOLOAD_MSRS)) {
printk_once(KERN_WARNING "Not enough msr switch entries. "
"Can't add msr %x\n", msr);
return;
@@ -7368,6 +7369,7 @@
if (!vmx->nested.vmxon)
return;
+ hrtimer_cancel(&vmx->nested.preemption_timer);
vmx->nested.vmxon = false;
free_vpid(vmx->nested.vpid02);
nested_release_vmcs12(vmx);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 851e9d6..5a35fee 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -4513,6 +4513,13 @@
{
u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0;
+ /*
+ * FIXME: this should call handle_emulation_failure if X86EMUL_IO_NEEDED
+ * is returned, but our callers are not ready for that and they blindly
+ * call kvm_inject_page_fault. Ensure that they at least do not leak
+ * uninitialized kernel stack memory into cr2 and error code.
+ */
+ memset(exception, 0, sizeof(*exception));
return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, access,
exception);
}
diff --git a/arch/x86/pci/broadcom_bus.c b/arch/x86/pci/broadcom_bus.c
index 526536c..ca1e8e6 100644
--- a/arch/x86/pci/broadcom_bus.c
+++ b/arch/x86/pci/broadcom_bus.c
@@ -50,8 +50,8 @@
word1 = read_pci_config_16(bus, slot, func, 0xc0);
word2 = read_pci_config_16(bus, slot, func, 0xc2);
if (word1 != word2) {
- res.start = (word1 << 16) | 0x0000;
- res.end = (word2 << 16) | 0xffff;
+ res.start = ((resource_size_t) word1 << 16) | 0x0000;
+ res.end = ((resource_size_t) word2 << 16) | 0xffff;
res.flags = IORESOURCE_MEM;
update_res(info, res.start, res.end, res.flags, 0);
}
diff --git a/arch/x86/platform/uv/bios_uv.c b/arch/x86/platform/uv/bios_uv.c
index 4a6a5a2..eb33432 100644
--- a/arch/x86/platform/uv/bios_uv.c
+++ b/arch/x86/platform/uv/bios_uv.c
@@ -29,7 +29,8 @@
struct uv_systab *uv_systab;
-s64 uv_bios_call(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3, u64 a4, u64 a5)
+static s64 __uv_bios_call(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3,
+ u64 a4, u64 a5)
{
struct uv_systab *tab = uv_systab;
s64 ret;
@@ -51,6 +52,19 @@
return ret;
}
+
+s64 uv_bios_call(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3, u64 a4, u64 a5)
+{
+ s64 ret;
+
+ if (down_interruptible(&__efi_uv_runtime_lock))
+ return BIOS_STATUS_ABORT;
+
+ ret = __uv_bios_call(which, a1, a2, a3, a4, a5);
+ up(&__efi_uv_runtime_lock);
+
+ return ret;
+}
EXPORT_SYMBOL_GPL(uv_bios_call);
s64 uv_bios_call_irqsave(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3,
@@ -59,10 +73,15 @@
unsigned long bios_flags;
s64 ret;
+ if (down_interruptible(&__efi_uv_runtime_lock))
+ return BIOS_STATUS_ABORT;
+
local_irq_save(bios_flags);
- ret = uv_bios_call(which, a1, a2, a3, a4, a5);
+ ret = __uv_bios_call(which, a1, a2, a3, a4, a5);
local_irq_restore(bios_flags);
+ up(&__efi_uv_runtime_lock);
+
return ret;
}
diff --git a/build.config.cuttlefish.aarch64 b/build.config.cuttlefish.aarch64
index e1f750d..7bf19df 100644
--- a/build.config.cuttlefish.aarch64
+++ b/build.config.cuttlefish.aarch64
@@ -6,7 +6,7 @@
EXTRA_CMDS=''
KERNEL_DIR=common
POST_DEFCONFIG_CMDS="check_defconfig"
-CLANG_PREBUILT_BIN=prebuilts-master/clang/host/linux-x86/clang-r346389b/bin
+CLANG_PREBUILT_BIN=prebuilts-master/clang/host/linux-x86/clang-r349610/bin
LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN=prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin
FILES="
arch/arm64/boot/Image.gz
diff --git a/build.config.cuttlefish.x86_64 b/build.config.cuttlefish.x86_64
index f8e85a1..a25afa0 100644
--- a/build.config.cuttlefish.x86_64
+++ b/build.config.cuttlefish.x86_64
@@ -6,7 +6,7 @@
EXTRA_CMDS=''
KERNEL_DIR=common
POST_DEFCONFIG_CMDS="check_defconfig"
-CLANG_PREBUILT_BIN=prebuilts-master/clang/host/linux-x86/clang-r346389b/bin
+CLANG_PREBUILT_BIN=prebuilts-master/clang/host/linux-x86/clang-r349610/bin
LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN=prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/bin
FILES="
arch/x86/boot/bzImage
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index 17b518c..0ea065c 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -147,9 +147,9 @@
{
struct acpi_srat_mem_affinity *p =
(struct acpi_srat_mem_affinity *)header;
- pr_debug("SRAT Memory (0x%lx length 0x%lx) in proximity domain %d %s%s%s\n",
- (unsigned long)p->base_address,
- (unsigned long)p->length,
+ pr_debug("SRAT Memory (0x%llx length 0x%llx) in proximity domain %d %s%s%s\n",
+ (unsigned long long)p->base_address,
+ (unsigned long long)p->length,
p->proximity_domain,
(p->flags & ACPI_SRAT_MEM_ENABLED) ?
"enabled" : "disabled",
diff --git a/drivers/ata/sata_rcar.c b/drivers/ata/sata_rcar.c
index e83a3d3..07e146b 100644
--- a/drivers/ata/sata_rcar.c
+++ b/drivers/ata/sata_rcar.c
@@ -872,7 +872,9 @@
int ret = 0;
irq = platform_get_irq(pdev, 0);
- if (irq <= 0)
+ if (irq < 0)
+ return irq;
+ if (!irq)
return -EINVAL;
priv = devm_kzalloc(&pdev->dev, sizeof(struct sata_rcar_priv),
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index 908c704..b83d6c7 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -668,14 +668,15 @@
if (rv == SS_TWO_PRIMARIES) {
/* Maybe the peer is detected as dead very soon...
retry at most once more in this case. */
- int timeo;
- rcu_read_lock();
- nc = rcu_dereference(connection->net_conf);
- timeo = nc ? (nc->ping_timeo + 1) * HZ / 10 : 1;
- rcu_read_unlock();
- schedule_timeout_interruptible(timeo);
- if (try < max_tries)
+ if (try < max_tries) {
+ int timeo;
try = max_tries - 1;
+ rcu_read_lock();
+ nc = rcu_dereference(connection->net_conf);
+ timeo = nc ? (nc->ping_timeo + 1) * HZ / 10 : 1;
+ rcu_read_unlock();
+ schedule_timeout_interruptible(timeo);
+ }
continue;
}
if (rv < SS_SUCCESS) {
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c
index 942384f..83957a1 100644
--- a/drivers/block/drbd/drbd_receiver.c
+++ b/drivers/block/drbd/drbd_receiver.c
@@ -3421,7 +3421,7 @@
enum drbd_conns rv = C_MASK;
enum drbd_disk_state mydisk;
struct net_conf *nc;
- int hg, rule_nr, rr_conflict, tentative;
+ int hg, rule_nr, rr_conflict, tentative, always_asbp;
mydisk = device->state.disk;
if (mydisk == D_NEGOTIATING)
@@ -3472,8 +3472,12 @@
rcu_read_lock();
nc = rcu_dereference(peer_device->connection->net_conf);
+ always_asbp = nc->always_asbp;
+ rr_conflict = nc->rr_conflict;
+ tentative = nc->tentative;
+ rcu_read_unlock();
- if (hg == 100 || (hg == -100 && nc->always_asbp)) {
+ if (hg == 100 || (hg == -100 && always_asbp)) {
int pcount = (device->state.role == R_PRIMARY)
+ (peer_role == R_PRIMARY);
int forced = (hg == -100);
@@ -3512,9 +3516,6 @@
"Sync from %s node\n",
(hg < 0) ? "peer" : "this");
}
- rr_conflict = nc->rr_conflict;
- tentative = nc->tentative;
- rcu_read_unlock();
if (hg == -100) {
/* FIXME this log message is not correct if we end up here
@@ -4198,7 +4199,7 @@
kfree(device->p_uuid);
device->p_uuid = p_uuid;
- if (device->state.conn < C_CONNECTED &&
+ if ((device->state.conn < C_CONNECTED || device->state.pdsk == D_DISKLESS) &&
device->state.disk < D_INCONSISTENT &&
device->state.role == R_PRIMARY &&
(device->ed_uuid & ~((u64)1)) != (p_uuid[UI_CURRENT] & ~((u64)1))) {
diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c
index cab1573..c6d43a2 100644
--- a/drivers/block/sunvdc.c
+++ b/drivers/block/sunvdc.c
@@ -40,6 +40,8 @@
#define WAITING_FOR_GEN_CMD 0x04
#define WAITING_FOR_ANY -1
+#define VDC_MAX_RETRIES 10
+
static struct workqueue_struct *sunvdc_wq;
struct vdc_req_entry {
@@ -419,6 +421,7 @@
.end_idx = dr->prod,
};
int err, delay;
+ int retries = 0;
hdr.seq = dr->snd_nxt;
delay = 1;
@@ -431,6 +434,8 @@
udelay(delay);
if ((delay <<= 1) > 128)
delay = 128;
+ if (retries++ > VDC_MAX_RETRIES)
+ break;
} while (err == -EAGAIN);
if (err == -ENOTCONN)
diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c
index c264f2d..2e0a9e2 100644
--- a/drivers/block/swim3.c
+++ b/drivers/block/swim3.c
@@ -1027,7 +1027,11 @@
struct swim3 __iomem *sw = fs->swim3;
mutex_lock(&swim3_mutex);
- if (fs->ref_count > 0 && --fs->ref_count == 0) {
+ if (fs->ref_count > 0)
+ --fs->ref_count;
+ else if (fs->ref_count == -1)
+ fs->ref_count = 0;
+ if (fs->ref_count == 0) {
swim3_action(fs, MOTOR_OFF);
out_8(&sw->control_bic, 0xff);
swim3_select(fs, RELAX);
diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c
index e2808fe..1852d19 100644
--- a/drivers/cdrom/gdrom.c
+++ b/drivers/cdrom/gdrom.c
@@ -882,6 +882,7 @@
platform_device_unregister(pd);
platform_driver_unregister(&gdrom_driver);
kfree(gd.toc);
+ kfree(gd.cd_info);
}
module_init(init_gdrom);
diff --git a/drivers/clk/imx/clk-imx6sl.c b/drivers/clk/imx/clk-imx6sl.c
index 5fd4dda..f3d9dc2 100644
--- a/drivers/clk/imx/clk-imx6sl.c
+++ b/drivers/clk/imx/clk-imx6sl.c
@@ -17,6 +17,8 @@
#include "clk.h"
+#define CCDR 0x4
+#define BM_CCM_CCDR_MMDC_CH0_MASK (1 << 17)
#define CCSR 0xc
#define BM_CCSR_PLL1_SW_CLK_SEL (1 << 2)
#define CACRR 0x10
@@ -414,6 +416,10 @@
clks[IMX6SL_CLK_USDHC3] = imx_clk_gate2("usdhc3", "usdhc3_podf", base + 0x80, 6);
clks[IMX6SL_CLK_USDHC4] = imx_clk_gate2("usdhc4", "usdhc4_podf", base + 0x80, 8);
+ /* Ensure the MMDC CH0 handshake is bypassed */
+ writel_relaxed(readl_relaxed(base + CCDR) |
+ BM_CCM_CCDR_MMDC_CH0_MASK, base + CCDR);
+
imx_check_clocks(clks, ARRAY_SIZE(clks));
clk_data.clks = clks;
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a33.c b/drivers/clk/sunxi-ng/ccu-sun8i-a33.c
index e1dc4e5..82add46 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-a33.c
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-a33.c
@@ -362,10 +362,10 @@
static const char * const i2s_parents[] = { "pll-audio-8x", "pll-audio-4x",
"pll-audio-2x", "pll-audio" };
static SUNXI_CCU_MUX_WITH_GATE(i2s0_clk, "i2s0", i2s_parents,
- 0x0b0, 16, 2, BIT(31), 0);
+ 0x0b0, 16, 2, BIT(31), CLK_SET_RATE_PARENT);
static SUNXI_CCU_MUX_WITH_GATE(i2s1_clk, "i2s1", i2s_parents,
- 0x0b4, 16, 2, BIT(31), 0);
+ 0x0b4, 16, 2, BIT(31), CLK_SET_RATE_PARENT);
/* TODO: the parent for most of the USB clocks is not known */
static SUNXI_CCU_GATE(usb_phy0_clk, "usb-phy0", "osc24M",
@@ -442,7 +442,7 @@
static SUNXI_CCU_GATE(ac_dig_clk, "ac-dig", "pll-audio",
0x140, BIT(31), 0);
static SUNXI_CCU_GATE(ac_dig_4x_clk, "ac-dig-4x", "pll-audio-4x",
- 0x140, BIT(30), 0);
+ 0x140, BIT(30), CLK_SET_RATE_PARENT);
static SUNXI_CCU_GATE(avs_clk, "avs", "osc24M",
0x144, BIT(31), 0);
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index c2b811f..4f61266 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -1620,17 +1620,16 @@
{
unsigned int ret_freq = 0;
- if (!cpufreq_driver->get)
+ if (unlikely(policy_is_inactive(policy)) || !cpufreq_driver->get)
return ret_freq;
ret_freq = cpufreq_driver->get(policy->cpu);
/*
- * Updating inactive policies is invalid, so avoid doing that. Also
- * if fast frequency switching is used with the given policy, the check
+ * If fast frequency switching is used with the given policy, the check
* against policy->cur is pointless, so skip it in that case too.
*/
- if (unlikely(policy_is_inactive(policy)) || policy->fast_switch_enabled)
+ if (policy->fast_switch_enabled)
return ret_freq;
if (ret_freq && policy->cur &&
diff --git a/drivers/cpuidle/cpuidle-big_little.c b/drivers/cpuidle/cpuidle-big_little.c
index db2ede5..b44476a 100644
--- a/drivers/cpuidle/cpuidle-big_little.c
+++ b/drivers/cpuidle/cpuidle-big_little.c
@@ -167,6 +167,7 @@
{
int ret;
struct device_node *root = of_find_node_by_path("/");
+ const struct of_device_id *match_id;
if (!root)
return -ENODEV;
@@ -174,7 +175,11 @@
/*
* Initialize the driver just for a compliant set of machines
*/
- if (!of_match_node(compatible_machine_match, root))
+ match_id = of_match_node(compatible_machine_match, root);
+
+ of_node_put(root);
+
+ if (!match_id)
return -ENODEV;
if (!mcpm_is_available())
diff --git a/drivers/crypto/ux500/cryp/cryp_core.c b/drivers/crypto/ux500/cryp/cryp_core.c
index 790f7ca..efebc484 100644
--- a/drivers/crypto/ux500/cryp/cryp_core.c
+++ b/drivers/crypto/ux500/cryp/cryp_core.c
@@ -555,7 +555,7 @@
desc = dmaengine_prep_slave_sg(channel,
ctx->device->dma.sg_src,
ctx->device->dma.sg_src_len,
- direction, DMA_CTRL_ACK);
+ DMA_MEM_TO_DEV, DMA_CTRL_ACK);
break;
case DMA_FROM_DEVICE:
@@ -579,7 +579,7 @@
desc = dmaengine_prep_slave_sg(channel,
ctx->device->dma.sg_dst,
ctx->device->dma.sg_dst_len,
- direction,
+ DMA_DEV_TO_MEM,
DMA_CTRL_ACK |
DMA_PREP_INTERRUPT);
diff --git a/drivers/crypto/ux500/hash/hash_core.c b/drivers/crypto/ux500/hash/hash_core.c
index 9acccad..17c8e2b 100644
--- a/drivers/crypto/ux500/hash/hash_core.c
+++ b/drivers/crypto/ux500/hash/hash_core.c
@@ -165,7 +165,7 @@
__func__);
desc = dmaengine_prep_slave_sg(channel,
ctx->device->dma.sg, ctx->device->dma.sg_len,
- direction, DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
+ DMA_MEM_TO_DEV, DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
if (!desc) {
dev_err(ctx->device->dev,
"%s: dmaengine_prep_slave_sg() failed!\n", __func__);
diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c
index 6204cc3..6ba53bb 100644
--- a/drivers/dma/bcm2835-dma.c
+++ b/drivers/dma/bcm2835-dma.c
@@ -415,38 +415,32 @@
}
}
-static int bcm2835_dma_abort(void __iomem *chan_base)
+static int bcm2835_dma_abort(struct bcm2835_chan *c)
{
- unsigned long cs;
+ void __iomem *chan_base = c->chan_base;
long int timeout = 10000;
- cs = readl(chan_base + BCM2835_DMA_CS);
- if (!(cs & BCM2835_DMA_ACTIVE))
+ /*
+ * A zero control block address means the channel is idle.
+ * (The ACTIVE flag in the CS register is not a reliable indicator.)
+ */
+ if (!readl(chan_base + BCM2835_DMA_ADDR))
return 0;
/* Write 0 to the active bit - Pause the DMA */
writel(0, chan_base + BCM2835_DMA_CS);
/* Wait for any current AXI transfer to complete */
- while ((cs & BCM2835_DMA_ISPAUSED) && --timeout) {
+ while ((readl(chan_base + BCM2835_DMA_CS) &
+ BCM2835_DMA_WAITING_FOR_WRITES) && --timeout)
cpu_relax();
- cs = readl(chan_base + BCM2835_DMA_CS);
- }
- /* We'll un-pause when we set of our next DMA */
+ /* Peripheral might be stuck and fail to signal AXI write responses */
if (!timeout)
- return -ETIMEDOUT;
+ dev_err(c->vc.chan.device->dev,
+ "failed to complete outstanding writes\n");
- if (!(cs & BCM2835_DMA_ACTIVE))
- return 0;
-
- /* Terminate the control block chain */
- writel(0, chan_base + BCM2835_DMA_NEXTCB);
-
- /* Abort the whole DMA */
- writel(BCM2835_DMA_ABORT | BCM2835_DMA_ACTIVE,
- chan_base + BCM2835_DMA_CS);
-
+ writel(BCM2835_DMA_RESET, chan_base + BCM2835_DMA_CS);
return 0;
}
@@ -485,8 +479,15 @@
spin_lock_irqsave(&c->vc.lock, flags);
- /* Acknowledge interrupt */
- writel(BCM2835_DMA_INT, c->chan_base + BCM2835_DMA_CS);
+ /*
+ * Clear the INT flag to receive further interrupts. Keep the channel
+ * active in case the descriptor is cyclic or in case the client has
+ * already terminated the descriptor and issued a new one. (May happen
+ * if this IRQ handler is threaded.) If the channel is finished, it
+ * will remain idle despite the ACTIVE flag being set.
+ */
+ writel(BCM2835_DMA_INT | BCM2835_DMA_ACTIVE,
+ c->chan_base + BCM2835_DMA_CS);
d = c->desc;
@@ -494,11 +495,7 @@
if (d->cyclic) {
/* call the cyclic callback */
vchan_cyclic_callback(&d->vd);
-
- /* Keep the DMA engine running */
- writel(BCM2835_DMA_ACTIVE,
- c->chan_base + BCM2835_DMA_CS);
- } else {
+ } else if (!readl(c->chan_base + BCM2835_DMA_ADDR)) {
vchan_cookie_complete(&c->desc->vd);
bcm2835_dma_start_desc(c);
}
@@ -796,7 +793,6 @@
struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
struct bcm2835_dmadev *d = to_bcm2835_dma_dev(c->vc.chan.device);
unsigned long flags;
- int timeout = 10000;
LIST_HEAD(head);
spin_lock_irqsave(&c->vc.lock, flags);
@@ -806,27 +802,11 @@
list_del_init(&c->node);
spin_unlock(&d->lock);
- /*
- * Stop DMA activity: we assume the callback will not be called
- * after bcm_dma_abort() returns (even if it does, it will see
- * c->desc is NULL and exit.)
- */
+ /* stop DMA activity */
if (c->desc) {
bcm2835_dma_desc_free(&c->desc->vd);
c->desc = NULL;
- bcm2835_dma_abort(c->chan_base);
-
- /* Wait for stopping */
- while (--timeout) {
- if (!(readl(c->chan_base + BCM2835_DMA_CS) &
- BCM2835_DMA_ACTIVE))
- break;
-
- cpu_relax();
- }
-
- if (!timeout)
- dev_err(d->ddev.dev, "DMA transfer could not be terminated\n");
+ bcm2835_dma_abort(c);
}
vchan_get_all_descriptors(&c->vc, &head);
diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c
index ab0fb80..1cfa1d9 100644
--- a/drivers/dma/imx-dma.c
+++ b/drivers/dma/imx-dma.c
@@ -623,7 +623,7 @@
{
struct imxdma_channel *imxdmac = (void *)data;
struct imxdma_engine *imxdma = imxdmac->imxdma;
- struct imxdma_desc *desc;
+ struct imxdma_desc *desc, *next_desc;
unsigned long flags;
spin_lock_irqsave(&imxdma->lock, flags);
@@ -653,10 +653,10 @@
list_move_tail(imxdmac->ld_active.next, &imxdmac->ld_free);
if (!list_empty(&imxdmac->ld_queue)) {
- desc = list_first_entry(&imxdmac->ld_queue, struct imxdma_desc,
- node);
+ next_desc = list_first_entry(&imxdmac->ld_queue,
+ struct imxdma_desc, node);
list_move_tail(imxdmac->ld_queue.next, &imxdmac->ld_active);
- if (imxdma_xfer_desc(desc) < 0)
+ if (imxdma_xfer_desc(next_desc) < 0)
dev_warn(imxdma->dev, "%s: channel: %d couldn't xfer desc\n",
__func__, imxdmac->channel);
}
diff --git a/drivers/dma/xilinx/zynqmp_dma.c b/drivers/dma/xilinx/zynqmp_dma.c
index 2265805..9069fb8 100644
--- a/drivers/dma/xilinx/zynqmp_dma.c
+++ b/drivers/dma/xilinx/zynqmp_dma.c
@@ -159,7 +159,7 @@
u32 ctrl;
u64 nxtdscraddr;
u64 rsvd;
-}; __aligned(64)
+};
/**
* struct zynqmp_dma_desc_sw - Per Transaction structure
diff --git a/drivers/firmware/efi/runtime-wrappers.c b/drivers/firmware/efi/runtime-wrappers.c
index ae54870b..dd7f633 100644
--- a/drivers/firmware/efi/runtime-wrappers.c
+++ b/drivers/firmware/efi/runtime-wrappers.c
@@ -50,6 +50,13 @@
}
/*
+ * Expose the EFI runtime lock to the UV platform
+ */
+#ifdef CONFIG_X86_UV
+extern struct semaphore __efi_uv_runtime_lock __alias(efi_runtime_lock);
+#endif
+
+/*
* According to section 7.1 of the UEFI spec, Runtime Services are not fully
* reentrant, and there are particular combinations of calls that need to be
* serialized. (source: UEFI Specification v2.4A)
diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c
index 9336ffd..fceaafd 100644
--- a/drivers/firmware/efi/vars.c
+++ b/drivers/firmware/efi/vars.c
@@ -318,7 +318,12 @@
static efi_status_t
check_var_size(u32 attributes, unsigned long size)
{
- const struct efivar_operations *fops = __efivars->ops;
+ const struct efivar_operations *fops;
+
+ if (!__efivars)
+ return EFI_UNSUPPORTED;
+
+ fops = __efivars->ops;
if (!fops->query_variable_store)
return EFI_UNSUPPORTED;
@@ -329,7 +334,12 @@
static efi_status_t
check_var_size_nonblocking(u32 attributes, unsigned long size)
{
- const struct efivar_operations *fops = __efivars->ops;
+ const struct efivar_operations *fops;
+
+ if (!__efivars)
+ return EFI_UNSUPPORTED;
+
+ fops = __efivars->ops;
if (!fops->query_variable_store)
return EFI_UNSUPPORTED;
@@ -429,13 +439,18 @@
int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *),
void *data, bool duplicates, struct list_head *head)
{
- const struct efivar_operations *ops = __efivars->ops;
+ const struct efivar_operations *ops;
unsigned long variable_name_size = 1024;
efi_char16_t *variable_name;
efi_status_t status;
efi_guid_t vendor_guid;
int err = 0;
+ if (!__efivars)
+ return -EFAULT;
+
+ ops = __efivars->ops;
+
variable_name = kzalloc(variable_name_size, GFP_KERNEL);
if (!variable_name) {
printk(KERN_ERR "efivars: Memory allocation failed.\n");
@@ -583,12 +598,14 @@
*/
int __efivar_entry_delete(struct efivar_entry *entry)
{
- const struct efivar_operations *ops = __efivars->ops;
efi_status_t status;
- status = ops->set_variable(entry->var.VariableName,
- &entry->var.VendorGuid,
- 0, 0, NULL);
+ if (!__efivars)
+ return -EINVAL;
+
+ status = __efivars->ops->set_variable(entry->var.VariableName,
+ &entry->var.VendorGuid,
+ 0, 0, NULL);
return efi_status_to_err(status);
}
@@ -607,12 +624,17 @@
*/
int efivar_entry_delete(struct efivar_entry *entry)
{
- const struct efivar_operations *ops = __efivars->ops;
+ const struct efivar_operations *ops;
efi_status_t status;
if (down_interruptible(&efivars_lock))
return -EINTR;
+ if (!__efivars) {
+ up(&efivars_lock);
+ return -EINVAL;
+ }
+ ops = __efivars->ops;
status = ops->set_variable(entry->var.VariableName,
&entry->var.VendorGuid,
0, 0, NULL);
@@ -650,13 +672,19 @@
int efivar_entry_set(struct efivar_entry *entry, u32 attributes,
unsigned long size, void *data, struct list_head *head)
{
- const struct efivar_operations *ops = __efivars->ops;
+ const struct efivar_operations *ops;
efi_status_t status;
efi_char16_t *name = entry->var.VariableName;
efi_guid_t vendor = entry->var.VendorGuid;
if (down_interruptible(&efivars_lock))
return -EINTR;
+
+ if (!__efivars) {
+ up(&efivars_lock);
+ return -EINVAL;
+ }
+ ops = __efivars->ops;
if (head && efivar_entry_find(name, vendor, head, false)) {
up(&efivars_lock);
return -EEXIST;
@@ -687,12 +715,17 @@
efivar_entry_set_nonblocking(efi_char16_t *name, efi_guid_t vendor,
u32 attributes, unsigned long size, void *data)
{
- const struct efivar_operations *ops = __efivars->ops;
+ const struct efivar_operations *ops;
efi_status_t status;
if (down_trylock(&efivars_lock))
return -EBUSY;
+ if (!__efivars) {
+ up(&efivars_lock);
+ return -EINVAL;
+ }
+
status = check_var_size_nonblocking(attributes,
size + ucs2_strsize(name, 1024));
if (status != EFI_SUCCESS) {
@@ -700,6 +733,7 @@
return -ENOSPC;
}
+ ops = __efivars->ops;
status = ops->set_variable_nonblocking(name, &vendor, attributes,
size, data);
@@ -727,9 +761,13 @@
int efivar_entry_set_safe(efi_char16_t *name, efi_guid_t vendor, u32 attributes,
bool block, unsigned long size, void *data)
{
- const struct efivar_operations *ops = __efivars->ops;
+ const struct efivar_operations *ops;
efi_status_t status;
+ if (!__efivars)
+ return -EINVAL;
+
+ ops = __efivars->ops;
if (!ops->query_variable_store)
return -ENOSYS;
@@ -829,13 +867,18 @@
*/
int efivar_entry_size(struct efivar_entry *entry, unsigned long *size)
{
- const struct efivar_operations *ops = __efivars->ops;
+ const struct efivar_operations *ops;
efi_status_t status;
*size = 0;
if (down_interruptible(&efivars_lock))
return -EINTR;
+ if (!__efivars) {
+ up(&efivars_lock);
+ return -EINVAL;
+ }
+ ops = __efivars->ops;
status = ops->get_variable(entry->var.VariableName,
&entry->var.VendorGuid, NULL, size, NULL);
up(&efivars_lock);
@@ -861,12 +904,14 @@
int __efivar_entry_get(struct efivar_entry *entry, u32 *attributes,
unsigned long *size, void *data)
{
- const struct efivar_operations *ops = __efivars->ops;
efi_status_t status;
- status = ops->get_variable(entry->var.VariableName,
- &entry->var.VendorGuid,
- attributes, size, data);
+ if (!__efivars)
+ return -EINVAL;
+
+ status = __efivars->ops->get_variable(entry->var.VariableName,
+ &entry->var.VendorGuid,
+ attributes, size, data);
return efi_status_to_err(status);
}
@@ -882,14 +927,19 @@
int efivar_entry_get(struct efivar_entry *entry, u32 *attributes,
unsigned long *size, void *data)
{
- const struct efivar_operations *ops = __efivars->ops;
efi_status_t status;
if (down_interruptible(&efivars_lock))
return -EINTR;
- status = ops->get_variable(entry->var.VariableName,
- &entry->var.VendorGuid,
- attributes, size, data);
+
+ if (!__efivars) {
+ up(&efivars_lock);
+ return -EINVAL;
+ }
+
+ status = __efivars->ops->get_variable(entry->var.VariableName,
+ &entry->var.VendorGuid,
+ attributes, size, data);
up(&efivars_lock);
return efi_status_to_err(status);
@@ -921,7 +971,7 @@
int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes,
unsigned long *size, void *data, bool *set)
{
- const struct efivar_operations *ops = __efivars->ops;
+ const struct efivar_operations *ops;
efi_char16_t *name = entry->var.VariableName;
efi_guid_t *vendor = &entry->var.VendorGuid;
efi_status_t status;
@@ -940,6 +990,11 @@
if (down_interruptible(&efivars_lock))
return -EINTR;
+ if (!__efivars) {
+ err = -EINVAL;
+ goto out;
+ }
+
/*
* Ensure that the available space hasn't shrunk below the safe level
*/
@@ -956,6 +1011,8 @@
}
}
+ ops = __efivars->ops;
+
status = ops->set_variable(name, vendor, attributes, *size, data);
if (status != EFI_SUCCESS) {
err = efi_status_to_err(status);
diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
index f64f35c..fa3f2f0 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -96,6 +96,8 @@
#define DP0_STARTVAL 0x064c
#define DP0_ACTIVEVAL 0x0650
#define DP0_SYNCVAL 0x0654
+#define SYNCVAL_HS_POL_ACTIVE_LOW (1 << 15)
+#define SYNCVAL_VS_POL_ACTIVE_LOW (1 << 31)
#define DP0_MISC 0x0658
#define TU_SIZE_RECOMMENDED (63) /* LSCLK cycles per TU */
#define BPC_6 (0 << 5)
@@ -140,6 +142,8 @@
#define DP0_LTLOOPCTRL 0x06d8
#define DP0_SNKLTCTRL 0x06e4
+#define DP1_SRCCTRL 0x07a0
+
/* PHY */
#define DP_PHY_CTRL 0x0800
#define DP_PHY_RST BIT(28) /* DP PHY Global Soft Reset */
@@ -148,6 +152,7 @@
#define PHY_M1_RST BIT(12) /* Reset PHY1 Main Channel */
#define PHY_RDY BIT(16) /* PHY Main Channels Ready */
#define PHY_M0_RST BIT(8) /* Reset PHY0 Main Channel */
+#define PHY_2LANE BIT(2) /* PHY Enable 2 lanes */
#define PHY_A0_EN BIT(1) /* PHY Aux Channel0 Enable */
#define PHY_M0_EN BIT(0) /* PHY Main Channel0 Enable */
@@ -538,6 +543,7 @@
unsigned long rate;
u32 value;
int ret;
+ u32 dp_phy_ctrl;
rate = clk_get_rate(tc->refclk);
switch (rate) {
@@ -562,7 +568,10 @@
value |= SYSCLK_SEL_LSCLK | LSCLK_DIV_2;
tc_write(SYS_PLLPARAM, value);
- tc_write(DP_PHY_CTRL, BGREN | PWR_SW_EN | BIT(2) | PHY_A0_EN);
+ dp_phy_ctrl = BGREN | PWR_SW_EN | PHY_A0_EN;
+ if (tc->link.base.num_lanes == 2)
+ dp_phy_ctrl |= PHY_2LANE;
+ tc_write(DP_PHY_CTRL, dp_phy_ctrl);
/*
* Initially PLLs are in bypass. Force PLL parameter update,
@@ -717,7 +726,9 @@
tc_write(DP0_ACTIVEVAL, (mode->vdisplay << 16) | (mode->hdisplay));
- tc_write(DP0_SYNCVAL, (vsync_len << 16) | (hsync_len << 0));
+ tc_write(DP0_SYNCVAL, (vsync_len << 16) | (hsync_len << 0) |
+ ((mode->flags & DRM_MODE_FLAG_NHSYNC) ? SYNCVAL_HS_POL_ACTIVE_LOW : 0) |
+ ((mode->flags & DRM_MODE_FLAG_NVSYNC) ? SYNCVAL_VS_POL_ACTIVE_LOW : 0));
tc_write(DPIPXLFMT, VS_POL_ACTIVE_LOW | HS_POL_ACTIVE_LOW |
DE_POL_ACTIVE_HIGH | SUB_CFG_TYPE_CONFIG1 | DPI_BPP_RGB888);
@@ -827,12 +838,11 @@
if (!tc->mode)
return -EINVAL;
- /* from excel file - DP0_SrcCtrl */
- tc_write(DP0_SRCCTRL, DP0_SRCCTRL_SCRMBLDIS | DP0_SRCCTRL_EN810B |
- DP0_SRCCTRL_LANESKEW | DP0_SRCCTRL_LANES_2 |
- DP0_SRCCTRL_BW27 | DP0_SRCCTRL_AUTOCORRECT);
- /* from excel file - DP1_SrcCtrl */
- tc_write(0x07a0, 0x00003083);
+ tc_write(DP0_SRCCTRL, tc_srcctrl(tc));
+ /* SSCG and BW27 on DP1 must be set to the same as on DP0 */
+ tc_write(DP1_SRCCTRL,
+ (tc->link.spread ? DP0_SRCCTRL_SSCG : 0) |
+ ((tc->link.base.rate != 162000) ? DP0_SRCCTRL_BW27 : 0));
rate = clk_get_rate(tc->refclk);
switch (rate) {
@@ -853,8 +863,11 @@
}
value |= SYSCLK_SEL_LSCLK | LSCLK_DIV_2;
tc_write(SYS_PLLPARAM, value);
+
/* Setup Main Link */
- dp_phy_ctrl = BGREN | PWR_SW_EN | BIT(2) | PHY_A0_EN | PHY_M0_EN;
+ dp_phy_ctrl = BGREN | PWR_SW_EN | PHY_A0_EN | PHY_M0_EN;
+ if (tc->link.base.num_lanes == 2)
+ dp_phy_ctrl |= PHY_2LANE;
tc_write(DP_PHY_CTRL, dp_phy_ctrl);
msleep(100);
@@ -1109,10 +1122,20 @@
static int tc_connector_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
+ struct tc_data *tc = connector_to_tc(connector);
+ u32 req, avail;
+ u32 bits_per_pixel = 24;
+
/* DPI interface clock limitation: upto 154 MHz */
if (mode->clock > 154000)
return MODE_CLOCK_HIGH;
+ req = mode->clock * bits_per_pixel / 8;
+ avail = tc->link.base.num_lanes * tc->link.base.rate;
+
+ if (req > avail)
+ return MODE_BAD;
+
return MODE_OK;
}
diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c
index adb1dd7..9ccd7d7 100644
--- a/drivers/gpu/drm/drm_bufs.c
+++ b/drivers/gpu/drm/drm_bufs.c
@@ -36,6 +36,8 @@
#include <drm/drmP.h>
#include "drm_legacy.h"
+#include <linux/nospec.h>
+
static struct drm_map_list *drm_find_matching_map(struct drm_device *dev,
struct drm_local_map *map)
{
@@ -1413,6 +1415,7 @@
idx, dma->buf_count - 1);
return -EINVAL;
}
+ idx = array_index_nospec(idx, dma->buf_count);
buf = dma->buflist[idx];
if (buf->file_priv != file_priv) {
DRM_ERROR("Process %d freeing buffer not owned\n",
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index e14366d..97387cf 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -753,7 +753,7 @@
if (mode->hsync)
return mode->hsync;
- if (mode->htotal < 0)
+ if (mode->htotal <= 0)
return 0;
calc_val = (mode->clock * 1000) / mode->htotal; /* hsync in Hz */
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 7b203092..6509031 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1593,6 +1593,16 @@
return err;
}
+static inline bool
+__vma_matches(struct vm_area_struct *vma, struct file *filp,
+ unsigned long addr, unsigned long size)
+{
+ if (vma->vm_file != filp)
+ return false;
+
+ return vma->vm_start == addr && (vma->vm_end - vma->vm_start) == size;
+}
+
/**
* i915_gem_mmap_ioctl - Maps the contents of an object, returning the address
* it is mapped to.
@@ -1651,7 +1661,7 @@
return -EINTR;
}
vma = find_vma(mm, addr);
- if (vma)
+ if (vma && __vma_matches(vma, obj->base.filp, addr, args->size))
vma->vm_page_prot =
pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
else
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
index 70051bf..0376c0c 100644
--- a/drivers/gpu/drm/vc4/vc4_plane.c
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
@@ -345,12 +345,14 @@
vc4_get_scaling_mode(vc4_state->src_h[1],
vc4_state->crtc_h);
- /* YUV conversion requires that horizontal scaling be enabled,
- * even on a plane that's otherwise 1:1. Looks like only PPF
- * works in that case, so let's pick that one.
+ /* YUV conversion requires that horizontal scaling be enabled
+ * on the UV plane even if vc4_get_scaling_mode() returned
+ * VC4_SCALING_NONE (which can happen when the down-scaling
+ * ratio is 0.5). Let's force it to VC4_SCALING_PPF in this
+ * case.
*/
- if (vc4_state->is_unity)
- vc4_state->x_scaling[0] = VC4_SCALING_PPF;
+ if (vc4_state->x_scaling[1] == VC4_SCALING_NONE)
+ vc4_state->x_scaling[1] = VC4_SCALING_PPF;
} else {
vc4_state->is_yuv = false;
vc4_state->x_scaling[1] = VC4_SCALING_NONE;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index 29abd28..4b556e6 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -605,13 +605,16 @@
static int vmw_dma_masks(struct vmw_private *dev_priv)
{
struct drm_device *dev = dev_priv->dev;
+ int ret = 0;
- if (intel_iommu_enabled &&
+ ret = dma_set_mask_and_coherent(dev->dev, DMA_BIT_MASK(64));
+ if (dev_priv->map_mode != vmw_dma_phys &&
(sizeof(unsigned long) == 4 || vmw_restrict_dma_mask)) {
DRM_INFO("Restricting DMA addresses to 44 bits.\n");
- return dma_set_mask(dev->dev, DMA_BIT_MASK(44));
+ return dma_set_mask_and_coherent(dev->dev, DMA_BIT_MASK(44));
}
- return 0;
+
+ return ret;
}
#else
static int vmw_dma_masks(struct vmw_private *dev_priv)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
index 81f5a55..9fe8eda 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
@@ -3769,7 +3769,7 @@
*p_fence = NULL;
}
- return 0;
+ return ret;
}
/**
diff --git a/drivers/gpu/ipu-v3/ipu-image-convert.c b/drivers/gpu/ipu-v3/ipu-image-convert.c
index 805b6fa..50b73f3 100644
--- a/drivers/gpu/ipu-v3/ipu-image-convert.c
+++ b/drivers/gpu/ipu-v3/ipu-image-convert.c
@@ -1513,7 +1513,7 @@
EXPORT_SYMBOL_GPL(ipu_image_convert_queue);
/* Abort any active or pending conversions for this context */
-void ipu_image_convert_abort(struct ipu_image_convert_ctx *ctx)
+static void __ipu_image_convert_abort(struct ipu_image_convert_ctx *ctx)
{
struct ipu_image_convert_chan *chan = ctx->chan;
struct ipu_image_convert_priv *priv = chan->priv;
@@ -1540,7 +1540,7 @@
need_abort = (run_count || active_run);
- ctx->aborting = need_abort;
+ ctx->aborting = true;
spin_unlock_irqrestore(&chan->irqlock, flags);
@@ -1561,7 +1561,11 @@
dev_warn(priv->ipu->dev, "%s: timeout\n", __func__);
force_abort(ctx);
}
+}
+void ipu_image_convert_abort(struct ipu_image_convert_ctx *ctx)
+{
+ __ipu_image_convert_abort(ctx);
ctx->aborting = false;
}
EXPORT_SYMBOL_GPL(ipu_image_convert_abort);
@@ -1575,7 +1579,7 @@
bool put_res;
/* make sure no runs are hanging around */
- ipu_image_convert_abort(ctx);
+ __ipu_image_convert_abort(ctx);
dev_dbg(priv->ipu->dev, "%s: task %u: removing ctx %p\n", __func__,
chan->ic_task, ctx);
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
index 2942369..d7179dd 100644
--- a/drivers/hid/hid-debug.c
+++ b/drivers/hid/hid-debug.c
@@ -30,6 +30,7 @@
#include <linux/debugfs.h>
#include <linux/seq_file.h>
+#include <linux/kfifo.h>
#include <linux/sched.h>
#include <linux/export.h>
#include <linux/slab.h>
@@ -455,7 +456,7 @@
char *buf = NULL;
if (!f) {
- buf = kzalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_ATOMIC);
+ buf = kzalloc(HID_DEBUG_BUFSIZE, GFP_ATOMIC);
if (!buf)
return ERR_PTR(-ENOMEM);
}
@@ -659,17 +660,12 @@
/* enqueue string to 'events' ring buffer */
void hid_debug_event(struct hid_device *hdev, char *buf)
{
- unsigned i;
struct hid_debug_list *list;
unsigned long flags;
spin_lock_irqsave(&hdev->debug_list_lock, flags);
- list_for_each_entry(list, &hdev->debug_list, node) {
- for (i = 0; buf[i]; i++)
- list->hid_debug_buf[(list->tail + i) % HID_DEBUG_BUFSIZE] =
- buf[i];
- list->tail = (list->tail + i) % HID_DEBUG_BUFSIZE;
- }
+ list_for_each_entry(list, &hdev->debug_list, node)
+ kfifo_in(&list->hid_debug_fifo, buf, strlen(buf));
spin_unlock_irqrestore(&hdev->debug_list_lock, flags);
wake_up_interruptible(&hdev->debug_wait);
@@ -720,8 +716,7 @@
hid_debug_event(hdev, buf);
kfree(buf);
- wake_up_interruptible(&hdev->debug_wait);
-
+ wake_up_interruptible(&hdev->debug_wait);
}
EXPORT_SYMBOL_GPL(hid_dump_input);
@@ -1086,8 +1081,8 @@
goto out;
}
- if (!(list->hid_debug_buf = kzalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_KERNEL))) {
- err = -ENOMEM;
+ err = kfifo_alloc(&list->hid_debug_fifo, HID_DEBUG_FIFOSIZE, GFP_KERNEL);
+ if (err) {
kfree(list);
goto out;
}
@@ -1107,77 +1102,57 @@
size_t count, loff_t *ppos)
{
struct hid_debug_list *list = file->private_data;
- int ret = 0, len;
+ int ret = 0, copied;
DECLARE_WAITQUEUE(wait, current);
mutex_lock(&list->read_mutex);
- while (ret == 0) {
- if (list->head == list->tail) {
- add_wait_queue(&list->hdev->debug_wait, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
+ if (kfifo_is_empty(&list->hid_debug_fifo)) {
+ add_wait_queue(&list->hdev->debug_wait, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
- while (list->head == list->tail) {
- if (file->f_flags & O_NONBLOCK) {
- ret = -EAGAIN;
- break;
- }
- if (signal_pending(current)) {
- ret = -ERESTARTSYS;
- break;
- }
-
- if (!list->hdev || !list->hdev->debug) {
- ret = -EIO;
- set_current_state(TASK_RUNNING);
- goto out;
- }
-
- /* allow O_NONBLOCK from other threads */
- mutex_unlock(&list->read_mutex);
- schedule();
- mutex_lock(&list->read_mutex);
- set_current_state(TASK_INTERRUPTIBLE);
+ while (kfifo_is_empty(&list->hid_debug_fifo)) {
+ if (file->f_flags & O_NONBLOCK) {
+ ret = -EAGAIN;
+ break;
}
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&list->hdev->debug_wait, &wait);
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+
+ /* if list->hdev is NULL we cannot remove_wait_queue().
+ * if list->hdev->debug is 0 then hid_debug_unregister()
+ * was already called and list->hdev is being destroyed.
+ * if we add remove_wait_queue() here we can hit a race.
+ */
+ if (!list->hdev || !list->hdev->debug) {
+ ret = -EIO;
+ set_current_state(TASK_RUNNING);
+ goto out;
+ }
+
+ /* allow O_NONBLOCK from other threads */
+ mutex_unlock(&list->read_mutex);
+ schedule();
+ mutex_lock(&list->read_mutex);
+ set_current_state(TASK_INTERRUPTIBLE);
}
+ __set_current_state(TASK_RUNNING);
+ remove_wait_queue(&list->hdev->debug_wait, &wait);
+
if (ret)
goto out;
-
- /* pass the ringbuffer contents to userspace */
-copy_rest:
- if (list->tail == list->head)
- goto out;
- if (list->tail > list->head) {
- len = list->tail - list->head;
- if (len > count)
- len = count;
-
- if (copy_to_user(buffer + ret, &list->hid_debug_buf[list->head], len)) {
- ret = -EFAULT;
- goto out;
- }
- ret += len;
- list->head += len;
- } else {
- len = HID_DEBUG_BUFSIZE - list->head;
- if (len > count)
- len = count;
-
- if (copy_to_user(buffer, &list->hid_debug_buf[list->head], len)) {
- ret = -EFAULT;
- goto out;
- }
- list->head = 0;
- ret += len;
- count -= len;
- if (count > 0)
- goto copy_rest;
- }
-
}
+
+ /* pass the fifo content to userspace, locking is not needed with only
+ * one concurrent reader and one concurrent writer
+ */
+ ret = kfifo_to_user(&list->hid_debug_fifo, buffer, count, &copied);
+ if (ret)
+ goto out;
+ ret = copied;
out:
mutex_unlock(&list->read_mutex);
return ret;
@@ -1188,7 +1163,7 @@
struct hid_debug_list *list = file->private_data;
poll_wait(file, &list->hdev->debug_wait, wait);
- if (list->head != list->tail)
+ if (!kfifo_is_empty(&list->hid_debug_fifo))
return POLLIN | POLLRDNORM;
if (!list->hdev->debug)
return POLLERR | POLLHUP;
@@ -1203,7 +1178,7 @@
spin_lock_irqsave(&list->hdev->debug_list_lock, flags);
list_del(&list->node);
spin_unlock_irqrestore(&list->hdev->debug_list_lock, flags);
- kfree(list->hid_debug_buf);
+ kfifo_free(&list->hid_debug_fifo);
kfree(list);
return 0;
@@ -1254,4 +1229,3 @@
{
debugfs_remove_recursive(hid_debug_root);
}
-
diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c
index 1ac4ff4..d409cc8 100644
--- a/drivers/hid/hid-lenovo.c
+++ b/drivers/hid/hid-lenovo.c
@@ -713,7 +713,9 @@
data_pointer->led_mute.brightness_get = lenovo_led_brightness_get_tpkbd;
data_pointer->led_mute.brightness_set = lenovo_led_brightness_set_tpkbd;
data_pointer->led_mute.dev = dev;
- led_classdev_register(dev, &data_pointer->led_mute);
+ ret = led_classdev_register(dev, &data_pointer->led_mute);
+ if (ret < 0)
+ goto err;
data_pointer->led_micmute.name = name_micmute;
data_pointer->led_micmute.brightness_get =
@@ -721,7 +723,11 @@
data_pointer->led_micmute.brightness_set =
lenovo_led_brightness_set_tpkbd;
data_pointer->led_micmute.dev = dev;
- led_classdev_register(dev, &data_pointer->led_micmute);
+ ret = led_classdev_register(dev, &data_pointer->led_micmute);
+ if (ret < 0) {
+ led_classdev_unregister(&data_pointer->led_mute);
+ goto err;
+ }
lenovo_features_set_tpkbd(hdev);
diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c
index 4bcd9b8..be60bd5 100644
--- a/drivers/hwmon/lm80.c
+++ b/drivers/hwmon/lm80.c
@@ -360,9 +360,11 @@
struct i2c_client *client = data->client;
unsigned long min, val;
u8 reg;
- int err = kstrtoul(buf, 10, &val);
- if (err < 0)
- return err;
+ int rv;
+
+ rv = kstrtoul(buf, 10, &val);
+ if (rv < 0)
+ return rv;
/* Save fan_min */
mutex_lock(&data->update_lock);
@@ -390,8 +392,13 @@
return -EINVAL;
}
- reg = (lm80_read_value(client, LM80_REG_FANDIV) &
- ~(3 << (2 * (nr + 1)))) | (data->fan_div[nr] << (2 * (nr + 1)));
+ rv = lm80_read_value(client, LM80_REG_FANDIV);
+ if (rv < 0) {
+ mutex_unlock(&data->update_lock);
+ return rv;
+ }
+ reg = (rv & ~(3 << (2 * (nr + 1))))
+ | (data->fan_div[nr] << (2 * (nr + 1)));
lm80_write_value(client, LM80_REG_FANDIV, reg);
/* Restore fan_min */
@@ -623,6 +630,7 @@
struct device *dev = &client->dev;
struct device *hwmon_dev;
struct lm80_data *data;
+ int rv;
data = devm_kzalloc(dev, sizeof(struct lm80_data), GFP_KERNEL);
if (!data)
@@ -635,8 +643,14 @@
lm80_init_client(client);
/* A few vars need to be filled upon startup */
- data->fan[f_min][0] = lm80_read_value(client, LM80_REG_FAN_MIN(1));
- data->fan[f_min][1] = lm80_read_value(client, LM80_REG_FAN_MIN(2));
+ rv = lm80_read_value(client, LM80_REG_FAN_MIN(1));
+ if (rv < 0)
+ return rv;
+ data->fan[f_min][0] = rv;
+ rv = lm80_read_value(client, LM80_REG_FAN_MIN(2));
+ if (rv < 0)
+ return rv;
+ data->fan[f_min][1] = rv;
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
data, lm80_groups);
diff --git a/drivers/i2c/busses/i2c-axxia.c b/drivers/i2c/busses/i2c-axxia.c
index 96a6d5d..b096289 100644
--- a/drivers/i2c/busses/i2c-axxia.c
+++ b/drivers/i2c/busses/i2c-axxia.c
@@ -296,22 +296,7 @@
i2c_int_disable(idev, MST_STATUS_TFL);
}
- if (status & MST_STATUS_SCC) {
- /* Stop completed */
- i2c_int_disable(idev, ~MST_STATUS_TSS);
- complete(&idev->msg_complete);
- } else if (status & MST_STATUS_SNS) {
- /* Transfer done */
- i2c_int_disable(idev, ~MST_STATUS_TSS);
- if (i2c_m_rd(idev->msg) && idev->msg_xfrd < idev->msg->len)
- axxia_i2c_empty_rx_fifo(idev);
- complete(&idev->msg_complete);
- } else if (status & MST_STATUS_TSS) {
- /* Transfer timeout */
- idev->msg_err = -ETIMEDOUT;
- i2c_int_disable(idev, ~MST_STATUS_TSS);
- complete(&idev->msg_complete);
- } else if (unlikely(status & MST_STATUS_ERR)) {
+ if (unlikely(status & MST_STATUS_ERR)) {
/* Transfer error */
i2c_int_disable(idev, ~0);
if (status & MST_STATUS_AL)
@@ -328,6 +313,21 @@
readl(idev->base + MST_TX_BYTES_XFRD),
readl(idev->base + MST_TX_XFER));
complete(&idev->msg_complete);
+ } else if (status & MST_STATUS_SCC) {
+ /* Stop completed */
+ i2c_int_disable(idev, ~MST_STATUS_TSS);
+ complete(&idev->msg_complete);
+ } else if (status & MST_STATUS_SNS) {
+ /* Transfer done */
+ i2c_int_disable(idev, ~MST_STATUS_TSS);
+ if (i2c_m_rd(idev->msg) && idev->msg_xfrd < idev->msg->len)
+ axxia_i2c_empty_rx_fifo(idev);
+ complete(&idev->msg_complete);
+ } else if (status & MST_STATUS_TSS) {
+ /* Transfer timeout */
+ idev->msg_err = -ETIMEDOUT;
+ i2c_int_disable(idev, ~MST_STATUS_TSS);
+ complete(&idev->msg_complete);
}
out:
diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c
index 3f968c4..7846368 100644
--- a/drivers/iio/accel/kxcjk-1013.c
+++ b/drivers/iio/accel/kxcjk-1013.c
@@ -1393,6 +1393,7 @@
{"KXCJ1008", KXCJ91008},
{"KXCJ9000", KXCJ91008},
{"KIOX000A", KXCJ91008},
+ {"KIOX010A", KXCJ91008}, /* KXCJ91008 inside the display of a 2-in-1 */
{"KXTJ1009", KXTJ21009},
{"SMO8500", KXCJ91008},
{ },
diff --git a/drivers/iio/chemical/atlas-ph-sensor.c b/drivers/iio/chemical/atlas-ph-sensor.c
index ef761a5..dad2a8b 100644
--- a/drivers/iio/chemical/atlas-ph-sensor.c
+++ b/drivers/iio/chemical/atlas-ph-sensor.c
@@ -453,9 +453,8 @@
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_TEMP:
- *val = 1; /* 0.01 */
- *val2 = 100;
- break;
+ *val = 10;
+ return IIO_VAL_INT;
case IIO_PH:
*val = 1; /* 0.001 */
*val2 = 1000;
@@ -486,7 +485,7 @@
int val, int val2, long mask)
{
struct atlas_data *data = iio_priv(indio_dev);
- __be32 reg = cpu_to_be32(val);
+ __be32 reg = cpu_to_be32(val / 10);
if (val2 != 0 || val < 0 || val > 20000)
return -EINVAL;
diff --git a/drivers/infiniband/hw/hfi1/ruc.c b/drivers/infiniband/hw/hfi1/ruc.c
index 9f768b4..d151429 100644
--- a/drivers/infiniband/hw/hfi1/ruc.c
+++ b/drivers/infiniband/hw/hfi1/ruc.c
@@ -471,6 +471,8 @@
goto op_err;
if (!ret)
goto rnr_nak;
+ if (wqe->length > qp->r_len)
+ goto inv_err;
break;
case IB_WR_RDMA_WRITE_WITH_IMM:
@@ -638,7 +640,10 @@
goto err;
inv_err:
- send_status = IB_WC_REM_INV_REQ_ERR;
+ send_status =
+ sqp->ibqp.qp_type == IB_QPT_RC ?
+ IB_WC_REM_INV_REQ_ERR :
+ IB_WC_SUCCESS;
wc.status = IB_WC_LOC_QP_OP_ERR;
goto err;
diff --git a/drivers/infiniband/hw/qib/qib_ruc.c b/drivers/infiniband/hw/qib/qib_ruc.c
index de1bde5..10afde6 100644
--- a/drivers/infiniband/hw/qib/qib_ruc.c
+++ b/drivers/infiniband/hw/qib/qib_ruc.c
@@ -449,6 +449,8 @@
goto op_err;
if (!ret)
goto rnr_nak;
+ if (wqe->length > qp->r_len)
+ goto inv_err;
break;
case IB_WR_RDMA_WRITE_WITH_IMM:
@@ -612,7 +614,10 @@
goto err;
inv_err:
- send_status = IB_WC_REM_INV_REQ_ERR;
+ send_status =
+ sqp->ibqp.qp_type == IB_QPT_RC ?
+ IB_WC_REM_INV_REQ_ERR :
+ IB_WC_SUCCESS;
wc.status = IB_WC_LOC_QP_OP_ERR;
goto err;
diff --git a/drivers/input/misc/bma150.c b/drivers/input/misc/bma150.c
index b0d4453..d43bc7b 100644
--- a/drivers/input/misc/bma150.c
+++ b/drivers/input/misc/bma150.c
@@ -482,13 +482,14 @@
idev->close = bma150_irq_close;
input_set_drvdata(idev, bma150);
+ bma150->input = idev;
+
error = input_register_device(idev);
if (error) {
input_free_device(idev);
return error;
}
- bma150->input = idev;
return 0;
}
@@ -511,15 +512,15 @@
bma150_init_input_device(bma150, ipoll_dev->input);
+ bma150->input_polled = ipoll_dev;
+ bma150->input = ipoll_dev->input;
+
error = input_register_polled_device(ipoll_dev);
if (error) {
input_free_polled_device(ipoll_dev);
return error;
}
- bma150->input_polled = ipoll_dev;
- bma150->input = ipoll_dev->input;
-
return 0;
}
diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c
index 30adc57..25ce904 100644
--- a/drivers/input/mouse/elan_i2c_core.c
+++ b/drivers/input/mouse/elan_i2c_core.c
@@ -1240,7 +1240,6 @@
static const struct acpi_device_id elan_acpi_id[] = {
{ "ELAN0000", 0 },
{ "ELAN0100", 0 },
- { "ELAN0501", 0 },
{ "ELAN0600", 0 },
{ "ELAN0602", 0 },
{ "ELAN0605", 0 },
@@ -1251,6 +1250,7 @@
{ "ELAN060C", 0 },
{ "ELAN0611", 0 },
{ "ELAN0612", 0 },
+ { "ELAN0617", 0 },
{ "ELAN0618", 0 },
{ "ELAN061C", 0 },
{ "ELAN061D", 0 },
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index c120afd..38edf8f 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -1117,6 +1117,8 @@
* Asus UX31 0x361f00 20, 15, 0e clickpad
* Asus UX32VD 0x361f02 00, 15, 0e clickpad
* Avatar AVIU-145A2 0x361f00 ? clickpad
+ * Fujitsu CELSIUS H760 0x570f02 40, 14, 0c 3 hw buttons (**)
+ * Fujitsu CELSIUS H780 0x5d0f02 41, 16, 0d 3 hw buttons (**)
* Fujitsu LIFEBOOK E544 0x470f00 d0, 12, 09 2 hw buttons
* Fujitsu LIFEBOOK E546 0x470f00 50, 12, 09 2 hw buttons
* Fujitsu LIFEBOOK E547 0x470f00 50, 12, 09 2 hw buttons
@@ -1169,6 +1171,13 @@
DMI_MATCH(DMI_PRODUCT_NAME, "CELSIUS H760"),
},
},
+ {
+ /* Fujitsu H780 also has a middle button */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "CELSIUS H780"),
+ },
+ },
#endif
{ }
};
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index bba1b9f..e984418 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -464,7 +464,14 @@
dev_data->alias = get_alias(dev);
- if (dev_is_pci(dev) && pci_iommuv2_capable(to_pci_dev(dev))) {
+ /*
+ * By default we use passthrough mode for IOMMUv2 capable device.
+ * But if amd_iommu=force_isolation is set (e.g. to debug DMA to
+ * invalid address), we ignore the capability for the device so
+ * it'll be forced to go into translation mode.
+ */
+ if ((iommu_pass_through || !amd_iommu_force_isolation) &&
+ dev_is_pci(dev) && pci_iommuv2_capable(to_pci_dev(dev))) {
struct amd_iommu *iommu;
iommu = amd_iommu_rlookup_table[dev_data->devid];
diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index ff4be11..7bd9858 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -697,7 +697,13 @@
u32 cons = (Q_WRP(q, q->cons) | Q_IDX(q, q->cons)) + 1;
q->cons = Q_OVF(q, q->cons) | Q_WRP(q, cons) | Q_IDX(q, cons);
- writel(q->cons, q->cons_reg);
+
+ /*
+ * Ensure that all CPU accesses (reads and writes) to the queue
+ * are complete before we update the cons pointer.
+ */
+ mb();
+ writel_relaxed(q->cons, q->cons_reg);
}
static int queue_sync_prod(struct arm_smmu_queue *q)
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
old mode 100644
new mode 100755
diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c
index 90449e1..1b1453d 100644
--- a/drivers/isdn/hisax/hfc_pci.c
+++ b/drivers/isdn/hisax/hfc_pci.c
@@ -1169,11 +1169,13 @@
if (cs->debug & L1_DEB_LAPD)
debugl1(cs, "-> PH_REQUEST_PULL");
#endif
+ spin_lock_irqsave(&cs->lock, flags);
if (!cs->tx_skb) {
test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
} else
test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+ spin_unlock_irqrestore(&cs->lock, flags);
break;
case (HW_RESET | REQUEST):
spin_lock_irqsave(&cs->lock, flags);
diff --git a/drivers/isdn/mISDN/timerdev.c b/drivers/isdn/mISDN/timerdev.c
index 9438d7e..8b29e97 100644
--- a/drivers/isdn/mISDN/timerdev.c
+++ b/drivers/isdn/mISDN/timerdev.c
@@ -168,8 +168,8 @@
spin_lock_irqsave(&timer->dev->lock, flags);
if (timer->id >= 0)
list_move_tail(&timer->list, &timer->dev->expired);
- spin_unlock_irqrestore(&timer->dev->lock, flags);
wake_up_interruptible(&timer->dev->wait);
+ spin_unlock_irqrestore(&timer->dev->lock, flags);
}
static int
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c
index ce08c9f..8ca97b2 100644
--- a/drivers/md/dm-thin.c
+++ b/drivers/md/dm-thin.c
@@ -257,6 +257,7 @@
spinlock_t lock;
struct bio_list deferred_flush_bios;
+ struct bio_list deferred_flush_completions;
struct list_head prepared_mappings;
struct list_head prepared_discards;
struct list_head prepared_discards_pt2;
@@ -925,6 +926,39 @@
mempool_free(m, m->tc->pool->mapping_pool);
}
+static void complete_overwrite_bio(struct thin_c *tc, struct bio *bio)
+{
+ struct pool *pool = tc->pool;
+ unsigned long flags;
+
+ /*
+ * If the bio has the REQ_FUA flag set we must commit the metadata
+ * before signaling its completion.
+ */
+ if (!bio_triggers_commit(tc, bio)) {
+ bio_endio(bio);
+ return;
+ }
+
+ /*
+ * Complete bio with an error if earlier I/O caused changes to the
+ * metadata that can't be committed, e.g, due to I/O errors on the
+ * metadata device.
+ */
+ if (dm_thin_aborted_changes(tc->td)) {
+ bio_io_error(bio);
+ return;
+ }
+
+ /*
+ * Batch together any bios that trigger commits and then issue a
+ * single commit for them in process_deferred_bios().
+ */
+ spin_lock_irqsave(&pool->lock, flags);
+ bio_list_add(&pool->deferred_flush_completions, bio);
+ spin_unlock_irqrestore(&pool->lock, flags);
+}
+
static void process_prepared_mapping(struct dm_thin_new_mapping *m)
{
struct thin_c *tc = m->tc;
@@ -957,7 +991,7 @@
*/
if (bio) {
inc_remap_and_issue_cell(tc, m->cell, m->data_block);
- bio_endio(bio);
+ complete_overwrite_bio(tc, bio);
} else {
inc_all_io_entry(tc->pool, m->cell->holder);
remap_and_issue(tc, m->cell->holder, m->data_block);
@@ -2303,7 +2337,7 @@
{
unsigned long flags;
struct bio *bio;
- struct bio_list bios;
+ struct bio_list bios, bio_completions;
struct thin_c *tc;
tc = get_first_thin(pool);
@@ -2314,26 +2348,36 @@
}
/*
- * If there are any deferred flush bios, we must commit
- * the metadata before issuing them.
+ * If there are any deferred flush bios, we must commit the metadata
+ * before issuing them or signaling their completion.
*/
bio_list_init(&bios);
+ bio_list_init(&bio_completions);
+
spin_lock_irqsave(&pool->lock, flags);
bio_list_merge(&bios, &pool->deferred_flush_bios);
bio_list_init(&pool->deferred_flush_bios);
+
+ bio_list_merge(&bio_completions, &pool->deferred_flush_completions);
+ bio_list_init(&pool->deferred_flush_completions);
spin_unlock_irqrestore(&pool->lock, flags);
- if (bio_list_empty(&bios) &&
+ if (bio_list_empty(&bios) && bio_list_empty(&bio_completions) &&
!(dm_pool_changed_this_transaction(pool->pmd) && need_commit_due_to_time(pool)))
return;
if (commit(pool)) {
+ bio_list_merge(&bios, &bio_completions);
+
while ((bio = bio_list_pop(&bios)))
bio_io_error(bio);
return;
}
pool->last_commit_jiffies = jiffies;
+ while ((bio = bio_list_pop(&bio_completions)))
+ bio_endio(bio);
+
while ((bio = bio_list_pop(&bios)))
generic_make_request(bio);
}
@@ -2968,6 +3012,7 @@
INIT_DELAYED_WORK(&pool->no_space_timeout, do_no_space_timeout);
spin_lock_init(&pool->lock);
bio_list_init(&pool->deferred_flush_bios);
+ bio_list_init(&pool->deferred_flush_completions);
INIT_LIST_HEAD(&pool->prepared_mappings);
INIT_LIST_HEAD(&pool->prepared_discards);
INIT_LIST_HEAD(&pool->prepared_discards_pt2);
diff --git a/drivers/media/i2c/ad9389b.c b/drivers/media/i2c/ad9389b.c
index 50f3541..2abbbc63 100644
--- a/drivers/media/i2c/ad9389b.c
+++ b/drivers/media/i2c/ad9389b.c
@@ -590,7 +590,7 @@
.type = V4L2_DV_BT_656_1120,
/* keep this initialization for compatibility with GCC < 4.4.6 */
.reserved = { 0 },
- V4L2_INIT_BT_TIMINGS(0, 1920, 0, 1200, 25000000, 170000000,
+ V4L2_INIT_BT_TIMINGS(640, 1920, 350, 1200, 25000000, 170000000,
V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_REDUCED_BLANKING |
diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c
index 5ba0f21..5f1c8ee 100644
--- a/drivers/media/i2c/adv7511.c
+++ b/drivers/media/i2c/adv7511.c
@@ -142,7 +142,7 @@
.type = V4L2_DV_BT_656_1120,
/* keep this initialization for compatibility with GCC < 4.4.6 */
.reserved = { 0 },
- V4L2_INIT_BT_TIMINGS(0, ADV7511_MAX_WIDTH, 0, ADV7511_MAX_HEIGHT,
+ V4L2_INIT_BT_TIMINGS(640, ADV7511_MAX_WIDTH, 350, ADV7511_MAX_HEIGHT,
ADV7511_MIN_PIXELCLOCK, ADV7511_MAX_PIXELCLOCK,
V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index 7b1935a..ce6f930 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -777,7 +777,7 @@
.type = V4L2_DV_BT_656_1120,
/* keep this initialization for compatibility with GCC < 4.4.6 */
.reserved = { 0 },
- V4L2_INIT_BT_TIMINGS(0, 1920, 0, 1200, 25000000, 170000000,
+ V4L2_INIT_BT_TIMINGS(640, 1920, 350, 1200, 25000000, 170000000,
V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_REDUCED_BLANKING |
@@ -788,7 +788,7 @@
.type = V4L2_DV_BT_656_1120,
/* keep this initialization for compatibility with GCC < 4.4.6 */
.reserved = { 0 },
- V4L2_INIT_BT_TIMINGS(0, 1920, 0, 1200, 25000000, 225000000,
+ V4L2_INIT_BT_TIMINGS(640, 1920, 350, 1200, 25000000, 225000000,
V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_REDUCED_BLANKING |
diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c
index 8c2a52e..cf3b42c 100644
--- a/drivers/media/i2c/adv7842.c
+++ b/drivers/media/i2c/adv7842.c
@@ -676,7 +676,7 @@
.type = V4L2_DV_BT_656_1120,
/* keep this initialization for compatibility with GCC < 4.4.6 */
.reserved = { 0 },
- V4L2_INIT_BT_TIMINGS(0, 1920, 0, 1200, 25000000, 170000000,
+ V4L2_INIT_BT_TIMINGS(640, 1920, 350, 1200, 25000000, 170000000,
V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_REDUCED_BLANKING |
@@ -687,7 +687,7 @@
.type = V4L2_DV_BT_656_1120,
/* keep this initialization for compatibility with GCC < 4.4.6 */
.reserved = { 0 },
- V4L2_INIT_BT_TIMINGS(0, 1920, 0, 1200, 25000000, 225000000,
+ V4L2_INIT_BT_TIMINGS(640, 1920, 350, 1200, 25000000, 225000000,
V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_REDUCED_BLANKING |
diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c
index 0f572bf..7ebcb94 100644
--- a/drivers/media/i2c/tc358743.c
+++ b/drivers/media/i2c/tc358743.c
@@ -66,7 +66,7 @@
/* keep this initialization for compatibility with GCC < 4.4.6 */
.reserved = { 0 },
/* Pixel clock from REF_01 p. 20. Min/max height/width are unknown */
- V4L2_INIT_BT_TIMINGS(1, 10000, 1, 10000, 0, 165000000,
+ V4L2_INIT_BT_TIMINGS(640, 1920, 350, 1200, 13000000, 165000000,
V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
V4L2_DV_BT_CAP_PROGRESSIVE |
diff --git a/drivers/media/i2c/ths8200.c b/drivers/media/i2c/ths8200.c
index 42340e3..e06e2de 100644
--- a/drivers/media/i2c/ths8200.c
+++ b/drivers/media/i2c/ths8200.c
@@ -49,7 +49,7 @@
.type = V4L2_DV_BT_656_1120,
/* keep this initialization for compatibility with GCC < 4.4.6 */
.reserved = { 0 },
- V4L2_INIT_BT_TIMINGS(0, 1920, 0, 1080, 25000000, 148500000,
+ V4L2_INIT_BT_TIMINGS(640, 1920, 350, 1080, 25000000, 148500000,
V4L2_DV_BT_STD_CEA861, V4L2_DV_BT_CAP_PROGRESSIVE)
};
diff --git a/drivers/media/platform/davinci/vpbe.c b/drivers/media/platform/davinci/vpbe.c
index 9a6c2cc..abce9c4 100644
--- a/drivers/media/platform/davinci/vpbe.c
+++ b/drivers/media/platform/davinci/vpbe.c
@@ -753,7 +753,7 @@
if (ret) {
v4l2_err(&vpbe_dev->v4l2_dev, "Failed to set default output %s",
def_output);
- return ret;
+ goto fail_kfree_amp;
}
printk(KERN_NOTICE "Setting default mode to %s\n", def_mode);
@@ -761,12 +761,15 @@
if (ret) {
v4l2_err(&vpbe_dev->v4l2_dev, "Failed to set default mode %s",
def_mode);
- return ret;
+ goto fail_kfree_amp;
}
vpbe_dev->initialized = 1;
/* TBD handling of bootargs for default output and mode */
return 0;
+fail_kfree_amp:
+ mutex_lock(&vpbe_dev->lock);
+ kfree(vpbe_dev->amp);
fail_kfree_encoders:
kfree(vpbe_dev->encoders);
fail_dev_unregister:
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c
index 3e73e9d..7c02504 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c
@@ -41,25 +41,27 @@
node = of_parse_phandle(dev->of_node, "mediatek,larb", 0);
if (!node) {
mtk_v4l2_err("no mediatek,larb found");
- return -1;
+ return -ENODEV;
}
pdev = of_find_device_by_node(node);
+ of_node_put(node);
if (!pdev) {
mtk_v4l2_err("no mediatek,larb device found");
- return -1;
+ return -ENODEV;
}
pm->larbvenc = &pdev->dev;
node = of_parse_phandle(dev->of_node, "mediatek,larb", 1);
if (!node) {
mtk_v4l2_err("no mediatek,larb found");
- return -1;
+ return -ENODEV;
}
pdev = of_find_device_by_node(node);
+ of_node_put(node);
if (!pdev) {
mtk_v4l2_err("no mediatek,larb device found");
- return -1;
+ return -ENODEV;
}
pm->larbvenclt = &pdev->dev;
diff --git a/drivers/memstick/core/memstick.c b/drivers/memstick/core/memstick.c
index a0547db..4d673a6 100644
--- a/drivers/memstick/core/memstick.c
+++ b/drivers/memstick/core/memstick.c
@@ -18,6 +18,7 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/module.h>
+#include <linux/pm_runtime.h>
#define DRIVER_NAME "memstick"
@@ -436,6 +437,7 @@
struct memstick_dev *card;
dev_dbg(&host->dev, "memstick_check started\n");
+ pm_runtime_get_noresume(host->dev.parent);
mutex_lock(&host->lock);
if (!host->card) {
if (memstick_power_on(host))
@@ -479,6 +481,7 @@
host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_OFF);
mutex_unlock(&host->lock);
+ pm_runtime_put(host->dev.parent);
dev_dbg(&host->dev, "memstick_check finished\n");
}
diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
index c4e41c2..fac10c0 100644
--- a/drivers/misc/eeprom/Kconfig
+++ b/drivers/misc/eeprom/Kconfig
@@ -12,7 +12,7 @@
ones like at24c64, 24lc02 or fm24c04:
24c00, 24c01, 24c02, spd (readonly 24c02), 24c04, 24c08,
- 24c16, 24c32, 24c64, 24c128, 24c256, 24c512, 24c1024
+ 24c16, 24c32, 24c64, 24c128, 24c256, 24c512, 24c1024, 24c2048
Unless you like data loss puzzles, always be sure that any chip
you configure as a 24c32 (32 kbit) or larger is NOT really a
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index d8a485f..a37b9b6 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -170,6 +170,7 @@
{ "24c256", AT24_DEVICE_MAGIC(262144 / 8, AT24_FLAG_ADDR16) },
{ "24c512", AT24_DEVICE_MAGIC(524288 / 8, AT24_FLAG_ADDR16) },
{ "24c1024", AT24_DEVICE_MAGIC(1048576 / 8, AT24_FLAG_ADDR16) },
+ { "24c2048", AT24_DEVICE_MAGIC(2097152 / 8, AT24_FLAG_ADDR16) },
{ "at24", 0 },
{ /* END OF LIST */ }
};
diff --git a/drivers/misc/vexpress-syscfg.c b/drivers/misc/vexpress-syscfg.c
index c344483..9f257c5 100644
--- a/drivers/misc/vexpress-syscfg.c
+++ b/drivers/misc/vexpress-syscfg.c
@@ -61,7 +61,7 @@
int tries;
long timeout;
- if (WARN_ON(index > func->num_templates))
+ if (WARN_ON(index >= func->num_templates))
return -EINVAL;
command = readl(syscfg->base + SYS_CFGCTRL);
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
index 141bd70..b950923 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
@@ -168,9 +168,10 @@
/*
* Reset BCH here, too. We got failures otherwise :(
- * See later BCH reset for explanation of MX23 handling
+ * See later BCH reset for explanation of MX23 and MX28 handling
*/
- ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MX23(this));
+ ret = gpmi_reset_block(r->bch_regs,
+ GPMI_IS_MX23(this) || GPMI_IS_MX28(this));
if (ret)
goto err_out;
@@ -275,13 +276,11 @@
/*
* Due to erratum #2847 of the MX23, the BCH cannot be soft reset on this
- * chip, otherwise it will lock up. So we skip resetting BCH on the MX23.
- * On the other hand, the MX28 needs the reset, because one case has been
- * seen where the BCH produced ECC errors constantly after 10000
- * consecutive reboots. The latter case has not been seen on the MX23
- * yet, still we don't know if it could happen there as well.
+ * chip, otherwise it will lock up. So we skip resetting BCH on the MX23
+ * and MX28.
*/
- ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MX23(this));
+ ret = gpmi_reset_block(r->bch_regs,
+ GPMI_IS_MX23(this) || GPMI_IS_MX28(this));
if (ret)
goto err_out;
diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c
index 16dc9ac..53a506b 100644
--- a/drivers/net/ethernet/broadcom/bcmsysport.c
+++ b/drivers/net/ethernet/broadcom/bcmsysport.c
@@ -378,7 +378,6 @@
struct ethtool_wolinfo *wol)
{
struct bcm_sysport_priv *priv = netdev_priv(dev);
- u32 reg;
wol->supported = WAKE_MAGIC | WAKE_MAGICSECURE;
wol->wolopts = priv->wolopts;
@@ -386,11 +385,7 @@
if (!(priv->wolopts & WAKE_MAGICSECURE))
return;
- /* Return the programmed SecureOn password */
- reg = umac_readl(priv, UMAC_PSW_MS);
- put_unaligned_be16(reg, &wol->sopass[0]);
- reg = umac_readl(priv, UMAC_PSW_LS);
- put_unaligned_be32(reg, &wol->sopass[2]);
+ memcpy(wol->sopass, priv->sopass, sizeof(priv->sopass));
}
static int bcm_sysport_set_wol(struct net_device *dev,
@@ -406,13 +401,8 @@
if (wol->wolopts & ~supported)
return -EINVAL;
- /* Program the SecureOn password */
- if (wol->wolopts & WAKE_MAGICSECURE) {
- umac_writel(priv, get_unaligned_be16(&wol->sopass[0]),
- UMAC_PSW_MS);
- umac_writel(priv, get_unaligned_be32(&wol->sopass[2]),
- UMAC_PSW_LS);
- }
+ if (wol->wolopts & WAKE_MAGICSECURE)
+ memcpy(priv->sopass, wol->sopass, sizeof(priv->sopass));
/* Flag the device and relevant IRQ as wakeup capable */
if (wol->wolopts) {
@@ -1875,12 +1865,17 @@
unsigned int timeout = 1000;
u32 reg;
- /* Password has already been programmed */
reg = umac_readl(priv, UMAC_MPD_CTRL);
reg |= MPD_EN;
reg &= ~PSW_EN;
- if (priv->wolopts & WAKE_MAGICSECURE)
+ if (priv->wolopts & WAKE_MAGICSECURE) {
+ /* Program the SecureOn password */
+ umac_writel(priv, get_unaligned_be16(&priv->sopass[0]),
+ UMAC_PSW_MS);
+ umac_writel(priv, get_unaligned_be32(&priv->sopass[2]),
+ UMAC_PSW_LS);
reg |= PSW_EN;
+ }
umac_writel(priv, reg, UMAC_MPD_CTRL);
/* Make sure RBUF entered WoL mode as result */
diff --git a/drivers/net/ethernet/broadcom/bcmsysport.h b/drivers/net/ethernet/broadcom/bcmsysport.h
index 07b0aaa..0d3444f 100644
--- a/drivers/net/ethernet/broadcom/bcmsysport.h
+++ b/drivers/net/ethernet/broadcom/bcmsysport.h
@@ -11,6 +11,7 @@
#ifndef __BCM_SYSPORT_H
#define __BCM_SYSPORT_H
+#include <linux/ethtool.h>
#include <linux/if_vlan.h>
/* Receive/transmit descriptor format */
@@ -681,6 +682,7 @@
unsigned int crc_fwd:1;
u16 rev;
u32 wolopts;
+ u8 sopass[SOPASS_MAX];
unsigned int wol_irq_disabled:1;
/* MIB related fields */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index 4bc2c80..eeeb4c5 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -12979,6 +12979,24 @@
struct net_device *dev,
netdev_features_t features)
{
+ /*
+ * A skb with gso_size + header length > 9700 will cause a
+ * firmware panic. Drop GSO support.
+ *
+ * Eventually the upper layer should not pass these packets down.
+ *
+ * For speed, if the gso_size is <= 9000, assume there will
+ * not be 700 bytes of headers and pass it through. Only do a
+ * full (slow) validation if the gso_size is > 9000.
+ *
+ * (Due to the way SKB_BY_FRAGS works this will also do a full
+ * validation in that case.)
+ */
+ if (unlikely(skb_is_gso(skb) &&
+ (skb_shinfo(skb)->gso_size > 9000) &&
+ !skb_gso_validate_mac_len(skb, 9700)))
+ features &= ~NETIF_F_GSO_MASK;
+
features = vlan_features_check(skb, features);
return vxlan_features_check(skb, features);
}
diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c
index 07282eb..89acf7b 100644
--- a/drivers/net/ethernet/cisco/enic/enic_main.c
+++ b/drivers/net/ethernet/cisco/enic/enic_main.c
@@ -1180,7 +1180,7 @@
* CHECSUM_UNNECESSARY.
*/
if ((netdev->features & NETIF_F_RXCSUM) && tcp_udp_csum_ok &&
- ipv4_csum_ok)
+ (ipv4_csum_ok || ipv6))
skb->ip_summed = CHECKSUM_UNNECESSARY;
if (vlan_stripped)
diff --git a/drivers/net/ethernet/freescale/fman/fman_memac.c b/drivers/net/ethernet/freescale/fman/fman_memac.c
index 71a5ded..21dd557 100644
--- a/drivers/net/ethernet/freescale/fman/fman_memac.c
+++ b/drivers/net/ethernet/freescale/fman/fman_memac.c
@@ -923,7 +923,7 @@
hash = get_mac_addr_hash_code(addr) & HASH_CTRL_ADDR_MASK;
/* Create element to be added to the driver hash table */
- hash_entry = kmalloc(sizeof(*hash_entry), GFP_KERNEL);
+ hash_entry = kmalloc(sizeof(*hash_entry), GFP_ATOMIC);
if (!hash_entry)
return -ENOMEM;
hash_entry->addr = addr;
diff --git a/drivers/net/ethernet/freescale/fman/fman_tgec.c b/drivers/net/ethernet/freescale/fman/fman_tgec.c
index 4b0f3a5..e575259 100644
--- a/drivers/net/ethernet/freescale/fman/fman_tgec.c
+++ b/drivers/net/ethernet/freescale/fman/fman_tgec.c
@@ -551,7 +551,7 @@
hash = (crc >> TGEC_HASH_MCAST_SHIFT) & TGEC_HASH_ADR_MSK;
/* Create element to be added to the driver hash table */
- hash_entry = kmalloc(sizeof(*hash_entry), GFP_KERNEL);
+ hash_entry = kmalloc(sizeof(*hash_entry), GFP_ATOMIC);
if (!hash_entry)
return -ENOMEM;
hash_entry->addr = addr;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index 57c7456..7836072 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -9194,6 +9194,9 @@
ether_addr_copy(netdev->dev_addr, mac_addr);
ether_addr_copy(netdev->perm_addr, mac_addr);
+ /* i40iw_net_event() reads 16 bytes from neigh->primary_key */
+ netdev->neigh_priv_len = sizeof(u32) * 4;
+
netdev->priv_flags |= IFF_UNICAST_FLT;
netdev->priv_flags |= IFF_SUPP_NOFCS;
/* Setup netdev TC information */
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 3a61491..82e48e3 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -7564,9 +7564,11 @@
rtnl_unlock();
#ifdef CONFIG_PM
- retval = pci_save_state(pdev);
- if (retval)
- return retval;
+ if (!runtime) {
+ retval = pci_save_state(pdev);
+ if (retval)
+ return retval;
+ }
#endif
status = rd32(E1000_STATUS);
diff --git a/drivers/net/ethernet/marvell/skge.c b/drivers/net/ethernet/marvell/skge.c
index 7173836..c9f4b54 100644
--- a/drivers/net/ethernet/marvell/skge.c
+++ b/drivers/net/ethernet/marvell/skge.c
@@ -152,8 +152,10 @@
memset(p, 0, regs->len);
memcpy_fromio(p, io, B3_RAM_ADDR);
- memcpy_fromio(p + B3_RI_WTO_R1, io + B3_RI_WTO_R1,
- regs->len - B3_RI_WTO_R1);
+ if (regs->len > B3_RI_WTO_R1) {
+ memcpy_fromio(p + B3_RI_WTO_R1, io + B3_RI_WTO_R1,
+ regs->len - B3_RI_WTO_R1);
+ }
}
/* Wake on Lan only supported on Yukon chips with rev 1 or above */
diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c
index 93ab0b3..af11781 100644
--- a/drivers/net/ethernet/marvell/sky2.c
+++ b/drivers/net/ethernet/marvell/sky2.c
@@ -5079,7 +5079,7 @@
INIT_WORK(&hw->restart_work, sky2_restart);
pci_set_drvdata(pdev, hw);
- pdev->d3_delay = 200;
+ pdev->d3_delay = 300;
return 0;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
index 7309ae3..2b6a7eb 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
@@ -553,6 +553,8 @@
return (ethertype == htons(ETH_P_IP) || ethertype == htons(ETH_P_IPV6));
}
+#define short_frame(size) ((size) <= ETH_ZLEN + ETH_FCS_LEN)
+
static inline void mlx5e_handle_csum(struct net_device *netdev,
struct mlx5_cqe64 *cqe,
struct mlx5e_rq *rq,
@@ -567,6 +569,17 @@
return;
}
+ /* CQE csum doesn't cover padding octets in short ethernet
+ * frames. And the pad field is appended prior to calculating
+ * and appending the FCS field.
+ *
+ * Detecting these padded frames requires to verify and parse
+ * IP headers, so we simply force all those small frames to be
+ * CHECKSUM_UNNECESSARY even if they are not padded.
+ */
+ if (short_frame(skb->len))
+ goto csum_unnecessary;
+
if (is_first_ethertype_ip(skb)) {
skb->ip_summed = CHECKSUM_COMPLETE;
skb->csum = csum_unfold((__force __sum16)cqe->check_sum);
@@ -574,6 +587,7 @@
return;
}
+csum_unnecessary:
if (likely((cqe->hds_ip_ext & CQE_L3_OK) &&
(cqe->hds_ip_ext & CQE_L4_OK))) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
index a601f8d..f988c75 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
@@ -237,15 +237,18 @@
static int dwmac4_rx_check_timestamp(void *desc)
{
struct dma_desc *p = (struct dma_desc *)desc;
+ unsigned int rdes0 = le32_to_cpu(p->des0);
+ unsigned int rdes1 = le32_to_cpu(p->des1);
+ unsigned int rdes3 = le32_to_cpu(p->des3);
u32 own, ctxt;
int ret = 1;
- own = p->des3 & RDES3_OWN;
- ctxt = ((p->des3 & RDES3_CONTEXT_DESCRIPTOR)
+ own = rdes3 & RDES3_OWN;
+ ctxt = ((rdes3 & RDES3_CONTEXT_DESCRIPTOR)
>> RDES3_CONTEXT_DESCRIPTOR_SHIFT);
if (likely(!own && ctxt)) {
- if ((p->des0 == 0xffffffff) && (p->des1 == 0xffffffff))
+ if ((rdes0 == 0xffffffff) && (rdes1 == 0xffffffff))
/* Corrupted value */
ret = -EINVAL;
else
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index c5d0142..3519a8a 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -676,25 +676,27 @@
struct ethtool_eee *edata)
{
struct stmmac_priv *priv = netdev_priv(dev);
+ int ret;
- priv->eee_enabled = edata->eee_enabled;
-
- if (!priv->eee_enabled)
+ if (!edata->eee_enabled) {
stmmac_disable_eee_mode(priv);
- else {
+ } else {
/* We are asking for enabling the EEE but it is safe
* to verify all by invoking the eee_init function.
* In case of failure it will return an error.
*/
- priv->eee_enabled = stmmac_eee_init(priv);
- if (!priv->eee_enabled)
+ edata->eee_enabled = stmmac_eee_init(priv);
+ if (!edata->eee_enabled)
return -EOPNOTSUPP;
-
- /* Do not change tx_lpi_timer in case of failure */
- priv->tx_lpi_timer = edata->tx_lpi_timer;
}
- return phy_ethtool_set_eee(priv->phydev, edata);
+ ret = phy_ethtool_set_eee(dev->phydev, edata);
+ if (ret)
+ return ret;
+
+ priv->eee_enabled = edata->eee_enabled;
+ priv->tx_lpi_timer = edata->tx_lpi_timer;
+ return 0;
}
static u32 stmmac_usec2riwt(u32 usec, struct stmmac_priv *priv)
diff --git a/drivers/net/ethernet/sun/niu.c b/drivers/net/ethernet/sun/niu.c
index e45e2f1..fe5b0ac 100644
--- a/drivers/net/ethernet/sun/niu.c
+++ b/drivers/net/ethernet/sun/niu.c
@@ -8121,6 +8121,8 @@
start += 3;
prop_len = niu_pci_eeprom_read(np, start + 4);
+ if (prop_len < 0)
+ return prop_len;
err = niu_pci_vpd_get_propname(np, start + 5, namebuf, 64);
if (err < 0)
return err;
@@ -8165,8 +8167,12 @@
netif_printk(np, probe, KERN_DEBUG, np->dev,
"VPD_SCAN: Reading in property [%s] len[%d]\n",
namebuf, prop_len);
- for (i = 0; i < prop_len; i++)
- *prop_buf++ = niu_pci_eeprom_read(np, off + i);
+ for (i = 0; i < prop_len; i++) {
+ err = niu_pci_eeprom_read(np, off + i);
+ if (err >= 0)
+ *prop_buf = err;
+ ++prop_buf;
+ }
}
start += len;
diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c
index 482ea40..557f651 100644
--- a/drivers/net/phy/dp83640.c
+++ b/drivers/net/phy/dp83640.c
@@ -891,14 +891,14 @@
struct phy_txts *phy_txts)
{
struct skb_shared_hwtstamps shhwtstamps;
+ struct dp83640_skb_info *skb_info;
struct sk_buff *skb;
- u64 ns;
u8 overflow;
+ u64 ns;
/* We must already have the skb that triggered this. */
-
+again:
skb = skb_dequeue(&dp83640->tx_queue);
-
if (!skb) {
pr_debug("have timestamp but tx_queue empty\n");
return;
@@ -913,6 +913,11 @@
}
return;
}
+ skb_info = (struct dp83640_skb_info *)skb->cb;
+ if (time_after(jiffies, skb_info->tmo)) {
+ kfree_skb(skb);
+ goto again;
+ }
ns = phy2txts(phy_txts);
memset(&shhwtstamps, 0, sizeof(shhwtstamps));
@@ -1463,6 +1468,7 @@
static void dp83640_txtstamp(struct phy_device *phydev,
struct sk_buff *skb, int type)
{
+ struct dp83640_skb_info *skb_info = (struct dp83640_skb_info *)skb->cb;
struct dp83640_private *dp83640 = phydev->priv;
switch (dp83640->hwts_tx_en) {
@@ -1475,6 +1481,7 @@
/* fall through */
case HWTSTAMP_TX_ON:
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+ skb_info->tmo = jiffies + SKB_TIMESTAMP_TIMEOUT;
skb_queue_tail(&dp83640->tx_queue, skb);
break;
diff --git a/drivers/net/phy/xilinx_gmii2rgmii.c b/drivers/net/phy/xilinx_gmii2rgmii.c
index 7a14e81..aef5254 100644
--- a/drivers/net/phy/xilinx_gmii2rgmii.c
+++ b/drivers/net/phy/xilinx_gmii2rgmii.c
@@ -42,7 +42,10 @@
u16 val = 0;
int err;
- err = priv->phy_drv->read_status(phydev);
+ if (priv->phy_drv->read_status)
+ err = priv->phy_drv->read_status(phydev);
+ else
+ err = genphy_read_status(phydev);
if (err < 0)
return err;
diff --git a/drivers/net/usb/ch9200.c b/drivers/net/usb/ch9200.c
index 8a40202..c4f1c36 100644
--- a/drivers/net/usb/ch9200.c
+++ b/drivers/net/usb/ch9200.c
@@ -254,14 +254,9 @@
tx_overhead = 0x40;
len = skb->len;
- if (skb_headroom(skb) < tx_overhead) {
- struct sk_buff *skb2;
-
- skb2 = skb_copy_expand(skb, tx_overhead, 0, flags);
+ if (skb_cow_head(skb, tx_overhead)) {
dev_kfree_skb_any(skb);
- skb = skb2;
- if (!skb)
- return NULL;
+ return NULL;
}
__skb_push(skb, tx_overhead);
diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c
index 66b34dd..72d9e79 100644
--- a/drivers/net/usb/kaweth.c
+++ b/drivers/net/usb/kaweth.c
@@ -803,18 +803,12 @@
}
/* We now decide whether we can put our special header into the sk_buff */
- if (skb_cloned(skb) || skb_headroom(skb) < 2) {
- /* no such luck - we make our own */
- struct sk_buff *copied_skb;
- copied_skb = skb_copy_expand(skb, 2, 0, GFP_ATOMIC);
- dev_kfree_skb_irq(skb);
- skb = copied_skb;
- if (!copied_skb) {
- kaweth->stats.tx_errors++;
- netif_start_queue(net);
- spin_unlock_irq(&kaweth->device_lock);
- return NETDEV_TX_OK;
- }
+ if (skb_cow_head(skb, 2)) {
+ kaweth->stats.tx_errors++;
+ netif_start_queue(net);
+ spin_unlock_irq(&kaweth->device_lock);
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
}
private_header = (__le16 *)__skb_push(skb, 2);
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index e29f4c0..e719ecd 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -2011,13 +2011,13 @@
/* We do not advertise SG, so skbs should be already linearized */
BUG_ON(skb_shinfo(skb)->nr_frags);
- if (skb_headroom(skb) < overhead) {
- struct sk_buff *skb2 = skb_copy_expand(skb,
- overhead, 0, flags);
+ /* Make writable and expand header space by overhead if required */
+ if (skb_cow_head(skb, overhead)) {
+ /* Must deallocate here as returning NULL to indicate error
+ * means the skb won't be deallocated in the caller.
+ */
dev_kfree_skb_any(skb);
- skb = skb2;
- if (!skb)
- return NULL;
+ return NULL;
}
if (csum) {
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 28afdf2..373713f 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -1911,7 +1911,7 @@
struct pcpu_sw_netstats *tx_stats, *rx_stats;
union vxlan_addr loopback;
union vxlan_addr *remote_ip = &dst_vxlan->default_dst.remote_ip;
- struct net_device *dev = skb->dev;
+ struct net_device *dev;
int len = skb->len;
tx_stats = this_cpu_ptr(src_vxlan->dev->tstats);
@@ -1931,8 +1931,15 @@
#endif
}
+ rcu_read_lock();
+ dev = skb->dev;
+ if (unlikely(!(dev->flags & IFF_UP))) {
+ kfree_skb(skb);
+ goto drop;
+ }
+
if (dst_vxlan->flags & VXLAN_F_LEARN)
- vxlan_snoop(skb->dev, &loopback, eth_hdr(skb)->h_source);
+ vxlan_snoop(dev, &loopback, eth_hdr(skb)->h_source);
u64_stats_update_begin(&tx_stats->syncp);
tx_stats->tx_packets++;
@@ -1945,8 +1952,10 @@
rx_stats->rx_bytes += len;
u64_stats_update_end(&rx_stats->syncp);
} else {
+drop:
dev->stats.rx_dropped++;
}
+ rcu_read_unlock();
}
static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index a731671..7bda18c 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -267,7 +267,7 @@
#endif
u8 key_idx[4];
- u32 ackto;
+ int ackto;
struct list_head list;
};
diff --git a/drivers/net/wireless/ath/ath9k/dynack.c b/drivers/net/wireless/ath/ath9k/dynack.c
index 7334c9b0..6e236a4 100644
--- a/drivers/net/wireless/ath/ath9k/dynack.c
+++ b/drivers/net/wireless/ath/ath9k/dynack.c
@@ -29,9 +29,13 @@
* ath_dynack_ewma - EWMA (Exponentially Weighted Moving Average) calculation
*
*/
-static inline u32 ath_dynack_ewma(u32 old, u32 new)
+static inline int ath_dynack_ewma(int old, int new)
{
- return (new * (EWMA_DIV - EWMA_LEVEL) + old * EWMA_LEVEL) / EWMA_DIV;
+ if (old > 0)
+ return (new * (EWMA_DIV - EWMA_LEVEL) +
+ old * EWMA_LEVEL) / EWMA_DIV;
+ else
+ return new;
}
/**
@@ -82,10 +86,10 @@
*/
static void ath_dynack_compute_ackto(struct ath_hw *ah)
{
- struct ath_node *an;
- u32 to = 0;
- struct ath_dynack *da = &ah->dynack;
struct ath_common *common = ath9k_hw_common(ah);
+ struct ath_dynack *da = &ah->dynack;
+ struct ath_node *an;
+ int to = 0;
list_for_each_entry(an, &da->nodes, list)
if (an->ackto > to)
@@ -144,7 +148,8 @@
an->ackto = ath_dynack_ewma(an->ackto,
ackto);
ath_dbg(ath9k_hw_common(ah), DYNACK,
- "%pM to %u\n", dst, an->ackto);
+ "%pM to %d [%u]\n", dst,
+ an->ackto, ackto);
if (time_is_before_jiffies(da->lto)) {
ath_dynack_compute_ackto(ah);
da->lto = jiffies + COMPUTE_TO;
@@ -166,10 +171,12 @@
* @ah: ath hw
* @skb: socket buffer
* @ts: tx status info
+ * @sta: station pointer
*
*/
void ath_dynack_sample_tx_ts(struct ath_hw *ah, struct sk_buff *skb,
- struct ath_tx_status *ts)
+ struct ath_tx_status *ts,
+ struct ieee80211_sta *sta)
{
u8 ridx;
struct ieee80211_hdr *hdr;
@@ -177,7 +184,7 @@
struct ath_common *common = ath9k_hw_common(ah);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- if ((info->flags & IEEE80211_TX_CTL_NO_ACK) || !da->enabled)
+ if (!da->enabled || (info->flags & IEEE80211_TX_CTL_NO_ACK))
return;
spin_lock_bh(&da->qlock);
@@ -187,11 +194,19 @@
/* late ACK */
if (ts->ts_status & ATH9K_TXERR_XRETRY) {
if (ieee80211_is_assoc_req(hdr->frame_control) ||
- ieee80211_is_assoc_resp(hdr->frame_control)) {
+ ieee80211_is_assoc_resp(hdr->frame_control) ||
+ ieee80211_is_auth(hdr->frame_control)) {
ath_dbg(common, DYNACK, "late ack\n");
+
ath9k_hw_setslottime(ah, (LATEACK_TO - 3) / 2);
ath9k_hw_set_ack_timeout(ah, LATEACK_TO);
ath9k_hw_set_cts_timeout(ah, LATEACK_TO);
+ if (sta) {
+ struct ath_node *an;
+
+ an = (struct ath_node *)sta->drv_priv;
+ an->ackto = -1;
+ }
da->lto = jiffies + LATEACK_DELAY;
}
@@ -251,7 +266,7 @@
struct ath_common *common = ath9k_hw_common(ah);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- if (!ath_dynack_bssidmask(ah, hdr->addr1) || !da->enabled)
+ if (!da->enabled || !ath_dynack_bssidmask(ah, hdr->addr1))
return;
spin_lock_bh(&da->qlock);
diff --git a/drivers/net/wireless/ath/ath9k/dynack.h b/drivers/net/wireless/ath/ath9k/dynack.h
index 6d7bef9..cf60224 100644
--- a/drivers/net/wireless/ath/ath9k/dynack.h
+++ b/drivers/net/wireless/ath/ath9k/dynack.h
@@ -86,7 +86,8 @@
void ath_dynack_init(struct ath_hw *ah);
void ath_dynack_sample_ack_ts(struct ath_hw *ah, struct sk_buff *skb, u32 ts);
void ath_dynack_sample_tx_ts(struct ath_hw *ah, struct sk_buff *skb,
- struct ath_tx_status *ts);
+ struct ath_tx_status *ts,
+ struct ieee80211_sta *sta);
#else
static inline void ath_dynack_init(struct ath_hw *ah) {}
static inline void ath_dynack_node_init(struct ath_hw *ah,
@@ -97,7 +98,8 @@
struct sk_buff *skb, u32 ts) {}
static inline void ath_dynack_sample_tx_ts(struct ath_hw *ah,
struct sk_buff *skb,
- struct ath_tx_status *ts) {}
+ struct ath_tx_status *ts,
+ struct ieee80211_sta *sta) {}
#endif
#endif /* DYNACK_H */
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 8a504af..0ef27d9 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -593,7 +593,7 @@
if (bf == bf->bf_lastbf)
ath_dynack_sample_tx_ts(sc->sc_ah,
bf->bf_mpdu,
- ts);
+ ts, sta);
}
ath_tx_complete_buf(sc, bf, txq, &bf_head, sta, ts,
@@ -709,7 +709,8 @@
memcpy(info->control.rates, bf->rates,
sizeof(info->control.rates));
ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok);
- ath_dynack_sample_tx_ts(sc->sc_ah, bf->bf_mpdu, ts);
+ ath_dynack_sample_tx_ts(sc->sc_ah, bf->bf_mpdu, ts,
+ sta);
}
ath_tx_complete_buf(sc, bf, txq, bf_head, sta, ts, txok);
} else
diff --git a/drivers/net/wireless/st/cw1200/scan.c b/drivers/net/wireless/st/cw1200/scan.c
index 0a0ff7e..c5492d7 100644
--- a/drivers/net/wireless/st/cw1200/scan.c
+++ b/drivers/net/wireless/st/cw1200/scan.c
@@ -78,6 +78,10 @@
if (req->n_ssids > WSM_SCAN_MAX_NUM_OF_SSIDS)
return -EINVAL;
+ /* will be unlocked in cw1200_scan_work() */
+ down(&priv->scan.lock);
+ mutex_lock(&priv->conf_mutex);
+
frame.skb = ieee80211_probereq_get(hw, priv->vif->addr, NULL, 0,
req->ie_len);
if (!frame.skb)
@@ -86,19 +90,15 @@
if (req->ie_len)
memcpy(skb_put(frame.skb, req->ie_len), req->ie, req->ie_len);
- /* will be unlocked in cw1200_scan_work() */
- down(&priv->scan.lock);
- mutex_lock(&priv->conf_mutex);
-
ret = wsm_set_template_frame(priv, &frame);
if (!ret) {
/* Host want to be the probe responder. */
ret = wsm_set_probe_responder(priv, true);
}
if (ret) {
+ dev_kfree_skb(frame.skb);
mutex_unlock(&priv->conf_mutex);
up(&priv->scan.lock);
- dev_kfree_skb(frame.skb);
return ret;
}
@@ -120,10 +120,9 @@
++priv->scan.n_ssids;
}
- mutex_unlock(&priv->conf_mutex);
-
if (frame.skb)
dev_kfree_skb(frame.skb);
+ mutex_unlock(&priv->conf_mutex);
queue_work(priv->workqueue, &priv->scan.work);
return 0;
}
diff --git a/drivers/net/wireless/virt_wifi.c b/drivers/net/wireless/virt_wifi.c
index 17dbc36..52f34b3 100644
--- a/drivers/net/wireless/virt_wifi.c
+++ b/drivers/net/wireless/virt_wifi.c
@@ -529,8 +529,10 @@
SET_NETDEV_DEV(dev, &priv->lowerdev->dev);
dev->ieee80211_ptr = kzalloc(sizeof(*dev->ieee80211_ptr), GFP_KERNEL);
- if (!dev->ieee80211_ptr)
+ if (!dev->ieee80211_ptr) {
+ err = -ENOMEM;
goto remove_handler;
+ }
dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION;
dev->ieee80211_ptr->wiphy = common_wiphy;
diff --git a/drivers/pci/host/vmd.c b/drivers/pci/host/vmd.c
index 0e7f8f3..9a60098 100644
--- a/drivers/pci/host/vmd.c
+++ b/drivers/pci/host/vmd.c
@@ -731,6 +731,11 @@
static int vmd_suspend(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
+ struct vmd_dev *vmd = pci_get_drvdata(pdev);
+ int i;
+
+ for (i = 0; i < vmd->msix_count; i++)
+ devm_free_irq(dev, pci_irq_vector(pdev, i), &vmd->irqs[i]);
pci_save_state(pdev);
return 0;
@@ -739,6 +744,16 @@
static int vmd_resume(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
+ struct vmd_dev *vmd = pci_get_drvdata(pdev);
+ int err, i;
+
+ for (i = 0; i < vmd->msix_count; i++) {
+ err = devm_request_irq(dev, pci_irq_vector(pdev, i),
+ vmd_irq, IRQF_NO_THREAD,
+ "vmd", &vmd->irqs[i]);
+ if (err)
+ return err;
+ }
pci_restore_state(pdev);
return 0;
diff --git a/drivers/pinctrl/meson/pinctrl-meson8.c b/drivers/pinctrl/meson/pinctrl-meson8.c
index 07f1cb2..0de7fa4 100644
--- a/drivers/pinctrl/meson/pinctrl-meson8.c
+++ b/drivers/pinctrl/meson/pinctrl-meson8.c
@@ -736,7 +736,9 @@
"BOOT_5", "BOOT_6", "BOOT_7", "BOOT_8", "BOOT_9",
"BOOT_10", "BOOT_11", "BOOT_12", "BOOT_13", "BOOT_14",
"BOOT_15", "BOOT_16", "BOOT_17", "BOOT_18",
+};
+static const char * const gpio_aobus_groups[] = {
"GPIOAO_0", "GPIOAO_1", "GPIOAO_2", "GPIOAO_3",
"GPIOAO_4", "GPIOAO_5", "GPIOAO_6", "GPIOAO_7",
"GPIOAO_8", "GPIOAO_9", "GPIOAO_10", "GPIOAO_11",
@@ -908,6 +910,7 @@
};
static struct meson_pmx_func meson8_aobus_functions[] = {
+ FUNCTION(gpio_aobus),
FUNCTION(uart_ao),
FUNCTION(remote),
FUNCTION(i2c_slave_ao),
diff --git a/drivers/pinctrl/meson/pinctrl-meson8b.c b/drivers/pinctrl/meson/pinctrl-meson8b.c
index f87ef5a..cbe5f5c 100644
--- a/drivers/pinctrl/meson/pinctrl-meson8b.c
+++ b/drivers/pinctrl/meson/pinctrl-meson8b.c
@@ -643,16 +643,18 @@
"BOOT_10", "BOOT_11", "BOOT_12", "BOOT_13", "BOOT_14",
"BOOT_15", "BOOT_16", "BOOT_17", "BOOT_18",
- "GPIOAO_0", "GPIOAO_1", "GPIOAO_2", "GPIOAO_3",
- "GPIOAO_4", "GPIOAO_5", "GPIOAO_6", "GPIOAO_7",
- "GPIOAO_8", "GPIOAO_9", "GPIOAO_10", "GPIOAO_11",
- "GPIOAO_12", "GPIOAO_13", "GPIO_BSD_EN", "GPIO_TEST_N",
-
"DIF_0_P", "DIF_0_N", "DIF_1_P", "DIF_1_N",
"DIF_2_P", "DIF_2_N", "DIF_3_P", "DIF_3_N",
"DIF_4_P", "DIF_4_N"
};
+static const char * const gpio_aobus_groups[] = {
+ "GPIOAO_0", "GPIOAO_1", "GPIOAO_2", "GPIOAO_3",
+ "GPIOAO_4", "GPIOAO_5", "GPIOAO_6", "GPIOAO_7",
+ "GPIOAO_8", "GPIOAO_9", "GPIOAO_10", "GPIOAO_11",
+ "GPIOAO_12", "GPIOAO_13", "GPIO_BSD_EN", "GPIO_TEST_N"
+};
+
static const char * const sd_a_groups[] = {
"sd_d0_a", "sd_d1_a", "sd_d2_a", "sd_d3_a", "sd_clk_a",
"sd_cmd_a"
@@ -868,6 +870,7 @@
};
static struct meson_pmx_func meson8b_aobus_functions[] = {
+ FUNCTION(gpio_aobus),
FUNCTION(uart_ao),
FUNCTION(uart_ao_b),
FUNCTION(i2c_slave_ao),
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c
index 4cf3aba..cef505b 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -1582,11 +1582,24 @@
return ret;
}
- ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev), 0, 0, chip->ngpio);
- if (ret) {
- dev_err(pctrl->dev, "Failed to add pin range\n");
- gpiochip_remove(&pctrl->chip);
- return ret;
+ /*
+ * For DeviceTree-supported systems, the gpio core checks the
+ * pinctrl's device node for the "gpio-ranges" property.
+ * If it is present, it takes care of adding the pin ranges
+ * for the driver. In this case the driver can skip ahead.
+ *
+ * In order to remain compatible with older, existing DeviceTree
+ * files which don't set the "gpio-ranges" property or systems that
+ * utilize ACPI the driver has to call gpiochip_add_pin_range().
+ */
+ if (!of_property_read_bool(pctrl->dev->of_node, "gpio-ranges")) {
+ ret = gpiochip_add_pin_range(&pctrl->chip,
+ dev_name(pctrl->dev), 0, 0, chip->ngpio);
+ if (ret) {
+ dev_err(pctrl->dev, "Failed to add pin range\n");
+ gpiochip_remove(&pctrl->chip);
+ return ret;
+ }
}
irq_parent = of_irq_find_parent(chip->of_node);
diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c
index a421d6c..ecb41ea 100644
--- a/drivers/ptp/ptp_chardev.c
+++ b/drivers/ptp/ptp_chardev.c
@@ -228,7 +228,9 @@
pct->sec = ts.tv_sec;
pct->nsec = ts.tv_nsec;
pct++;
- ptp->info->gettime64(ptp->info, &ts);
+ err = ptp->info->gettime64(ptp->info, &ts);
+ if (err)
+ goto out;
pct->sec = ts.tv_sec;
pct->nsec = ts.tv_nsec;
pct++;
@@ -281,6 +283,7 @@
break;
}
+out:
kfree(sysoff);
return err;
}
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index fc7adda..4905455 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -5396,6 +5396,9 @@
stat = (struct ls_rjt *)(pcmd + sizeof(uint32_t));
stat->un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
+ if (shdr_add_status == ADD_STATUS_OPERATION_ALREADY_ACTIVE)
+ stat->un.b.lsRjtRsnCodeExp = LSEXP_CMD_IN_PROGRESS;
+
elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
phba->fc_stat.elsXmitLSRJT++;
rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c
index b2b9699..06a0624 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -473,6 +473,7 @@
u8 driver_version_tag[2];
__le16 driver_version_length;
char driver_version[32];
+ u8 dont_write_tag[2];
u8 end_tag[2];
};
@@ -502,6 +503,8 @@
strncpy(buffer->driver_version, DRIVER_VERSION,
sizeof(buffer->driver_version) - 1);
buffer->driver_version[sizeof(buffer->driver_version) - 1] = '\0';
+ buffer->dont_write_tag[0] = 'D';
+ buffer->dont_write_tag[1] = 'W';
buffer->end_tag[0] = 'Z';
buffer->end_tag[1] = 'Z';
@@ -980,6 +983,9 @@
if (rc)
goto out;
+ if (vpd->page_code != CISS_VPD_LV_STATUS)
+ goto out;
+
page_length = offsetof(struct ciss_vpd_logical_volume_status,
volume_status) + vpd->page_length;
if (page_length < sizeof(*vpd))
diff --git a/drivers/soc/bcm/brcmstb/common.c b/drivers/soc/bcm/brcmstb/common.c
index 94e7335..3f6063b 100644
--- a/drivers/soc/bcm/brcmstb/common.c
+++ b/drivers/soc/bcm/brcmstb/common.c
@@ -31,13 +31,17 @@
bool soc_is_brcmstb(void)
{
+ const struct of_device_id *match;
struct device_node *root;
root = of_find_node_by_path("/");
if (!root)
return false;
- return of_match_node(brcmstb_machine_match, root) != NULL;
+ match = of_match_node(brcmstb_machine_match, root);
+ of_node_put(root);
+
+ return match != NULL;
}
static const struct of_device_id sun_top_ctrl_match[] = {
diff --git a/drivers/soc/tegra/common.c b/drivers/soc/tegra/common.c
index cd8f413..7bfb154 100644
--- a/drivers/soc/tegra/common.c
+++ b/drivers/soc/tegra/common.c
@@ -22,11 +22,15 @@
bool soc_is_tegra(void)
{
+ const struct of_device_id *match;
struct device_node *root;
root = of_find_node_by_path("/");
if (!root)
return false;
- return of_match_node(tegra_machine_match, root) != NULL;
+ match = of_match_node(tegra_machine_match, root);
+ of_node_put(root);
+
+ return match != NULL;
}
diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c
index b460dda..dec25fa 100644
--- a/drivers/staging/iio/adc/ad7280a.c
+++ b/drivers/staging/iio/adc/ad7280a.c
@@ -250,7 +250,9 @@
if (ret)
return ret;
- __ad7280_read32(st, &tmp);
+ ret = __ad7280_read32(st, &tmp);
+ if (ret)
+ return ret;
if (ad7280_check_crc(st, tmp))
return -EIO;
@@ -288,7 +290,9 @@
ad7280_delay(st);
- __ad7280_read32(st, &tmp);
+ ret = __ad7280_read32(st, &tmp);
+ if (ret)
+ return ret;
if (ad7280_check_crc(st, tmp))
return -EIO;
@@ -321,7 +325,9 @@
ad7280_delay(st);
for (i = 0; i < cnt; i++) {
- __ad7280_read32(st, &tmp);
+ ret = __ad7280_read32(st, &tmp);
+ if (ret)
+ return ret;
if (ad7280_check_crc(st, tmp))
return -EIO;
@@ -364,7 +370,10 @@
return ret;
for (n = 0; n <= AD7280A_MAX_CHAIN; n++) {
- __ad7280_read32(st, &val);
+ ret = __ad7280_read32(st, &val);
+ if (ret)
+ return ret;
+
if (val == 0)
return n - 1;
diff --git a/drivers/staging/iio/adc/ad7780.c b/drivers/staging/iio/adc/ad7780.c
index c9a0c2a..5d16338 100644
--- a/drivers/staging/iio/adc/ad7780.c
+++ b/drivers/staging/iio/adc/ad7780.c
@@ -87,12 +87,16 @@
long m)
{
struct ad7780_state *st = iio_priv(indio_dev);
+ int voltage_uv;
switch (m) {
case IIO_CHAN_INFO_RAW:
return ad_sigma_delta_single_conversion(indio_dev, chan, val);
case IIO_CHAN_INFO_SCALE:
- *val = st->int_vref_mv * st->gain;
+ voltage_uv = regulator_get_voltage(st->reg);
+ if (voltage_uv < 0)
+ return voltage_uv;
+ *val = (voltage_uv / 1000) * st->gain;
*val2 = chan->scan_type.realbits - 1;
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_CHAN_INFO_OFFSET:
diff --git a/drivers/staging/iio/resolver/ad2s90.c b/drivers/staging/iio/resolver/ad2s90.c
index 5b1c0db..b44253e 100644
--- a/drivers/staging/iio/resolver/ad2s90.c
+++ b/drivers/staging/iio/resolver/ad2s90.c
@@ -86,7 +86,12 @@
/* need 600ns between CS and the first falling edge of SCLK */
spi->max_speed_hz = 830000;
spi->mode = SPI_MODE_3;
- spi_setup(spi);
+ ret = spi_setup(spi);
+
+ if (ret < 0) {
+ dev_err(&spi->dev, "spi_setup failed!\n");
+ return ret;
+ }
return 0;
}
diff --git a/drivers/thermal/thermal-generic-adc.c b/drivers/thermal/thermal-generic-adc.c
index 73f55d6..ad601e5 100644
--- a/drivers/thermal/thermal-generic-adc.c
+++ b/drivers/thermal/thermal-generic-adc.c
@@ -26,7 +26,7 @@
static int gadc_thermal_adc_to_temp(struct gadc_thermal_info *gti, int val)
{
- int temp, adc_hi, adc_lo;
+ int temp, temp_hi, temp_lo, adc_hi, adc_lo;
int i;
for (i = 0; i < gti->nlookup_table; i++) {
@@ -36,13 +36,17 @@
if (i == 0) {
temp = gti->lookup_table[0];
- } else if (i >= (gti->nlookup_table - 1)) {
+ } else if (i >= gti->nlookup_table) {
temp = gti->lookup_table[2 * (gti->nlookup_table - 1)];
} else {
adc_hi = gti->lookup_table[2 * i - 1];
adc_lo = gti->lookup_table[2 * i + 1];
- temp = gti->lookup_table[2 * i];
- temp -= ((val - adc_lo) * 1000) / (adc_hi - adc_lo);
+
+ temp_hi = gti->lookup_table[2 * i - 2];
+ temp_lo = gti->lookup_table[2 * i];
+
+ temp = temp_hi + mult_frac(temp_lo - temp_hi, val - adc_hi,
+ adc_lo - adc_hi);
}
return temp;
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
old mode 100644
new mode 100755
index 98a59d7..6919082
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -608,16 +608,20 @@
store_temperature(tz, temp);
}
-static void thermal_zone_device_reset(struct thermal_zone_device *tz)
+static void thermal_zone_device_init(struct thermal_zone_device *tz)
{
struct thermal_instance *pos;
-
tz->temperature = THERMAL_TEMP_INVALID;
- tz->passive = 0;
list_for_each_entry(pos, &tz->thermal_instances, tz_node)
pos->initialized = false;
}
+static void thermal_zone_device_reset(struct thermal_zone_device *tz)
+{
+ tz->passive = 0;
+ thermal_zone_device_init(tz);
+}
+
void thermal_zone_device_update_temp(struct thermal_zone_device *tz,
enum thermal_notify_event event, int temp)
{
@@ -2620,7 +2624,7 @@
if (tz->ops->is_wakeable &&
tz->ops->is_wakeable(tz))
continue;
- thermal_zone_device_reset(tz);
+ thermal_zone_device_init(tz);
thermal_zone_device_update(tz,
THERMAL_EVENT_UNSPECIFIED);
}
diff --git a/drivers/thermal/thermal_hwmon.h b/drivers/thermal/thermal_hwmon.h
index c798fdb..f97f766 100644
--- a/drivers/thermal/thermal_hwmon.h
+++ b/drivers/thermal/thermal_hwmon.h
@@ -34,13 +34,13 @@
int thermal_add_hwmon_sysfs(struct thermal_zone_device *tz);
void thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz);
#else
-static int
+static inline int
thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
{
return 0;
}
-static void
+static inline void
thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
{
}
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index e2ec049..5c471c3 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -1344,6 +1344,8 @@
else
cr1 &= ~UARTCR1_PT;
}
+ } else {
+ cr1 &= ~UARTCR1_PE;
}
/* ask the core to calculate the divisor */
@@ -1487,6 +1489,8 @@
else
ctrl &= ~UARTCTRL_PT;
}
+ } else {
+ ctrl &= ~UARTCTRL_PE;
}
/* ask the core to calculate the divisor */
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index 5609305..01ff8ec 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -1335,11 +1335,14 @@
wr_regl(port, S3C2410_ULCON, ulcon);
wr_regl(port, S3C2410_UBRDIV, quot);
+ port->status &= ~UPSTAT_AUTOCTS;
+
umcon = rd_regl(port, S3C2410_UMCON);
if (termios->c_cflag & CRTSCTS) {
umcon |= S3C2410_UMCOM_AFC;
/* Disable RTS when RX FIFO contains 63 bytes */
umcon &= ~S3C2412_UMCON_AFC_8;
+ port->status = UPSTAT_AUTOCTS;
} else {
umcon &= ~S3C2410_UMCOM_AFC;
}
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index d04a956..2a5979f 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -144,6 +144,9 @@
struct uart_port *port;
unsigned long flags;
+ if (!state)
+ return;
+
port = uart_port_lock(state, flags);
__uart_start(tty);
uart_port_unlock(port, flags);
@@ -720,6 +723,9 @@
struct uart_port *port;
upstat_t mask = 0;
+ if (!state)
+ return;
+
port = uart_port_ref(state);
if (!port)
return;
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 86f251e..0ff6ae3 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1119,6 +1119,16 @@
USB_PORT_FEAT_ENABLE);
}
+ /*
+ * Add debounce if USB3 link is in polling/link training state.
+ * Link will automatically transition to Enabled state after
+ * link training completes.
+ */
+ if (hub_is_superspeed(hdev) &&
+ ((portstatus & USB_PORT_STAT_LINK_STATE) ==
+ USB_SS_PORT_LS_POLLING))
+ need_debounce_delay = true;
+
/* Clear status-change flags; we'll debounce later */
if (portchange & USB_PORT_STAT_C_CONNECTION) {
need_debounce_delay = true;
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 984d6aa..0e54353 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -5202,7 +5202,6 @@
error2:
usb_put_hcd(hcd);
error1:
- kfree(hsotg->core_params);
#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
kfree(hsotg->last_frame_num_array);
diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c
index 7c61134..40396a2 100644
--- a/drivers/usb/gadget/udc/net2272.c
+++ b/drivers/usb/gadget/udc/net2272.c
@@ -2096,7 +2096,7 @@
#if defined(PLX_PCI_RDK2)
/* see if PCI int for us by checking irqstat */
intcsr = readl(dev->rdk2.fpga_base_addr + RDK2_IRQSTAT);
- if (!intcsr & (1 << NET2272_PCI_IRQ)) {
+ if (!(intcsr & (1 << NET2272_PCI_IRQ))) {
spin_unlock(&dev->lock);
return IRQ_NONE;
}
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index f1219f6..60540a8 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -477,13 +477,10 @@
}
if (request) {
- u8 is_dma = 0;
- bool short_packet = false;
trace_musb_req_tx(req);
if (dma && (csr & MUSB_TXCSR_DMAENAB)) {
- is_dma = 1;
csr |= MUSB_TXCSR_P_WZC_BITS;
csr &= ~(MUSB_TXCSR_DMAENAB | MUSB_TXCSR_P_UNDERRUN |
MUSB_TXCSR_TXPKTRDY | MUSB_TXCSR_AUTOSET);
@@ -501,16 +498,8 @@
*/
if ((request->zero && request->length)
&& (request->length % musb_ep->packet_sz == 0)
- && (request->actual == request->length))
- short_packet = true;
+ && (request->actual == request->length)) {
- if ((musb_dma_inventra(musb) || musb_dma_ux500(musb)) &&
- (is_dma && (!dma->desired_mode ||
- (request->actual &
- (musb_ep->packet_sz - 1)))))
- short_packet = true;
-
- if (short_packet) {
/*
* On DMA completion, FIFO may not be
* available yet...
diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c
index 3620073..512108e 100644
--- a/drivers/usb/musb/musbhsdma.c
+++ b/drivers/usb/musb/musbhsdma.c
@@ -320,12 +320,10 @@
channel->status = MUSB_DMA_STATUS_FREE;
/* completed */
- if ((devctl & MUSB_DEVCTL_HM)
- && (musb_channel->transmit)
- && ((channel->desired_mode == 0)
- || (channel->actual_len &
- (musb_channel->max_packet_sz - 1)))
- ) {
+ if (musb_channel->transmit &&
+ (!channel->desired_mode ||
+ (channel->actual_len %
+ musb_channel->max_packet_sz))) {
u8 epnum = musb_channel->epnum;
int offset = musb->io.ep_offset(epnum,
MUSB_TXCSR);
@@ -337,11 +335,14 @@
*/
musb_ep_select(mbase, epnum);
txcsr = musb_readw(mbase, offset);
- txcsr &= ~(MUSB_TXCSR_DMAENAB
+ if (channel->desired_mode == 1) {
+ txcsr &= ~(MUSB_TXCSR_DMAENAB
| MUSB_TXCSR_AUTOSET);
- musb_writew(mbase, offset, txcsr);
- /* Send out the packet */
- txcsr &= ~MUSB_TXCSR_DMAMODE;
+ musb_writew(mbase, offset, txcsr);
+ /* Send out the packet */
+ txcsr &= ~MUSB_TXCSR_DMAMODE;
+ txcsr |= MUSB_TXCSR_DMAENAB;
+ }
txcsr |= MUSB_TXCSR_TXPKTRDY;
musb_writew(mbase, offset, txcsr);
}
diff --git a/drivers/usb/phy/phy-am335x.c b/drivers/usb/phy/phy-am335x.c
index 7e5aece..cb1382a 100644
--- a/drivers/usb/phy/phy-am335x.c
+++ b/drivers/usb/phy/phy-am335x.c
@@ -60,9 +60,6 @@
if (ret)
return ret;
- ret = usb_add_phy_dev(&am_phy->usb_phy_gen.phy);
- if (ret)
- return ret;
am_phy->usb_phy_gen.phy.init = am335x_init;
am_phy->usb_phy_gen.phy.shutdown = am335x_shutdown;
@@ -81,7 +78,7 @@
device_set_wakeup_enable(dev, false);
phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, am_phy->dr_mode, false);
- return 0;
+ return usb_add_phy_dev(&am_phy->usb_phy_gen.phy);
}
static int am335x_phy_remove(struct platform_device *pdev)
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index dc387a9..2383caf 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -1696,7 +1696,7 @@
ret = translate_desc(vq, (uintptr_t)vq->used + used_offset,
len, iov, 64, VHOST_ACCESS_WO);
- if (ret)
+ if (ret < 0)
return ret;
for (i = 0; i < ret; i++) {
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 4db10d7..178b507 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -3030,7 +3030,7 @@
for (i = first_fb_vc; i <= last_fb_vc; i++) {
if (con2fb_map[i] != idx &&
con2fb_map[i] != -1) {
- new_idx = i;
+ new_idx = con2fb_map[i];
break;
}
}
diff --git a/drivers/video/fbdev/clps711x-fb.c b/drivers/video/fbdev/clps711x-fb.c
index ff56107..42f9096 100644
--- a/drivers/video/fbdev/clps711x-fb.c
+++ b/drivers/video/fbdev/clps711x-fb.c
@@ -287,14 +287,17 @@
}
ret = of_get_fb_videomode(disp, &cfb->mode, OF_USE_NATIVE_MODE);
- if (ret)
+ if (ret) {
+ of_node_put(disp);
goto out_fb_release;
+ }
of_property_read_u32(disp, "ac-prescale", &cfb->ac_prescale);
cfb->cmap_invert = of_property_read_bool(disp, "cmap-invert");
ret = of_property_read_u32(disp, "bits-per-pixel",
&info->var.bits_per_pixel);
+ of_node_put(disp);
if (ret)
goto out_fb_release;
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index b2c8819..0dcdca1 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -433,7 +433,9 @@
image->dx += image->width + 8;
}
} else if (rotate == FB_ROTATE_UD) {
- for (x = 0; x < num; x++) {
+ u32 dx = image->dx;
+
+ for (x = 0; x < num && image->dx <= dx; x++) {
info->fbops->fb_imageblit(info, image);
image->dx -= image->width + 8;
}
@@ -445,7 +447,9 @@
image->dy += image->height + 8;
}
} else if (rotate == FB_ROTATE_CCW) {
- for (x = 0; x < num; x++) {
+ u32 dy = image->dy;
+
+ for (x = 0; x < num && image->dy <= dy; x++) {
info->fbops->fb_imageblit(info, image);
image->dy -= image->height + 8;
}
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 1a45df7..f605bfa 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -4452,29 +4452,25 @@
}
/*
- * Sanity check for fiemap cache
+ * Emit last fiemap cache
*
- * All fiemap cache should be submitted by emit_fiemap_extent()
- * Iteration should be terminated either by last fiemap extent or
- * fieinfo->fi_extents_max.
- * So no cached fiemap should exist.
+ * The last fiemap cache may still be cached in the following case:
+ * 0 4k 8k
+ * |<- Fiemap range ->|
+ * |<------------ First extent ----------->|
+ *
+ * In this case, the first extent range will be cached but not emitted.
+ * So we must emit it before ending extent_fiemap().
*/
-static int check_fiemap_cache(struct btrfs_fs_info *fs_info,
- struct fiemap_extent_info *fieinfo,
- struct fiemap_cache *cache)
+static int emit_last_fiemap_cache(struct btrfs_fs_info *fs_info,
+ struct fiemap_extent_info *fieinfo,
+ struct fiemap_cache *cache)
{
int ret;
if (!cache->cached)
return 0;
- /* Small and recoverbale problem, only to info developer */
-#ifdef CONFIG_BTRFS_DEBUG
- WARN_ON(1);
-#endif
- btrfs_warn(fs_info,
- "unhandled fiemap cache detected: offset=%llu phys=%llu len=%llu flags=0x%x",
- cache->offset, cache->phys, cache->len, cache->flags);
ret = fiemap_fill_next_extent(fieinfo, cache->offset, cache->phys,
cache->len, cache->flags);
cache->cached = false;
@@ -4690,7 +4686,7 @@
}
out_free:
if (!ret)
- ret = check_fiemap_cache(root->fs_info, fieinfo, &cache);
+ ret = emit_last_fiemap_cache(root->fs_info, fieinfo, &cache);
free_extent_map(em);
out:
btrfs_free_path(path);
diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig
index 8bef27b..e7b478b 100644
--- a/fs/cifs/Kconfig
+++ b/fs/cifs/Kconfig
@@ -111,7 +111,7 @@
config CIFS_POSIX
bool "CIFS POSIX Extensions"
- depends on CIFS && CIFS_ALLOW_INSECURE_LEGACY && CIFS_XATTR
+ depends on CIFS_XATTR
help
Enabling this option will cause the cifs client to attempt to
negotiate a newer dialect with servers, such as Samba 3.0.5
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index a3046b6..8ec2963 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1126,6 +1126,10 @@
return -EINVAL;
}
+ BUILD_BUG_ON(sizeof(struct smb_hdr) + sizeof(LOCKING_ANDX_RANGE) >
+ PAGE_SIZE);
+ max_buf = min_t(unsigned int, max_buf - sizeof(struct smb_hdr),
+ PAGE_SIZE);
max_num = (max_buf - sizeof(struct smb_hdr)) /
sizeof(LOCKING_ANDX_RANGE);
buf = kcalloc(max_num, sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL);
@@ -1462,6 +1466,10 @@
if (max_buf < (sizeof(struct smb_hdr) + sizeof(LOCKING_ANDX_RANGE)))
return -EINVAL;
+ BUILD_BUG_ON(sizeof(struct smb_hdr) + sizeof(LOCKING_ANDX_RANGE) >
+ PAGE_SIZE);
+ max_buf = min_t(unsigned int, max_buf - sizeof(struct smb_hdr),
+ PAGE_SIZE);
max_num = (max_buf - sizeof(struct smb_hdr)) /
sizeof(LOCKING_ANDX_RANGE);
buf = kcalloc(max_num, sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL);
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index ef24b45..6818387 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -655,7 +655,14 @@
/* scan and find it */
int i;
char *cur_ent;
- char *end_of_smb = cfile->srch_inf.ntwrk_buf_start +
+ char *end_of_smb;
+
+ if (cfile->srch_inf.ntwrk_buf_start == NULL) {
+ cifs_dbg(VFS, "ntwrk_buf_start is NULL during readdir\n");
+ return -EIO;
+ }
+
+ end_of_smb = cfile->srch_inf.ntwrk_buf_start +
server->ops->calc_smb_size(
cfile->srch_inf.ntwrk_buf_start);
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c
index b7885dc0d..dee5250 100644
--- a/fs/cifs/smb2file.c
+++ b/fs/cifs/smb2file.c
@@ -129,6 +129,8 @@
if (max_buf < sizeof(struct smb2_lock_element))
return -EINVAL;
+ BUILD_BUG_ON(sizeof(struct smb2_lock_element) > PAGE_SIZE);
+ max_buf = min_t(unsigned int, max_buf, PAGE_SIZE);
max_num = max_buf / sizeof(struct smb2_lock_element);
buf = kcalloc(max_num, sizeof(struct smb2_lock_element), GFP_KERNEL);
if (!buf)
@@ -265,6 +267,8 @@
return -EINVAL;
}
+ BUILD_BUG_ON(sizeof(struct smb2_lock_element) > PAGE_SIZE);
+ max_buf = min_t(unsigned int, max_buf, PAGE_SIZE);
max_num = max_buf / sizeof(struct smb2_lock_element);
buf = kcalloc(max_num, sizeof(struct smb2_lock_element), GFP_KERNEL);
if (!buf) {
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index f7f672d..ab8b867 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -760,6 +760,13 @@
struct dentry *dentry = NULL, *trap;
struct name_snapshot old_name;
+ if (IS_ERR(old_dir))
+ return old_dir;
+ if (IS_ERR(new_dir))
+ return new_dir;
+ if (IS_ERR_OR_NULL(old_dentry))
+ return old_dentry;
+
trap = lock_rename(new_dir, old_dir);
/* Source or destination directories don't exist? */
if (d_really_is_negative(old_dir) || d_really_is_negative(new_dir))
diff --git a/fs/dlm/ast.c b/fs/dlm/ast.c
index dcea1e3..f18619b 100644
--- a/fs/dlm/ast.c
+++ b/fs/dlm/ast.c
@@ -290,6 +290,8 @@
flush_workqueue(ls->ls_callback_wq);
}
+#define MAX_CB_QUEUE 25
+
void dlm_callback_resume(struct dlm_ls *ls)
{
struct dlm_lkb *lkb, *safe;
@@ -300,15 +302,23 @@
if (!ls->ls_callback_wq)
return;
+more:
mutex_lock(&ls->ls_cb_mutex);
list_for_each_entry_safe(lkb, safe, &ls->ls_cb_delay, lkb_cb_list) {
list_del_init(&lkb->lkb_cb_list);
queue_work(ls->ls_callback_wq, &lkb->lkb_cb_work);
count++;
+ if (count == MAX_CB_QUEUE)
+ break;
}
mutex_unlock(&ls->ls_cb_mutex);
if (count)
log_rinfo(ls, "dlm_callback_resume %d", count);
+ if (count == MAX_CB_QUEUE) {
+ count = 0;
+ cond_resched();
+ goto more;
+ }
}
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index 5b96ba7..e76d0c3 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -1041,7 +1041,7 @@
* semantics). All the events that happen during that period of time are
* chained in ep->ovflist and requeued later on.
*/
- if (unlikely(ep->ovflist != EP_UNACTIVE_PTR)) {
+ if (ep->ovflist != EP_UNACTIVE_PTR) {
if (epi->next == EP_UNACTIVE_PTR) {
epi->next = ep->ovflist;
ep->ovflist = epi;
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 3b094e3..c33cb1f 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -1695,7 +1695,6 @@
req->in.h.nodeid = outarg->nodeid;
req->in.numargs = 2;
req->in.argpages = 1;
- req->page_descs[0].offset = offset;
req->end = fuse_retrieve_end;
index = outarg->offset >> PAGE_SHIFT;
@@ -1710,6 +1709,7 @@
this_num = min_t(unsigned, num, PAGE_SIZE - offset);
req->pages[req->num_pages] = page;
+ req->page_descs[req->num_pages].offset = offset;
req->page_descs[req->num_pages].length = this_num;
req->num_pages++;
@@ -2037,8 +2037,10 @@
ret = fuse_dev_do_write(fud, &cs, len);
+ pipe_lock(pipe);
for (idx = 0; idx < nbuf; idx++)
pipe_buf_release(pipe, &bufs[idx]);
+ pipe_unlock(pipe);
out:
kfree(bufs);
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index a474c66..3541710 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1803,7 +1803,7 @@
spin_unlock(&fc->lock);
dec_wb_stat(&bdi->wb, WB_WRITEBACK);
- dec_node_page_state(page, NR_WRITEBACK_TEMP);
+ dec_node_page_state(new_req->pages[0], NR_WRITEBACK_TEMP);
wb_writeout_inc(&bdi->wb);
fuse_writepage_free(fc, new_req);
fuse_request_free(new_req);
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 2fdb8f5..35aef19 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -2403,8 +2403,7 @@
goto Ebusy;
if (a->acdirmax != b->acdirmax)
goto Ebusy;
- if (b->auth_info.flavor_len > 0 &&
- clnt_a->cl_auth->au_flavor != clnt_b->cl_auth->au_flavor)
+ if (clnt_a->cl_auth->au_flavor != clnt_b->cl_auth->au_flavor)
goto Ebusy;
return 1;
Ebusy:
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 12d7807..3656f87 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1472,8 +1472,10 @@
{
int i;
- for (i = 0; i < ses->se_fchannel.maxreqs; i++)
+ for (i = 0; i < ses->se_fchannel.maxreqs; i++) {
+ free_svc_cred(&ses->se_slots[i]->sl_cred);
kfree(ses->se_slots[i]);
+ }
}
/*
@@ -2344,14 +2346,18 @@
dprintk("--> %s slot %p\n", __func__, slot);
+ slot->sl_flags |= NFSD4_SLOT_INITIALIZED;
slot->sl_opcnt = resp->opcnt;
slot->sl_status = resp->cstate.status;
+ free_svc_cred(&slot->sl_cred);
+ copy_cred(&slot->sl_cred, &resp->rqstp->rq_cred);
- slot->sl_flags |= NFSD4_SLOT_INITIALIZED;
- if (nfsd4_not_cached(resp)) {
- slot->sl_datalen = 0;
+ if (!nfsd4_cache_this(resp)) {
+ slot->sl_flags &= ~NFSD4_SLOT_CACHED;
return;
}
+ slot->sl_flags |= NFSD4_SLOT_CACHED;
+
base = resp->cstate.data_offset;
slot->sl_datalen = buf->len - base;
if (read_bytes_from_xdr_buf(buf, base, slot->sl_data, slot->sl_datalen))
@@ -2378,8 +2384,16 @@
op = &args->ops[resp->opcnt - 1];
nfsd4_encode_operation(resp, op);
- /* Return nfserr_retry_uncached_rep in next operation. */
- if (args->opcnt > 1 && !(slot->sl_flags & NFSD4_SLOT_CACHETHIS)) {
+ if (slot->sl_flags & NFSD4_SLOT_CACHED)
+ return op->status;
+ if (args->opcnt == 1) {
+ /*
+ * The original operation wasn't a solo sequence--we
+ * always cache those--so this retry must not match the
+ * original:
+ */
+ op->status = nfserr_seq_false_retry;
+ } else {
op = &args->ops[resp->opcnt++];
op->status = nfserr_retry_uncached_rep;
nfsd4_encode_operation(resp, op);
@@ -3039,6 +3053,34 @@
return xb->len > session->se_fchannel.maxreq_sz;
}
+static bool replay_matches_cache(struct svc_rqst *rqstp,
+ struct nfsd4_sequence *seq, struct nfsd4_slot *slot)
+{
+ struct nfsd4_compoundargs *argp = rqstp->rq_argp;
+
+ if ((bool)(slot->sl_flags & NFSD4_SLOT_CACHETHIS) !=
+ (bool)seq->cachethis)
+ return false;
+ /*
+ * If there's an error than the reply can have fewer ops than
+ * the call. But if we cached a reply with *more* ops than the
+ * call you're sending us now, then this new call is clearly not
+ * really a replay of the old one:
+ */
+ if (slot->sl_opcnt < argp->opcnt)
+ return false;
+ /* This is the only check explicitly called by spec: */
+ if (!same_creds(&rqstp->rq_cred, &slot->sl_cred))
+ return false;
+ /*
+ * There may be more comparisons we could actually do, but the
+ * spec doesn't require us to catch every case where the calls
+ * don't match (that would require caching the call as well as
+ * the reply), so we don't bother.
+ */
+ return true;
+}
+
__be32
nfsd4_sequence(struct svc_rqst *rqstp,
struct nfsd4_compound_state *cstate,
@@ -3098,6 +3140,9 @@
status = nfserr_seq_misordered;
if (!(slot->sl_flags & NFSD4_SLOT_INITIALIZED))
goto out_put_session;
+ status = nfserr_seq_false_retry;
+ if (!replay_matches_cache(rqstp, seq, slot))
+ goto out_put_session;
cstate->slot = slot;
cstate->session = session;
cstate->clp = clp;
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 36b2af9..797a155 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -1103,6 +1103,8 @@
case 'Y':
case 'y':
case '1':
+ if (nn->nfsd_serv)
+ return -EBUSY;
nfsd4_end_grace(nn);
break;
default:
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 005c911..86aa92d 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -169,11 +169,13 @@
struct nfsd4_slot {
u32 sl_seqid;
__be32 sl_status;
+ struct svc_cred sl_cred;
u32 sl_datalen;
u16 sl_opcnt;
#define NFSD4_SLOT_INUSE (1 << 0)
#define NFSD4_SLOT_CACHETHIS (1 << 1)
#define NFSD4_SLOT_INITIALIZED (1 << 2)
+#define NFSD4_SLOT_CACHED (1 << 3)
u8 sl_flags;
char sl_data[];
};
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 8fda4ab..448e74e 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -645,9 +645,18 @@
return resp->opcnt == 1 && args->ops[0].opnum == OP_SEQUENCE;
}
-static inline bool nfsd4_not_cached(struct nfsd4_compoundres *resp)
+/*
+ * The session reply cache only needs to cache replies that the client
+ * actually asked us to. But it's almost free for us to cache compounds
+ * consisting of only a SEQUENCE op, so we may as well cache those too.
+ * Also, the protocol doesn't give us a convenient response in the case
+ * of a replay of a solo SEQUENCE op that wasn't cached
+ * (RETRY_UNCACHED_REP can only be returned in the second op of a
+ * compound).
+ */
+static inline bool nfsd4_cache_this(struct nfsd4_compoundres *resp)
{
- return !(resp->cstate.slot->sl_flags & NFSD4_SLOT_CACHETHIS)
+ return (resp->cstate.slot->sl_flags & NFSD4_SLOT_CACHETHIS)
|| nfsd4_is_solo_sequence(resp);
}
diff --git a/fs/ocfs2/buffer_head_io.c b/fs/ocfs2/buffer_head_io.c
index 25c8b32..935bac2 100644
--- a/fs/ocfs2/buffer_head_io.c
+++ b/fs/ocfs2/buffer_head_io.c
@@ -151,7 +151,6 @@
#endif
}
- clear_buffer_uptodate(bh);
get_bh(bh); /* for end_buffer_read_sync() */
bh->b_end_io = end_buffer_read_sync;
submit_bh(REQ_OP_READ, 0, bh);
@@ -305,7 +304,6 @@
continue;
}
- clear_buffer_uptodate(bh);
get_bh(bh); /* for end_buffer_read_sync() */
if (validate)
set_buffer_needs_validate(bh);
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index 0359435..fd81702 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -1372,6 +1372,12 @@
iinfo->i_alloc_type = le16_to_cpu(fe->icbTag.flags) &
ICBTAG_FLAG_AD_MASK;
+ if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_SHORT &&
+ iinfo->i_alloc_type != ICBTAG_FLAG_AD_LONG &&
+ iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
+ ret = -EIO;
+ goto out;
+ }
iinfo->i_unique = 0;
iinfo->i_lenEAttr = 0;
iinfo->i_lenExtents = 0;
diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c
index 00b661d..3fb4769 100644
--- a/fs/userfaultfd.c
+++ b/fs/userfaultfd.c
@@ -834,6 +834,18 @@
goto out_unlock;
/*
+ * UFFDIO_COPY will fill file holes even without
+ * PROT_WRITE. This check enforces that if this is a
+ * MAP_SHARED, the process has write permission to the backing
+ * file. If VM_MAYWRITE is set it also enforces that on a
+ * MAP_SHARED vma: there is no F_WRITE_SEAL and no further
+ * F_WRITE_SEAL can be taken until the vma is destroyed.
+ */
+ ret = -EPERM;
+ if (unlikely(!(cur->vm_flags & VM_MAYWRITE)))
+ goto out_unlock;
+
+ /*
* Check that this vma isn't already owned by a
* different userfaultfd. We can't allow more than one
* userfaultfd to own a single vma simultaneously or we
@@ -858,6 +870,7 @@
BUG_ON(vma->vm_ops);
BUG_ON(vma->vm_userfaultfd_ctx.ctx &&
vma->vm_userfaultfd_ctx.ctx != ctx);
+ WARN_ON(!(vma->vm_flags & VM_MAYWRITE));
/*
* Nothing to do: this vma is already registered into this
@@ -999,6 +1012,7 @@
cond_resched();
BUG_ON(vma->vm_ops);
+ WARN_ON(!(vma->vm_flags & VM_MAYWRITE));
/*
* Nothing to do: this vma is already registered into this
diff --git a/include/linux/genl_magic_struct.h b/include/linux/genl_magic_struct.h
index 6270a56..d0d6fdc 100644
--- a/include/linux/genl_magic_struct.h
+++ b/include/linux/genl_magic_struct.h
@@ -190,6 +190,7 @@
{
switch (0) {
#include GENL_MAGIC_INCLUDE_FILE
+ case 0:
;
}
}
@@ -208,6 +209,7 @@
{
switch (0) {
#include GENL_MAGIC_INCLUDE_FILE
+ case 0:
;
}
}
@@ -217,7 +219,8 @@
static inline void ct_assert_unique_ ## s_name ## _attributes(void) \
{ \
switch (0) { \
- s_fields \
+ s_fields \
+ case 0: \
; \
} \
}
diff --git a/include/linux/hid-debug.h b/include/linux/hid-debug.h
index 8663f21..2d6100e 100644
--- a/include/linux/hid-debug.h
+++ b/include/linux/hid-debug.h
@@ -24,7 +24,10 @@
#ifdef CONFIG_DEBUG_FS
+#include <linux/kfifo.h>
+
#define HID_DEBUG_BUFSIZE 512
+#define HID_DEBUG_FIFOSIZE 512
void hid_dump_input(struct hid_device *, struct hid_usage *, __s32);
void hid_dump_report(struct hid_device *, int , u8 *, int);
@@ -37,11 +40,8 @@
void hid_debug_exit(void);
void hid_debug_event(struct hid_device *, char *);
-
struct hid_debug_list {
- char *hid_debug_buf;
- int head;
- int tail;
+ DECLARE_KFIFO_PTR(hid_debug_fifo, char);
struct fasync_struct *fasync;
struct hid_device *hdev;
struct list_head node;
@@ -64,4 +64,3 @@
#endif
#endif
-
diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h
index 9c6c8ef..b692ede 100644
--- a/include/linux/netdev_features.h
+++ b/include/linux/netdev_features.h
@@ -11,6 +11,8 @@
#define _LINUX_NETDEV_FEATURES_H
#include <linux/types.h>
+#include <linux/bitops.h>
+#include <asm/byteorder.h>
typedef u64 netdev_features_t;
@@ -137,8 +139,26 @@
#define NETIF_F_BUSY_POLL __NETIF_F(BUSY_POLL)
#define NETIF_F_HW_TC __NETIF_F(HW_TC)
-#define for_each_netdev_feature(mask_addr, bit) \
- for_each_set_bit(bit, (unsigned long *)mask_addr, NETDEV_FEATURE_COUNT)
+/* Finds the next feature with the highest number of the range of start till 0.
+ */
+static inline int find_next_netdev_feature(u64 feature, unsigned long start)
+{
+ /* like BITMAP_LAST_WORD_MASK() for u64
+ * this sets the most significant 64 - start to 0.
+ */
+ feature &= ~0ULL >> (-start & ((sizeof(feature) * 8) - 1));
+
+ return fls64(feature) - 1;
+}
+
+/* This goes for the MSB to the LSB through the set feature bits,
+ * mask_addr should be a u64 and bit an int
+ */
+#define for_each_netdev_feature(mask_addr, bit) \
+ for ((bit) = find_next_netdev_feature((mask_addr), \
+ NETDEV_FEATURE_COUNT); \
+ (bit) >= 0; \
+ (bit) = find_next_netdev_feature((mask_addr), (bit) - 1))
/* Features valid for ethtool to change */
/* = all defined minus driver/device-class-related */
diff --git a/include/linux/netfilter/xt_qtaguid.h b/include/linux/netfilter/xt_qtaguid.h
deleted file mode 100644
index 1c67155..0000000
--- a/include/linux/netfilter/xt_qtaguid.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef _XT_QTAGUID_MATCH_H
-#define _XT_QTAGUID_MATCH_H
-
-/* For now we just replace the xt_owner.
- * FIXME: make iptables aware of qtaguid. */
-#include <linux/netfilter/xt_owner.h>
-
-#define XT_QTAGUID_UID XT_OWNER_UID
-#define XT_QTAGUID_GID XT_OWNER_GID
-#define XT_QTAGUID_SOCKET XT_OWNER_SOCKET
-#define xt_qtaguid_match_info xt_owner_match_info
-
-int qtaguid_untag(struct socket *sock, bool kernel);
-#endif /* _XT_QTAGUID_MATCH_H */
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 29dedd4..667f7e8 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -457,6 +457,11 @@
* Filter events for PMU-specific reasons.
*/
int (*filter_match) (struct perf_event *event); /* optional */
+
+ /*
+ * Check period value for PERF_EVENT_IOC_PERIOD ioctl.
+ */
+ int (*check_period) (struct perf_event *event, u64 value); /* optional */
};
/**
diff --git a/include/linux/sched.h b/include/linux/sched.h
old mode 100644
new mode 100755
index 153f173..3b2f96a
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -637,6 +637,7 @@
#define MMF_UNSTABLE 22 /* mm is unstable for copy_from_user */
#define MMF_HUGE_ZERO_PAGE 23 /* mm has ever used the global huge zero page */
#define MMF_OOM_VICTIM 25 /* mm is the oom victim */
+#define MMF_OOM_REAP_QUEUED 26 /* mm was queued for oom_reaper */
#define MMF_INIT_MASK (MMF_DUMPABLE_MASK | MMF_DUMP_FILTER_MASK)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 9dd4edf..4a6c87d 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -3106,6 +3106,7 @@
void skb_scrub_packet(struct sk_buff *skb, bool xnet);
unsigned int skb_gso_transport_seglen(const struct sk_buff *skb);
bool skb_gso_validate_mtu(const struct sk_buff *skb, unsigned int mtu);
+bool skb_gso_validate_mac_len(const struct sk_buff *skb, unsigned int len);
struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features);
struct sk_buff *skb_vlan_untag(struct sk_buff *skb);
int skb_ensure_writable(struct sk_buff *skb, int write_len);
@@ -3884,6 +3885,21 @@
return hdr_len + skb_gso_transport_seglen(skb);
}
+/**
+ * skb_gso_mac_seglen - Return length of individual segments of a gso packet
+ *
+ * @skb: GSO skb
+ *
+ * skb_gso_mac_seglen is used to determine the real size of the
+ * individual segments, including MAC/L2, Layer3 (IP, IPv6) and L4
+ * headers (TCP/UDP).
+ */
+static inline unsigned int skb_gso_mac_seglen(const struct sk_buff *skb)
+{
+ unsigned int hdr_len = skb_transport_header(skb) - skb_mac_header(skb);
+ return hdr_len + skb_gso_transport_seglen(skb);
+}
+
/* Local Checksum Offload.
* Compute outer checksum based on the assumption that the
* inner checksum will be offloaded later.
diff --git a/include/net/ax25.h b/include/net/ax25.h
index e602f81..b507ce2 100644
--- a/include/net/ax25.h
+++ b/include/net/ax25.h
@@ -199,6 +199,18 @@
void __ax25_put_route(ax25_route *ax25_rt);
+extern rwlock_t ax25_route_lock;
+
+static inline void ax25_route_lock_use(void)
+{
+ read_lock(&ax25_route_lock);
+}
+
+static inline void ax25_route_lock_unuse(void)
+{
+ read_unlock(&ax25_route_lock);
+}
+
static inline void ax25_put_route(ax25_route *ax25_rt)
{
if (atomic_dec_and_test(&ax25_rt->refcount))
diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h
index 235c781..408d76f 100644
--- a/include/net/inetpeer.h
+++ b/include/net/inetpeer.h
@@ -40,6 +40,7 @@
u32 metrics[RTAX_MAX];
u32 rate_tokens; /* rate limiting for ICMP */
+ u32 n_redirects;
unsigned long rate_last;
union {
struct list_head gc_list;
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index b02af0b..66f6b84 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -87,6 +87,35 @@
};
};
+/* Store/load an u16 or u8 integer to/from the u32 data register.
+ *
+ * Note, when using concatenations, register allocation happens at 32-bit
+ * level. So for store instruction, pad the rest part with zero to avoid
+ * garbage values.
+ */
+
+static inline void nft_reg_store16(u32 *dreg, u16 val)
+{
+ *dreg = 0;
+ *(u16 *)dreg = val;
+}
+
+static inline void nft_reg_store8(u32 *dreg, u8 val)
+{
+ *dreg = 0;
+ *(u8 *)dreg = val;
+}
+
+static inline u16 nft_reg_load16(u32 *sreg)
+{
+ return *(u16 *)sreg;
+}
+
+static inline u8 nft_reg_load8(u32 *sreg)
+{
+ return *(u8 *)sreg;
+}
+
static inline void nft_data_copy(u32 *dst, const struct nft_data *src,
unsigned int len)
{
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 1f5ddaf..96c2b19 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1545,6 +1545,7 @@
sk_wmem_free_skb(sk, skb);
sk_mem_reclaim(sk);
tcp_clear_all_retrans_hints(tcp_sk(sk));
+ inet_csk(sk)->icsk_backoff = 0;
}
static inline struct sk_buff *tcp_write_queue_head(const struct sock *sk)
diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h
index e5cbe27..fa86f45 100644
--- a/include/sound/compress_driver.h
+++ b/include/sound/compress_driver.h
@@ -191,7 +191,11 @@
if (snd_BUG_ON(!stream))
return;
- stream->runtime->state = SNDRV_PCM_STATE_SETUP;
+ if (stream->direction == SND_COMPRESS_PLAYBACK)
+ stream->runtime->state = SNDRV_PCM_STATE_SETUP;
+ else
+ stream->runtime->state = SNDRV_PCM_STATE_PREPARED;
+
wake_up(&stream->runtime->sleep);
}
diff --git a/include/uapi/linux/if_ether.h b/include/uapi/linux/if_ether.h
index 6475a16..bd32040 100644
--- a/include/uapi/linux/if_ether.h
+++ b/include/uapi/linux/if_ether.h
@@ -141,11 +141,18 @@
* This is an Ethernet frame header.
*/
+/* allow libcs like musl to deactivate this, glibc does not implement this. */
+#ifndef __UAPI_DEF_ETHHDR
+#define __UAPI_DEF_ETHHDR 1
+#endif
+
+#if __UAPI_DEF_ETHHDR
struct ethhdr {
unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
unsigned char h_source[ETH_ALEN]; /* source ether addr */
__be16 h_proto; /* packet type ID field */
} __attribute__((packed));
+#endif
#endif /* _UAPI_LINUX_IF_ETHER_H */
diff --git a/kernel/events/core.c b/kernel/events/core.c
index b7f83d6..da7a740 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -4776,6 +4776,11 @@
}
}
+static int perf_event_check_period(struct perf_event *event, u64 value)
+{
+ return event->pmu->check_period(event, value);
+}
+
static int perf_event_period(struct perf_event *event, u64 __user *arg)
{
u64 value;
@@ -4792,6 +4797,9 @@
if (event->attr.freq && value > sysctl_perf_event_sample_rate)
return -EINVAL;
+ if (perf_event_check_period(event, value))
+ return -EINVAL;
+
event_function_call(event, __perf_event_period, &value);
return 0;
@@ -8802,6 +8810,11 @@
return 0;
}
+static int perf_event_nop_int(struct perf_event *event, u64 value)
+{
+ return 0;
+}
+
static DEFINE_PER_CPU(unsigned int, nop_txn_flags);
static void perf_pmu_start_txn(struct pmu *pmu, unsigned int flags)
@@ -9124,6 +9137,9 @@
pmu->pmu_disable = perf_pmu_nop_void;
}
+ if (!pmu->check_period)
+ pmu->check_period = perf_event_nop_int;
+
if (!pmu->event_idx)
pmu->event_idx = perf_event_idx_default;
diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c
index 017f793..99becab 100644
--- a/kernel/events/ring_buffer.c
+++ b/kernel/events/ring_buffer.c
@@ -700,6 +700,9 @@
size = sizeof(struct ring_buffer);
size += nr_pages * sizeof(void *);
+ if (order_base_2(size) >= PAGE_SHIFT+MAX_ORDER)
+ goto fail;
+
rb = kzalloc(size, GFP_KERNEL);
if (!rb)
goto fail;
diff --git a/kernel/hung_task.c b/kernel/hung_task.c
index b94d3d1..c7e79d8 100644
--- a/kernel/hung_task.c
+++ b/kernel/hung_task.c
@@ -39,7 +39,7 @@
* is disabled during the critical section. It also controls the size of
* the RCU grace period. So it needs to be upper-bound.
*/
-#define HUNG_TASK_BATCHING 1024
+#define HUNG_TASK_LOCK_BREAK (HZ / 10)
/*
* Zero means infinite timeout - no checking done:
@@ -167,7 +167,7 @@
static void check_hung_uninterruptible_tasks(unsigned long timeout)
{
int max_count = sysctl_hung_task_check_count;
- int batch_count = HUNG_TASK_BATCHING;
+ unsigned long last_break = jiffies;
struct task_struct *g, *t;
/*
@@ -181,10 +181,10 @@
for_each_process_thread(g, t) {
if (!max_count--)
goto unlock;
- if (!--batch_count) {
- batch_count = HUNG_TASK_BATCHING;
+ if (time_after(jiffies, last_break + HUNG_TASK_LOCK_BREAK)) {
if (!rcu_lock_break(g, t))
goto unlock;
+ last_break = jiffies;
}
/* use "==" to skip the TASK_KILLABLE tasks waiting on NFS */
if (t->state == TASK_UNINTERRUPTIBLE)
diff --git a/kernel/signal.c b/kernel/signal.c
index a65d9cf..92766f70 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -698,6 +698,48 @@
(!is_si_special(info) && SI_FROMUSER(info));
}
+static int dequeue_synchronous_signal(siginfo_t *info)
+{
+ struct task_struct *tsk = current;
+ struct sigpending *pending = &tsk->pending;
+ struct sigqueue *q, *sync = NULL;
+
+ /*
+ * Might a synchronous signal be in the queue?
+ */
+ if (!((pending->signal.sig[0] & ~tsk->blocked.sig[0]) & SYNCHRONOUS_MASK))
+ return 0;
+
+ /*
+ * Return the first synchronous signal in the queue.
+ */
+ list_for_each_entry(q, &pending->list, list) {
+ /* Synchronous signals have a postive si_code */
+ if ((q->info.si_code > SI_USER) &&
+ (sigmask(q->info.si_signo) & SYNCHRONOUS_MASK)) {
+ sync = q;
+ goto next;
+ }
+ }
+ return 0;
+next:
+ /*
+ * Check if there is another siginfo for the same signal.
+ */
+ list_for_each_entry_continue(q, &pending->list, list) {
+ if (q->info.si_signo == sync->info.si_signo)
+ goto still_pending;
+ }
+
+ sigdelset(&pending->signal, sync->info.si_signo);
+ recalc_sigpending();
+still_pending:
+ list_del_init(&sync->list);
+ copy_siginfo(info, &sync->info);
+ __sigqueue_free(sync);
+ return info->si_signo;
+}
+
/*
* called with RCU read lock from check_kill_permission()
*/
@@ -2203,6 +2245,14 @@
goto relock;
}
+ /* Has this task already been marked for death? */
+ if (signal_group_exit(signal)) {
+ ksig->info.si_signo = signr = SIGKILL;
+ sigdelset(¤t->pending.signal, SIGKILL);
+ recalc_sigpending();
+ goto fatal;
+ }
+
for (;;) {
struct k_sigaction *ka;
@@ -2216,7 +2266,15 @@
goto relock;
}
- signr = dequeue_signal(current, ¤t->blocked, &ksig->info);
+ /*
+ * Signals generated by the execution of an instruction
+ * need to be delivered before any other pending signals
+ * so that the instruction pointer in the signal stack
+ * frame points to the faulting instruction.
+ */
+ signr = dequeue_synchronous_signal(&ksig->info);
+ if (!signr)
+ signr = dequeue_signal(current, ¤t->blocked, &ksig->info);
if (!signr)
break; /* will return 0 */
@@ -2298,6 +2356,7 @@
continue;
}
+ fatal:
spin_unlock_irq(&sighand->siglock);
/*
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 1e49ef6..b4f1889 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -2702,6 +2702,8 @@
bool neg;
left -= proc_skip_spaces(&p);
+ if (!left)
+ break;
err = proc_get_long(&p, &left, &val, &neg,
proc_wspace_sep,
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 5659b40..9d4c257 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -39,7 +39,9 @@
static struct {
seqcount_t seq;
struct timekeeper timekeeper;
-} tk_core ____cacheline_aligned;
+} tk_core ____cacheline_aligned = {
+ .seq = SEQCNT_ZERO(tk_core.seq),
+};
static DEFINE_RAW_SPINLOCK(timekeeper_lock);
static struct timekeeper shadow_timekeeper;
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index 92e394e..20bee0c 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -150,7 +150,14 @@
ret = strncpy_from_user(dst, src, maxlen);
if (ret == maxlen)
- dst[--ret] = '\0';
+ dst[ret - 1] = '\0';
+ else if (ret >= 0)
+ /*
+ * Include the terminating null byte. In this case it
+ * was copied by strncpy_from_user but not accounted
+ * for in ret.
+ */
+ ret++;
if (ret < 0) { /* Failed to fetch string */
((u8 *)get_rloc_data(dest))[0] = '\0';
diff --git a/lib/seq_buf.c b/lib/seq_buf.c
index cb18469..5954f9f 100644
--- a/lib/seq_buf.c
+++ b/lib/seq_buf.c
@@ -143,9 +143,13 @@
WARN_ON(s->size == 0);
+ /* Add 1 to len for the trailing null byte which must be there */
+ len += 1;
+
if (seq_buf_can_fit(s, len)) {
memcpy(s->buffer + s->len, str, len);
- s->len += len;
+ /* Don't count the trailing null byte against the capacity */
+ s->len += len - 1;
return 0;
}
seq_buf_set_overflow(s);
diff --git a/mm/memory.c b/mm/memory.c
old mode 100644
new mode 100755
index ab749d7..6a939ae
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -3550,15 +3550,24 @@
{
struct vm_area_struct *vma = fe->vma;
pgoff_t pgoff = linear_page_index(vma, fe->address);
+ int ret;
/* The VMA was not fully populated on mmap() or missing VM_DONTEXPAND */
if (!vma->vm_ops->fault)
- return VM_FAULT_SIGBUS;
- if (!(fe->flags & FAULT_FLAG_WRITE))
- return do_read_fault(fe, pgoff);
- if (!(fe->vma_flags & VM_SHARED))
- return do_cow_fault(fe, pgoff);
- return do_shared_fault(fe, pgoff);
+ ret = VM_FAULT_SIGBUS;
+ else if (!(fe->flags & FAULT_FLAG_WRITE))
+ ret = do_read_fault(fe, pgoff);
+ else if (!(fe->vma_flags & VM_SHARED))
+ ret = do_cow_fault(fe, pgoff);
+ else
+ ret = do_shared_fault(fe, pgoff);
+
+ /* preallocated pagetable is unused: free it */
+ if (fe->prealloc_pte) {
+ pte_free(vma->vm_mm, fe->prealloc_pte);
+ fe->prealloc_pte = 0;
+ }
+ return ret;
}
static int numa_migrate_prep(struct page *page, struct vm_area_struct *vma,
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
old mode 100644
new mode 100755
index 9469e46..de74080
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -622,8 +622,8 @@
*/
spin_lock(&oom_reaper_lock);
- /* tsk is already queued? */
- if (tsk == oom_reaper_list || tsk->oom_reaper_list) {
+ /* mm is already queued? */
+ if (test_and_set_bit(MMF_OOM_REAP_QUEUED, &tsk->signal->oom_mm->flags)) {
spin_unlock(&oom_reaper_lock);
return;
}
diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
index af817e5..a176847 100644
--- a/mm/userfaultfd.c
+++ b/mm/userfaultfd.c
@@ -182,13 +182,9 @@
goto out_unlock;
/*
- * Be strict and only allow __mcopy_atomic on userfaultfd
- * registered ranges to prevent userland errors going
- * unnoticed. As far as the VM consistency is concerned, it
- * would be perfectly safe to remove this check, but there's
- * no useful usage for __mcopy_atomic ouside of userfaultfd
- * registered ranges. This is after all why these are ioctls
- * belonging to the userfaultfd and not syscalls.
+ * Check the vma is registered in uffd, this is required to
+ * enforce the VM_MAYWRITE check done at uffd registration
+ * time.
*/
if (!dst_vma->vm_userfaultfd_ctx.ctx)
goto out_unlock;
diff --git a/net/ax25/ax25_ip.c b/net/ax25/ax25_ip.c
index 2fa3be9..cd9a24e 100644
--- a/net/ax25/ax25_ip.c
+++ b/net/ax25/ax25_ip.c
@@ -114,6 +114,7 @@
dst = (ax25_address *)(bp + 1);
src = (ax25_address *)(bp + 8);
+ ax25_route_lock_use();
route = ax25_get_route(dst, NULL);
if (route) {
digipeat = route->digipeat;
@@ -206,9 +207,8 @@
ax25_queue_xmit(skb, dev);
put:
- if (route)
- ax25_put_route(route);
+ ax25_route_lock_unuse();
return NETDEV_TX_OK;
}
diff --git a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c
index d390977..149f82b 100644
--- a/net/ax25/ax25_route.c
+++ b/net/ax25/ax25_route.c
@@ -40,7 +40,7 @@
#include <linux/export.h>
static ax25_route *ax25_route_list;
-static DEFINE_RWLOCK(ax25_route_lock);
+DEFINE_RWLOCK(ax25_route_lock);
void ax25_rt_device_down(struct net_device *dev)
{
@@ -349,6 +349,7 @@
* Find AX.25 route
*
* Only routes with a reference count of zero can be destroyed.
+ * Must be called with ax25_route_lock read locked.
*/
ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev)
{
@@ -356,7 +357,6 @@
ax25_route *ax25_def_rt = NULL;
ax25_route *ax25_rt;
- read_lock(&ax25_route_lock);
/*
* Bind to the physical interface we heard them on, or the default
* route if none is found;
@@ -379,11 +379,6 @@
if (ax25_spe_rt != NULL)
ax25_rt = ax25_spe_rt;
- if (ax25_rt != NULL)
- ax25_hold_route(ax25_rt);
-
- read_unlock(&ax25_route_lock);
-
return ax25_rt;
}
@@ -414,9 +409,12 @@
ax25_route *ax25_rt;
int err = 0;
- if ((ax25_rt = ax25_get_route(addr, NULL)) == NULL)
+ ax25_route_lock_use();
+ ax25_rt = ax25_get_route(addr, NULL);
+ if (!ax25_rt) {
+ ax25_route_lock_unuse();
return -EHOSTUNREACH;
-
+ }
if ((ax25->ax25_dev = ax25_dev_ax25dev(ax25_rt->dev)) == NULL) {
err = -EHOSTUNREACH;
goto put;
@@ -451,8 +449,7 @@
}
put:
- ax25_put_route(ax25_rt);
-
+ ax25_route_lock_unuse();
return err;
}
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c
index 08ce361..8f7883b 100644
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@ -19,7 +19,6 @@
#include "main.h"
#include <linux/atomic.h>
-#include <linux/bug.h>
#include <linux/byteorder/generic.h>
#include <linux/errno.h>
#include <linux/fs.h>
@@ -172,8 +171,10 @@
parent_dev = __dev_get_by_index((struct net *)parent_net,
dev_get_iflink(net_dev));
/* if we got a NULL parent_dev there is something broken.. */
- if (WARN(!parent_dev, "Cannot find parent device"))
+ if (!parent_dev) {
+ pr_err("Cannot find parent device\n");
return false;
+ }
if (batadv_mutual_parents(net_dev, net, parent_dev, parent_net))
return false;
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
index 05bc176..835af77 100644
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@ -211,6 +211,8 @@
netif_trans_update(soft_iface);
vid = batadv_get_vid(skb, 0);
+
+ skb_reset_mac_header(skb);
ethhdr = eth_hdr(skb);
switch (ntohs(ethhdr->h_proto)) {
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index d2f9eb1..6f78489 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -5212,6 +5212,12 @@
return true;
}
+ /* Check if request ended in Command Status - no way to retreive
+ * any extra parameters in this case.
+ */
+ if (hdr->evt == HCI_EV_CMD_STATUS)
+ return false;
+
if (hdr->evt != HCI_EV_CMD_COMPLETE) {
BT_DBG("Last event is not cmd complete (0x%2.2x)", hdr->evt);
return false;
diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c
index 5a8075d..93eb606 100644
--- a/net/ceph/messenger.c
+++ b/net/ceph/messenger.c
@@ -3186,9 +3186,10 @@
dout("con_keepalive %p\n", con);
mutex_lock(&con->mutex);
clear_standby(con);
+ con_flag_set(con, CON_FLAG_KEEPALIVE_PENDING);
mutex_unlock(&con->mutex);
- if (con_flag_test_and_set(con, CON_FLAG_KEEPALIVE_PENDING) == 0 &&
- con_flag_test_and_set(con, CON_FLAG_WRITE_PENDING) == 0)
+
+ if (con_flag_test_and_set(con, CON_FLAG_WRITE_PENDING) == 0)
queue_con(con);
}
EXPORT_SYMBOL(ceph_con_keepalive);
diff --git a/net/core/dev.c b/net/core/dev.c
index 53d98de..77dbbfc 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -7041,7 +7041,7 @@
netdev_features_t feature;
int feature_bit;
- for_each_netdev_feature(&upper_disables, feature_bit) {
+ for_each_netdev_feature(upper_disables, feature_bit) {
feature = __NETIF_F_BIT(feature_bit);
if (!(upper->wanted_features & feature)
&& (features & feature)) {
@@ -7061,7 +7061,7 @@
netdev_features_t feature;
int feature_bit;
- for_each_netdev_feature(&upper_disables, feature_bit) {
+ for_each_netdev_feature(upper_disables, feature_bit) {
feature = __NETIF_F_BIT(feature_bit);
if (!(features & feature) && (lower->features & feature)) {
netdev_dbg(upper, "Disabling feature %pNF on lower dev %s.\n",
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 57aefdc..57743e5 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -389,6 +389,8 @@
*/
void *netdev_alloc_frag(unsigned int fragsz)
{
+ fragsz = SKB_DATA_ALIGN(fragsz);
+
return __netdev_alloc_frag(fragsz, GFP_ATOMIC | __GFP_COLD);
}
EXPORT_SYMBOL(netdev_alloc_frag);
@@ -402,6 +404,8 @@
void *napi_alloc_frag(unsigned int fragsz)
{
+ fragsz = SKB_DATA_ALIGN(fragsz);
+
return __napi_alloc_frag(fragsz, GFP_ATOMIC | __GFP_COLD);
}
EXPORT_SYMBOL(napi_alloc_frag);
@@ -4475,6 +4479,45 @@
EXPORT_SYMBOL_GPL(skb_gso_transport_seglen);
/**
+ * skb_gso_size_check - check the skb size, considering GSO_BY_FRAGS
+ *
+ * There are a couple of instances where we have a GSO skb, and we
+ * want to determine what size it would be after it is segmented.
+ *
+ * We might want to check:
+ * - L3+L4+payload size (e.g. IP forwarding)
+ * - L2+L3+L4+payload size (e.g. sanity check before passing to driver)
+ *
+ * This is a helper to do that correctly considering GSO_BY_FRAGS.
+ *
+ * @seg_len: The segmented length (from skb_gso_*_seglen). In the
+ * GSO_BY_FRAGS case this will be [header sizes + GSO_BY_FRAGS].
+ *
+ * @max_len: The maximum permissible length.
+ *
+ * Returns true if the segmented length <= max length.
+ */
+static inline bool skb_gso_size_check(const struct sk_buff *skb,
+ unsigned int seg_len,
+ unsigned int max_len) {
+ const struct skb_shared_info *shinfo = skb_shinfo(skb);
+ const struct sk_buff *iter;
+
+ if (shinfo->gso_size != GSO_BY_FRAGS)
+ return seg_len <= max_len;
+
+ /* Undo this so we can re-use header sizes */
+ seg_len -= GSO_BY_FRAGS;
+
+ skb_walk_frags(skb, iter) {
+ if (seg_len + skb_headlen(iter) > max_len)
+ return false;
+ }
+
+ return true;
+}
+
+/**
* skb_gso_validate_mtu - Return in case such skb fits a given MTU
*
* @skb: GSO skb
@@ -4485,27 +4528,25 @@
*/
bool skb_gso_validate_mtu(const struct sk_buff *skb, unsigned int mtu)
{
- const struct skb_shared_info *shinfo = skb_shinfo(skb);
- const struct sk_buff *iter;
- unsigned int hlen;
-
- hlen = skb_gso_network_seglen(skb);
-
- if (shinfo->gso_size != GSO_BY_FRAGS)
- return hlen <= mtu;
-
- /* Undo this so we can re-use header sizes */
- hlen -= GSO_BY_FRAGS;
-
- skb_walk_frags(skb, iter) {
- if (hlen + skb_headlen(iter) > mtu)
- return false;
- }
-
- return true;
+ return skb_gso_size_check(skb, skb_gso_network_seglen(skb), mtu);
}
EXPORT_SYMBOL_GPL(skb_gso_validate_mtu);
+/**
+ * skb_gso_validate_mac_len - Will a split GSO skb fit in a given length?
+ *
+ * @skb: GSO skb
+ * @len: length to validate against
+ *
+ * skb_gso_validate_mac_len validates if a given skb will fit a wanted
+ * length once split, including L2, L3 and L4 headers and the payload.
+ */
+bool skb_gso_validate_mac_len(const struct sk_buff *skb, unsigned int len)
+{
+ return skb_gso_size_check(skb, skb_gso_mac_seglen(skb), len);
+}
+EXPORT_SYMBOL_GPL(skb_gso_validate_mac_len);
+
static struct sk_buff *skb_reorder_vlan_header(struct sk_buff *skb)
{
int mac_len;
diff --git a/net/dccp/ccid.h b/net/dccp/ccid.h
index 6eb837a..baaaeb2 100644
--- a/net/dccp/ccid.h
+++ b/net/dccp/ccid.h
@@ -202,7 +202,7 @@
static inline int ccid_hc_tx_parse_options(struct ccid *ccid, struct sock *sk,
u8 pkt, u8 opt, u8 *val, u8 len)
{
- if (ccid->ccid_ops->ccid_hc_tx_parse_options == NULL)
+ if (!ccid || !ccid->ccid_ops->ccid_hc_tx_parse_options)
return 0;
return ccid->ccid_ops->ccid_hc_tx_parse_options(sk, pkt, opt, val, len);
}
@@ -214,7 +214,7 @@
static inline int ccid_hc_rx_parse_options(struct ccid *ccid, struct sock *sk,
u8 pkt, u8 opt, u8 *val, u8 len)
{
- if (ccid->ccid_ops->ccid_hc_rx_parse_options == NULL)
+ if (!ccid || !ccid->ccid_ops->ccid_hc_rx_parse_options)
return 0;
return ccid->ccid_ops->ccid_hc_rx_parse_options(sk, pkt, opt, val, len);
}
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 339d9c6..d7883e5 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -180,10 +180,14 @@
struct dsa_slave_priv *p = netdev_priv(dev);
struct net_device *master = p->parent->dst->master_netdev;
- if (change & IFF_ALLMULTI)
- dev_set_allmulti(master, dev->flags & IFF_ALLMULTI ? 1 : -1);
- if (change & IFF_PROMISC)
- dev_set_promiscuity(master, dev->flags & IFF_PROMISC ? 1 : -1);
+ if (dev->flags & IFF_UP) {
+ if (change & IFF_ALLMULTI)
+ dev_set_allmulti(master,
+ dev->flags & IFF_ALLMULTI ? 1 : -1);
+ if (change & IFF_PROMISC)
+ dev_set_promiscuity(master,
+ dev->flags & IFF_PROMISC ? 1 : -1);
+ }
}
static void dsa_slave_set_rx_mode(struct net_device *dev)
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 275ef13..a726398 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -89,7 +89,6 @@
#include <linux/netfilter_ipv4.h>
#include <linux/random.h>
#include <linux/slab.h>
-#include <linux/netfilter/xt_qtaguid.h>
#include <asm/uaccess.h>
@@ -415,9 +414,6 @@
if (sk) {
long timeout;
-#ifdef CONFIG_NETFILTER_XT_MATCH_QTAGUID
- qtaguid_untag(sock, true);
-#endif
/* Applications forget to leave groups before exiting */
ip_mc_drop_socket(sk);
diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c
index 86fa458..0c58629 100644
--- a/net/ipv4/inetpeer.c
+++ b/net/ipv4/inetpeer.c
@@ -448,6 +448,7 @@
atomic_set(&p->rid, 0);
p->metrics[RTAX_LOCK-1] = INETPEER_METRICS_NEW;
p->rate_tokens = 0;
+ p->n_redirects = 0;
/* 60*HZ is arbitrary, but chosen enough high so that the first
* calculation of tokens is at its maximum.
*/
diff --git a/net/ipv4/netfilter/nft_masq_ipv4.c b/net/ipv4/netfilter/nft_masq_ipv4.c
index 51ced81..dc3628a 100644
--- a/net/ipv4/netfilter/nft_masq_ipv4.c
+++ b/net/ipv4/netfilter/nft_masq_ipv4.c
@@ -26,10 +26,10 @@
memset(&range, 0, sizeof(range));
range.flags = priv->flags;
if (priv->sreg_proto_min) {
- range.min_proto.all =
- *(__be16 *)®s->data[priv->sreg_proto_min];
- range.max_proto.all =
- *(__be16 *)®s->data[priv->sreg_proto_max];
+ range.min_proto.all = (__force __be16)nft_reg_load16(
+ ®s->data[priv->sreg_proto_min]);
+ range.max_proto.all = (__force __be16)nft_reg_load16(
+ ®s->data[priv->sreg_proto_max]);
}
regs->verdict.code = nf_nat_masquerade_ipv4(pkt->skb, pkt->hook,
&range, pkt->out);
diff --git a/net/ipv4/netfilter/nft_redir_ipv4.c b/net/ipv4/netfilter/nft_redir_ipv4.c
index c09d438..f760524 100644
--- a/net/ipv4/netfilter/nft_redir_ipv4.c
+++ b/net/ipv4/netfilter/nft_redir_ipv4.c
@@ -26,10 +26,10 @@
memset(&mr, 0, sizeof(mr));
if (priv->sreg_proto_min) {
- mr.range[0].min.all =
- *(__be16 *)®s->data[priv->sreg_proto_min];
- mr.range[0].max.all =
- *(__be16 *)®s->data[priv->sreg_proto_max];
+ mr.range[0].min.all = (__force __be16)nft_reg_load16(
+ ®s->data[priv->sreg_proto_min]);
+ mr.range[0].max.all = (__force __be16)nft_reg_load16(
+ ®s->data[priv->sreg_proto_max]);
mr.range[0].flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
}
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 583967b..94419b8 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -886,13 +886,15 @@
/* No redirected packets during ip_rt_redirect_silence;
* reset the algorithm.
*/
- if (time_after(jiffies, peer->rate_last + ip_rt_redirect_silence))
+ if (time_after(jiffies, peer->rate_last + ip_rt_redirect_silence)) {
peer->rate_tokens = 0;
+ peer->n_redirects = 0;
+ }
/* Too many ignored redirects; do not send anything
* set dst.rate_last to the last seen redirected packet.
*/
- if (peer->rate_tokens >= ip_rt_redirect_number) {
+ if (peer->n_redirects >= ip_rt_redirect_number) {
peer->rate_last = jiffies;
goto out_put_peer;
}
@@ -909,6 +911,7 @@
icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, gw);
peer->rate_last = jiffies;
++peer->rate_tokens;
+ ++peer->n_redirects;
#ifdef CONFIG_IP_ROUTE_VERBOSE
if (log_martians &&
peer->rate_tokens == ip_rt_redirect_number)
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 452d59b..a0e1fc1 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2324,7 +2324,6 @@
tp->write_seq += tp->max_window + 2;
if (tp->write_seq == 0)
tp->write_seq = 1;
- icsk->icsk_backoff = 0;
tp->snd_cwnd = 2;
icsk->icsk_probes_out = 0;
tp->packets_out = 0;
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 9bfa876..0116d9e 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -469,14 +469,15 @@
if (sock_owned_by_user(sk))
break;
+ skb = tcp_write_queue_head(sk);
+ if (WARN_ON_ONCE(!skb))
+ break;
+
icsk->icsk_backoff--;
icsk->icsk_rto = tp->srtt_us ? __tcp_set_rto(tp) :
TCP_TIMEOUT_INIT;
icsk->icsk_rto = inet_csk_rto_backoff(icsk, TCP_RTO_MAX);
- skb = tcp_write_queue_head(sk);
- BUG_ON(!skb);
-
remaining = icsk->icsk_rto -
min(icsk->icsk_rto,
tcp_time_stamp - tcp_skb_timestamp(skb));
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 9877dfa..185ae8f 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -1080,7 +1080,8 @@
list_for_each_entry(ifa, &idev->addr_list, if_list) {
if (ifa == ifp)
continue;
- if (!ipv6_prefix_equal(&ifa->addr, &ifp->addr,
+ if (ifa->prefix_len != ifp->prefix_len ||
+ !ipv6_prefix_equal(&ifa->addr, &ifp->addr,
ifp->prefix_len))
continue;
if (ifa->flags & (IFA_F_PERMANENT | IFA_F_NOPREFIXROUTE))
diff --git a/net/ipv6/netfilter/nft_masq_ipv6.c b/net/ipv6/netfilter/nft_masq_ipv6.c
index 9597ffb..b74a420 100644
--- a/net/ipv6/netfilter/nft_masq_ipv6.c
+++ b/net/ipv6/netfilter/nft_masq_ipv6.c
@@ -27,10 +27,10 @@
memset(&range, 0, sizeof(range));
range.flags = priv->flags;
if (priv->sreg_proto_min) {
- range.min_proto.all =
- *(__be16 *)®s->data[priv->sreg_proto_min];
- range.max_proto.all =
- *(__be16 *)®s->data[priv->sreg_proto_max];
+ range.min_proto.all = (__force __be16)nft_reg_load16(
+ ®s->data[priv->sreg_proto_min]);
+ range.max_proto.all = (__force __be16)nft_reg_load16(
+ ®s->data[priv->sreg_proto_max]);
}
regs->verdict.code = nf_nat_masquerade_ipv6(pkt->skb, &range, pkt->out);
}
diff --git a/net/ipv6/netfilter/nft_redir_ipv6.c b/net/ipv6/netfilter/nft_redir_ipv6.c
index aca44e8..7ef58e4 100644
--- a/net/ipv6/netfilter/nft_redir_ipv6.c
+++ b/net/ipv6/netfilter/nft_redir_ipv6.c
@@ -26,10 +26,10 @@
memset(&range, 0, sizeof(range));
if (priv->sreg_proto_min) {
- range.min_proto.all =
- *(__be16 *)®s->data[priv->sreg_proto_min],
- range.max_proto.all =
- *(__be16 *)®s->data[priv->sreg_proto_max],
+ range.min_proto.all = (__force __be16)nft_reg_load16(
+ ®s->data[priv->sreg_proto_min]);
+ range.max_proto.all = (__force __be16)nft_reg_load16(
+ ®s->data[priv->sreg_proto_max]);
range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
}
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c
index e1c0bbe..3a2701d 100644
--- a/net/ipv6/xfrm6_tunnel.c
+++ b/net/ipv6/xfrm6_tunnel.c
@@ -144,6 +144,9 @@
index = __xfrm6_tunnel_spi_check(net, spi);
if (index >= 0)
goto alloc_spi;
+
+ if (spi == XFRM6_TUNNEL_SPI_MAX)
+ break;
}
for (spi = XFRM6_TUNNEL_SPI_MIN; spi < xfrm6_tn->spi; spi++) {
index = __xfrm6_tunnel_spi_check(net, spi);
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 93c3327..af02d21 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -152,6 +152,9 @@
/* allocate extra bitmaps */
if (status->chains)
len += 4 * hweight8(status->chains);
+ /* vendor presence bitmap */
+ if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA)
+ len += 4;
if (ieee80211_have_rx_timestamp(status)) {
len = ALIGN(len, 8);
@@ -193,8 +196,6 @@
if (status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) {
struct ieee80211_vendor_radiotap *rtap = (void *)skb->data;
- /* vendor presence bitmap */
- len += 4;
/* alignment for fixed 6-byte vendor data header */
len = ALIGN(len, 2);
/* vendor data header */
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 6a0fb9d..f8de166 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1852,9 +1852,16 @@
int head_need, bool may_encrypt)
{
struct ieee80211_local *local = sdata->local;
+ struct ieee80211_hdr *hdr;
+ bool enc_tailroom;
int tail_need = 0;
- if (may_encrypt && sdata->crypto_tx_tailroom_needed_cnt) {
+ hdr = (struct ieee80211_hdr *) skb->data;
+ enc_tailroom = may_encrypt &&
+ (sdata->crypto_tx_tailroom_needed_cnt ||
+ ieee80211_is_mgmt(hdr->frame_control));
+
+ if (enc_tailroom) {
tail_need = IEEE80211_ENCRYPT_TAILROOM;
tail_need -= skb_tailroom(skb);
tail_need = max_t(int, tail_need, 0);
@@ -1862,8 +1869,7 @@
if (skb_cloned(skb) &&
(!ieee80211_hw_check(&local->hw, SUPPORTS_CLONED_SKBS) ||
- !skb_clone_writable(skb, ETH_HLEN) ||
- (may_encrypt && sdata->crypto_tx_tailroom_needed_cnt)))
+ !skb_clone_writable(skb, ETH_HLEN) || enc_tailroom))
I802_DEBUG_INC(local->tx_expand_skb_head_cloned);
else if (head_need || tail_need)
I802_DEBUG_INC(local->tx_expand_skb_head);
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 371cd9a..c1c978e 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -1365,22 +1365,6 @@
To compile it as a module, choose M here. If unsure, say N.
-config NETFILTER_XT_MATCH_QTAGUID
- bool '"quota, tag, owner" match and stats support'
- depends on NETFILTER_XT_MATCH_SOCKET
- depends on NETFILTER_XT_MATCH_OWNER=n
- help
- This option replaces the `owner' match. In addition to matching
- on uid, it keeps stats based on a tag assigned to a socket.
- The full tag is comprised of a UID and an accounting tag.
- The tags are assignable to sockets from user space (e.g. a download
- manager can assign the socket to another UID for accounting).
- Stats and control are done via /proc/net/xt_qtaguid/.
- It replaces owner as it takes the same arguments, but should
- really be recognized by the iptables tool.
-
- If unsure, say `N'.
-
config NETFILTER_XT_MATCH_QUOTA
tristate '"quota" match support'
depends on NETFILTER_ADVANCED
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 8b29a57..dd7c5ff 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -168,7 +168,6 @@
obj-$(CONFIG_NETFILTER_XT_MATCH_PHYSDEV) += xt_physdev.o
obj-$(CONFIG_NETFILTER_XT_MATCH_PKTTYPE) += xt_pkttype.o
obj-$(CONFIG_NETFILTER_XT_MATCH_POLICY) += xt_policy.o
-obj-$(CONFIG_NETFILTER_XT_MATCH_QTAGUID) += xt_qtaguid_print.o xt_qtaguid.o
obj-$(CONFIG_NETFILTER_XT_MATCH_QUOTA) += xt_quota.o
obj-$(CONFIG_NETFILTER_XT_MATCH_QUOTA2) += xt_quota2.o
obj-$(CONFIG_NETFILTER_XT_MATCH_RATEEST) += xt_rateest.o
diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c
index d7b0d171..2b9fda7 100644
--- a/net/netfilter/nft_ct.c
+++ b/net/netfilter/nft_ct.c
@@ -77,7 +77,7 @@
switch (priv->key) {
case NFT_CT_DIRECTION:
- *dest = CTINFO2DIR(ctinfo);
+ nft_reg_store8(dest, CTINFO2DIR(ctinfo));
return;
case NFT_CT_STATUS:
*dest = ct->status;
@@ -129,10 +129,10 @@
return;
}
case NFT_CT_L3PROTOCOL:
- *dest = nf_ct_l3num(ct);
+ nft_reg_store8(dest, nf_ct_l3num(ct));
return;
case NFT_CT_PROTOCOL:
- *dest = nf_ct_protonum(ct);
+ nft_reg_store8(dest, nf_ct_protonum(ct));
return;
default:
break;
@@ -149,10 +149,10 @@
nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16);
return;
case NFT_CT_PROTO_SRC:
- *dest = (__force __u16)tuple->src.u.all;
+ nft_reg_store16(dest, (__force u16)tuple->src.u.all);
return;
case NFT_CT_PROTO_DST:
- *dest = (__force __u16)tuple->dst.u.all;
+ nft_reg_store16(dest, (__force u16)tuple->dst.u.all);
return;
default:
break;
diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c
index 7c33955..cec8dc0 100644
--- a/net/netfilter/nft_meta.c
+++ b/net/netfilter/nft_meta.c
@@ -45,16 +45,15 @@
*dest = skb->len;
break;
case NFT_META_PROTOCOL:
- *dest = 0;
- *(__be16 *)dest = skb->protocol;
+ nft_reg_store16(dest, (__force u16)skb->protocol);
break;
case NFT_META_NFPROTO:
- *dest = pkt->pf;
+ nft_reg_store8(dest, pkt->pf);
break;
case NFT_META_L4PROTO:
if (!pkt->tprot_set)
goto err;
- *dest = pkt->tprot;
+ nft_reg_store8(dest, pkt->tprot);
break;
case NFT_META_PRIORITY:
*dest = skb->priority;
@@ -85,14 +84,12 @@
case NFT_META_IIFTYPE:
if (in == NULL)
goto err;
- *dest = 0;
- *(u16 *)dest = in->type;
+ nft_reg_store16(dest, in->type);
break;
case NFT_META_OIFTYPE:
if (out == NULL)
goto err;
- *dest = 0;
- *(u16 *)dest = out->type;
+ nft_reg_store16(dest, out->type);
break;
case NFT_META_SKUID:
sk = skb_to_full_sk(skb);
@@ -142,22 +139,22 @@
#endif
case NFT_META_PKTTYPE:
if (skb->pkt_type != PACKET_LOOPBACK) {
- *dest = skb->pkt_type;
+ nft_reg_store8(dest, skb->pkt_type);
break;
}
switch (pkt->pf) {
case NFPROTO_IPV4:
if (ipv4_is_multicast(ip_hdr(skb)->daddr))
- *dest = PACKET_MULTICAST;
+ nft_reg_store8(dest, PACKET_MULTICAST);
else
- *dest = PACKET_BROADCAST;
+ nft_reg_store8(dest, PACKET_BROADCAST);
break;
case NFPROTO_IPV6:
if (ipv6_hdr(skb)->daddr.s6_addr[0] == 0xFF)
- *dest = PACKET_MULTICAST;
+ nft_reg_store8(dest, PACKET_MULTICAST);
else
- *dest = PACKET_BROADCAST;
+ nft_reg_store8(dest, PACKET_BROADCAST);
break;
case NFPROTO_NETDEV:
switch (skb->protocol) {
@@ -171,14 +168,14 @@
goto err;
if (ipv4_is_multicast(iph->daddr))
- *dest = PACKET_MULTICAST;
+ nft_reg_store8(dest, PACKET_MULTICAST);
else
- *dest = PACKET_BROADCAST;
+ nft_reg_store8(dest, PACKET_BROADCAST);
break;
}
case htons(ETH_P_IPV6):
- *dest = PACKET_MULTICAST;
+ nft_reg_store8(dest, PACKET_MULTICAST);
break;
default:
WARN_ON_ONCE(1);
@@ -233,7 +230,9 @@
{
const struct nft_meta *meta = nft_expr_priv(expr);
struct sk_buff *skb = pkt->skb;
- u32 value = regs->data[meta->sreg];
+ u32 *sreg = ®s->data[meta->sreg];
+ u32 value = *sreg;
+ u8 pkt_type;
switch (meta->key) {
case NFT_META_MARK:
@@ -243,9 +242,12 @@
skb->priority = value;
break;
case NFT_META_PKTTYPE:
- if (skb->pkt_type != value &&
- skb_pkt_type_ok(value) && skb_pkt_type_ok(skb->pkt_type))
- skb->pkt_type = value;
+ pkt_type = nft_reg_load8(sreg);
+
+ if (skb->pkt_type != pkt_type &&
+ skb_pkt_type_ok(pkt_type) &&
+ skb_pkt_type_ok(skb->pkt_type))
+ skb->pkt_type = pkt_type;
break;
case NFT_META_NFTRACE:
skb->nf_trace = !!value;
diff --git a/net/netfilter/nft_nat.c b/net/netfilter/nft_nat.c
index ee2d717..4c48e9b 100644
--- a/net/netfilter/nft_nat.c
+++ b/net/netfilter/nft_nat.c
@@ -65,10 +65,10 @@
}
if (priv->sreg_proto_min) {
- range.min_proto.all =
- *(__be16 *)®s->data[priv->sreg_proto_min];
- range.max_proto.all =
- *(__be16 *)®s->data[priv->sreg_proto_max];
+ range.min_proto.all = (__force __be16)nft_reg_load16(
+ ®s->data[priv->sreg_proto_min]);
+ range.max_proto.all = (__force __be16)nft_reg_load16(
+ ®s->data[priv->sreg_proto_max]);
range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
}
diff --git a/net/netfilter/xt_qtaguid.c b/net/netfilter/xt_qtaguid.c
deleted file mode 100644
index 7f51f6d..0000000
--- a/net/netfilter/xt_qtaguid.c
+++ /dev/null
@@ -1,3021 +0,0 @@
-/*
- * Kernel iptables module to track stats for packets based on user tags.
- *
- * (C) 2011 Google, Inc
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-/*
- * There are run-time debug flags enabled via the debug_mask module param, or
- * via the DEFAULT_DEBUG_MASK. See xt_qtaguid_internal.h.
- */
-#define DEBUG
-
-#include <linux/file.h>
-#include <linux/inetdevice.h>
-#include <linux/module.h>
-#include <linux/miscdevice.h>
-#include <linux/netfilter/x_tables.h>
-#include <linux/netfilter/xt_qtaguid.h>
-#include <linux/ratelimit.h>
-#include <linux/seq_file.h>
-#include <linux/skbuff.h>
-#include <linux/workqueue.h>
-#include <net/addrconf.h>
-#include <net/sock.h>
-#include <net/tcp.h>
-#include <net/udp.h>
-
-#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
-#include <linux/netfilter_ipv6/ip6_tables.h>
-#endif
-
-#include <linux/netfilter/xt_socket.h>
-#include "xt_qtaguid_internal.h"
-#include "xt_qtaguid_print.h"
-#include "../../fs/proc/internal.h"
-
-/*
- * We only use the xt_socket funcs within a similar context to avoid unexpected
- * return values.
- */
-#define XT_SOCKET_SUPPORTED_HOOKS \
- ((1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_IN))
-
-
-static const char *module_procdirname = "xt_qtaguid";
-static struct proc_dir_entry *xt_qtaguid_procdir;
-
-static unsigned int proc_iface_perms = S_IRUGO;
-module_param_named(iface_perms, proc_iface_perms, uint, S_IRUGO | S_IWUSR);
-
-static struct proc_dir_entry *xt_qtaguid_stats_file;
-static unsigned int proc_stats_perms = S_IRUGO;
-module_param_named(stats_perms, proc_stats_perms, uint, S_IRUGO | S_IWUSR);
-
-static struct proc_dir_entry *xt_qtaguid_ctrl_file;
-
-/* Everybody can write. But proc_ctrl_write_limited is true by default which
- * limits what can be controlled. See the can_*() functions.
- */
-static unsigned int proc_ctrl_perms = S_IRUGO | S_IWUGO;
-module_param_named(ctrl_perms, proc_ctrl_perms, uint, S_IRUGO | S_IWUSR);
-
-/* Limited by default, so the gid of the ctrl and stats proc entries
- * will limit what can be done. See the can_*() functions.
- */
-static bool proc_stats_readall_limited = true;
-static bool proc_ctrl_write_limited = true;
-
-module_param_named(stats_readall_limited, proc_stats_readall_limited, bool,
- S_IRUGO | S_IWUSR);
-module_param_named(ctrl_write_limited, proc_ctrl_write_limited, bool,
- S_IRUGO | S_IWUSR);
-
-/*
- * Limit the number of active tags (via socket tags) for a given UID.
- * Multiple processes could share the UID.
- */
-static int max_sock_tags = DEFAULT_MAX_SOCK_TAGS;
-module_param(max_sock_tags, int, S_IRUGO | S_IWUSR);
-
-/*
- * After the kernel has initiallized this module, it is still possible
- * to make it passive.
- * Setting passive to Y:
- * - the iface stats handling will not act on notifications.
- * - iptables matches will never match.
- * - ctrl commands silently succeed.
- * - stats are always empty.
- * This is mostly usefull when a bug is suspected.
- */
-static bool module_passive;
-module_param_named(passive, module_passive, bool, S_IRUGO | S_IWUSR);
-
-/*
- * Control how qtaguid data is tracked per proc/uid.
- * Setting tag_tracking_passive to Y:
- * - don't create proc specific structs to track tags
- * - don't check that active tag stats exceed some limits.
- * - don't clean up socket tags on process exits.
- * This is mostly usefull when a bug is suspected.
- */
-static bool qtu_proc_handling_passive;
-module_param_named(tag_tracking_passive, qtu_proc_handling_passive, bool,
- S_IRUGO | S_IWUSR);
-
-#define QTU_DEV_NAME "xt_qtaguid"
-
-uint qtaguid_debug_mask = DEFAULT_DEBUG_MASK;
-module_param_named(debug_mask, qtaguid_debug_mask, uint, S_IRUGO | S_IWUSR);
-
-/*---------------------------------------------------------------------------*/
-static const char *iface_stat_procdirname = "iface_stat";
-static struct proc_dir_entry *iface_stat_procdir;
-/*
- * The iface_stat_all* will go away once userspace gets use to the new fields
- * that have a format line.
- */
-static const char *iface_stat_all_procfilename = "iface_stat_all";
-static struct proc_dir_entry *iface_stat_all_procfile;
-static const char *iface_stat_fmt_procfilename = "iface_stat_fmt";
-static struct proc_dir_entry *iface_stat_fmt_procfile;
-
-
-static LIST_HEAD(iface_stat_list);
-static DEFINE_SPINLOCK(iface_stat_list_lock);
-
-static struct rb_root sock_tag_tree = RB_ROOT;
-static DEFINE_SPINLOCK(sock_tag_list_lock);
-
-static struct rb_root tag_counter_set_tree = RB_ROOT;
-static DEFINE_SPINLOCK(tag_counter_set_list_lock);
-
-static struct rb_root uid_tag_data_tree = RB_ROOT;
-static DEFINE_SPINLOCK(uid_tag_data_tree_lock);
-
-static struct rb_root proc_qtu_data_tree = RB_ROOT;
-/* No proc_qtu_data_tree_lock; use uid_tag_data_tree_lock */
-
-static struct qtaguid_event_counts qtu_events;
-/*----------------------------------------------*/
-static bool can_manipulate_uids(void)
-{
- /* root pwnd */
- return in_egroup_p(xt_qtaguid_ctrl_file->gid)
- || unlikely(!from_kuid(&init_user_ns, current_fsuid())) || unlikely(!proc_ctrl_write_limited)
- || unlikely(uid_eq(current_fsuid(), xt_qtaguid_ctrl_file->uid));
-}
-
-static bool can_impersonate_uid(kuid_t uid)
-{
- return uid_eq(uid, current_fsuid()) || can_manipulate_uids();
-}
-
-static bool can_read_other_uid_stats(kuid_t uid)
-{
- /* root pwnd */
- return in_egroup_p(xt_qtaguid_stats_file->gid)
- || unlikely(!from_kuid(&init_user_ns, current_fsuid())) || uid_eq(uid, current_fsuid())
- || unlikely(!proc_stats_readall_limited)
- || unlikely(uid_eq(current_fsuid(), xt_qtaguid_ctrl_file->uid));
-}
-
-static inline void dc_add_byte_packets(struct data_counters *counters, int set,
- enum ifs_tx_rx direction,
- enum ifs_proto ifs_proto,
- int bytes,
- int packets)
-{
- counters->bpc[set][direction][ifs_proto].bytes += bytes;
- counters->bpc[set][direction][ifs_proto].packets += packets;
-}
-
-static struct tag_node *tag_node_tree_search(struct rb_root *root, tag_t tag)
-{
- struct rb_node *node = root->rb_node;
-
- while (node) {
- struct tag_node *data = rb_entry(node, struct tag_node, node);
- int result;
- RB_DEBUG("qtaguid: tag_node_tree_search(0x%llx): "
- " node=%p data=%p\n", tag, node, data);
- result = tag_compare(tag, data->tag);
- RB_DEBUG("qtaguid: tag_node_tree_search(0x%llx): "
- " data.tag=0x%llx (uid=%u) res=%d\n",
- tag, data->tag, get_uid_from_tag(data->tag), result);
- if (result < 0)
- node = node->rb_left;
- else if (result > 0)
- node = node->rb_right;
- else
- return data;
- }
- return NULL;
-}
-
-static void tag_node_tree_insert(struct tag_node *data, struct rb_root *root)
-{
- struct rb_node **new = &(root->rb_node), *parent = NULL;
-
- /* Figure out where to put new node */
- while (*new) {
- struct tag_node *this = rb_entry(*new, struct tag_node,
- node);
- int result = tag_compare(data->tag, this->tag);
- RB_DEBUG("qtaguid: %s(): tag=0x%llx"
- " (uid=%u)\n", __func__,
- this->tag,
- get_uid_from_tag(this->tag));
- parent = *new;
- if (result < 0)
- new = &((*new)->rb_left);
- else if (result > 0)
- new = &((*new)->rb_right);
- else
- BUG();
- }
-
- /* Add new node and rebalance tree. */
- rb_link_node(&data->node, parent, new);
- rb_insert_color(&data->node, root);
-}
-
-static void tag_stat_tree_insert(struct tag_stat *data, struct rb_root *root)
-{
- tag_node_tree_insert(&data->tn, root);
-}
-
-static struct tag_stat *tag_stat_tree_search(struct rb_root *root, tag_t tag)
-{
- struct tag_node *node = tag_node_tree_search(root, tag);
- if (!node)
- return NULL;
- return rb_entry(&node->node, struct tag_stat, tn.node);
-}
-
-static void tag_counter_set_tree_insert(struct tag_counter_set *data,
- struct rb_root *root)
-{
- tag_node_tree_insert(&data->tn, root);
-}
-
-static struct tag_counter_set *tag_counter_set_tree_search(struct rb_root *root,
- tag_t tag)
-{
- struct tag_node *node = tag_node_tree_search(root, tag);
- if (!node)
- return NULL;
- return rb_entry(&node->node, struct tag_counter_set, tn.node);
-
-}
-
-static void tag_ref_tree_insert(struct tag_ref *data, struct rb_root *root)
-{
- tag_node_tree_insert(&data->tn, root);
-}
-
-static struct tag_ref *tag_ref_tree_search(struct rb_root *root, tag_t tag)
-{
- struct tag_node *node = tag_node_tree_search(root, tag);
- if (!node)
- return NULL;
- return rb_entry(&node->node, struct tag_ref, tn.node);
-}
-
-static struct sock_tag *sock_tag_tree_search(struct rb_root *root,
- const struct sock *sk)
-{
- struct rb_node *node = root->rb_node;
-
- while (node) {
- struct sock_tag *data = rb_entry(node, struct sock_tag,
- sock_node);
- if (sk < data->sk)
- node = node->rb_left;
- else if (sk > data->sk)
- node = node->rb_right;
- else
- return data;
- }
- return NULL;
-}
-
-static void sock_tag_tree_insert(struct sock_tag *data, struct rb_root *root)
-{
- struct rb_node **new = &(root->rb_node), *parent = NULL;
-
- /* Figure out where to put new node */
- while (*new) {
- struct sock_tag *this = rb_entry(*new, struct sock_tag,
- sock_node);
- parent = *new;
- if (data->sk < this->sk)
- new = &((*new)->rb_left);
- else if (data->sk > this->sk)
- new = &((*new)->rb_right);
- else
- BUG();
- }
-
- /* Add new node and rebalance tree. */
- rb_link_node(&data->sock_node, parent, new);
- rb_insert_color(&data->sock_node, root);
-}
-
-static void sock_tag_tree_erase(struct rb_root *st_to_free_tree)
-{
- struct rb_node *node;
- struct sock_tag *st_entry;
-
- node = rb_first(st_to_free_tree);
- while (node) {
- st_entry = rb_entry(node, struct sock_tag, sock_node);
- node = rb_next(node);
- CT_DEBUG("qtaguid: %s(): "
- "erase st: sk=%p tag=0x%llx (uid=%u)\n", __func__,
- st_entry->sk,
- st_entry->tag,
- get_uid_from_tag(st_entry->tag));
- rb_erase(&st_entry->sock_node, st_to_free_tree);
- sock_put(st_entry->sk);
- kfree(st_entry);
- }
-}
-
-static struct proc_qtu_data *proc_qtu_data_tree_search(struct rb_root *root,
- const pid_t pid)
-{
- struct rb_node *node = root->rb_node;
-
- while (node) {
- struct proc_qtu_data *data = rb_entry(node,
- struct proc_qtu_data,
- node);
- if (pid < data->pid)
- node = node->rb_left;
- else if (pid > data->pid)
- node = node->rb_right;
- else
- return data;
- }
- return NULL;
-}
-
-static void proc_qtu_data_tree_insert(struct proc_qtu_data *data,
- struct rb_root *root)
-{
- struct rb_node **new = &(root->rb_node), *parent = NULL;
-
- /* Figure out where to put new node */
- while (*new) {
- struct proc_qtu_data *this = rb_entry(*new,
- struct proc_qtu_data,
- node);
- parent = *new;
- if (data->pid < this->pid)
- new = &((*new)->rb_left);
- else if (data->pid > this->pid)
- new = &((*new)->rb_right);
- else
- BUG();
- }
-
- /* Add new node and rebalance tree. */
- rb_link_node(&data->node, parent, new);
- rb_insert_color(&data->node, root);
-}
-
-static void uid_tag_data_tree_insert(struct uid_tag_data *data,
- struct rb_root *root)
-{
- struct rb_node **new = &(root->rb_node), *parent = NULL;
-
- /* Figure out where to put new node */
- while (*new) {
- struct uid_tag_data *this = rb_entry(*new,
- struct uid_tag_data,
- node);
- parent = *new;
- if (data->uid < this->uid)
- new = &((*new)->rb_left);
- else if (data->uid > this->uid)
- new = &((*new)->rb_right);
- else
- BUG();
- }
-
- /* Add new node and rebalance tree. */
- rb_link_node(&data->node, parent, new);
- rb_insert_color(&data->node, root);
-}
-
-static struct uid_tag_data *uid_tag_data_tree_search(struct rb_root *root,
- uid_t uid)
-{
- struct rb_node *node = root->rb_node;
-
- while (node) {
- struct uid_tag_data *data = rb_entry(node,
- struct uid_tag_data,
- node);
- if (uid < data->uid)
- node = node->rb_left;
- else if (uid > data->uid)
- node = node->rb_right;
- else
- return data;
- }
- return NULL;
-}
-
-/*
- * Allocates a new uid_tag_data struct if needed.
- * Returns a pointer to the found or allocated uid_tag_data.
- * Returns a PTR_ERR on failures, and lock is not held.
- * If found is not NULL:
- * sets *found to true if not allocated.
- * sets *found to false if allocated.
- */
-struct uid_tag_data *get_uid_data(uid_t uid, bool *found_res)
-{
- struct uid_tag_data *utd_entry;
-
- /* Look for top level uid_tag_data for the UID */
- utd_entry = uid_tag_data_tree_search(&uid_tag_data_tree, uid);
- DR_DEBUG("qtaguid: get_uid_data(%u) utd=%p\n", uid, utd_entry);
-
- if (found_res)
- *found_res = utd_entry;
- if (utd_entry)
- return utd_entry;
-
- utd_entry = kzalloc(sizeof(*utd_entry), GFP_ATOMIC);
- if (!utd_entry) {
- pr_err("qtaguid: get_uid_data(%u): "
- "tag data alloc failed\n", uid);
- return ERR_PTR(-ENOMEM);
- }
-
- utd_entry->uid = uid;
- utd_entry->tag_ref_tree = RB_ROOT;
- uid_tag_data_tree_insert(utd_entry, &uid_tag_data_tree);
- DR_DEBUG("qtaguid: get_uid_data(%u) new utd=%p\n", uid, utd_entry);
- return utd_entry;
-}
-
-/* Never returns NULL. Either PTR_ERR or a valid ptr. */
-static struct tag_ref *new_tag_ref(tag_t new_tag,
- struct uid_tag_data *utd_entry)
-{
- struct tag_ref *tr_entry;
- int res;
-
- if (utd_entry->num_active_tags + 1 > max_sock_tags) {
- pr_info("qtaguid: new_tag_ref(0x%llx): "
- "tag ref alloc quota exceeded. max=%d\n",
- new_tag, max_sock_tags);
- res = -EMFILE;
- goto err_res;
-
- }
-
- tr_entry = kzalloc(sizeof(*tr_entry), GFP_ATOMIC);
- if (!tr_entry) {
- pr_err("qtaguid: new_tag_ref(0x%llx): "
- "tag ref alloc failed\n",
- new_tag);
- res = -ENOMEM;
- goto err_res;
- }
- tr_entry->tn.tag = new_tag;
- /* tr_entry->num_sock_tags handled by caller */
- utd_entry->num_active_tags++;
- tag_ref_tree_insert(tr_entry, &utd_entry->tag_ref_tree);
- DR_DEBUG("qtaguid: new_tag_ref(0x%llx): "
- " inserted new tag ref %p\n",
- new_tag, tr_entry);
- return tr_entry;
-
-err_res:
- return ERR_PTR(res);
-}
-
-static struct tag_ref *lookup_tag_ref(tag_t full_tag,
- struct uid_tag_data **utd_res)
-{
- struct uid_tag_data *utd_entry;
- struct tag_ref *tr_entry;
- bool found_utd;
- uid_t uid = get_uid_from_tag(full_tag);
-
- DR_DEBUG("qtaguid: lookup_tag_ref(tag=0x%llx (uid=%u))\n",
- full_tag, uid);
-
- utd_entry = get_uid_data(uid, &found_utd);
- if (IS_ERR_OR_NULL(utd_entry)) {
- if (utd_res)
- *utd_res = utd_entry;
- return NULL;
- }
-
- tr_entry = tag_ref_tree_search(&utd_entry->tag_ref_tree, full_tag);
- if (utd_res)
- *utd_res = utd_entry;
- DR_DEBUG("qtaguid: lookup_tag_ref(0x%llx) utd_entry=%p tr_entry=%p\n",
- full_tag, utd_entry, tr_entry);
- return tr_entry;
-}
-
-/* Never returns NULL. Either PTR_ERR or a valid ptr. */
-static struct tag_ref *get_tag_ref(tag_t full_tag,
- struct uid_tag_data **utd_res)
-{
- struct uid_tag_data *utd_entry;
- struct tag_ref *tr_entry;
-
- DR_DEBUG("qtaguid: get_tag_ref(0x%llx)\n",
- full_tag);
- tr_entry = lookup_tag_ref(full_tag, &utd_entry);
- BUG_ON(IS_ERR_OR_NULL(utd_entry));
- if (!tr_entry)
- tr_entry = new_tag_ref(full_tag, utd_entry);
-
- if (utd_res)
- *utd_res = utd_entry;
- DR_DEBUG("qtaguid: get_tag_ref(0x%llx) utd=%p tr=%p\n",
- full_tag, utd_entry, tr_entry);
- return tr_entry;
-}
-
-/* Checks and maybe frees the UID Tag Data entry */
-static void put_utd_entry(struct uid_tag_data *utd_entry)
-{
- /* Are we done with the UID tag data entry? */
- if (RB_EMPTY_ROOT(&utd_entry->tag_ref_tree) &&
- !utd_entry->num_pqd) {
- DR_DEBUG("qtaguid: %s(): "
- "erase utd_entry=%p uid=%u "
- "by pid=%u tgid=%u uid=%u\n", __func__,
- utd_entry, utd_entry->uid,
- current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid()));
- BUG_ON(utd_entry->num_active_tags);
- rb_erase(&utd_entry->node, &uid_tag_data_tree);
- kfree(utd_entry);
- } else {
- DR_DEBUG("qtaguid: %s(): "
- "utd_entry=%p still has %d tags %d proc_qtu_data\n",
- __func__, utd_entry, utd_entry->num_active_tags,
- utd_entry->num_pqd);
- BUG_ON(!(utd_entry->num_active_tags ||
- utd_entry->num_pqd));
- }
-}
-
-/*
- * If no sock_tags are using this tag_ref,
- * decrements refcount of utd_entry, removes tr_entry
- * from utd_entry->tag_ref_tree and frees.
- */
-static void free_tag_ref_from_utd_entry(struct tag_ref *tr_entry,
- struct uid_tag_data *utd_entry)
-{
- DR_DEBUG("qtaguid: %s(): %p tag=0x%llx (uid=%u)\n", __func__,
- tr_entry, tr_entry->tn.tag,
- get_uid_from_tag(tr_entry->tn.tag));
- if (!tr_entry->num_sock_tags) {
- BUG_ON(!utd_entry->num_active_tags);
- utd_entry->num_active_tags--;
- rb_erase(&tr_entry->tn.node, &utd_entry->tag_ref_tree);
- DR_DEBUG("qtaguid: %s(): erased %p\n", __func__, tr_entry);
- kfree(tr_entry);
- }
-}
-
-static void put_tag_ref_tree(tag_t full_tag, struct uid_tag_data *utd_entry)
-{
- struct rb_node *node;
- struct tag_ref *tr_entry;
- tag_t acct_tag;
-
- DR_DEBUG("qtaguid: %s(tag=0x%llx (uid=%u))\n", __func__,
- full_tag, get_uid_from_tag(full_tag));
- acct_tag = get_atag_from_tag(full_tag);
- node = rb_first(&utd_entry->tag_ref_tree);
- while (node) {
- tr_entry = rb_entry(node, struct tag_ref, tn.node);
- node = rb_next(node);
- if (!acct_tag || tr_entry->tn.tag == full_tag)
- free_tag_ref_from_utd_entry(tr_entry, utd_entry);
- }
-}
-
-static ssize_t read_proc_u64(struct file *file, char __user *buf,
- size_t size, loff_t *ppos)
-{
- uint64_t *valuep = PDE_DATA(file_inode(file));
- char tmp[24];
- size_t tmp_size;
-
- tmp_size = scnprintf(tmp, sizeof(tmp), "%llu\n", *valuep);
- return simple_read_from_buffer(buf, size, ppos, tmp, tmp_size);
-}
-
-static ssize_t read_proc_bool(struct file *file, char __user *buf,
- size_t size, loff_t *ppos)
-{
- bool *valuep = PDE_DATA(file_inode(file));
- char tmp[24];
- size_t tmp_size;
-
- tmp_size = scnprintf(tmp, sizeof(tmp), "%u\n", *valuep);
- return simple_read_from_buffer(buf, size, ppos, tmp, tmp_size);
-}
-
-static int get_active_counter_set(tag_t tag)
-{
- int active_set = 0;
- struct tag_counter_set *tcs;
-
- MT_DEBUG("qtaguid: get_active_counter_set(tag=0x%llx)"
- " (uid=%u)\n",
- tag, get_uid_from_tag(tag));
- /* For now we only handle UID tags for active sets */
- tag = get_utag_from_tag(tag);
- spin_lock_bh(&tag_counter_set_list_lock);
- tcs = tag_counter_set_tree_search(&tag_counter_set_tree, tag);
- if (tcs)
- active_set = tcs->active_set;
- spin_unlock_bh(&tag_counter_set_list_lock);
- return active_set;
-}
-
-/*
- * Find the entry for tracking the specified interface.
- * Caller must hold iface_stat_list_lock
- */
-static struct iface_stat *get_iface_entry(const char *ifname)
-{
- struct iface_stat *iface_entry;
-
- /* Find the entry for tracking the specified tag within the interface */
- if (ifname == NULL) {
- pr_info("qtaguid: iface_stat: get() NULL device name\n");
- return NULL;
- }
-
- /* Iterate over interfaces */
- list_for_each_entry(iface_entry, &iface_stat_list, list) {
- if (!strcmp(ifname, iface_entry->ifname))
- goto done;
- }
- iface_entry = NULL;
-done:
- return iface_entry;
-}
-
-/* This is for fmt2 only */
-static void pp_iface_stat_header(struct seq_file *m)
-{
- seq_puts(m,
- "ifname "
- "total_skb_rx_bytes total_skb_rx_packets "
- "total_skb_tx_bytes total_skb_tx_packets "
- "rx_tcp_bytes rx_tcp_packets "
- "rx_udp_bytes rx_udp_packets "
- "rx_other_bytes rx_other_packets "
- "tx_tcp_bytes tx_tcp_packets "
- "tx_udp_bytes tx_udp_packets "
- "tx_other_bytes tx_other_packets\n"
- );
-}
-
-static void pp_iface_stat_line(struct seq_file *m,
- struct iface_stat *iface_entry)
-{
- struct data_counters *cnts;
- int cnt_set = 0; /* We only use one set for the device */
- cnts = &iface_entry->totals_via_skb;
- seq_printf(m, "%s %llu %llu %llu %llu %llu %llu %llu %llu "
- "%llu %llu %llu %llu %llu %llu %llu %llu\n",
- iface_entry->ifname,
- dc_sum_bytes(cnts, cnt_set, IFS_RX),
- dc_sum_packets(cnts, cnt_set, IFS_RX),
- dc_sum_bytes(cnts, cnt_set, IFS_TX),
- dc_sum_packets(cnts, cnt_set, IFS_TX),
- cnts->bpc[cnt_set][IFS_RX][IFS_TCP].bytes,
- cnts->bpc[cnt_set][IFS_RX][IFS_TCP].packets,
- cnts->bpc[cnt_set][IFS_RX][IFS_UDP].bytes,
- cnts->bpc[cnt_set][IFS_RX][IFS_UDP].packets,
- cnts->bpc[cnt_set][IFS_RX][IFS_PROTO_OTHER].bytes,
- cnts->bpc[cnt_set][IFS_RX][IFS_PROTO_OTHER].packets,
- cnts->bpc[cnt_set][IFS_TX][IFS_TCP].bytes,
- cnts->bpc[cnt_set][IFS_TX][IFS_TCP].packets,
- cnts->bpc[cnt_set][IFS_TX][IFS_UDP].bytes,
- cnts->bpc[cnt_set][IFS_TX][IFS_UDP].packets,
- cnts->bpc[cnt_set][IFS_TX][IFS_PROTO_OTHER].bytes,
- cnts->bpc[cnt_set][IFS_TX][IFS_PROTO_OTHER].packets);
-}
-
-struct proc_iface_stat_fmt_info {
- int fmt;
-};
-
-static void *iface_stat_fmt_proc_start(struct seq_file *m, loff_t *pos)
-{
- struct proc_iface_stat_fmt_info *p = m->private;
- loff_t n = *pos;
-
- /*
- * This lock will prevent iface_stat_update() from changing active,
- * and in turn prevent an interface from unregistering itself.
- */
- spin_lock_bh(&iface_stat_list_lock);
-
- if (unlikely(module_passive))
- return NULL;
-
- if (!n && p->fmt == 2)
- pp_iface_stat_header(m);
-
- return seq_list_start(&iface_stat_list, n);
-}
-
-static void *iface_stat_fmt_proc_next(struct seq_file *m, void *p, loff_t *pos)
-{
- return seq_list_next(p, &iface_stat_list, pos);
-}
-
-static void iface_stat_fmt_proc_stop(struct seq_file *m, void *p)
-{
- spin_unlock_bh(&iface_stat_list_lock);
-}
-
-static int iface_stat_fmt_proc_show(struct seq_file *m, void *v)
-{
- struct proc_iface_stat_fmt_info *p = m->private;
- struct iface_stat *iface_entry;
- struct rtnl_link_stats64 dev_stats, *stats;
- struct rtnl_link_stats64 no_dev_stats = {0};
-
-
- CT_DEBUG("qtaguid:proc iface_stat_fmt pid=%u tgid=%u uid=%u\n",
- current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid()));
-
- iface_entry = list_entry(v, struct iface_stat, list);
-
- if (iface_entry->active) {
- stats = dev_get_stats(iface_entry->net_dev,
- &dev_stats);
- } else {
- stats = &no_dev_stats;
- }
- /*
- * If the meaning of the data changes, then update the fmtX
- * string.
- */
- if (p->fmt == 1) {
- seq_printf(m, "%s %d %llu %llu %llu %llu %llu %llu %llu %llu\n",
- iface_entry->ifname,
- iface_entry->active,
- iface_entry->totals_via_dev[IFS_RX].bytes,
- iface_entry->totals_via_dev[IFS_RX].packets,
- iface_entry->totals_via_dev[IFS_TX].bytes,
- iface_entry->totals_via_dev[IFS_TX].packets,
- stats->rx_bytes, stats->rx_packets,
- stats->tx_bytes, stats->tx_packets
- );
- } else {
- pp_iface_stat_line(m, iface_entry);
- }
- return 0;
-}
-
-static const struct file_operations read_u64_fops = {
- .read = read_proc_u64,
- .llseek = default_llseek,
-};
-
-static const struct file_operations read_bool_fops = {
- .read = read_proc_bool,
- .llseek = default_llseek,
-};
-
-static void iface_create_proc_worker(struct work_struct *work)
-{
- struct proc_dir_entry *proc_entry;
- struct iface_stat_work *isw = container_of(work, struct iface_stat_work,
- iface_work);
- struct iface_stat *new_iface = isw->iface_entry;
-
- /* iface_entries are not deleted, so safe to manipulate. */
- proc_entry = proc_mkdir(new_iface->ifname, iface_stat_procdir);
- if (IS_ERR_OR_NULL(proc_entry)) {
- pr_err("qtaguid: iface_stat: create_proc(): alloc failed.\n");
- kfree(isw);
- return;
- }
-
- new_iface->proc_ptr = proc_entry;
-
- proc_create_data("tx_bytes", proc_iface_perms, proc_entry,
- &read_u64_fops,
- &new_iface->totals_via_dev[IFS_TX].bytes);
- proc_create_data("rx_bytes", proc_iface_perms, proc_entry,
- &read_u64_fops,
- &new_iface->totals_via_dev[IFS_RX].bytes);
- proc_create_data("tx_packets", proc_iface_perms, proc_entry,
- &read_u64_fops,
- &new_iface->totals_via_dev[IFS_TX].packets);
- proc_create_data("rx_packets", proc_iface_perms, proc_entry,
- &read_u64_fops,
- &new_iface->totals_via_dev[IFS_RX].packets);
- proc_create_data("active", proc_iface_perms, proc_entry,
- &read_bool_fops, &new_iface->active);
-
- IF_DEBUG("qtaguid: iface_stat: create_proc(): done "
- "entry=%p dev=%s\n", new_iface, new_iface->ifname);
- kfree(isw);
-}
-
-/*
- * Will set the entry's active state, and
- * update the net_dev accordingly also.
- */
-static void _iface_stat_set_active(struct iface_stat *entry,
- struct net_device *net_dev,
- bool activate)
-{
- if (activate) {
- entry->net_dev = net_dev;
- entry->active = true;
- IF_DEBUG("qtaguid: %s(%s): "
- "enable tracking. rfcnt=%d\n", __func__,
- entry->ifname,
- __this_cpu_read(*net_dev->pcpu_refcnt));
- } else {
- entry->active = false;
- entry->net_dev = NULL;
- IF_DEBUG("qtaguid: %s(%s): "
- "disable tracking. rfcnt=%d\n", __func__,
- entry->ifname,
- __this_cpu_read(*net_dev->pcpu_refcnt));
-
- }
-}
-
-/* Caller must hold iface_stat_list_lock */
-static struct iface_stat *iface_alloc(struct net_device *net_dev)
-{
- struct iface_stat *new_iface;
- struct iface_stat_work *isw;
-
- new_iface = kzalloc(sizeof(*new_iface), GFP_ATOMIC);
- if (new_iface == NULL) {
- pr_err("qtaguid: iface_stat: create(%s): "
- "iface_stat alloc failed\n", net_dev->name);
- return NULL;
- }
- new_iface->ifname = kstrdup(net_dev->name, GFP_ATOMIC);
- if (new_iface->ifname == NULL) {
- pr_err("qtaguid: iface_stat: create(%s): "
- "ifname alloc failed\n", net_dev->name);
- kfree(new_iface);
- return NULL;
- }
- spin_lock_init(&new_iface->tag_stat_list_lock);
- new_iface->tag_stat_tree = RB_ROOT;
- _iface_stat_set_active(new_iface, net_dev, true);
-
- /*
- * ipv6 notifier chains are atomic :(
- * No create_proc_read_entry() for you!
- */
- isw = kmalloc(sizeof(*isw), GFP_ATOMIC);
- if (!isw) {
- pr_err("qtaguid: iface_stat: create(%s): "
- "work alloc failed\n", new_iface->ifname);
- _iface_stat_set_active(new_iface, net_dev, false);
- kfree(new_iface->ifname);
- kfree(new_iface);
- return NULL;
- }
- isw->iface_entry = new_iface;
- INIT_WORK(&isw->iface_work, iface_create_proc_worker);
- schedule_work(&isw->iface_work);
- list_add(&new_iface->list, &iface_stat_list);
- return new_iface;
-}
-
-static void iface_check_stats_reset_and_adjust(struct net_device *net_dev,
- struct iface_stat *iface)
-{
- struct rtnl_link_stats64 dev_stats, *stats;
- bool stats_rewound;
-
- stats = dev_get_stats(net_dev, &dev_stats);
- /* No empty packets */
- stats_rewound =
- (stats->rx_bytes < iface->last_known[IFS_RX].bytes)
- || (stats->tx_bytes < iface->last_known[IFS_TX].bytes);
-
- IF_DEBUG("qtaguid: %s(%s): iface=%p netdev=%p "
- "bytes rx/tx=%llu/%llu "
- "active=%d last_known=%d "
- "stats_rewound=%d\n", __func__,
- net_dev ? net_dev->name : "?",
- iface, net_dev,
- stats->rx_bytes, stats->tx_bytes,
- iface->active, iface->last_known_valid, stats_rewound);
-
- if (iface->active && iface->last_known_valid && stats_rewound) {
- pr_warn_once("qtaguid: iface_stat: %s(%s): "
- "iface reset its stats unexpectedly\n", __func__,
- net_dev->name);
-
- iface->totals_via_dev[IFS_TX].bytes +=
- iface->last_known[IFS_TX].bytes;
- iface->totals_via_dev[IFS_TX].packets +=
- iface->last_known[IFS_TX].packets;
- iface->totals_via_dev[IFS_RX].bytes +=
- iface->last_known[IFS_RX].bytes;
- iface->totals_via_dev[IFS_RX].packets +=
- iface->last_known[IFS_RX].packets;
- iface->last_known_valid = false;
- IF_DEBUG("qtaguid: %s(%s): iface=%p "
- "used last known bytes rx/tx=%llu/%llu\n", __func__,
- iface->ifname, iface, iface->last_known[IFS_RX].bytes,
- iface->last_known[IFS_TX].bytes);
- }
-}
-
-/*
- * Create a new entry for tracking the specified interface.
- * Do nothing if the entry already exists.
- * Called when an interface is configured with a valid IP address.
- */
-static void iface_stat_create(struct net_device *net_dev,
- struct in_ifaddr *ifa)
-{
- struct in_device *in_dev = NULL;
- const char *ifname;
- struct iface_stat *entry;
- __be32 ipaddr = 0;
- struct iface_stat *new_iface;
-
- IF_DEBUG("qtaguid: iface_stat: create(%s): ifa=%p netdev=%p\n",
- net_dev ? net_dev->name : "?",
- ifa, net_dev);
- if (!net_dev) {
- pr_err("qtaguid: iface_stat: create(): no net dev\n");
- return;
- }
-
- ifname = net_dev->name;
- if (!ifa) {
- in_dev = in_dev_get(net_dev);
- if (!in_dev) {
- pr_err("qtaguid: iface_stat: create(%s): no inet dev\n",
- ifname);
- return;
- }
- IF_DEBUG("qtaguid: iface_stat: create(%s): in_dev=%p\n",
- ifname, in_dev);
- for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
- IF_DEBUG("qtaguid: iface_stat: create(%s): "
- "ifa=%p ifa_label=%s\n",
- ifname, ifa, ifa->ifa_label);
- if (!strcmp(ifname, ifa->ifa_label))
- break;
- }
- }
-
- if (!ifa) {
- IF_DEBUG("qtaguid: iface_stat: create(%s): no matching IP\n",
- ifname);
- goto done_put;
- }
- ipaddr = ifa->ifa_local;
-
- spin_lock_bh(&iface_stat_list_lock);
- entry = get_iface_entry(ifname);
- if (entry != NULL) {
- IF_DEBUG("qtaguid: iface_stat: create(%s): entry=%p\n",
- ifname, entry);
- iface_check_stats_reset_and_adjust(net_dev, entry);
- _iface_stat_set_active(entry, net_dev, true);
- IF_DEBUG("qtaguid: %s(%s): "
- "tracking now %d on ip=%pI4\n", __func__,
- entry->ifname, true, &ipaddr);
- goto done_unlock_put;
- }
-
- new_iface = iface_alloc(net_dev);
- IF_DEBUG("qtaguid: iface_stat: create(%s): done "
- "entry=%p ip=%pI4\n", ifname, new_iface, &ipaddr);
-done_unlock_put:
- spin_unlock_bh(&iface_stat_list_lock);
-done_put:
- if (in_dev)
- in_dev_put(in_dev);
-}
-
-static void iface_stat_create_ipv6(struct net_device *net_dev,
- struct inet6_ifaddr *ifa)
-{
- struct in_device *in_dev;
- const char *ifname;
- struct iface_stat *entry;
- struct iface_stat *new_iface;
- int addr_type;
-
- IF_DEBUG("qtaguid: iface_stat: create6(): ifa=%p netdev=%p->name=%s\n",
- ifa, net_dev, net_dev ? net_dev->name : "");
- if (!net_dev) {
- pr_err("qtaguid: iface_stat: create6(): no net dev!\n");
- return;
- }
- ifname = net_dev->name;
-
- in_dev = in_dev_get(net_dev);
- if (!in_dev) {
- pr_err("qtaguid: iface_stat: create6(%s): no inet dev\n",
- ifname);
- return;
- }
-
- IF_DEBUG("qtaguid: iface_stat: create6(%s): in_dev=%p\n",
- ifname, in_dev);
-
- if (!ifa) {
- IF_DEBUG("qtaguid: iface_stat: create6(%s): no matching IP\n",
- ifname);
- goto done_put;
- }
- addr_type = ipv6_addr_type(&ifa->addr);
-
- spin_lock_bh(&iface_stat_list_lock);
- entry = get_iface_entry(ifname);
- if (entry != NULL) {
- IF_DEBUG("qtaguid: %s(%s): entry=%p\n", __func__,
- ifname, entry);
- iface_check_stats_reset_and_adjust(net_dev, entry);
- _iface_stat_set_active(entry, net_dev, true);
- IF_DEBUG("qtaguid: %s(%s): "
- "tracking now %d on ip=%pI6c\n", __func__,
- entry->ifname, true, &ifa->addr);
- goto done_unlock_put;
- }
-
- new_iface = iface_alloc(net_dev);
- IF_DEBUG("qtaguid: iface_stat: create6(%s): done "
- "entry=%p ip=%pI6c\n", ifname, new_iface, &ifa->addr);
-
-done_unlock_put:
- spin_unlock_bh(&iface_stat_list_lock);
-done_put:
- in_dev_put(in_dev);
-}
-
-static struct sock_tag *get_sock_stat_nl(const struct sock *sk)
-{
- MT_DEBUG("qtaguid: get_sock_stat_nl(sk=%p)\n", sk);
- return sock_tag_tree_search(&sock_tag_tree, sk);
-}
-
-static struct sock_tag *get_sock_stat(const struct sock *sk)
-{
- struct sock_tag *sock_tag_entry;
- MT_DEBUG("qtaguid: get_sock_stat(sk=%p)\n", sk);
- if (!sk)
- return NULL;
- spin_lock_bh(&sock_tag_list_lock);
- sock_tag_entry = get_sock_stat_nl(sk);
- spin_unlock_bh(&sock_tag_list_lock);
- return sock_tag_entry;
-}
-
-static int ipx_proto(const struct sk_buff *skb,
- struct xt_action_param *par)
-{
- int thoff = 0, tproto;
-
- switch (par->family) {
- case NFPROTO_IPV6:
- tproto = ipv6_find_hdr(skb, &thoff, -1, NULL, NULL);
- if (tproto < 0)
- MT_DEBUG("%s(): transport header not found in ipv6"
- " skb=%p\n", __func__, skb);
- break;
- case NFPROTO_IPV4:
- tproto = ip_hdr(skb)->protocol;
- break;
- default:
- tproto = IPPROTO_RAW;
- }
- return tproto;
-}
-
-static void
-data_counters_update(struct data_counters *dc, int set,
- enum ifs_tx_rx direction, int proto, int bytes)
-{
- switch (proto) {
- case IPPROTO_TCP:
- dc_add_byte_packets(dc, set, direction, IFS_TCP, bytes, 1);
- break;
- case IPPROTO_UDP:
- dc_add_byte_packets(dc, set, direction, IFS_UDP, bytes, 1);
- break;
- case IPPROTO_IP:
- default:
- dc_add_byte_packets(dc, set, direction, IFS_PROTO_OTHER, bytes,
- 1);
- break;
- }
-}
-
-/*
- * Update stats for the specified interface. Do nothing if the entry
- * does not exist (when a device was never configured with an IP address).
- * Called when an device is being unregistered.
- */
-static void iface_stat_update(struct net_device *net_dev, bool stash_only)
-{
- struct rtnl_link_stats64 dev_stats, *stats;
- struct iface_stat *entry;
-
- stats = dev_get_stats(net_dev, &dev_stats);
- spin_lock_bh(&iface_stat_list_lock);
- entry = get_iface_entry(net_dev->name);
- if (entry == NULL) {
- IF_DEBUG("qtaguid: iface_stat: update(%s): not tracked\n",
- net_dev->name);
- spin_unlock_bh(&iface_stat_list_lock);
- return;
- }
-
- IF_DEBUG("qtaguid: %s(%s): entry=%p\n", __func__,
- net_dev->name, entry);
- if (!entry->active) {
- IF_DEBUG("qtaguid: %s(%s): already disabled\n", __func__,
- net_dev->name);
- spin_unlock_bh(&iface_stat_list_lock);
- return;
- }
-
- if (stash_only) {
- entry->last_known[IFS_TX].bytes = stats->tx_bytes;
- entry->last_known[IFS_TX].packets = stats->tx_packets;
- entry->last_known[IFS_RX].bytes = stats->rx_bytes;
- entry->last_known[IFS_RX].packets = stats->rx_packets;
- entry->last_known_valid = true;
- IF_DEBUG("qtaguid: %s(%s): "
- "dev stats stashed rx/tx=%llu/%llu\n", __func__,
- net_dev->name, stats->rx_bytes, stats->tx_bytes);
- spin_unlock_bh(&iface_stat_list_lock);
- return;
- }
- entry->totals_via_dev[IFS_TX].bytes += stats->tx_bytes;
- entry->totals_via_dev[IFS_TX].packets += stats->tx_packets;
- entry->totals_via_dev[IFS_RX].bytes += stats->rx_bytes;
- entry->totals_via_dev[IFS_RX].packets += stats->rx_packets;
- /* We don't need the last_known[] anymore */
- entry->last_known_valid = false;
- _iface_stat_set_active(entry, net_dev, false);
- IF_DEBUG("qtaguid: %s(%s): "
- "disable tracking. rx/tx=%llu/%llu\n", __func__,
- net_dev->name, stats->rx_bytes, stats->tx_bytes);
- spin_unlock_bh(&iface_stat_list_lock);
-}
-
-/* Guarantied to return a net_device that has a name */
-static void get_dev_and_dir(const struct sk_buff *skb,
- struct xt_action_param *par,
- enum ifs_tx_rx *direction,
- const struct net_device **el_dev)
-{
- BUG_ON(!direction || !el_dev);
-
- if (par->in) {
- *el_dev = par->in;
- *direction = IFS_RX;
- } else if (par->out) {
- *el_dev = par->out;
- *direction = IFS_TX;
- } else {
- pr_err("qtaguid[%d]: %s(): no par->in/out?!!\n",
- par->hooknum, __func__);
- BUG();
- }
- if (skb->dev && *el_dev != skb->dev) {
- MT_DEBUG("qtaguid[%d]: skb->dev=%pK %s vs par->%s=%pK %s\n",
- par->hooknum, skb->dev, skb->dev->name,
- *direction == IFS_RX ? "in" : "out", *el_dev,
- (*el_dev)->name);
- }
-}
-
-/*
- * Update stats for the specified interface from the skb.
- * Do nothing if the entry
- * does not exist (when a device was never configured with an IP address).
- * Called on each sk.
- */
-static void iface_stat_update_from_skb(const struct sk_buff *skb,
- struct xt_action_param *par)
-{
- struct iface_stat *entry;
- const struct net_device *el_dev;
- enum ifs_tx_rx direction;
- int bytes = skb->len;
- int proto;
-
- get_dev_and_dir(skb, par, &direction, &el_dev);
- proto = ipx_proto(skb, par);
- MT_DEBUG("qtaguid[%d]: iface_stat: %s(%s): "
- "type=%d fam=%d proto=%d dir=%d\n",
- par->hooknum, __func__, el_dev->name, el_dev->type,
- par->family, proto, direction);
-
- spin_lock_bh(&iface_stat_list_lock);
- entry = get_iface_entry(el_dev->name);
- if (entry == NULL) {
- IF_DEBUG("qtaguid[%d]: iface_stat: %s(%s): not tracked\n",
- par->hooknum, __func__, el_dev->name);
- spin_unlock_bh(&iface_stat_list_lock);
- return;
- }
-
- IF_DEBUG("qtaguid[%d]: %s(%s): entry=%p\n", par->hooknum, __func__,
- el_dev->name, entry);
-
- data_counters_update(&entry->totals_via_skb, 0, direction, proto,
- bytes);
- spin_unlock_bh(&iface_stat_list_lock);
-}
-
-static void tag_stat_update(struct tag_stat *tag_entry,
- enum ifs_tx_rx direction, int proto, int bytes)
-{
- int active_set;
- active_set = get_active_counter_set(tag_entry->tn.tag);
- MT_DEBUG("qtaguid: tag_stat_update(tag=0x%llx (uid=%u) set=%d "
- "dir=%d proto=%d bytes=%d)\n",
- tag_entry->tn.tag, get_uid_from_tag(tag_entry->tn.tag),
- active_set, direction, proto, bytes);
- data_counters_update(&tag_entry->counters, active_set, direction,
- proto, bytes);
- if (tag_entry->parent_counters)
- data_counters_update(tag_entry->parent_counters, active_set,
- direction, proto, bytes);
-}
-
-/*
- * Create a new entry for tracking the specified {acct_tag,uid_tag} within
- * the interface.
- * iface_entry->tag_stat_list_lock should be held.
- */
-static struct tag_stat *create_if_tag_stat(struct iface_stat *iface_entry,
- tag_t tag)
-{
- struct tag_stat *new_tag_stat_entry = NULL;
- IF_DEBUG("qtaguid: iface_stat: %s(): ife=%p tag=0x%llx"
- " (uid=%u)\n", __func__,
- iface_entry, tag, get_uid_from_tag(tag));
- new_tag_stat_entry = kzalloc(sizeof(*new_tag_stat_entry), GFP_ATOMIC);
- if (!new_tag_stat_entry) {
- pr_err("qtaguid: iface_stat: tag stat alloc failed\n");
- goto done;
- }
- new_tag_stat_entry->tn.tag = tag;
- tag_stat_tree_insert(new_tag_stat_entry, &iface_entry->tag_stat_tree);
-done:
- return new_tag_stat_entry;
-}
-
-static void if_tag_stat_update(const char *ifname, uid_t uid,
- const struct sock *sk, enum ifs_tx_rx direction,
- int proto, int bytes)
-{
- struct tag_stat *tag_stat_entry;
- tag_t tag, acct_tag;
- tag_t uid_tag;
- struct data_counters *uid_tag_counters;
- struct sock_tag *sock_tag_entry;
- struct iface_stat *iface_entry;
- struct tag_stat *new_tag_stat = NULL;
- MT_DEBUG("qtaguid: if_tag_stat_update(ifname=%s "
- "uid=%u sk=%p dir=%d proto=%d bytes=%d)\n",
- ifname, uid, sk, direction, proto, bytes);
-
- spin_lock_bh(&iface_stat_list_lock);
- iface_entry = get_iface_entry(ifname);
- if (!iface_entry) {
- pr_err_ratelimited("qtaguid: tag_stat: stat_update() "
- "%s not found\n", ifname);
- spin_unlock_bh(&iface_stat_list_lock);
- return;
- }
- /* It is ok to process data when an iface_entry is inactive */
-
- MT_DEBUG("qtaguid: tag_stat: stat_update() dev=%s entry=%pK\n",
- ifname, iface_entry);
-
- /*
- * Look for a tagged sock.
- * It will have an acct_uid.
- */
- sock_tag_entry = get_sock_stat(sk);
- if (sock_tag_entry) {
- tag = sock_tag_entry->tag;
- acct_tag = get_atag_from_tag(tag);
- uid_tag = get_utag_from_tag(tag);
- } else {
- acct_tag = make_atag_from_value(0);
- tag = combine_atag_with_uid(acct_tag, uid);
- uid_tag = make_tag_from_uid(uid);
- }
- MT_DEBUG("qtaguid: tag_stat: stat_update(): "
- " looking for tag=0x%llx (uid=%u) in ife=%pK\n",
- tag, get_uid_from_tag(tag), iface_entry);
- /* Loop over tag list under this interface for {acct_tag,uid_tag} */
- spin_lock_bh(&iface_entry->tag_stat_list_lock);
-
- tag_stat_entry = tag_stat_tree_search(&iface_entry->tag_stat_tree,
- tag);
- if (tag_stat_entry) {
- /*
- * Updating the {acct_tag, uid_tag} entry handles both stats:
- * {0, uid_tag} will also get updated.
- */
- tag_stat_update(tag_stat_entry, direction, proto, bytes);
- goto unlock;
- }
-
- /* Loop over tag list under this interface for {0,uid_tag} */
- tag_stat_entry = tag_stat_tree_search(&iface_entry->tag_stat_tree,
- uid_tag);
- if (!tag_stat_entry) {
- /* Here: the base uid_tag did not exist */
- /*
- * No parent counters. So
- * - No {0, uid_tag} stats and no {acc_tag, uid_tag} stats.
- */
- new_tag_stat = create_if_tag_stat(iface_entry, uid_tag);
- if (!new_tag_stat)
- goto unlock;
- uid_tag_counters = &new_tag_stat->counters;
- } else {
- uid_tag_counters = &tag_stat_entry->counters;
- }
-
- if (acct_tag) {
- /* Create the child {acct_tag, uid_tag} and hook up parent. */
- new_tag_stat = create_if_tag_stat(iface_entry, tag);
- if (!new_tag_stat)
- goto unlock;
- new_tag_stat->parent_counters = uid_tag_counters;
- } else {
- /*
- * For new_tag_stat to be still NULL here would require:
- * {0, uid_tag} exists
- * and {acct_tag, uid_tag} doesn't exist
- * AND acct_tag == 0.
- * Impossible. This reassures us that new_tag_stat
- * below will always be assigned.
- */
- BUG_ON(!new_tag_stat);
- }
- tag_stat_update(new_tag_stat, direction, proto, bytes);
-unlock:
- spin_unlock_bh(&iface_entry->tag_stat_list_lock);
- spin_unlock_bh(&iface_stat_list_lock);
-}
-
-static int iface_netdev_event_handler(struct notifier_block *nb,
- unsigned long event, void *ptr) {
- struct net_device *dev = netdev_notifier_info_to_dev(ptr);
-
- if (unlikely(module_passive))
- return NOTIFY_DONE;
-
- IF_DEBUG("qtaguid: iface_stat: netdev_event(): "
- "ev=0x%lx/%s netdev=%p->name=%s\n",
- event, netdev_evt_str(event), dev, dev ? dev->name : "");
-
- switch (event) {
- case NETDEV_UP:
- iface_stat_create(dev, NULL);
- atomic64_inc(&qtu_events.iface_events);
- break;
- case NETDEV_DOWN:
- case NETDEV_UNREGISTER:
- iface_stat_update(dev, event == NETDEV_DOWN);
- atomic64_inc(&qtu_events.iface_events);
- break;
- }
- return NOTIFY_DONE;
-}
-
-static int iface_inet6addr_event_handler(struct notifier_block *nb,
- unsigned long event, void *ptr)
-{
- struct inet6_ifaddr *ifa = ptr;
- struct net_device *dev;
-
- if (unlikely(module_passive))
- return NOTIFY_DONE;
-
- IF_DEBUG("qtaguid: iface_stat: inet6addr_event(): "
- "ev=0x%lx/%s ifa=%p\n",
- event, netdev_evt_str(event), ifa);
-
- switch (event) {
- case NETDEV_UP:
- BUG_ON(!ifa || !ifa->idev);
- dev = (struct net_device *)ifa->idev->dev;
- iface_stat_create_ipv6(dev, ifa);
- atomic64_inc(&qtu_events.iface_events);
- break;
- case NETDEV_DOWN:
- case NETDEV_UNREGISTER:
- BUG_ON(!ifa || !ifa->idev);
- dev = (struct net_device *)ifa->idev->dev;
- iface_stat_update(dev, event == NETDEV_DOWN);
- atomic64_inc(&qtu_events.iface_events);
- break;
- }
- return NOTIFY_DONE;
-}
-
-static int iface_inetaddr_event_handler(struct notifier_block *nb,
- unsigned long event, void *ptr)
-{
- struct in_ifaddr *ifa = ptr;
- struct net_device *dev;
-
- if (unlikely(module_passive))
- return NOTIFY_DONE;
-
- IF_DEBUG("qtaguid: iface_stat: inetaddr_event(): "
- "ev=0x%lx/%s ifa=%p\n",
- event, netdev_evt_str(event), ifa);
-
- switch (event) {
- case NETDEV_UP:
- BUG_ON(!ifa || !ifa->ifa_dev);
- dev = ifa->ifa_dev->dev;
- iface_stat_create(dev, ifa);
- atomic64_inc(&qtu_events.iface_events);
- break;
- case NETDEV_DOWN:
- case NETDEV_UNREGISTER:
- BUG_ON(!ifa || !ifa->ifa_dev);
- dev = ifa->ifa_dev->dev;
- iface_stat_update(dev, event == NETDEV_DOWN);
- atomic64_inc(&qtu_events.iface_events);
- break;
- }
- return NOTIFY_DONE;
-}
-
-static struct notifier_block iface_netdev_notifier_blk = {
- .notifier_call = iface_netdev_event_handler,
-};
-
-static struct notifier_block iface_inetaddr_notifier_blk = {
- .notifier_call = iface_inetaddr_event_handler,
-};
-
-static struct notifier_block iface_inet6addr_notifier_blk = {
- .notifier_call = iface_inet6addr_event_handler,
-};
-
-static const struct seq_operations iface_stat_fmt_proc_seq_ops = {
- .start = iface_stat_fmt_proc_start,
- .next = iface_stat_fmt_proc_next,
- .stop = iface_stat_fmt_proc_stop,
- .show = iface_stat_fmt_proc_show,
-};
-
-static int proc_iface_stat_fmt_open(struct inode *inode, struct file *file)
-{
- struct proc_iface_stat_fmt_info *s;
-
- s = __seq_open_private(file, &iface_stat_fmt_proc_seq_ops,
- sizeof(struct proc_iface_stat_fmt_info));
- if (!s)
- return -ENOMEM;
-
- s->fmt = (uintptr_t)PDE_DATA(inode);
- return 0;
-}
-
-static const struct file_operations proc_iface_stat_fmt_fops = {
- .open = proc_iface_stat_fmt_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release_private,
-};
-
-static int __init iface_stat_init(struct proc_dir_entry *parent_procdir)
-{
- int err;
-
- iface_stat_procdir = proc_mkdir(iface_stat_procdirname, parent_procdir);
- if (!iface_stat_procdir) {
- pr_err("qtaguid: iface_stat: init failed to create proc entry\n");
- err = -1;
- goto err;
- }
-
- iface_stat_all_procfile = proc_create_data(iface_stat_all_procfilename,
- proc_iface_perms,
- parent_procdir,
- &proc_iface_stat_fmt_fops,
- (void *)1 /* fmt1 */);
- if (!iface_stat_all_procfile) {
- pr_err("qtaguid: iface_stat: init "
- " failed to create stat_old proc entry\n");
- err = -1;
- goto err_zap_entry;
- }
-
- iface_stat_fmt_procfile = proc_create_data(iface_stat_fmt_procfilename,
- proc_iface_perms,
- parent_procdir,
- &proc_iface_stat_fmt_fops,
- (void *)2 /* fmt2 */);
- if (!iface_stat_fmt_procfile) {
- pr_err("qtaguid: iface_stat: init "
- " failed to create stat_all proc entry\n");
- err = -1;
- goto err_zap_all_stats_entry;
- }
-
-
- err = register_netdevice_notifier(&iface_netdev_notifier_blk);
- if (err) {
- pr_err("qtaguid: iface_stat: init "
- "failed to register dev event handler\n");
- goto err_zap_all_stats_entries;
- }
- err = register_inetaddr_notifier(&iface_inetaddr_notifier_blk);
- if (err) {
- pr_err("qtaguid: iface_stat: init "
- "failed to register ipv4 dev event handler\n");
- goto err_unreg_nd;
- }
-
- err = register_inet6addr_notifier(&iface_inet6addr_notifier_blk);
- if (err) {
- pr_err("qtaguid: iface_stat: init "
- "failed to register ipv6 dev event handler\n");
- goto err_unreg_ip4_addr;
- }
- return 0;
-
-err_unreg_ip4_addr:
- unregister_inetaddr_notifier(&iface_inetaddr_notifier_blk);
-err_unreg_nd:
- unregister_netdevice_notifier(&iface_netdev_notifier_blk);
-err_zap_all_stats_entries:
- remove_proc_entry(iface_stat_fmt_procfilename, parent_procdir);
-err_zap_all_stats_entry:
- remove_proc_entry(iface_stat_all_procfilename, parent_procdir);
-err_zap_entry:
- remove_proc_entry(iface_stat_procdirname, parent_procdir);
-err:
- return err;
-}
-
-static struct sock *qtaguid_find_sk(const struct sk_buff *skb,
- struct xt_action_param *par)
-{
- struct sock *sk;
- unsigned int hook_mask = (1 << par->hooknum);
-
- MT_DEBUG("qtaguid[%d]: find_sk(skb=%pK) family=%d\n",
- par->hooknum, skb, par->family);
-
- /*
- * Let's not abuse the the xt_socket_get*_sk(), or else it will
- * return garbage SKs.
- */
- if (!(hook_mask & XT_SOCKET_SUPPORTED_HOOKS))
- return NULL;
-
- switch (par->family) {
- case NFPROTO_IPV6:
- sk = xt_socket_lookup_slow_v6(dev_net(skb->dev), skb, par->in);
- break;
- case NFPROTO_IPV4:
- sk = xt_socket_lookup_slow_v4(dev_net(skb->dev), skb, par->in);
- break;
- default:
- return NULL;
- }
-
- if (sk) {
- MT_DEBUG("qtaguid[%d]: %pK->sk_proto=%u->sk_state=%d\n",
- par->hooknum, sk, sk->sk_protocol, sk->sk_state);
- }
- return sk;
-}
-
-static void account_for_uid(const struct sk_buff *skb,
- const struct sock *alternate_sk, uid_t uid,
- struct xt_action_param *par)
-{
- const struct net_device *el_dev;
- enum ifs_tx_rx direction;
- int proto;
-
- get_dev_and_dir(skb, par, &direction, &el_dev);
- proto = ipx_proto(skb, par);
- MT_DEBUG("qtaguid[%d]: dev name=%s type=%d fam=%d proto=%d dir=%d\n",
- par->hooknum, el_dev->name, el_dev->type,
- par->family, proto, direction);
-
- if_tag_stat_update(el_dev->name, uid,
- skb->sk ? skb->sk : alternate_sk,
- direction,
- proto, skb->len);
-}
-
-static bool qtaguid_mt(const struct sk_buff *skb, struct xt_action_param *par)
-{
- const struct xt_qtaguid_match_info *info = par->matchinfo;
- const struct file *filp;
- bool got_sock = false;
- struct sock *sk;
- kuid_t sock_uid;
- bool res;
- bool set_sk_callback_lock = false;
- /*
- * TODO: unhack how to force just accounting.
- * For now we only do tag stats when the uid-owner is not requested
- */
- bool do_tag_stat = !(info->match & XT_QTAGUID_UID);
-
- if (unlikely(module_passive))
- return (info->match ^ info->invert) == 0;
-
- MT_DEBUG("qtaguid[%d]: entered skb=%p par->in=%p/out=%p fam=%d\n",
- par->hooknum, skb, par->in, par->out, par->family);
-
- atomic64_inc(&qtu_events.match_calls);
- if (skb == NULL) {
- res = (info->match ^ info->invert) == 0;
- goto ret_res;
- }
-
- switch (par->hooknum) {
- case NF_INET_PRE_ROUTING:
- case NF_INET_POST_ROUTING:
- atomic64_inc(&qtu_events.match_calls_prepost);
- iface_stat_update_from_skb(skb, par);
- /*
- * We are done in pre/post. The skb will get processed
- * further alter.
- */
- res = (info->match ^ info->invert);
- goto ret_res;
- break;
- /* default: Fall through and do UID releated work */
- }
-
- sk = skb_to_full_sk(skb);
- /*
- * When in TCP_TIME_WAIT the sk is not a "struct sock" but
- * "struct inet_timewait_sock" which is missing fields.
- * So we ignore it.
- */
- if (sk && sk->sk_state == TCP_TIME_WAIT)
- sk = NULL;
- if (sk == NULL) {
- /*
- * A missing sk->sk_socket happens when packets are in-flight
- * and the matching socket is already closed and gone.
- */
- sk = qtaguid_find_sk(skb, par);
- /*
- * TCP_NEW_SYN_RECV are not "struct sock" but "struct request_sock"
- * where we can get a pointer to a full socket to retrieve uid/gid.
- * When in TCP_TIME_WAIT, sk is a struct inet_timewait_sock
- * which is missing fields and does not contain any reference
- * to a full socket, so just ignore the socket.
- */
- if (sk && sk->sk_state == TCP_NEW_SYN_RECV) {
- sock_gen_put(sk);
- sk = sk_to_full_sk(sk);
- } else if (sk && (!sk_fullsock(sk) || sk->sk_state == TCP_TIME_WAIT)) {
- sock_gen_put(sk);
- sk = NULL;
- } else {
- /*
- * If we got the socket from the find_sk(), we will need to put
- * it back, as nf_tproxy_get_sock_v4() got it.
- */
- got_sock = sk;
- }
- if (sk)
- atomic64_inc(&qtu_events.match_found_sk_in_ct);
- else
- atomic64_inc(&qtu_events.match_found_no_sk_in_ct);
- } else {
- atomic64_inc(&qtu_events.match_found_sk);
- }
- MT_DEBUG("qtaguid[%d]: sk=%p got_sock=%d fam=%d proto=%d\n",
- par->hooknum, sk, got_sock, par->family, ipx_proto(skb, par));
-
- if (!sk) {
- /*
- * Here, the qtaguid_find_sk() using connection tracking
- * couldn't find the owner, so for now we just count them
- * against the system.
- */
- if (do_tag_stat)
- account_for_uid(skb, sk, 0, par);
- MT_DEBUG("qtaguid[%d]: leaving (sk=NULL)\n", par->hooknum);
- res = (info->match ^ info->invert) == 0;
- atomic64_inc(&qtu_events.match_no_sk);
- goto put_sock_ret_res;
- } else if (info->match & info->invert & XT_QTAGUID_SOCKET) {
- res = false;
- goto put_sock_ret_res;
- }
- sock_uid = sk->sk_uid;
- if (do_tag_stat)
- account_for_uid(skb, sk, from_kuid(&init_user_ns, sock_uid),
- par);
-
- /*
- * The following two tests fail the match when:
- * id not in range AND no inverted condition requested
- * or id in range AND inverted condition requested
- * Thus (!a && b) || (a && !b) == a ^ b
- */
- if (info->match & XT_QTAGUID_UID) {
- kuid_t uid_min = make_kuid(&init_user_ns, info->uid_min);
- kuid_t uid_max = make_kuid(&init_user_ns, info->uid_max);
-
- if ((uid_gte(sock_uid, uid_min) &&
- uid_lte(sock_uid, uid_max)) ^
- !(info->invert & XT_QTAGUID_UID)) {
- MT_DEBUG("qtaguid[%d]: leaving uid not matching\n",
- par->hooknum);
- res = false;
- goto put_sock_ret_res;
- }
- }
- if (info->match & XT_QTAGUID_GID) {
- kgid_t gid_min = make_kgid(&init_user_ns, info->gid_min);
- kgid_t gid_max = make_kgid(&init_user_ns, info->gid_max);
- set_sk_callback_lock = true;
- read_lock_bh(&sk->sk_callback_lock);
- MT_DEBUG("qtaguid[%d]: sk=%pK->sk_socket=%pK->file=%pK\n",
- par->hooknum, sk, sk->sk_socket,
- sk->sk_socket ? sk->sk_socket->file : (void *)-1LL);
- filp = sk->sk_socket ? sk->sk_socket->file : NULL;
- if (!filp) {
- res = ((info->match ^ info->invert) &
- XT_QTAGUID_GID) == 0;
- atomic64_inc(&qtu_events.match_no_sk_gid);
- goto put_sock_ret_res;
- }
- MT_DEBUG("qtaguid[%d]: filp...uid=%u\n",
- par->hooknum, filp ?
- from_kuid(&init_user_ns, filp->f_cred->fsuid) : -1);
- if ((gid_gte(filp->f_cred->fsgid, gid_min) &&
- gid_lte(filp->f_cred->fsgid, gid_max)) ^
- !(info->invert & XT_QTAGUID_GID)) {
- MT_DEBUG("qtaguid[%d]: leaving gid not matching\n",
- par->hooknum);
- res = false;
- goto put_sock_ret_res;
- }
- }
- MT_DEBUG("qtaguid[%d]: leaving matched\n", par->hooknum);
- res = true;
-
-put_sock_ret_res:
- if (got_sock)
- sock_gen_put(sk);
- if (set_sk_callback_lock)
- read_unlock_bh(&sk->sk_callback_lock);
-ret_res:
- MT_DEBUG("qtaguid[%d]: left %d\n", par->hooknum, res);
- return res;
-}
-
-#ifdef DDEBUG
-/*
- * This function is not in xt_qtaguid_print.c because of locks visibility.
- * The lock of sock_tag_list must be aquired before calling this function
- */
-static void prdebug_full_state_locked(int indent_level, const char *fmt, ...)
-{
- va_list args;
- char *fmt_buff;
- char *buff;
-
- if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK))
- return;
-
- fmt_buff = kasprintf(GFP_ATOMIC,
- "qtaguid: %s(): %s {\n", __func__, fmt);
- BUG_ON(!fmt_buff);
- va_start(args, fmt);
- buff = kvasprintf(GFP_ATOMIC,
- fmt_buff, args);
- BUG_ON(!buff);
- pr_debug("%s", buff);
- kfree(fmt_buff);
- kfree(buff);
- va_end(args);
-
- prdebug_sock_tag_tree(indent_level, &sock_tag_tree);
-
- spin_lock_bh(&uid_tag_data_tree_lock);
- prdebug_uid_tag_data_tree(indent_level, &uid_tag_data_tree);
- prdebug_proc_qtu_data_tree(indent_level, &proc_qtu_data_tree);
- spin_unlock_bh(&uid_tag_data_tree_lock);
-
- spin_lock_bh(&iface_stat_list_lock);
- prdebug_iface_stat_list(indent_level, &iface_stat_list);
- spin_unlock_bh(&iface_stat_list_lock);
-
- pr_debug("qtaguid: %s(): }\n", __func__);
-}
-#else
-static void prdebug_full_state_locked(int indent_level, const char *fmt, ...) {}
-#endif
-
-struct proc_ctrl_print_info {
- struct sock *sk; /* socket found by reading to sk_pos */
- loff_t sk_pos;
-};
-
-static void *qtaguid_ctrl_proc_next(struct seq_file *m, void *v, loff_t *pos)
-{
- struct proc_ctrl_print_info *pcpi = m->private;
- struct sock_tag *sock_tag_entry = v;
- struct rb_node *node;
-
- (*pos)++;
-
- if (!v || v == SEQ_START_TOKEN)
- return NULL;
-
- node = rb_next(&sock_tag_entry->sock_node);
- if (!node) {
- pcpi->sk = NULL;
- sock_tag_entry = SEQ_START_TOKEN;
- } else {
- sock_tag_entry = rb_entry(node, struct sock_tag, sock_node);
- pcpi->sk = sock_tag_entry->sk;
- }
- pcpi->sk_pos = *pos;
- return sock_tag_entry;
-}
-
-static void *qtaguid_ctrl_proc_start(struct seq_file *m, loff_t *pos)
-{
- struct proc_ctrl_print_info *pcpi = m->private;
- struct sock_tag *sock_tag_entry;
- struct rb_node *node;
-
- spin_lock_bh(&sock_tag_list_lock);
-
- if (unlikely(module_passive))
- return NULL;
-
- if (*pos == 0) {
- pcpi->sk_pos = 0;
- node = rb_first(&sock_tag_tree);
- if (!node) {
- pcpi->sk = NULL;
- return SEQ_START_TOKEN;
- }
- sock_tag_entry = rb_entry(node, struct sock_tag, sock_node);
- pcpi->sk = sock_tag_entry->sk;
- } else {
- sock_tag_entry = (pcpi->sk ? get_sock_stat_nl(pcpi->sk) :
- NULL) ?: SEQ_START_TOKEN;
- if (*pos != pcpi->sk_pos) {
- /* seq_read skipped a next call */
- *pos = pcpi->sk_pos;
- return qtaguid_ctrl_proc_next(m, sock_tag_entry, pos);
- }
- }
- return sock_tag_entry;
-}
-
-static void qtaguid_ctrl_proc_stop(struct seq_file *m, void *v)
-{
- spin_unlock_bh(&sock_tag_list_lock);
-}
-
-/*
- * Procfs reader to get all active socket tags using style "1)" as described in
- * fs/proc/generic.c
- */
-static int qtaguid_ctrl_proc_show(struct seq_file *m, void *v)
-{
- struct sock_tag *sock_tag_entry = v;
- uid_t uid;
-
- CT_DEBUG("qtaguid: proc ctrl pid=%u tgid=%u uid=%u\n",
- current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid()));
-
- if (sock_tag_entry != SEQ_START_TOKEN) {
- int sk_ref_count;
- uid = get_uid_from_tag(sock_tag_entry->tag);
- CT_DEBUG("qtaguid: proc_read(): sk=%p tag=0x%llx (uid=%u) "
- "pid=%u\n",
- sock_tag_entry->sk,
- sock_tag_entry->tag,
- uid,
- sock_tag_entry->pid
- );
- sk_ref_count = atomic_read(
- &sock_tag_entry->sk->sk_refcnt);
- seq_printf(m, "sock=%pK tag=0x%llx (uid=%u) pid=%u "
- "f_count=%d\n",
- sock_tag_entry->sk,
- sock_tag_entry->tag, uid,
- sock_tag_entry->pid, sk_ref_count);
- } else {
- seq_printf(m, "events: sockets_tagged=%llu "
- "sockets_untagged=%llu "
- "counter_set_changes=%llu "
- "delete_cmds=%llu "
- "iface_events=%llu "
- "match_calls=%llu "
- "match_calls_prepost=%llu "
- "match_found_sk=%llu "
- "match_found_sk_in_ct=%llu "
- "match_found_no_sk_in_ct=%llu "
- "match_no_sk=%llu "
- "match_no_sk_gid=%llu\n",
- (u64)atomic64_read(&qtu_events.sockets_tagged),
- (u64)atomic64_read(&qtu_events.sockets_untagged),
- (u64)atomic64_read(&qtu_events.counter_set_changes),
- (u64)atomic64_read(&qtu_events.delete_cmds),
- (u64)atomic64_read(&qtu_events.iface_events),
- (u64)atomic64_read(&qtu_events.match_calls),
- (u64)atomic64_read(&qtu_events.match_calls_prepost),
- (u64)atomic64_read(&qtu_events.match_found_sk),
- (u64)atomic64_read(&qtu_events.match_found_sk_in_ct),
- (u64)atomic64_read(&qtu_events.match_found_no_sk_in_ct),
- (u64)atomic64_read(&qtu_events.match_no_sk),
- (u64)atomic64_read(&qtu_events.match_no_sk_gid));
-
- /* Count the following as part of the last item_index. No need
- * to lock the sock_tag_list here since it is already locked when
- * starting the seq_file operation
- */
- prdebug_full_state_locked(0, "proc ctrl");
- }
-
- return 0;
-}
-
-/*
- * Delete socket tags, and stat tags associated with a given
- * accouting tag and uid.
- */
-static int ctrl_cmd_delete(const char *input)
-{
- char cmd;
- int uid_int;
- kuid_t uid;
- uid_t entry_uid;
- tag_t acct_tag;
- tag_t tag;
- int res, argc;
- struct iface_stat *iface_entry;
- struct rb_node *node;
- struct sock_tag *st_entry;
- struct rb_root st_to_free_tree = RB_ROOT;
- struct tag_stat *ts_entry;
- struct tag_counter_set *tcs_entry;
- struct tag_ref *tr_entry;
- struct uid_tag_data *utd_entry;
-
- argc = sscanf(input, "%c %llu %u", &cmd, &acct_tag, &uid_int);
- uid = make_kuid(&init_user_ns, uid_int);
- CT_DEBUG("qtaguid: ctrl_delete(%s): argc=%d cmd=%c "
- "user_tag=0x%llx uid=%u\n", input, argc, cmd,
- acct_tag, uid_int);
- if (argc < 2) {
- res = -EINVAL;
- goto err;
- }
- if (!valid_atag(acct_tag)) {
- pr_info("qtaguid: ctrl_delete(%s): invalid tag\n", input);
- res = -EINVAL;
- goto err;
- }
- if (argc < 3) {
- uid = current_fsuid();
- uid_int = from_kuid(&init_user_ns, uid);
- } else if (!can_impersonate_uid(uid)) {
- pr_info("qtaguid: ctrl_delete(%s): "
- "insufficient priv from pid=%u tgid=%u uid=%u\n",
- input, current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid()));
- res = -EPERM;
- goto err;
- }
-
- tag = combine_atag_with_uid(acct_tag, uid_int);
- CT_DEBUG("qtaguid: ctrl_delete(%s): "
- "looking for tag=0x%llx (uid=%u)\n",
- input, tag, uid_int);
-
- /* Delete socket tags */
- spin_lock_bh(&sock_tag_list_lock);
- spin_lock_bh(&uid_tag_data_tree_lock);
- node = rb_first(&sock_tag_tree);
- while (node) {
- st_entry = rb_entry(node, struct sock_tag, sock_node);
- entry_uid = get_uid_from_tag(st_entry->tag);
- node = rb_next(node);
- if (entry_uid != uid_int)
- continue;
-
- CT_DEBUG("qtaguid: ctrl_delete(%s): st tag=0x%llx (uid=%u)\n",
- input, st_entry->tag, entry_uid);
-
- if (!acct_tag || st_entry->tag == tag) {
- rb_erase(&st_entry->sock_node, &sock_tag_tree);
- /* Can't sockfd_put() within spinlock, do it later. */
- sock_tag_tree_insert(st_entry, &st_to_free_tree);
- tr_entry = lookup_tag_ref(st_entry->tag, NULL);
- BUG_ON(tr_entry->num_sock_tags <= 0);
- tr_entry->num_sock_tags--;
- /*
- * TODO: remove if, and start failing.
- * This is a hack to work around the fact that in some
- * places we have "if (IS_ERR_OR_NULL(pqd_entry))"
- * and are trying to work around apps
- * that didn't open the /dev/xt_qtaguid.
- */
- if (st_entry->list.next && st_entry->list.prev)
- list_del(&st_entry->list);
- }
- }
- spin_unlock_bh(&uid_tag_data_tree_lock);
- spin_unlock_bh(&sock_tag_list_lock);
-
- sock_tag_tree_erase(&st_to_free_tree);
-
- /* Delete tag counter-sets */
- spin_lock_bh(&tag_counter_set_list_lock);
- /* Counter sets are only on the uid tag, not full tag */
- tcs_entry = tag_counter_set_tree_search(&tag_counter_set_tree, tag);
- if (tcs_entry) {
- CT_DEBUG("qtaguid: ctrl_delete(%s): "
- "erase tcs: tag=0x%llx (uid=%u) set=%d\n",
- input,
- tcs_entry->tn.tag,
- get_uid_from_tag(tcs_entry->tn.tag),
- tcs_entry->active_set);
- rb_erase(&tcs_entry->tn.node, &tag_counter_set_tree);
- kfree(tcs_entry);
- }
- spin_unlock_bh(&tag_counter_set_list_lock);
-
- /*
- * If acct_tag is 0, then all entries belonging to uid are
- * erased.
- */
- spin_lock_bh(&iface_stat_list_lock);
- list_for_each_entry(iface_entry, &iface_stat_list, list) {
- spin_lock_bh(&iface_entry->tag_stat_list_lock);
- node = rb_first(&iface_entry->tag_stat_tree);
- while (node) {
- ts_entry = rb_entry(node, struct tag_stat, tn.node);
- entry_uid = get_uid_from_tag(ts_entry->tn.tag);
- node = rb_next(node);
-
- CT_DEBUG("qtaguid: ctrl_delete(%s): "
- "ts tag=0x%llx (uid=%u)\n",
- input, ts_entry->tn.tag, entry_uid);
-
- if (entry_uid != uid_int)
- continue;
- if (!acct_tag || ts_entry->tn.tag == tag) {
- CT_DEBUG("qtaguid: ctrl_delete(%s): "
- "erase ts: %s 0x%llx %u\n",
- input, iface_entry->ifname,
- get_atag_from_tag(ts_entry->tn.tag),
- entry_uid);
- rb_erase(&ts_entry->tn.node,
- &iface_entry->tag_stat_tree);
- kfree(ts_entry);
- }
- }
- spin_unlock_bh(&iface_entry->tag_stat_list_lock);
- }
- spin_unlock_bh(&iface_stat_list_lock);
-
- /* Cleanup the uid_tag_data */
- spin_lock_bh(&uid_tag_data_tree_lock);
- node = rb_first(&uid_tag_data_tree);
- while (node) {
- utd_entry = rb_entry(node, struct uid_tag_data, node);
- entry_uid = utd_entry->uid;
- node = rb_next(node);
-
- CT_DEBUG("qtaguid: ctrl_delete(%s): "
- "utd uid=%u\n",
- input, entry_uid);
-
- if (entry_uid != uid_int)
- continue;
- /*
- * Go over the tag_refs, and those that don't have
- * sock_tags using them are freed.
- */
- put_tag_ref_tree(tag, utd_entry);
- put_utd_entry(utd_entry);
- }
- spin_unlock_bh(&uid_tag_data_tree_lock);
-
- atomic64_inc(&qtu_events.delete_cmds);
- res = 0;
-
-err:
- return res;
-}
-
-static int ctrl_cmd_counter_set(const char *input)
-{
- char cmd;
- uid_t uid = 0;
- tag_t tag;
- int res, argc;
- struct tag_counter_set *tcs;
- int counter_set;
-
- argc = sscanf(input, "%c %d %u", &cmd, &counter_set, &uid);
- CT_DEBUG("qtaguid: ctrl_counterset(%s): argc=%d cmd=%c "
- "set=%d uid=%u\n", input, argc, cmd,
- counter_set, uid);
- if (argc != 3) {
- res = -EINVAL;
- goto err;
- }
- if (counter_set < 0 || counter_set >= IFS_MAX_COUNTER_SETS) {
- pr_info("qtaguid: ctrl_counterset(%s): invalid counter_set range\n",
- input);
- res = -EINVAL;
- goto err;
- }
- if (!can_manipulate_uids()) {
- pr_info("qtaguid: ctrl_counterset(%s): "
- "insufficient priv from pid=%u tgid=%u uid=%u\n",
- input, current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid()));
- res = -EPERM;
- goto err;
- }
-
- tag = make_tag_from_uid(uid);
- spin_lock_bh(&tag_counter_set_list_lock);
- tcs = tag_counter_set_tree_search(&tag_counter_set_tree, tag);
- if (!tcs) {
- tcs = kzalloc(sizeof(*tcs), GFP_ATOMIC);
- if (!tcs) {
- spin_unlock_bh(&tag_counter_set_list_lock);
- pr_err("qtaguid: ctrl_counterset(%s): "
- "failed to alloc counter set\n",
- input);
- res = -ENOMEM;
- goto err;
- }
- tcs->tn.tag = tag;
- tag_counter_set_tree_insert(tcs, &tag_counter_set_tree);
- CT_DEBUG("qtaguid: ctrl_counterset(%s): added tcs tag=0x%llx "
- "(uid=%u) set=%d\n",
- input, tag, get_uid_from_tag(tag), counter_set);
- }
- tcs->active_set = counter_set;
- spin_unlock_bh(&tag_counter_set_list_lock);
- atomic64_inc(&qtu_events.counter_set_changes);
- res = 0;
-
-err:
- return res;
-}
-
-static int ctrl_cmd_tag(const char *input)
-{
- char cmd;
- int sock_fd = 0;
- kuid_t uid;
- unsigned int uid_int = 0;
- tag_t acct_tag = make_atag_from_value(0);
- tag_t full_tag;
- struct socket *el_socket;
- int res, argc;
- struct sock_tag *sock_tag_entry;
- struct tag_ref *tag_ref_entry;
- struct uid_tag_data *uid_tag_data_entry;
- struct proc_qtu_data *pqd_entry;
-
- /* Unassigned args will get defaulted later. */
- argc = sscanf(input, "%c %d %llu %u", &cmd, &sock_fd, &acct_tag, &uid_int);
- uid = make_kuid(&init_user_ns, uid_int);
- CT_DEBUG("qtaguid: ctrl_tag(%s): argc=%d cmd=%c sock_fd=%d "
- "acct_tag=0x%llx uid=%u\n", input, argc, cmd, sock_fd,
- acct_tag, uid_int);
- if (argc < 2) {
- res = -EINVAL;
- goto err;
- }
- el_socket = sockfd_lookup(sock_fd, &res); /* This locks the file */
- if (!el_socket) {
- pr_info("qtaguid: ctrl_tag(%s): failed to lookup"
- " sock_fd=%d err=%d pid=%u tgid=%u uid=%u\n",
- input, sock_fd, res, current->pid, current->tgid,
- from_kuid(&init_user_ns, current_fsuid()));
- goto err;
- }
- CT_DEBUG("qtaguid: ctrl_tag(%s): socket->...->sk_refcnt=%d ->sk=%p\n",
- input, atomic_read(&el_socket->sk->sk_refcnt),
- el_socket->sk);
- if (argc < 3) {
- acct_tag = make_atag_from_value(0);
- } else if (!valid_atag(acct_tag)) {
- pr_info("qtaguid: ctrl_tag(%s): invalid tag\n", input);
- res = -EINVAL;
- goto err_put;
- }
- CT_DEBUG("qtaguid: ctrl_tag(%s): "
- "pid=%u tgid=%u uid=%u euid=%u fsuid=%u "
- "ctrl.gid=%u in_group()=%d in_egroup()=%d\n",
- input, current->pid, current->tgid,
- from_kuid(&init_user_ns, current_uid()),
- from_kuid(&init_user_ns, current_euid()),
- from_kuid(&init_user_ns, current_fsuid()),
- from_kgid(&init_user_ns, xt_qtaguid_ctrl_file->gid),
- in_group_p(xt_qtaguid_ctrl_file->gid),
- in_egroup_p(xt_qtaguid_ctrl_file->gid));
- if (argc < 4) {
- uid = current_fsuid();
- uid_int = from_kuid(&init_user_ns, uid);
- } else if (!can_impersonate_uid(uid)) {
- pr_info("qtaguid: ctrl_tag(%s): "
- "insufficient priv from pid=%u tgid=%u uid=%u\n",
- input, current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid()));
- res = -EPERM;
- goto err_put;
- }
- full_tag = combine_atag_with_uid(acct_tag, uid_int);
-
- spin_lock_bh(&sock_tag_list_lock);
- spin_lock_bh(&uid_tag_data_tree_lock);
- sock_tag_entry = get_sock_stat_nl(el_socket->sk);
- tag_ref_entry = get_tag_ref(full_tag, &uid_tag_data_entry);
- if (IS_ERR(tag_ref_entry)) {
- res = PTR_ERR(tag_ref_entry);
- spin_unlock_bh(&uid_tag_data_tree_lock);
- spin_unlock_bh(&sock_tag_list_lock);
- goto err_put;
- }
- tag_ref_entry->num_sock_tags++;
- if (sock_tag_entry) {
- struct tag_ref *prev_tag_ref_entry;
-
- CT_DEBUG("qtaguid: ctrl_tag(%s): retag for sk=%p "
- "st@%p ...->sk_refcnt=%d\n",
- input, el_socket->sk, sock_tag_entry,
- atomic_read(&el_socket->sk->sk_refcnt));
- prev_tag_ref_entry = lookup_tag_ref(sock_tag_entry->tag,
- &uid_tag_data_entry);
- BUG_ON(IS_ERR_OR_NULL(prev_tag_ref_entry));
- BUG_ON(prev_tag_ref_entry->num_sock_tags <= 0);
- prev_tag_ref_entry->num_sock_tags--;
- sock_tag_entry->tag = full_tag;
- } else {
- CT_DEBUG("qtaguid: ctrl_tag(%s): newtag for sk=%p\n",
- input, el_socket->sk);
- sock_tag_entry = kzalloc(sizeof(*sock_tag_entry),
- GFP_ATOMIC);
- if (!sock_tag_entry) {
- pr_err("qtaguid: ctrl_tag(%s): "
- "socket tag alloc failed\n",
- input);
- BUG_ON(tag_ref_entry->num_sock_tags <= 0);
- tag_ref_entry->num_sock_tags--;
- free_tag_ref_from_utd_entry(tag_ref_entry,
- uid_tag_data_entry);
- spin_unlock_bh(&uid_tag_data_tree_lock);
- spin_unlock_bh(&sock_tag_list_lock);
- res = -ENOMEM;
- goto err_put;
- }
- /*
- * Hold the sk refcount here to make sure the sk pointer cannot
- * be freed and reused
- */
- sock_hold(el_socket->sk);
- sock_tag_entry->sk = el_socket->sk;
- sock_tag_entry->pid = current->tgid;
- sock_tag_entry->tag = combine_atag_with_uid(acct_tag, uid_int);
- pqd_entry = proc_qtu_data_tree_search(
- &proc_qtu_data_tree, current->tgid);
- /*
- * TODO: remove if, and start failing.
- * At first, we want to catch user-space code that is not
- * opening the /dev/xt_qtaguid.
- */
- if (IS_ERR_OR_NULL(pqd_entry))
- pr_warn_once(
- "qtaguid: %s(): "
- "User space forgot to open /dev/xt_qtaguid? "
- "pid=%u tgid=%u uid=%u\n", __func__,
- current->pid, current->tgid,
- from_kuid(&init_user_ns, current_fsuid()));
- else
- list_add(&sock_tag_entry->list,
- &pqd_entry->sock_tag_list);
-
- sock_tag_tree_insert(sock_tag_entry, &sock_tag_tree);
- atomic64_inc(&qtu_events.sockets_tagged);
- }
- spin_unlock_bh(&uid_tag_data_tree_lock);
- spin_unlock_bh(&sock_tag_list_lock);
- /* We keep the ref to the sk until it is untagged */
- CT_DEBUG("qtaguid: ctrl_tag(%s): done st@%p ...->sk_refcnt=%d\n",
- input, sock_tag_entry,
- atomic_read(&el_socket->sk->sk_refcnt));
- sockfd_put(el_socket);
- return 0;
-
-err_put:
- CT_DEBUG("qtaguid: ctrl_tag(%s): done. ...->sk_refcnt=%d\n",
- input, atomic_read(&el_socket->sk->sk_refcnt) - 1);
- /* Release the sock_fd that was grabbed by sockfd_lookup(). */
- sockfd_put(el_socket);
- return res;
-
-err:
- CT_DEBUG("qtaguid: ctrl_tag(%s): done.\n", input);
- return res;
-}
-
-static int ctrl_cmd_untag(const char *input)
-{
- char cmd;
- int sock_fd = 0;
- struct socket *el_socket;
- int res, argc;
-
- argc = sscanf(input, "%c %d", &cmd, &sock_fd);
- CT_DEBUG("qtaguid: ctrl_untag(%s): argc=%d cmd=%c sock_fd=%d\n",
- input, argc, cmd, sock_fd);
- if (argc < 2) {
- res = -EINVAL;
- return res;
- }
- el_socket = sockfd_lookup(sock_fd, &res); /* This locks the file */
- if (!el_socket) {
- pr_info("qtaguid: ctrl_untag(%s): failed to lookup"
- " sock_fd=%d err=%d pid=%u tgid=%u uid=%u\n",
- input, sock_fd, res, current->pid, current->tgid,
- from_kuid(&init_user_ns, current_fsuid()));
- return res;
- }
- CT_DEBUG("qtaguid: ctrl_untag(%s): socket->...->f_count=%ld ->sk=%p\n",
- input, atomic_long_read(&el_socket->file->f_count),
- el_socket->sk);
- res = qtaguid_untag(el_socket, false);
- sockfd_put(el_socket);
- return res;
-}
-
-int qtaguid_untag(struct socket *el_socket, bool kernel)
-{
- int res;
- pid_t pid;
- struct sock_tag *sock_tag_entry;
- struct tag_ref *tag_ref_entry;
- struct uid_tag_data *utd_entry;
- struct proc_qtu_data *pqd_entry;
-
- spin_lock_bh(&sock_tag_list_lock);
- sock_tag_entry = get_sock_stat_nl(el_socket->sk);
- if (!sock_tag_entry) {
- spin_unlock_bh(&sock_tag_list_lock);
- res = -EINVAL;
- return res;
- }
- /*
- * The socket already belongs to the current process
- * so it can do whatever it wants to it.
- */
- rb_erase(&sock_tag_entry->sock_node, &sock_tag_tree);
-
- tag_ref_entry = lookup_tag_ref(sock_tag_entry->tag, &utd_entry);
- BUG_ON(!tag_ref_entry);
- BUG_ON(tag_ref_entry->num_sock_tags <= 0);
- spin_lock_bh(&uid_tag_data_tree_lock);
- if (kernel)
- pid = sock_tag_entry->pid;
- else
- pid = current->tgid;
- pqd_entry = proc_qtu_data_tree_search(
- &proc_qtu_data_tree, pid);
- /*
- * TODO: remove if, and start failing.
- * At first, we want to catch user-space code that is not
- * opening the /dev/xt_qtaguid.
- */
- if (IS_ERR_OR_NULL(pqd_entry) || !sock_tag_entry->list.next) {
- pr_warn_once("qtaguid: %s(): "
- "User space forgot to open /dev/xt_qtaguid? "
- "pid=%u tgid=%u sk_pid=%u, uid=%u\n", __func__,
- current->pid, current->tgid, sock_tag_entry->pid,
- from_kuid(&init_user_ns, current_fsuid()));
- } else {
- list_del(&sock_tag_entry->list);
- }
- spin_unlock_bh(&uid_tag_data_tree_lock);
- /*
- * We don't free tag_ref from the utd_entry here,
- * only during a cmd_delete().
- */
- tag_ref_entry->num_sock_tags--;
- spin_unlock_bh(&sock_tag_list_lock);
- /*
- * Release the sock_fd that was grabbed at tag time.
- */
- sock_put(sock_tag_entry->sk);
- CT_DEBUG("qtaguid: done. st@%p ...->sk_refcnt=%d\n",
- sock_tag_entry,
- atomic_read(&el_socket->sk->sk_refcnt));
-
- kfree(sock_tag_entry);
- atomic64_inc(&qtu_events.sockets_untagged);
-
- return 0;
-}
-
-static ssize_t qtaguid_ctrl_parse(const char *input, size_t count)
-{
- char cmd;
- ssize_t res;
-
- CT_DEBUG("qtaguid: ctrl(%s): pid=%u tgid=%u uid=%u\n",
- input, current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid()));
-
- cmd = input[0];
- /* Collect params for commands */
- switch (cmd) {
- case 'd':
- res = ctrl_cmd_delete(input);
- break;
-
- case 's':
- res = ctrl_cmd_counter_set(input);
- break;
-
- case 't':
- res = ctrl_cmd_tag(input);
- break;
-
- case 'u':
- res = ctrl_cmd_untag(input);
- break;
-
- default:
- res = -EINVAL;
- goto err;
- }
- if (!res)
- res = count;
-err:
- CT_DEBUG("qtaguid: ctrl(%s): res=%zd\n", input, res);
- return res;
-}
-
-#define MAX_QTAGUID_CTRL_INPUT_LEN 255
-static ssize_t qtaguid_ctrl_proc_write(struct file *file, const char __user *buffer,
- size_t count, loff_t *offp)
-{
- char input_buf[MAX_QTAGUID_CTRL_INPUT_LEN];
-
- if (unlikely(module_passive))
- return count;
-
- if (count >= MAX_QTAGUID_CTRL_INPUT_LEN)
- return -EINVAL;
-
- if (copy_from_user(input_buf, buffer, count))
- return -EFAULT;
-
- input_buf[count] = '\0';
- return qtaguid_ctrl_parse(input_buf, count);
-}
-
-struct proc_print_info {
- struct iface_stat *iface_entry;
- int item_index;
- tag_t tag; /* tag found by reading to tag_pos */
- off_t tag_pos;
- int tag_item_index;
-};
-
-static void pp_stats_header(struct seq_file *m)
-{
- seq_puts(m,
- "idx iface acct_tag_hex uid_tag_int cnt_set "
- "rx_bytes rx_packets "
- "tx_bytes tx_packets "
- "rx_tcp_bytes rx_tcp_packets "
- "rx_udp_bytes rx_udp_packets "
- "rx_other_bytes rx_other_packets "
- "tx_tcp_bytes tx_tcp_packets "
- "tx_udp_bytes tx_udp_packets "
- "tx_other_bytes tx_other_packets\n");
-}
-
-static int pp_stats_line(struct seq_file *m, struct tag_stat *ts_entry,
- int cnt_set)
-{
- struct data_counters *cnts;
- tag_t tag = ts_entry->tn.tag;
- uid_t stat_uid = get_uid_from_tag(tag);
- struct proc_print_info *ppi = m->private;
- /* Detailed tags are not available to everybody */
- if (!can_read_other_uid_stats(make_kuid(&init_user_ns,stat_uid))) {
- CT_DEBUG("qtaguid: stats line: "
- "%s 0x%llx %u: insufficient priv "
- "from pid=%u tgid=%u uid=%u stats.gid=%u\n",
- ppi->iface_entry->ifname,
- get_atag_from_tag(tag), stat_uid,
- current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid()),
- from_kgid(&init_user_ns,xt_qtaguid_stats_file->gid));
- return 0;
- }
- ppi->item_index++;
- cnts = &ts_entry->counters;
- seq_printf(m, "%d %s 0x%llx %u %u "
- "%llu %llu "
- "%llu %llu "
- "%llu %llu "
- "%llu %llu "
- "%llu %llu "
- "%llu %llu "
- "%llu %llu "
- "%llu %llu\n",
- ppi->item_index,
- ppi->iface_entry->ifname,
- get_atag_from_tag(tag),
- stat_uid,
- cnt_set,
- dc_sum_bytes(cnts, cnt_set, IFS_RX),
- dc_sum_packets(cnts, cnt_set, IFS_RX),
- dc_sum_bytes(cnts, cnt_set, IFS_TX),
- dc_sum_packets(cnts, cnt_set, IFS_TX),
- cnts->bpc[cnt_set][IFS_RX][IFS_TCP].bytes,
- cnts->bpc[cnt_set][IFS_RX][IFS_TCP].packets,
- cnts->bpc[cnt_set][IFS_RX][IFS_UDP].bytes,
- cnts->bpc[cnt_set][IFS_RX][IFS_UDP].packets,
- cnts->bpc[cnt_set][IFS_RX][IFS_PROTO_OTHER].bytes,
- cnts->bpc[cnt_set][IFS_RX][IFS_PROTO_OTHER].packets,
- cnts->bpc[cnt_set][IFS_TX][IFS_TCP].bytes,
- cnts->bpc[cnt_set][IFS_TX][IFS_TCP].packets,
- cnts->bpc[cnt_set][IFS_TX][IFS_UDP].bytes,
- cnts->bpc[cnt_set][IFS_TX][IFS_UDP].packets,
- cnts->bpc[cnt_set][IFS_TX][IFS_PROTO_OTHER].bytes,
- cnts->bpc[cnt_set][IFS_TX][IFS_PROTO_OTHER].packets);
- return seq_has_overflowed(m) ? -ENOSPC : 1;
-}
-
-static bool pp_sets(struct seq_file *m, struct tag_stat *ts_entry)
-{
- int ret;
- int counter_set;
- for (counter_set = 0; counter_set < IFS_MAX_COUNTER_SETS;
- counter_set++) {
- ret = pp_stats_line(m, ts_entry, counter_set);
- if (ret < 0)
- return false;
- }
- return true;
-}
-
-static int qtaguid_stats_proc_iface_stat_ptr_valid(struct iface_stat *ptr)
-{
- struct iface_stat *iface_entry;
-
- if (!ptr)
- return false;
-
- list_for_each_entry(iface_entry, &iface_stat_list, list)
- if (iface_entry == ptr)
- return true;
- return false;
-}
-
-static void qtaguid_stats_proc_next_iface_entry(struct proc_print_info *ppi)
-{
- spin_unlock_bh(&ppi->iface_entry->tag_stat_list_lock);
- list_for_each_entry_continue(ppi->iface_entry, &iface_stat_list, list) {
- spin_lock_bh(&ppi->iface_entry->tag_stat_list_lock);
- return;
- }
- ppi->iface_entry = NULL;
-}
-
-static void *qtaguid_stats_proc_next(struct seq_file *m, void *v, loff_t *pos)
-{
- struct proc_print_info *ppi = m->private;
- struct tag_stat *ts_entry;
- struct rb_node *node;
-
- if (!v) {
- pr_err("qtaguid: %s(): unexpected v: NULL\n", __func__);
- return NULL;
- }
-
- (*pos)++;
-
- if (!ppi->iface_entry || unlikely(module_passive))
- return NULL;
-
- if (v == SEQ_START_TOKEN)
- node = rb_first(&ppi->iface_entry->tag_stat_tree);
- else
- node = rb_next(&((struct tag_stat *)v)->tn.node);
-
- while (!node) {
- qtaguid_stats_proc_next_iface_entry(ppi);
- if (!ppi->iface_entry)
- return NULL;
- node = rb_first(&ppi->iface_entry->tag_stat_tree);
- }
-
- ts_entry = rb_entry(node, struct tag_stat, tn.node);
- ppi->tag = ts_entry->tn.tag;
- ppi->tag_pos = *pos;
- ppi->tag_item_index = ppi->item_index;
- return ts_entry;
-}
-
-static void *qtaguid_stats_proc_start(struct seq_file *m, loff_t *pos)
-{
- struct proc_print_info *ppi = m->private;
- struct tag_stat *ts_entry = NULL;
-
- spin_lock_bh(&iface_stat_list_lock);
-
- if (*pos == 0) {
- ppi->item_index = 1;
- ppi->tag_pos = 0;
- if (list_empty(&iface_stat_list)) {
- ppi->iface_entry = NULL;
- } else {
- ppi->iface_entry = list_first_entry(&iface_stat_list,
- struct iface_stat,
- list);
- spin_lock_bh(&ppi->iface_entry->tag_stat_list_lock);
- }
- return SEQ_START_TOKEN;
- }
- if (!qtaguid_stats_proc_iface_stat_ptr_valid(ppi->iface_entry)) {
- if (ppi->iface_entry) {
- pr_err("qtaguid: %s(): iface_entry %p not found\n",
- __func__, ppi->iface_entry);
- ppi->iface_entry = NULL;
- }
- return NULL;
- }
-
- spin_lock_bh(&ppi->iface_entry->tag_stat_list_lock);
-
- if (!ppi->tag_pos) {
- /* seq_read skipped first next call */
- ts_entry = SEQ_START_TOKEN;
- } else {
- ts_entry = tag_stat_tree_search(
- &ppi->iface_entry->tag_stat_tree, ppi->tag);
- if (!ts_entry) {
- pr_info("qtaguid: %s(): tag_stat.tag 0x%llx not found. Abort.\n",
- __func__, ppi->tag);
- return NULL;
- }
- }
-
- if (*pos == ppi->tag_pos) { /* normal resume */
- ppi->item_index = ppi->tag_item_index;
- } else {
- /* seq_read skipped a next call */
- *pos = ppi->tag_pos;
- ts_entry = qtaguid_stats_proc_next(m, ts_entry, pos);
- }
-
- return ts_entry;
-}
-
-static void qtaguid_stats_proc_stop(struct seq_file *m, void *v)
-{
- struct proc_print_info *ppi = m->private;
- if (ppi->iface_entry)
- spin_unlock_bh(&ppi->iface_entry->tag_stat_list_lock);
- spin_unlock_bh(&iface_stat_list_lock);
-}
-
-/*
- * Procfs reader to get all tag stats using style "1)" as described in
- * fs/proc/generic.c
- * Groups all protocols tx/rx bytes.
- */
-static int qtaguid_stats_proc_show(struct seq_file *m, void *v)
-{
- struct tag_stat *ts_entry = v;
-
- if (v == SEQ_START_TOKEN)
- pp_stats_header(m);
- else
- pp_sets(m, ts_entry);
-
- return 0;
-}
-
-/*------------------------------------------*/
-static int qtudev_open(struct inode *inode, struct file *file)
-{
- struct uid_tag_data *utd_entry;
- struct proc_qtu_data *pqd_entry;
- struct proc_qtu_data *new_pqd_entry;
- int res;
- bool utd_entry_found;
-
- if (unlikely(qtu_proc_handling_passive))
- return 0;
-
- DR_DEBUG("qtaguid: qtudev_open(): pid=%u tgid=%u uid=%u\n",
- current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid()));
-
- spin_lock_bh(&uid_tag_data_tree_lock);
-
- /* Look for existing uid data, or alloc one. */
- utd_entry = get_uid_data(from_kuid(&init_user_ns, current_fsuid()), &utd_entry_found);
- if (IS_ERR_OR_NULL(utd_entry)) {
- res = PTR_ERR(utd_entry);
- goto err_unlock;
- }
-
- /* Look for existing PID based proc_data */
- pqd_entry = proc_qtu_data_tree_search(&proc_qtu_data_tree,
- current->tgid);
- if (pqd_entry) {
- pr_err("qtaguid: qtudev_open(): %u/%u %u "
- "%s already opened\n",
- current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid()),
- QTU_DEV_NAME);
- res = -EBUSY;
- goto err_unlock_free_utd;
- }
-
- new_pqd_entry = kzalloc(sizeof(*new_pqd_entry), GFP_ATOMIC);
- if (!new_pqd_entry) {
- pr_err("qtaguid: qtudev_open(): %u/%u %u: "
- "proc data alloc failed\n",
- current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid()));
- res = -ENOMEM;
- goto err_unlock_free_utd;
- }
- new_pqd_entry->pid = current->tgid;
- INIT_LIST_HEAD(&new_pqd_entry->sock_tag_list);
- new_pqd_entry->parent_tag_data = utd_entry;
- utd_entry->num_pqd++;
-
- proc_qtu_data_tree_insert(new_pqd_entry,
- &proc_qtu_data_tree);
-
- spin_unlock_bh(&uid_tag_data_tree_lock);
- DR_DEBUG("qtaguid: tracking data for uid=%u in pqd=%p\n",
- from_kuid(&init_user_ns, current_fsuid()), new_pqd_entry);
- file->private_data = new_pqd_entry;
- return 0;
-
-err_unlock_free_utd:
- if (!utd_entry_found) {
- rb_erase(&utd_entry->node, &uid_tag_data_tree);
- kfree(utd_entry);
- }
-err_unlock:
- spin_unlock_bh(&uid_tag_data_tree_lock);
- return res;
-}
-
-static int qtudev_release(struct inode *inode, struct file *file)
-{
- struct proc_qtu_data *pqd_entry = file->private_data;
- struct uid_tag_data *utd_entry = pqd_entry->parent_tag_data;
- struct sock_tag *st_entry;
- struct rb_root st_to_free_tree = RB_ROOT;
- struct list_head *entry, *next;
- struct tag_ref *tr;
-
- if (unlikely(qtu_proc_handling_passive))
- return 0;
-
- /*
- * Do not trust the current->pid, it might just be a kworker cleaning
- * up after a dead proc.
- */
- DR_DEBUG("qtaguid: qtudev_release(): "
- "pid=%u tgid=%u uid=%u "
- "pqd_entry=%p->pid=%u utd_entry=%p->active_tags=%d\n",
- current->pid, current->tgid, pqd_entry->parent_tag_data->uid,
- pqd_entry, pqd_entry->pid, utd_entry,
- utd_entry->num_active_tags);
-
- spin_lock_bh(&sock_tag_list_lock);
- spin_lock_bh(&uid_tag_data_tree_lock);
-
- list_for_each_safe(entry, next, &pqd_entry->sock_tag_list) {
- st_entry = list_entry(entry, struct sock_tag, list);
- DR_DEBUG("qtaguid: %s(): "
- "erase sock_tag=%p->sk=%p pid=%u tgid=%u uid=%u\n",
- __func__,
- st_entry, st_entry->sk,
- current->pid, current->tgid,
- pqd_entry->parent_tag_data->uid);
-
- utd_entry = uid_tag_data_tree_search(
- &uid_tag_data_tree,
- get_uid_from_tag(st_entry->tag));
- BUG_ON(IS_ERR_OR_NULL(utd_entry));
- DR_DEBUG("qtaguid: %s(): "
- "looking for tag=0x%llx in utd_entry=%p\n", __func__,
- st_entry->tag, utd_entry);
- tr = tag_ref_tree_search(&utd_entry->tag_ref_tree,
- st_entry->tag);
- BUG_ON(!tr);
- BUG_ON(tr->num_sock_tags <= 0);
- tr->num_sock_tags--;
- free_tag_ref_from_utd_entry(tr, utd_entry);
-
- rb_erase(&st_entry->sock_node, &sock_tag_tree);
- list_del(&st_entry->list);
- /* Can't sockfd_put() within spinlock, do it later. */
- sock_tag_tree_insert(st_entry, &st_to_free_tree);
-
- /*
- * Try to free the utd_entry if no other proc_qtu_data is
- * using it (num_pqd is 0) and it doesn't have active tags
- * (num_active_tags is 0).
- */
- put_utd_entry(utd_entry);
- }
-
- rb_erase(&pqd_entry->node, &proc_qtu_data_tree);
- BUG_ON(pqd_entry->parent_tag_data->num_pqd < 1);
- pqd_entry->parent_tag_data->num_pqd--;
- put_utd_entry(pqd_entry->parent_tag_data);
- kfree(pqd_entry);
- file->private_data = NULL;
-
- spin_unlock_bh(&uid_tag_data_tree_lock);
- spin_unlock_bh(&sock_tag_list_lock);
-
-
- sock_tag_tree_erase(&st_to_free_tree);
-
- spin_lock_bh(&sock_tag_list_lock);
- prdebug_full_state_locked(0, "%s(): pid=%u tgid=%u", __func__,
- current->pid, current->tgid);
- spin_unlock_bh(&sock_tag_list_lock);
- return 0;
-}
-
-/*------------------------------------------*/
-static const struct file_operations qtudev_fops = {
- .owner = THIS_MODULE,
- .open = qtudev_open,
- .release = qtudev_release,
-};
-
-static struct miscdevice qtu_device = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = QTU_DEV_NAME,
- .fops = &qtudev_fops,
- /* How sad it doesn't allow for defaults: .mode = S_IRUGO | S_IWUSR */
-};
-
-static const struct seq_operations proc_qtaguid_ctrl_seqops = {
- .start = qtaguid_ctrl_proc_start,
- .next = qtaguid_ctrl_proc_next,
- .stop = qtaguid_ctrl_proc_stop,
- .show = qtaguid_ctrl_proc_show,
-};
-
-static int proc_qtaguid_ctrl_open(struct inode *inode, struct file *file)
-{
- return seq_open_private(file, &proc_qtaguid_ctrl_seqops,
- sizeof(struct proc_ctrl_print_info));
-}
-
-static const struct file_operations proc_qtaguid_ctrl_fops = {
- .open = proc_qtaguid_ctrl_open,
- .read = seq_read,
- .write = qtaguid_ctrl_proc_write,
- .llseek = seq_lseek,
- .release = seq_release_private,
-};
-
-static const struct seq_operations proc_qtaguid_stats_seqops = {
- .start = qtaguid_stats_proc_start,
- .next = qtaguid_stats_proc_next,
- .stop = qtaguid_stats_proc_stop,
- .show = qtaguid_stats_proc_show,
-};
-
-static int proc_qtaguid_stats_open(struct inode *inode, struct file *file)
-{
- return seq_open_private(file, &proc_qtaguid_stats_seqops,
- sizeof(struct proc_print_info));
-}
-
-static const struct file_operations proc_qtaguid_stats_fops = {
- .open = proc_qtaguid_stats_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release_private,
-};
-
-/*------------------------------------------*/
-static int __init qtaguid_proc_register(struct proc_dir_entry **res_procdir)
-{
- int ret;
- *res_procdir = proc_mkdir(module_procdirname, init_net.proc_net);
- if (!*res_procdir) {
- pr_err("qtaguid: failed to create proc/.../xt_qtaguid\n");
- ret = -ENOMEM;
- goto no_dir;
- }
-
- xt_qtaguid_ctrl_file = proc_create_data("ctrl", proc_ctrl_perms,
- *res_procdir,
- &proc_qtaguid_ctrl_fops,
- NULL);
- if (!xt_qtaguid_ctrl_file) {
- pr_err("qtaguid: failed to create xt_qtaguid/ctrl "
- " file\n");
- ret = -ENOMEM;
- goto no_ctrl_entry;
- }
-
- xt_qtaguid_stats_file = proc_create_data("stats", proc_stats_perms,
- *res_procdir,
- &proc_qtaguid_stats_fops,
- NULL);
- if (!xt_qtaguid_stats_file) {
- pr_err("qtaguid: failed to create xt_qtaguid/stats "
- "file\n");
- ret = -ENOMEM;
- goto no_stats_entry;
- }
- /*
- * TODO: add support counter hacking
- * xt_qtaguid_stats_file->write_proc = qtaguid_stats_proc_write;
- */
- return 0;
-
-no_stats_entry:
- remove_proc_entry("ctrl", *res_procdir);
-no_ctrl_entry:
- remove_proc_entry("xt_qtaguid", NULL);
-no_dir:
- return ret;
-}
-
-static struct xt_match qtaguid_mt_reg __read_mostly = {
- /*
- * This module masquerades as the "owner" module so that iptables
- * tools can deal with it.
- */
- .name = "owner",
- .revision = 1,
- .family = NFPROTO_UNSPEC,
- .match = qtaguid_mt,
- .matchsize = sizeof(struct xt_qtaguid_match_info),
- .me = THIS_MODULE,
-};
-
-static int __init qtaguid_mt_init(void)
-{
- if (qtaguid_proc_register(&xt_qtaguid_procdir)
- || iface_stat_init(xt_qtaguid_procdir)
- || xt_register_match(&qtaguid_mt_reg)
- || misc_register(&qtu_device))
- return -1;
- return 0;
-}
-
-/*
- * TODO: allow unloading of the module.
- * For now stats are permanent.
- * Kconfig forces'y/n' and never an 'm'.
- */
-
-module_init(qtaguid_mt_init);
-MODULE_AUTHOR("jpa <jpa@google.com>");
-MODULE_DESCRIPTION("Xtables: socket owner+tag matching and associated stats");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("ipt_owner");
-MODULE_ALIAS("ip6t_owner");
-MODULE_ALIAS("ipt_qtaguid");
-MODULE_ALIAS("ip6t_qtaguid");
diff --git a/net/netfilter/xt_qtaguid_internal.h b/net/netfilter/xt_qtaguid_internal.h
deleted file mode 100644
index c705270..0000000
--- a/net/netfilter/xt_qtaguid_internal.h
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
- * Kernel iptables module to track stats for packets based on user tags.
- *
- * (C) 2011 Google, Inc
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#ifndef __XT_QTAGUID_INTERNAL_H__
-#define __XT_QTAGUID_INTERNAL_H__
-
-#include <linux/types.h>
-#include <linux/rbtree.h>
-#include <linux/spinlock_types.h>
-#include <linux/workqueue.h>
-
-/* Iface handling */
-#define IDEBUG_MASK (1<<0)
-/* Iptable Matching. Per packet. */
-#define MDEBUG_MASK (1<<1)
-/* Red-black tree handling. Per packet. */
-#define RDEBUG_MASK (1<<2)
-/* procfs ctrl/stats handling */
-#define CDEBUG_MASK (1<<3)
-/* dev and resource tracking */
-#define DDEBUG_MASK (1<<4)
-
-/* E.g (IDEBUG_MASK | CDEBUG_MASK | DDEBUG_MASK) */
-#define DEFAULT_DEBUG_MASK 0
-
-/*
- * (Un)Define these *DEBUG to compile out/in the pr_debug calls.
- * All undef: text size ~ 0x3030; all def: ~ 0x4404.
- */
-#define IDEBUG
-#define MDEBUG
-#define RDEBUG
-#define CDEBUG
-#define DDEBUG
-
-#define MSK_DEBUG(mask, ...) do { \
- if (unlikely(qtaguid_debug_mask & (mask))) \
- pr_debug(__VA_ARGS__); \
- } while (0)
-#ifdef IDEBUG
-#define IF_DEBUG(...) MSK_DEBUG(IDEBUG_MASK, __VA_ARGS__)
-#else
-#define IF_DEBUG(...) no_printk(__VA_ARGS__)
-#endif
-#ifdef MDEBUG
-#define MT_DEBUG(...) MSK_DEBUG(MDEBUG_MASK, __VA_ARGS__)
-#else
-#define MT_DEBUG(...) no_printk(__VA_ARGS__)
-#endif
-#ifdef RDEBUG
-#define RB_DEBUG(...) MSK_DEBUG(RDEBUG_MASK, __VA_ARGS__)
-#else
-#define RB_DEBUG(...) no_printk(__VA_ARGS__)
-#endif
-#ifdef CDEBUG
-#define CT_DEBUG(...) MSK_DEBUG(CDEBUG_MASK, __VA_ARGS__)
-#else
-#define CT_DEBUG(...) no_printk(__VA_ARGS__)
-#endif
-#ifdef DDEBUG
-#define DR_DEBUG(...) MSK_DEBUG(DDEBUG_MASK, __VA_ARGS__)
-#else
-#define DR_DEBUG(...) no_printk(__VA_ARGS__)
-#endif
-
-extern uint qtaguid_debug_mask;
-
-/*---------------------------------------------------------------------------*/
-/*
- * Tags:
- *
- * They represent what the data usage counters will be tracked against.
- * By default a tag is just based on the UID.
- * The UID is used as the base for policing, and can not be ignored.
- * So a tag will always at least represent a UID (uid_tag).
- *
- * A tag can be augmented with an "accounting tag" which is associated
- * with a UID.
- * User space can set the acct_tag portion of the tag which is then used
- * with sockets: all data belonging to that socket will be counted against the
- * tag. The policing is then based on the tag's uid_tag portion,
- * and stats are collected for the acct_tag portion separately.
- *
- * There could be
- * a: {acct_tag=1, uid_tag=10003}
- * b: {acct_tag=2, uid_tag=10003}
- * c: {acct_tag=3, uid_tag=10003}
- * d: {acct_tag=0, uid_tag=10003}
- * a, b, and c represent tags associated with specific sockets.
- * d is for the totals for that uid, including all untagged traffic.
- * Typically d is used with policing/quota rules.
- *
- * We want tag_t big enough to distinguish uid_t and acct_tag.
- * It might become a struct if needed.
- * Nothing should be using it as an int.
- */
-typedef uint64_t tag_t; /* Only used via accessors */
-
-#define TAG_UID_MASK 0xFFFFFFFFULL
-#define TAG_ACCT_MASK (~0xFFFFFFFFULL)
-
-static inline int tag_compare(tag_t t1, tag_t t2)
-{
- return t1 < t2 ? -1 : t1 == t2 ? 0 : 1;
-}
-
-static inline tag_t combine_atag_with_uid(tag_t acct_tag, uid_t uid)
-{
- return acct_tag | uid;
-}
-static inline tag_t make_tag_from_uid(uid_t uid)
-{
- return uid;
-}
-static inline uid_t get_uid_from_tag(tag_t tag)
-{
- return tag & TAG_UID_MASK;
-}
-static inline tag_t get_utag_from_tag(tag_t tag)
-{
- return tag & TAG_UID_MASK;
-}
-static inline tag_t get_atag_from_tag(tag_t tag)
-{
- return tag & TAG_ACCT_MASK;
-}
-
-static inline bool valid_atag(tag_t tag)
-{
- return !(tag & TAG_UID_MASK);
-}
-static inline tag_t make_atag_from_value(uint32_t value)
-{
- return (uint64_t)value << 32;
-}
-/*---------------------------------------------------------------------------*/
-
-/*
- * Maximum number of socket tags that a UID is allowed to have active.
- * Multiple processes belonging to the same UID contribute towards this limit.
- * Special UIDs that can impersonate a UID also contribute (e.g. download
- * manager, ...)
- */
-#define DEFAULT_MAX_SOCK_TAGS 1024
-
-/*
- * For now we only track 2 sets of counters.
- * The default set is 0.
- * Userspace can activate another set for a given uid being tracked.
- */
-#define IFS_MAX_COUNTER_SETS 2
-
-enum ifs_tx_rx {
- IFS_TX,
- IFS_RX,
- IFS_MAX_DIRECTIONS
-};
-
-/* For now, TCP, UDP, the rest */
-enum ifs_proto {
- IFS_TCP,
- IFS_UDP,
- IFS_PROTO_OTHER,
- IFS_MAX_PROTOS
-};
-
-struct byte_packet_counters {
- uint64_t bytes;
- uint64_t packets;
-};
-
-struct data_counters {
- struct byte_packet_counters bpc[IFS_MAX_COUNTER_SETS][IFS_MAX_DIRECTIONS][IFS_MAX_PROTOS];
-};
-
-static inline uint64_t dc_sum_bytes(struct data_counters *counters,
- int set,
- enum ifs_tx_rx direction)
-{
- return counters->bpc[set][direction][IFS_TCP].bytes
- + counters->bpc[set][direction][IFS_UDP].bytes
- + counters->bpc[set][direction][IFS_PROTO_OTHER].bytes;
-}
-
-static inline uint64_t dc_sum_packets(struct data_counters *counters,
- int set,
- enum ifs_tx_rx direction)
-{
- return counters->bpc[set][direction][IFS_TCP].packets
- + counters->bpc[set][direction][IFS_UDP].packets
- + counters->bpc[set][direction][IFS_PROTO_OTHER].packets;
-}
-
-
-/* Generic X based nodes used as a base for rb_tree ops */
-struct tag_node {
- struct rb_node node;
- tag_t tag;
-};
-
-struct tag_stat {
- struct tag_node tn;
- struct data_counters counters;
- /*
- * If this tag is acct_tag based, we need to count against the
- * matching parent uid_tag.
- */
- struct data_counters *parent_counters;
-};
-
-struct iface_stat {
- struct list_head list; /* in iface_stat_list */
- char *ifname;
- bool active;
- /* net_dev is only valid for active iface_stat */
- struct net_device *net_dev;
-
- struct byte_packet_counters totals_via_dev[IFS_MAX_DIRECTIONS];
- struct data_counters totals_via_skb;
- /*
- * We keep the last_known, because some devices reset their counters
- * just before NETDEV_UP, while some will reset just before
- * NETDEV_REGISTER (which is more normal).
- * So now, if the device didn't do a NETDEV_UNREGISTER and we see
- * its current dev stats smaller that what was previously known, we
- * assume an UNREGISTER and just use the last_known.
- */
- struct byte_packet_counters last_known[IFS_MAX_DIRECTIONS];
- /* last_known is usable when last_known_valid is true */
- bool last_known_valid;
-
- struct proc_dir_entry *proc_ptr;
-
- struct rb_root tag_stat_tree;
- spinlock_t tag_stat_list_lock;
-};
-
-/* This is needed to create proc_dir_entries from atomic context. */
-struct iface_stat_work {
- struct work_struct iface_work;
- struct iface_stat *iface_entry;
-};
-
-/*
- * Track tag that this socket is transferring data for, and not necessarily
- * the uid that owns the socket.
- * This is the tag against which tag_stat.counters will be billed.
- * These structs need to be looked up by sock and pid.
- */
-struct sock_tag {
- struct rb_node sock_node;
- struct sock *sk; /* Only used as a number, never dereferenced */
- /* Used to associate with a given pid */
- struct list_head list; /* in proc_qtu_data.sock_tag_list */
- pid_t pid;
-
- tag_t tag;
-};
-
-struct qtaguid_event_counts {
- /* Various successful events */
- atomic64_t sockets_tagged;
- atomic64_t sockets_untagged;
- atomic64_t counter_set_changes;
- atomic64_t delete_cmds;
- atomic64_t iface_events; /* Number of NETDEV_* events handled */
-
- atomic64_t match_calls; /* Number of times iptables called mt */
- /* Number of times iptables called mt from pre or post routing hooks */
- atomic64_t match_calls_prepost;
- /*
- * match_found_sk_*: numbers related to the netfilter matching
- * function finding a sock for the sk_buff.
- * Total skbs processed is sum(match_found*).
- */
- atomic64_t match_found_sk; /* An sk was already in the sk_buff. */
- /* The connection tracker had or didn't have the sk. */
- atomic64_t match_found_sk_in_ct;
- atomic64_t match_found_no_sk_in_ct;
- /*
- * No sk could be found. No apparent owner. Could happen with
- * unsolicited traffic.
- */
- atomic64_t match_no_sk;
- /*
- * The file ptr in the sk_socket wasn't there and we couldn't get GID.
- * This might happen for traffic while the socket is being closed.
- */
- atomic64_t match_no_sk_gid;
-};
-
-/* Track the set active_set for the given tag. */
-struct tag_counter_set {
- struct tag_node tn;
- int active_set;
-};
-
-/*----------------------------------------------*/
-/*
- * The qtu uid data is used to track resources that are created directly or
- * indirectly by processes (uid tracked).
- * It is shared by the processes with the same uid.
- * Some of the resource will be counted to prevent further rogue allocations,
- * some will need freeing once the owner process (uid) exits.
- */
-struct uid_tag_data {
- struct rb_node node;
- uid_t uid;
-
- /*
- * For the uid, how many accounting tags have been set.
- */
- int num_active_tags;
- /* Track the number of proc_qtu_data that reference it */
- int num_pqd;
- struct rb_root tag_ref_tree;
- /* No tag_node_tree_lock; use uid_tag_data_tree_lock */
-};
-
-struct tag_ref {
- struct tag_node tn;
-
- /*
- * This tracks the number of active sockets that have a tag on them
- * which matches this tag_ref.tn.tag.
- * A tag ref can live on after the sockets are untagged.
- * A tag ref can only be removed during a tag delete command.
- */
- int num_sock_tags;
-};
-
-struct proc_qtu_data {
- struct rb_node node;
- pid_t pid;
-
- struct uid_tag_data *parent_tag_data;
-
- /* Tracks the sock_tags that need freeing upon this proc's death */
- struct list_head sock_tag_list;
- /* No spinlock_t sock_tag_list_lock; use the global one. */
-};
-
-/*----------------------------------------------*/
-#endif /* ifndef __XT_QTAGUID_INTERNAL_H__ */
diff --git a/net/netfilter/xt_qtaguid_print.c b/net/netfilter/xt_qtaguid_print.c
deleted file mode 100644
index 2a7190d..0000000
--- a/net/netfilter/xt_qtaguid_print.c
+++ /dev/null
@@ -1,566 +0,0 @@
-/*
- * Pretty printing Support for iptables xt_qtaguid module.
- *
- * (C) 2011 Google, Inc
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-/*
- * Most of the functions in this file just waste time if DEBUG is not defined.
- * The matching xt_qtaguid_print.h will static inline empty funcs if the needed
- * debug flags ore not defined.
- * Those funcs that fail to allocate memory will panic as there is no need to
- * hobble allong just pretending to do the requested work.
- */
-
-#define DEBUG
-
-#include <linux/fs.h>
-#include <linux/gfp.h>
-#include <linux/net.h>
-#include <linux/rbtree.h>
-#include <linux/slab.h>
-#include <linux/spinlock_types.h>
-#include <net/sock.h>
-
-#include "xt_qtaguid_internal.h"
-#include "xt_qtaguid_print.h"
-
-#ifdef DDEBUG
-
-static void _bug_on_err_or_null(void *ptr)
-{
- if (IS_ERR_OR_NULL(ptr)) {
- pr_err("qtaguid: kmalloc failed\n");
- BUG();
- }
-}
-
-char *pp_tag_t(tag_t *tag)
-{
- char *res;
-
- if (!tag)
- res = kasprintf(GFP_ATOMIC, "tag_t@null{}");
- else
- res = kasprintf(GFP_ATOMIC,
- "tag_t@%p{tag=0x%llx, uid=%u}",
- tag, *tag, get_uid_from_tag(*tag));
- _bug_on_err_or_null(res);
- return res;
-}
-
-char *pp_data_counters(struct data_counters *dc, bool showValues)
-{
- char *res;
-
- if (!dc)
- res = kasprintf(GFP_ATOMIC, "data_counters@null{}");
- else if (showValues)
- res = kasprintf(
- GFP_ATOMIC, "data_counters@%p{"
- "set0{"
- "rx{"
- "tcp{b=%llu, p=%llu}, "
- "udp{b=%llu, p=%llu},"
- "other{b=%llu, p=%llu}}, "
- "tx{"
- "tcp{b=%llu, p=%llu}, "
- "udp{b=%llu, p=%llu},"
- "other{b=%llu, p=%llu}}}, "
- "set1{"
- "rx{"
- "tcp{b=%llu, p=%llu}, "
- "udp{b=%llu, p=%llu},"
- "other{b=%llu, p=%llu}}, "
- "tx{"
- "tcp{b=%llu, p=%llu}, "
- "udp{b=%llu, p=%llu},"
- "other{b=%llu, p=%llu}}}}",
- dc,
- dc->bpc[0][IFS_RX][IFS_TCP].bytes,
- dc->bpc[0][IFS_RX][IFS_TCP].packets,
- dc->bpc[0][IFS_RX][IFS_UDP].bytes,
- dc->bpc[0][IFS_RX][IFS_UDP].packets,
- dc->bpc[0][IFS_RX][IFS_PROTO_OTHER].bytes,
- dc->bpc[0][IFS_RX][IFS_PROTO_OTHER].packets,
- dc->bpc[0][IFS_TX][IFS_TCP].bytes,
- dc->bpc[0][IFS_TX][IFS_TCP].packets,
- dc->bpc[0][IFS_TX][IFS_UDP].bytes,
- dc->bpc[0][IFS_TX][IFS_UDP].packets,
- dc->bpc[0][IFS_TX][IFS_PROTO_OTHER].bytes,
- dc->bpc[0][IFS_TX][IFS_PROTO_OTHER].packets,
- dc->bpc[1][IFS_RX][IFS_TCP].bytes,
- dc->bpc[1][IFS_RX][IFS_TCP].packets,
- dc->bpc[1][IFS_RX][IFS_UDP].bytes,
- dc->bpc[1][IFS_RX][IFS_UDP].packets,
- dc->bpc[1][IFS_RX][IFS_PROTO_OTHER].bytes,
- dc->bpc[1][IFS_RX][IFS_PROTO_OTHER].packets,
- dc->bpc[1][IFS_TX][IFS_TCP].bytes,
- dc->bpc[1][IFS_TX][IFS_TCP].packets,
- dc->bpc[1][IFS_TX][IFS_UDP].bytes,
- dc->bpc[1][IFS_TX][IFS_UDP].packets,
- dc->bpc[1][IFS_TX][IFS_PROTO_OTHER].bytes,
- dc->bpc[1][IFS_TX][IFS_PROTO_OTHER].packets);
- else
- res = kasprintf(GFP_ATOMIC, "data_counters@%p{...}", dc);
- _bug_on_err_or_null(res);
- return res;
-}
-
-char *pp_tag_node(struct tag_node *tn)
-{
- char *tag_str;
- char *res;
-
- if (!tn) {
- res = kasprintf(GFP_ATOMIC, "tag_node@null{}");
- _bug_on_err_or_null(res);
- return res;
- }
- tag_str = pp_tag_t(&tn->tag);
- res = kasprintf(GFP_ATOMIC,
- "tag_node@%p{tag=%s}",
- tn, tag_str);
- _bug_on_err_or_null(res);
- kfree(tag_str);
- return res;
-}
-
-char *pp_tag_ref(struct tag_ref *tr)
-{
- char *tn_str;
- char *res;
-
- if (!tr) {
- res = kasprintf(GFP_ATOMIC, "tag_ref@null{}");
- _bug_on_err_or_null(res);
- return res;
- }
- tn_str = pp_tag_node(&tr->tn);
- res = kasprintf(GFP_ATOMIC,
- "tag_ref@%p{%s, num_sock_tags=%d}",
- tr, tn_str, tr->num_sock_tags);
- _bug_on_err_or_null(res);
- kfree(tn_str);
- return res;
-}
-
-char *pp_tag_stat(struct tag_stat *ts)
-{
- char *tn_str;
- char *counters_str;
- char *parent_counters_str;
- char *res;
-
- if (!ts) {
- res = kasprintf(GFP_ATOMIC, "tag_stat@null{}");
- _bug_on_err_or_null(res);
- return res;
- }
- tn_str = pp_tag_node(&ts->tn);
- counters_str = pp_data_counters(&ts->counters, true);
- parent_counters_str = pp_data_counters(ts->parent_counters, false);
- res = kasprintf(GFP_ATOMIC,
- "tag_stat@%p{%s, counters=%s, parent_counters=%s}",
- ts, tn_str, counters_str, parent_counters_str);
- _bug_on_err_or_null(res);
- kfree(tn_str);
- kfree(counters_str);
- kfree(parent_counters_str);
- return res;
-}
-
-char *pp_iface_stat(struct iface_stat *is)
-{
- char *res;
- if (!is) {
- res = kasprintf(GFP_ATOMIC, "iface_stat@null{}");
- } else {
- struct data_counters *cnts = &is->totals_via_skb;
- res = kasprintf(GFP_ATOMIC, "iface_stat@%p{"
- "list=list_head{...}, "
- "ifname=%s, "
- "total_dev={rx={bytes=%llu, "
- "packets=%llu}, "
- "tx={bytes=%llu, "
- "packets=%llu}}, "
- "total_skb={rx={bytes=%llu, "
- "packets=%llu}, "
- "tx={bytes=%llu, "
- "packets=%llu}}, "
- "last_known_valid=%d, "
- "last_known={rx={bytes=%llu, "
- "packets=%llu}, "
- "tx={bytes=%llu, "
- "packets=%llu}}, "
- "active=%d, "
- "net_dev=%p, "
- "proc_ptr=%p, "
- "tag_stat_tree=rb_root{...}}",
- is,
- is->ifname,
- is->totals_via_dev[IFS_RX].bytes,
- is->totals_via_dev[IFS_RX].packets,
- is->totals_via_dev[IFS_TX].bytes,
- is->totals_via_dev[IFS_TX].packets,
- dc_sum_bytes(cnts, 0, IFS_RX),
- dc_sum_packets(cnts, 0, IFS_RX),
- dc_sum_bytes(cnts, 0, IFS_TX),
- dc_sum_packets(cnts, 0, IFS_TX),
- is->last_known_valid,
- is->last_known[IFS_RX].bytes,
- is->last_known[IFS_RX].packets,
- is->last_known[IFS_TX].bytes,
- is->last_known[IFS_TX].packets,
- is->active,
- is->net_dev,
- is->proc_ptr);
- }
- _bug_on_err_or_null(res);
- return res;
-}
-
-char *pp_sock_tag(struct sock_tag *st)
-{
- char *tag_str;
- char *res;
-
- if (!st) {
- res = kasprintf(GFP_ATOMIC, "sock_tag@null{}");
- _bug_on_err_or_null(res);
- return res;
- }
- tag_str = pp_tag_t(&st->tag);
- res = kasprintf(GFP_ATOMIC, "sock_tag@%p{"
- "sock_node=rb_node{...}, "
- "sk=%p (f_count=%d), list=list_head{...}, "
- "pid=%u, tag=%s}",
- st, st->sk, atomic_read(
- &st->sk->sk_refcnt),
- st->pid, tag_str);
- _bug_on_err_or_null(res);
- kfree(tag_str);
- return res;
-}
-
-char *pp_uid_tag_data(struct uid_tag_data *utd)
-{
- char *res;
-
- if (!utd)
- res = kasprintf(GFP_ATOMIC, "uid_tag_data@null{}");
- else
- res = kasprintf(GFP_ATOMIC, "uid_tag_data@%p{"
- "uid=%u, num_active_acct_tags=%d, "
- "num_pqd=%d, "
- "tag_node_tree=rb_root{...}, "
- "proc_qtu_data_tree=rb_root{...}}",
- utd, utd->uid,
- utd->num_active_tags, utd->num_pqd);
- _bug_on_err_or_null(res);
- return res;
-}
-
-char *pp_proc_qtu_data(struct proc_qtu_data *pqd)
-{
- char *parent_tag_data_str;
- char *res;
-
- if (!pqd) {
- res = kasprintf(GFP_ATOMIC, "proc_qtu_data@null{}");
- _bug_on_err_or_null(res);
- return res;
- }
- parent_tag_data_str = pp_uid_tag_data(pqd->parent_tag_data);
- res = kasprintf(GFP_ATOMIC, "proc_qtu_data@%p{"
- "node=rb_node{...}, pid=%u, "
- "parent_tag_data=%s, "
- "sock_tag_list=list_head{...}}",
- pqd, pqd->pid, parent_tag_data_str
- );
- _bug_on_err_or_null(res);
- kfree(parent_tag_data_str);
- return res;
-}
-
-/*------------------------------------------*/
-void prdebug_sock_tag_tree(int indent_level,
- struct rb_root *sock_tag_tree)
-{
- struct rb_node *node;
- struct sock_tag *sock_tag_entry;
- char *str;
-
- if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK))
- return;
-
- if (RB_EMPTY_ROOT(sock_tag_tree)) {
- str = "sock_tag_tree=rb_root{}";
- pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
- return;
- }
-
- str = "sock_tag_tree=rb_root{";
- pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
- indent_level++;
- for (node = rb_first(sock_tag_tree);
- node;
- node = rb_next(node)) {
- sock_tag_entry = rb_entry(node, struct sock_tag, sock_node);
- str = pp_sock_tag(sock_tag_entry);
- pr_debug("%*d: %s,\n", indent_level*2, indent_level, str);
- kfree(str);
- }
- indent_level--;
- str = "}";
- pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
-}
-
-void prdebug_sock_tag_list(int indent_level,
- struct list_head *sock_tag_list)
-{
- struct sock_tag *sock_tag_entry;
- char *str;
-
- if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK))
- return;
-
- if (list_empty(sock_tag_list)) {
- str = "sock_tag_list=list_head{}";
- pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
- return;
- }
-
- str = "sock_tag_list=list_head{";
- pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
- indent_level++;
- list_for_each_entry(sock_tag_entry, sock_tag_list, list) {
- str = pp_sock_tag(sock_tag_entry);
- pr_debug("%*d: %s,\n", indent_level*2, indent_level, str);
- kfree(str);
- }
- indent_level--;
- str = "}";
- pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
-}
-
-void prdebug_proc_qtu_data_tree(int indent_level,
- struct rb_root *proc_qtu_data_tree)
-{
- char *str;
- struct rb_node *node;
- struct proc_qtu_data *proc_qtu_data_entry;
-
- if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK))
- return;
-
- if (RB_EMPTY_ROOT(proc_qtu_data_tree)) {
- str = "proc_qtu_data_tree=rb_root{}";
- pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
- return;
- }
-
- str = "proc_qtu_data_tree=rb_root{";
- pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
- indent_level++;
- for (node = rb_first(proc_qtu_data_tree);
- node;
- node = rb_next(node)) {
- proc_qtu_data_entry = rb_entry(node,
- struct proc_qtu_data,
- node);
- str = pp_proc_qtu_data(proc_qtu_data_entry);
- pr_debug("%*d: %s,\n", indent_level*2, indent_level,
- str);
- kfree(str);
- indent_level++;
- prdebug_sock_tag_list(indent_level,
- &proc_qtu_data_entry->sock_tag_list);
- indent_level--;
-
- }
- indent_level--;
- str = "}";
- pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
-}
-
-void prdebug_tag_ref_tree(int indent_level, struct rb_root *tag_ref_tree)
-{
- char *str;
- struct rb_node *node;
- struct tag_ref *tag_ref_entry;
-
- if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK))
- return;
-
- if (RB_EMPTY_ROOT(tag_ref_tree)) {
- str = "tag_ref_tree{}";
- pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
- return;
- }
-
- str = "tag_ref_tree{";
- pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
- indent_level++;
- for (node = rb_first(tag_ref_tree);
- node;
- node = rb_next(node)) {
- tag_ref_entry = rb_entry(node,
- struct tag_ref,
- tn.node);
- str = pp_tag_ref(tag_ref_entry);
- pr_debug("%*d: %s,\n", indent_level*2, indent_level,
- str);
- kfree(str);
- }
- indent_level--;
- str = "}";
- pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
-}
-
-void prdebug_uid_tag_data_tree(int indent_level,
- struct rb_root *uid_tag_data_tree)
-{
- char *str;
- struct rb_node *node;
- struct uid_tag_data *uid_tag_data_entry;
-
- if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK))
- return;
-
- if (RB_EMPTY_ROOT(uid_tag_data_tree)) {
- str = "uid_tag_data_tree=rb_root{}";
- pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
- return;
- }
-
- str = "uid_tag_data_tree=rb_root{";
- pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
- indent_level++;
- for (node = rb_first(uid_tag_data_tree);
- node;
- node = rb_next(node)) {
- uid_tag_data_entry = rb_entry(node, struct uid_tag_data,
- node);
- str = pp_uid_tag_data(uid_tag_data_entry);
- pr_debug("%*d: %s,\n", indent_level*2, indent_level, str);
- kfree(str);
- if (!RB_EMPTY_ROOT(&uid_tag_data_entry->tag_ref_tree)) {
- indent_level++;
- prdebug_tag_ref_tree(indent_level,
- &uid_tag_data_entry->tag_ref_tree);
- indent_level--;
- }
- }
- indent_level--;
- str = "}";
- pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
-}
-
-void prdebug_tag_stat_tree(int indent_level,
- struct rb_root *tag_stat_tree)
-{
- char *str;
- struct rb_node *node;
- struct tag_stat *ts_entry;
-
- if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK))
- return;
-
- if (RB_EMPTY_ROOT(tag_stat_tree)) {
- str = "tag_stat_tree{}";
- pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
- return;
- }
-
- str = "tag_stat_tree{";
- pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
- indent_level++;
- for (node = rb_first(tag_stat_tree);
- node;
- node = rb_next(node)) {
- ts_entry = rb_entry(node, struct tag_stat, tn.node);
- str = pp_tag_stat(ts_entry);
- pr_debug("%*d: %s\n", indent_level*2, indent_level,
- str);
- kfree(str);
- }
- indent_level--;
- str = "}";
- pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
-}
-
-void prdebug_iface_stat_list(int indent_level,
- struct list_head *iface_stat_list)
-{
- char *str;
- struct iface_stat *iface_entry;
-
- if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK))
- return;
-
- if (list_empty(iface_stat_list)) {
- str = "iface_stat_list=list_head{}";
- pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
- return;
- }
-
- str = "iface_stat_list=list_head{";
- pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
- indent_level++;
- list_for_each_entry(iface_entry, iface_stat_list, list) {
- str = pp_iface_stat(iface_entry);
- pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
- kfree(str);
-
- spin_lock_bh(&iface_entry->tag_stat_list_lock);
- if (!RB_EMPTY_ROOT(&iface_entry->tag_stat_tree)) {
- indent_level++;
- prdebug_tag_stat_tree(indent_level,
- &iface_entry->tag_stat_tree);
- indent_level--;
- }
- spin_unlock_bh(&iface_entry->tag_stat_list_lock);
- }
- indent_level--;
- str = "}";
- pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
-}
-
-#endif /* ifdef DDEBUG */
-/*------------------------------------------*/
-static const char * const netdev_event_strings[] = {
- "netdev_unknown",
- "NETDEV_UP",
- "NETDEV_DOWN",
- "NETDEV_REBOOT",
- "NETDEV_CHANGE",
- "NETDEV_REGISTER",
- "NETDEV_UNREGISTER",
- "NETDEV_CHANGEMTU",
- "NETDEV_CHANGEADDR",
- "NETDEV_GOING_DOWN",
- "NETDEV_CHANGENAME",
- "NETDEV_FEAT_CHANGE",
- "NETDEV_BONDING_FAILOVER",
- "NETDEV_PRE_UP",
- "NETDEV_PRE_TYPE_CHANGE",
- "NETDEV_POST_TYPE_CHANGE",
- "NETDEV_POST_INIT",
- "NETDEV_UNREGISTER_BATCH",
- "NETDEV_RELEASE",
- "NETDEV_NOTIFY_PEERS",
- "NETDEV_JOIN",
-};
-
-const char *netdev_evt_str(int netdev_event)
-{
- if (netdev_event < 0
- || netdev_event >= ARRAY_SIZE(netdev_event_strings))
- return "bad event num";
- return netdev_event_strings[netdev_event];
-}
diff --git a/net/netfilter/xt_qtaguid_print.h b/net/netfilter/xt_qtaguid_print.h
deleted file mode 100644
index b63871a..0000000
--- a/net/netfilter/xt_qtaguid_print.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Pretty printing Support for iptables xt_qtaguid module.
- *
- * (C) 2011 Google, Inc
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#ifndef __XT_QTAGUID_PRINT_H__
-#define __XT_QTAGUID_PRINT_H__
-
-#include "xt_qtaguid_internal.h"
-
-#ifdef DDEBUG
-
-char *pp_tag_t(tag_t *tag);
-char *pp_data_counters(struct data_counters *dc, bool showValues);
-char *pp_tag_node(struct tag_node *tn);
-char *pp_tag_ref(struct tag_ref *tr);
-char *pp_tag_stat(struct tag_stat *ts);
-char *pp_iface_stat(struct iface_stat *is);
-char *pp_sock_tag(struct sock_tag *st);
-char *pp_uid_tag_data(struct uid_tag_data *qtd);
-char *pp_proc_qtu_data(struct proc_qtu_data *pqd);
-
-/*------------------------------------------*/
-void prdebug_sock_tag_list(int indent_level,
- struct list_head *sock_tag_list);
-void prdebug_sock_tag_tree(int indent_level,
- struct rb_root *sock_tag_tree);
-void prdebug_proc_qtu_data_tree(int indent_level,
- struct rb_root *proc_qtu_data_tree);
-void prdebug_tag_ref_tree(int indent_level, struct rb_root *tag_ref_tree);
-void prdebug_uid_tag_data_tree(int indent_level,
- struct rb_root *uid_tag_data_tree);
-void prdebug_tag_stat_tree(int indent_level,
- struct rb_root *tag_stat_tree);
-void prdebug_iface_stat_list(int indent_level,
- struct list_head *iface_stat_list);
-
-#else
-
-/*------------------------------------------*/
-static inline char *pp_tag_t(tag_t *tag)
-{
- return NULL;
-}
-static inline char *pp_data_counters(struct data_counters *dc, bool showValues)
-{
- return NULL;
-}
-static inline char *pp_tag_node(struct tag_node *tn)
-{
- return NULL;
-}
-static inline char *pp_tag_ref(struct tag_ref *tr)
-{
- return NULL;
-}
-static inline char *pp_tag_stat(struct tag_stat *ts)
-{
- return NULL;
-}
-static inline char *pp_iface_stat(struct iface_stat *is)
-{
- return NULL;
-}
-static inline char *pp_sock_tag(struct sock_tag *st)
-{
- return NULL;
-}
-static inline char *pp_uid_tag_data(struct uid_tag_data *qtd)
-{
- return NULL;
-}
-static inline char *pp_proc_qtu_data(struct proc_qtu_data *pqd)
-{
- return NULL;
-}
-
-/*------------------------------------------*/
-static inline
-void prdebug_sock_tag_list(int indent_level,
- struct list_head *sock_tag_list)
-{
-}
-static inline
-void prdebug_sock_tag_tree(int indent_level,
- struct rb_root *sock_tag_tree)
-{
-}
-static inline
-void prdebug_proc_qtu_data_tree(int indent_level,
- struct rb_root *proc_qtu_data_tree)
-{
-}
-static inline
-void prdebug_tag_ref_tree(int indent_level, struct rb_root *tag_ref_tree)
-{
-}
-static inline
-void prdebug_uid_tag_data_tree(int indent_level,
- struct rb_root *uid_tag_data_tree)
-{
-}
-static inline
-void prdebug_tag_stat_tree(int indent_level,
- struct rb_root *tag_stat_tree)
-{
-}
-static inline
-void prdebug_iface_stat_list(int indent_level,
- struct list_head *iface_stat_list)
-{
-}
-#endif
-/*------------------------------------------*/
-const char *netdev_evt_str(int netdev_event);
-#endif /* ifndef __XT_QTAGUID_PRINT_H__ */
diff --git a/net/rds/bind.c b/net/rds/bind.c
index cc7e3a1..438452f 100644
--- a/net/rds/bind.c
+++ b/net/rds/bind.c
@@ -62,10 +62,10 @@
rcu_read_lock();
rs = rhashtable_lookup(&bind_hash_table, &key, ht_parms);
- if (rs && !sock_flag(rds_rs_to_sk(rs), SOCK_DEAD))
- rds_sock_addref(rs);
- else
+ if (rs && (sock_flag(rds_rs_to_sk(rs), SOCK_DEAD) ||
+ !atomic_inc_not_zero(&rds_rs_to_sk(rs)->sk_refcnt)))
rs = NULL;
+
rcu_read_unlock();
rdsdebug("returning rs %p for %pI4:%u\n", rs, &addr,
diff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c
index 3e52b7fd..72de691 100644
--- a/net/rxrpc/recvmsg.c
+++ b/net/rxrpc/recvmsg.c
@@ -552,6 +552,7 @@
rxrpc_put_call(call, rxrpc_call_put);
error_no_call:
release_sock(&rx->sk);
+error_trace:
trace_rxrpc_recvmsg(call, rxrpc_recvmsg_return, 0, 0, 0, ret);
return ret;
@@ -560,7 +561,7 @@
wait_error:
finish_wait(sk_sleep(&rx->sk), &wait);
call = NULL;
- goto error_no_call;
+ goto error_trace;
}
/**
diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c
index b3f7980..d646aa7 100644
--- a/net/sched/sch_tbf.c
+++ b/net/sched/sch_tbf.c
@@ -142,16 +142,6 @@
return len;
}
-/*
- * Return length of individual segments of a gso packet,
- * including all headers (MAC, IP, TCP/UDP)
- */
-static unsigned int skb_gso_mac_seglen(const struct sk_buff *skb)
-{
- unsigned int hdr_len = skb_transport_header(skb) - skb_mac_header(skb);
- return hdr_len + skb_gso_transport_seglen(skb);
-}
-
/* GSO packet is too big, segment it so that tbf can transmit
* each segment in time
*/
diff --git a/net/vmw_vsock/vmci_transport.c b/net/vmw_vsock/vmci_transport.c
index 008f342..102bf91 100644
--- a/net/vmw_vsock/vmci_transport.c
+++ b/net/vmw_vsock/vmci_transport.c
@@ -1656,6 +1656,10 @@
static void vmci_transport_destruct(struct vsock_sock *vsk)
{
+ /* transport can be NULL if we hit a failure at init() time */
+ if (!vmci_trans(vsk))
+ return;
+
/* Ensure that the detach callback doesn't use the sk/vsk
* we are about to destruct.
*/
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index 0077216..0a7e5d9 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -352,17 +352,15 @@
unsigned int lci = 1;
struct sock *sk;
- read_lock_bh(&x25_list_lock);
-
- while ((sk = __x25_find_socket(lci, nb)) != NULL) {
+ while ((sk = x25_find_socket(lci, nb)) != NULL) {
sock_put(sk);
if (++lci == 4096) {
lci = 0;
break;
}
+ cond_resched();
}
- read_unlock_bh(&x25_list_lock);
return lci;
}
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 052ce07..f54bed8 100755
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -1461,10 +1461,15 @@
if (!ut[i].family)
ut[i].family = family;
- if ((ut[i].mode == XFRM_MODE_TRANSPORT) &&
- (ut[i].family != prev_family))
- return -EINVAL;
-
+ switch (ut[i].mode) {
+ case XFRM_MODE_TUNNEL:
+ case XFRM_MODE_BEET:
+ break;
+ default:
+ if (ut[i].family != prev_family)
+ return -EINVAL;
+ break;
+ }
if (ut[i].mode >= XFRM_MODE_MAX)
return -EINVAL;
diff --git a/samples/mei/mei-amt-version.c b/samples/mei/mei-amt-version.c
index 57d0d87..bb99889 100644
--- a/samples/mei/mei-amt-version.c
+++ b/samples/mei/mei-amt-version.c
@@ -117,7 +117,7 @@
me->verbose = verbose;
- me->fd = open("/dev/mei", O_RDWR);
+ me->fd = open("/dev/mei0", O_RDWR);
if (me->fd == -1) {
mei_err(me, "Cannot establish a handle to the Intel MEI driver\n");
goto err;
diff --git a/scripts/decode_stacktrace.sh b/scripts/decode_stacktrace.sh
index c332684..edde825 100755
--- a/scripts/decode_stacktrace.sh
+++ b/scripts/decode_stacktrace.sh
@@ -77,7 +77,7 @@
fi
# Strip out the base of the path
- code=${code//$basepath/""}
+ code=${code//^$basepath/""}
# In the case of inlines, move everything to same line
code=${code//$'\n'/' '}
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 13b0d56..d683c41 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -4362,6 +4362,12 @@
int request = 0;
int rc;
+ /*
+ * Validate requested permissions
+ */
+ if (perm & ~KEY_NEED_ALL)
+ return -EINVAL;
+
keyp = key_ref_to_ptr(key_ref);
if (keyp == NULL)
return -EINVAL;
@@ -4381,10 +4387,10 @@
ad.a.u.key_struct.key = keyp->serial;
ad.a.u.key_struct.key_desc = keyp->description;
#endif
- if (perm & KEY_NEED_READ)
- request = MAY_READ;
+ if (perm & (KEY_NEED_READ | KEY_NEED_SEARCH | KEY_NEED_VIEW))
+ request |= MAY_READ;
if (perm & (KEY_NEED_WRITE | KEY_NEED_LINK | KEY_NEED_SETATTR))
- request = MAY_WRITE;
+ request |= MAY_WRITE;
rc = smk_access(tkp, keyp->security, request, &ad);
rc = smk_bu_note("key access", tkp, keyp->security, request, rc);
return rc;
diff --git a/sound/pci/hda/hda_bind.c b/sound/pci/hda/hda_bind.c
index 6efadbf..7ea201c 100644
--- a/sound/pci/hda/hda_bind.c
+++ b/sound/pci/hda/hda_bind.c
@@ -109,7 +109,8 @@
err = snd_hda_codec_build_controls(codec);
if (err < 0)
goto error_module;
- if (codec->card->registered) {
+ /* only register after the bus probe finished; otherwise it's racy */
+ if (!codec->bus->bus_probing && codec->card->registered) {
err = snd_card_register(codec->card);
if (err < 0)
goto error_module;
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 776dffa..171e11b 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -68,6 +68,7 @@
unsigned int response_reset:1; /* controller was reset */
unsigned int in_reset:1; /* during reset operation */
unsigned int no_response_fallback:1; /* don't fallback at RIRB error */
+ unsigned int bus_probing :1; /* during probing process */
int primary_dig_out_type; /* primary digital out PCM type */
unsigned int mixer_assigned; /* codec addr for mixer name */
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index fcd583e..789eca1 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -2089,6 +2089,7 @@
int val;
int err;
+ to_hda_bus(bus)->bus_probing = 1;
hda->probe_continued = 1;
/* Request display power well for the HDA controller or codec. For
@@ -2189,6 +2190,7 @@
if (err < 0)
hda->init_failed = 1;
complete_all(&hda->probe_wait);
+ to_hda_bus(bus)->bus_probing = 0;
return err;
}
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index ba9cd75..447b3a8 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -854,6 +854,7 @@
SND_PCI_QUIRK(0x103c, 0x807C, "HP EliteBook 820 G3", CXT_FIXUP_HP_DOCK),
SND_PCI_QUIRK(0x103c, 0x80FD, "HP ProBook 640 G2", CXT_FIXUP_HP_DOCK),
SND_PCI_QUIRK(0x103c, 0x828c, "HP EliteBook 840 G4", CXT_FIXUP_HP_DOCK),
+ SND_PCI_QUIRK(0x103c, 0x83b2, "HP EliteBook 840 G5", CXT_FIXUP_HP_DOCK),
SND_PCI_QUIRK(0x103c, 0x83b3, "HP EliteBook 830 G5", CXT_FIXUP_HP_DOCK),
SND_PCI_QUIRK(0x103c, 0x83d3, "HP ProBook 640 G4", CXT_FIXUP_HP_DOCK),
SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE),
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 19bdcac..a732b3a 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -220,7 +220,7 @@
config SND_SOC_EUKREA_TLV320
tristate "Eukrea TLV320"
- depends on ARCH_MXC && I2C
+ depends on ARCH_MXC && !ARM64 && I2C
select SND_SOC_TLV320AIC23_I2C
select SND_SOC_IMX_AUDMUX
select SND_SOC_IMX_SSI
diff --git a/sound/soc/intel/atom/sst/sst_loader.c b/sound/soc/intel/atom/sst/sst_loader.c
index 3391714..054b1d5 100644
--- a/sound/soc/intel/atom/sst/sst_loader.c
+++ b/sound/soc/intel/atom/sst/sst_loader.c
@@ -354,14 +354,14 @@
const struct firmware *fw;
retval = request_firmware(&fw, sst->firmware_name, sst->dev);
- if (fw == NULL) {
- dev_err(sst->dev, "fw is returning as null\n");
- return -EINVAL;
- }
if (retval) {
dev_err(sst->dev, "request fw failed %d\n", retval);
return retval;
}
+ if (fw == NULL) {
+ dev_err(sst->dev, "fw is returning as null\n");
+ return -EINVAL;
+ }
mutex_lock(&sst->sst_lock);
retval = sst_cache_and_parse_fw(sst, fw);
mutex_unlock(&sst->sst_lock);
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index b57d1d4..f61bf84 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -315,6 +315,9 @@
return 0;
}
+/* Setup an implicit feedback endpoint from a quirk. Returns 0 if no quirk
+ * applies. Returns 1 if a quirk was found.
+ */
static int set_sync_ep_implicit_fb_quirk(struct snd_usb_substream *subs,
struct usb_device *dev,
struct usb_interface_descriptor *altsd,
@@ -393,7 +396,7 @@
subs->data_endpoint->sync_master = subs->sync_endpoint;
- return 0;
+ return 1;
}
static int set_sync_endpoint(struct snd_usb_substream *subs,
@@ -432,6 +435,10 @@
if (err < 0)
return err;
+ /* endpoint set by quirk */
+ if (err > 0)
+ return 0;
+
if (altsd->bNumEndpoints < 2)
return 0;
diff --git a/tools/perf/arch/x86/util/kvm-stat.c b/tools/perf/arch/x86/util/kvm-stat.c
index b63d4be..2020e12 100644
--- a/tools/perf/arch/x86/util/kvm-stat.c
+++ b/tools/perf/arch/x86/util/kvm-stat.c
@@ -154,7 +154,7 @@
if (strstr(cpuid, "Intel")) {
kvm->exit_reasons = vmx_exit_reasons;
kvm->exit_reasons_isa = "VMX";
- } else if (strstr(cpuid, "AMD")) {
+ } else if (strstr(cpuid, "AMD") || strstr(cpuid, "Hygon")) {
kvm->exit_reasons = svm_exit_reasons;
kvm->exit_reasons_isa = "SVM";
} else
diff --git a/tools/perf/tests/evsel-tp-sched.c b/tools/perf/tests/evsel-tp-sched.c
index 1984b3b..66b53f1 100644
--- a/tools/perf/tests/evsel-tp-sched.c
+++ b/tools/perf/tests/evsel-tp-sched.c
@@ -16,7 +16,7 @@
return -1;
}
- is_signed = !!(field->flags | FIELD_IS_SIGNED);
+ is_signed = !!(field->flags & FIELD_IS_SIGNED);
if (should_be_signed && !is_signed) {
pr_debug("%s: \"%s\" signedness(%d) is wrong, should be %d\n",
evsel->name, name, is_signed, should_be_signed);
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index ab36aa5..a11f676 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -2988,7 +2988,7 @@
if (ev == NULL)
return -ENOMEM;
- strncpy(ev->data, evsel->unit, size);
+ strlcpy(ev->data, evsel->unit, size + 1);
err = process(tool, (union perf_event *)ev, NULL, NULL);
free(ev);
return err;
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index 436b647..b9507a8 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -414,7 +414,7 @@
if (target && build_id_cache__cached(target)) {
/* This is a cached buildid */
- strncpy(sbuildid, target, SBUILD_ID_SIZE);
+ strlcpy(sbuildid, target, SBUILD_ID_SIZE);
dir_name = build_id_cache__linkname(sbuildid, NULL, 0);
goto found;
}
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
index 046a485..ff32ca1 100644
--- a/tools/perf/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw.c
@@ -231,7 +231,7 @@
err = dwfl_getthread_frames(ui->dwfl, thread->tid, frame_callback, ui);
- if (err && !ui->max_stack)
+ if (err && ui->max_stack != max_stack)
err = 0;
/*
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 4f2a2df..60de4c3 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -2900,8 +2900,10 @@
if (ops->init)
ops->init(dev);
+ kvm_get_kvm(kvm);
ret = anon_inode_getfd(ops->name, &kvm_device_fops, dev, O_RDWR | O_CLOEXEC);
if (ret < 0) {
+ kvm_put_kvm(kvm);
mutex_lock(&kvm->lock);
list_del(&dev->vm_node);
mutex_unlock(&kvm->lock);
@@ -2909,7 +2911,6 @@
return ret;
}
- kvm_get_kvm(kvm);
cd->fd = ret;
return 0;
}