diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2009-08-16 11:50:10 +0200 |
---|---|---|
committer | Rafael J. Wysocki <rjw@sisk.pl> | 2009-08-16 11:50:10 +0200 |
commit | 3e2bcad89814030ad6a369a97ad1481fd35938d3 (patch) | |
tree | 8d6b9b163dc9ed44ec377ca5b57be1a1fb80f923 | |
parent | dcbf77cac640af0ab944d5cbb07934bf6708b4d9 (diff) | |
parent | b2add73dbf93fd50f00564d7abc3e2b9aa9dd20c (diff) | |
download | op-kernel-dev-3e2bcad89814030ad6a369a97ad1481fd35938d3.zip op-kernel-dev-3e2bcad89814030ad6a369a97ad1481fd35938d3.tar.gz |
Merge branch 'master' into for-linus
167 files changed, 1643 insertions, 851 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index dd1a6d4..7936b80 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1115,6 +1115,10 @@ and is between 256 and 4096 characters. It is defined in the file libata.dma=4 Compact Flash DMA only Combinations also work, so libata.dma=3 enables DMA for disks and CDROMs, but not CFs. + + libata.ignore_hpa= [LIBATA] Ignore HPA limit + libata.ignore_hpa=0 keep BIOS limits (default) + libata.ignore_hpa=1 ignore limits, using full disk libata.noacpi [LIBATA] Disables use of ACPI in libata suspend/resume when set. diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx index 68c236c..e352d75 100644 --- a/Documentation/video4linux/CARDLIST.em28xx +++ b/Documentation/video4linux/CARDLIST.em28xx @@ -1,5 +1,5 @@ 0 -> Unknown EM2800 video grabber (em2800) [eb1a:2800] - 1 -> Unknown EM2750/28xx video grabber (em2820/em2840) [eb1a:2820,eb1a:2821,eb1a:2860,eb1a:2861,eb1a:2870,eb1a:2881,eb1a:2883] + 1 -> Unknown EM2750/28xx video grabber (em2820/em2840) [eb1a:2710,eb1a:2820,eb1a:2821,eb1a:2860,eb1a:2861,eb1a:2870,eb1a:2881,eb1a:2883] 2 -> Terratec Cinergy 250 USB (em2820/em2840) [0ccd:0036] 3 -> Pinnacle PCTV USB 2 (em2820/em2840) [2304:0208] 4 -> Hauppauge WinTV USB 2 (em2820/em2840) [2040:4200,2040:4201] diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index 1556242..c913e56 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -153,8 +153,8 @@ 152 -> Asus Tiger Rev:1.00 [1043:4857] 153 -> Kworld Plus TV Analog Lite PCI [17de:7128] 154 -> Avermedia AVerTV GO 007 FM Plus [1461:f31d] -155 -> Hauppauge WinTV-HVR1120 ATSC/QAM-Hybrid [0070:6706,0070:6708] -156 -> Hauppauge WinTV-HVR1110r3 DVB-T/Hybrid [0070:6707,0070:6709,0070:670a] +155 -> Hauppauge WinTV-HVR1150 ATSC/QAM-Hybrid [0070:6706,0070:6708] +156 -> Hauppauge WinTV-HVR1120 DVB-T/Hybrid [0070:6707,0070:6709,0070:670a] 157 -> Avermedia AVerTV Studio 507UA [1461:a11b] 158 -> AVerMedia Cardbus TV/Radio (E501R) [1461:b7e9] 159 -> Beholder BeholdTV 505 RDS [0000:505B] diff --git a/MAINTAINERS b/MAINTAINERS index b1114cf..2c4326c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2238,6 +2238,14 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git S: Maintained F: drivers/media/video/gspca/pac207.c +GSPCA SN9C20X SUBDRIVER +P: Brian Johnson +M: brijohn@gmail.com +L: linux-media@vger.kernel.org +T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git +S: Maintained +F: drivers/media/video/gspca/sn9c20x.c + GSPCA T613 SUBDRIVER M: Leandro Costantino <lcostantino@gmail.com> L: linux-media@vger.kernel.org @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 31 -EXTRAVERSION = -rc5 +EXTRAVERSION = -rc6 NAME = Man-Eating Seals of Antiquity # *DOCUMENTATION* diff --git a/arch/ia64/Makefile b/arch/ia64/Makefile index 58a7e46a..e7cbaa0 100644 --- a/arch/ia64/Makefile +++ b/arch/ia64/Makefile @@ -41,11 +41,6 @@ $(error Sorry, you need a newer version of the assember, one that is built from ftp://ftp.hpl.hp.com/pub/linux-ia64/gas-030124.tar.gz) endif -ifeq ($(call cc-version),0304) - cflags-$(CONFIG_ITANIUM) += -mtune=merced - cflags-$(CONFIG_MCKINLEY) += -mtune=mckinley -endif - KBUILD_CFLAGS += $(cflags-y) head-y := arch/ia64/kernel/head.o arch/ia64/kernel/init_task.o diff --git a/arch/ia64/include/asm/bitops.h b/arch/ia64/include/asm/bitops.h index e2ca800..57a2787 100644 --- a/arch/ia64/include/asm/bitops.h +++ b/arch/ia64/include/asm/bitops.h @@ -286,7 +286,7 @@ __test_and_clear_bit(int nr, volatile void * addr) { __u32 *p = (__u32 *) addr + (nr >> 5); __u32 m = 1 << (nr & 31); - int oldbitset = *p & m; + int oldbitset = (*p & m) != 0; *p &= ~m; return oldbitset; diff --git a/arch/ia64/include/asm/pgtable.h b/arch/ia64/include/asm/pgtable.h index 0a9cc73..8840a69 100644 --- a/arch/ia64/include/asm/pgtable.h +++ b/arch/ia64/include/asm/pgtable.h @@ -155,7 +155,6 @@ #include <linux/bitops.h> #include <asm/cacheflush.h> #include <asm/mmu_context.h> -#include <asm/processor.h> /* * Next come the mappings that determine how mmap() protection bits diff --git a/arch/ia64/kernel/ia64_ksyms.c b/arch/ia64/kernel/ia64_ksyms.c index 2d31186..8ebccb5 100644 --- a/arch/ia64/kernel/ia64_ksyms.c +++ b/arch/ia64/kernel/ia64_ksyms.c @@ -21,6 +21,7 @@ EXPORT_SYMBOL(csum_ipv6_magic); #include <asm/page.h> EXPORT_SYMBOL(clear_page); +EXPORT_SYMBOL(copy_page); #ifdef CONFIG_VIRTUAL_MEM_MAP #include <linux/bootmem.h> @@ -60,9 +61,6 @@ EXPORT_SYMBOL(__udivdi3); EXPORT_SYMBOL(__moddi3); EXPORT_SYMBOL(__umoddi3); -#include <asm/page.h> -EXPORT_SYMBOL(copy_page); - #if defined(CONFIG_MD_RAID456) || defined(CONFIG_MD_RAID456_MODULE) extern void xor_ia64_2(void); extern void xor_ia64_3(void); diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c index c48b03f..dab4d39 100644 --- a/arch/ia64/kernel/iosapic.c +++ b/arch/ia64/kernel/iosapic.c @@ -1072,6 +1072,10 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base) } addr = ioremap(phys_addr, 0); + if (addr == NULL) { + spin_unlock_irqrestore(&iosapic_lock, flags); + return -ENOMEM; + } ver = iosapic_version(addr); if ((err = iosapic_check_gsi_range(gsi_base, ver))) { iounmap(addr); diff --git a/arch/ia64/kernel/pci-dma.c b/arch/ia64/kernel/pci-dma.c index 0569596..f6b1ff0 100644 --- a/arch/ia64/kernel/pci-dma.c +++ b/arch/ia64/kernel/pci-dma.c @@ -69,11 +69,6 @@ iommu_dma_init(void) int iommu_dma_supported(struct device *dev, u64 mask) { - struct dma_map_ops *ops = platform_dma_get_ops(dev); - - if (ops->dma_supported) - return ops->dma_supported(dev, mask); - /* Copied from i386. Doesn't make much sense, because it will only work for pci_alloc_coherent. The caller just has to use GFP_DMA in this case. */ diff --git a/arch/ia64/kernel/topology.c b/arch/ia64/kernel/topology.c index bc80dff..8f06035 100644 --- a/arch/ia64/kernel/topology.c +++ b/arch/ia64/kernel/topology.c @@ -372,6 +372,10 @@ static int __cpuinit cache_add_dev(struct sys_device * sys_dev) retval = kobject_init_and_add(&all_cpu_cache_info[cpu].kobj, &cache_ktype_percpu_entry, &sys_dev->kobj, "%s", "cache"); + if (unlikely(retval < 0)) { + cpu_cache_sysfs_exit(cpu); + return retval; + } for (i = 0; i < all_cpu_cache_info[cpu].num_cache_leaves; i++) { this_object = LEAF_KOBJECT_PTR(cpu,i); @@ -385,7 +389,7 @@ static int __cpuinit cache_add_dev(struct sys_device * sys_dev) } kobject_put(&all_cpu_cache_info[cpu].kobj); cpu_cache_sysfs_exit(cpu); - break; + return retval; } kobject_uevent(&(this_object->kobj), KOBJ_ADD); } diff --git a/arch/sh/boards/board-ap325rxa.c b/arch/sh/boards/board-ap325rxa.c index 7ffd1b43..b9c88cc 100644 --- a/arch/sh/boards/board-ap325rxa.c +++ b/arch/sh/boards/board-ap325rxa.c @@ -547,7 +547,7 @@ static int __init ap325rxa_devices_setup(void) return platform_add_devices(ap325rxa_devices, ARRAY_SIZE(ap325rxa_devices)); } -device_initcall(ap325rxa_devices_setup); +arch_initcall(ap325rxa_devices_setup); /* Return the board specific boot mode pin configuration */ static int ap325rxa_mode_pins(void) diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c index f70f4644..f9b2e4d 100644 --- a/arch/sh/boards/mach-migor/setup.c +++ b/arch/sh/boards/mach-migor/setup.c @@ -608,7 +608,7 @@ static int __init migor_devices_setup(void) return platform_add_devices(migor_devices, ARRAY_SIZE(migor_devices)); } -__initcall(migor_devices_setup); +arch_initcall(migor_devices_setup); /* Return the board specific boot mode pin configuration */ static int migor_mode_pins(void) diff --git a/arch/sh/kernel/cpu/sh2/setup-sh7619.c b/arch/sh/kernel/cpu/sh2/setup-sh7619.c index 1379873..8555c05 100644 --- a/arch/sh/kernel/cpu/sh2/setup-sh7619.c +++ b/arch/sh/kernel/cpu/sh2/setup-sh7619.c @@ -187,7 +187,7 @@ static int __init sh7619_devices_setup(void) return platform_add_devices(sh7619_devices, ARRAY_SIZE(sh7619_devices)); } -__initcall(sh7619_devices_setup); +arch_initcall(sh7619_devices_setup); void __init plat_irq_setup(void) { diff --git a/arch/sh/kernel/cpu/sh2a/setup-mxg.c b/arch/sh/kernel/cpu/sh2a/setup-mxg.c index 869c2da..b673764 100644 --- a/arch/sh/kernel/cpu/sh2a/setup-mxg.c +++ b/arch/sh/kernel/cpu/sh2a/setup-mxg.c @@ -238,7 +238,7 @@ static int __init mxg_devices_setup(void) return platform_add_devices(mxg_devices, ARRAY_SIZE(mxg_devices)); } -__initcall(mxg_devices_setup); +arch_initcall(mxg_devices_setup); void __init plat_irq_setup(void) { diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7201.c b/arch/sh/kernel/cpu/sh2a/setup-sh7201.c index d8febe1..fbde5b7 100644 --- a/arch/sh/kernel/cpu/sh2a/setup-sh7201.c +++ b/arch/sh/kernel/cpu/sh2a/setup-sh7201.c @@ -357,7 +357,7 @@ static int __init sh7201_devices_setup(void) return platform_add_devices(sh7201_devices, ARRAY_SIZE(sh7201_devices)); } -__initcall(sh7201_devices_setup); +arch_initcall(sh7201_devices_setup); void __init plat_irq_setup(void) { diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7203.c b/arch/sh/kernel/cpu/sh2a/setup-sh7203.c index 62e3039..d3fd536 100644 --- a/arch/sh/kernel/cpu/sh2a/setup-sh7203.c +++ b/arch/sh/kernel/cpu/sh2a/setup-sh7203.c @@ -367,7 +367,7 @@ static int __init sh7203_devices_setup(void) return platform_add_devices(sh7203_devices, ARRAY_SIZE(sh7203_devices)); } -__initcall(sh7203_devices_setup); +arch_initcall(sh7203_devices_setup); void __init plat_irq_setup(void) { diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c index 3e6f3d7..a9ccc5e 100644 --- a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c +++ b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c @@ -338,7 +338,7 @@ static int __init sh7206_devices_setup(void) return platform_add_devices(sh7206_devices, ARRAY_SIZE(sh7206_devices)); } -__initcall(sh7206_devices_setup); +arch_initcall(sh7206_devices_setup); void __init plat_irq_setup(void) { diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7705.c b/arch/sh/kernel/cpu/sh3/setup-sh7705.c index 88f742f..c231059 100644 --- a/arch/sh/kernel/cpu/sh3/setup-sh7705.c +++ b/arch/sh/kernel/cpu/sh3/setup-sh7705.c @@ -222,7 +222,7 @@ static int __init sh7705_devices_setup(void) return platform_add_devices(sh7705_devices, ARRAY_SIZE(sh7705_devices)); } -__initcall(sh7705_devices_setup); +arch_initcall(sh7705_devices_setup); static struct platform_device *sh7705_early_devices[] __initdata = { &tmu0_device, diff --git a/arch/sh/kernel/cpu/sh3/setup-sh770x.c b/arch/sh/kernel/cpu/sh3/setup-sh770x.c index c563067..347ab35 100644 --- a/arch/sh/kernel/cpu/sh3/setup-sh770x.c +++ b/arch/sh/kernel/cpu/sh3/setup-sh770x.c @@ -250,7 +250,7 @@ static int __init sh770x_devices_setup(void) return platform_add_devices(sh770x_devices, ARRAY_SIZE(sh770x_devices)); } -__initcall(sh770x_devices_setup); +arch_initcall(sh770x_devices_setup); static struct platform_device *sh770x_early_devices[] __initdata = { &tmu0_device, diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7710.c b/arch/sh/kernel/cpu/sh3/setup-sh7710.c index efa76c8..717e90a 100644 --- a/arch/sh/kernel/cpu/sh3/setup-sh7710.c +++ b/arch/sh/kernel/cpu/sh3/setup-sh7710.c @@ -226,7 +226,7 @@ static int __init sh7710_devices_setup(void) return platform_add_devices(sh7710_devices, ARRAY_SIZE(sh7710_devices)); } -__initcall(sh7710_devices_setup); +arch_initcall(sh7710_devices_setup); static struct platform_device *sh7710_early_devices[] __initdata = { &tmu0_device, diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7720.c b/arch/sh/kernel/cpu/sh3/setup-sh7720.c index 5b21077..74d8baa 100644 --- a/arch/sh/kernel/cpu/sh3/setup-sh7720.c +++ b/arch/sh/kernel/cpu/sh3/setup-sh7720.c @@ -388,7 +388,7 @@ static int __init sh7720_devices_setup(void) return platform_add_devices(sh7720_devices, ARRAY_SIZE(sh7720_devices)); } -__initcall(sh7720_devices_setup); +arch_initcall(sh7720_devices_setup); static struct platform_device *sh7720_early_devices[] __initdata = { &cmt0_device, diff --git a/arch/sh/kernel/cpu/sh4/setup-sh4-202.c b/arch/sh/kernel/cpu/sh4/setup-sh4-202.c index 6d088d1..de4827d 100644 --- a/arch/sh/kernel/cpu/sh4/setup-sh4-202.c +++ b/arch/sh/kernel/cpu/sh4/setup-sh4-202.c @@ -138,7 +138,7 @@ static int __init sh4202_devices_setup(void) return platform_add_devices(sh4202_devices, ARRAY_SIZE(sh4202_devices)); } -__initcall(sh4202_devices_setup); +arch_initcall(sh4202_devices_setup); static struct platform_device *sh4202_early_devices[] __initdata = { &tmu0_device, diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7750.c b/arch/sh/kernel/cpu/sh4/setup-sh7750.c index 851672d..1b8b122 100644 --- a/arch/sh/kernel/cpu/sh4/setup-sh7750.c +++ b/arch/sh/kernel/cpu/sh4/setup-sh7750.c @@ -239,7 +239,7 @@ static int __init sh7750_devices_setup(void) return platform_add_devices(sh7750_devices, ARRAY_SIZE(sh7750_devices)); } -__initcall(sh7750_devices_setup); +arch_initcall(sh7750_devices_setup); static struct platform_device *sh7750_early_devices[] __initdata = { &tmu0_device, diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7760.c b/arch/sh/kernel/cpu/sh4/setup-sh7760.c index 5b82251..7fbb7be 100644 --- a/arch/sh/kernel/cpu/sh4/setup-sh7760.c +++ b/arch/sh/kernel/cpu/sh4/setup-sh7760.c @@ -265,7 +265,7 @@ static int __init sh7760_devices_setup(void) return platform_add_devices(sh7760_devices, ARRAY_SIZE(sh7760_devices)); } -__initcall(sh7760_devices_setup); +arch_initcall(sh7760_devices_setup); static struct platform_device *sh7760_early_devices[] __initdata = { &tmu0_device, diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7343.c b/arch/sh/kernel/cpu/sh4a/setup-sh7343.c index 6307e08..ac4d567 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7343.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7343.c @@ -325,7 +325,7 @@ static int __init sh7343_devices_setup(void) return platform_add_devices(sh7343_devices, ARRAY_SIZE(sh7343_devices)); } -__initcall(sh7343_devices_setup); +arch_initcall(sh7343_devices_setup); static struct platform_device *sh7343_early_devices[] __initdata = { &cmt_device, diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7366.c b/arch/sh/kernel/cpu/sh4a/setup-sh7366.c index c18f7d0..1a956b1 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7366.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7366.c @@ -318,7 +318,7 @@ static int __init sh7366_devices_setup(void) return platform_add_devices(sh7366_devices, ARRAY_SIZE(sh7366_devices)); } -__initcall(sh7366_devices_setup); +arch_initcall(sh7366_devices_setup); static struct platform_device *sh7366_early_devices[] __initdata = { &cmt_device, diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c index ea524a2..cda76eb 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c @@ -359,7 +359,7 @@ static int __init sh7722_devices_setup(void) return platform_add_devices(sh7722_devices, ARRAY_SIZE(sh7722_devices)); } -__initcall(sh7722_devices_setup); +arch_initcall(sh7722_devices_setup); static struct platform_device *sh7722_early_devices[] __initdata = { &cmt_device, diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7723.c b/arch/sh/kernel/cpu/sh4a/setup-sh7723.c index e1bb80b..b45dace 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7723.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7723.c @@ -473,7 +473,7 @@ static int __init sh7723_devices_setup(void) return platform_add_devices(sh7723_devices, ARRAY_SIZE(sh7723_devices)); } -__initcall(sh7723_devices_setup); +arch_initcall(sh7723_devices_setup); static struct platform_device *sh7723_early_devices[] __initdata = { &cmt_device, diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c index e5ac9eb..a04edaa 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c @@ -508,7 +508,7 @@ static int __init sh7724_devices_setup(void) return platform_add_devices(sh7724_devices, ARRAY_SIZE(sh7724_devices)); } -device_initcall(sh7724_devices_setup); +arch_initcall(sh7724_devices_setup); static struct platform_device *sh7724_early_devices[] __initdata = { &cmt_device, diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7763.c b/arch/sh/kernel/cpu/sh4a/setup-sh7763.c index f1e0c0d..4659fff 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7763.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7763.c @@ -314,7 +314,7 @@ static int __init sh7763_devices_setup(void) return platform_add_devices(sh7763_devices, ARRAY_SIZE(sh7763_devices)); } -__initcall(sh7763_devices_setup); +arch_initcall(sh7763_devices_setup); static struct platform_device *sh7763_early_devices[] __initdata = { &tmu0_device, diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7770.c b/arch/sh/kernel/cpu/sh4a/setup-sh7770.c index 1e86209..eead08d 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7770.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7770.c @@ -368,7 +368,7 @@ static int __init sh7770_devices_setup(void) return platform_add_devices(sh7770_devices, ARRAY_SIZE(sh7770_devices)); } -__initcall(sh7770_devices_setup); +arch_initcall(sh7770_devices_setup); static struct platform_device *sh7770_early_devices[] __initdata = { &tmu0_device, diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7780.c b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c index 715e05b..2c901f4 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7780.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c @@ -256,7 +256,7 @@ static int __init sh7780_devices_setup(void) return platform_add_devices(sh7780_devices, ARRAY_SIZE(sh7780_devices)); } -__initcall(sh7780_devices_setup); +arch_initcall(sh7780_devices_setup); static struct platform_device *sh7780_early_devices[] __initdata = { &tmu0_device, diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c index af56140..7f6c718 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c @@ -263,7 +263,7 @@ static int __init sh7785_devices_setup(void) return platform_add_devices(sh7785_devices, ARRAY_SIZE(sh7785_devices)); } -__initcall(sh7785_devices_setup); +arch_initcall(sh7785_devices_setup); static struct platform_device *sh7785_early_devices[] __initdata = { &tmu0_device, diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7786.c b/arch/sh/kernel/cpu/sh4a/setup-sh7786.c index b700494..0104a8e 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7786.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7786.c @@ -547,7 +547,7 @@ static int __init sh7786_devices_setup(void) return platform_add_devices(sh7786_devices, ARRAY_SIZE(sh7786_devices)); } -device_initcall(sh7786_devices_setup); +arch_initcall(sh7786_devices_setup); void __init plat_early_device_setup(void) { diff --git a/arch/sh/kernel/cpu/sh4a/setup-shx3.c b/arch/sh/kernel/cpu/sh4a/setup-shx3.c index 53c65fd..07f0789 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-shx3.c +++ b/arch/sh/kernel/cpu/sh4a/setup-shx3.c @@ -256,7 +256,7 @@ static int __init shx3_devices_setup(void) return platform_add_devices(shx3_devices, ARRAY_SIZE(shx3_devices)); } -__initcall(shx3_devices_setup); +arch_initcall(shx3_devices_setup); void __init plat_early_device_setup(void) { diff --git a/arch/sh/kernel/cpu/sh5/setup-sh5.c b/arch/sh/kernel/cpu/sh5/setup-sh5.c index f5ff1ac..6a0f82f 100644 --- a/arch/sh/kernel/cpu/sh5/setup-sh5.c +++ b/arch/sh/kernel/cpu/sh5/setup-sh5.c @@ -186,7 +186,7 @@ static int __init sh5_devices_setup(void) return platform_add_devices(sh5_devices, ARRAY_SIZE(sh5_devices)); } -__initcall(sh5_devices_setup); +arch_initcall(sh5_devices_setup); void __init plat_early_device_setup(void) { diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 738bdc6..13ffa5d 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -24,6 +24,7 @@ config X86 select HAVE_UNSTABLE_SCHED_CLOCK select HAVE_IDE select HAVE_OPROFILE + select HAVE_PERF_COUNTERS if (!M386 && !M486) select HAVE_IOREMAP_PROT select HAVE_KPROBES select ARCH_WANT_OPTIONAL_GPIOLIB @@ -742,7 +743,6 @@ config X86_UP_IOAPIC config X86_LOCAL_APIC def_bool y depends on X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_APIC - select HAVE_PERF_COUNTERS if (!M386 && !M486) config X86_IO_APIC def_bool y diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index e2485b0..63fddcd0 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -400,6 +400,13 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c) level = cpuid_eax(1); if((level >= 0x0f48 && level < 0x0f50) || level >= 0x0f58) set_cpu_cap(c, X86_FEATURE_REP_GOOD); + + /* + * Some BIOSes incorrectly force this feature, but only K8 + * revision D (model = 0x14) and later actually support it. + */ + if (c->x86_model < 0x14) + clear_cpu_cap(c, X86_FEATURE_LAHF_LM); } if (c->x86 == 0x10 || c->x86 == 0x11) set_cpu_cap(c, X86_FEATURE_REP_GOOD); diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index f1961c0..5ce60a8 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -59,7 +59,30 @@ void __init setup_cpu_local_masks(void) alloc_bootmem_cpumask_var(&cpu_sibling_setup_mask); } -static const struct cpu_dev *this_cpu __cpuinitdata; +static void __cpuinit default_init(struct cpuinfo_x86 *c) +{ +#ifdef CONFIG_X86_64 + display_cacheinfo(c); +#else + /* Not much we can do here... */ + /* Check if at least it has cpuid */ + if (c->cpuid_level == -1) { + /* No cpuid. It must be an ancient CPU */ + if (c->x86 == 4) + strcpy(c->x86_model_id, "486"); + else if (c->x86 == 3) + strcpy(c->x86_model_id, "386"); + } +#endif +} + +static const struct cpu_dev __cpuinitconst default_cpu = { + .c_init = default_init, + .c_vendor = "Unknown", + .c_x86_vendor = X86_VENDOR_UNKNOWN, +}; + +static const struct cpu_dev *this_cpu __cpuinitdata = &default_cpu; DEFINE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page) = { .gdt = { #ifdef CONFIG_X86_64 @@ -332,29 +355,6 @@ void switch_to_new_gdt(int cpu) static const struct cpu_dev *__cpuinitdata cpu_devs[X86_VENDOR_NUM] = {}; -static void __cpuinit default_init(struct cpuinfo_x86 *c) -{ -#ifdef CONFIG_X86_64 - display_cacheinfo(c); -#else - /* Not much we can do here... */ - /* Check if at least it has cpuid */ - if (c->cpuid_level == -1) { - /* No cpuid. It must be an ancient CPU */ - if (c->x86 == 4) - strcpy(c->x86_model_id, "486"); - else if (c->x86 == 3) - strcpy(c->x86_model_id, "386"); - } -#endif -} - -static const struct cpu_dev __cpuinitconst default_cpu = { - .c_init = default_init, - .c_vendor = "Unknown", - .c_x86_vendor = X86_VENDOR_UNKNOWN, -}; - static void __cpuinit get_model_name(struct cpuinfo_x86 *c) { unsigned int *v; diff --git a/arch/x86/kernel/cpu/mcheck/therm_throt.c b/arch/x86/kernel/cpu/mcheck/therm_throt.c index bff8dd1..8bc64cf 100644 --- a/arch/x86/kernel/cpu/mcheck/therm_throt.c +++ b/arch/x86/kernel/cpu/mcheck/therm_throt.c @@ -36,6 +36,7 @@ static DEFINE_PER_CPU(__u64, next_check) = INITIAL_JIFFIES; static DEFINE_PER_CPU(unsigned long, thermal_throttle_count); +static DEFINE_PER_CPU(bool, thermal_throttle_active); static atomic_t therm_throt_en = ATOMIC_INIT(0); @@ -96,24 +97,27 @@ static int therm_throt_process(int curr) { unsigned int cpu = smp_processor_id(); __u64 tmp_jiffs = get_jiffies_64(); + bool was_throttled = __get_cpu_var(thermal_throttle_active); + bool is_throttled = __get_cpu_var(thermal_throttle_active) = curr; - if (curr) + if (is_throttled) __get_cpu_var(thermal_throttle_count)++; - if (time_before64(tmp_jiffs, __get_cpu_var(next_check))) + if (!(was_throttled ^ is_throttled) && + time_before64(tmp_jiffs, __get_cpu_var(next_check))) return 0; __get_cpu_var(next_check) = tmp_jiffs + CHECK_INTERVAL; /* if we just entered the thermal event */ - if (curr) { + if (is_throttled) { printk(KERN_CRIT "CPU%d: Temperature above threshold, " - "cpu clock throttled (total events = %lu)\n", cpu, - __get_cpu_var(thermal_throttle_count)); + "cpu clock throttled (total events = %lu)\n", + cpu, __get_cpu_var(thermal_throttle_count)); add_taint(TAINT_MACHINE_CHECK); - } else { - printk(KERN_CRIT "CPU%d: Temperature/speed normal\n", cpu); + } else if (was_throttled) { + printk(KERN_INFO "CPU%d: Temperature/speed normal\n", cpu); } return 1; diff --git a/arch/x86/kernel/cpu/perf_counter.c b/arch/x86/kernel/cpu/perf_counter.c index a7aa8f9..900332b 100644 --- a/arch/x86/kernel/cpu/perf_counter.c +++ b/arch/x86/kernel/cpu/perf_counter.c @@ -55,6 +55,7 @@ struct x86_pmu { int num_counters_fixed; int counter_bits; u64 counter_mask; + int apic; u64 max_period; u64 intel_ctrl; }; @@ -72,8 +73,8 @@ static const u64 p6_perfmon_event_map[] = { [PERF_COUNT_HW_CPU_CYCLES] = 0x0079, [PERF_COUNT_HW_INSTRUCTIONS] = 0x00c0, - [PERF_COUNT_HW_CACHE_REFERENCES] = 0x0000, - [PERF_COUNT_HW_CACHE_MISSES] = 0x0000, + [PERF_COUNT_HW_CACHE_REFERENCES] = 0x0f2e, + [PERF_COUNT_HW_CACHE_MISSES] = 0x012e, [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x00c4, [PERF_COUNT_HW_BRANCH_MISSES] = 0x00c5, [PERF_COUNT_HW_BUS_CYCLES] = 0x0062, @@ -613,6 +614,7 @@ static DEFINE_MUTEX(pmc_reserve_mutex); static bool reserve_pmc_hardware(void) { +#ifdef CONFIG_X86_LOCAL_APIC int i; if (nmi_watchdog == NMI_LOCAL_APIC) @@ -627,9 +629,11 @@ static bool reserve_pmc_hardware(void) if (!reserve_evntsel_nmi(x86_pmu.eventsel + i)) goto eventsel_fail; } +#endif return true; +#ifdef CONFIG_X86_LOCAL_APIC eventsel_fail: for (i--; i >= 0; i--) release_evntsel_nmi(x86_pmu.eventsel + i); @@ -644,10 +648,12 @@ perfctr_fail: enable_lapic_nmi_watchdog(); return false; +#endif } static void release_pmc_hardware(void) { +#ifdef CONFIG_X86_LOCAL_APIC int i; for (i = 0; i < x86_pmu.num_counters; i++) { @@ -657,6 +663,7 @@ static void release_pmc_hardware(void) if (nmi_watchdog == NMI_LOCAL_APIC) enable_lapic_nmi_watchdog(); +#endif } static void hw_perf_counter_destroy(struct perf_counter *counter) @@ -748,6 +755,15 @@ static int __hw_perf_counter_init(struct perf_counter *counter) hwc->sample_period = x86_pmu.max_period; hwc->last_period = hwc->sample_period; atomic64_set(&hwc->period_left, hwc->sample_period); + } else { + /* + * If we have a PMU initialized but no APIC + * interrupts, we cannot sample hardware + * counters (user-space has to fall back and + * sample via a hrtimer based software counter): + */ + if (!x86_pmu.apic) + return -EOPNOTSUPP; } counter->destroy = hw_perf_counter_destroy; @@ -1449,18 +1465,22 @@ void smp_perf_pending_interrupt(struct pt_regs *regs) void set_perf_counter_pending(void) { +#ifdef CONFIG_X86_LOCAL_APIC apic->send_IPI_self(LOCAL_PENDING_VECTOR); +#endif } void perf_counters_lapic_init(void) { - if (!x86_pmu_initialized()) +#ifdef CONFIG_X86_LOCAL_APIC + if (!x86_pmu.apic || !x86_pmu_initialized()) return; /* * Always use NMI for PMU */ apic_write(APIC_LVTPC, APIC_DM_NMI); +#endif } static int __kprobes @@ -1484,7 +1504,9 @@ perf_counter_nmi_handler(struct notifier_block *self, regs = args->regs; +#ifdef CONFIG_X86_LOCAL_APIC apic_write(APIC_LVTPC, APIC_DM_NMI); +#endif /* * Can't rely on the handled return value to say it was our NMI, two * counters could trigger 'simultaneously' raising two back-to-back NMIs. @@ -1515,6 +1537,7 @@ static struct x86_pmu p6_pmu = { .event_map = p6_pmu_event_map, .raw_event = p6_pmu_raw_event, .max_events = ARRAY_SIZE(p6_perfmon_event_map), + .apic = 1, .max_period = (1ULL << 31) - 1, .version = 0, .num_counters = 2, @@ -1541,6 +1564,7 @@ static struct x86_pmu intel_pmu = { .event_map = intel_pmu_event_map, .raw_event = intel_pmu_raw_event, .max_events = ARRAY_SIZE(intel_perfmon_event_map), + .apic = 1, /* * Intel PMCs cannot be accessed sanely above 32 bit width, * so we install an artificial 1<<31 period regardless of @@ -1564,6 +1588,7 @@ static struct x86_pmu amd_pmu = { .num_counters = 4, .counter_bits = 48, .counter_mask = (1ULL << 48) - 1, + .apic = 1, /* use highest bit to detect overflow */ .max_period = (1ULL << 47) - 1, }; @@ -1589,13 +1614,14 @@ static int p6_pmu_init(void) return -ENODEV; } + x86_pmu = p6_pmu; + if (!cpu_has_apic) { - pr_info("no Local APIC, try rebooting with lapic"); - return -ENODEV; + pr_info("no APIC, boot with the \"lapic\" boot parameter to force-enable it.\n"); + pr_info("no hardware sampling interrupt available.\n"); + x86_pmu.apic = 0; } - x86_pmu = p6_pmu; - return 0; } diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 9eb8976..a06e8d1 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -418,20 +418,20 @@ static int __init set_pci_reboot(const struct dmi_system_id *d) } static struct dmi_system_id __initdata pci_reboot_dmi_table[] = { - { /* Handle problems with rebooting on Apple MacBook5,2 */ + { /* Handle problems with rebooting on Apple MacBook5 */ .callback = set_pci_reboot, - .ident = "Apple MacBook", + .ident = "Apple MacBook5", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5,2"), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5"), }, }, - { /* Handle problems with rebooting on Apple MacBookPro5,1 */ + { /* Handle problems with rebooting on Apple MacBookPro5 */ .callback = set_pci_reboot, - .ident = "Apple MacBookPro5,1", + .ident = "Apple MacBookPro5", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,1"), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5"), }, }, { } diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 958c1fa..fe3eba5 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -219,6 +219,8 @@ enum { AHCI_HFLAG_SECT255 = (1 << 8), /* max 255 sectors */ AHCI_HFLAG_YES_NCQ = (1 << 9), /* force NCQ cap on */ AHCI_HFLAG_NO_SUSPEND = (1 << 10), /* don't suspend */ + AHCI_HFLAG_SRST_TOUT_IS_OFFLINE = (1 << 11), /* treat SRST timeout as + link offline */ /* ap->flags bits */ @@ -1663,6 +1665,7 @@ static int ahci_do_softreset(struct ata_link *link, unsigned int *class, int (*check_ready)(struct ata_link *link)) { struct ata_port *ap = link->ap; + struct ahci_host_priv *hpriv = ap->host->private_data; const char *reason = NULL; unsigned long now, msecs; struct ata_taskfile tf; @@ -1701,12 +1704,21 @@ static int ahci_do_softreset(struct ata_link *link, unsigned int *class, /* wait for link to become ready */ rc = ata_wait_after_reset(link, deadline, check_ready); - /* link occupied, -ENODEV too is an error */ - if (rc) { + if (rc == -EBUSY && hpriv->flags & AHCI_HFLAG_SRST_TOUT_IS_OFFLINE) { + /* + * Workaround for cases where link online status can't + * be trusted. Treat device readiness timeout as link + * offline. + */ + ata_link_printk(link, KERN_INFO, + "device not ready, treating as offline\n"); + *class = ATA_DEV_NONE; + } else if (rc) { + /* link occupied, -ENODEV too is an error */ reason = "device not ready"; goto fail; - } - *class = ahci_dev_classify(ap); + } else + *class = ahci_dev_classify(ap); DPRINTK("EXIT, class=%u\n", *class); return 0; @@ -1773,7 +1785,8 @@ static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class, irq_sts = readl(port_mmio + PORT_IRQ_STAT); if (irq_sts & PORT_IRQ_BAD_PMP) { ata_link_printk(link, KERN_WARNING, - "failed due to HW bug, retry pmp=0\n"); + "applying SB600 PMP SRST workaround " + "and retrying\n"); rc = ahci_do_softreset(link, class, 0, deadline, ahci_check_ready); } @@ -2726,6 +2739,56 @@ static bool ahci_broken_suspend(struct pci_dev *pdev) return !ver || strcmp(ver, dmi->driver_data) < 0; } +static bool ahci_broken_online(struct pci_dev *pdev) +{ +#define ENCODE_BUSDEVFN(bus, slot, func) \ + (void *)(unsigned long)(((bus) << 8) | PCI_DEVFN((slot), (func))) + static const struct dmi_system_id sysids[] = { + /* + * There are several gigabyte boards which use + * SIMG5723s configured as hardware RAID. Certain + * 5723 firmware revisions shipped there keep the link + * online but fail to answer properly to SRST or + * IDENTIFY when no device is attached downstream + * causing libata to retry quite a few times leading + * to excessive detection delay. + * + * As these firmwares respond to the second reset try + * with invalid device signature, considering unknown + * sig as offline works around the problem acceptably. + */ + { + .ident = "EP45-DQ6", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, + "Gigabyte Technology Co., Ltd."), + DMI_MATCH(DMI_BOARD_NAME, "EP45-DQ6"), + }, + .driver_data = ENCODE_BUSDEVFN(0x0a, 0x00, 0), + }, + { + .ident = "EP45-DS5", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, + "Gigabyte Technology Co., Ltd."), + DMI_MATCH(DMI_BOARD_NAME, "EP45-DS5"), + }, + .driver_data = ENCODE_BUSDEVFN(0x03, 0x00, 0), + }, + { } /* terminate list */ + }; +#undef ENCODE_BUSDEVFN + const struct dmi_system_id *dmi = dmi_first_match(sysids); + unsigned int val; + + if (!dmi) + return false; + + val = (unsigned long)dmi->driver_data; + + return pdev->bus->number == (val >> 8) && pdev->devfn == (val & 0xff); +} + static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; @@ -2841,6 +2904,12 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) "BIOS update required for suspend/resume\n"); } + if (ahci_broken_online(pdev)) { + hpriv->flags |= AHCI_HFLAG_SRST_TOUT_IS_OFFLINE; + dev_info(&pdev->dev, + "online status unreliable, applying workaround\n"); + } + /* CAP.NP sometimes indicate the index of the last enabled * port, at other times, that of the last possible port, so * determining the maximum port number requires looking at diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 8ac98ff..072ba5e 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4302,6 +4302,9 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "WDC WD2500JD-00HBB0", "WD-WMAL71490727", ATA_HORKAGE_BROKEN_HPA }, { "MAXTOR 6L080L4", "A93.0500", ATA_HORKAGE_BROKEN_HPA }, + /* this one allows HPA unlocking but fails IOs on the area */ + { "OCZ-VERTEX", "1.30", ATA_HORKAGE_BROKEN_HPA }, + /* Devices which report 1 sector over size HPA */ { "ST340823A", NULL, ATA_HORKAGE_HPA_SIZE, }, { "ST320413A", NULL, ATA_HORKAGE_HPA_SIZE, }, diff --git a/drivers/ata/pata_at91.c b/drivers/ata/pata_at91.c index 5702aff..41c94b1 100644 --- a/drivers/ata/pata_at91.c +++ b/drivers/ata/pata_at91.c @@ -250,7 +250,7 @@ static int __devinit pata_at91_probe(struct platform_device *pdev) ata_port_desc(ap, "no IRQ, using PIO polling"); } - info = kzalloc(sizeof(*info), GFP_KERNEL); + info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); if (!info) { dev_err(dev, "failed to allocate memory for private data\n"); @@ -275,7 +275,7 @@ static int __devinit pata_at91_probe(struct platform_device *pdev) if (!info->ide_addr) { dev_err(dev, "failed to map IO base\n"); ret = -ENOMEM; - goto err_ide_ioremap; + goto err_put; } info->alt_addr = devm_ioremap(dev, @@ -284,7 +284,7 @@ static int __devinit pata_at91_probe(struct platform_device *pdev) if (!info->alt_addr) { dev_err(dev, "failed to map CTL base\n"); ret = -ENOMEM; - goto err_alt_ioremap; + goto err_put; } ap->ioaddr.cmd_addr = info->ide_addr; @@ -303,13 +303,8 @@ static int __devinit pata_at91_probe(struct platform_device *pdev) irq ? ata_sff_interrupt : NULL, irq_flags, &pata_at91_sht); -err_alt_ioremap: - devm_iounmap(dev, info->ide_addr); - -err_ide_ioremap: +err_put: clk_put(info->mck); - kfree(info); - return ret; } @@ -317,7 +312,6 @@ static int __devexit pata_at91_remove(struct platform_device *pdev) { struct ata_host *host = dev_get_drvdata(&pdev->dev); struct at91_ide_info *info; - struct device *dev = &pdev->dev; if (!host) return 0; @@ -328,11 +322,8 @@ static int __devexit pata_at91_remove(struct platform_device *pdev) if (!info) return 0; - devm_iounmap(dev, info->ide_addr); - devm_iounmap(dev, info->alt_addr); clk_put(info->mck); - kfree(info); return 0; } diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index bec0b8a..4591556 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c @@ -1,6 +1,7 @@ /* * pata_atiixp.c - ATI PATA for new ATA layer * (C) 2005 Red Hat Inc + * (C) 2009 Bartlomiej Zolnierkiewicz * * Based on * @@ -61,20 +62,19 @@ static void atiixp_set_pio_timing(struct ata_port *ap, struct ata_device *adev, struct pci_dev *pdev = to_pci_dev(ap->host->dev); int dn = 2 * ap->port_no + adev->devno; - - /* Check this is correct - the order is odd in both drivers */ int timing_shift = (16 * ap->port_no) + 8 * (adev->devno ^ 1); - u16 pio_mode_data, pio_timing_data; + u32 pio_timing_data; + u16 pio_mode_data; pci_read_config_word(pdev, ATIIXP_IDE_PIO_MODE, &pio_mode_data); pio_mode_data &= ~(0x7 << (4 * dn)); pio_mode_data |= pio << (4 * dn); pci_write_config_word(pdev, ATIIXP_IDE_PIO_MODE, pio_mode_data); - pci_read_config_word(pdev, ATIIXP_IDE_PIO_TIMING, &pio_timing_data); + pci_read_config_dword(pdev, ATIIXP_IDE_PIO_TIMING, &pio_timing_data); pio_timing_data &= ~(0xFF << timing_shift); pio_timing_data |= (pio_timings[pio] << timing_shift); - pci_write_config_word(pdev, ATIIXP_IDE_PIO_TIMING, pio_timing_data); + pci_write_config_dword(pdev, ATIIXP_IDE_PIO_TIMING, pio_timing_data); } /** @@ -119,16 +119,17 @@ static void atiixp_set_dmamode(struct ata_port *ap, struct ata_device *adev) udma_mode_data |= dma << (4 * dn); pci_write_config_word(pdev, ATIIXP_IDE_UDMA_MODE, udma_mode_data); } else { - u16 mwdma_timing_data; - /* Check this is correct - the order is odd in both drivers */ int timing_shift = (16 * ap->port_no) + 8 * (adev->devno ^ 1); + u32 mwdma_timing_data; dma -= XFER_MW_DMA_0; - pci_read_config_word(pdev, ATIIXP_IDE_MWDMA_TIMING, &mwdma_timing_data); + pci_read_config_dword(pdev, ATIIXP_IDE_MWDMA_TIMING, + &mwdma_timing_data); mwdma_timing_data &= ~(0xFF << timing_shift); mwdma_timing_data |= (mwdma_timings[dma] << timing_shift); - pci_write_config_word(pdev, ATIIXP_IDE_MWDMA_TIMING, mwdma_timing_data); + pci_write_config_dword(pdev, ATIIXP_IDE_MWDMA_TIMING, + mwdma_timing_data); } /* * We must now look at the PIO mode situation. We may need to diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index b2d11f3..86a4058 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -602,6 +602,7 @@ MODULE_VERSION(DRV_VERSION); static int adma_enabled; static int swncq_enabled = 1; +static int msi_enabled; static void nv_adma_register_mode(struct ata_port *ap) { @@ -2459,6 +2460,11 @@ static int nv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) } else if (type == SWNCQ) nv_swncq_host_init(host); + if (msi_enabled) { + dev_printk(KERN_NOTICE, &pdev->dev, "Using MSI\n"); + pci_enable_msi(pdev); + } + pci_set_master(pdev); return ata_host_activate(host, pdev->irq, ipriv->irq_handler, IRQF_SHARED, ipriv->sht); @@ -2558,4 +2564,6 @@ module_param_named(adma, adma_enabled, bool, 0444); MODULE_PARM_DESC(adma, "Enable use of ADMA (Default: false)"); module_param_named(swncq, swncq_enabled, bool, 0444); MODULE_PARM_DESC(swncq, "Enable use of SWNCQ (Default: true)"); +module_param_named(msi, msi_enabled, bool, 0444); +MODULE_PARM_DESC(msi, "Enable use of MSI (Default: false)"); diff --git a/drivers/base/platform.c b/drivers/base/platform.c index ae5c4aa..d28c289 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -483,9 +483,6 @@ int platform_driver_register(struct platform_driver *drv) drv->driver.remove = platform_drv_remove; if (drv->shutdown) drv->driver.shutdown = platform_drv_shutdown; - if (drv->suspend || drv->resume) - pr_warning("Platform driver '%s' needs updating - please use " - "dev_pm_ops\n", drv->driver.name); return driver_register(&drv->driver); } diff --git a/drivers/md/md.c b/drivers/md/md.c index 5b98bea..103f2d3 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -359,6 +359,7 @@ static mddev_t * mddev_find(dev_t unit) else new->md_minor = MINOR(unit) >> MdpMinorShift; + mutex_init(&new->open_mutex); mutex_init(&new->reconfig_mutex); INIT_LIST_HEAD(&new->disks); INIT_LIST_HEAD(&new->all_mddevs); @@ -1974,17 +1975,14 @@ repeat: /* otherwise we have to go forward and ... */ mddev->events ++; if (!mddev->in_sync || mddev->recovery_cp != MaxSector) { /* not clean */ - /* .. if the array isn't clean, insist on an odd 'events' */ - if ((mddev->events&1)==0) { - mddev->events++; + /* .. if the array isn't clean, an 'even' event must also go + * to spares. */ + if ((mddev->events&1)==0) nospares = 0; - } } else { - /* otherwise insist on an even 'events' (for clean states) */ - if ((mddev->events&1)) { - mddev->events++; + /* otherwise an 'odd' event must go to spares */ + if ((mddev->events&1)) nospares = 0; - } } } @@ -3601,6 +3599,7 @@ max_sync_store(mddev_t *mddev, const char *buf, size_t len) if (max < mddev->resync_min) return -EINVAL; if (max < mddev->resync_max && + mddev->ro == 0 && test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) return -EBUSY; @@ -4304,12 +4303,11 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open) struct gendisk *disk = mddev->gendisk; mdk_rdev_t *rdev; + mutex_lock(&mddev->open_mutex); if (atomic_read(&mddev->openers) > is_open) { printk("md: %s still in use.\n",mdname(mddev)); - return -EBUSY; - } - - if (mddev->pers) { + err = -EBUSY; + } else if (mddev->pers) { if (mddev->sync_thread) { set_bit(MD_RECOVERY_FROZEN, &mddev->recovery); @@ -4367,7 +4365,10 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open) set_disk_ro(disk, 1); clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery); } - +out: + mutex_unlock(&mddev->open_mutex); + if (err) + return err; /* * Free resources if final stop */ @@ -4433,7 +4434,6 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open) blk_integrity_unregister(disk); md_new_event(mddev); sysfs_notify_dirent(mddev->sysfs_state); -out: return err; } @@ -5518,12 +5518,12 @@ static int md_open(struct block_device *bdev, fmode_t mode) } BUG_ON(mddev != bdev->bd_disk->private_data); - if ((err = mutex_lock_interruptible_nested(&mddev->reconfig_mutex, 1))) + if ((err = mutex_lock_interruptible(&mddev->open_mutex))) goto out; err = 0; atomic_inc(&mddev->openers); - mddev_unlock(mddev); + mutex_unlock(&mddev->open_mutex); check_disk_change(bdev); out: diff --git a/drivers/md/md.h b/drivers/md/md.h index 78f0316..f8fc188 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -223,6 +223,16 @@ struct mddev_s * so we don't loop trying */ int in_sync; /* know to not need resync */ + /* 'open_mutex' avoids races between 'md_open' and 'do_md_stop', so + * that we are never stopping an array while it is open. + * 'reconfig_mutex' protects all other reconfiguration. + * These locks are separate due to conflicting interactions + * with bdev->bd_mutex. + * Lock ordering is: + * reconfig_mutex -> bd_mutex : e.g. do_md_run -> revalidate_disk + * bd_mutex -> open_mutex: e.g. __blkdev_get -> md_open + */ + struct mutex open_mutex; struct mutex reconfig_mutex; atomic_t active; /* general refcount */ atomic_t openers; /* number of active opens */ diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 2b521ee..b8a2c5d 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3785,7 +3785,7 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped conf->reshape_progress < raid5_size(mddev, 0, 0)) { sector_nr = raid5_size(mddev, 0, 0) - conf->reshape_progress; - } else if (mddev->delta_disks > 0 && + } else if (mddev->delta_disks >= 0 && conf->reshape_progress > 0) sector_nr = conf->reshape_progress; sector_div(sector_nr, new_data_disks); @@ -4509,7 +4509,26 @@ static int run(mddev_t *mddev) (old_disks-max_degraded)); /* here_old is the first stripe that we might need to read * from */ - if (here_new >= here_old) { + if (mddev->delta_disks == 0) { + /* We cannot be sure it is safe to start an in-place + * reshape. It is only safe if user-space if monitoring + * and taking constant backups. + * mdadm always starts a situation like this in + * readonly mode so it can take control before + * allowing any writes. So just check for that. + */ + if ((here_new * mddev->new_chunk_sectors != + here_old * mddev->chunk_sectors) || + mddev->ro == 0) { + printk(KERN_ERR "raid5: in-place reshape must be started" + " in read-only mode - aborting\n"); + return -EINVAL; + } + } else if (mddev->delta_disks < 0 + ? (here_new * mddev->new_chunk_sectors <= + here_old * mddev->chunk_sectors) + : (here_new * mddev->new_chunk_sectors >= + here_old * mddev->chunk_sectors)) { /* Reading from the same stripe as writing to - bad */ printk(KERN_ERR "raid5: reshape_position too early for " "auto-recovery - aborting.\n"); @@ -5078,8 +5097,15 @@ static void raid5_finish_reshape(mddev_t *mddev) mddev->degraded--; for (d = conf->raid_disks ; d < conf->raid_disks - mddev->delta_disks; - d++) - raid5_remove_disk(mddev, d); + d++) { + mdk_rdev_t *rdev = conf->disks[d].rdev; + if (rdev && raid5_remove_disk(mddev, d) == 0) { + char nm[20]; + sprintf(nm, "rd%d", rdev->raid_disk); + sysfs_remove_link(&mddev->kobj, nm); + rdev->raid_disk = -1; + } + } } mddev->layout = conf->algorithm; mddev->chunk_sectors = conf->chunk_sectors; diff --git a/drivers/media/common/tuners/qt1010.c b/drivers/media/common/tuners/qt1010.c index 825aa14..9f5dba2 100644 --- a/drivers/media/common/tuners/qt1010.c +++ b/drivers/media/common/tuners/qt1010.c @@ -64,24 +64,22 @@ static int qt1010_writereg(struct qt1010_priv *priv, u8 reg, u8 val) /* dump all registers */ static void qt1010_dump_regs(struct qt1010_priv *priv) { - char buf[52], buf2[4]; u8 reg, val; for (reg = 0; ; reg++) { if (reg % 16 == 0) { if (reg) - printk("%s\n", buf); - sprintf(buf, "%02x: ", reg); + printk(KERN_CONT "\n"); + printk(KERN_DEBUG "%02x:", reg); } if (qt1010_readreg(priv, reg, &val) == 0) - sprintf(buf2, "%02x ", val); + printk(KERN_CONT " %02x", val); else - strcpy(buf2, "-- "); - strcat(buf, buf2); + printk(KERN_CONT " --"); if (reg == 0x2f) break; } - printk("%s\n", buf); + printk(KERN_CONT "\n"); } static int qt1010_set_params(struct dvb_frontend *fe, diff --git a/drivers/media/common/tuners/tuner-xc2028.c b/drivers/media/common/tuners/tuner-xc2028.c index aa20ce8..f270e60 100644 --- a/drivers/media/common/tuners/tuner-xc2028.c +++ b/drivers/media/common/tuners/tuner-xc2028.c @@ -1119,8 +1119,8 @@ static int xc2028_sleep(struct dvb_frontend *fe) struct xc2028_data *priv = fe->tuner_priv; int rc = 0; - /* Avoid firmware reload on slow devices */ - if (no_poweroff) + /* Avoid firmware reload on slow devices or if PM disabled */ + if (no_poweroff || priv->ctrl.disable_power_mgmt) return 0; tuner_dbg("Putting xc2028/3028 into poweroff mode.\n"); diff --git a/drivers/media/common/tuners/tuner-xc2028.h b/drivers/media/common/tuners/tuner-xc2028.h index 19de792..a90c35d 100644 --- a/drivers/media/common/tuners/tuner-xc2028.h +++ b/drivers/media/common/tuners/tuner-xc2028.h @@ -38,6 +38,7 @@ struct xc2028_ctrl { unsigned int input1:1; unsigned int vhfbw7:1; unsigned int uhfbw8:1; + unsigned int disable_power_mgmt:1; unsigned int demod; enum firmware_type type:2; }; diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index 4cb31e7..26690df 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -81,7 +81,6 @@ static int af9015_rw_udev(struct usb_device *udev, struct req_t *req) switch (req->cmd) { case GET_CONFIG: - case BOOT: case READ_MEMORY: case RECONNECT_USB: case GET_IR_CODE: @@ -100,6 +99,7 @@ static int af9015_rw_udev(struct usb_device *udev, struct req_t *req) case WRITE_VIRTUAL_MEMORY: case COPY_FIRMWARE: case DOWNLOAD_FIRMWARE: + case BOOT: break; default: err("unknown command:%d", req->cmd); diff --git a/drivers/media/dvb/frontends/cx22700.c b/drivers/media/dvb/frontends/cx22700.c index ace5cb1..fbd838e 100644 --- a/drivers/media/dvb/frontends/cx22700.c +++ b/drivers/media/dvb/frontends/cx22700.c @@ -380,7 +380,7 @@ struct dvb_frontend* cx22700_attach(const struct cx22700_config* config, struct cx22700_state* state = NULL; /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct cx22700_state), GFP_KERNEL); + state = kzalloc(sizeof(struct cx22700_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c index 5d1abe3..00b5c7e 100644 --- a/drivers/media/dvb/frontends/cx22702.c +++ b/drivers/media/dvb/frontends/cx22702.c @@ -580,7 +580,7 @@ struct dvb_frontend *cx22702_attach(const struct cx22702_config *config, struct cx22702_state *state = NULL; /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct cx22702_state), GFP_KERNEL); + state = kzalloc(sizeof(struct cx22702_state), GFP_KERNEL); if (state == NULL) goto error; diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c index 87ae29d..ffbcfab 100644 --- a/drivers/media/dvb/frontends/cx24110.c +++ b/drivers/media/dvb/frontends/cx24110.c @@ -598,7 +598,7 @@ struct dvb_frontend* cx24110_attach(const struct cx24110_config* config, int ret; /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct cx24110_state), GFP_KERNEL); + state = kzalloc(sizeof(struct cx24110_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ diff --git a/drivers/media/dvb/frontends/dvb_dummy_fe.c b/drivers/media/dvb/frontends/dvb_dummy_fe.c index db8a937..a7fc7e5 100644 --- a/drivers/media/dvb/frontends/dvb_dummy_fe.c +++ b/drivers/media/dvb/frontends/dvb_dummy_fe.c @@ -117,7 +117,7 @@ struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void) struct dvb_dummy_fe_state* state = NULL; /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); + state = kzalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); if (state == NULL) goto error; /* create dvb_frontend */ @@ -137,7 +137,7 @@ struct dvb_frontend *dvb_dummy_fe_qpsk_attach(void) struct dvb_dummy_fe_state* state = NULL; /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); + state = kzalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); if (state == NULL) goto error; /* create dvb_frontend */ @@ -157,7 +157,7 @@ struct dvb_frontend *dvb_dummy_fe_qam_attach(void) struct dvb_dummy_fe_state* state = NULL; /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); + state = kzalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); if (state == NULL) goto error; /* create dvb_frontend */ diff --git a/drivers/media/dvb/frontends/l64781.c b/drivers/media/dvb/frontends/l64781.c index e1e70e9..3051b64 100644 --- a/drivers/media/dvb/frontends/l64781.c +++ b/drivers/media/dvb/frontends/l64781.c @@ -501,7 +501,7 @@ struct dvb_frontend* l64781_attach(const struct l64781_config* config, { .addr = config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct l64781_state), GFP_KERNEL); + state = kzalloc(sizeof(struct l64781_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ diff --git a/drivers/media/dvb/frontends/lgs8gl5.c b/drivers/media/dvb/frontends/lgs8gl5.c index 855852f..bb37ed2 100644 --- a/drivers/media/dvb/frontends/lgs8gl5.c +++ b/drivers/media/dvb/frontends/lgs8gl5.c @@ -387,7 +387,7 @@ lgs8gl5_attach(const struct lgs8gl5_config *config, struct i2c_adapter *i2c) dprintk("%s\n", __func__); /* Allocate memory for the internal state */ - state = kmalloc(sizeof(struct lgs8gl5_state), GFP_KERNEL); + state = kzalloc(sizeof(struct lgs8gl5_state), GFP_KERNEL); if (state == NULL) goto error; diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c index a621f72..f69daaa 100644 --- a/drivers/media/dvb/frontends/mt312.c +++ b/drivers/media/dvb/frontends/mt312.c @@ -782,7 +782,7 @@ struct dvb_frontend *mt312_attach(const struct mt312_config *config, struct mt312_state *state = NULL; /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct mt312_state), GFP_KERNEL); + state = kzalloc(sizeof(struct mt312_state), GFP_KERNEL); if (state == NULL) goto error; diff --git a/drivers/media/dvb/frontends/nxt6000.c b/drivers/media/dvb/frontends/nxt6000.c index 0eef22d..a763ec75 100644 --- a/drivers/media/dvb/frontends/nxt6000.c +++ b/drivers/media/dvb/frontends/nxt6000.c @@ -545,7 +545,7 @@ struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config, struct nxt6000_state* state = NULL; /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct nxt6000_state), GFP_KERNEL); + state = kzalloc(sizeof(struct nxt6000_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c index 8133ea3..38e67ac 100644 --- a/drivers/media/dvb/frontends/or51132.c +++ b/drivers/media/dvb/frontends/or51132.c @@ -562,7 +562,7 @@ struct dvb_frontend* or51132_attach(const struct or51132_config* config, struct or51132_state* state = NULL; /* Allocate memory for the internal state */ - state = kmalloc(sizeof(struct or51132_state), GFP_KERNEL); + state = kzalloc(sizeof(struct or51132_state), GFP_KERNEL); if (state == NULL) return NULL; diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c index 16cf2fdd..c709ce6 100644 --- a/drivers/media/dvb/frontends/or51211.c +++ b/drivers/media/dvb/frontends/or51211.c @@ -527,7 +527,7 @@ struct dvb_frontend* or51211_attach(const struct or51211_config* config, struct or51211_state* state = NULL; /* Allocate memory for the internal state */ - state = kmalloc(sizeof(struct or51211_state), GFP_KERNEL); + state = kzalloc(sizeof(struct or51211_state), GFP_KERNEL); if (state == NULL) return NULL; diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c index 3e08d98..fb30115 100644 --- a/drivers/media/dvb/frontends/s5h1409.c +++ b/drivers/media/dvb/frontends/s5h1409.c @@ -796,7 +796,7 @@ struct dvb_frontend *s5h1409_attach(const struct s5h1409_config *config, u16 reg; /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct s5h1409_state), GFP_KERNEL); + state = kzalloc(sizeof(struct s5h1409_state), GFP_KERNEL); if (state == NULL) goto error; diff --git a/drivers/media/dvb/frontends/s5h1411.c b/drivers/media/dvb/frontends/s5h1411.c index 66e2dd6..d8adf1e 100644 --- a/drivers/media/dvb/frontends/s5h1411.c +++ b/drivers/media/dvb/frontends/s5h1411.c @@ -844,7 +844,7 @@ struct dvb_frontend *s5h1411_attach(const struct s5h1411_config *config, u16 reg; /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct s5h1411_state), GFP_KERNEL); + state = kzalloc(sizeof(struct s5h1411_state), GFP_KERNEL); if (state == NULL) goto error; diff --git a/drivers/media/dvb/frontends/si21xx.c b/drivers/media/dvb/frontends/si21xx.c index 0bd16af..9552a22 100644 --- a/drivers/media/dvb/frontends/si21xx.c +++ b/drivers/media/dvb/frontends/si21xx.c @@ -928,7 +928,7 @@ struct dvb_frontend *si21xx_attach(const struct si21xx_config *config, dprintk("%s\n", __func__); /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct si21xx_state), GFP_KERNEL); + state = kzalloc(sizeof(struct si21xx_state), GFP_KERNEL); if (state == NULL) goto error; diff --git a/drivers/media/dvb/frontends/sp8870.c b/drivers/media/dvb/frontends/sp8870.c index 1c9a9b4..b85eb60 100644 --- a/drivers/media/dvb/frontends/sp8870.c +++ b/drivers/media/dvb/frontends/sp8870.c @@ -557,7 +557,7 @@ struct dvb_frontend* sp8870_attach(const struct sp8870_config* config, struct sp8870_state* state = NULL; /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct sp8870_state), GFP_KERNEL); + state = kzalloc(sizeof(struct sp8870_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c index 559509a..4a7c3d8 100644 --- a/drivers/media/dvb/frontends/sp887x.c +++ b/drivers/media/dvb/frontends/sp887x.c @@ -557,7 +557,7 @@ struct dvb_frontend* sp887x_attach(const struct sp887x_config* config, struct sp887x_state* state = NULL; /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct sp887x_state), GFP_KERNEL); + state = kzalloc(sizeof(struct sp887x_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ diff --git a/drivers/media/dvb/frontends/stv0288.c b/drivers/media/dvb/frontends/stv0288.c index ff1194d..2930a5d 100644 --- a/drivers/media/dvb/frontends/stv0288.c +++ b/drivers/media/dvb/frontends/stv0288.c @@ -570,7 +570,7 @@ struct dvb_frontend *stv0288_attach(const struct stv0288_config *config, int id; /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct stv0288_state), GFP_KERNEL); + state = kzalloc(sizeof(struct stv0288_state), GFP_KERNEL); if (state == NULL) goto error; diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c index 62caf80..4fd7479 100644 --- a/drivers/media/dvb/frontends/stv0297.c +++ b/drivers/media/dvb/frontends/stv0297.c @@ -663,7 +663,7 @@ struct dvb_frontend *stv0297_attach(const struct stv0297_config *config, struct stv0297_state *state = NULL; /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct stv0297_state), GFP_KERNEL); + state = kzalloc(sizeof(struct stv0297_state), GFP_KERNEL); if (state == NULL) goto error; diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c index 6c1cb19..9688744 100644 --- a/drivers/media/dvb/frontends/stv0299.c +++ b/drivers/media/dvb/frontends/stv0299.c @@ -667,7 +667,7 @@ struct dvb_frontend* stv0299_attach(const struct stv0299_config* config, int id; /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct stv0299_state), GFP_KERNEL); + state = kzalloc(sizeof(struct stv0299_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c index f648fdb..f5d7b32 100644 --- a/drivers/media/dvb/frontends/tda10021.c +++ b/drivers/media/dvb/frontends/tda10021.c @@ -413,7 +413,7 @@ struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config, u8 id; /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct tda10021_state), GFP_KERNEL); + state = kzalloc(sizeof(struct tda10021_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ diff --git a/drivers/media/dvb/frontends/tda10048.c b/drivers/media/dvb/frontends/tda10048.c index cc8862c..4e2a7c8 100644 --- a/drivers/media/dvb/frontends/tda10048.c +++ b/drivers/media/dvb/frontends/tda10048.c @@ -1095,7 +1095,7 @@ struct dvb_frontend *tda10048_attach(const struct tda10048_config *config, dprintk(1, "%s()\n", __func__); /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct tda10048_state), GFP_KERNEL); + state = kzalloc(sizeof(struct tda10048_state), GFP_KERNEL); if (state == NULL) goto error; diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c index 4981cef..f2a8abe 100644 --- a/drivers/media/dvb/frontends/tda1004x.c +++ b/drivers/media/dvb/frontends/tda1004x.c @@ -1269,7 +1269,7 @@ struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config, int id; /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL); + state = kzalloc(sizeof(struct tda1004x_state), GFP_KERNEL); if (!state) { printk(KERN_ERR "Can't alocate memory for tda10045 state\n"); return NULL; @@ -1339,7 +1339,7 @@ struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config, int id; /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL); + state = kzalloc(sizeof(struct tda1004x_state), GFP_KERNEL); if (!state) { printk(KERN_ERR "Can't alocate memory for tda10046 state\n"); return NULL; diff --git a/drivers/media/dvb/frontends/tda10086.c b/drivers/media/dvb/frontends/tda10086.c index a17ce3c..f2c8faa 100644 --- a/drivers/media/dvb/frontends/tda10086.c +++ b/drivers/media/dvb/frontends/tda10086.c @@ -745,7 +745,7 @@ struct dvb_frontend* tda10086_attach(const struct tda10086_config* config, dprintk ("%s\n", __func__); /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct tda10086_state), GFP_KERNEL); + state = kzalloc(sizeof(struct tda10086_state), GFP_KERNEL); if (!state) return NULL; diff --git a/drivers/media/dvb/frontends/tda8083.c b/drivers/media/dvb/frontends/tda8083.c index 5b843b2..9369f74 100644 --- a/drivers/media/dvb/frontends/tda8083.c +++ b/drivers/media/dvb/frontends/tda8083.c @@ -417,7 +417,7 @@ struct dvb_frontend* tda8083_attach(const struct tda8083_config* config, struct tda8083_state* state = NULL; /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct tda8083_state), GFP_KERNEL); + state = kzalloc(sizeof(struct tda8083_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ diff --git a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c index a184597..6e78e48 100644 --- a/drivers/media/dvb/frontends/ves1820.c +++ b/drivers/media/dvb/frontends/ves1820.c @@ -374,7 +374,7 @@ struct dvb_frontend* ves1820_attach(const struct ves1820_config* config, struct ves1820_state* state = NULL; /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct ves1820_state), GFP_KERNEL); + state = kzalloc(sizeof(struct ves1820_state), GFP_KERNEL); if (state == NULL) goto error; diff --git a/drivers/media/dvb/frontends/ves1x93.c b/drivers/media/dvb/frontends/ves1x93.c index bd55896..8d7854c 100644 --- a/drivers/media/dvb/frontends/ves1x93.c +++ b/drivers/media/dvb/frontends/ves1x93.c @@ -456,7 +456,7 @@ struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config, u8 identity; /* allocate memory for the internal state */ - state = kmalloc(sizeof(struct ves1x93_state), GFP_KERNEL); + state = kzalloc(sizeof(struct ves1x93_state), GFP_KERNEL); if (state == NULL) goto error; /* setup the state */ diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c index 148b6f7..66f5c1f 100644 --- a/drivers/media/dvb/frontends/zl10353.c +++ b/drivers/media/dvb/frontends/zl10353.c @@ -98,7 +98,6 @@ static int zl10353_read_register(struct zl10353_state *state, u8 reg) static void zl10353_dump_regs(struct dvb_frontend *fe) { struct zl10353_state *state = fe->demodulator_priv; - char buf[52], buf2[4]; int ret; u8 reg; @@ -106,19 +105,18 @@ static void zl10353_dump_regs(struct dvb_frontend *fe) for (reg = 0; ; reg++) { if (reg % 16 == 0) { if (reg) - printk(KERN_DEBUG "%s\n", buf); - sprintf(buf, "%02x: ", reg); + printk(KERN_CONT "\n"); + printk(KERN_DEBUG "%02x:", reg); } ret = zl10353_read_register(state, reg); if (ret >= 0) - sprintf(buf2, "%02x ", (u8)ret); + printk(KERN_CONT " %02x", (u8)ret); else - strcpy(buf2, "-- "); - strcat(buf, buf2); + printk(KERN_CONT " --"); if (reg == 0xff) break; } - printk(KERN_DEBUG "%s\n", buf); + printk(KERN_CONT "\n"); } static void zl10353_calc_nominal_rate(struct dvb_frontend *fe, diff --git a/drivers/media/dvb/siano/Kconfig b/drivers/media/dvb/siano/Kconfig index dd863f2..88847d1 100644 --- a/drivers/media/dvb/siano/Kconfig +++ b/drivers/media/dvb/siano/Kconfig @@ -4,7 +4,7 @@ config DVB_SIANO_SMS1XXX tristate "Siano SMS1XXX USB dongle support" - depends on DVB_CORE && USB + depends on DVB_CORE && USB && INPUT ---help--- Choose Y here if you have a USB dongle with a SMS1XXX chipset. diff --git a/drivers/media/dvb/siano/sms-cards.c b/drivers/media/dvb/siano/sms-cards.c index d8b15d5..0420e28 100644 --- a/drivers/media/dvb/siano/sms-cards.c +++ b/drivers/media/dvb/siano/sms-cards.c @@ -116,99 +116,21 @@ static inline void sms_gpio_assign_11xx_default_led_config( int sms_board_event(struct smscore_device_t *coredev, enum SMS_BOARD_EVENTS gevent) { - int board_id = smscore_get_board_id(coredev); - struct sms_board *board = sms_get_board(board_id); struct smscore_gpio_config MyGpioConfig; sms_gpio_assign_11xx_default_led_config(&MyGpioConfig); switch (gevent) { case BOARD_EVENT_POWER_INIT: /* including hotplug */ - switch (board_id) { - case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: - /* set I/O and turn off all LEDs */ - smscore_gpio_configure(coredev, - board->board_cfg.leds_power, - &MyGpioConfig); - smscore_gpio_set_level(coredev, - board->board_cfg.leds_power, 0); - smscore_gpio_configure(coredev, board->board_cfg.led0, - &MyGpioConfig); - smscore_gpio_set_level(coredev, - board->board_cfg.led0, 0); - smscore_gpio_configure(coredev, board->board_cfg.led1, - &MyGpioConfig); - smscore_gpio_set_level(coredev, - board->board_cfg.led1, 0); - break; - case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2: - case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD: - /* set I/O and turn off LNA */ - smscore_gpio_configure(coredev, - board->board_cfg.foreign_lna0_ctrl, - &MyGpioConfig); - smscore_gpio_set_level(coredev, - board->board_cfg.foreign_lna0_ctrl, - 0); - break; - } break; /* BOARD_EVENT_BIND */ case BOARD_EVENT_POWER_SUSPEND: - switch (board_id) { - case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: - smscore_gpio_set_level(coredev, - board->board_cfg.leds_power, 0); - smscore_gpio_set_level(coredev, - board->board_cfg.led0, 0); - smscore_gpio_set_level(coredev, - board->board_cfg.led1, 0); - break; - case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2: - case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD: - smscore_gpio_set_level(coredev, - board->board_cfg.foreign_lna0_ctrl, - 0); - break; - } break; /* BOARD_EVENT_POWER_SUSPEND */ case BOARD_EVENT_POWER_RESUME: - switch (board_id) { - case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: - smscore_gpio_set_level(coredev, - board->board_cfg.leds_power, 1); - smscore_gpio_set_level(coredev, - board->board_cfg.led0, 1); - smscore_gpio_set_level(coredev, - board->board_cfg.led1, 0); - break; - case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2: - case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD: - smscore_gpio_set_level(coredev, - board->board_cfg.foreign_lna0_ctrl, - 1); - break; - } break; /* BOARD_EVENT_POWER_RESUME */ case BOARD_EVENT_BIND: - switch (board_id) { - case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: - smscore_gpio_set_level(coredev, - board->board_cfg.leds_power, 1); - smscore_gpio_set_level(coredev, - board->board_cfg.led0, 1); - smscore_gpio_set_level(coredev, - board->board_cfg.led1, 0); - break; - case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2: - case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD: - smscore_gpio_set_level(coredev, - board->board_cfg.foreign_lna0_ctrl, - 1); - break; - } break; /* BOARD_EVENT_BIND */ case BOARD_EVENT_SCAN_PROG: @@ -218,20 +140,8 @@ int sms_board_event(struct smscore_device_t *coredev, case BOARD_EVENT_EMERGENCY_WARNING_SIGNAL: break; /* BOARD_EVENT_EMERGENCY_WARNING_SIGNAL */ case BOARD_EVENT_FE_LOCK: - switch (board_id) { - case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: - smscore_gpio_set_level(coredev, - board->board_cfg.led1, 1); - break; - } break; /* BOARD_EVENT_FE_LOCK */ case BOARD_EVENT_FE_UNLOCK: - switch (board_id) { - case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: - smscore_gpio_set_level(coredev, - board->board_cfg.led1, 0); - break; - } break; /* BOARD_EVENT_FE_UNLOCK */ case BOARD_EVENT_DEMOD_LOCK: break; /* BOARD_EVENT_DEMOD_LOCK */ @@ -248,20 +158,8 @@ int sms_board_event(struct smscore_device_t *coredev, case BOARD_EVENT_RECEPTION_LOST_0: break; /* BOARD_EVENT_RECEPTION_LOST_0 */ case BOARD_EVENT_MULTIPLEX_OK: - switch (board_id) { - case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: - smscore_gpio_set_level(coredev, - board->board_cfg.led1, 1); - break; - } break; /* BOARD_EVENT_MULTIPLEX_OK */ case BOARD_EVENT_MULTIPLEX_ERRORS: - switch (board_id) { - case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: - smscore_gpio_set_level(coredev, - board->board_cfg.led1, 0); - break; - } break; /* BOARD_EVENT_MULTIPLEX_ERRORS */ default: diff --git a/drivers/media/dvb/siano/smscoreapi.c b/drivers/media/dvb/siano/smscoreapi.c index a246903..bd9ab9d 100644 --- a/drivers/media/dvb/siano/smscoreapi.c +++ b/drivers/media/dvb/siano/smscoreapi.c @@ -816,7 +816,7 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode) sms_debug("set device mode to %d", mode); if (coredev->device_flags & SMS_DEVICE_FAMILY2) { - if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_RAW_TUNER) { + if (mode < DEVICE_MODE_DVBT || mode >= DEVICE_MODE_RAW_TUNER) { sms_err("invalid mode specified %d", mode); return -EINVAL; } diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 84b6fc1..dcf9fa9 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -920,6 +920,8 @@ source "drivers/media/video/pwc/Kconfig" config USB_ZR364XX tristate "USB ZR364XX Camera support" depends on VIDEO_V4L2 + select VIDEOBUF_GEN + select VIDEOBUF_VMALLOC ---help--- Say Y here if you want to connect this type of camera to your computer's USB port. diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c index 10dbd4a..9e39bc5 100644 --- a/drivers/media/video/bw-qcam.c +++ b/drivers/media/video/bw-qcam.c @@ -992,7 +992,7 @@ static int accept_bwqcam(struct parport *port) if (parport[0] && strncmp(parport[0], "auto", 4) != 0) { /* user gave parport parameters */ - for(n=0; parport[n] && n<MAX_CAMS; n++){ + for (n = 0; n < MAX_CAMS && parport[n]; n++) { char *ep; unsigned long r; r = simple_strtoul(parport[n], &ep, 0); diff --git a/drivers/media/video/cx18/cx18-controls.c b/drivers/media/video/cx18/cx18-controls.c index 5136df1..93f0dae 100644 --- a/drivers/media/video/cx18/cx18-controls.c +++ b/drivers/media/video/cx18/cx18-controls.c @@ -20,6 +20,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA */ +#include <linux/kernel.h> #include "cx18-driver.h" #include "cx18-cards.h" @@ -317,7 +318,7 @@ int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c) idx = p.audio_properties & 0x03; /* The audio clock of the digitizer must match the codec sample rate otherwise you get some very strange effects. */ - if (idx < sizeof(freqs)) + if (idx < ARRAY_SIZE(freqs)) cx18_call_all(cx, audio, s_clock_freq, freqs[idx]); return err; } diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c index e0cf21e..1a1048b 100644 --- a/drivers/media/video/cx23885/cx23885-417.c +++ b/drivers/media/video/cx23885/cx23885-417.c @@ -1715,6 +1715,8 @@ static struct video_device cx23885_mpeg_template = { .fops = &mpeg_fops, .ioctl_ops = &mpeg_ioctl_ops, .minor = -1, + .tvnorms = CX23885_NORMS, + .current_norm = V4L2_STD_NTSC_M, }; void cx23885_417_unregister(struct cx23885_dev *dev) diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index a5cc1c1..3946530 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -3003,6 +3003,14 @@ void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl) case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO: ctl->demod = XC3028_FE_OREN538; break; + case CX88_BOARD_GENIATECH_X8000_MT: + /* FIXME: For this board, the xc3028 never recovers after being + powered down (the reset GPIO probably is not set properly). + We don't have access to the hardware so we cannot determine + which GPIO is used for xc3028, so just disable power xc3028 + power management for now */ + ctl->disable_power_mgmt = 1; + break; case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL: case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME: case CX88_BOARD_PROLINK_PV_8000GT: diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index c44e876..e237b50 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -501,6 +501,7 @@ static struct zl10353_config cx88_pinnacle_hybrid_pctv = { static struct zl10353_config cx88_geniatech_x8000_mt = { .demod_address = (0x1e >> 1), .no_tuner = 1, + .disable_i2c_gate_ctrl = 1, }; static struct s5h1411_config dvico_fusionhdtv7_config = { diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index da4e391..7172dcf 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -116,6 +116,10 @@ static int cx8802_start_dma(struct cx8802_dev *dev, udelay(100); break; case CX88_BOARD_HAUPPAUGE_HVR1300: + /* Enable MPEG parallel IO and video signal pins */ + cx_write(MO_PINMUX_IO, 0x88); + cx_write(TS_SOP_STAT, 0); + cx_write(TS_VALERR_CNTRL, 0); break; case CX88_BOARD_PINNACLE_PCTV_HD_800i: /* Enable MPEG parallel IO and video signal pins */ diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 320f1f6..ed281f5 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -218,7 +218,7 @@ static struct em28xx_reg_seq silvercrest_reg_seq[] = { struct em28xx_board em28xx_boards[] = { [EM2750_BOARD_UNKNOWN] = { .name = "EM2710/EM2750/EM2751 webcam grabber", - .xclk = EM28XX_XCLK_FREQUENCY_48MHZ, + .xclk = EM28XX_XCLK_FREQUENCY_20MHZ, .tuner_type = TUNER_ABSENT, .is_webcam = 1, .input = { { @@ -622,22 +622,27 @@ struct em28xx_board em28xx_boards[] = { }, [EM2861_BOARD_PLEXTOR_PX_TV100U] = { .name = "Plextor ConvertX PX-TV100U", - .valid = EM28XX_BOARD_NOT_VALIDATED, .tuner_type = TUNER_TNF_5335MF, + .xclk = EM28XX_XCLK_I2S_MSB_TIMING | + EM28XX_XCLK_FREQUENCY_12MHZ, .tda9887_conf = TDA9887_PRESENT, .decoder = EM28XX_TVP5150, + .has_msp34xx = 1, .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, .amux = EM28XX_AMUX_LINE_IN, + .gpio = pinnacle_hybrid_pro_analog, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, .amux = EM28XX_AMUX_LINE_IN, + .gpio = pinnacle_hybrid_pro_analog, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, .amux = EM28XX_AMUX_LINE_IN, + .gpio = pinnacle_hybrid_pro_analog, } }, }, @@ -1544,6 +1549,8 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM2750_BOARD_UNKNOWN }, { USB_DEVICE(0xeb1a, 0x2800), .driver_info = EM2800_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2710), + .driver_info = EM2820_BOARD_UNKNOWN }, { USB_DEVICE(0xeb1a, 0x2820), .driver_info = EM2820_BOARD_UNKNOWN }, { USB_DEVICE(0xeb1a, 0x2821), @@ -1761,6 +1768,7 @@ static int em28xx_hint_sensor(struct em28xx *dev) __be16 version_be; u16 version; + /* Micron sensor detection */ dev->i2c_client.addr = 0xba >> 1; cmd = 0; i2c_master_send(&dev->i2c_client, &cmd, 1); @@ -1769,15 +1777,27 @@ static int em28xx_hint_sensor(struct em28xx *dev) return -EINVAL; version = be16_to_cpu(version_be); - switch (version) { - case 0x8243: /* mt9v011 640x480 1.3 Mpix sensor */ + case 0x8232: /* mt9v011 640x480 1.3 Mpix sensor */ + case 0x8243: /* mt9v011 rev B 640x480 1.3 Mpix sensor */ dev->model = EM2820_BOARD_SILVERCREST_WEBCAM; + em28xx_set_model(dev); + sensor_name = "mt9v011"; dev->em28xx_sensor = EM28XX_MT9V011; dev->sensor_xres = 640; dev->sensor_yres = 480; - dev->sensor_xtal = 6300000; + /* + * FIXME: mt9v011 uses I2S speed as xtal clk - at least with + * the Silvercrest cam I have here for testing - for higher + * resolutions, a high clock cause horizontal artifacts, so we + * need to use a lower xclk frequency. + * Yet, it would be possible to adjust xclk depending on the + * desired resolution, since this affects directly the + * frame rate. + */ + dev->board.xclk = EM28XX_XCLK_FREQUENCY_4_3MHZ; + dev->sensor_xtal = 4300000; /* probably means GRGB 16 bit bayer */ dev->vinmode = 0x0d; @@ -1786,6 +1806,8 @@ static int em28xx_hint_sensor(struct em28xx *dev) break; case 0x8431: dev->model = EM2750_BOARD_UNKNOWN; + em28xx_set_model(dev); + sensor_name = "mt9m001"; dev->em28xx_sensor = EM28XX_MT9M001; em28xx_initialize_mt9m001(dev); @@ -1802,6 +1824,9 @@ static int em28xx_hint_sensor(struct em28xx *dev) return -EINVAL; } + /* Setup webcam defaults */ + em28xx_pre_card_setup(dev); + em28xx_errdev("Sensor is %s, using model %s entry.\n", sensor_name, em28xx_boards[dev->model].name); @@ -1813,60 +1838,6 @@ static int em28xx_hint_sensor(struct em28xx *dev) */ void em28xx_pre_card_setup(struct em28xx *dev) { - int rc; - - em28xx_set_model(dev); - - em28xx_info("Identified as %s (card=%d)\n", - dev->board.name, dev->model); - - /* Set the default GPO/GPIO for legacy devices */ - dev->reg_gpo_num = EM2880_R04_GPO; - dev->reg_gpio_num = EM28XX_R08_GPIO; - - dev->wait_after_write = 5; - - /* Based on the Chip ID, set the device configuration */ - rc = em28xx_read_reg(dev, EM28XX_R0A_CHIPID); - if (rc > 0) { - dev->chip_id = rc; - - switch (dev->chip_id) { - case CHIP_ID_EM2750: - em28xx_info("chip ID is em2750\n"); - break; - case CHIP_ID_EM2820: - em28xx_info("chip ID is em2710 or em2820\n"); - break; - case CHIP_ID_EM2840: - em28xx_info("chip ID is em2840\n"); - break; - case CHIP_ID_EM2860: - em28xx_info("chip ID is em2860\n"); - break; - case CHIP_ID_EM2870: - em28xx_info("chip ID is em2870\n"); - dev->wait_after_write = 0; - break; - case CHIP_ID_EM2874: - em28xx_info("chip ID is em2874\n"); - dev->reg_gpio_num = EM2874_R80_GPIO; - dev->wait_after_write = 0; - break; - case CHIP_ID_EM2883: - em28xx_info("chip ID is em2882/em2883\n"); - dev->wait_after_write = 0; - break; - default: - em28xx_info("em28xx chip ID = %d\n", dev->chip_id); - } - } - - /* Prepopulate cached GPO register content */ - rc = em28xx_read_reg(dev, dev->reg_gpo_num); - if (rc >= 0) - dev->reg_gpo = rc; - /* Set the initial XCLK and I2C clock values based on the board definition */ em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk & 0x7f); @@ -1876,9 +1847,8 @@ void em28xx_pre_card_setup(struct em28xx *dev) /* request some modules */ switch (dev->model) { case EM2861_BOARD_PLEXTOR_PX_TV100U: - /* FIXME guess */ - /* Turn on analog audio output */ - em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd); + /* Sets the msp34xx I2S speed */ + dev->i2s_speed = 2048000; break; case EM2861_BOARD_KWORLD_PVRTV_300U: case EM2880_BOARD_KWORLD_DVB_305U: @@ -2216,7 +2186,20 @@ void em28xx_register_i2c_ir(struct em28xx *dev) void em28xx_card_setup(struct em28xx *dev) { - em28xx_set_model(dev); + /* + * If the device can be a webcam, seek for a sensor. + * If sensor is not found, then it isn't a webcam. + */ + if (dev->board.is_webcam) { + if (em28xx_hint_sensor(dev) < 0) + dev->board.is_webcam = 0; + else + dev->progressive = 1; + } else + em28xx_set_model(dev); + + em28xx_info("Identified as %s (card=%d)\n", + dev->board.name, dev->model); dev->tuner_type = em28xx_boards[dev->model].tuner_type; if (em28xx_boards[dev->model].tuner_addr) @@ -2290,10 +2273,6 @@ void em28xx_card_setup(struct em28xx *dev) em28xx_gpio_set(dev, dev->board.tuner_gpio); em28xx_set_mode(dev, EM28XX_ANALOG_MODE); break; - case EM2820_BOARD_SILVERCREST_WEBCAM: - /* FIXME: need to document the registers bellow */ - em28xx_write_reg(dev, 0x0d, 0x42); - em28xx_write_reg(dev, 0x13, 0x08); } if (dev->board.has_snapshot_button) @@ -2433,7 +2412,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, int minor) { struct em28xx *dev = *devhandle; - int retval = -ENOMEM; + int retval; int errCode; dev->udev = udev; @@ -2450,6 +2429,58 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, dev->em28xx_read_reg_req = em28xx_read_reg_req; dev->board.is_em2800 = em28xx_boards[dev->model].is_em2800; + em28xx_set_model(dev); + + /* Set the default GPO/GPIO for legacy devices */ + dev->reg_gpo_num = EM2880_R04_GPO; + dev->reg_gpio_num = EM28XX_R08_GPIO; + + dev->wait_after_write = 5; + + /* Based on the Chip ID, set the device configuration */ + retval = em28xx_read_reg(dev, EM28XX_R0A_CHIPID); + if (retval > 0) { + dev->chip_id = retval; + + switch (dev->chip_id) { + case CHIP_ID_EM2710: + em28xx_info("chip ID is em2710\n"); + break; + case CHIP_ID_EM2750: + em28xx_info("chip ID is em2750\n"); + break; + case CHIP_ID_EM2820: + em28xx_info("chip ID is em2820 (or em2710)\n"); + break; + case CHIP_ID_EM2840: + em28xx_info("chip ID is em2840\n"); + break; + case CHIP_ID_EM2860: + em28xx_info("chip ID is em2860\n"); + break; + case CHIP_ID_EM2870: + em28xx_info("chip ID is em2870\n"); + dev->wait_after_write = 0; + break; + case CHIP_ID_EM2874: + em28xx_info("chip ID is em2874\n"); + dev->reg_gpio_num = EM2874_R80_GPIO; + dev->wait_after_write = 0; + break; + case CHIP_ID_EM2883: + em28xx_info("chip ID is em2882/em2883\n"); + dev->wait_after_write = 0; + break; + default: + em28xx_info("em28xx chip ID = %d\n", dev->chip_id); + } + } + + /* Prepopulate cached GPO register content */ + retval = em28xx_read_reg(dev, dev->reg_gpo_num); + if (retval >= 0) + dev->reg_gpo = retval; + em28xx_pre_card_setup(dev); if (!dev->board.is_em2800) { @@ -2484,14 +2515,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, dev->vinmode = 0x10; dev->vinctl = 0x11; - /* - * If the device can be a webcam, seek for a sensor. - * If sensor is not found, then it isn't a webcam. - */ - if (dev->board.is_webcam) - if (em28xx_hint_sensor(dev) < 0) - dev->board.is_webcam = 0; - /* Do board specific init and eeprom reading */ em28xx_card_setup(dev); diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index 5b78e19..98e140b 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c @@ -632,6 +632,9 @@ int em28xx_capture_start(struct em28xx *dev, int start) return rc; } + if (dev->board.is_webcam) + rc = em28xx_write_reg(dev, 0x13, 0x0c); + /* enable video capture */ rc = em28xx_write_reg(dev, 0x48, 0x00); @@ -720,7 +723,10 @@ int em28xx_resolution_set(struct em28xx *dev) { int width, height; width = norm_maxw(dev); - height = norm_maxh(dev) >> 1; + height = norm_maxh(dev); + + if (!dev->progressive) + height >>= norm_maxh(dev); em28xx_set_outfmt(dev); diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c index cf0ac7f..d603575 100644 --- a/drivers/media/video/em28xx/em28xx-dvb.c +++ b/drivers/media/video/em28xx/em28xx-dvb.c @@ -478,7 +478,6 @@ static int dvb_init(struct em28xx *dev) } break; case EM2880_BOARD_KWORLD_DVB_310U: - case EM2880_BOARD_EMPIRE_DUAL_TV: dvb->frontend = dvb_attach(zl10353_attach, &em28xx_zl10353_with_xc3028, &dev->i2c_adap); @@ -488,6 +487,7 @@ static int dvb_init(struct em28xx *dev) } break; case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: + case EM2880_BOARD_EMPIRE_DUAL_TV: dvb->frontend = dvb_attach(zl10353_attach, &em28xx_zl10353_xc3028_no_i2c_gate, &dev->i2c_adap); diff --git a/drivers/media/video/em28xx/em28xx-reg.h b/drivers/media/video/em28xx/em28xx-reg.h index a2676d6..6bf84bd 100644 --- a/drivers/media/video/em28xx/em28xx-reg.h +++ b/drivers/media/video/em28xx/em28xx-reg.h @@ -176,7 +176,8 @@ /* FIXME: Need to be populated with the other chip ID's */ enum em28xx_chip_id { - CHIP_ID_EM2820 = 18, /* Also used by em2710 */ + CHIP_ID_EM2710 = 17, + CHIP_ID_EM2820 = 18, /* Also used by some em2710 */ CHIP_ID_EM2840 = 20, CHIP_ID_EM2750 = 33, CHIP_ID_EM2860 = 34, diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index ff37b4c..ab079d9 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -194,15 +194,24 @@ static void em28xx_copy_video(struct em28xx *dev, startread = p; remain = len; - /* Interlaces frame */ - if (buf->top_field) + if (dev->progressive) fieldstart = outp; - else - fieldstart = outp + bytesperline; + else { + /* Interlaces two half frames */ + if (buf->top_field) + fieldstart = outp; + else + fieldstart = outp + bytesperline; + } linesdone = dma_q->pos / bytesperline; currlinedone = dma_q->pos % bytesperline; - offset = linesdone * bytesperline * 2 + currlinedone; + + if (dev->progressive) + offset = linesdone * bytesperline + currlinedone; + else + offset = linesdone * bytesperline * 2 + currlinedone; + startwrite = fieldstart + offset; lencopy = bytesperline - currlinedone; lencopy = lencopy > remain ? remain : lencopy; @@ -376,7 +385,7 @@ static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb) em28xx_isocdbg("Video frame %d, length=%i, %s\n", p[2], len, (p[2] & 1) ? "odd" : "even"); - if (!(p[2] & 1)) { + if (dev->progressive || !(p[2] & 1)) { if (buf != NULL) buffer_filled(dev, dma_q, buf); get_next_buf(dma_q, &buf); @@ -689,7 +698,10 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */ - f->fmt.pix.field = dev->interlaced ? + if (dev->progressive) + f->fmt.pix.field = V4L2_FIELD_NONE; + else + f->fmt.pix.field = dev->interlaced ? V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; mutex_unlock(&dev->lock); @@ -753,7 +765,11 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.bytesperline = (dev->width * fmt->depth + 7) >> 3; f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * height; f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - f->fmt.pix.field = V4L2_FIELD_INTERLACED; + if (dev->progressive) + f->fmt.pix.field = V4L2_FIELD_NONE; + else + f->fmt.pix.field = dev->interlaced ? + V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; return 0; } @@ -846,6 +862,41 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) return 0; } +static int vidioc_g_parm(struct file *file, void *priv, + struct v4l2_streamparm *p) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc = 0; + + if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if (dev->board.is_webcam) + rc = v4l2_device_call_until_err(&dev->v4l2_dev, 0, + video, g_parm, p); + else + v4l2_video_std_frame_period(dev->norm, + &p->parm.capture.timeperframe); + + return rc; +} + +static int vidioc_s_parm(struct file *file, void *priv, + struct v4l2_streamparm *p) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + + if (!dev->board.is_webcam) + return -EINVAL; + + if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + return v4l2_device_call_until_err(&dev->v4l2_dev, 0, video, s_parm, p); +} + static const char *iname[] = { [EM28XX_VMUX_COMPOSITE1] = "Composite1", [EM28XX_VMUX_COMPOSITE2] = "Composite2", @@ -1624,6 +1675,7 @@ static int em28xx_v4l2_open(struct file *filp) struct em28xx *dev; enum v4l2_buf_type fh_type; struct em28xx_fh *fh; + enum v4l2_field field; dev = em28xx_get_device(minor, &fh_type, &radio); @@ -1665,8 +1717,13 @@ static int em28xx_v4l2_open(struct file *filp) dev->users++; + if (dev->progressive) + field = V4L2_FIELD_NONE; + else + field = V4L2_FIELD_INTERLACED; + videobuf_queue_vmalloc_init(&fh->vb_vidq, &em28xx_video_qops, - NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED, + NULL, &dev->slock, fh->type, field, sizeof(struct em28xx_buffer), fh); mutex_unlock(&dev->lock); @@ -1885,6 +1942,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_qbuf = vidioc_qbuf, .vidioc_dqbuf = vidioc_dqbuf, .vidioc_s_std = vidioc_s_std, + .vidioc_g_parm = vidioc_g_parm, + .vidioc_s_parm = vidioc_s_parm, .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 45bd513..8c2dc38 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -484,6 +484,9 @@ struct em28xx { int sensor_xres, sensor_yres; int sensor_xtal; + /* Allows progressive (e. g. non-interlaced) mode */ + int progressive; + /* Vinmode/Vinctl used at the driver */ int vinmode, vinctl; diff --git a/drivers/media/video/hdpvr/hdpvr-video.c b/drivers/media/video/hdpvr/hdpvr-video.c index ccd47f5..d678765 100644 --- a/drivers/media/video/hdpvr/hdpvr-video.c +++ b/drivers/media/video/hdpvr/hdpvr-video.c @@ -1220,6 +1220,8 @@ static const struct video_device hdpvr_video_template = { V4L2_STD_PAL_G | V4L2_STD_PAL_H | V4L2_STD_PAL_I | V4L2_STD_PAL_D | V4L2_STD_PAL_M | V4L2_STD_PAL_N | V4L2_STD_PAL_60, + .current_norm = V4L2_STD_NTSC | V4L2_STD_PAL_M | + V4L2_STD_PAL_60, }; int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent, diff --git a/drivers/media/video/ivtv/ivtv-controls.c b/drivers/media/video/ivtv/ivtv-controls.c index a3b77ed..4a9c8ce 100644 --- a/drivers/media/video/ivtv/ivtv-controls.c +++ b/drivers/media/video/ivtv/ivtv-controls.c @@ -17,6 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <linux/kernel.h> #include "ivtv-driver.h" #include "ivtv-cards.h" @@ -281,7 +282,7 @@ int ivtv_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c) idx = p.audio_properties & 0x03; /* The audio clock of the digitizer must match the codec sample rate otherwise you get some very strange effects. */ - if (idx < sizeof(freqs)) + if (idx < ARRAY_SIZE(freqs)) ivtv_call_all(itv, audio, s_clock_freq, freqs[idx]); return err; } diff --git a/drivers/media/video/mt9v011.c b/drivers/media/video/mt9v011.c index b2260de..cc85f77 100644 --- a/drivers/media/video/mt9v011.c +++ b/drivers/media/video/mt9v011.c @@ -52,13 +52,34 @@ static struct v4l2_queryctrl mt9v011_qctrl[] = { .step = 1, .default_value = 0, .flags = 0, - }, + }, { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mirror", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Vflip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, { + } }; struct mt9v011 { struct v4l2_subdev sd; unsigned width, height; unsigned xtal; + unsigned hflip:1; + unsigned vflip:1; u16 global_gain, red_bal, blue_bal; }; @@ -131,7 +152,6 @@ static const struct i2c_reg_value mt9v011_init_default[] = { { R0A_MT9V011_CLK_SPEED, 0x0000 }, { R1E_MT9V011_DIGITAL_ZOOM, 0x0000 }, - { R20_MT9V011_READ_MODE, 0x1000 }, { R07_MT9V011_OUT_CTRL, 0x0002 }, /* chip enable */ }; @@ -156,7 +176,7 @@ static void set_balance(struct v4l2_subdev *sd) mt9v011_write(sd, R2D_MT9V011_RED_GAIN, red_gain); } -static void calc_fps(struct v4l2_subdev *sd) +static void calc_fps(struct v4l2_subdev *sd, u32 *numerator, u32 *denominator) { struct mt9v011 *core = to_mt9v011(sd); unsigned height, width, hblank, vblank, speed; @@ -179,6 +199,51 @@ static void calc_fps(struct v4l2_subdev *sd) v4l2_dbg(1, debug, sd, "Programmed to %u.%03u fps (%d pixel clcks)\n", tmp / 1000, tmp % 1000, t_time); + + if (numerator && denominator) { + *numerator = 1000; + *denominator = (u32)frames_per_ms; + } +} + +static u16 calc_speed(struct v4l2_subdev *sd, u32 numerator, u32 denominator) +{ + struct mt9v011 *core = to_mt9v011(sd); + unsigned height, width, hblank, vblank; + unsigned row_time, line_time; + u64 t_time, speed; + + /* Avoid bogus calculus */ + if (!numerator || !denominator) + return 0; + + height = mt9v011_read(sd, R03_MT9V011_HEIGHT); + width = mt9v011_read(sd, R04_MT9V011_WIDTH); + hblank = mt9v011_read(sd, R05_MT9V011_HBLANK); + vblank = mt9v011_read(sd, R06_MT9V011_VBLANK); + + row_time = width + 113 + hblank; + line_time = height + vblank + 1; + + t_time = core->xtal * ((u64)numerator); + /* round to the closest value */ + t_time += denominator / 2; + do_div(t_time, denominator); + + speed = t_time; + do_div(speed, row_time * line_time); + + /* Avoid having a negative value for speed */ + if (speed < 2) + speed = 0; + else + speed -= 2; + + /* Avoid speed overflow */ + if (speed > 15) + return 15; + + return (u16)speed; } static void set_res(struct v4l2_subdev *sd) @@ -207,9 +272,23 @@ static void set_res(struct v4l2_subdev *sd) mt9v011_write(sd, R03_MT9V011_HEIGHT, core->height); mt9v011_write(sd, R06_MT9V011_VBLANK, 508 - core->height); - calc_fps(sd); + calc_fps(sd, NULL, NULL); }; +static void set_read_mode(struct v4l2_subdev *sd) +{ + struct mt9v011 *core = to_mt9v011(sd); + unsigned mode = 0x1000; + + if (core->hflip) + mode |= 0x4000; + + if (core->vflip) + mode |= 0x8000; + + mt9v011_write(sd, R20_MT9V011_READ_MODE, mode); +} + static int mt9v011_reset(struct v4l2_subdev *sd, u32 val) { int i; @@ -220,6 +299,7 @@ static int mt9v011_reset(struct v4l2_subdev *sd, u32 val) set_balance(sd); set_res(sd); + set_read_mode(sd); return 0; }; @@ -240,6 +320,12 @@ static int mt9v011_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) case V4L2_CID_BLUE_BALANCE: ctrl->value = core->blue_bal; return 0; + case V4L2_CID_HFLIP: + ctrl->value = core->hflip ? 1 : 0; + return 0; + case V4L2_CID_VFLIP: + ctrl->value = core->vflip ? 1 : 0; + return 0; } return -EINVAL; } @@ -288,6 +374,14 @@ static int mt9v011_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) case V4L2_CID_BLUE_BALANCE: core->blue_bal = ctrl->value; break; + case V4L2_CID_HFLIP: + core->hflip = ctrl->value; + set_read_mode(sd); + return 0; + case V4L2_CID_VFLIP: + core->vflip = ctrl->value; + set_read_mode(sd); + return 0; default: return -EINVAL; } @@ -322,6 +416,44 @@ static int mt9v011_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) return 0; } +static int mt9v011_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) +{ + struct v4l2_captureparm *cp = &parms->parm.capture; + + if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + memset(cp, 0, sizeof(struct v4l2_captureparm)); + cp->capability = V4L2_CAP_TIMEPERFRAME; + calc_fps(sd, + &cp->timeperframe.numerator, + &cp->timeperframe.denominator); + + return 0; +} + +static int mt9v011_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) +{ + struct v4l2_captureparm *cp = &parms->parm.capture; + struct v4l2_fract *tpf = &cp->timeperframe; + u16 speed; + + if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + if (cp->extendedmode != 0) + return -EINVAL; + + speed = calc_speed(sd, tpf->numerator, tpf->denominator); + + mt9v011_write(sd, R0A_MT9V011_CLK_SPEED, speed); + v4l2_dbg(1, debug, sd, "Setting speed to %d\n", speed); + + /* Recalculate and update fps info */ + calc_fps(sd, &tpf->numerator, &tpf->denominator); + + return 0; +} + static int mt9v011_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) { struct v4l2_pix_format *pix = &fmt->fmt.pix; @@ -393,10 +525,13 @@ static int mt9v011_s_register(struct v4l2_subdev *sd, static int mt9v011_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) { + u16 version; struct i2c_client *client = v4l2_get_subdevdata(sd); + version = mt9v011_read(sd, R00_MT9V011_CHIP_VERSION); + return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_MT9V011, - MT9V011_VERSION); + version); } static const struct v4l2_subdev_core_ops mt9v011_core_ops = { @@ -416,6 +551,8 @@ static const struct v4l2_subdev_video_ops mt9v011_video_ops = { .enum_fmt = mt9v011_enum_fmt, .try_fmt = mt9v011_try_fmt, .s_fmt = mt9v011_s_fmt, + .g_parm = mt9v011_g_parm, + .s_parm = mt9v011_s_parm, }; static const struct v4l2_subdev_ops mt9v011_ops = { @@ -449,8 +586,9 @@ static int mt9v011_probe(struct i2c_client *c, /* Check if the sensor is really a MT9V011 */ version = mt9v011_read(sd, R00_MT9V011_CHIP_VERSION); - if (version != MT9V011_VERSION) { - v4l2_info(sd, "*** unknown micron chip detected (0x%04x.\n", + if ((version != MT9V011_VERSION) && + (version != MT9V011_REV_B_VERSION)) { + v4l2_info(sd, "*** unknown micron chip detected (0x%04x).\n", version); kfree(core); return -EINVAL; @@ -461,8 +599,8 @@ static int mt9v011_probe(struct i2c_client *c, core->height = 480; core->xtal = 27000000; /* Hz */ - v4l_info(c, "chip found @ 0x%02x (%s)\n", - c->addr << 1, c->adapter->name); + v4l_info(c, "chip found @ 0x%02x (%s - chip version 0x%04x)\n", + c->addr << 1, c->adapter->name, version); return 0; } diff --git a/drivers/media/video/mt9v011.h b/drivers/media/video/mt9v011.h index 9e443ee..3350fd6 100644 --- a/drivers/media/video/mt9v011.h +++ b/drivers/media/video/mt9v011.h @@ -30,6 +30,7 @@ #define R35_MT9V011_GLOBAL_GAIN 0x35 #define RF1_MT9V011_CHIP_ENABLE 0xf1 -#define MT9V011_VERSION 0x8243 +#define MT9V011_VERSION 0x8232 +#define MT9V011_REV_B_VERSION 0x8243 #endif diff --git a/drivers/media/video/mx1_camera.c b/drivers/media/video/mx1_camera.c index 2d07520..736c31d 100644 --- a/drivers/media/video/mx1_camera.c +++ b/drivers/media/video/mx1_camera.c @@ -234,6 +234,7 @@ static int mx1_camera_setup_dma(struct mx1_camera_dev *pcdev) return ret; } +/* Called under spinlock_irqsave(&pcdev->lock, ...) */ static void mx1_videobuf_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) { @@ -241,13 +242,10 @@ static void mx1_videobuf_queue(struct videobuf_queue *vq, struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct mx1_camera_dev *pcdev = ici->priv; struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb); - unsigned long flags; dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb, vb->baddr, vb->bsize); - spin_lock_irqsave(&pcdev->lock, flags); - list_add_tail(&vb->queue, &pcdev->capture); vb->state = VIDEOBUF_ACTIVE; @@ -264,8 +262,6 @@ static void mx1_videobuf_queue(struct videobuf_queue *vq, __raw_writel(temp, pcdev->base + CSICR1); } } - - spin_unlock_irqrestore(&pcdev->lock, flags); } static void mx1_videobuf_release(struct videobuf_queue *vq, diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c index e605c07..9770cb7 100644 --- a/drivers/media/video/mx3_camera.c +++ b/drivers/media/video/mx3_camera.c @@ -332,7 +332,10 @@ static enum pixel_fmt fourcc_to_ipu_pix(__u32 fourcc) } } -/* Called with .vb_lock held */ +/* + * Called with .vb_lock mutex held and + * under spinlock_irqsave(&mx3_cam->lock, ...) + */ static void mx3_videobuf_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) { @@ -346,7 +349,8 @@ static void mx3_videobuf_queue(struct videobuf_queue *vq, struct idmac_video_param *video = &ichan->params.video; const struct soc_camera_data_format *data_fmt = icd->current_fmt; dma_cookie_t cookie; - unsigned long flags; + + BUG_ON(!irqs_disabled()); /* This is the configuration of one sg-element */ video->out_pixel_fmt = fourcc_to_ipu_pix(data_fmt->fourcc); @@ -359,8 +363,6 @@ static void mx3_videobuf_queue(struct videobuf_queue *vq, memset((void *)vb->baddr, 0xaa, vb->bsize); #endif - spin_lock_irqsave(&mx3_cam->lock, flags); - list_add_tail(&vb->queue, &mx3_cam->capture); if (!mx3_cam->active) { @@ -370,24 +372,23 @@ static void mx3_videobuf_queue(struct videobuf_queue *vq, vb->state = VIDEOBUF_QUEUED; } - spin_unlock_irqrestore(&mx3_cam->lock, flags); + spin_unlock_irq(&mx3_cam->lock); cookie = txd->tx_submit(txd); dev_dbg(&icd->dev, "Submitted cookie %d DMA 0x%08x\n", cookie, sg_dma_address(&buf->sg)); + + spin_lock_irq(&mx3_cam->lock); + if (cookie >= 0) return; /* Submit error */ vb->state = VIDEOBUF_PREPARED; - spin_lock_irqsave(&mx3_cam->lock, flags); - list_del_init(&vb->queue); if (mx3_cam->active == buf) mx3_cam->active = NULL; - - spin_unlock_irqrestore(&mx3_cam->lock, flags); } /* Called with .vb_lock held */ diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index 46e0d8a..016bb45 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c @@ -612,6 +612,7 @@ static void pxa_camera_stop_capture(struct pxa_camera_dev *pcdev) dev_dbg(pcdev->soc_host.dev, "%s\n", __func__); } +/* Called under spinlock_irqsave(&pcdev->lock, ...) */ static void pxa_videobuf_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) { @@ -619,13 +620,10 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq, struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct pxa_camera_dev *pcdev = ici->priv; struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb); - unsigned long flags; dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d active=%p\n", __func__, vb, vb->baddr, vb->bsize, pcdev->active); - spin_lock_irqsave(&pcdev->lock, flags); - list_add_tail(&vb->queue, &pcdev->capture); vb->state = VIDEOBUF_ACTIVE; @@ -633,8 +631,6 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq, if (!pcdev->active) pxa_camera_start_capture(pcdev); - - spin_unlock_irqrestore(&pcdev->lock, flags); } static void pxa_videobuf_release(struct videobuf_queue *vq, @@ -1579,6 +1575,7 @@ static int __devinit pxa_camera_probe(struct platform_device *pdev) pcdev->mclk = 20000000; } + pcdev->soc_host.dev = &pdev->dev; pcdev->mclk_divisor = mclk_get_divisor(pcdev); INIT_LIST_HEAD(&pcdev->capture); @@ -1644,7 +1641,6 @@ static int __devinit pxa_camera_probe(struct platform_device *pdev) pcdev->soc_host.drv_name = PXA_CAM_DRV_NAME; pcdev->soc_host.ops = &pxa_soc_camera_host_ops; pcdev->soc_host.priv = pcdev; - pcdev->soc_host.dev = &pdev->dev; pcdev->soc_host.nr = pdev->id; err = soc_camera_host_register(&pcdev->soc_host); diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 06861b7..6eebe3e 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -3331,8 +3331,8 @@ struct saa7134_board saa7134_boards[] = { .gpio = 0x0200100, }, }, - [SAA7134_BOARD_HAUPPAUGE_HVR1120] = { - .name = "Hauppauge WinTV-HVR1120 ATSC/QAM-Hybrid", + [SAA7134_BOARD_HAUPPAUGE_HVR1150] = { + .name = "Hauppauge WinTV-HVR1150 ATSC/QAM-Hybrid", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_TDA8290, .radio_type = UNSET, @@ -3363,8 +3363,8 @@ struct saa7134_board saa7134_boards[] = { .gpio = 0x0800100, /* GPIO 23 HI for FM */ }, }, - [SAA7134_BOARD_HAUPPAUGE_HVR1110R3] = { - .name = "Hauppauge WinTV-HVR1110r3 DVB-T/Hybrid", + [SAA7134_BOARD_HAUPPAUGE_HVR1120] = { + .name = "Hauppauge WinTV-HVR1120 DVB-T/Hybrid", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_TDA8290, .radio_type = UNSET, @@ -5862,31 +5862,31 @@ struct pci_device_id saa7134_pci_tbl[] = { .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x0070, .subdevice = 0x6706, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1120, + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1150, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x0070, .subdevice = 0x6707, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110R3, + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1120, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x0070, .subdevice = 0x6708, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1120, + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1150, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x0070, .subdevice = 0x6709, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110R3, + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1120, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x0070, .subdevice = 0x670a, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110R3, + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1120, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, @@ -6363,8 +6363,8 @@ static int saa7134_tda8290_18271_callback(struct saa7134_dev *dev, switch (command) { case TDA18271_CALLBACK_CMD_AGC_ENABLE: /* 0 */ switch (dev->board) { + case SAA7134_BOARD_HAUPPAUGE_HVR1150: case SAA7134_BOARD_HAUPPAUGE_HVR1120: - case SAA7134_BOARD_HAUPPAUGE_HVR1110R3: ret = saa7134_tda18271_hvr11x0_toggle_agc(dev, arg); break; default: @@ -6384,8 +6384,8 @@ static int saa7134_tda8290_callback(struct saa7134_dev *dev, int ret; switch (dev->board) { + case SAA7134_BOARD_HAUPPAUGE_HVR1150: case SAA7134_BOARD_HAUPPAUGE_HVR1120: - case SAA7134_BOARD_HAUPPAUGE_HVR1110R3: /* tda8290 + tda18271 */ ret = saa7134_tda8290_18271_callback(dev, command, arg); break; @@ -6427,7 +6427,7 @@ static void hauppauge_eeprom(struct saa7134_dev *dev, u8 *eeprom_data) switch (tv.model) { case 67019: /* WinTV-HVR1110 (Retail, IR Blaster, hybrid, FM, SVid/Comp, 3.5mm audio in) */ case 67109: /* WinTV-HVR1000 (Retail, IR Receive, analog, no FM, SVid/Comp, 3.5mm audio in) */ - case 67201: /* WinTV-HVR1120 (Retail, IR Receive, hybrid, FM, SVid/Comp, 3.5mm audio in) */ + case 67201: /* WinTV-HVR1150 (Retail, IR Receive, hybrid, FM, SVid/Comp, 3.5mm audio in) */ case 67301: /* WinTV-HVR1000 (Retail, IR Receive, analog, no FM, SVid/Comp, 3.5mm audio in) */ case 67209: /* WinTV-HVR1110 (Retail, IR Receive, hybrid, FM, SVid/Comp, 3.5mm audio in) */ case 67559: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */ @@ -6435,7 +6435,7 @@ static void hauppauge_eeprom(struct saa7134_dev *dev, u8 *eeprom_data) case 67579: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM) */ case 67589: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */ case 67599: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */ - case 67651: /* WinTV-HVR1120 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */ + case 67651: /* WinTV-HVR1150 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */ case 67659: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */ break; default: @@ -6625,8 +6625,8 @@ int saa7134_board_init1(struct saa7134_dev *dev) saa_writeb (SAA7134_PRODUCTION_TEST_MODE, 0x00); break; + case SAA7134_BOARD_HAUPPAUGE_HVR1150: case SAA7134_BOARD_HAUPPAUGE_HVR1120: - case SAA7134_BOARD_HAUPPAUGE_HVR1110R3: /* GPIO 26 high for digital, low for analog */ saa7134_set_gpio(dev, 26, 0); msleep(1); @@ -6891,8 +6891,8 @@ int saa7134_board_init2(struct saa7134_dev *dev) dev->name, saa7134_boards[dev->board].name); } break; + case SAA7134_BOARD_HAUPPAUGE_HVR1150: case SAA7134_BOARD_HAUPPAUGE_HVR1120: - case SAA7134_BOARD_HAUPPAUGE_HVR1110R3: hauppauge_eeprom(dev, dev->eedata+0x80); break; case SAA7134_BOARD_HAUPPAUGE_HVR1110: diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index 31930f2..98f3efd 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -1119,7 +1119,7 @@ static int dvb_init(struct saa7134_dev *dev) &tda827x_cfg_2) < 0) goto dettach_frontend; break; - case SAA7134_BOARD_HAUPPAUGE_HVR1110R3: + case SAA7134_BOARD_HAUPPAUGE_HVR1120: fe0->dvb.frontend = dvb_attach(tda10048_attach, &hcw_tda10048_config, &dev->i2c_adap); @@ -1147,7 +1147,7 @@ static int dvb_init(struct saa7134_dev *dev) &tda827x_cfg_1) < 0) goto dettach_frontend; break; - case SAA7134_BOARD_HAUPPAUGE_HVR1120: + case SAA7134_BOARD_HAUPPAUGE_HVR1150: fe0->dvb.frontend = dvb_attach(lgdt3305_attach, &hcw_lgdt3305_config, &dev->i2c_adap); diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 8226884..fb564f1 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -278,8 +278,8 @@ struct saa7134_format { #define SAA7134_BOARD_ASUSTeK_TIGER 152 #define SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG 153 #define SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS 154 -#define SAA7134_BOARD_HAUPPAUGE_HVR1120 155 -#define SAA7134_BOARD_HAUPPAUGE_HVR1110R3 156 +#define SAA7134_BOARD_HAUPPAUGE_HVR1150 155 +#define SAA7134_BOARD_HAUPPAUGE_HVR1120 156 #define SAA7134_BOARD_AVERMEDIA_STUDIO_507UA 157 #define SAA7134_BOARD_AVERMEDIA_CARDBUS_501 158 #define SAA7134_BOARD_BEHOLD_505RDS 159 diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 0db88a5..e86878d 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -282,27 +282,24 @@ out: return ret; } +/* Called under spinlock_irqsave(&pcdev->lock, ...) */ static void sh_mobile_ceu_videobuf_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) { struct soc_camera_device *icd = vq->priv_data; struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct sh_mobile_ceu_dev *pcdev = ici->priv; - unsigned long flags; dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__, vb, vb->baddr, vb->bsize); vb->state = VIDEOBUF_QUEUED; - spin_lock_irqsave(&pcdev->lock, flags); list_add_tail(&vb->queue, &pcdev->capture); if (!pcdev->active) { pcdev->active = vb; sh_mobile_ceu_capture(pcdev); } - - spin_unlock_irqrestore(&pcdev->lock, flags); } static void sh_mobile_ceu_videobuf_release(struct videobuf_queue *vq, diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c index 4d6785e..b154bd9 100644 --- a/drivers/media/video/stk-webcam.c +++ b/drivers/media/video/stk-webcam.c @@ -1050,8 +1050,8 @@ static int stk_setup_format(struct stk_camera *dev) depth = 1; else depth = 2; - while (stk_sizes[i].m != dev->vsettings.mode - && i < ARRAY_SIZE(stk_sizes)) + while (i < ARRAY_SIZE(stk_sizes) && + stk_sizes[i].m != dev->vsettings.mode) i++; if (i == ARRAY_SIZE(stk_sizes)) { STK_ERROR("Something is broken in %s\n", __func__); diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c index 89927b7..04b4783 100644 --- a/drivers/media/video/uvc/uvc_driver.c +++ b/drivers/media/video/uvc/uvc_driver.c @@ -1845,11 +1845,29 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_STREAM_NO_FID }, - /* ViMicro */ - { .match_flags = USB_DEVICE_ID_MATCH_VENDOR + /* ViMicro Vega */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x0ac8, + .idProduct = 0x332d, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_QUIRK_FIX_BANDWIDTH }, + /* ViMicro - Minoru3D */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x0ac8, + .idProduct = 0x3410, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_QUIRK_FIX_BANDWIDTH }, + /* ViMicro Venus - Minoru3D */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, .idVendor = 0x0ac8, - .idProduct = 0x0000, + .idProduct = 0x3420, .bInterfaceClass = USB_CLASS_VIDEO, .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, diff --git a/drivers/media/video/uvc/uvc_status.c b/drivers/media/video/uvc/uvc_status.c index f152a99..1ca6dff 100644 --- a/drivers/media/video/uvc/uvc_status.c +++ b/drivers/media/video/uvc/uvc_status.c @@ -145,8 +145,8 @@ static void uvc_status_complete(struct urb *urb) break; default: - uvc_printk(KERN_INFO, "unknown event type %u.\n", - dev->status[0]); + uvc_trace(UVC_TRACE_STATUS, "Unknown status event " + "type %u.\n", dev->status[0]); break; } } diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index be64a50..f2afc4e 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c @@ -1081,8 +1081,10 @@ static long __video_do_ioctl(struct file *file, /* Calls the specific handler */ if (ops->vidioc_g_std) ret = ops->vidioc_g_std(file, fh, id); - else + else if (vfd->current_norm) *id = vfd->current_norm; + else + ret = -EINVAL; if (!ret) dbgarg(cmd, "std=0x%08Lx\n", (long long unsigned)*id); @@ -1553,12 +1555,19 @@ static long __video_do_ioctl(struct file *file, break; ret = ops->vidioc_g_parm(file, fh, p); } else { + v4l2_std_id std = vfd->current_norm; + if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - v4l2_video_std_frame_period(vfd->current_norm, - &p->parm.capture.timeperframe); ret = 0; + if (ops->vidioc_g_std) + ret = ops->vidioc_g_std(file, fh, &std); + else if (std == 0) + ret = -EINVAL; + if (ret == 0) + v4l2_video_std_frame_period(std, + &p->parm.capture.timeperframe); } dbgarg(cmd, "type=%d\n", p->type); diff --git a/drivers/mtd/maps/sbc8240.c b/drivers/mtd/maps/sbc8240.c deleted file mode 100644 index e69de29..0000000 --- a/drivers/mtd/maps/sbc8240.c +++ /dev/null diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index 23419dc..a7cbfbd 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -386,16 +386,16 @@ static ssize_t jid_show(struct gfs2_sbd *sdp, char *buf) #define GDLM_ATTR(_name,_mode,_show,_store) \ static struct gfs2_attr gdlm_attr_##_name = __ATTR(_name,_mode,_show,_store) -GDLM_ATTR(proto_name, 0444, proto_name_show, NULL); -GDLM_ATTR(block, 0644, block_show, block_store); -GDLM_ATTR(withdraw, 0644, withdraw_show, withdraw_store); -GDLM_ATTR(id, 0444, lkid_show, NULL); -GDLM_ATTR(jid, 0444, jid_show, NULL); -GDLM_ATTR(first, 0444, lkfirst_show, NULL); -GDLM_ATTR(first_done, 0444, first_done_show, NULL); -GDLM_ATTR(recover, 0200, NULL, recover_store); -GDLM_ATTR(recover_done, 0444, recover_done_show, NULL); -GDLM_ATTR(recover_status, 0444, recover_status_show, NULL); +GDLM_ATTR(proto_name, 0444, proto_name_show, NULL); +GDLM_ATTR(block, 0644, block_show, block_store); +GDLM_ATTR(withdraw, 0644, withdraw_show, withdraw_store); +GDLM_ATTR(id, 0444, lkid_show, NULL); +GDLM_ATTR(jid, 0444, jid_show, NULL); +GDLM_ATTR(first, 0444, lkfirst_show, NULL); +GDLM_ATTR(first_done, 0444, first_done_show, NULL); +GDLM_ATTR(recover, 0600, NULL, recover_store); +GDLM_ATTR(recover_done, 0444, recover_done_show, NULL); +GDLM_ATTR(recover_status, 0444, recover_status_show, NULL); static struct attribute *lock_module_attrs[] = { &gdlm_attr_proto_name.attr, diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 489fc01..e4e089a 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -255,7 +255,7 @@ static void nfs_direct_read_release(void *calldata) if (put_dreq(dreq)) nfs_direct_complete(dreq); - nfs_readdata_release(calldata); + nfs_readdata_free(data); } static const struct rpc_call_ops nfs_read_direct_ops = { @@ -314,14 +314,14 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq, data->npages, 1, 0, data->pagevec, NULL); up_read(¤t->mm->mmap_sem); if (result < 0) { - nfs_readdata_release(data); + nfs_readdata_free(data); break; } if ((unsigned)result < data->npages) { bytes = result * PAGE_SIZE; if (bytes <= pgbase) { nfs_direct_release_pages(data->pagevec, result); - nfs_readdata_release(data); + nfs_readdata_free(data); break; } bytes -= pgbase; @@ -334,7 +334,7 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq, data->inode = inode; data->cred = msg.rpc_cred; data->args.fh = NFS_FH(inode); - data->args.context = get_nfs_open_context(ctx); + data->args.context = ctx; data->args.offset = pos; data->args.pgbase = pgbase; data->args.pages = data->pagevec; @@ -441,7 +441,7 @@ static void nfs_direct_free_writedata(struct nfs_direct_req *dreq) struct nfs_write_data *data = list_entry(dreq->rewrite_list.next, struct nfs_write_data, pages); list_del(&data->pages); nfs_direct_release_pages(data->pagevec, data->npages); - nfs_writedata_release(data); + nfs_writedata_free(data); } } @@ -534,7 +534,7 @@ static void nfs_direct_commit_release(void *calldata) dprintk("NFS: %5u commit returned %d\n", data->task.tk_pid, status); nfs_direct_write_complete(dreq, data->inode); - nfs_commitdata_release(calldata); + nfs_commit_free(data); } static const struct rpc_call_ops nfs_commit_direct_ops = { @@ -570,7 +570,7 @@ static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) data->args.fh = NFS_FH(data->inode); data->args.offset = 0; data->args.count = 0; - data->args.context = get_nfs_open_context(dreq->ctx); + data->args.context = dreq->ctx; data->res.count = 0; data->res.fattr = &data->fattr; data->res.verf = &data->verf; @@ -734,14 +734,14 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq, data->npages, 0, 0, data->pagevec, NULL); up_read(¤t->mm->mmap_sem); if (result < 0) { - nfs_writedata_release(data); + nfs_writedata_free(data); break; } if ((unsigned)result < data->npages) { bytes = result * PAGE_SIZE; if (bytes <= pgbase) { nfs_direct_release_pages(data->pagevec, result); - nfs_writedata_release(data); + nfs_writedata_free(data); break; } bytes -= pgbase; @@ -756,7 +756,7 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq, data->inode = inode; data->cred = msg.rpc_cred; data->args.fh = NFS_FH(inode); - data->args.context = get_nfs_open_context(ctx); + data->args.context = ctx; data->args.offset = pos; data->args.pgbase = pgbase; data->args.pages = data->pagevec; diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 73ea5e8..12c9e66 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -60,17 +60,15 @@ struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount) return p; } -static void nfs_readdata_free(struct nfs_read_data *p) +void nfs_readdata_free(struct nfs_read_data *p) { if (p && (p->pagevec != &p->page_array[0])) kfree(p->pagevec); mempool_free(p, nfs_rdata_mempool); } -void nfs_readdata_release(void *data) +static void nfs_readdata_release(struct nfs_read_data *rdata) { - struct nfs_read_data *rdata = data; - put_nfs_open_context(rdata->args.context); nfs_readdata_free(rdata); } diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 0a0a2ff..a34fae2 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -87,17 +87,15 @@ struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount) return p; } -static void nfs_writedata_free(struct nfs_write_data *p) +void nfs_writedata_free(struct nfs_write_data *p) { if (p && (p->pagevec != &p->page_array[0])) kfree(p->pagevec); mempool_free(p, nfs_wdata_mempool); } -void nfs_writedata_release(void *data) +static void nfs_writedata_release(struct nfs_write_data *wdata) { - struct nfs_write_data *wdata = data; - put_nfs_open_context(wdata->args.context); nfs_writedata_free(wdata); } diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index 9edcde4..f9a3e89 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c @@ -1914,7 +1914,8 @@ static void ocfs2_adjust_adjacent_records(struct ocfs2_extent_rec *left_rec, * immediately to their right. */ left_clusters = le32_to_cpu(right_child_el->l_recs[0].e_cpos); - if (ocfs2_is_empty_extent(&right_child_el->l_recs[0])) { + if (!ocfs2_rec_clusters(right_child_el, &right_child_el->l_recs[0])) { + BUG_ON(right_child_el->l_tree_depth); BUG_ON(le16_to_cpu(right_child_el->l_next_free_rec) <= 1); left_clusters = le32_to_cpu(right_child_el->l_recs[1].e_cpos); } @@ -2476,15 +2477,37 @@ out_ret_path: return ret; } -static void ocfs2_update_edge_lengths(struct inode *inode, handle_t *handle, - struct ocfs2_path *path) +static int ocfs2_update_edge_lengths(struct inode *inode, handle_t *handle, + int subtree_index, struct ocfs2_path *path) { - int i, idx; + int i, idx, ret; struct ocfs2_extent_rec *rec; struct ocfs2_extent_list *el; struct ocfs2_extent_block *eb; u32 range; + /* + * In normal tree rotation process, we will never touch the + * tree branch above subtree_index and ocfs2_extend_rotate_transaction + * doesn't reserve the credits for them either. + * + * But we do have a special case here which will update the rightmost + * records for all the bh in the path. + * So we have to allocate extra credits and access them. + */ + ret = ocfs2_extend_trans(handle, + handle->h_buffer_credits + subtree_index); + if (ret) { + mlog_errno(ret); + goto out; + } + + ret = ocfs2_journal_access_path(inode, handle, path); + if (ret) { + mlog_errno(ret); + goto out; + } + /* Path should always be rightmost. */ eb = (struct ocfs2_extent_block *)path_leaf_bh(path)->b_data; BUG_ON(eb->h_next_leaf_blk != 0ULL); @@ -2505,6 +2528,8 @@ static void ocfs2_update_edge_lengths(struct inode *inode, handle_t *handle, ocfs2_journal_dirty(handle, path->p_node[i].bh); } +out: + return ret; } static void ocfs2_unlink_path(struct inode *inode, handle_t *handle, @@ -2717,7 +2742,12 @@ static int ocfs2_rotate_subtree_left(struct inode *inode, handle_t *handle, if (del_right_subtree) { ocfs2_unlink_subtree(inode, handle, left_path, right_path, subtree_index, dealloc); - ocfs2_update_edge_lengths(inode, handle, left_path); + ret = ocfs2_update_edge_lengths(inode, handle, subtree_index, + left_path); + if (ret) { + mlog_errno(ret); + goto out; + } eb = (struct ocfs2_extent_block *)path_leaf_bh(left_path)->b_data; ocfs2_et_set_last_eb_blk(et, le64_to_cpu(eb->h_blkno)); @@ -3034,7 +3064,12 @@ static int ocfs2_remove_rightmost_path(struct inode *inode, handle_t *handle, ocfs2_unlink_subtree(inode, handle, left_path, path, subtree_index, dealloc); - ocfs2_update_edge_lengths(inode, handle, left_path); + ret = ocfs2_update_edge_lengths(inode, handle, subtree_index, + left_path); + if (ret) { + mlog_errno(ret); + goto out; + } eb = (struct ocfs2_extent_block *)path_leaf_bh(left_path)->b_data; ocfs2_et_set_last_eb_blk(et, le64_to_cpu(eb->h_blkno)); diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index b2c52b3..b401654 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -193,6 +193,7 @@ static int ocfs2_get_block(struct inode *inode, sector_t iblock, (unsigned long long)OCFS2_I(inode)->ip_blkno); mlog(ML_ERROR, "Size %llu, clusters %u\n", (unsigned long long)i_size_read(inode), OCFS2_I(inode)->ip_clusters); dump_stack(); + goto bail; } past_eof = ocfs2_blocks_for_bytes(inode->i_sb, i_size_read(inode)); @@ -894,18 +895,17 @@ struct ocfs2_write_cluster_desc { */ unsigned c_new; unsigned c_unwritten; + unsigned c_needs_zero; }; -static inline int ocfs2_should_zero_cluster(struct ocfs2_write_cluster_desc *d) -{ - return d->c_new || d->c_unwritten; -} - struct ocfs2_write_ctxt { /* Logical cluster position / len of write */ u32 w_cpos; u32 w_clen; + /* First cluster allocated in a nonsparse extend */ + u32 w_first_new_cpos; + struct ocfs2_write_cluster_desc w_desc[OCFS2_MAX_CLUSTERS_PER_PAGE]; /* @@ -983,6 +983,7 @@ static int ocfs2_alloc_write_ctxt(struct ocfs2_write_ctxt **wcp, return -ENOMEM; wc->w_cpos = pos >> osb->s_clustersize_bits; + wc->w_first_new_cpos = UINT_MAX; cend = (pos + len - 1) >> osb->s_clustersize_bits; wc->w_clen = cend - wc->w_cpos + 1; get_bh(di_bh); @@ -1217,20 +1218,18 @@ out: */ static int ocfs2_write_cluster(struct address_space *mapping, u32 phys, unsigned int unwritten, + unsigned int should_zero, struct ocfs2_alloc_context *data_ac, struct ocfs2_alloc_context *meta_ac, struct ocfs2_write_ctxt *wc, u32 cpos, loff_t user_pos, unsigned user_len) { - int ret, i, new, should_zero = 0; + int ret, i, new; u64 v_blkno, p_blkno; struct inode *inode = mapping->host; struct ocfs2_extent_tree et; new = phys == 0 ? 1 : 0; - if (new || unwritten) - should_zero = 1; - if (new) { u32 tmp_pos; @@ -1301,7 +1300,7 @@ static int ocfs2_write_cluster(struct address_space *mapping, if (tmpret) { mlog_errno(tmpret); if (ret == 0) - tmpret = ret; + ret = tmpret; } } @@ -1341,7 +1340,9 @@ static int ocfs2_write_cluster_by_desc(struct address_space *mapping, local_len = osb->s_clustersize - cluster_off; ret = ocfs2_write_cluster(mapping, desc->c_phys, - desc->c_unwritten, data_ac, meta_ac, + desc->c_unwritten, + desc->c_needs_zero, + data_ac, meta_ac, wc, desc->c_cpos, pos, local_len); if (ret) { mlog_errno(ret); @@ -1391,14 +1392,14 @@ static void ocfs2_set_target_boundaries(struct ocfs2_super *osb, * newly allocated cluster. */ desc = &wc->w_desc[0]; - if (ocfs2_should_zero_cluster(desc)) + if (desc->c_needs_zero) ocfs2_figure_cluster_boundaries(osb, desc->c_cpos, &wc->w_target_from, NULL); desc = &wc->w_desc[wc->w_clen - 1]; - if (ocfs2_should_zero_cluster(desc)) + if (desc->c_needs_zero) ocfs2_figure_cluster_boundaries(osb, desc->c_cpos, NULL, @@ -1466,13 +1467,28 @@ static int ocfs2_populate_write_desc(struct inode *inode, phys++; } + /* + * If w_first_new_cpos is < UINT_MAX, we have a non-sparse + * file that got extended. w_first_new_cpos tells us + * where the newly allocated clusters are so we can + * zero them. + */ + if (desc->c_cpos >= wc->w_first_new_cpos) { + BUG_ON(phys == 0); + desc->c_needs_zero = 1; + } + desc->c_phys = phys; if (phys == 0) { desc->c_new = 1; + desc->c_needs_zero = 1; *clusters_to_alloc = *clusters_to_alloc + 1; } - if (ext_flags & OCFS2_EXT_UNWRITTEN) + + if (ext_flags & OCFS2_EXT_UNWRITTEN) { desc->c_unwritten = 1; + desc->c_needs_zero = 1; + } num_clusters--; } @@ -1632,10 +1648,13 @@ static int ocfs2_expand_nonsparse_inode(struct inode *inode, loff_t pos, if (newsize <= i_size_read(inode)) return 0; - ret = ocfs2_extend_no_holes(inode, newsize, newsize - len); + ret = ocfs2_extend_no_holes(inode, newsize, pos); if (ret) mlog_errno(ret); + wc->w_first_new_cpos = + ocfs2_clusters_for_bytes(inode->i_sb, i_size_read(inode)); + return ret; } @@ -1644,7 +1663,7 @@ int ocfs2_write_begin_nolock(struct address_space *mapping, struct page **pagep, void **fsdata, struct buffer_head *di_bh, struct page *mmap_page) { - int ret, credits = OCFS2_INODE_UPDATE_CREDITS; + int ret, cluster_of_pages, credits = OCFS2_INODE_UPDATE_CREDITS; unsigned int clusters_to_alloc, extents_to_split; struct ocfs2_write_ctxt *wc; struct inode *inode = mapping->host; @@ -1722,8 +1741,19 @@ int ocfs2_write_begin_nolock(struct address_space *mapping, } - ocfs2_set_target_boundaries(osb, wc, pos, len, - clusters_to_alloc + extents_to_split); + /* + * We have to zero sparse allocated clusters, unwritten extent clusters, + * and non-sparse clusters we just extended. For non-sparse writes, + * we know zeros will only be needed in the first and/or last cluster. + */ + if (clusters_to_alloc || extents_to_split || + wc->w_desc[0].c_needs_zero || + wc->w_desc[wc->w_clen - 1].c_needs_zero) + cluster_of_pages = 1; + else + cluster_of_pages = 0; + + ocfs2_set_target_boundaries(osb, wc, pos, len, cluster_of_pages); handle = ocfs2_start_trans(osb, credits); if (IS_ERR(handle)) { @@ -1756,8 +1786,7 @@ int ocfs2_write_begin_nolock(struct address_space *mapping, * extent. */ ret = ocfs2_grab_pages_for_write(mapping, wc, wc->w_cpos, pos, - clusters_to_alloc + extents_to_split, - mmap_page); + cluster_of_pages, mmap_page); if (ret) { mlog_errno(ret); goto out_quota; diff --git a/fs/ocfs2/dcache.c b/fs/ocfs2/dcache.c index b574431..2f28b7d 100644 --- a/fs/ocfs2/dcache.c +++ b/fs/ocfs2/dcache.c @@ -310,22 +310,19 @@ out_attach: return ret; } -static DEFINE_SPINLOCK(dentry_list_lock); +DEFINE_SPINLOCK(dentry_list_lock); /* We limit the number of dentry locks to drop in one go. We have * this limit so that we don't starve other users of ocfs2_wq. */ #define DL_INODE_DROP_COUNT 64 /* Drop inode references from dentry locks */ -void ocfs2_drop_dl_inodes(struct work_struct *work) +static void __ocfs2_drop_dl_inodes(struct ocfs2_super *osb, int drop_count) { - struct ocfs2_super *osb = container_of(work, struct ocfs2_super, - dentry_lock_work); struct ocfs2_dentry_lock *dl; - int drop_count = DL_INODE_DROP_COUNT; spin_lock(&dentry_list_lock); - while (osb->dentry_lock_list && drop_count--) { + while (osb->dentry_lock_list && (drop_count < 0 || drop_count--)) { dl = osb->dentry_lock_list; osb->dentry_lock_list = dl->dl_next; spin_unlock(&dentry_list_lock); @@ -333,11 +330,32 @@ void ocfs2_drop_dl_inodes(struct work_struct *work) kfree(dl); spin_lock(&dentry_list_lock); } - if (osb->dentry_lock_list) + spin_unlock(&dentry_list_lock); +} + +void ocfs2_drop_dl_inodes(struct work_struct *work) +{ + struct ocfs2_super *osb = container_of(work, struct ocfs2_super, + dentry_lock_work); + + __ocfs2_drop_dl_inodes(osb, DL_INODE_DROP_COUNT); + /* + * Don't queue dropping if umount is in progress. We flush the + * list in ocfs2_dismount_volume + */ + spin_lock(&dentry_list_lock); + if (osb->dentry_lock_list && + !ocfs2_test_osb_flag(osb, OCFS2_OSB_DROP_DENTRY_LOCK_IMMED)) queue_work(ocfs2_wq, &osb->dentry_lock_work); spin_unlock(&dentry_list_lock); } +/* Flush the whole work queue */ +void ocfs2_drop_all_dl_inodes(struct ocfs2_super *osb) +{ + __ocfs2_drop_dl_inodes(osb, -1); +} + /* * ocfs2_dentry_iput() and friends. * @@ -368,7 +386,8 @@ static void ocfs2_drop_dentry_lock(struct ocfs2_super *osb, /* We leave dropping of inode reference to ocfs2_wq as that can * possibly lead to inode deletion which gets tricky */ spin_lock(&dentry_list_lock); - if (!osb->dentry_lock_list) + if (!osb->dentry_lock_list && + !ocfs2_test_osb_flag(osb, OCFS2_OSB_DROP_DENTRY_LOCK_IMMED)) queue_work(ocfs2_wq, &osb->dentry_lock_work); dl->dl_next = osb->dentry_lock_list; osb->dentry_lock_list = dl; diff --git a/fs/ocfs2/dcache.h b/fs/ocfs2/dcache.h index faa12e7..f5dd178 100644 --- a/fs/ocfs2/dcache.h +++ b/fs/ocfs2/dcache.h @@ -49,10 +49,13 @@ struct ocfs2_dentry_lock { int ocfs2_dentry_attach_lock(struct dentry *dentry, struct inode *inode, u64 parent_blkno); +extern spinlock_t dentry_list_lock; + void ocfs2_dentry_lock_put(struct ocfs2_super *osb, struct ocfs2_dentry_lock *dl); void ocfs2_drop_dl_inodes(struct work_struct *work); +void ocfs2_drop_all_dl_inodes(struct ocfs2_super *osb); struct dentry *ocfs2_find_local_alias(struct inode *inode, u64 parent_blkno, int skip_unhashed); diff --git a/fs/ocfs2/dlm/dlmast.c b/fs/ocfs2/dlm/dlmast.c index d07ddbe..81eff8e 100644 --- a/fs/ocfs2/dlm/dlmast.c +++ b/fs/ocfs2/dlm/dlmast.c @@ -103,7 +103,6 @@ static void __dlm_queue_ast(struct dlm_ctxt *dlm, struct dlm_lock *lock) lock->ast_pending, lock->ml.type); BUG(); } - BUG_ON(!list_empty(&lock->ast_list)); if (lock->ast_pending) mlog(0, "lock has an ast getting flushed right now\n"); diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c index bcb9260..43e6e32 100644 --- a/fs/ocfs2/dlm/dlmrecovery.c +++ b/fs/ocfs2/dlm/dlmrecovery.c @@ -1118,7 +1118,7 @@ static int dlm_send_mig_lockres_msg(struct dlm_ctxt *dlm, mlog(0, "%s:%.*s: sending mig lockres (%s) to %u\n", dlm->name, res->lockname.len, res->lockname.name, - orig_flags & DLM_MRES_MIGRATION ? "migrate" : "recovery", + orig_flags & DLM_MRES_MIGRATION ? "migration" : "recovery", send_to); /* send it */ diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 62442e4..aa501d3 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -1851,6 +1851,7 @@ relock: if (ret) goto out_dio; + count = ocount; ret = generic_write_checks(file, ppos, &count, S_ISBLK(inode->i_mode)); if (ret) @@ -1918,8 +1919,10 @@ out_sems: mutex_unlock(&inode->i_mutex); + if (written) + ret = written; mlog_exit(ret); - return written ? written : ret; + return ret; } static int ocfs2_splice_to_file(struct pipe_inode_info *pipe, diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c index f033760..c48b93a 100644 --- a/fs/ocfs2/journal.c +++ b/fs/ocfs2/journal.c @@ -1954,10 +1954,16 @@ void ocfs2_orphan_scan_init(struct ocfs2_super *osb) os->os_osb = osb; os->os_count = 0; os->os_seqno = 0; - os->os_scantime = CURRENT_TIME; mutex_init(&os->os_lock); INIT_DELAYED_WORK(&os->os_orphan_scan_work, ocfs2_orphan_scan_work); +} +void ocfs2_orphan_scan_start(struct ocfs2_super *osb) +{ + struct ocfs2_orphan_scan *os; + + os = &osb->osb_orphan_scan; + os->os_scantime = CURRENT_TIME; if (ocfs2_is_hard_readonly(osb) || ocfs2_mount_local(osb)) atomic_set(&os->os_state, ORPHAN_SCAN_INACTIVE); else { diff --git a/fs/ocfs2/journal.h b/fs/ocfs2/journal.h index 5432c7f..2c3222a 100644 --- a/fs/ocfs2/journal.h +++ b/fs/ocfs2/journal.h @@ -145,6 +145,7 @@ static inline void ocfs2_inode_set_new(struct ocfs2_super *osb, /* Exported only for the journal struct init code in super.c. Do not call. */ void ocfs2_orphan_scan_init(struct ocfs2_super *osb); +void ocfs2_orphan_scan_start(struct ocfs2_super *osb); void ocfs2_orphan_scan_stop(struct ocfs2_super *osb); void ocfs2_orphan_scan_exit(struct ocfs2_super *osb); @@ -329,20 +330,27 @@ int ocfs2_journal_dirty(handle_t *handle, /* extended attribute block update */ #define OCFS2_XATTR_BLOCK_UPDATE_CREDITS 1 +/* Update of a single quota block */ +#define OCFS2_QUOTA_BLOCK_UPDATE_CREDITS 1 + /* global quotafile inode update, data block */ -#define OCFS2_QINFO_WRITE_CREDITS (OCFS2_INODE_UPDATE_CREDITS + 1) +#define OCFS2_QINFO_WRITE_CREDITS (OCFS2_INODE_UPDATE_CREDITS + \ + OCFS2_QUOTA_BLOCK_UPDATE_CREDITS) +#define OCFS2_LOCAL_QINFO_WRITE_CREDITS OCFS2_QUOTA_BLOCK_UPDATE_CREDITS /* * The two writes below can accidentally see global info dirty due * to set_info() quotactl so make them prepared for the writes. */ /* quota data block, global info */ /* Write to local quota file */ -#define OCFS2_QWRITE_CREDITS (OCFS2_QINFO_WRITE_CREDITS + 1) +#define OCFS2_QWRITE_CREDITS (OCFS2_QINFO_WRITE_CREDITS + \ + OCFS2_QUOTA_BLOCK_UPDATE_CREDITS) /* global quota data block, local quota data block, global quota inode, * global quota info */ -#define OCFS2_QSYNC_CREDITS (OCFS2_INODE_UPDATE_CREDITS + 3) +#define OCFS2_QSYNC_CREDITS (OCFS2_QINFO_WRITE_CREDITS + \ + 2 * OCFS2_QUOTA_BLOCK_UPDATE_CREDITS) static inline int ocfs2_quota_trans_credits(struct super_block *sb) { @@ -355,11 +363,6 @@ static inline int ocfs2_quota_trans_credits(struct super_block *sb) return credits; } -/* Number of credits needed for removing quota structure from file */ -int ocfs2_calc_qdel_credits(struct super_block *sb, int type); -/* Number of credits needed for initialization of new quota structure */ -int ocfs2_calc_qinit_credits(struct super_block *sb, int type); - /* group extend. inode update and last group update. */ #define OCFS2_GROUP_EXTEND_CREDITS (OCFS2_INODE_UPDATE_CREDITS + 1) diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h index c9345eb..39e1d5a 100644 --- a/fs/ocfs2/ocfs2.h +++ b/fs/ocfs2/ocfs2.h @@ -224,10 +224,12 @@ enum ocfs2_mount_options OCFS2_MOUNT_GRPQUOTA = 1 << 10, /* We support group quotas */ }; -#define OCFS2_OSB_SOFT_RO 0x0001 -#define OCFS2_OSB_HARD_RO 0x0002 -#define OCFS2_OSB_ERROR_FS 0x0004 -#define OCFS2_DEFAULT_ATIME_QUANTUM 60 +#define OCFS2_OSB_SOFT_RO 0x0001 +#define OCFS2_OSB_HARD_RO 0x0002 +#define OCFS2_OSB_ERROR_FS 0x0004 +#define OCFS2_OSB_DROP_DENTRY_LOCK_IMMED 0x0008 + +#define OCFS2_DEFAULT_ATIME_QUANTUM 60 struct ocfs2_journal; struct ocfs2_slot_info; @@ -490,6 +492,18 @@ static inline void ocfs2_set_osb_flag(struct ocfs2_super *osb, spin_unlock(&osb->osb_lock); } + +static inline unsigned long ocfs2_test_osb_flag(struct ocfs2_super *osb, + unsigned long flag) +{ + unsigned long ret; + + spin_lock(&osb->osb_lock); + ret = osb->osb_flags & flag; + spin_unlock(&osb->osb_lock); + return ret; +} + static inline void ocfs2_set_ro_flag(struct ocfs2_super *osb, int hard) { diff --git a/fs/ocfs2/quota.h b/fs/ocfs2/quota.h index 7365e2e..3fb96fcd 100644 --- a/fs/ocfs2/quota.h +++ b/fs/ocfs2/quota.h @@ -50,7 +50,6 @@ struct ocfs2_mem_dqinfo { unsigned int dqi_chunks; /* Number of chunks in local quota file */ unsigned int dqi_blocks; /* Number of blocks allocated for local quota file */ unsigned int dqi_syncms; /* How often should we sync with other nodes */ - unsigned int dqi_syncjiff; /* Precomputed dqi_syncms in jiffies */ struct list_head dqi_chunk; /* List of chunks */ struct inode *dqi_gqinode; /* Global quota file inode */ struct ocfs2_lock_res dqi_gqlock; /* Lock protecting quota information structure */ diff --git a/fs/ocfs2/quota_global.c b/fs/ocfs2/quota_global.c index edfa60c..bf7742d 100644 --- a/fs/ocfs2/quota_global.c +++ b/fs/ocfs2/quota_global.c @@ -69,6 +69,7 @@ static void ocfs2_global_mem2diskdqb(void *dp, struct dquot *dquot) d->dqb_curspace = cpu_to_le64(m->dqb_curspace); d->dqb_btime = cpu_to_le64(m->dqb_btime); d->dqb_itime = cpu_to_le64(m->dqb_itime); + d->dqb_pad1 = d->dqb_pad2 = 0; } static int ocfs2_global_is_id(void *dp, struct dquot *dquot) @@ -211,14 +212,13 @@ ssize_t ocfs2_quota_write(struct super_block *sb, int type, mutex_lock_nested(&gqinode->i_mutex, I_MUTEX_QUOTA); if (gqinode->i_size < off + len) { - down_write(&OCFS2_I(gqinode)->ip_alloc_sem); - err = ocfs2_extend_no_holes(gqinode, off + len, off); - up_write(&OCFS2_I(gqinode)->ip_alloc_sem); - if (err < 0) - goto out; + loff_t rounded_end = + ocfs2_align_bytes_to_blocks(sb, off + len); + + /* Space is already allocated in ocfs2_global_read_dquot() */ err = ocfs2_simple_size_update(gqinode, oinfo->dqi_gqi_bh, - off + len); + rounded_end); if (err < 0) goto out; new = 1; @@ -234,7 +234,7 @@ ssize_t ocfs2_quota_write(struct super_block *sb, int type, } if (err) { mlog_errno(err); - return err; + goto out; } lock_buffer(bh); if (new) @@ -342,7 +342,6 @@ int ocfs2_global_read_info(struct super_block *sb, int type) info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace); info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace); oinfo->dqi_syncms = le32_to_cpu(dinfo.dqi_syncms); - oinfo->dqi_syncjiff = msecs_to_jiffies(oinfo->dqi_syncms); oinfo->dqi_gi.dqi_blocks = le32_to_cpu(dinfo.dqi_blocks); oinfo->dqi_gi.dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk); oinfo->dqi_gi.dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry); @@ -352,7 +351,7 @@ int ocfs2_global_read_info(struct super_block *sb, int type) oinfo->dqi_gi.dqi_qtree_depth = qtree_depth(&oinfo->dqi_gi); INIT_DELAYED_WORK(&oinfo->dqi_sync_work, qsync_work_fn); queue_delayed_work(ocfs2_quota_wq, &oinfo->dqi_sync_work, - oinfo->dqi_syncjiff); + msecs_to_jiffies(oinfo->dqi_syncms)); out_err: mlog_exit(status); @@ -402,13 +401,36 @@ int ocfs2_global_write_info(struct super_block *sb, int type) return err; } +static int ocfs2_global_qinit_alloc(struct super_block *sb, int type) +{ + struct ocfs2_mem_dqinfo *oinfo = sb_dqinfo(sb, type)->dqi_priv; + + /* + * We may need to allocate tree blocks and a leaf block but not the + * root block + */ + return oinfo->dqi_gi.dqi_qtree_depth; +} + +static int ocfs2_calc_global_qinit_credits(struct super_block *sb, int type) +{ + /* We modify all the allocated blocks, tree root, and info block */ + return (ocfs2_global_qinit_alloc(sb, type) + 2) * + OCFS2_QUOTA_BLOCK_UPDATE_CREDITS; +} + /* Read in information from global quota file and acquire a reference to it. * dquot_acquire() has already started the transaction and locked quota file */ int ocfs2_global_read_dquot(struct dquot *dquot) { int err, err2, ex = 0; - struct ocfs2_mem_dqinfo *info = - sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv; + struct super_block *sb = dquot->dq_sb; + int type = dquot->dq_type; + struct ocfs2_mem_dqinfo *info = sb_dqinfo(sb, type)->dqi_priv; + struct ocfs2_super *osb = OCFS2_SB(sb); + struct inode *gqinode = info->dqi_gqinode; + int need_alloc = ocfs2_global_qinit_alloc(sb, type); + handle_t *handle = NULL; err = ocfs2_qinfo_lock(info, 0); if (err < 0) @@ -419,14 +441,33 @@ int ocfs2_global_read_dquot(struct dquot *dquot) OCFS2_DQUOT(dquot)->dq_use_count++; OCFS2_DQUOT(dquot)->dq_origspace = dquot->dq_dqb.dqb_curspace; OCFS2_DQUOT(dquot)->dq_originodes = dquot->dq_dqb.dqb_curinodes; + ocfs2_qinfo_unlock(info, 0); + if (!dquot->dq_off) { /* No real quota entry? */ - /* Upgrade to exclusive lock for allocation */ - ocfs2_qinfo_unlock(info, 0); - err = ocfs2_qinfo_lock(info, 1); - if (err < 0) - goto out_qlock; ex = 1; + /* + * Add blocks to quota file before we start a transaction since + * locking allocators ranks above a transaction start + */ + WARN_ON(journal_current_handle()); + down_write(&OCFS2_I(gqinode)->ip_alloc_sem); + err = ocfs2_extend_no_holes(gqinode, + gqinode->i_size + (need_alloc << sb->s_blocksize_bits), + gqinode->i_size); + up_write(&OCFS2_I(gqinode)->ip_alloc_sem); + if (err < 0) + goto out; } + + handle = ocfs2_start_trans(osb, + ocfs2_calc_global_qinit_credits(sb, type)); + if (IS_ERR(handle)) { + err = PTR_ERR(handle); + goto out; + } + err = ocfs2_qinfo_lock(info, ex); + if (err < 0) + goto out_trans; err = qtree_write_dquot(&info->dqi_gi, dquot); if (ex && info_dirty(sb_dqinfo(dquot->dq_sb, dquot->dq_type))) { err2 = __ocfs2_global_write_info(dquot->dq_sb, dquot->dq_type); @@ -438,6 +479,9 @@ out_qlock: ocfs2_qinfo_unlock(info, 1); else ocfs2_qinfo_unlock(info, 0); +out_trans: + if (handle) + ocfs2_commit_trans(osb, handle); out: if (err < 0) mlog_errno(err); @@ -607,7 +651,7 @@ static void qsync_work_fn(struct work_struct *work) dquot_scan_active(sb, ocfs2_sync_dquot_helper, oinfo->dqi_type); queue_delayed_work(ocfs2_quota_wq, &oinfo->dqi_sync_work, - oinfo->dqi_syncjiff); + msecs_to_jiffies(oinfo->dqi_syncms)); } /* @@ -635,20 +679,18 @@ out: return status; } -int ocfs2_calc_qdel_credits(struct super_block *sb, int type) +static int ocfs2_calc_qdel_credits(struct super_block *sb, int type) { - struct ocfs2_mem_dqinfo *oinfo; - int features[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA, - OCFS2_FEATURE_RO_COMPAT_GRPQUOTA }; - - if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, features[type])) - return 0; - - oinfo = sb_dqinfo(sb, type)->dqi_priv; - /* We modify tree, leaf block, global info, local chunk header, - * global and local inode */ - return oinfo->dqi_gi.dqi_qtree_depth + 2 + 1 + - 2 * OCFS2_INODE_UPDATE_CREDITS; + struct ocfs2_mem_dqinfo *oinfo = sb_dqinfo(sb, type)->dqi_priv; + /* + * We modify tree, leaf block, global info, local chunk header, + * global and local inode; OCFS2_QINFO_WRITE_CREDITS already + * accounts for inode update + */ + return (oinfo->dqi_gi.dqi_qtree_depth + 2) * + OCFS2_QUOTA_BLOCK_UPDATE_CREDITS + + OCFS2_QINFO_WRITE_CREDITS + + OCFS2_INODE_UPDATE_CREDITS; } static int ocfs2_release_dquot(struct dquot *dquot) @@ -680,33 +722,10 @@ out: return status; } -int ocfs2_calc_qinit_credits(struct super_block *sb, int type) -{ - struct ocfs2_mem_dqinfo *oinfo; - int features[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA, - OCFS2_FEATURE_RO_COMPAT_GRPQUOTA }; - struct ocfs2_dinode *lfe, *gfe; - - if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, features[type])) - return 0; - - oinfo = sb_dqinfo(sb, type)->dqi_priv; - gfe = (struct ocfs2_dinode *)oinfo->dqi_gqi_bh->b_data; - lfe = (struct ocfs2_dinode *)oinfo->dqi_lqi_bh->b_data; - /* We can extend local file + global file. In local file we - * can modify info, chunk header block and dquot block. In - * global file we can modify info, tree and leaf block */ - return ocfs2_calc_extend_credits(sb, &lfe->id2.i_list, 0) + - ocfs2_calc_extend_credits(sb, &gfe->id2.i_list, 0) + - 3 + oinfo->dqi_gi.dqi_qtree_depth + 2; -} - static int ocfs2_acquire_dquot(struct dquot *dquot) { - handle_t *handle; struct ocfs2_mem_dqinfo *oinfo = sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv; - struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb); int status = 0; mlog_entry("id=%u, type=%d", dquot->dq_id, dquot->dq_type); @@ -715,16 +734,7 @@ static int ocfs2_acquire_dquot(struct dquot *dquot) status = ocfs2_lock_global_qf(oinfo, 1); if (status < 0) goto out; - handle = ocfs2_start_trans(osb, - ocfs2_calc_qinit_credits(dquot->dq_sb, dquot->dq_type)); - if (IS_ERR(handle)) { - status = PTR_ERR(handle); - mlog_errno(status); - goto out_ilock; - } status = dquot_acquire(dquot); - ocfs2_commit_trans(osb, handle); -out_ilock: ocfs2_unlock_global_qf(oinfo, 1); out: mlog_exit(status); diff --git a/fs/ocfs2/quota_local.c b/fs/ocfs2/quota_local.c index 5a460fa..bdb09cb 100644 --- a/fs/ocfs2/quota_local.c +++ b/fs/ocfs2/quota_local.c @@ -20,6 +20,7 @@ #include "sysfile.h" #include "dlmglue.h" #include "quota.h" +#include "uptodate.h" /* Number of local quota structures per block */ static inline unsigned int ol_quota_entries_per_block(struct super_block *sb) @@ -100,7 +101,8 @@ static int ocfs2_modify_bh(struct inode *inode, struct buffer_head *bh, handle_t *handle; int status; - handle = ocfs2_start_trans(OCFS2_SB(sb), 1); + handle = ocfs2_start_trans(OCFS2_SB(sb), + OCFS2_QUOTA_BLOCK_UPDATE_CREDITS); if (IS_ERR(handle)) { status = PTR_ERR(handle); mlog_errno(status); @@ -610,7 +612,8 @@ int ocfs2_finish_quota_recovery(struct ocfs2_super *osb, goto out_bh; /* Mark quota file as clean if we are recovering quota file of * some other node. */ - handle = ocfs2_start_trans(osb, 1); + handle = ocfs2_start_trans(osb, + OCFS2_LOCAL_QINFO_WRITE_CREDITS); if (IS_ERR(handle)) { status = PTR_ERR(handle); mlog_errno(status); @@ -940,7 +943,7 @@ static struct ocfs2_quota_chunk *ocfs2_local_quota_add_chunk( struct ocfs2_local_disk_chunk *dchunk; int status; handle_t *handle; - struct buffer_head *bh = NULL; + struct buffer_head *bh = NULL, *dbh = NULL; u64 p_blkno; /* We are protected by dqio_sem so no locking needed */ @@ -964,32 +967,35 @@ static struct ocfs2_quota_chunk *ocfs2_local_quota_add_chunk( mlog_errno(status); goto out; } + /* Local quota info and two new blocks we initialize */ + handle = ocfs2_start_trans(OCFS2_SB(sb), + OCFS2_LOCAL_QINFO_WRITE_CREDITS + + 2 * OCFS2_QUOTA_BLOCK_UPDATE_CREDITS); + if (IS_ERR(handle)) { + status = PTR_ERR(handle); + mlog_errno(status); + goto out; + } + /* Initialize chunk header */ down_read(&OCFS2_I(lqinode)->ip_alloc_sem); status = ocfs2_extent_map_get_blocks(lqinode, oinfo->dqi_blocks, &p_blkno, NULL, NULL); up_read(&OCFS2_I(lqinode)->ip_alloc_sem); if (status < 0) { mlog_errno(status); - goto out; + goto out_trans; } bh = sb_getblk(sb, p_blkno); if (!bh) { status = -ENOMEM; mlog_errno(status); - goto out; + goto out_trans; } dchunk = (struct ocfs2_local_disk_chunk *)bh->b_data; - - handle = ocfs2_start_trans(OCFS2_SB(sb), 2); - if (IS_ERR(handle)) { - status = PTR_ERR(handle); - mlog_errno(status); - goto out; - } - + ocfs2_set_new_buffer_uptodate(lqinode, bh); status = ocfs2_journal_access_dq(handle, lqinode, bh, - OCFS2_JOURNAL_ACCESS_WRITE); + OCFS2_JOURNAL_ACCESS_CREATE); if (status < 0) { mlog_errno(status); goto out_trans; @@ -999,7 +1005,6 @@ static struct ocfs2_quota_chunk *ocfs2_local_quota_add_chunk( memset(dchunk->dqc_bitmap, 0, sb->s_blocksize - sizeof(struct ocfs2_local_disk_chunk) - OCFS2_QBLK_RESERVED_SPACE); - set_buffer_uptodate(bh); unlock_buffer(bh); status = ocfs2_journal_dirty(handle, bh); if (status < 0) { @@ -1007,6 +1012,38 @@ static struct ocfs2_quota_chunk *ocfs2_local_quota_add_chunk( goto out_trans; } + /* Initialize new block with structures */ + down_read(&OCFS2_I(lqinode)->ip_alloc_sem); + status = ocfs2_extent_map_get_blocks(lqinode, oinfo->dqi_blocks + 1, + &p_blkno, NULL, NULL); + up_read(&OCFS2_I(lqinode)->ip_alloc_sem); + if (status < 0) { + mlog_errno(status); + goto out_trans; + } + dbh = sb_getblk(sb, p_blkno); + if (!dbh) { + status = -ENOMEM; + mlog_errno(status); + goto out_trans; + } + ocfs2_set_new_buffer_uptodate(lqinode, dbh); + status = ocfs2_journal_access_dq(handle, lqinode, dbh, + OCFS2_JOURNAL_ACCESS_CREATE); + if (status < 0) { + mlog_errno(status); + goto out_trans; + } + lock_buffer(dbh); + memset(dbh->b_data, 0, sb->s_blocksize - OCFS2_QBLK_RESERVED_SPACE); + unlock_buffer(dbh); + status = ocfs2_journal_dirty(handle, dbh); + if (status < 0) { + mlog_errno(status); + goto out_trans; + } + + /* Update local quotafile info */ oinfo->dqi_blocks += 2; oinfo->dqi_chunks++; status = ocfs2_local_write_info(sb, type); @@ -1031,6 +1068,7 @@ out_trans: ocfs2_commit_trans(OCFS2_SB(sb), handle); out: brelse(bh); + brelse(dbh); kmem_cache_free(ocfs2_qf_chunk_cachep, chunk); return ERR_PTR(status); } @@ -1048,6 +1086,8 @@ static struct ocfs2_quota_chunk *ocfs2_extend_local_quota_file( struct ocfs2_local_disk_chunk *dchunk; int epb = ol_quota_entries_per_block(sb); unsigned int chunk_blocks; + struct buffer_head *bh; + u64 p_blkno; int status; handle_t *handle; @@ -1075,12 +1115,49 @@ static struct ocfs2_quota_chunk *ocfs2_extend_local_quota_file( mlog_errno(status); goto out; } - handle = ocfs2_start_trans(OCFS2_SB(sb), 2); + + /* Get buffer from the just added block */ + down_read(&OCFS2_I(lqinode)->ip_alloc_sem); + status = ocfs2_extent_map_get_blocks(lqinode, oinfo->dqi_blocks, + &p_blkno, NULL, NULL); + up_read(&OCFS2_I(lqinode)->ip_alloc_sem); + if (status < 0) { + mlog_errno(status); + goto out; + } + bh = sb_getblk(sb, p_blkno); + if (!bh) { + status = -ENOMEM; + mlog_errno(status); + goto out; + } + ocfs2_set_new_buffer_uptodate(lqinode, bh); + + /* Local quota info, chunk header and the new block we initialize */ + handle = ocfs2_start_trans(OCFS2_SB(sb), + OCFS2_LOCAL_QINFO_WRITE_CREDITS + + 2 * OCFS2_QUOTA_BLOCK_UPDATE_CREDITS); if (IS_ERR(handle)) { status = PTR_ERR(handle); mlog_errno(status); goto out; } + /* Zero created block */ + status = ocfs2_journal_access_dq(handle, lqinode, bh, + OCFS2_JOURNAL_ACCESS_CREATE); + if (status < 0) { + mlog_errno(status); + goto out_trans; + } + lock_buffer(bh); + memset(bh->b_data, 0, sb->s_blocksize); + unlock_buffer(bh); + status = ocfs2_journal_dirty(handle, bh); + if (status < 0) { + mlog_errno(status); + goto out_trans; + } + /* Update chunk header */ status = ocfs2_journal_access_dq(handle, lqinode, chunk->qc_headerbh, OCFS2_JOURNAL_ACCESS_WRITE); if (status < 0) { @@ -1097,6 +1174,7 @@ static struct ocfs2_quota_chunk *ocfs2_extend_local_quota_file( mlog_errno(status); goto out_trans; } + /* Update file header */ oinfo->dqi_blocks++; status = ocfs2_local_write_info(sb, type); if (status < 0) { diff --git a/fs/ocfs2/stack_o2cb.c b/fs/ocfs2/stack_o2cb.c index 3f66137..e49c410 100644 --- a/fs/ocfs2/stack_o2cb.c +++ b/fs/ocfs2/stack_o2cb.c @@ -17,6 +17,7 @@ * General Public License for more details. */ +#include <linux/kernel.h> #include <linux/crc32.h> #include <linux/module.h> @@ -153,7 +154,7 @@ static int status_map[] = { static int dlm_status_to_errno(enum dlm_status status) { - BUG_ON(status > (sizeof(status_map) / sizeof(status_map[0]))); + BUG_ON(status < 0 || status >= ARRAY_SIZE(status_map)); return status_map[status]; } diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 7efb349..b0ee0fd 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -777,6 +777,7 @@ static int ocfs2_sb_probe(struct super_block *sb, } di = (struct ocfs2_dinode *) (*bh)->b_data; memset(stats, 0, sizeof(struct ocfs2_blockcheck_stats)); + spin_lock_init(&stats->b_lock); status = ocfs2_verify_volume(di, *bh, blksize, stats); if (status >= 0) goto bail; @@ -1182,7 +1183,7 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) wake_up(&osb->osb_mount_event); /* Start this when the mount is almost sure of being successful */ - ocfs2_orphan_scan_init(osb); + ocfs2_orphan_scan_start(osb); mlog_exit(status); return status; @@ -1213,14 +1214,27 @@ static int ocfs2_get_sb(struct file_system_type *fs_type, mnt); } +static void ocfs2_kill_sb(struct super_block *sb) +{ + struct ocfs2_super *osb = OCFS2_SB(sb); + + /* Prevent further queueing of inode drop events */ + spin_lock(&dentry_list_lock); + ocfs2_set_osb_flag(osb, OCFS2_OSB_DROP_DENTRY_LOCK_IMMED); + spin_unlock(&dentry_list_lock); + /* Wait for work to finish and/or remove it */ + cancel_work_sync(&osb->dentry_lock_work); + + kill_block_super(sb); +} + static struct file_system_type ocfs2_fs_type = { .owner = THIS_MODULE, .name = "ocfs2", .get_sb = ocfs2_get_sb, /* is this called when we mount * the fs? */ - .kill_sb = kill_block_super, /* set to the generic one - * right now, but do we - * need to change that? */ + .kill_sb = ocfs2_kill_sb, + .fs_flags = FS_REQUIRES_DEV|FS_RENAME_DOES_D_MOVE, .next = NULL }; @@ -1819,6 +1833,12 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err) debugfs_remove(osb->osb_ctxt); + /* + * Flush inode dropping work queue so that deletes are + * performed while the filesystem is still working + */ + ocfs2_drop_all_dl_inodes(osb); + /* Orphan scan should be stopped as early as possible */ ocfs2_orphan_scan_stop(osb); @@ -1981,6 +2001,8 @@ static int ocfs2_initialize_super(struct super_block *sb, snprintf(osb->dev_str, sizeof(osb->dev_str), "%u,%u", MAJOR(osb->sb->s_dev), MINOR(osb->sb->s_dev)); + ocfs2_orphan_scan_init(osb); + status = ocfs2_recovery_init(osb); if (status) { mlog(ML_ERROR, "Unable to initialize recovery state\n"); diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index ba320e2..d1a27cd 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c @@ -1052,7 +1052,8 @@ static int ocfs2_xattr_block_get(struct inode *inode, struct ocfs2_xattr_block *xb; struct ocfs2_xattr_value_root *xv; size_t size; - int ret = -ENODATA, name_offset, name_len, block_off, i; + int ret = -ENODATA, name_offset, name_len, i; + int uninitialized_var(block_off); xs->bucket = ocfs2_xattr_bucket_new(inode); if (!xs->bucket) { diff --git a/fs/select.c b/fs/select.c index d870237..8084834 100644 --- a/fs/select.c +++ b/fs/select.c @@ -110,6 +110,7 @@ void poll_initwait(struct poll_wqueues *pwq) { init_poll_funcptr(&pwq->pt, __pollwait); pwq->polling_task = current; + pwq->triggered = 0; pwq->error = 0; pwq->table = NULL; pwq->inline_index = 0; diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index 0c93c7e..965df12 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -770,7 +770,7 @@ xfs_buf_associate_memory( bp->b_pages = NULL; bp->b_addr = mem; - rval = _xfs_buf_get_pages(bp, page_count, 0); + rval = _xfs_buf_get_pages(bp, page_count, XBF_DONT_BLOCK); if (rval) return rval; diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c index db15feb..4ece190 100644 --- a/fs/xfs/xfs_attr.c +++ b/fs/xfs/xfs_attr.c @@ -2010,7 +2010,9 @@ xfs_attr_rmtval_get(xfs_da_args_t *args) dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock); blkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount); error = xfs_read_buf(mp, mp->m_ddev_targp, dblkno, - blkcnt, XFS_BUF_LOCK, &bp); + blkcnt, + XFS_BUF_LOCK | XBF_DONT_BLOCK, + &bp); if (error) return(error); @@ -2141,8 +2143,8 @@ xfs_attr_rmtval_set(xfs_da_args_t *args) dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock), blkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); - bp = xfs_buf_get_flags(mp->m_ddev_targp, dblkno, - blkcnt, XFS_BUF_LOCK); + bp = xfs_buf_get_flags(mp->m_ddev_targp, dblkno, blkcnt, + XFS_BUF_LOCK | XBF_DONT_BLOCK); ASSERT(bp); ASSERT(!XFS_BUF_GETERROR(bp)); diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index 7928b99..8ee5b5a 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c @@ -6009,7 +6009,7 @@ xfs_getbmap( */ error = ENOMEM; subnex = 16; - map = kmem_alloc(subnex * sizeof(*map), KM_MAYFAIL); + map = kmem_alloc(subnex * sizeof(*map), KM_MAYFAIL | KM_NOFS); if (!map) goto out_unlock_ilock; diff --git a/fs/xfs/xfs_btree.c b/fs/xfs/xfs_btree.c index e9df995..2671738 100644 --- a/fs/xfs/xfs_btree.c +++ b/fs/xfs/xfs_btree.c @@ -120,8 +120,8 @@ xfs_btree_check_sblock( XFS_RANDOM_BTREE_CHECK_SBLOCK))) { if (bp) xfs_buftrace("SBTREE ERROR", bp); - XFS_ERROR_REPORT("xfs_btree_check_sblock", XFS_ERRLEVEL_LOW, - cur->bc_mp); + XFS_CORRUPTION_ERROR("xfs_btree_check_sblock", + XFS_ERRLEVEL_LOW, cur->bc_mp, block); return XFS_ERROR(EFSCORRUPTED); } return 0; diff --git a/fs/xfs/xfs_da_btree.c b/fs/xfs/xfs_da_btree.c index 9ff6e57..2847bbc 100644 --- a/fs/xfs/xfs_da_btree.c +++ b/fs/xfs/xfs_da_btree.c @@ -2201,7 +2201,7 @@ kmem_zone_t *xfs_dabuf_zone; /* dabuf zone */ xfs_da_state_t * xfs_da_state_alloc(void) { - return kmem_zone_zalloc(xfs_da_state_zone, KM_SLEEP); + return kmem_zone_zalloc(xfs_da_state_zone, KM_NOFS); } /* @@ -2261,9 +2261,9 @@ xfs_da_buf_make(int nbuf, xfs_buf_t **bps, inst_t *ra) int off; if (nbuf == 1) - dabuf = kmem_zone_alloc(xfs_dabuf_zone, KM_SLEEP); + dabuf = kmem_zone_alloc(xfs_dabuf_zone, KM_NOFS); else - dabuf = kmem_alloc(XFS_DA_BUF_SIZE(nbuf), KM_SLEEP); + dabuf = kmem_alloc(XFS_DA_BUF_SIZE(nbuf), KM_NOFS); dabuf->dirty = 0; #ifdef XFS_DABUF_DEBUG dabuf->ra = ra; diff --git a/fs/xfs/xfs_dir2.c b/fs/xfs/xfs_dir2.c index c657bec..bb1d58eb 100644 --- a/fs/xfs/xfs_dir2.c +++ b/fs/xfs/xfs_dir2.c @@ -256,7 +256,7 @@ xfs_dir_cilookup_result( !(args->op_flags & XFS_DA_OP_CILOOKUP)) return EEXIST; - args->value = kmem_alloc(len, KM_MAYFAIL); + args->value = kmem_alloc(len, KM_NOFS | KM_MAYFAIL); if (!args->value) return ENOMEM; diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index cbd451b..2d0b3e1 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c @@ -167,17 +167,25 @@ xfs_growfs_data_private( new = nb - mp->m_sb.sb_dblocks; oagcount = mp->m_sb.sb_agcount; if (nagcount > oagcount) { + void *new_perag, *old_perag; + xfs_filestream_flush(mp); + + new_perag = kmem_zalloc(sizeof(xfs_perag_t) * nagcount, + KM_MAYFAIL); + if (!new_perag) + return XFS_ERROR(ENOMEM); + down_write(&mp->m_peraglock); - mp->m_perag = kmem_realloc(mp->m_perag, - sizeof(xfs_perag_t) * nagcount, - sizeof(xfs_perag_t) * oagcount, - KM_SLEEP); - memset(&mp->m_perag[oagcount], 0, - (nagcount - oagcount) * sizeof(xfs_perag_t)); + memcpy(new_perag, mp->m_perag, sizeof(xfs_perag_t) * oagcount); + old_perag = mp->m_perag; + mp->m_perag = new_perag; + mp->m_flags |= XFS_MOUNT_32BITINODES; nagimax = xfs_initialize_perag(mp, nagcount); up_write(&mp->m_peraglock); + + kmem_free(old_perag); } tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFS); tp->t_flags |= XFS_TRANS_RESERVE; diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 1f22d65..da428b3 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -343,6 +343,16 @@ xfs_iformat( return XFS_ERROR(EFSCORRUPTED); } + if (unlikely((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) && + !ip->i_mount->m_rtdev_targp)) { + xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount, + "corrupt dinode %Lu, has realtime flag set.", + ip->i_ino); + XFS_CORRUPTION_ERROR("xfs_iformat(realtime)", + XFS_ERRLEVEL_LOW, ip->i_mount, dip); + return XFS_ERROR(EFSCORRUPTED); + } + switch (ip->i_d.di_mode & S_IFMT) { case S_IFIFO: case S_IFCHR: diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index 3750f04..9dbdff3 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c @@ -3180,7 +3180,7 @@ try_again: STATIC void xlog_state_want_sync(xlog_t *log, xlog_in_core_t *iclog) { - ASSERT(spin_is_locked(&log->l_icloglock)); + assert_spin_locked(&log->l_icloglock); if (iclog->ic_state == XLOG_STATE_ACTIVE) { xlog_state_switch_iclogs(log, iclog, 0); diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index c4eca5e..492d75b 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -538,7 +538,9 @@ xfs_readlink_bmap( d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock); byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount); - bp = xfs_buf_read(mp->m_ddev_targp, d, BTOBB(byte_cnt), 0); + bp = xfs_buf_read_flags(mp->m_ddev_targp, d, BTOBB(byte_cnt), + XBF_LOCK | XBF_MAPPED | + XBF_DONT_BLOCK); error = XFS_BUF_GETERROR(bp); if (error) { xfs_ioerror_alert("xfs_readlink", diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index fdffb41..f6b9024 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -473,7 +473,6 @@ extern int nfs_writepages(struct address_space *, struct writeback_control *); extern int nfs_flush_incompatible(struct file *file, struct page *page); extern int nfs_updatepage(struct file *, struct page *, unsigned int, unsigned int); extern int nfs_writeback_done(struct rpc_task *, struct nfs_write_data *); -extern void nfs_writedata_release(void *); /* * Try to write back everything synchronously (but check the @@ -488,7 +487,6 @@ extern int nfs_wb_page_cancel(struct inode *inode, struct page* page); extern int nfs_commit_inode(struct inode *, int); extern struct nfs_write_data *nfs_commitdata_alloc(void); extern void nfs_commit_free(struct nfs_write_data *wdata); -extern void nfs_commitdata_release(void *wdata); #else static inline int nfs_commit_inode(struct inode *inode, int how) @@ -507,6 +505,7 @@ nfs_have_writebacks(struct inode *inode) * Allocate nfs_write_data structures */ extern struct nfs_write_data *nfs_writedata_alloc(unsigned int npages); +extern void nfs_writedata_free(struct nfs_write_data *); /* * linux/fs/nfs/read.c @@ -515,7 +514,6 @@ extern int nfs_readpage(struct file *, struct page *); extern int nfs_readpages(struct file *, struct address_space *, struct list_head *, unsigned); extern int nfs_readpage_result(struct rpc_task *, struct nfs_read_data *); -extern void nfs_readdata_release(void *data); extern int nfs_readpage_async(struct nfs_open_context *, struct inode *, struct page *); @@ -523,6 +521,7 @@ extern int nfs_readpage_async(struct nfs_open_context *, struct inode *, * Allocate nfs_read_data structures */ extern struct nfs_read_data *nfs_readdata_alloc(unsigned int npages); +extern void nfs_readdata_free(struct nfs_read_data *); /* * linux/fs/nfs3proc.c diff --git a/include/linux/perf_counter.h b/include/linux/perf_counter.h index a9d823a..b53f700 100644 --- a/include/linux/perf_counter.h +++ b/include/linux/perf_counter.h @@ -115,7 +115,7 @@ enum perf_counter_sample_format { PERF_SAMPLE_TID = 1U << 1, PERF_SAMPLE_TIME = 1U << 2, PERF_SAMPLE_ADDR = 1U << 3, - PERF_SAMPLE_GROUP = 1U << 4, + PERF_SAMPLE_READ = 1U << 4, PERF_SAMPLE_CALLCHAIN = 1U << 5, PERF_SAMPLE_ID = 1U << 6, PERF_SAMPLE_CPU = 1U << 7, @@ -127,16 +127,32 @@ enum perf_counter_sample_format { }; /* - * Bits that can be set in attr.read_format to request that - * reads on the counter should return the indicated quantities, - * in increasing order of bit value, after the counter value. + * The format of the data returned by read() on a perf counter fd, + * as specified by attr.read_format: + * + * struct read_format { + * { u64 value; + * { u64 time_enabled; } && PERF_FORMAT_ENABLED + * { u64 time_running; } && PERF_FORMAT_RUNNING + * { u64 id; } && PERF_FORMAT_ID + * } && !PERF_FORMAT_GROUP + * + * { u64 nr; + * { u64 time_enabled; } && PERF_FORMAT_ENABLED + * { u64 time_running; } && PERF_FORMAT_RUNNING + * { u64 value; + * { u64 id; } && PERF_FORMAT_ID + * } cntr[nr]; + * } && PERF_FORMAT_GROUP + * }; */ enum perf_counter_read_format { PERF_FORMAT_TOTAL_TIME_ENABLED = 1U << 0, PERF_FORMAT_TOTAL_TIME_RUNNING = 1U << 1, PERF_FORMAT_ID = 1U << 2, + PERF_FORMAT_GROUP = 1U << 3, - PERF_FORMAT_MAX = 1U << 3, /* non-ABI */ + PERF_FORMAT_MAX = 1U << 4, /* non-ABI */ }; #define PERF_ATTR_SIZE_VER0 64 /* sizeof first published struct */ @@ -343,10 +359,8 @@ enum perf_event_type { * struct { * struct perf_event_header header; * u32 pid, tid; - * u64 value; - * { u64 time_enabled; } && PERF_FORMAT_ENABLED - * { u64 time_running; } && PERF_FORMAT_RUNNING - * { u64 parent_id; } && PERF_FORMAT_ID + * + * struct read_format values; * }; */ PERF_EVENT_READ = 8, @@ -364,11 +378,22 @@ enum perf_event_type { * { u32 cpu, res; } && PERF_SAMPLE_CPU * { u64 period; } && PERF_SAMPLE_PERIOD * - * { u64 nr; - * { u64 id, val; } cnt[nr]; } && PERF_SAMPLE_GROUP + * { struct read_format values; } && PERF_SAMPLE_READ * * { u64 nr, * u64 ips[nr]; } && PERF_SAMPLE_CALLCHAIN + * + * # + * # The RAW record below is opaque data wrt the ABI + * # + * # That is, the ABI doesn't make any promises wrt to + * # the stability of its content, it may vary depending + * # on event, hardware, kernel version and phase of + * # the moon. + * # + * # In other words, PERF_SAMPLE_RAW contents are not an ABI. + * # + * * { u32 size; * char data[size];}&& PERF_SAMPLE_RAW * }; @@ -694,6 +719,8 @@ struct perf_sample_data { extern int perf_counter_overflow(struct perf_counter *counter, int nmi, struct perf_sample_data *data); +extern void perf_counter_output(struct perf_counter *counter, int nmi, + struct perf_sample_data *data); /* * Return 1 for a software counter, 0 for a hardware counter diff --git a/include/linux/wait.h b/include/linux/wait.h index 6788e1a..cf3c2f5 100644 --- a/include/linux/wait.h +++ b/include/linux/wait.h @@ -77,7 +77,14 @@ struct task_struct; #define __WAIT_BIT_KEY_INITIALIZER(word, bit) \ { .flags = word, .bit_nr = bit, } -extern void init_waitqueue_head(wait_queue_head_t *q); +extern void __init_waitqueue_head(wait_queue_head_t *q, struct lock_class_key *); + +#define init_waitqueue_head(q) \ + do { \ + static struct lock_class_key __key; \ + \ + __init_waitqueue_head((q), &__key); \ + } while (0) #ifdef CONFIG_LOCKDEP # define __WAIT_QUEUE_HEAD_INIT_ONSTACK(name) \ diff --git a/kernel/futex.c b/kernel/futex.c index 0672ff8..e18cfbd 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -1010,15 +1010,19 @@ void requeue_futex(struct futex_q *q, struct futex_hash_bucket *hb1, * requeue_pi_wake_futex() - Wake a task that acquired the lock during requeue * q: the futex_q * key: the key of the requeue target futex + * hb: the hash_bucket of the requeue target futex * * During futex_requeue, with requeue_pi=1, it is possible to acquire the * target futex if it is uncontended or via a lock steal. Set the futex_q key * to the requeue target futex so the waiter can detect the wakeup on the right * futex, but remove it from the hb and NULL the rt_waiter so it can detect - * atomic lock acquisition. Must be called with the q->lock_ptr held. + * atomic lock acquisition. Set the q->lock_ptr to the requeue target hb->lock + * to protect access to the pi_state to fixup the owner later. Must be called + * with both q->lock_ptr and hb->lock held. */ static inline -void requeue_pi_wake_futex(struct futex_q *q, union futex_key *key) +void requeue_pi_wake_futex(struct futex_q *q, union futex_key *key, + struct futex_hash_bucket *hb) { drop_futex_key_refs(&q->key); get_futex_key_refs(key); @@ -1030,6 +1034,11 @@ void requeue_pi_wake_futex(struct futex_q *q, union futex_key *key) WARN_ON(!q->rt_waiter); q->rt_waiter = NULL; + q->lock_ptr = &hb->lock; +#ifdef CONFIG_DEBUG_PI_LIST + q->list.plist.lock = &hb->lock; +#endif + wake_up_state(q->task, TASK_NORMAL); } @@ -1088,7 +1097,7 @@ static int futex_proxy_trylock_atomic(u32 __user *pifutex, ret = futex_lock_pi_atomic(pifutex, hb2, key2, ps, top_waiter->task, set_waiters); if (ret == 1) - requeue_pi_wake_futex(top_waiter, key2); + requeue_pi_wake_futex(top_waiter, key2, hb2); return ret; } @@ -1247,8 +1256,15 @@ retry_private: if (!match_futex(&this->key, &key1)) continue; - WARN_ON(!requeue_pi && this->rt_waiter); - WARN_ON(requeue_pi && !this->rt_waiter); + /* + * FUTEX_WAIT_REQEUE_PI and FUTEX_CMP_REQUEUE_PI should always + * be paired with each other and no other futex ops. + */ + if ((requeue_pi && !this->rt_waiter) || + (!requeue_pi && this->rt_waiter)) { + ret = -EINVAL; + break; + } /* * Wake nr_wake waiters. For requeue_pi, if we acquired the @@ -1273,7 +1289,7 @@ retry_private: this->task, 1); if (ret == 1) { /* We got the lock. */ - requeue_pi_wake_futex(this, &key2); + requeue_pi_wake_futex(this, &key2, hb2); continue; } else if (ret) { /* -EDEADLK */ diff --git a/kernel/futex_compat.c b/kernel/futex_compat.c index d607a5b..2357165 100644 --- a/kernel/futex_compat.c +++ b/kernel/futex_compat.c @@ -180,7 +180,8 @@ asmlinkage long compat_sys_futex(u32 __user *uaddr, int op, u32 val, int cmd = op & FUTEX_CMD_MASK; if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI || - cmd == FUTEX_WAIT_BITSET)) { + cmd == FUTEX_WAIT_BITSET || + cmd == FUTEX_WAIT_REQUEUE_PI)) { if (get_compat_timespec(&ts, utime)) return -EFAULT; if (!timespec_valid(&ts)) @@ -191,7 +192,8 @@ asmlinkage long compat_sys_futex(u32 __user *uaddr, int op, u32 val, t = ktime_add_safe(ktime_get(), t); tp = &t; } - if (cmd == FUTEX_REQUEUE || cmd == FUTEX_CMP_REQUEUE) + if (cmd == FUTEX_REQUEUE || cmd == FUTEX_CMP_REQUEUE || + cmd == FUTEX_CMP_REQUEUE_PI || cmd == FUTEX_WAKE_OP) val2 = (int) (unsigned long) utime; return do_futex(uaddr, op, val, tp, uaddr2, val2, val3); diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 61c679d..d222515 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -761,7 +761,6 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id) { struct irq_desc *desc = irq_to_desc(irq); struct irqaction *action, **action_ptr; - struct task_struct *irqthread; unsigned long flags; WARN(in_interrupt(), "Trying to free IRQ %d from IRQ context!\n", irq); @@ -809,9 +808,6 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id) desc->chip->disable(irq); } - irqthread = action->thread; - action->thread = NULL; - spin_unlock_irqrestore(&desc->lock, flags); unregister_handler_proc(irq, action); @@ -819,12 +815,6 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id) /* Make sure it's not being used on another CPU: */ synchronize_irq(irq); - if (irqthread) { - if (!test_bit(IRQTF_DIED, &action->thread_flags)) - kthread_stop(irqthread); - put_task_struct(irqthread); - } - #ifdef CONFIG_DEBUG_SHIRQ /* * It's a shared IRQ -- the driver ought to be prepared for an IRQ @@ -840,6 +830,13 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id) local_irq_restore(flags); } #endif + + if (action->thread) { + if (!test_bit(IRQTF_DIED, &action->thread_flags)) + kthread_stop(action->thread); + put_task_struct(action->thread); + } + return action; } diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c index b0b20a0..534e20d 100644 --- a/kernel/perf_counter.c +++ b/kernel/perf_counter.c @@ -88,6 +88,7 @@ void __weak hw_perf_disable(void) { barrier(); } void __weak hw_perf_enable(void) { barrier(); } void __weak hw_perf_counter_setup(int cpu) { barrier(); } +void __weak hw_perf_counter_setup_online(int cpu) { barrier(); } int __weak hw_perf_group_sched_in(struct perf_counter *group_leader, @@ -306,6 +307,10 @@ counter_sched_out(struct perf_counter *counter, return; counter->state = PERF_COUNTER_STATE_INACTIVE; + if (counter->pending_disable) { + counter->pending_disable = 0; + counter->state = PERF_COUNTER_STATE_OFF; + } counter->tstamp_stopped = ctx->time; counter->pmu->disable(counter); counter->oncpu = -1; @@ -1691,7 +1696,32 @@ static int perf_release(struct inode *inode, struct file *file) return 0; } -static u64 perf_counter_read_tree(struct perf_counter *counter) +static int perf_counter_read_size(struct perf_counter *counter) +{ + int entry = sizeof(u64); /* value */ + int size = 0; + int nr = 1; + + if (counter->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) + size += sizeof(u64); + + if (counter->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) + size += sizeof(u64); + + if (counter->attr.read_format & PERF_FORMAT_ID) + entry += sizeof(u64); + + if (counter->attr.read_format & PERF_FORMAT_GROUP) { + nr += counter->group_leader->nr_siblings; + size += sizeof(u64); + } + + size += entry * nr; + + return size; +} + +static u64 perf_counter_read_value(struct perf_counter *counter) { struct perf_counter *child; u64 total = 0; @@ -1703,14 +1733,96 @@ static u64 perf_counter_read_tree(struct perf_counter *counter) return total; } +static int perf_counter_read_entry(struct perf_counter *counter, + u64 read_format, char __user *buf) +{ + int n = 0, count = 0; + u64 values[2]; + + values[n++] = perf_counter_read_value(counter); + if (read_format & PERF_FORMAT_ID) + values[n++] = primary_counter_id(counter); + + count = n * sizeof(u64); + + if (copy_to_user(buf, values, count)) + return -EFAULT; + + return count; +} + +static int perf_counter_read_group(struct perf_counter *counter, + u64 read_format, char __user *buf) +{ + struct perf_counter *leader = counter->group_leader, *sub; + int n = 0, size = 0, err = -EFAULT; + u64 values[3]; + + values[n++] = 1 + leader->nr_siblings; + if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) { + values[n++] = leader->total_time_enabled + + atomic64_read(&leader->child_total_time_enabled); + } + if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) { + values[n++] = leader->total_time_running + + atomic64_read(&leader->child_total_time_running); + } + + size = n * sizeof(u64); + + if (copy_to_user(buf, values, size)) + return -EFAULT; + + err = perf_counter_read_entry(leader, read_format, buf + size); + if (err < 0) + return err; + + size += err; + + list_for_each_entry(sub, &leader->sibling_list, list_entry) { + err = perf_counter_read_entry(counter, read_format, + buf + size); + if (err < 0) + return err; + + size += err; + } + + return size; +} + +static int perf_counter_read_one(struct perf_counter *counter, + u64 read_format, char __user *buf) +{ + u64 values[4]; + int n = 0; + + values[n++] = perf_counter_read_value(counter); + if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) { + values[n++] = counter->total_time_enabled + + atomic64_read(&counter->child_total_time_enabled); + } + if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) { + values[n++] = counter->total_time_running + + atomic64_read(&counter->child_total_time_running); + } + if (read_format & PERF_FORMAT_ID) + values[n++] = primary_counter_id(counter); + + if (copy_to_user(buf, values, n * sizeof(u64))) + return -EFAULT; + + return n * sizeof(u64); +} + /* * Read the performance counter - simple non blocking version for now */ static ssize_t perf_read_hw(struct perf_counter *counter, char __user *buf, size_t count) { - u64 values[4]; - int n; + u64 read_format = counter->attr.read_format; + int ret; /* * Return end-of-file for a read on a counter that is in @@ -1720,28 +1832,18 @@ perf_read_hw(struct perf_counter *counter, char __user *buf, size_t count) if (counter->state == PERF_COUNTER_STATE_ERROR) return 0; + if (count < perf_counter_read_size(counter)) + return -ENOSPC; + WARN_ON_ONCE(counter->ctx->parent_ctx); mutex_lock(&counter->child_mutex); - values[0] = perf_counter_read_tree(counter); - n = 1; - if (counter->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) - values[n++] = counter->total_time_enabled + - atomic64_read(&counter->child_total_time_enabled); - if (counter->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) - values[n++] = counter->total_time_running + - atomic64_read(&counter->child_total_time_running); - if (counter->attr.read_format & PERF_FORMAT_ID) - values[n++] = primary_counter_id(counter); + if (read_format & PERF_FORMAT_GROUP) + ret = perf_counter_read_group(counter, read_format, buf); + else + ret = perf_counter_read_one(counter, read_format, buf); mutex_unlock(&counter->child_mutex); - if (count < n * sizeof(u64)) - return -EINVAL; - count = n * sizeof(u64); - - if (copy_to_user(buf, values, count)) - return -EFAULT; - - return count; + return ret; } static ssize_t @@ -2245,7 +2347,7 @@ static void perf_pending_counter(struct perf_pending_entry *entry) if (counter->pending_disable) { counter->pending_disable = 0; - perf_counter_disable(counter); + __perf_counter_disable(counter); } if (counter->pending_wakeup) { @@ -2630,7 +2732,80 @@ static u32 perf_counter_tid(struct perf_counter *counter, struct task_struct *p) return task_pid_nr_ns(p, counter->ns); } -static void perf_counter_output(struct perf_counter *counter, int nmi, +static void perf_output_read_one(struct perf_output_handle *handle, + struct perf_counter *counter) +{ + u64 read_format = counter->attr.read_format; + u64 values[4]; + int n = 0; + + values[n++] = atomic64_read(&counter->count); + if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) { + values[n++] = counter->total_time_enabled + + atomic64_read(&counter->child_total_time_enabled); + } + if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) { + values[n++] = counter->total_time_running + + atomic64_read(&counter->child_total_time_running); + } + if (read_format & PERF_FORMAT_ID) + values[n++] = primary_counter_id(counter); + + perf_output_copy(handle, values, n * sizeof(u64)); +} + +/* + * XXX PERF_FORMAT_GROUP vs inherited counters seems difficult. + */ +static void perf_output_read_group(struct perf_output_handle *handle, + struct perf_counter *counter) +{ + struct perf_counter *leader = counter->group_leader, *sub; + u64 read_format = counter->attr.read_format; + u64 values[5]; + int n = 0; + + values[n++] = 1 + leader->nr_siblings; + + if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) + values[n++] = leader->total_time_enabled; + + if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) + values[n++] = leader->total_time_running; + + if (leader != counter) + leader->pmu->read(leader); + + values[n++] = atomic64_read(&leader->count); + if (read_format & PERF_FORMAT_ID) + values[n++] = primary_counter_id(leader); + + perf_output_copy(handle, values, n * sizeof(u64)); + + list_for_each_entry(sub, &leader->sibling_list, list_entry) { + n = 0; + + if (sub != counter) + sub->pmu->read(sub); + + values[n++] = atomic64_read(&sub->count); + if (read_format & PERF_FORMAT_ID) + values[n++] = primary_counter_id(sub); + + perf_output_copy(handle, values, n * sizeof(u64)); + } +} + +static void perf_output_read(struct perf_output_handle *handle, + struct perf_counter *counter) +{ + if (counter->attr.read_format & PERF_FORMAT_GROUP) + perf_output_read_group(handle, counter); + else + perf_output_read_one(handle, counter); +} + +void perf_counter_output(struct perf_counter *counter, int nmi, struct perf_sample_data *data) { int ret; @@ -2641,10 +2816,6 @@ static void perf_counter_output(struct perf_counter *counter, int nmi, struct { u32 pid, tid; } tid_entry; - struct { - u64 id; - u64 counter; - } group_entry; struct perf_callchain_entry *callchain = NULL; int callchain_size = 0; u64 time; @@ -2699,10 +2870,8 @@ static void perf_counter_output(struct perf_counter *counter, int nmi, if (sample_type & PERF_SAMPLE_PERIOD) header.size += sizeof(u64); - if (sample_type & PERF_SAMPLE_GROUP) { - header.size += sizeof(u64) + - counter->nr_siblings * sizeof(group_entry); - } + if (sample_type & PERF_SAMPLE_READ) + header.size += perf_counter_read_size(counter); if (sample_type & PERF_SAMPLE_CALLCHAIN) { callchain = perf_callchain(data->regs); @@ -2759,26 +2928,8 @@ static void perf_counter_output(struct perf_counter *counter, int nmi, if (sample_type & PERF_SAMPLE_PERIOD) perf_output_put(&handle, data->period); - /* - * XXX PERF_SAMPLE_GROUP vs inherited counters seems difficult. - */ - if (sample_type & PERF_SAMPLE_GROUP) { - struct perf_counter *leader, *sub; - u64 nr = counter->nr_siblings; - - perf_output_put(&handle, nr); - - leader = counter->group_leader; - list_for_each_entry(sub, &leader->sibling_list, list_entry) { - if (sub != counter) - sub->pmu->read(sub); - - group_entry.id = primary_counter_id(sub); - group_entry.counter = atomic64_read(&sub->count); - - perf_output_put(&handle, group_entry); - } - } + if (sample_type & PERF_SAMPLE_READ) + perf_output_read(&handle, counter); if (sample_type & PERF_SAMPLE_CALLCHAIN) { if (callchain) @@ -2817,8 +2968,6 @@ struct perf_read_event { u32 pid; u32 tid; - u64 value; - u64 format[3]; }; static void @@ -2830,34 +2979,20 @@ perf_counter_read_event(struct perf_counter *counter, .header = { .type = PERF_EVENT_READ, .misc = 0, - .size = sizeof(event) - sizeof(event.format), + .size = sizeof(event) + perf_counter_read_size(counter), }, .pid = perf_counter_pid(counter, task), .tid = perf_counter_tid(counter, task), - .value = atomic64_read(&counter->count), }; - int ret, i = 0; - - if (counter->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) { - event.header.size += sizeof(u64); - event.format[i++] = counter->total_time_enabled; - } - - if (counter->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) { - event.header.size += sizeof(u64); - event.format[i++] = counter->total_time_running; - } - - if (counter->attr.read_format & PERF_FORMAT_ID) { - event.header.size += sizeof(u64); - event.format[i++] = primary_counter_id(counter); - } + int ret; ret = perf_output_begin(&handle, counter, event.header.size, 0, 0); if (ret) return; - perf_output_copy(&handle, &event, event.header.size); + perf_output_put(&handle, event); + perf_output_read(&handle, counter); + perf_output_end(&handle); } @@ -2893,10 +3028,10 @@ static void perf_counter_task_output(struct perf_counter *counter, return; task_event->event.pid = perf_counter_pid(counter, task); - task_event->event.ppid = perf_counter_pid(counter, task->real_parent); + task_event->event.ppid = perf_counter_pid(counter, current); task_event->event.tid = perf_counter_tid(counter, task); - task_event->event.ptid = perf_counter_tid(counter, task->real_parent); + task_event->event.ptid = perf_counter_tid(counter, current); perf_output_put(&handle, task_event->event); perf_output_end(&handle); @@ -3443,40 +3578,32 @@ static void perf_swcounter_add(struct perf_counter *counter, u64 nr, static int perf_swcounter_is_counting(struct perf_counter *counter) { - struct perf_counter_context *ctx; - unsigned long flags; - int count; - + /* + * The counter is active, we're good! + */ if (counter->state == PERF_COUNTER_STATE_ACTIVE) return 1; + /* + * The counter is off/error, not counting. + */ if (counter->state != PERF_COUNTER_STATE_INACTIVE) return 0; /* - * If the counter is inactive, it could be just because - * its task is scheduled out, or because it's in a group - * which could not go on the PMU. We want to count in - * the first case but not the second. If the context is - * currently active then an inactive software counter must - * be the second case. If it's not currently active then - * we need to know whether the counter was active when the - * context was last active, which we can determine by - * comparing counter->tstamp_stopped with ctx->time. - * - * We are within an RCU read-side critical section, - * which protects the existence of *ctx. + * The counter is inactive, if the context is active + * we're part of a group that didn't make it on the 'pmu', + * not counting. */ - ctx = counter->ctx; - spin_lock_irqsave(&ctx->lock, flags); - count = 1; - /* Re-check state now we have the lock */ - if (counter->state < PERF_COUNTER_STATE_INACTIVE || - counter->ctx->is_active || - counter->tstamp_stopped < ctx->time) - count = 0; - spin_unlock_irqrestore(&ctx->lock, flags); - return count; + if (counter->ctx->is_active) + return 0; + + /* + * We're inactive and the context is too, this means the + * task is scheduled out, we're counting events that happen + * to us, like migration events. + */ + return 1; } static int perf_swcounter_match(struct perf_counter *counter, @@ -3928,9 +4055,9 @@ perf_counter_alloc(struct perf_counter_attr *attr, atomic64_set(&hwc->period_left, hwc->sample_period); /* - * we currently do not support PERF_SAMPLE_GROUP on inherited counters + * we currently do not support PERF_FORMAT_GROUP on inherited counters */ - if (attr->inherit && (attr->sample_type & PERF_SAMPLE_GROUP)) + if (attr->inherit && (attr->read_format & PERF_FORMAT_GROUP)) goto done; switch (attr->type) { @@ -4592,6 +4719,11 @@ perf_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) perf_counter_init_cpu(cpu); break; + case CPU_ONLINE: + case CPU_ONLINE_FROZEN: + hw_perf_counter_setup_online(cpu); + break; + case CPU_DOWN_PREPARE: case CPU_DOWN_PREPARE_FROZEN: perf_counter_exit_cpu(cpu); @@ -4616,6 +4748,8 @@ void __init perf_counter_init(void) { perf_cpu_notify(&perf_cpu_nb, (unsigned long)CPU_UP_PREPARE, (void *)(long)smp_processor_id()); + perf_cpu_notify(&perf_cpu_nb, (unsigned long)CPU_ONLINE, + (void *)(long)smp_processor_id()); register_cpu_notifier(&perf_cpu_nb); } diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c index 1090b0a..7a34cb5 100644 --- a/kernel/trace/blktrace.c +++ b/kernel/trace/blktrace.c @@ -267,8 +267,8 @@ static void blk_trace_free(struct blk_trace *bt) { debugfs_remove(bt->msg_file); debugfs_remove(bt->dropped_file); - debugfs_remove(bt->dir); relay_close(bt->rchan); + debugfs_remove(bt->dir); free_percpu(bt->sequence); free_percpu(bt->msg_data); kfree(bt); @@ -378,18 +378,8 @@ static int blk_subbuf_start_callback(struct rchan_buf *buf, void *subbuf, static int blk_remove_buf_file_callback(struct dentry *dentry) { - struct dentry *parent = dentry->d_parent; debugfs_remove(dentry); - /* - * this will fail for all but the last file, but that is ok. what we - * care about is the top level buts->name directory going away, when - * the last trace file is gone. Then we don't have to rmdir() that - * manually on trace stop, so it nicely solves the issue with - * force killing of running traces. - */ - - debugfs_remove(parent); return 0; } diff --git a/kernel/wait.c b/kernel/wait.c index ea7c3b4..c4bd3d8 100644 --- a/kernel/wait.c +++ b/kernel/wait.c @@ -10,13 +10,14 @@ #include <linux/wait.h> #include <linux/hash.h> -void init_waitqueue_head(wait_queue_head_t *q) +void __init_waitqueue_head(wait_queue_head_t *q, struct lock_class_key *key) { spin_lock_init(&q->lock); + lockdep_set_class(&q->lock, key); INIT_LIST_HEAD(&q->task_list); } -EXPORT_SYMBOL(init_waitqueue_head); +EXPORT_SYMBOL(__init_waitqueue_head); void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait) { diff --git a/net/socket.c b/net/socket.c index 791d71a..6d47165 100644 --- a/net/socket.c +++ b/net/socket.c @@ -736,7 +736,7 @@ static ssize_t sock_sendpage(struct file *file, struct page *page, if (more) flags |= MSG_MORE; - return sock->ops->sendpage(sock, page, offset, size, flags); + return kernel_sendpage(sock, page, offset, size, flags); } static ssize_t sock_splice_read(struct file *file, loff_t *ppos, diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 15c2a08..1e8cfc4 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1285,6 +1285,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX, context, len); if (rc == -ERANGE) { + kfree(context); + /* Need a larger buffer. Query for the right size. */ rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX, NULL, 0); @@ -1292,7 +1294,6 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent dput(dentry); goto out_unlock; } - kfree(context); len = rc; context = kmalloc(len+1, GFP_NOFS); if (!context) { diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 51c44fd..fea9767 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -13563,6 +13563,8 @@ static int patch_alc269(struct hda_codec *codec) set_capture_mixer(spec); set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); + spec->vmaster_nid = 0x02; + codec->patch_ops = alc_patch_ops; if (board_config == ALC269_AUTO) spec->init_hook = alc269_auto_init; @@ -15577,9 +15579,12 @@ static int patch_alc861vd(struct hda_codec *codec) spec->stream_digital_playback = &alc861vd_pcm_digital_playback; spec->stream_digital_capture = &alc861vd_pcm_digital_capture; - spec->adc_nids = alc861vd_adc_nids; - spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids); - spec->capsrc_nids = alc861vd_capsrc_nids; + if (!spec->adc_nids) { + spec->adc_nids = alc861vd_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids); + } + if (!spec->capsrc_nids) + spec->capsrc_nids = alc861vd_capsrc_nids; set_capture_mixer(spec); set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); @@ -17496,9 +17501,12 @@ static int patch_alc662(struct hda_codec *codec) spec->stream_digital_playback = &alc662_pcm_digital_playback; spec->stream_digital_capture = &alc662_pcm_digital_capture; - spec->adc_nids = alc662_adc_nids; - spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids); - spec->capsrc_nids = alc662_capsrc_nids; + if (!spec->adc_nids) { + spec->adc_nids = alc662_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids); + } + if (!spec->capsrc_nids) + spec->capsrc_nids = alc662_capsrc_nids; if (!spec->cap_mixer) set_capture_mixer(spec); diff --git a/sound/soc/fsl/efika-audio-fabric.c b/sound/soc/fsl/efika-audio-fabric.c index 85b0e75..3326e2a 100644 --- a/sound/soc/fsl/efika-audio-fabric.c +++ b/sound/soc/fsl/efika-audio-fabric.c @@ -30,6 +30,8 @@ #include "mpc5200_psc_ac97.h" #include "../codecs/stac9766.h" +#define DRV_NAME "efika-audio-fabric" + static struct snd_soc_device device; static struct snd_soc_card card; diff --git a/sound/soc/fsl/pcm030-audio-fabric.c b/sound/soc/fsl/pcm030-audio-fabric.c index 8766f7a..b928ef7 100644 --- a/sound/soc/fsl/pcm030-audio-fabric.c +++ b/sound/soc/fsl/pcm030-audio-fabric.c @@ -30,6 +30,8 @@ #include "mpc5200_psc_ac97.h" #include "../codecs/wm9712.h" +#define DRV_NAME "pcm030-audio-fabric" + static struct snd_soc_device device; static struct snd_soc_card card; diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 60411e9..c045b42 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -382,22 +382,29 @@ endif ifdef NO_DEMANGLE BASIC_CFLAGS += -DNO_DEMANGLE else - has_bfd := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) -lbfd > /dev/null 2>&1 && echo y") - has_bfd_iberty := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) -lbfd -liberty > /dev/null 2>&1 && echo y") - - has_bfd_iberty_z := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) -lbfd -liberty -lz > /dev/null 2>&1 && echo y") - ifeq ($(has_bfd),y) EXTLIBS += -lbfd - else ifeq ($(has_bfd_iberty),y) - EXTLIBS += -lbfd -liberty - else ifeq ($(has_bfd_iberty_z),y) - EXTLIBS += -lbfd -liberty -lz else - msg := $(warning No bfd.h/libbfd found, install binutils-dev[el] to gain symbol demangling) - BASIC_CFLAGS += -DNO_DEMANGLE + has_bfd_iberty := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) -lbfd -liberty > /dev/null 2>&1 && echo y") + ifeq ($(has_bfd_iberty),y) + EXTLIBS += -lbfd -liberty + else + has_bfd_iberty_z := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) -lbfd -liberty -lz > /dev/null 2>&1 && echo y") + ifeq ($(has_bfd_iberty_z),y) + EXTLIBS += -lbfd -liberty -lz + else + has_cplus_demangle := $(shell sh -c "(echo 'extern char *cplus_demangle(const char *, int);'; echo 'int main(void) { cplus_demangle(0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o /dev/null $(ALL_LDFLAGS) -liberty > /dev/null 2>&1 && echo y") + ifeq ($(has_cplus_demangle),y) + EXTLIBS += -liberty + BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE + else + msg := $(warning No bfd.h/libbfd found, install binutils-dev[el] to gain symbol demangling) + BASIC_CFLAGS += -DNO_DEMANGLE + endif + endif + endif endif endif diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c index f990fa8..d88c696 100644 --- a/tools/perf/builtin-list.c +++ b/tools/perf/builtin-list.c @@ -10,11 +10,12 @@ #include "perf.h" -#include "util/parse-options.h" #include "util/parse-events.h" +#include "util/cache.h" int cmd_list(int argc __used, const char **argv __used, const char *prefix __used) { + setup_pager(); print_events(); return 0; } diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 0345aad..3d051b9 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -34,7 +34,9 @@ static int output; static const char *output_name = "perf.data"; static int group = 0; static unsigned int realtime_prio = 0; +static int raw_samples = 0; static int system_wide = 0; +static int profile_cpu = -1; static pid_t target_pid = -1; static int inherit = 1; static int force = 0; @@ -203,46 +205,48 @@ static void sig_atexit(void) kill(getpid(), signr); } -static void pid_synthesize_comm_event(pid_t pid, int full) +static pid_t pid_synthesize_comm_event(pid_t pid, int full) { struct comm_event comm_ev; char filename[PATH_MAX]; char bf[BUFSIZ]; - int fd; - size_t size; - char *field, *sep; + FILE *fp; + size_t size = 0; DIR *tasks; struct dirent dirent, *next; + pid_t tgid = 0; - snprintf(filename, sizeof(filename), "/proc/%d/stat", pid); + snprintf(filename, sizeof(filename), "/proc/%d/status", pid); - fd = open(filename, O_RDONLY); - if (fd < 0) { + fp = fopen(filename, "r"); + if (fd == NULL) { /* * We raced with a task exiting - just return: */ if (verbose) fprintf(stderr, "couldn't open %s\n", filename); - return; - } - if (read(fd, bf, sizeof(bf)) < 0) { - fprintf(stderr, "couldn't read %s\n", filename); - exit(EXIT_FAILURE); + return 0; } - close(fd); - /* 9027 (cat) R 6747 9027 6747 34816 9027 ... */ memset(&comm_ev, 0, sizeof(comm_ev)); - field = strchr(bf, '('); - if (field == NULL) - goto out_failure; - sep = strchr(++field, ')'); - if (sep == NULL) - goto out_failure; - size = sep - field; - memcpy(comm_ev.comm, field, size++); - - comm_ev.pid = pid; + while (!comm_ev.comm[0] || !comm_ev.pid) { + if (fgets(bf, sizeof(bf), fp) == NULL) + goto out_failure; + + if (memcmp(bf, "Name:", 5) == 0) { + char *name = bf + 5; + while (*name && isspace(*name)) + ++name; + size = strlen(name) - 1; + memcpy(comm_ev.comm, name, size++); + } else if (memcmp(bf, "Tgid:", 5) == 0) { + char *tgids = bf + 5; + while (*tgids && isspace(*tgids)) + ++tgids; + tgid = comm_ev.pid = atoi(tgids); + } + } + comm_ev.header.type = PERF_EVENT_COMM; size = ALIGN(size, sizeof(u64)); comm_ev.header.size = sizeof(comm_ev) - (sizeof(comm_ev.comm) - size); @@ -251,7 +255,7 @@ static void pid_synthesize_comm_event(pid_t pid, int full) comm_ev.tid = pid; write_output(&comm_ev, comm_ev.header.size); - return; + goto out_fclose; } snprintf(filename, sizeof(filename), "/proc/%d/task", pid); @@ -268,7 +272,10 @@ static void pid_synthesize_comm_event(pid_t pid, int full) write_output(&comm_ev, comm_ev.header.size); } closedir(tasks); - return; + +out_fclose: + fclose(fp); + return tgid; out_failure: fprintf(stderr, "couldn't get COMM and pgid, malformed %s\n", @@ -276,7 +283,7 @@ out_failure: exit(EXIT_FAILURE); } -static void pid_synthesize_mmap_samples(pid_t pid) +static void pid_synthesize_mmap_samples(pid_t pid, pid_t tgid) { char filename[PATH_MAX]; FILE *fp; @@ -328,7 +335,7 @@ static void pid_synthesize_mmap_samples(pid_t pid) mmap_ev.len -= mmap_ev.start; mmap_ev.header.size = (sizeof(mmap_ev) - (sizeof(mmap_ev.filename) - size)); - mmap_ev.pid = pid; + mmap_ev.pid = tgid; mmap_ev.tid = pid; write_output(&mmap_ev, mmap_ev.header.size); @@ -347,14 +354,14 @@ static void synthesize_all(void) while (!readdir_r(proc, &dirent, &next) && next) { char *end; - pid_t pid; + pid_t pid, tgid; pid = strtol(dirent.d_name, &end, 10); if (*end) /* only interested in proper numerical dirents */ continue; - pid_synthesize_comm_event(pid, 1); - pid_synthesize_mmap_samples(pid); + tgid = pid_synthesize_comm_event(pid, 1); + pid_synthesize_mmap_samples(pid, tgid); } closedir(proc); @@ -392,7 +399,7 @@ static void create_counter(int counter, int cpu, pid_t pid) PERF_FORMAT_TOTAL_TIME_RUNNING | PERF_FORMAT_ID; - attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; + attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; if (freq) { attr->sample_type |= PERF_SAMPLE_PERIOD; @@ -412,6 +419,8 @@ static void create_counter(int counter, int cpu, pid_t pid) if (call_graph) attr->sample_type |= PERF_SAMPLE_CALLCHAIN; + if (raw_samples) + attr->sample_type |= PERF_SAMPLE_RAW; attr->mmap = track; attr->comm = track; @@ -426,6 +435,8 @@ try_again: if (err == EPERM) die("Permission error - are you root?\n"); + else if (err == ENODEV && profile_cpu != -1) + die("No such device - did you specify an out-of-range profile CPU?\n"); /* * If it's cycles then fall back to hrtimer @@ -559,16 +570,22 @@ static int __cmd_record(int argc, const char **argv) if (pid == -1) pid = getpid(); - open_counters(-1, pid); - } else for (i = 0; i < nr_cpus; i++) - open_counters(i, target_pid); + open_counters(profile_cpu, pid); + } else { + if (profile_cpu != -1) { + open_counters(profile_cpu, target_pid); + } else { + for (i = 0; i < nr_cpus; i++) + open_counters(i, target_pid); + } + } if (file_new) perf_header__write(header, output); if (!system_wide) { - pid_synthesize_comm_event(pid, 0); - pid_synthesize_mmap_samples(pid); + pid_t tgid = pid_synthesize_comm_event(pid, 0); + pid_synthesize_mmap_samples(pid, tgid); } else synthesize_all(); @@ -636,10 +653,14 @@ static const struct option options[] = { "record events on existing pid"), OPT_INTEGER('r', "realtime", &realtime_prio, "collect data with this RT SCHED_FIFO priority"), + OPT_BOOLEAN('R', "raw-samples", &raw_samples, + "collect raw sample records from all opened counters"), OPT_BOOLEAN('a', "all-cpus", &system_wide, "system-wide collection from all CPUs"), OPT_BOOLEAN('A', "append", &append_file, "append to the output file to do incremental profiling"), + OPT_INTEGER('C', "profile_cpu", &profile_cpu, + "CPU to profile on"), OPT_BOOLEAN('f', "force", &force, "overwrite existing data file"), OPT_LONG('c', "count", &default_interval, diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 99274ce..b53a60f 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -1526,11 +1526,11 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) more_data += sizeof(u64); } - dprintf("%p [%p]: PERF_EVENT_SAMPLE (IP, %d): %d: %p period: %Ld\n", + dprintf("%p [%p]: PERF_EVENT_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n", (void *)(offset + head), (void *)(long)(event->header.size), event->header.misc, - event->ip.pid, + event->ip.pid, event->ip.tid, (void *)(long)ip, (long long)period); @@ -1590,10 +1590,11 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) if (show & show_mask) { struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip); - if (dso_list && dso && dso->name && !strlist__has_entry(dso_list, dso->name)) + if (dso_list && (!dso || !dso->name || + !strlist__has_entry(dso_list, dso->name))) return 0; - if (sym_list && sym && !strlist__has_entry(sym_list, sym->name)) + if (sym_list && (!sym || !strlist__has_entry(sym_list, sym->name))) return 0; if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) { @@ -1612,10 +1613,11 @@ process_mmap_event(event_t *event, unsigned long offset, unsigned long head) struct thread *thread = threads__findnew(event->mmap.pid); struct map *map = map__new(&event->mmap); - dprintf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n", + dprintf("%p [%p]: PERF_EVENT_MMAP %d/%d: [%p(%p) @ %p]: %s\n", (void *)(offset + head), (void *)(long)(event->header.size), event->mmap.pid, + event->mmap.tid, (void *)(long)event->mmap.start, (void *)(long)event->mmap.len, (void *)(long)event->mmap.pgoff, diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 4858d83..0441784 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -379,6 +379,7 @@ static int parse_tracepoint_event(const char **strp, struct perf_counter_attr *attr) { const char *evt_name; + char *flags; char sys_name[MAX_EVENT_LENGTH]; char id_buf[4]; int fd; @@ -400,6 +401,15 @@ static int parse_tracepoint_event(const char **strp, strncpy(sys_name, *strp, sys_length); sys_name[sys_length] = '\0'; evt_name = evt_name + 1; + + flags = strchr(evt_name, ':'); + if (flags) { + *flags = '\0'; + flags++; + if (!strncmp(flags, "record", strlen(flags))) + attr->sample_type |= PERF_SAMPLE_RAW; + } + evt_length = strlen(evt_name); if (evt_length >= MAX_EVENT_LENGTH) return 0; diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index f1dcede..5c0f42e 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -7,23 +7,8 @@ #include <gelf.h> #include <elf.h> -#ifndef NO_DEMANGLE -#include <bfd.h> -#else -static inline -char *bfd_demangle(void __used *v, const char __used *c, int __used i) -{ - return NULL; -} -#endif - const char *sym_hist_filter; -#ifndef DMGL_PARAMS -#define DMGL_PARAMS (1 << 0) /* Include function args */ -#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ -#endif - enum dso_origin { DSO__ORIG_KERNEL = 0, DSO__ORIG_JAVA_JIT, @@ -816,6 +801,8 @@ more: } out: free(name); + if (ret < 0 && strstr(self->name, " (deleted)") != NULL) + return 0; return ret; } diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 1e003ec..b53bf01 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -7,6 +7,30 @@ #include <linux/rbtree.h> #include "module.h" +#ifdef HAVE_CPLUS_DEMANGLE +extern char *cplus_demangle(const char *, int); + +static inline char *bfd_demangle(void __used *v, const char *c, int i) +{ + return cplus_demangle(c, i); +} +#else +#ifdef NO_DEMANGLE +static inline char *bfd_demangle(void __used *v, const char __used *c, + int __used i) +{ + return NULL; +} +#else +#include <bfd.h> +#endif +#endif + +#ifndef DMGL_PARAMS +#define DMGL_PARAMS (1 << 0) /* Include function args */ +#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ +#endif + struct symbol { struct rb_node rb_node; u64 start; |