Skip to content

Commit c8ded18

Browse files
committed
Merge branch 'qu6-rel-topic' into uek-build
2 parents 4ad8c84 + a88f79f commit c8ded18

File tree

14 files changed

+624
-62
lines changed

14 files changed

+624
-62
lines changed

arch/sparc/kernel/fbt_blacklist.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,9 @@ BL_DENTRY(void *, gup_pud_range)
2828
BL_DENTRY(void *, gup_pmd_range)
2929
BL_DENTRY(void *, gup_huge_pmd)
3030
BL_DENTRY(void *, gup_pte_range)
31+
32+
/*
33+
* Functions used in dtrace_sync().
34+
*/
35+
BL_DENTRY(void *, find_next_bit)
36+
BL_DENTRY(void *, _find_next_bit)

arch/x86/kernel/fbt_blacklist.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,9 @@ BL_DENTRY(void *, gup_pmd_range)
6666
BL_DENTRY(void *, gup_huge_pmd)
6767
BL_DENTRY(void *, gup_pte_range)
6868
BL_DENTRY(void *, pte_mfn_to_pfn)
69+
70+
/*
71+
* Functions used in dtrace_sync().
72+
*/
73+
BL_DENTRY(void *, find_next_bit)
74+
BL_DENTRY(void *, _find_next_bit)

dtrace/dtrace_ecb.c

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,41 @@ static dtrace_action_t *dtrace_ecb_aggregation_create(dtrace_ecb_t *ecb,
7777
break;
7878
}
7979

80+
case DTRACEAGG_LLQUANTIZE: {
81+
uint16_t factor = DTRACE_LLQUANTIZE_FACTOR(desc->dtad_arg);
82+
uint16_t lmag = DTRACE_LLQUANTIZE_LMAG(desc->dtad_arg);
83+
uint16_t hmag = DTRACE_LLQUANTIZE_HMAG(desc->dtad_arg);
84+
uint16_t steps = DTRACE_LLQUANTIZE_STEPS(desc->dtad_arg);
85+
86+
agg->dtag_initial = desc->dtad_arg;
87+
agg->dtag_aggregate = dtrace_aggregate_llquantize;
88+
89+
/*
90+
* 64 is the largest hmag can practically be (for the smallest
91+
* possible value of factor, 2). libdtrace has already checked
92+
* for overflow, so if hmag > 64, we have corrupted DOF.
93+
*/
94+
if (factor < 2 || steps == 0 || hmag > 64)
95+
goto err;
96+
97+
/*
98+
* The size of the buffer for an llquantize() is given by:
99+
* (hmag-lmag+1) logarithmic ranges
100+
* x
101+
* (steps - steps/factor) bins per range
102+
* x
103+
* 2 signs
104+
* +
105+
* two overflow bins
106+
* +
107+
* one underflow bin
108+
* +
109+
* beginning word to encode factor,lmag,hmag,steps
110+
*/
111+
size = ((hmag-lmag+1)*(steps-steps/factor)*2+4) * sizeof (uint64_t);
112+
break;
113+
}
114+
80115
case DTRACEAGG_AVG:
81116
agg->dtag_aggregate = dtrace_aggregate_avg;
82117
size = sizeof(uint64_t) * 2;
@@ -129,11 +164,7 @@ static dtrace_action_t *dtrace_ecb_aggregation_create(dtrace_ecb_t *ecb,
129164
/*
130165
* Get an ID for the aggregation (add it to the idr).
131166
*/
132-
mutex_unlock(&dtrace_lock);
133-
134167
idr_preload(GFP_KERNEL);
135-
mutex_lock(&dtrace_lock);
136-
137168
aggid = idr_alloc_cyclic(&state->dts_agg_idr, agg, 0, 0, GFP_NOWAIT);
138169
idr_preload_end();
139170
if (aggid < 0) {
@@ -222,6 +253,7 @@ static int dtrace_ecb_action_add(dtrace_ecb_t *ecb, dtrace_actdesc_t *desc)
222253
state, (char *)(uintptr_t)arg);
223254
}
224255

256+
case DTRACEACT_TRACEMEM:
225257
case DTRACEACT_LIBACT:
226258
case DTRACEACT_DIFEXPR:
227259
if (dp == NULL)
@@ -547,6 +579,11 @@ static dtrace_ecb_t *dtrace_ecb_add(dtrace_state_t *state,
547579
}
548580

549581
ecbs = vzalloc(necbs * sizeof(*ecbs));
582+
if (ecbs == NULL) {
583+
kfree(ecb);
584+
return NULL;
585+
}
586+
550587
if (oecbs != NULL)
551588
memcpy(ecbs, oecbs, state->dts_necbs * sizeof(*ecbs));
552589

@@ -591,6 +628,9 @@ static dtrace_ecb_t *dtrace_ecb_create(dtrace_state_t *state,
591628
ASSERT(state != NULL);
592629

593630
ecb = dtrace_ecb_add(state, probe);
631+
if (ecb == NULL)
632+
return NULL;
633+
594634
ecb->dte_uarg = desc->dted_uarg;
595635

596636
if ((pred = desc->dted_pred.dtpdd_predicate) != NULL) {

dtrace/dtrace_isa.c

Lines changed: 124 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <linux/mm.h>
2121
#include <linux/smp.h>
2222
#include <linux/uaccess.h>
23+
#include <linux/cpumask.h>
2324
#include <asm/cacheflush.h>
2425
#include <asm/ptrace.h>
2526
#include <asm/stacktrace.h>
@@ -36,10 +37,6 @@ int dtrace_getipl(void)
3637
return in_interrupt();
3738
}
3839

39-
static void dtrace_sync_func(void)
40-
{
41-
}
42-
4340
void dtrace_xcall(processorid_t cpu, dtrace_xcall_t func, void *arg)
4441
{
4542
if (cpu == DTRACE_CPUALL) {
@@ -48,14 +45,133 @@ void dtrace_xcall(processorid_t cpu, dtrace_xcall_t func, void *arg)
4845
smp_call_function_single(cpu, func, arg, 1);
4946
}
5047

51-
void dtrace_sync(void)
48+
void dtrace_toxic_ranges(void (*func)(uintptr_t, uintptr_t))
5249
{
53-
dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)dtrace_sync_func, NULL);
50+
/* FIXME */
5451
}
5552

56-
void dtrace_toxic_ranges(void (*func)(uintptr_t, uintptr_t))
53+
/*
54+
* Note: not called from probe context. This function is called
55+
* asynchronously (and at a regular interval) from outside of probe context
56+
* by the DTrace framework to sync shared data which DTrace probe context
57+
* may access without locks.
58+
*
59+
* Whenever the framework updates data which can be accessed from probe context,
60+
* the framework then calls dtrace_sync(). dtrace_sync() guarantees all probes
61+
* are using the new data before returning.
62+
*
63+
* See the comment in dtrace_impl.h which describes this algorithm.
64+
* The cpuc_in_probe_ctxt flag is an increasing 16-bit count. It is odd when
65+
* in DTrace probe context and even when not in DTrace probe context.
66+
* The upper 15 bits are a counter which are incremented when exiting DTrace
67+
* probe context. These upper 15 bits are used to detect "sample aliasing":
68+
* i.e. the target CPU is not in DTrace probe context between samples but
69+
* continually enters probe context just before being sampled.
70+
*
71+
* dtrace_sync() loops over NCPUs. CPUs which are not in DTrace probe context
72+
* (cpuc_in_probe_ctxt is even) are removed from the list. This is repeated
73+
* until there are no CPUs left in the sync list.
74+
*
75+
* In the rare cases where dtrace_sync() loops over all NCPUs more than
76+
* dtrace_sync_sample_count times, dtrace_sync() then spins on one CPU's
77+
* cpuc_in_probe_ctxt count until the count increments. This is intended to
78+
* avoid sample aliasing.
79+
*/
80+
void dtrace_sync(void)
5781
{
58-
/* FIXME */
82+
/*
83+
* sync_cpus is a bitmap of CPUs that need to be synced with.
84+
*/
85+
cpumask_t sync_cpus;
86+
uint64_t sample_count = 0;
87+
int cpuid, sample_cpuid;
88+
int outstanding;
89+
90+
/*
91+
* Create bitmap of CPUs that need to be synced with.
92+
*/
93+
cpumask_copy(&sync_cpus, cpu_online_mask);
94+
outstanding = 0;
95+
for_each_cpu(cpuid, &sync_cpus) {
96+
++outstanding;
97+
98+
/*
99+
* Set a flag to let the CPU know we are syncing with it.
100+
*/
101+
DTRACE_SYNC_START(cpuid);
102+
}
103+
104+
/*
105+
* The preceding stores by DTRACE_SYNC_START() must complete before
106+
* subsequent loads or stores. No membar is needed because the
107+
* atomic-add operation in DTRACE_SYNC_START is a memory barrier on
108+
* SPARC and X86.
109+
*/
110+
111+
while (outstanding > 0) {
112+
/*
113+
* Loop over the map of CPUs that need to be synced with.
114+
*/
115+
for_each_cpu(cpuid, &sync_cpus) {
116+
if (!DTRACE_SYNC_IN_CRITICAL(cpuid)) {
117+
118+
/* Clear the CPU's sync request flag */
119+
DTRACE_SYNC_END(cpuid);
120+
121+
/*
122+
* remove cpuid from list of CPUs that
123+
* still need to be synced with.
124+
*/
125+
DTRACE_SYNC_DONE(cpuid, &sync_cpus);
126+
--outstanding;
127+
} else {
128+
/*
129+
* Remember one of the outstanding CPUs to spin
130+
* on once we reach the sampling limit.
131+
*/
132+
sample_cpuid = cpuid;
133+
}
134+
}
135+
136+
/*
137+
* dtrace_probe may be running in sibling threads in this core.
138+
*/
139+
if (outstanding > 0) {
140+
dtrace_safe_smt_pause();
141+
142+
/*
143+
* After sample_count loops, spin on one CPU's count
144+
* instead of just checking for odd/even.
145+
*/
146+
if (++sample_count > dtrace_sync_sample_count) {
147+
uint64_t count =
148+
DTRACE_SYNC_CRITICAL_COUNT(sample_cpuid);
149+
150+
/*
151+
* Spin until critical section count increments.
152+
*/
153+
if (DTRACE_SYNC_IN_CRITICAL(sample_cpuid)) {
154+
while (count ==
155+
DTRACE_SYNC_CRITICAL_COUNT(
156+
sample_cpuid)) {
157+
158+
dtrace_safe_smt_pause();
159+
}
160+
}
161+
162+
DTRACE_SYNC_END(sample_cpuid);
163+
DTRACE_SYNC_DONE(sample_cpuid, &sync_cpus);
164+
--outstanding;
165+
}
166+
}
167+
}
168+
169+
/*
170+
* All preceding loads by DTRACE_SYNC_IN_CRITICAL() and
171+
* DTRACE_SYNC_CRITICAL_COUNT() must complete before subsequent loads
172+
* or stores. No membar is needed because the atomic-add operation in
173+
* DTRACE_SYNC_END() is a memory barrier on SPARC and X86.
174+
*/
59175
}
60176

61177
/*

dtrace/dtrace_probe.c

Lines changed: 18 additions & 18 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) {
@@ -515,6 +521,7 @@ void dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1,
515521
int onintr;
516522
volatile uint16_t *flags;
517523
int pflag = 0;
524+
uint32_t re_entry;
518525

519526
#ifdef FIXME
520527
/*
@@ -526,12 +533,13 @@ void dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1,
526533
return;
527534
#endif
528535

536+
DTRACE_SYNC_ENTER_CRITICAL(cookie, re_entry);
537+
529538
/*
530539
* If preemption has already been disabled before we get here, we
531540
* accept it as a free gift. We just need to make sure that we don't
532541
* re-enable preemption on the way out...
533542
*/
534-
local_irq_save(cookie);
535543
if ((pflag = dtrace_is_preemptive()))
536544
dtrace_preempt_off();
537545

@@ -547,7 +555,7 @@ void dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1,
547555
*/
548556
if (pflag)
549557
dtrace_preempt_on();
550-
local_irq_restore(cookie);
558+
DTRACE_SYNC_EXIT_CRITICAL(cookie, re_entry);
551559
return;
552560
}
553561

@@ -557,7 +565,7 @@ void dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1,
557565
*/
558566
if (pflag)
559567
dtrace_preempt_on();
560-
local_irq_restore(cookie);
568+
DTRACE_SYNC_EXIT_CRITICAL(cookie, re_entry);
561569
return;
562570
}
563571

@@ -574,7 +582,7 @@ void dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1,
574582
pflag);
575583
if (pflag)
576584
dtrace_preempt_on();
577-
local_irq_restore(cookie);
585+
DTRACE_SYNC_EXIT_CRITICAL(cookie, re_entry);
578586
return;
579587
}
580588

@@ -996,6 +1004,7 @@ void dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1,
9961004
case DTRACEACT_PRINTA:
9971005
case DTRACEACT_SYSTEM:
9981006
case DTRACEACT_FREOPEN:
1007+
case DTRACEACT_TRACEMEM:
9991008
break;
10001009

10011010
case DTRACEACT_SYM:
@@ -1249,7 +1258,7 @@ void dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1,
12491258

12501259
if (pflag)
12511260
dtrace_preempt_on();
1252-
local_irq_restore(cookie);
1261+
DTRACE_SYNC_EXIT_CRITICAL(cookie, re_entry);
12531262

12541263
if (current->dtrace_sig != 0) {
12551264
int sig = current->dtrace_sig;
@@ -1279,16 +1288,7 @@ int dtrace_probe_init(void)
12791288
* We need to drop our locks when calling idr_preload(), so we try to
12801289
* get them back right after.
12811290
*/
1282-
mutex_unlock(&dtrace_lock);
1283-
mutex_unlock(&dtrace_provider_lock);
1284-
mutex_unlock(&cpu_lock);
1285-
12861291
idr_preload(GFP_KERNEL);
1287-
1288-
mutex_lock(&cpu_lock);
1289-
mutex_lock(&dtrace_provider_lock);
1290-
mutex_lock(&dtrace_lock);
1291-
12921292
id = idr_alloc_cyclic(&dtrace_probe_idr, NULL, 0, 0, GFP_NOWAIT);
12931293
idr_preload_end();
12941294

0 commit comments

Comments
 (0)