return 0;
 }
 
+/*
+ * Uprobe with multiple reference counter is not allowed. i.e.
+ * If inode and offset matches, reference counter offset *must*
+ * match as well. Though, there is one exception: If user is
+ * replacing old trace_uprobe with new one(same group/event),
+ * then we allow same uprobe with new reference counter as far
+ * as the new one does not conflict with any other existing
+ * ones.
+ */
+static struct trace_uprobe *find_old_trace_uprobe(struct trace_uprobe *new)
+{
+       struct trace_uprobe *tmp, *old = NULL;
+       struct inode *new_inode = d_real_inode(new->path.dentry);
+
+       old = find_probe_event(trace_event_name(&new->tp.call),
+                               new->tp.call.class->system);
+
+       list_for_each_entry(tmp, &uprobe_list, list) {
+               if ((old ? old != tmp : true) &&
+                   new_inode == d_real_inode(tmp->path.dentry) &&
+                   new->offset == tmp->offset &&
+                   new->ref_ctr_offset != tmp->ref_ctr_offset) {
+                       pr_warn("Reference counter offset mismatch.");
+                       return ERR_PTR(-EINVAL);
+               }
+       }
+       return old;
+}
+
 /* Register a trace_uprobe and probe_event */
 static int register_trace_uprobe(struct trace_uprobe *tu)
 {
        mutex_lock(&uprobe_lock);
 
        /* register as an event */
-       old_tu = find_probe_event(trace_event_name(&tu->tp.call),
-                       tu->tp.call.class->system);
+       old_tu = find_old_trace_uprobe(tu);
+       if (IS_ERR(old_tu)) {
+               ret = PTR_ERR(old_tu);
+               goto end;
+       }
+
        if (old_tu) {
                /* delete old event */
                ret = unregister_trace_uprobe(old_tu);