Skip to content

Commit 508457e

Browse files
committed
dtrace: should not sleep in idr code paths
The idr_preload() causes thread to continue in atomic context. Taking mutex in this code path may lead to deadlock or scheduler problems. This fix alters locking scheme in a way that may cause some latency issues in DTrace framework but will keep host safe. Orabug: 26680802 Signed-off-by: Tomas Jedlicka <[email protected]> Reviewed-by: Nick Alcock <[email protected]>
1 parent e23d136 commit 508457e

File tree

3 files changed

+10
-24
lines changed

3 files changed

+10
-24
lines changed

dtrace/dtrace_ecb.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,11 +164,7 @@ static dtrace_action_t *dtrace_ecb_aggregation_create(dtrace_ecb_t *ecb,
164164
/*
165165
* Get an ID for the aggregation (add it to the idr).
166166
*/
167-
mutex_unlock(&dtrace_lock);
168-
169167
idr_preload(GFP_KERNEL);
170-
mutex_lock(&dtrace_lock);
171-
172168
aggid = idr_alloc_cyclic(&state->dts_agg_idr, agg, 0, 0, GFP_NOWAIT);
173169
idr_preload_end();
174170
if (aggid < 0) {

dtrace/dtrace_probe.c

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -53,18 +53,24 @@ dtrace_id_t dtrace_probe_create(dtrace_provider_id_t prov, const char *mod,
5353
probe = kmem_cache_alloc(dtrace_probe_cachep, __GFP_NOFAIL);
5454

5555
/*
56-
* The ir_preload() function should be called without holding locks.
56+
* The idr_preload() should be called without holding locks as it may
57+
* block. At the same time it is required to protect DTrace structures.
58+
* We can't drop it before idr_preload() and acquire after it because
59+
* we can't sleep in atomic context (until we reach idr_preload_end()).
60+
*
61+
* It is better to delay DTrace framework than traced host so the lock
62+
* is being held for the duration of idr allocation.
63+
*
5764
* When the provider is the DTrace core itself, dtrace_lock will be
5865
* held when we enter this function.
5966
*/
6067
if (provider == dtrace_provider) {
6168
ASSERT(MUTEX_HELD(&dtrace_lock));
62-
mutex_unlock(&dtrace_lock);
69+
} else {
70+
mutex_lock(&dtrace_lock);
6371
}
6472

6573
idr_preload(GFP_KERNEL);
66-
67-
mutex_lock(&dtrace_lock);
6874
id = idr_alloc_cyclic(&dtrace_probe_idr, probe, 0, 0, GFP_NOWAIT);
6975
idr_preload_end();
7076
if (id < 0) {
@@ -1282,16 +1288,7 @@ int dtrace_probe_init(void)
12821288
* We need to drop our locks when calling idr_preload(), so we try to
12831289
* get them back right after.
12841290
*/
1285-
mutex_unlock(&dtrace_lock);
1286-
mutex_unlock(&dtrace_provider_lock);
1287-
mutex_unlock(&cpu_lock);
1288-
12891291
idr_preload(GFP_KERNEL);
1290-
1291-
mutex_lock(&cpu_lock);
1292-
mutex_lock(&dtrace_provider_lock);
1293-
mutex_lock(&dtrace_lock);
1294-
12951292
id = idr_alloc_cyclic(&dtrace_probe_idr, NULL, 0, 0, GFP_NOWAIT);
12961293
idr_preload_end();
12971294

dtrace/dtrace_state.c

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -352,14 +352,7 @@ dtrace_state_t *dtrace_state_create(struct file *file)
352352
* Create a first entry in the aggregation IDR, so that ID 0 is used as
353353
* that gets used as meaning 'none'.
354354
*/
355-
mutex_unlock(&dtrace_lock);
356-
mutex_unlock(&cpu_lock);
357-
358355
idr_preload(GFP_KERNEL);
359-
360-
mutex_lock(&cpu_lock);
361-
mutex_lock(&dtrace_lock);
362-
363356
aggid = idr_alloc_cyclic(&state->dts_agg_idr, NULL, 0, 0, GFP_NOWAIT);
364357
idr_preload_end();
365358

0 commit comments

Comments
 (0)