diff options
| author | H. Peter Anvin <hpa@linux.intel.com> | 2014-02-14 14:11:18 -0500 |
|---|---|---|
| committer | H. Peter Anvin <hpa@linux.intel.com> | 2014-02-14 14:11:18 -0500 |
| commit | 31fce91e7afc25c666276f65f019bc13fd27e216 (patch) | |
| tree | 24f9673614a98a06fd8f4254c63b306dddd5aac6 | |
| parent | 4640c7ee9b8953237d05a61ea3ea93981d1bc961 (diff) | |
| parent | 09503379dc99535b1bbfa51aa1aeef340f5d82ec (diff) | |
Merge remote-tracking branch 'efi/urgent' into x86/urgent
There have been reports of EFI crashes since -rc1. The following two
commits fix known issues.
* Fix boot failure on 32-bit EFI due to the recent EFI memmap changes
merged during the merge window - Borislav Petkov
* Avoid a crash during efi_bgrt_init() by detecting invalid BGRT
headers based on the 'status' field.
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
34 files changed, 215 insertions, 107 deletions
| @@ -1,7 +1,7 @@ | |||
| 1 | VERSION = 3 | 1 | VERSION = 3 |
| 2 | PATCHLEVEL = 14 | 2 | PATCHLEVEL = 14 |
| 3 | SUBLEVEL = 0 | 3 | SUBLEVEL = 0 |
| 4 | EXTRAVERSION = -rc1 | 4 | EXTRAVERSION = -rc2 |
| 5 | NAME = Shuffling Zombie Juror | 5 | NAME = Shuffling Zombie Juror |
| 6 | 6 | ||
| 7 | # *DOCUMENTATION* | 7 | # *DOCUMENTATION* |
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index 3b978c472d08..3d6b9f81cc68 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h | |||
| @@ -132,6 +132,8 @@ extern void __init efi_map_region_fixed(efi_memory_desc_t *md); | |||
| 132 | extern void efi_sync_low_kernel_mappings(void); | 132 | extern void efi_sync_low_kernel_mappings(void); |
| 133 | extern void efi_setup_page_tables(void); | 133 | extern void efi_setup_page_tables(void); |
| 134 | extern void __init old_map_region(efi_memory_desc_t *md); | 134 | extern void __init old_map_region(efi_memory_desc_t *md); |
| 135 | extern void __init runtime_code_page_mkexec(void); | ||
| 136 | extern void __init efi_runtime_mkexec(void); | ||
| 135 | 137 | ||
| 136 | struct efi_setup_data { | 138 | struct efi_setup_data { |
| 137 | u64 fw_vendor; | 139 | u64 fw_vendor; |
diff --git a/arch/x86/platform/efi/efi-bgrt.c b/arch/x86/platform/efi/efi-bgrt.c index 4df9591eadad..f15103dff4b4 100644 --- a/arch/x86/platform/efi/efi-bgrt.c +++ b/arch/x86/platform/efi/efi-bgrt.c | |||
| @@ -42,7 +42,7 @@ void __init efi_bgrt_init(void) | |||
| 42 | 42 | ||
| 43 | if (bgrt_tab->header.length < sizeof(*bgrt_tab)) | 43 | if (bgrt_tab->header.length < sizeof(*bgrt_tab)) |
| 44 | return; | 44 | return; |
| 45 | if (bgrt_tab->version != 1) | 45 | if (bgrt_tab->version != 1 || bgrt_tab->status != 1) |
| 46 | return; | 46 | return; |
| 47 | if (bgrt_tab->image_type != 0 || !bgrt_tab->image_address) | 47 | if (bgrt_tab->image_type != 0 || !bgrt_tab->image_address) |
| 48 | return; | 48 | return; |
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index d62ec87a2b26..1a201ac7cef8 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c | |||
| @@ -792,7 +792,7 @@ void __init efi_set_executable(efi_memory_desc_t *md, bool executable) | |||
| 792 | set_memory_nx(addr, npages); | 792 | set_memory_nx(addr, npages); |
| 793 | } | 793 | } |
| 794 | 794 | ||
| 795 | static void __init runtime_code_page_mkexec(void) | 795 | void __init runtime_code_page_mkexec(void) |
| 796 | { | 796 | { |
| 797 | efi_memory_desc_t *md; | 797 | efi_memory_desc_t *md; |
| 798 | void *p; | 798 | void *p; |
| @@ -1069,8 +1069,7 @@ void __init efi_enter_virtual_mode(void) | |||
| 1069 | efi.update_capsule = virt_efi_update_capsule; | 1069 | efi.update_capsule = virt_efi_update_capsule; |
| 1070 | efi.query_capsule_caps = virt_efi_query_capsule_caps; | 1070 | efi.query_capsule_caps = virt_efi_query_capsule_caps; |
| 1071 | 1071 | ||
| 1072 | if (efi_enabled(EFI_OLD_MEMMAP) && (__supported_pte_mask & _PAGE_NX)) | 1072 | efi_runtime_mkexec(); |
| 1073 | runtime_code_page_mkexec(); | ||
| 1074 | 1073 | ||
| 1075 | kfree(new_memmap); | 1074 | kfree(new_memmap); |
| 1076 | 1075 | ||
diff --git a/arch/x86/platform/efi/efi_32.c b/arch/x86/platform/efi/efi_32.c index 249b183cf417..0b74cdf7f816 100644 --- a/arch/x86/platform/efi/efi_32.c +++ b/arch/x86/platform/efi/efi_32.c | |||
| @@ -77,3 +77,9 @@ void efi_call_phys_epilog(void) | |||
| 77 | 77 | ||
| 78 | local_irq_restore(efi_rt_eflags); | 78 | local_irq_restore(efi_rt_eflags); |
| 79 | } | 79 | } |
| 80 | |||
| 81 | void __init efi_runtime_mkexec(void) | ||
| 82 | { | ||
| 83 | if (__supported_pte_mask & _PAGE_NX) | ||
| 84 | runtime_code_page_mkexec(); | ||
| 85 | } | ||
diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c index 6284f158a47d..0c2a234fef1e 100644 --- a/arch/x86/platform/efi/efi_64.c +++ b/arch/x86/platform/efi/efi_64.c | |||
| @@ -233,3 +233,12 @@ void __init parse_efi_setup(u64 phys_addr, u32 data_len) | |||
| 233 | { | 233 | { |
| 234 | efi_setup = phys_addr + sizeof(struct setup_data); | 234 | efi_setup = phys_addr + sizeof(struct setup_data); |
| 235 | } | 235 | } |
| 236 | |||
| 237 | void __init efi_runtime_mkexec(void) | ||
| 238 | { | ||
| 239 | if (!efi_enabled(EFI_OLD_MEMMAP)) | ||
| 240 | return; | ||
| 241 | |||
| 242 | if (__supported_pte_mask & _PAGE_NX) | ||
| 243 | runtime_code_page_mkexec(); | ||
| 244 | } | ||
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index feea87cc6b8f..6928d094451d 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c | |||
| @@ -890,12 +890,10 @@ static int pipe_to_sg(struct pipe_inode_info *pipe, struct pipe_buffer *buf, | |||
| 890 | } else { | 890 | } else { |
| 891 | /* Failback to copying a page */ | 891 | /* Failback to copying a page */ |
| 892 | struct page *page = alloc_page(GFP_KERNEL); | 892 | struct page *page = alloc_page(GFP_KERNEL); |
| 893 | char *src = buf->ops->map(pipe, buf, 1); | 893 | char *src; |
| 894 | char *dst; | ||
| 895 | 894 | ||
| 896 | if (!page) | 895 | if (!page) |
| 897 | return -ENOMEM; | 896 | return -ENOMEM; |
| 898 | dst = kmap(page); | ||
| 899 | 897 | ||
| 900 | offset = sd->pos & ~PAGE_MASK; | 898 | offset = sd->pos & ~PAGE_MASK; |
| 901 | 899 | ||
| @@ -903,9 +901,8 @@ static int pipe_to_sg(struct pipe_inode_info *pipe, struct pipe_buffer *buf, | |||
| 903 | if (len + offset > PAGE_SIZE) | 901 | if (len + offset > PAGE_SIZE) |
| 904 | len = PAGE_SIZE - offset; | 902 | len = PAGE_SIZE - offset; |
| 905 | 903 | ||
| 906 | memcpy(dst + offset, src + buf->offset, len); | 904 | src = buf->ops->map(pipe, buf, 1); |
| 907 | 905 | memcpy(page_address(page) + offset, src + buf->offset, len); | |
| 908 | kunmap(page); | ||
| 909 | buf->ops->unmap(pipe, buf, src); | 906 | buf->ops->unmap(pipe, buf, src); |
| 910 | 907 | ||
| 911 | sg_set_page(&(sgl->sg[sgl->n]), page, len, offset); | 908 | sg_set_page(&(sgl->sg[sgl->n]), page, len, offset); |
diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index e2600cdb6c25..b01fb6c527e3 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c | |||
| @@ -1010,6 +1010,8 @@ int btrfs_decompress_buf2page(char *buf, unsigned long buf_start, | |||
| 1010 | bytes = min(bytes, working_bytes); | 1010 | bytes = min(bytes, working_bytes); |
| 1011 | kaddr = kmap_atomic(page_out); | 1011 | kaddr = kmap_atomic(page_out); |
| 1012 | memcpy(kaddr + *pg_offset, buf + buf_offset, bytes); | 1012 | memcpy(kaddr + *pg_offset, buf + buf_offset, bytes); |
| 1013 | if (*pg_index == (vcnt - 1) && *pg_offset == 0) | ||
| 1014 | memset(kaddr + bytes, 0, PAGE_CACHE_SIZE - bytes); | ||
| 1013 | kunmap_atomic(kaddr); | 1015 | kunmap_atomic(kaddr); |
| 1014 | flush_dcache_page(page_out); | 1016 | flush_dcache_page(page_out); |
| 1015 | 1017 | ||
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 9c9ecc93ae2c..32312e09f0f5 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
| @@ -2385,6 +2385,7 @@ static noinline int __btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, | |||
| 2385 | spin_unlock(&delayed_refs->lock); | 2385 | spin_unlock(&delayed_refs->lock); |
| 2386 | locked_ref = NULL; | 2386 | locked_ref = NULL; |
| 2387 | cond_resched(); | 2387 | cond_resched(); |
| 2388 | count++; | ||
| 2388 | continue; | 2389 | continue; |
| 2389 | } | 2390 | } |
| 2390 | 2391 | ||
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index b0134892dc70..383ab455bfa7 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
| @@ -4525,7 +4525,7 @@ static int btrfs_ioctl_set_fslabel(struct file *file, void __user *arg) | |||
| 4525 | spin_lock(&root->fs_info->super_lock); | 4525 | spin_lock(&root->fs_info->super_lock); |
| 4526 | strcpy(super_block->label, label); | 4526 | strcpy(super_block->label, label); |
| 4527 | spin_unlock(&root->fs_info->super_lock); | 4527 | spin_unlock(&root->fs_info->super_lock); |
| 4528 | ret = btrfs_end_transaction(trans, root); | 4528 | ret = btrfs_commit_transaction(trans, root); |
| 4529 | 4529 | ||
| 4530 | out_unlock: | 4530 | out_unlock: |
| 4531 | mnt_drop_write_file(file); | 4531 | mnt_drop_write_file(file); |
| @@ -4668,7 +4668,7 @@ static int btrfs_ioctl_set_features(struct file *file, void __user *arg) | |||
| 4668 | if (ret) | 4668 | if (ret) |
| 4669 | return ret; | 4669 | return ret; |
| 4670 | 4670 | ||
| 4671 | trans = btrfs_start_transaction(root, 1); | 4671 | trans = btrfs_start_transaction(root, 0); |
| 4672 | if (IS_ERR(trans)) | 4672 | if (IS_ERR(trans)) |
| 4673 | return PTR_ERR(trans); | 4673 | return PTR_ERR(trans); |
| 4674 | 4674 | ||
| @@ -4689,7 +4689,7 @@ static int btrfs_ioctl_set_features(struct file *file, void __user *arg) | |||
| 4689 | btrfs_set_super_incompat_flags(super_block, newflags); | 4689 | btrfs_set_super_incompat_flags(super_block, newflags); |
| 4690 | spin_unlock(&root->fs_info->super_lock); | 4690 | spin_unlock(&root->fs_info->super_lock); |
| 4691 | 4691 | ||
| 4692 | return btrfs_end_transaction(trans, root); | 4692 | return btrfs_commit_transaction(trans, root); |
| 4693 | } | 4693 | } |
| 4694 | 4694 | ||
| 4695 | long btrfs_ioctl(struct file *file, unsigned int | 4695 | long btrfs_ioctl(struct file *file, unsigned int |
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index cf9107a64204..9c8d1a3fdc3a 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c | |||
| @@ -2774,8 +2774,6 @@ static int add_waiting_dir_move(struct send_ctx *sctx, u64 ino) | |||
| 2774 | return 0; | 2774 | return 0; |
| 2775 | } | 2775 | } |
| 2776 | 2776 | ||
| 2777 | #ifdef CONFIG_BTRFS_ASSERT | ||
| 2778 | |||
| 2779 | static int del_waiting_dir_move(struct send_ctx *sctx, u64 ino) | 2777 | static int del_waiting_dir_move(struct send_ctx *sctx, u64 ino) |
| 2780 | { | 2778 | { |
| 2781 | struct rb_node *n = sctx->waiting_dir_moves.rb_node; | 2779 | struct rb_node *n = sctx->waiting_dir_moves.rb_node; |
| @@ -2796,8 +2794,6 @@ static int del_waiting_dir_move(struct send_ctx *sctx, u64 ino) | |||
| 2796 | return -ENOENT; | 2794 | return -ENOENT; |
| 2797 | } | 2795 | } |
| 2798 | 2796 | ||
| 2799 | #endif | ||
| 2800 | |||
| 2801 | static int add_pending_dir_move(struct send_ctx *sctx, u64 parent_ino) | 2797 | static int add_pending_dir_move(struct send_ctx *sctx, u64 parent_ino) |
| 2802 | { | 2798 | { |
| 2803 | struct rb_node **p = &sctx->pending_dir_moves.rb_node; | 2799 | struct rb_node **p = &sctx->pending_dir_moves.rb_node; |
| @@ -2902,7 +2898,9 @@ static int apply_dir_move(struct send_ctx *sctx, struct pending_dir_move *pm) | |||
| 2902 | } | 2898 | } |
| 2903 | 2899 | ||
| 2904 | sctx->send_progress = sctx->cur_ino + 1; | 2900 | sctx->send_progress = sctx->cur_ino + 1; |
| 2905 | ASSERT(del_waiting_dir_move(sctx, pm->ino) == 0); | 2901 | ret = del_waiting_dir_move(sctx, pm->ino); |
| 2902 | ASSERT(ret == 0); | ||
| 2903 | |||
| 2906 | ret = get_cur_path(sctx, pm->ino, pm->gen, to_path); | 2904 | ret = get_cur_path(sctx, pm->ino, pm->gen, to_path); |
| 2907 | if (ret < 0) | 2905 | if (ret < 0) |
| 2908 | goto out; | 2906 | goto out; |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 853d6d1cc822..a7eda8ebfacc 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
| @@ -2559,8 +2559,8 @@ cifs_writev(struct kiocb *iocb, const struct iovec *iov, | |||
| 2559 | if (rc > 0) { | 2559 | if (rc > 0) { |
| 2560 | ssize_t err; | 2560 | ssize_t err; |
| 2561 | 2561 | ||
| 2562 | err = generic_write_sync(file, pos, rc); | 2562 | err = generic_write_sync(file, iocb->ki_pos - rc, rc); |
| 2563 | if (err < 0 && rc > 0) | 2563 | if (err < 0) |
| 2564 | rc = err; | 2564 | rc = err; |
| 2565 | } | 2565 | } |
| 2566 | 2566 | ||
diff --git a/fs/ext4/file.c b/fs/ext4/file.c index 43e64f6022eb..1a5073959f32 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c | |||
| @@ -152,7 +152,7 @@ ext4_file_dio_write(struct kiocb *iocb, const struct iovec *iov, | |||
| 152 | if (ret > 0) { | 152 | if (ret > 0) { |
| 153 | ssize_t err; | 153 | ssize_t err; |
| 154 | 154 | ||
| 155 | err = generic_write_sync(file, pos, ret); | 155 | err = generic_write_sync(file, iocb->ki_pos - ret, ret); |
| 156 | if (err < 0 && ret > 0) | 156 | if (err < 0 && ret > 0) |
| 157 | ret = err; | 157 | ret = err; |
| 158 | } | 158 | } |
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index ea4ba9daeb47..db9bd8a31725 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c | |||
| @@ -2134,7 +2134,7 @@ static ssize_t ntfs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, | |||
| 2134 | ret = ntfs_file_aio_write_nolock(iocb, iov, nr_segs, &iocb->ki_pos); | 2134 | ret = ntfs_file_aio_write_nolock(iocb, iov, nr_segs, &iocb->ki_pos); |
| 2135 | mutex_unlock(&inode->i_mutex); | 2135 | mutex_unlock(&inode->i_mutex); |
| 2136 | if (ret > 0) { | 2136 | if (ret > 0) { |
| 2137 | int err = generic_write_sync(file, pos, ret); | 2137 | int err = generic_write_sync(file, iocb->ki_pos - ret, ret); |
| 2138 | if (err < 0) | 2138 | if (err < 0) |
| 2139 | ret = err; | 2139 | ret = err; |
| 2140 | } | 2140 | } |
| @@ -222,23 +222,6 @@ SYSCALL_DEFINE1(fdatasync, unsigned int, fd) | |||
| 222 | return do_fsync(fd, 1); | 222 | return do_fsync(fd, 1); |
| 223 | } | 223 | } |
| 224 | 224 | ||
| 225 | /** | ||
| 226 | * generic_write_sync - perform syncing after a write if file / inode is sync | ||
| 227 | * @file: file to which the write happened | ||
| 228 | * @pos: offset where the write started | ||
| 229 | * @count: length of the write | ||
| 230 | * | ||
| 231 | * This is just a simple wrapper about our general syncing function. | ||
| 232 | */ | ||
| 233 | int generic_write_sync(struct file *file, loff_t pos, loff_t count) | ||
| 234 | { | ||
| 235 | if (!(file->f_flags & O_DSYNC) && !IS_SYNC(file->f_mapping->host)) | ||
| 236 | return 0; | ||
| 237 | return vfs_fsync_range(file, pos, pos + count - 1, | ||
| 238 | (file->f_flags & __O_SYNC) ? 0 : 1); | ||
| 239 | } | ||
| 240 | EXPORT_SYMBOL(generic_write_sync); | ||
| 241 | |||
| 242 | /* | 225 | /* |
| 243 | * sys_sync_file_range() permits finely controlled syncing over a segment of | 226 | * sys_sync_file_range() permits finely controlled syncing over a segment of |
| 244 | * a file in the range offset .. (offset+nbytes-1) inclusive. If nbytes is | 227 | * a file in the range offset .. (offset+nbytes-1) inclusive. If nbytes is |
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 2e7989e3a2d6..64b48eade91d 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c | |||
| @@ -799,7 +799,7 @@ xfs_file_aio_write( | |||
| 799 | XFS_STATS_ADD(xs_write_bytes, ret); | 799 | XFS_STATS_ADD(xs_write_bytes, ret); |
| 800 | 800 | ||
| 801 | /* Handle various SYNC-type writes */ | 801 | /* Handle various SYNC-type writes */ |
| 802 | err = generic_write_sync(file, pos, ret); | 802 | err = generic_write_sync(file, iocb->ki_pos - ret, ret); |
| 803 | if (err < 0) | 803 | if (err < 0) |
| 804 | ret = err; | 804 | ret = err; |
| 805 | } | 805 | } |
diff --git a/include/linux/fs.h b/include/linux/fs.h index d79678c188ad..60829565e552 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
| @@ -2274,7 +2274,13 @@ extern int filemap_fdatawrite_range(struct address_space *mapping, | |||
| 2274 | extern int vfs_fsync_range(struct file *file, loff_t start, loff_t end, | 2274 | extern int vfs_fsync_range(struct file *file, loff_t start, loff_t end, |
| 2275 | int datasync); | 2275 | int datasync); |
| 2276 | extern int vfs_fsync(struct file *file, int datasync); | 2276 | extern int vfs_fsync(struct file *file, int datasync); |
| 2277 | extern int generic_write_sync(struct file *file, loff_t pos, loff_t count); | 2277 | static inline int generic_write_sync(struct file *file, loff_t pos, loff_t count) |
| 2278 | { | ||
| 2279 | if (!(file->f_flags & O_DSYNC) && !IS_SYNC(file->f_mapping->host)) | ||
| 2280 | return 0; | ||
| 2281 | return vfs_fsync_range(file, pos, pos + count - 1, | ||
| 2282 | (file->f_flags & __O_SYNC) ? 0 : 1); | ||
| 2283 | } | ||
| 2278 | extern void emergency_sync(void); | 2284 | extern void emergency_sync(void); |
| 2279 | extern void emergency_remount(void); | 2285 | extern void emergency_remount(void); |
| 2280 | #ifdef CONFIG_BLOCK | 2286 | #ifdef CONFIG_BLOCK |
diff --git a/mm/filemap.c b/mm/filemap.c index d56d3c145b9f..7a13f6ac5421 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
| @@ -2553,8 +2553,8 @@ ssize_t generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov, | |||
| 2553 | if (ret > 0) { | 2553 | if (ret > 0) { |
| 2554 | ssize_t err; | 2554 | ssize_t err; |
| 2555 | 2555 | ||
| 2556 | err = generic_write_sync(file, pos, ret); | 2556 | err = generic_write_sync(file, iocb->ki_pos - ret, ret); |
| 2557 | if (err < 0 && ret > 0) | 2557 | if (err < 0) |
| 2558 | ret = err; | 2558 | ret = err; |
| 2559 | } | 2559 | } |
| 2560 | return ret; | 2560 | return ret; |
diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index 332ac8a80cf5..2df7b900e259 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include <linux/inet_diag.h> | 17 | #include <linux/inet_diag.h> |
| 18 | #include <linux/xfrm.h> | 18 | #include <linux/xfrm.h> |
| 19 | #include <linux/audit.h> | 19 | #include <linux/audit.h> |
| 20 | #include <linux/sock_diag.h> | ||
| 20 | 21 | ||
| 21 | #include "flask.h" | 22 | #include "flask.h" |
| 22 | #include "av_permissions.h" | 23 | #include "av_permissions.h" |
| @@ -78,6 +79,7 @@ static struct nlmsg_perm nlmsg_tcpdiag_perms[] = | |||
| 78 | { | 79 | { |
| 79 | { TCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, | 80 | { TCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, |
| 80 | { DCCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, | 81 | { DCCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, |
| 82 | { SOCK_DIAG_BY_FAMILY, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, | ||
| 81 | }; | 83 | }; |
| 82 | 84 | ||
| 83 | static struct nlmsg_perm nlmsg_xfrm_perms[] = | 85 | static struct nlmsg_perm nlmsg_xfrm_perms[] = |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index c93c21127f0c..5d0144ee8ed6 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
| @@ -1232,6 +1232,10 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len, | |||
| 1232 | struct context context; | 1232 | struct context context; |
| 1233 | int rc = 0; | 1233 | int rc = 0; |
| 1234 | 1234 | ||
| 1235 | /* An empty security context is never valid. */ | ||
| 1236 | if (!scontext_len) | ||
| 1237 | return -EINVAL; | ||
| 1238 | |||
| 1235 | if (!ss_initialized) { | 1239 | if (!ss_initialized) { |
| 1236 | int i; | 1240 | int i; |
| 1237 | 1241 | ||
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c index cfede86161d8..b22dbb16f877 100644 --- a/tools/perf/builtin-buildid-cache.c +++ b/tools/perf/builtin-buildid-cache.c | |||
| @@ -63,11 +63,35 @@ static int build_id_cache__kcore_dir(char *dir, size_t sz) | |||
| 63 | return 0; | 63 | return 0; |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | static bool same_kallsyms_reloc(const char *from_dir, char *to_dir) | ||
| 67 | { | ||
| 68 | char from[PATH_MAX]; | ||
| 69 | char to[PATH_MAX]; | ||
| 70 | const char *name; | ||
| 71 | u64 addr1 = 0, addr2 = 0; | ||
| 72 | int i; | ||
| 73 | |||
| 74 | scnprintf(from, sizeof(from), "%s/kallsyms", from_dir); | ||
| 75 | scnprintf(to, sizeof(to), "%s/kallsyms", to_dir); | ||
| 76 | |||
| 77 | for (i = 0; (name = ref_reloc_sym_names[i]) != NULL; i++) { | ||
| 78 | addr1 = kallsyms__get_function_start(from, name); | ||
| 79 | if (addr1) | ||
| 80 | break; | ||
| 81 | } | ||
| 82 | |||
| 83 | if (name) | ||
| 84 | addr2 = kallsyms__get_function_start(to, name); | ||
| 85 | |||
| 86 | return addr1 == addr2; | ||
| 87 | } | ||
| 88 | |||
| 66 | static int build_id_cache__kcore_existing(const char *from_dir, char *to_dir, | 89 | static int build_id_cache__kcore_existing(const char *from_dir, char *to_dir, |
| 67 | size_t to_dir_sz) | 90 | size_t to_dir_sz) |
| 68 | { | 91 | { |
| 69 | char from[PATH_MAX]; | 92 | char from[PATH_MAX]; |
| 70 | char to[PATH_MAX]; | 93 | char to[PATH_MAX]; |
| 94 | char to_subdir[PATH_MAX]; | ||
| 71 | struct dirent *dent; | 95 | struct dirent *dent; |
| 72 | int ret = -1; | 96 | int ret = -1; |
| 73 | DIR *d; | 97 | DIR *d; |
| @@ -86,10 +110,11 @@ static int build_id_cache__kcore_existing(const char *from_dir, char *to_dir, | |||
| 86 | continue; | 110 | continue; |
| 87 | scnprintf(to, sizeof(to), "%s/%s/modules", to_dir, | 111 | scnprintf(to, sizeof(to), "%s/%s/modules", to_dir, |
| 88 | dent->d_name); | 112 | dent->d_name); |
| 89 | if (!compare_proc_modules(from, to)) { | 113 | scnprintf(to_subdir, sizeof(to_subdir), "%s/%s", |
| 90 | scnprintf(to, sizeof(to), "%s/%s", to_dir, | 114 | to_dir, dent->d_name); |
| 91 | dent->d_name); | 115 | if (!compare_proc_modules(from, to) && |
| 92 | strlcpy(to_dir, to, to_dir_sz); | 116 | same_kallsyms_reloc(from_dir, to_subdir)) { |
| 117 | strlcpy(to_dir, to_subdir, to_dir_sz); | ||
| 93 | ret = 0; | 118 | ret = 0; |
| 94 | break; | 119 | break; |
| 95 | } | 120 | } |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 3c394bf16fa8..af47531b82ec 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
| @@ -287,10 +287,7 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data) | |||
| 287 | * have no _text sometimes. | 287 | * have no _text sometimes. |
| 288 | */ | 288 | */ |
| 289 | err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, | 289 | err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, |
| 290 | machine, "_text"); | 290 | machine); |
| 291 | if (err < 0) | ||
| 292 | err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, | ||
| 293 | machine, "_stext"); | ||
| 294 | if (err < 0) | 291 | if (err < 0) |
| 295 | pr_err("Couldn't record guest kernel [%d]'s reference" | 292 | pr_err("Couldn't record guest kernel [%d]'s reference" |
| 296 | " relocation symbol.\n", machine->pid); | 293 | " relocation symbol.\n", machine->pid); |
| @@ -457,10 +454,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) | |||
| 457 | } | 454 | } |
| 458 | 455 | ||
| 459 | err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, | 456 | err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, |
| 460 | machine, "_text"); | 457 | machine); |
| 461 | if (err < 0) | ||
| 462 | err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, | ||
| 463 | machine, "_stext"); | ||
| 464 | if (err < 0) | 458 | if (err < 0) |
| 465 | pr_err("Couldn't record kernel reference relocation symbol\n" | 459 | pr_err("Couldn't record kernel reference relocation symbol\n" |
| 466 | "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" | 460 | "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" |
diff --git a/tools/perf/design.txt b/tools/perf/design.txt index 67e5d0cace85..63a0e6f04a01 100644 --- a/tools/perf/design.txt +++ b/tools/perf/design.txt | |||
| @@ -454,7 +454,6 @@ So to start with, in order to add HAVE_PERF_EVENTS to your Kconfig, you | |||
| 454 | will need at least this: | 454 | will need at least this: |
| 455 | - asm/perf_event.h - a basic stub will suffice at first | 455 | - asm/perf_event.h - a basic stub will suffice at first |
| 456 | - support for atomic64 types (and associated helper functions) | 456 | - support for atomic64 types (and associated helper functions) |
| 457 | - set_perf_event_pending() implemented | ||
| 458 | 457 | ||
| 459 | If your architecture does have hardware capabilities, you can override the | 458 | If your architecture does have hardware capabilities, you can override the |
| 460 | weak stub hw_perf_event_init() to register hardware counters. | 459 | weak stub hw_perf_event_init() to register hardware counters. |
diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 7daa806d9050..e84fa26bc1be 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h | |||
| @@ -100,8 +100,8 @@ | |||
| 100 | 100 | ||
| 101 | #ifdef __aarch64__ | 101 | #ifdef __aarch64__ |
| 102 | #define mb() asm volatile("dmb ish" ::: "memory") | 102 | #define mb() asm volatile("dmb ish" ::: "memory") |
| 103 | #define wmb() asm volatile("dmb ishld" ::: "memory") | 103 | #define wmb() asm volatile("dmb ishst" ::: "memory") |
| 104 | #define rmb() asm volatile("dmb ishst" ::: "memory") | 104 | #define rmb() asm volatile("dmb ishld" ::: "memory") |
| 105 | #define cpu_relax() asm volatile("yield" ::: "memory") | 105 | #define cpu_relax() asm volatile("yield" ::: "memory") |
| 106 | #endif | 106 | #endif |
| 107 | 107 | ||
diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c index 2bd13edcbc17..3d9088003a5b 100644 --- a/tools/perf/tests/vmlinux-kallsyms.c +++ b/tools/perf/tests/vmlinux-kallsyms.c | |||
| @@ -26,7 +26,6 @@ int test__vmlinux_matches_kallsyms(void) | |||
| 26 | struct map *kallsyms_map, *vmlinux_map; | 26 | struct map *kallsyms_map, *vmlinux_map; |
| 27 | struct machine kallsyms, vmlinux; | 27 | struct machine kallsyms, vmlinux; |
| 28 | enum map_type type = MAP__FUNCTION; | 28 | enum map_type type = MAP__FUNCTION; |
| 29 | struct ref_reloc_sym ref_reloc_sym = { .name = "_stext", }; | ||
| 30 | u64 mem_start, mem_end; | 29 | u64 mem_start, mem_end; |
| 31 | 30 | ||
| 32 | /* | 31 | /* |
| @@ -70,14 +69,6 @@ int test__vmlinux_matches_kallsyms(void) | |||
| 70 | */ | 69 | */ |
| 71 | kallsyms_map = machine__kernel_map(&kallsyms, type); | 70 | kallsyms_map = machine__kernel_map(&kallsyms, type); |
| 72 | 71 | ||
| 73 | sym = map__find_symbol_by_name(kallsyms_map, ref_reloc_sym.name, NULL); | ||
| 74 | if (sym == NULL) { | ||
| 75 | pr_debug("dso__find_symbol_by_name "); | ||
| 76 | goto out; | ||
| 77 | } | ||
| 78 | |||
| 79 | ref_reloc_sym.addr = UM(sym->start); | ||
| 80 | |||
| 81 | /* | 72 | /* |
| 82 | * Step 5: | 73 | * Step 5: |
| 83 | * | 74 | * |
| @@ -89,7 +80,6 @@ int test__vmlinux_matches_kallsyms(void) | |||
| 89 | } | 80 | } |
| 90 | 81 | ||
| 91 | vmlinux_map = machine__kernel_map(&vmlinux, type); | 82 | vmlinux_map = machine__kernel_map(&vmlinux, type); |
| 92 | map__kmap(vmlinux_map)->ref_reloc_sym = &ref_reloc_sym; | ||
| 93 | 83 | ||
| 94 | /* | 84 | /* |
| 95 | * Step 6: | 85 | * Step 6: |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 1fc1c2f04772..b0f3ca850e9e 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
| @@ -470,23 +470,32 @@ static int find_symbol_cb(void *arg, const char *name, char type, | |||
| 470 | return 1; | 470 | return 1; |
| 471 | } | 471 | } |
| 472 | 472 | ||
| 473 | u64 kallsyms__get_function_start(const char *kallsyms_filename, | ||
| 474 | const char *symbol_name) | ||
| 475 | { | ||
| 476 | struct process_symbol_args args = { .name = symbol_name, }; | ||
| 477 | |||
| 478 | if (kallsyms__parse(kallsyms_filename, &args, find_symbol_cb) <= 0) | ||
| 479 | return 0; | ||
| 480 | |||
| 481 | return args.start; | ||
| 482 | } | ||
| 483 | |||
| 473 | int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, | 484 | int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, |
| 474 | perf_event__handler_t process, | 485 | perf_event__handler_t process, |
| 475 | struct machine *machine, | 486 | struct machine *machine) |
| 476 | const char *symbol_name) | ||
| 477 | { | 487 | { |
| 478 | size_t size; | 488 | size_t size; |
| 479 | const char *filename, *mmap_name; | 489 | const char *mmap_name; |
| 480 | char path[PATH_MAX]; | ||
| 481 | char name_buff[PATH_MAX]; | 490 | char name_buff[PATH_MAX]; |
| 482 | struct map *map; | 491 | struct map *map; |
| 492 | struct kmap *kmap; | ||
| 483 | int err; | 493 | int err; |
| 484 | /* | 494 | /* |
| 485 | * We should get this from /sys/kernel/sections/.text, but till that is | 495 | * We should get this from /sys/kernel/sections/.text, but till that is |
| 486 | * available use this, and after it is use this as a fallback for older | 496 | * available use this, and after it is use this as a fallback for older |
| 487 | * kernels. | 497 | * kernels. |
| 488 | */ | 498 | */ |
| 489 | struct process_symbol_args args = { .name = symbol_name, }; | ||
| 490 | union perf_event *event = zalloc((sizeof(event->mmap) + | 499 | union perf_event *event = zalloc((sizeof(event->mmap) + |
| 491 | machine->id_hdr_size)); | 500 | machine->id_hdr_size)); |
| 492 | if (event == NULL) { | 501 | if (event == NULL) { |
| @@ -502,30 +511,19 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, | |||
| 502 | * see kernel/perf_event.c __perf_event_mmap | 511 | * see kernel/perf_event.c __perf_event_mmap |
| 503 | */ | 512 | */ |
| 504 | event->header.misc = PERF_RECORD_MISC_KERNEL; | 513 | event->header.misc = PERF_RECORD_MISC_KERNEL; |
| 505 | filename = "/proc/kallsyms"; | ||
| 506 | } else { | 514 | } else { |
| 507 | event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; | 515 | event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; |
| 508 | if (machine__is_default_guest(machine)) | ||
| 509 | filename = (char *) symbol_conf.default_guest_kallsyms; | ||
| 510 | else { | ||
| 511 | sprintf(path, "%s/proc/kallsyms", machine->root_dir); | ||
| 512 | filename = path; | ||
| 513 | } | ||
| 514 | } | ||
| 515 | |||
| 516 | if (kallsyms__parse(filename, &args, find_symbol_cb) <= 0) { | ||
| 517 | free(event); | ||
| 518 | return -ENOENT; | ||
| 519 | } | 516 | } |
| 520 | 517 | ||
| 521 | map = machine->vmlinux_maps[MAP__FUNCTION]; | 518 | map = machine->vmlinux_maps[MAP__FUNCTION]; |
| 519 | kmap = map__kmap(map); | ||
| 522 | size = snprintf(event->mmap.filename, sizeof(event->mmap.filename), | 520 | size = snprintf(event->mmap.filename, sizeof(event->mmap.filename), |
| 523 | "%s%s", mmap_name, symbol_name) + 1; | 521 | "%s%s", mmap_name, kmap->ref_reloc_sym->name) + 1; |
| 524 | size = PERF_ALIGN(size, sizeof(u64)); | 522 | size = PERF_ALIGN(size, sizeof(u64)); |
| 525 | event->mmap.header.type = PERF_RECORD_MMAP; | 523 | event->mmap.header.type = PERF_RECORD_MMAP; |
| 526 | event->mmap.header.size = (sizeof(event->mmap) - | 524 | event->mmap.header.size = (sizeof(event->mmap) - |
| 527 | (sizeof(event->mmap.filename) - size) + machine->id_hdr_size); | 525 | (sizeof(event->mmap.filename) - size) + machine->id_hdr_size); |
| 528 | event->mmap.pgoff = args.start; | 526 | event->mmap.pgoff = kmap->ref_reloc_sym->addr; |
| 529 | event->mmap.start = map->start; | 527 | event->mmap.start = map->start; |
| 530 | event->mmap.len = map->end - event->mmap.start; | 528 | event->mmap.len = map->end - event->mmap.start; |
| 531 | event->mmap.pid = machine->pid; | 529 | event->mmap.pid = machine->pid; |
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index faf6e219be21..851fa06f4a42 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
| @@ -214,8 +214,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool, | |||
| 214 | struct machine *machine, bool mmap_data); | 214 | struct machine *machine, bool mmap_data); |
| 215 | int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, | 215 | int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, |
| 216 | perf_event__handler_t process, | 216 | perf_event__handler_t process, |
| 217 | struct machine *machine, | 217 | struct machine *machine); |
| 218 | const char *symbol_name); | ||
| 219 | 218 | ||
| 220 | int perf_event__synthesize_modules(struct perf_tool *tool, | 219 | int perf_event__synthesize_modules(struct perf_tool *tool, |
| 221 | perf_event__handler_t process, | 220 | perf_event__handler_t process, |
| @@ -279,4 +278,7 @@ size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp); | |||
| 279 | size_t perf_event__fprintf_task(union perf_event *event, FILE *fp); | 278 | size_t perf_event__fprintf_task(union perf_event *event, FILE *fp); |
| 280 | size_t perf_event__fprintf(union perf_event *event, FILE *fp); | 279 | size_t perf_event__fprintf(union perf_event *event, FILE *fp); |
| 281 | 280 | ||
| 281 | u64 kallsyms__get_function_start(const char *kallsyms_filename, | ||
| 282 | const char *symbol_name); | ||
| 283 | |||
| 282 | #endif /* __PERF_RECORD_H */ | 284 | #endif /* __PERF_RECORD_H */ |
diff --git a/tools/perf/util/include/asm/hash.h b/tools/perf/util/include/asm/hash.h new file mode 100644 index 000000000000..d82b170bb216 --- /dev/null +++ b/tools/perf/util/include/asm/hash.h | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | #ifndef __ASM_GENERIC_HASH_H | ||
| 2 | #define __ASM_GENERIC_HASH_H | ||
| 3 | |||
| 4 | /* Stub */ | ||
| 5 | |||
| 6 | #endif /* __ASM_GENERIC_HASH_H */ | ||
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index ded74590b92f..c872991e0f65 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
| @@ -496,19 +496,22 @@ static int symbol__in_kernel(void *arg, const char *name, | |||
| 496 | return 1; | 496 | return 1; |
| 497 | } | 497 | } |
| 498 | 498 | ||
| 499 | static void machine__get_kallsyms_filename(struct machine *machine, char *buf, | ||
| 500 | size_t bufsz) | ||
| 501 | { | ||
| 502 | if (machine__is_default_guest(machine)) | ||
| 503 | scnprintf(buf, bufsz, "%s", symbol_conf.default_guest_kallsyms); | ||
| 504 | else | ||
| 505 | scnprintf(buf, bufsz, "%s/proc/kallsyms", machine->root_dir); | ||
| 506 | } | ||
| 507 | |||
| 499 | /* Figure out the start address of kernel map from /proc/kallsyms */ | 508 | /* Figure out the start address of kernel map from /proc/kallsyms */ |
| 500 | static u64 machine__get_kernel_start_addr(struct machine *machine) | 509 | static u64 machine__get_kernel_start_addr(struct machine *machine) |
| 501 | { | 510 | { |
| 502 | const char *filename; | 511 | char filename[PATH_MAX]; |
| 503 | char path[PATH_MAX]; | ||
| 504 | struct process_args args; | 512 | struct process_args args; |
| 505 | 513 | ||
| 506 | if (machine__is_default_guest(machine)) | 514 | machine__get_kallsyms_filename(machine, filename, PATH_MAX); |
| 507 | filename = (char *)symbol_conf.default_guest_kallsyms; | ||
| 508 | else { | ||
| 509 | sprintf(path, "%s/proc/kallsyms", machine->root_dir); | ||
| 510 | filename = path; | ||
| 511 | } | ||
| 512 | 515 | ||
| 513 | if (symbol__restricted_filename(filename, "/proc/kallsyms")) | 516 | if (symbol__restricted_filename(filename, "/proc/kallsyms")) |
| 514 | return 0; | 517 | return 0; |
| @@ -829,9 +832,25 @@ static int machine__create_modules(struct machine *machine) | |||
| 829 | return 0; | 832 | return 0; |
| 830 | } | 833 | } |
| 831 | 834 | ||
| 835 | const char *ref_reloc_sym_names[] = {"_text", "_stext", NULL}; | ||
| 836 | |||
| 832 | int machine__create_kernel_maps(struct machine *machine) | 837 | int machine__create_kernel_maps(struct machine *machine) |
| 833 | { | 838 | { |
| 834 | struct dso *kernel = machine__get_kernel(machine); | 839 | struct dso *kernel = machine__get_kernel(machine); |
| 840 | char filename[PATH_MAX]; | ||
| 841 | const char *name; | ||
| 842 | u64 addr = 0; | ||
| 843 | int i; | ||
| 844 | |||
| 845 | machine__get_kallsyms_filename(machine, filename, PATH_MAX); | ||
| 846 | |||
| 847 | for (i = 0; (name = ref_reloc_sym_names[i]) != NULL; i++) { | ||
| 848 | addr = kallsyms__get_function_start(filename, name); | ||
| 849 | if (addr) | ||
| 850 | break; | ||
| 851 | } | ||
| 852 | if (!addr) | ||
| 853 | return -1; | ||
| 835 | 854 | ||
| 836 | if (kernel == NULL || | 855 | if (kernel == NULL || |
| 837 | __machine__create_kernel_maps(machine, kernel) < 0) | 856 | __machine__create_kernel_maps(machine, kernel) < 0) |
| @@ -850,6 +869,13 @@ int machine__create_kernel_maps(struct machine *machine) | |||
| 850 | * Now that we have all the maps created, just set the ->end of them: | 869 | * Now that we have all the maps created, just set the ->end of them: |
| 851 | */ | 870 | */ |
| 852 | map_groups__fixup_end(&machine->kmaps); | 871 | map_groups__fixup_end(&machine->kmaps); |
| 872 | |||
| 873 | if (maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, name, | ||
| 874 | addr)) { | ||
| 875 | machine__destroy_kernel_maps(machine); | ||
| 876 | return -1; | ||
| 877 | } | ||
| 878 | |||
| 853 | return 0; | 879 | return 0; |
| 854 | } | 880 | } |
| 855 | 881 | ||
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index 477133015440..f77e91e483dc 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h | |||
| @@ -18,6 +18,8 @@ union perf_event; | |||
| 18 | #define HOST_KERNEL_ID (-1) | 18 | #define HOST_KERNEL_ID (-1) |
| 19 | #define DEFAULT_GUEST_KERNEL_ID (0) | 19 | #define DEFAULT_GUEST_KERNEL_ID (0) |
| 20 | 20 | ||
| 21 | extern const char *ref_reloc_sym_names[]; | ||
| 22 | |||
| 21 | struct machine { | 23 | struct machine { |
| 22 | struct rb_node rb_node; | 24 | struct rb_node rb_node; |
| 23 | pid_t pid; | 25 | pid_t pid; |
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 3b97513f0e77..39cd2d0faff6 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c | |||
| @@ -39,6 +39,7 @@ void map__init(struct map *map, enum map_type type, | |||
| 39 | map->start = start; | 39 | map->start = start; |
| 40 | map->end = end; | 40 | map->end = end; |
| 41 | map->pgoff = pgoff; | 41 | map->pgoff = pgoff; |
| 42 | map->reloc = 0; | ||
| 42 | map->dso = dso; | 43 | map->dso = dso; |
| 43 | map->map_ip = map__map_ip; | 44 | map->map_ip = map__map_ip; |
| 44 | map->unmap_ip = map__unmap_ip; | 45 | map->unmap_ip = map__unmap_ip; |
| @@ -288,7 +289,7 @@ u64 map__rip_2objdump(struct map *map, u64 rip) | |||
| 288 | if (map->dso->rel) | 289 | if (map->dso->rel) |
| 289 | return rip - map->pgoff; | 290 | return rip - map->pgoff; |
| 290 | 291 | ||
| 291 | return map->unmap_ip(map, rip); | 292 | return map->unmap_ip(map, rip) - map->reloc; |
| 292 | } | 293 | } |
| 293 | 294 | ||
| 294 | /** | 295 | /** |
| @@ -311,7 +312,7 @@ u64 map__objdump_2mem(struct map *map, u64 ip) | |||
| 311 | if (map->dso->rel) | 312 | if (map->dso->rel) |
| 312 | return map->unmap_ip(map, ip + map->pgoff); | 313 | return map->unmap_ip(map, ip + map->pgoff); |
| 313 | 314 | ||
| 314 | return ip; | 315 | return ip + map->reloc; |
| 315 | } | 316 | } |
| 316 | 317 | ||
| 317 | void map_groups__init(struct map_groups *mg) | 318 | void map_groups__init(struct map_groups *mg) |
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 18068c6b71c1..257e513205ce 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h | |||
| @@ -36,6 +36,7 @@ struct map { | |||
| 36 | bool erange_warned; | 36 | bool erange_warned; |
| 37 | u32 priv; | 37 | u32 priv; |
| 38 | u64 pgoff; | 38 | u64 pgoff; |
| 39 | u64 reloc; | ||
| 39 | u32 maj, min; /* only valid for MMAP2 record */ | 40 | u32 maj, min; /* only valid for MMAP2 record */ |
| 40 | u64 ino; /* only valid for MMAP2 record */ | 41 | u64 ino; /* only valid for MMAP2 record */ |
| 41 | u64 ino_generation;/* only valid for MMAP2 record */ | 42 | u64 ino_generation;/* only valid for MMAP2 record */ |
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 759456728703..3e9f336740fa 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c | |||
| @@ -751,6 +751,8 @@ int dso__load_sym(struct dso *dso, struct map *map, | |||
| 751 | if (strcmp(elf_name, kmap->ref_reloc_sym->name)) | 751 | if (strcmp(elf_name, kmap->ref_reloc_sym->name)) |
| 752 | continue; | 752 | continue; |
| 753 | kmap->ref_reloc_sym->unrelocated_addr = sym.st_value; | 753 | kmap->ref_reloc_sym->unrelocated_addr = sym.st_value; |
| 754 | map->reloc = kmap->ref_reloc_sym->addr - | ||
| 755 | kmap->ref_reloc_sym->unrelocated_addr; | ||
| 754 | break; | 756 | break; |
| 755 | } | 757 | } |
| 756 | } | 758 | } |
| @@ -922,6 +924,7 @@ int dso__load_sym(struct dso *dso, struct map *map, | |||
| 922 | (u64)shdr.sh_offset); | 924 | (u64)shdr.sh_offset); |
| 923 | sym.st_value -= shdr.sh_addr - shdr.sh_offset; | 925 | sym.st_value -= shdr.sh_addr - shdr.sh_offset; |
| 924 | } | 926 | } |
| 927 | new_symbol: | ||
| 925 | /* | 928 | /* |
| 926 | * We need to figure out if the object was created from C++ sources | 929 | * We need to figure out if the object was created from C++ sources |
| 927 | * DWARF DW_compile_unit has this, but we don't always have access | 930 | * DWARF DW_compile_unit has this, but we don't always have access |
| @@ -933,7 +936,6 @@ int dso__load_sym(struct dso *dso, struct map *map, | |||
| 933 | if (demangled != NULL) | 936 | if (demangled != NULL) |
| 934 | elf_name = demangled; | 937 | elf_name = demangled; |
| 935 | } | 938 | } |
| 936 | new_symbol: | ||
| 937 | f = symbol__new(sym.st_value, sym.st_size, | 939 | f = symbol__new(sym.st_value, sym.st_size, |
| 938 | GELF_ST_BIND(sym.st_info), elf_name); | 940 | GELF_ST_BIND(sym.st_info), elf_name); |
| 939 | free(demangled); | 941 | free(demangled); |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 39ce9adbaaf0..a9d758a3b371 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
| @@ -627,7 +627,7 @@ static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map, | |||
| 627 | * kernel range is broken in several maps, named [kernel].N, as we don't have | 627 | * kernel range is broken in several maps, named [kernel].N, as we don't have |
| 628 | * the original ELF section names vmlinux have. | 628 | * the original ELF section names vmlinux have. |
| 629 | */ | 629 | */ |
| 630 | static int dso__split_kallsyms(struct dso *dso, struct map *map, | 630 | static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta, |
| 631 | symbol_filter_t filter) | 631 | symbol_filter_t filter) |
| 632 | { | 632 | { |
| 633 | struct map_groups *kmaps = map__kmap(map)->kmaps; | 633 | struct map_groups *kmaps = map__kmap(map)->kmaps; |
| @@ -692,6 +692,12 @@ static int dso__split_kallsyms(struct dso *dso, struct map *map, | |||
| 692 | char dso_name[PATH_MAX]; | 692 | char dso_name[PATH_MAX]; |
| 693 | struct dso *ndso; | 693 | struct dso *ndso; |
| 694 | 694 | ||
| 695 | if (delta) { | ||
| 696 | /* Kernel was relocated at boot time */ | ||
| 697 | pos->start -= delta; | ||
| 698 | pos->end -= delta; | ||
| 699 | } | ||
| 700 | |||
| 695 | if (count == 0) { | 701 | if (count == 0) { |
| 696 | curr_map = map; | 702 | curr_map = map; |
| 697 | goto filter_symbol; | 703 | goto filter_symbol; |
| @@ -721,6 +727,10 @@ static int dso__split_kallsyms(struct dso *dso, struct map *map, | |||
| 721 | curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; | 727 | curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; |
| 722 | map_groups__insert(kmaps, curr_map); | 728 | map_groups__insert(kmaps, curr_map); |
| 723 | ++kernel_range; | 729 | ++kernel_range; |
| 730 | } else if (delta) { | ||
| 731 | /* Kernel was relocated at boot time */ | ||
| 732 | pos->start -= delta; | ||
| 733 | pos->end -= delta; | ||
| 724 | } | 734 | } |
| 725 | filter_symbol: | 735 | filter_symbol: |
| 726 | if (filter && filter(curr_map, pos)) { | 736 | if (filter && filter(curr_map, pos)) { |
| @@ -976,6 +986,23 @@ static int validate_kcore_modules(const char *kallsyms_filename, | |||
| 976 | return 0; | 986 | return 0; |
| 977 | } | 987 | } |
| 978 | 988 | ||
| 989 | static int validate_kcore_addresses(const char *kallsyms_filename, | ||
| 990 | struct map *map) | ||
| 991 | { | ||
| 992 | struct kmap *kmap = map__kmap(map); | ||
| 993 | |||
| 994 | if (kmap->ref_reloc_sym && kmap->ref_reloc_sym->name) { | ||
| 995 | u64 start; | ||
| 996 | |||
| 997 | start = kallsyms__get_function_start(kallsyms_filename, | ||
| 998 | kmap->ref_reloc_sym->name); | ||
| 999 | if (start != kmap->ref_reloc_sym->addr) | ||
| 1000 | return -EINVAL; | ||
| 1001 | } | ||
| 1002 | |||
| 1003 | return validate_kcore_modules(kallsyms_filename, map); | ||
| 1004 | } | ||
| 1005 | |||
| 979 | struct kcore_mapfn_data { | 1006 | struct kcore_mapfn_data { |
| 980 | struct dso *dso; | 1007 | struct dso *dso; |
| 981 | enum map_type type; | 1008 | enum map_type type; |
| @@ -1019,8 +1046,8 @@ static int dso__load_kcore(struct dso *dso, struct map *map, | |||
| 1019 | kallsyms_filename)) | 1046 | kallsyms_filename)) |
| 1020 | return -EINVAL; | 1047 | return -EINVAL; |
| 1021 | 1048 | ||
| 1022 | /* All modules must be present at their original addresses */ | 1049 | /* Modules and kernel must be present at their original addresses */ |
| 1023 | if (validate_kcore_modules(kallsyms_filename, map)) | 1050 | if (validate_kcore_addresses(kallsyms_filename, map)) |
| 1024 | return -EINVAL; | 1051 | return -EINVAL; |
| 1025 | 1052 | ||
| 1026 | md.dso = dso; | 1053 | md.dso = dso; |
| @@ -1113,15 +1140,41 @@ out_err: | |||
| 1113 | return -EINVAL; | 1140 | return -EINVAL; |
| 1114 | } | 1141 | } |
| 1115 | 1142 | ||
| 1143 | /* | ||
| 1144 | * If the kernel is relocated at boot time, kallsyms won't match. Compute the | ||
| 1145 | * delta based on the relocation reference symbol. | ||
| 1146 | */ | ||
| 1147 | static int kallsyms__delta(struct map *map, const char *filename, u64 *delta) | ||
| 1148 | { | ||
| 1149 | struct kmap *kmap = map__kmap(map); | ||
| 1150 | u64 addr; | ||
| 1151 | |||
| 1152 | if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->name) | ||
| 1153 | return 0; | ||
| 1154 | |||
| 1155 | addr = kallsyms__get_function_start(filename, | ||
| 1156 | kmap->ref_reloc_sym->name); | ||
| 1157 | if (!addr) | ||
| 1158 | return -1; | ||
| 1159 | |||
| 1160 | *delta = addr - kmap->ref_reloc_sym->addr; | ||
| 1161 | return 0; | ||
| 1162 | } | ||
| 1163 | |||
| 1116 | int dso__load_kallsyms(struct dso *dso, const char *filename, | 1164 | int dso__load_kallsyms(struct dso *dso, const char *filename, |
| 1117 | struct map *map, symbol_filter_t filter) | 1165 | struct map *map, symbol_filter_t filter) |
| 1118 | { | 1166 | { |
| 1167 | u64 delta = 0; | ||
| 1168 | |||
| 1119 | if (symbol__restricted_filename(filename, "/proc/kallsyms")) | 1169 | if (symbol__restricted_filename(filename, "/proc/kallsyms")) |
| 1120 | return -1; | 1170 | return -1; |
| 1121 | 1171 | ||
| 1122 | if (dso__load_all_kallsyms(dso, filename, map) < 0) | 1172 | if (dso__load_all_kallsyms(dso, filename, map) < 0) |
| 1123 | return -1; | 1173 | return -1; |
| 1124 | 1174 | ||
| 1175 | if (kallsyms__delta(map, filename, &delta)) | ||
| 1176 | return -1; | ||
| 1177 | |||
| 1125 | symbols__fixup_duplicate(&dso->symbols[map->type]); | 1178 | symbols__fixup_duplicate(&dso->symbols[map->type]); |
| 1126 | symbols__fixup_end(&dso->symbols[map->type]); | 1179 | symbols__fixup_end(&dso->symbols[map->type]); |
| 1127 | 1180 | ||
| @@ -1133,7 +1186,7 @@ int dso__load_kallsyms(struct dso *dso, const char *filename, | |||
| 1133 | if (!dso__load_kcore(dso, map, filename)) | 1186 | if (!dso__load_kcore(dso, map, filename)) |
| 1134 | return dso__split_kallsyms_for_kcore(dso, map, filter); | 1187 | return dso__split_kallsyms_for_kcore(dso, map, filter); |
| 1135 | else | 1188 | else |
| 1136 | return dso__split_kallsyms(dso, map, filter); | 1189 | return dso__split_kallsyms(dso, map, delta, filter); |
| 1137 | } | 1190 | } |
| 1138 | 1191 | ||
| 1139 | static int dso__load_perf_map(struct dso *dso, struct map *map, | 1192 | static int dso__load_perf_map(struct dso *dso, struct map *map, |
| @@ -1424,7 +1477,7 @@ static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz) | |||
| 1424 | continue; | 1477 | continue; |
| 1425 | scnprintf(kallsyms_filename, sizeof(kallsyms_filename), | 1478 | scnprintf(kallsyms_filename, sizeof(kallsyms_filename), |
| 1426 | "%s/%s/kallsyms", dir, dent->d_name); | 1479 | "%s/%s/kallsyms", dir, dent->d_name); |
| 1427 | if (!validate_kcore_modules(kallsyms_filename, map)) { | 1480 | if (!validate_kcore_addresses(kallsyms_filename, map)) { |
| 1428 | strlcpy(dir, kallsyms_filename, dir_sz); | 1481 | strlcpy(dir, kallsyms_filename, dir_sz); |
| 1429 | ret = 0; | 1482 | ret = 0; |
| 1430 | break; | 1483 | break; |
| @@ -1479,7 +1532,7 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map) | |||
| 1479 | if (fd != -1) { | 1532 | if (fd != -1) { |
| 1480 | close(fd); | 1533 | close(fd); |
| 1481 | /* If module maps match go with /proc/kallsyms */ | 1534 | /* If module maps match go with /proc/kallsyms */ |
| 1482 | if (!validate_kcore_modules("/proc/kallsyms", map)) | 1535 | if (!validate_kcore_addresses("/proc/kallsyms", map)) |
| 1483 | goto proc_kallsyms; | 1536 | goto proc_kallsyms; |
| 1484 | } | 1537 | } |
| 1485 | 1538 | ||
