diff options
Diffstat (limited to '3.2.62/1043_linux-3.2.44.patch')
-rw-r--r-- | 3.2.62/1043_linux-3.2.44.patch | 2808 |
1 files changed, 2808 insertions, 0 deletions
diff --git a/3.2.62/1043_linux-3.2.44.patch b/3.2.62/1043_linux-3.2.44.patch new file mode 100644 index 0000000..3d5e6ff --- /dev/null +++ b/3.2.62/1043_linux-3.2.44.patch @@ -0,0 +1,2808 @@ +diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt +index ddbf18e..897f223 100644 +--- a/Documentation/kernel-parameters.txt ++++ b/Documentation/kernel-parameters.txt +@@ -948,6 +948,20 @@ bytes respectively. Such letter suffixes can also be entirely omitted. + i8k.restricted [HW] Allow controlling fans only if SYS_ADMIN + capability is set. + ++ i915.invert_brightness= ++ [DRM] Invert the sense of the variable that is used to ++ set the brightness of the panel backlight. Normally a ++ brightness value of 0 indicates backlight switched off, ++ and the maximum of the brightness value sets the backlight ++ to maximum brightness. If this parameter is set to 0 ++ (default) and the machine requires it, or this parameter ++ is set to 1, a brightness value of 0 sets the backlight ++ to maximum brightness, and the maximum of the brightness ++ value switches the backlight off. ++ -1 -- never invert brightness ++ 0 -- machine default ++ 1 -- force brightness inversion ++ + icn= [HW,ISDN] + Format: <io>[,<membase>[,<icn_id>[,<icn_id2>]]] + +diff --git a/Makefile b/Makefile +index 59130db..566750c 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,6 +1,6 @@ + VERSION = 3 + PATCHLEVEL = 2 +-SUBLEVEL = 43 ++SUBLEVEL = 44 + EXTRAVERSION = + NAME = Saber-toothed Squirrel + +diff --git a/arch/alpha/kernel/sys_nautilus.c b/arch/alpha/kernel/sys_nautilus.c +index 4112200..c52a8ef 100644 +--- a/arch/alpha/kernel/sys_nautilus.c ++++ b/arch/alpha/kernel/sys_nautilus.c +@@ -189,6 +189,10 @@ nautilus_machine_check(unsigned long vector, unsigned long la_ptr) + extern void free_reserved_mem(void *, void *); + extern void pcibios_claim_one_bus(struct pci_bus *); + ++static struct resource irongate_io = { ++ .name = "Irongate PCI IO", ++ .flags = IORESOURCE_IO, ++}; + static struct resource irongate_mem = { + .name = "Irongate PCI MEM", + .flags = IORESOURCE_MEM, +@@ -210,6 +214,7 @@ nautilus_init_pci(void) + + irongate = pci_get_bus_and_slot(0, 0); + bus->self = irongate; ++ bus->resource[0] = &irongate_io; + bus->resource[1] = &irongate_mem; + + pci_bus_size_bridges(bus); +diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c +index ecebb89..a559ee7 100644 +--- a/arch/arm/kernel/perf_event.c ++++ b/arch/arm/kernel/perf_event.c +@@ -326,7 +326,10 @@ validate_event(struct pmu_hw_events *hw_events, + struct hw_perf_event fake_event = event->hw; + struct pmu *leader_pmu = event->group_leader->pmu; + +- if (event->pmu != leader_pmu || event->state <= PERF_EVENT_STATE_OFF) ++ if (event->pmu != leader_pmu || event->state < PERF_EVENT_STATE_OFF) ++ return 1; ++ ++ if (event->state == PERF_EVENT_STATE_OFF && !event->attr.enable_on_exec) + return 1; + + return armpmu->get_event_idx(hw_events, &fake_event) >= 0; +diff --git a/arch/arm/mm/cache-feroceon-l2.c b/arch/arm/mm/cache-feroceon-l2.c +index e0b0e7a..09f8851 100644 +--- a/arch/arm/mm/cache-feroceon-l2.c ++++ b/arch/arm/mm/cache-feroceon-l2.c +@@ -342,6 +342,7 @@ void __init feroceon_l2_init(int __l2_wt_override) + outer_cache.inv_range = feroceon_l2_inv_range; + outer_cache.clean_range = feroceon_l2_clean_range; + outer_cache.flush_range = feroceon_l2_flush_range; ++ outer_cache.inv_all = l2_inv_all; + + enable_l2(); + +diff --git a/arch/arm/mm/proc-arm920.S b/arch/arm/mm/proc-arm920.S +index 88fb3d9..927a639 100644 +--- a/arch/arm/mm/proc-arm920.S ++++ b/arch/arm/mm/proc-arm920.S +@@ -380,7 +380,7 @@ ENTRY(cpu_arm920_set_pte_ext) + /* Suspend/resume support: taken from arch/arm/plat-s3c24xx/sleep.S */ + .globl cpu_arm920_suspend_size + .equ cpu_arm920_suspend_size, 4 * 3 +-#ifdef CONFIG_PM_SLEEP ++#ifdef CONFIG_ARM_CPU_SUSPEND + ENTRY(cpu_arm920_do_suspend) + stmfd sp!, {r4 - r6, lr} + mrc p15, 0, r4, c13, c0, 0 @ PID +diff --git a/arch/arm/mm/proc-arm926.S b/arch/arm/mm/proc-arm926.S +index 9f8fd91..090f18f 100644 +--- a/arch/arm/mm/proc-arm926.S ++++ b/arch/arm/mm/proc-arm926.S +@@ -395,7 +395,7 @@ ENTRY(cpu_arm926_set_pte_ext) + /* Suspend/resume support: taken from arch/arm/plat-s3c24xx/sleep.S */ + .globl cpu_arm926_suspend_size + .equ cpu_arm926_suspend_size, 4 * 3 +-#ifdef CONFIG_PM_SLEEP ++#ifdef CONFIG_ARM_CPU_SUSPEND + ENTRY(cpu_arm926_do_suspend) + stmfd sp!, {r4 - r6, lr} + mrc p15, 0, r4, c13, c0, 0 @ PID +diff --git a/arch/arm/mm/proc-sa1100.S b/arch/arm/mm/proc-sa1100.S +index 7d91545..6594aef 100644 +--- a/arch/arm/mm/proc-sa1100.S ++++ b/arch/arm/mm/proc-sa1100.S +@@ -169,7 +169,7 @@ ENTRY(cpu_sa1100_set_pte_ext) + + .globl cpu_sa1100_suspend_size + .equ cpu_sa1100_suspend_size, 4 * 3 +-#ifdef CONFIG_PM_SLEEP ++#ifdef CONFIG_ARM_CPU_SUSPEND + ENTRY(cpu_sa1100_do_suspend) + stmfd sp!, {r4 - r6, lr} + mrc p15, 0, r4, c3, c0, 0 @ domain ID +diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S +index d061d2f..8168d99 100644 +--- a/arch/arm/mm/proc-v6.S ++++ b/arch/arm/mm/proc-v6.S +@@ -129,7 +129,7 @@ ENTRY(cpu_v6_set_pte_ext) + /* Suspend/resume support: taken from arch/arm/mach-s3c64xx/sleep.S */ + .globl cpu_v6_suspend_size + .equ cpu_v6_suspend_size, 4 * 6 +-#ifdef CONFIG_PM_SLEEP ++#ifdef CONFIG_ARM_CPU_SUSPEND + ENTRY(cpu_v6_do_suspend) + stmfd sp!, {r4 - r9, lr} + mrc p15, 0, r4, c13, c0, 0 @ FCSE/PID +diff --git a/arch/arm/mm/proc-xsc3.S b/arch/arm/mm/proc-xsc3.S +index abf0507..5c4969d 100644 +--- a/arch/arm/mm/proc-xsc3.S ++++ b/arch/arm/mm/proc-xsc3.S +@@ -407,7 +407,7 @@ ENTRY(cpu_xsc3_set_pte_ext) + + .globl cpu_xsc3_suspend_size + .equ cpu_xsc3_suspend_size, 4 * 6 +-#ifdef CONFIG_PM_SLEEP ++#ifdef CONFIG_ARM_CPU_SUSPEND + ENTRY(cpu_xsc3_do_suspend) + stmfd sp!, {r4 - r9, lr} + mrc p14, 0, r4, c6, c0, 0 @ clock configuration, for turbo mode +diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S +index 3277904..b09d036 100644 +--- a/arch/arm/mm/proc-xscale.S ++++ b/arch/arm/mm/proc-xscale.S +@@ -521,7 +521,7 @@ ENTRY(cpu_xscale_set_pte_ext) + + .globl cpu_xscale_suspend_size + .equ cpu_xscale_suspend_size, 4 * 6 +-#ifdef CONFIG_PM_SLEEP ++#ifdef CONFIG_ARM_CPU_SUSPEND + ENTRY(cpu_xscale_do_suspend) + stmfd sp!, {r4 - r9, lr} + mrc p14, 0, r4, c6, c0, 0 @ clock configuration, for turbo mode +diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c +index dc36ea6..eb19b6c 100644 +--- a/arch/powerpc/platforms/pseries/lpar.c ++++ b/arch/powerpc/platforms/pseries/lpar.c +@@ -186,7 +186,13 @@ static long pSeries_lpar_hpte_remove(unsigned long hpte_group) + (0x1UL << 4), &dummy1, &dummy2); + if (lpar_rc == H_SUCCESS) + return i; +- BUG_ON(lpar_rc != H_NOT_FOUND); ++ ++ /* ++ * The test for adjunct partition is performed before the ++ * ANDCOND test. H_RESOURCE may be returned, so we need to ++ * check for that as well. ++ */ ++ BUG_ON(lpar_rc != H_NOT_FOUND && lpar_rc != H_RESOURCE); + + slot_offset++; + slot_offset &= 0x7; +diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h +index b4973f4..cfb5a40 100644 +--- a/arch/x86/include/asm/kvm_host.h ++++ b/arch/x86/include/asm/kvm_host.h +@@ -393,8 +393,8 @@ struct kvm_vcpu_arch { + gpa_t time; + struct pvclock_vcpu_time_info hv_clock; + unsigned int hw_tsc_khz; +- unsigned int time_offset; +- struct page *time_page; ++ struct gfn_to_hva_cache pv_time; ++ bool pv_time_enabled; + + struct { + u64 msr_val; +diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h +index a7d2db9..91e758b 100644 +--- a/arch/x86/include/asm/paravirt.h ++++ b/arch/x86/include/asm/paravirt.h +@@ -740,7 +740,10 @@ static inline void arch_leave_lazy_mmu_mode(void) + PVOP_VCALL0(pv_mmu_ops.lazy_mode.leave); + } + +-void arch_flush_lazy_mmu_mode(void); ++static inline void arch_flush_lazy_mmu_mode(void) ++{ ++ PVOP_VCALL0(pv_mmu_ops.lazy_mode.flush); ++} + + static inline void __set_fixmap(unsigned /* enum fixed_addresses */ idx, + phys_addr_t phys, pgprot_t flags) +diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h +index 8e8b9a4..faf2c04 100644 +--- a/arch/x86/include/asm/paravirt_types.h ++++ b/arch/x86/include/asm/paravirt_types.h +@@ -91,6 +91,7 @@ struct pv_lazy_ops { + /* Set deferred update mode, used for batching operations. */ + void (*enter)(void); + void (*leave)(void); ++ void (*flush)(void); + }; + + struct pv_time_ops { +@@ -680,6 +681,7 @@ void paravirt_end_context_switch(struct task_struct *next); + + void paravirt_enter_lazy_mmu(void); + void paravirt_leave_lazy_mmu(void); ++void paravirt_flush_lazy_mmu(void); + + void _paravirt_nop(void); + u32 _paravirt_ident_32(u32); +diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c +index d90272e..84c938f 100644 +--- a/arch/x86/kernel/paravirt.c ++++ b/arch/x86/kernel/paravirt.c +@@ -261,6 +261,18 @@ void paravirt_leave_lazy_mmu(void) + leave_lazy(PARAVIRT_LAZY_MMU); + } + ++void paravirt_flush_lazy_mmu(void) ++{ ++ preempt_disable(); ++ ++ if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU) { ++ arch_leave_lazy_mmu_mode(); ++ arch_enter_lazy_mmu_mode(); ++ } ++ ++ preempt_enable(); ++} ++ + void paravirt_start_context_switch(struct task_struct *prev) + { + BUG_ON(preemptible()); +@@ -290,18 +302,6 @@ enum paravirt_lazy_mode paravirt_get_lazy_mode(void) + return percpu_read(paravirt_lazy_mode); + } + +-void arch_flush_lazy_mmu_mode(void) +-{ +- preempt_disable(); +- +- if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU) { +- arch_leave_lazy_mmu_mode(); +- arch_enter_lazy_mmu_mode(); +- } +- +- preempt_enable(); +-} +- + struct pv_info pv_info = { + .name = "bare hardware", + .paravirt_enabled = 0, +@@ -475,6 +475,7 @@ struct pv_mmu_ops pv_mmu_ops = { + .lazy_mode = { + .enter = paravirt_nop, + .leave = paravirt_nop, ++ .flush = paravirt_nop, + }, + + .set_fixmap = native_set_fixmap, +diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c +index f4063fd..e82a53a 100644 +--- a/arch/x86/kvm/x86.c ++++ b/arch/x86/kvm/x86.c +@@ -1105,7 +1105,6 @@ static int kvm_guest_time_update(struct kvm_vcpu *v) + { + unsigned long flags; + struct kvm_vcpu_arch *vcpu = &v->arch; +- void *shared_kaddr; + unsigned long this_tsc_khz; + s64 kernel_ns, max_kernel_ns; + u64 tsc_timestamp; +@@ -1141,7 +1140,7 @@ static int kvm_guest_time_update(struct kvm_vcpu *v) + + local_irq_restore(flags); + +- if (!vcpu->time_page) ++ if (!vcpu->pv_time_enabled) + return 0; + + /* +@@ -1199,14 +1198,9 @@ static int kvm_guest_time_update(struct kvm_vcpu *v) + */ + vcpu->hv_clock.version += 2; + +- shared_kaddr = kmap_atomic(vcpu->time_page, KM_USER0); +- +- memcpy(shared_kaddr + vcpu->time_offset, &vcpu->hv_clock, +- sizeof(vcpu->hv_clock)); +- +- kunmap_atomic(shared_kaddr, KM_USER0); +- +- mark_page_dirty(v->kvm, vcpu->time >> PAGE_SHIFT); ++ kvm_write_guest_cached(v->kvm, &vcpu->pv_time, ++ &vcpu->hv_clock, ++ sizeof(vcpu->hv_clock)); + return 0; + } + +@@ -1486,7 +1480,8 @@ static int kvm_pv_enable_async_pf(struct kvm_vcpu *vcpu, u64 data) + return 0; + } + +- if (kvm_gfn_to_hva_cache_init(vcpu->kvm, &vcpu->arch.apf.data, gpa)) ++ if (kvm_gfn_to_hva_cache_init(vcpu->kvm, &vcpu->arch.apf.data, gpa, ++ sizeof(u32))) + return 1; + + vcpu->arch.apf.send_user_only = !(data & KVM_ASYNC_PF_SEND_ALWAYS); +@@ -1496,10 +1491,7 @@ static int kvm_pv_enable_async_pf(struct kvm_vcpu *vcpu, u64 data) + + static void kvmclock_reset(struct kvm_vcpu *vcpu) + { +- if (vcpu->arch.time_page) { +- kvm_release_page_dirty(vcpu->arch.time_page); +- vcpu->arch.time_page = NULL; +- } ++ vcpu->arch.pv_time_enabled = false; + } + + static void accumulate_steal_time(struct kvm_vcpu *vcpu) +@@ -1591,6 +1583,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) + break; + case MSR_KVM_SYSTEM_TIME_NEW: + case MSR_KVM_SYSTEM_TIME: { ++ u64 gpa_offset; + kvmclock_reset(vcpu); + + vcpu->arch.time = data; +@@ -1600,16 +1593,14 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) + if (!(data & 1)) + break; + +- /* ...but clean it before doing the actual write */ +- vcpu->arch.time_offset = data & ~(PAGE_MASK | 1); ++ gpa_offset = data & ~(PAGE_MASK | 1); + +- vcpu->arch.time_page = +- gfn_to_page(vcpu->kvm, data >> PAGE_SHIFT); +- +- if (is_error_page(vcpu->arch.time_page)) { +- kvm_release_page_clean(vcpu->arch.time_page); +- vcpu->arch.time_page = NULL; +- } ++ if (kvm_gfn_to_hva_cache_init(vcpu->kvm, ++ &vcpu->arch.pv_time, data & ~1ULL, ++ sizeof(struct pvclock_vcpu_time_info))) ++ vcpu->arch.pv_time_enabled = false; ++ else ++ vcpu->arch.pv_time_enabled = true; + break; + } + case MSR_KVM_ASYNC_PF_EN: +@@ -1625,7 +1616,8 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) + return 1; + + if (kvm_gfn_to_hva_cache_init(vcpu->kvm, &vcpu->arch.st.stime, +- data & KVM_STEAL_VALID_BITS)) ++ data & KVM_STEAL_VALID_BITS, ++ sizeof(struct kvm_steal_time))) + return 1; + + vcpu->arch.st.msr_val = data; +@@ -6549,6 +6541,7 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) + if (!zalloc_cpumask_var(&vcpu->arch.wbinvd_dirty_mask, GFP_KERNEL)) + goto fail_free_mce_banks; + ++ vcpu->arch.pv_time_enabled = false; + kvm_async_pf_hash_reset(vcpu); + + return 0; +diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c +index cf4603b..8f4fda4 100644 +--- a/arch/x86/lguest/boot.c ++++ b/arch/x86/lguest/boot.c +@@ -1328,6 +1328,7 @@ __init void lguest_init(void) + pv_mmu_ops.read_cr3 = lguest_read_cr3; + pv_mmu_ops.lazy_mode.enter = paravirt_enter_lazy_mmu; + pv_mmu_ops.lazy_mode.leave = lguest_leave_lazy_mmu_mode; ++ pv_mmu_ops.lazy_mode.flush = paravirt_flush_lazy_mmu; + pv_mmu_ops.pte_update = lguest_pte_update; + pv_mmu_ops.pte_update_defer = lguest_pte_update; + +diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c +index 7b73c88..53a7b69 100644 +--- a/arch/x86/mm/fault.c ++++ b/arch/x86/mm/fault.c +@@ -377,10 +377,12 @@ static noinline __kprobes int vmalloc_fault(unsigned long address) + if (pgd_none(*pgd_ref)) + return -1; + +- if (pgd_none(*pgd)) ++ if (pgd_none(*pgd)) { + set_pgd(pgd, *pgd_ref); +- else ++ arch_flush_lazy_mmu_mode(); ++ } else { + BUG_ON(pgd_page_vaddr(*pgd) != pgd_page_vaddr(*pgd_ref)); ++ } + + /* + * Below here mismatches are bugs because these lower tables +diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c +index 2b8b0de..fe00be6 100644 +--- a/arch/x86/xen/mmu.c ++++ b/arch/x86/xen/mmu.c +@@ -2079,6 +2079,7 @@ static const struct pv_mmu_ops xen_mmu_ops __initconst = { + .lazy_mode = { + .enter = paravirt_enter_lazy_mmu, + .leave = xen_leave_lazy_mmu, ++ .flush = paravirt_flush_lazy_mmu, + }, + + .set_fixmap = xen_set_fixmap, +diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c +index f0b2ca8..1789e7a 100644 +--- a/block/blk-sysfs.c ++++ b/block/blk-sysfs.c +@@ -200,6 +200,8 @@ queue_store_##name(struct request_queue *q, const char *page, size_t count) \ + unsigned long val; \ + ssize_t ret; \ + ret = queue_var_store(&val, page, count); \ ++ if (ret < 0) \ ++ return ret; \ + if (neg) \ + val = !val; \ + \ +diff --git a/crypto/gcm.c b/crypto/gcm.c +index 1a25263..b97b186 100644 +--- a/crypto/gcm.c ++++ b/crypto/gcm.c +@@ -44,6 +44,7 @@ struct crypto_rfc4543_ctx { + + struct crypto_rfc4543_req_ctx { + u8 auth_tag[16]; ++ u8 assocbuf[32]; + struct scatterlist cipher[1]; + struct scatterlist payload[2]; + struct scatterlist assoc[2]; +@@ -1142,9 +1143,19 @@ static struct aead_request *crypto_rfc4543_crypt(struct aead_request *req, + scatterwalk_crypto_chain(payload, dst, vdst == req->iv + 8, 2); + assoclen += 8 + req->cryptlen - (enc ? 0 : authsize); + +- sg_init_table(assoc, 2); +- sg_set_page(assoc, sg_page(req->assoc), req->assoc->length, +- req->assoc->offset); ++ if (req->assoc->length == req->assoclen) { ++ sg_init_table(assoc, 2); ++ sg_set_page(assoc, sg_page(req->assoc), req->assoc->length, ++ req->assoc->offset); ++ } else { ++ BUG_ON(req->assoclen > sizeof(rctx->assocbuf)); ++ ++ scatterwalk_map_and_copy(rctx->assocbuf, req->assoc, 0, ++ req->assoclen, 0); ++ ++ sg_init_table(assoc, 2); ++ sg_set_buf(assoc, rctx->assocbuf, req->assoclen); ++ } + scatterwalk_crypto_chain(assoc, payload, 0, 2); + + aead_request_set_tfm(subreq, ctx->child); +diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c +index df47397..ddfc1c1 100644 +--- a/drivers/ata/ata_piix.c ++++ b/drivers/ata/ata_piix.c +@@ -150,6 +150,7 @@ enum piix_controller_ids { + tolapai_sata, + piix_pata_vmw, /* PIIX4 for VMware, spurious DMA_ERR */ + ich8_sata_snb, ++ ich8_2port_sata_snb, + }; + + struct piix_map_db { +@@ -326,7 +327,7 @@ static const struct pci_device_id piix_pci_tbl[] = { + /* SATA Controller IDE (Lynx Point) */ + { 0x8086, 0x8c01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb }, + /* SATA Controller IDE (Lynx Point) */ +- { 0x8086, 0x8c08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, ++ { 0x8086, 0x8c08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata_snb }, + /* SATA Controller IDE (Lynx Point) */ + { 0x8086, 0x8c09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, + /* SATA Controller IDE (Lynx Point-LP) */ +@@ -519,6 +520,7 @@ static const struct piix_map_db *piix_map_db_table[] = { + [ich8m_apple_sata] = &ich8m_apple_map_db, + [tolapai_sata] = &tolapai_map_db, + [ich8_sata_snb] = &ich8_map_db, ++ [ich8_2port_sata_snb] = &ich8_2port_map_db, + }; + + static struct ata_port_info piix_port_info[] = { +@@ -660,6 +662,16 @@ static struct ata_port_info piix_port_info[] = { + .port_ops = &piix_sata_ops, + }, + ++ [ich8_2port_sata_snb] = ++ { ++ .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SIDPR ++ | PIIX_FLAG_PIO16, ++ .pio_mask = ATA_PIO4, ++ .mwdma_mask = ATA_MWDMA2, ++ .udma_mask = ATA_UDMA6, ++ .port_ops = &piix_sata_ops, ++ }, ++ + }; + + static struct pci_bits piix_enable_bits[] = { +diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c +index c9540c0..288b635 100644 +--- a/drivers/ata/libata-core.c ++++ b/drivers/ata/libata-core.c +@@ -2401,6 +2401,9 @@ int ata_dev_configure(struct ata_device *dev) + dev->max_sectors = min_t(unsigned int, ATA_MAX_SECTORS_128, + dev->max_sectors); + ++ if (dev->horkage & ATA_HORKAGE_MAX_SEC_LBA48) ++ dev->max_sectors = ATA_MAX_SECTORS_LBA48; ++ + if (ap->ops->dev_config) + ap->ops->dev_config(dev); + +@@ -4057,6 +4060,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { + /* Weird ATAPI devices */ + { "TORiSAN DVD-ROM DRD-N216", NULL, ATA_HORKAGE_MAX_SEC_128 }, + { "QUANTUM DAT DAT72-000", NULL, ATA_HORKAGE_ATAPI_MOD16_DMA }, ++ { "Slimtype DVD A DS8A8SH", NULL, ATA_HORKAGE_MAX_SEC_LBA48 }, + + /* Devices we expect to fail diagnostics */ + +diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h +index 012a9d2..144d37c 100644 +--- a/drivers/gpu/drm/i915/i915_drv.h ++++ b/drivers/gpu/drm/i915/i915_drv.h +@@ -274,6 +274,7 @@ enum intel_pch { + + #define QUIRK_PIPEA_FORCE (1<<0) + #define QUIRK_LVDS_SSC_DISABLE (1<<1) ++#define QUIRK_INVERT_BRIGHTNESS (1<<2) + + struct intel_fbdev; + struct intel_fbc_work; +diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c +index 17961df..897ca06 100644 +--- a/drivers/gpu/drm/i915/intel_display.c ++++ b/drivers/gpu/drm/i915/intel_display.c +@@ -25,6 +25,7 @@ + */ + + #include <linux/cpufreq.h> ++#include <linux/dmi.h> + #include <linux/module.h> + #include <linux/input.h> + #include <linux/i2c.h> +@@ -8831,6 +8832,16 @@ static void quirk_ssc_force_disable(struct drm_device *dev) + dev_priv->quirks |= QUIRK_LVDS_SSC_DISABLE; + } + ++/* ++ * A machine (e.g. Acer Aspire 5734Z) may need to invert the panel backlight ++ * brightness value ++ */ ++static void quirk_invert_brightness(struct drm_device *dev) ++{ ++ struct drm_i915_private *dev_priv = dev->dev_private; ++ dev_priv->quirks |= QUIRK_INVERT_BRIGHTNESS; ++} ++ + struct intel_quirk { + int device; + int subsystem_vendor; +@@ -8838,6 +8849,34 @@ struct intel_quirk { + void (*hook)(struct drm_device *dev); + }; + ++/* For systems that don't have a meaningful PCI subdevice/subvendor ID */ ++struct intel_dmi_quirk { ++ void (*hook)(struct drm_device *dev); ++ const struct dmi_system_id (*dmi_id_list)[]; ++}; ++ ++static int intel_dmi_reverse_brightness(const struct dmi_system_id *id) ++{ ++ DRM_INFO("Backlight polarity reversed on %s\n", id->ident); ++ return 1; ++} ++ ++static const struct intel_dmi_quirk intel_dmi_quirks[] = { ++ { ++ .dmi_id_list = &(const struct dmi_system_id[]) { ++ { ++ .callback = intel_dmi_reverse_brightness, ++ .ident = "NCR Corporation", ++ .matches = {DMI_MATCH(DMI_SYS_VENDOR, "NCR Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, ""), ++ }, ++ }, ++ { } /* terminating entry */ ++ }, ++ .hook = quirk_invert_brightness, ++ }, ++}; ++ + struct intel_quirk intel_quirks[] = { + /* HP Compaq 2730p needs pipe A force quirk (LP: #291555) */ + { 0x2a42, 0x103c, 0x30eb, quirk_pipea_force }, +@@ -8865,6 +8904,18 @@ struct intel_quirk intel_quirks[] = { + + /* Sony Vaio Y cannot use SSC on LVDS */ + { 0x0046, 0x104d, 0x9076, quirk_ssc_force_disable }, ++ ++ /* Acer Aspire 5734Z must invert backlight brightness */ ++ { 0x2a42, 0x1025, 0x0459, quirk_invert_brightness }, ++ ++ /* Acer/eMachines G725 */ ++ { 0x2a42, 0x1025, 0x0210, quirk_invert_brightness }, ++ ++ /* Acer/eMachines e725 */ ++ { 0x2a42, 0x1025, 0x0212, quirk_invert_brightness }, ++ ++ /* Acer/Packard Bell NCL20 */ ++ { 0x2a42, 0x1025, 0x034b, quirk_invert_brightness }, + }; + + static void intel_init_quirks(struct drm_device *dev) +@@ -8882,6 +8933,10 @@ static void intel_init_quirks(struct drm_device *dev) + q->subsystem_device == PCI_ANY_ID)) + q->hook(dev); + } ++ for (i = 0; i < ARRAY_SIZE(intel_dmi_quirks); i++) { ++ if (dmi_check_system(*intel_dmi_quirks[i].dmi_id_list) != 0) ++ intel_dmi_quirks[i].hook(dev); ++ } + } + + /* Disable the VGA plane that we never use */ +diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c +index 04d79fd..72b8949 100644 +--- a/drivers/gpu/drm/i915/intel_panel.c ++++ b/drivers/gpu/drm/i915/intel_panel.c +@@ -28,6 +28,7 @@ + * Chris Wilson <chris@chris-wilson.co.uk> + */ + ++#include <linux/moduleparam.h> + #include "intel_drv.h" + + #define PCI_LBPC 0xf4 /* legacy/combination backlight modes */ +@@ -191,6 +192,27 @@ u32 intel_panel_get_max_backlight(struct drm_device *dev) + return max; + } + ++static int i915_panel_invert_brightness; ++MODULE_PARM_DESC(invert_brightness, "Invert backlight brightness " ++ "(-1 force normal, 0 machine defaults, 1 force inversion), please " ++ "report PCI device ID, subsystem vendor and subsystem device ID " ++ "to dri-devel@lists.freedesktop.org, if your machine needs it. " ++ "It will then be included in an upcoming module version."); ++module_param_named(invert_brightness, i915_panel_invert_brightness, int, 0600); ++static u32 intel_panel_compute_brightness(struct drm_device *dev, u32 val) ++{ ++ struct drm_i915_private *dev_priv = dev->dev_private; ++ ++ if (i915_panel_invert_brightness < 0) ++ return val; ++ ++ if (i915_panel_invert_brightness > 0 || ++ dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) ++ return intel_panel_get_max_backlight(dev) - val; ++ ++ return val; ++} ++ + u32 intel_panel_get_backlight(struct drm_device *dev) + { + struct drm_i915_private *dev_priv = dev->dev_private; +@@ -211,6 +233,7 @@ u32 intel_panel_get_backlight(struct drm_device *dev) + } + } + ++ val = intel_panel_compute_brightness(dev, val); + DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val); + return val; + } +@@ -228,6 +251,7 @@ static void intel_panel_actually_set_backlight(struct drm_device *dev, u32 level + u32 tmp; + + DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level); ++ level = intel_panel_compute_brightness(dev, level); + + if (HAS_PCH_SPLIT(dev)) + return intel_pch_panel_set_backlight(dev, level); +diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c +index 58434e8..37fe246 100644 +--- a/drivers/gpu/vga/vga_switcheroo.c ++++ b/drivers/gpu/vga/vga_switcheroo.c +@@ -26,6 +26,7 @@ + #include <linux/fb.h> + + #include <linux/pci.h> ++#include <linux/console.h> + #include <linux/vga_switcheroo.h> + + struct vga_switcheroo_client { +@@ -256,8 +257,10 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client) + + if (new_client->fb_info) { + struct fb_event event; ++ console_lock(); + event.info = new_client->fb_info; + fb_notifier_call_chain(FB_EVENT_REMAP_ALL_CONSOLE, &event); ++ console_unlock(); + } + + ret = vgasr_priv.handler->switchto(new_client->id); +diff --git a/drivers/hwspinlock/hwspinlock_core.c b/drivers/hwspinlock/hwspinlock_core.c +index 1201a15..08e7e72 100644 +--- a/drivers/hwspinlock/hwspinlock_core.c ++++ b/drivers/hwspinlock/hwspinlock_core.c +@@ -416,6 +416,8 @@ static int __hwspin_lock_request(struct hwspinlock *hwlock) + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + dev_err(dev, "%s: can't power on device\n", __func__); ++ pm_runtime_put_noidle(dev); ++ module_put(dev->driver->owner); + return ret; + } + +diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c +index e7dc732..1d90e26 100644 +--- a/drivers/mtd/mtdchar.c ++++ b/drivers/mtd/mtdchar.c +@@ -1154,7 +1154,11 @@ static int mtd_mmap(struct file *file, struct vm_area_struct *vma) + unsigned long off; + u32 len; + +- if (mtd->type == MTD_RAM || mtd->type == MTD_ROM) { ++ /* This is broken because it assumes the MTD device is map-based ++ and that mtd->priv is a valid struct map_info. It should be ++ replaced with something that uses the mtd_get_unmapped_area() ++ operation properly. */ ++ if (0 /*mtd->type == MTD_RAM || mtd->type == MTD_ROM*/) { + off = vma->vm_pgoff << PAGE_SHIFT; + start = map->phys; + len = PAGE_ALIGN((start & ~PAGE_MASK) + map->size); +diff --git a/drivers/net/can/sja1000/sja1000_of_platform.c b/drivers/net/can/sja1000/sja1000_of_platform.c +index c3dd9d0..1ee5f0c 100644 +--- a/drivers/net/can/sja1000/sja1000_of_platform.c ++++ b/drivers/net/can/sja1000/sja1000_of_platform.c +@@ -94,8 +94,8 @@ static int __devinit sja1000_ofp_probe(struct platform_device *ofdev) + struct net_device *dev; + struct sja1000_priv *priv; + struct resource res; +- const u32 *prop; +- int err, irq, res_size, prop_size; ++ u32 prop; ++ int err, irq, res_size; + void __iomem *base; + + err = of_address_to_resource(np, 0, &res); +@@ -136,27 +136,27 @@ static int __devinit sja1000_ofp_probe(struct platform_device *ofdev) + priv->read_reg = sja1000_ofp_read_reg; + priv->write_reg = sja1000_ofp_write_reg; + +- prop = of_get_property(np, "nxp,external-clock-frequency", &prop_size); +- if (prop && (prop_size == sizeof(u32))) +- priv->can.clock.freq = *prop / 2; ++ err = of_property_read_u32(np, "nxp,external-clock-frequency", &prop); ++ if (!err) ++ priv->can.clock.freq = prop / 2; + else + priv->can.clock.freq = SJA1000_OFP_CAN_CLOCK; /* default */ + +- prop = of_get_property(np, "nxp,tx-output-mode", &prop_size); +- if (prop && (prop_size == sizeof(u32))) +- priv->ocr |= *prop & OCR_MODE_MASK; ++ err = of_property_read_u32(np, "nxp,tx-output-mode", &prop); ++ if (!err) ++ priv->ocr |= prop & OCR_MODE_MASK; + else + priv->ocr |= OCR_MODE_NORMAL; /* default */ + +- prop = of_get_property(np, "nxp,tx-output-config", &prop_size); +- if (prop && (prop_size == sizeof(u32))) +- priv->ocr |= (*prop << OCR_TX_SHIFT) & OCR_TX_MASK; ++ err = of_property_read_u32(np, "nxp,tx-output-config", &prop); ++ if (!err) ++ priv->ocr |= (prop << OCR_TX_SHIFT) & OCR_TX_MASK; + else + priv->ocr |= OCR_TX0_PULLDOWN; /* default */ + +- prop = of_get_property(np, "nxp,clock-out-frequency", &prop_size); +- if (prop && (prop_size == sizeof(u32)) && *prop) { +- u32 divider = priv->can.clock.freq * 2 / *prop; ++ err = of_property_read_u32(np, "nxp,clock-out-frequency", &prop); ++ if (!err && prop) { ++ u32 divider = priv->can.clock.freq * 2 / prop; + + if (divider > 1) + priv->cdr |= divider / 2 - 1; +@@ -166,8 +166,7 @@ static int __devinit sja1000_ofp_probe(struct platform_device *ofdev) + priv->cdr |= CDR_CLK_OFF; /* default */ + } + +- prop = of_get_property(np, "nxp,no-comparator-bypass", NULL); +- if (!prop) ++ if (!of_property_read_bool(np, "nxp,no-comparator-bypass")) + priv->cdr |= CDR_CBP; /* default */ + + priv->irq_flags = IRQF_SHARED; +diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c +index a6153f1..d812790 100644 +--- a/drivers/net/ethernet/realtek/r8169.c ++++ b/drivers/net/ethernet/realtek/r8169.c +@@ -3516,6 +3516,30 @@ static void __devinit rtl_init_mdio_ops(struct rtl8169_private *tp) + } + } + ++static void rtl_speed_down(struct rtl8169_private *tp) ++{ ++ u32 adv; ++ int lpa; ++ ++ rtl_writephy(tp, 0x1f, 0x0000); ++ lpa = rtl_readphy(tp, MII_LPA); ++ ++ if (lpa & (LPA_10HALF | LPA_10FULL)) ++ adv = ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full; ++ else if (lpa & (LPA_100HALF | LPA_100FULL)) ++ adv = ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | ++ ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full; ++ else ++ adv = ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | ++ ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | ++ (tp->mii.supports_gmii ? ++ ADVERTISED_1000baseT_Half | ++ ADVERTISED_1000baseT_Full : 0); ++ ++ rtl8169_set_speed(tp->dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL, ++ adv); ++} ++ + static void rtl_wol_suspend_quirk(struct rtl8169_private *tp) + { + void __iomem *ioaddr = tp->mmio_addr; +@@ -3541,9 +3565,7 @@ static bool rtl_wol_pll_power_down(struct rtl8169_private *tp) + if (!(__rtl8169_get_wol(tp) & WAKE_ANY)) + return false; + +- rtl_writephy(tp, 0x1f, 0x0000); +- rtl_writephy(tp, MII_BMCR, 0x0000); +- ++ rtl_speed_down(tp); + rtl_wol_suspend_quirk(tp); + + return true; +diff --git a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h +index 06b3f0d..c16bea4 100644 +--- a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h ++++ b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h +@@ -648,7 +648,7 @@ static const u32 ar9580_1p0_mac_core[][2] = { + {0x00008258, 0x00000000}, + {0x0000825c, 0x40000000}, + {0x00008260, 0x00080922}, +- {0x00008264, 0x9bc00010}, ++ {0x00008264, 0x9d400010}, + {0x00008268, 0xffffffff}, + {0x0000826c, 0x0000ffff}, + {0x00008270, 0x00000000}, +diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c +index 966661c..84890d5 100644 +--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c ++++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c +@@ -801,7 +801,7 @@ static int ath9k_init_firmware_version(struct ath9k_htc_priv *priv) + * required version. + */ + if (priv->fw_version_major != MAJOR_VERSION_REQ || +- priv->fw_version_minor != MINOR_VERSION_REQ) { ++ priv->fw_version_minor < MINOR_VERSION_REQ) { + dev_err(priv->dev, "ath9k_htc: Please upgrade to FW version %d.%d\n", + MAJOR_VERSION_REQ, MINOR_VERSION_REQ); + return -EINVAL; +diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c +index 17148bb..10fe07d 100644 +--- a/drivers/net/wireless/rt2x00/rt2x00pci.c ++++ b/drivers/net/wireless/rt2x00/rt2x00pci.c +@@ -52,8 +52,8 @@ int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev, + udelay(REGISTER_BUSY_DELAY); + } + +- ERROR(rt2x00dev, "Indirect register access failed: " +- "offset=0x%.08x, value=0x%.08x\n", offset, *reg); ++ printk_once(KERN_ERR "%s() Indirect register access failed: " ++ "offset=0x%.08x, value=0x%.08x\n", __func__, offset, *reg); + *reg = ~0; + + return 0; +diff --git a/drivers/platform/x86/msi-wmi.c b/drivers/platform/x86/msi-wmi.c +index 2264331..b96766b 100644 +--- a/drivers/platform/x86/msi-wmi.c ++++ b/drivers/platform/x86/msi-wmi.c +@@ -176,7 +176,7 @@ static void msi_wmi_notify(u32 value, void *context) + pr_debug("Suppressed key event 0x%X - " + "Last press was %lld us ago\n", + key->code, ktime_to_us(diff)); +- return; ++ goto msi_wmi_notify_exit; + } + last_pressed[key->code - SCANCODE_BASE] = cur; + +@@ -195,6 +195,8 @@ static void msi_wmi_notify(u32 value, void *context) + pr_info("Unknown key pressed - %x\n", eventcode); + } else + pr_info("Unknown event received\n"); ++ ++msi_wmi_notify_exit: + kfree(response.pointer); + } + +diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c +index 0364ca2..d5f4eb8 100644 +--- a/drivers/target/target_core_alua.c ++++ b/drivers/target/target_core_alua.c +@@ -393,8 +393,9 @@ static inline int core_alua_state_standby( + case REPORT_LUNS: + case RECEIVE_DIAGNOSTIC: + case SEND_DIAGNOSTIC: ++ return 0; + case MAINTENANCE_IN: +- switch (cdb[1]) { ++ switch (cdb[1] & 0x1f) { + case MI_REPORT_TARGET_PGS: + return 0; + default: +@@ -435,8 +436,9 @@ static inline int core_alua_state_unavailable( + switch (cdb[0]) { + case INQUIRY: + case REPORT_LUNS: ++ return 0; + case MAINTENANCE_IN: +- switch (cdb[1]) { ++ switch (cdb[1] & 0x1f) { + case MI_REPORT_TARGET_PGS: + return 0; + default: +@@ -475,8 +477,9 @@ static inline int core_alua_state_transition( + switch (cdb[0]) { + case INQUIRY: + case REPORT_LUNS: ++ return 0; + case MAINTENANCE_IN: +- switch (cdb[1]) { ++ switch (cdb[1] & 0x1f) { + case MI_REPORT_TARGET_PGS: + return 0; + default: +diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c +index 9176b2e..898c1de 100644 +--- a/drivers/target/target_core_transport.c ++++ b/drivers/target/target_core_transport.c +@@ -1445,6 +1445,7 @@ static inline void transport_generic_prepare_cdb( + case VERIFY_16: /* SBC - VRProtect */ + case WRITE_VERIFY: /* SBC - VRProtect */ + case WRITE_VERIFY_12: /* SBC - VRProtect */ ++ case MAINTENANCE_IN: /* SPC - Parameter Data Format for SA RTPG */ + break; + default: + cdb[1] &= 0x1f; /* clear logical unit number */ +@@ -2683,7 +2684,7 @@ static int transport_generic_cmd_sequencer( + /* + * Check for emulated MI_REPORT_TARGET_PGS. + */ +- if (cdb[1] == MI_REPORT_TARGET_PGS && ++ if ((cdb[1] & 0x1f) == MI_REPORT_TARGET_PGS && + su_dev->t10_alua.alua_type == SPC3_ALUA_EMULATED) { + cmd->execute_task = + target_emulate_report_target_port_groups; +diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c +index dd9a574..f6fb292 100644 +--- a/drivers/thermal/thermal_sys.c ++++ b/drivers/thermal/thermal_sys.c +@@ -1399,6 +1399,7 @@ static int __init thermal_init(void) + idr_destroy(&thermal_cdev_idr); + mutex_destroy(&thermal_idr_lock); + mutex_destroy(&thermal_list_lock); ++ return result; + } + result = genetlink_init(); + return result; +diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c +index 18e875b..3ca6c0d 100644 +--- a/drivers/usb/serial/ark3116.c ++++ b/drivers/usb/serial/ark3116.c +@@ -68,7 +68,6 @@ static int is_irda(struct usb_serial *serial) + } + + struct ark3116_private { +- wait_queue_head_t delta_msr_wait; + struct async_icount icount; + int irda; /* 1 for irda device */ + +@@ -148,7 +147,6 @@ static int ark3116_attach(struct usb_serial *serial) + if (!priv) + return -ENOMEM; + +- init_waitqueue_head(&priv->delta_msr_wait); + mutex_init(&priv->hw_lock); + spin_lock_init(&priv->status_lock); + +@@ -460,10 +458,14 @@ static int ark3116_ioctl(struct tty_struct *tty, + case TIOCMIWAIT: + for (;;) { + struct async_icount prev = priv->icount; +- interruptible_sleep_on(&priv->delta_msr_wait); ++ interruptible_sleep_on(&port->delta_msr_wait); + /* see if a signal did it */ + if (signal_pending(current)) + return -ERESTARTSYS; ++ ++ if (port->serial->disconnected) ++ return -EIO; ++ + if ((prev.rng == priv->icount.rng) && + (prev.dsr == priv->icount.dsr) && + (prev.dcd == priv->icount.dcd) && +@@ -584,7 +586,7 @@ static void ark3116_update_msr(struct usb_serial_port *port, __u8 msr) + priv->icount.dcd++; + if (msr & UART_MSR_TERI) + priv->icount.rng++; +- wake_up_interruptible(&priv->delta_msr_wait); ++ wake_up_interruptible(&port->delta_msr_wait); + } + } + +diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c +index 6ae1c06..c4d95b0 100644 +--- a/drivers/usb/serial/ch341.c ++++ b/drivers/usb/serial/ch341.c +@@ -82,7 +82,6 @@ MODULE_DEVICE_TABLE(usb, id_table); + + struct ch341_private { + spinlock_t lock; /* access lock */ +- wait_queue_head_t delta_msr_wait; /* wait queue for modem status */ + unsigned baud_rate; /* set baud rate */ + u8 line_control; /* set line control value RTS/DTR */ + u8 line_status; /* active status of modem control inputs */ +@@ -262,7 +261,6 @@ static int ch341_attach(struct usb_serial *serial) + return -ENOMEM; + + spin_lock_init(&priv->lock); +- init_waitqueue_head(&priv->delta_msr_wait); + priv->baud_rate = DEFAULT_BAUD_RATE; + priv->line_control = CH341_BIT_RTS | CH341_BIT_DTR; + +@@ -299,7 +297,7 @@ static void ch341_dtr_rts(struct usb_serial_port *port, int on) + priv->line_control &= ~(CH341_BIT_RTS | CH341_BIT_DTR); + spin_unlock_irqrestore(&priv->lock, flags); + ch341_set_handshake(port->serial->dev, priv->line_control); +- wake_up_interruptible(&priv->delta_msr_wait); ++ wake_up_interruptible(&port->delta_msr_wait); + } + + static void ch341_close(struct usb_serial_port *port) +@@ -503,7 +501,7 @@ static void ch341_read_int_callback(struct urb *urb) + tty_kref_put(tty); + } + +- wake_up_interruptible(&priv->delta_msr_wait); ++ wake_up_interruptible(&port->delta_msr_wait); + } + + exit: +@@ -529,11 +527,14 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) + spin_unlock_irqrestore(&priv->lock, flags); + + while (!multi_change) { +- interruptible_sleep_on(&priv->delta_msr_wait); ++ interruptible_sleep_on(&port->delta_msr_wait); + /* see if a signal did it */ + if (signal_pending(current)) + return -ERESTARTSYS; + ++ if (port->serial->disconnected) ++ return -EIO; ++ + spin_lock_irqsave(&priv->lock, flags); + status = priv->line_status; + multi_change = priv->multi_status_change; +diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c +index d9906eb..01a44d3 100644 +--- a/drivers/usb/serial/cypress_m8.c ++++ b/drivers/usb/serial/cypress_m8.c +@@ -150,7 +150,6 @@ struct cypress_private { + int baud_rate; /* stores current baud rate in + integer form */ + int isthrottled; /* if throttled, discard reads */ +- wait_queue_head_t delta_msr_wait; /* used for TIOCMIWAIT */ + char prev_status, diff_status; /* used for TIOCMIWAIT */ + /* we pass a pointer to this as the argument sent to + cypress_set_termios old_termios */ +@@ -488,7 +487,6 @@ static int generic_startup(struct usb_serial *serial) + kfree(priv); + return -ENOMEM; + } +- init_waitqueue_head(&priv->delta_msr_wait); + + usb_reset_configuration(serial->dev); + +@@ -928,12 +926,16 @@ static int cypress_ioctl(struct tty_struct *tty, + switch (cmd) { + /* This code comes from drivers/char/serial.c and ftdi_sio.c */ + case TIOCMIWAIT: +- while (priv != NULL) { +- interruptible_sleep_on(&priv->delta_msr_wait); ++ for (;;) { ++ interruptible_sleep_on(&port->delta_msr_wait); + /* see if a signal did it */ + if (signal_pending(current)) + return -ERESTARTSYS; +- else { ++ ++ if (port->serial->disconnected) ++ return -EIO; ++ ++ { + char diff = priv->diff_status; + if (diff == 0) + return -EIO; /* no change => error */ +@@ -1261,7 +1263,7 @@ static void cypress_read_int_callback(struct urb *urb) + if (priv->current_status != priv->prev_status) { + priv->diff_status |= priv->current_status ^ + priv->prev_status; +- wake_up_interruptible(&priv->delta_msr_wait); ++ wake_up_interruptible(&port->delta_msr_wait); + priv->prev_status = priv->current_status; + } + spin_unlock_irqrestore(&priv->lock, flags); +diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c +index 878ff05..06394e5a 100644 +--- a/drivers/usb/serial/ftdi_sio.c ++++ b/drivers/usb/serial/ftdi_sio.c +@@ -74,9 +74,7 @@ struct ftdi_private { + int flags; /* some ASYNC_xxxx flags are supported */ + unsigned long last_dtr_rts; /* saved modem control outputs */ + struct async_icount icount; +- wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ + char prev_status; /* Used for TIOCMIWAIT */ +- bool dev_gone; /* Used to abort TIOCMIWAIT */ + char transmit_empty; /* If transmitter is empty or not */ + struct usb_serial_port *port; + __u16 interface; /* FT2232C, FT2232H or FT4232H port interface +@@ -1708,10 +1706,8 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) + kref_init(&priv->kref); + mutex_init(&priv->cfg_lock); + memset(&priv->icount, 0x00, sizeof(priv->icount)); +- init_waitqueue_head(&priv->delta_msr_wait); + + priv->flags = ASYNC_LOW_LATENCY; +- priv->dev_gone = false; + + if (quirk && quirk->port_probe) + quirk->port_probe(priv); +@@ -1869,8 +1865,7 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port) + + dbg("%s", __func__); + +- priv->dev_gone = true; +- wake_up_interruptible_all(&priv->delta_msr_wait); ++ wake_up_interruptible(&port->delta_msr_wait); + + remove_sysfs_attrs(port); + +@@ -2025,7 +2020,7 @@ static int ftdi_process_packet(struct tty_struct *tty, + if (diff_status & FTDI_RS0_RLSD) + priv->icount.dcd++; + +- wake_up_interruptible_all(&priv->delta_msr_wait); ++ wake_up_interruptible(&port->delta_msr_wait); + priv->prev_status = status; + } + +@@ -2424,11 +2419,15 @@ static int ftdi_ioctl(struct tty_struct *tty, + */ + case TIOCMIWAIT: + cprev = priv->icount; +- while (!priv->dev_gone) { +- interruptible_sleep_on(&priv->delta_msr_wait); ++ for (;;) { ++ interruptible_sleep_on(&port->delta_msr_wait); + /* see if a signal did it */ + if (signal_pending(current)) + return -ERESTARTSYS; ++ ++ if (port->serial->disconnected) ++ return -EIO; ++ + cnow = priv->icount; + if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || + ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || +@@ -2438,8 +2437,6 @@ static int ftdi_ioctl(struct tty_struct *tty, + } + cprev = cnow; + } +- return -EIO; +- break; + case TIOCSERGETLSR: + return get_lsr_info(port, (struct serial_struct __user *)arg); + break; +diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c +index 2ee8075..0af0b41 100644 +--- a/drivers/usb/serial/io_edgeport.c ++++ b/drivers/usb/serial/io_edgeport.c +@@ -114,7 +114,6 @@ struct edgeport_port { + wait_queue_head_t wait_chase; /* for handling sleeping while waiting for chase to finish */ + wait_queue_head_t wait_open; /* for handling sleeping while waiting for open to finish */ + wait_queue_head_t wait_command; /* for handling sleeping while waiting for command to finish */ +- wait_queue_head_t delta_msr_wait; /* for handling sleeping while waiting for msr change to happen */ + + struct async_icount icount; + struct usb_serial_port *port; /* loop back to the owner of this object */ +@@ -885,7 +884,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) + /* initialize our wait queues */ + init_waitqueue_head(&edge_port->wait_open); + init_waitqueue_head(&edge_port->wait_chase); +- init_waitqueue_head(&edge_port->delta_msr_wait); + init_waitqueue_head(&edge_port->wait_command); + + /* initialize our icount structure */ +@@ -1703,13 +1701,17 @@ static int edge_ioctl(struct tty_struct *tty, + dbg("%s (%d) TIOCMIWAIT", __func__, port->number); + cprev = edge_port->icount; + while (1) { +- prepare_to_wait(&edge_port->delta_msr_wait, ++ prepare_to_wait(&port->delta_msr_wait, + &wait, TASK_INTERRUPTIBLE); + schedule(); +- finish_wait(&edge_port->delta_msr_wait, &wait); ++ finish_wait(&port->delta_msr_wait, &wait); + /* see if a signal did it */ + if (signal_pending(current)) + return -ERESTARTSYS; ++ ++ if (port->serial->disconnected) ++ return -EIO; ++ + cnow = edge_port->icount; + if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && + cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) +@@ -2090,7 +2092,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 newMsr) + icount->dcd++; + if (newMsr & EDGEPORT_MSR_DELTA_RI) + icount->rng++; +- wake_up_interruptible(&edge_port->delta_msr_wait); ++ wake_up_interruptible(&edge_port->port->delta_msr_wait); + } + + /* Save the new modem status */ +diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c +index 1f145bf..f42119d 100644 +--- a/drivers/usb/serial/io_ti.c ++++ b/drivers/usb/serial/io_ti.c +@@ -98,9 +98,6 @@ struct edgeport_port { + int close_pending; + int lsr_event; + struct async_icount icount; +- wait_queue_head_t delta_msr_wait; /* for handling sleeping while +- waiting for msr change to +- happen */ + struct edgeport_serial *edge_serial; + struct usb_serial_port *port; + __u8 bUartMode; /* Port type, 0: RS232, etc. */ +@@ -1557,7 +1554,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr) + icount->dcd++; + if (msr & EDGEPORT_MSR_DELTA_RI) + icount->rng++; +- wake_up_interruptible(&edge_port->delta_msr_wait); ++ wake_up_interruptible(&edge_port->port->delta_msr_wait); + } + + /* Save the new modem status */ +@@ -1876,7 +1873,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) + dev = port->serial->dev; + + memset(&(edge_port->icount), 0x00, sizeof(edge_port->icount)); +- init_waitqueue_head(&edge_port->delta_msr_wait); + + /* turn off loopback */ + status = ti_do_config(edge_port, UMPC_SET_CLR_LOOPBACK, 0); +@@ -2574,10 +2570,14 @@ static int edge_ioctl(struct tty_struct *tty, + dbg("%s - (%d) TIOCMIWAIT", __func__, port->number); + cprev = edge_port->icount; + while (1) { +- interruptible_sleep_on(&edge_port->delta_msr_wait); ++ interruptible_sleep_on(&port->delta_msr_wait); + /* see if a signal did it */ + if (signal_pending(current)) + return -ERESTARTSYS; ++ ++ if (port->serial->disconnected) ++ return -EIO; ++ + cnow = edge_port->icount; + if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && + cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) +diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c +index de0bb8e..96a62dd 100644 +--- a/drivers/usb/serial/mct_u232.c ++++ b/drivers/usb/serial/mct_u232.c +@@ -168,8 +168,6 @@ struct mct_u232_private { + unsigned char last_msr; /* Modem Status Register */ + unsigned int rx_flags; /* Throttling flags */ + struct async_icount icount; +- wait_queue_head_t msr_wait; /* for handling sleeping while waiting +- for msr change to happen */ + }; + + #define THROTTLED 0x01 +@@ -449,7 +447,6 @@ static int mct_u232_startup(struct usb_serial *serial) + if (!priv) + return -ENOMEM; + spin_lock_init(&priv->lock); +- init_waitqueue_head(&priv->msr_wait); + usb_set_serial_port_data(serial->port[0], priv); + + init_waitqueue_head(&serial->port[0]->write_wait); +@@ -675,7 +672,7 @@ static void mct_u232_read_int_callback(struct urb *urb) + tty_kref_put(tty); + } + #endif +- wake_up_interruptible(&priv->msr_wait); ++ wake_up_interruptible(&port->delta_msr_wait); + spin_unlock_irqrestore(&priv->lock, flags); + exit: + retval = usb_submit_urb(urb, GFP_ATOMIC); +@@ -896,13 +893,17 @@ static int mct_u232_ioctl(struct tty_struct *tty, + cprev = mct_u232_port->icount; + spin_unlock_irqrestore(&mct_u232_port->lock, flags); + for ( ; ; ) { +- prepare_to_wait(&mct_u232_port->msr_wait, ++ prepare_to_wait(&port->delta_msr_wait, + &wait, TASK_INTERRUPTIBLE); + schedule(); +- finish_wait(&mct_u232_port->msr_wait, &wait); ++ finish_wait(&port->delta_msr_wait, &wait); + /* see if a signal did it */ + if (signal_pending(current)) + return -ERESTARTSYS; ++ ++ if (port->serial->disconnected) ++ return -EIO; ++ + spin_lock_irqsave(&mct_u232_port->lock, flags); + cnow = mct_u232_port->icount; + spin_unlock_irqrestore(&mct_u232_port->lock, flags); +diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c +index 43a38aa..e89ee48 100644 +--- a/drivers/usb/serial/mos7840.c ++++ b/drivers/usb/serial/mos7840.c +@@ -240,7 +240,6 @@ struct moschip_port { + char open; + char open_ports; + wait_queue_head_t wait_chase; /* for handling sleeping while waiting for chase to finish */ +- wait_queue_head_t delta_msr_wait; /* for handling sleeping while waiting for msr change to happen */ + int delta_msr_cond; + struct async_icount icount; + struct usb_serial_port *port; /* loop back to the owner of this object */ +@@ -453,6 +452,9 @@ static void mos7840_handle_new_msr(struct moschip_port *port, __u8 new_msr) + icount->rng++; + smp_wmb(); + } ++ ++ mos7840_port->delta_msr_cond = 1; ++ wake_up_interruptible(&port->port->delta_msr_wait); + } + } + +@@ -1115,7 +1117,6 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port) + + /* initialize our wait queues */ + init_waitqueue_head(&mos7840_port->wait_chase); +- init_waitqueue_head(&mos7840_port->delta_msr_wait); + + /* initialize our icount structure */ + memset(&(mos7840_port->icount), 0x00, sizeof(mos7840_port->icount)); +@@ -2073,8 +2074,6 @@ static void mos7840_change_port_settings(struct tty_struct *tty, + mos7840_port->read_urb_busy = false; + } + } +- wake_up(&mos7840_port->delta_msr_wait); +- mos7840_port->delta_msr_cond = 1; + dbg("mos7840_change_port_settings mos7840_port->shadowLCR is End %x", + mos7840_port->shadowLCR); + } +@@ -2284,13 +2283,18 @@ static int mos7840_ioctl(struct tty_struct *tty, + while (1) { + /* interruptible_sleep_on(&mos7840_port->delta_msr_wait); */ + mos7840_port->delta_msr_cond = 0; +- wait_event_interruptible(mos7840_port->delta_msr_wait, +- (mos7840_port-> ++ wait_event_interruptible(port->delta_msr_wait, ++ (port->serial->disconnected || ++ mos7840_port-> + delta_msr_cond == 1)); + + /* see if a signal did it */ + if (signal_pending(current)) + return -ERESTARTSYS; ++ ++ if (port->serial->disconnected) ++ return -EIO; ++ + cnow = mos7840_port->icount; + smp_rmb(); + if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && +diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c +index 4c29e6c..8ceaa89 100644 +--- a/drivers/usb/serial/oti6858.c ++++ b/drivers/usb/serial/oti6858.c +@@ -196,7 +196,6 @@ struct oti6858_private { + u8 setup_done; + struct delayed_work delayed_setup_work; + +- wait_queue_head_t intr_wait; + struct usb_serial_port *port; /* USB port with which associated */ + }; + +@@ -357,7 +356,6 @@ static int oti6858_startup(struct usb_serial *serial) + break; + + spin_lock_init(&priv->lock); +- init_waitqueue_head(&priv->intr_wait); + /* INIT_WORK(&priv->setup_work, setup_line, serial->port[i]); */ + /* INIT_WORK(&priv->write_work, send_data, serial->port[i]); */ + priv->port = port; +@@ -705,11 +703,15 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) + spin_unlock_irqrestore(&priv->lock, flags); + + while (1) { +- wait_event_interruptible(priv->intr_wait, ++ wait_event_interruptible(port->delta_msr_wait, ++ port->serial->disconnected || + priv->status.pin_state != prev); + if (signal_pending(current)) + return -ERESTARTSYS; + ++ if (port->serial->disconnected) ++ return -EIO; ++ + spin_lock_irqsave(&priv->lock, flags); + status = priv->status.pin_state & PIN_MASK; + spin_unlock_irqrestore(&priv->lock, flags); +@@ -821,7 +823,7 @@ static void oti6858_read_int_callback(struct urb *urb) + + if (!priv->transient) { + if (xs->pin_state != priv->status.pin_state) +- wake_up_interruptible(&priv->intr_wait); ++ wake_up_interruptible(&port->delta_msr_wait); + memcpy(&priv->status, xs, OTI6858_CTRL_PKT_SIZE); + } + +diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c +index 5532ea5..fd86e0e 100644 +--- a/drivers/usb/serial/pl2303.c ++++ b/drivers/usb/serial/pl2303.c +@@ -150,7 +150,6 @@ enum pl2303_type { + + struct pl2303_private { + spinlock_t lock; +- wait_queue_head_t delta_msr_wait; + u8 line_control; + u8 line_status; + enum pl2303_type type; +@@ -204,7 +203,6 @@ static int pl2303_startup(struct usb_serial *serial) + if (!priv) + goto cleanup; + spin_lock_init(&priv->lock); +- init_waitqueue_head(&priv->delta_msr_wait); + priv->type = type; + usb_set_serial_port_data(serial->port[i], priv); + } +@@ -599,11 +597,14 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) + spin_unlock_irqrestore(&priv->lock, flags); + + while (1) { +- interruptible_sleep_on(&priv->delta_msr_wait); ++ interruptible_sleep_on(&port->delta_msr_wait); + /* see if a signal did it */ + if (signal_pending(current)) + return -ERESTARTSYS; + ++ if (port->serial->disconnected) ++ return -EIO; ++ + spin_lock_irqsave(&priv->lock, flags); + status = priv->line_status; + spin_unlock_irqrestore(&priv->lock, flags); +@@ -725,7 +726,7 @@ static void pl2303_update_line_status(struct usb_serial_port *port, + spin_unlock_irqrestore(&priv->lock, flags); + if (priv->line_status & UART_BREAK_ERROR) + usb_serial_handle_break(port); +- wake_up_interruptible(&priv->delta_msr_wait); ++ wake_up_interruptible(&port->delta_msr_wait); + + tty = tty_port_tty_get(&port->port); + if (!tty) +@@ -792,7 +793,7 @@ static void pl2303_process_read_urb(struct urb *urb) + line_status = priv->line_status; + priv->line_status &= ~UART_STATE_TRANSIENT_MASK; + spin_unlock_irqrestore(&priv->lock, flags); +- wake_up_interruptible(&priv->delta_msr_wait); ++ wake_up_interruptible(&port->delta_msr_wait); + + if (!urb->actual_length) + return; +diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c +index 180ea6c..ba6b438 100644 +--- a/drivers/usb/serial/spcp8x5.c ++++ b/drivers/usb/serial/spcp8x5.c +@@ -163,7 +163,6 @@ static struct usb_driver spcp8x5_driver = { + struct spcp8x5_private { + spinlock_t lock; + enum spcp8x5_type type; +- wait_queue_head_t delta_msr_wait; + u8 line_control; + u8 line_status; + }; +@@ -197,7 +196,6 @@ static int spcp8x5_startup(struct usb_serial *serial) + goto cleanup; + + spin_lock_init(&priv->lock); +- init_waitqueue_head(&priv->delta_msr_wait); + priv->type = type; + usb_set_serial_port_data(serial->port[i] , priv); + } +@@ -502,7 +500,7 @@ static void spcp8x5_process_read_urb(struct urb *urb) + priv->line_status &= ~UART_STATE_TRANSIENT_MASK; + spin_unlock_irqrestore(&priv->lock, flags); + /* wake up the wait for termios */ +- wake_up_interruptible(&priv->delta_msr_wait); ++ wake_up_interruptible(&port->delta_msr_wait); + + if (!urb->actual_length) + return; +@@ -552,12 +550,15 @@ static int spcp8x5_wait_modem_info(struct usb_serial_port *port, + + while (1) { + /* wake up in bulk read */ +- interruptible_sleep_on(&priv->delta_msr_wait); ++ interruptible_sleep_on(&port->delta_msr_wait); + + /* see if a signal did it */ + if (signal_pending(current)) + return -ERESTARTSYS; + ++ if (port->serial->disconnected) ++ return -EIO; ++ + spin_lock_irqsave(&priv->lock, flags); + status = priv->line_status; + spin_unlock_irqrestore(&priv->lock, flags); +diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c +index fff7f17..bf1f8ea 100644 +--- a/drivers/usb/serial/ssu100.c ++++ b/drivers/usb/serial/ssu100.c +@@ -78,7 +78,6 @@ struct ssu100_port_private { + spinlock_t status_lock; + u8 shadowLSR; + u8 shadowMSR; +- wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ + struct async_icount icount; + }; + +@@ -387,8 +386,9 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) + spin_unlock_irqrestore(&priv->status_lock, flags); + + while (1) { +- wait_event_interruptible(priv->delta_msr_wait, +- ((priv->icount.rng != prev.rng) || ++ wait_event_interruptible(port->delta_msr_wait, ++ (port->serial->disconnected || ++ (priv->icount.rng != prev.rng) || + (priv->icount.dsr != prev.dsr) || + (priv->icount.dcd != prev.dcd) || + (priv->icount.cts != prev.cts))); +@@ -396,6 +396,9 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) + if (signal_pending(current)) + return -ERESTARTSYS; + ++ if (port->serial->disconnected) ++ return -EIO; ++ + spin_lock_irqsave(&priv->status_lock, flags); + cur = priv->icount; + spin_unlock_irqrestore(&priv->status_lock, flags); +@@ -478,7 +481,6 @@ static int ssu100_attach(struct usb_serial *serial) + } + + spin_lock_init(&priv->status_lock); +- init_waitqueue_head(&priv->delta_msr_wait); + usb_set_serial_port_data(port, priv); + + return ssu100_initdevice(serial->dev); +@@ -564,7 +566,7 @@ static void ssu100_update_msr(struct usb_serial_port *port, u8 msr) + priv->icount.dcd++; + if (msr & UART_MSR_TERI) + priv->icount.rng++; +- wake_up_interruptible(&priv->delta_msr_wait); ++ wake_up_interruptible(&port->delta_msr_wait); + } + } + +diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c +index 2856474..4b805be 100644 +--- a/drivers/usb/serial/ti_usb_3410_5052.c ++++ b/drivers/usb/serial/ti_usb_3410_5052.c +@@ -75,7 +75,6 @@ struct ti_port { + int tp_flags; + int tp_closing_wait;/* in .01 secs */ + struct async_icount tp_icount; +- wait_queue_head_t tp_msr_wait; /* wait for msr change */ + wait_queue_head_t tp_write_wait; + struct ti_device *tp_tdev; + struct usb_serial_port *tp_port; +@@ -447,7 +446,6 @@ static int ti_startup(struct usb_serial *serial) + tport->tp_uart_base_addr = (i == 0 ? + TI_UART1_BASE_ADDR : TI_UART2_BASE_ADDR); + tport->tp_closing_wait = closing_wait; +- init_waitqueue_head(&tport->tp_msr_wait); + init_waitqueue_head(&tport->tp_write_wait); + if (kfifo_alloc(&tport->write_fifo, TI_WRITE_BUF_SIZE, + GFP_KERNEL)) { +@@ -848,9 +846,13 @@ static int ti_ioctl(struct tty_struct *tty, + dbg("%s - (%d) TIOCMIWAIT", __func__, port->number); + cprev = tport->tp_icount; + while (1) { +- interruptible_sleep_on(&tport->tp_msr_wait); ++ interruptible_sleep_on(&port->delta_msr_wait); + if (signal_pending(current)) + return -ERESTARTSYS; ++ ++ if (port->serial->disconnected) ++ return -EIO; ++ + cnow = tport->tp_icount; + if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && + cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) +@@ -1481,7 +1483,7 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr) + icount->dcd++; + if (msr & TI_MSR_DELTA_RI) + icount->rng++; +- wake_up_interruptible(&tport->tp_msr_wait); ++ wake_up_interruptible(&tport->tp_port->delta_msr_wait); + spin_unlock_irqrestore(&tport->tp_lock, flags); + } + +diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c +index 2482d5e..850faa4 100644 +--- a/drivers/usb/serial/usb-serial.c ++++ b/drivers/usb/serial/usb-serial.c +@@ -905,6 +905,7 @@ int usb_serial_probe(struct usb_interface *interface, + port->port.ops = &serial_port_ops; + port->serial = serial; + spin_lock_init(&port->lock); ++ init_waitqueue_head(&port->delta_msr_wait); + /* Keep this for private driver use for the moment but + should probably go away */ + INIT_WORK(&port->work, usb_serial_port_work); +diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c +index 9b8bcab..7a36dff 100644 +--- a/drivers/video/console/fbcon.c ++++ b/drivers/video/console/fbcon.c +@@ -843,6 +843,8 @@ static void con2fb_init_display(struct vc_data *vc, struct fb_info *info, + * + * Maps a virtual console @unit to a frame buffer device + * @newidx. ++ * ++ * This should be called with the console lock held. + */ + static int set_con2fb_map(int unit, int newidx, int user) + { +@@ -860,7 +862,7 @@ static int set_con2fb_map(int unit, int newidx, int user) + + if (!search_for_mapped_con() || !con_is_bound(&fb_con)) { + info_idx = newidx; +- return fbcon_takeover(0); ++ return do_fbcon_takeover(0); + } + + if (oldidx != -1) +@@ -868,7 +870,6 @@ static int set_con2fb_map(int unit, int newidx, int user) + + found = search_fb_in_map(newidx); + +- console_lock(); + con2fb_map[unit] = newidx; + if (!err && !found) + err = con2fb_acquire_newinfo(vc, info, unit, oldidx); +@@ -895,7 +896,6 @@ static int set_con2fb_map(int unit, int newidx, int user) + if (!search_fb_in_map(info_idx)) + info_idx = newidx; + +- console_unlock(); + return err; + } + +@@ -3026,6 +3026,7 @@ static inline int fbcon_unbind(void) + } + #endif /* CONFIG_VT_HW_CONSOLE_BINDING */ + ++/* called with console_lock held */ + static int fbcon_fb_unbind(int idx) + { + int i, new_idx = -1, ret = 0; +@@ -3052,6 +3053,7 @@ static int fbcon_fb_unbind(int idx) + return ret; + } + ++/* called with console_lock held */ + static int fbcon_fb_unregistered(struct fb_info *info) + { + int i, idx; +@@ -3089,6 +3091,7 @@ static int fbcon_fb_unregistered(struct fb_info *info) + return 0; + } + ++/* called with console_lock held */ + static void fbcon_remap_all(int idx) + { + int i; +@@ -3133,6 +3136,7 @@ static inline void fbcon_select_primary(struct fb_info *info) + } + #endif /* CONFIG_FRAMEBUFFER_DETECT_PRIMARY */ + ++/* called with console_lock held */ + static int fbcon_fb_registered(struct fb_info *info) + { + int ret = 0, i, idx; +@@ -3285,6 +3289,7 @@ static int fbcon_event_notify(struct notifier_block *self, + ret = fbcon_fb_unregistered(info); + break; + case FB_EVENT_SET_CONSOLE_MAP: ++ /* called with console lock held */ + con2fb = event->data; + ret = set_con2fb_map(con2fb->console - 1, + con2fb->framebuffer, 1); +diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c +index c133dde..babbb07 100644 +--- a/drivers/video/fbmem.c ++++ b/drivers/video/fbmem.c +@@ -1154,8 +1154,10 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, + event.data = &con2fb; + if (!lock_fb_info(info)) + return -ENODEV; ++ console_lock(); + event.info = info; + ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, &event); ++ console_unlock(); + unlock_fb_info(info); + break; + case FBIOBLANK: +diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c +index 49f3c9d..73e4cbc 100644 +--- a/fs/btrfs/extent_io.c ++++ b/fs/btrfs/extent_io.c +@@ -1209,6 +1209,39 @@ int unlock_extent(struct extent_io_tree *tree, u64 start, u64 end, gfp_t mask) + mask); + } + ++int extent_range_clear_dirty_for_io(struct inode *inode, u64 start, u64 end) ++{ ++ unsigned long index = start >> PAGE_CACHE_SHIFT; ++ unsigned long end_index = end >> PAGE_CACHE_SHIFT; ++ struct page *page; ++ ++ while (index <= end_index) { ++ page = find_get_page(inode->i_mapping, index); ++ BUG_ON(!page); /* Pages should be in the extent_io_tree */ ++ clear_page_dirty_for_io(page); ++ page_cache_release(page); ++ index++; ++ } ++ return 0; ++} ++ ++int extent_range_redirty_for_io(struct inode *inode, u64 start, u64 end) ++{ ++ unsigned long index = start >> PAGE_CACHE_SHIFT; ++ unsigned long end_index = end >> PAGE_CACHE_SHIFT; ++ struct page *page; ++ ++ while (index <= end_index) { ++ page = find_get_page(inode->i_mapping, index); ++ BUG_ON(!page); /* Pages should be in the extent_io_tree */ ++ account_page_redirty(page); ++ __set_page_dirty_nobuffers(page); ++ page_cache_release(page); ++ index++; ++ } ++ return 0; ++} ++ + /* + * helper function to set both pages and extents in the tree writeback + */ +diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h +index 7604c30..2e32510 100644 +--- a/fs/btrfs/extent_io.h ++++ b/fs/btrfs/extent_io.h +@@ -304,6 +304,8 @@ int map_private_extent_buffer(struct extent_buffer *eb, unsigned long offset, + unsigned long *map_len); + int extent_range_uptodate(struct extent_io_tree *tree, + u64 start, u64 end); ++int extent_range_clear_dirty_for_io(struct inode *inode, u64 start, u64 end); ++int extent_range_redirty_for_io(struct inode *inode, u64 start, u64 end); + int extent_clear_unlock_delalloc(struct inode *inode, + struct extent_io_tree *tree, + u64 start, u64 end, struct page *locked_page, +diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c +index fd1a06d..1372634 100644 +--- a/fs/btrfs/inode.c ++++ b/fs/btrfs/inode.c +@@ -343,6 +343,7 @@ static noinline int compress_file_range(struct inode *inode, + int i; + int will_compress; + int compress_type = root->fs_info->compress_type; ++ int redirty = 0; + + /* if this is a small write inside eof, kick off a defragbot */ + if (end <= BTRFS_I(inode)->disk_i_size && (end - start + 1) < 16 * 1024) +@@ -404,6 +405,17 @@ again: + if (BTRFS_I(inode)->force_compress) + compress_type = BTRFS_I(inode)->force_compress; + ++ /* ++ * we need to call clear_page_dirty_for_io on each ++ * page in the range. Otherwise applications with the file ++ * mmap'd can wander in and change the page contents while ++ * we are compressing them. ++ * ++ * If the compression fails for any reason, we set the pages ++ * dirty again later on. ++ */ ++ extent_range_clear_dirty_for_io(inode, start, end); ++ redirty = 1; + ret = btrfs_compress_pages(compress_type, + inode->i_mapping, start, + total_compressed, pages, +@@ -541,6 +553,8 @@ cleanup_and_bail_uncompressed: + __set_page_dirty_nobuffers(locked_page); + /* unlocked later on in the async handlers */ + } ++ if (redirty) ++ extent_range_redirty_for_io(inode, start, end); + add_async_extent(async_cow, start, end - start + 1, + 0, NULL, 0, BTRFS_COMPRESS_NONE); + *num_added += 1; +diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c +index 19b127c..21faa12 100644 +--- a/fs/btrfs/tree-log.c ++++ b/fs/btrfs/tree-log.c +@@ -316,6 +316,7 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans, + unsigned long src_ptr; + unsigned long dst_ptr; + int overwrite_root = 0; ++ bool inode_item = key->type == BTRFS_INODE_ITEM_KEY; + + if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) + overwrite_root = 1; +@@ -325,6 +326,9 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans, + + /* look for the key in the destination tree */ + ret = btrfs_search_slot(NULL, root, key, path, 0, 0); ++ if (ret < 0) ++ return ret; ++ + if (ret == 0) { + char *src_copy; + char *dst_copy; +@@ -366,6 +370,30 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans, + return 0; + } + ++ /* ++ * We need to load the old nbytes into the inode so when we ++ * replay the extents we've logged we get the right nbytes. ++ */ ++ if (inode_item) { ++ struct btrfs_inode_item *item; ++ u64 nbytes; ++ ++ item = btrfs_item_ptr(path->nodes[0], path->slots[0], ++ struct btrfs_inode_item); ++ nbytes = btrfs_inode_nbytes(path->nodes[0], item); ++ item = btrfs_item_ptr(eb, slot, ++ struct btrfs_inode_item); ++ btrfs_set_inode_nbytes(eb, item, nbytes); ++ } ++ } else if (inode_item) { ++ struct btrfs_inode_item *item; ++ ++ /* ++ * New inode, set nbytes to 0 so that the nbytes comes out ++ * properly when we replay the extents. ++ */ ++ item = btrfs_item_ptr(eb, slot, struct btrfs_inode_item); ++ btrfs_set_inode_nbytes(eb, item, 0); + } + insert: + btrfs_release_path(path); +@@ -488,7 +516,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, + u64 extent_end; + u64 alloc_hint; + u64 start = key->offset; +- u64 saved_nbytes; ++ u64 nbytes = 0; + struct btrfs_file_extent_item *item; + struct inode *inode = NULL; + unsigned long size; +@@ -498,10 +526,19 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, + found_type = btrfs_file_extent_type(eb, item); + + if (found_type == BTRFS_FILE_EXTENT_REG || +- found_type == BTRFS_FILE_EXTENT_PREALLOC) +- extent_end = start + btrfs_file_extent_num_bytes(eb, item); +- else if (found_type == BTRFS_FILE_EXTENT_INLINE) { ++ found_type == BTRFS_FILE_EXTENT_PREALLOC) { ++ nbytes = btrfs_file_extent_num_bytes(eb, item); ++ extent_end = start + nbytes; ++ ++ /* ++ * We don't add to the inodes nbytes if we are prealloc or a ++ * hole. ++ */ ++ if (btrfs_file_extent_disk_bytenr(eb, item) == 0) ++ nbytes = 0; ++ } else if (found_type == BTRFS_FILE_EXTENT_INLINE) { + size = btrfs_file_extent_inline_len(eb, item); ++ nbytes = btrfs_file_extent_ram_bytes(eb, item); + extent_end = (start + size + mask) & ~mask; + } else { + ret = 0; +@@ -550,7 +587,6 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, + } + btrfs_release_path(path); + +- saved_nbytes = inode_get_bytes(inode); + /* drop any overlapping extents */ + ret = btrfs_drop_extents(trans, inode, start, extent_end, + &alloc_hint, 1); +@@ -638,7 +674,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, + BUG_ON(ret); + } + +- inode_set_bytes(inode, saved_nbytes); ++ inode_add_bytes(inode, nbytes); + btrfs_update_inode(trans, root, inode); + out: + if (inode) +diff --git a/fs/hfsplus/extents.c b/fs/hfsplus/extents.c +index 5849e3e..32b12e5 100644 +--- a/fs/hfsplus/extents.c ++++ b/fs/hfsplus/extents.c +@@ -517,7 +517,7 @@ void hfsplus_file_truncate(struct inode *inode) + struct address_space *mapping = inode->i_mapping; + struct page *page; + void *fsdata; +- u32 size = inode->i_size; ++ loff_t size = inode->i_size; + + res = pagecache_write_begin(NULL, mapping, size, 0, + AOP_FLAG_UNINTERRUPTIBLE, +diff --git a/fs/inode.c b/fs/inode.c +index ee4e66b..e2d3633 100644 +--- a/fs/inode.c ++++ b/fs/inode.c +@@ -634,7 +634,7 @@ void prune_icache_sb(struct super_block *sb, int nr_to_scan) + * inode to the back of the list so we don't spin on it. + */ + if (!spin_trylock(&inode->i_lock)) { +- list_move_tail(&inode->i_lru, &sb->s_inode_lru); ++ list_move(&inode->i_lru, &sb->s_inode_lru); + continue; + } + +diff --git a/include/linux/ata.h b/include/linux/ata.h +index 32df2b6..5856c9e 100644 +--- a/include/linux/ata.h ++++ b/include/linux/ata.h +@@ -937,7 +937,7 @@ static inline int atapi_cdb_len(const u16 *dev_id) + } + } + +-static inline bool atapi_command_packet_set(const u16 *dev_id) ++static inline int atapi_command_packet_set(const u16 *dev_id) + { + return (dev_id[ATA_ID_CONFIG] >> 8) & 0x1f; + } +diff --git a/include/linux/kref.h b/include/linux/kref.h +index d4a62ab..d064502 100644 +--- a/include/linux/kref.h ++++ b/include/linux/kref.h +@@ -16,6 +16,7 @@ + #define _KREF_H_ + + #include <linux/types.h> ++#include <linux/atomic.h> + + struct kref { + atomic_t refcount; +@@ -27,4 +28,24 @@ int kref_put(struct kref *kref, void (*release) (struct kref *kref)); + int kref_sub(struct kref *kref, unsigned int count, + void (*release) (struct kref *kref)); + ++/** ++ * kref_get_unless_zero - Increment refcount for object unless it is zero. ++ * @kref: object. ++ * ++ * Return non-zero if the increment succeeded. Otherwise return 0. ++ * ++ * This function is intended to simplify locking around refcounting for ++ * objects that can be looked up from a lookup structure, and which are ++ * removed from that lookup structure in the object destructor. ++ * Operations on such objects require at least a read lock around ++ * lookup + kref_get, and a write lock around kref_put + remove from lookup ++ * structure. Furthermore, RCU implementations become extremely tricky. ++ * With a lookup followed by a kref_get_unless_zero *with return value check* ++ * locking in the kref_put path can be deferred to the actual removal from ++ * the lookup structure and RCU lookups become trivial. ++ */ ++static inline int __must_check kref_get_unless_zero(struct kref *kref) ++{ ++ return atomic_add_unless(&kref->refcount, 1, 0); ++} + #endif /* _KREF_H_ */ +diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h +index 6136821..e6796c1 100644 +--- a/include/linux/kvm_host.h ++++ b/include/linux/kvm_host.h +@@ -396,7 +396,7 @@ int kvm_write_guest(struct kvm *kvm, gpa_t gpa, const void *data, + int kvm_write_guest_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc, + void *data, unsigned long len); + int kvm_gfn_to_hva_cache_init(struct kvm *kvm, struct gfn_to_hva_cache *ghc, +- gpa_t gpa); ++ gpa_t gpa, unsigned long len); + int kvm_clear_guest_page(struct kvm *kvm, gfn_t gfn, int offset, int len); + int kvm_clear_guest(struct kvm *kvm, gpa_t gpa, unsigned long len); + struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn); +diff --git a/include/linux/kvm_types.h b/include/linux/kvm_types.h +index fa7cc72..b0bcce0 100644 +--- a/include/linux/kvm_types.h ++++ b/include/linux/kvm_types.h +@@ -71,6 +71,7 @@ struct gfn_to_hva_cache { + u64 generation; + gpa_t gpa; + unsigned long hva; ++ unsigned long len; + struct kvm_memory_slot *memslot; + }; + +diff --git a/include/linux/libata.h b/include/linux/libata.h +index cafc09a..62467ca 100644 +--- a/include/linux/libata.h ++++ b/include/linux/libata.h +@@ -392,6 +392,7 @@ enum { + ATA_HORKAGE_NOSETXFER = (1 << 14), /* skip SETXFER, SATA only */ + ATA_HORKAGE_BROKEN_FPDMA_AA = (1 << 15), /* skip AA */ + ATA_HORKAGE_DUMP_ID = (1 << 16), /* dump IDENTIFY data */ ++ ATA_HORKAGE_MAX_SEC_LBA48 = (1 << 17), /* Set max sects to 65535 */ + + /* DMA mask for user DMA control: User visible values; DO NOT + renumber */ +diff --git a/include/linux/of.h b/include/linux/of.h +index 4948552..9bf9611 100644 +--- a/include/linux/of.h ++++ b/include/linux/of.h +@@ -336,6 +336,22 @@ static inline int of_machine_is_compatible(const char *compat) + #define of_match_node(_matches, _node) NULL + #endif /* CONFIG_OF */ + ++/** ++ * of_property_read_bool - Findfrom a property ++ * @np: device node from which the property value is to be read. ++ * @propname: name of the property to be searched. ++ * ++ * Search for a property in a device node. ++ * Returns true if the property exist false otherwise. ++ */ ++static inline bool of_property_read_bool(const struct device_node *np, ++ const char *propname) ++{ ++ struct property *prop = of_find_property(np, propname, NULL); ++ ++ return prop ? true : false; ++} ++ + static inline int of_property_read_u32(const struct device_node *np, + const char *propname, + u32 *out_value) +diff --git a/include/linux/preempt.h b/include/linux/preempt.h +index 58969b2..e86bf01 100644 +--- a/include/linux/preempt.h ++++ b/include/linux/preempt.h +@@ -91,13 +91,19 @@ do { \ + + #else /* !CONFIG_PREEMPT_COUNT */ + +-#define preempt_disable() do { } while (0) +-#define preempt_enable_no_resched() do { } while (0) +-#define preempt_enable() do { } while (0) ++/* ++ * Even if we don't have any preemption, we need preempt disable/enable ++ * to be barriers, so that we don't have things like get_user/put_user ++ * that can cause faults and scheduling migrate into our preempt-protected ++ * region. ++ */ ++#define preempt_disable() barrier() ++#define preempt_enable_no_resched() barrier() ++#define preempt_enable() barrier() + +-#define preempt_disable_notrace() do { } while (0) +-#define preempt_enable_no_resched_notrace() do { } while (0) +-#define preempt_enable_notrace() do { } while (0) ++#define preempt_disable_notrace() barrier() ++#define preempt_enable_no_resched_notrace() barrier() ++#define preempt_enable_notrace() barrier() + + #endif /* CONFIG_PREEMPT_COUNT */ + +diff --git a/include/linux/socket.h b/include/linux/socket.h +index ad919e0..2acd2e2 100644 +--- a/include/linux/socket.h ++++ b/include/linux/socket.h +@@ -317,6 +317,7 @@ struct ucred { + #define IPX_TYPE 1 + + extern void cred_to_ucred(struct pid *pid, const struct cred *cred, struct ucred *ucred); ++extern void cred_real_to_ucred(struct pid *pid, const struct cred *cred, struct ucred *ucred); + + extern int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len); + extern int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov, +diff --git a/include/linux/spinlock_up.h b/include/linux/spinlock_up.h +index a26e2fb..e2369c1 100644 +--- a/include/linux/spinlock_up.h ++++ b/include/linux/spinlock_up.h +@@ -16,7 +16,10 @@ + * In the debug case, 1 means unlocked, 0 means locked. (the values + * are inverted, to catch initialization bugs) + * +- * No atomicity anywhere, we are on UP. ++ * No atomicity anywhere, we are on UP. However, we still need ++ * the compiler barriers, because we do not want the compiler to ++ * move potentially faulting instructions (notably user accesses) ++ * into the locked sequence, resulting in non-atomic execution. + */ + + #ifdef CONFIG_DEBUG_SPINLOCK +@@ -25,6 +28,7 @@ + static inline void arch_spin_lock(arch_spinlock_t *lock) + { + lock->slock = 0; ++ barrier(); + } + + static inline void +@@ -32,6 +36,7 @@ arch_spin_lock_flags(arch_spinlock_t *lock, unsigned long flags) + { + local_irq_save(flags); + lock->slock = 0; ++ barrier(); + } + + static inline int arch_spin_trylock(arch_spinlock_t *lock) +@@ -39,32 +44,34 @@ static inline int arch_spin_trylock(arch_spinlock_t *lock) + char oldval = lock->slock; + + lock->slock = 0; ++ barrier(); + + return oldval > 0; + } + + static inline void arch_spin_unlock(arch_spinlock_t *lock) + { ++ barrier(); + lock->slock = 1; + } + + /* + * Read-write spinlocks. No debug version. + */ +-#define arch_read_lock(lock) do { (void)(lock); } while (0) +-#define arch_write_lock(lock) do { (void)(lock); } while (0) +-#define arch_read_trylock(lock) ({ (void)(lock); 1; }) +-#define arch_write_trylock(lock) ({ (void)(lock); 1; }) +-#define arch_read_unlock(lock) do { (void)(lock); } while (0) +-#define arch_write_unlock(lock) do { (void)(lock); } while (0) ++#define arch_read_lock(lock) do { barrier(); (void)(lock); } while (0) ++#define arch_write_lock(lock) do { barrier(); (void)(lock); } while (0) ++#define arch_read_trylock(lock) ({ barrier(); (void)(lock); 1; }) ++#define arch_write_trylock(lock) ({ barrier(); (void)(lock); 1; }) ++#define arch_read_unlock(lock) do { barrier(); (void)(lock); } while (0) ++#define arch_write_unlock(lock) do { barrier(); (void)(lock); } while (0) + + #else /* DEBUG_SPINLOCK */ + #define arch_spin_is_locked(lock) ((void)(lock), 0) + /* for sched.c and kernel_lock.c: */ +-# define arch_spin_lock(lock) do { (void)(lock); } while (0) +-# define arch_spin_lock_flags(lock, flags) do { (void)(lock); } while (0) +-# define arch_spin_unlock(lock) do { (void)(lock); } while (0) +-# define arch_spin_trylock(lock) ({ (void)(lock); 1; }) ++# define arch_spin_lock(lock) do { barrier(); (void)(lock); } while (0) ++# define arch_spin_lock_flags(lock, flags) do { barrier(); (void)(lock); } while (0) ++# define arch_spin_unlock(lock) do { barrier(); (void)(lock); } while (0) ++# define arch_spin_trylock(lock) ({ barrier(); (void)(lock); 1; }) + #endif /* DEBUG_SPINLOCK */ + + #define arch_spin_is_contended(lock) (((void)(lock), 0)) +diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h +index b29f70b..237d5f8 100644 +--- a/include/linux/usb/serial.h ++++ b/include/linux/usb/serial.h +@@ -71,6 +71,7 @@ enum port_dev_state { + * port. + * @flags: usb serial port flags + * @write_wait: a wait_queue_head_t used by the port. ++ * @delta_msr_wait: modem-status-change wait queue + * @work: work queue entry for the line discipline waking up. + * @throttled: nonzero if the read urb is inactive to throttle the device + * @throttle_req: nonzero if the tty wants to throttle us +@@ -114,6 +115,7 @@ struct usb_serial_port { + + unsigned long flags; + wait_queue_head_t write_wait; ++ wait_queue_head_t delta_msr_wait; + struct work_struct work; + char throttled; + char throttle_req; +diff --git a/include/linux/writeback.h b/include/linux/writeback.h +index a378c29..7e85d45 100644 +--- a/include/linux/writeback.h ++++ b/include/linux/writeback.h +@@ -195,6 +195,8 @@ void writeback_set_ratelimit(void); + void tag_pages_for_writeback(struct address_space *mapping, + pgoff_t start, pgoff_t end); + ++void account_page_redirty(struct page *page); ++ + /* pdflush.c */ + extern int nr_pdflush_threads; /* Global so it can be exported to sysctl + read-only. */ +diff --git a/include/net/scm.h b/include/net/scm.h +index 0c0017c..5da0a7b 100644 +--- a/include/net/scm.h ++++ b/include/net/scm.h +@@ -50,7 +50,7 @@ static __inline__ void scm_set_cred(struct scm_cookie *scm, + { + scm->pid = get_pid(pid); + scm->cred = cred ? get_cred(cred) : NULL; +- cred_to_ucred(pid, cred, &scm->creds); ++ cred_real_to_ucred(pid, cred, &scm->creds); + } + + static __inline__ void scm_destroy_cred(struct scm_cookie *scm) +diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c +index cdd5607..e4cee8d 100644 +--- a/kernel/hrtimer.c ++++ b/kernel/hrtimer.c +@@ -61,6 +61,7 @@ + DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) = + { + ++ .lock = __RAW_SPIN_LOCK_UNLOCKED(hrtimer_bases.lock), + .clock_base = + { + { +@@ -1640,8 +1641,6 @@ static void __cpuinit init_hrtimers_cpu(int cpu) + struct hrtimer_cpu_base *cpu_base = &per_cpu(hrtimer_bases, cpu); + int i; + +- raw_spin_lock_init(&cpu_base->lock); +- + for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) { + cpu_base->clock_base[i].cpu_base = cpu_base; + timerqueue_init_head(&cpu_base->clock_base[i].active); +diff --git a/kernel/sched.c b/kernel/sched.c +index eeeec4e..d08c9f4 100644 +--- a/kernel/sched.c ++++ b/kernel/sched.c +@@ -2889,8 +2889,10 @@ static void try_to_wake_up_local(struct task_struct *p) + { + struct rq *rq = task_rq(p); + +- BUG_ON(rq != this_rq()); +- BUG_ON(p == current); ++ if (WARN_ON_ONCE(rq != this_rq()) || ++ WARN_ON_ONCE(p == current)) ++ return; ++ + lockdep_assert_held(&rq->lock); + + if (!raw_spin_trylock(&p->pi_lock)) { +diff --git a/kernel/sched_clock.c b/kernel/sched_clock.c +index c685e31..c3ae144 100644 +--- a/kernel/sched_clock.c ++++ b/kernel/sched_clock.c +@@ -176,10 +176,36 @@ static u64 sched_clock_remote(struct sched_clock_data *scd) + u64 this_clock, remote_clock; + u64 *ptr, old_val, val; + ++#if BITS_PER_LONG != 64 ++again: ++ /* ++ * Careful here: The local and the remote clock values need to ++ * be read out atomic as we need to compare the values and ++ * then update either the local or the remote side. So the ++ * cmpxchg64 below only protects one readout. ++ * ++ * We must reread via sched_clock_local() in the retry case on ++ * 32bit as an NMI could use sched_clock_local() via the ++ * tracer and hit between the readout of ++ * the low32bit and the high 32bit portion. ++ */ ++ this_clock = sched_clock_local(my_scd); ++ /* ++ * We must enforce atomic readout on 32bit, otherwise the ++ * update on the remote cpu can hit inbetween the readout of ++ * the low32bit and the high 32bit portion. ++ */ ++ remote_clock = cmpxchg64(&scd->clock, 0, 0); ++#else ++ /* ++ * On 64bit the read of [my]scd->clock is atomic versus the ++ * update, so we can avoid the above 32bit dance. ++ */ + sched_clock_local(my_scd); + again: + this_clock = my_scd->clock; + remote_clock = scd->clock; ++#endif + + /* + * Use the opportunity that we have both locks +diff --git a/kernel/signal.c b/kernel/signal.c +index ea76d30..3ecf574 100644 +--- a/kernel/signal.c ++++ b/kernel/signal.c +@@ -2790,7 +2790,7 @@ do_send_specific(pid_t tgid, pid_t pid, int sig, struct siginfo *info) + + static int do_tkill(pid_t tgid, pid_t pid, int sig) + { +- struct siginfo info; ++ struct siginfo info = {}; + + info.si_signo = sig; + info.si_errno = 0; +diff --git a/kernel/sys.c b/kernel/sys.c +index f5939c2..be5fa8b 100644 +--- a/kernel/sys.c ++++ b/kernel/sys.c +@@ -320,7 +320,6 @@ void kernel_restart_prepare(char *cmd) + system_state = SYSTEM_RESTART; + usermodehelper_disable(); + device_shutdown(); +- syscore_shutdown(); + } + + /** +@@ -366,6 +365,7 @@ void kernel_restart(char *cmd) + { + kernel_restart_prepare(cmd); + disable_nonboot_cpus(); ++ syscore_shutdown(); + if (!cmd) + printk(KERN_EMERG "Restarting system.\n"); + else +@@ -391,6 +391,7 @@ static void kernel_shutdown_prepare(enum system_states state) + void kernel_halt(void) + { + kernel_shutdown_prepare(SYSTEM_HALT); ++ disable_nonboot_cpus(); + syscore_shutdown(); + printk(KERN_EMERG "System halted.\n"); + kmsg_dump(KMSG_DUMP_HALT); +diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c +index 0943d2a..5527211 100644 +--- a/kernel/trace/ftrace.c ++++ b/kernel/trace/ftrace.c +@@ -572,7 +572,6 @@ int ftrace_profile_pages_init(struct ftrace_profile_stat *stat) + free_page(tmp); + } + +- free_page((unsigned long)stat->pages); + stat->pages = NULL; + stat->start = NULL; + +@@ -2317,7 +2316,7 @@ ftrace_notrace_open(struct inode *inode, struct file *file) + } + + static loff_t +-ftrace_regex_lseek(struct file *file, loff_t offset, int origin) ++ftrace_filter_lseek(struct file *file, loff_t offset, int origin) + { + loff_t ret; + +@@ -3135,7 +3134,7 @@ static const struct file_operations ftrace_filter_fops = { + .open = ftrace_filter_open, + .read = seq_read, + .write = ftrace_filter_write, +- .llseek = ftrace_regex_lseek, ++ .llseek = ftrace_filter_lseek, + .release = ftrace_regex_release, + }; + +@@ -3143,7 +3142,7 @@ static const struct file_operations ftrace_notrace_fops = { + .open = ftrace_notrace_open, + .read = seq_read, + .write = ftrace_notrace_write, +- .llseek = ftrace_regex_lseek, ++ .llseek = ftrace_filter_lseek, + .release = ftrace_regex_release, + }; + +@@ -3351,8 +3350,8 @@ static const struct file_operations ftrace_graph_fops = { + .open = ftrace_graph_open, + .read = seq_read, + .write = ftrace_graph_write, ++ .llseek = ftrace_filter_lseek, + .release = ftrace_graph_release, +- .llseek = seq_lseek, + }; + #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ + +@@ -3844,7 +3843,7 @@ static const struct file_operations ftrace_pid_fops = { + .open = ftrace_pid_open, + .write = ftrace_pid_write, + .read = seq_read, +- .llseek = seq_lseek, ++ .llseek = ftrace_filter_lseek, + .release = ftrace_pid_release, + }; + +@@ -3964,12 +3963,8 @@ ftrace_enable_sysctl(struct ctl_table *table, int write, + ftrace_startup_sysctl(); + + /* we are starting ftrace again */ +- if (ftrace_ops_list != &ftrace_list_end) { +- if (ftrace_ops_list->next == &ftrace_list_end) +- ftrace_trace_function = ftrace_ops_list->func; +- else +- ftrace_trace_function = ftrace_ops_list_func; +- } ++ if (ftrace_ops_list != &ftrace_list_end) ++ update_ftrace_function(); + + } else { + /* stopping ftrace calls (just send to ftrace_stub) */ +diff --git a/lib/kobject.c b/lib/kobject.c +index 640bd98..83bd5b3 100644 +--- a/lib/kobject.c ++++ b/lib/kobject.c +@@ -531,6 +531,13 @@ struct kobject *kobject_get(struct kobject *kobj) + return kobj; + } + ++static struct kobject *kobject_get_unless_zero(struct kobject *kobj) ++{ ++ if (!kref_get_unless_zero(&kobj->kref)) ++ kobj = NULL; ++ return kobj; ++} ++ + /* + * kobject_cleanup - free kobject resources. + * @kobj: object to cleanup +@@ -785,7 +792,7 @@ struct kobject *kset_find_obj_hinted(struct kset *kset, const char *name, + slow_search: + list_for_each_entry(k, &kset->list, entry) { + if (kobject_name(k) && !strcmp(kobject_name(k), name)) { +- ret = kobject_get(k); ++ ret = kobject_get_unless_zero(k); + break; + } + } +diff --git a/mm/hugetlb.c b/mm/hugetlb.c +index 4c7d42a..70b4733 100644 +--- a/mm/hugetlb.c ++++ b/mm/hugetlb.c +@@ -2889,7 +2889,17 @@ int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, + break; + } + +- if (absent || ++ /* ++ * We need call hugetlb_fault for both hugepages under migration ++ * (in which case hugetlb_fault waits for the migration,) and ++ * hwpoisoned hugepages (in which case we need to prevent the ++ * caller from accessing to them.) In order to do this, we use ++ * here is_swap_pte instead of is_hugetlb_entry_migration and ++ * is_hugetlb_entry_hwpoisoned. This is because it simply covers ++ * both cases, and because we can't follow correct pages ++ * directly from any kind of swap entries. ++ */ ++ if (absent || is_swap_pte(huge_ptep_get(pte)) || + ((flags & FOLL_WRITE) && !pte_write(huge_ptep_get(pte)))) { + int ret; + +diff --git a/mm/page-writeback.c b/mm/page-writeback.c +index 50f0824..ea3f83b 100644 +--- a/mm/page-writeback.c ++++ b/mm/page-writeback.c +@@ -1801,6 +1801,24 @@ int __set_page_dirty_nobuffers(struct page *page) + EXPORT_SYMBOL(__set_page_dirty_nobuffers); + + /* ++ * Call this whenever redirtying a page, to de-account the dirty counters ++ * (NR_DIRTIED, BDI_DIRTIED, tsk->nr_dirtied), so that they match the written ++ * counters (NR_WRITTEN, BDI_WRITTEN) in long term. The mismatches will lead to ++ * systematic errors in balanced_dirty_ratelimit and the dirty pages position ++ * control. ++ */ ++void account_page_redirty(struct page *page) ++{ ++ struct address_space *mapping = page->mapping; ++ if (mapping && mapping_cap_account_dirty(mapping)) { ++ current->nr_dirtied--; ++ dec_zone_page_state(page, NR_DIRTIED); ++ dec_bdi_stat(mapping->backing_dev_info, BDI_DIRTIED); ++ } ++} ++EXPORT_SYMBOL(account_page_redirty); ++ ++/* + * When a writepage implementation decides that it doesn't want to write this + * page for some reason, it should redirty the locked page via + * redirty_page_for_writepage() and it should then unlock the page and return 0 +@@ -1808,6 +1826,7 @@ EXPORT_SYMBOL(__set_page_dirty_nobuffers); + int redirty_page_for_writepage(struct writeback_control *wbc, struct page *page) + { + wbc->pages_skipped++; ++ account_page_redirty(page); + return __set_page_dirty_nobuffers(page); + } + EXPORT_SYMBOL(redirty_page_for_writepage); +diff --git a/net/can/gw.c b/net/can/gw.c +index 3d79b12..f78f898 100644 +--- a/net/can/gw.c ++++ b/net/can/gw.c +@@ -436,7 +436,7 @@ static int cgw_notifier(struct notifier_block *nb, + if (gwj->src.dev == dev || gwj->dst.dev == dev) { + hlist_del(&gwj->list); + cgw_unregister_filter(gwj); +- kfree(gwj); ++ kmem_cache_free(cgw_cache, gwj); + } + } + } +@@ -850,7 +850,7 @@ static void cgw_remove_all_jobs(void) + hlist_for_each_entry_safe(gwj, n, nx, &cgw_list, list) { + hlist_del(&gwj->list); + cgw_unregister_filter(gwj); +- kfree(gwj); ++ kmem_cache_free(cgw_cache, gwj); + } + } + +@@ -903,7 +903,7 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) + + hlist_del(&gwj->list); + cgw_unregister_filter(gwj); +- kfree(gwj); ++ kmem_cache_free(cgw_cache, gwj); + err = 0; + break; + } +diff --git a/net/core/sock.c b/net/core/sock.c +index 1e8a882..2c73adf 100644 +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -761,6 +761,20 @@ void cred_to_ucred(struct pid *pid, const struct cred *cred, + } + EXPORT_SYMBOL_GPL(cred_to_ucred); + ++void cred_real_to_ucred(struct pid *pid, const struct cred *cred, ++ struct ucred *ucred) ++{ ++ ucred->pid = pid_vnr(pid); ++ ucred->uid = ucred->gid = -1; ++ if (cred) { ++ struct user_namespace *current_ns = current_user_ns(); ++ ++ ucred->uid = user_ns_map_uid(current_ns, cred, cred->uid); ++ ucred->gid = user_ns_map_gid(current_ns, cred, cred->gid); ++ } ++} ++EXPORT_SYMBOL_GPL(cred_real_to_ucred); ++ + int sock_getsockopt(struct socket *sock, int level, int optname, + char __user *optval, int __user *optlen) + { +diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c +index 7747d26..4707b6c 100644 +--- a/sound/pci/hda/hda_codec.c ++++ b/sound/pci/hda/hda_codec.c +@@ -163,7 +163,7 @@ const char *snd_hda_get_jack_type(u32 cfg) + "Line Out", "Speaker", "HP Out", "CD", + "SPDIF Out", "Digital Out", "Modem Line", "Modem Hand", + "Line In", "Aux", "Mic", "Telephony", +- "SPDIF In", "Digitial In", "Reserved", "Other" ++ "SPDIF In", "Digital In", "Reserved", "Other" + }; + + return jack_types[(cfg & AC_DEFCFG_DEVICE) +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index f3e0b24..1b43fde 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -5595,7 +5595,8 @@ static int alc662_parse_auto_config(struct hda_codec *codec) + const hda_nid_t *ssids; + + if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 || +- codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670) ++ codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670 || ++ codec->vendor_id == 0x10ec0671) + ssids = alc663_ssids; + else + ssids = alc662_ssids; +@@ -6045,6 +6046,7 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = { + { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 }, + { .id = 0x10ec0668, .name = "ALC668", .patch = patch_alc662 }, + { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 }, ++ { .id = 0x10ec0671, .name = "ALC671", .patch = patch_alc662 }, + { .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 }, + { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, + { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 }, +diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c +index 4ad8ebd..4352ffb 100644 +--- a/sound/soc/codecs/wm8903.c ++++ b/sound/soc/codecs/wm8903.c +@@ -1101,6 +1101,8 @@ static const struct snd_soc_dapm_route wm8903_intercon[] = { + { "ROP", NULL, "Right Speaker PGA" }, + { "RON", NULL, "Right Speaker PGA" }, + ++ { "Charge Pump", NULL, "CLK_DSP" }, ++ + { "Left Headphone Output PGA", NULL, "Charge Pump" }, + { "Right Headphone Output PGA", NULL, "Charge Pump" }, + { "Left Line Output PGA", NULL, "Charge Pump" }, +diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c +index 38a607a..fb95069 100644 +--- a/sound/usb/mixer_quirks.c ++++ b/sound/usb/mixer_quirks.c +@@ -396,7 +396,7 @@ static int snd_nativeinstruments_control_get(struct snd_kcontrol *kcontrol, + else + ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, +- 0, cpu_to_le16(wIndex), ++ 0, wIndex, + &tmp, sizeof(tmp), 1000); + up_read(&mixer->chip->shutdown_rwsem); + +@@ -427,7 +427,7 @@ static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol, + else + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), bRequest, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, +- cpu_to_le16(wValue), cpu_to_le16(wIndex), ++ wValue, wIndex, + NULL, 0, 1000); + up_read(&mixer->chip->shutdown_rwsem); + +diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c +index 1b275f0..dfbd65d 100644 +--- a/sound/usb/quirks.c ++++ b/sound/usb/quirks.c +@@ -482,7 +482,7 @@ static int snd_usb_nativeinstruments_boot_quirk(struct usb_device *dev) + { + int ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + 0xaf, USB_TYPE_VENDOR | USB_RECIP_DEVICE, +- cpu_to_le16(1), 0, NULL, 0, 1000); ++ 1, 0, NULL, 0, 1000); + + if (ret < 0) + return ret; +diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c +index 3eed61e..79647cd 100644 +--- a/virt/kvm/ioapic.c ++++ b/virt/kvm/ioapic.c +@@ -73,9 +73,12 @@ static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic, + u32 redir_index = (ioapic->ioregsel - 0x10) >> 1; + u64 redir_content; + +- ASSERT(redir_index < IOAPIC_NUM_PINS); ++ if (redir_index < IOAPIC_NUM_PINS) ++ redir_content = ++ ioapic->redirtbl[redir_index].bits; ++ else ++ redir_content = ~0ULL; + +- redir_content = ioapic->redirtbl[redir_index].bits; + result = (ioapic->ioregsel & 0x1) ? + (redir_content >> 32) & 0xffffffff : + redir_content & 0xffffffff; +diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c +index ec747dc..8bf05f0 100644 +--- a/virt/kvm/kvm_main.c ++++ b/virt/kvm/kvm_main.c +@@ -1401,21 +1401,38 @@ int kvm_write_guest(struct kvm *kvm, gpa_t gpa, const void *data, + } + + int kvm_gfn_to_hva_cache_init(struct kvm *kvm, struct gfn_to_hva_cache *ghc, +- gpa_t gpa) ++ gpa_t gpa, unsigned long len) + { + struct kvm_memslots *slots = kvm_memslots(kvm); + int offset = offset_in_page(gpa); +- gfn_t gfn = gpa >> PAGE_SHIFT; ++ gfn_t start_gfn = gpa >> PAGE_SHIFT; ++ gfn_t end_gfn = (gpa + len - 1) >> PAGE_SHIFT; ++ gfn_t nr_pages_needed = end_gfn - start_gfn + 1; ++ gfn_t nr_pages_avail; + + ghc->gpa = gpa; + ghc->generation = slots->generation; +- ghc->memslot = __gfn_to_memslot(slots, gfn); +- ghc->hva = gfn_to_hva_many(ghc->memslot, gfn, NULL); +- if (!kvm_is_error_hva(ghc->hva)) ++ ghc->len = len; ++ ghc->memslot = __gfn_to_memslot(slots, start_gfn); ++ ghc->hva = gfn_to_hva_many(ghc->memslot, start_gfn, &nr_pages_avail); ++ if (!kvm_is_error_hva(ghc->hva) && nr_pages_avail >= nr_pages_needed) { + ghc->hva += offset; +- else +- return -EFAULT; +- ++ } else { ++ /* ++ * If the requested region crosses two memslots, we still ++ * verify that the entire region is valid here. ++ */ ++ while (start_gfn <= end_gfn) { ++ ghc->memslot = __gfn_to_memslot(slots, start_gfn); ++ ghc->hva = gfn_to_hva_many(ghc->memslot, start_gfn, ++ &nr_pages_avail); ++ if (kvm_is_error_hva(ghc->hva)) ++ return -EFAULT; ++ start_gfn += nr_pages_avail; ++ } ++ /* Use the slow path for cross page reads and writes. */ ++ ghc->memslot = NULL; ++ } + return 0; + } + EXPORT_SYMBOL_GPL(kvm_gfn_to_hva_cache_init); +@@ -1426,8 +1443,13 @@ int kvm_write_guest_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc, + struct kvm_memslots *slots = kvm_memslots(kvm); + int r; + ++ BUG_ON(len > ghc->len); ++ + if (slots->generation != ghc->generation) +- kvm_gfn_to_hva_cache_init(kvm, ghc, ghc->gpa); ++ kvm_gfn_to_hva_cache_init(kvm, ghc, ghc->gpa, ghc->len); ++ ++ if (unlikely(!ghc->memslot)) ++ return kvm_write_guest(kvm, ghc->gpa, data, len); + + if (kvm_is_error_hva(ghc->hva)) + return -EFAULT; +@@ -1447,8 +1469,13 @@ int kvm_read_guest_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc, + struct kvm_memslots *slots = kvm_memslots(kvm); + int r; + ++ BUG_ON(len > ghc->len); ++ + if (slots->generation != ghc->generation) +- kvm_gfn_to_hva_cache_init(kvm, ghc, ghc->gpa); ++ kvm_gfn_to_hva_cache_init(kvm, ghc, ghc->gpa, ghc->len); ++ ++ if (unlikely(!ghc->memslot)) ++ return kvm_read_guest(kvm, ghc->gpa, data, len); + + if (kvm_is_error_hva(ghc->hva)) + return -EFAULT; |