diff options
97 files changed, 1097 insertions, 701 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index c2238cd..4c33ca8 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -729,14 +729,26 @@ config ARCH_U8500 endchoice +source "arch/arm/mach-aaec2000/Kconfig" + +source "arch/arm/mach-at91/Kconfig" + +source "arch/arm/mach-bcmring/Kconfig" + source "arch/arm/mach-clps711x/Kconfig" +source "arch/arm/mach-davinci/Kconfig" + +source "arch/arm/mach-dove/Kconfig" + source "arch/arm/mach-ep93xx/Kconfig" source "arch/arm/mach-footbridge/Kconfig" source "arch/arm/mach-gemini/Kconfig" +source "arch/arm/mach-h720x/Kconfig" + source "arch/arm/mach-integrator/Kconfig" source "arch/arm/mach-iop32x/Kconfig" @@ -751,16 +763,26 @@ source "arch/arm/mach-ixp2000/Kconfig" source "arch/arm/mach-ixp23xx/Kconfig" +source "arch/arm/mach-kirkwood/Kconfig" + +source "arch/arm/mach-ks8695/Kconfig" + +source "arch/arm/mach-lh7a40x/Kconfig" + source "arch/arm/mach-loki/Kconfig" +source "arch/arm/mach-msm/Kconfig" + source "arch/arm/mach-mv78xx0/Kconfig" -source "arch/arm/mach-pxa/Kconfig" -source "arch/arm/plat-pxa/Kconfig" +source "arch/arm/plat-mxc/Kconfig" -source "arch/arm/mach-mmp/Kconfig" +source "arch/arm/mach-netx/Kconfig" -source "arch/arm/mach-sa1100/Kconfig" +source "arch/arm/mach-nomadik/Kconfig" +source "arch/arm/plat-nomadik/Kconfig" + +source "arch/arm/mach-ns9xxx/Kconfig" source "arch/arm/plat-omap/Kconfig" @@ -770,9 +792,14 @@ source "arch/arm/mach-omap2/Kconfig" source "arch/arm/mach-orion5x/Kconfig" -source "arch/arm/mach-kirkwood/Kconfig" +source "arch/arm/mach-pxa/Kconfig" +source "arch/arm/plat-pxa/Kconfig" -source "arch/arm/mach-dove/Kconfig" +source "arch/arm/mach-mmp/Kconfig" + +source "arch/arm/mach-realview/Kconfig" + +source "arch/arm/mach-sa1100/Kconfig" source "arch/arm/plat-samsung/Kconfig" source "arch/arm/plat-s3c24xx/Kconfig" @@ -800,41 +827,14 @@ if ARCH_S5PC1XX source "arch/arm/mach-s5pc100/Kconfig" endif -source "arch/arm/mach-lh7a40x/Kconfig" +source "arch/arm/mach-u300/Kconfig" -source "arch/arm/mach-h720x/Kconfig" +source "arch/arm/mach-ux500/Kconfig" source "arch/arm/mach-versatile/Kconfig" -source "arch/arm/mach-aaec2000/Kconfig" - -source "arch/arm/mach-realview/Kconfig" - -source "arch/arm/mach-at91/Kconfig" - -source "arch/arm/plat-mxc/Kconfig" - -source "arch/arm/mach-nomadik/Kconfig" -source "arch/arm/plat-nomadik/Kconfig" - -source "arch/arm/mach-netx/Kconfig" - -source "arch/arm/mach-ns9xxx/Kconfig" - -source "arch/arm/mach-davinci/Kconfig" - -source "arch/arm/mach-ks8695/Kconfig" - -source "arch/arm/mach-msm/Kconfig" - -source "arch/arm/mach-u300/Kconfig" - source "arch/arm/mach-w90x900/Kconfig" -source "arch/arm/mach-bcmring/Kconfig" - -source "arch/arm/mach-ux500/Kconfig" - # Definitions to make life easier config ARCH_ACORN bool diff --git a/arch/arm/Makefile b/arch/arm/Makefile index e9da084..9e75825 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -146,6 +146,7 @@ machine-$(CONFIG_ARCH_MX1) := mx1 machine-$(CONFIG_ARCH_MX2) := mx2 machine-$(CONFIG_ARCH_MX25) := mx25 machine-$(CONFIG_ARCH_MX3) := mx3 +machine-$(CONFIG_ARCH_MXC91231) := mxc91231 machine-$(CONFIG_ARCH_NETX) := netx machine-$(CONFIG_ARCH_NOMADIK) := nomadik machine-$(CONFIG_ARCH_NS9XXX) := ns9xxx @@ -171,12 +172,12 @@ machine-$(CONFIG_ARCH_U8500) := ux500 machine-$(CONFIG_ARCH_VERSATILE) := versatile machine-$(CONFIG_ARCH_W90X900) := w90x900 machine-$(CONFIG_FOOTBRIDGE) := footbridge -machine-$(CONFIG_ARCH_MXC91231) := mxc91231 # Platform directory name. This list is sorted alphanumerically # by CONFIG_* macro name. plat-$(CONFIG_ARCH_MXC) := mxc plat-$(CONFIG_ARCH_OMAP) := omap +plat-$(CONFIG_ARCH_STMP3XXX) := stmp3xxx plat-$(CONFIG_PLAT_IOP) := iop plat-$(CONFIG_PLAT_NOMADIK) := nomadik plat-$(CONFIG_PLAT_ORION) := orion @@ -184,7 +185,6 @@ plat-$(CONFIG_PLAT_PXA) := pxa plat-$(CONFIG_PLAT_S3C24XX) := s3c24xx s3c samsung plat-$(CONFIG_PLAT_S3C64XX) := s3c64xx s3c samsung plat-$(CONFIG_PLAT_S5PC1XX) := s5pc1xx s3c samsung -plat-$(CONFIG_ARCH_STMP3XXX) := stmp3xxx ifeq ($(CONFIG_ARCH_EBSA110),y) # This is what happens if you forget the IOCS16 line. diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index d356af7..4fddc50 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -27,6 +27,14 @@ .macro writeb, ch, rb mcr p14, 0, \ch, c0, c5, 0 .endm +#elif defined(CONFIG_CPU_V7) + .macro loadsp, rb + .endm + .macro writeb, ch, rb +wait: mrc p14, 0, pc, c0, c1, 0 + bcs wait + mcr p14, 0, \ch, c0, c5, 0 + .endm #elif defined(CONFIG_CPU_XSCALE) .macro loadsp, rb .endm diff --git a/arch/arm/boot/compressed/misc.c b/arch/arm/boot/compressed/misc.c index 7e0fe4d..56a0d11 100644 --- a/arch/arm/boot/compressed/misc.c +++ b/arch/arm/boot/compressed/misc.c @@ -53,6 +53,18 @@ static void icedcc_putc(int ch) asm("mcr p14, 0, %0, c0, c5, 0" : : "r" (ch)); } + +#elif defined(CONFIG_CPU_V7) + +static void icedcc_putc(int ch) +{ + asm( + "wait: mrc p14, 0, pc, c0, c1, 0 \n\ + bcs wait \n\ + mcr p14, 0, %0, c0, c5, 0 " + : : "r" (ch)); +} + #elif defined(CONFIG_CPU_XSCALE) static void icedcc_putc(int ch) @@ -88,7 +100,6 @@ static void icedcc_putc(int ch) #endif #define putc(ch) icedcc_putc(ch) -#define flush() do { } while (0) #endif static void putstr(const char *ptr) diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h index 730aefc..c77d2fa 100644 --- a/arch/arm/include/asm/cacheflush.h +++ b/arch/arm/include/asm/cacheflush.h @@ -154,16 +154,16 @@ * Please note that the implementation of these, and the required * effects are cache-type (VIVT/VIPT/PIPT) specific. * - * flush_cache_kern_all() + * flush_kern_all() * * Unconditionally clean and invalidate the entire cache. * - * flush_cache_user_mm(mm) + * flush_user_all() * * Clean and invalidate all user space cache entries * before a change of page tables. * - * flush_cache_user_range(start, end, flags) + * flush_user_range(start, end, flags) * * Clean and invalidate a range of cache entries in the * specified address space before a change of page tables. @@ -179,6 +179,20 @@ * - start - virtual start address * - end - virtual end address * + * coherent_user_range(start, end) + * + * Ensure coherency between the Icache and the Dcache in the + * region described by start, end. If you have non-snooping + * Harvard caches, you need to implement this function. + * - start - virtual start address + * - end - virtual end address + * + * flush_kern_dcache_area(kaddr, size) + * + * Ensure that the data held in page is written back. + * - kaddr - page address + * - size - region size + * * DMA Cache Coherency * =================== * diff --git a/arch/arm/kernel/debug.S b/arch/arm/kernel/debug.S index b121b60..5c91add 100644 --- a/arch/arm/kernel/debug.S +++ b/arch/arm/kernel/debug.S @@ -49,6 +49,26 @@ 1002: .endm +#elif defined(CONFIG_CPU_V7) + + .macro addruart, rx + .endm + + .macro senduart, rd, rx + mcr p14, 0, \rd, c0, c5, 0 + .endm + + .macro busyuart, rd, rx +busy: mrc p14, 0, pc, c0, c1, 0 + bcs busy + .endm + + .macro waituart, rd, rx +wait: mrc p14, 0, pc, c0, c1, 0 + bcs wait + + .endm + #elif defined(CONFIG_CPU_XSCALE) .macro addruart, rx diff --git a/arch/arm/kernel/elf.c b/arch/arm/kernel/elf.c index 950391f..d4a0da1 100644 --- a/arch/arm/kernel/elf.c +++ b/arch/arm/kernel/elf.c @@ -78,15 +78,6 @@ int arm_elf_read_implies_exec(const struct elf32_hdr *x, int executable_stack) return 1; if (cpu_architecture() < CPU_ARCH_ARMv6) return 1; -#if !defined(CONFIG_AEABI) || defined(CONFIG_OABI_COMPAT) - /* - * If we have support for OABI programs, we can never allow NX - * support - our signal syscall restart mechanism relies upon - * being able to execute code placed on the user stack. - */ - return 1; -#else return 0; -#endif } EXPORT_SYMBOL(arm_elf_read_implies_exec); diff --git a/arch/arm/mach-gemini/include/mach/uncompress.h b/arch/arm/mach-gemini/include/mach/uncompress.h index 59c5df7..5483f61 100644 --- a/arch/arm/mach-gemini/include/mach/uncompress.h +++ b/arch/arm/mach-gemini/include/mach/uncompress.h @@ -30,7 +30,9 @@ static inline void putc(char c) UART[UART_TX] = c; } -#define flush() do { } while (0) +static inline void flush(void) +{ +} /* * nothing to do diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 1708da8..761ffed 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -1067,4 +1067,6 @@ void setup_mm_for_reboot(char mode) pmd[1] = __pmd(pmdval + (1 << (PGDIR_SHIFT - 1))); flush_pmd_entry(pmd); } + + local_flush_tlb_all(); } diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S index 395cc90..7a5337e 100644 --- a/arch/arm/mm/proc-v6.S +++ b/arch/arm/mm/proc-v6.S @@ -59,8 +59,6 @@ ENTRY(cpu_v6_proc_fin) * to what would be the reset vector. * * - loc - location to jump to for soft reset - * - * It is assumed that: */ .align 5 ENTRY(cpu_v6_reset) diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index 3a28521..7aaf88a 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S @@ -45,7 +45,14 @@ ENTRY(cpu_v7_proc_init) ENDPROC(cpu_v7_proc_init) ENTRY(cpu_v7_proc_fin) - mov pc, lr + stmfd sp!, {lr} + cpsid if @ disable interrupts + bl v7_flush_kern_cache_all + mrc p15, 0, r0, c1, c0, 0 @ ctrl register + bic r0, r0, #0x1000 @ ...i............ + bic r0, r0, #0x0006 @ .............ca. + mcr p15, 0, r0, c1, c0, 0 @ disable caches + ldmfd sp!, {pc} ENDPROC(cpu_v7_proc_fin) /* @@ -56,8 +63,6 @@ ENDPROC(cpu_v7_proc_fin) * to what would be the reset vector. * * - loc - location to jump to for soft reset - * - * It is assumed that: */ .align 5 ENTRY(cpu_v7_reset) diff --git a/arch/arm/plat-mxc/include/mach/uncompress.h b/arch/arm/plat-mxc/include/mach/uncompress.h index 4d5d395..d49384c 100644 --- a/arch/arm/plat-mxc/include/mach/uncompress.h +++ b/arch/arm/plat-mxc/include/mach/uncompress.h @@ -60,7 +60,9 @@ static void putc(int ch) UART(TXR) = ch; } -#define flush() do { } while (0) +static inline void flush(void) +{ +} #define MX1_UART1_BASE_ADDR 0x00206000 #define MX25_UART1_BASE_ADDR 0x43f90000 diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c index 5d0f70b..858ecb2 100644 --- a/arch/sh/boards/mach-se/7724/setup.c +++ b/arch/sh/boards/mach-se/7724/setup.c @@ -533,7 +533,7 @@ static int __init sh_eth_is_eeprom_ready(void) while (t--) { if (!ctrl_inw(EEPROM_STAT)) return 1; - cpu_relax(); + udelay(1); } printk(KERN_ERR "ms7724se can not access to eeprom\n"); diff --git a/arch/sh/include/asm/unistd_32.h b/arch/sh/include/asm/unistd_32.h index f18c4f9..365744b 100644 --- a/arch/sh/include/asm/unistd_32.h +++ b/arch/sh/include/asm/unistd_32.h @@ -345,12 +345,13 @@ #define __NR_pwritev 334 #define __NR_rt_tgsigqueueinfo 335 #define __NR_perf_event_open 336 -#define __NR_recvmmsg 337 -#define NR_syscalls 338 +#define NR_syscalls 337 #ifdef __KERNEL__ +#define __IGNORE_recvmmsg + #define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_OLD_READDIR #define __ARCH_WANT_OLD_STAT diff --git a/arch/sh/include/asm/unistd_64.h b/arch/sh/include/asm/unistd_64.h index 3e7645d..25de158 100644 --- a/arch/sh/include/asm/unistd_64.h +++ b/arch/sh/include/asm/unistd_64.h @@ -386,10 +386,11 @@ #define __NR_rt_tgsigqueueinfo 363 #define __NR_perf_event_open 364 #define __NR_recvmmsg 365 +#define __NR_accept4 366 #ifdef __KERNEL__ -#define NR_syscalls 366 +#define NR_syscalls 367 #define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_OLD_READDIR diff --git a/arch/sh/kernel/syscalls_32.S b/arch/sh/kernel/syscalls_32.S index 4bd5a11..19fd11d 100644 --- a/arch/sh/kernel/syscalls_32.S +++ b/arch/sh/kernel/syscalls_32.S @@ -353,4 +353,3 @@ ENTRY(sys_call_table) .long sys_pwritev .long sys_rt_tgsigqueueinfo /* 335 */ .long sys_perf_event_open - .long sys_recvmmsg diff --git a/arch/sh/kernel/syscalls_64.S b/arch/sh/kernel/syscalls_64.S index 07d2aae..2048a20 100644 --- a/arch/sh/kernel/syscalls_64.S +++ b/arch/sh/kernel/syscalls_64.S @@ -392,3 +392,4 @@ sys_call_table: .long sys_rt_tgsigqueueinfo .long sys_perf_event_open .long sys_recvmmsg /* 365 */ + .long sys_accept4 diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index fb1035c..036d28a 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -1529,16 +1529,10 @@ static struct dmi_system_id __initdata acpi_dmi_table_late[] = { * if acpi_blacklisted() acpi_disabled = 1; * acpi_irq_model=... * ... - * - * return value: (currently ignored) - * 0: success - * !0: failure */ -int __init acpi_boot_table_init(void) +void __init acpi_boot_table_init(void) { - int error; - dmi_check_system(acpi_dmi_table); /* @@ -1546,15 +1540,14 @@ int __init acpi_boot_table_init(void) * One exception: acpi=ht continues far enough to enumerate LAPICs */ if (acpi_disabled && !acpi_ht) - return 1; + return; /* * Initialize the ACPI boot-time table parser. */ - error = acpi_table_init(); - if (error) { + if (acpi_table_init()) { disable_acpi(); - return error; + return; } acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf); @@ -1562,18 +1555,15 @@ int __init acpi_boot_table_init(void) /* * blacklist may disable ACPI entirely */ - error = acpi_blacklisted(); - if (error) { + if (acpi_blacklisted()) { if (acpi_force) { printk(KERN_WARNING PREFIX "acpi=force override\n"); } else { printk(KERN_WARNING PREFIX "Disabling ACPI support\n"); disable_acpi(); - return error; + return; } } - - return 0; } int __init early_acpi_boot_init(void) diff --git a/block/blk-ioc.c b/block/blk-ioc.c index cbdabb0..98e6bf6 100644 --- a/block/blk-ioc.c +++ b/block/blk-ioc.c @@ -39,8 +39,6 @@ int put_io_context(struct io_context *ioc) if (atomic_long_dec_and_test(&ioc->refcount)) { rcu_read_lock(); - if (ioc->aic && ioc->aic->dtor) - ioc->aic->dtor(ioc->aic); cfq_dtor(ioc); rcu_read_unlock(); @@ -76,8 +74,6 @@ void exit_io_context(struct task_struct *task) task_unlock(task); if (atomic_dec_and_test(&ioc->nr_tasks)) { - if (ioc->aic && ioc->aic->exit) - ioc->aic->exit(ioc->aic); cfq_exit(ioc); } @@ -97,7 +93,6 @@ struct io_context *alloc_io_context(gfp_t gfp_flags, int node) ret->ioprio = 0; ret->last_waited = jiffies; /* doesn't matter... */ ret->nr_batch_requests = 0; /* because this is 0 */ - ret->aic = NULL; INIT_RADIX_TREE(&ret->radix_root, GFP_ATOMIC | __GFP_HIGH); INIT_HLIST_HEAD(&ret->cic_list); ret->ioc_data = NULL; diff --git a/block/blk-settings.c b/block/blk-settings.c index d52d4ad..5eeb9e0 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -528,7 +528,7 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, sector_t offset) { sector_t alignment; - unsigned int top, bottom; + unsigned int top, bottom, ret = 0; t->max_sectors = min_not_zero(t->max_sectors, b->max_sectors); t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors); @@ -546,6 +546,8 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, t->max_segment_size = min_not_zero(t->max_segment_size, b->max_segment_size); + t->misaligned |= b->misaligned; + alignment = queue_limit_alignment_offset(b, offset); /* Bottom device has different alignment. Check that it is @@ -558,8 +560,10 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, bottom = max(b->physical_block_size, b->io_min) + alignment; /* Verify that top and bottom intervals line up */ - if (max(top, bottom) & (min(top, bottom) - 1)) + if (max(top, bottom) & (min(top, bottom) - 1)) { t->misaligned = 1; + ret = -1; + } } t->logical_block_size = max(t->logical_block_size, @@ -578,18 +582,21 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, if (t->physical_block_size & (t->logical_block_size - 1)) { t->physical_block_size = t->logical_block_size; t->misaligned = 1; + ret = -1; } /* Minimum I/O a multiple of the physical block size? */ if (t->io_min & (t->physical_block_size - 1)) { t->io_min = t->physical_block_size; t->misaligned = 1; + ret = -1; } /* Optimal I/O a multiple of the physical block size? */ if (t->io_opt & (t->physical_block_size - 1)) { t->io_opt = 0; t->misaligned = 1; + ret = -1; } /* Find lowest common alignment_offset */ @@ -597,8 +604,10 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, & (max(t->physical_block_size, t->io_min) - 1); /* Verify that new alignment_offset is on a logical block boundary */ - if (t->alignment_offset & (t->logical_block_size - 1)) + if (t->alignment_offset & (t->logical_block_size - 1)) { t->misaligned = 1; + ret = -1; + } /* Discard alignment and granularity */ if (b->discard_granularity) { @@ -626,11 +635,33 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, (t->discard_granularity - 1); } - return t->misaligned ? -1 : 0; + return ret; } EXPORT_SYMBOL(blk_stack_limits); /** + * bdev_stack_limits - adjust queue limits for stacked drivers + * @t: the stacking driver limits (top device) + * @bdev: the component block_device (bottom) + * @start: first data sector within component device + * + * Description: + * Merges queue limits for a top device and a block_device. Returns + * 0 if alignment didn't change. Returns -1 if adding the bottom + * device caused misalignment. + */ +int bdev_stack_limits(struct queue_limits *t, struct block_device *bdev, + sector_t start) +{ + struct request_queue *bq = bdev_get_queue(bdev); + + start += get_start_sect(bdev); + + return blk_stack_limits(t, &bq->limits, start << 9); +} +EXPORT_SYMBOL(bdev_stack_limits); + +/** * disk_stack_limits - adjust queue limits for stacked drivers * @disk: MD/DM gendisk (top) * @bdev: the underlying block device (bottom) diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 918c7fd..ee130f1 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -3077,6 +3077,12 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq, return true; /* + * Don't allow a non-RT request to preempt an ongoing RT cfqq timeslice. + */ + if (cfq_class_rt(cfqq) && !cfq_class_rt(new_cfqq)) + return false; + + /* * if the new request is sync, but the currently running queue is * not, let the sync request have priority. */ diff --git a/block/genhd.c b/block/genhd.c index b11a4ad..d13ba76 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -867,7 +867,7 @@ static ssize_t disk_discard_alignment_show(struct device *dev, { struct gendisk *disk = dev_to_disk(dev); - return sprintf(buf, "%u\n", queue_discard_alignment(disk->queue)); + return sprintf(buf, "%d\n", queue_discard_alignment(disk->queue)); } static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL); diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index 97991ac..7e52295 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -208,7 +208,7 @@ static int power_saving_thread(void *data) * the mechanism only works when all CPUs have RT task running, * as if one CPU hasn't RT task, RT task from other CPUs will * borrow CPU time from this CPU and cause RT task use > 95% - * CPU time. To make 'avoid staration' work, takes a nap here. + * CPU time. To make 'avoid starvation' work, takes a nap here. */ if (do_sleep) schedule_timeout_killable(HZ * idle_pct / 100); @@ -222,14 +222,18 @@ static struct task_struct *ps_tsks[NR_CPUS]; static unsigned int ps_tsk_num; static int create_power_saving_task(void) { + int rc = -ENOMEM; + ps_tsks[ps_tsk_num] = kthread_run(power_saving_thread, (void *)(unsigned long)ps_tsk_num, "power_saving/%d", ps_tsk_num); - if (ps_tsks[ps_tsk_num]) { + rc = IS_ERR(ps_tsks[ps_tsk_num]) ? PTR_ERR(ps_tsks[ps_tsk_num]) : 0; + if (!rc) ps_tsk_num++; - return 0; - } - return -EINVAL; + else + ps_tsks[ps_tsk_num] = NULL; + + return rc; } static void destroy_power_saving_task(void) @@ -237,6 +241,7 @@ static void destroy_power_saving_task(void) if (ps_tsk_num > 0) { ps_tsk_num--; kthread_stop(ps_tsks[ps_tsk_num]); + ps_tsks[ps_tsk_num] = NULL; } } @@ -253,7 +258,7 @@ static void set_power_saving_task_num(unsigned int num) } } -static int acpi_pad_idle_cpus(unsigned int num_cpus) +static void acpi_pad_idle_cpus(unsigned int num_cpus) { get_online_cpus(); @@ -261,7 +266,6 @@ static int acpi_pad_idle_cpus(unsigned int num_cpus) set_power_saving_task_num(num_cpus); put_online_cpus(); - return 0; } static uint32_t acpi_pad_idle_cpus_num(void) @@ -369,19 +373,21 @@ static void acpi_pad_remove_sysfs(struct acpi_device *device) static int acpi_pad_pur(acpi_handle handle, int *num_cpus) { struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; - acpi_status status; union acpi_object *package; int rev, num, ret = -EINVAL; - status = acpi_evaluate_object(handle, "_PUR", NULL, &buffer); - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(acpi_evaluate_object(handle, "_PUR", NULL, &buffer))) + return -EINVAL; + + if (!buffer.length || !buffer.pointer) return -EINVAL; + package = buffer.pointer; if (package->type != ACPI_TYPE_PACKAGE || package->package.count != 2) goto out; rev = package->package.elements[0].integer.value; num = package->package.elements[1].integer.value; - if (rev != 1) + if (rev != 1 || num < 0) goto out; *num_cpus = num; ret = 0; @@ -410,7 +416,7 @@ static void acpi_pad_ost(acpi_handle handle, int stat, static void acpi_pad_handle_notify(acpi_handle handle) { - int num_cpus, ret; + int num_cpus; uint32_t idle_cpus; mutex_lock(&isolated_cpus_lock); @@ -418,12 +424,9 @@ static void acpi_pad_handle_notify(acpi_handle handle) mutex_unlock(&isolated_cpus_lock); return; } - ret = acpi_pad_idle_cpus(num_cpus); + acpi_pad_idle_cpus(num_cpus); idle_cpus = acpi_pad_idle_cpus_num(); - if (!ret) - acpi_pad_ost(handle, 0, idle_cpus); - else - acpi_pad_ost(handle, 1, 0); + acpi_pad_ost(handle, 0, idle_cpus); mutex_unlock(&isolated_cpus_lock); } diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index cf761b9..a52126e 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -490,9 +490,14 @@ static void acpi_bus_osc_support(void) capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE; capbuf[OSC_SUPPORT_TYPE] = OSC_SB_PR3_SUPPORT; /* _PR3 is in use */ -#ifdef CONFIG_ACPI_PROCESSOR_AGGREGATOR +#if defined(CONFIG_ACPI_PROCESSOR_AGGREGATOR) ||\ + defined(CONFIG_ACPI_PROCESSOR_AGGREGATOR_MODULE) capbuf[OSC_SUPPORT_TYPE] |= OSC_SB_PAD_SUPPORT; #endif + +#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) + capbuf[OSC_SUPPORT_TYPE] |= OSC_SB_PPC_OST_SUPPORT; +#endif if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle))) return; if (ACPI_SUCCESS(acpi_run_osc(handle, &context))) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index fd1801b..d6471bb 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -201,14 +201,13 @@ unlock: spin_unlock_irqrestore(&ec->curr_lock, flags); } -static void acpi_ec_gpe_query(void *ec_cxt); +static int acpi_ec_sync_query(struct acpi_ec *ec); -static int ec_check_sci(struct acpi_ec *ec, u8 state) +static int ec_check_sci_sync(struct acpi_ec *ec, u8 state) { if (state & ACPI_EC_FLAG_SCI) { if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) - return acpi_os_execute(OSL_EC_BURST_HANDLER, - acpi_ec_gpe_query, ec); + return acpi_ec_sync_query(ec); } return 0; } @@ -249,11 +248,6 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, { unsigned long tmp; int ret = 0; - pr_debug(PREFIX "transaction start\n"); - /* disable GPE during transaction if storm is detected */ - if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { - acpi_disable_gpe(NULL, ec->gpe); - } if (EC_FLAGS_MSI) udelay(ACPI_EC_MSI_UDELAY); /* start transaction */ @@ -265,20 +259,9 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); spin_unlock_irqrestore(&ec->curr_lock, tmp); ret = ec_poll(ec); - pr_debug(PREFIX "transaction end\n"); spin_lock_irqsave(&ec->curr_lock, tmp); ec->curr = NULL; spin_unlock_irqrestore(&ec->curr_lock, tmp); - if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { - /* check if we received SCI during transaction */ - ec_check_sci(ec, acpi_ec_read_status(ec)); - /* it is safe to enable GPE outside of transaction */ - acpi_enable_gpe(NULL, ec->gpe); - } else if (t->irq_count > ACPI_EC_STORM_THRESHOLD) { - pr_info(PREFIX "GPE storm detected, " - "transactions will use polling mode\n"); - set_bit(EC_FLAGS_GPE_STORM, &ec->flags); - } return ret; } @@ -321,7 +304,26 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) status = -ETIME; goto end; } + pr_debug(PREFIX "transaction start\n"); + /* disable GPE during transaction if storm is detected */ + if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { + acpi_disable_gpe(NULL, ec->gpe); + } + status = acpi_ec_transaction_unlocked(ec, t); + + /* check if we received SCI during transaction */ + ec_check_sci_sync(ec, acpi_ec_read_status(ec)); + if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { + msleep(1); + /* it is safe to enable GPE outside of transaction */ + acpi_enable_gpe(NULL, ec->gpe); + } else if (t->irq_count > ACPI_EC_STORM_THRESHOLD) { + pr_info(PREFIX "GPE storm detected, " + "transactions will use polling mode\n"); + set_bit(EC_FLAGS_GPE_STORM, &ec->flags); + } + pr_debug(PREFIX "transaction end\n"); end: if (ec->global_lock) acpi_release_global_lock(glk); @@ -443,7 +445,7 @@ int ec_transaction(u8 command, EXPORT_SYMBOL(ec_transaction); -static int acpi_ec_query(struct acpi_ec *ec, u8 * data) +static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 * data) { int result; u8 d; @@ -452,20 +454,16 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data) .wlen = 0, .rlen = 1}; if (!ec || !data) return -EINVAL; - /* * Query the EC to find out which _Qxx method we need to evaluate. * Note that successful completion of the query causes the ACPI_EC_SCI * bit to be cleared (and thus clearing the interrupt source). */ - - result = acpi_ec_transaction(ec, &t); + result = acpi_ec_transaction_unlocked(ec, &t); if (result) return result; - if (!d) return -ENODATA; - *data = d; return 0; } @@ -509,43 +507,79 @@ void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit) EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler); -static void acpi_ec_gpe_query(void *ec_cxt) +static void acpi_ec_run(void *cxt) { - struct acpi_ec *ec = ec_cxt; - u8 value = 0; - struct acpi_ec_query_handler *handler, copy; - - if (!ec || acpi_ec_query(ec, &value)) + struct acpi_ec_query_handler *handler = cxt; + if (!handler) return; - mutex_lock(&ec->lock); + pr_debug(PREFIX "start query execution\n"); + if (handler->func) + handler->func(handler->data); + else if (handler->handle) + acpi_evaluate_object(handler->handle, NULL, NULL, NULL); + pr_debug(PREFIX "stop query execution\n"); + kfree(handler); +} + +static int acpi_ec_sync_query(struct acpi_ec *ec) +{ + u8 value = 0; + int status; + struct acpi_ec_query_handler *handler, *copy; + if ((status = acpi_ec_query_unlocked(ec, &value))) + return status; list_for_each_entry(handler, &ec->list, node) { if (value == handler->query_bit) { /* have custom handler for this bit */ - memcpy(©, handler, sizeof(copy)); - mutex_unlock(&ec->lock); - if (copy.func) { - copy.func(copy.data); - } else if (copy.handle) { - acpi_evaluate_object(copy.handle, NULL, NULL, NULL); - } - return; + copy = kmalloc(sizeof(*handler), GFP_KERNEL); + if (!copy) + return -ENOMEM; + memcpy(copy, handler, sizeof(*copy)); + pr_debug(PREFIX "push query execution (0x%2x) on queue\n", value); + return acpi_os_execute((copy->func) ? + OSL_NOTIFY_HANDLER : OSL_GPE_HANDLER, + acpi_ec_run, copy); } } + return 0; +} + +static void acpi_ec_gpe_query(void *ec_cxt) +{ + struct acpi_ec *ec = ec_cxt; + if (!ec) + return; + mutex_lock(&ec->lock); + acpi_ec_sync_query(ec); mutex_unlock(&ec->lock); } +static void acpi_ec_gpe_query(void *ec_cxt); + +static int ec_check_sci(struct acpi_ec *ec, u8 state) +{ + if (state & ACPI_EC_FLAG_SCI) { + if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) { + pr_debug(PREFIX "push gpe query to the queue\n"); + return acpi_os_execute(OSL_NOTIFY_HANDLER, + acpi_ec_gpe_query, ec); + } + } + return 0; +} + static u32 acpi_ec_gpe_handler(void *data) { struct acpi_ec *ec = data; - u8 status; pr_debug(PREFIX "~~~> interrupt\n"); - status = acpi_ec_read_status(ec); - advance_transaction(ec, status); - if (ec_transaction_done(ec) && (status & ACPI_EC_FLAG_IBF) == 0) + advance_transaction(ec, acpi_ec_read_status(ec)); + if (ec_transaction_done(ec) && + (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) == 0) { wake_up(&ec->wait); - ec_check_sci(ec, status); + ec_check_sci(ec, acpi_ec_read_status(ec)); + } return ACPI_INTERRUPT_HANDLED; } diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index 394ae89..04b0f00 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -56,7 +56,7 @@ ACPI_MODULE_NAME("pci_link"); static int acpi_pci_link_add(struct acpi_device *device); static int acpi_pci_link_remove(struct acpi_device *device, int type); -static struct acpi_device_id link_device_ids[] = { +static const struct acpi_device_id link_device_ids[] = { {"PNP0C0F", 0}, {"", 0}, }; diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 101cce3..64f55b6 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -46,7 +46,7 @@ static int acpi_pci_root_add(struct acpi_device *device); static int acpi_pci_root_remove(struct acpi_device *device, int type); static int acpi_pci_root_start(struct acpi_device *device); -static struct acpi_device_id root_device_ids[] = { +static const struct acpi_device_id root_device_ids[] = { {"PNP0A03", 0}, {"", 0}, }; diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 22b2979..0f30c3c 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -65,7 +65,7 @@ static int acpi_power_remove(struct acpi_device *device, int type); static int acpi_power_resume(struct acpi_device *device); static int acpi_power_open_fs(struct inode *inode, struct file *file); -static struct acpi_device_id power_device_ids[] = { +static const struct acpi_device_id power_device_ids[] = { {ACPI_POWER_HID, 0}, {"", 0}, }; diff --git a/drivers/acpi/power_meter.c b/drivers/acpi/power_meter.c index 2ef7030..dc4ffad 100644 --- a/drivers/acpi/power_meter.c +++ b/drivers/acpi/power_meter.c @@ -64,7 +64,7 @@ static int can_cap_in_hardware(void) return force_cap_on || cap_in_hardware; } -static struct acpi_device_id power_meter_ids[] = { +static const struct acpi_device_id power_meter_ids[] = { {"ACPI000D", 0}, {"", 0}, }; @@ -534,6 +534,7 @@ static void remove_domain_devices(struct acpi_power_meter_resource *resource) kfree(resource->domain_devices); kobject_put(resource->holders_dir); + resource->num_domain_devices = 0; } static int read_domain_devices(struct acpi_power_meter_resource *resource) @@ -740,7 +741,6 @@ skip_unsafe_cap: return res; error: - remove_domain_devices(resource); remove_attrs(resource); return res; } diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index d1676b1..7c0441f 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -305,6 +305,28 @@ static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr) pr->power.states[ACPI_STATE_C2].latency = acpi_gbl_FADT.C2latency; pr->power.states[ACPI_STATE_C3].latency = acpi_gbl_FADT.C3latency; + /* + * FADT specified C2 latency must be less than or equal to + * 100 microseconds. + */ + if (acpi_gbl_FADT.C2latency > ACPI_PROCESSOR_MAX_C2_LATENCY) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "C2 latency too large [%d]\n", acpi_gbl_FADT.C2latency)); + /* invalidate C2 */ + pr->power.states[ACPI_STATE_C2].address = 0; + } + + /* + * FADT supplied C3 latency must be less than or equal to + * 1000 microseconds. + */ + if (acpi_gbl_FADT.C3latency > ACPI_PROCESSOR_MAX_C3_LATENCY) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "C3 latency too large [%d]\n", acpi_gbl_FADT.C3latency)); + /* invalidate C3 */ + pr->power.states[ACPI_STATE_C3].address = 0; + } + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "lvl2[0x%08x] lvl3[0x%08x]\n", pr->power.states[ACPI_STATE_C2].address, @@ -494,33 +516,6 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr) return status; } -static void acpi_processor_power_verify_c2(struct acpi_processor_cx *cx) -{ - - if (!cx->address) - return; - - /* - * C2 latency must be less than or equal to 100 - * microseconds. - */ - else if (cx->latency > ACPI_PROCESSOR_MAX_C2_LATENCY) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "latency too large [%d]\n", cx->latency)); - return; - } - - /* - * Otherwise we've met all of our C2 requirements. - * Normalize the C2 latency to expidite policy - */ - cx->valid = 1; - - cx->latency_ticks = cx->latency; - - return; -} - static void acpi_processor_power_verify_c3(struct acpi_processor *pr, struct acpi_processor_cx *cx) { @@ -532,16 +527,6 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr, return; /* - * C3 latency must be less than or equal to 1000 - * microseconds. - */ - else if (cx->latency > ACPI_PROCESSOR_MAX_C3_LATENCY) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "latency too large [%d]\n", cx->latency)); - return; - } - - /* * PIIX4 Erratum #18: We don't support C3 when Type-F (fast) * DMA transfers are used by any ISA device to avoid livelock. * Note that we could disable Type-F DMA (as recommended by @@ -629,7 +614,10 @@ static int acpi_processor_power_verify(struct acpi_processor *pr) break; case ACPI_STATE_C2: - acpi_processor_power_verify_c2(cx); + if (!cx->address) + break; + cx->valid = 1; + cx->latency_ticks = cx->latency; /* Normalize latency */ break; case ACPI_STATE_C3: diff --git a/drivers/acpi/processor_pdc.c b/drivers/acpi/processor_pdc.c index 30e4dc0..7247819 100644 --- a/drivers/acpi/processor_pdc.c +++ b/drivers/acpi/processor_pdc.c @@ -144,6 +144,29 @@ void acpi_processor_set_pdc(acpi_handle handle) } EXPORT_SYMBOL_GPL(acpi_processor_set_pdc); +static int early_pdc_optin; +static int set_early_pdc_optin(const struct dmi_system_id *id) +{ + early_pdc_optin = 1; + return 0; +} + +static struct dmi_system_id __cpuinitdata early_pdc_optin_table[] = { + { + set_early_pdc_optin, "HP Envy", { + DMI_MATCH(DMI_BIOS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Envy") }, NULL}, + { + set_early_pdc_optin, "HP Pavilion dv6", { + DMI_MATCH(DMI_BIOS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv6") }, NULL}, + { + set_early_pdc_optin, "HP Pavilion dv7", { + DMI_MATCH(DMI_BIOS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv7") }, NULL}, + {}, +}; + static acpi_status early_init_pdc(acpi_handle handle, u32 lvl, void *context, void **rv) { @@ -151,7 +174,7 @@ early_init_pdc(acpi_handle handle, u32 lvl, void *context, void **rv) return AE_OK; } -void acpi_early_processor_set_pdc(void) +void __init acpi_early_processor_set_pdc(void) { /* * Check whether the system is DMI table. If yes, OSPM @@ -159,6 +182,13 @@ void acpi_early_processor_set_pdc(void) */ dmi_check_system(processor_idle_dmi_table); + /* + * Allow systems to opt-in to early _PDC evaluation. + */ + dmi_check_system(early_pdc_optin_table); + if (!early_pdc_optin) + return; + acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, early_init_pdc, NULL, NULL, NULL); diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c index 140c5c5..6deafb4 100644 --- a/drivers/acpi/processor_thermal.c +++ b/drivers/acpi/processor_thermal.c @@ -443,8 +443,7 @@ struct thermal_cooling_device_ops processor_cooling_ops = { #ifdef CONFIG_ACPI_PROCFS static int acpi_processor_limit_seq_show(struct seq_file *seq, void *offset) { - struct acpi_processor *pr = (struct acpi_processor *)seq->private; - + struct acpi_processor *pr = seq->private; if (!pr) goto end; diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index 52b9db8..b16ddbf 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -822,7 +822,10 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id) static void acpi_battery_remove(struct acpi_sbs *sbs, int id) { +#if defined(CONFIG_ACPI_SYSFS_POWER) || defined(CONFIG_ACPI_PROCFS_POWER) struct acpi_battery *battery = &sbs->battery[id]; +#endif + #ifdef CONFIG_ACPI_SYSFS_POWER if (battery->bat.dev) { if (battery->have_sysfs_alarm) diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c index d933980..fd09229 100644 --- a/drivers/acpi/sbshc.c +++ b/drivers/acpi/sbshc.c @@ -242,7 +242,7 @@ static int smbus_alarm(void *context) case ACPI_SBS_CHARGER: case ACPI_SBS_MANAGER: case ACPI_SBS_BATTERY: - acpi_os_execute(OSL_GPE_HANDLER, + acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_smbus_callback, hc); default:; } diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 72e76b4..b765790 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -78,6 +78,13 @@ MODULE_LICENSE("GPL"); static int brightness_switch_enabled = 1; module_param(brightness_switch_enabled, bool, 0644); +/* + * By default, we don't allow duplicate ACPI video bus devices + * under the same VGA controller + */ +static int allow_duplicates; +module_param(allow_duplicates, bool, 0644); + static int register_count = 0; static int acpi_video_bus_add(struct acpi_device *device); static int acpi_video_bus_remove(struct acpi_device *device, int type); @@ -2239,11 +2246,47 @@ static int acpi_video_resume(struct acpi_device *device) return AE_OK; } +static acpi_status +acpi_video_bus_match(acpi_handle handle, u32 level, void *context, + void **return_value) +{ + struct acpi_device *device = context; + struct acpi_device *sibling; + int result; + + if (handle == device->handle) + return AE_CTRL_TERMINATE; + + result = acpi_bus_get_device(handle, &sibling); + if (result) + return AE_OK; + + if (!strcmp(acpi_device_name(sibling), ACPI_VIDEO_BUS_NAME)) + return AE_ALREADY_EXISTS; + + return AE_OK; +} + static int acpi_video_bus_add(struct acpi_device *device) { struct acpi_video_bus *video; struct input_dev *input; int error; + acpi_status status; + + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, + device->parent->handle, 1, + acpi_video_bus_match, NULL, + device, NULL); + if (status == AE_ALREADY_EXISTS) { + printk(KERN_WARNING FW_BUG + "Duplicate ACPI video bus devices for the" + " same VGA controller, please try module " + "parameter \"video.allow_duplicates=1\"" + "if the current driver doesn't work.\n"); + if (!allow_duplicates) + return -ENODEV; + } video = kzalloc(sizeof(struct acpi_video_bus), GFP_KERNEL); if (!video) diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 0ea97c9..9f6cfac 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2028,8 +2028,9 @@ static void ata_eh_link_autopsy(struct ata_link *link) qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_OTHER); /* determine whether the command is worth retrying */ - if (!(qc->err_mask & AC_ERR_INVALID) && - ((qc->flags & ATA_QCFLAG_IO) || qc->err_mask != AC_ERR_DEV)) + if (qc->flags & ATA_QCFLAG_IO || + (!(qc->err_mask & AC_ERR_INVALID) && + qc->err_mask != AC_ERR_DEV)) qc->flags |= ATA_QCFLAG_RETRY; /* accumulate error info */ diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c index 090dd48..42ae452 100644 --- a/drivers/base/devtmpfs.c +++ b/drivers/base/devtmpfs.c @@ -354,6 +354,7 @@ int __init devtmpfs_init(void) { int err; struct vfsmount *mnt; + char options[] = "mode=0755"; err = register_filesystem(&dev_fs_type); if (err) { @@ -362,7 +363,7 @@ int __init devtmpfs_init(void) return err; } - mnt = kern_mount_data(&dev_fs_type, "mode=0755"); + mnt = kern_mount_data(&dev_fs_type, options); if (IS_ERR(mnt)) { err = PTR_ERR(mnt); printk(KERN_ERR "devtmpfs: unable to create devtmpfs %i\n", err); diff --git a/drivers/base/memory.c b/drivers/base/memory.c index ae6b6c4..bd02505 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -309,19 +309,17 @@ static SYSDEV_ATTR(removable, 0444, show_mem_removable, NULL); * Block size attribute stuff */ static ssize_t -print_block_size(struct sysdev_class *class, - struct sysdev_class_attribute *class_attr, - char *buf) +print_block_size(struct class *class, char *buf) { return sprintf(buf, "%#lx\n", (unsigned long)PAGES_PER_SECTION * PAGE_SIZE); } -static SYSDEV_CLASS_ATTR(block_size_bytes, 0444, print_block_size, NULL); +static CLASS_ATTR(block_size_bytes, 0444, print_block_size, NULL); static int block_size_init(void) { return sysfs_create_file(&memory_sysdev_class.kset.kobj, - &attr_block_size_bytes.attr); + &class_attr_block_size_bytes.attr); } /* @@ -332,9 +330,7 @@ static int block_size_init(void) */ #ifdef CONFIG_ARCH_MEMORY_PROBE static ssize_t -memory_probe_store(struct sysdev_class *class, - struct sysdev_class_attribute *class_attr, - const char *buf, size_t count) +memory_probe_store(struct class *class, const char *buf, size_t count) { u64 phys_addr; int nid; @@ -350,12 +346,12 @@ memory_probe_store(struct sysdev_class *class, return count; } -static SYSDEV_CLASS_ATTR(probe, S_IWUSR, NULL, memory_probe_store); +static CLASS_ATTR(probe, S_IWUSR, NULL, memory_probe_store); static int memory_probe_init(void) { return sysfs_create_file(&memory_sysdev_class.kset.kobj, - &attr_probe.attr); + &class_attr_probe.attr); } #else static inline int memory_probe_init(void) @@ -371,9 +367,7 @@ static inline int memory_probe_init(void) /* Soft offline a page */ static ssize_t -store_soft_offline_page(struct sysdev_class *class, - struct sysdev_class_attribute *class_attr, - const char *buf, size_t count) +store_soft_offline_page(struct class *class, const char *buf, size_t count) { int ret; u64 pfn; @@ -390,9 +384,7 @@ store_soft_offline_page(struct sysdev_class *class, /* Forcibly offline a page, including killing processes. */ static ssize_t -store_hard_offline_page(struct sysdev_class *class, - struct sysdev_class_attribute *class_attr, - const char *buf, size_t count) +store_hard_offline_page(struct class *class, const char *buf, size_t count) { int ret; u64 pfn; @@ -405,18 +397,18 @@ store_hard_offline_page(struct sysdev_class *class, return ret ? ret : count; } -static SYSDEV_CLASS_ATTR(soft_offline_page, 0644, NULL, store_soft_offline_page); -static SYSDEV_CLASS_ATTR(hard_offline_page, 0644, NULL, store_hard_offline_page); +static CLASS_ATTR(soft_offline_page, 0644, NULL, store_soft_offline_page); +static CLASS_ATTR(hard_offline_page, 0644, NULL, store_hard_offline_page); static __init int memory_fail_init(void) { int err; err = sysfs_create_file(&memory_sysdev_class.kset.kobj, - &attr_soft_offline_page.attr); + &class_attr_soft_offline_page.attr); if (!err) err = sysfs_create_file(&memory_sysdev_class.kset.kobj, - &attr_hard_offline_page.attr); + &class_attr_hard_offline_page.attr); return err; } #else diff --git a/drivers/block/drbd/Kconfig b/drivers/block/drbd/Kconfig index f4acd04..df09837 100644 --- a/drivers/block/drbd/Kconfig +++ b/drivers/block/drbd/Kconfig @@ -3,7 +3,7 @@ # comment "DRBD disabled because PROC_FS, INET or CONNECTOR not selected" - depends on !PROC_FS || !INET || !CONNECTOR + depends on PROC_FS='n' || INET='n' || CONNECTOR='n' config BLK_DEV_DRBD tristate "DRBD Distributed Replicated Block Device support" diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index c9755876..2bf3a6e 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1275,7 +1275,7 @@ struct bm_extent { #if DRBD_MAX_SECTORS_BM < DRBD_MAX_SECTORS_32 #define DRBD_MAX_SECTORS DRBD_MAX_SECTORS_BM #define DRBD_MAX_SECTORS_FLEX DRBD_MAX_SECTORS_BM -#elif !defined(CONFIG_LBD) && BITS_PER_LONG == 32 +#elif !defined(CONFIG_LBDAF) && BITS_PER_LONG == 32 #define DRBD_MAX_SECTORS DRBD_MAX_SECTORS_32 #define DRBD_MAX_SECTORS_FLEX DRBD_MAX_SECTORS_32 #else @@ -1371,10 +1371,9 @@ extern int is_valid_ar_handle(struct drbd_request *, sector_t); extern void drbd_suspend_io(struct drbd_conf *mdev); extern void drbd_resume_io(struct drbd_conf *mdev); extern char *ppsize(char *buf, unsigned long long size); -extern sector_t drbd_new_dev_size(struct drbd_conf *, - struct drbd_backing_dev *); +extern sector_t drbd_new_dev_size(struct drbd_conf *, struct drbd_backing_dev *, int); enum determine_dev_size { dev_size_error = -1, unchanged = 0, shrunk = 1, grew = 2 }; -extern enum determine_dev_size drbd_determin_dev_size(struct drbd_conf *) __must_hold(local); +extern enum determine_dev_size drbd_determin_dev_size(struct drbd_conf *, int force) __must_hold(local); extern void resync_after_online_grow(struct drbd_conf *); extern void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int) __must_hold(local); extern int drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 9348f33..e898ad9 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1298,6 +1298,7 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, dev_err(DEV, "Sending state in drbd_io_error() failed\n"); } + wait_event(mdev->misc_wait, !atomic_read(&mdev->local_cnt)); lc_destroy(mdev->resync); mdev->resync = NULL; lc_destroy(mdev->act_log); diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 4e0726a..1292e06 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -510,7 +510,7 @@ void drbd_resume_io(struct drbd_conf *mdev) * Returns 0 on success, negative return values indicate errors. * You should call drbd_md_sync() after calling this function. */ -enum determine_dev_size drbd_determin_dev_size(struct drbd_conf *mdev) __must_hold(local) +enum determine_dev_size drbd_determin_dev_size(struct drbd_conf *mdev, int force) __must_hold(local) { sector_t prev_first_sect, prev_size; /* previous meta location */ sector_t la_size; @@ -541,7 +541,7 @@ enum determine_dev_size drbd_determin_dev_size(struct drbd_conf *mdev) __must_ho /* TODO: should only be some assert here, not (re)init... */ drbd_md_set_sector_offsets(mdev, mdev->ldev); - size = drbd_new_dev_size(mdev, mdev->ldev); + size = drbd_new_dev_size(mdev, mdev->ldev, force); if (drbd_get_capacity(mdev->this_bdev) != size || drbd_bm_capacity(mdev) != size) { @@ -596,7 +596,7 @@ out: } sector_t -drbd_new_dev_size(struct drbd_conf *mdev, struct drbd_backing_dev *bdev) +drbd_new_dev_size(struct drbd_conf *mdev, struct drbd_backing_dev *bdev, int assume_peer_has_space) { sector_t p_size = mdev->p_size; /* partner's disk size. */ sector_t la_size = bdev->md.la_size_sect; /* last agreed size. */ @@ -606,6 +606,11 @@ drbd_new_dev_size(struct drbd_conf *mdev, struct drbd_backing_dev *bdev) m_size = drbd_get_max_capacity(bdev); + if (mdev->state.conn < C_CONNECTED && assume_peer_has_space) { + dev_warn(DEV, "Resize while not connected was forced by the user!\n"); + p_size = m_size; + } + if (p_size && m_size) { size = min_t(sector_t, p_size, m_size); } else { @@ -965,7 +970,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp /* Prevent shrinking of consistent devices ! */ if (drbd_md_test_flag(nbc, MDF_CONSISTENT) && - drbd_new_dev_size(mdev, nbc) < nbc->md.la_size_sect) { + drbd_new_dev_size(mdev, nbc, 0) < nbc->md.la_size_sect) { dev_warn(DEV, "refusing to truncate a consistent device\n"); retcode = ERR_DISK_TO_SMALL; goto force_diskless_dec; @@ -1052,7 +1057,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp !drbd_md_test_flag(mdev->ldev, MDF_CONNECTED_IND)) set_bit(USE_DEGR_WFC_T, &mdev->flags); - dd = drbd_determin_dev_size(mdev); + dd = drbd_determin_dev_size(mdev, 0); if (dd == dev_size_error) { retcode = ERR_NOMEM_BITMAP; goto force_diskless_dec; @@ -1271,7 +1276,7 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, goto fail; } - if (crypto_tfm_alg_type(crypto_hash_tfm(tfm)) != CRYPTO_ALG_TYPE_SHASH) { + if (!drbd_crypto_is_hash(crypto_hash_tfm(tfm))) { retcode = ERR_AUTH_ALG_ND; goto fail; } @@ -1504,7 +1509,7 @@ static int drbd_nl_resize(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, } mdev->ldev->dc.disk_size = (sector_t)rs.resize_size; - dd = drbd_determin_dev_size(mdev); + dd = drbd_determin_dev_size(mdev, rs.resize_force); drbd_md_sync(mdev); put_ldev(mdev); if (dd == dev_size_error) { diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 259c135..f22a528 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -878,9 +878,13 @@ retry: if (mdev->cram_hmac_tfm) { /* drbd_request_state(mdev, NS(conn, WFAuth)); */ - if (!drbd_do_auth(mdev)) { + switch (drbd_do_auth(mdev)) { + case -1: dev_err(DEV, "Authentication of peer failed\n"); return -1; + case 0: + dev_err(DEV, "Authentication of peer failed, trying again.\n"); + return 0; } } @@ -1201,10 +1205,11 @@ static int receive_Barrier(struct drbd_conf *mdev, struct p_header *h) case WO_bdev_flush: case WO_drain_io: - D_ASSERT(rv == FE_STILL_LIVE); - set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &mdev->current_epoch->flags); - drbd_wait_ee_list_empty(mdev, &mdev->active_ee); - rv = drbd_flush_after_epoch(mdev, mdev->current_epoch); + if (rv == FE_STILL_LIVE) { + set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &mdev->current_epoch->flags); + drbd_wait_ee_list_empty(mdev, &mdev->active_ee); + rv = drbd_flush_after_epoch(mdev, mdev->current_epoch); + } if (rv == FE_RECYCLED) return TRUE; @@ -2865,7 +2870,7 @@ static int receive_sizes(struct drbd_conf *mdev, struct p_header *h) /* Never shrink a device with usable data during connect. But allow online shrinking if we are connected. */ - if (drbd_new_dev_size(mdev, mdev->ldev) < + if (drbd_new_dev_size(mdev, mdev->ldev, 0) < drbd_get_capacity(mdev->this_bdev) && mdev->state.disk >= D_OUTDATED && mdev->state.conn < C_CONNECTED) { @@ -2880,7 +2885,7 @@ static int receive_sizes(struct drbd_conf *mdev, struct p_header *h) #undef min_not_zero if (get_ldev(mdev)) { - dd = drbd_determin_dev_size(mdev); + dd = drbd_determin_dev_size(mdev, 0); put_ldev(mdev); if (dd == dev_size_error) return FALSE; @@ -3830,10 +3835,17 @@ static int drbd_do_auth(struct drbd_conf *mdev) { dev_err(DEV, "This kernel was build without CONFIG_CRYPTO_HMAC.\n"); dev_err(DEV, "You need to disable 'cram-hmac-alg' in drbd.conf.\n"); - return 0; + return -1; } #else #define CHALLENGE_LEN 64 + +/* Return value: + 1 - auth succeeded, + 0 - failed, try again (network error), + -1 - auth failed, don't try again. +*/ + static int drbd_do_auth(struct drbd_conf *mdev) { char my_challenge[CHALLENGE_LEN]; /* 64 Bytes... */ @@ -3854,7 +3866,7 @@ static int drbd_do_auth(struct drbd_conf *mdev) (u8 *)mdev->net_conf->shared_secret, key_len); if (rv) { dev_err(DEV, "crypto_hash_setkey() failed with %d\n", rv); - rv = 0; + rv = -1; goto fail; } @@ -3877,14 +3889,14 @@ static int drbd_do_auth(struct drbd_conf *mdev) if (p.length > CHALLENGE_LEN*2) { dev_err(DEV, "expected AuthChallenge payload too big.\n"); - rv = 0; + rv = -1; goto fail; } peers_ch = kmalloc(p.length, GFP_NOIO); if (peers_ch == NULL) { dev_err(DEV, "kmalloc of peers_ch failed\n"); - rv = 0; + rv = -1; goto fail; } @@ -3900,7 +3912,7 @@ static int drbd_do_auth(struct drbd_conf *mdev) response = kmalloc(resp_size, GFP_NOIO); if (response == NULL) { dev_err(DEV, "kmalloc of response failed\n"); - rv = 0; + rv = -1; goto fail; } @@ -3910,7 +3922,7 @@ static int drbd_do_auth(struct drbd_conf *mdev) rv = crypto_hash_digest(&desc, &sg, sg.length, response); if (rv) { dev_err(DEV, "crypto_hash_digest() failed with %d\n", rv); - rv = 0; + rv = -1; goto fail; } @@ -3944,9 +3956,9 @@ static int drbd_do_auth(struct drbd_conf *mdev) } right_response = kmalloc(resp_size, GFP_NOIO); - if (response == NULL) { + if (right_response == NULL) { dev_err(DEV, "kmalloc of right_response failed\n"); - rv = 0; + rv = -1; goto fail; } @@ -3955,7 +3967,7 @@ static int drbd_do_auth(struct drbd_conf *mdev) rv = crypto_hash_digest(&desc, &sg, sg.length, right_response); if (rv) { dev_err(DEV, "crypto_hash_digest() failed with %d\n", rv); - rv = 0; + rv = -1; goto fail; } @@ -3964,6 +3976,8 @@ static int drbd_do_auth(struct drbd_conf *mdev) if (rv) dev_info(DEV, "Peer authenticated using %d bytes of '%s' HMAC\n", resp_size, mdev->net_conf->cram_hmac_alg); + else + rv = -1; fail: kfree(peers_ch); diff --git a/drivers/char/nozomi.c b/drivers/char/nozomi.c index 7d73cd4..2ad7d37 100644 --- a/drivers/char/nozomi.c +++ b/drivers/char/nozomi.c @@ -1651,10 +1651,10 @@ static void ntty_close(struct tty_struct *tty, struct file *file) dc->open_ttys--; port->count--; - tty_port_tty_set(port, NULL); if (port->count == 0) { DBG1("close: %d", nport->token_dl); + tty_port_tty_set(port, NULL); spin_lock_irqsave(&dc->spin_mutex, flags); dc->last_ier &= ~(nport->token_dl); writew(dc->last_ier, dc->reg_ier); diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index f15df40..c6f3b48 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -1951,8 +1951,8 @@ static int tty_fasync(int fd, struct file *filp, int on) pid = task_pid(current); type = PIDTYPE_PID; } - spin_unlock_irqrestore(&tty->ctrl_lock, flags); retval = __f_setown(filp, pid, type, 0); + spin_unlock_irqrestore(&tty->ctrl_lock, flags); if (retval) goto out; } else { diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index be62547..4b22feb 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -503,16 +503,15 @@ int dm_set_device_limits(struct dm_target *ti, struct dm_dev *dev, return 0; } - if (blk_stack_limits(limits, &q->limits, start << 9) < 0) - DMWARN("%s: target device %s is misaligned: " + if (bdev_stack_limits(limits, bdev, start) < 0) + DMWARN("%s: adding target device %s caused an alignment inconsistency: " "physical_block_size=%u, logical_block_size=%u, " "alignment_offset=%u, start=%llu", dm_device_name(ti->table->md), bdevname(bdev, b), q->limits.physical_block_size, q->limits.logical_block_size, q->limits.alignment_offset, - (unsigned long long) start << 9); - + (unsigned long long) start << SECTOR_SHIFT); /* * Check if merge fn is supported. @@ -1026,9 +1025,9 @@ combine_limits: * for the table. */ if (blk_stack_limits(limits, &ti_limits, 0) < 0) - DMWARN("%s: target device " + DMWARN("%s: adding target device " "(start sect %llu len %llu) " - "is misaligned", + "caused an alignment inconsistency", dm_device_name(table->md), (unsigned long long) ti->begin, (unsigned long long) ti->len); @@ -1080,15 +1079,6 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q, struct queue_limits *limits) { /* - * Each target device in the table has a data area that should normally - * be aligned such that the DM device's alignment_offset is 0. - * FIXME: Propagate alignment_offsets up the stack and warn of - * sub-optimal or inconsistent settings. - */ - limits->alignment_offset = 0; - limits->misaligned = 0; - - /* * Copy table's limits to the DM device's request_queue */ q->limits = *limits; diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index db32c25..f526e73 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -364,6 +364,7 @@ config EEEPC_LAPTOP select HWMON select LEDS_CLASS select NEW_LEDS + select INPUT_SPARSEKMAP ---help--- This driver supports the Fn-Fx keys on Eee PC laptops. diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 5838c69..e2be6bb 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -31,10 +31,12 @@ #include <acpi/acpi_bus.h> #include <linux/uaccess.h> #include <linux/input.h> +#include <linux/input/sparse-keymap.h> #include <linux/rfkill.h> #include <linux/pci.h> #include <linux/pci_hotplug.h> #include <linux/leds.h> +#include <linux/dmi.h> #define EEEPC_LAPTOP_VERSION "0.1" #define EEEPC_LAPTOP_NAME "Eee PC Hotkey Driver" @@ -48,6 +50,14 @@ MODULE_AUTHOR("Corentin Chary, Eric Cooper"); MODULE_DESCRIPTION(EEEPC_LAPTOP_NAME); MODULE_LICENSE("GPL"); +static bool hotplug_disabled; + +module_param(hotplug_disabled, bool, 0644); +MODULE_PARM_DESC(hotplug_disabled, + "Disable hotplug for wireless device. " + "If your laptop need that, please report to " + "acpi4asus-user@lists.sourceforge.net."); + /* * Definitions for Asus EeePC */ @@ -120,38 +130,28 @@ static const char *cm_setv[] = { NULL, NULL, "PBPS", "TPDS" }; -struct key_entry { - char type; - u8 code; - u16 keycode; -}; - -enum { KE_KEY, KE_END }; - static const struct key_entry eeepc_keymap[] = { - /* Sleep already handled via generic ACPI code */ - {KE_KEY, 0x10, KEY_WLAN }, - {KE_KEY, 0x11, KEY_WLAN }, - {KE_KEY, 0x12, KEY_PROG1 }, - {KE_KEY, 0x13, KEY_MUTE }, - {KE_KEY, 0x14, KEY_VOLUMEDOWN }, - {KE_KEY, 0x15, KEY_VOLUMEUP }, - {KE_KEY, 0x16, KEY_DISPLAY_OFF }, - {KE_KEY, 0x1a, KEY_COFFEE }, - {KE_KEY, 0x1b, KEY_ZOOM }, - {KE_KEY, 0x1c, KEY_PROG2 }, - {KE_KEY, 0x1d, KEY_PROG3 }, - {KE_KEY, NOTIFY_BRN_MIN, KEY_BRIGHTNESSDOWN }, - {KE_KEY, NOTIFY_BRN_MAX, KEY_BRIGHTNESSUP }, - {KE_KEY, 0x30, KEY_SWITCHVIDEOMODE }, - {KE_KEY, 0x31, KEY_SWITCHVIDEOMODE }, - {KE_KEY, 0x32, KEY_SWITCHVIDEOMODE }, - {KE_KEY, 0x37, KEY_F13 }, /* Disable Touchpad */ - {KE_KEY, 0x38, KEY_F14 }, - {KE_END, 0}, + { KE_KEY, 0x10, { KEY_WLAN } }, + { KE_KEY, 0x11, { KEY_WLAN } }, + { KE_KEY, 0x12, { KEY_PROG1 } }, + { KE_KEY, 0x13, { KEY_MUTE } }, + { KE_KEY, 0x14, { KEY_VOLUMEDOWN } }, + { KE_KEY, 0x15, { KEY_VOLUMEUP } }, + { KE_KEY, 0x16, { KEY_DISPLAY_OFF } }, + { KE_KEY, 0x1a, { KEY_COFFEE } }, + { KE_KEY, 0x1b, { KEY_ZOOM } }, + { KE_KEY, 0x1c, { KEY_PROG2 } }, + { KE_KEY, 0x1d, { KEY_PROG3 } }, + { KE_KEY, NOTIFY_BRN_MIN, { KEY_BRIGHTNESSDOWN } }, + { KE_KEY, NOTIFY_BRN_MAX, { KEY_BRIGHTNESSUP } }, + { KE_KEY, 0x30, { KEY_SWITCHVIDEOMODE } }, + { KE_KEY, 0x31, { KEY_SWITCHVIDEOMODE } }, + { KE_KEY, 0x32, { KEY_SWITCHVIDEOMODE } }, + { KE_KEY, 0x37, { KEY_F13 } }, /* Disable Touchpad */ + { KE_KEY, 0x38, { KEY_F14 } }, + { KE_END, 0 }, }; - /* * This is the main structure, we can use it to store useful information */ @@ -159,6 +159,8 @@ struct eeepc_laptop { acpi_handle handle; /* the handle of the acpi device */ u32 cm_supported; /* the control methods supported by this BIOS */ + bool cpufv_disabled; + bool hotplug_disabled; u16 event_count[128]; /* count for each event */ struct platform_device *platform_device; @@ -378,6 +380,8 @@ static ssize_t store_cpufv(struct device *dev, struct eeepc_cpufv c; int rv, value; + if (eeepc->cpufv_disabled) + return -EPERM; if (get_cpufv(eeepc, &c)) return -ENODEV; rv = parse_arg(buf, count, &value); @@ -389,6 +393,41 @@ static ssize_t store_cpufv(struct device *dev, return rv; } +static ssize_t show_cpufv_disabled(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct eeepc_laptop *eeepc = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", eeepc->cpufv_disabled); +} + +static ssize_t store_cpufv_disabled(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct eeepc_laptop *eeepc = dev_get_drvdata(dev); + int rv, value; + + rv = parse_arg(buf, count, &value); + if (rv < 0) + return rv; + + switch (value) { + case 0: + if (eeepc->cpufv_disabled) + pr_warning("cpufv enabled (not officially supported " + "on this model)\n"); + eeepc->cpufv_disabled = false; + return rv; + case 1: + return -EPERM; + default: + return -EINVAL; + } +} + + static struct device_attribute dev_attr_cpufv = { .attr = { .name = "cpufv", @@ -404,12 +443,22 @@ static struct device_attribute dev_attr_available_cpufv = { .show = show_available_cpufv }; +static struct device_attribute dev_attr_cpufv_disabled = { + .attr = { + .name = "cpufv_disabled", + .mode = 0644 }, + .show = show_cpufv_disabled, + .store = store_cpufv_disabled +}; + + static struct attribute *platform_attributes[] = { &dev_attr_camera.attr, &dev_attr_cardr.attr, &dev_attr_disp.attr, &dev_attr_cpufv.attr, &dev_attr_available_cpufv.attr, + &dev_attr_cpufv_disabled.attr, NULL }; @@ -796,6 +845,9 @@ static int eeepc_rfkill_init(struct eeepc_laptop *eeepc) if (result && result != -ENODEV) goto exit; + if (eeepc->hotplug_disabled) + return 0; + result = eeepc_setup_pci_hotplug(eeepc); /* * If we get -EBUSY then something else is handling the PCI hotplug - @@ -1090,120 +1142,42 @@ static void eeepc_backlight_exit(struct eeepc_laptop *eeepc) /* * Input device (i.e. hotkeys) */ -static struct key_entry *eeepc_get_entry_by_scancode( - struct eeepc_laptop *eeepc, - int code) +static int eeepc_input_init(struct eeepc_laptop *eeepc) { - struct key_entry *key; + struct input_dev *input; + int error; - for (key = eeepc->keymap; key->type != KE_END; key++) - if (code == key->code) - return key; - - return NULL; -} - -static void eeepc_input_notify(struct eeepc_laptop *eeepc, int event) -{ - static struct key_entry *key; - - key = eeepc_get_entry_by_scancode(eeepc, event); - if (key) { - switch (key->type) { - case KE_KEY: - input_report_key(eeepc->inputdev, key->keycode, - 1); - input_sync(eeepc->inputdev); - input_report_key(eeepc->inputdev, key->keycode, - 0); - input_sync(eeepc->inputdev); - break; - } + input = input_allocate_device(); + if (!input) { + pr_info("Unable to allocate input device\n"); + return -ENOMEM; } -} - -static struct key_entry *eeepc_get_entry_by_keycode( - struct eeepc_laptop *eeepc, int code) -{ - struct key_entry *key; - - for (key = eeepc->keymap; key->type != KE_END; key++) - if (code == key->keycode && key->type == KE_KEY) - return key; - return NULL; -} + input->name = "Asus EeePC extra buttons"; + input->phys = EEEPC_LAPTOP_FILE "/input0"; + input->id.bustype = BUS_HOST; + input->dev.parent = &eeepc->platform_device->dev; -static int eeepc_getkeycode(struct input_dev *dev, int scancode, int *keycode) -{ - struct eeepc_laptop *eeepc = input_get_drvdata(dev); - struct key_entry *key = eeepc_get_entry_by_scancode(eeepc, scancode); - - if (key && key->type == KE_KEY) { - *keycode = key->keycode; - return 0; + error = sparse_keymap_setup(input, eeepc_keymap, NULL); + if (error) { + pr_err("Unable to setup input device keymap\n"); + goto err_free_dev; } - return -EINVAL; -} - -static int eeepc_setkeycode(struct input_dev *dev, int scancode, int keycode) -{ - struct eeepc_laptop *eeepc = input_get_drvdata(dev); - struct key_entry *key; - int old_keycode; - - if (keycode < 0 || keycode > KEY_MAX) - return -EINVAL; - - key = eeepc_get_entry_by_scancode(eeepc, scancode); - if (key && key->type == KE_KEY) { - old_keycode = key->keycode; - key->keycode = keycode; - set_bit(keycode, dev->keybit); - if (!eeepc_get_entry_by_keycode(eeepc, old_keycode)) - clear_bit(old_keycode, dev->keybit); - return 0; + error = input_register_device(input); + if (error) { + pr_err("Unable to register input device\n"); + goto err_free_keymap; } - return -EINVAL; -} - -static int eeepc_input_init(struct eeepc_laptop *eeepc) -{ - const struct key_entry *key; - int result; - - eeepc->inputdev = input_allocate_device(); - if (!eeepc->inputdev) { - pr_info("Unable to allocate input device\n"); - return -ENOMEM; - } - eeepc->inputdev->name = "Asus EeePC extra buttons"; - eeepc->inputdev->dev.parent = &eeepc->platform_device->dev; - eeepc->inputdev->phys = EEEPC_LAPTOP_FILE "/input0"; - eeepc->inputdev->id.bustype = BUS_HOST; - eeepc->inputdev->getkeycode = eeepc_getkeycode; - eeepc->inputdev->setkeycode = eeepc_setkeycode; - input_set_drvdata(eeepc->inputdev, eeepc); - - eeepc->keymap = kmemdup(eeepc_keymap, sizeof(eeepc_keymap), - GFP_KERNEL); - for (key = eeepc_keymap; key->type != KE_END; key++) { - switch (key->type) { - case KE_KEY: - set_bit(EV_KEY, eeepc->inputdev->evbit); - set_bit(key->keycode, eeepc->inputdev->keybit); - break; - } - } - result = input_register_device(eeepc->inputdev); - if (result) { - pr_info("Unable to register input device\n"); - input_free_device(eeepc->inputdev); - return result; - } + eeepc->inputdev = input; return 0; + + err_free_keymap: + sparse_keymap_free(input); + err_free_dev: + input_free_device(input); + return error; } static void eeepc_input_exit(struct eeepc_laptop *eeepc) @@ -1253,11 +1227,59 @@ static void eeepc_acpi_notify(struct acpi_device *device, u32 event) * event will be desired value (or else ignored) */ } - eeepc_input_notify(eeepc, event); + sparse_keymap_report_event(eeepc->inputdev, event, + 1, true); } } else { /* Everything else is a bona-fide keypress event */ - eeepc_input_notify(eeepc, event); + sparse_keymap_report_event(eeepc->inputdev, event, 1, true); + } +} + +static void eeepc_dmi_check(struct eeepc_laptop *eeepc) +{ + const char *model; + + model = dmi_get_system_info(DMI_PRODUCT_NAME); + if (!model) + return; + + /* + * Blacklist for setting cpufv (cpu speed). + * + * EeePC 4G ("701") implements CFVS, but it is not supported + * by the pre-installed OS, and the original option to change it + * in the BIOS setup screen was removed in later versions. + * + * Judging by the lack of "Super Hybrid Engine" on Asus product pages, + * this applies to all "701" models (4G/4G Surf/2G Surf). + * + * So Asus made a deliberate decision not to support it on this model. + * We have several reports that using it can cause the system to hang + * + * The hang has also been reported on a "702" (Model name "8G"?). + * + * We avoid dmi_check_system() / dmi_match(), because they use + * substring matching. We don't want to affect the "701SD" + * and "701SDX" models, because they do support S.H.E. + */ + if (strcmp(model, "701") == 0 || strcmp(model, "702") == 0) { + eeepc->cpufv_disabled = true; + pr_info("model %s does not officially support setting cpu " + "speed\n", model); + pr_info("cpufv disabled to avoid instability\n"); + } + + /* + * Blacklist for wlan hotplug + * + * Eeepc 1005HA doesn't work like others models and don't need the + * hotplug code. In fact, current hotplug code seems to unplug another + * device... + */ + if (strcmp(model, "1005HA") == 0 || strcmp(model, "1201N") == 0) { + eeepc->hotplug_disabled = true; + pr_info("wlan hotplug disabled\n"); } } @@ -1342,6 +1364,10 @@ static int __devinit eeepc_acpi_add(struct acpi_device *device) strcpy(acpi_device_class(device), EEEPC_ACPI_CLASS); device->driver_data = eeepc; + eeepc->hotplug_disabled = hotplug_disabled; + + eeepc_dmi_check(eeepc); + result = eeepc_acpi_init(eeepc, device); if (result) goto fail_platform; @@ -1452,10 +1478,12 @@ static int __init eeepc_laptop_init(void) result = acpi_bus_register_driver(&eeepc_acpi_driver); if (result < 0) goto fail_acpi_driver; + if (!eeepc_device_present) { result = -ENODEV; goto fail_no_device; } + return 0; fail_no_device: diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 5af5334..3f71a60 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -1201,9 +1201,12 @@ static void sony_nc_rfkill_setup(struct acpi_device *device) /* the buffer is filled with magic numbers describing the devices * available, 0xff terminates the enumeration */ - while ((dev_code = *(device_enum->buffer.pointer + i)) != 0xff && - i < device_enum->buffer.length) { - i++; + for (i = 0; i < device_enum->buffer.length; i++) { + + dev_code = *(device_enum->buffer.pointer + i); + if (dev_code == 0xff) + break; + dprintk("Radio devices, looking at 0x%.2x\n", dev_code); if (dev_code == 0 && !sony_rfkill_devices[SONY_WIFI]) diff --git a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c index b5496a1..24485cc 100644 --- a/drivers/serial/8250_pnp.c +++ b/drivers/serial/8250_pnp.c @@ -328,15 +328,7 @@ static const struct pnp_device_id pnp_dev_table[] = { /* U.S. Robotics 56K Voice INT PnP*/ { "USR9190", 0 }, /* Wacom tablets */ - { "WACF004", 0 }, - { "WACF005", 0 }, - { "WACF006", 0 }, - { "WACF007", 0 }, - { "WACF008", 0 }, - { "WACF009", 0 }, - { "WACF00A", 0 }, - { "WACF00B", 0 }, - { "WACF00C", 0 }, + { "WACFXXX", 0 }, /* Compaq touchscreen */ { "FPI2002", 0 }, /* Fujitsu Stylistic touchscreens */ diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index 18130f1..60d665a 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -1088,7 +1088,7 @@ imx_console_get_options(struct imx_port *sport, int *baud, int *parity, int *bits) { - if ( readl(sport->port.membase + UCR1) | UCR1_UARTEN ) { + if (readl(sport->port.membase + UCR1) & UCR1_UARTEN) { /* ok, the port was enabled */ unsigned int ucr2, ubir,ubmr, uartclk; unsigned int baud_raw; diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index 047530b..7f28307 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -385,13 +385,20 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, } /* - * As a last resort, if the quotient is zero, - * default to 9600 bps + * As a last resort, if the range cannot be met then clip to + * the nearest chip supported rate. */ - if (!hung_up) - tty_termios_encode_baud_rate(termios, 9600, 9600); + if (!hung_up) { + if (baud <= min) + tty_termios_encode_baud_rate(termios, + min + 1, min + 1); + else + tty_termios_encode_baud_rate(termios, + max - 1, max - 1); + } } - + /* Should never happen */ + WARN_ON(1); return 0; } @@ -2006,12 +2013,6 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport) mutex_lock(&port->mutex); - if (!console_suspend_enabled && uart_console(uport)) { - /* we're going to avoid suspending serial console */ - mutex_unlock(&port->mutex); - return 0; - } - tty_dev = device_find_child(uport->dev, &match, serial_match_port); if (device_may_wakeup(tty_dev)) { enable_irq_wake(uport->irq); @@ -2019,20 +2020,23 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport) mutex_unlock(&port->mutex); return 0; } - uport->suspended = 1; + if (console_suspend_enabled || !uart_console(uport)) + uport->suspended = 1; if (port->flags & ASYNC_INITIALIZED) { const struct uart_ops *ops = uport->ops; int tries; - set_bit(ASYNCB_SUSPENDED, &port->flags); - clear_bit(ASYNCB_INITIALIZED, &port->flags); + if (console_suspend_enabled || !uart_console(uport)) { + set_bit(ASYNCB_SUSPENDED, &port->flags); + clear_bit(ASYNCB_INITIALIZED, &port->flags); - spin_lock_irq(&uport->lock); - ops->stop_tx(uport); - ops->set_mctrl(uport, 0); - ops->stop_rx(uport); - spin_unlock_irq(&uport->lock); + spin_lock_irq(&uport->lock); + ops->stop_tx(uport); + ops->set_mctrl(uport, 0); + ops->stop_rx(uport); + spin_unlock_irq(&uport->lock); + } /* * Wait for the transmitter to empty. @@ -2047,16 +2051,18 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport) drv->dev_name, drv->tty_driver->name_base + uport->line); - ops->shutdown(uport); + if (console_suspend_enabled || !uart_console(uport)) + ops->shutdown(uport); } /* * Disable the console device before suspending. */ - if (uart_console(uport)) + if (console_suspend_enabled && uart_console(uport)) console_stop(uport->cons); - uart_change_pm(state, 3); + if (console_suspend_enabled || !uart_console(uport)) + uart_change_pm(state, 3); mutex_unlock(&port->mutex); @@ -2073,29 +2079,6 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) mutex_lock(&port->mutex); - if (!console_suspend_enabled && uart_console(uport)) { - /* no need to resume serial console, it wasn't suspended */ - /* - * First try to use the console cflag setting. - */ - memset(&termios, 0, sizeof(struct ktermios)); - termios.c_cflag = uport->cons->cflag; - /* - * If that's unset, use the tty termios setting. - */ - if (termios.c_cflag == 0) - termios = *state->port.tty->termios; - else { - termios.c_ispeed = termios.c_ospeed = - tty_termios_input_baud_rate(&termios); - termios.c_ispeed = termios.c_ospeed = - tty_termios_baud_rate(&termios); - } - uport->ops->set_termios(uport, &termios, NULL); - mutex_unlock(&port->mutex); - return 0; - } - tty_dev = device_find_child(uport->dev, &match, serial_match_port); if (!uport->suspended && device_may_wakeup(tty_dev)) { disable_irq_wake(uport->irq); @@ -2121,21 +2104,23 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) spin_lock_irq(&uport->lock); ops->set_mctrl(uport, 0); spin_unlock_irq(&uport->lock); - ret = ops->startup(uport); - if (ret == 0) { - uart_change_speed(state, NULL); - spin_lock_irq(&uport->lock); - ops->set_mctrl(uport, uport->mctrl); - ops->start_tx(uport); - spin_unlock_irq(&uport->lock); - set_bit(ASYNCB_INITIALIZED, &port->flags); - } else { - /* - * Failed to resume - maybe hardware went away? - * Clear the "initialized" flag so we won't try - * to call the low level drivers shutdown method. - */ - uart_shutdown(state); + if (console_suspend_enabled || !uart_console(uport)) { + ret = ops->startup(uport); + if (ret == 0) { + uart_change_speed(state, NULL); + spin_lock_irq(&uport->lock); + ops->set_mctrl(uport, uport->mctrl); + ops->start_tx(uport); + spin_unlock_irq(&uport->lock); + set_bit(ASYNCB_INITIALIZED, &port->flags); + } else { + /* + * Failed to resume - maybe hardware went away? + * Clear the "initialized" flag so we won't try + * to call the low level drivers shutdown method. + */ + uart_shutdown(state); + } } clear_bit(ASYNCB_SUSPENDED, &port->flags); diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index 0ee7239..df85440 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c @@ -146,7 +146,8 @@ static void quirk_wakeup_oxsemi(struct pcmcia_device *link) { struct serial_info *info = link->priv; - outb(12, info->c950ctrl + 1); + if (info->c950ctrl) + outb(12, info->c950ctrl + 1); } /* request_region? oxsemi branch does no request_region too... */ diff --git a/drivers/staging/asus_oled/asus_oled.c b/drivers/staging/asus_oled/asus_oled.c index f4c2657..43c57b7 100644 --- a/drivers/staging/asus_oled/asus_oled.c +++ b/drivers/staging/asus_oled/asus_oled.c @@ -194,9 +194,11 @@ static ssize_t set_enabled(struct device *dev, struct device_attribute *attr, { struct usb_interface *intf = to_usb_interface(dev); struct asus_oled_dev *odev = usb_get_intfdata(intf); - int temp = strict_strtoul(buf, 10, NULL); + unsigned long value; + if (strict_strtoul(buf, 10, &value)) + return -EINVAL; - enable_oled(odev, temp); + enable_oled(odev, value); return count; } @@ -207,10 +209,12 @@ static ssize_t class_set_enabled(struct device *device, { struct asus_oled_dev *odev = (struct asus_oled_dev *) dev_get_drvdata(device); + unsigned long value; - int temp = strict_strtoul(buf, 10, NULL); + if (strict_strtoul(buf, 10, &value)) + return -EINVAL; - enable_oled(odev, temp); + enable_oled(odev, value); return count; } diff --git a/drivers/staging/et131x/et1310_address_map.h b/drivers/staging/et131x/et1310_address_map.h index 6da843c..e715e4d 100644 --- a/drivers/staging/et131x/et1310_address_map.h +++ b/drivers/staging/et131x/et1310_address_map.h @@ -203,11 +203,14 @@ typedef struct _GLOBAL_t { /* Location: */ * 9-0: pr ndes */ -#define ET_DMA10_MASK 0x3FF /* 10 bit mask for DMA10W types */ -#define ET_DMA10_WRAP 0x400 -#define ET_DMA4_MASK 0x00F /* 4 bit mask for DMA4W types */ -#define ET_DMA4_WRAP 0x010 - +#define ET_DMA12_MASK 0x0FFF /* 12 bit mask for DMA12W types */ +#define ET_DMA12_WRAP 0x1000 +#define ET_DMA10_MASK 0x03FF /* 10 bit mask for DMA10W types */ +#define ET_DMA10_WRAP 0x0400 +#define ET_DMA4_MASK 0x000F /* 4 bit mask for DMA4W types */ +#define ET_DMA4_WRAP 0x0010 + +#define INDEX12(x) ((x) & ET_DMA12_MASK) #define INDEX10(x) ((x) & ET_DMA10_MASK) #define INDEX4(x) ((x) & ET_DMA4_MASK) @@ -216,6 +219,11 @@ extern inline void add_10bit(u32 *v, int n) *v = INDEX10(*v + n) | (*v & ET_DMA10_WRAP); } +extern inline void add_12bit(u32 *v, int n) +{ + *v = INDEX12(*v + n) | (*v & ET_DMA12_WRAP); +} + /* * 10bit DMA with wrap * txdma tx queue write address reg in txdma address map at 0x1010 diff --git a/drivers/staging/et131x/et1310_rx.c b/drivers/staging/et131x/et1310_rx.c index 3ddc9b1..81c1a74 100644 --- a/drivers/staging/et131x/et1310_rx.c +++ b/drivers/staging/et131x/et1310_rx.c @@ -831,10 +831,10 @@ PMP_RFD nic_rx_pkts(struct et131x_adapter *etdev) /* Indicate that we have used this PSR entry. */ /* FIXME wrap 12 */ - rx_local->local_psr_full = (rx_local->local_psr_full + 1) & 0xFFF; - if (rx_local->local_psr_full > rx_local->PsrNumEntries - 1) { + add_12bit(&rx_local->local_psr_full, 1); + if ((rx_local->local_psr_full & 0xFFF) > rx_local->PsrNumEntries - 1) { /* Clear psr full and toggle the wrap bit */ - rx_local->local_psr_full &= 0xFFF; + rx_local->local_psr_full &= ~0xFFF; rx_local->local_psr_full ^= 0x1000; } diff --git a/drivers/staging/hv/Hv.c b/drivers/staging/hv/Hv.c index c5b6613..c2809f2 100644 --- a/drivers/staging/hv/Hv.c +++ b/drivers/staging/hv/Hv.c @@ -386,7 +386,7 @@ u16 HvSignalEvent(void) * retrieve the initialized message and event pages. Otherwise, we create and * initialize the message and event pages. */ -int HvSynicInit(u32 irqVector) +void HvSynicInit(void *irqarg) { u64 version; union hv_synic_simp simp; @@ -394,13 +394,14 @@ int HvSynicInit(u32 irqVector) union hv_synic_sint sharedSint; union hv_synic_scontrol sctrl; u64 guestID; - int ret = 0; + u32 irqVector = *((u32 *)(irqarg)); + int cpu = smp_processor_id(); DPRINT_ENTER(VMBUS); if (!gHvContext.HypercallPage) { DPRINT_EXIT(VMBUS); - return ret; + return; } /* Check the version */ @@ -425,27 +426,27 @@ int HvSynicInit(u32 irqVector) */ rdmsrl(HV_X64_MSR_GUEST_OS_ID, guestID); if (guestID == HV_LINUX_GUEST_ID) { - gHvContext.synICMessagePage[0] = + gHvContext.synICMessagePage[cpu] = phys_to_virt(simp.BaseSimpGpa << PAGE_SHIFT); - gHvContext.synICEventPage[0] = + gHvContext.synICEventPage[cpu] = phys_to_virt(siefp.BaseSiefpGpa << PAGE_SHIFT); } else { DPRINT_ERR(VMBUS, "unknown guest id!!"); goto Cleanup; } DPRINT_DBG(VMBUS, "MAPPED: Simp: %p, Sifep: %p", - gHvContext.synICMessagePage[0], - gHvContext.synICEventPage[0]); + gHvContext.synICMessagePage[cpu], + gHvContext.synICEventPage[cpu]); } else { - gHvContext.synICMessagePage[0] = osd_PageAlloc(1); - if (gHvContext.synICMessagePage[0] == NULL) { + gHvContext.synICMessagePage[cpu] = (void *)get_zeroed_page(GFP_ATOMIC); + if (gHvContext.synICMessagePage[cpu] == NULL) { DPRINT_ERR(VMBUS, "unable to allocate SYNIC message page!!"); goto Cleanup; } - gHvContext.synICEventPage[0] = osd_PageAlloc(1); - if (gHvContext.synICEventPage[0] == NULL) { + gHvContext.synICEventPage[cpu] = (void *)get_zeroed_page(GFP_ATOMIC); + if (gHvContext.synICEventPage[cpu] == NULL) { DPRINT_ERR(VMBUS, "unable to allocate SYNIC event page!!"); goto Cleanup; @@ -454,7 +455,7 @@ int HvSynicInit(u32 irqVector) /* Setup the Synic's message page */ rdmsrl(HV_X64_MSR_SIMP, simp.AsUINT64); simp.SimpEnabled = 1; - simp.BaseSimpGpa = virt_to_phys(gHvContext.synICMessagePage[0]) + simp.BaseSimpGpa = virt_to_phys(gHvContext.synICMessagePage[cpu]) >> PAGE_SHIFT; DPRINT_DBG(VMBUS, "HV_X64_MSR_SIMP msr set to: %llx", @@ -465,7 +466,7 @@ int HvSynicInit(u32 irqVector) /* Setup the Synic's event page */ rdmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64); siefp.SiefpEnabled = 1; - siefp.BaseSiefpGpa = virt_to_phys(gHvContext.synICEventPage[0]) + siefp.BaseSiefpGpa = virt_to_phys(gHvContext.synICEventPage[cpu]) >> PAGE_SHIFT; DPRINT_DBG(VMBUS, "HV_X64_MSR_SIEFP msr set to: %llx", @@ -501,32 +502,30 @@ int HvSynicInit(u32 irqVector) DPRINT_EXIT(VMBUS); - return ret; + return; Cleanup: - ret = -1; - if (gHvContext.GuestId == HV_LINUX_GUEST_ID) { - if (gHvContext.synICEventPage[0]) - osd_PageFree(gHvContext.synICEventPage[0], 1); + if (gHvContext.synICEventPage[cpu]) + osd_PageFree(gHvContext.synICEventPage[cpu], 1); - if (gHvContext.synICMessagePage[0]) - osd_PageFree(gHvContext.synICMessagePage[0], 1); + if (gHvContext.synICMessagePage[cpu]) + osd_PageFree(gHvContext.synICMessagePage[cpu], 1); } DPRINT_EXIT(VMBUS); - - return ret; + return; } /** * HvSynicCleanup - Cleanup routine for HvSynicInit(). */ -void HvSynicCleanup(void) +void HvSynicCleanup(void *arg) { union hv_synic_sint sharedSint; union hv_synic_simp simp; union hv_synic_siefp siefp; + int cpu = smp_processor_id(); DPRINT_ENTER(VMBUS); @@ -539,6 +538,7 @@ void HvSynicCleanup(void) sharedSint.Masked = 1; + /* Need to correctly cleanup in the case of SMP!!! */ /* Disable the interrupt */ wrmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, sharedSint.AsUINT64); @@ -560,8 +560,8 @@ void HvSynicCleanup(void) wrmsrl(HV_X64_MSR_SIEFP, siefp.AsUINT64); - osd_PageFree(gHvContext.synICMessagePage[0], 1); - osd_PageFree(gHvContext.synICEventPage[0], 1); + osd_PageFree(gHvContext.synICMessagePage[cpu], 1); + osd_PageFree(gHvContext.synICEventPage[cpu], 1); } DPRINT_EXIT(VMBUS); diff --git a/drivers/staging/hv/Hv.h b/drivers/staging/hv/Hv.h index 5379e4b..fce4b5c 100644 --- a/drivers/staging/hv/Hv.h +++ b/drivers/staging/hv/Hv.h @@ -93,7 +93,7 @@ static const struct hv_guid VMBUS_SERVICE_ID = { }, }; -#define MAX_NUM_CPUS 1 +#define MAX_NUM_CPUS 32 struct hv_input_signal_event_buffer { @@ -137,8 +137,8 @@ extern u16 HvPostMessage(union hv_connection_id connectionId, extern u16 HvSignalEvent(void); -extern int HvSynicInit(u32 irqVector); +extern void HvSynicInit(void *irqarg); -extern void HvSynicCleanup(void); +extern void HvSynicCleanup(void *arg); #endif /* __HV_H__ */ diff --git a/drivers/staging/hv/Vmbus.c b/drivers/staging/hv/Vmbus.c index a4dd06f..35a023e 100644 --- a/drivers/staging/hv/Vmbus.c +++ b/drivers/staging/hv/Vmbus.c @@ -129,7 +129,7 @@ static int VmbusOnDeviceAdd(struct hv_device *dev, void *AdditionalInfo) /* strcpy(dev->name, "vmbus"); */ /* SynIC setup... */ - ret = HvSynicInit(*irqvector); + on_each_cpu(HvSynicInit, (void *)irqvector, 1); /* Connect to VMBus in the root partition */ ret = VmbusConnect(); @@ -150,7 +150,7 @@ static int VmbusOnDeviceRemove(struct hv_device *dev) DPRINT_ENTER(VMBUS); VmbusChannelReleaseUnattachedChannels(); VmbusDisconnect(); - HvSynicCleanup(); + on_each_cpu(HvSynicCleanup, NULL, 1); DPRINT_EXIT(VMBUS); return ret; @@ -173,7 +173,8 @@ static void VmbusOnCleanup(struct hv_driver *drv) */ static void VmbusOnMsgDPC(struct hv_driver *drv) { - void *page_addr = gHvContext.synICMessagePage[0]; + int cpu = smp_processor_id(); + void *page_addr = gHvContext.synICMessagePage[cpu]; struct hv_message *msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT; struct hv_message *copied; @@ -230,11 +231,12 @@ static void VmbusOnEventDPC(struct hv_driver *drv) static int VmbusOnISR(struct hv_driver *drv) { int ret = 0; + int cpu = smp_processor_id(); void *page_addr; struct hv_message *msg; union hv_synic_event_flags *event; - page_addr = gHvContext.synICMessagePage[0]; + page_addr = gHvContext.synICMessagePage[cpu]; msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT; DPRINT_ENTER(VMBUS); @@ -248,7 +250,7 @@ static int VmbusOnISR(struct hv_driver *drv) } /* TODO: Check if there are events to be process */ - page_addr = gHvContext.synICEventPage[0]; + page_addr = gHvContext.synICEventPage[cpu]; event = (union hv_synic_event_flags *)page_addr + VMBUS_MESSAGE_SINT; /* Since we are a child, we only need to check bit 0 */ diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index 96f1171..355dffc 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -494,7 +494,7 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, return 0; /* allocate 2^1 pages = 8K (on i386); * should be more than enough for one device */ - pages_start = (char *)__get_free_pages(GFP_KERNEL, 1); + pages_start = (char *)__get_free_pages(GFP_NOIO, 1); if (!pages_start) return -ENOMEM; diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 0495fa6..80995ef 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1684,6 +1684,24 @@ int usb_hcd_alloc_bandwidth(struct usb_device *udev, } } if (cur_alt && new_alt) { + struct usb_interface *iface = usb_ifnum_to_if(udev, + cur_alt->desc.bInterfaceNumber); + + if (iface->resetting_device) { + /* + * The USB core just reset the device, so the xHCI host + * and the device will think alt setting 0 is installed. + * However, the USB core will pass in the alternate + * setting installed before the reset as cur_alt. Dig + * out the alternate setting 0 structure, or the first + * alternate setting if a broken device doesn't have alt + * setting 0. + */ + cur_alt = usb_altnum_to_altsetting(iface, 0); + if (!cur_alt) + cur_alt = &iface->altsetting[0]; + } + /* Drop all the endpoints in the current alt setting */ for (i = 0; i < cur_alt->desc.bNumEndpoints; i++) { ret = hcd->driver->drop_endpoint(hcd, udev, diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 0cec6ca..35cc8b9 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -3347,6 +3347,9 @@ static void hub_events(void) USB_PORT_FEAT_C_SUSPEND); udev = hdev->children[i-1]; if (udev) { + /* TRSMRCY = 10 msec */ + msleep(10); + usb_lock_device(udev); ret = remote_wakeup(hdev-> children[i-1]); @@ -3692,19 +3695,14 @@ static int usb_reset_and_verify_device(struct usb_device *udev) usb_enable_interface(udev, intf, true); ret = 0; } else { - /* We've just reset the device, so it will think alt - * setting 0 is installed. For usb_set_interface() to - * work properly, we need to set the current alternate - * interface setting to 0 (or the first alt setting, if - * the device doesn't have alt setting 0). + /* Let the bandwidth allocation function know that this + * device has been reset, and it will have to use + * alternate setting 0 as the current alternate setting. */ - intf->cur_altsetting = - usb_find_alt_setting(config, i, 0); - if (!intf->cur_altsetting) - intf->cur_altsetting = - &config->intf_cache[i]->altsetting[0]; + intf->resetting_device = 1; ret = usb_set_interface(udev, desc->bInterfaceNumber, desc->bAlternateSetting); + intf->resetting_device = 0; } if (ret < 0) { dev_err(&udev->dev, "failed to restore interface %d " diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 1b99484..9bc95fe 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -906,11 +906,11 @@ char *usb_cache_string(struct usb_device *udev, int index) if (index <= 0) return NULL; - buf = kmalloc(MAX_USB_STRING_SIZE, GFP_KERNEL); + buf = kmalloc(MAX_USB_STRING_SIZE, GFP_NOIO); if (buf) { len = usb_string(udev, index, buf, MAX_USB_STRING_SIZE); if (len > 0) { - smallbuf = kmalloc(++len, GFP_KERNEL); + smallbuf = kmalloc(++len, GFP_NOIO); if (!smallbuf) return buf; memcpy(smallbuf, buf, len); @@ -1731,7 +1731,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration) if (cp) { nintf = cp->desc.bNumInterfaces; new_interfaces = kmalloc(nintf * sizeof(*new_interfaces), - GFP_KERNEL); + GFP_NOIO); if (!new_interfaces) { dev_err(&dev->dev, "Out of memory\n"); return -ENOMEM; @@ -1740,7 +1740,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration) for (; n < nintf; ++n) { new_interfaces[n] = kzalloc( sizeof(struct usb_interface), - GFP_KERNEL); + GFP_NOIO); if (!new_interfaces[n]) { dev_err(&dev->dev, "Out of memory\n"); ret = -ENOMEM; diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 485edf9..5f3908f 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -115,6 +115,12 @@ show_speed(struct device *dev, struct device_attribute *attr, char *buf) case USB_SPEED_HIGH: speed = "480"; break; + case USB_SPEED_VARIABLE: + speed = "480"; + break; + case USB_SPEED_SUPER: + speed = "5000"; + break; default: speed = "unknown"; } diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 5859522..1ec3857 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -787,9 +787,10 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) /* start 20 msec resume signaling from this port, * and make khubd collect PORT_STAT_C_SUSPEND to - * stop that signaling. + * stop that signaling. Use 5 ms extra for safety, + * like usb_port_resume() does. */ - ehci->reset_done [i] = jiffies + msecs_to_jiffies (20); + ehci->reset_done[i] = jiffies + msecs_to_jiffies(25); ehci_dbg (ehci, "port %d remote wakeup\n", i + 1); mod_timer(&hcd->rh_timer, ehci->reset_done[i]); } diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 2c6571c..c75d927 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -120,9 +120,26 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) del_timer_sync(&ehci->watchdog); del_timer_sync(&ehci->iaa_watchdog); - port = HCS_N_PORTS (ehci->hcs_params); spin_lock_irq (&ehci->lock); + /* Once the controller is stopped, port resumes that are already + * in progress won't complete. Hence if remote wakeup is enabled + * for the root hub and any ports are in the middle of a resume or + * remote wakeup, we must fail the suspend. + */ + if (hcd->self.root_hub->do_remote_wakeup) { + port = HCS_N_PORTS(ehci->hcs_params); + while (port--) { + if (ehci->reset_done[port] != 0) { + spin_unlock_irq(&ehci->lock); + ehci_dbg(ehci, "suspend failed because " + "port %d is resuming\n", + port + 1); + return -EBUSY; + } + } + } + /* stop schedules, clean any completed work */ if (HC_IS_RUNNING(hcd->state)) { ehci_quiesce (ehci); @@ -138,6 +155,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) */ ehci->bus_suspended = 0; ehci->owned_ports = 0; + port = HCS_N_PORTS(ehci->hcs_params); while (port--) { u32 __iomem *reg = &ehci->regs->port_status [port]; u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS; diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index a427d3b..8952177 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -849,9 +849,10 @@ qh_make ( * But interval 1 scheduling is simpler, and * includes high bandwidth. */ - dbg ("intr period %d uframes, NYET!", - urb->interval); - goto done; + urb->interval = 1; + } else if (qh->period > ehci->periodic_size) { + qh->period = ehci->periodic_size; + urb->interval = qh->period << 3; } } else { int think_time; @@ -874,6 +875,10 @@ qh_make ( usb_calc_bus_time (urb->dev->speed, is_input, 0, max_packet (maxp))); qh->period = urb->interval; + if (qh->period > ehci->periodic_size) { + qh->period = ehci->periodic_size; + urb->interval = qh->period; + } } } diff --git a/drivers/usb/host/fhci-hcd.c b/drivers/usb/host/fhci-hcd.c index 0951818..78e7c3c 100644 --- a/drivers/usb/host/fhci-hcd.c +++ b/drivers/usb/host/fhci-hcd.c @@ -242,9 +242,10 @@ err: static void fhci_usb_free(void *lld) { struct fhci_usb *usb = lld; - struct fhci_hcd *fhci = usb->fhci; + struct fhci_hcd *fhci; if (usb) { + fhci = usb->fhci; fhci_config_transceiver(fhci, FHCI_PORT_POWER_OFF); fhci_ep0_free(usb); kfree(usb->actual_frame); diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c index 73352f3..4297165 100644 --- a/drivers/usb/host/isp1362-hcd.c +++ b/drivers/usb/host/isp1362-hcd.c @@ -2270,10 +2270,10 @@ static int isp1362_mem_config(struct usb_hcd *hcd) dev_info(hcd->self.controller, "ISP1362 Memory usage:\n"); dev_info(hcd->self.controller, " ISTL: 2 * %4d: %4d @ $%04x:$%04x\n", istl_size / 2, istl_size, 0, istl_size / 2); - dev_info(hcd->self.controller, " INTL: %4d * (%3lu+8): %4d @ $%04x\n", + dev_info(hcd->self.controller, " INTL: %4d * (%3zu+8): %4d @ $%04x\n", ISP1362_INTL_BUFFERS, intl_blksize - PTD_HEADER_SIZE, intl_size, istl_size); - dev_info(hcd->self.controller, " ATL : %4d * (%3lu+8): %4d @ $%04x\n", + dev_info(hcd->self.controller, " ATL : %4d * (%3zu+8): %4d @ $%04x\n", atl_buffers, atl_blksize - PTD_HEADER_SIZE, atl_size, istl_size + intl_size); dev_info(hcd->self.controller, " USED/FREE: %4d %4d\n", total, @@ -2697,6 +2697,8 @@ static int __init isp1362_probe(struct platform_device *pdev) void __iomem *data_reg; int irq; int retval = 0; + struct resource *irq_res; + unsigned int irq_flags = 0; /* basic sanity checks first. board-specific init logic should * have initialized this the three resources and probably board @@ -2710,11 +2712,12 @@ static int __init isp1362_probe(struct platform_device *pdev) data = platform_get_resource(pdev, IORESOURCE_MEM, 0); addr = platform_get_resource(pdev, IORESOURCE_MEM, 1); - irq = platform_get_irq(pdev, 0); - if (!addr || !data || irq < 0) { + irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!addr || !data || !irq_res) { retval = -ENODEV; goto err1; } + irq = irq_res->start; #ifdef CONFIG_USB_HCD_DMA if (pdev->dev.dma_mask) { @@ -2781,12 +2784,16 @@ static int __init isp1362_probe(struct platform_device *pdev) } #endif -#ifdef CONFIG_ARM - if (isp1362_hcd->board) - set_irq_type(irq, isp1362_hcd->board->int_act_high ? IRQT_RISING : IRQT_FALLING); -#endif + if (irq_res->flags & IORESOURCE_IRQ_HIGHEDGE) + irq_flags |= IRQF_TRIGGER_RISING; + if (irq_res->flags & IORESOURCE_IRQ_LOWEDGE) + irq_flags |= IRQF_TRIGGER_FALLING; + if (irq_res->flags & IORESOURCE_IRQ_HIGHLEVEL) + irq_flags |= IRQF_TRIGGER_HIGH; + if (irq_res->flags & IORESOURCE_IRQ_LOWLEVEL) + irq_flags |= IRQF_TRIGGER_LOW; - retval = usb_add_hcd(hcd, irq, IRQF_TRIGGER_LOW | IRQF_DISABLED | IRQF_SHARED); + retval = usb_add_hcd(hcd, irq, irq_flags | IRQF_DISABLED | IRQF_SHARED); if (retval != 0) goto err6; pr_info("%s, irq %d\n", hcd->product_desc, irq); diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c index 9600a58..27b8f7c 100644 --- a/drivers/usb/host/isp1760-hcd.c +++ b/drivers/usb/host/isp1760-hcd.c @@ -1039,12 +1039,12 @@ static void do_atl_int(struct usb_hcd *usb_hcd) if (!nakcount && (dw3 & DW3_QTD_ACTIVE)) { u32 buffstatus; - /* XXX + /* * NAKs are handled in HW by the chip. Usually if the * device is not able to send data fast enough. - * This did not trigger for a long time now. + * This happens mostly on slower hardware. */ - printk(KERN_ERR "Reloading ptd %p/%p... qh %p readed: " + printk(KERN_NOTICE "Reloading ptd %p/%p... qh %p read: " "%d of %zu done: %08x cur: %08x\n", qtd, urb, qh, PTD_XFERRED_LENGTH(dw3), qtd->length, done_map, diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 5cd0e48..99cd00f 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -749,7 +749,20 @@ static int uhci_rh_suspend(struct usb_hcd *hcd) spin_lock_irq(&uhci->lock); if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) rc = -ESHUTDOWN; - else if (!uhci->dead) + else if (uhci->dead) + ; /* Dead controllers tell no tales */ + + /* Once the controller is stopped, port resumes that are already + * in progress won't complete. Hence if remote wakeup is enabled + * for the root hub and any ports are in the middle of a resume or + * remote wakeup, we must fail the suspend. + */ + else if (hcd->self.root_hub->do_remote_wakeup && + uhci->resuming_ports) { + dev_dbg(uhci_dev(uhci), "suspend failed because a port " + "is resuming\n"); + rc = -EBUSY; + } else suspend_rh(uhci, UHCI_RH_SUSPENDED); spin_unlock_irq(&uhci->lock); return rc; diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c index 885b585..8270055 100644 --- a/drivers/usb/host/uhci-hub.c +++ b/drivers/usb/host/uhci-hub.c @@ -167,7 +167,7 @@ static void uhci_check_ports(struct uhci_hcd *uhci) /* Port received a wakeup request */ set_bit(port, &uhci->resuming_ports); uhci->ports_timeout = jiffies + - msecs_to_jiffies(20); + msecs_to_jiffies(25); /* Make sure we see the port again * after the resuming period is over. */ diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index f1ea3a3..83443d6 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -386,12 +386,12 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty) dbg("%s - port %d", __func__, port->number); - if (serial->type->max_in_flight_urbs) { - spin_lock_irqsave(&port->lock, flags); + spin_lock_irqsave(&port->lock, flags); + if (serial->type->max_in_flight_urbs) chars = port->tx_bytes_flight; - spin_unlock_irqrestore(&port->lock, flags); - } else if (serial->num_bulk_out) + else if (serial->num_bulk_out) chars = kfifo_len(&port->write_fifo); + spin_unlock_irqrestore(&port->lock, flags); dbg("%s - returns %d", __func__, chars); return chars; @@ -489,6 +489,8 @@ void usb_serial_generic_write_bulk_callback(struct urb *urb) dbg("%s - port %d", __func__, port->number); if (port->serial->type->max_in_flight_urbs) { + kfree(urb->transfer_buffer); + spin_lock_irqsave(&port->lock, flags); --port->urbs_in_flight; port->tx_bytes_flight -= urb->transfer_buffer_length; diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 64a0a2c..c932f90 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1807,13 +1807,6 @@ UNUSUAL_DEV( 0x2735, 0x100b, 0x0000, 0x9999, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_GO_SLOW ), -/* Reported by Rohan Hart <rohan.hart17@gmail.com> */ -UNUSUAL_DEV( 0x2770, 0x915d, 0x0010, 0x0010, - "INTOVA", - "Pixtreme", - US_SC_DEVICE, US_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY ), - /* Reported by Frederic Marchal <frederic.marchal@wowcompany.com> * Mio Moov 330 */ diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 5a53d4f..e9f9954 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -434,7 +434,8 @@ static void adjust_quirks(struct us_data *us) u16 vid = le16_to_cpu(us->pusb_dev->descriptor.idVendor); u16 pid = le16_to_cpu(us->pusb_dev->descriptor.idProduct); unsigned f = 0; - unsigned int mask = (US_FL_SANE_SENSE | US_FL_FIX_CAPACITY | + unsigned int mask = (US_FL_SANE_SENSE | US_FL_BAD_SENSE | + US_FL_FIX_CAPACITY | US_FL_CAPACITY_HEURISTICS | US_FL_IGNORE_DEVICE | US_FL_NOT_LOCKABLE | US_FL_MAX_SECTORS_64 | US_FL_CAPACITY_OK | US_FL_IGNORE_RESIDUE | @@ -78,7 +78,7 @@ static struct kmem_cache *bio_find_or_create_slab(unsigned int extra_size) i = 0; while (i < bio_slab_nr) { - struct bio_slab *bslab = &bio_slabs[i]; + bslab = &bio_slabs[i]; if (!bslab->slab && entry == -1) entry = i; diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c index 2e9e699..54f4798 100644 --- a/fs/btrfs/acl.c +++ b/fs/btrfs/acl.c @@ -112,12 +112,14 @@ static int btrfs_set_acl(struct btrfs_trans_handle *trans, switch (type) { case ACL_TYPE_ACCESS: mode = inode->i_mode; - ret = posix_acl_equiv_mode(acl, &mode); - if (ret < 0) - return ret; - ret = 0; - inode->i_mode = mode; name = POSIX_ACL_XATTR_ACCESS; + if (acl) { + ret = posix_acl_equiv_mode(acl, &mode); + if (ret < 0) + return ret; + inode->i_mode = mode; + } + ret = 0; break; case ACL_TYPE_DEFAULT: if (!S_ISDIR(inode->i_mode)) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 56e5013..432a2da 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -83,6 +83,17 @@ static int block_group_bits(struct btrfs_block_group_cache *cache, u64 bits) return (cache->flags & bits) == bits; } +void btrfs_get_block_group(struct btrfs_block_group_cache *cache) +{ + atomic_inc(&cache->count); +} + +void btrfs_put_block_group(struct btrfs_block_group_cache *cache) +{ + if (atomic_dec_and_test(&cache->count)) + kfree(cache); +} + /* * this adds the block group to the fs_info rb tree for the block group * cache @@ -156,7 +167,7 @@ block_group_cache_tree_search(struct btrfs_fs_info *info, u64 bytenr, } } if (ret) - atomic_inc(&ret->count); + btrfs_get_block_group(ret); spin_unlock(&info->block_group_cache_lock); return ret; @@ -407,6 +418,8 @@ err: put_caching_control(caching_ctl); atomic_dec(&block_group->space_info->caching_threads); + btrfs_put_block_group(block_group); + return 0; } @@ -447,6 +460,7 @@ static int cache_block_group(struct btrfs_block_group_cache *cache) up_write(&fs_info->extent_commit_sem); atomic_inc(&cache->space_info->caching_threads); + btrfs_get_block_group(cache); tsk = kthread_run(caching_kthread, cache, "btrfs-cache-%llu\n", cache->key.objectid); @@ -486,12 +500,6 @@ struct btrfs_block_group_cache *btrfs_lookup_block_group( return cache; } -void btrfs_put_block_group(struct btrfs_block_group_cache *cache) -{ - if (atomic_dec_and_test(&cache->count)) - kfree(cache); -} - static struct btrfs_space_info *__find_space_info(struct btrfs_fs_info *info, u64 flags) { @@ -2582,7 +2590,7 @@ next_block_group(struct btrfs_root *root, if (node) { cache = rb_entry(node, struct btrfs_block_group_cache, cache_node); - atomic_inc(&cache->count); + btrfs_get_block_group(cache); } else cache = NULL; spin_unlock(&root->fs_info->block_group_cache_lock); @@ -4227,7 +4235,7 @@ search: u64 offset; int cached; - atomic_inc(&block_group->count); + btrfs_get_block_group(block_group); search_start = block_group->key.objectid; have_block_group: @@ -4315,7 +4323,7 @@ have_block_group: btrfs_put_block_group(block_group); block_group = last_ptr->block_group; - atomic_inc(&block_group->count); + btrfs_get_block_group(block_group); spin_unlock(&last_ptr->lock); spin_unlock(&last_ptr->refill_lock); @@ -7395,9 +7403,7 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info) wait_block_group_cache_done(block_group); btrfs_remove_free_space_cache(block_group); - - WARN_ON(atomic_read(&block_group->count) != 1); - kfree(block_group); + btrfs_put_block_group(block_group); spin_lock(&info->block_group_cache_lock); } diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index feaa13b..c020335 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -506,7 +506,8 @@ next_slot: } static int extent_mergeable(struct extent_buffer *leaf, int slot, - u64 objectid, u64 bytenr, u64 *start, u64 *end) + u64 objectid, u64 bytenr, u64 orig_offset, + u64 *start, u64 *end) { struct btrfs_file_extent_item *fi; struct btrfs_key key; @@ -522,6 +523,7 @@ static int extent_mergeable(struct extent_buffer *leaf, int slot, fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); if (btrfs_file_extent_type(leaf, fi) != BTRFS_FILE_EXTENT_REG || btrfs_file_extent_disk_bytenr(leaf, fi) != bytenr || + btrfs_file_extent_offset(leaf, fi) != key.offset - orig_offset || btrfs_file_extent_compression(leaf, fi) || btrfs_file_extent_encryption(leaf, fi) || btrfs_file_extent_other_encoding(leaf, fi)) @@ -561,6 +563,7 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, u64 split; int del_nr = 0; int del_slot = 0; + int recow; int ret; btrfs_drop_extent_cache(inode, start, end - 1, 0); @@ -568,6 +571,7 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, path = btrfs_alloc_path(); BUG_ON(!path); again: + recow = 0; split = start; key.objectid = inode->i_ino; key.type = BTRFS_EXTENT_DATA_KEY; @@ -591,12 +595,60 @@ again: bytenr = btrfs_file_extent_disk_bytenr(leaf, fi); num_bytes = btrfs_file_extent_disk_num_bytes(leaf, fi); orig_offset = key.offset - btrfs_file_extent_offset(leaf, fi); + memcpy(&new_key, &key, sizeof(new_key)); + + if (start == key.offset && end < extent_end) { + other_start = 0; + other_end = start; + if (extent_mergeable(leaf, path->slots[0] - 1, + inode->i_ino, bytenr, orig_offset, + &other_start, &other_end)) { + new_key.offset = end; + btrfs_set_item_key_safe(trans, root, path, &new_key); + fi = btrfs_item_ptr(leaf, path->slots[0], + struct btrfs_file_extent_item); + btrfs_set_file_extent_num_bytes(leaf, fi, + extent_end - end); + btrfs_set_file_extent_offset(leaf, fi, + end - orig_offset); + fi = btrfs_item_ptr(leaf, path->slots[0] - 1, + struct btrfs_file_extent_item); + btrfs_set_file_extent_num_bytes(leaf, fi, + end - other_start); + btrfs_mark_buffer_dirty(leaf); + goto out; + } + } + + if (start > key.offset && end == extent_end) { + other_start = end; + other_end = 0; + if (extent_mergeable(leaf, path->slots[0] + 1, + inode->i_ino, bytenr, orig_offset, + &other_start, &other_end)) { + fi = btrfs_item_ptr(leaf, path->slots[0], + struct btrfs_file_extent_item); + btrfs_set_file_extent_num_bytes(leaf, fi, + start - key.offset); + path->slots[0]++; + new_key.offset = start; + btrfs_set_item_key_safe(trans, root, path, &new_key); + + fi = btrfs_item_ptr(leaf, path->slots[0], + struct btrfs_file_extent_item); + btrfs_set_file_extent_num_bytes(leaf, fi, + other_end - start); + btrfs_set_file_extent_offset(leaf, fi, + start - orig_offset); + btrfs_mark_buffer_dirty(leaf); + goto out; + } + } while (start > key.offset || end < extent_end) { if (key.offset == start) split = end; - memcpy(&new_key, &key, sizeof(new_key)); new_key.offset = split; ret = btrfs_duplicate_item(trans, root, path, &new_key); if (ret == -EAGAIN) { @@ -631,15 +683,18 @@ again: path->slots[0]--; extent_end = end; } + recow = 1; } - fi = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_file_extent_item); - other_start = end; other_end = 0; - if (extent_mergeable(leaf, path->slots[0] + 1, inode->i_ino, - bytenr, &other_start, &other_end)) { + if (extent_mergeable(leaf, path->slots[0] + 1, + inode->i_ino, bytenr, orig_offset, + &other_start, &other_end)) { + if (recow) { + btrfs_release_path(root, path); + goto again; + } extent_end = other_end; del_slot = path->slots[0] + 1; del_nr++; @@ -650,8 +705,13 @@ again: } other_start = 0; other_end = start; - if (extent_mergeable(leaf, path->slots[0] - 1, inode->i_ino, - bytenr, &other_start, &other_end)) { + if (extent_mergeable(leaf, path->slots[0] - 1, + inode->i_ino, bytenr, orig_offset, + &other_start, &other_end)) { + if (recow) { + btrfs_release_path(root, path); + goto again; + } key.offset = other_start; del_slot = path->slots[0]; del_nr++; @@ -660,22 +720,22 @@ again: inode->i_ino, orig_offset); BUG_ON(ret); } + fi = btrfs_item_ptr(leaf, path->slots[0], + struct btrfs_file_extent_item); if (del_nr == 0) { btrfs_set_file_extent_type(leaf, fi, BTRFS_FILE_EXTENT_REG); btrfs_mark_buffer_dirty(leaf); - goto out; - } - - fi = btrfs_item_ptr(leaf, del_slot - 1, - struct btrfs_file_extent_item); - btrfs_set_file_extent_type(leaf, fi, BTRFS_FILE_EXTENT_REG); - btrfs_set_file_extent_num_bytes(leaf, fi, - extent_end - key.offset); - btrfs_mark_buffer_dirty(leaf); + } else { + btrfs_set_file_extent_type(leaf, fi, + BTRFS_FILE_EXTENT_REG); + btrfs_set_file_extent_num_bytes(leaf, fi, + extent_end - key.offset); + btrfs_mark_buffer_dirty(leaf); - ret = btrfs_del_items(trans, root, path, del_slot, del_nr); - BUG_ON(ret); + ret = btrfs_del_items(trans, root, path, del_slot, del_nr); + BUG_ON(ret); + } out: btrfs_free_path(path); return 0; diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 5440bab..b330e27c 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -3796,6 +3796,12 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry) if (location.type == BTRFS_INODE_ITEM_KEY) { inode = btrfs_iget(dir->i_sb, &location, root); + if (unlikely(root->clean_orphans) && + !(inode->i_sb->s_flags & MS_RDONLY)) { + down_read(&root->fs_info->cleanup_work_sem); + btrfs_orphan_cleanup(root); + up_read(&root->fs_info->cleanup_work_sem); + } return inode; } @@ -3995,7 +4001,11 @@ skip: /* Reached end of directory/root. Bump pos past the last item. */ if (key_type == BTRFS_DIR_INDEX_KEY) - filp->f_pos = INT_LIMIT(off_t); + /* + * 32-bit glibc will use getdents64, but then strtol - + * so the last number we can serve is this. + */ + filp->f_pos = 0x7fffffff; else filp->f_pos++; nopos: diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index b10a49d..5c2a9e7 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c @@ -626,6 +626,8 @@ int btrfs_ordered_update_i_size(struct inode *inode, u64 offset, if (ordered) offset = entry_end(ordered); + else + offset = ALIGN(offset, BTRFS_I(inode)->root->sectorsize); mutex_lock(&tree->mutex); disk_i_size = BTRFS_I(inode)->disk_i_size; diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index a972868..ed3e4a2 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -3281,8 +3281,10 @@ static noinline_for_stack int relocate_block_group(struct reloc_control *rc) return -ENOMEM; path = btrfs_alloc_path(); - if (!path) + if (!path) { + kfree(cluster); return -ENOMEM; + } rc->extents_found = 0; rc->extents_skipped = 0; diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 198cff2..220dad5 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -2649,8 +2649,10 @@ again: em = lookup_extent_mapping(em_tree, logical, *length); read_unlock(&em_tree->lock); - if (!em && unplug_page) + if (!em && unplug_page) { + kfree(multi); return 0; + } if (!em) { printk(KERN_CRIT "unable to find logical %llu len %llu\n", diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 332dd00..c5c45de 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -1005,6 +1005,9 @@ COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND) COMPATIBLE_IOCTL(SCSI_IOCTL_PROBE_HOST) COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI) #endif +/* Big V (don't complain on serial console) */ +IGNORE_IOCTL(VT_OPENQRY) +IGNORE_IOCTL(VT_GETMODE) /* Little p (/dev/rtc, /dev/envctrl, etc.) */ COMPATIBLE_IOCTL(RTC_AIE_ON) COMPATIBLE_IOCTL(RTC_AIE_OFF) diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index fbb6e5e..7cb0a59 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c @@ -1748,7 +1748,7 @@ ecryptfs_process_key_cipher(struct crypto_blkcipher **key_tfm, char *cipher_name, size_t *key_size) { char dummy_key[ECRYPTFS_MAX_KEY_BYTES]; - char *full_alg_name; + char *full_alg_name = NULL; int rc; *key_tfm = NULL; @@ -1763,7 +1763,6 @@ ecryptfs_process_key_cipher(struct crypto_blkcipher **key_tfm, if (rc) goto out; *key_tfm = crypto_alloc_blkcipher(full_alg_name, 0, CRYPTO_ALG_ASYNC); - kfree(full_alg_name); if (IS_ERR(*key_tfm)) { rc = PTR_ERR(*key_tfm); printk(KERN_ERR "Unable to allocate crypto cipher with name " @@ -1786,6 +1785,7 @@ ecryptfs_process_key_cipher(struct crypto_blkcipher **key_tfm, goto out; } out: + kfree(full_alg_name); return rc; } diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index 9e94405..678172b 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c @@ -158,7 +158,7 @@ static int ecryptfs_open(struct inode *inode, struct file *file) struct dentry *ecryptfs_dentry = file->f_path.dentry; /* Private value of ecryptfs_dentry allocated in * ecryptfs_lookup() */ - struct dentry *lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); + struct dentry *lower_dentry; struct ecryptfs_file_info *file_info; mount_crypt_stat = &ecryptfs_superblock_to_private( @@ -191,13 +191,6 @@ static int ecryptfs_open(struct inode *inode, struct file *file) | ECRYPTFS_ENCRYPTED); } mutex_unlock(&crypt_stat->cs_mutex); - if ((ecryptfs_inode_to_private(inode)->lower_file->f_flags & O_RDONLY) - && !(file->f_flags & O_RDONLY)) { - rc = -EPERM; - printk(KERN_WARNING "%s: Lower persistent file is RO; eCryptfs " - "file must hence be opened RO\n", __func__); - goto out; - } if (!ecryptfs_inode_to_private(inode)->lower_file) { rc = ecryptfs_init_persistent_file(ecryptfs_dentry); if (rc) { @@ -208,6 +201,13 @@ static int ecryptfs_open(struct inode *inode, struct file *file) goto out; } } + if ((ecryptfs_inode_to_private(inode)->lower_file->f_flags & O_RDONLY) + && !(file->f_flags & O_RDONLY)) { + rc = -EPERM; + printk(KERN_WARNING "%s: Lower persistent file is RO; eCryptfs " + "file must hence be opened RO\n", __func__); + goto out; + } ecryptfs_set_file_lower( file, ecryptfs_inode_to_private(inode)->lower_file); if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) { @@ -299,7 +299,6 @@ static int ecryptfs_ioctl(struct inode *inode, struct file *file, const struct file_operations ecryptfs_dir_fops = { .readdir = ecryptfs_readdir, .ioctl = ecryptfs_ioctl, - .mmap = generic_file_mmap, .open = ecryptfs_open, .flush = ecryptfs_flush, .release = ecryptfs_release, diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 7f85450..4a430ab 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -282,7 +282,8 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, goto out; } rc = ecryptfs_interpose(lower_dentry, ecryptfs_dentry, - ecryptfs_dir_inode->i_sb, 1); + ecryptfs_dir_inode->i_sb, + ECRYPTFS_INTERPOSE_FLAG_D_ADD); if (rc) { printk(KERN_ERR "%s: Error interposing; rc = [%d]\n", __func__, rc); @@ -463,9 +464,6 @@ out_lock: unlock_dir(lower_dir_dentry); dput(lower_new_dentry); dput(lower_old_dentry); - d_drop(lower_old_dentry); - d_drop(new_dentry); - d_drop(old_dentry); return rc; } @@ -614,6 +612,7 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct dentry *lower_new_dentry; struct dentry *lower_old_dir_dentry; struct dentry *lower_new_dir_dentry; + struct dentry *trap = NULL; lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry); lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry); @@ -621,7 +620,17 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry, dget(lower_new_dentry); lower_old_dir_dentry = dget_parent(lower_old_dentry); lower_new_dir_dentry = dget_parent(lower_new_dentry); - lock_rename(lower_old_dir_dentry, lower_new_dir_dentry); + trap = lock_rename(lower_old_dir_dentry, lower_new_dir_dentry); + /* source should not be ancestor of target */ + if (trap == lower_old_dentry) { + rc = -EINVAL; + goto out_lock; + } + /* target should not be ancestor of source */ + if (trap == lower_new_dentry) { + rc = -ENOTEMPTY; + goto out_lock; + } rc = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry, lower_new_dir_dentry->d_inode, lower_new_dentry); if (rc) @@ -772,18 +781,23 @@ upper_size_to_lower_size(struct ecryptfs_crypt_stat *crypt_stat, } /** - * ecryptfs_truncate + * truncate_upper * @dentry: The ecryptfs layer dentry - * @new_length: The length to expand the file to + * @ia: Address of the ecryptfs inode's attributes + * @lower_ia: Address of the lower inode's attributes * * Function to handle truncations modifying the size of the file. Note * that the file sizes are interpolated. When expanding, we are simply - * writing strings of 0's out. When truncating, we need to modify the - * underlying file size according to the page index interpolations. + * writing strings of 0's out. When truncating, we truncate the upper + * inode and update the lower_ia according to the page index + * interpolations. If ATTR_SIZE is set in lower_ia->ia_valid upon return, + * the caller must use lower_ia in a call to notify_change() to perform + * the truncation of the lower inode. * * Returns zero on success; non-zero otherwise */ -int ecryptfs_truncate(struct dentry *dentry, loff_t new_length) +static int truncate_upper(struct dentry *dentry, struct iattr *ia, + struct iattr *lower_ia) { int rc = 0; struct inode *inode = dentry->d_inode; @@ -794,8 +808,10 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length) loff_t lower_size_before_truncate; loff_t lower_size_after_truncate; - if (unlikely((new_length == i_size))) + if (unlikely((ia->ia_size == i_size))) { + lower_ia->ia_valid &= ~ATTR_SIZE; goto out; + } crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat; /* Set up a fake ecryptfs file, this is used to interface with * the file in the underlying filesystem so that the @@ -815,28 +831,30 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length) &fake_ecryptfs_file, ecryptfs_inode_to_private(dentry->d_inode)->lower_file); /* Switch on growing or shrinking file */ - if (new_length > i_size) { + if (ia->ia_size > i_size) { char zero[] = { 0x00 }; + lower_ia->ia_valid &= ~ATTR_SIZE; /* Write a single 0 at the last position of the file; * this triggers code that will fill in 0's throughout * the intermediate portion of the previous end of the * file and the new and of the file */ rc = ecryptfs_write(&fake_ecryptfs_file, zero, - (new_length - 1), 1); - } else { /* new_length < i_size_read(inode) */ - /* We're chopping off all the pages down do the page - * in which new_length is located. Fill in the end of - * that page from (new_length & ~PAGE_CACHE_MASK) to + (ia->ia_size - 1), 1); + } else { /* ia->ia_size < i_size_read(inode) */ + /* We're chopping off all the pages down to the page + * in which ia->ia_size is located. Fill in the end of + * that page from (ia->ia_size & ~PAGE_CACHE_MASK) to * PAGE_CACHE_SIZE with zeros. */ size_t num_zeros = (PAGE_CACHE_SIZE - - (new_length & ~PAGE_CACHE_MASK)); + - (ia->ia_size & ~PAGE_CACHE_MASK)); if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { - rc = vmtruncate(inode, new_length); + rc = vmtruncate(inode, ia->ia_size); if (rc) goto out_free; - rc = vmtruncate(lower_dentry->d_inode, new_length); + lower_ia->ia_size = ia->ia_size; + lower_ia->ia_valid |= ATTR_SIZE; goto out_free; } if (num_zeros) { @@ -848,7 +866,7 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length) goto out_free; } rc = ecryptfs_write(&fake_ecryptfs_file, zeros_virt, - new_length, num_zeros); + ia->ia_size, num_zeros); kfree(zeros_virt); if (rc) { printk(KERN_ERR "Error attempting to zero out " @@ -857,7 +875,7 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length) goto out_free; } } - vmtruncate(inode, new_length); + vmtruncate(inode, ia->ia_size); rc = ecryptfs_write_inode_size_to_metadata(inode); if (rc) { printk(KERN_ERR "Problem with " @@ -870,10 +888,12 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length) lower_size_before_truncate = upper_size_to_lower_size(crypt_stat, i_size); lower_size_after_truncate = - upper_size_to_lower_size(crypt_stat, new_length); - if (lower_size_after_truncate < lower_size_before_truncate) - vmtruncate(lower_dentry->d_inode, - lower_size_after_truncate); + upper_size_to_lower_size(crypt_stat, ia->ia_size); + if (lower_size_after_truncate < lower_size_before_truncate) { + lower_ia->ia_size = lower_size_after_truncate; + lower_ia->ia_valid |= ATTR_SIZE; + } else + lower_ia->ia_valid &= ~ATTR_SIZE; } out_free: if (ecryptfs_file_to_private(&fake_ecryptfs_file)) @@ -883,6 +903,33 @@ out: return rc; } +/** + * ecryptfs_truncate + * @dentry: The ecryptfs layer dentry + * @new_length: The length to expand the file to + * + * Simple function that handles the truncation of an eCryptfs inode and + * its corresponding lower inode. + * + * Returns zero on success; non-zero otherwise + */ +int ecryptfs_truncate(struct dentry *dentry, loff_t new_length) +{ + struct iattr ia = { .ia_valid = ATTR_SIZE, .ia_size = new_length }; + struct iattr lower_ia = { .ia_valid = 0 }; + int rc; + + rc = truncate_upper(dentry, &ia, &lower_ia); + if (!rc && lower_ia.ia_valid & ATTR_SIZE) { + struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); + + mutex_lock(&lower_dentry->d_inode->i_mutex); + rc = notify_change(lower_dentry, &lower_ia); + mutex_unlock(&lower_dentry->d_inode->i_mutex); + } + return rc; +} + static int ecryptfs_permission(struct inode *inode, int mask) { @@ -905,6 +952,7 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia) { int rc = 0; struct dentry *lower_dentry; + struct iattr lower_ia; struct inode *inode; struct inode *lower_inode; struct ecryptfs_crypt_stat *crypt_stat; @@ -943,15 +991,11 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia) } } mutex_unlock(&crypt_stat->cs_mutex); + memcpy(&lower_ia, ia, sizeof(lower_ia)); + if (ia->ia_valid & ATTR_FILE) + lower_ia.ia_file = ecryptfs_file_to_lower(ia->ia_file); if (ia->ia_valid & ATTR_SIZE) { - ecryptfs_printk(KERN_DEBUG, - "ia->ia_valid = [0x%x] ATTR_SIZE" " = [0x%x]\n", - ia->ia_valid, ATTR_SIZE); - rc = ecryptfs_truncate(dentry, ia->ia_size); - /* ecryptfs_truncate handles resizing of the lower file */ - ia->ia_valid &= ~ATTR_SIZE; - ecryptfs_printk(KERN_DEBUG, "ia->ia_valid = [%x]\n", - ia->ia_valid); + rc = truncate_upper(dentry, ia, &lower_ia); if (rc < 0) goto out; } @@ -960,17 +1004,32 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia) * mode change is for clearing setuid/setgid bits. Allow lower fs * to interpret this in its own way. */ - if (ia->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) - ia->ia_valid &= ~ATTR_MODE; + if (lower_ia.ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) + lower_ia.ia_valid &= ~ATTR_MODE; mutex_lock(&lower_dentry->d_inode->i_mutex); - rc = notify_change(lower_dentry, ia); + rc = notify_change(lower_dentry, &lower_ia); mutex_unlock(&lower_dentry->d_inode->i_mutex); out: fsstack_copy_attr_all(inode, lower_inode); return rc; } +int ecryptfs_getattr(struct vfsmount *mnt, struct dentry *dentry, + struct kstat *stat) +{ + struct kstat lower_stat; + int rc; + + rc = vfs_getattr(ecryptfs_dentry_to_lower_mnt(dentry), + ecryptfs_dentry_to_lower(dentry), &lower_stat); + if (!rc) { + generic_fillattr(dentry->d_inode, stat); + stat->blocks = lower_stat.blocks; + } + return rc; +} + int ecryptfs_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) @@ -1100,6 +1159,7 @@ const struct inode_operations ecryptfs_dir_iops = { const struct inode_operations ecryptfs_main_iops = { .permission = ecryptfs_permission, .setattr = ecryptfs_setattr, + .getattr = ecryptfs_getattr, .setxattr = ecryptfs_setxattr, .getxattr = ecryptfs_getxattr, .listxattr = ecryptfs_listxattr, diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index 567bc4b..ea2f921 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -585,8 +585,8 @@ out: * with as much information as it can before needing * the lower filesystem. * ecryptfs_read_super(): this accesses the lower filesystem and uses - * ecryptfs_interpolate to perform most of the linking - * ecryptfs_interpolate(): links the lower filesystem into ecryptfs + * ecryptfs_interpose to perform most of the linking + * ecryptfs_interpose(): links the lower filesystem into ecryptfs (inode.c) */ static int ecryptfs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *raw_data, diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index 9d7febd..0946997 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h @@ -152,7 +152,7 @@ static inline void *acpi_os_acquire_object(acpi_cache_t * cache) #include <linux/hardirq.h> #define ACPI_PREEMPTION_POINT() \ do { \ - if (!in_atomic_preempt_off()) \ + if (!in_atomic_preempt_off() && !irqs_disabled()) \ cond_resched(); \ } while (0) diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 3692425..b926afe 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -80,7 +80,7 @@ char * __acpi_map_table (unsigned long phys_addr, unsigned long size); void __acpi_unmap_table(char *map, unsigned long size); int early_acpi_boot_init(void); int acpi_boot_init (void); -int acpi_boot_table_init (void); +void acpi_boot_table_init (void); int acpi_mps_check (void); int acpi_numa_init (void); @@ -321,9 +321,9 @@ static inline int acpi_boot_init(void) return 0; } -static inline int acpi_boot_table_init(void) +static inline void acpi_boot_table_init(void) { - return 0; + return; } static inline int acpi_mps_check(void) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 9b98173..5c80189 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -938,6 +938,8 @@ extern void blk_queue_io_opt(struct request_queue *q, unsigned int opt); extern void blk_set_default_limits(struct queue_limits *lim); extern int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, sector_t offset); +extern int bdev_stack_limits(struct queue_limits *t, struct block_device *bdev, + sector_t offset); extern void disk_stack_limits(struct gendisk *disk, struct block_device *bdev, sector_t offset); extern void blk_queue_stack_limits(struct request_queue *t, struct request_queue *b); @@ -1148,8 +1150,11 @@ static inline int queue_discard_alignment(struct request_queue *q) static inline int queue_sector_discard_alignment(struct request_queue *q, sector_t sector) { - return ((sector << 9) - q->limits.discard_alignment) - & (q->limits.discard_granularity - 1); + struct queue_limits *lim = &q->limits; + unsigned int alignment = (sector << 9) & (lim->discard_granularity - 1); + + return (lim->discard_granularity + lim->discard_alignment - alignment) + & (lim->discard_granularity - 1); } static inline unsigned int queue_discard_zeroes_data(struct request_queue *q) diff --git a/include/linux/drbd.h b/include/linux/drbd.h index e84f473..7896227 100644 --- a/include/linux/drbd.h +++ b/include/linux/drbd.h @@ -53,7 +53,7 @@ extern const char *drbd_buildtag(void); -#define REL_VERSION "8.3.6" +#define REL_VERSION "8.3.7" #define API_VERSION 88 #define PRO_VERSION_MIN 86 #define PRO_VERSION_MAX 91 diff --git a/include/linux/drbd_nl.h b/include/linux/drbd_nl.h index db5721a..a4d82f8 100644 --- a/include/linux/drbd_nl.h +++ b/include/linux/drbd_nl.h @@ -69,6 +69,7 @@ NL_PACKET(disconnect, 6, ) NL_PACKET(resize, 7, NL_INT64( 29, T_MAY_IGNORE, resize_size) + NL_BIT( 68, T_MAY_IGNORE, resize_force) ) NL_PACKET(syncer_conf, 8, diff --git a/include/linux/genhd.h b/include/linux/genhd.h index c6c0c41..9717081 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -256,9 +256,9 @@ extern struct hd_struct *disk_map_sector_rcu(struct gendisk *disk, #define part_stat_read(part, field) \ ({ \ typeof((part)->dkstats->field) res = 0; \ - int i; \ - for_each_possible_cpu(i) \ - res += per_cpu_ptr((part)->dkstats, i)->field; \ + unsigned int _cpu; \ + for_each_possible_cpu(_cpu) \ + res += per_cpu_ptr((part)->dkstats, _cpu)->field; \ res; \ }) diff --git a/include/linux/iocontext.h b/include/linux/iocontext.h index a632359..78ef023 100644 --- a/include/linux/iocontext.h +++ b/include/linux/iocontext.h @@ -4,32 +4,6 @@ #include <linux/radix-tree.h> #include <linux/rcupdate.h> -/* - * This is the per-process anticipatory I/O scheduler state. - */ -struct as_io_context { - spinlock_t lock; - - void (*dtor)(struct as_io_context *aic); /* destructor */ - void (*exit)(struct as_io_context *aic); /* called on task exit */ - - unsigned long state; - atomic_t nr_queued; /* queued reads & sync writes */ - atomic_t nr_dispatched; /* number of requests gone to the drivers */ - - /* IO History tracking */ - /* Thinktime */ - unsigned long last_end_request; - unsigned long ttime_total; - unsigned long ttime_samples; - unsigned long ttime_mean; - /* Layout pattern */ - unsigned int seek_samples; - sector_t last_request_pos; - u64 seek_total; - sector_t seek_mean; -}; - struct cfq_queue; struct cfq_io_context { void *key; @@ -78,7 +52,6 @@ struct io_context { unsigned long last_waited; /* Time last woken after wait for request */ int nr_batch_requests; /* Number of requests left in the batch */ - struct as_io_context *aic; struct radix_tree_root radix_root; struct hlist_head cic_list; void *ioc_data; diff --git a/include/linux/usb.h b/include/linux/usb.h index e101a2d..d7ace1b 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -192,6 +192,7 @@ struct usb_interface { unsigned needs_altsetting0:1; /* switch to altsetting 0 is pending */ unsigned needs_binding:1; /* needs delayed unbind/rebind */ unsigned reset_running:1; + unsigned resetting_device:1; /* true: bandwidth alloc after reset */ struct device dev; /* interface specific device info */ struct device *usb_dev; diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 37e6929..d55d905 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -555,10 +555,8 @@ static void __purge_vmap_area_lazy(unsigned long *start, unsigned long *end, } rcu_read_unlock(); - if (nr) { - BUG_ON(nr > atomic_read(&vmap_lazy_nr)); + if (nr) atomic_sub(nr, &vmap_lazy_nr); - } if (nr || force_flush) flush_tlb_kernel_range(*start, *end); |