diff options
author | Wang Nan <wangnan0@huawei.com> | 2016-11-14 23:05:44 -0500 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2016-11-25 09:00:30 -0500 |
commit | d18acd15c6dfb669f0463afa31ac5343594d2fe2 (patch) | |
tree | 518a4ddf76295a74020dd5ec8a9a1282bd2d8beb | |
parent | 8388deb3ba4d36ffcae91a2a01cb2ea6f27553e6 (diff) |
perf tools: Fix kernel version error in ubuntu
On ubuntu the internal kernel version code is different from what can
be retrived from uname:
$ uname -r
4.4.0-47-generic
$ cat /lib/modules/`uname -r`/build/include/generated/uapi/linux/version.h
#define LINUX_VERSION_CODE 263192
#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
$ cat /lib/modules/`uname -r`/build/include/generated/utsrelease.h
#define UTS_RELEASE "4.4.0-47-generic"
#define UTS_UBUNTU_RELEASE_ABI 47
$ cat /proc/version_signature
Ubuntu 4.4.0-47.68-generic 4.4.24
The macro LINUX_VERSION_CODE is set to 4.4.24 (263192 == 0x40418), but
`uname -r` reports 4.4.0.
This mismatch causes LINUX_VERSION_CODE macro passed to BPF script become
an incorrect value, results in magic failure in BPF loading:
$ sudo ./buildperf/perf record -e ./tools/perf/tests/bpf-script-example.c ls
event syntax error: './tools/perf/tests/bpf-script-example.c'
\___ Failed to load program for unknown reason
According to Ubuntu document (https://wiki.ubuntu.com/Kernel/FAQ), the
correct kernel version can be retrived through /proc/version_signature, which
is ubuntu specific.
This patch checks the existance of /proc/version_signature, and returns
version number through parsing this file instead of uname. Version string
is untouched (value returns from uname) because `uname -r` is required
to be consistence with path of kbuild directory in /lib/module.
Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: Alexei Starovoitov <ast@fb.com>
Cc: He Kuang <hekuang@huawei.com>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/20161115040617.69788-2-wangnan0@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r-- | tools/perf/util/util.c | 55 |
1 files changed, 53 insertions, 2 deletions
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 5bbd1f609f1f..67ac765da27a 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c | |||
@@ -637,12 +637,63 @@ bool find_process(const char *name) | |||
637 | return ret ? false : true; | 637 | return ret ? false : true; |
638 | } | 638 | } |
639 | 639 | ||
640 | static int | ||
641 | fetch_ubuntu_kernel_version(unsigned int *puint) | ||
642 | { | ||
643 | ssize_t len; | ||
644 | size_t line_len = 0; | ||
645 | char *ptr, *line = NULL; | ||
646 | int version, patchlevel, sublevel, err; | ||
647 | FILE *vsig = fopen("/proc/version_signature", "r"); | ||
648 | |||
649 | if (!vsig) { | ||
650 | pr_debug("Open /proc/version_signature failed: %s\n", | ||
651 | strerror(errno)); | ||
652 | return -1; | ||
653 | } | ||
654 | |||
655 | len = getline(&line, &line_len, vsig); | ||
656 | fclose(vsig); | ||
657 | err = -1; | ||
658 | if (len <= 0) { | ||
659 | pr_debug("Reading from /proc/version_signature failed: %s\n", | ||
660 | strerror(errno)); | ||
661 | goto errout; | ||
662 | } | ||
663 | |||
664 | ptr = strrchr(line, ' '); | ||
665 | if (!ptr) { | ||
666 | pr_debug("Parsing /proc/version_signature failed: %s\n", line); | ||
667 | goto errout; | ||
668 | } | ||
669 | |||
670 | err = sscanf(ptr + 1, "%d.%d.%d", | ||
671 | &version, &patchlevel, &sublevel); | ||
672 | if (err != 3) { | ||
673 | pr_debug("Unable to get kernel version from /proc/version_signature '%s'\n", | ||
674 | line); | ||
675 | goto errout; | ||
676 | } | ||
677 | |||
678 | if (puint) | ||
679 | *puint = (version << 16) + (patchlevel << 8) + sublevel; | ||
680 | err = 0; | ||
681 | errout: | ||
682 | free(line); | ||
683 | return err; | ||
684 | } | ||
685 | |||
640 | int | 686 | int |
641 | fetch_kernel_version(unsigned int *puint, char *str, | 687 | fetch_kernel_version(unsigned int *puint, char *str, |
642 | size_t str_size) | 688 | size_t str_size) |
643 | { | 689 | { |
644 | struct utsname utsname; | 690 | struct utsname utsname; |
645 | int version, patchlevel, sublevel, err; | 691 | int version, patchlevel, sublevel, err; |
692 | bool int_ver_ready = false; | ||
693 | |||
694 | if (access("/proc/version_signature", R_OK) == 0) | ||
695 | if (!fetch_ubuntu_kernel_version(puint)) | ||
696 | int_ver_ready = true; | ||
646 | 697 | ||
647 | if (uname(&utsname)) | 698 | if (uname(&utsname)) |
648 | return -1; | 699 | return -1; |
@@ -656,12 +707,12 @@ fetch_kernel_version(unsigned int *puint, char *str, | |||
656 | &version, &patchlevel, &sublevel); | 707 | &version, &patchlevel, &sublevel); |
657 | 708 | ||
658 | if (err != 3) { | 709 | if (err != 3) { |
659 | pr_debug("Unablt to get kernel version from uname '%s'\n", | 710 | pr_debug("Unable to get kernel version from uname '%s'\n", |
660 | utsname.release); | 711 | utsname.release); |
661 | return -1; | 712 | return -1; |
662 | } | 713 | } |
663 | 714 | ||
664 | if (puint) | 715 | if (puint && !int_ver_ready) |
665 | *puint = (version << 16) + (patchlevel << 8) + sublevel; | 716 | *puint = (version << 16) + (patchlevel << 8) + sublevel; |
666 | return 0; | 717 | return 0; |
667 | } | 718 | } |