diff options
72 files changed, 778 insertions, 348 deletions
diff --git a/Documentation/networking/index.rst b/Documentation/networking/index.rst index 66e620866245..7d4b15977d61 100644 --- a/Documentation/networking/index.rst +++ b/Documentation/networking/index.rst @@ -9,6 +9,7 @@ Contents:     batman-adv     kapi     z8530book +   msg_zerocopy  .. only::  subproject @@ -16,4 +17,3 @@ Contents:     =======     * :ref:`genindex` - diff --git a/Documentation/networking/msg_zerocopy.rst b/Documentation/networking/msg_zerocopy.rst index 77f6d7e25cfd..291a01264967 100644 --- a/Documentation/networking/msg_zerocopy.rst +++ b/Documentation/networking/msg_zerocopy.rst @@ -72,6 +72,10 @@ this flag, a process must first signal intent by setting a socket option:  	if (setsockopt(fd, SOL_SOCKET, SO_ZEROCOPY, &one, sizeof(one)))  		error(1, errno, "setsockopt zerocopy"); +Setting the socket option only works when the socket is in its initial +(TCP_CLOSED) state.  Trying to set the option for a socket returned by accept(), +for example, will lead to an EBUSY error. In this case, the option should be set +to the listening socket and it will be inherited by the accepted sockets.  Transmission  ------------ diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S index c7ed26029cbb..e68e6e04063a 100644 --- a/arch/mips/kernel/cps-vec.S +++ b/arch/mips/kernel/cps-vec.S @@ -235,6 +235,7 @@ LEAF(mips_cps_core_init)  	has_mt	t0, 3f  	.set	push +	.set	MIPS_ISA_LEVEL_RAW  	.set	mt  	/* Only allow 1 TC per VPE to execute... */ @@ -388,6 +389,7 @@ LEAF(mips_cps_boot_vpes)  #elif defined(CONFIG_MIPS_MT)  	.set	push +	.set	MIPS_ISA_LEVEL_RAW  	.set	mt  	/* If the core doesn't support MT then return */ diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 45d0b6b037ee..57028d49c202 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -705,6 +705,18 @@ int mips_set_process_fp_mode(struct task_struct *task, unsigned int value)  	struct task_struct *t;  	int max_users; +	/* If nothing to change, return right away, successfully.  */ +	if (value == mips_get_process_fp_mode(task)) +		return 0; + +	/* Only accept a mode change if 64-bit FP enabled for o32.  */ +	if (!IS_ENABLED(CONFIG_MIPS_O32_FP64_SUPPORT)) +		return -EOPNOTSUPP; + +	/* And only for o32 tasks.  */ +	if (IS_ENABLED(CONFIG_64BIT) && !test_thread_flag(TIF_32BIT_REGS)) +		return -EOPNOTSUPP; +  	/* Check the value is valid */  	if (value & ~known_bits)  		return -EOPNOTSUPP; diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index efbd8df8b665..0b23b1ad99e6 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -419,63 +419,160 @@ static int gpr64_set(struct task_struct *target,  #endif /* CONFIG_64BIT */ +/* + * Copy the floating-point context to the supplied NT_PRFPREG buffer, + * !CONFIG_CPU_HAS_MSA variant.  FP context's general register slots + * correspond 1:1 to buffer slots.  Only general registers are copied. + */ +static int fpr_get_fpa(struct task_struct *target, +		       unsigned int *pos, unsigned int *count, +		       void **kbuf, void __user **ubuf) +{ +	return user_regset_copyout(pos, count, kbuf, ubuf, +				   &target->thread.fpu, +				   0, NUM_FPU_REGS * sizeof(elf_fpreg_t)); +} + +/* + * Copy the floating-point context to the supplied NT_PRFPREG buffer, + * CONFIG_CPU_HAS_MSA variant.  Only lower 64 bits of FP context's + * general register slots are copied to buffer slots.  Only general + * registers are copied. + */ +static int fpr_get_msa(struct task_struct *target, +		       unsigned int *pos, unsigned int *count, +		       void **kbuf, void __user **ubuf) +{ +	unsigned int i; +	u64 fpr_val; +	int err; + +	BUILD_BUG_ON(sizeof(fpr_val) != sizeof(elf_fpreg_t)); +	for (i = 0; i < NUM_FPU_REGS; i++) { +		fpr_val = get_fpr64(&target->thread.fpu.fpr[i], 0); +		err = user_regset_copyout(pos, count, kbuf, ubuf, +					  &fpr_val, i * sizeof(elf_fpreg_t), +					  (i + 1) * sizeof(elf_fpreg_t)); +		if (err) +			return err; +	} + +	return 0; +} + +/* + * Copy the floating-point context to the supplied NT_PRFPREG buffer. + * Choose the appropriate helper for general registers, and then copy + * the FCSR register separately. + */  static int fpr_get(struct task_struct *target,  		   const struct user_regset *regset,  		   unsigned int pos, unsigned int count,  		   void *kbuf, void __user *ubuf)  { -	unsigned i; +	const int fcr31_pos = NUM_FPU_REGS * sizeof(elf_fpreg_t);  	int err; -	u64 fpr_val; -	/* XXX fcr31  */ +	if (sizeof(target->thread.fpu.fpr[0]) == sizeof(elf_fpreg_t)) +		err = fpr_get_fpa(target, &pos, &count, &kbuf, &ubuf); +	else +		err = fpr_get_msa(target, &pos, &count, &kbuf, &ubuf); +	if (err) +		return err; -	if (sizeof(target->thread.fpu.fpr[i]) == sizeof(elf_fpreg_t)) -		return user_regset_copyout(&pos, &count, &kbuf, &ubuf, -					   &target->thread.fpu, -					   0, sizeof(elf_fpregset_t)); +	err = user_regset_copyout(&pos, &count, &kbuf, &ubuf, +				  &target->thread.fpu.fcr31, +				  fcr31_pos, fcr31_pos + sizeof(u32)); -	for (i = 0; i < NUM_FPU_REGS; i++) { -		fpr_val = get_fpr64(&target->thread.fpu.fpr[i], 0); -		err = user_regset_copyout(&pos, &count, &kbuf, &ubuf, -					  &fpr_val, i * sizeof(elf_fpreg_t), -					  (i + 1) * sizeof(elf_fpreg_t)); +	return err; +} + +/* + * Copy the supplied NT_PRFPREG buffer to the floating-point context, + * !CONFIG_CPU_HAS_MSA variant.   Buffer slots correspond 1:1 to FP + * context's general register slots.  Only general registers are copied. + */ +static int fpr_set_fpa(struct task_struct *target, +		       unsigned int *pos, unsigned int *count, +		       const void **kbuf, const void __user **ubuf) +{ +	return user_regset_copyin(pos, count, kbuf, ubuf, +				  &target->thread.fpu, +				  0, NUM_FPU_REGS * sizeof(elf_fpreg_t)); +} + +/* + * Copy the supplied NT_PRFPREG buffer to the floating-point context, + * CONFIG_CPU_HAS_MSA variant.  Buffer slots are copied to lower 64 + * bits only of FP context's general register slots.  Only general + * registers are copied. + */ +static int fpr_set_msa(struct task_struct *target, +		       unsigned int *pos, unsigned int *count, +		       const void **kbuf, const void __user **ubuf) +{ +	unsigned int i; +	u64 fpr_val; +	int err; + +	BUILD_BUG_ON(sizeof(fpr_val) != sizeof(elf_fpreg_t)); +	for (i = 0; i < NUM_FPU_REGS && *count > 0; i++) { +		err = user_regset_copyin(pos, count, kbuf, ubuf, +					 &fpr_val, i * sizeof(elf_fpreg_t), +					 (i + 1) * sizeof(elf_fpreg_t));  		if (err)  			return err; +		set_fpr64(&target->thread.fpu.fpr[i], 0, fpr_val);  	}  	return 0;  } +/* + * Copy the supplied NT_PRFPREG buffer to the floating-point context. + * Choose the appropriate helper for general registers, and then copy + * the FCSR register separately. + * + * We optimize for the case where `count % sizeof(elf_fpreg_t) == 0', + * which is supposed to have been guaranteed by the kernel before + * calling us, e.g. in `ptrace_regset'.  We enforce that requirement, + * so that we can safely avoid preinitializing temporaries for + * partial register writes. + */  static int fpr_set(struct task_struct *target,  		   const struct user_regset *regset,  		   unsigned int pos, unsigned int count,  		   const void *kbuf, const void __user *ubuf)  { -	unsigned i; +	const int fcr31_pos = NUM_FPU_REGS * sizeof(elf_fpreg_t); +	u32 fcr31;  	int err; -	u64 fpr_val; -	/* XXX fcr31  */ +	BUG_ON(count % sizeof(elf_fpreg_t)); + +	if (pos + count > sizeof(elf_fpregset_t)) +		return -EIO;  	init_fp_ctx(target); -	if (sizeof(target->thread.fpu.fpr[i]) == sizeof(elf_fpreg_t)) -		return user_regset_copyin(&pos, &count, &kbuf, &ubuf, -					  &target->thread.fpu, -					  0, sizeof(elf_fpregset_t)); +	if (sizeof(target->thread.fpu.fpr[0]) == sizeof(elf_fpreg_t)) +		err = fpr_set_fpa(target, &pos, &count, &kbuf, &ubuf); +	else +		err = fpr_set_msa(target, &pos, &count, &kbuf, &ubuf); +	if (err) +		return err; -	BUILD_BUG_ON(sizeof(fpr_val) != sizeof(elf_fpreg_t)); -	for (i = 0; i < NUM_FPU_REGS && count >= sizeof(elf_fpreg_t); i++) { +	if (count > 0) {  		err = user_regset_copyin(&pos, &count, &kbuf, &ubuf, -					 &fpr_val, i * sizeof(elf_fpreg_t), -					 (i + 1) * sizeof(elf_fpreg_t)); +					 &fcr31, +					 fcr31_pos, fcr31_pos + sizeof(u32));  		if (err)  			return err; -		set_fpr64(&target->thread.fpu.fpr[i], 0, fpr_val); + +		ptrace_setfcr31(target, fcr31);  	} -	return 0; +	return err;  }  enum mips_regset { diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig index e69de29bb2d1..47dacf06c679 100644 --- a/arch/riscv/configs/defconfig +++ b/arch/riscv/configs/defconfig @@ -0,0 +1,75 @@ +CONFIG_SMP=y +CONFIG_PCI=y +CONFIG_PCIE_XILINX=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_CGROUPS=y +CONFIG_CGROUP_SCHED=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_CGROUP_BPF=y +CONFIG_NAMESPACES=y +CONFIG_USER_NS=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_EXPERT=y +CONFIG_CHECKPOINT_RESTORE=y +CONFIG_BPF_SYSCALL=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +CONFIG_NETLINK_DIAG=y +CONFIG_DEVTMPFS=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_VIRTIO_BLK=y +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_DEV_SR=y +CONFIG_ATA=y +CONFIG_SATA_AHCI=y +CONFIG_SATA_AHCI_PLATFORM=y +CONFIG_NETDEVICES=y +CONFIG_VIRTIO_NET=y +CONFIG_MACB=y +CONFIG_E1000E=y +CONFIG_R8169=y +CONFIG_MICROSEMI_PHY=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_OF_PLATFORM=y +# CONFIG_PTP_1588_CLOCK is not set +CONFIG_DRM=y +CONFIG_DRM_RADEON=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_USB=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_PLATFORM=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_HCD_PLATFORM=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PLATFORM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_UAS=y +CONFIG_VIRTIO_MMIO=y +CONFIG_RAS=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_AUTOFS4_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_NFS_FS=y +CONFIG_NFS_V4=y +CONFIG_NFS_V4_1=y +CONFIG_NFS_V4_2=y +CONFIG_ROOT_NFS=y +# CONFIG_RCU_TRACE is not set +CONFIG_CRYPTO_USER_API_HASH=y diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h index 0d64bc9f4f91..3c7a2c97e377 100644 --- a/arch/riscv/include/asm/csr.h +++ b/arch/riscv/include/asm/csr.h @@ -17,10 +17,10 @@  #include <linux/const.h>  /* Status register flags */ -#define SR_IE   _AC(0x00000002, UL) /* Interrupt Enable */ -#define SR_PIE  _AC(0x00000020, UL) /* Previous IE */ -#define SR_PS   _AC(0x00000100, UL) /* Previously Supervisor */ -#define SR_SUM  _AC(0x00040000, UL) /* Supervisor may access User Memory */ +#define SR_SIE	_AC(0x00000002, UL) /* Supervisor Interrupt Enable */ +#define SR_SPIE	_AC(0x00000020, UL) /* Previous Supervisor IE */ +#define SR_SPP	_AC(0x00000100, UL) /* Previously Supervisor */ +#define SR_SUM	_AC(0x00040000, UL) /* Supervisor may access User Memory */  #define SR_FS           _AC(0x00006000, UL) /* Floating-point Status */  #define SR_FS_OFF       _AC(0x00000000, UL) diff --git a/arch/riscv/include/asm/io.h b/arch/riscv/include/asm/io.h index a82ce599b639..b269451e7e85 100644 --- a/arch/riscv/include/asm/io.h +++ b/arch/riscv/include/asm/io.h @@ -21,8 +21,6 @@  #include <linux/types.h> -#ifdef CONFIG_MMU -  extern void __iomem *ioremap(phys_addr_t offset, unsigned long size);  /* @@ -36,8 +34,6 @@ extern void __iomem *ioremap(phys_addr_t offset, unsigned long size);  extern void iounmap(volatile void __iomem *addr); -#endif /* CONFIG_MMU */ -  /* Generic IO read/write.  These perform native-endian accesses. */  #define __raw_writeb __raw_writeb  static inline void __raw_writeb(u8 val, volatile void __iomem *addr) diff --git a/arch/riscv/include/asm/irqflags.h b/arch/riscv/include/asm/irqflags.h index 6fdc860d7f84..07a3c6d5706f 100644 --- a/arch/riscv/include/asm/irqflags.h +++ b/arch/riscv/include/asm/irqflags.h @@ -27,25 +27,25 @@ static inline unsigned long arch_local_save_flags(void)  /* unconditionally enable interrupts */  static inline void arch_local_irq_enable(void)  { -	csr_set(sstatus, SR_IE); +	csr_set(sstatus, SR_SIE);  }  /* unconditionally disable interrupts */  static inline void arch_local_irq_disable(void)  { -	csr_clear(sstatus, SR_IE); +	csr_clear(sstatus, SR_SIE);  }  /* get status and disable interrupts */  static inline unsigned long arch_local_irq_save(void)  { -	return csr_read_clear(sstatus, SR_IE); +	return csr_read_clear(sstatus, SR_SIE);  }  /* test flags */  static inline int arch_irqs_disabled_flags(unsigned long flags)  { -	return !(flags & SR_IE); +	return !(flags & SR_SIE);  }  /* test hardware interrupt enable bit */ @@ -57,7 +57,7 @@ static inline int arch_irqs_disabled(void)  /* set interrupt enabled status */  static inline void arch_local_irq_restore(unsigned long flags)  { -	csr_set(sstatus, flags & SR_IE); +	csr_set(sstatus, flags & SR_SIE);  }  #endif /* _ASM_RISCV_IRQFLAGS_H */ diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h index 2cbd92ed1629..16301966d65b 100644 --- a/arch/riscv/include/asm/pgtable.h +++ b/arch/riscv/include/asm/pgtable.h @@ -20,8 +20,6 @@  #ifndef __ASSEMBLY__ -#ifdef CONFIG_MMU -  /* Page Upper Directory not used in RISC-V */  #include <asm-generic/pgtable-nopud.h>  #include <asm/page.h> @@ -413,8 +411,6 @@ static inline void pgtable_cache_init(void)  	/* No page table caches to initialize */  } -#endif /* CONFIG_MMU */ -  #define VMALLOC_SIZE     (KERN_VIRT_SIZE >> 1)  #define VMALLOC_END      (PAGE_OFFSET - 1)  #define VMALLOC_START    (PAGE_OFFSET - VMALLOC_SIZE) diff --git a/arch/riscv/include/asm/ptrace.h b/arch/riscv/include/asm/ptrace.h index 93b8956e25e4..2c5df945d43c 100644 --- a/arch/riscv/include/asm/ptrace.h +++ b/arch/riscv/include/asm/ptrace.h @@ -66,7 +66,7 @@ struct pt_regs {  #define REG_FMT "%08lx"  #endif -#define user_mode(regs) (((regs)->sstatus & SR_PS) == 0) +#define user_mode(regs) (((regs)->sstatus & SR_SPP) == 0)  /* Helpers for working with the instruction pointer */ diff --git a/arch/riscv/include/asm/tlbflush.h b/arch/riscv/include/asm/tlbflush.h index 715b0f10af58..7b9c24ebdf52 100644 --- a/arch/riscv/include/asm/tlbflush.h +++ b/arch/riscv/include/asm/tlbflush.h @@ -15,8 +15,6 @@  #ifndef _ASM_RISCV_TLBFLUSH_H  #define _ASM_RISCV_TLBFLUSH_H -#ifdef CONFIG_MMU -  #include <linux/mm_types.h>  /* @@ -64,6 +62,4 @@ static inline void flush_tlb_kernel_range(unsigned long start,  	flush_tlb_all();  } -#endif /* CONFIG_MMU */ -  #endif /* _ASM_RISCV_TLBFLUSH_H */ diff --git a/arch/riscv/include/asm/uaccess.h b/arch/riscv/include/asm/uaccess.h index 27b90d64814b..14b0b22fb578 100644 --- a/arch/riscv/include/asm/uaccess.h +++ b/arch/riscv/include/asm/uaccess.h @@ -127,7 +127,6 @@ extern int fixup_exception(struct pt_regs *state);   * call.   */ -#ifdef CONFIG_MMU  #define __get_user_asm(insn, x, ptr, err)			\  do {								\  	uintptr_t __tmp;					\ @@ -153,13 +152,11 @@ do {								\  	__disable_user_access();				\  	(x) = __x;						\  } while (0) -#endif /* CONFIG_MMU */  #ifdef CONFIG_64BIT  #define __get_user_8(x, ptr, err) \  	__get_user_asm("ld", x, ptr, err)  #else /* !CONFIG_64BIT */ -#ifdef CONFIG_MMU  #define __get_user_8(x, ptr, err)				\  do {								\  	u32 __user *__ptr = (u32 __user *)(ptr);		\ @@ -193,7 +190,6 @@ do {								\  	(x) = (__typeof__(x))((__typeof__((x)-(x)))(		\  		(((u64)__hi << 32) | __lo)));			\  } while (0) -#endif /* CONFIG_MMU */  #endif /* CONFIG_64BIT */ @@ -267,8 +263,6 @@ do {								\  		((x) = 0, -EFAULT);				\  }) - -#ifdef CONFIG_MMU  #define __put_user_asm(insn, x, ptr, err)			\  do {								\  	uintptr_t __tmp;					\ @@ -292,14 +286,11 @@ do {								\  		: "rJ" (__x), "i" (-EFAULT));			\  	__disable_user_access();				\  } while (0) -#endif /* CONFIG_MMU */ -  #ifdef CONFIG_64BIT  #define __put_user_8(x, ptr, err) \  	__put_user_asm("sd", x, ptr, err)  #else /* !CONFIG_64BIT */ -#ifdef CONFIG_MMU  #define __put_user_8(x, ptr, err)				\  do {								\  	u32 __user *__ptr = (u32 __user *)(ptr);		\ @@ -329,7 +320,6 @@ do {								\  		: "rJ" (__x), "rJ" (__x >> 32), "i" (-EFAULT));	\  	__disable_user_access();				\  } while (0) -#endif /* CONFIG_MMU */  #endif /* CONFIG_64BIT */ @@ -438,7 +428,6 @@ unsigned long __must_check clear_user(void __user *to, unsigned long n)   * will set "err" to -EFAULT, while successful accesses return the previous   * value.   */ -#ifdef CONFIG_MMU  #define __cmpxchg_user(ptr, old, new, err, size, lrb, scb)	\  ({								\  	__typeof__(ptr) __ptr = (ptr);				\ @@ -508,6 +497,5 @@ unsigned long __must_check clear_user(void __user *to, unsigned long n)  	(err) = __err;						\  	__ret;							\  }) -#endif /* CONFIG_MMU */  #endif /* _ASM_RISCV_UACCESS_H */ diff --git a/arch/riscv/include/asm/unistd.h b/arch/riscv/include/asm/unistd.h index 9f250ed007cd..2f704a5c4196 100644 --- a/arch/riscv/include/asm/unistd.h +++ b/arch/riscv/include/asm/unistd.h @@ -14,3 +14,4 @@  #define __ARCH_HAVE_MMU  #define __ARCH_WANT_SYS_CLONE  #include <uapi/asm/unistd.h> +#include <uapi/asm/syscalls.h> diff --git a/arch/riscv/include/asm/vdso-syscalls.h b/arch/riscv/include/asm/vdso-syscalls.h deleted file mode 100644 index a2ccf1894929..000000000000 --- a/arch/riscv/include/asm/vdso-syscalls.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2017 SiFive - * - * 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program.  If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef _ASM_RISCV_VDSO_SYSCALLS_H -#define _ASM_RISCV_VDSO_SYSCALLS_H - -#ifdef CONFIG_SMP - -/* These syscalls are only used by the vDSO and are not in the uapi. */ -#define __NR_riscv_flush_icache (__NR_arch_specific_syscall + 15) -__SYSCALL(__NR_riscv_flush_icache, sys_riscv_flush_icache) - -#endif - -#endif /* _ASM_RISCV_VDSO_H */ diff --git a/arch/riscv/include/uapi/asm/syscalls.h b/arch/riscv/include/uapi/asm/syscalls.h new file mode 100644 index 000000000000..818655b0d535 --- /dev/null +++ b/arch/riscv/include/uapi/asm/syscalls.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2017 SiFive + */ + +#ifndef _ASM__UAPI__SYSCALLS_H +#define _ASM__UAPI__SYSCALLS_H + +/* + * Allows the instruction cache to be flushed from userspace.  Despite RISC-V + * having a direct 'fence.i' instruction available to userspace (which we + * can't trap!), that's not actually viable when running on Linux because the + * kernel might schedule a process on another hart.  There is no way for + * userspace to handle this without invoking the kernel (as it doesn't know the + * thread->hart mappings), so we've defined a RISC-V specific system call to + * flush the instruction cache. + * + * __NR_riscv_flush_icache is defined to flush the instruction cache over an + * address range, with the flush applying to either all threads or just the + * caller.  We don't currently do anything with the address range, that's just + * in there for forwards compatibility. + */ +#define __NR_riscv_flush_icache (__NR_arch_specific_syscall + 15) +__SYSCALL(__NR_riscv_flush_icache, sys_riscv_flush_icache) + +#endif diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S index 20ee86f782a9..7404ec222406 100644 --- a/arch/riscv/kernel/entry.S +++ b/arch/riscv/kernel/entry.S @@ -196,7 +196,7 @@ handle_syscall:  	addi s2, s2, 0x4  	REG_S s2, PT_SEPC(sp)  	/* System calls run with interrupts enabled */ -	csrs sstatus, SR_IE +	csrs sstatus, SR_SIE  	/* Trace syscalls, but only if requested by the user. */  	REG_L t0, TASK_TI_FLAGS(tp)  	andi t0, t0, _TIF_SYSCALL_TRACE @@ -224,8 +224,8 @@ ret_from_syscall:  ret_from_exception:  	REG_L s0, PT_SSTATUS(sp) -	csrc sstatus, SR_IE -	andi s0, s0, SR_PS +	csrc sstatus, SR_SIE +	andi s0, s0, SR_SPP  	bnez s0, restore_all  resume_userspace: @@ -255,7 +255,7 @@ work_pending:  	bnez s1, work_resched  work_notifysig:  	/* Handle pending signals and notify-resume requests */ -	csrs sstatus, SR_IE /* Enable interrupts for do_notify_resume() */ +	csrs sstatus, SR_SIE /* Enable interrupts for do_notify_resume() */  	move a0, sp /* pt_regs */  	move a1, s0 /* current_thread_info->flags */  	tail do_notify_resume diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c index 0d90dcc1fbd3..d74d4adf2d54 100644 --- a/arch/riscv/kernel/process.c +++ b/arch/riscv/kernel/process.c @@ -76,7 +76,7 @@ void show_regs(struct pt_regs *regs)  void start_thread(struct pt_regs *regs, unsigned long pc,  	unsigned long sp)  { -	regs->sstatus = SR_PIE /* User mode, irqs on */ | SR_FS_INITIAL; +	regs->sstatus = SR_SPIE /* User mode, irqs on */ | SR_FS_INITIAL;  	regs->sepc = pc;  	regs->sp = sp;  	set_fs(USER_DS); @@ -110,7 +110,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,  		const register unsigned long gp __asm__ ("gp");  		memset(childregs, 0, sizeof(struct pt_regs));  		childregs->gp = gp; -		childregs->sstatus = SR_PS | SR_PIE; /* Supervisor, irqs on */ +		childregs->sstatus = SR_SPP | SR_SPIE; /* Supervisor, irqs on */  		p->thread.ra = (unsigned long)ret_from_kernel_thread;  		p->thread.s[0] = usp; /* fn */ diff --git a/arch/riscv/kernel/syscall_table.c b/arch/riscv/kernel/syscall_table.c index a5bd6401f95e..ade52b903a43 100644 --- a/arch/riscv/kernel/syscall_table.c +++ b/arch/riscv/kernel/syscall_table.c @@ -23,5 +23,4 @@  void *sys_call_table[__NR_syscalls] = {  	[0 ... __NR_syscalls - 1] = sys_ni_syscall,  #include <asm/unistd.h> -#include <asm/vdso-syscalls.h>  }; diff --git a/arch/riscv/kernel/vdso/flush_icache.S b/arch/riscv/kernel/vdso/flush_icache.S index b0fbad74e873..023e4d4aef58 100644 --- a/arch/riscv/kernel/vdso/flush_icache.S +++ b/arch/riscv/kernel/vdso/flush_icache.S @@ -13,7 +13,6 @@  #include <linux/linkage.h>  #include <asm/unistd.h> -#include <asm/vdso-syscalls.h>  	.text  /* int __vdso_flush_icache(void *start, void *end, unsigned long flags); */ diff --git a/arch/riscv/mm/fault.c b/arch/riscv/mm/fault.c index df2ca3c65048..0713f3c67ab4 100644 --- a/arch/riscv/mm/fault.c +++ b/arch/riscv/mm/fault.c @@ -63,7 +63,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs)  		goto vmalloc_fault;  	/* Enable interrupts if they were enabled in the parent context. */ -	if (likely(regs->sstatus & SR_PIE)) +	if (likely(regs->sstatus & SR_SPIE))  		local_irq_enable();  	/* diff --git a/arch/sh/boards/mach-se/770x/setup.c b/arch/sh/boards/mach-se/770x/setup.c index 77c35350ee77..412326d59e6f 100644 --- a/arch/sh/boards/mach-se/770x/setup.c +++ b/arch/sh/boards/mach-se/770x/setup.c @@ -9,6 +9,7 @@   */  #include <linux/init.h>  #include <linux/platform_device.h> +#include <linux/sh_eth.h>  #include <mach-se/mach/se.h>  #include <mach-se/mach/mrshpc.h>  #include <asm/machvec.h> @@ -115,13 +116,23 @@ static struct platform_device heartbeat_device = {  #if defined(CONFIG_CPU_SUBTYPE_SH7710) ||\  	defined(CONFIG_CPU_SUBTYPE_SH7712)  /* SH771X Ethernet driver */ +static struct sh_eth_plat_data sh_eth_plat = { +	.phy = PHY_ID, +	.phy_interface = PHY_INTERFACE_MODE_MII, +}; +  static struct resource sh_eth0_resources[] = {  	[0] = {  		.start = SH_ETH0_BASE, -		.end = SH_ETH0_BASE + 0x1B8, +		.end = SH_ETH0_BASE + 0x1B8 - 1,  		.flags = IORESOURCE_MEM,  	},  	[1] = { +		.start = SH_TSU_BASE, +		.end = SH_TSU_BASE + 0x200 - 1, +		.flags = IORESOURCE_MEM, +	}, +	[2] = {  		.start = SH_ETH0_IRQ,  		.end = SH_ETH0_IRQ,  		.flags = IORESOURCE_IRQ, @@ -132,7 +143,7 @@ static struct platform_device sh_eth0_device = {  	.name = "sh771x-ether",  	.id = 0,  	.dev = { -		.platform_data = PHY_ID, +		.platform_data = &sh_eth_plat,  	},  	.num_resources = ARRAY_SIZE(sh_eth0_resources),  	.resource = sh_eth0_resources, @@ -141,10 +152,15 @@ static struct platform_device sh_eth0_device = {  static struct resource sh_eth1_resources[] = {  	[0] = {  		.start = SH_ETH1_BASE, -		.end = SH_ETH1_BASE + 0x1B8, +		.end = SH_ETH1_BASE + 0x1B8 - 1,  		.flags = IORESOURCE_MEM,  	},  	[1] = { +		.start = SH_TSU_BASE, +		.end = SH_TSU_BASE + 0x200 - 1, +		.flags = IORESOURCE_MEM, +	}, +	[2] = {  		.start = SH_ETH1_IRQ,  		.end = SH_ETH1_IRQ,  		.flags = IORESOURCE_IRQ, @@ -155,7 +171,7 @@ static struct platform_device sh_eth1_device = {  	.name = "sh771x-ether",  	.id = 1,  	.dev = { -		.platform_data = PHY_ID, +		.platform_data = &sh_eth_plat,  	},  	.num_resources = ARRAY_SIZE(sh_eth1_resources),  	.resource = sh_eth1_resources, diff --git a/arch/sh/include/mach-se/mach/se.h b/arch/sh/include/mach-se/mach/se.h index 4246ef9b07a3..aa83fe1ff0b1 100644 --- a/arch/sh/include/mach-se/mach/se.h +++ b/arch/sh/include/mach-se/mach/se.h @@ -100,6 +100,7 @@  /* Base address */  #define SH_ETH0_BASE 0xA7000000  #define SH_ETH1_BASE 0xA7000400 +#define SH_TSU_BASE  0xA7000800  /* PHY ID */  #if defined(CONFIG_CPU_SUBTYPE_SH7710)  # define PHY_ID 0x00 diff --git a/block/blk-core.c b/block/blk-core.c index b8881750a3ac..3ba4326a63b5 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -562,6 +562,13 @@ static void __blk_drain_queue(struct request_queue *q, bool drain_all)  	}  } +void blk_drain_queue(struct request_queue *q) +{ +	spin_lock_irq(q->queue_lock); +	__blk_drain_queue(q, true); +	spin_unlock_irq(q->queue_lock); +} +  /**   * blk_queue_bypass_start - enter queue bypass mode   * @q: queue of interest @@ -689,8 +696,6 @@ void blk_cleanup_queue(struct request_queue *q)  	 */  	blk_freeze_queue(q);  	spin_lock_irq(lock); -	if (!q->mq_ops) -		__blk_drain_queue(q, true);  	queue_flag_set(QUEUE_FLAG_DEAD, q);  	spin_unlock_irq(lock); diff --git a/block/blk-mq.c b/block/blk-mq.c index 11097477eeab..3d3797327491 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -161,6 +161,8 @@ void blk_freeze_queue(struct request_queue *q)  	 * exported to drivers as the only user for unfreeze is blk_mq.  	 */  	blk_freeze_queue_start(q); +	if (!q->mq_ops) +		blk_drain_queue(q);  	blk_mq_freeze_queue_wait(q);  } diff --git a/block/blk.h b/block/blk.h index 3f1446937aec..442098aa9463 100644 --- a/block/blk.h +++ b/block/blk.h @@ -330,4 +330,6 @@ static inline void blk_queue_bounce(struct request_queue *q, struct bio **bio)  }  #endif /* CONFIG_BOUNCE */ +extern void blk_drain_queue(struct request_queue *q); +  #endif /* BLK_INTERNAL_H */ diff --git a/drivers/block/loop.c b/drivers/block/loop.c index bc8e61506968..d5fe720cf149 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1581,9 +1581,8 @@ out:  	return err;  } -static void lo_release(struct gendisk *disk, fmode_t mode) +static void __lo_release(struct loop_device *lo)  { -	struct loop_device *lo = disk->private_data;  	int err;  	if (atomic_dec_return(&lo->lo_refcnt)) @@ -1610,6 +1609,13 @@ static void lo_release(struct gendisk *disk, fmode_t mode)  	mutex_unlock(&lo->lo_ctl_mutex);  } +static void lo_release(struct gendisk *disk, fmode_t mode) +{ +	mutex_lock(&loop_index_mutex); +	__lo_release(disk->private_data); +	mutex_unlock(&loop_index_mutex); +} +  static const struct block_device_operations lo_fops = {  	.owner =	THIS_MODULE,  	.open =		lo_open, diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 38fc5f397fde..cc93522a6d41 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -3047,13 +3047,21 @@ static void format_lock_cookie(struct rbd_device *rbd_dev, char *buf)  	mutex_unlock(&rbd_dev->watch_mutex);  } +static void __rbd_lock(struct rbd_device *rbd_dev, const char *cookie) +{ +	struct rbd_client_id cid = rbd_get_cid(rbd_dev); + +	strcpy(rbd_dev->lock_cookie, cookie); +	rbd_set_owner_cid(rbd_dev, &cid); +	queue_work(rbd_dev->task_wq, &rbd_dev->acquired_lock_work); +} +  /*   * lock_rwsem must be held for write   */  static int rbd_lock(struct rbd_device *rbd_dev)  {  	struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc; -	struct rbd_client_id cid = rbd_get_cid(rbd_dev);  	char cookie[32];  	int ret; @@ -3068,9 +3076,7 @@ static int rbd_lock(struct rbd_device *rbd_dev)  		return ret;  	rbd_dev->lock_state = RBD_LOCK_STATE_LOCKED; -	strcpy(rbd_dev->lock_cookie, cookie); -	rbd_set_owner_cid(rbd_dev, &cid); -	queue_work(rbd_dev->task_wq, &rbd_dev->acquired_lock_work); +	__rbd_lock(rbd_dev, cookie);  	return 0;  } @@ -3856,7 +3862,7 @@ static void rbd_reacquire_lock(struct rbd_device *rbd_dev)  			queue_delayed_work(rbd_dev->task_wq,  					   &rbd_dev->lock_dwork, 0);  	} else { -		strcpy(rbd_dev->lock_cookie, cookie); +		__rbd_lock(rbd_dev, cookie);  	}  } @@ -4381,7 +4387,7 @@ static int rbd_init_disk(struct rbd_device *rbd_dev)  	segment_size = rbd_obj_bytes(&rbd_dev->header);  	blk_queue_max_hw_sectors(q, segment_size / SECTOR_SIZE);  	q->limits.max_sectors = queue_max_hw_sectors(q); -	blk_queue_max_segments(q, segment_size / SECTOR_SIZE); +	blk_queue_max_segments(q, USHRT_MAX);  	blk_queue_max_segment_size(q, segment_size);  	blk_queue_io_min(q, segment_size);  	blk_queue_io_opt(q, segment_size); diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 44332b793718..14532d9576e4 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -2893,6 +2893,27 @@ void gpiod_set_raw_value(struct gpio_desc *desc, int value)  EXPORT_SYMBOL_GPL(gpiod_set_raw_value);  /** + * gpiod_set_value_nocheck() - set a GPIO line value without checking + * @desc: the descriptor to set the value on + * @value: value to set + * + * This sets the value of a GPIO line backing a descriptor, applying + * different semantic quirks like active low and open drain/source + * handling. + */ +static void gpiod_set_value_nocheck(struct gpio_desc *desc, int value) +{ +	if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) +		value = !value; +	if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) +		gpio_set_open_drain_value_commit(desc, value); +	else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) +		gpio_set_open_source_value_commit(desc, value); +	else +		gpiod_set_raw_value_commit(desc, value); +} + +/**   * gpiod_set_value() - assign a gpio's value   * @desc: gpio whose value will be assigned   * @value: value to assign @@ -2906,16 +2927,8 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_value);  void gpiod_set_value(struct gpio_desc *desc, int value)  {  	VALIDATE_DESC_VOID(desc); -	/* Should be using gpiod_set_value_cansleep() */  	WARN_ON(desc->gdev->chip->can_sleep); -	if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) -		value = !value; -	if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) -		gpio_set_open_drain_value_commit(desc, value); -	else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) -		gpio_set_open_source_value_commit(desc, value); -	else -		gpiod_set_raw_value_commit(desc, value); +	gpiod_set_value_nocheck(desc, value);  }  EXPORT_SYMBOL_GPL(gpiod_set_value); @@ -3243,9 +3256,7 @@ void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)  {  	might_sleep_if(extra_checks);  	VALIDATE_DESC_VOID(desc); -	if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) -		value = !value; -	gpiod_set_raw_value_commit(desc, value); +	gpiod_set_value_nocheck(desc, value);  }  EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep); diff --git a/drivers/net/ethernet/freescale/gianfar_ptp.c b/drivers/net/ethernet/freescale/gianfar_ptp.c index 544114281ea7..9f8d4f8e57e3 100644 --- a/drivers/net/ethernet/freescale/gianfar_ptp.c +++ b/drivers/net/ethernet/freescale/gianfar_ptp.c @@ -319,11 +319,10 @@ static int ptp_gianfar_adjtime(struct ptp_clock_info *ptp, s64 delta)  	now = tmr_cnt_read(etsects);  	now += delta;  	tmr_cnt_write(etsects, now); +	set_fipers(etsects);  	spin_unlock_irqrestore(&etsects->lock, flags); -	set_fipers(etsects); -  	return 0;  } diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c index 23f7d828cf67..6ef20e5cc77d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci.c +++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c @@ -1643,7 +1643,12 @@ static int mlxsw_pci_sw_reset(struct mlxsw_pci *mlxsw_pci,  		return 0;  	} -	wmb(); /* reset needs to be written before we read control register */ +	/* Reset needs to be written before we read control register, and +	 * we must wait for the HW to become responsive once again +	 */ +	wmb(); +	msleep(MLXSW_PCI_SW_RESET_WAIT_MSECS); +  	end = jiffies + msecs_to_jiffies(MLXSW_PCI_SW_RESET_TIMEOUT_MSECS);  	do {  		u32 val = mlxsw_pci_read32(mlxsw_pci, FW_READY); diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h b/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h index a6441208e9d9..fb082ad21b00 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h +++ b/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h @@ -59,6 +59,7 @@  #define MLXSW_PCI_SW_RESET			0xF0010  #define MLXSW_PCI_SW_RESET_RST_BIT		BIT(0)  #define MLXSW_PCI_SW_RESET_TIMEOUT_MSECS	5000 +#define MLXSW_PCI_SW_RESET_WAIT_MSECS		100  #define MLXSW_PCI_FW_READY			0xA1844  #define MLXSW_PCI_FW_READY_MASK			0xFFFF  #define MLXSW_PCI_FW_READY_MAGIC		0x5E diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c index 273300b75a68..971f689dd833 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c @@ -178,7 +178,8 @@ mlxsw_sp_tclass_congestion_enable(struct mlxsw_sp_port *mlxsw_sp_port,  				  int tclass_num, u32 min, u32 max,  				  u32 probability, bool is_ecn)  { -	char cwtp_cmd[max_t(u8, MLXSW_REG_CWTP_LEN, MLXSW_REG_CWTPM_LEN)]; +	char cwtpm_cmd[MLXSW_REG_CWTPM_LEN]; +	char cwtp_cmd[MLXSW_REG_CWTP_LEN];  	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;  	int err; @@ -192,10 +193,10 @@ mlxsw_sp_tclass_congestion_enable(struct mlxsw_sp_port *mlxsw_sp_port,  	if (err)  		return err; -	mlxsw_reg_cwtpm_pack(cwtp_cmd, mlxsw_sp_port->local_port, tclass_num, +	mlxsw_reg_cwtpm_pack(cwtpm_cmd, mlxsw_sp_port->local_port, tclass_num,  			     MLXSW_REG_CWTP_DEFAULT_PROFILE, true, is_ecn); -	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(cwtpm), cwtp_cmd); +	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(cwtpm), cwtpm_cmd);  }  static int diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index caee147fce04..07e0587dc14e 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -568,6 +568,7 @@ nfp_net_aux_irq_request(struct nfp_net *nn, u32 ctrl_offset,  		return err;  	}  	nn_writeb(nn, ctrl_offset, entry->entry); +	nfp_net_irq_unmask(nn, entry->entry);  	return 0;  } @@ -582,6 +583,7 @@ static void nfp_net_aux_irq_free(struct nfp_net *nn, u32 ctrl_offset,  				 unsigned int vector_idx)  {  	nn_writeb(nn, ctrl_offset, 0xff); +	nn_pci_flush(nn);  	free_irq(nn->irq_entries[vector_idx].vector, nn);  } diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 5bed323f1100..ab5be6d2c691 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -384,6 +384,18 @@ static int wcn36xx_config(struct ieee80211_hw *hw, u32 changed)  		}  	} +	if (changed & IEEE80211_CONF_CHANGE_PS) { +		list_for_each_entry(tmp, &wcn->vif_list, list) { +			vif = wcn36xx_priv_to_vif(tmp); +			if (hw->conf.flags & IEEE80211_CONF_PS) { +				if (vif->bss_conf.ps) /* ps allowed ? */ +					wcn36xx_pmc_enter_bmps_state(wcn, vif); +			} else { +				wcn36xx_pmc_exit_bmps_state(wcn, vif); +			} +		} +	} +  	mutex_unlock(&wcn->conf_mutex);  	return 0; @@ -757,17 +769,6 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw,  		vif_priv->dtim_period = bss_conf->dtim_period;  	} -	if (changed & BSS_CHANGED_PS) { -		wcn36xx_dbg(WCN36XX_DBG_MAC, -			    "mac bss PS set %d\n", -			    bss_conf->ps); -		if (bss_conf->ps) { -			wcn36xx_pmc_enter_bmps_state(wcn, vif); -		} else { -			wcn36xx_pmc_exit_bmps_state(wcn, vif); -		} -	} -  	if (changed & BSS_CHANGED_BSSID) {  		wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss changed_bssid %pM\n",  			    bss_conf->bssid); diff --git a/drivers/net/wireless/ath/wcn36xx/pmc.c b/drivers/net/wireless/ath/wcn36xx/pmc.c index 589fe5f70971..1976b80c235f 100644 --- a/drivers/net/wireless/ath/wcn36xx/pmc.c +++ b/drivers/net/wireless/ath/wcn36xx/pmc.c @@ -45,8 +45,10 @@ int wcn36xx_pmc_exit_bmps_state(struct wcn36xx *wcn,  	struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);  	if (WCN36XX_BMPS != vif_priv->pw_state) { -		wcn36xx_err("Not in BMPS mode, no need to exit from BMPS mode!\n"); -		return -EINVAL; +		/* Unbalanced call or last BMPS enter failed */ +		wcn36xx_dbg(WCN36XX_DBG_PMC, +			    "Not in BMPS mode, no need to exit\n"); +		return -EALREADY;  	}  	wcn36xx_smd_exit_bmps(wcn, vif);  	vif_priv->pw_state = WCN36XX_FULL_POWER; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index d749abeca3ae..403e65c309d0 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -670,11 +670,15 @@ static inline u8 iwl_pcie_get_cmd_index(struct iwl_txq *q, u32 index)  	return index & (q->n_window - 1);  } -static inline void *iwl_pcie_get_tfd(struct iwl_trans_pcie *trans_pcie, +static inline void *iwl_pcie_get_tfd(struct iwl_trans *trans,  				     struct iwl_txq *txq, int idx)  { -	return txq->tfds + trans_pcie->tfd_size * iwl_pcie_get_cmd_index(txq, -									 idx); +	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + +	if (trans->cfg->use_tfh) +		idx = iwl_pcie_get_cmd_index(txq, idx); + +	return txq->tfds + trans_pcie->tfd_size * idx;  }  static inline void iwl_enable_rfkill_int(struct iwl_trans *trans) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 16b345f54ff0..6d0a907d5ba5 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -171,8 +171,6 @@ static void iwl_pcie_gen2_tfd_unmap(struct iwl_trans *trans,  static void iwl_pcie_gen2_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq)  { -	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); -  	/* rd_ptr is bounded by TFD_QUEUE_SIZE_MAX and  	 * idx is bounded by n_window  	 */ @@ -181,7 +179,7 @@ static void iwl_pcie_gen2_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq)  	lockdep_assert_held(&txq->lock);  	iwl_pcie_gen2_tfd_unmap(trans, &txq->entries[idx].meta, -				iwl_pcie_get_tfd(trans_pcie, txq, idx)); +				iwl_pcie_get_tfd(trans, txq, idx));  	/* free SKB */  	if (txq->entries) { @@ -364,11 +362,9 @@ struct iwl_tfh_tfd *iwl_pcie_gen2_build_tfd(struct iwl_trans *trans,  					    struct sk_buff *skb,  					    struct iwl_cmd_meta *out_meta)  { -	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;  	int idx = iwl_pcie_get_cmd_index(txq, txq->write_ptr); -	struct iwl_tfh_tfd *tfd = -		iwl_pcie_get_tfd(trans_pcie, txq, idx); +	struct iwl_tfh_tfd *tfd = iwl_pcie_get_tfd(trans, txq, idx);  	dma_addr_t tb_phys;  	bool amsdu;  	int i, len, tb1_len, tb2_len, hdr_len; @@ -565,8 +561,7 @@ static int iwl_pcie_gen2_enqueue_hcmd(struct iwl_trans *trans,  	u8 group_id = iwl_cmd_groupid(cmd->id);  	const u8 *cmddata[IWL_MAX_CMD_TBS_PER_TFD];  	u16 cmdlen[IWL_MAX_CMD_TBS_PER_TFD]; -	struct iwl_tfh_tfd *tfd = -		iwl_pcie_get_tfd(trans_pcie, txq, txq->write_ptr); +	struct iwl_tfh_tfd *tfd = iwl_pcie_get_tfd(trans, txq, txq->write_ptr);  	memset(tfd, 0, sizeof(*tfd)); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index fed6d842a5e1..3f85713c41dc 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -373,7 +373,7 @@ static void iwl_pcie_tfd_unmap(struct iwl_trans *trans,  {  	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);  	int i, num_tbs; -	void *tfd = iwl_pcie_get_tfd(trans_pcie, txq, index); +	void *tfd = iwl_pcie_get_tfd(trans, txq, index);  	/* Sanity check on number of chunks */  	num_tbs = iwl_pcie_tfd_get_num_tbs(trans, tfd); @@ -2018,7 +2018,7 @@ static int iwl_fill_data_tbs(struct iwl_trans *trans, struct sk_buff *skb,  	}  	trace_iwlwifi_dev_tx(trans->dev, skb, -			     iwl_pcie_get_tfd(trans_pcie, txq, txq->write_ptr), +			     iwl_pcie_get_tfd(trans, txq, txq->write_ptr),  			     trans_pcie->tfd_size,  			     &dev_cmd->hdr, IWL_FIRST_TB_SIZE + tb1_len,  			     hdr_len); @@ -2092,7 +2092,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb,  		IEEE80211_CCMP_HDR_LEN : 0;  	trace_iwlwifi_dev_tx(trans->dev, skb, -			     iwl_pcie_get_tfd(trans_pcie, txq, txq->write_ptr), +			     iwl_pcie_get_tfd(trans, txq, txq->write_ptr),  			     trans_pcie->tfd_size,  			     &dev_cmd->hdr, IWL_FIRST_TB_SIZE + tb1_len, 0); @@ -2425,7 +2425,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,  	memcpy(&txq->first_tb_bufs[txq->write_ptr], &dev_cmd->hdr,  	       IWL_FIRST_TB_SIZE); -	tfd = iwl_pcie_get_tfd(trans_pcie, txq, txq->write_ptr); +	tfd = iwl_pcie_get_tfd(trans, txq, txq->write_ptr);  	/* Set up entry for this TFD in Tx byte-count array */  	iwl_pcie_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len),  					 iwl_pcie_tfd_get_num_tbs(trans, tfd)); diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 1e46e60b8f10..839650e0926a 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -1335,6 +1335,7 @@ static void nvme_update_disk_info(struct gendisk *disk,  		struct nvme_ns *ns, struct nvme_id_ns *id)  {  	sector_t capacity = le64_to_cpup(&id->nsze) << (ns->lba_shift - 9); +	unsigned short bs = 1 << ns->lba_shift;  	unsigned stream_alignment = 0;  	if (ns->ctrl->nr_streams && ns->sws && ns->sgs) @@ -1343,7 +1344,10 @@ static void nvme_update_disk_info(struct gendisk *disk,  	blk_mq_freeze_queue(disk->queue);  	blk_integrity_unregister(disk); -	blk_queue_logical_block_size(disk->queue, 1 << ns->lba_shift); +	blk_queue_logical_block_size(disk->queue, bs); +	blk_queue_physical_block_size(disk->queue, bs); +	blk_queue_io_min(disk->queue, bs); +  	if (ns->ms && !ns->ext &&  	    (ns->ctrl->ops->flags & NVME_F_METADATA_SUPPORTED))  		nvme_init_integrity(disk, ns->ms, ns->pi_type); @@ -2987,6 +2991,7 @@ static void nvme_ns_remove(struct nvme_ns *ns)  	mutex_unlock(&ns->ctrl->namespaces_mutex);  	synchronize_srcu(&ns->head->srcu); +	nvme_mpath_check_last_path(ns);  	nvme_put_ns(ns);  } diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index ea1aa5283e8e..a00eabd06427 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -417,6 +417,15 @@ static inline void nvme_mpath_clear_current_path(struct nvme_ns *ns)  		rcu_assign_pointer(head->current_path, NULL);  }  struct nvme_ns *nvme_find_path(struct nvme_ns_head *head); + +static inline void nvme_mpath_check_last_path(struct nvme_ns *ns) +{ +	struct nvme_ns_head *head = ns->head; + +	if (head->disk && list_empty(&head->list)) +		kblockd_schedule_work(&head->requeue_work); +} +  #else  static inline void nvme_failover_req(struct request *req)  { @@ -448,6 +457,9 @@ static inline void nvme_mpath_remove_disk_links(struct nvme_ns *ns)  static inline void nvme_mpath_clear_current_path(struct nvme_ns *ns)  {  } +static inline void nvme_mpath_check_last_path(struct nvme_ns *ns) +{ +}  #endif /* CONFIG_NVME_MULTIPATH */  #ifdef CONFIG_NVM diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index f5800c3c9082..d53550e612bc 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -448,12 +448,31 @@ static void **nvme_pci_iod_list(struct request *req)  	return (void **)(iod->sg + blk_rq_nr_phys_segments(req));  } +static inline bool nvme_pci_use_sgls(struct nvme_dev *dev, struct request *req) +{ +	struct nvme_iod *iod = blk_mq_rq_to_pdu(req); +	unsigned int avg_seg_size; + +	avg_seg_size = DIV_ROUND_UP(blk_rq_payload_bytes(req), +			blk_rq_nr_phys_segments(req)); + +	if (!(dev->ctrl.sgls & ((1 << 0) | (1 << 1)))) +		return false; +	if (!iod->nvmeq->qid) +		return false; +	if (!sgl_threshold || avg_seg_size < sgl_threshold) +		return false; +	return true; +} +  static blk_status_t nvme_init_iod(struct request *rq, struct nvme_dev *dev)  {  	struct nvme_iod *iod = blk_mq_rq_to_pdu(rq);  	int nseg = blk_rq_nr_phys_segments(rq);  	unsigned int size = blk_rq_payload_bytes(rq); +	iod->use_sgl = nvme_pci_use_sgls(dev, rq); +  	if (nseg > NVME_INT_PAGES || size > NVME_INT_BYTES(dev)) {  		size_t alloc_size = nvme_pci_iod_alloc_size(dev, size, nseg,  				iod->use_sgl); @@ -604,8 +623,6 @@ static blk_status_t nvme_pci_setup_prps(struct nvme_dev *dev,  	dma_addr_t prp_dma;  	int nprps, i; -	iod->use_sgl = false; -  	length -= (page_size - offset);  	if (length <= 0) {  		iod->first_dma = 0; @@ -715,8 +732,6 @@ static blk_status_t nvme_pci_setup_sgls(struct nvme_dev *dev,  	int entries = iod->nents, i = 0;  	dma_addr_t sgl_dma; -	iod->use_sgl = true; -  	/* setting the transfer type as SGL */  	cmd->flags = NVME_CMD_SGL_METABUF; @@ -770,23 +785,6 @@ static blk_status_t nvme_pci_setup_sgls(struct nvme_dev *dev,  	return BLK_STS_OK;  } -static inline bool nvme_pci_use_sgls(struct nvme_dev *dev, struct request *req) -{ -	struct nvme_iod *iod = blk_mq_rq_to_pdu(req); -	unsigned int avg_seg_size; - -	avg_seg_size = DIV_ROUND_UP(blk_rq_payload_bytes(req), -			blk_rq_nr_phys_segments(req)); - -	if (!(dev->ctrl.sgls & ((1 << 0) | (1 << 1)))) -		return false; -	if (!iod->nvmeq->qid) -		return false; -	if (!sgl_threshold || avg_seg_size < sgl_threshold) -		return false; -	return true; -} -  static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req,  		struct nvme_command *cmnd)  { @@ -806,7 +804,7 @@ static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req,  				DMA_ATTR_NO_WARN))  		goto out; -	if (nvme_pci_use_sgls(dev, req)) +	if (iod->use_sgl)  		ret = nvme_pci_setup_sgls(dev, req, &cmnd->rw);  	else  		ret = nvme_pci_setup_prps(dev, req, &cmnd->rw); diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c index 37af56596be6..2a0bba7f50cf 100644 --- a/drivers/nvme/host/rdma.c +++ b/drivers/nvme/host/rdma.c @@ -974,12 +974,18 @@ static void nvme_rdma_error_recovery_work(struct work_struct *work)  	blk_mq_unquiesce_queue(ctrl->ctrl.admin_q);  	nvme_start_queues(&ctrl->ctrl); +	if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_RECONNECTING)) { +		/* state change failure should never happen */ +		WARN_ON_ONCE(1); +		return; +	} +  	nvme_rdma_reconnect_or_remove(ctrl);  }  static void nvme_rdma_error_recovery(struct nvme_rdma_ctrl *ctrl)  { -	if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_RECONNECTING)) +	if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_RESETTING))  		return;  	queue_work(nvme_wq, &ctrl->err_work); @@ -1753,6 +1759,12 @@ static void nvme_rdma_reset_ctrl_work(struct work_struct *work)  	nvme_stop_ctrl(&ctrl->ctrl);  	nvme_rdma_shutdown_ctrl(ctrl, false); +	if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_RECONNECTING)) { +		/* state change failure should never happen */ +		WARN_ON_ONCE(1); +		return; +	} +  	ret = nvme_rdma_configure_admin_queue(ctrl, false);  	if (ret)  		goto out_fail; diff --git a/drivers/nvme/target/fcloop.c b/drivers/nvme/target/fcloop.c index 7b75d9de55ab..6a018a0bd6ce 100644 --- a/drivers/nvme/target/fcloop.c +++ b/drivers/nvme/target/fcloop.c @@ -1085,7 +1085,7 @@ fcloop_delete_target_port(struct device *dev, struct device_attribute *attr,  		const char *buf, size_t count)  {  	struct fcloop_nport *nport = NULL, *tmpport; -	struct fcloop_tport *tport; +	struct fcloop_tport *tport = NULL;  	u64 nodename, portname;  	unsigned long flags;  	int ret; diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index 1b9ef35cf0d9..8c0c92712fc9 100644 --- a/drivers/of/of_mdio.c +++ b/drivers/of/of_mdio.c @@ -236,7 +236,12 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)  			rc = of_mdiobus_register_phy(mdio, child, addr);  		else  			rc = of_mdiobus_register_device(mdio, child, addr); -		if (rc) + +		if (rc == -ENODEV) +			dev_err(&mdio->dev, +				"MDIO device at address %d is missing.\n", +				addr); +		else if (rc)  			goto unregister;  	} @@ -260,7 +265,7 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)  			if (of_mdiobus_child_is_phy(child)) {  				rc = of_mdiobus_register_phy(mdio, child, addr); -				if (rc) +				if (rc && rc != -ENODEV)  					goto unregister;  			}  		} diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 6be837c063c3..44f26f6df8fc 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -44,7 +44,14 @@ struct bpf_map_ops {  };  struct bpf_map { -	atomic_t refcnt; +	/* 1st cacheline with read-mostly members of which some +	 * are also accessed in fast-path (e.g. ops, max_entries). +	 */ +	const struct bpf_map_ops *ops ____cacheline_aligned; +	struct bpf_map *inner_map_meta; +#ifdef CONFIG_SECURITY +	void *security; +#endif  	enum bpf_map_type map_type;  	u32 key_size;  	u32 value_size; @@ -53,15 +60,17 @@ struct bpf_map {  	u32 pages;  	u32 id;  	int numa_node; -	struct user_struct *user; -	const struct bpf_map_ops *ops; -	struct work_struct work; +	bool unpriv_array; +	/* 7 bytes hole */ + +	/* 2nd cacheline with misc members to avoid false sharing +	 * particularly with refcounting. +	 */ +	struct user_struct *user ____cacheline_aligned; +	atomic_t refcnt;  	atomic_t usercnt; -	struct bpf_map *inner_map_meta; +	struct work_struct work;  	char name[BPF_OBJ_NAME_LEN]; -#ifdef CONFIG_SECURITY -	void *security; -#endif  };  /* function argument constraints */ @@ -230,6 +239,7 @@ struct bpf_prog_aux {  struct bpf_array {  	struct bpf_map map;  	u32 elem_size; +	u32 index_mask;  	/* 'ownership' of prog_array is claimed by the first program that  	 * is going to use this map or by the first program which FD is stored  	 * in the map to make sure that all callers and callees have the same diff --git a/init/Kconfig b/init/Kconfig index 690a381adee0..19a6b845d834 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1396,6 +1396,13 @@ config BPF_SYSCALL  	  Enable the bpf() system call that allows to manipulate eBPF  	  programs and maps via file descriptors. +config BPF_JIT_ALWAYS_ON +	bool "Permanently enable BPF JIT and remove BPF interpreter" +	depends on BPF_SYSCALL && HAVE_EBPF_JIT && BPF_JIT +	help +	  Enables BPF JIT and removes BPF interpreter to avoid +	  speculative execution of BPF instructions by the interpreter +  config USERFAULTFD  	bool "Enable userfaultfd() system call"  	select ANON_INODES diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c index 7c25426d3cf5..aaa319848e7d 100644 --- a/kernel/bpf/arraymap.c +++ b/kernel/bpf/arraymap.c @@ -53,9 +53,10 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr)  {  	bool percpu = attr->map_type == BPF_MAP_TYPE_PERCPU_ARRAY;  	int numa_node = bpf_map_attr_numa_node(attr); +	u32 elem_size, index_mask, max_entries; +	bool unpriv = !capable(CAP_SYS_ADMIN);  	struct bpf_array *array;  	u64 array_size; -	u32 elem_size;  	/* check sanity of attributes */  	if (attr->max_entries == 0 || attr->key_size != 4 || @@ -72,11 +73,20 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr)  	elem_size = round_up(attr->value_size, 8); +	max_entries = attr->max_entries; +	index_mask = roundup_pow_of_two(max_entries) - 1; + +	if (unpriv) +		/* round up array size to nearest power of 2, +		 * since cpu will speculate within index_mask limits +		 */ +		max_entries = index_mask + 1; +  	array_size = sizeof(*array);  	if (percpu) -		array_size += (u64) attr->max_entries * sizeof(void *); +		array_size += (u64) max_entries * sizeof(void *);  	else -		array_size += (u64) attr->max_entries * elem_size; +		array_size += (u64) max_entries * elem_size;  	/* make sure there is no u32 overflow later in round_up() */  	if (array_size >= U32_MAX - PAGE_SIZE) @@ -86,6 +96,8 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr)  	array = bpf_map_area_alloc(array_size, numa_node);  	if (!array)  		return ERR_PTR(-ENOMEM); +	array->index_mask = index_mask; +	array->map.unpriv_array = unpriv;  	/* copy mandatory map attributes */  	array->map.map_type = attr->map_type; @@ -121,12 +133,13 @@ static void *array_map_lookup_elem(struct bpf_map *map, void *key)  	if (unlikely(index >= array->map.max_entries))  		return NULL; -	return array->value + array->elem_size * index; +	return array->value + array->elem_size * (index & array->index_mask);  }  /* emit BPF instructions equivalent to C code of array_map_lookup_elem() */  static u32 array_map_gen_lookup(struct bpf_map *map, struct bpf_insn *insn_buf)  { +	struct bpf_array *array = container_of(map, struct bpf_array, map);  	struct bpf_insn *insn = insn_buf;  	u32 elem_size = round_up(map->value_size, 8);  	const int ret = BPF_REG_0; @@ -135,7 +148,12 @@ static u32 array_map_gen_lookup(struct bpf_map *map, struct bpf_insn *insn_buf)  	*insn++ = BPF_ALU64_IMM(BPF_ADD, map_ptr, offsetof(struct bpf_array, value));  	*insn++ = BPF_LDX_MEM(BPF_W, ret, index, 0); -	*insn++ = BPF_JMP_IMM(BPF_JGE, ret, map->max_entries, 3); +	if (map->unpriv_array) { +		*insn++ = BPF_JMP_IMM(BPF_JGE, ret, map->max_entries, 4); +		*insn++ = BPF_ALU32_IMM(BPF_AND, ret, array->index_mask); +	} else { +		*insn++ = BPF_JMP_IMM(BPF_JGE, ret, map->max_entries, 3); +	}  	if (is_power_of_2(elem_size)) {  		*insn++ = BPF_ALU64_IMM(BPF_LSH, ret, ilog2(elem_size)); @@ -157,7 +175,7 @@ static void *percpu_array_map_lookup_elem(struct bpf_map *map, void *key)  	if (unlikely(index >= array->map.max_entries))  		return NULL; -	return this_cpu_ptr(array->pptrs[index]); +	return this_cpu_ptr(array->pptrs[index & array->index_mask]);  }  int bpf_percpu_array_copy(struct bpf_map *map, void *key, void *value) @@ -177,7 +195,7 @@ int bpf_percpu_array_copy(struct bpf_map *map, void *key, void *value)  	 */  	size = round_up(map->value_size, 8);  	rcu_read_lock(); -	pptr = array->pptrs[index]; +	pptr = array->pptrs[index & array->index_mask];  	for_each_possible_cpu(cpu) {  		bpf_long_memcpy(value + off, per_cpu_ptr(pptr, cpu), size);  		off += size; @@ -225,10 +243,11 @@ static int array_map_update_elem(struct bpf_map *map, void *key, void *value,  		return -EEXIST;  	if (array->map.map_type == BPF_MAP_TYPE_PERCPU_ARRAY) -		memcpy(this_cpu_ptr(array->pptrs[index]), +		memcpy(this_cpu_ptr(array->pptrs[index & array->index_mask]),  		       value, map->value_size);  	else -		memcpy(array->value + array->elem_size * index, +		memcpy(array->value + +		       array->elem_size * (index & array->index_mask),  		       value, map->value_size);  	return 0;  } @@ -262,7 +281,7 @@ int bpf_percpu_array_update(struct bpf_map *map, void *key, void *value,  	 */  	size = round_up(map->value_size, 8);  	rcu_read_lock(); -	pptr = array->pptrs[index]; +	pptr = array->pptrs[index & array->index_mask];  	for_each_possible_cpu(cpu) {  		bpf_long_memcpy(per_cpu_ptr(pptr, cpu), value + off, size);  		off += size; @@ -613,6 +632,7 @@ static void *array_of_map_lookup_elem(struct bpf_map *map, void *key)  static u32 array_of_map_gen_lookup(struct bpf_map *map,  				   struct bpf_insn *insn_buf)  { +	struct bpf_array *array = container_of(map, struct bpf_array, map);  	u32 elem_size = round_up(map->value_size, 8);  	struct bpf_insn *insn = insn_buf;  	const int ret = BPF_REG_0; @@ -621,7 +641,12 @@ static u32 array_of_map_gen_lookup(struct bpf_map *map,  	*insn++ = BPF_ALU64_IMM(BPF_ADD, map_ptr, offsetof(struct bpf_array, value));  	*insn++ = BPF_LDX_MEM(BPF_W, ret, index, 0); -	*insn++ = BPF_JMP_IMM(BPF_JGE, ret, map->max_entries, 5); +	if (map->unpriv_array) { +		*insn++ = BPF_JMP_IMM(BPF_JGE, ret, map->max_entries, 6); +		*insn++ = BPF_ALU32_IMM(BPF_AND, ret, array->index_mask); +	} else { +		*insn++ = BPF_JMP_IMM(BPF_JGE, ret, map->max_entries, 5); +	}  	if (is_power_of_2(elem_size))  		*insn++ = BPF_ALU64_IMM(BPF_LSH, ret, ilog2(elem_size));  	else diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index 70a534549cd3..25e723b0dfd4 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -781,6 +781,7 @@ noinline u64 __bpf_call_base(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5)  }  EXPORT_SYMBOL_GPL(__bpf_call_base); +#ifndef CONFIG_BPF_JIT_ALWAYS_ON  /**   *	__bpf_prog_run - run eBPF program on a given context   *	@ctx: is the data we are operating on @@ -1377,6 +1378,14 @@ void bpf_patch_call_args(struct bpf_insn *insn, u32 stack_depth)  	insn->code = BPF_JMP | BPF_CALL_ARGS;  } +#else +static unsigned int __bpf_prog_ret0(const void *ctx, +				    const struct bpf_insn *insn) +{ +	return 0; +} +#endif +  bool bpf_prog_array_compatible(struct bpf_array *array,  			       const struct bpf_prog *fp)  { @@ -1427,9 +1436,13 @@ static int bpf_check_tail_call(const struct bpf_prog *fp)   */  struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err)  { +#ifndef CONFIG_BPF_JIT_ALWAYS_ON  	u32 stack_depth = max_t(u32, fp->aux->stack_depth, 1);  	fp->bpf_func = interpreters[(round_up(stack_depth, 32) / 32) - 1]; +#else +	fp->bpf_func = __bpf_prog_ret0; +#endif  	/* eBPF JITs can rewrite the program in case constant  	 * blinding is active. However, in case of error during @@ -1439,6 +1452,12 @@ struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err)  	 */  	if (!bpf_prog_is_dev_bound(fp->aux)) {  		fp = bpf_int_jit_compile(fp); +#ifdef CONFIG_BPF_JIT_ALWAYS_ON +		if (!fp->jited) { +			*err = -ENOTSUPP; +			return fp; +		} +#endif  	} else {  		*err = bpf_prog_offload_compile(fp);  		if (*err) diff --git a/kernel/bpf/sockmap.c b/kernel/bpf/sockmap.c index 3f662ee23a34..079968680bc3 100644 --- a/kernel/bpf/sockmap.c +++ b/kernel/bpf/sockmap.c @@ -583,8 +583,15 @@ static void sock_map_free(struct bpf_map *map)  		write_lock_bh(&sock->sk_callback_lock);  		psock = smap_psock_sk(sock); -		smap_list_remove(psock, &stab->sock_map[i]); -		smap_release_sock(psock, sock); +		/* This check handles a racing sock event that can get the +		 * sk_callback_lock before this case but after xchg happens +		 * causing the refcnt to hit zero and sock user data (psock) +		 * to be null and queued for garbage collection. +		 */ +		if (likely(psock)) { +			smap_list_remove(psock, &stab->sock_map[i]); +			smap_release_sock(psock, sock); +		}  		write_unlock_bh(&sock->sk_callback_lock);  	}  	rcu_read_unlock(); diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 3b2b47666180..48b61caa94cb 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -1523,6 +1523,7 @@ continue_func:  	goto continue_func;  } +#ifndef CONFIG_BPF_JIT_ALWAYS_ON  static int get_callee_stack_depth(struct bpf_verifier_env *env,  				  const struct bpf_insn *insn, int idx)  { @@ -1537,6 +1538,7 @@ static int get_callee_stack_depth(struct bpf_verifier_env *env,  	subprog++;  	return env->subprog_stack_depth[subprog];  } +#endif  /* truncate register to smaller size (in bytes)   * must be called with size < BPF_REG_SIZE @@ -2321,6 +2323,13 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn  	err = check_func_arg(env, BPF_REG_2, fn->arg2_type, &meta);  	if (err)  		return err; +	if (func_id == BPF_FUNC_tail_call) { +		if (meta.map_ptr == NULL) { +			verbose(env, "verifier bug\n"); +			return -EINVAL; +		} +		env->insn_aux_data[insn_idx].map_ptr = meta.map_ptr; +	}  	err = check_func_arg(env, BPF_REG_3, fn->arg3_type, &meta);  	if (err)  		return err; @@ -5264,14 +5273,20 @@ out_free:  static int fixup_call_args(struct bpf_verifier_env *env)  { +#ifndef CONFIG_BPF_JIT_ALWAYS_ON  	struct bpf_prog *prog = env->prog;  	struct bpf_insn *insn = prog->insnsi;  	int i, depth; +#endif +	int err; -	if (env->prog->jit_requested) -		if (jit_subprogs(env) == 0) +	err = 0; +	if (env->prog->jit_requested) { +		err = jit_subprogs(env); +		if (err == 0)  			return 0; - +	} +#ifndef CONFIG_BPF_JIT_ALWAYS_ON  	for (i = 0; i < prog->len; i++, insn++) {  		if (insn->code != (BPF_JMP | BPF_CALL) ||  		    insn->src_reg != BPF_PSEUDO_CALL) @@ -5281,7 +5296,9 @@ static int fixup_call_args(struct bpf_verifier_env *env)  			return depth;  		bpf_patch_call_args(insn, depth);  	} -	return 0; +	err = 0; +#endif +	return err;  }  /* fixup insn->imm field of bpf_call instructions @@ -5328,6 +5345,35 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)  			 */  			insn->imm = 0;  			insn->code = BPF_JMP | BPF_TAIL_CALL; + +			/* instead of changing every JIT dealing with tail_call +			 * emit two extra insns: +			 * if (index >= max_entries) goto out; +			 * index &= array->index_mask; +			 * to avoid out-of-bounds cpu speculation +			 */ +			map_ptr = env->insn_aux_data[i + delta].map_ptr; +			if (map_ptr == BPF_MAP_PTR_POISON) { +				verbose(env, "tail_call obusing map_ptr\n"); +				return -EINVAL; +			} +			if (!map_ptr->unpriv_array) +				continue; +			insn_buf[0] = BPF_JMP_IMM(BPF_JGE, BPF_REG_3, +						  map_ptr->max_entries, 2); +			insn_buf[1] = BPF_ALU32_IMM(BPF_AND, BPF_REG_3, +						    container_of(map_ptr, +								 struct bpf_array, +								 map)->index_mask); +			insn_buf[2] = *insn; +			cnt = 3; +			new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt); +			if (!new_prog) +				return -ENOMEM; + +			delta    += cnt - 1; +			env->prog = prog = new_prog; +			insn      = new_prog->insnsi + i + delta;  			continue;  		} diff --git a/lib/test_bpf.c b/lib/test_bpf.c index 9e9748089270..f369889e521d 100644 --- a/lib/test_bpf.c +++ b/lib/test_bpf.c @@ -6250,9 +6250,8 @@ static struct bpf_prog *generate_filter(int which, int *err)  				return NULL;  			}  		} -		/* We don't expect to fail. */  		if (*err) { -			pr_cont("FAIL to attach err=%d len=%d\n", +			pr_cont("FAIL to prog_create err=%d len=%d\n",  				*err, fprog.len);  			return NULL;  		} @@ -6276,6 +6275,10 @@ static struct bpf_prog *generate_filter(int which, int *err)  		 * checks.  		 */  		fp = bpf_prog_select_runtime(fp, err); +		if (*err) { +			pr_cont("FAIL to select_runtime err=%d\n", *err); +			return NULL; +		}  		break;  	} @@ -6461,8 +6464,8 @@ static __init int test_bpf(void)  				pass_cnt++;  				continue;  			} - -			return err; +			err_cnt++; +			continue;  		}  		pr_cont("jited:%u ", fp->jited); diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 8dfdd94e430f..bad01b14a4ad 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -111,12 +111,7 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)  		vlan_gvrp_uninit_applicant(real_dev);  	} -	/* Take it out of our own structures, but be sure to interlock with -	 * HW accelerating devices or SW vlan input packet processing if -	 * VLAN is not 0 (leave it there for 802.1p). -	 */ -	if (vlan_id) -		vlan_vid_del(real_dev, vlan->vlan_proto, vlan_id); +	vlan_vid_del(real_dev, vlan->vlan_proto, vlan_id);  	/* Get rid of the vlan's reference to real_dev */  	dev_put(real_dev); diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c index 2d38b6e34203..e0adcd123f48 100644 --- a/net/caif/caif_dev.c +++ b/net/caif/caif_dev.c @@ -334,9 +334,8 @@ void caif_enroll_dev(struct net_device *dev, struct caif_dev_common *caifdev,  	mutex_lock(&caifdevs->lock);  	list_add_rcu(&caifd->list, &caifdevs->list); -	strncpy(caifd->layer.name, dev->name, -		sizeof(caifd->layer.name) - 1); -	caifd->layer.name[sizeof(caifd->layer.name) - 1] = 0; +	strlcpy(caifd->layer.name, dev->name, +		sizeof(caifd->layer.name));  	caifd->layer.transmit = transmit;  	cfcnfg_add_phy_layer(cfg,  				dev, diff --git a/net/caif/caif_usb.c b/net/caif/caif_usb.c index 5cd44f001f64..1a082a946045 100644 --- a/net/caif/caif_usb.c +++ b/net/caif/caif_usb.c @@ -176,9 +176,7 @@ static int cfusbl_device_notify(struct notifier_block *me, unsigned long what,  		dev_add_pack(&caif_usb_type);  	pack_added = true; -	strncpy(layer->name, dev->name, -			sizeof(layer->name) - 1); -	layer->name[sizeof(layer->name) - 1] = 0; +	strlcpy(layer->name, dev->name, sizeof(layer->name));  	return 0;  } diff --git a/net/caif/cfcnfg.c b/net/caif/cfcnfg.c index 273cb07f57d8..8f00bea093b9 100644 --- a/net/caif/cfcnfg.c +++ b/net/caif/cfcnfg.c @@ -268,17 +268,15 @@ static int caif_connect_req_to_link_param(struct cfcnfg *cnfg,  	case CAIFPROTO_RFM:  		l->linktype = CFCTRL_SRV_RFM;  		l->u.datagram.connid = s->sockaddr.u.rfm.connection_id; -		strncpy(l->u.rfm.volume, s->sockaddr.u.rfm.volume, -			sizeof(l->u.rfm.volume)-1); -		l->u.rfm.volume[sizeof(l->u.rfm.volume)-1] = 0; +		strlcpy(l->u.rfm.volume, s->sockaddr.u.rfm.volume, +			sizeof(l->u.rfm.volume));  		break;  	case CAIFPROTO_UTIL:  		l->linktype = CFCTRL_SRV_UTIL;  		l->endpoint = 0x00;  		l->chtype = 0x00; -		strncpy(l->u.utility.name, s->sockaddr.u.util.service, -			sizeof(l->u.utility.name)-1); -		l->u.utility.name[sizeof(l->u.utility.name)-1] = 0; +		strlcpy(l->u.utility.name, s->sockaddr.u.util.service, +			sizeof(l->u.utility.name));  		caif_assert(sizeof(l->u.utility.name) > 10);  		l->u.utility.paramlen = s->param.size;  		if (l->u.utility.paramlen > sizeof(l->u.utility.params)) diff --git a/net/caif/cfctrl.c b/net/caif/cfctrl.c index f5afda1abc76..655ed7032150 100644 --- a/net/caif/cfctrl.c +++ b/net/caif/cfctrl.c @@ -258,8 +258,8 @@ int cfctrl_linkup_request(struct cflayer *layer,  		tmp16 = cpu_to_le16(param->u.utility.fifosize_bufs);  		cfpkt_add_body(pkt, &tmp16, 2);  		memset(utility_name, 0, sizeof(utility_name)); -		strncpy(utility_name, param->u.utility.name, -			UTILITY_NAME_LENGTH - 1); +		strlcpy(utility_name, param->u.utility.name, +			UTILITY_NAME_LENGTH);  		cfpkt_add_body(pkt, utility_name, UTILITY_NAME_LENGTH);  		tmp8 = param->u.utility.paramlen;  		cfpkt_add_body(pkt, &tmp8, 1); diff --git a/net/core/filter.c b/net/core/filter.c index acdb94c0e97f..d4b190e63b79 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -1054,11 +1054,9 @@ static struct bpf_prog *bpf_migrate_filter(struct bpf_prog *fp)  		 */  		goto out_err_free; -	/* We are guaranteed to never error here with cBPF to eBPF -	 * transitions, since there's no issue with type compatibility -	 * checks on program arrays. -	 */  	fp = bpf_prog_select_runtime(fp, &err); +	if (err) +		goto out_err_free;  	kfree(old_prog);  	return fp; diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c index 217f4e3b82f6..146b50e30659 100644 --- a/net/core/sock_diag.c +++ b/net/core/sock_diag.c @@ -288,7 +288,7 @@ static int sock_diag_bind(struct net *net, int group)  	case SKNLGRP_INET6_UDP_DESTROY:  		if (!sock_diag_handlers[AF_INET6])  			request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK, -				       NETLINK_SOCK_DIAG, AF_INET); +				       NETLINK_SOCK_DIAG, AF_INET6);  		break;  	}  	return 0; diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index cbc3dde4cfcc..a47ad6cd41c0 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c @@ -325,7 +325,13 @@ static struct ctl_table net_core_table[] = {  		.data		= &bpf_jit_enable,  		.maxlen		= sizeof(int),  		.mode		= 0644, +#ifndef CONFIG_BPF_JIT_ALWAYS_ON  		.proc_handler	= proc_dointvec +#else +		.proc_handler	= proc_dointvec_minmax, +		.extra1		= &one, +		.extra2		= &one, +#endif  	},  # ifdef CONFIG_HAVE_EBPF_JIT  	{ diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 125c1eab3eaa..5e570aa9e43b 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -520,9 +520,11 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)  		goto out;  	/* hdrincl should be READ_ONCE(inet->hdrincl) -	 * but READ_ONCE() doesn't work with bit fields +	 * but READ_ONCE() doesn't work with bit fields. +	 * Doing this indirectly yields the same result.  	 */  	hdrincl = inet->hdrincl; +	hdrincl = READ_ONCE(hdrincl);  	/*  	 *	Check the flags.  	 */ diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index 83bd75713535..bc68eb661970 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -925,6 +925,15 @@ static void ipv6_push_rthdr4(struct sk_buff *skb, u8 *proto,  	sr_phdr->segments[0] = **addr_p;  	*addr_p = &sr_ihdr->segments[sr_ihdr->segments_left]; +	if (sr_ihdr->hdrlen > hops * 2) { +		int tlvs_offset, tlvs_length; + +		tlvs_offset = (1 + hops * 2) << 3; +		tlvs_length = (sr_ihdr->hdrlen - hops * 2) << 3; +		memcpy((char *)sr_phdr + tlvs_offset, +		       (char *)sr_ihdr + tlvs_offset, tlvs_length); +	} +  #ifdef CONFIG_IPV6_SEG6_HMAC  	if (sr_has_hmac(sr_phdr)) {  		struct net *net = NULL; diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index e31118f417b4..b7c4befe67ec 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -637,6 +637,11 @@ static struct fib6_node *fib6_add_1(struct net *net,  			if (!(fn->fn_flags & RTN_RTINFO)) {  				RCU_INIT_POINTER(fn->leaf, NULL);  				rt6_release(leaf); +			/* remove null_entry in the root node */ +			} else if (fn->fn_flags & RTN_TL_ROOT && +				   rcu_access_pointer(fn->leaf) == +				   net->ipv6.ip6_null_entry) { +				RCU_INIT_POINTER(fn->leaf, NULL);  			}  			return fn; @@ -1267,13 +1272,17 @@ out:  	return err;  failure: -	/* fn->leaf could be NULL if fn is an intermediate node and we -	 * failed to add the new route to it in both subtree creation -	 * failure and fib6_add_rt2node() failure case. -	 * In both cases, fib6_repair_tree() should be called to fix -	 * fn->leaf. +	/* fn->leaf could be NULL and fib6_repair_tree() needs to be called if: +	 * 1. fn is an intermediate node and we failed to add the new +	 * route to it in both subtree creation failure and fib6_add_rt2node() +	 * failure case. +	 * 2. fn is the root node in the table and we fail to add the first +	 * default route to it.  	 */ -	if (fn && !(fn->fn_flags & (RTN_RTINFO|RTN_ROOT))) +	if (fn && +	    (!(fn->fn_flags & (RTN_RTINFO|RTN_ROOT)) || +	     (fn->fn_flags & RTN_TL_ROOT && +	      !rcu_access_pointer(fn->leaf))))  		fib6_repair_tree(info->nl_net, table, fn);  	/* Always release dst as dst->__refcnt is guaranteed  	 * to be taken before entering this function @@ -1528,6 +1537,12 @@ static struct fib6_node *fib6_repair_tree(struct net *net,  	struct fib6_walker *w;  	int iter = 0; +	/* Set fn->leaf to null_entry for root node. */ +	if (fn->fn_flags & RTN_TL_ROOT) { +		rcu_assign_pointer(fn->leaf, net->ipv6.ip6_null_entry); +		return fn; +	} +  	for (;;) {  		struct fib6_node *fn_r = rcu_dereference_protected(fn->right,  					    lockdep_is_held(&table->tb6_lock)); @@ -1683,10 +1698,15 @@ static void fib6_del_route(struct fib6_table *table, struct fib6_node *fn,  	}  	read_unlock(&net->ipv6.fib6_walker_lock); -	/* If it was last route, expunge its radix tree node */ +	/* If it was last route, call fib6_repair_tree() to: +	 * 1. For root node, put back null_entry as how the table was created. +	 * 2. For other nodes, expunge its radix tree node. +	 */  	if (!rcu_access_pointer(fn->leaf)) { -		fn->fn_flags &= ~RTN_RTINFO; -		net->ipv6.rt6_stats->fib_route_nodes--; +		if (!(fn->fn_flags & RTN_TL_ROOT)) { +			fn->fn_flags &= ~RTN_RTINFO; +			net->ipv6.rt6_stats->fib_route_nodes--; +		}  		fn = fib6_repair_tree(net, table, fn);  	} diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 19adad6d90bc..18547a44bdaf 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1744,9 +1744,10 @@ struct sk_buff *ip6_make_skb(struct sock *sk,  	cork.base.opt = NULL;  	v6_cork.opt = NULL;  	err = ip6_setup_cork(sk, &cork, &v6_cork, ipc6, rt, fl6); -	if (err) +	if (err) { +		ip6_cork_release(&cork, &v6_cork);  		return ERR_PTR(err); - +	}  	if (ipc6->dontfrag < 0)  		ipc6->dontfrag = inet6_sk(sk)->dontfrag; diff --git a/net/sctp/socket.c b/net/sctp/socket.c index a5e2150ab013..6a54ff06c9da 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -2307,7 +2307,7 @@ static int sctp_setsockopt_events(struct sock *sk, char __user *optval,  		if (asoc && sctp_outq_is_empty(&asoc->outqueue)) {  			event = sctp_ulpevent_make_sender_dry_event(asoc, -					GFP_ATOMIC); +					GFP_USER | __GFP_NOWARN);  			if (!event)  				return -ENOMEM; @@ -3531,6 +3531,8 @@ static int sctp_setsockopt_hmac_ident(struct sock *sk,  	if (optlen < sizeof(struct sctp_hmacalgo))  		return -EINVAL; +	optlen = min_t(unsigned int, optlen, sizeof(struct sctp_hmacalgo) + +					     SCTP_AUTH_NUM_HMACS * sizeof(u16));  	hmacs = memdup_user(optval, optlen);  	if (IS_ERR(hmacs)) @@ -3569,6 +3571,11 @@ static int sctp_setsockopt_auth_key(struct sock *sk,  	if (optlen <= sizeof(struct sctp_authkey))  		return -EINVAL; +	/* authkey->sca_keylength is u16, so optlen can't be bigger than +	 * this. +	 */ +	optlen = min_t(unsigned int, optlen, USHRT_MAX + +					     sizeof(struct sctp_authkey));  	authkey = memdup_user(optval, optlen);  	if (IS_ERR(authkey)) @@ -3926,6 +3933,9 @@ static int sctp_setsockopt_reset_streams(struct sock *sk,  	if (optlen < sizeof(*params))  		return -EINVAL; +	/* srs_number_streams is u16, so optlen can't be bigger than this. */ +	optlen = min_t(unsigned int, optlen, USHRT_MAX + +					     sizeof(__u16) * sizeof(*params));  	params = memdup_user(optval, optlen);  	if (IS_ERR(params)) @@ -5075,7 +5085,7 @@ static int sctp_getsockopt_autoclose(struct sock *sk, int len, char __user *optv  	len = sizeof(int);  	if (put_user(len, optlen))  		return -EFAULT; -	if (copy_to_user(optval, &sctp_sk(sk)->autoclose, sizeof(int))) +	if (copy_to_user(optval, &sctp_sk(sk)->autoclose, len))  		return -EFAULT;  	return 0;  } @@ -5705,6 +5715,9 @@ copy_getaddrs:  		err = -EFAULT;  		goto out;  	} +	/* XXX: We should have accounted for sizeof(struct sctp_getaddrs) too, +	 * but we can't change it anymore. +	 */  	if (put_user(bytes_copied, optlen))  		err = -EFAULT;  out: @@ -6141,7 +6154,7 @@ static int sctp_getsockopt_maxseg(struct sock *sk, int len,  		params.assoc_id = 0;  	} else if (len >= sizeof(struct sctp_assoc_value)) {  		len = sizeof(struct sctp_assoc_value); -		if (copy_from_user(¶ms, optval, sizeof(params))) +		if (copy_from_user(¶ms, optval, len))  			return -EFAULT;  	} else  		return -EINVAL; @@ -6311,7 +6324,9 @@ static int sctp_getsockopt_active_key(struct sock *sk, int len,  	if (len < sizeof(struct sctp_authkeyid))  		return -EINVAL; -	if (copy_from_user(&val, optval, sizeof(struct sctp_authkeyid))) + +	len = sizeof(struct sctp_authkeyid); +	if (copy_from_user(&val, optval, len))  		return -EFAULT;  	asoc = sctp_id2assoc(sk, val.scact_assoc_id); @@ -6323,7 +6338,6 @@ static int sctp_getsockopt_active_key(struct sock *sk, int len,  	else  		val.scact_keynumber = ep->active_key_id; -	len = sizeof(struct sctp_authkeyid);  	if (put_user(len, optlen))  		return -EFAULT;  	if (copy_to_user(optval, &val, len)) @@ -6349,7 +6363,7 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len,  	if (len < sizeof(struct sctp_authchunks))  		return -EINVAL; -	if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks))) +	if (copy_from_user(&val, optval, sizeof(val)))  		return -EFAULT;  	to = p->gauth_chunks; @@ -6394,7 +6408,7 @@ static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len,  	if (len < sizeof(struct sctp_authchunks))  		return -EINVAL; -	if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks))) +	if (copy_from_user(&val, optval, sizeof(val)))  		return -EFAULT;  	to = p->gauth_chunks; diff --git a/net/socket.c b/net/socket.c index bbd2e9ceb692..fbfae1ed3ff5 100644 --- a/net/socket.c +++ b/net/socket.c @@ -430,8 +430,10 @@ static int sock_map_fd(struct socket *sock, int flags)  {  	struct file *newfile;  	int fd = get_unused_fd_flags(flags); -	if (unlikely(fd < 0)) +	if (unlikely(fd < 0)) { +		sock_release(sock);  		return fd; +	}  	newfile = sock_alloc_file(sock, flags, NULL);  	if (likely(!IS_ERR(newfile))) { @@ -2611,6 +2613,15 @@ out_fs:  core_initcall(sock_init);	/* early initcall */ +static int __init jit_init(void) +{ +#ifdef CONFIG_BPF_JIT_ALWAYS_ON +	bpf_jit_enable = 1; +#endif +	return 0; +} +pure_initcall(jit_init); +  #ifdef CONFIG_PROC_FS  void socket_seq_show(struct seq_file *seq)  { diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index e49f448ee04f..c2db7e905f7d 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -455,7 +455,6 @@ static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm,  		v = snd_pcm_hw_param_last(pcm, params, var, dir);  	else  		v = snd_pcm_hw_param_first(pcm, params, var, dir); -	snd_BUG_ON(v < 0);  	return v;  } @@ -1335,8 +1334,11 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha  	if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)  		return tmp; -	mutex_lock(&runtime->oss.params_lock);  	while (bytes > 0) { +		if (mutex_lock_interruptible(&runtime->oss.params_lock)) { +			tmp = -ERESTARTSYS; +			break; +		}  		if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {  			tmp = bytes;  			if (tmp + runtime->oss.buffer_used > runtime->oss.period_bytes) @@ -1380,14 +1382,18 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha  			xfer += tmp;  			if ((substream->f_flags & O_NONBLOCK) != 0 &&  			    tmp != runtime->oss.period_bytes) -				break; +				tmp = -EAGAIN;  		} -	} -	mutex_unlock(&runtime->oss.params_lock); -	return xfer; -   err: -	mutex_unlock(&runtime->oss.params_lock); +		mutex_unlock(&runtime->oss.params_lock); +		if (tmp < 0) +			break; +		if (signal_pending(current)) { +			tmp = -ERESTARTSYS; +			break; +		} +		tmp = 0; +	}  	return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;  } @@ -1435,8 +1441,11 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use  	if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)  		return tmp; -	mutex_lock(&runtime->oss.params_lock);  	while (bytes > 0) { +		if (mutex_lock_interruptible(&runtime->oss.params_lock)) { +			tmp = -ERESTARTSYS; +			break; +		}  		if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {  			if (runtime->oss.buffer_used == 0) {  				tmp = snd_pcm_oss_read2(substream, runtime->oss.buffer, runtime->oss.period_bytes, 1); @@ -1467,12 +1476,16 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use  			bytes -= tmp;  			xfer += tmp;  		} -	} -	mutex_unlock(&runtime->oss.params_lock); -	return xfer; -   err: -	mutex_unlock(&runtime->oss.params_lock); +		mutex_unlock(&runtime->oss.params_lock); +		if (tmp < 0) +			break; +		if (signal_pending(current)) { +			tmp = -ERESTARTSYS; +			break; +		} +		tmp = 0; +	}  	return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;  } diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c index cadc93792868..85a56af104bd 100644 --- a/sound/core/oss/pcm_plugin.c +++ b/sound/core/oss/pcm_plugin.c @@ -592,18 +592,26 @@ snd_pcm_sframes_t snd_pcm_plug_write_transfer(struct snd_pcm_substream *plug, st  	snd_pcm_sframes_t frames = size;  	plugin = snd_pcm_plug_first(plug); -	while (plugin && frames > 0) { +	while (plugin) { +		if (frames <= 0) +			return frames;  		if ((next = plugin->next) != NULL) {  			snd_pcm_sframes_t frames1 = frames; -			if (plugin->dst_frames) +			if (plugin->dst_frames) {  				frames1 = plugin->dst_frames(plugin, frames); +				if (frames1 <= 0) +					return frames1; +			}  			if ((err = next->client_channels(next, frames1, &dst_channels)) < 0) {  				return err;  			}  			if (err != frames1) {  				frames = err; -				if (plugin->src_frames) +				if (plugin->src_frames) {  					frames = plugin->src_frames(plugin, frames1); +					if (frames <= 0) +						return frames; +				}  			}  		} else  			dst_channels = NULL; diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 10e7ef7a8804..db7894bb028c 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1632,7 +1632,7 @@ int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm,  		return changed;  	if (params->rmask) {  		int err = snd_pcm_hw_refine(pcm, params); -		if (snd_BUG_ON(err < 0)) +		if (err < 0)  			return err;  	}  	return snd_pcm_hw_param_value(params, var, dir); @@ -1678,7 +1678,7 @@ int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm,  		return changed;  	if (params->rmask) {  		int err = snd_pcm_hw_refine(pcm, params); -		if (snd_BUG_ON(err < 0)) +		if (err < 0)  			return err;  	}  	return snd_pcm_hw_param_value(params, var, dir); diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index a4d92e46c459..f08772568c17 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -2580,7 +2580,7 @@ static snd_pcm_sframes_t forward_appl_ptr(struct snd_pcm_substream *substream,  	return ret < 0 ? ret : frames;  } -/* decrease the appl_ptr; returns the processed frames or a negative error */ +/* decrease the appl_ptr; returns the processed frames or zero for error */  static snd_pcm_sframes_t rewind_appl_ptr(struct snd_pcm_substream *substream,  					 snd_pcm_uframes_t frames,  					 snd_pcm_sframes_t avail) @@ -2597,7 +2597,12 @@ static snd_pcm_sframes_t rewind_appl_ptr(struct snd_pcm_substream *substream,  	if (appl_ptr < 0)  		appl_ptr += runtime->boundary;  	ret = pcm_lib_apply_appl_ptr(substream, appl_ptr); -	return ret < 0 ? ret : frames; +	/* NOTE: we return zero for errors because PulseAudio gets depressed +	 * upon receiving an error from rewind ioctl and stops processing +	 * any longer.  Returning zero means that no rewind is done, so +	 * it's not absolutely wrong to answer like that. +	 */ +	return ret < 0 ? 0 : frames;  }  static snd_pcm_sframes_t snd_pcm_playback_rewind(struct snd_pcm_substream *substream, diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index afac886ffa28..0333143a1fa7 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -39,6 +39,7 @@  #include <sound/core.h>  #include <sound/control.h>  #include <sound/pcm.h> +#include <sound/pcm_params.h>  #include <sound/info.h>  #include <sound/initval.h> @@ -305,19 +306,6 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd)  	return 0;  } -static void params_change_substream(struct loopback_pcm *dpcm, -				    struct snd_pcm_runtime *runtime) -{ -	struct snd_pcm_runtime *dst_runtime; - -	if (dpcm == NULL || dpcm->substream == NULL) -		return; -	dst_runtime = dpcm->substream->runtime; -	if (dst_runtime == NULL) -		return; -	dst_runtime->hw = dpcm->cable->hw; -} -  static void params_change(struct snd_pcm_substream *substream)  {  	struct snd_pcm_runtime *runtime = substream->runtime; @@ -329,10 +317,6 @@ static void params_change(struct snd_pcm_substream *substream)  	cable->hw.rate_max = runtime->rate;  	cable->hw.channels_min = runtime->channels;  	cable->hw.channels_max = runtime->channels; -	params_change_substream(cable->streams[SNDRV_PCM_STREAM_PLAYBACK], -				runtime); -	params_change_substream(cable->streams[SNDRV_PCM_STREAM_CAPTURE], -				runtime);  }  static int loopback_prepare(struct snd_pcm_substream *substream) @@ -620,26 +604,29 @@ static unsigned int get_cable_index(struct snd_pcm_substream *substream)  static int rule_format(struct snd_pcm_hw_params *params,  		       struct snd_pcm_hw_rule *rule)  { +	struct loopback_pcm *dpcm = rule->private; +	struct loopback_cable *cable = dpcm->cable; +	struct snd_mask m; -	struct snd_pcm_hardware *hw = rule->private; -	struct snd_mask *maskp = hw_param_mask(params, rule->var); - -	maskp->bits[0] &= (u_int32_t)hw->formats; -	maskp->bits[1] &= (u_int32_t)(hw->formats >> 32); -	memset(maskp->bits + 2, 0, (SNDRV_MASK_MAX-64) / 8); /* clear rest */ -	if (! maskp->bits[0] && ! maskp->bits[1]) -		return -EINVAL; -	return 0; +	snd_mask_none(&m); +	mutex_lock(&dpcm->loopback->cable_lock); +	m.bits[0] = (u_int32_t)cable->hw.formats; +	m.bits[1] = (u_int32_t)(cable->hw.formats >> 32); +	mutex_unlock(&dpcm->loopback->cable_lock); +	return snd_mask_refine(hw_param_mask(params, rule->var), &m);  }  static int rule_rate(struct snd_pcm_hw_params *params,  		     struct snd_pcm_hw_rule *rule)  { -	struct snd_pcm_hardware *hw = rule->private; +	struct loopback_pcm *dpcm = rule->private; +	struct loopback_cable *cable = dpcm->cable;  	struct snd_interval t; -        t.min = hw->rate_min; -        t.max = hw->rate_max; +	mutex_lock(&dpcm->loopback->cable_lock); +	t.min = cable->hw.rate_min; +	t.max = cable->hw.rate_max; +	mutex_unlock(&dpcm->loopback->cable_lock);          t.openmin = t.openmax = 0;          t.integer = 0;  	return snd_interval_refine(hw_param_interval(params, rule->var), &t); @@ -648,22 +635,44 @@ static int rule_rate(struct snd_pcm_hw_params *params,  static int rule_channels(struct snd_pcm_hw_params *params,  			 struct snd_pcm_hw_rule *rule)  { -	struct snd_pcm_hardware *hw = rule->private; +	struct loopback_pcm *dpcm = rule->private; +	struct loopback_cable *cable = dpcm->cable;  	struct snd_interval t; -        t.min = hw->channels_min; -        t.max = hw->channels_max; +	mutex_lock(&dpcm->loopback->cable_lock); +	t.min = cable->hw.channels_min; +	t.max = cable->hw.channels_max; +	mutex_unlock(&dpcm->loopback->cable_lock);          t.openmin = t.openmax = 0;          t.integer = 0;  	return snd_interval_refine(hw_param_interval(params, rule->var), &t);  } +static void free_cable(struct snd_pcm_substream *substream) +{ +	struct loopback *loopback = substream->private_data; +	int dev = get_cable_index(substream); +	struct loopback_cable *cable; + +	cable = loopback->cables[substream->number][dev]; +	if (!cable) +		return; +	if (cable->streams[!substream->stream]) { +		/* other stream is still alive */ +		cable->streams[substream->stream] = NULL; +	} else { +		/* free the cable */ +		loopback->cables[substream->number][dev] = NULL; +		kfree(cable); +	} +} +  static int loopback_open(struct snd_pcm_substream *substream)  {  	struct snd_pcm_runtime *runtime = substream->runtime;  	struct loopback *loopback = substream->private_data;  	struct loopback_pcm *dpcm; -	struct loopback_cable *cable; +	struct loopback_cable *cable = NULL;  	int err = 0;  	int dev = get_cable_index(substream); @@ -681,7 +690,6 @@ static int loopback_open(struct snd_pcm_substream *substream)  	if (!cable) {  		cable = kzalloc(sizeof(*cable), GFP_KERNEL);  		if (!cable) { -			kfree(dpcm);  			err = -ENOMEM;  			goto unlock;  		} @@ -699,19 +707,19 @@ static int loopback_open(struct snd_pcm_substream *substream)  	/* are cached -> they do not reflect the actual state */  	err = snd_pcm_hw_rule_add(runtime, 0,  				  SNDRV_PCM_HW_PARAM_FORMAT, -				  rule_format, &runtime->hw, +				  rule_format, dpcm,  				  SNDRV_PCM_HW_PARAM_FORMAT, -1);  	if (err < 0)  		goto unlock;  	err = snd_pcm_hw_rule_add(runtime, 0,  				  SNDRV_PCM_HW_PARAM_RATE, -				  rule_rate, &runtime->hw, +				  rule_rate, dpcm,  				  SNDRV_PCM_HW_PARAM_RATE, -1);  	if (err < 0)  		goto unlock;  	err = snd_pcm_hw_rule_add(runtime, 0,  				  SNDRV_PCM_HW_PARAM_CHANNELS, -				  rule_channels, &runtime->hw, +				  rule_channels, dpcm,  				  SNDRV_PCM_HW_PARAM_CHANNELS, -1);  	if (err < 0)  		goto unlock; @@ -723,6 +731,10 @@ static int loopback_open(struct snd_pcm_substream *substream)  	else  		runtime->hw = cable->hw;   unlock: +	if (err < 0) { +		free_cable(substream); +		kfree(dpcm); +	}  	mutex_unlock(&loopback->cable_lock);  	return err;  } @@ -731,20 +743,10 @@ static int loopback_close(struct snd_pcm_substream *substream)  {  	struct loopback *loopback = substream->private_data;  	struct loopback_pcm *dpcm = substream->runtime->private_data; -	struct loopback_cable *cable; -	int dev = get_cable_index(substream);  	loopback_timer_stop(dpcm);  	mutex_lock(&loopback->cable_lock); -	cable = loopback->cables[substream->number][dev]; -	if (cable->streams[!substream->stream]) { -		/* other stream is still alive */ -		cable->streams[substream->stream] = NULL; -	} else { -		/* free the cable */ -		loopback->cables[substream->number][dev] = NULL; -		kfree(cable); -	} +	free_cable(substream);  	mutex_unlock(&loopback->cable_lock);  	return 0;  } diff --git a/tools/testing/selftests/bpf/test_align.c b/tools/testing/selftests/bpf/test_align.c index fe916d29e166..e19b410125eb 100644 --- a/tools/testing/selftests/bpf/test_align.c +++ b/tools/testing/selftests/bpf/test_align.c @@ -474,27 +474,7 @@ static struct bpf_align_test tests[] = {  		.result = REJECT,  		.matches = {  			{4, "R5_w=pkt(id=0,off=0,r=0,imm=0)"}, -			/* ptr & 0x40 == either 0 or 0x40 */ -			{5, "R5_w=inv(id=0,umax_value=64,var_off=(0x0; 0x40))"}, -			/* ptr << 2 == unknown, (4n) */ -			{7, "R5_w=inv(id=0,smax_value=9223372036854775804,umax_value=18446744073709551612,var_off=(0x0; 0xfffffffffffffffc))"}, -			/* (4n) + 14 == (4n+2).  We blow our bounds, because -			 * the add could overflow. -			 */ -			{8, "R5=inv(id=0,var_off=(0x2; 0xfffffffffffffffc))"}, -			/* Checked s>=0 */ -			{10, "R5=inv(id=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc))"}, -			/* packet pointer + nonnegative (4n+2) */ -			{12, "R6_w=pkt(id=1,off=0,r=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc))"}, -			{14, "R4=pkt(id=1,off=4,r=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc))"}, -			/* NET_IP_ALIGN + (4n+2) == (4n), alignment is fine. -			 * We checked the bounds, but it might have been able -			 * to overflow if the packet pointer started in the -			 * upper half of the address space. -			 * So we did not get a 'range' on R6, and the access -			 * attempt will fail. -			 */ -			{16, "R6=pkt(id=1,off=0,r=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc))"}, +			/* R5 bitwise operator &= on pointer prohibited */  		}  	},  	{  | 
