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 | ||