diff options
66 files changed, 1455 insertions, 341 deletions
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index 7bb0d934b6d8..dbea4f95fc85 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt | |||
| @@ -139,6 +139,7 @@ Code Seq# Include File Comments | |||
| 139 | 'm' all linux/synclink.h conflict! | 139 | 'm' all linux/synclink.h conflict! |
| 140 | 'm' 00-1F net/irda/irmod.h conflict! | 140 | 'm' 00-1F net/irda/irmod.h conflict! |
| 141 | 'n' 00-7F linux/ncp_fs.h | 141 | 'n' 00-7F linux/ncp_fs.h |
| 142 | 'n' 80-8F linux/nilfs2_fs.h NILFS2 | ||
| 142 | 'n' E0-FF video/matrox.h matroxfb | 143 | 'n' E0-FF video/matrox.h matroxfb |
| 143 | 'o' 00-1F fs/ocfs2/ocfs2_fs.h OCFS2 | 144 | 'o' 00-1F fs/ocfs2/ocfs2_fs.h OCFS2 |
| 144 | 'o' 00-03 include/mtd/ubi-user.h conflict! (OCFS2 and UBI overlaps) | 145 | 'o' 00-03 include/mtd/ubi-user.h conflict! (OCFS2 and UBI overlaps) |
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index dd1a6d4bb747..7936b801fe6a 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 | |||
| 1115 | libata.dma=4 Compact Flash DMA only | 1115 | libata.dma=4 Compact Flash DMA only |
| 1116 | Combinations also work, so libata.dma=3 enables DMA | 1116 | Combinations also work, so libata.dma=3 enables DMA |
| 1117 | for disks and CDROMs, but not CFs. | 1117 | for disks and CDROMs, but not CFs. |
| 1118 | |||
| 1119 | libata.ignore_hpa= [LIBATA] Ignore HPA limit | ||
| 1120 | libata.ignore_hpa=0 keep BIOS limits (default) | ||
| 1121 | libata.ignore_hpa=1 ignore limits, using full disk | ||
| 1118 | 1122 | ||
| 1119 | libata.noacpi [LIBATA] Disables use of ACPI in libata suspend/resume | 1123 | libata.noacpi [LIBATA] Disables use of ACPI in libata suspend/resume |
| 1120 | when set. | 1124 | when set. |
diff --git a/arch/arm/plat-s3c24xx/clock-dclk.c b/arch/arm/plat-s3c24xx/clock-dclk.c index 5b75a797b5ab..0afb217a775e 100644 --- a/arch/arm/plat-s3c24xx/clock-dclk.c +++ b/arch/arm/plat-s3c24xx/clock-dclk.c | |||
| @@ -129,7 +129,7 @@ static int s3c24xx_clkout_setparent(struct clk *clk, struct clk *parent) | |||
| 129 | 129 | ||
| 130 | /* calculate the MISCCR setting for the clock */ | 130 | /* calculate the MISCCR setting for the clock */ |
| 131 | 131 | ||
| 132 | if (parent == &clk_xtal) | 132 | if (parent == &clk_mpll) |
| 133 | source = S3C2410_MISCCR_CLK0_MPLL; | 133 | source = S3C2410_MISCCR_CLK0_MPLL; |
| 134 | else if (parent == &clk_upll) | 134 | else if (parent == &clk_upll) |
| 135 | source = S3C2410_MISCCR_CLK0_UPLL; | 135 | source = S3C2410_MISCCR_CLK0_UPLL; |
diff --git a/arch/ia64/Makefile b/arch/ia64/Makefile index 58a7e46affda..e7cbaa02cd0b 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 | |||
| 41 | ftp://ftp.hpl.hp.com/pub/linux-ia64/gas-030124.tar.gz) | 41 | ftp://ftp.hpl.hp.com/pub/linux-ia64/gas-030124.tar.gz) |
| 42 | endif | 42 | endif |
| 43 | 43 | ||
| 44 | ifeq ($(call cc-version),0304) | ||
| 45 | cflags-$(CONFIG_ITANIUM) += -mtune=merced | ||
| 46 | cflags-$(CONFIG_MCKINLEY) += -mtune=mckinley | ||
| 47 | endif | ||
| 48 | |||
| 49 | KBUILD_CFLAGS += $(cflags-y) | 44 | KBUILD_CFLAGS += $(cflags-y) |
| 50 | head-y := arch/ia64/kernel/head.o arch/ia64/kernel/init_task.o | 45 | head-y := arch/ia64/kernel/head.o arch/ia64/kernel/init_task.o |
| 51 | 46 | ||
diff --git a/arch/ia64/include/asm/bitops.h b/arch/ia64/include/asm/bitops.h index e2ca80037335..57a2787bc9fb 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) | |||
| 286 | { | 286 | { |
| 287 | __u32 *p = (__u32 *) addr + (nr >> 5); | 287 | __u32 *p = (__u32 *) addr + (nr >> 5); |
| 288 | __u32 m = 1 << (nr & 31); | 288 | __u32 m = 1 << (nr & 31); |
| 289 | int oldbitset = *p & m; | 289 | int oldbitset = (*p & m) != 0; |
| 290 | 290 | ||
| 291 | *p &= ~m; | 291 | *p &= ~m; |
| 292 | return oldbitset; | 292 | return oldbitset; |
diff --git a/arch/ia64/include/asm/pgtable.h b/arch/ia64/include/asm/pgtable.h index 0a9cc73d35c7..8840a690d1e7 100644 --- a/arch/ia64/include/asm/pgtable.h +++ b/arch/ia64/include/asm/pgtable.h | |||
| @@ -155,7 +155,6 @@ | |||
| 155 | #include <linux/bitops.h> | 155 | #include <linux/bitops.h> |
| 156 | #include <asm/cacheflush.h> | 156 | #include <asm/cacheflush.h> |
| 157 | #include <asm/mmu_context.h> | 157 | #include <asm/mmu_context.h> |
| 158 | #include <asm/processor.h> | ||
| 159 | 158 | ||
| 160 | /* | 159 | /* |
| 161 | * Next come the mappings that determine how mmap() protection bits | 160 | * 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 2d311864e359..8ebccb589e1c 100644 --- a/arch/ia64/kernel/ia64_ksyms.c +++ b/arch/ia64/kernel/ia64_ksyms.c | |||
| @@ -21,6 +21,7 @@ EXPORT_SYMBOL(csum_ipv6_magic); | |||
| 21 | 21 | ||
| 22 | #include <asm/page.h> | 22 | #include <asm/page.h> |
| 23 | EXPORT_SYMBOL(clear_page); | 23 | EXPORT_SYMBOL(clear_page); |
| 24 | EXPORT_SYMBOL(copy_page); | ||
| 24 | 25 | ||
| 25 | #ifdef CONFIG_VIRTUAL_MEM_MAP | 26 | #ifdef CONFIG_VIRTUAL_MEM_MAP |
| 26 | #include <linux/bootmem.h> | 27 | #include <linux/bootmem.h> |
| @@ -60,9 +61,6 @@ EXPORT_SYMBOL(__udivdi3); | |||
| 60 | EXPORT_SYMBOL(__moddi3); | 61 | EXPORT_SYMBOL(__moddi3); |
| 61 | EXPORT_SYMBOL(__umoddi3); | 62 | EXPORT_SYMBOL(__umoddi3); |
| 62 | 63 | ||
| 63 | #include <asm/page.h> | ||
| 64 | EXPORT_SYMBOL(copy_page); | ||
| 65 | |||
| 66 | #if defined(CONFIG_MD_RAID456) || defined(CONFIG_MD_RAID456_MODULE) | 64 | #if defined(CONFIG_MD_RAID456) || defined(CONFIG_MD_RAID456_MODULE) |
| 67 | extern void xor_ia64_2(void); | 65 | extern void xor_ia64_2(void); |
| 68 | extern void xor_ia64_3(void); | 66 | extern void xor_ia64_3(void); |
diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c index c48b03f2b61d..dab4d393908c 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) | |||
| 1072 | } | 1072 | } |
| 1073 | 1073 | ||
| 1074 | addr = ioremap(phys_addr, 0); | 1074 | addr = ioremap(phys_addr, 0); |
| 1075 | if (addr == NULL) { | ||
| 1076 | spin_unlock_irqrestore(&iosapic_lock, flags); | ||
| 1077 | return -ENOMEM; | ||
| 1078 | } | ||
| 1075 | ver = iosapic_version(addr); | 1079 | ver = iosapic_version(addr); |
| 1076 | if ((err = iosapic_check_gsi_range(gsi_base, ver))) { | 1080 | if ((err = iosapic_check_gsi_range(gsi_base, ver))) { |
| 1077 | iounmap(addr); | 1081 | iounmap(addr); |
diff --git a/arch/ia64/kernel/pci-dma.c b/arch/ia64/kernel/pci-dma.c index 05695962fe44..f6b1ff0aea76 100644 --- a/arch/ia64/kernel/pci-dma.c +++ b/arch/ia64/kernel/pci-dma.c | |||
| @@ -69,11 +69,6 @@ iommu_dma_init(void) | |||
| 69 | 69 | ||
| 70 | int iommu_dma_supported(struct device *dev, u64 mask) | 70 | int iommu_dma_supported(struct device *dev, u64 mask) |
| 71 | { | 71 | { |
| 72 | struct dma_map_ops *ops = platform_dma_get_ops(dev); | ||
| 73 | |||
| 74 | if (ops->dma_supported) | ||
| 75 | return ops->dma_supported(dev, mask); | ||
| 76 | |||
| 77 | /* Copied from i386. Doesn't make much sense, because it will | 72 | /* Copied from i386. Doesn't make much sense, because it will |
| 78 | only work for pci_alloc_coherent. | 73 | only work for pci_alloc_coherent. |
| 79 | The caller just has to use GFP_DMA in this case. */ | 74 | 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 bc80dff1df7a..8f060352e129 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) | |||
| 372 | retval = kobject_init_and_add(&all_cpu_cache_info[cpu].kobj, | 372 | retval = kobject_init_and_add(&all_cpu_cache_info[cpu].kobj, |
| 373 | &cache_ktype_percpu_entry, &sys_dev->kobj, | 373 | &cache_ktype_percpu_entry, &sys_dev->kobj, |
| 374 | "%s", "cache"); | 374 | "%s", "cache"); |
| 375 | if (unlikely(retval < 0)) { | ||
| 376 | cpu_cache_sysfs_exit(cpu); | ||
| 377 | return retval; | ||
| 378 | } | ||
| 375 | 379 | ||
| 376 | for (i = 0; i < all_cpu_cache_info[cpu].num_cache_leaves; i++) { | 380 | for (i = 0; i < all_cpu_cache_info[cpu].num_cache_leaves; i++) { |
| 377 | this_object = LEAF_KOBJECT_PTR(cpu,i); | 381 | this_object = LEAF_KOBJECT_PTR(cpu,i); |
| @@ -385,7 +389,7 @@ static int __cpuinit cache_add_dev(struct sys_device * sys_dev) | |||
| 385 | } | 389 | } |
| 386 | kobject_put(&all_cpu_cache_info[cpu].kobj); | 390 | kobject_put(&all_cpu_cache_info[cpu].kobj); |
| 387 | cpu_cache_sysfs_exit(cpu); | 391 | cpu_cache_sysfs_exit(cpu); |
| 388 | break; | 392 | return retval; |
| 389 | } | 393 | } |
| 390 | kobject_uevent(&(this_object->kobj), KOBJ_ADD); | 394 | kobject_uevent(&(this_object->kobj), KOBJ_ADD); |
| 391 | } | 395 | } |
diff --git a/arch/mn10300/include/asm/pci.h b/arch/mn10300/include/asm/pci.h index 35d2ed6396f6..19aecc90f7a4 100644 --- a/arch/mn10300/include/asm/pci.h +++ b/arch/mn10300/include/asm/pci.h | |||
| @@ -59,7 +59,6 @@ void pcibios_penalize_isa_irq(int irq); | |||
| 59 | #include <linux/slab.h> | 59 | #include <linux/slab.h> |
| 60 | #include <asm/scatterlist.h> | 60 | #include <asm/scatterlist.h> |
| 61 | #include <linux/string.h> | 61 | #include <linux/string.h> |
| 62 | #include <linux/mm.h> | ||
| 63 | #include <asm/io.h> | 62 | #include <asm/io.h> |
| 64 | 63 | ||
| 65 | struct pci_dev; | 64 | struct pci_dev; |
diff --git a/arch/powerpc/kernel/dma.c b/arch/powerpc/kernel/dma.c index 20a60d661ba8..ccf129d47d84 100644 --- a/arch/powerpc/kernel/dma.c +++ b/arch/powerpc/kernel/dma.c | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | 7 | ||
| 8 | #include <linux/device.h> | 8 | #include <linux/device.h> |
| 9 | #include <linux/dma-mapping.h> | 9 | #include <linux/dma-mapping.h> |
| 10 | #include <linux/lmb.h> | ||
| 10 | #include <asm/bug.h> | 11 | #include <asm/bug.h> |
| 11 | #include <asm/abs_addr.h> | 12 | #include <asm/abs_addr.h> |
| 12 | 13 | ||
| @@ -90,11 +91,10 @@ static void dma_direct_unmap_sg(struct device *dev, struct scatterlist *sg, | |||
| 90 | static int dma_direct_dma_supported(struct device *dev, u64 mask) | 91 | static int dma_direct_dma_supported(struct device *dev, u64 mask) |
| 91 | { | 92 | { |
| 92 | #ifdef CONFIG_PPC64 | 93 | #ifdef CONFIG_PPC64 |
| 93 | /* Could be improved to check for memory though it better be | 94 | /* Could be improved so platforms can set the limit in case |
| 94 | * done via some global so platforms can set the limit in case | ||
| 95 | * they have limited DMA windows | 95 | * they have limited DMA windows |
| 96 | */ | 96 | */ |
| 97 | return mask >= DMA_BIT_MASK(32); | 97 | return mask >= (lmb_end_of_DRAM() - 1); |
| 98 | #else | 98 | #else |
| 99 | return 1; | 99 | return 1; |
| 100 | #endif | 100 | #endif |
diff --git a/arch/powerpc/kernel/perf_counter.c b/arch/powerpc/kernel/perf_counter.c index 809fdf94b95f..70e1f57f7dd8 100644 --- a/arch/powerpc/kernel/perf_counter.c +++ b/arch/powerpc/kernel/perf_counter.c | |||
| @@ -518,6 +518,8 @@ void hw_perf_disable(void) | |||
| 518 | struct cpu_hw_counters *cpuhw; | 518 | struct cpu_hw_counters *cpuhw; |
| 519 | unsigned long flags; | 519 | unsigned long flags; |
| 520 | 520 | ||
| 521 | if (!ppmu) | ||
| 522 | return; | ||
| 521 | local_irq_save(flags); | 523 | local_irq_save(flags); |
| 522 | cpuhw = &__get_cpu_var(cpu_hw_counters); | 524 | cpuhw = &__get_cpu_var(cpu_hw_counters); |
| 523 | 525 | ||
| @@ -572,6 +574,8 @@ void hw_perf_enable(void) | |||
| 572 | int n_lim; | 574 | int n_lim; |
| 573 | int idx; | 575 | int idx; |
| 574 | 576 | ||
| 577 | if (!ppmu) | ||
| 578 | return; | ||
| 575 | local_irq_save(flags); | 579 | local_irq_save(flags); |
| 576 | cpuhw = &__get_cpu_var(cpu_hw_counters); | 580 | cpuhw = &__get_cpu_var(cpu_hw_counters); |
| 577 | if (!cpuhw->disabled) { | 581 | if (!cpuhw->disabled) { |
| @@ -737,6 +741,8 @@ int hw_perf_group_sched_in(struct perf_counter *group_leader, | |||
| 737 | long i, n, n0; | 741 | long i, n, n0; |
| 738 | struct perf_counter *sub; | 742 | struct perf_counter *sub; |
| 739 | 743 | ||
| 744 | if (!ppmu) | ||
| 745 | return 0; | ||
| 740 | cpuhw = &__get_cpu_var(cpu_hw_counters); | 746 | cpuhw = &__get_cpu_var(cpu_hw_counters); |
| 741 | n0 = cpuhw->n_counters; | 747 | n0 = cpuhw->n_counters; |
| 742 | n = collect_events(group_leader, ppmu->n_counter - n0, | 748 | n = collect_events(group_leader, ppmu->n_counter - n0, |
| @@ -1281,6 +1287,8 @@ void hw_perf_counter_setup(int cpu) | |||
| 1281 | { | 1287 | { |
| 1282 | struct cpu_hw_counters *cpuhw = &per_cpu(cpu_hw_counters, cpu); | 1288 | struct cpu_hw_counters *cpuhw = &per_cpu(cpu_hw_counters, cpu); |
| 1283 | 1289 | ||
| 1290 | if (!ppmu) | ||
| 1291 | return; | ||
| 1284 | memset(cpuhw, 0, sizeof(*cpuhw)); | 1292 | memset(cpuhw, 0, sizeof(*cpuhw)); |
| 1285 | cpuhw->mmcr[0] = MMCR0_FC; | 1293 | cpuhw->mmcr[0] = MMCR0_FC; |
| 1286 | } | 1294 | } |
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index 6e1a368d21d4..71f4368b357e 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c | |||
| @@ -275,15 +275,20 @@ static unsigned long pit_calibrate_tsc(u32 latch, unsigned long ms, int loopmin) | |||
| 275 | * use the TSC value at the transitions to calculate a pretty | 275 | * use the TSC value at the transitions to calculate a pretty |
| 276 | * good value for the TSC frequencty. | 276 | * good value for the TSC frequencty. |
| 277 | */ | 277 | */ |
| 278 | static inline int pit_verify_msb(unsigned char val) | ||
| 279 | { | ||
| 280 | /* Ignore LSB */ | ||
| 281 | inb(0x42); | ||
| 282 | return inb(0x42) == val; | ||
| 283 | } | ||
| 284 | |||
| 278 | static inline int pit_expect_msb(unsigned char val, u64 *tscp, unsigned long *deltap) | 285 | static inline int pit_expect_msb(unsigned char val, u64 *tscp, unsigned long *deltap) |
| 279 | { | 286 | { |
| 280 | int count; | 287 | int count; |
| 281 | u64 tsc = 0; | 288 | u64 tsc = 0; |
| 282 | 289 | ||
| 283 | for (count = 0; count < 50000; count++) { | 290 | for (count = 0; count < 50000; count++) { |
| 284 | /* Ignore LSB */ | 291 | if (!pit_verify_msb(val)) |
| 285 | inb(0x42); | ||
| 286 | if (inb(0x42) != val) | ||
| 287 | break; | 292 | break; |
| 288 | tsc = get_cycles(); | 293 | tsc = get_cycles(); |
| 289 | } | 294 | } |
| @@ -336,8 +341,7 @@ static unsigned long quick_pit_calibrate(void) | |||
| 336 | * to do that is to just read back the 16-bit counter | 341 | * to do that is to just read back the 16-bit counter |
| 337 | * once from the PIT. | 342 | * once from the PIT. |
| 338 | */ | 343 | */ |
| 339 | inb(0x42); | 344 | pit_verify_msb(0); |
| 340 | inb(0x42); | ||
| 341 | 345 | ||
| 342 | if (pit_expect_msb(0xff, &tsc, &d1)) { | 346 | if (pit_expect_msb(0xff, &tsc, &d1)) { |
| 343 | for (i = 1; i <= MAX_QUICK_PIT_ITERATIONS; i++) { | 347 | for (i = 1; i <= MAX_QUICK_PIT_ITERATIONS; i++) { |
| @@ -348,8 +352,19 @@ static unsigned long quick_pit_calibrate(void) | |||
| 348 | * Iterate until the error is less than 500 ppm | 352 | * Iterate until the error is less than 500 ppm |
| 349 | */ | 353 | */ |
| 350 | delta -= tsc; | 354 | delta -= tsc; |
| 351 | if (d1+d2 < delta >> 11) | 355 | if (d1+d2 >= delta >> 11) |
| 352 | goto success; | 356 | continue; |
| 357 | |||
| 358 | /* | ||
| 359 | * Check the PIT one more time to verify that | ||
| 360 | * all TSC reads were stable wrt the PIT. | ||
| 361 | * | ||
| 362 | * This also guarantees serialization of the | ||
| 363 | * last cycle read ('d2') in pit_expect_msb. | ||
| 364 | */ | ||
| 365 | if (!pit_verify_msb(0xfe - i)) | ||
| 366 | break; | ||
| 367 | goto success; | ||
| 353 | } | 368 | } |
| 354 | } | 369 | } |
| 355 | printk("Fast TSC calibration failed\n"); | 370 | printk("Fast TSC calibration failed\n"); |
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 958c1fa41900..fe3eba5d6b3e 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c | |||
| @@ -219,6 +219,8 @@ enum { | |||
| 219 | AHCI_HFLAG_SECT255 = (1 << 8), /* max 255 sectors */ | 219 | AHCI_HFLAG_SECT255 = (1 << 8), /* max 255 sectors */ |
| 220 | AHCI_HFLAG_YES_NCQ = (1 << 9), /* force NCQ cap on */ | 220 | AHCI_HFLAG_YES_NCQ = (1 << 9), /* force NCQ cap on */ |
| 221 | AHCI_HFLAG_NO_SUSPEND = (1 << 10), /* don't suspend */ | 221 | AHCI_HFLAG_NO_SUSPEND = (1 << 10), /* don't suspend */ |
| 222 | AHCI_HFLAG_SRST_TOUT_IS_OFFLINE = (1 << 11), /* treat SRST timeout as | ||
| 223 | link offline */ | ||
| 222 | 224 | ||
| 223 | /* ap->flags bits */ | 225 | /* ap->flags bits */ |
| 224 | 226 | ||
| @@ -1663,6 +1665,7 @@ static int ahci_do_softreset(struct ata_link *link, unsigned int *class, | |||
| 1663 | int (*check_ready)(struct ata_link *link)) | 1665 | int (*check_ready)(struct ata_link *link)) |
| 1664 | { | 1666 | { |
| 1665 | struct ata_port *ap = link->ap; | 1667 | struct ata_port *ap = link->ap; |
| 1668 | struct ahci_host_priv *hpriv = ap->host->private_data; | ||
| 1666 | const char *reason = NULL; | 1669 | const char *reason = NULL; |
| 1667 | unsigned long now, msecs; | 1670 | unsigned long now, msecs; |
| 1668 | struct ata_taskfile tf; | 1671 | struct ata_taskfile tf; |
| @@ -1701,12 +1704,21 @@ static int ahci_do_softreset(struct ata_link *link, unsigned int *class, | |||
| 1701 | 1704 | ||
| 1702 | /* wait for link to become ready */ | 1705 | /* wait for link to become ready */ |
| 1703 | rc = ata_wait_after_reset(link, deadline, check_ready); | 1706 | rc = ata_wait_after_reset(link, deadline, check_ready); |
| 1704 | /* link occupied, -ENODEV too is an error */ | 1707 | if (rc == -EBUSY && hpriv->flags & AHCI_HFLAG_SRST_TOUT_IS_OFFLINE) { |
| 1705 | if (rc) { | 1708 | /* |
| 1709 | * Workaround for cases where link online status can't | ||
| 1710 | * be trusted. Treat device readiness timeout as link | ||
| 1711 | * offline. | ||
| 1712 | */ | ||
| 1713 | ata_link_printk(link, KERN_INFO, | ||
| 1714 | "device not ready, treating as offline\n"); | ||
| 1715 | *class = ATA_DEV_NONE; | ||
| 1716 | } else if (rc) { | ||
| 1717 | /* link occupied, -ENODEV too is an error */ | ||
| 1706 | reason = "device not ready"; | 1718 | reason = "device not ready"; |
| 1707 | goto fail; | 1719 | goto fail; |
| 1708 | } | 1720 | } else |
| 1709 | *class = ahci_dev_classify(ap); | 1721 | *class = ahci_dev_classify(ap); |
| 1710 | 1722 | ||
| 1711 | DPRINTK("EXIT, class=%u\n", *class); | 1723 | DPRINTK("EXIT, class=%u\n", *class); |
| 1712 | return 0; | 1724 | return 0; |
| @@ -1773,7 +1785,8 @@ static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class, | |||
| 1773 | irq_sts = readl(port_mmio + PORT_IRQ_STAT); | 1785 | irq_sts = readl(port_mmio + PORT_IRQ_STAT); |
| 1774 | if (irq_sts & PORT_IRQ_BAD_PMP) { | 1786 | if (irq_sts & PORT_IRQ_BAD_PMP) { |
| 1775 | ata_link_printk(link, KERN_WARNING, | 1787 | ata_link_printk(link, KERN_WARNING, |
| 1776 | "failed due to HW bug, retry pmp=0\n"); | 1788 | "applying SB600 PMP SRST workaround " |
| 1789 | "and retrying\n"); | ||
| 1777 | rc = ahci_do_softreset(link, class, 0, deadline, | 1790 | rc = ahci_do_softreset(link, class, 0, deadline, |
| 1778 | ahci_check_ready); | 1791 | ahci_check_ready); |
| 1779 | } | 1792 | } |
| @@ -2726,6 +2739,56 @@ static bool ahci_broken_suspend(struct pci_dev *pdev) | |||
| 2726 | return !ver || strcmp(ver, dmi->driver_data) < 0; | 2739 | return !ver || strcmp(ver, dmi->driver_data) < 0; |
| 2727 | } | 2740 | } |
| 2728 | 2741 | ||
| 2742 | static bool ahci_broken_online(struct pci_dev *pdev) | ||
| 2743 | { | ||
| 2744 | #define ENCODE_BUSDEVFN(bus, slot, func) \ | ||
| 2745 | (void *)(unsigned long)(((bus) << 8) | PCI_DEVFN((slot), (func))) | ||
| 2746 | static const struct dmi_system_id sysids[] = { | ||
| 2747 | /* | ||
| 2748 | * There are several gigabyte boards which use | ||
| 2749 | * SIMG5723s configured as hardware RAID. Certain | ||
| 2750 | * 5723 firmware revisions shipped there keep the link | ||
| 2751 | * online but fail to answer properly to SRST or | ||
| 2752 | * IDENTIFY when no device is attached downstream | ||
| 2753 | * causing libata to retry quite a few times leading | ||
| 2754 | * to excessive detection delay. | ||
| 2755 | * | ||
| 2756 | * As these firmwares respond to the second reset try | ||
| 2757 | * with invalid device signature, considering unknown | ||
| 2758 | * sig as offline works around the problem acceptably. | ||
| 2759 | */ | ||
| 2760 | { | ||
| 2761 | .ident = "EP45-DQ6", | ||
| 2762 | .matches = { | ||
| 2763 | DMI_MATCH(DMI_BOARD_VENDOR, | ||
| 2764 | "Gigabyte Technology Co., Ltd."), | ||
| 2765 | DMI_MATCH(DMI_BOARD_NAME, "EP45-DQ6"), | ||
| 2766 | }, | ||
| 2767 | .driver_data = ENCODE_BUSDEVFN(0x0a, 0x00, 0), | ||
| 2768 | }, | ||
| 2769 | { | ||
| 2770 | .ident = "EP45-DS5", | ||
| 2771 | .matches = { | ||
| 2772 | DMI_MATCH(DMI_BOARD_VENDOR, | ||
| 2773 | "Gigabyte Technology Co., Ltd."), | ||
| 2774 | DMI_MATCH(DMI_BOARD_NAME, "EP45-DS5"), | ||
| 2775 | }, | ||
| 2776 | .driver_data = ENCODE_BUSDEVFN(0x03, 0x00, 0), | ||
| 2777 | }, | ||
| 2778 | { } /* terminate list */ | ||
| 2779 | }; | ||
| 2780 | #undef ENCODE_BUSDEVFN | ||
| 2781 | const struct dmi_system_id *dmi = dmi_first_match(sysids); | ||
| 2782 | unsigned int val; | ||
| 2783 | |||
| 2784 | if (!dmi) | ||
| 2785 | return false; | ||
| 2786 | |||
| 2787 | val = (unsigned long)dmi->driver_data; | ||
| 2788 | |||
| 2789 | return pdev->bus->number == (val >> 8) && pdev->devfn == (val & 0xff); | ||
| 2790 | } | ||
| 2791 | |||
| 2729 | static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | 2792 | static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) |
| 2730 | { | 2793 | { |
| 2731 | static int printed_version; | 2794 | static int printed_version; |
| @@ -2841,6 +2904,12 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
| 2841 | "BIOS update required for suspend/resume\n"); | 2904 | "BIOS update required for suspend/resume\n"); |
| 2842 | } | 2905 | } |
| 2843 | 2906 | ||
| 2907 | if (ahci_broken_online(pdev)) { | ||
| 2908 | hpriv->flags |= AHCI_HFLAG_SRST_TOUT_IS_OFFLINE; | ||
| 2909 | dev_info(&pdev->dev, | ||
| 2910 | "online status unreliable, applying workaround\n"); | ||
| 2911 | } | ||
| 2912 | |||
| 2844 | /* CAP.NP sometimes indicate the index of the last enabled | 2913 | /* CAP.NP sometimes indicate the index of the last enabled |
| 2845 | * port, at other times, that of the last possible port, so | 2914 | * port, at other times, that of the last possible port, so |
| 2846 | * determining the maximum port number requires looking at | 2915 | * determining the maximum port number requires looking at |
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 8ac98ff16d7d..072ba5ea138f 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 [] = { | |||
| 4302 | { "WDC WD2500JD-00HBB0", "WD-WMAL71490727", ATA_HORKAGE_BROKEN_HPA }, | 4302 | { "WDC WD2500JD-00HBB0", "WD-WMAL71490727", ATA_HORKAGE_BROKEN_HPA }, |
| 4303 | { "MAXTOR 6L080L4", "A93.0500", ATA_HORKAGE_BROKEN_HPA }, | 4303 | { "MAXTOR 6L080L4", "A93.0500", ATA_HORKAGE_BROKEN_HPA }, |
| 4304 | 4304 | ||
| 4305 | /* this one allows HPA unlocking but fails IOs on the area */ | ||
| 4306 | { "OCZ-VERTEX", "1.30", ATA_HORKAGE_BROKEN_HPA }, | ||
| 4307 | |||
| 4305 | /* Devices which report 1 sector over size HPA */ | 4308 | /* Devices which report 1 sector over size HPA */ |
| 4306 | { "ST340823A", NULL, ATA_HORKAGE_HPA_SIZE, }, | 4309 | { "ST340823A", NULL, ATA_HORKAGE_HPA_SIZE, }, |
| 4307 | { "ST320413A", NULL, ATA_HORKAGE_HPA_SIZE, }, | 4310 | { "ST320413A", NULL, ATA_HORKAGE_HPA_SIZE, }, |
diff --git a/drivers/ata/pata_at91.c b/drivers/ata/pata_at91.c index 5702affcb325..41c94b1ae493 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) | |||
| 250 | ata_port_desc(ap, "no IRQ, using PIO polling"); | 250 | ata_port_desc(ap, "no IRQ, using PIO polling"); |
| 251 | } | 251 | } |
| 252 | 252 | ||
| 253 | info = kzalloc(sizeof(*info), GFP_KERNEL); | 253 | info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); |
| 254 | 254 | ||
| 255 | if (!info) { | 255 | if (!info) { |
| 256 | dev_err(dev, "failed to allocate memory for private data\n"); | 256 | 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) | |||
| 275 | if (!info->ide_addr) { | 275 | if (!info->ide_addr) { |
| 276 | dev_err(dev, "failed to map IO base\n"); | 276 | dev_err(dev, "failed to map IO base\n"); |
| 277 | ret = -ENOMEM; | 277 | ret = -ENOMEM; |
| 278 | goto err_ide_ioremap; | 278 | goto err_put; |
| 279 | } | 279 | } |
| 280 | 280 | ||
| 281 | info->alt_addr = devm_ioremap(dev, | 281 | info->alt_addr = devm_ioremap(dev, |
| @@ -284,7 +284,7 @@ static int __devinit pata_at91_probe(struct platform_device *pdev) | |||
| 284 | if (!info->alt_addr) { | 284 | if (!info->alt_addr) { |
| 285 | dev_err(dev, "failed to map CTL base\n"); | 285 | dev_err(dev, "failed to map CTL base\n"); |
| 286 | ret = -ENOMEM; | 286 | ret = -ENOMEM; |
| 287 | goto err_alt_ioremap; | 287 | goto err_put; |
| 288 | } | 288 | } |
| 289 | 289 | ||
| 290 | ap->ioaddr.cmd_addr = info->ide_addr; | 290 | ap->ioaddr.cmd_addr = info->ide_addr; |
| @@ -303,13 +303,8 @@ static int __devinit pata_at91_probe(struct platform_device *pdev) | |||
| 303 | irq ? ata_sff_interrupt : NULL, | 303 | irq ? ata_sff_interrupt : NULL, |
| 304 | irq_flags, &pata_at91_sht); | 304 | irq_flags, &pata_at91_sht); |
| 305 | 305 | ||
| 306 | err_alt_ioremap: | 306 | err_put: |
| 307 | devm_iounmap(dev, info->ide_addr); | ||
| 308 | |||
| 309 | err_ide_ioremap: | ||
| 310 | clk_put(info->mck); | 307 | clk_put(info->mck); |
| 311 | kfree(info); | ||
| 312 | |||
| 313 | return ret; | 308 | return ret; |
| 314 | } | 309 | } |
| 315 | 310 | ||
| @@ -317,7 +312,6 @@ static int __devexit pata_at91_remove(struct platform_device *pdev) | |||
| 317 | { | 312 | { |
| 318 | struct ata_host *host = dev_get_drvdata(&pdev->dev); | 313 | struct ata_host *host = dev_get_drvdata(&pdev->dev); |
| 319 | struct at91_ide_info *info; | 314 | struct at91_ide_info *info; |
| 320 | struct device *dev = &pdev->dev; | ||
| 321 | 315 | ||
| 322 | if (!host) | 316 | if (!host) |
| 323 | return 0; | 317 | return 0; |
| @@ -328,11 +322,8 @@ static int __devexit pata_at91_remove(struct platform_device *pdev) | |||
| 328 | if (!info) | 322 | if (!info) |
| 329 | return 0; | 323 | return 0; |
| 330 | 324 | ||
| 331 | devm_iounmap(dev, info->ide_addr); | ||
| 332 | devm_iounmap(dev, info->alt_addr); | ||
| 333 | clk_put(info->mck); | 325 | clk_put(info->mck); |
| 334 | 326 | ||
| 335 | kfree(info); | ||
| 336 | return 0; | 327 | return 0; |
| 337 | } | 328 | } |
| 338 | 329 | ||
diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index bec0b8ade66d..45915566e4e9 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * pata_atiixp.c - ATI PATA for new ATA layer | 2 | * pata_atiixp.c - ATI PATA for new ATA layer |
| 3 | * (C) 2005 Red Hat Inc | 3 | * (C) 2005 Red Hat Inc |
| 4 | * (C) 2009 Bartlomiej Zolnierkiewicz | ||
| 4 | * | 5 | * |
| 5 | * Based on | 6 | * Based on |
| 6 | * | 7 | * |
| @@ -61,20 +62,19 @@ static void atiixp_set_pio_timing(struct ata_port *ap, struct ata_device *adev, | |||
| 61 | 62 | ||
| 62 | struct pci_dev *pdev = to_pci_dev(ap->host->dev); | 63 | struct pci_dev *pdev = to_pci_dev(ap->host->dev); |
| 63 | int dn = 2 * ap->port_no + adev->devno; | 64 | int dn = 2 * ap->port_no + adev->devno; |
| 64 | |||
| 65 | /* Check this is correct - the order is odd in both drivers */ | ||
| 66 | int timing_shift = (16 * ap->port_no) + 8 * (adev->devno ^ 1); | 65 | int timing_shift = (16 * ap->port_no) + 8 * (adev->devno ^ 1); |
| 67 | u16 pio_mode_data, pio_timing_data; | 66 | u32 pio_timing_data; |
| 67 | u16 pio_mode_data; | ||
| 68 | 68 | ||
| 69 | pci_read_config_word(pdev, ATIIXP_IDE_PIO_MODE, &pio_mode_data); | 69 | pci_read_config_word(pdev, ATIIXP_IDE_PIO_MODE, &pio_mode_data); |
| 70 | pio_mode_data &= ~(0x7 << (4 * dn)); | 70 | pio_mode_data &= ~(0x7 << (4 * dn)); |
| 71 | pio_mode_data |= pio << (4 * dn); | 71 | pio_mode_data |= pio << (4 * dn); |
| 72 | pci_write_config_word(pdev, ATIIXP_IDE_PIO_MODE, pio_mode_data); | 72 | pci_write_config_word(pdev, ATIIXP_IDE_PIO_MODE, pio_mode_data); |
| 73 | 73 | ||
| 74 | pci_read_config_word(pdev, ATIIXP_IDE_PIO_TIMING, &pio_timing_data); | 74 | pci_read_config_dword(pdev, ATIIXP_IDE_PIO_TIMING, &pio_timing_data); |
| 75 | pio_timing_data &= ~(0xFF << timing_shift); | 75 | pio_timing_data &= ~(0xFF << timing_shift); |
| 76 | pio_timing_data |= (pio_timings[pio] << timing_shift); | 76 | pio_timing_data |= (pio_timings[pio] << timing_shift); |
| 77 | pci_write_config_word(pdev, ATIIXP_IDE_PIO_TIMING, pio_timing_data); | 77 | pci_write_config_dword(pdev, ATIIXP_IDE_PIO_TIMING, pio_timing_data); |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | /** | 80 | /** |
| @@ -119,16 +119,17 @@ static void atiixp_set_dmamode(struct ata_port *ap, struct ata_device *adev) | |||
| 119 | udma_mode_data |= dma << (4 * dn); | 119 | udma_mode_data |= dma << (4 * dn); |
| 120 | pci_write_config_word(pdev, ATIIXP_IDE_UDMA_MODE, udma_mode_data); | 120 | pci_write_config_word(pdev, ATIIXP_IDE_UDMA_MODE, udma_mode_data); |
| 121 | } else { | 121 | } else { |
| 122 | u16 mwdma_timing_data; | ||
| 123 | /* Check this is correct - the order is odd in both drivers */ | ||
| 124 | int timing_shift = (16 * ap->port_no) + 8 * (adev->devno ^ 1); | 122 | int timing_shift = (16 * ap->port_no) + 8 * (adev->devno ^ 1); |
| 123 | u32 mwdma_timing_data; | ||
| 125 | 124 | ||
| 126 | dma -= XFER_MW_DMA_0; | 125 | dma -= XFER_MW_DMA_0; |
| 127 | 126 | ||
| 128 | pci_read_config_word(pdev, ATIIXP_IDE_MWDMA_TIMING, &mwdma_timing_data); | 127 | pci_read_config_dword(pdev, ATIIXP_IDE_MWDMA_TIMING, |
| 128 | &mwdma_timing_data); | ||
| 129 | mwdma_timing_data &= ~(0xFF << timing_shift); | 129 | mwdma_timing_data &= ~(0xFF << timing_shift); |
| 130 | mwdma_timing_data |= (mwdma_timings[dma] << timing_shift); | 130 | mwdma_timing_data |= (mwdma_timings[dma] << timing_shift); |
| 131 | pci_write_config_word(pdev, ATIIXP_IDE_MWDMA_TIMING, mwdma_timing_data); | 131 | pci_write_config_dword(pdev, ATIIXP_IDE_MWDMA_TIMING, |
| 132 | mwdma_timing_data); | ||
| 132 | } | 133 | } |
| 133 | /* | 134 | /* |
| 134 | * We must now look at the PIO mode situation. We may need to | 135 | * 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 b2d11f300c39..86a40582999c 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c | |||
| @@ -602,6 +602,7 @@ MODULE_VERSION(DRV_VERSION); | |||
| 602 | 602 | ||
| 603 | static int adma_enabled; | 603 | static int adma_enabled; |
| 604 | static int swncq_enabled = 1; | 604 | static int swncq_enabled = 1; |
| 605 | static int msi_enabled; | ||
| 605 | 606 | ||
| 606 | static void nv_adma_register_mode(struct ata_port *ap) | 607 | static void nv_adma_register_mode(struct ata_port *ap) |
| 607 | { | 608 | { |
| @@ -2459,6 +2460,11 @@ static int nv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
| 2459 | } else if (type == SWNCQ) | 2460 | } else if (type == SWNCQ) |
| 2460 | nv_swncq_host_init(host); | 2461 | nv_swncq_host_init(host); |
| 2461 | 2462 | ||
| 2463 | if (msi_enabled) { | ||
| 2464 | dev_printk(KERN_NOTICE, &pdev->dev, "Using MSI\n"); | ||
| 2465 | pci_enable_msi(pdev); | ||
| 2466 | } | ||
| 2467 | |||
| 2462 | pci_set_master(pdev); | 2468 | pci_set_master(pdev); |
| 2463 | return ata_host_activate(host, pdev->irq, ipriv->irq_handler, | 2469 | return ata_host_activate(host, pdev->irq, ipriv->irq_handler, |
| 2464 | IRQF_SHARED, ipriv->sht); | 2470 | IRQF_SHARED, ipriv->sht); |
| @@ -2558,4 +2564,6 @@ module_param_named(adma, adma_enabled, bool, 0444); | |||
| 2558 | MODULE_PARM_DESC(adma, "Enable use of ADMA (Default: false)"); | 2564 | MODULE_PARM_DESC(adma, "Enable use of ADMA (Default: false)"); |
| 2559 | module_param_named(swncq, swncq_enabled, bool, 0444); | 2565 | module_param_named(swncq, swncq_enabled, bool, 0444); |
| 2560 | MODULE_PARM_DESC(swncq, "Enable use of SWNCQ (Default: true)"); | 2566 | MODULE_PARM_DESC(swncq, "Enable use of SWNCQ (Default: true)"); |
| 2567 | module_param_named(msi, msi_enabled, bool, 0444); | ||
| 2568 | MODULE_PARM_DESC(msi, "Enable use of MSI (Default: false)"); | ||
| 2561 | 2569 | ||
diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 81cb01bfc356..456594bd97bc 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c | |||
| @@ -483,9 +483,6 @@ int platform_driver_register(struct platform_driver *drv) | |||
| 483 | drv->driver.remove = platform_drv_remove; | 483 | drv->driver.remove = platform_drv_remove; |
| 484 | if (drv->shutdown) | 484 | if (drv->shutdown) |
| 485 | drv->driver.shutdown = platform_drv_shutdown; | 485 | drv->driver.shutdown = platform_drv_shutdown; |
| 486 | if (drv->suspend || drv->resume) | ||
| 487 | pr_warning("Platform driver '%s' needs updating - please use " | ||
| 488 | "dev_pm_ops\n", drv->driver.name); | ||
| 489 | 486 | ||
| 490 | return driver_register(&drv->driver); | 487 | return driver_register(&drv->driver); |
| 491 | } | 488 | } |
diff --git a/drivers/char/pty.c b/drivers/char/pty.c index 6e6942c45f5b..d083c73d784a 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c | |||
| @@ -144,6 +144,8 @@ static int pty_write(struct tty_struct *tty, const unsigned char *buf, | |||
| 144 | 144 | ||
| 145 | static int pty_write_room(struct tty_struct *tty) | 145 | static int pty_write_room(struct tty_struct *tty) |
| 146 | { | 146 | { |
| 147 | if (tty->stopped) | ||
| 148 | return 0; | ||
| 147 | return pty_space(tty->link); | 149 | return pty_space(tty->link); |
| 148 | } | 150 | } |
| 149 | 151 | ||
diff --git a/drivers/mtd/maps/sbc8240.c b/drivers/mtd/maps/sbc8240.c deleted file mode 100644 index e69de29bb2d1..000000000000 --- a/drivers/mtd/maps/sbc8240.c +++ /dev/null | |||
diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index a4494d78e7c2..8aebe1e9d3d6 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c | |||
| @@ -90,11 +90,10 @@ static struct hotplug_slot_ops sn_hotplug_slot_ops = { | |||
| 90 | 90 | ||
| 91 | static DEFINE_MUTEX(sn_hotplug_mutex); | 91 | static DEFINE_MUTEX(sn_hotplug_mutex); |
| 92 | 92 | ||
| 93 | static ssize_t path_show (struct hotplug_slot *bss_hotplug_slot, | 93 | static ssize_t path_show(struct pci_slot *pci_slot, char *buf) |
| 94 | char *buf) | ||
| 95 | { | 94 | { |
| 96 | int retval = -ENOENT; | 95 | int retval = -ENOENT; |
| 97 | struct slot *slot = bss_hotplug_slot->private; | 96 | struct slot *slot = pci_slot->hotplug->private; |
| 98 | 97 | ||
| 99 | if (!slot) | 98 | if (!slot) |
| 100 | return retval; | 99 | return retval; |
| @@ -103,7 +102,7 @@ static ssize_t path_show (struct hotplug_slot *bss_hotplug_slot, | |||
| 103 | return retval; | 102 | return retval; |
| 104 | } | 103 | } |
| 105 | 104 | ||
| 106 | static struct hotplug_slot_attribute sn_slot_path_attr = __ATTR_RO(path); | 105 | static struct pci_slot_attribute sn_slot_path_attr = __ATTR_RO(path); |
| 107 | 106 | ||
| 108 | static int sn_pci_slot_valid(struct pci_bus *pci_bus, int device) | 107 | static int sn_pci_slot_valid(struct pci_bus *pci_bus, int device) |
| 109 | { | 108 | { |
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 037c1e0b7c4c..6553833c12db 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig | |||
| @@ -527,7 +527,7 @@ config SERIAL_S3C24A0 | |||
| 527 | 527 | ||
| 528 | config SERIAL_S3C6400 | 528 | config SERIAL_S3C6400 |
| 529 | tristate "Samsung S3C6400/S3C6410 Serial port support" | 529 | tristate "Samsung S3C6400/S3C6410 Serial port support" |
| 530 | depends on SERIAL_SAMSUNG && (CPU_S3C600 || CPU_S3C6410) | 530 | depends on SERIAL_SAMSUNG && (CPU_S3C6400 || CPU_S3C6410) |
| 531 | default y | 531 | default y |
| 532 | help | 532 | help |
| 533 | Serial port support for the Samsung S3C6400 and S3C6410 | 533 | Serial port support for the Samsung S3C6400 and S3C6410 |
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 489fc01a3204..e4e089a8f294 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
| @@ -255,7 +255,7 @@ static void nfs_direct_read_release(void *calldata) | |||
| 255 | 255 | ||
| 256 | if (put_dreq(dreq)) | 256 | if (put_dreq(dreq)) |
| 257 | nfs_direct_complete(dreq); | 257 | nfs_direct_complete(dreq); |
| 258 | nfs_readdata_release(calldata); | 258 | nfs_readdata_free(data); |
| 259 | } | 259 | } |
| 260 | 260 | ||
| 261 | static const struct rpc_call_ops nfs_read_direct_ops = { | 261 | 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, | |||
| 314 | data->npages, 1, 0, data->pagevec, NULL); | 314 | data->npages, 1, 0, data->pagevec, NULL); |
| 315 | up_read(¤t->mm->mmap_sem); | 315 | up_read(¤t->mm->mmap_sem); |
| 316 | if (result < 0) { | 316 | if (result < 0) { |
| 317 | nfs_readdata_release(data); | 317 | nfs_readdata_free(data); |
| 318 | break; | 318 | break; |
| 319 | } | 319 | } |
| 320 | if ((unsigned)result < data->npages) { | 320 | if ((unsigned)result < data->npages) { |
| 321 | bytes = result * PAGE_SIZE; | 321 | bytes = result * PAGE_SIZE; |
| 322 | if (bytes <= pgbase) { | 322 | if (bytes <= pgbase) { |
| 323 | nfs_direct_release_pages(data->pagevec, result); | 323 | nfs_direct_release_pages(data->pagevec, result); |
| 324 | nfs_readdata_release(data); | 324 | nfs_readdata_free(data); |
| 325 | break; | 325 | break; |
| 326 | } | 326 | } |
| 327 | bytes -= pgbase; | 327 | bytes -= pgbase; |
| @@ -334,7 +334,7 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq, | |||
| 334 | data->inode = inode; | 334 | data->inode = inode; |
| 335 | data->cred = msg.rpc_cred; | 335 | data->cred = msg.rpc_cred; |
| 336 | data->args.fh = NFS_FH(inode); | 336 | data->args.fh = NFS_FH(inode); |
| 337 | data->args.context = get_nfs_open_context(ctx); | 337 | data->args.context = ctx; |
| 338 | data->args.offset = pos; | 338 | data->args.offset = pos; |
| 339 | data->args.pgbase = pgbase; | 339 | data->args.pgbase = pgbase; |
| 340 | data->args.pages = data->pagevec; | 340 | data->args.pages = data->pagevec; |
| @@ -441,7 +441,7 @@ static void nfs_direct_free_writedata(struct nfs_direct_req *dreq) | |||
| 441 | struct nfs_write_data *data = list_entry(dreq->rewrite_list.next, struct nfs_write_data, pages); | 441 | struct nfs_write_data *data = list_entry(dreq->rewrite_list.next, struct nfs_write_data, pages); |
| 442 | list_del(&data->pages); | 442 | list_del(&data->pages); |
| 443 | nfs_direct_release_pages(data->pagevec, data->npages); | 443 | nfs_direct_release_pages(data->pagevec, data->npages); |
| 444 | nfs_writedata_release(data); | 444 | nfs_writedata_free(data); |
| 445 | } | 445 | } |
| 446 | } | 446 | } |
| 447 | 447 | ||
| @@ -534,7 +534,7 @@ static void nfs_direct_commit_release(void *calldata) | |||
| 534 | 534 | ||
| 535 | dprintk("NFS: %5u commit returned %d\n", data->task.tk_pid, status); | 535 | dprintk("NFS: %5u commit returned %d\n", data->task.tk_pid, status); |
| 536 | nfs_direct_write_complete(dreq, data->inode); | 536 | nfs_direct_write_complete(dreq, data->inode); |
| 537 | nfs_commitdata_release(calldata); | 537 | nfs_commit_free(data); |
| 538 | } | 538 | } |
| 539 | 539 | ||
| 540 | static const struct rpc_call_ops nfs_commit_direct_ops = { | 540 | 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) | |||
| 570 | data->args.fh = NFS_FH(data->inode); | 570 | data->args.fh = NFS_FH(data->inode); |
| 571 | data->args.offset = 0; | 571 | data->args.offset = 0; |
| 572 | data->args.count = 0; | 572 | data->args.count = 0; |
| 573 | data->args.context = get_nfs_open_context(dreq->ctx); | 573 | data->args.context = dreq->ctx; |
| 574 | data->res.count = 0; | 574 | data->res.count = 0; |
| 575 | data->res.fattr = &data->fattr; | 575 | data->res.fattr = &data->fattr; |
| 576 | data->res.verf = &data->verf; | 576 | data->res.verf = &data->verf; |
| @@ -734,14 +734,14 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq, | |||
| 734 | data->npages, 0, 0, data->pagevec, NULL); | 734 | data->npages, 0, 0, data->pagevec, NULL); |
| 735 | up_read(¤t->mm->mmap_sem); | 735 | up_read(¤t->mm->mmap_sem); |
| 736 | if (result < 0) { | 736 | if (result < 0) { |
| 737 | nfs_writedata_release(data); | 737 | nfs_writedata_free(data); |
| 738 | break; | 738 | break; |
| 739 | } | 739 | } |
| 740 | if ((unsigned)result < data->npages) { | 740 | if ((unsigned)result < data->npages) { |
| 741 | bytes = result * PAGE_SIZE; | 741 | bytes = result * PAGE_SIZE; |
| 742 | if (bytes <= pgbase) { | 742 | if (bytes <= pgbase) { |
| 743 | nfs_direct_release_pages(data->pagevec, result); | 743 | nfs_direct_release_pages(data->pagevec, result); |
| 744 | nfs_writedata_release(data); | 744 | nfs_writedata_free(data); |
| 745 | break; | 745 | break; |
| 746 | } | 746 | } |
| 747 | bytes -= pgbase; | 747 | bytes -= pgbase; |
| @@ -756,7 +756,7 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq, | |||
| 756 | data->inode = inode; | 756 | data->inode = inode; |
| 757 | data->cred = msg.rpc_cred; | 757 | data->cred = msg.rpc_cred; |
| 758 | data->args.fh = NFS_FH(inode); | 758 | data->args.fh = NFS_FH(inode); |
| 759 | data->args.context = get_nfs_open_context(ctx); | 759 | data->args.context = ctx; |
| 760 | data->args.offset = pos; | 760 | data->args.offset = pos; |
| 761 | data->args.pgbase = pgbase; | 761 | data->args.pgbase = pgbase; |
| 762 | data->args.pages = data->pagevec; | 762 | data->args.pages = data->pagevec; |
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 73ea5e8d66ce..12c9e66d3f1d 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) | |||
| 60 | return p; | 60 | return p; |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | static void nfs_readdata_free(struct nfs_read_data *p) | 63 | void nfs_readdata_free(struct nfs_read_data *p) |
| 64 | { | 64 | { |
| 65 | if (p && (p->pagevec != &p->page_array[0])) | 65 | if (p && (p->pagevec != &p->page_array[0])) |
| 66 | kfree(p->pagevec); | 66 | kfree(p->pagevec); |
| 67 | mempool_free(p, nfs_rdata_mempool); | 67 | mempool_free(p, nfs_rdata_mempool); |
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | void nfs_readdata_release(void *data) | 70 | static void nfs_readdata_release(struct nfs_read_data *rdata) |
| 71 | { | 71 | { |
| 72 | struct nfs_read_data *rdata = data; | ||
| 73 | |||
| 74 | put_nfs_open_context(rdata->args.context); | 72 | put_nfs_open_context(rdata->args.context); |
| 75 | nfs_readdata_free(rdata); | 73 | nfs_readdata_free(rdata); |
| 76 | } | 74 | } |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 0a0a2ff767c3..a34fae21fe10 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) | |||
| 87 | return p; | 87 | return p; |
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | static void nfs_writedata_free(struct nfs_write_data *p) | 90 | void nfs_writedata_free(struct nfs_write_data *p) |
| 91 | { | 91 | { |
| 92 | if (p && (p->pagevec != &p->page_array[0])) | 92 | if (p && (p->pagevec != &p->page_array[0])) |
| 93 | kfree(p->pagevec); | 93 | kfree(p->pagevec); |
| 94 | mempool_free(p, nfs_wdata_mempool); | 94 | mempool_free(p, nfs_wdata_mempool); |
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | void nfs_writedata_release(void *data) | 97 | static void nfs_writedata_release(struct nfs_write_data *wdata) |
| 98 | { | 98 | { |
| 99 | struct nfs_write_data *wdata = data; | ||
| 100 | |||
| 101 | put_nfs_open_context(wdata->args.context); | 99 | put_nfs_open_context(wdata->args.context); |
| 102 | nfs_writedata_free(wdata); | 100 | nfs_writedata_free(wdata); |
| 103 | } | 101 | } |
diff --git a/fs/proc/base.c b/fs/proc/base.c index 3ce5ae9e3d2d..175db258942f 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
| @@ -234,23 +234,20 @@ static int check_mem_permission(struct task_struct *task) | |||
| 234 | 234 | ||
| 235 | struct mm_struct *mm_for_maps(struct task_struct *task) | 235 | struct mm_struct *mm_for_maps(struct task_struct *task) |
| 236 | { | 236 | { |
| 237 | struct mm_struct *mm = get_task_mm(task); | 237 | struct mm_struct *mm; |
| 238 | if (!mm) | 238 | |
| 239 | if (mutex_lock_killable(&task->cred_guard_mutex)) | ||
| 239 | return NULL; | 240 | return NULL; |
| 240 | down_read(&mm->mmap_sem); | 241 | |
| 241 | task_lock(task); | 242 | mm = get_task_mm(task); |
| 242 | if (task->mm != mm) | 243 | if (mm && mm != current->mm && |
| 243 | goto out; | 244 | !ptrace_may_access(task, PTRACE_MODE_READ)) { |
| 244 | if (task->mm != current->mm && | 245 | mmput(mm); |
| 245 | __ptrace_may_access(task, PTRACE_MODE_READ) < 0) | 246 | mm = NULL; |
| 246 | goto out; | 247 | } |
| 247 | task_unlock(task); | 248 | mutex_unlock(&task->cred_guard_mutex); |
| 249 | |||
| 248 | return mm; | 250 | return mm; |
| 249 | out: | ||
| 250 | task_unlock(task); | ||
| 251 | up_read(&mm->mmap_sem); | ||
| 252 | mmput(mm); | ||
| 253 | return NULL; | ||
| 254 | } | 251 | } |
| 255 | 252 | ||
| 256 | static int proc_pid_cmdline(struct task_struct *task, char * buffer) | 253 | static int proc_pid_cmdline(struct task_struct *task, char * buffer) |
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 6f61b7cc32e0..9bd8be1d235c 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c | |||
| @@ -119,6 +119,7 @@ static void *m_start(struct seq_file *m, loff_t *pos) | |||
| 119 | mm = mm_for_maps(priv->task); | 119 | mm = mm_for_maps(priv->task); |
| 120 | if (!mm) | 120 | if (!mm) |
| 121 | return NULL; | 121 | return NULL; |
| 122 | down_read(&mm->mmap_sem); | ||
| 122 | 123 | ||
| 123 | tail_vma = get_gate_vma(priv->task); | 124 | tail_vma = get_gate_vma(priv->task); |
| 124 | priv->tail_vma = tail_vma; | 125 | priv->tail_vma = tail_vma; |
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c index 64a72e2e7650..8f5c05d3dbd3 100644 --- a/fs/proc/task_nommu.c +++ b/fs/proc/task_nommu.c | |||
| @@ -189,6 +189,7 @@ static void *m_start(struct seq_file *m, loff_t *pos) | |||
| 189 | priv->task = NULL; | 189 | priv->task = NULL; |
| 190 | return NULL; | 190 | return NULL; |
| 191 | } | 191 | } |
| 192 | down_read(&mm->mmap_sem); | ||
| 192 | 193 | ||
| 193 | /* start from the Nth VMA */ | 194 | /* start from the Nth VMA */ |
| 194 | for (p = rb_first(&mm->mm_rb); p; p = rb_next(p)) | 195 | for (p = rb_first(&mm->mm_rb); p; p = rb_next(p)) |
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index 0c93c7ef3d18..965df1227d64 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( | |||
| 770 | bp->b_pages = NULL; | 770 | bp->b_pages = NULL; |
| 771 | bp->b_addr = mem; | 771 | bp->b_addr = mem; |
| 772 | 772 | ||
| 773 | rval = _xfs_buf_get_pages(bp, page_count, 0); | 773 | rval = _xfs_buf_get_pages(bp, page_count, XBF_DONT_BLOCK); |
| 774 | if (rval) | 774 | if (rval) |
| 775 | return rval; | 775 | return rval; |
| 776 | 776 | ||
diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c index db15feb906ff..4ece1906bd41 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) | |||
| 2010 | dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock); | 2010 | dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock); |
| 2011 | blkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount); | 2011 | blkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount); |
| 2012 | error = xfs_read_buf(mp, mp->m_ddev_targp, dblkno, | 2012 | error = xfs_read_buf(mp, mp->m_ddev_targp, dblkno, |
| 2013 | blkcnt, XFS_BUF_LOCK, &bp); | 2013 | blkcnt, |
| 2014 | XFS_BUF_LOCK | XBF_DONT_BLOCK, | ||
| 2015 | &bp); | ||
| 2014 | if (error) | 2016 | if (error) |
| 2015 | return(error); | 2017 | return(error); |
| 2016 | 2018 | ||
| @@ -2141,8 +2143,8 @@ xfs_attr_rmtval_set(xfs_da_args_t *args) | |||
| 2141 | dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock), | 2143 | dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock), |
| 2142 | blkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); | 2144 | blkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); |
| 2143 | 2145 | ||
| 2144 | bp = xfs_buf_get_flags(mp->m_ddev_targp, dblkno, | 2146 | bp = xfs_buf_get_flags(mp->m_ddev_targp, dblkno, blkcnt, |
| 2145 | blkcnt, XFS_BUF_LOCK); | 2147 | XFS_BUF_LOCK | XBF_DONT_BLOCK); |
| 2146 | ASSERT(bp); | 2148 | ASSERT(bp); |
| 2147 | ASSERT(!XFS_BUF_GETERROR(bp)); | 2149 | ASSERT(!XFS_BUF_GETERROR(bp)); |
| 2148 | 2150 | ||
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index 7928b9983c1d..8ee5b5a76a2a 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c | |||
| @@ -6009,7 +6009,7 @@ xfs_getbmap( | |||
| 6009 | */ | 6009 | */ |
| 6010 | error = ENOMEM; | 6010 | error = ENOMEM; |
| 6011 | subnex = 16; | 6011 | subnex = 16; |
| 6012 | map = kmem_alloc(subnex * sizeof(*map), KM_MAYFAIL); | 6012 | map = kmem_alloc(subnex * sizeof(*map), KM_MAYFAIL | KM_NOFS); |
| 6013 | if (!map) | 6013 | if (!map) |
| 6014 | goto out_unlock_ilock; | 6014 | goto out_unlock_ilock; |
| 6015 | 6015 | ||
diff --git a/fs/xfs/xfs_btree.c b/fs/xfs/xfs_btree.c index e9df99574829..26717388acf5 100644 --- a/fs/xfs/xfs_btree.c +++ b/fs/xfs/xfs_btree.c | |||
| @@ -120,8 +120,8 @@ xfs_btree_check_sblock( | |||
| 120 | XFS_RANDOM_BTREE_CHECK_SBLOCK))) { | 120 | XFS_RANDOM_BTREE_CHECK_SBLOCK))) { |
| 121 | if (bp) | 121 | if (bp) |
| 122 | xfs_buftrace("SBTREE ERROR", bp); | 122 | xfs_buftrace("SBTREE ERROR", bp); |
| 123 | XFS_ERROR_REPORT("xfs_btree_check_sblock", XFS_ERRLEVEL_LOW, | 123 | XFS_CORRUPTION_ERROR("xfs_btree_check_sblock", |
| 124 | cur->bc_mp); | 124 | XFS_ERRLEVEL_LOW, cur->bc_mp, block); |
| 125 | return XFS_ERROR(EFSCORRUPTED); | 125 | return XFS_ERROR(EFSCORRUPTED); |
| 126 | } | 126 | } |
| 127 | return 0; | 127 | return 0; |
diff --git a/fs/xfs/xfs_da_btree.c b/fs/xfs/xfs_da_btree.c index 9ff6e57a5075..2847bbc1c534 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 */ | |||
| 2201 | xfs_da_state_t * | 2201 | xfs_da_state_t * |
| 2202 | xfs_da_state_alloc(void) | 2202 | xfs_da_state_alloc(void) |
| 2203 | { | 2203 | { |
| 2204 | return kmem_zone_zalloc(xfs_da_state_zone, KM_SLEEP); | 2204 | return kmem_zone_zalloc(xfs_da_state_zone, KM_NOFS); |
| 2205 | } | 2205 | } |
| 2206 | 2206 | ||
| 2207 | /* | 2207 | /* |
| @@ -2261,9 +2261,9 @@ xfs_da_buf_make(int nbuf, xfs_buf_t **bps, inst_t *ra) | |||
| 2261 | int off; | 2261 | int off; |
| 2262 | 2262 | ||
| 2263 | if (nbuf == 1) | 2263 | if (nbuf == 1) |
| 2264 | dabuf = kmem_zone_alloc(xfs_dabuf_zone, KM_SLEEP); | 2264 | dabuf = kmem_zone_alloc(xfs_dabuf_zone, KM_NOFS); |
| 2265 | else | 2265 | else |
| 2266 | dabuf = kmem_alloc(XFS_DA_BUF_SIZE(nbuf), KM_SLEEP); | 2266 | dabuf = kmem_alloc(XFS_DA_BUF_SIZE(nbuf), KM_NOFS); |
| 2267 | dabuf->dirty = 0; | 2267 | dabuf->dirty = 0; |
| 2268 | #ifdef XFS_DABUF_DEBUG | 2268 | #ifdef XFS_DABUF_DEBUG |
| 2269 | dabuf->ra = ra; | 2269 | dabuf->ra = ra; |
diff --git a/fs/xfs/xfs_dir2.c b/fs/xfs/xfs_dir2.c index c657bec6d951..bb1d58eb3982 100644 --- a/fs/xfs/xfs_dir2.c +++ b/fs/xfs/xfs_dir2.c | |||
| @@ -256,7 +256,7 @@ xfs_dir_cilookup_result( | |||
| 256 | !(args->op_flags & XFS_DA_OP_CILOOKUP)) | 256 | !(args->op_flags & XFS_DA_OP_CILOOKUP)) |
| 257 | return EEXIST; | 257 | return EEXIST; |
| 258 | 258 | ||
| 259 | args->value = kmem_alloc(len, KM_MAYFAIL); | 259 | args->value = kmem_alloc(len, KM_NOFS | KM_MAYFAIL); |
| 260 | if (!args->value) | 260 | if (!args->value) |
| 261 | return ENOMEM; | 261 | return ENOMEM; |
| 262 | 262 | ||
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index cbd451bb4848..2d0b3e1da9e6 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c | |||
| @@ -167,17 +167,25 @@ xfs_growfs_data_private( | |||
| 167 | new = nb - mp->m_sb.sb_dblocks; | 167 | new = nb - mp->m_sb.sb_dblocks; |
| 168 | oagcount = mp->m_sb.sb_agcount; | 168 | oagcount = mp->m_sb.sb_agcount; |
| 169 | if (nagcount > oagcount) { | 169 | if (nagcount > oagcount) { |
| 170 | void *new_perag, *old_perag; | ||
| 171 | |||
| 170 | xfs_filestream_flush(mp); | 172 | xfs_filestream_flush(mp); |
| 173 | |||
| 174 | new_perag = kmem_zalloc(sizeof(xfs_perag_t) * nagcount, | ||
| 175 | KM_MAYFAIL); | ||
| 176 | if (!new_perag) | ||
| 177 | return XFS_ERROR(ENOMEM); | ||
| 178 | |||
| 171 | down_write(&mp->m_peraglock); | 179 | down_write(&mp->m_peraglock); |
| 172 | mp->m_perag = kmem_realloc(mp->m_perag, | 180 | memcpy(new_perag, mp->m_perag, sizeof(xfs_perag_t) * oagcount); |
| 173 | sizeof(xfs_perag_t) * nagcount, | 181 | old_perag = mp->m_perag; |
| 174 | sizeof(xfs_perag_t) * oagcount, | 182 | mp->m_perag = new_perag; |
| 175 | KM_SLEEP); | 183 | |
| 176 | memset(&mp->m_perag[oagcount], 0, | ||
| 177 | (nagcount - oagcount) * sizeof(xfs_perag_t)); | ||
| 178 | mp->m_flags |= XFS_MOUNT_32BITINODES; | 184 | mp->m_flags |= XFS_MOUNT_32BITINODES; |
| 179 | nagimax = xfs_initialize_perag(mp, nagcount); | 185 | nagimax = xfs_initialize_perag(mp, nagcount); |
| 180 | up_write(&mp->m_peraglock); | 186 | up_write(&mp->m_peraglock); |
| 187 | |||
| 188 | kmem_free(old_perag); | ||
| 181 | } | 189 | } |
| 182 | tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFS); | 190 | tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFS); |
| 183 | tp->t_flags |= XFS_TRANS_RESERVE; | 191 | tp->t_flags |= XFS_TRANS_RESERVE; |
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 1f22d65fed0a..da428b3fe0f5 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c | |||
| @@ -343,6 +343,16 @@ xfs_iformat( | |||
| 343 | return XFS_ERROR(EFSCORRUPTED); | 343 | return XFS_ERROR(EFSCORRUPTED); |
| 344 | } | 344 | } |
| 345 | 345 | ||
| 346 | if (unlikely((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) && | ||
| 347 | !ip->i_mount->m_rtdev_targp)) { | ||
| 348 | xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount, | ||
| 349 | "corrupt dinode %Lu, has realtime flag set.", | ||
| 350 | ip->i_ino); | ||
| 351 | XFS_CORRUPTION_ERROR("xfs_iformat(realtime)", | ||
| 352 | XFS_ERRLEVEL_LOW, ip->i_mount, dip); | ||
| 353 | return XFS_ERROR(EFSCORRUPTED); | ||
| 354 | } | ||
| 355 | |||
| 346 | switch (ip->i_d.di_mode & S_IFMT) { | 356 | switch (ip->i_d.di_mode & S_IFMT) { |
| 347 | case S_IFIFO: | 357 | case S_IFIFO: |
| 348 | case S_IFCHR: | 358 | case S_IFCHR: |
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index 3750f04ede0b..9dbdff3ea484 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c | |||
| @@ -3180,7 +3180,7 @@ try_again: | |||
| 3180 | STATIC void | 3180 | STATIC void |
| 3181 | xlog_state_want_sync(xlog_t *log, xlog_in_core_t *iclog) | 3181 | xlog_state_want_sync(xlog_t *log, xlog_in_core_t *iclog) |
| 3182 | { | 3182 | { |
| 3183 | ASSERT(spin_is_locked(&log->l_icloglock)); | 3183 | assert_spin_locked(&log->l_icloglock); |
| 3184 | 3184 | ||
| 3185 | if (iclog->ic_state == XLOG_STATE_ACTIVE) { | 3185 | if (iclog->ic_state == XLOG_STATE_ACTIVE) { |
| 3186 | xlog_state_switch_iclogs(log, iclog, 0); | 3186 | xlog_state_switch_iclogs(log, iclog, 0); |
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index c4eca5ed5dab..492d75bae2bf 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c | |||
| @@ -538,7 +538,9 @@ xfs_readlink_bmap( | |||
| 538 | d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock); | 538 | d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock); |
| 539 | byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount); | 539 | byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount); |
| 540 | 540 | ||
| 541 | bp = xfs_buf_read(mp->m_ddev_targp, d, BTOBB(byte_cnt), 0); | 541 | bp = xfs_buf_read_flags(mp->m_ddev_targp, d, BTOBB(byte_cnt), |
| 542 | XBF_LOCK | XBF_MAPPED | | ||
| 543 | XBF_DONT_BLOCK); | ||
| 542 | error = XFS_BUF_GETERROR(bp); | 544 | error = XFS_BUF_GETERROR(bp); |
| 543 | if (error) { | 545 | if (error) { |
| 544 | xfs_ioerror_alert("xfs_readlink", | 546 | xfs_ioerror_alert("xfs_readlink", |
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index fdffb413b192..f6b90240dd41 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 *); | |||
| 473 | extern int nfs_flush_incompatible(struct file *file, struct page *page); | 473 | extern int nfs_flush_incompatible(struct file *file, struct page *page); |
| 474 | extern int nfs_updatepage(struct file *, struct page *, unsigned int, unsigned int); | 474 | extern int nfs_updatepage(struct file *, struct page *, unsigned int, unsigned int); |
| 475 | extern int nfs_writeback_done(struct rpc_task *, struct nfs_write_data *); | 475 | extern int nfs_writeback_done(struct rpc_task *, struct nfs_write_data *); |
| 476 | extern void nfs_writedata_release(void *); | ||
| 477 | 476 | ||
| 478 | /* | 477 | /* |
| 479 | * Try to write back everything synchronously (but check the | 478 | * 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); | |||
| 488 | extern int nfs_commit_inode(struct inode *, int); | 487 | extern int nfs_commit_inode(struct inode *, int); |
| 489 | extern struct nfs_write_data *nfs_commitdata_alloc(void); | 488 | extern struct nfs_write_data *nfs_commitdata_alloc(void); |
| 490 | extern void nfs_commit_free(struct nfs_write_data *wdata); | 489 | extern void nfs_commit_free(struct nfs_write_data *wdata); |
| 491 | extern void nfs_commitdata_release(void *wdata); | ||
| 492 | #else | 490 | #else |
| 493 | static inline int | 491 | static inline int |
| 494 | nfs_commit_inode(struct inode *inode, int how) | 492 | nfs_commit_inode(struct inode *inode, int how) |
| @@ -507,6 +505,7 @@ nfs_have_writebacks(struct inode *inode) | |||
| 507 | * Allocate nfs_write_data structures | 505 | * Allocate nfs_write_data structures |
| 508 | */ | 506 | */ |
| 509 | extern struct nfs_write_data *nfs_writedata_alloc(unsigned int npages); | 507 | extern struct nfs_write_data *nfs_writedata_alloc(unsigned int npages); |
| 508 | extern void nfs_writedata_free(struct nfs_write_data *); | ||
| 510 | 509 | ||
| 511 | /* | 510 | /* |
| 512 | * linux/fs/nfs/read.c | 511 | * linux/fs/nfs/read.c |
| @@ -515,7 +514,6 @@ extern int nfs_readpage(struct file *, struct page *); | |||
| 515 | extern int nfs_readpages(struct file *, struct address_space *, | 514 | extern int nfs_readpages(struct file *, struct address_space *, |
| 516 | struct list_head *, unsigned); | 515 | struct list_head *, unsigned); |
| 517 | extern int nfs_readpage_result(struct rpc_task *, struct nfs_read_data *); | 516 | extern int nfs_readpage_result(struct rpc_task *, struct nfs_read_data *); |
| 518 | extern void nfs_readdata_release(void *data); | ||
| 519 | extern int nfs_readpage_async(struct nfs_open_context *, struct inode *, | 517 | extern int nfs_readpage_async(struct nfs_open_context *, struct inode *, |
| 520 | struct page *); | 518 | struct page *); |
| 521 | 519 | ||
| @@ -523,6 +521,7 @@ extern int nfs_readpage_async(struct nfs_open_context *, struct inode *, | |||
| 523 | * Allocate nfs_read_data structures | 521 | * Allocate nfs_read_data structures |
| 524 | */ | 522 | */ |
| 525 | extern struct nfs_read_data *nfs_readdata_alloc(unsigned int npages); | 523 | extern struct nfs_read_data *nfs_readdata_alloc(unsigned int npages); |
| 524 | extern void nfs_readdata_free(struct nfs_read_data *); | ||
| 526 | 525 | ||
| 527 | /* | 526 | /* |
| 528 | * linux/fs/nfs3proc.c | 527 | * linux/fs/nfs3proc.c |
diff --git a/include/linux/perf_counter.h b/include/linux/perf_counter.h index a67dd5c5b6d3..a9d823a93fe8 100644 --- a/include/linux/perf_counter.h +++ b/include/linux/perf_counter.h | |||
| @@ -121,7 +121,7 @@ enum perf_counter_sample_format { | |||
| 121 | PERF_SAMPLE_CPU = 1U << 7, | 121 | PERF_SAMPLE_CPU = 1U << 7, |
| 122 | PERF_SAMPLE_PERIOD = 1U << 8, | 122 | PERF_SAMPLE_PERIOD = 1U << 8, |
| 123 | PERF_SAMPLE_STREAM_ID = 1U << 9, | 123 | PERF_SAMPLE_STREAM_ID = 1U << 9, |
| 124 | PERF_SAMPLE_TP_RECORD = 1U << 10, | 124 | PERF_SAMPLE_RAW = 1U << 10, |
| 125 | 125 | ||
| 126 | PERF_SAMPLE_MAX = 1U << 11, /* non-ABI */ | 126 | PERF_SAMPLE_MAX = 1U << 11, /* non-ABI */ |
| 127 | }; | 127 | }; |
| @@ -369,6 +369,8 @@ enum perf_event_type { | |||
| 369 | * | 369 | * |
| 370 | * { u64 nr, | 370 | * { u64 nr, |
| 371 | * u64 ips[nr]; } && PERF_SAMPLE_CALLCHAIN | 371 | * u64 ips[nr]; } && PERF_SAMPLE_CALLCHAIN |
| 372 | * { u32 size; | ||
| 373 | * char data[size];}&& PERF_SAMPLE_RAW | ||
| 372 | * }; | 374 | * }; |
| 373 | */ | 375 | */ |
| 374 | PERF_EVENT_SAMPLE = 9, | 376 | PERF_EVENT_SAMPLE = 9, |
| @@ -414,9 +416,9 @@ struct perf_callchain_entry { | |||
| 414 | __u64 ip[PERF_MAX_STACK_DEPTH]; | 416 | __u64 ip[PERF_MAX_STACK_DEPTH]; |
| 415 | }; | 417 | }; |
| 416 | 418 | ||
| 417 | struct perf_tracepoint_record { | 419 | struct perf_raw_record { |
| 418 | int size; | 420 | u32 size; |
| 419 | char *record; | 421 | void *data; |
| 420 | }; | 422 | }; |
| 421 | 423 | ||
| 422 | struct task_struct; | 424 | struct task_struct; |
| @@ -687,7 +689,7 @@ struct perf_sample_data { | |||
| 687 | struct pt_regs *regs; | 689 | struct pt_regs *regs; |
| 688 | u64 addr; | 690 | u64 addr; |
| 689 | u64 period; | 691 | u64 period; |
| 690 | void *private; | 692 | struct perf_raw_record *raw; |
| 691 | }; | 693 | }; |
| 692 | 694 | ||
| 693 | extern int perf_counter_overflow(struct perf_counter *counter, int nmi, | 695 | extern int perf_counter_overflow(struct perf_counter *counter, int nmi, |
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index 7fb16d90e7b1..f64fbaae781a 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h | |||
| @@ -637,12 +637,20 @@ __attribute__((section("_ftrace_events"))) event_##call = { \ | |||
| 637 | * pc = preempt_count(); | 637 | * pc = preempt_count(); |
| 638 | * | 638 | * |
| 639 | * __data_size = ftrace_get_offsets_<call>(&__data_offsets, args); | 639 | * __data_size = ftrace_get_offsets_<call>(&__data_offsets, args); |
| 640 | * __entry_size = __data_size + sizeof(*entry); | 640 | * |
| 641 | * // Below we want to get the aligned size by taking into account | ||
| 642 | * // the u32 field that will later store the buffer size | ||
| 643 | * __entry_size = ALIGN(__data_size + sizeof(*entry) + sizeof(u32), | ||
| 644 | * sizeof(u64)); | ||
| 645 | * __entry_size -= sizeof(u32); | ||
| 641 | * | 646 | * |
| 642 | * do { | 647 | * do { |
| 643 | * char raw_data[__entry_size]; <- allocate our sample in the stack | 648 | * char raw_data[__entry_size]; <- allocate our sample in the stack |
| 644 | * struct trace_entry *ent; | 649 | * struct trace_entry *ent; |
| 645 | * | 650 | * |
| 651 | * zero dead bytes from alignment to avoid stack leak to userspace: | ||
| 652 | * | ||
| 653 | * *(u64 *)(&raw_data[__entry_size - sizeof(u64)]) = 0ULL; | ||
| 646 | * entry = (struct ftrace_raw_<call> *)raw_data; | 654 | * entry = (struct ftrace_raw_<call> *)raw_data; |
| 647 | * ent = &entry->ent; | 655 | * ent = &entry->ent; |
| 648 | * tracing_generic_entry_update(ent, irq_flags, pc); | 656 | * tracing_generic_entry_update(ent, irq_flags, pc); |
| @@ -685,12 +693,15 @@ static void ftrace_profile_##call(proto) \ | |||
| 685 | pc = preempt_count(); \ | 693 | pc = preempt_count(); \ |
| 686 | \ | 694 | \ |
| 687 | __data_size = ftrace_get_offsets_##call(&__data_offsets, args); \ | 695 | __data_size = ftrace_get_offsets_##call(&__data_offsets, args); \ |
| 688 | __entry_size = ALIGN(__data_size + sizeof(*entry), sizeof(u64));\ | 696 | __entry_size = ALIGN(__data_size + sizeof(*entry) + sizeof(u32),\ |
| 697 | sizeof(u64)); \ | ||
| 698 | __entry_size -= sizeof(u32); \ | ||
| 689 | \ | 699 | \ |
| 690 | do { \ | 700 | do { \ |
| 691 | char raw_data[__entry_size]; \ | 701 | char raw_data[__entry_size]; \ |
| 692 | struct trace_entry *ent; \ | 702 | struct trace_entry *ent; \ |
| 693 | \ | 703 | \ |
| 704 | *(u64 *)(&raw_data[__entry_size - sizeof(u64)]) = 0ULL; \ | ||
| 694 | entry = (struct ftrace_raw_##call *)raw_data; \ | 705 | entry = (struct ftrace_raw_##call *)raw_data; \ |
| 695 | ent = &entry->ent; \ | 706 | ent = &entry->ent; \ |
| 696 | tracing_generic_entry_update(ent, irq_flags, pc); \ | 707 | tracing_generic_entry_update(ent, irq_flags, pc); \ |
diff --git a/kernel/irq/numa_migrate.c b/kernel/irq/numa_migrate.c index 2f69bee57bf2..3fd30197da2e 100644 --- a/kernel/irq/numa_migrate.c +++ b/kernel/irq/numa_migrate.c | |||
| @@ -107,8 +107,8 @@ out_unlock: | |||
| 107 | 107 | ||
| 108 | struct irq_desc *move_irq_desc(struct irq_desc *desc, int node) | 108 | struct irq_desc *move_irq_desc(struct irq_desc *desc, int node) |
| 109 | { | 109 | { |
| 110 | /* those all static, do move them */ | 110 | /* those static or target node is -1, do not move them */ |
| 111 | if (desc->irq < NR_IRQS_LEGACY) | 111 | if (desc->irq < NR_IRQS_LEGACY || node == -1) |
| 112 | return desc; | 112 | return desc; |
| 113 | 113 | ||
| 114 | if (desc->node != node) | 114 | if (desc->node != node) |
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c index 868102172aa4..b0b20a07f394 100644 --- a/kernel/perf_counter.c +++ b/kernel/perf_counter.c | |||
| @@ -2646,7 +2646,6 @@ static void perf_counter_output(struct perf_counter *counter, int nmi, | |||
| 2646 | u64 counter; | 2646 | u64 counter; |
| 2647 | } group_entry; | 2647 | } group_entry; |
| 2648 | struct perf_callchain_entry *callchain = NULL; | 2648 | struct perf_callchain_entry *callchain = NULL; |
| 2649 | struct perf_tracepoint_record *tp; | ||
| 2650 | int callchain_size = 0; | 2649 | int callchain_size = 0; |
| 2651 | u64 time; | 2650 | u64 time; |
| 2652 | struct { | 2651 | struct { |
| @@ -2715,9 +2714,16 @@ static void perf_counter_output(struct perf_counter *counter, int nmi, | |||
| 2715 | header.size += sizeof(u64); | 2714 | header.size += sizeof(u64); |
| 2716 | } | 2715 | } |
| 2717 | 2716 | ||
| 2718 | if (sample_type & PERF_SAMPLE_TP_RECORD) { | 2717 | if (sample_type & PERF_SAMPLE_RAW) { |
| 2719 | tp = data->private; | 2718 | int size = sizeof(u32); |
| 2720 | header.size += tp->size; | 2719 | |
| 2720 | if (data->raw) | ||
| 2721 | size += data->raw->size; | ||
| 2722 | else | ||
| 2723 | size += sizeof(u32); | ||
| 2724 | |||
| 2725 | WARN_ON_ONCE(size & (sizeof(u64)-1)); | ||
| 2726 | header.size += size; | ||
| 2721 | } | 2727 | } |
| 2722 | 2728 | ||
| 2723 | ret = perf_output_begin(&handle, counter, header.size, nmi, 1); | 2729 | ret = perf_output_begin(&handle, counter, header.size, nmi, 1); |
| @@ -2783,8 +2789,21 @@ static void perf_counter_output(struct perf_counter *counter, int nmi, | |||
| 2783 | } | 2789 | } |
| 2784 | } | 2790 | } |
| 2785 | 2791 | ||
| 2786 | if (sample_type & PERF_SAMPLE_TP_RECORD) | 2792 | if (sample_type & PERF_SAMPLE_RAW) { |
| 2787 | perf_output_copy(&handle, tp->record, tp->size); | 2793 | if (data->raw) { |
| 2794 | perf_output_put(&handle, data->raw->size); | ||
| 2795 | perf_output_copy(&handle, data->raw->data, data->raw->size); | ||
| 2796 | } else { | ||
| 2797 | struct { | ||
| 2798 | u32 size; | ||
| 2799 | u32 data; | ||
| 2800 | } raw = { | ||
| 2801 | .size = sizeof(u32), | ||
| 2802 | .data = 0, | ||
| 2803 | }; | ||
| 2804 | perf_output_put(&handle, raw); | ||
| 2805 | } | ||
| 2806 | } | ||
| 2788 | 2807 | ||
| 2789 | perf_output_end(&handle); | 2808 | perf_output_end(&handle); |
| 2790 | } | 2809 | } |
| @@ -2849,7 +2868,8 @@ perf_counter_read_event(struct perf_counter *counter, | |||
| 2849 | */ | 2868 | */ |
| 2850 | 2869 | ||
| 2851 | struct perf_task_event { | 2870 | struct perf_task_event { |
| 2852 | struct task_struct *task; | 2871 | struct task_struct *task; |
| 2872 | struct perf_counter_context *task_ctx; | ||
| 2853 | 2873 | ||
| 2854 | struct { | 2874 | struct { |
| 2855 | struct perf_event_header header; | 2875 | struct perf_event_header header; |
| @@ -2909,24 +2929,23 @@ static void perf_counter_task_ctx(struct perf_counter_context *ctx, | |||
| 2909 | static void perf_counter_task_event(struct perf_task_event *task_event) | 2929 | static void perf_counter_task_event(struct perf_task_event *task_event) |
| 2910 | { | 2930 | { |
| 2911 | struct perf_cpu_context *cpuctx; | 2931 | struct perf_cpu_context *cpuctx; |
| 2912 | struct perf_counter_context *ctx; | 2932 | struct perf_counter_context *ctx = task_event->task_ctx; |
| 2913 | 2933 | ||
| 2914 | cpuctx = &get_cpu_var(perf_cpu_context); | 2934 | cpuctx = &get_cpu_var(perf_cpu_context); |
| 2915 | perf_counter_task_ctx(&cpuctx->ctx, task_event); | 2935 | perf_counter_task_ctx(&cpuctx->ctx, task_event); |
| 2916 | put_cpu_var(perf_cpu_context); | 2936 | put_cpu_var(perf_cpu_context); |
| 2917 | 2937 | ||
| 2918 | rcu_read_lock(); | 2938 | rcu_read_lock(); |
| 2919 | /* | 2939 | if (!ctx) |
| 2920 | * doesn't really matter which of the child contexts the | 2940 | ctx = rcu_dereference(task_event->task->perf_counter_ctxp); |
| 2921 | * events ends up in. | ||
| 2922 | */ | ||
| 2923 | ctx = rcu_dereference(current->perf_counter_ctxp); | ||
| 2924 | if (ctx) | 2941 | if (ctx) |
| 2925 | perf_counter_task_ctx(ctx, task_event); | 2942 | perf_counter_task_ctx(ctx, task_event); |
| 2926 | rcu_read_unlock(); | 2943 | rcu_read_unlock(); |
| 2927 | } | 2944 | } |
| 2928 | 2945 | ||
| 2929 | static void perf_counter_task(struct task_struct *task, int new) | 2946 | static void perf_counter_task(struct task_struct *task, |
| 2947 | struct perf_counter_context *task_ctx, | ||
| 2948 | int new) | ||
| 2930 | { | 2949 | { |
| 2931 | struct perf_task_event task_event; | 2950 | struct perf_task_event task_event; |
| 2932 | 2951 | ||
| @@ -2936,8 +2955,9 @@ static void perf_counter_task(struct task_struct *task, int new) | |||
| 2936 | return; | 2955 | return; |
| 2937 | 2956 | ||
| 2938 | task_event = (struct perf_task_event){ | 2957 | task_event = (struct perf_task_event){ |
| 2939 | .task = task, | 2958 | .task = task, |
| 2940 | .event = { | 2959 | .task_ctx = task_ctx, |
| 2960 | .event = { | ||
| 2941 | .header = { | 2961 | .header = { |
| 2942 | .type = new ? PERF_EVENT_FORK : PERF_EVENT_EXIT, | 2962 | .type = new ? PERF_EVENT_FORK : PERF_EVENT_EXIT, |
| 2943 | .misc = 0, | 2963 | .misc = 0, |
| @@ -2955,7 +2975,7 @@ static void perf_counter_task(struct task_struct *task, int new) | |||
| 2955 | 2975 | ||
| 2956 | void perf_counter_fork(struct task_struct *task) | 2976 | void perf_counter_fork(struct task_struct *task) |
| 2957 | { | 2977 | { |
| 2958 | perf_counter_task(task, 1); | 2978 | perf_counter_task(task, NULL, 1); |
| 2959 | } | 2979 | } |
| 2960 | 2980 | ||
| 2961 | /* | 2981 | /* |
| @@ -3344,87 +3364,81 @@ int perf_counter_overflow(struct perf_counter *counter, int nmi, | |||
| 3344 | * Generic software counter infrastructure | 3364 | * Generic software counter infrastructure |
| 3345 | */ | 3365 | */ |
| 3346 | 3366 | ||
| 3347 | static void perf_swcounter_update(struct perf_counter *counter) | 3367 | /* |
| 3368 | * We directly increment counter->count and keep a second value in | ||
| 3369 | * counter->hw.period_left to count intervals. This period counter | ||
| 3370 | * is kept in the range [-sample_period, 0] so that we can use the | ||
| 3371 | * sign as trigger. | ||
| 3372 | */ | ||
| 3373 | |||
| 3374 | static u64 perf_swcounter_set_period(struct perf_counter *counter) | ||
| 3348 | { | 3375 | { |
| 3349 | struct hw_perf_counter *hwc = &counter->hw; | 3376 | struct hw_perf_counter *hwc = &counter->hw; |
| 3350 | u64 prev, now; | 3377 | u64 period = hwc->last_period; |
| 3351 | s64 delta; | 3378 | u64 nr, offset; |
| 3379 | s64 old, val; | ||
| 3380 | |||
| 3381 | hwc->last_period = hwc->sample_period; | ||
| 3352 | 3382 | ||
| 3353 | again: | 3383 | again: |
| 3354 | prev = atomic64_read(&hwc->prev_count); | 3384 | old = val = atomic64_read(&hwc->period_left); |
| 3355 | now = atomic64_read(&hwc->count); | 3385 | if (val < 0) |
| 3356 | if (atomic64_cmpxchg(&hwc->prev_count, prev, now) != prev) | 3386 | return 0; |
| 3357 | goto again; | ||
| 3358 | 3387 | ||
| 3359 | delta = now - prev; | 3388 | nr = div64_u64(period + val, period); |
| 3389 | offset = nr * period; | ||
| 3390 | val -= offset; | ||
| 3391 | if (atomic64_cmpxchg(&hwc->period_left, old, val) != old) | ||
| 3392 | goto again; | ||
| 3360 | 3393 | ||
| 3361 | atomic64_add(delta, &counter->count); | 3394 | return nr; |
| 3362 | atomic64_sub(delta, &hwc->period_left); | ||
| 3363 | } | 3395 | } |
| 3364 | 3396 | ||
| 3365 | static void perf_swcounter_set_period(struct perf_counter *counter) | 3397 | static void perf_swcounter_overflow(struct perf_counter *counter, |
| 3398 | int nmi, struct perf_sample_data *data) | ||
| 3366 | { | 3399 | { |
| 3367 | struct hw_perf_counter *hwc = &counter->hw; | 3400 | struct hw_perf_counter *hwc = &counter->hw; |
| 3368 | s64 left = atomic64_read(&hwc->period_left); | 3401 | u64 overflow; |
| 3369 | s64 period = hwc->sample_period; | ||
| 3370 | 3402 | ||
| 3371 | if (unlikely(left <= -period)) { | 3403 | data->period = counter->hw.last_period; |
| 3372 | left = period; | 3404 | overflow = perf_swcounter_set_period(counter); |
| 3373 | atomic64_set(&hwc->period_left, left); | ||
| 3374 | hwc->last_period = period; | ||
| 3375 | } | ||
| 3376 | 3405 | ||
| 3377 | if (unlikely(left <= 0)) { | 3406 | if (hwc->interrupts == MAX_INTERRUPTS) |
| 3378 | left += period; | 3407 | return; |
| 3379 | atomic64_add(period, &hwc->period_left); | ||
| 3380 | hwc->last_period = period; | ||
| 3381 | } | ||
| 3382 | 3408 | ||
| 3383 | atomic64_set(&hwc->prev_count, -left); | 3409 | for (; overflow; overflow--) { |
| 3384 | atomic64_set(&hwc->count, -left); | 3410 | if (perf_counter_overflow(counter, nmi, data)) { |
| 3411 | /* | ||
| 3412 | * We inhibit the overflow from happening when | ||
| 3413 | * hwc->interrupts == MAX_INTERRUPTS. | ||
| 3414 | */ | ||
| 3415 | break; | ||
| 3416 | } | ||
| 3417 | } | ||
| 3385 | } | 3418 | } |
| 3386 | 3419 | ||
| 3387 | static enum hrtimer_restart perf_swcounter_hrtimer(struct hrtimer *hrtimer) | 3420 | static void perf_swcounter_unthrottle(struct perf_counter *counter) |
| 3388 | { | 3421 | { |
| 3389 | enum hrtimer_restart ret = HRTIMER_RESTART; | ||
| 3390 | struct perf_sample_data data; | ||
| 3391 | struct perf_counter *counter; | ||
| 3392 | u64 period; | ||
| 3393 | |||
| 3394 | counter = container_of(hrtimer, struct perf_counter, hw.hrtimer); | ||
| 3395 | counter->pmu->read(counter); | ||
| 3396 | |||
| 3397 | data.addr = 0; | ||
| 3398 | data.regs = get_irq_regs(); | ||
| 3399 | /* | 3422 | /* |
| 3400 | * In case we exclude kernel IPs or are somehow not in interrupt | 3423 | * Nothing to do, we already reset hwc->interrupts. |
| 3401 | * context, provide the next best thing, the user IP. | ||
| 3402 | */ | 3424 | */ |
| 3403 | if ((counter->attr.exclude_kernel || !data.regs) && | 3425 | } |
| 3404 | !counter->attr.exclude_user) | ||
| 3405 | data.regs = task_pt_regs(current); | ||
| 3406 | 3426 | ||
| 3407 | if (data.regs) { | 3427 | static void perf_swcounter_add(struct perf_counter *counter, u64 nr, |
| 3408 | if (perf_counter_overflow(counter, 0, &data)) | 3428 | int nmi, struct perf_sample_data *data) |
| 3409 | ret = HRTIMER_NORESTART; | 3429 | { |
| 3410 | } | 3430 | struct hw_perf_counter *hwc = &counter->hw; |
| 3411 | 3431 | ||
| 3412 | period = max_t(u64, 10000, counter->hw.sample_period); | 3432 | atomic64_add(nr, &counter->count); |
| 3413 | hrtimer_forward_now(hrtimer, ns_to_ktime(period)); | ||
| 3414 | 3433 | ||
| 3415 | return ret; | 3434 | if (!hwc->sample_period) |
| 3416 | } | 3435 | return; |
| 3417 | 3436 | ||
| 3418 | static void perf_swcounter_overflow(struct perf_counter *counter, | 3437 | if (!data->regs) |
| 3419 | int nmi, struct perf_sample_data *data) | 3438 | return; |
| 3420 | { | ||
| 3421 | data->period = counter->hw.last_period; | ||
| 3422 | 3439 | ||
| 3423 | perf_swcounter_update(counter); | 3440 | if (!atomic64_add_negative(nr, &hwc->period_left)) |
| 3424 | perf_swcounter_set_period(counter); | 3441 | perf_swcounter_overflow(counter, nmi, data); |
| 3425 | if (perf_counter_overflow(counter, nmi, data)) | ||
| 3426 | /* soft-disable the counter */ | ||
| 3427 | ; | ||
| 3428 | } | 3442 | } |
| 3429 | 3443 | ||
| 3430 | static int perf_swcounter_is_counting(struct perf_counter *counter) | 3444 | static int perf_swcounter_is_counting(struct perf_counter *counter) |
| @@ -3488,15 +3502,6 @@ static int perf_swcounter_match(struct perf_counter *counter, | |||
| 3488 | return 1; | 3502 | return 1; |
| 3489 | } | 3503 | } |
| 3490 | 3504 | ||
| 3491 | static void perf_swcounter_add(struct perf_counter *counter, u64 nr, | ||
| 3492 | int nmi, struct perf_sample_data *data) | ||
| 3493 | { | ||
| 3494 | int neg = atomic64_add_negative(nr, &counter->hw.count); | ||
| 3495 | |||
| 3496 | if (counter->hw.sample_period && !neg && data->regs) | ||
| 3497 | perf_swcounter_overflow(counter, nmi, data); | ||
| 3498 | } | ||
| 3499 | |||
| 3500 | static void perf_swcounter_ctx_event(struct perf_counter_context *ctx, | 3505 | static void perf_swcounter_ctx_event(struct perf_counter_context *ctx, |
| 3501 | enum perf_type_id type, | 3506 | enum perf_type_id type, |
| 3502 | u32 event, u64 nr, int nmi, | 3507 | u32 event, u64 nr, int nmi, |
| @@ -3575,27 +3580,66 @@ void __perf_swcounter_event(u32 event, u64 nr, int nmi, | |||
| 3575 | 3580 | ||
| 3576 | static void perf_swcounter_read(struct perf_counter *counter) | 3581 | static void perf_swcounter_read(struct perf_counter *counter) |
| 3577 | { | 3582 | { |
| 3578 | perf_swcounter_update(counter); | ||
| 3579 | } | 3583 | } |
| 3580 | 3584 | ||
| 3581 | static int perf_swcounter_enable(struct perf_counter *counter) | 3585 | static int perf_swcounter_enable(struct perf_counter *counter) |
| 3582 | { | 3586 | { |
| 3583 | perf_swcounter_set_period(counter); | 3587 | struct hw_perf_counter *hwc = &counter->hw; |
| 3588 | |||
| 3589 | if (hwc->sample_period) { | ||
| 3590 | hwc->last_period = hwc->sample_period; | ||
| 3591 | perf_swcounter_set_period(counter); | ||
| 3592 | } | ||
| 3584 | return 0; | 3593 | return 0; |
| 3585 | } | 3594 | } |
| 3586 | 3595 | ||
| 3587 | static void perf_swcounter_disable(struct perf_counter *counter) | 3596 | static void perf_swcounter_disable(struct perf_counter *counter) |
| 3588 | { | 3597 | { |
| 3589 | perf_swcounter_update(counter); | ||
| 3590 | } | 3598 | } |
| 3591 | 3599 | ||
| 3592 | static const struct pmu perf_ops_generic = { | 3600 | static const struct pmu perf_ops_generic = { |
| 3593 | .enable = perf_swcounter_enable, | 3601 | .enable = perf_swcounter_enable, |
| 3594 | .disable = perf_swcounter_disable, | 3602 | .disable = perf_swcounter_disable, |
| 3595 | .read = perf_swcounter_read, | 3603 | .read = perf_swcounter_read, |
| 3604 | .unthrottle = perf_swcounter_unthrottle, | ||
| 3596 | }; | 3605 | }; |
| 3597 | 3606 | ||
| 3598 | /* | 3607 | /* |
| 3608 | * hrtimer based swcounter callback | ||
| 3609 | */ | ||
| 3610 | |||
| 3611 | static enum hrtimer_restart perf_swcounter_hrtimer(struct hrtimer *hrtimer) | ||
| 3612 | { | ||
| 3613 | enum hrtimer_restart ret = HRTIMER_RESTART; | ||
| 3614 | struct perf_sample_data data; | ||
| 3615 | struct perf_counter *counter; | ||
| 3616 | u64 period; | ||
| 3617 | |||
| 3618 | counter = container_of(hrtimer, struct perf_counter, hw.hrtimer); | ||
| 3619 | counter->pmu->read(counter); | ||
| 3620 | |||
| 3621 | data.addr = 0; | ||
| 3622 | data.regs = get_irq_regs(); | ||
| 3623 | /* | ||
| 3624 | * In case we exclude kernel IPs or are somehow not in interrupt | ||
| 3625 | * context, provide the next best thing, the user IP. | ||
| 3626 | */ | ||
| 3627 | if ((counter->attr.exclude_kernel || !data.regs) && | ||
| 3628 | !counter->attr.exclude_user) | ||
| 3629 | data.regs = task_pt_regs(current); | ||
| 3630 | |||
| 3631 | if (data.regs) { | ||
| 3632 | if (perf_counter_overflow(counter, 0, &data)) | ||
| 3633 | ret = HRTIMER_NORESTART; | ||
| 3634 | } | ||
| 3635 | |||
| 3636 | period = max_t(u64, 10000, counter->hw.sample_period); | ||
| 3637 | hrtimer_forward_now(hrtimer, ns_to_ktime(period)); | ||
| 3638 | |||
| 3639 | return ret; | ||
| 3640 | } | ||
| 3641 | |||
| 3642 | /* | ||
| 3599 | * Software counter: cpu wall time clock | 3643 | * Software counter: cpu wall time clock |
| 3600 | */ | 3644 | */ |
| 3601 | 3645 | ||
| @@ -3715,15 +3759,15 @@ static const struct pmu perf_ops_task_clock = { | |||
| 3715 | void perf_tpcounter_event(int event_id, u64 addr, u64 count, void *record, | 3759 | void perf_tpcounter_event(int event_id, u64 addr, u64 count, void *record, |
| 3716 | int entry_size) | 3760 | int entry_size) |
| 3717 | { | 3761 | { |
| 3718 | struct perf_tracepoint_record tp = { | 3762 | struct perf_raw_record raw = { |
| 3719 | .size = entry_size, | 3763 | .size = entry_size, |
| 3720 | .record = record, | 3764 | .data = record, |
| 3721 | }; | 3765 | }; |
| 3722 | 3766 | ||
| 3723 | struct perf_sample_data data = { | 3767 | struct perf_sample_data data = { |
| 3724 | .regs = get_irq_regs(), | 3768 | .regs = get_irq_regs(), |
| 3725 | .addr = addr, | 3769 | .addr = addr, |
| 3726 | .private = &tp, | 3770 | .raw = &raw, |
| 3727 | }; | 3771 | }; |
| 3728 | 3772 | ||
| 3729 | if (!data.regs) | 3773 | if (!data.regs) |
| @@ -3743,6 +3787,14 @@ static void tp_perf_counter_destroy(struct perf_counter *counter) | |||
| 3743 | 3787 | ||
| 3744 | static const struct pmu *tp_perf_counter_init(struct perf_counter *counter) | 3788 | static const struct pmu *tp_perf_counter_init(struct perf_counter *counter) |
| 3745 | { | 3789 | { |
| 3790 | /* | ||
| 3791 | * Raw tracepoint data is a severe data leak, only allow root to | ||
| 3792 | * have these. | ||
| 3793 | */ | ||
| 3794 | if ((counter->attr.sample_type & PERF_SAMPLE_RAW) && | ||
| 3795 | !capable(CAP_SYS_ADMIN)) | ||
| 3796 | return ERR_PTR(-EPERM); | ||
| 3797 | |||
| 3746 | if (ftrace_profile_enable(counter->attr.config)) | 3798 | if (ftrace_profile_enable(counter->attr.config)) |
| 3747 | return NULL; | 3799 | return NULL; |
| 3748 | 3800 | ||
| @@ -4285,7 +4337,7 @@ void perf_counter_exit_task(struct task_struct *child) | |||
| 4285 | unsigned long flags; | 4337 | unsigned long flags; |
| 4286 | 4338 | ||
| 4287 | if (likely(!child->perf_counter_ctxp)) { | 4339 | if (likely(!child->perf_counter_ctxp)) { |
| 4288 | perf_counter_task(child, 0); | 4340 | perf_counter_task(child, NULL, 0); |
| 4289 | return; | 4341 | return; |
| 4290 | } | 4342 | } |
| 4291 | 4343 | ||
| @@ -4305,6 +4357,7 @@ void perf_counter_exit_task(struct task_struct *child) | |||
| 4305 | * incremented the context's refcount before we do put_ctx below. | 4357 | * incremented the context's refcount before we do put_ctx below. |
| 4306 | */ | 4358 | */ |
| 4307 | spin_lock(&child_ctx->lock); | 4359 | spin_lock(&child_ctx->lock); |
| 4360 | child->perf_counter_ctxp = NULL; | ||
| 4308 | /* | 4361 | /* |
| 4309 | * If this context is a clone; unclone it so it can't get | 4362 | * If this context is a clone; unclone it so it can't get |
| 4310 | * swapped to another process while we're removing all | 4363 | * swapped to another process while we're removing all |
| @@ -4318,9 +4371,7 @@ void perf_counter_exit_task(struct task_struct *child) | |||
| 4318 | * won't get any samples after PERF_EVENT_EXIT. We can however still | 4371 | * won't get any samples after PERF_EVENT_EXIT. We can however still |
| 4319 | * get a few PERF_EVENT_READ events. | 4372 | * get a few PERF_EVENT_READ events. |
| 4320 | */ | 4373 | */ |
| 4321 | perf_counter_task(child, 0); | 4374 | perf_counter_task(child, child_ctx, 0); |
| 4322 | |||
| 4323 | child->perf_counter_ctxp = NULL; | ||
| 4324 | 4375 | ||
| 4325 | /* | 4376 | /* |
| 4326 | * We can recurse on the same lock type through: | 4377 | * We can recurse on the same lock type through: |
diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c index 1090b0aed9ba..7a34cb563fec 100644 --- a/kernel/trace/blktrace.c +++ b/kernel/trace/blktrace.c | |||
| @@ -267,8 +267,8 @@ static void blk_trace_free(struct blk_trace *bt) | |||
| 267 | { | 267 | { |
| 268 | debugfs_remove(bt->msg_file); | 268 | debugfs_remove(bt->msg_file); |
| 269 | debugfs_remove(bt->dropped_file); | 269 | debugfs_remove(bt->dropped_file); |
| 270 | debugfs_remove(bt->dir); | ||
| 271 | relay_close(bt->rchan); | 270 | relay_close(bt->rchan); |
| 271 | debugfs_remove(bt->dir); | ||
| 272 | free_percpu(bt->sequence); | 272 | free_percpu(bt->sequence); |
| 273 | free_percpu(bt->msg_data); | 273 | free_percpu(bt->msg_data); |
| 274 | kfree(bt); | 274 | kfree(bt); |
| @@ -378,18 +378,8 @@ static int blk_subbuf_start_callback(struct rchan_buf *buf, void *subbuf, | |||
| 378 | 378 | ||
| 379 | static int blk_remove_buf_file_callback(struct dentry *dentry) | 379 | static int blk_remove_buf_file_callback(struct dentry *dentry) |
| 380 | { | 380 | { |
| 381 | struct dentry *parent = dentry->d_parent; | ||
| 382 | debugfs_remove(dentry); | 381 | debugfs_remove(dentry); |
| 383 | 382 | ||
| 384 | /* | ||
| 385 | * this will fail for all but the last file, but that is ok. what we | ||
| 386 | * care about is the top level buts->name directory going away, when | ||
| 387 | * the last trace file is gone. Then we don't have to rmdir() that | ||
| 388 | * manually on trace stop, so it nicely solves the issue with | ||
| 389 | * force killing of running traces. | ||
| 390 | */ | ||
| 391 | |||
| 392 | debugfs_remove(parent); | ||
| 393 | return 0; | 383 | return 0; |
| 394 | } | 384 | } |
| 395 | 385 | ||
diff --git a/mm/mempool.c b/mm/mempool.c index a46eb1b4bb66..32e75d400503 100644 --- a/mm/mempool.c +++ b/mm/mempool.c | |||
| @@ -303,14 +303,14 @@ EXPORT_SYMBOL(mempool_free_slab); | |||
| 303 | */ | 303 | */ |
| 304 | void *mempool_kmalloc(gfp_t gfp_mask, void *pool_data) | 304 | void *mempool_kmalloc(gfp_t gfp_mask, void *pool_data) |
| 305 | { | 305 | { |
| 306 | size_t size = (size_t)(long)pool_data; | 306 | size_t size = (size_t)pool_data; |
| 307 | return kmalloc(size, gfp_mask); | 307 | return kmalloc(size, gfp_mask); |
| 308 | } | 308 | } |
| 309 | EXPORT_SYMBOL(mempool_kmalloc); | 309 | EXPORT_SYMBOL(mempool_kmalloc); |
| 310 | 310 | ||
| 311 | void *mempool_kzalloc(gfp_t gfp_mask, void *pool_data) | 311 | void *mempool_kzalloc(gfp_t gfp_mask, void *pool_data) |
| 312 | { | 312 | { |
| 313 | size_t size = (size_t) pool_data; | 313 | size_t size = (size_t)pool_data; |
| 314 | return kzalloc(size, gfp_mask); | 314 | return kzalloc(size, gfp_mask); |
| 315 | } | 315 | } |
| 316 | EXPORT_SYMBOL(mempool_kzalloc); | 316 | EXPORT_SYMBOL(mempool_kzalloc); |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 15c2a08a66f1..1e8cfc4c2ed6 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 | |||
| 1285 | rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX, | 1285 | rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX, |
| 1286 | context, len); | 1286 | context, len); |
| 1287 | if (rc == -ERANGE) { | 1287 | if (rc == -ERANGE) { |
| 1288 | kfree(context); | ||
| 1289 | |||
| 1288 | /* Need a larger buffer. Query for the right size. */ | 1290 | /* Need a larger buffer. Query for the right size. */ |
| 1289 | rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX, | 1291 | rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX, |
| 1290 | NULL, 0); | 1292 | NULL, 0); |
| @@ -1292,7 +1294,6 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent | |||
| 1292 | dput(dentry); | 1294 | dput(dentry); |
| 1293 | goto out_unlock; | 1295 | goto out_unlock; |
| 1294 | } | 1296 | } |
| 1295 | kfree(context); | ||
| 1296 | len = rc; | 1297 | len = rc; |
| 1297 | context = kmalloc(len+1, GFP_NOFS); | 1298 | context = kmalloc(len+1, GFP_NOFS); |
| 1298 | if (!context) { | 1299 | if (!context) { |
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 51c44fdbc0f0..fea976793ae5 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) | |||
| 13563 | set_capture_mixer(spec); | 13563 | set_capture_mixer(spec); |
| 13564 | set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); | 13564 | set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); |
| 13565 | 13565 | ||
| 13566 | spec->vmaster_nid = 0x02; | ||
| 13567 | |||
| 13566 | codec->patch_ops = alc_patch_ops; | 13568 | codec->patch_ops = alc_patch_ops; |
| 13567 | if (board_config == ALC269_AUTO) | 13569 | if (board_config == ALC269_AUTO) |
| 13568 | spec->init_hook = alc269_auto_init; | 13570 | spec->init_hook = alc269_auto_init; |
| @@ -15577,9 +15579,12 @@ static int patch_alc861vd(struct hda_codec *codec) | |||
| 15577 | spec->stream_digital_playback = &alc861vd_pcm_digital_playback; | 15579 | spec->stream_digital_playback = &alc861vd_pcm_digital_playback; |
| 15578 | spec->stream_digital_capture = &alc861vd_pcm_digital_capture; | 15580 | spec->stream_digital_capture = &alc861vd_pcm_digital_capture; |
| 15579 | 15581 | ||
| 15580 | spec->adc_nids = alc861vd_adc_nids; | 15582 | if (!spec->adc_nids) { |
| 15581 | spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids); | 15583 | spec->adc_nids = alc861vd_adc_nids; |
| 15582 | spec->capsrc_nids = alc861vd_capsrc_nids; | 15584 | spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids); |
| 15585 | } | ||
| 15586 | if (!spec->capsrc_nids) | ||
| 15587 | spec->capsrc_nids = alc861vd_capsrc_nids; | ||
| 15583 | 15588 | ||
| 15584 | set_capture_mixer(spec); | 15589 | set_capture_mixer(spec); |
| 15585 | set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); | 15590 | set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); |
| @@ -17496,9 +17501,12 @@ static int patch_alc662(struct hda_codec *codec) | |||
| 17496 | spec->stream_digital_playback = &alc662_pcm_digital_playback; | 17501 | spec->stream_digital_playback = &alc662_pcm_digital_playback; |
| 17497 | spec->stream_digital_capture = &alc662_pcm_digital_capture; | 17502 | spec->stream_digital_capture = &alc662_pcm_digital_capture; |
| 17498 | 17503 | ||
| 17499 | spec->adc_nids = alc662_adc_nids; | 17504 | if (!spec->adc_nids) { |
| 17500 | spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids); | 17505 | spec->adc_nids = alc662_adc_nids; |
| 17501 | spec->capsrc_nids = alc662_capsrc_nids; | 17506 | spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids); |
| 17507 | } | ||
| 17508 | if (!spec->capsrc_nids) | ||
| 17509 | spec->capsrc_nids = alc662_capsrc_nids; | ||
| 17502 | 17510 | ||
| 17503 | if (!spec->cap_mixer) | 17511 | if (!spec->cap_mixer) |
| 17504 | set_capture_mixer(spec); | 17512 | set_capture_mixer(spec); |
diff --git a/sound/soc/fsl/efika-audio-fabric.c b/sound/soc/fsl/efika-audio-fabric.c index 85b0e7569504..3326e2a1e863 100644 --- a/sound/soc/fsl/efika-audio-fabric.c +++ b/sound/soc/fsl/efika-audio-fabric.c | |||
| @@ -30,6 +30,8 @@ | |||
| 30 | #include "mpc5200_psc_ac97.h" | 30 | #include "mpc5200_psc_ac97.h" |
| 31 | #include "../codecs/stac9766.h" | 31 | #include "../codecs/stac9766.h" |
| 32 | 32 | ||
| 33 | #define DRV_NAME "efika-audio-fabric" | ||
| 34 | |||
| 33 | static struct snd_soc_device device; | 35 | static struct snd_soc_device device; |
| 34 | static struct snd_soc_card card; | 36 | static struct snd_soc_card card; |
| 35 | 37 | ||
diff --git a/sound/soc/fsl/pcm030-audio-fabric.c b/sound/soc/fsl/pcm030-audio-fabric.c index 8766f7a3893d..b928ef7d28eb 100644 --- a/sound/soc/fsl/pcm030-audio-fabric.c +++ b/sound/soc/fsl/pcm030-audio-fabric.c | |||
| @@ -30,6 +30,8 @@ | |||
| 30 | #include "mpc5200_psc_ac97.h" | 30 | #include "mpc5200_psc_ac97.h" |
| 31 | #include "../codecs/wm9712.h" | 31 | #include "../codecs/wm9712.h" |
| 32 | 32 | ||
| 33 | #define DRV_NAME "pcm030-audio-fabric" | ||
| 34 | |||
| 33 | static struct snd_soc_device device; | 35 | static struct snd_soc_device device; |
| 34 | static struct snd_soc_card card; | 36 | static struct snd_soc_card card; |
| 35 | 37 | ||
diff --git a/tools/perf/Documentation/perf-examples.txt b/tools/perf/Documentation/perf-examples.txt new file mode 100644 index 000000000000..8eb6c489fb15 --- /dev/null +++ b/tools/perf/Documentation/perf-examples.txt | |||
| @@ -0,0 +1,225 @@ | |||
| 1 | |||
| 2 | ------------------------------ | ||
| 3 | ****** perf by examples ****** | ||
| 4 | ------------------------------ | ||
| 5 | |||
| 6 | [ From an e-mail by Ingo Molnar, http://lkml.org/lkml/2009/8/4/346 ] | ||
| 7 | |||
| 8 | |||
| 9 | First, discovery/enumeration of available counters can be done via | ||
| 10 | 'perf list': | ||
| 11 | |||
| 12 | titan:~> perf list | ||
| 13 | [...] | ||
| 14 | kmem:kmalloc [Tracepoint event] | ||
| 15 | kmem:kmem_cache_alloc [Tracepoint event] | ||
| 16 | kmem:kmalloc_node [Tracepoint event] | ||
| 17 | kmem:kmem_cache_alloc_node [Tracepoint event] | ||
| 18 | kmem:kfree [Tracepoint event] | ||
| 19 | kmem:kmem_cache_free [Tracepoint event] | ||
| 20 | kmem:mm_page_free_direct [Tracepoint event] | ||
| 21 | kmem:mm_pagevec_free [Tracepoint event] | ||
| 22 | kmem:mm_page_alloc [Tracepoint event] | ||
| 23 | kmem:mm_page_alloc_zone_locked [Tracepoint event] | ||
| 24 | kmem:mm_page_pcpu_drain [Tracepoint event] | ||
| 25 | kmem:mm_page_alloc_extfrag [Tracepoint event] | ||
| 26 | |||
| 27 | Then any (or all) of the above event sources can be activated and | ||
| 28 | measured. For example the page alloc/free properties of a 'hackbench | ||
| 29 | run' are: | ||
| 30 | |||
| 31 | titan:~> perf stat -e kmem:mm_page_pcpu_drain -e kmem:mm_page_alloc | ||
| 32 | -e kmem:mm_pagevec_free -e kmem:mm_page_free_direct ./hackbench 10 | ||
| 33 | Time: 0.575 | ||
| 34 | |||
| 35 | Performance counter stats for './hackbench 10': | ||
| 36 | |||
| 37 | 13857 kmem:mm_page_pcpu_drain | ||
| 38 | 27576 kmem:mm_page_alloc | ||
| 39 | 6025 kmem:mm_pagevec_free | ||
| 40 | 20934 kmem:mm_page_free_direct | ||
| 41 | |||
| 42 | 0.613972165 seconds time elapsed | ||
| 43 | |||
| 44 | You can observe the statistical properties as well, by using the | ||
| 45 | 'repeat the workload N times' feature of perf stat: | ||
| 46 | |||
| 47 | titan:~> perf stat --repeat 5 -e kmem:mm_page_pcpu_drain -e | ||
| 48 | kmem:mm_page_alloc -e kmem:mm_pagevec_free -e | ||
| 49 | kmem:mm_page_free_direct ./hackbench 10 | ||
| 50 | Time: 0.627 | ||
| 51 | Time: 0.644 | ||
| 52 | Time: 0.564 | ||
| 53 | Time: 0.559 | ||
| 54 | Time: 0.626 | ||
| 55 | |||
| 56 | Performance counter stats for './hackbench 10' (5 runs): | ||
| 57 | |||
| 58 | 12920 kmem:mm_page_pcpu_drain ( +- 3.359% ) | ||
| 59 | 25035 kmem:mm_page_alloc ( +- 3.783% ) | ||
| 60 | 6104 kmem:mm_pagevec_free ( +- 0.934% ) | ||
| 61 | 18376 kmem:mm_page_free_direct ( +- 4.941% ) | ||
| 62 | |||
| 63 | 0.643954516 seconds time elapsed ( +- 2.363% ) | ||
| 64 | |||
| 65 | Furthermore, these tracepoints can be used to sample the workload as | ||
| 66 | well. For example the page allocations done by a 'git gc' can be | ||
| 67 | captured the following way: | ||
| 68 | |||
| 69 | titan:~/git> perf record -f -e kmem:mm_page_alloc -c 1 ./git gc | ||
| 70 | Counting objects: 1148, done. | ||
| 71 | Delta compression using up to 2 threads. | ||
| 72 | Compressing objects: 100% (450/450), done. | ||
| 73 | Writing objects: 100% (1148/1148), done. | ||
| 74 | Total 1148 (delta 690), reused 1148 (delta 690) | ||
| 75 | [ perf record: Captured and wrote 0.267 MB perf.data (~11679 samples) ] | ||
| 76 | |||
| 77 | To check which functions generated page allocations: | ||
| 78 | |||
| 79 | titan:~/git> perf report | ||
| 80 | # Samples: 10646 | ||
| 81 | # | ||
| 82 | # Overhead Command Shared Object | ||
| 83 | # ........ ............... .......................... | ||
| 84 | # | ||
| 85 | 23.57% git-repack /lib64/libc-2.5.so | ||
| 86 | 21.81% git /lib64/libc-2.5.so | ||
| 87 | 14.59% git ./git | ||
| 88 | 11.79% git-repack ./git | ||
| 89 | 7.12% git /lib64/ld-2.5.so | ||
| 90 | 3.16% git-repack /lib64/libpthread-2.5.so | ||
| 91 | 2.09% git-repack /bin/bash | ||
| 92 | 1.97% rm /lib64/libc-2.5.so | ||
| 93 | 1.39% mv /lib64/ld-2.5.so | ||
| 94 | 1.37% mv /lib64/libc-2.5.so | ||
| 95 | 1.12% git-repack /lib64/ld-2.5.so | ||
| 96 | 0.95% rm /lib64/ld-2.5.so | ||
| 97 | 0.90% git-update-serv /lib64/libc-2.5.so | ||
| 98 | 0.73% git-update-serv /lib64/ld-2.5.so | ||
| 99 | 0.68% perf /lib64/libpthread-2.5.so | ||
| 100 | 0.64% git-repack /usr/lib64/libz.so.1.2.3 | ||
| 101 | |||
| 102 | Or to see it on a more finegrained level: | ||
| 103 | |||
| 104 | titan:~/git> perf report --sort comm,dso,symbol | ||
| 105 | # Samples: 10646 | ||
| 106 | # | ||
| 107 | # Overhead Command Shared Object Symbol | ||
| 108 | # ........ ............... .......................... ...... | ||
| 109 | # | ||
| 110 | 9.35% git-repack ./git [.] insert_obj_hash | ||
| 111 | 9.12% git ./git [.] insert_obj_hash | ||
| 112 | 7.31% git /lib64/libc-2.5.so [.] memcpy | ||
| 113 | 6.34% git-repack /lib64/libc-2.5.so [.] _int_malloc | ||
| 114 | 6.24% git-repack /lib64/libc-2.5.so [.] memcpy | ||
| 115 | 5.82% git-repack /lib64/libc-2.5.so [.] __GI___fork | ||
| 116 | 5.47% git /lib64/libc-2.5.so [.] _int_malloc | ||
| 117 | 2.99% git /lib64/libc-2.5.so [.] memset | ||
| 118 | |||
| 119 | Furthermore, call-graph sampling can be done too, of page | ||
| 120 | allocations - to see precisely what kind of page allocations there | ||
| 121 | are: | ||
| 122 | |||
| 123 | titan:~/git> perf record -f -g -e kmem:mm_page_alloc -c 1 ./git gc | ||
| 124 | Counting objects: 1148, done. | ||
| 125 | Delta compression using up to 2 threads. | ||
| 126 | Compressing objects: 100% (450/450), done. | ||
| 127 | Writing objects: 100% (1148/1148), done. | ||
| 128 | Total 1148 (delta 690), reused 1148 (delta 690) | ||
| 129 | [ perf record: Captured and wrote 0.963 MB perf.data (~42069 samples) ] | ||
| 130 | |||
| 131 | titan:~/git> perf report -g | ||
| 132 | # Samples: 10686 | ||
| 133 | # | ||
| 134 | # Overhead Command Shared Object | ||
| 135 | # ........ ............... .......................... | ||
| 136 | # | ||
| 137 | 23.25% git-repack /lib64/libc-2.5.so | ||
| 138 | | | ||
| 139 | |--50.00%-- _int_free | ||
| 140 | | | ||
| 141 | |--37.50%-- __GI___fork | ||
| 142 | | make_child | ||
| 143 | | | ||
| 144 | |--12.50%-- ptmalloc_unlock_all2 | ||
| 145 | | make_child | ||
| 146 | | | ||
| 147 | --6.25%-- __GI_strcpy | ||
| 148 | 21.61% git /lib64/libc-2.5.so | ||
| 149 | | | ||
| 150 | |--30.00%-- __GI_read | ||
| 151 | | | | ||
| 152 | | --83.33%-- git_config_from_file | ||
| 153 | | git_config | ||
| 154 | | | | ||
| 155 | [...] | ||
| 156 | |||
| 157 | Or you can observe the whole system's page allocations for 10 | ||
| 158 | seconds: | ||
| 159 | |||
| 160 | titan:~/git> perf stat -a -e kmem:mm_page_pcpu_drain -e | ||
| 161 | kmem:mm_page_alloc -e kmem:mm_pagevec_free -e | ||
| 162 | kmem:mm_page_free_direct sleep 10 | ||
| 163 | |||
| 164 | Performance counter stats for 'sleep 10': | ||
| 165 | |||
| 166 | 171585 kmem:mm_page_pcpu_drain | ||
| 167 | 322114 kmem:mm_page_alloc | ||
| 168 | 73623 kmem:mm_pagevec_free | ||
| 169 | 254115 kmem:mm_page_free_direct | ||
| 170 | |||
| 171 | 10.000591410 seconds time elapsed | ||
| 172 | |||
| 173 | Or observe how fluctuating the page allocations are, via statistical | ||
| 174 | analysis done over ten 1-second intervals: | ||
| 175 | |||
| 176 | titan:~/git> perf stat --repeat 10 -a -e kmem:mm_page_pcpu_drain -e | ||
| 177 | kmem:mm_page_alloc -e kmem:mm_pagevec_free -e | ||
| 178 | kmem:mm_page_free_direct sleep 1 | ||
| 179 | |||
| 180 | Performance counter stats for 'sleep 1' (10 runs): | ||
| 181 | |||
| 182 | 17254 kmem:mm_page_pcpu_drain ( +- 3.709% ) | ||
| 183 | 34394 kmem:mm_page_alloc ( +- 4.617% ) | ||
| 184 | 7509 kmem:mm_pagevec_free ( +- 4.820% ) | ||
| 185 | 25653 kmem:mm_page_free_direct ( +- 3.672% ) | ||
| 186 | |||
| 187 | 1.058135029 seconds time elapsed ( +- 3.089% ) | ||
| 188 | |||
| 189 | Or you can annotate the recorded 'git gc' run on a per symbol basis | ||
| 190 | and check which instructions/source-code generated page allocations: | ||
| 191 | |||
| 192 | titan:~/git> perf annotate __GI___fork | ||
| 193 | ------------------------------------------------ | ||
| 194 | Percent | Source code & Disassembly of libc-2.5.so | ||
| 195 | ------------------------------------------------ | ||
| 196 | : | ||
| 197 | : | ||
| 198 | : Disassembly of section .plt: | ||
| 199 | : Disassembly of section .text: | ||
| 200 | : | ||
| 201 | : 00000031a2e95560 <__fork>: | ||
| 202 | [...] | ||
| 203 | 0.00 : 31a2e95602: b8 38 00 00 00 mov $0x38,%eax | ||
| 204 | 0.00 : 31a2e95607: 0f 05 syscall | ||
| 205 | 83.42 : 31a2e95609: 48 3d 00 f0 ff ff cmp $0xfffffffffffff000,%rax | ||
| 206 | 0.00 : 31a2e9560f: 0f 87 4d 01 00 00 ja 31a2e95762 <__fork+0x202> | ||
| 207 | 0.00 : 31a2e95615: 85 c0 test %eax,%eax | ||
| 208 | |||
| 209 | ( this shows that 83.42% of __GI___fork's page allocations come from | ||
| 210 | the 0x38 system call it performs. ) | ||
| 211 | |||
| 212 | etc. etc. - a lot more is possible. I could list a dozen of | ||
| 213 | other different usecases straight away - neither of which is | ||
| 214 | possible via /proc/vmstat. | ||
| 215 | |||
| 216 | /proc/vmstat is not in the same league really, in terms of | ||
| 217 | expressive power of system analysis and performance | ||
| 218 | analysis. | ||
| 219 | |||
| 220 | All that the above results needed were those new tracepoints | ||
| 221 | in include/tracing/events/kmem.h. | ||
| 222 | |||
| 223 | Ingo | ||
| 224 | |||
| 225 | |||
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index 0d74346d21ab..484080dd5b6f 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt | |||
| @@ -40,7 +40,7 @@ OPTIONS | |||
| 40 | -a:: | 40 | -a:: |
| 41 | system-wide collection | 41 | system-wide collection |
| 42 | 42 | ||
| 43 | -S:: | 43 | -c:: |
| 44 | scale counter values | 44 | scale counter values |
| 45 | 45 | ||
| 46 | EXAMPLES | 46 | EXAMPLES |
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt index 539d01289725..4a7d558dc309 100644 --- a/tools/perf/Documentation/perf-top.txt +++ b/tools/perf/Documentation/perf-top.txt | |||
| @@ -3,36 +3,122 @@ perf-top(1) | |||
| 3 | 3 | ||
| 4 | NAME | 4 | NAME |
| 5 | ---- | 5 | ---- |
| 6 | perf-top - Run a command and profile it | 6 | perf-top - System profiling tool. |
| 7 | 7 | ||
| 8 | SYNOPSIS | 8 | SYNOPSIS |
| 9 | -------- | 9 | -------- |
| 10 | [verse] | 10 | [verse] |
| 11 | 'perf top' [-e <EVENT> | --event=EVENT] [-l] [-a] <command> | 11 | 'perf top' [-e <EVENT> | --event=EVENT] [<options>] |
| 12 | 12 | ||
| 13 | DESCRIPTION | 13 | DESCRIPTION |
| 14 | ----------- | 14 | ----------- |
| 15 | This command runs a command and gathers a performance counter profile | 15 | This command generates and displays a performance counter profile in realtime. |
| 16 | from it. | ||
| 17 | 16 | ||
| 18 | 17 | ||
| 19 | OPTIONS | 18 | OPTIONS |
| 20 | ------- | 19 | ------- |
| 21 | <command>...:: | 20 | -a:: |
| 22 | Any command you can specify in a shell. | 21 | --all-cpus:: |
| 22 | System-wide collection. (default) | ||
| 23 | |||
| 24 | -c <count>:: | ||
| 25 | --count=<count>:: | ||
| 26 | Event period to sample. | ||
| 27 | |||
| 28 | -C <cpu>:: | ||
| 29 | --CPU=<cpu>:: | ||
| 30 | CPU to profile. | ||
| 31 | |||
| 32 | -d <seconds>:: | ||
| 33 | --delay=<seconds>:: | ||
| 34 | Number of seconds to delay between refreshes. | ||
| 23 | 35 | ||
| 24 | -e:: | 36 | -e <event>:: |
| 25 | --event=:: | 37 | --event=<event>:: |
| 26 | Select the PMU event. Selection can be a symbolic event name | 38 | Select the PMU event. Selection can be a symbolic event name |
| 27 | (use 'perf list' to list all events) or a raw PMU | 39 | (use 'perf list' to list all events) or a raw PMU |
| 28 | event (eventsel+umask) in the form of rNNN where NNN is a | 40 | event (eventsel+umask) in the form of rNNN where NNN is a |
| 29 | hexadecimal event descriptor. | 41 | hexadecimal event descriptor. |
| 30 | 42 | ||
| 31 | -a:: | 43 | -E <entries>:: |
| 32 | system-wide collection | 44 | --entries=<entries>:: |
| 45 | Display this many functions. | ||
| 46 | |||
| 47 | -f <count>:: | ||
| 48 | --count-filter=<count>:: | ||
| 49 | Only display functions with more events than this. | ||
| 50 | |||
| 51 | -F <freq>:: | ||
| 52 | --freq=<freq>:: | ||
| 53 | Profile at this frequency. | ||
| 54 | |||
| 55 | -i:: | ||
| 56 | --inherit:: | ||
| 57 | Child tasks inherit counters, only makes sens with -p option. | ||
| 58 | |||
| 59 | -k <path>:: | ||
| 60 | --vmlinux=<path>:: | ||
| 61 | Path to vmlinux. Required for annotation functionality. | ||
| 62 | |||
| 63 | -m <pages>:: | ||
| 64 | --mmap-pages=<pages>:: | ||
| 65 | Number of mmapped data pages. | ||
| 66 | |||
| 67 | -p <pid>:: | ||
| 68 | --pid=<pid>:: | ||
| 69 | Profile events on existing pid. | ||
| 70 | |||
| 71 | -r <priority>:: | ||
| 72 | --realtime=<priority>:: | ||
| 73 | Collect data with this RT SCHED_FIFO priority. | ||
| 74 | |||
| 75 | -s <symbol>:: | ||
| 76 | --sym-annotate=<symbol>:: | ||
| 77 | Annotate this symbol. Requires -k option. | ||
| 78 | |||
| 79 | -v:: | ||
| 80 | --verbose:: | ||
| 81 | Be more verbose (show counter open errors, etc). | ||
| 82 | |||
| 83 | -z:: | ||
| 84 | --zero:: | ||
| 85 | Zero history across display updates. | ||
| 86 | |||
| 87 | INTERACTIVE PROMPTING KEYS | ||
| 88 | -------------------------- | ||
| 89 | |||
| 90 | [d]:: | ||
| 91 | Display refresh delay. | ||
| 92 | |||
| 93 | [e]:: | ||
| 94 | Number of entries to display. | ||
| 95 | |||
| 96 | [E]:: | ||
| 97 | Event to display when multiple counters are active. | ||
| 98 | |||
| 99 | [f]:: | ||
| 100 | Profile display filter (>= hit count). | ||
| 101 | |||
| 102 | [F]:: | ||
| 103 | Annotation display filter (>= % of total). | ||
| 104 | |||
| 105 | [s]:: | ||
| 106 | Annotate symbol. | ||
| 107 | |||
| 108 | [S]:: | ||
| 109 | Stop annotation, return to full profile display. | ||
| 110 | |||
| 111 | [w]:: | ||
| 112 | Toggle between weighted sum and individual count[E]r profile. | ||
| 113 | |||
| 114 | [z]:: | ||
| 115 | Toggle event count zeroing across display updates. | ||
| 116 | |||
| 117 | [qQ]:: | ||
| 118 | Quit. | ||
| 119 | |||
| 120 | Pressing any unmapped key displays a menu, and prompts for input. | ||
| 33 | 121 | ||
| 34 | -l:: | ||
| 35 | scale counter values | ||
| 36 | 122 | ||
| 37 | SEE ALSO | 123 | SEE ALSO |
| 38 | -------- | 124 | -------- |
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 1916e44b9bb0..60411e94113b 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
| @@ -387,10 +387,14 @@ else | |||
| 387 | 387 | ||
| 388 | 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") | 388 | 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") |
| 389 | 389 | ||
| 390 | 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") | ||
| 391 | |||
| 390 | ifeq ($(has_bfd),y) | 392 | ifeq ($(has_bfd),y) |
| 391 | EXTLIBS += -lbfd | 393 | EXTLIBS += -lbfd |
| 392 | else ifeq ($(has_bfd_iberty),y) | 394 | else ifeq ($(has_bfd_iberty),y) |
| 393 | EXTLIBS += -lbfd -liberty | 395 | EXTLIBS += -lbfd -liberty |
| 396 | else ifeq ($(has_bfd_iberty_z),y) | ||
| 397 | EXTLIBS += -lbfd -liberty -lz | ||
| 394 | else | 398 | else |
| 395 | msg := $(warning No bfd.h/libbfd found, install binutils-dev[el] to gain symbol demangling) | 399 | msg := $(warning No bfd.h/libbfd found, install binutils-dev[el] to gain symbol demangling) |
| 396 | BASIC_CFLAGS += -DNO_DEMANGLE | 400 | BASIC_CFLAGS += -DNO_DEMANGLE |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 90c98082af10..0345aad8eba5 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
| @@ -525,10 +525,14 @@ static int __cmd_record(int argc, const char **argv) | |||
| 525 | signal(SIGCHLD, sig_handler); | 525 | signal(SIGCHLD, sig_handler); |
| 526 | signal(SIGINT, sig_handler); | 526 | signal(SIGINT, sig_handler); |
| 527 | 527 | ||
| 528 | if (!stat(output_name, &st) && !force && !append_file) { | 528 | if (!stat(output_name, &st) && st.st_size) { |
| 529 | fprintf(stderr, "Error, output file %s exists, use -A to append or -f to overwrite.\n", | 529 | if (!force && !append_file) { |
| 530 | output_name); | 530 | fprintf(stderr, "Error, output file %s exists, use -A to append or -f to overwrite.\n", |
| 531 | exit(-1); | 531 | output_name); |
| 532 | exit(-1); | ||
| 533 | } | ||
| 534 | } else { | ||
| 535 | append_file = 0; | ||
| 532 | } | 536 | } |
| 533 | 537 | ||
| 534 | flags = O_CREAT|O_RDWR; | 538 | flags = O_CREAT|O_RDWR; |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 8cb58d68a006..99274cec0adb 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
| @@ -68,7 +68,7 @@ static int callchain; | |||
| 68 | 68 | ||
| 69 | static | 69 | static |
| 70 | struct callchain_param callchain_param = { | 70 | struct callchain_param callchain_param = { |
| 71 | .mode = CHAIN_GRAPH_ABS, | 71 | .mode = CHAIN_GRAPH_REL, |
| 72 | .min_percent = 0.5 | 72 | .min_percent = 0.5 |
| 73 | }; | 73 | }; |
| 74 | 74 | ||
| @@ -112,7 +112,9 @@ struct read_event { | |||
| 112 | struct perf_event_header header; | 112 | struct perf_event_header header; |
| 113 | u32 pid,tid; | 113 | u32 pid,tid; |
| 114 | u64 value; | 114 | u64 value; |
| 115 | u64 format[3]; | 115 | u64 time_enabled; |
| 116 | u64 time_running; | ||
| 117 | u64 id; | ||
| 116 | }; | 118 | }; |
| 117 | 119 | ||
| 118 | typedef union event_union { | 120 | typedef union event_union { |
| @@ -698,7 +700,8 @@ sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used) | |||
| 698 | size_t ret = 0; | 700 | size_t ret = 0; |
| 699 | 701 | ||
| 700 | if (verbose) | 702 | if (verbose) |
| 701 | ret += repsep_fprintf(fp, "%#018llx ", (u64)self->ip); | 703 | ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip, |
| 704 | dso__symtab_origin(self->dso)); | ||
| 702 | 705 | ||
| 703 | ret += repsep_fprintf(fp, "[%c] ", self->level); | 706 | ret += repsep_fprintf(fp, "[%c] ", self->level); |
| 704 | if (self->sym) { | 707 | if (self->sym) { |
| @@ -888,6 +891,21 @@ ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth, | |||
| 888 | return ret; | 891 | return ret; |
| 889 | } | 892 | } |
| 890 | 893 | ||
| 894 | static struct symbol *rem_sq_bracket; | ||
| 895 | static struct callchain_list rem_hits; | ||
| 896 | |||
| 897 | static void init_rem_hits(void) | ||
| 898 | { | ||
| 899 | rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6); | ||
| 900 | if (!rem_sq_bracket) { | ||
| 901 | fprintf(stderr, "Not enough memory to display remaining hits\n"); | ||
| 902 | return; | ||
| 903 | } | ||
| 904 | |||
| 905 | strcpy(rem_sq_bracket->name, "[...]"); | ||
| 906 | rem_hits.sym = rem_sq_bracket; | ||
| 907 | } | ||
| 908 | |||
| 891 | static size_t | 909 | static size_t |
| 892 | callchain__fprintf_graph(FILE *fp, struct callchain_node *self, | 910 | callchain__fprintf_graph(FILE *fp, struct callchain_node *self, |
| 893 | u64 total_samples, int depth, int depth_mask) | 911 | u64 total_samples, int depth, int depth_mask) |
| @@ -897,25 +915,34 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self, | |||
| 897 | struct callchain_list *chain; | 915 | struct callchain_list *chain; |
| 898 | int new_depth_mask = depth_mask; | 916 | int new_depth_mask = depth_mask; |
| 899 | u64 new_total; | 917 | u64 new_total; |
| 918 | u64 remaining; | ||
| 900 | size_t ret = 0; | 919 | size_t ret = 0; |
| 901 | int i; | 920 | int i; |
| 902 | 921 | ||
| 903 | if (callchain_param.mode == CHAIN_GRAPH_REL) | 922 | if (callchain_param.mode == CHAIN_GRAPH_REL) |
| 904 | new_total = self->cumul_hit; | 923 | new_total = self->children_hit; |
| 905 | else | 924 | else |
| 906 | new_total = total_samples; | 925 | new_total = total_samples; |
| 907 | 926 | ||
| 927 | remaining = new_total; | ||
| 928 | |||
| 908 | node = rb_first(&self->rb_root); | 929 | node = rb_first(&self->rb_root); |
| 909 | while (node) { | 930 | while (node) { |
| 931 | u64 cumul; | ||
| 932 | |||
| 910 | child = rb_entry(node, struct callchain_node, rb_node); | 933 | child = rb_entry(node, struct callchain_node, rb_node); |
| 934 | cumul = cumul_hits(child); | ||
| 935 | remaining -= cumul; | ||
| 911 | 936 | ||
| 912 | /* | 937 | /* |
| 913 | * The depth mask manages the output of pipes that show | 938 | * The depth mask manages the output of pipes that show |
| 914 | * the depth. We don't want to keep the pipes of the current | 939 | * the depth. We don't want to keep the pipes of the current |
| 915 | * level for the last child of this depth | 940 | * level for the last child of this depth. |
| 941 | * Except if we have remaining filtered hits. They will | ||
| 942 | * supersede the last child | ||
| 916 | */ | 943 | */ |
| 917 | next = rb_next(node); | 944 | next = rb_next(node); |
| 918 | if (!next) | 945 | if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining)) |
| 919 | new_depth_mask &= ~(1 << (depth - 1)); | 946 | new_depth_mask &= ~(1 << (depth - 1)); |
| 920 | 947 | ||
| 921 | /* | 948 | /* |
| @@ -930,7 +957,7 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self, | |||
| 930 | ret += ipchain__fprintf_graph(fp, chain, depth, | 957 | ret += ipchain__fprintf_graph(fp, chain, depth, |
| 931 | new_depth_mask, i++, | 958 | new_depth_mask, i++, |
| 932 | new_total, | 959 | new_total, |
| 933 | child->cumul_hit); | 960 | cumul); |
| 934 | } | 961 | } |
| 935 | ret += callchain__fprintf_graph(fp, child, new_total, | 962 | ret += callchain__fprintf_graph(fp, child, new_total, |
| 936 | depth + 1, | 963 | depth + 1, |
| @@ -938,6 +965,19 @@ callchain__fprintf_graph(FILE *fp, struct callchain_node *self, | |||
| 938 | node = next; | 965 | node = next; |
| 939 | } | 966 | } |
| 940 | 967 | ||
| 968 | if (callchain_param.mode == CHAIN_GRAPH_REL && | ||
| 969 | remaining && remaining != new_total) { | ||
| 970 | |||
| 971 | if (!rem_sq_bracket) | ||
| 972 | return ret; | ||
| 973 | |||
| 974 | new_depth_mask &= ~(1 << (depth - 1)); | ||
| 975 | |||
| 976 | ret += ipchain__fprintf_graph(fp, &rem_hits, depth, | ||
| 977 | new_depth_mask, 0, new_total, | ||
| 978 | remaining); | ||
| 979 | } | ||
| 980 | |||
| 941 | return ret; | 981 | return ret; |
| 942 | } | 982 | } |
| 943 | 983 | ||
| @@ -1358,6 +1398,8 @@ static size_t output__fprintf(FILE *fp, u64 total_samples) | |||
| 1358 | unsigned int width; | 1398 | unsigned int width; |
| 1359 | char *col_width = col_width_list_str; | 1399 | char *col_width = col_width_list_str; |
| 1360 | 1400 | ||
| 1401 | init_rem_hits(); | ||
| 1402 | |||
| 1361 | fprintf(fp, "# Samples: %Ld\n", (u64)total_samples); | 1403 | fprintf(fp, "# Samples: %Ld\n", (u64)total_samples); |
| 1362 | fprintf(fp, "#\n"); | 1404 | fprintf(fp, "#\n"); |
| 1363 | 1405 | ||
| @@ -1429,6 +1471,8 @@ print_entries: | |||
| 1429 | } | 1471 | } |
| 1430 | fprintf(fp, "\n"); | 1472 | fprintf(fp, "\n"); |
| 1431 | 1473 | ||
| 1474 | free(rem_sq_bracket); | ||
| 1475 | |||
| 1432 | return ret; | 1476 | return ret; |
| 1433 | } | 1477 | } |
| 1434 | 1478 | ||
| @@ -1690,14 +1734,37 @@ static void trace_event(event_t *event) | |||
| 1690 | dprintf(".\n"); | 1734 | dprintf(".\n"); |
| 1691 | } | 1735 | } |
| 1692 | 1736 | ||
| 1737 | static struct perf_header *header; | ||
| 1738 | |||
| 1739 | static struct perf_counter_attr *perf_header__find_attr(u64 id) | ||
| 1740 | { | ||
| 1741 | int i; | ||
| 1742 | |||
| 1743 | for (i = 0; i < header->attrs; i++) { | ||
| 1744 | struct perf_header_attr *attr = header->attr[i]; | ||
| 1745 | int j; | ||
| 1746 | |||
| 1747 | for (j = 0; j < attr->ids; j++) { | ||
| 1748 | if (attr->id[j] == id) | ||
| 1749 | return &attr->attr; | ||
| 1750 | } | ||
| 1751 | } | ||
| 1752 | |||
| 1753 | return NULL; | ||
| 1754 | } | ||
| 1755 | |||
| 1693 | static int | 1756 | static int |
| 1694 | process_read_event(event_t *event, unsigned long offset, unsigned long head) | 1757 | process_read_event(event_t *event, unsigned long offset, unsigned long head) |
| 1695 | { | 1758 | { |
| 1696 | dprintf("%p [%p]: PERF_EVENT_READ: %d %d %Lu\n", | 1759 | struct perf_counter_attr *attr = perf_header__find_attr(event->read.id); |
| 1760 | |||
| 1761 | dprintf("%p [%p]: PERF_EVENT_READ: %d %d %s %Lu\n", | ||
| 1697 | (void *)(offset + head), | 1762 | (void *)(offset + head), |
| 1698 | (void *)(long)(event->header.size), | 1763 | (void *)(long)(event->header.size), |
| 1699 | event->read.pid, | 1764 | event->read.pid, |
| 1700 | event->read.tid, | 1765 | event->read.tid, |
| 1766 | attr ? __event_name(attr->type, attr->config) | ||
| 1767 | : "FAIL", | ||
| 1701 | event->read.value); | 1768 | event->read.value); |
| 1702 | 1769 | ||
| 1703 | return 0; | 1770 | return 0; |
| @@ -1743,8 +1810,6 @@ process_event(event_t *event, unsigned long offset, unsigned long head) | |||
| 1743 | return 0; | 1810 | return 0; |
| 1744 | } | 1811 | } |
| 1745 | 1812 | ||
| 1746 | static struct perf_header *header; | ||
| 1747 | |||
| 1748 | static u64 perf_header__sample_type(void) | 1813 | static u64 perf_header__sample_type(void) |
| 1749 | { | 1814 | { |
| 1750 | u64 sample_type = 0; | 1815 | u64 sample_type = 0; |
| @@ -1812,6 +1877,13 @@ static int __cmd_report(void) | |||
| 1812 | " -g?\n"); | 1877 | " -g?\n"); |
| 1813 | exit(-1); | 1878 | exit(-1); |
| 1814 | } | 1879 | } |
| 1880 | } else if (callchain_param.mode != CHAIN_NONE && !callchain) { | ||
| 1881 | callchain = 1; | ||
| 1882 | if (register_callchain_param(&callchain_param) < 0) { | ||
| 1883 | fprintf(stderr, "Can't register callchain" | ||
| 1884 | " params\n"); | ||
| 1885 | exit(-1); | ||
| 1886 | } | ||
| 1815 | } | 1887 | } |
| 1816 | 1888 | ||
| 1817 | if (load_kernel() < 0) { | 1889 | if (load_kernel() < 0) { |
| @@ -1950,6 +2022,13 @@ parse_callchain_opt(const struct option *opt __used, const char *arg, | |||
| 1950 | else if (!strncmp(tok, "fractal", strlen(arg))) | 2022 | else if (!strncmp(tok, "fractal", strlen(arg))) |
| 1951 | callchain_param.mode = CHAIN_GRAPH_REL; | 2023 | callchain_param.mode = CHAIN_GRAPH_REL; |
| 1952 | 2024 | ||
| 2025 | else if (!strncmp(tok, "none", strlen(arg))) { | ||
| 2026 | callchain_param.mode = CHAIN_NONE; | ||
| 2027 | callchain = 0; | ||
| 2028 | |||
| 2029 | return 0; | ||
| 2030 | } | ||
| 2031 | |||
| 1953 | else | 2032 | else |
| 1954 | return -1; | 2033 | return -1; |
| 1955 | 2034 | ||
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index f9510eeeb6c7..b4b06c7903e1 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
| @@ -496,7 +496,7 @@ static const struct option options[] = { | |||
| 496 | "stat events on existing pid"), | 496 | "stat events on existing pid"), |
| 497 | OPT_BOOLEAN('a', "all-cpus", &system_wide, | 497 | OPT_BOOLEAN('a', "all-cpus", &system_wide, |
| 498 | "system-wide collection from all CPUs"), | 498 | "system-wide collection from all CPUs"), |
| 499 | OPT_BOOLEAN('S', "scale", &scale, | 499 | OPT_BOOLEAN('c', "scale", &scale, |
| 500 | "scale/normalize counters"), | 500 | "scale/normalize counters"), |
| 501 | OPT_BOOLEAN('v', "verbose", &verbose, | 501 | OPT_BOOLEAN('v', "verbose", &verbose, |
| 502 | "be more verbose (show counter open errors, etc)"), | 502 | "be more verbose (show counter open errors, etc)"), |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index f139f1ab9333..7de28ce9ca26 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
| @@ -31,6 +31,8 @@ | |||
| 31 | #include <fcntl.h> | 31 | #include <fcntl.h> |
| 32 | 32 | ||
| 33 | #include <stdio.h> | 33 | #include <stdio.h> |
| 34 | #include <termios.h> | ||
| 35 | #include <unistd.h> | ||
| 34 | 36 | ||
| 35 | #include <errno.h> | 37 | #include <errno.h> |
| 36 | #include <time.h> | 38 | #include <time.h> |
| @@ -54,7 +56,7 @@ static int system_wide = 0; | |||
| 54 | 56 | ||
| 55 | static int default_interval = 100000; | 57 | static int default_interval = 100000; |
| 56 | 58 | ||
| 57 | static u64 count_filter = 5; | 59 | static int count_filter = 5; |
| 58 | static int print_entries = 15; | 60 | static int print_entries = 15; |
| 59 | 61 | ||
| 60 | static int target_pid = -1; | 62 | static int target_pid = -1; |
| @@ -69,15 +71,28 @@ static int freq = 0; | |||
| 69 | static int verbose = 0; | 71 | static int verbose = 0; |
| 70 | static char *vmlinux = NULL; | 72 | static char *vmlinux = NULL; |
| 71 | 73 | ||
| 72 | static char *sym_filter; | ||
| 73 | static unsigned long filter_start; | ||
| 74 | static unsigned long filter_end; | ||
| 75 | |||
| 76 | static int delay_secs = 2; | 74 | static int delay_secs = 2; |
| 77 | static int zero; | 75 | static int zero; |
| 78 | static int dump_symtab; | 76 | static int dump_symtab; |
| 79 | 77 | ||
| 80 | /* | 78 | /* |
| 79 | * Source | ||
| 80 | */ | ||
| 81 | |||
| 82 | struct source_line { | ||
| 83 | u64 eip; | ||
| 84 | unsigned long count[MAX_COUNTERS]; | ||
| 85 | char *line; | ||
| 86 | struct source_line *next; | ||
| 87 | }; | ||
| 88 | |||
| 89 | static char *sym_filter = NULL; | ||
| 90 | struct sym_entry *sym_filter_entry = NULL; | ||
| 91 | static int sym_pcnt_filter = 5; | ||
| 92 | static int sym_counter = 0; | ||
| 93 | static int display_weighted = -1; | ||
| 94 | |||
| 95 | /* | ||
| 81 | * Symbols | 96 | * Symbols |
| 82 | */ | 97 | */ |
| 83 | 98 | ||
| @@ -91,9 +106,237 @@ struct sym_entry { | |||
| 91 | unsigned long snap_count; | 106 | unsigned long snap_count; |
| 92 | double weight; | 107 | double weight; |
| 93 | int skip; | 108 | int skip; |
| 109 | struct source_line *source; | ||
| 110 | struct source_line *lines; | ||
| 111 | struct source_line **lines_tail; | ||
| 112 | pthread_mutex_t source_lock; | ||
| 94 | }; | 113 | }; |
| 95 | 114 | ||
| 96 | struct sym_entry *sym_filter_entry; | 115 | /* |
| 116 | * Source functions | ||
| 117 | */ | ||
| 118 | |||
| 119 | static void parse_source(struct sym_entry *syme) | ||
| 120 | { | ||
| 121 | struct symbol *sym; | ||
| 122 | struct module *module; | ||
| 123 | struct section *section = NULL; | ||
| 124 | FILE *file; | ||
| 125 | char command[PATH_MAX*2], *path = vmlinux; | ||
| 126 | u64 start, end, len; | ||
| 127 | |||
| 128 | if (!syme) | ||
| 129 | return; | ||
| 130 | |||
| 131 | if (syme->lines) { | ||
| 132 | pthread_mutex_lock(&syme->source_lock); | ||
| 133 | goto out_assign; | ||
| 134 | } | ||
| 135 | |||
| 136 | sym = (struct symbol *)(syme + 1); | ||
| 137 | module = sym->module; | ||
| 138 | |||
| 139 | if (module) | ||
| 140 | path = module->path; | ||
| 141 | if (!path) | ||
| 142 | return; | ||
| 143 | |||
| 144 | start = sym->obj_start; | ||
| 145 | if (!start) | ||
| 146 | start = sym->start; | ||
| 147 | |||
| 148 | if (module) { | ||
| 149 | section = module->sections->find_section(module->sections, ".text"); | ||
| 150 | if (section) | ||
| 151 | start -= section->vma; | ||
| 152 | } | ||
| 153 | |||
| 154 | end = start + sym->end - sym->start + 1; | ||
| 155 | len = sym->end - sym->start; | ||
| 156 | |||
| 157 | sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", start, end, path); | ||
| 158 | |||
| 159 | file = popen(command, "r"); | ||
| 160 | if (!file) | ||
| 161 | return; | ||
| 162 | |||
| 163 | pthread_mutex_lock(&syme->source_lock); | ||
| 164 | syme->lines_tail = &syme->lines; | ||
| 165 | while (!feof(file)) { | ||
| 166 | struct source_line *src; | ||
| 167 | size_t dummy = 0; | ||
| 168 | char *c; | ||
| 169 | |||
| 170 | src = malloc(sizeof(struct source_line)); | ||
| 171 | assert(src != NULL); | ||
| 172 | memset(src, 0, sizeof(struct source_line)); | ||
| 173 | |||
| 174 | if (getline(&src->line, &dummy, file) < 0) | ||
| 175 | break; | ||
| 176 | if (!src->line) | ||
| 177 | break; | ||
| 178 | |||
| 179 | c = strchr(src->line, '\n'); | ||
| 180 | if (c) | ||
| 181 | *c = 0; | ||
| 182 | |||
| 183 | src->next = NULL; | ||
| 184 | *syme->lines_tail = src; | ||
| 185 | syme->lines_tail = &src->next; | ||
| 186 | |||
| 187 | if (strlen(src->line)>8 && src->line[8] == ':') { | ||
| 188 | src->eip = strtoull(src->line, NULL, 16); | ||
| 189 | if (section) | ||
| 190 | src->eip += section->vma; | ||
| 191 | } | ||
| 192 | if (strlen(src->line)>8 && src->line[16] == ':') { | ||
| 193 | src->eip = strtoull(src->line, NULL, 16); | ||
| 194 | if (section) | ||
| 195 | src->eip += section->vma; | ||
| 196 | } | ||
| 197 | } | ||
| 198 | pclose(file); | ||
| 199 | out_assign: | ||
| 200 | sym_filter_entry = syme; | ||
| 201 | pthread_mutex_unlock(&syme->source_lock); | ||
| 202 | } | ||
| 203 | |||
| 204 | static void __zero_source_counters(struct sym_entry *syme) | ||
| 205 | { | ||
| 206 | int i; | ||
| 207 | struct source_line *line; | ||
| 208 | |||
| 209 | line = syme->lines; | ||
| 210 | while (line) { | ||
| 211 | for (i = 0; i < nr_counters; i++) | ||
| 212 | line->count[i] = 0; | ||
| 213 | line = line->next; | ||
| 214 | } | ||
| 215 | } | ||
| 216 | |||
| 217 | static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip) | ||
| 218 | { | ||
| 219 | struct source_line *line; | ||
| 220 | |||
| 221 | if (syme != sym_filter_entry) | ||
| 222 | return; | ||
| 223 | |||
| 224 | if (pthread_mutex_trylock(&syme->source_lock)) | ||
| 225 | return; | ||
| 226 | |||
| 227 | if (!syme->source) | ||
| 228 | goto out_unlock; | ||
| 229 | |||
| 230 | for (line = syme->lines; line; line = line->next) { | ||
| 231 | if (line->eip == ip) { | ||
| 232 | line->count[counter]++; | ||
| 233 | break; | ||
| 234 | } | ||
| 235 | if (line->eip > ip) | ||
| 236 | break; | ||
| 237 | } | ||
| 238 | out_unlock: | ||
| 239 | pthread_mutex_unlock(&syme->source_lock); | ||
| 240 | } | ||
| 241 | |||
| 242 | static void lookup_sym_source(struct sym_entry *syme) | ||
| 243 | { | ||
| 244 | struct symbol *symbol = (struct symbol *)(syme + 1); | ||
| 245 | struct source_line *line; | ||
| 246 | char pattern[PATH_MAX]; | ||
| 247 | char *idx; | ||
| 248 | |||
| 249 | sprintf(pattern, "<%s>:", symbol->name); | ||
| 250 | |||
| 251 | if (symbol->module) { | ||
| 252 | idx = strstr(pattern, "\t"); | ||
| 253 | if (idx) | ||
| 254 | *idx = 0; | ||
| 255 | } | ||
| 256 | |||
| 257 | pthread_mutex_lock(&syme->source_lock); | ||
| 258 | for (line = syme->lines; line; line = line->next) { | ||
| 259 | if (strstr(line->line, pattern)) { | ||
| 260 | syme->source = line; | ||
| 261 | break; | ||
| 262 | } | ||
| 263 | } | ||
| 264 | pthread_mutex_unlock(&syme->source_lock); | ||
| 265 | } | ||
| 266 | |||
| 267 | static void show_lines(struct source_line *queue, int count, int total) | ||
| 268 | { | ||
| 269 | int i; | ||
| 270 | struct source_line *line; | ||
| 271 | |||
| 272 | line = queue; | ||
| 273 | for (i = 0; i < count; i++) { | ||
| 274 | float pcnt = 100.0*(float)line->count[sym_counter]/(float)total; | ||
| 275 | |||
| 276 | printf("%8li %4.1f%%\t%s\n", line->count[sym_counter], pcnt, line->line); | ||
| 277 | line = line->next; | ||
| 278 | } | ||
| 279 | } | ||
| 280 | |||
| 281 | #define TRACE_COUNT 3 | ||
| 282 | |||
| 283 | static void show_details(struct sym_entry *syme) | ||
| 284 | { | ||
| 285 | struct symbol *symbol; | ||
| 286 | struct source_line *line; | ||
| 287 | struct source_line *line_queue = NULL; | ||
| 288 | int displayed = 0; | ||
| 289 | int line_queue_count = 0, total = 0, more = 0; | ||
| 290 | |||
| 291 | if (!syme) | ||
| 292 | return; | ||
| 293 | |||
| 294 | if (!syme->source) | ||
| 295 | lookup_sym_source(syme); | ||
| 296 | |||
| 297 | if (!syme->source) | ||
| 298 | return; | ||
| 299 | |||
| 300 | symbol = (struct symbol *)(syme + 1); | ||
| 301 | printf("Showing %s for %s\n", event_name(sym_counter), symbol->name); | ||
| 302 | printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter); | ||
| 303 | |||
| 304 | pthread_mutex_lock(&syme->source_lock); | ||
| 305 | line = syme->source; | ||
| 306 | while (line) { | ||
| 307 | total += line->count[sym_counter]; | ||
| 308 | line = line->next; | ||
| 309 | } | ||
| 310 | |||
| 311 | line = syme->source; | ||
| 312 | while (line) { | ||
| 313 | float pcnt = 0.0; | ||
| 314 | |||
| 315 | if (!line_queue_count) | ||
| 316 | line_queue = line; | ||
| 317 | line_queue_count++; | ||
| 318 | |||
| 319 | if (line->count[sym_counter]) | ||
| 320 | pcnt = 100.0 * line->count[sym_counter] / (float)total; | ||
| 321 | if (pcnt >= (float)sym_pcnt_filter) { | ||
| 322 | if (displayed <= print_entries) | ||
| 323 | show_lines(line_queue, line_queue_count, total); | ||
| 324 | else more++; | ||
| 325 | displayed += line_queue_count; | ||
| 326 | line_queue_count = 0; | ||
| 327 | line_queue = NULL; | ||
| 328 | } else if (line_queue_count > TRACE_COUNT) { | ||
| 329 | line_queue = line_queue->next; | ||
| 330 | line_queue_count--; | ||
| 331 | } | ||
| 332 | |||
| 333 | line->count[sym_counter] = zero ? 0 : line->count[sym_counter] * 7 / 8; | ||
| 334 | line = line->next; | ||
| 335 | } | ||
| 336 | pthread_mutex_unlock(&syme->source_lock); | ||
| 337 | if (more) | ||
| 338 | printf("%d lines not displayed, maybe increase display entries [e]\n", more); | ||
| 339 | } | ||
| 97 | 340 | ||
| 98 | struct dso *kernel_dso; | 341 | struct dso *kernel_dso; |
| 99 | 342 | ||
| @@ -112,6 +355,9 @@ static double sym_weight(const struct sym_entry *sym) | |||
| 112 | double weight = sym->snap_count; | 355 | double weight = sym->snap_count; |
| 113 | int counter; | 356 | int counter; |
| 114 | 357 | ||
| 358 | if (!display_weighted) | ||
| 359 | return weight; | ||
| 360 | |||
| 115 | for (counter = 1; counter < nr_counters-1; counter++) | 361 | for (counter = 1; counter < nr_counters-1; counter++) |
| 116 | weight *= sym->count[counter]; | 362 | weight *= sym->count[counter]; |
| 117 | 363 | ||
| @@ -159,7 +405,7 @@ static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se) | |||
| 159 | static void print_sym_table(void) | 405 | static void print_sym_table(void) |
| 160 | { | 406 | { |
| 161 | int printed = 0, j; | 407 | int printed = 0, j; |
| 162 | int counter; | 408 | int counter, snap = !display_weighted ? sym_counter : 0; |
| 163 | float samples_per_sec = samples/delay_secs; | 409 | float samples_per_sec = samples/delay_secs; |
| 164 | float ksamples_per_sec = (samples-userspace_samples)/delay_secs; | 410 | float ksamples_per_sec = (samples-userspace_samples)/delay_secs; |
| 165 | float sum_ksamples = 0.0; | 411 | float sum_ksamples = 0.0; |
| @@ -175,7 +421,7 @@ static void print_sym_table(void) | |||
| 175 | pthread_mutex_unlock(&active_symbols_lock); | 421 | pthread_mutex_unlock(&active_symbols_lock); |
| 176 | 422 | ||
| 177 | list_for_each_entry_safe_from(syme, n, &active_symbols, node) { | 423 | list_for_each_entry_safe_from(syme, n, &active_symbols, node) { |
| 178 | syme->snap_count = syme->count[0]; | 424 | syme->snap_count = syme->count[snap]; |
| 179 | if (syme->snap_count != 0) { | 425 | if (syme->snap_count != 0) { |
| 180 | syme->weight = sym_weight(syme); | 426 | syme->weight = sym_weight(syme); |
| 181 | rb_insert_active_sym(&tmp, syme); | 427 | rb_insert_active_sym(&tmp, syme); |
| @@ -195,7 +441,7 @@ static void print_sym_table(void) | |||
| 195 | samples_per_sec, | 441 | samples_per_sec, |
| 196 | 100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec))); | 442 | 100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec))); |
| 197 | 443 | ||
| 198 | if (nr_counters == 1) { | 444 | if (nr_counters == 1 || !display_weighted) { |
| 199 | printf("%Ld", (u64)attrs[0].sample_period); | 445 | printf("%Ld", (u64)attrs[0].sample_period); |
| 200 | if (freq) | 446 | if (freq) |
| 201 | printf("Hz "); | 447 | printf("Hz "); |
| @@ -203,7 +449,9 @@ static void print_sym_table(void) | |||
| 203 | printf(" "); | 449 | printf(" "); |
| 204 | } | 450 | } |
| 205 | 451 | ||
| 206 | for (counter = 0; counter < nr_counters; counter++) { | 452 | if (!display_weighted) |
| 453 | printf("%s", event_name(sym_counter)); | ||
| 454 | else for (counter = 0; counter < nr_counters; counter++) { | ||
| 207 | if (counter) | 455 | if (counter) |
| 208 | printf("/"); | 456 | printf("/"); |
| 209 | 457 | ||
| @@ -228,6 +476,11 @@ static void print_sym_table(void) | |||
| 228 | 476 | ||
| 229 | printf("------------------------------------------------------------------------------\n\n"); | 477 | printf("------------------------------------------------------------------------------\n\n"); |
| 230 | 478 | ||
| 479 | if (sym_filter_entry) { | ||
| 480 | show_details(sym_filter_entry); | ||
| 481 | return; | ||
| 482 | } | ||
| 483 | |||
| 231 | if (nr_counters == 1) | 484 | if (nr_counters == 1) |
| 232 | printf(" samples pcnt"); | 485 | printf(" samples pcnt"); |
| 233 | else | 486 | else |
| @@ -242,13 +495,13 @@ static void print_sym_table(void) | |||
| 242 | struct symbol *sym = (struct symbol *)(syme + 1); | 495 | struct symbol *sym = (struct symbol *)(syme + 1); |
| 243 | double pcnt; | 496 | double pcnt; |
| 244 | 497 | ||
| 245 | if (++printed > print_entries || syme->snap_count < count_filter) | 498 | if (++printed > print_entries || (int)syme->snap_count < count_filter) |
| 246 | continue; | 499 | continue; |
| 247 | 500 | ||
| 248 | pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) / | 501 | pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) / |
| 249 | sum_ksamples)); | 502 | sum_ksamples)); |
| 250 | 503 | ||
| 251 | if (nr_counters == 1) | 504 | if (nr_counters == 1 || !display_weighted) |
| 252 | printf("%20.2f - ", syme->weight); | 505 | printf("%20.2f - ", syme->weight); |
| 253 | else | 506 | else |
| 254 | printf("%9.1f %10ld - ", syme->weight, syme->snap_count); | 507 | printf("%9.1f %10ld - ", syme->weight, syme->snap_count); |
| @@ -261,19 +514,250 @@ static void print_sym_table(void) | |||
| 261 | } | 514 | } |
| 262 | } | 515 | } |
| 263 | 516 | ||
| 517 | static void prompt_integer(int *target, const char *msg) | ||
| 518 | { | ||
| 519 | char *buf = malloc(0), *p; | ||
| 520 | size_t dummy = 0; | ||
| 521 | int tmp; | ||
| 522 | |||
| 523 | fprintf(stdout, "\n%s: ", msg); | ||
| 524 | if (getline(&buf, &dummy, stdin) < 0) | ||
| 525 | return; | ||
| 526 | |||
| 527 | p = strchr(buf, '\n'); | ||
| 528 | if (p) | ||
| 529 | *p = 0; | ||
| 530 | |||
| 531 | p = buf; | ||
| 532 | while(*p) { | ||
| 533 | if (!isdigit(*p)) | ||
| 534 | goto out_free; | ||
| 535 | p++; | ||
| 536 | } | ||
| 537 | tmp = strtoul(buf, NULL, 10); | ||
| 538 | *target = tmp; | ||
| 539 | out_free: | ||
| 540 | free(buf); | ||
| 541 | } | ||
| 542 | |||
| 543 | static void prompt_percent(int *target, const char *msg) | ||
| 544 | { | ||
| 545 | int tmp = 0; | ||
| 546 | |||
| 547 | prompt_integer(&tmp, msg); | ||
| 548 | if (tmp >= 0 && tmp <= 100) | ||
| 549 | *target = tmp; | ||
| 550 | } | ||
| 551 | |||
| 552 | static void prompt_symbol(struct sym_entry **target, const char *msg) | ||
| 553 | { | ||
| 554 | char *buf = malloc(0), *p; | ||
| 555 | struct sym_entry *syme = *target, *n, *found = NULL; | ||
| 556 | size_t dummy = 0; | ||
| 557 | |||
| 558 | /* zero counters of active symbol */ | ||
| 559 | if (syme) { | ||
| 560 | pthread_mutex_lock(&syme->source_lock); | ||
| 561 | __zero_source_counters(syme); | ||
| 562 | *target = NULL; | ||
| 563 | pthread_mutex_unlock(&syme->source_lock); | ||
| 564 | } | ||
| 565 | |||
| 566 | fprintf(stdout, "\n%s: ", msg); | ||
| 567 | if (getline(&buf, &dummy, stdin) < 0) | ||
| 568 | goto out_free; | ||
| 569 | |||
| 570 | p = strchr(buf, '\n'); | ||
| 571 | if (p) | ||
| 572 | *p = 0; | ||
| 573 | |||
| 574 | pthread_mutex_lock(&active_symbols_lock); | ||
| 575 | syme = list_entry(active_symbols.next, struct sym_entry, node); | ||
| 576 | pthread_mutex_unlock(&active_symbols_lock); | ||
| 577 | |||
| 578 | list_for_each_entry_safe_from(syme, n, &active_symbols, node) { | ||
| 579 | struct symbol *sym = (struct symbol *)(syme + 1); | ||
| 580 | |||
| 581 | if (!strcmp(buf, sym->name)) { | ||
| 582 | found = syme; | ||
| 583 | break; | ||
| 584 | } | ||
| 585 | } | ||
| 586 | |||
| 587 | if (!found) { | ||
| 588 | fprintf(stderr, "Sorry, %s is not active.\n", sym_filter); | ||
| 589 | sleep(1); | ||
| 590 | return; | ||
| 591 | } else | ||
| 592 | parse_source(found); | ||
| 593 | |||
| 594 | out_free: | ||
| 595 | free(buf); | ||
| 596 | } | ||
| 597 | |||
| 598 | static void print_mapped_keys(void) | ||
| 599 | { | ||
| 600 | char *name = NULL; | ||
| 601 | |||
| 602 | if (sym_filter_entry) { | ||
| 603 | struct symbol *sym = (struct symbol *)(sym_filter_entry+1); | ||
| 604 | name = sym->name; | ||
| 605 | } | ||
| 606 | |||
| 607 | fprintf(stdout, "\nMapped keys:\n"); | ||
| 608 | fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", delay_secs); | ||
| 609 | fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", print_entries); | ||
| 610 | |||
| 611 | if (nr_counters > 1) | ||
| 612 | fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(sym_counter)); | ||
| 613 | |||
| 614 | fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter); | ||
| 615 | |||
| 616 | if (vmlinux) { | ||
| 617 | fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter); | ||
| 618 | fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); | ||
| 619 | fprintf(stdout, "\t[S] stop annotation.\n"); | ||
| 620 | } | ||
| 621 | |||
| 622 | if (nr_counters > 1) | ||
| 623 | fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0); | ||
| 624 | |||
| 625 | fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", zero ? 1 : 0); | ||
| 626 | fprintf(stdout, "\t[qQ] quit.\n"); | ||
| 627 | } | ||
| 628 | |||
| 629 | static int key_mapped(int c) | ||
| 630 | { | ||
| 631 | switch (c) { | ||
| 632 | case 'd': | ||
| 633 | case 'e': | ||
| 634 | case 'f': | ||
| 635 | case 'z': | ||
| 636 | case 'q': | ||
| 637 | case 'Q': | ||
| 638 | return 1; | ||
| 639 | case 'E': | ||
| 640 | case 'w': | ||
| 641 | return nr_counters > 1 ? 1 : 0; | ||
| 642 | case 'F': | ||
| 643 | case 's': | ||
| 644 | case 'S': | ||
| 645 | return vmlinux ? 1 : 0; | ||
| 646 | } | ||
| 647 | |||
| 648 | return 0; | ||
| 649 | } | ||
| 650 | |||
| 651 | static void handle_keypress(int c) | ||
| 652 | { | ||
| 653 | if (!key_mapped(c)) { | ||
| 654 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; | ||
| 655 | struct termios tc, save; | ||
| 656 | |||
| 657 | print_mapped_keys(); | ||
| 658 | fprintf(stdout, "\nEnter selection, or unmapped key to continue: "); | ||
| 659 | fflush(stdout); | ||
| 660 | |||
| 661 | tcgetattr(0, &save); | ||
| 662 | tc = save; | ||
| 663 | tc.c_lflag &= ~(ICANON | ECHO); | ||
| 664 | tc.c_cc[VMIN] = 0; | ||
| 665 | tc.c_cc[VTIME] = 0; | ||
| 666 | tcsetattr(0, TCSANOW, &tc); | ||
| 667 | |||
| 668 | poll(&stdin_poll, 1, -1); | ||
| 669 | c = getc(stdin); | ||
| 670 | |||
| 671 | tcsetattr(0, TCSAFLUSH, &save); | ||
| 672 | if (!key_mapped(c)) | ||
| 673 | return; | ||
| 674 | } | ||
| 675 | |||
| 676 | switch (c) { | ||
| 677 | case 'd': | ||
| 678 | prompt_integer(&delay_secs, "Enter display delay"); | ||
| 679 | break; | ||
| 680 | case 'e': | ||
| 681 | prompt_integer(&print_entries, "Enter display entries (lines)"); | ||
| 682 | break; | ||
| 683 | case 'E': | ||
| 684 | if (nr_counters > 1) { | ||
| 685 | int i; | ||
| 686 | |||
| 687 | fprintf(stderr, "\nAvailable events:"); | ||
| 688 | for (i = 0; i < nr_counters; i++) | ||
| 689 | fprintf(stderr, "\n\t%d %s", i, event_name(i)); | ||
| 690 | |||
| 691 | prompt_integer(&sym_counter, "Enter details event counter"); | ||
| 692 | |||
| 693 | if (sym_counter >= nr_counters) { | ||
| 694 | fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(0)); | ||
| 695 | sym_counter = 0; | ||
| 696 | sleep(1); | ||
| 697 | } | ||
| 698 | } else sym_counter = 0; | ||
| 699 | break; | ||
| 700 | case 'f': | ||
| 701 | prompt_integer(&count_filter, "Enter display event count filter"); | ||
| 702 | break; | ||
| 703 | case 'F': | ||
| 704 | prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)"); | ||
| 705 | break; | ||
| 706 | case 'q': | ||
| 707 | case 'Q': | ||
| 708 | printf("exiting.\n"); | ||
| 709 | exit(0); | ||
| 710 | case 's': | ||
| 711 | prompt_symbol(&sym_filter_entry, "Enter details symbol"); | ||
| 712 | break; | ||
| 713 | case 'S': | ||
| 714 | if (!sym_filter_entry) | ||
| 715 | break; | ||
| 716 | else { | ||
| 717 | struct sym_entry *syme = sym_filter_entry; | ||
| 718 | |||
| 719 | pthread_mutex_lock(&syme->source_lock); | ||
| 720 | sym_filter_entry = NULL; | ||
| 721 | __zero_source_counters(syme); | ||
| 722 | pthread_mutex_unlock(&syme->source_lock); | ||
| 723 | } | ||
| 724 | break; | ||
| 725 | case 'w': | ||
| 726 | display_weighted = ~display_weighted; | ||
| 727 | break; | ||
| 728 | case 'z': | ||
| 729 | zero = ~zero; | ||
| 730 | break; | ||
| 731 | } | ||
| 732 | } | ||
| 733 | |||
| 264 | static void *display_thread(void *arg __used) | 734 | static void *display_thread(void *arg __used) |
| 265 | { | 735 | { |
| 266 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; | 736 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; |
| 267 | int delay_msecs = delay_secs * 1000; | 737 | struct termios tc, save; |
| 738 | int delay_msecs, c; | ||
| 739 | |||
| 740 | tcgetattr(0, &save); | ||
| 741 | tc = save; | ||
| 742 | tc.c_lflag &= ~(ICANON | ECHO); | ||
| 743 | tc.c_cc[VMIN] = 0; | ||
| 744 | tc.c_cc[VTIME] = 0; | ||
| 268 | 745 | ||
| 269 | printf("PerfTop refresh period: %d seconds\n", delay_secs); | 746 | repeat: |
| 747 | delay_msecs = delay_secs * 1000; | ||
| 748 | tcsetattr(0, TCSANOW, &tc); | ||
| 749 | /* trash return*/ | ||
| 750 | getc(stdin); | ||
| 270 | 751 | ||
| 271 | do { | 752 | do { |
| 272 | print_sym_table(); | 753 | print_sym_table(); |
| 273 | } while (!poll(&stdin_poll, 1, delay_msecs) == 1); | 754 | } while (!poll(&stdin_poll, 1, delay_msecs) == 1); |
| 274 | 755 | ||
| 275 | printf("key pressed - exiting.\n"); | 756 | c = getc(stdin); |
| 276 | exit(0); | 757 | tcsetattr(0, TCSAFLUSH, &save); |
| 758 | |||
| 759 | handle_keypress(c); | ||
| 760 | goto repeat; | ||
| 277 | 761 | ||
| 278 | return NULL; | 762 | return NULL; |
| 279 | } | 763 | } |
| @@ -293,7 +777,6 @@ static const char *skip_symbols[] = { | |||
| 293 | 777 | ||
| 294 | static int symbol_filter(struct dso *self, struct symbol *sym) | 778 | static int symbol_filter(struct dso *self, struct symbol *sym) |
| 295 | { | 779 | { |
| 296 | static int filter_match; | ||
| 297 | struct sym_entry *syme; | 780 | struct sym_entry *syme; |
| 298 | const char *name = sym->name; | 781 | const char *name = sym->name; |
| 299 | int i; | 782 | int i; |
| @@ -315,6 +798,10 @@ static int symbol_filter(struct dso *self, struct symbol *sym) | |||
| 315 | return 1; | 798 | return 1; |
| 316 | 799 | ||
| 317 | syme = dso__sym_priv(self, sym); | 800 | syme = dso__sym_priv(self, sym); |
| 801 | pthread_mutex_init(&syme->source_lock, NULL); | ||
| 802 | if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) | ||
| 803 | sym_filter_entry = syme; | ||
| 804 | |||
| 318 | for (i = 0; skip_symbols[i]; i++) { | 805 | for (i = 0; skip_symbols[i]; i++) { |
| 319 | if (!strcmp(skip_symbols[i], name)) { | 806 | if (!strcmp(skip_symbols[i], name)) { |
| 320 | syme->skip = 1; | 807 | syme->skip = 1; |
| @@ -322,29 +809,6 @@ static int symbol_filter(struct dso *self, struct symbol *sym) | |||
| 322 | } | 809 | } |
| 323 | } | 810 | } |
| 324 | 811 | ||
| 325 | if (filter_match == 1) { | ||
| 326 | filter_end = sym->start; | ||
| 327 | filter_match = -1; | ||
| 328 | if (filter_end - filter_start > 10000) { | ||
| 329 | fprintf(stderr, | ||
| 330 | "hm, too large filter symbol <%s> - skipping.\n", | ||
| 331 | sym_filter); | ||
| 332 | fprintf(stderr, "symbol filter start: %016lx\n", | ||
| 333 | filter_start); | ||
| 334 | fprintf(stderr, " end: %016lx\n", | ||
| 335 | filter_end); | ||
| 336 | filter_end = filter_start = 0; | ||
| 337 | sym_filter = NULL; | ||
| 338 | sleep(1); | ||
| 339 | } | ||
| 340 | } | ||
| 341 | |||
| 342 | if (filter_match == 0 && sym_filter && !strcmp(name, sym_filter)) { | ||
| 343 | filter_match = 1; | ||
| 344 | filter_start = sym->start; | ||
| 345 | } | ||
| 346 | |||
| 347 | |||
| 348 | return 0; | 812 | return 0; |
| 349 | } | 813 | } |
| 350 | 814 | ||
| @@ -380,8 +844,6 @@ out_delete_dso: | |||
| 380 | return -1; | 844 | return -1; |
| 381 | } | 845 | } |
| 382 | 846 | ||
| 383 | #define TRACE_COUNT 3 | ||
| 384 | |||
| 385 | /* | 847 | /* |
| 386 | * Binary search in the histogram table and record the hit: | 848 | * Binary search in the histogram table and record the hit: |
| 387 | */ | 849 | */ |
| @@ -394,6 +856,7 @@ static void record_ip(u64 ip, int counter) | |||
| 394 | 856 | ||
| 395 | if (!syme->skip) { | 857 | if (!syme->skip) { |
| 396 | syme->count[counter]++; | 858 | syme->count[counter]++; |
| 859 | record_precise_ip(syme, counter, ip); | ||
| 397 | pthread_mutex_lock(&active_symbols_lock); | 860 | pthread_mutex_lock(&active_symbols_lock); |
| 398 | if (list_empty(&syme->node) || !syme->node.next) | 861 | if (list_empty(&syme->node) || !syme->node.next) |
| 399 | __list_insert_active_sym(syme); | 862 | __list_insert_active_sym(syme); |
| @@ -690,8 +1153,8 @@ static const struct option options[] = { | |||
| 690 | "put the counters into a counter group"), | 1153 | "put the counters into a counter group"), |
| 691 | OPT_BOOLEAN('i', "inherit", &inherit, | 1154 | OPT_BOOLEAN('i', "inherit", &inherit, |
| 692 | "child tasks inherit counters"), | 1155 | "child tasks inherit counters"), |
| 693 | OPT_STRING('s', "sym-filter", &sym_filter, "pattern", | 1156 | OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name", |
| 694 | "only display symbols matchig this pattern"), | 1157 | "symbol to annotate - requires -k option"), |
| 695 | OPT_BOOLEAN('z', "zero", &zero, | 1158 | OPT_BOOLEAN('z', "zero", &zero, |
| 696 | "zero history across updates"), | 1159 | "zero history across updates"), |
| 697 | OPT_INTEGER('F', "freq", &freq, | 1160 | OPT_INTEGER('F', "freq", &freq, |
| @@ -734,6 +1197,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
| 734 | delay_secs = 1; | 1197 | delay_secs = 1; |
| 735 | 1198 | ||
| 736 | parse_symbols(); | 1199 | parse_symbols(); |
| 1200 | parse_source(sym_filter_entry); | ||
| 737 | 1201 | ||
| 738 | /* | 1202 | /* |
| 739 | * Fill in the ones not specifically initialized via -c: | 1203 | * Fill in the ones not specifically initialized via -c: |
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 9d3c8141b8c1..011473411642 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #include <stdio.h> | 13 | #include <stdio.h> |
| 14 | #include <stdbool.h> | 14 | #include <stdbool.h> |
| 15 | #include <errno.h> | 15 | #include <errno.h> |
| 16 | #include <math.h> | ||
| 16 | 17 | ||
| 17 | #include "callchain.h" | 18 | #include "callchain.h" |
| 18 | 19 | ||
| @@ -26,10 +27,14 @@ rb_insert_callchain(struct rb_root *root, struct callchain_node *chain, | |||
| 26 | struct rb_node **p = &root->rb_node; | 27 | struct rb_node **p = &root->rb_node; |
| 27 | struct rb_node *parent = NULL; | 28 | struct rb_node *parent = NULL; |
| 28 | struct callchain_node *rnode; | 29 | struct callchain_node *rnode; |
| 30 | u64 chain_cumul = cumul_hits(chain); | ||
| 29 | 31 | ||
| 30 | while (*p) { | 32 | while (*p) { |
| 33 | u64 rnode_cumul; | ||
| 34 | |||
| 31 | parent = *p; | 35 | parent = *p; |
| 32 | rnode = rb_entry(parent, struct callchain_node, rb_node); | 36 | rnode = rb_entry(parent, struct callchain_node, rb_node); |
| 37 | rnode_cumul = cumul_hits(rnode); | ||
| 33 | 38 | ||
| 34 | switch (mode) { | 39 | switch (mode) { |
| 35 | case CHAIN_FLAT: | 40 | case CHAIN_FLAT: |
| @@ -40,7 +45,7 @@ rb_insert_callchain(struct rb_root *root, struct callchain_node *chain, | |||
| 40 | break; | 45 | break; |
| 41 | case CHAIN_GRAPH_ABS: /* Falldown */ | 46 | case CHAIN_GRAPH_ABS: /* Falldown */ |
| 42 | case CHAIN_GRAPH_REL: | 47 | case CHAIN_GRAPH_REL: |
| 43 | if (rnode->cumul_hit < chain->cumul_hit) | 48 | if (rnode_cumul < chain_cumul) |
| 44 | p = &(*p)->rb_left; | 49 | p = &(*p)->rb_left; |
| 45 | else | 50 | else |
| 46 | p = &(*p)->rb_right; | 51 | p = &(*p)->rb_right; |
| @@ -87,7 +92,7 @@ static void __sort_chain_graph_abs(struct callchain_node *node, | |||
| 87 | 92 | ||
| 88 | chain_for_each_child(child, node) { | 93 | chain_for_each_child(child, node) { |
| 89 | __sort_chain_graph_abs(child, min_hit); | 94 | __sort_chain_graph_abs(child, min_hit); |
| 90 | if (child->cumul_hit >= min_hit) | 95 | if (cumul_hits(child) >= min_hit) |
| 91 | rb_insert_callchain(&node->rb_root, child, | 96 | rb_insert_callchain(&node->rb_root, child, |
| 92 | CHAIN_GRAPH_ABS); | 97 | CHAIN_GRAPH_ABS); |
| 93 | } | 98 | } |
| @@ -108,11 +113,11 @@ static void __sort_chain_graph_rel(struct callchain_node *node, | |||
| 108 | u64 min_hit; | 113 | u64 min_hit; |
| 109 | 114 | ||
| 110 | node->rb_root = RB_ROOT; | 115 | node->rb_root = RB_ROOT; |
| 111 | min_hit = node->cumul_hit * min_percent / 100.0; | 116 | min_hit = ceil(node->children_hit * min_percent); |
| 112 | 117 | ||
| 113 | chain_for_each_child(child, node) { | 118 | chain_for_each_child(child, node) { |
| 114 | __sort_chain_graph_rel(child, min_percent); | 119 | __sort_chain_graph_rel(child, min_percent); |
| 115 | if (child->cumul_hit >= min_hit) | 120 | if (cumul_hits(child) >= min_hit) |
| 116 | rb_insert_callchain(&node->rb_root, child, | 121 | rb_insert_callchain(&node->rb_root, child, |
| 117 | CHAIN_GRAPH_REL); | 122 | CHAIN_GRAPH_REL); |
| 118 | } | 123 | } |
| @@ -122,7 +127,7 @@ static void | |||
| 122 | sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_node *chain_root, | 127 | sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_node *chain_root, |
| 123 | u64 min_hit __used, struct callchain_param *param) | 128 | u64 min_hit __used, struct callchain_param *param) |
| 124 | { | 129 | { |
| 125 | __sort_chain_graph_rel(chain_root, param->min_percent); | 130 | __sort_chain_graph_rel(chain_root, param->min_percent / 100.0); |
| 126 | rb_root->rb_node = chain_root->rb_root.rb_node; | 131 | rb_root->rb_node = chain_root->rb_root.rb_node; |
| 127 | } | 132 | } |
| 128 | 133 | ||
| @@ -211,7 +216,8 @@ add_child(struct callchain_node *parent, struct ip_callchain *chain, | |||
| 211 | new = create_child(parent, false); | 216 | new = create_child(parent, false); |
| 212 | fill_node(new, chain, start, syms); | 217 | fill_node(new, chain, start, syms); |
| 213 | 218 | ||
| 214 | new->cumul_hit = new->hit = 1; | 219 | new->children_hit = 0; |
| 220 | new->hit = 1; | ||
| 215 | } | 221 | } |
| 216 | 222 | ||
| 217 | /* | 223 | /* |
| @@ -241,7 +247,8 @@ split_add_child(struct callchain_node *parent, struct ip_callchain *chain, | |||
| 241 | 247 | ||
| 242 | /* split the hits */ | 248 | /* split the hits */ |
| 243 | new->hit = parent->hit; | 249 | new->hit = parent->hit; |
| 244 | new->cumul_hit = parent->cumul_hit; | 250 | new->children_hit = parent->children_hit; |
| 251 | parent->children_hit = cumul_hits(new); | ||
| 245 | new->val_nr = parent->val_nr - idx_local; | 252 | new->val_nr = parent->val_nr - idx_local; |
| 246 | parent->val_nr = idx_local; | 253 | parent->val_nr = idx_local; |
| 247 | 254 | ||
| @@ -249,6 +256,7 @@ split_add_child(struct callchain_node *parent, struct ip_callchain *chain, | |||
| 249 | if (idx_total < chain->nr) { | 256 | if (idx_total < chain->nr) { |
| 250 | parent->hit = 0; | 257 | parent->hit = 0; |
| 251 | add_child(parent, chain, idx_total, syms); | 258 | add_child(parent, chain, idx_total, syms); |
| 259 | parent->children_hit++; | ||
| 252 | } else { | 260 | } else { |
| 253 | parent->hit = 1; | 261 | parent->hit = 1; |
| 254 | } | 262 | } |
| @@ -269,13 +277,13 @@ __append_chain_children(struct callchain_node *root, struct ip_callchain *chain, | |||
| 269 | unsigned int ret = __append_chain(rnode, chain, start, syms); | 277 | unsigned int ret = __append_chain(rnode, chain, start, syms); |
| 270 | 278 | ||
| 271 | if (!ret) | 279 | if (!ret) |
| 272 | goto cumul; | 280 | goto inc_children_hit; |
| 273 | } | 281 | } |
| 274 | /* nothing in children, add to the current node */ | 282 | /* nothing in children, add to the current node */ |
| 275 | add_child(root, chain, start, syms); | 283 | add_child(root, chain, start, syms); |
| 276 | 284 | ||
| 277 | cumul: | 285 | inc_children_hit: |
| 278 | root->cumul_hit++; | 286 | root->children_hit++; |
| 279 | } | 287 | } |
| 280 | 288 | ||
| 281 | static int | 289 | static int |
| @@ -317,8 +325,6 @@ __append_chain(struct callchain_node *root, struct ip_callchain *chain, | |||
| 317 | /* we match 100% of the path, increment the hit */ | 325 | /* we match 100% of the path, increment the hit */ |
| 318 | if (i - start == root->val_nr && i == chain->nr) { | 326 | if (i - start == root->val_nr && i == chain->nr) { |
| 319 | root->hit++; | 327 | root->hit++; |
| 320 | root->cumul_hit++; | ||
| 321 | |||
| 322 | return 0; | 328 | return 0; |
| 323 | } | 329 | } |
| 324 | 330 | ||
| @@ -331,5 +337,7 @@ __append_chain(struct callchain_node *root, struct ip_callchain *chain, | |||
| 331 | void append_chain(struct callchain_node *root, struct ip_callchain *chain, | 337 | void append_chain(struct callchain_node *root, struct ip_callchain *chain, |
| 332 | struct symbol **syms) | 338 | struct symbol **syms) |
| 333 | { | 339 | { |
| 340 | if (!chain->nr) | ||
| 341 | return; | ||
| 334 | __append_chain_children(root, chain, syms, 0); | 342 | __append_chain_children(root, chain, syms, 0); |
| 335 | } | 343 | } |
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index 7812122bea1d..a926ae4f5a16 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include "symbol.h" | 7 | #include "symbol.h" |
| 8 | 8 | ||
| 9 | enum chain_mode { | 9 | enum chain_mode { |
| 10 | CHAIN_NONE, | ||
| 10 | CHAIN_FLAT, | 11 | CHAIN_FLAT, |
| 11 | CHAIN_GRAPH_ABS, | 12 | CHAIN_GRAPH_ABS, |
| 12 | CHAIN_GRAPH_REL | 13 | CHAIN_GRAPH_REL |
| @@ -21,7 +22,7 @@ struct callchain_node { | |||
| 21 | struct rb_root rb_root; /* sorted tree of children */ | 22 | struct rb_root rb_root; /* sorted tree of children */ |
| 22 | unsigned int val_nr; | 23 | unsigned int val_nr; |
| 23 | u64 hit; | 24 | u64 hit; |
| 24 | u64 cumul_hit; /* hit + hits of children */ | 25 | u64 children_hit; |
| 25 | }; | 26 | }; |
| 26 | 27 | ||
| 27 | struct callchain_param; | 28 | struct callchain_param; |
| @@ -48,6 +49,11 @@ static inline void callchain_init(struct callchain_node *node) | |||
| 48 | INIT_LIST_HEAD(&node->val); | 49 | INIT_LIST_HEAD(&node->val); |
| 49 | } | 50 | } |
| 50 | 51 | ||
| 52 | static inline u64 cumul_hits(struct callchain_node *node) | ||
| 53 | { | ||
| 54 | return node->hit + node->children_hit; | ||
| 55 | } | ||
| 56 | |||
| 51 | int register_callchain_param(struct callchain_param *param); | 57 | int register_callchain_param(struct callchain_param *param); |
| 52 | void append_chain(struct callchain_node *root, struct ip_callchain *chain, | 58 | void append_chain(struct callchain_node *root, struct ip_callchain *chain, |
| 53 | struct symbol **syms); | 59 | struct symbol **syms); |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 450384b3bbe5..b92a457ca32e 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
| @@ -185,6 +185,8 @@ static void do_read(int fd, void *buf, size_t size) | |||
| 185 | 185 | ||
| 186 | if (ret < 0) | 186 | if (ret < 0) |
| 187 | die("failed to read"); | 187 | die("failed to read"); |
| 188 | if (ret == 0) | ||
| 189 | die("failed to read: missing data"); | ||
| 188 | 190 | ||
| 189 | size -= ret; | 191 | size -= ret; |
| 190 | buf += ret; | 192 | buf += ret; |
| @@ -213,9 +215,10 @@ struct perf_header *perf_header__read(int fd) | |||
| 213 | 215 | ||
| 214 | for (i = 0; i < nr_attrs; i++) { | 216 | for (i = 0; i < nr_attrs; i++) { |
| 215 | struct perf_header_attr *attr; | 217 | struct perf_header_attr *attr; |
| 216 | off_t tmp = lseek(fd, 0, SEEK_CUR); | 218 | off_t tmp; |
| 217 | 219 | ||
| 218 | do_read(fd, &f_attr, sizeof(f_attr)); | 220 | do_read(fd, &f_attr, sizeof(f_attr)); |
| 221 | tmp = lseek(fd, 0, SEEK_CUR); | ||
| 219 | 222 | ||
| 220 | attr = perf_header_attr__new(&f_attr.attr); | 223 | attr = perf_header_attr__new(&f_attr.attr); |
| 221 | 224 | ||
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 7bdad8df22a6..4858d83b3b67 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
| @@ -121,13 +121,29 @@ static unsigned long hw_cache_stat[C(MAX)] = { | |||
| 121 | (strcmp(sys_dirent.d_name, ".")) && \ | 121 | (strcmp(sys_dirent.d_name, ".")) && \ |
| 122 | (strcmp(sys_dirent.d_name, ".."))) | 122 | (strcmp(sys_dirent.d_name, ".."))) |
| 123 | 123 | ||
| 124 | static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir) | ||
| 125 | { | ||
| 126 | char evt_path[MAXPATHLEN]; | ||
| 127 | int fd; | ||
| 128 | |||
| 129 | snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path, | ||
| 130 | sys_dir->d_name, evt_dir->d_name); | ||
| 131 | fd = open(evt_path, O_RDONLY); | ||
| 132 | if (fd < 0) | ||
| 133 | return -EINVAL; | ||
| 134 | close(fd); | ||
| 135 | |||
| 136 | return 0; | ||
| 137 | } | ||
| 138 | |||
| 124 | #define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, file, st) \ | 139 | #define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, file, st) \ |
| 125 | while (!readdir_r(evt_dir, &evt_dirent, &evt_next) && evt_next) \ | 140 | while (!readdir_r(evt_dir, &evt_dirent, &evt_next) && evt_next) \ |
| 126 | if (snprintf(file, MAXPATHLEN, "%s/%s/%s", debugfs_path, \ | 141 | if (snprintf(file, MAXPATHLEN, "%s/%s/%s", debugfs_path, \ |
| 127 | sys_dirent.d_name, evt_dirent.d_name) && \ | 142 | sys_dirent.d_name, evt_dirent.d_name) && \ |
| 128 | (!stat(file, &st)) && (S_ISDIR(st.st_mode)) && \ | 143 | (!stat(file, &st)) && (S_ISDIR(st.st_mode)) && \ |
| 129 | (strcmp(evt_dirent.d_name, ".")) && \ | 144 | (strcmp(evt_dirent.d_name, ".")) && \ |
| 130 | (strcmp(evt_dirent.d_name, ".."))) | 145 | (strcmp(evt_dirent.d_name, "..")) && \ |
| 146 | (!tp_event_has_id(&sys_dirent, &evt_dirent))) | ||
| 131 | 147 | ||
| 132 | #define MAX_EVENT_LENGTH 30 | 148 | #define MAX_EVENT_LENGTH 30 |
| 133 | 149 | ||
| @@ -223,9 +239,15 @@ char *event_name(int counter) | |||
| 223 | { | 239 | { |
| 224 | u64 config = attrs[counter].config; | 240 | u64 config = attrs[counter].config; |
| 225 | int type = attrs[counter].type; | 241 | int type = attrs[counter].type; |
| 242 | |||
| 243 | return __event_name(type, config); | ||
| 244 | } | ||
| 245 | |||
| 246 | char *__event_name(int type, u64 config) | ||
| 247 | { | ||
| 226 | static char buf[32]; | 248 | static char buf[32]; |
| 227 | 249 | ||
| 228 | if (attrs[counter].type == PERF_TYPE_RAW) { | 250 | if (type == PERF_TYPE_RAW) { |
| 229 | sprintf(buf, "raw 0x%llx", config); | 251 | sprintf(buf, "raw 0x%llx", config); |
| 230 | return buf; | 252 | return buf; |
| 231 | } | 253 | } |
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 1ea5d09b6eb1..192a962e3a0f 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h | |||
| @@ -10,6 +10,7 @@ extern int nr_counters; | |||
| 10 | extern struct perf_counter_attr attrs[MAX_COUNTERS]; | 10 | extern struct perf_counter_attr attrs[MAX_COUNTERS]; |
| 11 | 11 | ||
| 12 | extern char *event_name(int ctr); | 12 | extern char *event_name(int ctr); |
| 13 | extern char *__event_name(int type, u64 config); | ||
| 13 | 14 | ||
| 14 | extern int parse_events(const struct option *opt, const char *str, int unset); | 15 | extern int parse_events(const struct option *opt, const char *str, int unset); |
| 15 | 16 | ||
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 16ddca202948..f1dcede14307 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
| @@ -24,6 +24,16 @@ const char *sym_hist_filter; | |||
| 24 | #define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ | 24 | #define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ |
| 25 | #endif | 25 | #endif |
| 26 | 26 | ||
| 27 | enum dso_origin { | ||
| 28 | DSO__ORIG_KERNEL = 0, | ||
| 29 | DSO__ORIG_JAVA_JIT, | ||
| 30 | DSO__ORIG_FEDORA, | ||
| 31 | DSO__ORIG_UBUNTU, | ||
| 32 | DSO__ORIG_BUILDID, | ||
| 33 | DSO__ORIG_DSO, | ||
| 34 | DSO__ORIG_NOT_FOUND, | ||
| 35 | }; | ||
| 36 | |||
| 27 | static struct symbol *symbol__new(u64 start, u64 len, | 37 | static struct symbol *symbol__new(u64 start, u64 len, |
| 28 | const char *name, unsigned int priv_size, | 38 | const char *name, unsigned int priv_size, |
| 29 | u64 obj_start, int verbose) | 39 | u64 obj_start, int verbose) |
| @@ -81,6 +91,7 @@ struct dso *dso__new(const char *name, unsigned int sym_priv_size) | |||
| 81 | self->sym_priv_size = sym_priv_size; | 91 | self->sym_priv_size = sym_priv_size; |
| 82 | self->find_symbol = dso__find_symbol; | 92 | self->find_symbol = dso__find_symbol; |
| 83 | self->slen_calculated = 0; | 93 | self->slen_calculated = 0; |
| 94 | self->origin = DSO__ORIG_NOT_FOUND; | ||
| 84 | } | 95 | } |
| 85 | 96 | ||
| 86 | return self; | 97 | return self; |
| @@ -710,7 +721,7 @@ static char *dso__read_build_id(struct dso *self, int verbose) | |||
| 710 | ++raw; | 721 | ++raw; |
| 711 | bid += 2; | 722 | bid += 2; |
| 712 | } | 723 | } |
| 713 | if (verbose) | 724 | if (verbose >= 2) |
| 714 | printf("%s(%s): %s\n", __func__, self->name, build_id); | 725 | printf("%s(%s): %s\n", __func__, self->name, build_id); |
| 715 | out_elf_end: | 726 | out_elf_end: |
| 716 | elf_end(elf); | 727 | elf_end(elf); |
| @@ -720,11 +731,26 @@ out: | |||
| 720 | return build_id; | 731 | return build_id; |
| 721 | } | 732 | } |
| 722 | 733 | ||
| 734 | char dso__symtab_origin(const struct dso *self) | ||
| 735 | { | ||
| 736 | static const char origin[] = { | ||
| 737 | [DSO__ORIG_KERNEL] = 'k', | ||
| 738 | [DSO__ORIG_JAVA_JIT] = 'j', | ||
| 739 | [DSO__ORIG_FEDORA] = 'f', | ||
| 740 | [DSO__ORIG_UBUNTU] = 'u', | ||
| 741 | [DSO__ORIG_BUILDID] = 'b', | ||
| 742 | [DSO__ORIG_DSO] = 'd', | ||
| 743 | }; | ||
| 744 | |||
| 745 | if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) | ||
| 746 | return '!'; | ||
| 747 | return origin[self->origin]; | ||
| 748 | } | ||
| 749 | |||
| 723 | int dso__load(struct dso *self, symbol_filter_t filter, int verbose) | 750 | int dso__load(struct dso *self, symbol_filter_t filter, int verbose) |
| 724 | { | 751 | { |
| 725 | int size = PATH_MAX; | 752 | int size = PATH_MAX; |
| 726 | char *name = malloc(size), *build_id = NULL; | 753 | char *name = malloc(size), *build_id = NULL; |
| 727 | int variant = 0; | ||
| 728 | int ret = -1; | 754 | int ret = -1; |
| 729 | int fd; | 755 | int fd; |
| 730 | 756 | ||
| @@ -733,19 +759,26 @@ int dso__load(struct dso *self, symbol_filter_t filter, int verbose) | |||
| 733 | 759 | ||
| 734 | self->adjust_symbols = 0; | 760 | self->adjust_symbols = 0; |
| 735 | 761 | ||
| 736 | if (strncmp(self->name, "/tmp/perf-", 10) == 0) | 762 | if (strncmp(self->name, "/tmp/perf-", 10) == 0) { |
| 737 | return dso__load_perf_map(self, filter, verbose); | 763 | ret = dso__load_perf_map(self, filter, verbose); |
| 764 | self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : | ||
| 765 | DSO__ORIG_NOT_FOUND; | ||
| 766 | return ret; | ||
| 767 | } | ||
| 768 | |||
| 769 | self->origin = DSO__ORIG_FEDORA - 1; | ||
| 738 | 770 | ||
| 739 | more: | 771 | more: |
| 740 | do { | 772 | do { |
| 741 | switch (variant) { | 773 | self->origin++; |
| 742 | case 0: /* Fedora */ | 774 | switch (self->origin) { |
| 775 | case DSO__ORIG_FEDORA: | ||
| 743 | snprintf(name, size, "/usr/lib/debug%s.debug", self->name); | 776 | snprintf(name, size, "/usr/lib/debug%s.debug", self->name); |
| 744 | break; | 777 | break; |
| 745 | case 1: /* Ubuntu */ | 778 | case DSO__ORIG_UBUNTU: |
| 746 | snprintf(name, size, "/usr/lib/debug%s", self->name); | 779 | snprintf(name, size, "/usr/lib/debug%s", self->name); |
| 747 | break; | 780 | break; |
| 748 | case 2: | 781 | case DSO__ORIG_BUILDID: |
| 749 | build_id = dso__read_build_id(self, verbose); | 782 | build_id = dso__read_build_id(self, verbose); |
| 750 | if (build_id != NULL) { | 783 | if (build_id != NULL) { |
| 751 | snprintf(name, size, | 784 | snprintf(name, size, |
| @@ -754,16 +787,15 @@ more: | |||
| 754 | free(build_id); | 787 | free(build_id); |
| 755 | break; | 788 | break; |
| 756 | } | 789 | } |
| 757 | variant++; | 790 | self->origin++; |
| 758 | /* Fall thru */ | 791 | /* Fall thru */ |
| 759 | case 3: /* Sane people */ | 792 | case DSO__ORIG_DSO: |
| 760 | snprintf(name, size, "%s", self->name); | 793 | snprintf(name, size, "%s", self->name); |
| 761 | break; | 794 | break; |
| 762 | 795 | ||
| 763 | default: | 796 | default: |
| 764 | goto out; | 797 | goto out; |
| 765 | } | 798 | } |
| 766 | variant++; | ||
| 767 | 799 | ||
| 768 | fd = open(name, O_RDONLY); | 800 | fd = open(name, O_RDONLY); |
| 769 | } while (fd < 0); | 801 | } while (fd < 0); |
| @@ -899,6 +931,9 @@ int dso__load_kernel(struct dso *self, const char *vmlinux, | |||
| 899 | if (err <= 0) | 931 | if (err <= 0) |
| 900 | err = dso__load_kallsyms(self, filter, verbose); | 932 | err = dso__load_kallsyms(self, filter, verbose); |
| 901 | 933 | ||
| 934 | if (err > 0) | ||
| 935 | self->origin = DSO__ORIG_KERNEL; | ||
| 936 | |||
| 902 | return err; | 937 | return err; |
| 903 | } | 938 | } |
| 904 | 939 | ||
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 2f92b21c712d..1e003ec2f4b1 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
| @@ -26,6 +26,7 @@ struct dso { | |||
| 26 | unsigned int sym_priv_size; | 26 | unsigned int sym_priv_size; |
| 27 | unsigned char adjust_symbols; | 27 | unsigned char adjust_symbols; |
| 28 | unsigned char slen_calculated; | 28 | unsigned char slen_calculated; |
| 29 | unsigned char origin; | ||
| 29 | char name[0]; | 30 | char name[0]; |
| 30 | }; | 31 | }; |
| 31 | 32 | ||
| @@ -49,6 +50,7 @@ int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose); | |||
| 49 | int dso__load(struct dso *self, symbol_filter_t filter, int verbose); | 50 | int dso__load(struct dso *self, symbol_filter_t filter, int verbose); |
| 50 | 51 | ||
| 51 | size_t dso__fprintf(struct dso *self, FILE *fp); | 52 | size_t dso__fprintf(struct dso *self, FILE *fp); |
| 53 | char dso__symtab_origin(const struct dso *self); | ||
| 52 | 54 | ||
| 53 | void symbol__init(void); | 55 | void symbol__init(void); |
| 54 | #endif /* _PERF_SYMBOL_ */ | 56 | #endif /* _PERF_SYMBOL_ */ |
