Skip to content

Commit

Permalink
perf tools: Fix kernel version error in ubuntu
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Wang Nan authored and Arnaldo Carvalho de Melo committed Nov 25, 2016
1 parent 8388deb commit d18acd1
Showing 1 changed file with 53 additions and 2 deletions.
55 changes: 53 additions & 2 deletions tools/perf/util/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -637,12 +637,63 @@ bool find_process(const char *name)
return ret ? false : true;
}

static int
fetch_ubuntu_kernel_version(unsigned int *puint)
{
ssize_t len;
size_t line_len = 0;
char *ptr, *line = NULL;
int version, patchlevel, sublevel, err;
FILE *vsig = fopen("/proc/version_signature", "r");

if (!vsig) {
pr_debug("Open /proc/version_signature failed: %s\n",
strerror(errno));
return -1;
}

len = getline(&line, &line_len, vsig);
fclose(vsig);
err = -1;
if (len <= 0) {
pr_debug("Reading from /proc/version_signature failed: %s\n",
strerror(errno));
goto errout;
}

ptr = strrchr(line, ' ');
if (!ptr) {
pr_debug("Parsing /proc/version_signature failed: %s\n", line);
goto errout;
}

err = sscanf(ptr + 1, "%d.%d.%d",
&version, &patchlevel, &sublevel);
if (err != 3) {
pr_debug("Unable to get kernel version from /proc/version_signature '%s'\n",
line);
goto errout;
}

if (puint)
*puint = (version << 16) + (patchlevel << 8) + sublevel;
err = 0;
errout:
free(line);
return err;
}

int
fetch_kernel_version(unsigned int *puint, char *str,
size_t str_size)
{
struct utsname utsname;
int version, patchlevel, sublevel, err;
bool int_ver_ready = false;

if (access("/proc/version_signature", R_OK) == 0)
if (!fetch_ubuntu_kernel_version(puint))
int_ver_ready = true;

if (uname(&utsname))
return -1;
Expand All @@ -656,12 +707,12 @@ fetch_kernel_version(unsigned int *puint, char *str,
&version, &patchlevel, &sublevel);

if (err != 3) {
pr_debug("Unablt to get kernel version from uname '%s'\n",
pr_debug("Unable to get kernel version from uname '%s'\n",
utsname.release);
return -1;
}

if (puint)
if (puint && !int_ver_ready)
*puint = (version << 16) + (patchlevel << 8) + sublevel;
return 0;
}
Expand Down

0 comments on commit d18acd1

Please sign in to comment.