For RFC, this patch is full of hacks: - non-generic vdso_mnt -- it will not built on !x86_64 - used externs in trace_uprobe.c, rather than clean header-includes
This patch converts vdsofs from lookup-less, renames vdso file name to just "64". It also adds support to uprobe_events for setting uprobe to vdso image file. One can set vdso uprobe now like this: echo 'p:gettimeofday :vdso:/64:0xc50' >> uprobe_events Signed-off-by: Dmitry Safonov <dsafo...@virtuozzo.com> --- arch/x86/entry/vdso/vma.c | 28 ++++++++++++++------------- kernel/trace/trace_uprobe.c | 46 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 53 insertions(+), 21 deletions(-) diff --git a/arch/x86/entry/vdso/vma.c b/arch/x86/entry/vdso/vma.c index e83830e422ae..9e966b649028 100644 --- a/arch/x86/entry/vdso/vma.c +++ b/arch/x86/entry/vdso/vma.c @@ -39,7 +39,7 @@ void __init init_vdso_image(const struct vdso_image *image) image->alt_len)); } -static struct vfsmount *vdso_mnt; +struct vfsmount *vdso_mnt; struct file *vdso_file_64; struct linux_binprm; @@ -401,38 +401,40 @@ static __init struct file *init_vdso_file(const struct vdso_image *vdso_image, const char *name) { struct super_block *sb; - struct qstr name_str; struct inode *inode; struct path path; struct file *res; + int ret; if (IS_ERR(vdso_mnt)) return ERR_CAST(vdso_mnt); sb = vdso_mnt->mnt_sb; - name_str.hash = 0; - name_str.len = strlen(name); - name_str.name = name; - res = ERR_PTR(-ENOMEM); path.mnt = mntget(vdso_mnt); - path.dentry = d_alloc_pseudo(sb, &name_str); - if (!path.dentry) + path.dentry = d_alloc_name(vdso_mnt->mnt_root, name); + if (!path.dentry) { + pr_err("Failed to allocate dentry for %s vdso file\n", name); goto put_path; + } d_set_d_op(path.dentry, &vdso_dops); res = ERR_PTR(-ENOSPC); inode = ramfs_get_inode(sb, NULL, S_IFREG | S_IRUGO | S_IXUGO, 0); - if (!inode) + if (!inode) { + pr_err("Failed to get inode for %s vdso file\n", name); goto put_path; + } inode->i_flags |= S_PRIVATE; - d_instantiate(path.dentry, inode); + d_add(path.dentry, inode); inode->i_size = vdso_image->size; - res = ERR_PTR(add_vdso_pages_to_page_cache(vdso_image, inode)); - if (IS_ERR(res)) + ret = add_vdso_pages_to_page_cache(vdso_image, inode); + if (ret) { + pr_err("Failed to put %s pages in page cache: %d\n", name, ret); goto put_path; + } res = alloc_file(&path, FMODE_READ, &ramfs_file_operations); if (!IS_ERR(res)) @@ -475,7 +477,7 @@ static int __init init_vdso(void) BUG_ON(init_vdso_fs()); - vdso_file_64 = init_vdso_file(&vdso_image_64, "vdso_image_64"); + vdso_file_64 = init_vdso_file(&vdso_image_64, "64"); BUG_ON(IS_ERR(vdso_file_64)); /* notifier priority > KVM */ diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c index a74f2d9ff379..3d4dc6c6ddd9 100644 --- a/kernel/trace/trace_uprobe.c +++ b/kernel/trace/trace_uprobe.c @@ -23,6 +23,7 @@ #include <linux/uprobes.h> #include <linux/namei.h> #include <linux/string.h> +#include <linux/mount.h> #include "trace_probe.h" @@ -352,6 +353,9 @@ end: * * - Remove uprobe: -:[GRP/]EVENT */ +extern struct vfsmount *vdso_mnt; +extern int vfs_path_lookup(struct dentry *, struct vfsmount *, + const char *, unsigned int, struct path *); static int create_trace_uprobe(int argc, char **argv) { struct trace_uprobe *tu; @@ -427,15 +431,41 @@ static int create_trace_uprobe(int argc, char **argv) pr_info("Probe point is not specified.\n"); return -EINVAL; } - arg = strchr(argv[1], ':'); - if (!arg) { - ret = -EINVAL; - goto fail_address_parse; - } + if (argv[1][0] == ':') { + arg = strchr(&argv[1][1], ':'); + if (!arg) { + ret = -EINVAL; + goto fail_address_parse; + } + *arg++ = '\0'; + if (strcmp(&argv[1][1], "vdso")) { + ret = -EINVAL; + goto fail_address_parse; + } + filename = arg; + arg = strchr(filename, ':'); + if (!filename) { + ret = -EINVAL; + goto fail_address_parse; + } + *arg++ = '\0'; + if (!vdso_mnt) { + ret = -ENODEV; + goto fail_address_parse; + } + ret = vfs_path_lookup(vdso_mnt->mnt_root, vdso_mnt, + filename, LOOKUP_FOLLOW, &path); + } else { + arg = strchr(argv[1], ':'); + if (!arg) { + ret = -EINVAL; + goto fail_address_parse; + } - *arg++ = '\0'; - filename = argv[1]; - ret = kern_path(filename, LOOKUP_FOLLOW, &path); + *arg++ = '\0'; + filename = argv[1]; + ret = kern_path(filename, LOOKUP_FOLLOW, &path); + } if (ret) goto fail_address_parse; -- 2.9.0