This is the mail archive of the systemtap@sourceware.org mailing list for the systemtap project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFC 2/3] Kprobes: userspace probes adding readpages hook


This patch provides the feature to insert the probes on the pages
that are not present in the memory during registeration. The actual
insertion of probes is differed until the pages are read into the
memory through readpage and readpages() routines defined in address
space operation object.	

To add readpage and readpages() hooks, two new datastructs 
are added to uprobe_module object.
struct address_space_operations *ori_a_ops;
struct address_space_operations user_a_ops;

User space probe also allows the probes to be inserted within the pages 
even if the pages are not in the memory at the time of registration. 
This is done by adding hooks to readpage and readpages. During 
registration, the address space operation object is modified by 
replacing with user space probes's specific readpage and readpages 
routines. So that when the pages are readinto the memory through the 
readpage and readpages address space operations, the probes can be 
automatically inserted into thouse pages. These user space readpage and 
readpages routines internally call the original readpage() and 
readpages() routines and then check if the probes are to be added to 
these pages and then insert the probes on these pages. Overhead of 
adding these hooks are limited to the application on which probes are 
inserted. Thus probes can even be implanted into the pages when not in 
memory through readpage and readpages hooks.

While unregiteration, care should be taken to replace the readpage and
readpages() hooks by original routines if no probes exists on that
application.

Signed-of-by: Prasanna S Panchamukhi <prasanna@in.ibm.com>


---

 linux-2.6.13-prasanna/include/linux/kprobes.h |    2 
 linux-2.6.13-prasanna/kernel/kprobes.c        |  113 ++++++++++++++++++++++++++
 2 files changed, 115 insertions(+)

diff -puN kernel/kprobes.c~kprobes_userspace_probes-readpages kernel/kprobes.c
--- linux-2.6.13/kernel/kprobes.c~kprobes_userspace_probes-readpages	2005-09-14 11:01:18.495513696 +0530
+++ linux-2.6.13-prasanna/kernel/kprobes.c	2005-09-14 11:01:18.550505336 +0530
@@ -652,6 +652,109 @@ static struct uprobe_module *get_module_
 }
 
 /*
+ * Check if the given offset lies within given page range.
+ */
+static int find_page_probe(unsigned long offset, unsigned long page_start)
+{
+      unsigned long page_end = page_start + PAGE_SIZE;
+	if (offset >= page_start && offset < page_end)
+		return 1;
+	return 0;
+}
+
+/*
+ * This function handles the readpages of all modules that have active probes
+ * in them. Here, we first call the original readpages() of this
+ * inode / address_space to actually read the pages into memory. Then, we will
+ * insert all the probes that are specified in this pages before returning.
+ */
+static int up_readpages(struct file *file, struct address_space *mapping,
+			struct list_head *pages, unsigned nr_pages)
+{
+	int retval = 0;
+	struct page *page;
+	struct uprobe_module *m;
+	struct uprobe *up = NULL;
+	struct hlist_node *node;
+
+	m = get_module_by_inode(file->f_dentry->d_inode);
+	if (!m) {
+		printk("up_readpages: major problem. we don't  \
+						have mod for this !!!\n");
+		return -EINVAL;
+	}
+
+	/* call original readpages() */
+	retval = m->ori_a_ops->readpages(file, mapping, pages, nr_pages);
+	if (retval >= 0) {
+		hlist_for_each_entry(up, node, &m->ulist_head, ulist) {
+			/*
+			 * TODO: Walk through readpages page list and get
+			 * pages with probes instead of find_get_page().
+			 */
+			if ((page = find_get_page(mapping,
+				up->offset >> PAGE_CACHE_SHIFT)) != NULL) {
+				if (find_page_probe
+				    (up->offset >> PAGE_CACHE_SHIFT,
+				     page->index << PAGE_CACHE_SHIFT)) {
+					up->page = page;
+					if (!map_uprobe_page(up, 0)) {
+						lock_page(up->page);
+						insert_probe_page(up);
+						unmap_uprobe_page(up);
+						unlock_page(up->page);
+					}
+				}
+				page_cache_release(up->page);
+			}
+		}
+	}
+	return retval;
+}
+
+/*
+ * This function handles the readpage of all modules that have active probes
+ * in them. Here, we first call the original readpage() of this
+ * inode / address_space to actually read the page into memory. Then, we will
+ * insert all the probes that are specified in this page before returning.
+ */
+int up_readpage(struct file *file, struct page *page)
+{
+	int retval = 0;
+	struct uprobe_module *m;
+	struct uprobe *up = NULL;
+	int kprobe_page_mapped = 0;
+	struct hlist_node *node;
+
+	m = get_module_by_inode(file->f_dentry->d_inode);
+	if (!m) {
+		printk("up_readpage: major problem. we don't have mod for this !!!\n");
+		return -EINVAL;
+	}
+
+	/* call original readpage() */
+	retval = m->ori_a_ops->readpage(file, page);
+	if (retval >= 0) {
+		hlist_for_each_entry(up, node, &m->ulist_head, ulist) {
+			if (find_page_probe (up->offset >> PAGE_CACHE_SHIFT,
+					page->index << PAGE_CACHE_SHIFT)) {
+				up->page = page;
+				if (!map_uprobe_page(up, kprobe_page_mapped)) {
+					lock_page(up->page);
+					kprobe_page_mapped = 1;
+					retval = insert_probe_page(up);
+				}
+			}
+		}
+		if (kprobe_page_mapped) {
+			unmap_uprobe_page(up);
+			unlock_page(up->page);
+		}
+	}
+	return retval;
+}
+
+/*
  * Walk the path and get the inode. Check for matching inode with the module
  * list.
  */
@@ -681,6 +784,7 @@ static struct uprobe_module *get_module_
 static struct uprobe_module *get_inode_ops(struct uprobe *up)
 {
 	struct uprobe_module *um = NULL;
+	struct address_space *as;
 	int error;
 	char *temp = up->name;
 
@@ -706,6 +810,13 @@ static struct uprobe_module *get_inode_o
 	hlist_add_head(&up->ulist, &um->ulist_head);
 	list_add(&um->mlist, &uprobe_module_list);
 	um->inode = up->inode;
+	as = up->inode->i_mapping;
+	/* switch i_op to hook into readpage and readpages */
+	um->ori_a_ops = as->a_ops;
+	um->user_a_ops = *as->a_ops;
+	um->user_a_ops.readpage = up_readpage;
+	um->user_a_ops.readpages = up_readpages;
+	as->a_ops = &um->user_a_ops;
 	goto out;
 
 err:
@@ -773,6 +884,8 @@ void unregister_userspace_probe(struct u
 	hlist_del(&up->ulist);
 	if (hlist_empty(&um->ulist_head)) {
 		list_del(&um->mlist);
+		/* unhook readpage */
+		um->inode->i_mapping->a_ops = um->ori_a_ops;
 		ex_write_unlock(up->inode);
 		path_release(&um->nd);	/* release path */
 	}
diff -puN include/linux/kprobes.h~kprobes_userspace_probes-readpages include/linux/kprobes.h
--- linux-2.6.13/include/linux/kprobes.h~kprobes_userspace_probes-readpages	2005-09-14 11:01:18.498513240 +0530
+++ linux-2.6.13-prasanna/include/linux/kprobes.h	2005-09-14 11:01:18.551505184 +0530
@@ -122,6 +122,8 @@ struct uprobe_module {
 	struct list_head mlist;
 	struct inode *inode;
 	struct nameidata nd; /* to hold path/dentry etc. */
+	struct address_space_operations *ori_a_ops;
+	struct address_space_operations user_a_ops;
 };
 
 #ifdef ARCH_SUPPORTS_KRETPROBES

_
-- 

Prasanna S Panchamukhi
Linux Technology Center
India Software Labs, IBM Bangalore
Ph: 91-80-25044636
<prasanna@in.ibm.com>


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]