3189 lines
100 KiB
Diff
3189 lines
100 KiB
Diff
|
diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt
|
||
|
index edad99a..69820b2 100644
|
||
|
--- a/Documentation/sound/alsa/HD-Audio-Models.txt
|
||
|
+++ b/Documentation/sound/alsa/HD-Audio-Models.txt
|
||
|
@@ -60,10 +60,11 @@ ALC267/268
|
||
|
==========
|
||
|
N/A
|
||
|
|
||
|
-ALC269
|
||
|
+ALC269/270/275/276/280/282
|
||
|
======
|
||
|
laptop-amic Laptops with analog-mic input
|
||
|
laptop-dmic Laptops with digital-mic input
|
||
|
+ lenovo-dock Enables docking station I/O for some Lenovos
|
||
|
|
||
|
ALC662/663/272
|
||
|
==============
|
||
|
diff --git a/Documentation/stable_kernel_rules.txt b/Documentation/stable_kernel_rules.txt
|
||
|
index e1f856b..22bf11b 100644
|
||
|
--- a/Documentation/stable_kernel_rules.txt
|
||
|
+++ b/Documentation/stable_kernel_rules.txt
|
||
|
@@ -1,4 +1,4 @@
|
||
|
-Everything you ever wanted to know about Linux 2.6 -stable releases.
|
||
|
+Everything you ever wanted to know about Linux -stable releases.
|
||
|
|
||
|
Rules on what kind of patches are accepted, and which ones are not, into the
|
||
|
"-stable" tree:
|
||
|
@@ -41,10 +41,10 @@ Procedure for submitting patches to the -stable tree:
|
||
|
cherry-picked than this can be specified in the following format in
|
||
|
the sign-off area:
|
||
|
|
||
|
- Cc: <stable@vger.kernel.org> # .32.x: a1f84a3: sched: Check for idle
|
||
|
- Cc: <stable@vger.kernel.org> # .32.x: 1b9508f: sched: Rate-limit newidle
|
||
|
- Cc: <stable@vger.kernel.org> # .32.x: fd21073: sched: Fix affinity logic
|
||
|
- Cc: <stable@vger.kernel.org> # .32.x
|
||
|
+ Cc: <stable@vger.kernel.org> # 3.3.x: a1f84a3: sched: Check for idle
|
||
|
+ Cc: <stable@vger.kernel.org> # 3.3.x: 1b9508f: sched: Rate-limit newidle
|
||
|
+ Cc: <stable@vger.kernel.org> # 3.3.x: fd21073: sched: Fix affinity logic
|
||
|
+ Cc: <stable@vger.kernel.org> # 3.3.x
|
||
|
Signed-off-by: Ingo Molnar <mingo@elte.hu>
|
||
|
|
||
|
The tag sequence has the meaning of:
|
||
|
@@ -78,6 +78,15 @@ Review cycle:
|
||
|
security kernel team, and not go through the normal review cycle.
|
||
|
Contact the kernel security team for more details on this procedure.
|
||
|
|
||
|
+Trees:
|
||
|
+
|
||
|
+ - The queues of patches, for both completed versions and in progress
|
||
|
+ versions can be found at:
|
||
|
+ http://git.kernel.org/?p=linux/kernel/git/stable/stable-queue.git
|
||
|
+ - The finalized and tagged releases of all stable kernels can be found
|
||
|
+ in separate branches per version at:
|
||
|
+ http://git.kernel.org/?p=linux/kernel/git/stable/linux-stable.git
|
||
|
+
|
||
|
|
||
|
Review committee:
|
||
|
|
||
|
diff --git a/Makefile b/Makefile
|
||
|
index fa5acc83..bdf851f 100644
|
||
|
--- a/Makefile
|
||
|
+++ b/Makefile
|
||
|
@@ -1,6 +1,6 @@
|
||
|
VERSION = 3
|
||
|
PATCHLEVEL = 2
|
||
|
-SUBLEVEL = 26
|
||
|
+SUBLEVEL = 27
|
||
|
EXTRAVERSION =
|
||
|
NAME = Saber-toothed Squirrel
|
||
|
|
||
|
diff --git a/arch/arm/include/asm/mutex.h b/arch/arm/include/asm/mutex.h
|
||
|
index 93226cf..b1479fd 100644
|
||
|
--- a/arch/arm/include/asm/mutex.h
|
||
|
+++ b/arch/arm/include/asm/mutex.h
|
||
|
@@ -7,121 +7,10 @@
|
||
|
*/
|
||
|
#ifndef _ASM_MUTEX_H
|
||
|
#define _ASM_MUTEX_H
|
||
|
-
|
||
|
-#if __LINUX_ARM_ARCH__ < 6
|
||
|
-/* On pre-ARMv6 hardware the swp based implementation is the most efficient. */
|
||
|
-# include <asm-generic/mutex-xchg.h>
|
||
|
-#else
|
||
|
-
|
||
|
/*
|
||
|
- * Attempting to lock a mutex on ARMv6+ can be done with a bastardized
|
||
|
- * atomic decrement (it is not a reliable atomic decrement but it satisfies
|
||
|
- * the defined semantics for our purpose, while being smaller and faster
|
||
|
- * than a real atomic decrement or atomic swap. The idea is to attempt
|
||
|
- * decrementing the lock value only once. If once decremented it isn't zero,
|
||
|
- * or if its store-back fails due to a dispute on the exclusive store, we
|
||
|
- * simply bail out immediately through the slow path where the lock will be
|
||
|
- * reattempted until it succeeds.
|
||
|
+ * On pre-ARMv6 hardware this results in a swp-based implementation,
|
||
|
+ * which is the most efficient. For ARMv6+, we emit a pair of exclusive
|
||
|
+ * accesses instead.
|
||
|
*/
|
||
|
-static inline void
|
||
|
-__mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *))
|
||
|
-{
|
||
|
- int __ex_flag, __res;
|
||
|
-
|
||
|
- __asm__ (
|
||
|
-
|
||
|
- "ldrex %0, [%2] \n\t"
|
||
|
- "sub %0, %0, #1 \n\t"
|
||
|
- "strex %1, %0, [%2] "
|
||
|
-
|
||
|
- : "=&r" (__res), "=&r" (__ex_flag)
|
||
|
- : "r" (&(count)->counter)
|
||
|
- : "cc","memory" );
|
||
|
-
|
||
|
- __res |= __ex_flag;
|
||
|
- if (unlikely(__res != 0))
|
||
|
- fail_fn(count);
|
||
|
-}
|
||
|
-
|
||
|
-static inline int
|
||
|
-__mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *))
|
||
|
-{
|
||
|
- int __ex_flag, __res;
|
||
|
-
|
||
|
- __asm__ (
|
||
|
-
|
||
|
- "ldrex %0, [%2] \n\t"
|
||
|
- "sub %0, %0, #1 \n\t"
|
||
|
- "strex %1, %0, [%2] "
|
||
|
-
|
||
|
- : "=&r" (__res), "=&r" (__ex_flag)
|
||
|
- : "r" (&(count)->counter)
|
||
|
- : "cc","memory" );
|
||
|
-
|
||
|
- __res |= __ex_flag;
|
||
|
- if (unlikely(__res != 0))
|
||
|
- __res = fail_fn(count);
|
||
|
- return __res;
|
||
|
-}
|
||
|
-
|
||
|
-/*
|
||
|
- * Same trick is used for the unlock fast path. However the original value,
|
||
|
- * rather than the result, is used to test for success in order to have
|
||
|
- * better generated assembly.
|
||
|
- */
|
||
|
-static inline void
|
||
|
-__mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *))
|
||
|
-{
|
||
|
- int __ex_flag, __res, __orig;
|
||
|
-
|
||
|
- __asm__ (
|
||
|
-
|
||
|
- "ldrex %0, [%3] \n\t"
|
||
|
- "add %1, %0, #1 \n\t"
|
||
|
- "strex %2, %1, [%3] "
|
||
|
-
|
||
|
- : "=&r" (__orig), "=&r" (__res), "=&r" (__ex_flag)
|
||
|
- : "r" (&(count)->counter)
|
||
|
- : "cc","memory" );
|
||
|
-
|
||
|
- __orig |= __ex_flag;
|
||
|
- if (unlikely(__orig != 0))
|
||
|
- fail_fn(count);
|
||
|
-}
|
||
|
-
|
||
|
-/*
|
||
|
- * If the unlock was done on a contended lock, or if the unlock simply fails
|
||
|
- * then the mutex remains locked.
|
||
|
- */
|
||
|
-#define __mutex_slowpath_needs_to_unlock() 1
|
||
|
-
|
||
|
-/*
|
||
|
- * For __mutex_fastpath_trylock we use another construct which could be
|
||
|
- * described as a "single value cmpxchg".
|
||
|
- *
|
||
|
- * This provides the needed trylock semantics like cmpxchg would, but it is
|
||
|
- * lighter and less generic than a true cmpxchg implementation.
|
||
|
- */
|
||
|
-static inline int
|
||
|
-__mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *))
|
||
|
-{
|
||
|
- int __ex_flag, __res, __orig;
|
||
|
-
|
||
|
- __asm__ (
|
||
|
-
|
||
|
- "1: ldrex %0, [%3] \n\t"
|
||
|
- "subs %1, %0, #1 \n\t"
|
||
|
- "strexeq %2, %1, [%3] \n\t"
|
||
|
- "movlt %0, #0 \n\t"
|
||
|
- "cmpeq %2, #0 \n\t"
|
||
|
- "bgt 1b "
|
||
|
-
|
||
|
- : "=&r" (__orig), "=&r" (__res), "=&r" (__ex_flag)
|
||
|
- : "r" (&count->counter)
|
||
|
- : "cc", "memory" );
|
||
|
-
|
||
|
- return __orig;
|
||
|
-}
|
||
|
-
|
||
|
-#endif
|
||
|
+#include <asm-generic/mutex-xchg.h>
|
||
|
#endif
|
||
|
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
|
||
|
index b145f16..ece0996 100644
|
||
|
--- a/arch/arm/kernel/entry-armv.S
|
||
|
+++ b/arch/arm/kernel/entry-armv.S
|
||
|
@@ -242,6 +242,19 @@ svc_preempt:
|
||
|
b 1b
|
||
|
#endif
|
||
|
|
||
|
+__und_fault:
|
||
|
+ @ Correct the PC such that it is pointing at the instruction
|
||
|
+ @ which caused the fault. If the faulting instruction was ARM
|
||
|
+ @ the PC will be pointing at the next instruction, and have to
|
||
|
+ @ subtract 4. Otherwise, it is Thumb, and the PC will be
|
||
|
+ @ pointing at the second half of the Thumb instruction. We
|
||
|
+ @ have to subtract 2.
|
||
|
+ ldr r2, [r0, #S_PC]
|
||
|
+ sub r2, r2, r1
|
||
|
+ str r2, [r0, #S_PC]
|
||
|
+ b do_undefinstr
|
||
|
+ENDPROC(__und_fault)
|
||
|
+
|
||
|
.align 5
|
||
|
__und_svc:
|
||
|
#ifdef CONFIG_KPROBES
|
||
|
@@ -259,25 +272,32 @@ __und_svc:
|
||
|
@
|
||
|
@ r0 - instruction
|
||
|
@
|
||
|
-#ifndef CONFIG_THUMB2_KERNEL
|
||
|
+#ifndef CONFIG_THUMB2_KERNEL
|
||
|
ldr r0, [r4, #-4]
|
||
|
#else
|
||
|
+ mov r1, #2
|
||
|
ldrh r0, [r4, #-2] @ Thumb instruction at LR - 2
|
||
|
cmp r0, #0xe800 @ 32-bit instruction if xx >= 0
|
||
|
- ldrhhs r9, [r4] @ bottom 16 bits
|
||
|
- orrhs r0, r9, r0, lsl #16
|
||
|
+ blo __und_svc_fault
|
||
|
+ ldrh r9, [r4] @ bottom 16 bits
|
||
|
+ add r4, r4, #2
|
||
|
+ str r4, [sp, #S_PC]
|
||
|
+ orr r0, r9, r0, lsl #16
|
||
|
#endif
|
||
|
- adr r9, BSYM(1f)
|
||
|
+ adr r9, BSYM(__und_svc_finish)
|
||
|
mov r2, r4
|
||
|
bl call_fpe
|
||
|
|
||
|
+ mov r1, #4 @ PC correction to apply
|
||
|
+__und_svc_fault:
|
||
|
mov r0, sp @ struct pt_regs *regs
|
||
|
- bl do_undefinstr
|
||
|
+ bl __und_fault
|
||
|
|
||
|
@
|
||
|
@ IRQs off again before pulling preserved data off the stack
|
||
|
@
|
||
|
-1: disable_irq_notrace
|
||
|
+__und_svc_finish:
|
||
|
+ disable_irq_notrace
|
||
|
|
||
|
@
|
||
|
@ restore SPSR and restart the instruction
|
||
|
@@ -421,25 +441,33 @@ __und_usr:
|
||
|
mov r2, r4
|
||
|
mov r3, r5
|
||
|
|
||
|
+ @ r2 = regs->ARM_pc, which is either 2 or 4 bytes ahead of the
|
||
|
+ @ faulting instruction depending on Thumb mode.
|
||
|
+ @ r3 = regs->ARM_cpsr
|
||
|
@
|
||
|
- @ fall through to the emulation code, which returns using r9 if
|
||
|
- @ it has emulated the instruction, or the more conventional lr
|
||
|
- @ if we are to treat this as a real undefined instruction
|
||
|
- @
|
||
|
- @ r0 - instruction
|
||
|
+ @ The emulation code returns using r9 if it has emulated the
|
||
|
+ @ instruction, or the more conventional lr if we are to treat
|
||
|
+ @ this as a real undefined instruction
|
||
|
@
|
||
|
adr r9, BSYM(ret_from_exception)
|
||
|
- adr lr, BSYM(__und_usr_unknown)
|
||
|
+
|
||
|
tst r3, #PSR_T_BIT @ Thumb mode?
|
||
|
- itet eq @ explicit IT needed for the 1f label
|
||
|
- subeq r4, r2, #4 @ ARM instr at LR - 4
|
||
|
- subne r4, r2, #2 @ Thumb instr at LR - 2
|
||
|
-1: ldreqt r0, [r4]
|
||
|
+ bne __und_usr_thumb
|
||
|
+ sub r4, r2, #4 @ ARM instr at LR - 4
|
||
|
+1: ldrt r0, [r4]
|
||
|
#ifdef CONFIG_CPU_ENDIAN_BE8
|
||
|
- reveq r0, r0 @ little endian instruction
|
||
|
+ rev r0, r0 @ little endian instruction
|
||
|
#endif
|
||
|
- beq call_fpe
|
||
|
+ @ r0 = 32-bit ARM instruction which caused the exception
|
||
|
+ @ r2 = PC value for the following instruction (:= regs->ARM_pc)
|
||
|
+ @ r4 = PC value for the faulting instruction
|
||
|
+ @ lr = 32-bit undefined instruction function
|
||
|
+ adr lr, BSYM(__und_usr_fault_32)
|
||
|
+ b call_fpe
|
||
|
+
|
||
|
+__und_usr_thumb:
|
||
|
@ Thumb instruction
|
||
|
+ sub r4, r2, #2 @ First half of thumb instr at LR - 2
|
||
|
#if CONFIG_ARM_THUMB && __LINUX_ARM_ARCH__ >= 6 && CONFIG_CPU_V7
|
||
|
/*
|
||
|
* Thumb-2 instruction handling. Note that because pre-v6 and >= v6 platforms
|
||
|
@@ -453,7 +481,7 @@ __und_usr:
|
||
|
ldr r5, .LCcpu_architecture
|
||
|
ldr r5, [r5]
|
||
|
cmp r5, #CPU_ARCH_ARMv7
|
||
|
- blo __und_usr_unknown
|
||
|
+ blo __und_usr_fault_16 @ 16bit undefined instruction
|
||
|
/*
|
||
|
* The following code won't get run unless the running CPU really is v7, so
|
||
|
* coding round the lack of ldrht on older arches is pointless. Temporarily
|
||
|
@@ -461,15 +489,18 @@ __und_usr:
|
||
|
*/
|
||
|
.arch armv6t2
|
||
|
#endif
|
||
|
-2:
|
||
|
- ARM( ldrht r5, [r4], #2 )
|
||
|
- THUMB( ldrht r5, [r4] )
|
||
|
- THUMB( add r4, r4, #2 )
|
||
|
+2: ldrht r5, [r4]
|
||
|
cmp r5, #0xe800 @ 32bit instruction if xx != 0
|
||
|
- blo __und_usr_unknown
|
||
|
-3: ldrht r0, [r4]
|
||
|
+ blo __und_usr_fault_16 @ 16bit undefined instruction
|
||
|
+3: ldrht r0, [r2]
|
||
|
add r2, r2, #2 @ r2 is PC + 2, make it PC + 4
|
||
|
+ str r2, [sp, #S_PC] @ it's a 2x16bit instr, update
|
||
|
orr r0, r0, r5, lsl #16
|
||
|
+ adr lr, BSYM(__und_usr_fault_32)
|
||
|
+ @ r0 = the two 16-bit Thumb instructions which caused the exception
|
||
|
+ @ r2 = PC value for the following Thumb instruction (:= regs->ARM_pc)
|
||
|
+ @ r4 = PC value for the first 16-bit Thumb instruction
|
||
|
+ @ lr = 32bit undefined instruction function
|
||
|
|
||
|
#if __LINUX_ARM_ARCH__ < 7
|
||
|
/* If the target arch was overridden, change it back: */
|
||
|
@@ -480,17 +511,13 @@ __und_usr:
|
||
|
#endif
|
||
|
#endif /* __LINUX_ARM_ARCH__ < 7 */
|
||
|
#else /* !(CONFIG_ARM_THUMB && __LINUX_ARM_ARCH__ >= 6 && CONFIG_CPU_V7) */
|
||
|
- b __und_usr_unknown
|
||
|
+ b __und_usr_fault_16
|
||
|
#endif
|
||
|
- UNWIND(.fnend )
|
||
|
+ UNWIND(.fnend)
|
||
|
ENDPROC(__und_usr)
|
||
|
|
||
|
- @
|
||
|
- @ fallthrough to call_fpe
|
||
|
- @
|
||
|
-
|
||
|
/*
|
||
|
- * The out of line fixup for the ldrt above.
|
||
|
+ * The out of line fixup for the ldrt instructions above.
|
||
|
*/
|
||
|
.pushsection .fixup, "ax"
|
||
|
4: mov pc, r9
|
||
|
@@ -521,11 +548,12 @@ ENDPROC(__und_usr)
|
||
|
* NEON handler code.
|
||
|
*
|
||
|
* Emulators may wish to make use of the following registers:
|
||
|
- * r0 = instruction opcode.
|
||
|
- * r2 = PC+4
|
||
|
+ * r0 = instruction opcode (32-bit ARM or two 16-bit Thumb)
|
||
|
+ * r2 = PC value to resume execution after successful emulation
|
||
|
* r9 = normal "successful" return address
|
||
|
- * r10 = this threads thread_info structure.
|
||
|
+ * r10 = this threads thread_info structure
|
||
|
* lr = unrecognised instruction return address
|
||
|
+ * IRQs disabled, FIQs enabled.
|
||
|
*/
|
||
|
@
|
||
|
@ Fall-through from Thumb-2 __und_usr
|
||
|
@@ -660,12 +688,17 @@ ENTRY(no_fp)
|
||
|
mov pc, lr
|
||
|
ENDPROC(no_fp)
|
||
|
|
||
|
-__und_usr_unknown:
|
||
|
- enable_irq
|
||
|
+__und_usr_fault_32:
|
||
|
+ mov r1, #4
|
||
|
+ b 1f
|
||
|
+__und_usr_fault_16:
|
||
|
+ mov r1, #2
|
||
|
+1: enable_irq
|
||
|
mov r0, sp
|
||
|
adr lr, BSYM(ret_from_exception)
|
||
|
- b do_undefinstr
|
||
|
-ENDPROC(__und_usr_unknown)
|
||
|
+ b __und_fault
|
||
|
+ENDPROC(__und_usr_fault_32)
|
||
|
+ENDPROC(__und_usr_fault_16)
|
||
|
|
||
|
.align 5
|
||
|
__pabt_usr:
|
||
|
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
|
||
|
index 3d0c6fb..e68d251 100644
|
||
|
--- a/arch/arm/kernel/process.c
|
||
|
+++ b/arch/arm/kernel/process.c
|
||
|
@@ -125,6 +125,7 @@ void arm_machine_restart(char mode, const char *cmd)
|
||
|
*/
|
||
|
mdelay(1000);
|
||
|
printk("Reboot failed -- System halted\n");
|
||
|
+ local_irq_disable();
|
||
|
while (1);
|
||
|
}
|
||
|
|
||
|
@@ -240,6 +241,7 @@ void machine_shutdown(void)
|
||
|
void machine_halt(void)
|
||
|
{
|
||
|
machine_shutdown();
|
||
|
+ local_irq_disable();
|
||
|
while (1);
|
||
|
}
|
||
|
|
||
|
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
|
||
|
index 160cb16..8380bd1 100644
|
||
|
--- a/arch/arm/kernel/traps.c
|
||
|
+++ b/arch/arm/kernel/traps.c
|
||
|
@@ -362,18 +362,10 @@ static int call_undef_hook(struct pt_regs *regs, unsigned int instr)
|
||
|
|
||
|
asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
|
||
|
{
|
||
|
- unsigned int correction = thumb_mode(regs) ? 2 : 4;
|
||
|
unsigned int instr;
|
||
|
siginfo_t info;
|
||
|
void __user *pc;
|
||
|
|
||
|
- /*
|
||
|
- * According to the ARM ARM, PC is 2 or 4 bytes ahead,
|
||
|
- * depending whether we're in Thumb mode or not.
|
||
|
- * Correct this offset.
|
||
|
- */
|
||
|
- regs->ARM_pc -= correction;
|
||
|
-
|
||
|
pc = (void __user *)instruction_pointer(regs);
|
||
|
|
||
|
if (processor_mode(regs) == SVC_MODE) {
|
||
|
diff --git a/arch/arm/mm/tlb-v7.S b/arch/arm/mm/tlb-v7.S
|
||
|
index 845f461..c202113 100644
|
||
|
--- a/arch/arm/mm/tlb-v7.S
|
||
|
+++ b/arch/arm/mm/tlb-v7.S
|
||
|
@@ -38,11 +38,19 @@ ENTRY(v7wbi_flush_user_tlb_range)
|
||
|
dsb
|
||
|
mov r0, r0, lsr #PAGE_SHIFT @ align address
|
||
|
mov r1, r1, lsr #PAGE_SHIFT
|
||
|
+#ifdef CONFIG_ARM_ERRATA_720789
|
||
|
+ mov r3, #0
|
||
|
+#else
|
||
|
asid r3, r3 @ mask ASID
|
||
|
+#endif
|
||
|
orr r0, r3, r0, lsl #PAGE_SHIFT @ Create initial MVA
|
||
|
mov r1, r1, lsl #PAGE_SHIFT
|
||
|
1:
|
||
|
+#ifdef CONFIG_ARM_ERRATA_720789
|
||
|
+ ALT_SMP(mcr p15, 0, r0, c8, c3, 3) @ TLB invalidate U MVA all ASID (shareable)
|
||
|
+#else
|
||
|
ALT_SMP(mcr p15, 0, r0, c8, c3, 1) @ TLB invalidate U MVA (shareable)
|
||
|
+#endif
|
||
|
ALT_UP(mcr p15, 0, r0, c8, c7, 1) @ TLB invalidate U MVA
|
||
|
|
||
|
add r0, r0, #PAGE_SZ
|
||
|
@@ -67,7 +75,11 @@ ENTRY(v7wbi_flush_kern_tlb_range)
|
||
|
mov r0, r0, lsl #PAGE_SHIFT
|
||
|
mov r1, r1, lsl #PAGE_SHIFT
|
||
|
1:
|
||
|
+#ifdef CONFIG_ARM_ERRATA_720789
|
||
|
+ ALT_SMP(mcr p15, 0, r0, c8, c3, 3) @ TLB invalidate U MVA all ASID (shareable)
|
||
|
+#else
|
||
|
ALT_SMP(mcr p15, 0, r0, c8, c3, 1) @ TLB invalidate U MVA (shareable)
|
||
|
+#endif
|
||
|
ALT_UP(mcr p15, 0, r0, c8, c7, 1) @ TLB invalidate U MVA
|
||
|
add r0, r0, #PAGE_SZ
|
||
|
cmp r0, r1
|
||
|
diff --git a/arch/arm/vfp/entry.S b/arch/arm/vfp/entry.S
|
||
|
index 4fa9903..cc926c9 100644
|
||
|
--- a/arch/arm/vfp/entry.S
|
||
|
+++ b/arch/arm/vfp/entry.S
|
||
|
@@ -7,18 +7,20 @@
|
||
|
* 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.
|
||
|
- *
|
||
|
- * Basic entry code, called from the kernel's undefined instruction trap.
|
||
|
- * r0 = faulted instruction
|
||
|
- * r5 = faulted PC+4
|
||
|
- * r9 = successful return
|
||
|
- * r10 = thread_info structure
|
||
|
- * lr = failure return
|
||
|
*/
|
||
|
#include <asm/thread_info.h>
|
||
|
#include <asm/vfpmacros.h>
|
||
|
#include "../kernel/entry-header.S"
|
||
|
|
||
|
+@ VFP entry point.
|
||
|
+@
|
||
|
+@ r0 = instruction opcode (32-bit ARM or two 16-bit Thumb)
|
||
|
+@ r2 = PC value to resume execution after successful emulation
|
||
|
+@ r9 = normal "successful" return address
|
||
|
+@ r10 = this threads thread_info structure
|
||
|
+@ lr = unrecognised instruction return address
|
||
|
+@ IRQs disabled.
|
||
|
+@
|
||
|
ENTRY(do_vfp)
|
||
|
#ifdef CONFIG_PREEMPT
|
||
|
ldr r4, [r10, #TI_PREEMPT] @ get preempt count
|
||
|
diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S
|
||
|
index 2d30c7f..3a0efaa 100644
|
||
|
--- a/arch/arm/vfp/vfphw.S
|
||
|
+++ b/arch/arm/vfp/vfphw.S
|
||
|
@@ -61,13 +61,13 @@
|
||
|
|
||
|
@ VFP hardware support entry point.
|
||
|
@
|
||
|
-@ r0 = faulted instruction
|
||
|
-@ r2 = faulted PC+4
|
||
|
-@ r9 = successful return
|
||
|
+@ r0 = instruction opcode (32-bit ARM or two 16-bit Thumb)
|
||
|
+@ r2 = PC value to resume execution after successful emulation
|
||
|
+@ r9 = normal "successful" return address
|
||
|
@ r10 = vfp_state union
|
||
|
@ r11 = CPU number
|
||
|
-@ lr = failure return
|
||
|
-
|
||
|
+@ lr = unrecognised instruction return address
|
||
|
+@ IRQs enabled.
|
||
|
ENTRY(vfp_support_entry)
|
||
|
DBGSTR3 "instr %08x pc %08x state %p", r0, r2, r10
|
||
|
|
||
|
@@ -161,9 +161,12 @@ vfp_hw_state_valid:
|
||
|
@ exception before retrying branch
|
||
|
@ out before setting an FPEXC that
|
||
|
@ stops us reading stuff
|
||
|
- VFPFMXR FPEXC, r1 @ restore FPEXC last
|
||
|
- sub r2, r2, #4
|
||
|
- str r2, [sp, #S_PC] @ retry the instruction
|
||
|
+ VFPFMXR FPEXC, r1 @ Restore FPEXC last
|
||
|
+ sub r2, r2, #4 @ Retry current instruction - if Thumb
|
||
|
+ str r2, [sp, #S_PC] @ mode it's two 16-bit instructions,
|
||
|
+ @ else it's one 32-bit instruction, so
|
||
|
+ @ always subtract 4 from the following
|
||
|
+ @ instruction address.
|
||
|
#ifdef CONFIG_PREEMPT
|
||
|
get_thread_info r10
|
||
|
ldr r4, [r10, #TI_PREEMPT] @ get preempt count
|
||
|
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
|
||
|
index 8ea07e4..ad83dad 100644
|
||
|
--- a/arch/arm/vfp/vfpmodule.c
|
||
|
+++ b/arch/arm/vfp/vfpmodule.c
|
||
|
@@ -453,10 +453,16 @@ static int vfp_pm_suspend(void)
|
||
|
|
||
|
/* disable, just in case */
|
||
|
fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
|
||
|
+ } else if (vfp_current_hw_state[ti->cpu]) {
|
||
|
+#ifndef CONFIG_SMP
|
||
|
+ fmxr(FPEXC, fpexc | FPEXC_EN);
|
||
|
+ vfp_save_state(vfp_current_hw_state[ti->cpu], fpexc);
|
||
|
+ fmxr(FPEXC, fpexc);
|
||
|
+#endif
|
||
|
}
|
||
|
|
||
|
/* clear any information we had about last context state */
|
||
|
- memset(vfp_current_hw_state, 0, sizeof(vfp_current_hw_state));
|
||
|
+ vfp_current_hw_state[ti->cpu] = NULL;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
diff --git a/arch/ia64/include/asm/atomic.h b/arch/ia64/include/asm/atomic.h
|
||
|
index 3fad89e..2fc214b 100644
|
||
|
--- a/arch/ia64/include/asm/atomic.h
|
||
|
+++ b/arch/ia64/include/asm/atomic.h
|
||
|
@@ -18,8 +18,8 @@
|
||
|
#include <asm/system.h>
|
||
|
|
||
|
|
||
|
-#define ATOMIC_INIT(i) ((atomic_t) { (i) })
|
||
|
-#define ATOMIC64_INIT(i) ((atomic64_t) { (i) })
|
||
|
+#define ATOMIC_INIT(i) { (i) }
|
||
|
+#define ATOMIC64_INIT(i) { (i) }
|
||
|
|
||
|
#define atomic_read(v) (*(volatile int *)&(v)->counter)
|
||
|
#define atomic64_read(v) (*(volatile long *)&(v)->counter)
|
||
|
diff --git a/arch/m68k/include/asm/entry.h b/arch/m68k/include/asm/entry.h
|
||
|
index c3c5a86..8798ebc 100644
|
||
|
--- a/arch/m68k/include/asm/entry.h
|
||
|
+++ b/arch/m68k/include/asm/entry.h
|
||
|
@@ -33,8 +33,8 @@
|
||
|
|
||
|
/* the following macro is used when enabling interrupts */
|
||
|
#if defined(MACH_ATARI_ONLY)
|
||
|
- /* block out HSYNC on the atari */
|
||
|
-#define ALLOWINT (~0x400)
|
||
|
+ /* block out HSYNC = ipl 2 on the atari */
|
||
|
+#define ALLOWINT (~0x500)
|
||
|
#define MAX_NOINT_IPL 3
|
||
|
#else
|
||
|
/* portable version */
|
||
|
diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c
|
||
|
index 8623f8d..9a5932e 100644
|
||
|
--- a/arch/m68k/kernel/sys_m68k.c
|
||
|
+++ b/arch/m68k/kernel/sys_m68k.c
|
||
|
@@ -479,9 +479,13 @@ sys_atomic_cmpxchg_32(unsigned long newval, int oldval, int d3, int d4, int d5,
|
||
|
goto bad_access;
|
||
|
}
|
||
|
|
||
|
- mem_value = *mem;
|
||
|
+ /*
|
||
|
+ * No need to check for EFAULT; we know that the page is
|
||
|
+ * present and writable.
|
||
|
+ */
|
||
|
+ __get_user(mem_value, mem);
|
||
|
if (mem_value == oldval)
|
||
|
- *mem = newval;
|
||
|
+ __put_user(newval, mem);
|
||
|
|
||
|
pte_unmap_unlock(pte, ptl);
|
||
|
up_read(&mm->mmap_sem);
|
||
|
diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h
|
||
|
index 5682f16..20f0e01 100644
|
||
|
--- a/arch/s390/include/asm/mmu_context.h
|
||
|
+++ b/arch/s390/include/asm/mmu_context.h
|
||
|
@@ -12,7 +12,6 @@
|
||
|
#include <asm/pgalloc.h>
|
||
|
#include <asm/uaccess.h>
|
||
|
#include <asm/tlbflush.h>
|
||
|
-#include <asm-generic/mm_hooks.h>
|
||
|
|
||
|
static inline int init_new_context(struct task_struct *tsk,
|
||
|
struct mm_struct *mm)
|
||
|
@@ -92,4 +91,17 @@ static inline void activate_mm(struct mm_struct *prev,
|
||
|
switch_mm(prev, next, current);
|
||
|
}
|
||
|
|
||
|
+static inline void arch_dup_mmap(struct mm_struct *oldmm,
|
||
|
+ struct mm_struct *mm)
|
||
|
+{
|
||
|
+#ifdef CONFIG_64BIT
|
||
|
+ if (oldmm->context.asce_limit < mm->context.asce_limit)
|
||
|
+ crst_table_downgrade(mm, oldmm->context.asce_limit);
|
||
|
+#endif
|
||
|
+}
|
||
|
+
|
||
|
+static inline void arch_exit_mmap(struct mm_struct *mm)
|
||
|
+{
|
||
|
+}
|
||
|
+
|
||
|
#endif /* __S390_MMU_CONTEXT_H */
|
||
|
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h
|
||
|
index 5f33d37..172550d 100644
|
||
|
--- a/arch/s390/include/asm/processor.h
|
||
|
+++ b/arch/s390/include/asm/processor.h
|
||
|
@@ -130,7 +130,9 @@ struct stack_frame {
|
||
|
regs->psw.mask = psw_user_bits | PSW_MASK_BA; \
|
||
|
regs->psw.addr = new_psw | PSW_ADDR_AMODE; \
|
||
|
regs->gprs[15] = new_stackp; \
|
||
|
+ __tlb_flush_mm(current->mm); \
|
||
|
crst_table_downgrade(current->mm, 1UL << 31); \
|
||
|
+ update_mm(current->mm, current); \
|
||
|
} while (0)
|
||
|
|
||
|
/* Forward declaration, a strange C thing */
|
||
|
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
|
||
|
index b28aaa4..0fc0a7e 100644
|
||
|
--- a/arch/s390/mm/fault.c
|
||
|
+++ b/arch/s390/mm/fault.c
|
||
|
@@ -453,6 +453,7 @@ int __handle_fault(unsigned long uaddr, unsigned long pgm_int_code, int write)
|
||
|
struct pt_regs regs;
|
||
|
int access, fault;
|
||
|
|
||
|
+ /* Emulate a uaccess fault from kernel mode. */
|
||
|
regs.psw.mask = psw_kernel_bits | PSW_MASK_DAT | PSW_MASK_MCHECK;
|
||
|
if (!irqs_disabled())
|
||
|
regs.psw.mask |= PSW_MASK_IO | PSW_MASK_EXT;
|
||
|
@@ -461,12 +462,12 @@ int __handle_fault(unsigned long uaddr, unsigned long pgm_int_code, int write)
|
||
|
uaddr &= PAGE_MASK;
|
||
|
access = write ? VM_WRITE : VM_READ;
|
||
|
fault = do_exception(®s, access, uaddr | 2);
|
||
|
- if (unlikely(fault)) {
|
||
|
- if (fault & VM_FAULT_OOM)
|
||
|
- return -EFAULT;
|
||
|
- else if (fault & VM_FAULT_SIGBUS)
|
||
|
- do_sigbus(®s, pgm_int_code, uaddr);
|
||
|
- }
|
||
|
+ /*
|
||
|
+ * Since the fault happened in kernel mode while performing a uaccess
|
||
|
+ * all we need to do now is emulating a fixup in case "fault" is not
|
||
|
+ * zero.
|
||
|
+ * For the calling uaccess functions this results always in -EFAULT.
|
||
|
+ */
|
||
|
return fault ? -EFAULT : 0;
|
||
|
}
|
||
|
|
||
|
diff --git a/arch/s390/mm/mmap.c b/arch/s390/mm/mmap.c
|
||
|
index a0155c0..c70b3d8 100644
|
||
|
--- a/arch/s390/mm/mmap.c
|
||
|
+++ b/arch/s390/mm/mmap.c
|
||
|
@@ -106,9 +106,15 @@ EXPORT_SYMBOL_GPL(arch_pick_mmap_layout);
|
||
|
|
||
|
int s390_mmap_check(unsigned long addr, unsigned long len)
|
||
|
{
|
||
|
+ int rc;
|
||
|
+
|
||
|
if (!is_compat_task() &&
|
||
|
- len >= TASK_SIZE && TASK_SIZE < (1UL << 53))
|
||
|
- return crst_table_upgrade(current->mm, 1UL << 53);
|
||
|
+ len >= TASK_SIZE && TASK_SIZE < (1UL << 53)) {
|
||
|
+ rc = crst_table_upgrade(current->mm, 1UL << 53);
|
||
|
+ if (rc)
|
||
|
+ return rc;
|
||
|
+ update_mm(current->mm, current);
|
||
|
+ }
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@@ -128,6 +134,7 @@ s390_get_unmapped_area(struct file *filp, unsigned long addr,
|
||
|
rc = crst_table_upgrade(mm, 1UL << 53);
|
||
|
if (rc)
|
||
|
return (unsigned long) rc;
|
||
|
+ update_mm(mm, current);
|
||
|
area = arch_get_unmapped_area(filp, addr, len, pgoff, flags);
|
||
|
}
|
||
|
return area;
|
||
|
@@ -150,6 +157,7 @@ s390_get_unmapped_area_topdown(struct file *filp, const unsigned long addr,
|
||
|
rc = crst_table_upgrade(mm, 1UL << 53);
|
||
|
if (rc)
|
||
|
return (unsigned long) rc;
|
||
|
+ update_mm(mm, current);
|
||
|
area = arch_get_unmapped_area_topdown(filp, addr, len,
|
||
|
pgoff, flags);
|
||
|
}
|
||
|
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
|
||
|
index f8ceac4..f8e92f8 100644
|
||
|
--- a/arch/s390/mm/pgtable.c
|
||
|
+++ b/arch/s390/mm/pgtable.c
|
||
|
@@ -97,7 +97,6 @@ repeat:
|
||
|
crst_table_free(mm, table);
|
||
|
if (mm->context.asce_limit < limit)
|
||
|
goto repeat;
|
||
|
- update_mm(mm, current);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@@ -105,9 +104,6 @@ void crst_table_downgrade(struct mm_struct *mm, unsigned long limit)
|
||
|
{
|
||
|
pgd_t *pgd;
|
||
|
|
||
|
- if (mm->context.asce_limit <= limit)
|
||
|
- return;
|
||
|
- __tlb_flush_mm(mm);
|
||
|
while (mm->context.asce_limit > limit) {
|
||
|
pgd = mm->pgd;
|
||
|
switch (pgd_val(*pgd) & _REGION_ENTRY_TYPE_MASK) {
|
||
|
@@ -130,7 +126,6 @@ void crst_table_downgrade(struct mm_struct *mm, unsigned long limit)
|
||
|
mm->task_size = mm->context.asce_limit;
|
||
|
crst_table_free(mm, (unsigned long *) pgd);
|
||
|
}
|
||
|
- update_mm(mm, current);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
|
||
|
index 1f84794..73ef56c 100644
|
||
|
--- a/arch/x86/kernel/alternative.c
|
||
|
+++ b/arch/x86/kernel/alternative.c
|
||
|
@@ -219,7 +219,7 @@ void __init arch_init_ideal_nops(void)
|
||
|
ideal_nops = intel_nops;
|
||
|
#endif
|
||
|
}
|
||
|
-
|
||
|
+ break;
|
||
|
default:
|
||
|
#ifdef CONFIG_X86_64
|
||
|
ideal_nops = k8_nops;
|
||
|
diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c
|
||
|
index 1b267e7..00a0385 100644
|
||
|
--- a/arch/x86/xen/p2m.c
|
||
|
+++ b/arch/x86/xen/p2m.c
|
||
|
@@ -686,6 +686,7 @@ int m2p_add_override(unsigned long mfn, struct page *page,
|
||
|
unsigned long uninitialized_var(address);
|
||
|
unsigned level;
|
||
|
pte_t *ptep = NULL;
|
||
|
+ int ret = 0;
|
||
|
|
||
|
pfn = page_to_pfn(page);
|
||
|
if (!PageHighMem(page)) {
|
||
|
@@ -721,6 +722,24 @@ int m2p_add_override(unsigned long mfn, struct page *page,
|
||
|
list_add(&page->lru, &m2p_overrides[mfn_hash(mfn)]);
|
||
|
spin_unlock_irqrestore(&m2p_override_lock, flags);
|
||
|
|
||
|
+ /* p2m(m2p(mfn)) == mfn: the mfn is already present somewhere in
|
||
|
+ * this domain. Set the FOREIGN_FRAME_BIT in the p2m for the other
|
||
|
+ * pfn so that the following mfn_to_pfn(mfn) calls will return the
|
||
|
+ * pfn from the m2p_override (the backend pfn) instead.
|
||
|
+ * We need to do this because the pages shared by the frontend
|
||
|
+ * (xen-blkfront) can be already locked (lock_page, called by
|
||
|
+ * do_read_cache_page); when the userspace backend tries to use them
|
||
|
+ * with direct_IO, mfn_to_pfn returns the pfn of the frontend, so
|
||
|
+ * do_blockdev_direct_IO is going to try to lock the same pages
|
||
|
+ * again resulting in a deadlock.
|
||
|
+ * As a side effect get_user_pages_fast might not be safe on the
|
||
|
+ * frontend pages while they are being shared with the backend,
|
||
|
+ * because mfn_to_pfn (that ends up being called by GUPF) will
|
||
|
+ * return the backend pfn rather than the frontend pfn. */
|
||
|
+ ret = __get_user(pfn, &machine_to_phys_mapping[mfn]);
|
||
|
+ if (ret == 0 && get_phys_to_machine(pfn) == mfn)
|
||
|
+ set_phys_to_machine(pfn, FOREIGN_FRAME(mfn));
|
||
|
+
|
||
|
return 0;
|
||
|
}
|
||
|
EXPORT_SYMBOL_GPL(m2p_add_override);
|
||
|
@@ -732,6 +751,7 @@ int m2p_remove_override(struct page *page, bool clear_pte)
|
||
|
unsigned long uninitialized_var(address);
|
||
|
unsigned level;
|
||
|
pte_t *ptep = NULL;
|
||
|
+ int ret = 0;
|
||
|
|
||
|
pfn = page_to_pfn(page);
|
||
|
mfn = get_phys_to_machine(pfn);
|
||
|
@@ -801,6 +821,22 @@ int m2p_remove_override(struct page *page, bool clear_pte)
|
||
|
} else
|
||
|
set_phys_to_machine(pfn, page->index);
|
||
|
|
||
|
+ /* p2m(m2p(mfn)) == FOREIGN_FRAME(mfn): the mfn is already present
|
||
|
+ * somewhere in this domain, even before being added to the
|
||
|
+ * m2p_override (see comment above in m2p_add_override).
|
||
|
+ * If there are no other entries in the m2p_override corresponding
|
||
|
+ * to this mfn, then remove the FOREIGN_FRAME_BIT from the p2m for
|
||
|
+ * the original pfn (the one shared by the frontend): the backend
|
||
|
+ * cannot do any IO on this page anymore because it has been
|
||
|
+ * unshared. Removing the FOREIGN_FRAME_BIT from the p2m entry of
|
||
|
+ * the original pfn causes mfn_to_pfn(mfn) to return the frontend
|
||
|
+ * pfn again. */
|
||
|
+ mfn &= ~FOREIGN_FRAME_BIT;
|
||
|
+ ret = __get_user(pfn, &machine_to_phys_mapping[mfn]);
|
||
|
+ if (ret == 0 && get_phys_to_machine(pfn) == FOREIGN_FRAME(mfn) &&
|
||
|
+ m2p_find_override(mfn) == NULL)
|
||
|
+ set_phys_to_machine(pfn, mfn);
|
||
|
+
|
||
|
return 0;
|
||
|
}
|
||
|
EXPORT_SYMBOL_GPL(m2p_remove_override);
|
||
|
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
|
||
|
index 9955a53..c864add 100644
|
||
|
--- a/drivers/block/floppy.c
|
||
|
+++ b/drivers/block/floppy.c
|
||
|
@@ -4369,8 +4369,14 @@ out_unreg_blkdev:
|
||
|
out_put_disk:
|
||
|
while (dr--) {
|
||
|
del_timer_sync(&motor_off_timer[dr]);
|
||
|
- if (disks[dr]->queue)
|
||
|
+ if (disks[dr]->queue) {
|
||
|
blk_cleanup_queue(disks[dr]->queue);
|
||
|
+ /*
|
||
|
+ * put_disk() is not paired with add_disk() and
|
||
|
+ * will put queue reference one extra time. fix it.
|
||
|
+ */
|
||
|
+ disks[dr]->queue = NULL;
|
||
|
+ }
|
||
|
put_disk(disks[dr]);
|
||
|
}
|
||
|
return err;
|
||
|
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
|
||
|
index e46f2f7..650a308 100644
|
||
|
--- a/drivers/block/virtio_blk.c
|
||
|
+++ b/drivers/block/virtio_blk.c
|
||
|
@@ -20,8 +20,6 @@ struct workqueue_struct *virtblk_wq;
|
||
|
|
||
|
struct virtio_blk
|
||
|
{
|
||
|
- spinlock_t lock;
|
||
|
-
|
||
|
struct virtio_device *vdev;
|
||
|
struct virtqueue *vq;
|
||
|
|
||
|
@@ -62,7 +60,7 @@ static void blk_done(struct virtqueue *vq)
|
||
|
unsigned int len;
|
||
|
unsigned long flags;
|
||
|
|
||
|
- spin_lock_irqsave(&vblk->lock, flags);
|
||
|
+ spin_lock_irqsave(vblk->disk->queue->queue_lock, flags);
|
||
|
while ((vbr = virtqueue_get_buf(vblk->vq, &len)) != NULL) {
|
||
|
int error;
|
||
|
|
||
|
@@ -97,7 +95,7 @@ static void blk_done(struct virtqueue *vq)
|
||
|
}
|
||
|
/* In case queue is stopped waiting for more buffers. */
|
||
|
blk_start_queue(vblk->disk->queue);
|
||
|
- spin_unlock_irqrestore(&vblk->lock, flags);
|
||
|
+ spin_unlock_irqrestore(vblk->disk->queue->queue_lock, flags);
|
||
|
}
|
||
|
|
||
|
static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
|
||
|
@@ -384,7 +382,6 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
|
||
|
}
|
||
|
|
||
|
INIT_LIST_HEAD(&vblk->reqs);
|
||
|
- spin_lock_init(&vblk->lock);
|
||
|
vblk->vdev = vdev;
|
||
|
vblk->sg_elems = sg_elems;
|
||
|
sg_init_table(vblk->sg, vblk->sg_elems);
|
||
|
@@ -410,7 +407,7 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
|
||
|
goto out_mempool;
|
||
|
}
|
||
|
|
||
|
- q = vblk->disk->queue = blk_init_queue(do_virtblk_request, &vblk->lock);
|
||
|
+ q = vblk->disk->queue = blk_init_queue(do_virtblk_request, NULL);
|
||
|
if (!q) {
|
||
|
err = -ENOMEM;
|
||
|
goto out_put_disk;
|
||
|
diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c
|
||
|
index 5c0d96a..b12ffea 100644
|
||
|
--- a/drivers/char/mspec.c
|
||
|
+++ b/drivers/char/mspec.c
|
||
|
@@ -284,7 +284,7 @@ mspec_mmap(struct file *file, struct vm_area_struct *vma,
|
||
|
vdata->flags = flags;
|
||
|
vdata->type = type;
|
||
|
spin_lock_init(&vdata->lock);
|
||
|
- vdata->refcnt = ATOMIC_INIT(1);
|
||
|
+ atomic_set(&vdata->refcnt, 1);
|
||
|
vma->vm_private_data = vdata;
|
||
|
|
||
|
vma->vm_flags |= (VM_IO | VM_RESERVED | VM_PFNMAP | VM_DONTEXPAND);
|
||
|
diff --git a/drivers/char/random.c b/drivers/char/random.c
|
||
|
index 6035ab8..631d4f6 100644
|
||
|
--- a/drivers/char/random.c
|
||
|
+++ b/drivers/char/random.c
|
||
|
@@ -125,21 +125,26 @@
|
||
|
* The current exported interfaces for gathering environmental noise
|
||
|
* from the devices are:
|
||
|
*
|
||
|
+ * void add_device_randomness(const void *buf, unsigned int size);
|
||
|
* void add_input_randomness(unsigned int type, unsigned int code,
|
||
|
* unsigned int value);
|
||
|
- * void add_interrupt_randomness(int irq);
|
||
|
+ * void add_interrupt_randomness(int irq, int irq_flags);
|
||
|
* void add_disk_randomness(struct gendisk *disk);
|
||
|
*
|
||
|
+ * add_device_randomness() is for adding data to the random pool that
|
||
|
+ * is likely to differ between two devices (or possibly even per boot).
|
||
|
+ * This would be things like MAC addresses or serial numbers, or the
|
||
|
+ * read-out of the RTC. This does *not* add any actual entropy to the
|
||
|
+ * pool, but it initializes the pool to different values for devices
|
||
|
+ * that might otherwise be identical and have very little entropy
|
||
|
+ * available to them (particularly common in the embedded world).
|
||
|
+ *
|
||
|
* add_input_randomness() uses the input layer interrupt timing, as well as
|
||
|
* the event type information from the hardware.
|
||
|
*
|
||
|
- * add_interrupt_randomness() uses the inter-interrupt timing as random
|
||
|
- * inputs to the entropy pool. Note that not all interrupts are good
|
||
|
- * sources of randomness! For example, the timer interrupts is not a
|
||
|
- * good choice, because the periodicity of the interrupts is too
|
||
|
- * regular, and hence predictable to an attacker. Network Interface
|
||
|
- * Controller interrupts are a better measure, since the timing of the
|
||
|
- * NIC interrupts are more unpredictable.
|
||
|
+ * add_interrupt_randomness() uses the interrupt timing as random
|
||
|
+ * inputs to the entropy pool. Using the cycle counters and the irq source
|
||
|
+ * as inputs, it feeds the randomness roughly once a second.
|
||
|
*
|
||
|
* add_disk_randomness() uses what amounts to the seek time of block
|
||
|
* layer request events, on a per-disk_devt basis, as input to the
|
||
|
@@ -248,6 +253,8 @@
|
||
|
#include <linux/percpu.h>
|
||
|
#include <linux/cryptohash.h>
|
||
|
#include <linux/fips.h>
|
||
|
+#include <linux/ptrace.h>
|
||
|
+#include <linux/kmemcheck.h>
|
||
|
|
||
|
#ifdef CONFIG_GENERIC_HARDIRQS
|
||
|
# include <linux/irq.h>
|
||
|
@@ -256,6 +263,7 @@
|
||
|
#include <asm/processor.h>
|
||
|
#include <asm/uaccess.h>
|
||
|
#include <asm/irq.h>
|
||
|
+#include <asm/irq_regs.h>
|
||
|
#include <asm/io.h>
|
||
|
|
||
|
/*
|
||
|
@@ -266,6 +274,8 @@
|
||
|
#define SEC_XFER_SIZE 512
|
||
|
#define EXTRACT_SIZE 10
|
||
|
|
||
|
+#define LONGS(x) (((x) + sizeof(unsigned long) - 1)/sizeof(unsigned long))
|
||
|
+
|
||
|
/*
|
||
|
* The minimum number of bits of entropy before we wake up a read on
|
||
|
* /dev/random. Should be enough to do a significant reseed.
|
||
|
@@ -420,8 +430,10 @@ struct entropy_store {
|
||
|
/* read-write data: */
|
||
|
spinlock_t lock;
|
||
|
unsigned add_ptr;
|
||
|
+ unsigned input_rotate;
|
||
|
int entropy_count;
|
||
|
- int input_rotate;
|
||
|
+ int entropy_total;
|
||
|
+ unsigned int initialized:1;
|
||
|
__u8 last_data[EXTRACT_SIZE];
|
||
|
};
|
||
|
|
||
|
@@ -454,6 +466,10 @@ static struct entropy_store nonblocking_pool = {
|
||
|
.pool = nonblocking_pool_data
|
||
|
};
|
||
|
|
||
|
+static __u32 const twist_table[8] = {
|
||
|
+ 0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158,
|
||
|
+ 0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 };
|
||
|
+
|
||
|
/*
|
||
|
* This function adds bytes into the entropy "pool". It does not
|
||
|
* update the entropy estimate. The caller should call
|
||
|
@@ -464,29 +480,24 @@ static struct entropy_store nonblocking_pool = {
|
||
|
* it's cheap to do so and helps slightly in the expected case where
|
||
|
* the entropy is concentrated in the low-order bits.
|
||
|
*/
|
||
|
-static void mix_pool_bytes_extract(struct entropy_store *r, const void *in,
|
||
|
- int nbytes, __u8 out[64])
|
||
|
+static void __mix_pool_bytes(struct entropy_store *r, const void *in,
|
||
|
+ int nbytes, __u8 out[64])
|
||
|
{
|
||
|
- static __u32 const twist_table[8] = {
|
||
|
- 0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158,
|
||
|
- 0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 };
|
||
|
unsigned long i, j, tap1, tap2, tap3, tap4, tap5;
|
||
|
int input_rotate;
|
||
|
int wordmask = r->poolinfo->poolwords - 1;
|
||
|
const char *bytes = in;
|
||
|
__u32 w;
|
||
|
- unsigned long flags;
|
||
|
|
||
|
- /* Taps are constant, so we can load them without holding r->lock. */
|
||
|
tap1 = r->poolinfo->tap1;
|
||
|
tap2 = r->poolinfo->tap2;
|
||
|
tap3 = r->poolinfo->tap3;
|
||
|
tap4 = r->poolinfo->tap4;
|
||
|
tap5 = r->poolinfo->tap5;
|
||
|
|
||
|
- spin_lock_irqsave(&r->lock, flags);
|
||
|
- input_rotate = r->input_rotate;
|
||
|
- i = r->add_ptr;
|
||
|
+ smp_rmb();
|
||
|
+ input_rotate = ACCESS_ONCE(r->input_rotate);
|
||
|
+ i = ACCESS_ONCE(r->add_ptr);
|
||
|
|
||
|
/* mix one byte at a time to simplify size handling and churn faster */
|
||
|
while (nbytes--) {
|
||
|
@@ -513,19 +524,53 @@ static void mix_pool_bytes_extract(struct entropy_store *r, const void *in,
|
||
|
input_rotate += i ? 7 : 14;
|
||
|
}
|
||
|
|
||
|
- r->input_rotate = input_rotate;
|
||
|
- r->add_ptr = i;
|
||
|
+ ACCESS_ONCE(r->input_rotate) = input_rotate;
|
||
|
+ ACCESS_ONCE(r->add_ptr) = i;
|
||
|
+ smp_wmb();
|
||
|
|
||
|
if (out)
|
||
|
for (j = 0; j < 16; j++)
|
||
|
((__u32 *)out)[j] = r->pool[(i - j) & wordmask];
|
||
|
+}
|
||
|
+
|
||
|
+static void mix_pool_bytes(struct entropy_store *r, const void *in,
|
||
|
+ int nbytes, __u8 out[64])
|
||
|
+{
|
||
|
+ unsigned long flags;
|
||
|
|
||
|
+ spin_lock_irqsave(&r->lock, flags);
|
||
|
+ __mix_pool_bytes(r, in, nbytes, out);
|
||
|
spin_unlock_irqrestore(&r->lock, flags);
|
||
|
}
|
||
|
|
||
|
-static void mix_pool_bytes(struct entropy_store *r, const void *in, int bytes)
|
||
|
+struct fast_pool {
|
||
|
+ __u32 pool[4];
|
||
|
+ unsigned long last;
|
||
|
+ unsigned short count;
|
||
|
+ unsigned char rotate;
|
||
|
+ unsigned char last_timer_intr;
|
||
|
+};
|
||
|
+
|
||
|
+/*
|
||
|
+ * This is a fast mixing routine used by the interrupt randomness
|
||
|
+ * collector. It's hardcoded for an 128 bit pool and assumes that any
|
||
|
+ * locks that might be needed are taken by the caller.
|
||
|
+ */
|
||
|
+static void fast_mix(struct fast_pool *f, const void *in, int nbytes)
|
||
|
{
|
||
|
- mix_pool_bytes_extract(r, in, bytes, NULL);
|
||
|
+ const char *bytes = in;
|
||
|
+ __u32 w;
|
||
|
+ unsigned i = f->count;
|
||
|
+ unsigned input_rotate = f->rotate;
|
||
|
+
|
||
|
+ while (nbytes--) {
|
||
|
+ w = rol32(*bytes++, input_rotate & 31) ^ f->pool[i & 3] ^
|
||
|
+ f->pool[(i + 1) & 3];
|
||
|
+ f->pool[i & 3] = (w >> 3) ^ twist_table[w & 7];
|
||
|
+ input_rotate += (i++ & 3) ? 7 : 14;
|
||
|
+ }
|
||
|
+ f->count = i;
|
||
|
+ f->rotate = input_rotate;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
@@ -533,30 +578,34 @@ static void mix_pool_bytes(struct entropy_store *r, const void *in, int bytes)
|
||
|
*/
|
||
|
static void credit_entropy_bits(struct entropy_store *r, int nbits)
|
||
|
{
|
||
|
- unsigned long flags;
|
||
|
- int entropy_count;
|
||
|
+ int entropy_count, orig;
|
||
|
|
||
|
if (!nbits)
|
||
|
return;
|
||
|
|
||
|
- spin_lock_irqsave(&r->lock, flags);
|
||
|
-
|
||
|
DEBUG_ENT("added %d entropy credits to %s\n", nbits, r->name);
|
||
|
- entropy_count = r->entropy_count;
|
||
|
+retry:
|
||
|
+ entropy_count = orig = ACCESS_ONCE(r->entropy_count);
|
||
|
entropy_count += nbits;
|
||
|
if (entropy_count < 0) {
|
||
|
DEBUG_ENT("negative entropy/overflow\n");
|
||
|
entropy_count = 0;
|
||
|
} else if (entropy_count > r->poolinfo->POOLBITS)
|
||
|
entropy_count = r->poolinfo->POOLBITS;
|
||
|
- r->entropy_count = entropy_count;
|
||
|
+ if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig)
|
||
|
+ goto retry;
|
||
|
+
|
||
|
+ if (!r->initialized && nbits > 0) {
|
||
|
+ r->entropy_total += nbits;
|
||
|
+ if (r->entropy_total > 128)
|
||
|
+ r->initialized = 1;
|
||
|
+ }
|
||
|
|
||
|
/* should we wake readers? */
|
||
|
if (r == &input_pool && entropy_count >= random_read_wakeup_thresh) {
|
||
|
wake_up_interruptible(&random_read_wait);
|
||
|
kill_fasync(&fasync, SIGIO, POLL_IN);
|
||
|
}
|
||
|
- spin_unlock_irqrestore(&r->lock, flags);
|
||
|
}
|
||
|
|
||
|
/*********************************************************************
|
||
|
@@ -609,6 +658,25 @@ static void set_timer_rand_state(unsigned int irq,
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
+/*
|
||
|
+ * Add device- or boot-specific data to the input and nonblocking
|
||
|
+ * pools to help initialize them to unique values.
|
||
|
+ *
|
||
|
+ * None of this adds any entropy, it is meant to avoid the
|
||
|
+ * problem of the nonblocking pool having similar initial state
|
||
|
+ * across largely identical devices.
|
||
|
+ */
|
||
|
+void add_device_randomness(const void *buf, unsigned int size)
|
||
|
+{
|
||
|
+ unsigned long time = get_cycles() ^ jiffies;
|
||
|
+
|
||
|
+ mix_pool_bytes(&input_pool, buf, size, NULL);
|
||
|
+ mix_pool_bytes(&input_pool, &time, sizeof(time), NULL);
|
||
|
+ mix_pool_bytes(&nonblocking_pool, buf, size, NULL);
|
||
|
+ mix_pool_bytes(&nonblocking_pool, &time, sizeof(time), NULL);
|
||
|
+}
|
||
|
+EXPORT_SYMBOL(add_device_randomness);
|
||
|
+
|
||
|
static struct timer_rand_state input_timer_state;
|
||
|
|
||
|
/*
|
||
|
@@ -624,8 +692,8 @@ static struct timer_rand_state input_timer_state;
|
||
|
static void add_timer_randomness(struct timer_rand_state *state, unsigned num)
|
||
|
{
|
||
|
struct {
|
||
|
- cycles_t cycles;
|
||
|
long jiffies;
|
||
|
+ unsigned cycles;
|
||
|
unsigned num;
|
||
|
} sample;
|
||
|
long delta, delta2, delta3;
|
||
|
@@ -639,7 +707,7 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num)
|
||
|
sample.jiffies = jiffies;
|
||
|
sample.cycles = get_cycles();
|
||
|
sample.num = num;
|
||
|
- mix_pool_bytes(&input_pool, &sample, sizeof(sample));
|
||
|
+ mix_pool_bytes(&input_pool, &sample, sizeof(sample), NULL);
|
||
|
|
||
|
/*
|
||
|
* Calculate number of bits of randomness we probably added.
|
||
|
@@ -696,17 +764,48 @@ void add_input_randomness(unsigned int type, unsigned int code,
|
||
|
}
|
||
|
EXPORT_SYMBOL_GPL(add_input_randomness);
|
||
|
|
||
|
-void add_interrupt_randomness(int irq)
|
||
|
+static DEFINE_PER_CPU(struct fast_pool, irq_randomness);
|
||
|
+
|
||
|
+void add_interrupt_randomness(int irq, int irq_flags)
|
||
|
{
|
||
|
- struct timer_rand_state *state;
|
||
|
+ struct entropy_store *r;
|
||
|
+ struct fast_pool *fast_pool = &__get_cpu_var(irq_randomness);
|
||
|
+ struct pt_regs *regs = get_irq_regs();
|
||
|
+ unsigned long now = jiffies;
|
||
|
+ __u32 input[4], cycles = get_cycles();
|
||
|
+
|
||
|
+ input[0] = cycles ^ jiffies;
|
||
|
+ input[1] = irq;
|
||
|
+ if (regs) {
|
||
|
+ __u64 ip = instruction_pointer(regs);
|
||
|
+ input[2] = ip;
|
||
|
+ input[3] = ip >> 32;
|
||
|
+ }
|
||
|
|
||
|
- state = get_timer_rand_state(irq);
|
||
|
+ fast_mix(fast_pool, input, sizeof(input));
|
||
|
|
||
|
- if (state == NULL)
|
||
|
+ if ((fast_pool->count & 1023) &&
|
||
|
+ !time_after(now, fast_pool->last + HZ))
|
||
|
return;
|
||
|
|
||
|
- DEBUG_ENT("irq event %d\n", irq);
|
||
|
- add_timer_randomness(state, 0x100 + irq);
|
||
|
+ fast_pool->last = now;
|
||
|
+
|
||
|
+ r = nonblocking_pool.initialized ? &input_pool : &nonblocking_pool;
|
||
|
+ __mix_pool_bytes(r, &fast_pool->pool, sizeof(fast_pool->pool), NULL);
|
||
|
+ /*
|
||
|
+ * If we don't have a valid cycle counter, and we see
|
||
|
+ * back-to-back timer interrupts, then skip giving credit for
|
||
|
+ * any entropy.
|
||
|
+ */
|
||
|
+ if (cycles == 0) {
|
||
|
+ if (irq_flags & __IRQF_TIMER) {
|
||
|
+ if (fast_pool->last_timer_intr)
|
||
|
+ return;
|
||
|
+ fast_pool->last_timer_intr = 1;
|
||
|
+ } else
|
||
|
+ fast_pool->last_timer_intr = 0;
|
||
|
+ }
|
||
|
+ credit_entropy_bits(r, 1);
|
||
|
}
|
||
|
|
||
|
#ifdef CONFIG_BLOCK
|
||
|
@@ -738,7 +837,7 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf,
|
||
|
*/
|
||
|
static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes)
|
||
|
{
|
||
|
- __u32 tmp[OUTPUT_POOL_WORDS];
|
||
|
+ __u32 tmp[OUTPUT_POOL_WORDS];
|
||
|
|
||
|
if (r->pull && r->entropy_count < nbytes * 8 &&
|
||
|
r->entropy_count < r->poolinfo->POOLBITS) {
|
||
|
@@ -757,7 +856,7 @@ static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes)
|
||
|
|
||
|
bytes = extract_entropy(r->pull, tmp, bytes,
|
||
|
random_read_wakeup_thresh / 8, rsvd);
|
||
|
- mix_pool_bytes(r, tmp, bytes);
|
||
|
+ mix_pool_bytes(r, tmp, bytes, NULL);
|
||
|
credit_entropy_bits(r, bytes*8);
|
||
|
}
|
||
|
}
|
||
|
@@ -816,13 +915,19 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min,
|
||
|
static void extract_buf(struct entropy_store *r, __u8 *out)
|
||
|
{
|
||
|
int i;
|
||
|
- __u32 hash[5], workspace[SHA_WORKSPACE_WORDS];
|
||
|
+ union {
|
||
|
+ __u32 w[5];
|
||
|
+ unsigned long l[LONGS(EXTRACT_SIZE)];
|
||
|
+ } hash;
|
||
|
+ __u32 workspace[SHA_WORKSPACE_WORDS];
|
||
|
__u8 extract[64];
|
||
|
+ unsigned long flags;
|
||
|
|
||
|
/* Generate a hash across the pool, 16 words (512 bits) at a time */
|
||
|
- sha_init(hash);
|
||
|
+ sha_init(hash.w);
|
||
|
+ spin_lock_irqsave(&r->lock, flags);
|
||
|
for (i = 0; i < r->poolinfo->poolwords; i += 16)
|
||
|
- sha_transform(hash, (__u8 *)(r->pool + i), workspace);
|
||
|
+ sha_transform(hash.w, (__u8 *)(r->pool + i), workspace);
|
||
|
|
||
|
/*
|
||
|
* We mix the hash back into the pool to prevent backtracking
|
||
|
@@ -833,13 +938,14 @@ static void extract_buf(struct entropy_store *r, __u8 *out)
|
||
|
* brute-forcing the feedback as hard as brute-forcing the
|
||
|
* hash.
|
||
|
*/
|
||
|
- mix_pool_bytes_extract(r, hash, sizeof(hash), extract);
|
||
|
+ __mix_pool_bytes(r, hash.w, sizeof(hash.w), extract);
|
||
|
+ spin_unlock_irqrestore(&r->lock, flags);
|
||
|
|
||
|
/*
|
||
|
* To avoid duplicates, we atomically extract a portion of the
|
||
|
* pool while mixing, and hash one final time.
|
||
|
*/
|
||
|
- sha_transform(hash, extract, workspace);
|
||
|
+ sha_transform(hash.w, extract, workspace);
|
||
|
memset(extract, 0, sizeof(extract));
|
||
|
memset(workspace, 0, sizeof(workspace));
|
||
|
|
||
|
@@ -848,19 +954,30 @@ static void extract_buf(struct entropy_store *r, __u8 *out)
|
||
|
* pattern, we fold it in half. Thus, we always feed back
|
||
|
* twice as much data as we output.
|
||
|
*/
|
||
|
- hash[0] ^= hash[3];
|
||
|
- hash[1] ^= hash[4];
|
||
|
- hash[2] ^= rol32(hash[2], 16);
|
||
|
- memcpy(out, hash, EXTRACT_SIZE);
|
||
|
- memset(hash, 0, sizeof(hash));
|
||
|
+ hash.w[0] ^= hash.w[3];
|
||
|
+ hash.w[1] ^= hash.w[4];
|
||
|
+ hash.w[2] ^= rol32(hash.w[2], 16);
|
||
|
+
|
||
|
+ /*
|
||
|
+ * If we have a architectural hardware random number
|
||
|
+ * generator, mix that in, too.
|
||
|
+ */
|
||
|
+ for (i = 0; i < LONGS(EXTRACT_SIZE); i++) {
|
||
|
+ unsigned long v;
|
||
|
+ if (!arch_get_random_long(&v))
|
||
|
+ break;
|
||
|
+ hash.l[i] ^= v;
|
||
|
+ }
|
||
|
+
|
||
|
+ memcpy(out, &hash, EXTRACT_SIZE);
|
||
|
+ memset(&hash, 0, sizeof(hash));
|
||
|
}
|
||
|
|
||
|
static ssize_t extract_entropy(struct entropy_store *r, void *buf,
|
||
|
- size_t nbytes, int min, int reserved)
|
||
|
+ size_t nbytes, int min, int reserved)
|
||
|
{
|
||
|
ssize_t ret = 0, i;
|
||
|
__u8 tmp[EXTRACT_SIZE];
|
||
|
- unsigned long flags;
|
||
|
|
||
|
xfer_secondary_pool(r, nbytes);
|
||
|
nbytes = account(r, nbytes, min, reserved);
|
||
|
@@ -869,6 +986,8 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf,
|
||
|
extract_buf(r, tmp);
|
||
|
|
||
|
if (fips_enabled) {
|
||
|
+ unsigned long flags;
|
||
|
+
|
||
|
spin_lock_irqsave(&r->lock, flags);
|
||
|
if (!memcmp(tmp, r->last_data, EXTRACT_SIZE))
|
||
|
panic("Hardware RNG duplicated output!\n");
|
||
|
@@ -927,17 +1046,34 @@ static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf,
|
||
|
|
||
|
/*
|
||
|
* This function is the exported kernel interface. It returns some
|
||
|
- * number of good random numbers, suitable for seeding TCP sequence
|
||
|
- * numbers, etc.
|
||
|
+ * number of good random numbers, suitable for key generation, seeding
|
||
|
+ * TCP sequence numbers, etc. It does not use the hw random number
|
||
|
+ * generator, if available; use get_random_bytes_arch() for that.
|
||
|
*/
|
||
|
void get_random_bytes(void *buf, int nbytes)
|
||
|
{
|
||
|
+ extract_entropy(&nonblocking_pool, buf, nbytes, 0, 0);
|
||
|
+}
|
||
|
+EXPORT_SYMBOL(get_random_bytes);
|
||
|
+
|
||
|
+/*
|
||
|
+ * This function will use the architecture-specific hardware random
|
||
|
+ * number generator if it is available. The arch-specific hw RNG will
|
||
|
+ * almost certainly be faster than what we can do in software, but it
|
||
|
+ * is impossible to verify that it is implemented securely (as
|
||
|
+ * opposed, to, say, the AES encryption of a sequence number using a
|
||
|
+ * key known by the NSA). So it's useful if we need the speed, but
|
||
|
+ * only if we're willing to trust the hardware manufacturer not to
|
||
|
+ * have put in a back door.
|
||
|
+ */
|
||
|
+void get_random_bytes_arch(void *buf, int nbytes)
|
||
|
+{
|
||
|
char *p = buf;
|
||
|
|
||
|
while (nbytes) {
|
||
|
unsigned long v;
|
||
|
int chunk = min(nbytes, (int)sizeof(unsigned long));
|
||
|
-
|
||
|
+
|
||
|
if (!arch_get_random_long(&v))
|
||
|
break;
|
||
|
|
||
|
@@ -946,9 +1082,11 @@ void get_random_bytes(void *buf, int nbytes)
|
||
|
nbytes -= chunk;
|
||
|
}
|
||
|
|
||
|
- extract_entropy(&nonblocking_pool, p, nbytes, 0, 0);
|
||
|
+ if (nbytes)
|
||
|
+ extract_entropy(&nonblocking_pool, p, nbytes, 0, 0);
|
||
|
}
|
||
|
-EXPORT_SYMBOL(get_random_bytes);
|
||
|
+EXPORT_SYMBOL(get_random_bytes_arch);
|
||
|
+
|
||
|
|
||
|
/*
|
||
|
* init_std_data - initialize pool with system data
|
||
|
@@ -961,16 +1099,19 @@ EXPORT_SYMBOL(get_random_bytes);
|
||
|
*/
|
||
|
static void init_std_data(struct entropy_store *r)
|
||
|
{
|
||
|
- ktime_t now;
|
||
|
- unsigned long flags;
|
||
|
+ int i;
|
||
|
+ ktime_t now = ktime_get_real();
|
||
|
+ unsigned long rv;
|
||
|
|
||
|
- spin_lock_irqsave(&r->lock, flags);
|
||
|
r->entropy_count = 0;
|
||
|
- spin_unlock_irqrestore(&r->lock, flags);
|
||
|
-
|
||
|
- now = ktime_get_real();
|
||
|
- mix_pool_bytes(r, &now, sizeof(now));
|
||
|
- mix_pool_bytes(r, utsname(), sizeof(*(utsname())));
|
||
|
+ r->entropy_total = 0;
|
||
|
+ mix_pool_bytes(r, &now, sizeof(now), NULL);
|
||
|
+ for (i = r->poolinfo->POOLBYTES; i > 0; i -= sizeof(rv)) {
|
||
|
+ if (!arch_get_random_long(&rv))
|
||
|
+ break;
|
||
|
+ mix_pool_bytes(r, &rv, sizeof(rv), NULL);
|
||
|
+ }
|
||
|
+ mix_pool_bytes(r, utsname(), sizeof(*(utsname())), NULL);
|
||
|
}
|
||
|
|
||
|
static int rand_initialize(void)
|
||
|
@@ -1107,7 +1248,7 @@ write_pool(struct entropy_store *r, const char __user *buffer, size_t count)
|
||
|
count -= bytes;
|
||
|
p += bytes;
|
||
|
|
||
|
- mix_pool_bytes(r, buf, bytes);
|
||
|
+ mix_pool_bytes(r, buf, bytes, NULL);
|
||
|
cond_resched();
|
||
|
}
|
||
|
|
||
|
diff --git a/drivers/firmware/pcdp.c b/drivers/firmware/pcdp.c
|
||
|
index 51e0e2d..a330492 100644
|
||
|
--- a/drivers/firmware/pcdp.c
|
||
|
+++ b/drivers/firmware/pcdp.c
|
||
|
@@ -95,7 +95,7 @@ efi_setup_pcdp_console(char *cmdline)
|
||
|
if (efi.hcdp == EFI_INVALID_TABLE_ADDR)
|
||
|
return -ENODEV;
|
||
|
|
||
|
- pcdp = ioremap(efi.hcdp, 4096);
|
||
|
+ pcdp = early_ioremap(efi.hcdp, 4096);
|
||
|
printk(KERN_INFO "PCDP: v%d at 0x%lx\n", pcdp->rev, efi.hcdp);
|
||
|
|
||
|
if (strstr(cmdline, "console=hcdp")) {
|
||
|
@@ -131,6 +131,6 @@ efi_setup_pcdp_console(char *cmdline)
|
||
|
}
|
||
|
|
||
|
out:
|
||
|
- iounmap(pcdp);
|
||
|
+ early_iounmap(pcdp, 4096);
|
||
|
return rc;
|
||
|
}
|
||
|
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
|
||
|
index d4c4937..fae2050 100644
|
||
|
--- a/drivers/gpu/drm/i915/intel_dp.c
|
||
|
+++ b/drivers/gpu/drm/i915/intel_dp.c
|
||
|
@@ -708,8 +708,8 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
|
||
|
|
||
|
bpp = adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC ? 18 : 24;
|
||
|
|
||
|
- for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) {
|
||
|
- for (clock = 0; clock <= max_clock; clock++) {
|
||
|
+ for (clock = 0; clock <= max_clock; clock++) {
|
||
|
+ for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) {
|
||
|
int link_avail = intel_dp_max_data_rate(intel_dp_link_clock(bws[clock]), lane_count);
|
||
|
|
||
|
if (intel_dp_link_required(mode->clock, bpp)
|
||
|
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
|
||
|
index a6dcd18..96532bc 100644
|
||
|
--- a/drivers/input/mouse/synaptics.c
|
||
|
+++ b/drivers/input/mouse/synaptics.c
|
||
|
@@ -40,11 +40,28 @@
|
||
|
* Note that newer firmware allows querying device for maximum useable
|
||
|
* coordinates.
|
||
|
*/
|
||
|
+#define XMIN 0
|
||
|
+#define XMAX 6143
|
||
|
+#define YMIN 0
|
||
|
+#define YMAX 6143
|
||
|
#define XMIN_NOMINAL 1472
|
||
|
#define XMAX_NOMINAL 5472
|
||
|
#define YMIN_NOMINAL 1408
|
||
|
#define YMAX_NOMINAL 4448
|
||
|
|
||
|
+/* Size in bits of absolute position values reported by the hardware */
|
||
|
+#define ABS_POS_BITS 13
|
||
|
+
|
||
|
+/*
|
||
|
+ * Any position values from the hardware above the following limits are
|
||
|
+ * treated as "wrapped around negative" values that have been truncated to
|
||
|
+ * the 13-bit reporting range of the hardware. These are just reasonable
|
||
|
+ * guesses and can be adjusted if hardware is found that operates outside
|
||
|
+ * of these parameters.
|
||
|
+ */
|
||
|
+#define X_MAX_POSITIVE (((1 << ABS_POS_BITS) + XMAX) / 2)
|
||
|
+#define Y_MAX_POSITIVE (((1 << ABS_POS_BITS) + YMAX) / 2)
|
||
|
+
|
||
|
/*
|
||
|
* Synaptics touchpads report the y coordinate from bottom to top, which is
|
||
|
* opposite from what userspace expects.
|
||
|
@@ -544,6 +561,12 @@ static int synaptics_parse_hw_state(const unsigned char buf[],
|
||
|
hw->right = (buf[0] & 0x02) ? 1 : 0;
|
||
|
}
|
||
|
|
||
|
+ /* Convert wrap-around values to negative */
|
||
|
+ if (hw->x > X_MAX_POSITIVE)
|
||
|
+ hw->x -= 1 << ABS_POS_BITS;
|
||
|
+ if (hw->y > Y_MAX_POSITIVE)
|
||
|
+ hw->y -= 1 << ABS_POS_BITS;
|
||
|
+
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c
|
||
|
index 532a902..d432032 100644
|
||
|
--- a/drivers/md/dm-thin.c
|
||
|
+++ b/drivers/md/dm-thin.c
|
||
|
@@ -19,7 +19,7 @@
|
||
|
/*
|
||
|
* Tunable constants
|
||
|
*/
|
||
|
-#define ENDIO_HOOK_POOL_SIZE 10240
|
||
|
+#define ENDIO_HOOK_POOL_SIZE 1024
|
||
|
#define DEFERRED_SET_SIZE 64
|
||
|
#define MAPPING_POOL_SIZE 1024
|
||
|
#define PRISON_CELLS 1024
|
||
|
@@ -857,7 +857,7 @@ static void process_prepared_mapping(struct new_mapping *m)
|
||
|
|
||
|
if (m->err) {
|
||
|
cell_error(m->cell);
|
||
|
- return;
|
||
|
+ goto out;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
@@ -869,7 +869,7 @@ static void process_prepared_mapping(struct new_mapping *m)
|
||
|
if (r) {
|
||
|
DMERR("dm_thin_insert_block() failed");
|
||
|
cell_error(m->cell);
|
||
|
- return;
|
||
|
+ goto out;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
@@ -884,6 +884,7 @@ static void process_prepared_mapping(struct new_mapping *m)
|
||
|
} else
|
||
|
cell_defer(tc, m->cell, m->data_block);
|
||
|
|
||
|
+out:
|
||
|
list_del(&m->list);
|
||
|
mempool_free(m, tc->pool->mapping_pool);
|
||
|
}
|
||
|
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
|
||
|
index 2d97bf0..62306e5 100644
|
||
|
--- a/drivers/md/raid1.c
|
||
|
+++ b/drivers/md/raid1.c
|
||
|
@@ -2321,7 +2321,10 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, int *skipp
|
||
|
/* There is nowhere to write, so all non-sync
|
||
|
* drives must be failed - so we are finished
|
||
|
*/
|
||
|
- sector_t rv = max_sector - sector_nr;
|
||
|
+ sector_t rv;
|
||
|
+ if (min_bad > 0)
|
||
|
+ max_sector = sector_nr + min_bad;
|
||
|
+ rv = max_sector - sector_nr;
|
||
|
*skipped = 1;
|
||
|
put_buf(r1_bio);
|
||
|
return rv;
|
||
|
diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c
|
||
|
index ed77c6d..5327061 100644
|
||
|
--- a/drivers/media/rc/ene_ir.c
|
||
|
+++ b/drivers/media/rc/ene_ir.c
|
||
|
@@ -1018,6 +1018,8 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
|
||
|
|
||
|
spin_lock_init(&dev->hw_lock);
|
||
|
|
||
|
+ dev->hw_io = pnp_port_start(pnp_dev, 0);
|
||
|
+
|
||
|
pnp_set_drvdata(pnp_dev, dev);
|
||
|
dev->pnp_dev = pnp_dev;
|
||
|
|
||
|
@@ -1072,7 +1074,6 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
|
||
|
|
||
|
/* claim the resources */
|
||
|
error = -EBUSY;
|
||
|
- dev->hw_io = pnp_port_start(pnp_dev, 0);
|
||
|
if (!request_region(dev->hw_io, ENE_IO_SIZE, ENE_DRIVER_NAME)) {
|
||
|
dev->hw_io = -1;
|
||
|
dev->irq = -1;
|
||
|
diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c
|
||
|
index 60107ee..4eec7b7 100644
|
||
|
--- a/drivers/mfd/ab3100-core.c
|
||
|
+++ b/drivers/mfd/ab3100-core.c
|
||
|
@@ -409,8 +409,6 @@ static irqreturn_t ab3100_irq_handler(int irq, void *data)
|
||
|
u32 fatevent;
|
||
|
int err;
|
||
|
|
||
|
- add_interrupt_randomness(irq);
|
||
|
-
|
||
|
err = ab3100_get_register_page_interruptible(ab3100, AB3100_EVENTA1,
|
||
|
event_regs, 3);
|
||
|
if (err)
|
||
|
diff --git a/drivers/mfd/wm831x-otp.c b/drivers/mfd/wm831x-otp.c
|
||
|
index f742745..b90f3e0 100644
|
||
|
--- a/drivers/mfd/wm831x-otp.c
|
||
|
+++ b/drivers/mfd/wm831x-otp.c
|
||
|
@@ -18,6 +18,7 @@
|
||
|
#include <linux/bcd.h>
|
||
|
#include <linux/delay.h>
|
||
|
#include <linux/mfd/core.h>
|
||
|
+#include <linux/random.h>
|
||
|
|
||
|
#include <linux/mfd/wm831x/core.h>
|
||
|
#include <linux/mfd/wm831x/otp.h>
|
||
|
@@ -66,6 +67,7 @@ static DEVICE_ATTR(unique_id, 0444, wm831x_unique_id_show, NULL);
|
||
|
|
||
|
int wm831x_otp_init(struct wm831x *wm831x)
|
||
|
{
|
||
|
+ char uuid[WM831X_UNIQUE_ID_LEN];
|
||
|
int ret;
|
||
|
|
||
|
ret = device_create_file(wm831x->dev, &dev_attr_unique_id);
|
||
|
@@ -73,6 +75,12 @@ int wm831x_otp_init(struct wm831x *wm831x)
|
||
|
dev_err(wm831x->dev, "Unique ID attribute not created: %d\n",
|
||
|
ret);
|
||
|
|
||
|
+ ret = wm831x_unique_id_read(wm831x, uuid);
|
||
|
+ if (ret == 0)
|
||
|
+ add_device_randomness(uuid, sizeof(uuid));
|
||
|
+ else
|
||
|
+ dev_err(wm831x->dev, "Failed to read UUID: %d\n", ret);
|
||
|
+
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
|
||
|
index bdf960b..ae7528b 100644
|
||
|
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
|
||
|
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
|
||
|
@@ -925,6 +925,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
|
||
|
{ USB_DEVICE(0x0411, 0x015d) },
|
||
|
{ USB_DEVICE(0x0411, 0x016f) },
|
||
|
{ USB_DEVICE(0x0411, 0x01a2) },
|
||
|
+ { USB_DEVICE(0x0411, 0x01ee) },
|
||
|
/* Corega */
|
||
|
{ USB_DEVICE(0x07aa, 0x002f) },
|
||
|
{ USB_DEVICE(0x07aa, 0x003c) },
|
||
|
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
|
||
|
index d1049ee..26fba2d 100644
|
||
|
--- a/drivers/platform/x86/asus-wmi.c
|
||
|
+++ b/drivers/platform/x86/asus-wmi.c
|
||
|
@@ -1431,14 +1431,9 @@ static int asus_wmi_platform_init(struct asus_wmi *asus)
|
||
|
*/
|
||
|
if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, 0, 0, NULL))
|
||
|
asus->dsts_id = ASUS_WMI_METHODID_DSTS;
|
||
|
- else if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS2, 0, 0, NULL))
|
||
|
+ else
|
||
|
asus->dsts_id = ASUS_WMI_METHODID_DSTS2;
|
||
|
|
||
|
- if (!asus->dsts_id) {
|
||
|
- pr_err("Can't find DSTS");
|
||
|
- return -ENODEV;
|
||
|
- }
|
||
|
-
|
||
|
/* CWAP allow to define the behavior of the Fn+F2 key,
|
||
|
* this method doesn't seems to be present on Eee PCs */
|
||
|
if (asus->driver->wapf >= 0)
|
||
|
diff --git a/drivers/rtc/rtc-wm831x.c b/drivers/rtc/rtc-wm831x.c
|
||
|
index bdc909b..f3c2110 100644
|
||
|
--- a/drivers/rtc/rtc-wm831x.c
|
||
|
+++ b/drivers/rtc/rtc-wm831x.c
|
||
|
@@ -24,7 +24,7 @@
|
||
|
#include <linux/mfd/wm831x/core.h>
|
||
|
#include <linux/delay.h>
|
||
|
#include <linux/platform_device.h>
|
||
|
-
|
||
|
+#include <linux/random.h>
|
||
|
|
||
|
/*
|
||
|
* R16416 (0x4020) - RTC Write Counter
|
||
|
@@ -96,6 +96,26 @@ struct wm831x_rtc {
|
||
|
unsigned int alarm_enabled:1;
|
||
|
};
|
||
|
|
||
|
+static void wm831x_rtc_add_randomness(struct wm831x *wm831x)
|
||
|
+{
|
||
|
+ int ret;
|
||
|
+ u16 reg;
|
||
|
+
|
||
|
+ /*
|
||
|
+ * The write counter contains a pseudo-random number which is
|
||
|
+ * regenerated every time we set the RTC so it should be a
|
||
|
+ * useful per-system source of entropy.
|
||
|
+ */
|
||
|
+ ret = wm831x_reg_read(wm831x, WM831X_RTC_WRITE_COUNTER);
|
||
|
+ if (ret >= 0) {
|
||
|
+ reg = ret;
|
||
|
+ add_device_randomness(®, sizeof(reg));
|
||
|
+ } else {
|
||
|
+ dev_warn(wm831x->dev, "Failed to read RTC write counter: %d\n",
|
||
|
+ ret);
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
/*
|
||
|
* Read current time and date in RTC
|
||
|
*/
|
||
|
@@ -449,6 +469,8 @@ static int wm831x_rtc_probe(struct platform_device *pdev)
|
||
|
alm_irq, ret);
|
||
|
}
|
||
|
|
||
|
+ wm831x_rtc_add_randomness(wm831x);
|
||
|
+
|
||
|
return 0;
|
||
|
|
||
|
err:
|
||
|
diff --git a/drivers/staging/media/lirc/lirc_sir.c b/drivers/staging/media/lirc/lirc_sir.c
|
||
|
index 6903d39..90e9e32 100644
|
||
|
--- a/drivers/staging/media/lirc/lirc_sir.c
|
||
|
+++ b/drivers/staging/media/lirc/lirc_sir.c
|
||
|
@@ -53,6 +53,7 @@
|
||
|
#include <linux/io.h>
|
||
|
#include <asm/irq.h>
|
||
|
#include <linux/fcntl.h>
|
||
|
+#include <linux/platform_device.h>
|
||
|
#ifdef LIRC_ON_SA1100
|
||
|
#include <asm/hardware.h>
|
||
|
#ifdef CONFIG_SA1100_COLLIE
|
||
|
@@ -488,9 +489,11 @@ static struct lirc_driver driver = {
|
||
|
.owner = THIS_MODULE,
|
||
|
};
|
||
|
|
||
|
+static struct platform_device *lirc_sir_dev;
|
||
|
|
||
|
static int init_chrdev(void)
|
||
|
{
|
||
|
+ driver.dev = &lirc_sir_dev->dev;
|
||
|
driver.minor = lirc_register_driver(&driver);
|
||
|
if (driver.minor < 0) {
|
||
|
printk(KERN_ERR LIRC_DRIVER_NAME ": init_chrdev() failed.\n");
|
||
|
@@ -1216,20 +1219,71 @@ static int init_lirc_sir(void)
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
+static int __devinit lirc_sir_probe(struct platform_device *dev)
|
||
|
+{
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static int __devexit lirc_sir_remove(struct platform_device *dev)
|
||
|
+{
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static struct platform_driver lirc_sir_driver = {
|
||
|
+ .probe = lirc_sir_probe,
|
||
|
+ .remove = __devexit_p(lirc_sir_remove),
|
||
|
+ .driver = {
|
||
|
+ .name = "lirc_sir",
|
||
|
+ .owner = THIS_MODULE,
|
||
|
+ },
|
||
|
+};
|
||
|
|
||
|
static int __init lirc_sir_init(void)
|
||
|
{
|
||
|
int retval;
|
||
|
|
||
|
+ retval = platform_driver_register(&lirc_sir_driver);
|
||
|
+ if (retval) {
|
||
|
+ printk(KERN_ERR LIRC_DRIVER_NAME ": Platform driver register "
|
||
|
+ "failed!\n");
|
||
|
+ return -ENODEV;
|
||
|
+ }
|
||
|
+
|
||
|
+ lirc_sir_dev = platform_device_alloc("lirc_dev", 0);
|
||
|
+ if (!lirc_sir_dev) {
|
||
|
+ printk(KERN_ERR LIRC_DRIVER_NAME ": Platform device alloc "
|
||
|
+ "failed!\n");
|
||
|
+ retval = -ENOMEM;
|
||
|
+ goto pdev_alloc_fail;
|
||
|
+ }
|
||
|
+
|
||
|
+ retval = platform_device_add(lirc_sir_dev);
|
||
|
+ if (retval) {
|
||
|
+ printk(KERN_ERR LIRC_DRIVER_NAME ": Platform device add "
|
||
|
+ "failed!\n");
|
||
|
+ retval = -ENODEV;
|
||
|
+ goto pdev_add_fail;
|
||
|
+ }
|
||
|
+
|
||
|
retval = init_chrdev();
|
||
|
if (retval < 0)
|
||
|
- return retval;
|
||
|
+ goto fail;
|
||
|
+
|
||
|
retval = init_lirc_sir();
|
||
|
if (retval) {
|
||
|
drop_chrdev();
|
||
|
- return retval;
|
||
|
+ goto fail;
|
||
|
}
|
||
|
+
|
||
|
return 0;
|
||
|
+
|
||
|
+fail:
|
||
|
+ platform_device_del(lirc_sir_dev);
|
||
|
+pdev_add_fail:
|
||
|
+ platform_device_put(lirc_sir_dev);
|
||
|
+pdev_alloc_fail:
|
||
|
+ platform_driver_unregister(&lirc_sir_driver);
|
||
|
+ return retval;
|
||
|
}
|
||
|
|
||
|
static void __exit lirc_sir_exit(void)
|
||
|
@@ -1237,6 +1291,8 @@ static void __exit lirc_sir_exit(void)
|
||
|
drop_hardware();
|
||
|
drop_chrdev();
|
||
|
drop_port();
|
||
|
+ platform_device_unregister(lirc_sir_dev);
|
||
|
+ platform_driver_unregister(&lirc_sir_driver);
|
||
|
printk(KERN_INFO LIRC_DRIVER_NAME ": Uninstalled.\n");
|
||
|
}
|
||
|
|
||
|
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
|
||
|
index a4b192d..08b92a6 100644
|
||
|
--- a/drivers/tty/serial/pch_uart.c
|
||
|
+++ b/drivers/tty/serial/pch_uart.c
|
||
|
@@ -660,7 +660,8 @@ static void pch_dma_rx_complete(void *arg)
|
||
|
tty_flip_buffer_push(tty);
|
||
|
tty_kref_put(tty);
|
||
|
async_tx_ack(priv->desc_rx);
|
||
|
- pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_RX_INT);
|
||
|
+ pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_RX_INT |
|
||
|
+ PCH_UART_HAL_RX_ERR_INT);
|
||
|
}
|
||
|
|
||
|
static void pch_dma_tx_complete(void *arg)
|
||
|
@@ -715,7 +716,8 @@ static int handle_rx_to(struct eg20t_port *priv)
|
||
|
int rx_size;
|
||
|
int ret;
|
||
|
if (!priv->start_rx) {
|
||
|
- pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT);
|
||
|
+ pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT |
|
||
|
+ PCH_UART_HAL_RX_ERR_INT);
|
||
|
return 0;
|
||
|
}
|
||
|
buf = &priv->rxbuf;
|
||
|
@@ -977,11 +979,13 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
|
||
|
case PCH_UART_IID_RDR: /* Received Data Ready */
|
||
|
if (priv->use_dma) {
|
||
|
pch_uart_hal_disable_interrupt(priv,
|
||
|
- PCH_UART_HAL_RX_INT);
|
||
|
+ PCH_UART_HAL_RX_INT |
|
||
|
+ PCH_UART_HAL_RX_ERR_INT);
|
||
|
ret = dma_handle_rx(priv);
|
||
|
if (!ret)
|
||
|
pch_uart_hal_enable_interrupt(priv,
|
||
|
- PCH_UART_HAL_RX_INT);
|
||
|
+ PCH_UART_HAL_RX_INT |
|
||
|
+ PCH_UART_HAL_RX_ERR_INT);
|
||
|
} else {
|
||
|
ret = handle_rx(priv);
|
||
|
}
|
||
|
@@ -1107,7 +1111,8 @@ static void pch_uart_stop_rx(struct uart_port *port)
|
||
|
struct eg20t_port *priv;
|
||
|
priv = container_of(port, struct eg20t_port, port);
|
||
|
priv->start_rx = 0;
|
||
|
- pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT);
|
||
|
+ pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT |
|
||
|
+ PCH_UART_HAL_RX_ERR_INT);
|
||
|
priv->int_dis_flag = 1;
|
||
|
}
|
||
|
|
||
|
@@ -1163,6 +1168,7 @@ static int pch_uart_startup(struct uart_port *port)
|
||
|
break;
|
||
|
case 16:
|
||
|
fifo_size = PCH_UART_HAL_FIFO16;
|
||
|
+ break;
|
||
|
case 1:
|
||
|
default:
|
||
|
fifo_size = PCH_UART_HAL_FIFO_DIS;
|
||
|
@@ -1200,7 +1206,8 @@ static int pch_uart_startup(struct uart_port *port)
|
||
|
pch_request_dma(port);
|
||
|
|
||
|
priv->start_rx = 1;
|
||
|
- pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_RX_INT);
|
||
|
+ pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_RX_INT |
|
||
|
+ PCH_UART_HAL_RX_ERR_INT);
|
||
|
uart_update_timeout(port, CS8, default_baud);
|
||
|
|
||
|
return 0;
|
||
|
@@ -1258,7 +1265,7 @@ static void pch_uart_set_termios(struct uart_port *port,
|
||
|
stb = PCH_UART_HAL_STB1;
|
||
|
|
||
|
if (termios->c_cflag & PARENB) {
|
||
|
- if (!(termios->c_cflag & PARODD))
|
||
|
+ if (termios->c_cflag & PARODD)
|
||
|
parity = PCH_UART_HAL_PARITY_ODD;
|
||
|
else
|
||
|
parity = PCH_UART_HAL_PARITY_EVEN;
|
||
|
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
|
||
|
index 175b6bb..52340cc 100644
|
||
|
--- a/drivers/usb/core/hub.c
|
||
|
+++ b/drivers/usb/core/hub.c
|
||
|
@@ -24,6 +24,7 @@
|
||
|
#include <linux/kthread.h>
|
||
|
#include <linux/mutex.h>
|
||
|
#include <linux/freezer.h>
|
||
|
+#include <linux/random.h>
|
||
|
|
||
|
#include <asm/uaccess.h>
|
||
|
#include <asm/byteorder.h>
|
||
|
@@ -1897,6 +1898,14 @@ int usb_new_device(struct usb_device *udev)
|
||
|
/* Tell the world! */
|
||
|
announce_device(udev);
|
||
|
|
||
|
+ if (udev->serial)
|
||
|
+ add_device_randomness(udev->serial, strlen(udev->serial));
|
||
|
+ if (udev->product)
|
||
|
+ add_device_randomness(udev->product, strlen(udev->product));
|
||
|
+ if (udev->manufacturer)
|
||
|
+ add_device_randomness(udev->manufacturer,
|
||
|
+ strlen(udev->manufacturer));
|
||
|
+
|
||
|
device_enable_async_suspend(&udev->dev);
|
||
|
/* Register the device. The device driver is responsible
|
||
|
* for configuring the device and invoking the add-device
|
||
|
diff --git a/drivers/usb/early/ehci-dbgp.c b/drivers/usb/early/ehci-dbgp.c
|
||
|
index 1fc8f12..347bb05 100644
|
||
|
--- a/drivers/usb/early/ehci-dbgp.c
|
||
|
+++ b/drivers/usb/early/ehci-dbgp.c
|
||
|
@@ -450,7 +450,7 @@ static int dbgp_ehci_startup(void)
|
||
|
writel(FLAG_CF, &ehci_regs->configured_flag);
|
||
|
|
||
|
/* Wait until the controller is no longer halted */
|
||
|
- loop = 10;
|
||
|
+ loop = 1000;
|
||
|
do {
|
||
|
status = readl(&ehci_regs->status);
|
||
|
if (!(status & STS_HALT))
|
||
|
diff --git a/drivers/video/smscufx.c b/drivers/video/smscufx.c
|
||
|
index aaccffa..dd9533a 100644
|
||
|
--- a/drivers/video/smscufx.c
|
||
|
+++ b/drivers/video/smscufx.c
|
||
|
@@ -904,7 +904,7 @@ static ssize_t ufx_ops_write(struct fb_info *info, const char __user *buf,
|
||
|
result = fb_sys_write(info, buf, count, ppos);
|
||
|
|
||
|
if (result > 0) {
|
||
|
- int start = max((int)(offset / info->fix.line_length) - 1, 0);
|
||
|
+ int start = max((int)(offset / info->fix.line_length), 0);
|
||
|
int lines = min((u32)((result / info->fix.line_length) + 1),
|
||
|
(u32)info->var.yres);
|
||
|
|
||
|
diff --git a/fs/exofs/ore.c b/fs/exofs/ore.c
|
||
|
index 24a49d4..1585db1 100644
|
||
|
--- a/fs/exofs/ore.c
|
||
|
+++ b/fs/exofs/ore.c
|
||
|
@@ -837,11 +837,11 @@ static int _write_mirror(struct ore_io_state *ios, int cur_comp)
|
||
|
bio->bi_rw |= REQ_WRITE;
|
||
|
}
|
||
|
|
||
|
- osd_req_write(or, _ios_obj(ios, dev), per_dev->offset,
|
||
|
- bio, per_dev->length);
|
||
|
+ osd_req_write(or, _ios_obj(ios, cur_comp),
|
||
|
+ per_dev->offset, bio, per_dev->length);
|
||
|
ORE_DBGMSG("write(0x%llx) offset=0x%llx "
|
||
|
"length=0x%llx dev=%d\n",
|
||
|
- _LLU(_ios_obj(ios, dev)->id),
|
||
|
+ _LLU(_ios_obj(ios, cur_comp)->id),
|
||
|
_LLU(per_dev->offset),
|
||
|
_LLU(per_dev->length), dev);
|
||
|
} else if (ios->kern_buff) {
|
||
|
@@ -853,20 +853,20 @@ static int _write_mirror(struct ore_io_state *ios, int cur_comp)
|
||
|
(ios->si.unit_off + ios->length >
|
||
|
ios->layout->stripe_unit));
|
||
|
|
||
|
- ret = osd_req_write_kern(or, _ios_obj(ios, per_dev->dev),
|
||
|
+ ret = osd_req_write_kern(or, _ios_obj(ios, cur_comp),
|
||
|
per_dev->offset,
|
||
|
ios->kern_buff, ios->length);
|
||
|
if (unlikely(ret))
|
||
|
goto out;
|
||
|
ORE_DBGMSG2("write_kern(0x%llx) offset=0x%llx "
|
||
|
"length=0x%llx dev=%d\n",
|
||
|
- _LLU(_ios_obj(ios, dev)->id),
|
||
|
+ _LLU(_ios_obj(ios, cur_comp)->id),
|
||
|
_LLU(per_dev->offset),
|
||
|
_LLU(ios->length), per_dev->dev);
|
||
|
} else {
|
||
|
- osd_req_set_attributes(or, _ios_obj(ios, dev));
|
||
|
+ osd_req_set_attributes(or, _ios_obj(ios, cur_comp));
|
||
|
ORE_DBGMSG2("obj(0x%llx) set_attributes=%d dev=%d\n",
|
||
|
- _LLU(_ios_obj(ios, dev)->id),
|
||
|
+ _LLU(_ios_obj(ios, cur_comp)->id),
|
||
|
ios->out_attr_len, dev);
|
||
|
}
|
||
|
|
||
|
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
|
||
|
index c43a452..961e562 100644
|
||
|
--- a/fs/nfs/file.c
|
||
|
+++ b/fs/nfs/file.c
|
||
|
@@ -452,8 +452,11 @@ static int nfs_release_page(struct page *page, gfp_t gfp)
|
||
|
|
||
|
dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page);
|
||
|
|
||
|
- /* Only do I/O if gfp is a superset of GFP_KERNEL */
|
||
|
- if (mapping && (gfp & GFP_KERNEL) == GFP_KERNEL) {
|
||
|
+ /* Only do I/O if gfp is a superset of GFP_KERNEL, and we're not
|
||
|
+ * doing this memory reclaim for a fs-related allocation.
|
||
|
+ */
|
||
|
+ if (mapping && (gfp & GFP_KERNEL) == GFP_KERNEL &&
|
||
|
+ !(current->flags & PF_FSTRANS)) {
|
||
|
int how = FLUSH_SYNC;
|
||
|
|
||
|
/* Don't let kswapd deadlock waiting for OOM RPC calls */
|
||
|
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
|
||
|
index 9cfa60a..87a1746 100644
|
||
|
--- a/fs/nfsd/nfs4xdr.c
|
||
|
+++ b/fs/nfsd/nfs4xdr.c
|
||
|
@@ -2236,7 +2236,7 @@ out_acl:
|
||
|
if (bmval0 & FATTR4_WORD0_CASE_INSENSITIVE) {
|
||
|
if ((buflen -= 4) < 0)
|
||
|
goto out_resource;
|
||
|
- WRITE32(1);
|
||
|
+ WRITE32(0);
|
||
|
}
|
||
|
if (bmval0 & FATTR4_WORD0_CASE_PRESERVING) {
|
||
|
if ((buflen -= 4) < 0)
|
||
|
diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c
|
||
|
index ac258be..c598cfb 100644
|
||
|
--- a/fs/nilfs2/ioctl.c
|
||
|
+++ b/fs/nilfs2/ioctl.c
|
||
|
@@ -182,7 +182,7 @@ static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp,
|
||
|
if (copy_from_user(&cpmode, argp, sizeof(cpmode)))
|
||
|
goto out;
|
||
|
|
||
|
- down_read(&inode->i_sb->s_umount);
|
||
|
+ mutex_lock(&nilfs->ns_snapshot_mount_mutex);
|
||
|
|
||
|
nilfs_transaction_begin(inode->i_sb, &ti, 0);
|
||
|
ret = nilfs_cpfile_change_cpmode(
|
||
|
@@ -192,7 +192,7 @@ static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp,
|
||
|
else
|
||
|
nilfs_transaction_commit(inode->i_sb); /* never fails */
|
||
|
|
||
|
- up_read(&inode->i_sb->s_umount);
|
||
|
+ mutex_unlock(&nilfs->ns_snapshot_mount_mutex);
|
||
|
out:
|
||
|
mnt_drop_write(filp->f_path.mnt);
|
||
|
return ret;
|
||
|
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c
|
||
|
index 8351c44..97bfbdd 100644
|
||
|
--- a/fs/nilfs2/super.c
|
||
|
+++ b/fs/nilfs2/super.c
|
||
|
@@ -951,6 +951,8 @@ static int nilfs_attach_snapshot(struct super_block *s, __u64 cno,
|
||
|
struct nilfs_root *root;
|
||
|
int ret;
|
||
|
|
||
|
+ mutex_lock(&nilfs->ns_snapshot_mount_mutex);
|
||
|
+
|
||
|
down_read(&nilfs->ns_segctor_sem);
|
||
|
ret = nilfs_cpfile_is_snapshot(nilfs->ns_cpfile, cno);
|
||
|
up_read(&nilfs->ns_segctor_sem);
|
||
|
@@ -975,6 +977,7 @@ static int nilfs_attach_snapshot(struct super_block *s, __u64 cno,
|
||
|
ret = nilfs_get_root_dentry(s, root, root_dentry);
|
||
|
nilfs_put_root(root);
|
||
|
out:
|
||
|
+ mutex_unlock(&nilfs->ns_snapshot_mount_mutex);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c
|
||
|
index 35a8970..1c98f53 100644
|
||
|
--- a/fs/nilfs2/the_nilfs.c
|
||
|
+++ b/fs/nilfs2/the_nilfs.c
|
||
|
@@ -76,6 +76,7 @@ struct the_nilfs *alloc_nilfs(struct block_device *bdev)
|
||
|
nilfs->ns_bdev = bdev;
|
||
|
atomic_set(&nilfs->ns_ndirtyblks, 0);
|
||
|
init_rwsem(&nilfs->ns_sem);
|
||
|
+ mutex_init(&nilfs->ns_snapshot_mount_mutex);
|
||
|
INIT_LIST_HEAD(&nilfs->ns_dirty_files);
|
||
|
INIT_LIST_HEAD(&nilfs->ns_gc_inodes);
|
||
|
spin_lock_init(&nilfs->ns_inode_lock);
|
||
|
diff --git a/fs/nilfs2/the_nilfs.h b/fs/nilfs2/the_nilfs.h
|
||
|
index 9992b11..de7435f 100644
|
||
|
--- a/fs/nilfs2/the_nilfs.h
|
||
|
+++ b/fs/nilfs2/the_nilfs.h
|
||
|
@@ -47,6 +47,7 @@ enum {
|
||
|
* @ns_flags: flags
|
||
|
* @ns_bdev: block device
|
||
|
* @ns_sem: semaphore for shared states
|
||
|
+ * @ns_snapshot_mount_mutex: mutex to protect snapshot mounts
|
||
|
* @ns_sbh: buffer heads of on-disk super blocks
|
||
|
* @ns_sbp: pointers to super block data
|
||
|
* @ns_sbwtime: previous write time of super block
|
||
|
@@ -99,6 +100,7 @@ struct the_nilfs {
|
||
|
|
||
|
struct block_device *ns_bdev;
|
||
|
struct rw_semaphore ns_sem;
|
||
|
+ struct mutex ns_snapshot_mount_mutex;
|
||
|
|
||
|
/*
|
||
|
* used for
|
||
|
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
|
||
|
index c5ed2f1..a2227f7 100644
|
||
|
--- a/include/linux/hugetlb.h
|
||
|
+++ b/include/linux/hugetlb.h
|
||
|
@@ -41,6 +41,9 @@ int follow_hugetlb_page(struct mm_struct *, struct vm_area_struct *,
|
||
|
unsigned long *, int *, int, unsigned int flags);
|
||
|
void unmap_hugepage_range(struct vm_area_struct *,
|
||
|
unsigned long, unsigned long, struct page *);
|
||
|
+void __unmap_hugepage_range_final(struct vm_area_struct *vma,
|
||
|
+ unsigned long start, unsigned long end,
|
||
|
+ struct page *ref_page);
|
||
|
void __unmap_hugepage_range(struct vm_area_struct *,
|
||
|
unsigned long, unsigned long, struct page *);
|
||
|
int hugetlb_prefault(struct address_space *, struct vm_area_struct *);
|
||
|
@@ -99,6 +102,13 @@ static inline unsigned long hugetlb_total_pages(void)
|
||
|
#define copy_hugetlb_page_range(src, dst, vma) ({ BUG(); 0; })
|
||
|
#define hugetlb_prefault(mapping, vma) ({ BUG(); 0; })
|
||
|
#define unmap_hugepage_range(vma, start, end, page) BUG()
|
||
|
+static inline void __unmap_hugepage_range_final(struct vm_area_struct *vma,
|
||
|
+ unsigned long start, unsigned long end,
|
||
|
+ struct page *ref_page)
|
||
|
+{
|
||
|
+ BUG();
|
||
|
+}
|
||
|
+
|
||
|
static inline void hugetlb_report_meminfo(struct seq_file *m)
|
||
|
{
|
||
|
}
|
||
|
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
|
||
|
index df53fdf..cdde2b3 100644
|
||
|
--- a/include/linux/init_task.h
|
||
|
+++ b/include/linux/init_task.h
|
||
|
@@ -124,8 +124,17 @@ extern struct group_info init_groups;
|
||
|
|
||
|
extern struct cred init_cred;
|
||
|
|
||
|
+extern struct task_group root_task_group;
|
||
|
+
|
||
|
+#ifdef CONFIG_CGROUP_SCHED
|
||
|
+# define INIT_CGROUP_SCHED(tsk) \
|
||
|
+ .sched_task_group = &root_task_group,
|
||
|
+#else
|
||
|
+# define INIT_CGROUP_SCHED(tsk)
|
||
|
+#endif
|
||
|
+
|
||
|
#ifdef CONFIG_PERF_EVENTS
|
||
|
-# define INIT_PERF_EVENTS(tsk) \
|
||
|
+# define INIT_PERF_EVENTS(tsk) \
|
||
|
.perf_event_mutex = \
|
||
|
__MUTEX_INITIALIZER(tsk.perf_event_mutex), \
|
||
|
.perf_event_list = LIST_HEAD_INIT(tsk.perf_event_list),
|
||
|
@@ -162,6 +171,7 @@ extern struct cred init_cred;
|
||
|
}, \
|
||
|
.tasks = LIST_HEAD_INIT(tsk.tasks), \
|
||
|
INIT_PUSHABLE_TASKS(tsk) \
|
||
|
+ INIT_CGROUP_SCHED(tsk) \
|
||
|
.ptraced = LIST_HEAD_INIT(tsk.ptraced), \
|
||
|
.ptrace_entry = LIST_HEAD_INIT(tsk.ptrace_entry), \
|
||
|
.real_parent = &tsk, \
|
||
|
diff --git a/include/linux/random.h b/include/linux/random.h
|
||
|
index 8f74538..29e217a 100644
|
||
|
--- a/include/linux/random.h
|
||
|
+++ b/include/linux/random.h
|
||
|
@@ -50,11 +50,13 @@ struct rnd_state {
|
||
|
|
||
|
extern void rand_initialize_irq(int irq);
|
||
|
|
||
|
+extern void add_device_randomness(const void *, unsigned int);
|
||
|
extern void add_input_randomness(unsigned int type, unsigned int code,
|
||
|
unsigned int value);
|
||
|
-extern void add_interrupt_randomness(int irq);
|
||
|
+extern void add_interrupt_randomness(int irq, int irq_flags);
|
||
|
|
||
|
extern void get_random_bytes(void *buf, int nbytes);
|
||
|
+extern void get_random_bytes_arch(void *buf, int nbytes);
|
||
|
void generate_random_uuid(unsigned char uuid_out[16]);
|
||
|
|
||
|
#ifndef MODULE
|
||
|
diff --git a/include/linux/sched.h b/include/linux/sched.h
|
||
|
index d336c35..1e86bb4 100644
|
||
|
--- a/include/linux/sched.h
|
||
|
+++ b/include/linux/sched.h
|
||
|
@@ -1236,6 +1236,9 @@ struct task_struct {
|
||
|
const struct sched_class *sched_class;
|
||
|
struct sched_entity se;
|
||
|
struct sched_rt_entity rt;
|
||
|
+#ifdef CONFIG_CGROUP_SCHED
|
||
|
+ struct task_group *sched_task_group;
|
||
|
+#endif
|
||
|
|
||
|
#ifdef CONFIG_PREEMPT_NOTIFIERS
|
||
|
/* list of struct preempt_notifier: */
|
||
|
@@ -2646,7 +2649,7 @@ extern int sched_group_set_rt_period(struct task_group *tg,
|
||
|
extern long sched_group_rt_period(struct task_group *tg);
|
||
|
extern int sched_rt_can_attach(struct task_group *tg, struct task_struct *tsk);
|
||
|
#endif
|
||
|
-#endif
|
||
|
+#endif /* CONFIG_CGROUP_SCHED */
|
||
|
|
||
|
extern int task_can_switch_user(struct user_struct *up,
|
||
|
struct task_struct *tsk);
|
||
|
diff --git a/kernel/futex.c b/kernel/futex.c
|
||
|
index 866c9d5..80fb1c6 100644
|
||
|
--- a/kernel/futex.c
|
||
|
+++ b/kernel/futex.c
|
||
|
@@ -2231,11 +2231,11 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,
|
||
|
* @uaddr2: the pi futex we will take prior to returning to user-space
|
||
|
*
|
||
|
* The caller will wait on uaddr and will be requeued by futex_requeue() to
|
||
|
- * uaddr2 which must be PI aware. Normal wakeup will wake on uaddr2 and
|
||
|
- * complete the acquisition of the rt_mutex prior to returning to userspace.
|
||
|
- * This ensures the rt_mutex maintains an owner when it has waiters; without
|
||
|
- * one, the pi logic wouldn't know which task to boost/deboost, if there was a
|
||
|
- * need to.
|
||
|
+ * uaddr2 which must be PI aware and unique from uaddr. Normal wakeup will wake
|
||
|
+ * on uaddr2 and complete the acquisition of the rt_mutex prior to returning to
|
||
|
+ * userspace. This ensures the rt_mutex maintains an owner when it has waiters;
|
||
|
+ * without one, the pi logic would not know which task to boost/deboost, if
|
||
|
+ * there was a need to.
|
||
|
*
|
||
|
* We call schedule in futex_wait_queue_me() when we enqueue and return there
|
||
|
* via the following:
|
||
|
@@ -2272,6 +2272,9 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
|
||
|
struct futex_q q = futex_q_init;
|
||
|
int res, ret;
|
||
|
|
||
|
+ if (uaddr == uaddr2)
|
||
|
+ return -EINVAL;
|
||
|
+
|
||
|
if (!bitset)
|
||
|
return -EINVAL;
|
||
|
|
||
|
@@ -2343,7 +2346,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
|
||
|
* signal. futex_unlock_pi() will not destroy the lock_ptr nor
|
||
|
* the pi_state.
|
||
|
*/
|
||
|
- WARN_ON(!&q.pi_state);
|
||
|
+ WARN_ON(!q.pi_state);
|
||
|
pi_mutex = &q.pi_state->pi_mutex;
|
||
|
ret = rt_mutex_finish_proxy_lock(pi_mutex, to, &rt_waiter, 1);
|
||
|
debug_rt_mutex_free_waiter(&rt_waiter);
|
||
|
@@ -2370,7 +2373,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
|
||
|
* fault, unlock the rt_mutex and return the fault to userspace.
|
||
|
*/
|
||
|
if (ret == -EFAULT) {
|
||
|
- if (rt_mutex_owner(pi_mutex) == current)
|
||
|
+ if (pi_mutex && rt_mutex_owner(pi_mutex) == current)
|
||
|
rt_mutex_unlock(pi_mutex);
|
||
|
} else if (ret == -EINTR) {
|
||
|
/*
|
||
|
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c
|
||
|
index 470d08c..10e0772 100644
|
||
|
--- a/kernel/irq/handle.c
|
||
|
+++ b/kernel/irq/handle.c
|
||
|
@@ -117,7 +117,7 @@ irqreturn_t
|
||
|
handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action)
|
||
|
{
|
||
|
irqreturn_t retval = IRQ_NONE;
|
||
|
- unsigned int random = 0, irq = desc->irq_data.irq;
|
||
|
+ unsigned int flags = 0, irq = desc->irq_data.irq;
|
||
|
|
||
|
do {
|
||
|
irqreturn_t res;
|
||
|
@@ -145,7 +145,7 @@ handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action)
|
||
|
|
||
|
/* Fall through to add to randomness */
|
||
|
case IRQ_HANDLED:
|
||
|
- random |= action->flags;
|
||
|
+ flags |= action->flags;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
@@ -156,8 +156,7 @@ handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action)
|
||
|
action = action->next;
|
||
|
} while (action);
|
||
|
|
||
|
- if (random & IRQF_SAMPLE_RANDOM)
|
||
|
- add_interrupt_randomness(irq);
|
||
|
+ add_interrupt_randomness(irq, flags);
|
||
|
|
||
|
if (!noirqdebug)
|
||
|
note_interrupt(irq, desc, retval);
|
||
|
diff --git a/kernel/sched.c b/kernel/sched.c
|
||
|
index 9cd8ca7..e0431c4 100644
|
||
|
--- a/kernel/sched.c
|
||
|
+++ b/kernel/sched.c
|
||
|
@@ -746,22 +746,19 @@ static inline int cpu_of(struct rq *rq)
|
||
|
/*
|
||
|
* Return the group to which this tasks belongs.
|
||
|
*
|
||
|
- * We use task_subsys_state_check() and extend the RCU verification with
|
||
|
- * pi->lock and rq->lock because cpu_cgroup_attach() holds those locks for each
|
||
|
- * task it moves into the cgroup. Therefore by holding either of those locks,
|
||
|
- * we pin the task to the current cgroup.
|
||
|
+ * We cannot use task_subsys_state() and friends because the cgroup
|
||
|
+ * subsystem changes that value before the cgroup_subsys::attach() method
|
||
|
+ * is called, therefore we cannot pin it and might observe the wrong value.
|
||
|
+ *
|
||
|
+ * The same is true for autogroup's p->signal->autogroup->tg, the autogroup
|
||
|
+ * core changes this before calling sched_move_task().
|
||
|
+ *
|
||
|
+ * Instead we use a 'copy' which is updated from sched_move_task() while
|
||
|
+ * holding both task_struct::pi_lock and rq::lock.
|
||
|
*/
|
||
|
static inline struct task_group *task_group(struct task_struct *p)
|
||
|
{
|
||
|
- struct task_group *tg;
|
||
|
- struct cgroup_subsys_state *css;
|
||
|
-
|
||
|
- css = task_subsys_state_check(p, cpu_cgroup_subsys_id,
|
||
|
- lockdep_is_held(&p->pi_lock) ||
|
||
|
- lockdep_is_held(&task_rq(p)->lock));
|
||
|
- tg = container_of(css, struct task_group, css);
|
||
|
-
|
||
|
- return autogroup_task_group(p, tg);
|
||
|
+ return p->sched_task_group;
|
||
|
}
|
||
|
|
||
|
/* Change a task's cfs_rq and parent entity if it moves across CPUs/groups */
|
||
|
@@ -2372,7 +2369,7 @@ void set_task_cpu(struct task_struct *p, unsigned int new_cpu)
|
||
|
* a task's CPU. ->pi_lock for waking tasks, rq->lock for runnable tasks.
|
||
|
*
|
||
|
* sched_move_task() holds both and thus holding either pins the cgroup,
|
||
|
- * see set_task_rq().
|
||
|
+ * see task_group().
|
||
|
*
|
||
|
* Furthermore, all task_rq users should acquire both locks, see
|
||
|
* task_rq_lock().
|
||
|
@@ -8952,6 +8949,7 @@ void sched_destroy_group(struct task_group *tg)
|
||
|
*/
|
||
|
void sched_move_task(struct task_struct *tsk)
|
||
|
{
|
||
|
+ struct task_group *tg;
|
||
|
int on_rq, running;
|
||
|
unsigned long flags;
|
||
|
struct rq *rq;
|
||
|
@@ -8966,6 +8964,12 @@ void sched_move_task(struct task_struct *tsk)
|
||
|
if (unlikely(running))
|
||
|
tsk->sched_class->put_prev_task(rq, tsk);
|
||
|
|
||
|
+ tg = container_of(task_subsys_state_check(tsk, cpu_cgroup_subsys_id,
|
||
|
+ lockdep_is_held(&tsk->sighand->siglock)),
|
||
|
+ struct task_group, css);
|
||
|
+ tg = autogroup_task_group(tsk, tg);
|
||
|
+ tsk->sched_task_group = tg;
|
||
|
+
|
||
|
#ifdef CONFIG_FAIR_GROUP_SCHED
|
||
|
if (tsk->sched_class->task_move_group)
|
||
|
tsk->sched_class->task_move_group(tsk, on_rq);
|
||
|
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
|
||
|
index 993599e..d74c317 100644
|
||
|
--- a/lib/vsprintf.c
|
||
|
+++ b/lib/vsprintf.c
|
||
|
@@ -886,7 +886,8 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
|
||
|
* %pK cannot be used in IRQ context because its test
|
||
|
* for CAP_SYSLOG would be meaningless.
|
||
|
*/
|
||
|
- if (in_irq() || in_serving_softirq() || in_nmi()) {
|
||
|
+ if (kptr_restrict && (in_irq() || in_serving_softirq() ||
|
||
|
+ in_nmi())) {
|
||
|
if (spec.field_width == -1)
|
||
|
spec.field_width = 2 * sizeof(void *);
|
||
|
return string(buf, end, "pK-error", spec);
|
||
|
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
|
||
|
index b1e1bad..0f897b8 100644
|
||
|
--- a/mm/hugetlb.c
|
||
|
+++ b/mm/hugetlb.c
|
||
|
@@ -2382,6 +2382,25 @@ void __unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+void __unmap_hugepage_range_final(struct vm_area_struct *vma,
|
||
|
+ unsigned long start, unsigned long end,
|
||
|
+ struct page *ref_page)
|
||
|
+{
|
||
|
+ __unmap_hugepage_range(vma, start, end, ref_page);
|
||
|
+
|
||
|
+ /*
|
||
|
+ * Clear this flag so that x86's huge_pmd_share page_table_shareable
|
||
|
+ * test will fail on a vma being torn down, and not grab a page table
|
||
|
+ * on its way out. We're lucky that the flag has such an appropriate
|
||
|
+ * name, and can in fact be safely cleared here. We could clear it
|
||
|
+ * before the __unmap_hugepage_range above, but all that's necessary
|
||
|
+ * is to clear it before releasing the i_mmap_mutex. This works
|
||
|
+ * because in the context this is called, the VMA is about to be
|
||
|
+ * destroyed and the i_mmap_mutex is held.
|
||
|
+ */
|
||
|
+ vma->vm_flags &= ~VM_MAYSHARE;
|
||
|
+}
|
||
|
+
|
||
|
void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,
|
||
|
unsigned long end, struct page *ref_page)
|
||
|
{
|
||
|
@@ -2939,9 +2958,14 @@ void hugetlb_change_protection(struct vm_area_struct *vma,
|
||
|
}
|
||
|
}
|
||
|
spin_unlock(&mm->page_table_lock);
|
||
|
- mutex_unlock(&vma->vm_file->f_mapping->i_mmap_mutex);
|
||
|
-
|
||
|
+ /*
|
||
|
+ * Must flush TLB before releasing i_mmap_mutex: x86's huge_pmd_unshare
|
||
|
+ * may have cleared our pud entry and done put_page on the page table:
|
||
|
+ * once we release i_mmap_mutex, another task can do the final put_page
|
||
|
+ * and that page table be reused and filled with junk.
|
||
|
+ */
|
||
|
flush_tlb_range(vma, start, end);
|
||
|
+ mutex_unlock(&vma->vm_file->f_mapping->i_mmap_mutex);
|
||
|
}
|
||
|
|
||
|
int hugetlb_reserve_pages(struct inode *inode,
|
||
|
diff --git a/mm/internal.h b/mm/internal.h
|
||
|
index 2189af4..0c26b5e 100644
|
||
|
--- a/mm/internal.h
|
||
|
+++ b/mm/internal.h
|
||
|
@@ -309,3 +309,5 @@ extern u64 hwpoison_filter_flags_mask;
|
||
|
extern u64 hwpoison_filter_flags_value;
|
||
|
extern u64 hwpoison_filter_memcg;
|
||
|
extern u32 hwpoison_filter_enable;
|
||
|
+
|
||
|
+extern void set_pageblock_order(void);
|
||
|
diff --git a/mm/memory.c b/mm/memory.c
|
||
|
index 1b1ca17..70f5daf 100644
|
||
|
--- a/mm/memory.c
|
||
|
+++ b/mm/memory.c
|
||
|
@@ -1358,8 +1358,11 @@ unsigned long unmap_vmas(struct mmu_gather *tlb,
|
||
|
* Since no pte has actually been setup, it is
|
||
|
* safe to do nothing in this case.
|
||
|
*/
|
||
|
- if (vma->vm_file)
|
||
|
- unmap_hugepage_range(vma, start, end, NULL);
|
||
|
+ if (vma->vm_file) {
|
||
|
+ mutex_lock(&vma->vm_file->f_mapping->i_mmap_mutex);
|
||
|
+ __unmap_hugepage_range_final(vma, start, end, NULL);
|
||
|
+ mutex_unlock(&vma->vm_file->f_mapping->i_mmap_mutex);
|
||
|
+ }
|
||
|
|
||
|
start = end;
|
||
|
} else
|
||
|
diff --git a/mm/mmu_notifier.c b/mm/mmu_notifier.c
|
||
|
index 9a611d3..862b608 100644
|
||
|
--- a/mm/mmu_notifier.c
|
||
|
+++ b/mm/mmu_notifier.c
|
||
|
@@ -33,6 +33,24 @@
|
||
|
void __mmu_notifier_release(struct mm_struct *mm)
|
||
|
{
|
||
|
struct mmu_notifier *mn;
|
||
|
+ struct hlist_node *n;
|
||
|
+
|
||
|
+ /*
|
||
|
+ * RCU here will block mmu_notifier_unregister until
|
||
|
+ * ->release returns.
|
||
|
+ */
|
||
|
+ rcu_read_lock();
|
||
|
+ hlist_for_each_entry_rcu(mn, n, &mm->mmu_notifier_mm->list, hlist)
|
||
|
+ /*
|
||
|
+ * if ->release runs before mmu_notifier_unregister it
|
||
|
+ * must be handled as it's the only way for the driver
|
||
|
+ * to flush all existing sptes and stop the driver
|
||
|
+ * from establishing any more sptes before all the
|
||
|
+ * pages in the mm are freed.
|
||
|
+ */
|
||
|
+ if (mn->ops->release)
|
||
|
+ mn->ops->release(mn, mm);
|
||
|
+ rcu_read_unlock();
|
||
|
|
||
|
spin_lock(&mm->mmu_notifier_mm->lock);
|
||
|
while (unlikely(!hlist_empty(&mm->mmu_notifier_mm->list))) {
|
||
|
@@ -46,23 +64,6 @@ void __mmu_notifier_release(struct mm_struct *mm)
|
||
|
* mmu_notifier_unregister to return.
|
||
|
*/
|
||
|
hlist_del_init_rcu(&mn->hlist);
|
||
|
- /*
|
||
|
- * RCU here will block mmu_notifier_unregister until
|
||
|
- * ->release returns.
|
||
|
- */
|
||
|
- rcu_read_lock();
|
||
|
- spin_unlock(&mm->mmu_notifier_mm->lock);
|
||
|
- /*
|
||
|
- * if ->release runs before mmu_notifier_unregister it
|
||
|
- * must be handled as it's the only way for the driver
|
||
|
- * to flush all existing sptes and stop the driver
|
||
|
- * from establishing any more sptes before all the
|
||
|
- * pages in the mm are freed.
|
||
|
- */
|
||
|
- if (mn->ops->release)
|
||
|
- mn->ops->release(mn, mm);
|
||
|
- rcu_read_unlock();
|
||
|
- spin_lock(&mm->mmu_notifier_mm->lock);
|
||
|
}
|
||
|
spin_unlock(&mm->mmu_notifier_mm->lock);
|
||
|
|
||
|
@@ -284,16 +285,13 @@ void mmu_notifier_unregister(struct mmu_notifier *mn, struct mm_struct *mm)
|
||
|
{
|
||
|
BUG_ON(atomic_read(&mm->mm_count) <= 0);
|
||
|
|
||
|
- spin_lock(&mm->mmu_notifier_mm->lock);
|
||
|
if (!hlist_unhashed(&mn->hlist)) {
|
||
|
- hlist_del_rcu(&mn->hlist);
|
||
|
-
|
||
|
/*
|
||
|
* RCU here will force exit_mmap to wait ->release to finish
|
||
|
* before freeing the pages.
|
||
|
*/
|
||
|
rcu_read_lock();
|
||
|
- spin_unlock(&mm->mmu_notifier_mm->lock);
|
||
|
+
|
||
|
/*
|
||
|
* exit_mmap will block in mmu_notifier_release to
|
||
|
* guarantee ->release is called before freeing the
|
||
|
@@ -302,8 +300,11 @@ void mmu_notifier_unregister(struct mmu_notifier *mn, struct mm_struct *mm)
|
||
|
if (mn->ops->release)
|
||
|
mn->ops->release(mn, mm);
|
||
|
rcu_read_unlock();
|
||
|
- } else
|
||
|
+
|
||
|
+ spin_lock(&mm->mmu_notifier_mm->lock);
|
||
|
+ hlist_del_rcu(&mn->hlist);
|
||
|
spin_unlock(&mm->mmu_notifier_mm->lock);
|
||
|
+ }
|
||
|
|
||
|
/*
|
||
|
* Wait any running method to finish, of course including
|
||
|
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
|
||
|
index 065dbe8..6e51bf0 100644
|
||
|
--- a/mm/page_alloc.c
|
||
|
+++ b/mm/page_alloc.c
|
||
|
@@ -4281,25 +4281,24 @@ static inline void setup_usemap(struct pglist_data *pgdat,
|
||
|
|
||
|
#ifdef CONFIG_HUGETLB_PAGE_SIZE_VARIABLE
|
||
|
|
||
|
-/* Return a sensible default order for the pageblock size. */
|
||
|
-static inline int pageblock_default_order(void)
|
||
|
-{
|
||
|
- if (HPAGE_SHIFT > PAGE_SHIFT)
|
||
|
- return HUGETLB_PAGE_ORDER;
|
||
|
-
|
||
|
- return MAX_ORDER-1;
|
||
|
-}
|
||
|
-
|
||
|
/* Initialise the number of pages represented by NR_PAGEBLOCK_BITS */
|
||
|
-static inline void __init set_pageblock_order(unsigned int order)
|
||
|
+void __init set_pageblock_order(void)
|
||
|
{
|
||
|
+ unsigned int order;
|
||
|
+
|
||
|
/* Check that pageblock_nr_pages has not already been setup */
|
||
|
if (pageblock_order)
|
||
|
return;
|
||
|
|
||
|
+ if (HPAGE_SHIFT > PAGE_SHIFT)
|
||
|
+ order = HUGETLB_PAGE_ORDER;
|
||
|
+ else
|
||
|
+ order = MAX_ORDER - 1;
|
||
|
+
|
||
|
/*
|
||
|
* Assume the largest contiguous order of interest is a huge page.
|
||
|
- * This value may be variable depending on boot parameters on IA64
|
||
|
+ * This value may be variable depending on boot parameters on IA64 and
|
||
|
+ * powerpc.
|
||
|
*/
|
||
|
pageblock_order = order;
|
||
|
}
|
||
|
@@ -4307,15 +4306,13 @@ static inline void __init set_pageblock_order(unsigned int order)
|
||
|
|
||
|
/*
|
||
|
* When CONFIG_HUGETLB_PAGE_SIZE_VARIABLE is not set, set_pageblock_order()
|
||
|
- * and pageblock_default_order() are unused as pageblock_order is set
|
||
|
- * at compile-time. See include/linux/pageblock-flags.h for the values of
|
||
|
- * pageblock_order based on the kernel config
|
||
|
+ * is unused as pageblock_order is set at compile-time. See
|
||
|
+ * include/linux/pageblock-flags.h for the values of pageblock_order based on
|
||
|
+ * the kernel config
|
||
|
*/
|
||
|
-static inline int pageblock_default_order(unsigned int order)
|
||
|
+void __init set_pageblock_order(void)
|
||
|
{
|
||
|
- return MAX_ORDER-1;
|
||
|
}
|
||
|
-#define set_pageblock_order(x) do {} while (0)
|
||
|
|
||
|
#endif /* CONFIG_HUGETLB_PAGE_SIZE_VARIABLE */
|
||
|
|
||
|
@@ -4403,7 +4400,7 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat,
|
||
|
if (!size)
|
||
|
continue;
|
||
|
|
||
|
- set_pageblock_order(pageblock_default_order());
|
||
|
+ set_pageblock_order();
|
||
|
setup_usemap(pgdat, zone, size);
|
||
|
ret = init_currently_empty_zone(zone, zone_start_pfn,
|
||
|
size, MEMMAP_EARLY);
|
||
|
diff --git a/mm/sparse.c b/mm/sparse.c
|
||
|
index a8bc7d3..bf7d3cc 100644
|
||
|
--- a/mm/sparse.c
|
||
|
+++ b/mm/sparse.c
|
||
|
@@ -486,6 +486,9 @@ void __init sparse_init(void)
|
||
|
struct page **map_map;
|
||
|
#endif
|
||
|
|
||
|
+ /* Setup pageblock_order for HUGETLB_PAGE_SIZE_VARIABLE */
|
||
|
+ set_pageblock_order();
|
||
|
+
|
||
|
/*
|
||
|
* map is using big page (aka 2M in x86 64 bit)
|
||
|
* usemap is less one page (aka 24 bytes)
|
||
|
diff --git a/net/core/dev.c b/net/core/dev.c
|
||
|
index 5738654..4b18703 100644
|
||
|
--- a/net/core/dev.c
|
||
|
+++ b/net/core/dev.c
|
||
|
@@ -1177,6 +1177,7 @@ static int __dev_open(struct net_device *dev)
|
||
|
net_dmaengine_get();
|
||
|
dev_set_rx_mode(dev);
|
||
|
dev_activate(dev);
|
||
|
+ add_device_randomness(dev->dev_addr, dev->addr_len);
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
@@ -4841,6 +4842,7 @@ int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa)
|
||
|
err = ops->ndo_set_mac_address(dev, sa);
|
||
|
if (!err)
|
||
|
call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
|
||
|
+ add_device_randomness(dev->dev_addr, dev->addr_len);
|
||
|
return err;
|
||
|
}
|
||
|
EXPORT_SYMBOL(dev_set_mac_address);
|
||
|
@@ -5621,6 +5623,7 @@ int register_netdevice(struct net_device *dev)
|
||
|
dev_init_scheduler(dev);
|
||
|
dev_hold(dev);
|
||
|
list_netdevice(dev);
|
||
|
+ add_device_randomness(dev->dev_addr, dev->addr_len);
|
||
|
|
||
|
/* Notify protocols, that a new device appeared. */
|
||
|
ret = call_netdevice_notifiers(NETDEV_REGISTER, dev);
|
||
|
diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c
|
||
|
index 7f36b38..b856f87 100644
|
||
|
--- a/net/core/drop_monitor.c
|
||
|
+++ b/net/core/drop_monitor.c
|
||
|
@@ -33,22 +33,19 @@
|
||
|
#define TRACE_ON 1
|
||
|
#define TRACE_OFF 0
|
||
|
|
||
|
-static void send_dm_alert(struct work_struct *unused);
|
||
|
-
|
||
|
-
|
||
|
/*
|
||
|
* Globals, our netlink socket pointer
|
||
|
* and the work handle that will send up
|
||
|
* netlink alerts
|
||
|
*/
|
||
|
static int trace_state = TRACE_OFF;
|
||
|
-static DEFINE_SPINLOCK(trace_state_lock);
|
||
|
+static DEFINE_MUTEX(trace_state_mutex);
|
||
|
|
||
|
struct per_cpu_dm_data {
|
||
|
- struct work_struct dm_alert_work;
|
||
|
- struct sk_buff *skb;
|
||
|
- atomic_t dm_hit_count;
|
||
|
- struct timer_list send_timer;
|
||
|
+ spinlock_t lock;
|
||
|
+ struct sk_buff *skb;
|
||
|
+ struct work_struct dm_alert_work;
|
||
|
+ struct timer_list send_timer;
|
||
|
};
|
||
|
|
||
|
struct dm_hw_stat_delta {
|
||
|
@@ -74,56 +71,59 @@ static int dm_delay = 1;
|
||
|
static unsigned long dm_hw_check_delta = 2*HZ;
|
||
|
static LIST_HEAD(hw_stats_list);
|
||
|
|
||
|
-static void reset_per_cpu_data(struct per_cpu_dm_data *data)
|
||
|
+static struct sk_buff *reset_per_cpu_data(struct per_cpu_dm_data *data)
|
||
|
{
|
||
|
size_t al;
|
||
|
struct net_dm_alert_msg *msg;
|
||
|
struct nlattr *nla;
|
||
|
+ struct sk_buff *skb;
|
||
|
+ unsigned long flags;
|
||
|
|
||
|
al = sizeof(struct net_dm_alert_msg);
|
||
|
al += dm_hit_limit * sizeof(struct net_dm_drop_point);
|
||
|
al += sizeof(struct nlattr);
|
||
|
|
||
|
- data->skb = genlmsg_new(al, GFP_KERNEL);
|
||
|
- genlmsg_put(data->skb, 0, 0, &net_drop_monitor_family,
|
||
|
- 0, NET_DM_CMD_ALERT);
|
||
|
- nla = nla_reserve(data->skb, NLA_UNSPEC, sizeof(struct net_dm_alert_msg));
|
||
|
- msg = nla_data(nla);
|
||
|
- memset(msg, 0, al);
|
||
|
- atomic_set(&data->dm_hit_count, dm_hit_limit);
|
||
|
+ skb = genlmsg_new(al, GFP_KERNEL);
|
||
|
+
|
||
|
+ if (skb) {
|
||
|
+ genlmsg_put(skb, 0, 0, &net_drop_monitor_family,
|
||
|
+ 0, NET_DM_CMD_ALERT);
|
||
|
+ nla = nla_reserve(skb, NLA_UNSPEC,
|
||
|
+ sizeof(struct net_dm_alert_msg));
|
||
|
+ msg = nla_data(nla);
|
||
|
+ memset(msg, 0, al);
|
||
|
+ } else {
|
||
|
+ mod_timer(&data->send_timer, jiffies + HZ / 10);
|
||
|
+ }
|
||
|
+
|
||
|
+ spin_lock_irqsave(&data->lock, flags);
|
||
|
+ swap(data->skb, skb);
|
||
|
+ spin_unlock_irqrestore(&data->lock, flags);
|
||
|
+
|
||
|
+ return skb;
|
||
|
}
|
||
|
|
||
|
-static void send_dm_alert(struct work_struct *unused)
|
||
|
+static void send_dm_alert(struct work_struct *work)
|
||
|
{
|
||
|
struct sk_buff *skb;
|
||
|
- struct per_cpu_dm_data *data = &__get_cpu_var(dm_cpu_data);
|
||
|
+ struct per_cpu_dm_data *data;
|
||
|
|
||
|
- /*
|
||
|
- * Grab the skb we're about to send
|
||
|
- */
|
||
|
- skb = data->skb;
|
||
|
+ data = container_of(work, struct per_cpu_dm_data, dm_alert_work);
|
||
|
|
||
|
- /*
|
||
|
- * Replace it with a new one
|
||
|
- */
|
||
|
- reset_per_cpu_data(data);
|
||
|
-
|
||
|
- /*
|
||
|
- * Ship it!
|
||
|
- */
|
||
|
- genlmsg_multicast(skb, 0, NET_DM_GRP_ALERT, GFP_KERNEL);
|
||
|
+ skb = reset_per_cpu_data(data);
|
||
|
|
||
|
+ if (skb)
|
||
|
+ genlmsg_multicast(skb, 0, NET_DM_GRP_ALERT, GFP_KERNEL);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* This is the timer function to delay the sending of an alert
|
||
|
* in the event that more drops will arrive during the
|
||
|
- * hysteresis period. Note that it operates under the timer interrupt
|
||
|
- * so we don't need to disable preemption here
|
||
|
+ * hysteresis period.
|
||
|
*/
|
||
|
-static void sched_send_work(unsigned long unused)
|
||
|
+static void sched_send_work(unsigned long _data)
|
||
|
{
|
||
|
- struct per_cpu_dm_data *data = &__get_cpu_var(dm_cpu_data);
|
||
|
+ struct per_cpu_dm_data *data = (struct per_cpu_dm_data *)_data;
|
||
|
|
||
|
schedule_work(&data->dm_alert_work);
|
||
|
}
|
||
|
@@ -134,17 +134,19 @@ static void trace_drop_common(struct sk_buff *skb, void *location)
|
||
|
struct nlmsghdr *nlh;
|
||
|
struct nlattr *nla;
|
||
|
int i;
|
||
|
- struct per_cpu_dm_data *data = &__get_cpu_var(dm_cpu_data);
|
||
|
+ struct sk_buff *dskb;
|
||
|
+ struct per_cpu_dm_data *data;
|
||
|
+ unsigned long flags;
|
||
|
|
||
|
+ local_irq_save(flags);
|
||
|
+ data = &__get_cpu_var(dm_cpu_data);
|
||
|
+ spin_lock(&data->lock);
|
||
|
+ dskb = data->skb;
|
||
|
|
||
|
- if (!atomic_add_unless(&data->dm_hit_count, -1, 0)) {
|
||
|
- /*
|
||
|
- * we're already at zero, discard this hit
|
||
|
- */
|
||
|
+ if (!dskb)
|
||
|
goto out;
|
||
|
- }
|
||
|
|
||
|
- nlh = (struct nlmsghdr *)data->skb->data;
|
||
|
+ nlh = (struct nlmsghdr *)dskb->data;
|
||
|
nla = genlmsg_data(nlmsg_data(nlh));
|
||
|
msg = nla_data(nla);
|
||
|
for (i = 0; i < msg->entries; i++) {
|
||
|
@@ -153,11 +155,12 @@ static void trace_drop_common(struct sk_buff *skb, void *location)
|
||
|
goto out;
|
||
|
}
|
||
|
}
|
||
|
-
|
||
|
+ if (msg->entries == dm_hit_limit)
|
||
|
+ goto out;
|
||
|
/*
|
||
|
* We need to create a new entry
|
||
|
*/
|
||
|
- __nla_reserve_nohdr(data->skb, sizeof(struct net_dm_drop_point));
|
||
|
+ __nla_reserve_nohdr(dskb, sizeof(struct net_dm_drop_point));
|
||
|
nla->nla_len += NLA_ALIGN(sizeof(struct net_dm_drop_point));
|
||
|
memcpy(msg->points[msg->entries].pc, &location, sizeof(void *));
|
||
|
msg->points[msg->entries].count = 1;
|
||
|
@@ -165,11 +168,11 @@ static void trace_drop_common(struct sk_buff *skb, void *location)
|
||
|
|
||
|
if (!timer_pending(&data->send_timer)) {
|
||
|
data->send_timer.expires = jiffies + dm_delay * HZ;
|
||
|
- add_timer_on(&data->send_timer, smp_processor_id());
|
||
|
+ add_timer(&data->send_timer);
|
||
|
}
|
||
|
|
||
|
out:
|
||
|
- return;
|
||
|
+ spin_unlock_irqrestore(&data->lock, flags);
|
||
|
}
|
||
|
|
||
|
static void trace_kfree_skb_hit(void *ignore, struct sk_buff *skb, void *location)
|
||
|
@@ -213,7 +216,7 @@ static int set_all_monitor_traces(int state)
|
||
|
struct dm_hw_stat_delta *new_stat = NULL;
|
||
|
struct dm_hw_stat_delta *temp;
|
||
|
|
||
|
- spin_lock(&trace_state_lock);
|
||
|
+ mutex_lock(&trace_state_mutex);
|
||
|
|
||
|
if (state == trace_state) {
|
||
|
rc = -EAGAIN;
|
||
|
@@ -252,7 +255,7 @@ static int set_all_monitor_traces(int state)
|
||
|
rc = -EINPROGRESS;
|
||
|
|
||
|
out_unlock:
|
||
|
- spin_unlock(&trace_state_lock);
|
||
|
+ mutex_unlock(&trace_state_mutex);
|
||
|
|
||
|
return rc;
|
||
|
}
|
||
|
@@ -295,12 +298,12 @@ static int dropmon_net_event(struct notifier_block *ev_block,
|
||
|
|
||
|
new_stat->dev = dev;
|
||
|
new_stat->last_rx = jiffies;
|
||
|
- spin_lock(&trace_state_lock);
|
||
|
+ mutex_lock(&trace_state_mutex);
|
||
|
list_add_rcu(&new_stat->list, &hw_stats_list);
|
||
|
- spin_unlock(&trace_state_lock);
|
||
|
+ mutex_unlock(&trace_state_mutex);
|
||
|
break;
|
||
|
case NETDEV_UNREGISTER:
|
||
|
- spin_lock(&trace_state_lock);
|
||
|
+ mutex_lock(&trace_state_mutex);
|
||
|
list_for_each_entry_safe(new_stat, tmp, &hw_stats_list, list) {
|
||
|
if (new_stat->dev == dev) {
|
||
|
new_stat->dev = NULL;
|
||
|
@@ -311,7 +314,7 @@ static int dropmon_net_event(struct notifier_block *ev_block,
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
- spin_unlock(&trace_state_lock);
|
||
|
+ mutex_unlock(&trace_state_mutex);
|
||
|
break;
|
||
|
}
|
||
|
out:
|
||
|
@@ -367,13 +370,15 @@ static int __init init_net_drop_monitor(void)
|
||
|
|
||
|
for_each_present_cpu(cpu) {
|
||
|
data = &per_cpu(dm_cpu_data, cpu);
|
||
|
- reset_per_cpu_data(data);
|
||
|
INIT_WORK(&data->dm_alert_work, send_dm_alert);
|
||
|
init_timer(&data->send_timer);
|
||
|
- data->send_timer.data = cpu;
|
||
|
+ data->send_timer.data = (unsigned long)data;
|
||
|
data->send_timer.function = sched_send_work;
|
||
|
+ spin_lock_init(&data->lock);
|
||
|
+ reset_per_cpu_data(data);
|
||
|
}
|
||
|
|
||
|
+
|
||
|
goto out;
|
||
|
|
||
|
out_unreg:
|
||
|
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
|
||
|
index 2ef859a..05842ab 100644
|
||
|
--- a/net/core/rtnetlink.c
|
||
|
+++ b/net/core/rtnetlink.c
|
||
|
@@ -1354,6 +1354,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
|
||
|
goto errout;
|
||
|
send_addr_notify = 1;
|
||
|
modified = 1;
|
||
|
+ add_device_randomness(dev->dev_addr, dev->addr_len);
|
||
|
}
|
||
|
|
||
|
if (tb[IFLA_MTU]) {
|
||
|
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
|
||
|
index 8761bf8..337c68b 100644
|
||
|
--- a/net/sunrpc/rpcb_clnt.c
|
||
|
+++ b/net/sunrpc/rpcb_clnt.c
|
||
|
@@ -246,7 +246,7 @@ static int rpcb_create_local_unix(void)
|
||
|
if (IS_ERR(clnt)) {
|
||
|
dprintk("RPC: failed to create AF_LOCAL rpcbind "
|
||
|
"client (errno %ld).\n", PTR_ERR(clnt));
|
||
|
- result = -PTR_ERR(clnt);
|
||
|
+ result = PTR_ERR(clnt);
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
@@ -293,7 +293,7 @@ static int rpcb_create_local_net(void)
|
||
|
if (IS_ERR(clnt)) {
|
||
|
dprintk("RPC: failed to create local rpcbind "
|
||
|
"client (errno %ld).\n", PTR_ERR(clnt));
|
||
|
- result = -PTR_ERR(clnt);
|
||
|
+ result = PTR_ERR(clnt);
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
|
||
|
index 4e2b3b4..c90b832 100644
|
||
|
--- a/net/sunrpc/sched.c
|
||
|
+++ b/net/sunrpc/sched.c
|
||
|
@@ -755,7 +755,9 @@ void rpc_execute(struct rpc_task *task)
|
||
|
|
||
|
static void rpc_async_schedule(struct work_struct *work)
|
||
|
{
|
||
|
+ current->flags |= PF_FSTRANS;
|
||
|
__rpc_execute(container_of(work, struct rpc_task, u.tk_work));
|
||
|
+ current->flags &= ~PF_FSTRANS;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c
|
||
|
index b446e10..06cdbff 100644
|
||
|
--- a/net/sunrpc/xprtrdma/transport.c
|
||
|
+++ b/net/sunrpc/xprtrdma/transport.c
|
||
|
@@ -200,6 +200,7 @@ xprt_rdma_connect_worker(struct work_struct *work)
|
||
|
int rc = 0;
|
||
|
|
||
|
if (!xprt->shutdown) {
|
||
|
+ current->flags |= PF_FSTRANS;
|
||
|
xprt_clear_connected(xprt);
|
||
|
|
||
|
dprintk("RPC: %s: %sconnect\n", __func__,
|
||
|
@@ -212,10 +213,10 @@ xprt_rdma_connect_worker(struct work_struct *work)
|
||
|
|
||
|
out:
|
||
|
xprt_wake_pending_tasks(xprt, rc);
|
||
|
-
|
||
|
out_clear:
|
||
|
dprintk("RPC: %s: exit\n", __func__);
|
||
|
xprt_clear_connecting(xprt);
|
||
|
+ current->flags &= ~PF_FSTRANS;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
|
||
|
index 55472c4..1a6edc7 100644
|
||
|
--- a/net/sunrpc/xprtsock.c
|
||
|
+++ b/net/sunrpc/xprtsock.c
|
||
|
@@ -1895,6 +1895,8 @@ static void xs_local_setup_socket(struct work_struct *work)
|
||
|
if (xprt->shutdown)
|
||
|
goto out;
|
||
|
|
||
|
+ current->flags |= PF_FSTRANS;
|
||
|
+
|
||
|
clear_bit(XPRT_CONNECTION_ABORT, &xprt->state);
|
||
|
status = __sock_create(xprt->xprt_net, AF_LOCAL,
|
||
|
SOCK_STREAM, 0, &sock, 1);
|
||
|
@@ -1928,6 +1930,7 @@ static void xs_local_setup_socket(struct work_struct *work)
|
||
|
out:
|
||
|
xprt_clear_connecting(xprt);
|
||
|
xprt_wake_pending_tasks(xprt, status);
|
||
|
+ current->flags &= ~PF_FSTRANS;
|
||
|
}
|
||
|
|
||
|
static void xs_udp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
|
||
|
@@ -1970,6 +1973,8 @@ static void xs_udp_setup_socket(struct work_struct *work)
|
||
|
if (xprt->shutdown)
|
||
|
goto out;
|
||
|
|
||
|
+ current->flags |= PF_FSTRANS;
|
||
|
+
|
||
|
/* Start by resetting any existing state */
|
||
|
xs_reset_transport(transport);
|
||
|
sock = xs_create_sock(xprt, transport,
|
||
|
@@ -1988,6 +1993,7 @@ static void xs_udp_setup_socket(struct work_struct *work)
|
||
|
out:
|
||
|
xprt_clear_connecting(xprt);
|
||
|
xprt_wake_pending_tasks(xprt, status);
|
||
|
+ current->flags &= ~PF_FSTRANS;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
@@ -2113,6 +2119,8 @@ static void xs_tcp_setup_socket(struct work_struct *work)
|
||
|
if (xprt->shutdown)
|
||
|
goto out;
|
||
|
|
||
|
+ current->flags |= PF_FSTRANS;
|
||
|
+
|
||
|
if (!sock) {
|
||
|
clear_bit(XPRT_CONNECTION_ABORT, &xprt->state);
|
||
|
sock = xs_create_sock(xprt, transport,
|
||
|
@@ -2162,6 +2170,7 @@ static void xs_tcp_setup_socket(struct work_struct *work)
|
||
|
case -EINPROGRESS:
|
||
|
case -EALREADY:
|
||
|
xprt_clear_connecting(xprt);
|
||
|
+ current->flags &= ~PF_FSTRANS;
|
||
|
return;
|
||
|
case -EINVAL:
|
||
|
/* Happens, for instance, if the user specified a link
|
||
|
@@ -2174,6 +2183,7 @@ out_eagain:
|
||
|
out:
|
||
|
xprt_clear_connecting(xprt);
|
||
|
xprt_wake_pending_tasks(xprt, status);
|
||
|
+ current->flags &= ~PF_FSTRANS;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
diff --git a/net/wireless/util.c b/net/wireless/util.c
|
||
|
index 74d5292..b5e4c1c 100644
|
||
|
--- a/net/wireless/util.c
|
||
|
+++ b/net/wireless/util.c
|
||
|
@@ -981,6 +981,9 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
|
||
|
}
|
||
|
mutex_unlock(&rdev->devlist_mtx);
|
||
|
|
||
|
+ if (total == 1)
|
||
|
+ return 0;
|
||
|
+
|
||
|
for (i = 0; i < rdev->wiphy.n_iface_combinations; i++) {
|
||
|
const struct ieee80211_iface_combination *c;
|
||
|
struct ieee80211_iface_limit *limits;
|
||
|
diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c
|
||
|
index 1cff331..4608c2c 100644
|
||
|
--- a/sound/drivers/mpu401/mpu401_uart.c
|
||
|
+++ b/sound/drivers/mpu401/mpu401_uart.c
|
||
|
@@ -554,6 +554,7 @@ int snd_mpu401_uart_new(struct snd_card *card, int device,
|
||
|
spin_lock_init(&mpu->output_lock);
|
||
|
spin_lock_init(&mpu->timer_lock);
|
||
|
mpu->hardware = hardware;
|
||
|
+ mpu->irq = -1;
|
||
|
if (! (info_flags & MPU401_INFO_INTEGRATED)) {
|
||
|
int res_size = hardware == MPU401_HW_PC98II ? 4 : 2;
|
||
|
mpu->res = request_region(port, res_size, "MPU401 UART");
|
||
|
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
|
||
|
index 191fd78..2e2eb93 100644
|
||
|
--- a/sound/pci/hda/patch_realtek.c
|
||
|
+++ b/sound/pci/hda/patch_realtek.c
|
||
|
@@ -4809,6 +4809,15 @@ static int alc269_resume(struct hda_codec *codec)
|
||
|
}
|
||
|
#endif /* CONFIG_PM */
|
||
|
|
||
|
+static void alc269_fixup_pincfg_no_hp_to_lineout(struct hda_codec *codec,
|
||
|
+ const struct alc_fixup *fix, int action)
|
||
|
+{
|
||
|
+ struct alc_spec *spec = codec->spec;
|
||
|
+
|
||
|
+ if (action == ALC_FIXUP_ACT_PRE_PROBE)
|
||
|
+ spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
|
||
|
+}
|
||
|
+
|
||
|
static void alc269_fixup_hweq(struct hda_codec *codec,
|
||
|
const struct alc_fixup *fix, int action)
|
||
|
{
|
||
|
@@ -4909,6 +4918,8 @@ enum {
|
||
|
ALC269_FIXUP_DMIC,
|
||
|
ALC269VB_FIXUP_AMIC,
|
||
|
ALC269VB_FIXUP_DMIC,
|
||
|
+ ALC269_FIXUP_LENOVO_DOCK,
|
||
|
+ ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT,
|
||
|
};
|
||
|
|
||
|
static const struct alc_fixup alc269_fixups[] = {
|
||
|
@@ -5029,6 +5040,20 @@ static const struct alc_fixup alc269_fixups[] = {
|
||
|
{ }
|
||
|
},
|
||
|
},
|
||
|
+ [ALC269_FIXUP_LENOVO_DOCK] = {
|
||
|
+ .type = ALC_FIXUP_PINS,
|
||
|
+ .v.pins = (const struct alc_pincfg[]) {
|
||
|
+ { 0x19, 0x23a11040 }, /* dock mic */
|
||
|
+ { 0x1b, 0x2121103f }, /* dock headphone */
|
||
|
+ { }
|
||
|
+ },
|
||
|
+ .chained = true,
|
||
|
+ .chain_id = ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT
|
||
|
+ },
|
||
|
+ [ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT] = {
|
||
|
+ .type = ALC_FIXUP_FUNC,
|
||
|
+ .v.func = alc269_fixup_pincfg_no_hp_to_lineout,
|
||
|
+ },
|
||
|
};
|
||
|
|
||
|
static const struct snd_pci_quirk alc269_fixup_tbl[] = {
|
||
|
@@ -5051,6 +5076,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
|
||
|
SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
|
||
|
SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE),
|
||
|
SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE),
|
||
|
+ SND_PCI_QUIRK(0x17aa, 0x21f6, "Thinkpad T530", ALC269_FIXUP_LENOVO_DOCK),
|
||
|
+ SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK),
|
||
|
SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_QUANTA_MUTE),
|
||
|
SND_PCI_QUIRK(0x17aa, 0x3bf8, "Lenovo Ideapd", ALC269_FIXUP_PCM_44K),
|
||
|
SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
|
||
|
@@ -5109,6 +5136,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
|
||
|
static const struct alc_model_fixup alc269_fixup_models[] = {
|
||
|
{.id = ALC269_FIXUP_AMIC, .name = "laptop-amic"},
|
||
|
{.id = ALC269_FIXUP_DMIC, .name = "laptop-dmic"},
|
||
|
+ {.id = ALC269_FIXUP_LENOVO_DOCK, .name = "lenovo-dock"},
|
||
|
{}
|
||
|
};
|
||
|
|
||
|
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
|
||
|
index 1fe1308..7160ff2 100644
|
||
|
--- a/sound/pci/hda/patch_via.c
|
||
|
+++ b/sound/pci/hda/patch_via.c
|
||
|
@@ -3227,7 +3227,7 @@ static void set_widgets_power_state_vt1718S(struct hda_codec *codec)
|
||
|
{
|
||
|
struct via_spec *spec = codec->spec;
|
||
|
int imux_is_smixer;
|
||
|
- unsigned int parm;
|
||
|
+ unsigned int parm, parm2;
|
||
|
/* MUX6 (1eh) = stereo mixer */
|
||
|
imux_is_smixer =
|
||
|
snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5;
|
||
|
@@ -3250,7 +3250,7 @@ static void set_widgets_power_state_vt1718S(struct hda_codec *codec)
|
||
|
parm = AC_PWRST_D3;
|
||
|
set_pin_power_state(codec, 0x27, &parm);
|
||
|
snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE, parm);
|
||
|
- snd_hda_codec_write(codec, 0xb, 0, AC_VERB_SET_POWER_STATE, parm);
|
||
|
+ parm2 = parm; /* for pin 0x0b */
|
||
|
|
||
|
/* PW2 (26h), AOW2 (ah) */
|
||
|
parm = AC_PWRST_D3;
|
||
|
@@ -3265,6 +3265,9 @@ static void set_widgets_power_state_vt1718S(struct hda_codec *codec)
|
||
|
if (!spec->hp_independent_mode) /* check for redirected HP */
|
||
|
set_pin_power_state(codec, 0x28, &parm);
|
||
|
snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE, parm);
|
||
|
+ if (!spec->hp_independent_mode && parm2 != AC_PWRST_D3)
|
||
|
+ parm = parm2;
|
||
|
+ snd_hda_codec_write(codec, 0xb, 0, AC_VERB_SET_POWER_STATE, parm);
|
||
|
/* MW9 (21h), Mw2 (1ah), AOW0 (8h) */
|
||
|
snd_hda_codec_write(codec, 0x21, 0, AC_VERB_SET_POWER_STATE,
|
||
|
imux_is_smixer ? AC_PWRST_D0 : parm);
|
||
|
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
|
||
|
index 07dd7eb..e97df24 100644
|
||
|
--- a/sound/soc/codecs/wm8962.c
|
||
|
+++ b/sound/soc/codecs/wm8962.c
|
||
|
@@ -3105,6 +3105,9 @@ static int wm8962_set_bias_level(struct snd_soc_codec *codec,
|
||
|
/* VMID 2*250k */
|
||
|
snd_soc_update_bits(codec, WM8962_PWR_MGMT_1,
|
||
|
WM8962_VMID_SEL_MASK, 0x100);
|
||
|
+
|
||
|
+ if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
|
||
|
+ msleep(100);
|
||
|
break;
|
||
|
|
||
|
case SND_SOC_BIAS_OFF:
|
||
|
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
|
||
|
index de61b8a..98c5774 100644
|
||
|
--- a/sound/soc/codecs/wm8994.c
|
||
|
+++ b/sound/soc/codecs/wm8994.c
|
||
|
@@ -2508,7 +2508,7 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
- bclk_rate = params_rate(params) * 2;
|
||
|
+ bclk_rate = params_rate(params) * 4;
|
||
|
switch (params_format(params)) {
|
||
|
case SNDRV_PCM_FORMAT_S16_LE:
|
||
|
bclk_rate *= 16;
|
||
|
diff --git a/sound/usb/clock.c b/sound/usb/clock.c
|
||
|
index 379baad..5e634a2 100644
|
||
|
--- a/sound/usb/clock.c
|
||
|
+++ b/sound/usb/clock.c
|
||
|
@@ -111,7 +111,8 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id)
|
||
|
return 0;
|
||
|
|
||
|
/* If a clock source can't tell us whether it's valid, we assume it is */
|
||
|
- if (!uac2_control_is_readable(cs_desc->bmControls, UAC2_CS_CONTROL_CLOCK_VALID))
|
||
|
+ if (!uac2_control_is_readable(cs_desc->bmControls,
|
||
|
+ UAC2_CS_CONTROL_CLOCK_VALID - 1))
|
||
|
return 1;
|
||
|
|
||
|
err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
|