@@ -41,6 +41,8 @@ static struct rb_root uprobes_tree = RB_ROOT;
41
41
42
42
static DEFINE_RWLOCK (uprobes_treelock ); /* serialize rbtree access */
43
43
44
+ DEFINE_STATIC_SRCU (uprobes_srcu );
45
+
44
46
#define UPROBES_HASH_SZ 13
45
47
/* serialize uprobe->pending_list */
46
48
static struct mutex uprobes_mmap_mutex [UPROBES_HASH_SZ ];
@@ -59,6 +61,7 @@ struct uprobe {
59
61
struct list_head pending_list ;
60
62
struct uprobe_consumer * consumers ;
61
63
struct inode * inode ; /* Also hold a ref to inode */
64
+ struct rcu_head rcu ;
62
65
loff_t offset ;
63
66
loff_t ref_ctr_offset ;
64
67
unsigned long flags ;
@@ -617,6 +620,13 @@ static inline bool uprobe_is_active(struct uprobe *uprobe)
617
620
return !RB_EMPTY_NODE (& uprobe -> rb_node );
618
621
}
619
622
623
+ static void uprobe_free_rcu (struct rcu_head * rcu )
624
+ {
625
+ struct uprobe * uprobe = container_of (rcu , struct uprobe , rcu );
626
+
627
+ kfree (uprobe );
628
+ }
629
+
620
630
static void put_uprobe (struct uprobe * uprobe )
621
631
{
622
632
if (!refcount_dec_and_test (& uprobe -> ref ))
@@ -638,7 +648,7 @@ static void put_uprobe(struct uprobe *uprobe)
638
648
delayed_uprobe_remove (uprobe , NULL );
639
649
mutex_unlock (& delayed_uprobe_lock );
640
650
641
- kfree ( uprobe );
651
+ call_srcu ( & uprobes_srcu , & uprobe -> rcu , uprobe_free_rcu );
642
652
}
643
653
644
654
static __always_inline
@@ -680,33 +690,25 @@ static inline int __uprobe_cmp(struct rb_node *a, const struct rb_node *b)
680
690
return uprobe_cmp (u -> inode , u -> offset , __node_2_uprobe (b ));
681
691
}
682
692
683
- static struct uprobe * __find_uprobe (struct inode * inode , loff_t offset )
693
+ /*
694
+ * Assumes being inside RCU protected region.
695
+ * No refcount is taken on returned uprobe.
696
+ */
697
+ static struct uprobe * find_uprobe_rcu (struct inode * inode , loff_t offset )
684
698
{
685
699
struct __uprobe_key key = {
686
700
.inode = inode ,
687
701
.offset = offset ,
688
702
};
689
- struct rb_node * node = rb_find (& key , & uprobes_tree , __uprobe_cmp_key );
690
-
691
- if (node )
692
- return try_get_uprobe (__node_2_uprobe (node ));
693
-
694
- return NULL ;
695
- }
703
+ struct rb_node * node ;
696
704
697
- /*
698
- * Find a uprobe corresponding to a given inode:offset
699
- * Acquires uprobes_treelock
700
- */
701
- static struct uprobe * find_uprobe (struct inode * inode , loff_t offset )
702
- {
703
- struct uprobe * uprobe ;
705
+ lockdep_assert (srcu_read_lock_held (& uprobes_srcu ));
704
706
705
707
read_lock (& uprobes_treelock );
706
- uprobe = __find_uprobe ( inode , offset );
708
+ node = rb_find ( & key , & uprobes_tree , __uprobe_cmp_key );
707
709
read_unlock (& uprobes_treelock );
708
710
709
- return uprobe ;
711
+ return node ? __node_2_uprobe ( node ) : NULL ;
710
712
}
711
713
712
714
/*
@@ -1080,10 +1082,10 @@ register_for_each_vma(struct uprobe *uprobe, struct uprobe_consumer *new)
1080
1082
goto free ;
1081
1083
/*
1082
1084
* We take mmap_lock for writing to avoid the race with
1083
- * find_active_uprobe () which takes mmap_lock for reading.
1085
+ * find_active_uprobe_rcu () which takes mmap_lock for reading.
1084
1086
* Thus this install_breakpoint() can not make
1085
- * is_trap_at_addr() true right after find_uprobe ()
1086
- * returns NULL in find_active_uprobe ().
1087
+ * is_trap_at_addr() true right after find_uprobe_rcu ()
1088
+ * returns NULL in find_active_uprobe_rcu ().
1087
1089
*/
1088
1090
mmap_write_lock (mm );
1089
1091
vma = find_vma (mm , info -> vaddr );
@@ -1884,9 +1886,13 @@ static void prepare_uretprobe(struct uprobe *uprobe, struct pt_regs *regs)
1884
1886
return ;
1885
1887
}
1886
1888
1889
+ /* we need to bump refcount to store uprobe in utask */
1890
+ if (!try_get_uprobe (uprobe ))
1891
+ return ;
1892
+
1887
1893
ri = kmalloc (sizeof (struct return_instance ), GFP_KERNEL );
1888
1894
if (!ri )
1889
- return ;
1895
+ goto fail ;
1890
1896
1891
1897
trampoline_vaddr = uprobe_get_trampoline_vaddr ();
1892
1898
orig_ret_vaddr = arch_uretprobe_hijack_return_addr (trampoline_vaddr , regs );
@@ -1913,11 +1919,7 @@ static void prepare_uretprobe(struct uprobe *uprobe, struct pt_regs *regs)
1913
1919
}
1914
1920
orig_ret_vaddr = utask -> return_instances -> orig_ret_vaddr ;
1915
1921
}
1916
- /*
1917
- * uprobe's refcnt is positive, held by caller, so it's safe to
1918
- * unconditionally bump it one more time here
1919
- */
1920
- ri -> uprobe = get_uprobe (uprobe );
1922
+ ri -> uprobe = uprobe ;
1921
1923
ri -> func = instruction_pointer (regs );
1922
1924
ri -> stack = user_stack_pointer (regs );
1923
1925
ri -> orig_ret_vaddr = orig_ret_vaddr ;
@@ -1928,8 +1930,9 @@ static void prepare_uretprobe(struct uprobe *uprobe, struct pt_regs *regs)
1928
1930
utask -> return_instances = ri ;
1929
1931
1930
1932
return ;
1931
- fail :
1933
+ fail :
1932
1934
kfree (ri );
1935
+ put_uprobe (uprobe );
1933
1936
}
1934
1937
1935
1938
/* Prepare to single-step probed instruction out of line. */
@@ -1944,22 +1947,30 @@ pre_ssout(struct uprobe *uprobe, struct pt_regs *regs, unsigned long bp_vaddr)
1944
1947
if (!utask )
1945
1948
return - ENOMEM ;
1946
1949
1950
+ if (!try_get_uprobe (uprobe ))
1951
+ return - EINVAL ;
1952
+
1947
1953
xol_vaddr = xol_get_insn_slot (uprobe );
1948
- if (!xol_vaddr )
1949
- return - ENOMEM ;
1954
+ if (!xol_vaddr ) {
1955
+ err = - ENOMEM ;
1956
+ goto err_out ;
1957
+ }
1950
1958
1951
1959
utask -> xol_vaddr = xol_vaddr ;
1952
1960
utask -> vaddr = bp_vaddr ;
1953
1961
1954
1962
err = arch_uprobe_pre_xol (& uprobe -> arch , regs );
1955
1963
if (unlikely (err )) {
1956
1964
xol_free_insn_slot (current );
1957
- return err ;
1965
+ goto err_out ;
1958
1966
}
1959
1967
1960
1968
utask -> active_uprobe = uprobe ;
1961
1969
utask -> state = UTASK_SSTEP ;
1962
1970
return 0 ;
1971
+ err_out :
1972
+ put_uprobe (uprobe );
1973
+ return err ;
1963
1974
}
1964
1975
1965
1976
/*
@@ -2043,7 +2054,8 @@ static int is_trap_at_addr(struct mm_struct *mm, unsigned long vaddr)
2043
2054
return is_trap_insn (& opcode );
2044
2055
}
2045
2056
2046
- static struct uprobe * find_active_uprobe (unsigned long bp_vaddr , int * is_swbp )
2057
+ /* assumes being inside RCU protected region */
2058
+ static struct uprobe * find_active_uprobe_rcu (unsigned long bp_vaddr , int * is_swbp )
2047
2059
{
2048
2060
struct mm_struct * mm = current -> mm ;
2049
2061
struct uprobe * uprobe = NULL ;
@@ -2056,7 +2068,7 @@ static struct uprobe *find_active_uprobe(unsigned long bp_vaddr, int *is_swbp)
2056
2068
struct inode * inode = file_inode (vma -> vm_file );
2057
2069
loff_t offset = vaddr_to_offset (vma , bp_vaddr );
2058
2070
2059
- uprobe = find_uprobe (inode , offset );
2071
+ uprobe = find_uprobe_rcu (inode , offset );
2060
2072
}
2061
2073
2062
2074
if (!uprobe )
@@ -2202,13 +2214,15 @@ static void handle_swbp(struct pt_regs *regs)
2202
2214
{
2203
2215
struct uprobe * uprobe ;
2204
2216
unsigned long bp_vaddr ;
2205
- int is_swbp ;
2217
+ int is_swbp , srcu_idx ;
2206
2218
2207
2219
bp_vaddr = uprobe_get_swbp_addr (regs );
2208
2220
if (bp_vaddr == uprobe_get_trampoline_vaddr ())
2209
2221
return uprobe_handle_trampoline (regs );
2210
2222
2211
- uprobe = find_active_uprobe (bp_vaddr , & is_swbp );
2223
+ srcu_idx = srcu_read_lock (& uprobes_srcu );
2224
+
2225
+ uprobe = find_active_uprobe_rcu (bp_vaddr , & is_swbp );
2212
2226
if (!uprobe ) {
2213
2227
if (is_swbp > 0 ) {
2214
2228
/* No matching uprobe; signal SIGTRAP. */
@@ -2224,7 +2238,7 @@ static void handle_swbp(struct pt_regs *regs)
2224
2238
*/
2225
2239
instruction_pointer_set (regs , bp_vaddr );
2226
2240
}
2227
- return ;
2241
+ goto out ;
2228
2242
}
2229
2243
2230
2244
/* change it in advance for ->handler() and restart */
@@ -2259,12 +2273,12 @@ static void handle_swbp(struct pt_regs *regs)
2259
2273
if (arch_uprobe_skip_sstep (& uprobe -> arch , regs ))
2260
2274
goto out ;
2261
2275
2262
- if (! pre_ssout (uprobe , regs , bp_vaddr ))
2263
- return ;
2276
+ if (pre_ssout (uprobe , regs , bp_vaddr ))
2277
+ goto out ;
2264
2278
2265
- /* arch_uprobe_skip_sstep() succeeded, or restart if can't singlestep */
2266
2279
out :
2267
- put_uprobe (uprobe );
2280
+ /* arch_uprobe_skip_sstep() succeeded, or restart if can't singlestep */
2281
+ srcu_read_unlock (& uprobes_srcu , srcu_idx );
2268
2282
}
2269
2283
2270
2284
/*
0 commit comments