Commit 45e0a79a authored by Oleg Nesterov's avatar Oleg Nesterov

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.
Reported-by: default avatarDenys Vlasenko <dvlasenk@redhat.com>
Suggested-by: default avatarHugh Dickins <hughd@google.com>
Acked-by: default avatarSrikar Dronamraju <srikar@linux.vnet.ibm.com>
Signed-off-by: default avatarOleg Nesterov <oleg@redhat.com>
parent 7fa31348
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include "../../mm/internal.h" /* munlock_vma_page */ #include "../../mm/internal.h" /* munlock_vma_page */
#include <linux/percpu-rwsem.h> #include <linux/percpu-rwsem.h>
#include <linux/task_work.h> #include <linux/task_work.h>
#include <linux/shmem_fs.h>
#include <linux/uprobes.h> #include <linux/uprobes.h>
...@@ -537,10 +538,14 @@ static int __copy_insn(struct address_space *mapping, struct file *filp, ...@@ -537,10 +538,14 @@ static int __copy_insn(struct address_space *mapping, struct file *filp,
{ {
struct page *page; struct page *page;
/* /*
* Ensure that the page that has the original instruction is * Ensure that the page that has the original instruction is populated
* populated and in page-cache. * 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)) if (IS_ERR(page))
return PTR_ERR(page); return PTR_ERR(page);
...@@ -876,8 +881,8 @@ int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer * ...@@ -876,8 +881,8 @@ int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *
if (!uc->handler && !uc->ret_handler) if (!uc->handler && !uc->ret_handler)
return -EINVAL; return -EINVAL;
/* copy_insn()->read_mapping_page() needs ->readpage() */ /* copy_insn() uses read_mapping_page() or shmem_read_mapping_page() */
if (!inode->i_mapping->a_ops->readpage) if (!inode->i_mapping->a_ops->readpage && !shmem_mapping(inode->i_mapping))
return -EIO; return -EIO;
/* Racy, just to catch the obvious mistakes */ /* Racy, just to catch the obvious mistakes */
if (offset > i_size_read(inode)) if (offset > i_size_read(inode))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment