uprobes: Shift ->readpage check from __copy_insn() to uprobe_register()
Subsystems (2)
Oleg Nesterov
maintainerPATCH 1/1 uprobes: Shift ->readpage check from __copy_insn() to uprobe_register()
Sorry for double-posting, but it seems that this patch didn't reach lkml. Let me resend it just on case. Plus another patch in reply, on top of this change.
-------------------------------------------------------------------------------
Subject: [PATCH] uprobes: Shift ->readpage check from __copy_insn() to uprobe_register()
copy_insn() fails with -EIO if ->readpage == NULL, but this error is not propagated unless uprobe_register() path finds ->mm which already mmaps this file. In this case (say) "perf record" does not actually install the probe, but the user can't know about this.
Move this check into uprobe_register() so that this problem can be detected earlier and reported to user.
Note: this is still not perfect,
- copy_insn() and arch_uprobe_analyze_insn() should be called by uprobe_register() but this is not simple, we need vm_file for read_mapping_page() (although perhaps we can pass NULL), and we need ->mm for is_64bit_mm() (although this logic is broken anyway).
- uprobe_register() should be called by create_trace_uprobe(), not by probe_event_enable(), so that an error can be detected at "perf probe -x" time. This also needs more changes in the core uprobe code, uprobe register/unregister interface was poorly designed from the very beginning.
--- kernel/events/uprobes.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-)
kernel/events/uprobes.c +3 -3
@@ -536,9 +536,6 @@ static int __copy_insn(struct address_space *mapping, struct file *filp, void *insn, int nbytes, loff_t offset) { struct page *page; - -if (!mapping->a_ops->readpage) -return -EIO ;/* * Ensure that the page that has the original instruction is * populated and in page-cache.
@@ -879,6 +876,9 @@ int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *if (!uc->handler && !uc->ret_handler)return -EINVAL ; +/* copy_insn()->read_mapping_page() needs ->readpage() */ +if (!inode->i_mapping->a_ops->readpage) +return -EIO ;/* Racy, just to catch the obvious mistakes */ if (offset >i_size_read (inode))return -EINVAL ;
Signature · 1 line
1.5.5.1
Oleg Nesterov
maintainerPATCH 1/1 uprobes: Teach copy_insn() to support tmpfs
tmpfs is widely used but as Denys reports shmem_aops doesn't have ->readpage() and thus you can't probe a binary on this filesystem.
As Hugh suggested we can use shmem_read_mapping_page() in this case, just we need to check shmem_mapping() if ->readpage == NULL.
--- kernel/events/uprobes.c | 15 ++++++++++----- 1 files changed, 10 insertions(+), 5 deletions(-)
kernel/events/uprobes.c +10 -5
@@ -36,6 +36,7 @@#include "../../mm/internal.h" /* munlock_vma_page */ #include <linux/percpu-rwsem.h> #include <linux/task_work.h> +#include <linux/shmem_fs.h> #include <linux/uprobes.h>
@@ -537,10 +538,14 @@ static int __copy_insn(struct address_space *mapping, struct file *filp, {struct page *page;/* -* Ensure that the page that has the original instruction is -* populated and in page-cache. +* Ensure that the page that has the original instruction is populated +* and in page-cache. If ->readpage == NULL it must be shmem_mapping(), +* see uprobe_register(). */ - page =read_mapping_page (mapping, offset >>PAGE_CACHE_SHIFT , filp); +if (mapping->a_ops->readpage) + page =read_mapping_page (mapping, offset >>PAGE_CACHE_SHIFT , filp); +else + page =shmem_read_mapping_page (mapping, offset >>PAGE_CACHE_SHIFT );if (IS_ERR (page))return PTR_ERR (page);
@@ -876,8 +881,8 @@ int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *if (!uc->handler && !uc->ret_handler)return -EINVAL ; -/* copy_insn()->read_mapping_page() needs ->readpage() */ -if (!inode->i_mapping->a_ops->readpage) +/* copy_insn() uses read_mapping_page() or shmem_read_mapping_page() */ +if (!inode->i_mapping->a_ops->readpage && !shmem_mapping (inode->i_mapping))return -EIO ;/* Racy, just to catch the obvious mistakes */ if (offset >i_size_read (inode))
Signature · 1 line
1.5.5.1
Re: [PATCH] uprobes: Teach copy_insn() to support tmpfs
Quoted 9 lines · Oleg Nesterov
tmpfs is widely used but as Denys reports
shmem_aopsdoesn't have ->readpage() and thus you can't probe a binary on this filesystem.As Hugh suggested we can use
shmem_read_mapping_page()in this case, just we need to checkshmem_mapping()if ->readpage == NULL.Reported-by Denys Vlasenko <[email protected]>Suggested-by Hugh Dickins <[email protected]>Signed-off-by Oleg Nesterov <[email protected]>
Signature · 2 lines
Thanks and Regards Srikar Dronamraju
tip-bot for Oleg Nesterov
merge bot[tip:perf/core] uprobes: Teach copy_insn() to support tmpfs
In reply to Oleg Nesterovuprobes: Teach copy_insn() to support tmpfs
Commit-ID: 40814f6805a524130a5ec313871147f7aa9b5318 Gitweb: http://git.kernel.org/tip/40814f6805a524130a5ec313871147f7aa9b5318 Author: Oleg Nesterov <[email protected]> AuthorDate: Mon, 19 May 2014 20:41:36 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 5 Jun 2014 12:30:11 +0200
uprobes: Teach copy_insn() to support tmpfs
tmpfs is widely used but as Denys reports shmem_aops doesn't have ->readpage() and thus you can't probe a binary on this filesystem.
As Hugh suggested we can use shmem_read_mapping_page() in this case, just we need to check shmem_mapping() if ->readpage == NULL.
--- kernel/events/uprobes.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-)
kernel/events/uprobes.c +10 -5
@@ -36,6 +36,7 @@#include "../../mm/internal.h" /* munlock_vma_page */ #include <linux/percpu-rwsem.h> #include <linux/task_work.h> +#include <linux/shmem_fs.h> #include <linux/uprobes.h>
@@ -537,10 +538,14 @@ static int __copy_insn(struct address_space *mapping, struct file *filp, {struct page *page;/* -* Ensure that the page that has the original instruction is -* populated and in page-cache. +* Ensure that the page that has the original instruction is populated +* and in page-cache. If ->readpage == NULL it must be shmem_mapping(), +* see uprobe_register(). */ - page =read_mapping_page (mapping, offset >>PAGE_CACHE_SHIFT , filp); +if (mapping->a_ops->readpage) + page =read_mapping_page (mapping, offset >>PAGE_CACHE_SHIFT , filp); +else + page =shmem_read_mapping_page (mapping, offset >>PAGE_CACHE_SHIFT );if (IS_ERR (page))return PTR_ERR (page);
@@ -876,8 +881,8 @@ int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *if (!uc->handler && !uc->ret_handler)return -EINVAL ; -/* copy_insn()->read_mapping_page() needs ->readpage() */ -if (!inode->i_mapping->a_ops->readpage) +/* copy_insn() uses read_mapping_page() or shmem_read_mapping_page() */ +if (!inode->i_mapping->a_ops->readpage && !shmem_mapping (inode->i_mapping))return -EIO ;/* Racy, just to catch the obvious mistakes */ if (offset >i_size_read (inode))
Quoted 23 lines · Oleg Nesterov
Sorry for double-posting, but it seems that this patch didn't reach lkml. Let me resend it just on case. Plus another patch in reply, on top of this change.
-------------------------------------------------------------------------------
Subject: [PATCH] uprobes: Shift ->readpage check from__copy_insn()touprobe_register()
copy_insn()fails with-EIOif ->readpage == NULL, but this error is not propagated unlessuprobe_register()path finds ->mm which already mmaps this file. In this case (say) "perf record" does not actually install the probe, but the user can't know about this.Move this check into
uprobe_register()so that this problem can be detected earlier and reported to user.Note: this is still not perfect,
-
copy_insn()andarch_uprobe_analyze_insn()should be called byuprobe_register()but this is not simple, we needvm_fileforread_mapping_page()(although perhaps we can pass NULL), and we need ->mm foris_64bit_mm()(although this logic is broken anyway).
Quoted 8 lines
-
uprobe_register()should be called bycreate_trace_uprobe(), not byprobe_event_enable(), so that an error can be detected at "perf probe -x" time. This also needs more changes in the core uprobe code, uprobe register/unregister interface was poorly designed from the very beginning.Reported-by Denys Vlasenko <[email protected]>Signed-off-by Oleg Nesterov <[email protected]>
Signature · 2 lines
Thanks and Regards Srikar Dronamraju
tip-bot for Oleg Nesterov
merge bot[tip:perf/core] uprobes: Shift ->readpage check from __copy_insn( ) to uprobe_register()
In reply to Oleg Nesterovuprobes: Shift ->readpage check from __copy_insn() to uprobe_register()
Commit-ID: 41ccba029e9492dd0fc1bf5c23b72c6322a6dfe9 Gitweb: http://git.kernel.org/tip/41ccba029e9492dd0fc1bf5c23b72c6322a6dfe9 Author: Oleg Nesterov <[email protected]> AuthorDate: Mon, 19 May 2014 20:40:54 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 5 Jun 2014 12:30:07 +0200
uprobes: Shift ->readpage check from __copy_insn() to uprobe_register()
copy_insn() fails with -EIO if ->readpage == NULL, but this error is not propagated unless uprobe_register() path finds ->mm which already mmaps this file. In this case (say) "perf record" does not actually install the probe, but the user can't know about this.
Move this check into uprobe_register() so that this problem can be detected earlier and reported to user.
Note: this is still not perfect,
- copy_insn() and arch_uprobe_analyze_insn() should be called by uprobe_register() but this is not simple, we need vm_file for read_mapping_page() (although perhaps we can pass NULL), and we need ->mm for is_64bit_mm() (although this logic is broken anyway).
- uprobe_register() should be called by create_trace_uprobe(), not by probe_event_enable(), so that an error can be detected at "perf probe -x" time. This also needs more changes in the core uprobe code, uprobe register/unregister interface was poorly designed from the very beginning.
--- kernel/events/uprobes.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
kernel/events/uprobes.c +3 -3
@@ -536,9 +536,6 @@ static int __copy_insn(struct address_space *mapping, struct file *filp, void *insn, int nbytes, loff_t offset) { struct page *page; - -if (!mapping->a_ops->readpage) -return -EIO ;/* * Ensure that the page that has the original instruction is * populated and in page-cache.
@@ -879,6 +876,9 @@ int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *if (!uc->handler && !uc->ret_handler)return -EINVAL ; +/* copy_insn()->read_mapping_page() needs ->readpage() */ +if (!inode->i_mapping->a_ops->readpage) +return -EIO ;/* Racy, just to catch the obvious mistakes */ if (offset >i_size_read (inode))return -EINVAL ;