summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/dtrace/dtrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/common/dtrace/dtrace.c')
-rw-r--r--usr/src/uts/common/dtrace/dtrace.c369
1 files changed, 263 insertions, 106 deletions
diff --git a/usr/src/uts/common/dtrace/dtrace.c b/usr/src/uts/common/dtrace/dtrace.c
index c352f66d5d..a430f656b4 100644
--- a/usr/src/uts/common/dtrace/dtrace.c
+++ b/usr/src/uts/common/dtrace/dtrace.c
@@ -1108,10 +1108,13 @@ dtrace_priv_proc_common_nocd()
}
static int
-dtrace_priv_proc_destructive(dtrace_state_t *state)
+dtrace_priv_proc_destructive(dtrace_state_t *state, dtrace_mstate_t *mstate)
{
int action = state->dts_cred.dcr_action;
+ if (!(mstate->dtms_access & DTRACE_ACCESS_PROC))
+ goto bad;
+
if (((action & DTRACE_CRA_PROC_DESTRUCTIVE_ALLZONE) == 0) &&
dtrace_priv_proc_common_zone(state) == 0)
goto bad;
@@ -1133,15 +1136,17 @@ bad:
}
static int
-dtrace_priv_proc_control(dtrace_state_t *state)
+dtrace_priv_proc_control(dtrace_state_t *state, dtrace_mstate_t *mstate)
{
- if (state->dts_cred.dcr_action & DTRACE_CRA_PROC_CONTROL)
- return (1);
+ if (mstate->dtms_access & DTRACE_ACCESS_PROC) {
+ if (state->dts_cred.dcr_action & DTRACE_CRA_PROC_CONTROL)
+ return (1);
- if (dtrace_priv_proc_common_zone(state) &&
- dtrace_priv_proc_common_user(state) &&
- dtrace_priv_proc_common_nocd())
- return (1);
+ if (dtrace_priv_proc_common_zone(state) &&
+ dtrace_priv_proc_common_user(state) &&
+ dtrace_priv_proc_common_nocd())
+ return (1);
+ }
cpu_core[CPU->cpu_id].cpuc_dtrace_flags |= CPU_DTRACE_UPRIV;
@@ -1149,9 +1154,10 @@ dtrace_priv_proc_control(dtrace_state_t *state)
}
static int
-dtrace_priv_proc(dtrace_state_t *state)
+dtrace_priv_proc(dtrace_state_t *state, dtrace_mstate_t *mstate)
{
- if (state->dts_cred.dcr_action & DTRACE_CRA_PROC)
+ if ((mstate->dtms_access & DTRACE_ACCESS_PROC) &&
+ (state->dts_cred.dcr_action & DTRACE_CRA_PROC))
return (1);
cpu_core[CPU->cpu_id].cpuc_dtrace_flags |= CPU_DTRACE_UPRIV;
@@ -1182,6 +1188,109 @@ dtrace_priv_kernel_destructive(dtrace_state_t *state)
}
/*
+ * Determine if the dte_cond of the specified ECB allows for processing of
+ * the current probe to continue. Note that this routine may allow continued
+ * processing, but with access(es) stripped from the mstate's dtms_access
+ * field.
+ */
+static int
+dtrace_priv_probe(dtrace_state_t *state, dtrace_mstate_t *mstate,
+ dtrace_ecb_t *ecb)
+{
+ dtrace_probe_t *probe = ecb->dte_probe;
+ dtrace_provider_t *prov = probe->dtpr_provider;
+ dtrace_pops_t *pops = &prov->dtpv_pops;
+ int mode = DTRACE_MODE_NOPRIV_DROP;
+
+ ASSERT(ecb->dte_cond);
+
+ if (pops->dtps_mode != NULL) {
+ mode = pops->dtps_mode(prov->dtpv_arg,
+ probe->dtpr_id, probe->dtpr_arg);
+
+ ASSERT((mode & DTRACE_MODE_USER) ||
+ (mode & DTRACE_MODE_KERNEL));
+ ASSERT((mode & DTRACE_MODE_NOPRIV_RESTRICT) ||
+ (mode & DTRACE_MODE_NOPRIV_DROP));
+ }
+
+ /*
+ * If the dte_cond bits indicate that this consumer is only allowed to
+ * see user-mode firings of this probe, call the provider's dtps_mode()
+ * entry point to check that the probe was fired while in a user
+ * context. If that's not the case, use the policy specified by the
+ * provider to determine if we drop the probe or merely restrict
+ * operation.
+ */
+ if (ecb->dte_cond & DTRACE_COND_USERMODE) {
+ ASSERT(mode != DTRACE_MODE_NOPRIV_DROP);
+
+ if (!(mode & DTRACE_MODE_USER)) {
+ if (mode & DTRACE_MODE_NOPRIV_DROP)
+ return (0);
+
+ mstate->dtms_access &= ~DTRACE_ACCESS_ARGS;
+ }
+ }
+
+ /*
+ * This is more subtle than it looks. We have to be absolutely certain
+ * that CRED() isn't going to change out from under us so it's only
+ * legit to examine that structure if we're in constrained situations.
+ * Currently, the only times we'll this check is if a non-super-user
+ * has enabled the profile or syscall providers -- providers that
+ * allow visibility of all processes. For the profile case, the check
+ * above will ensure that we're examining a user context.
+ */
+ if (ecb->dte_cond & DTRACE_COND_OWNER) {
+ cred_t *cr;
+ cred_t *s_cr = state->dts_cred.dcr_cred;
+ proc_t *proc;
+
+ ASSERT(s_cr != NULL);
+
+ if ((cr = CRED()) == NULL ||
+ s_cr->cr_uid != cr->cr_uid ||
+ s_cr->cr_uid != cr->cr_ruid ||
+ s_cr->cr_uid != cr->cr_suid ||
+ s_cr->cr_gid != cr->cr_gid ||
+ s_cr->cr_gid != cr->cr_rgid ||
+ s_cr->cr_gid != cr->cr_sgid ||
+ (proc = ttoproc(curthread)) == NULL ||
+ (proc->p_flag & SNOCD)) {
+ if (mode & DTRACE_MODE_NOPRIV_DROP)
+ return (0);
+
+ mstate->dtms_access &= ~DTRACE_ACCESS_PROC;
+ }
+ }
+
+ /*
+ * If our dte_cond is set to DTRACE_COND_ZONEOWNER and we are not
+ * in our zone, check to see if our mode policy is to restrict rather
+ * than to drop; if to restrict, strip away both DTRACE_ACCESS_PROC
+ * and DTRACE_ACCESS_ARGS
+ */
+ if (ecb->dte_cond & DTRACE_COND_ZONEOWNER) {
+ cred_t *cr;
+ cred_t *s_cr = state->dts_cred.dcr_cred;
+
+ ASSERT(s_cr != NULL);
+
+ if ((cr = CRED()) == NULL ||
+ s_cr->cr_zone->zone_id != cr->cr_zone->zone_id) {
+ if (mode & DTRACE_MODE_NOPRIV_DROP)
+ return (0);
+
+ mstate->dtms_access &=
+ ~(DTRACE_ACCESS_PROC | DTRACE_ACCESS_ARGS);
+ }
+ }
+
+ return (1);
+}
+
+/*
* Note: not called from probe context. This function is called
* asynchronously (and at a regular interval) from outside of probe context to
* clean the dirty dynamic variable lists on all CPUs. Dynamic variable
@@ -2713,6 +2822,12 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v,
switch (v) {
case DIF_VAR_ARGS:
+ if (!(mstate->dtms_access & DTRACE_ACCESS_ARGS)) {
+ cpu_core[CPU->cpu_id].cpuc_dtrace_flags |=
+ CPU_DTRACE_KPRIV;
+ return (0);
+ }
+
ASSERT(mstate->dtms_present & DTRACE_MSTATE_ARGS);
if (ndx >= sizeof (mstate->dtms_arg) /
sizeof (mstate->dtms_arg[0])) {
@@ -2748,7 +2863,7 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v,
case DIF_VAR_UREGS: {
klwp_t *lwp;
- if (!dtrace_priv_proc(state))
+ if (!dtrace_priv_proc(state, mstate))
return (0);
if ((lwp = curthread->t_lwp) == NULL) {
@@ -2828,7 +2943,7 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v,
return (mstate->dtms_stackdepth);
case DIF_VAR_USTACKDEPTH:
- if (!dtrace_priv_proc(state))
+ if (!dtrace_priv_proc(state, mstate))
return (0);
if (!(mstate->dtms_present & DTRACE_MSTATE_USTACKDEPTH)) {
/*
@@ -2883,7 +2998,7 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v,
return (mstate->dtms_caller);
case DIF_VAR_UCALLER:
- if (!dtrace_priv_proc(state))
+ if (!dtrace_priv_proc(state, mstate))
return (0);
if (!(mstate->dtms_present & DTRACE_MSTATE_UCALLER)) {
@@ -2931,7 +3046,7 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v,
state, mstate));
case DIF_VAR_PID:
- if (!dtrace_priv_proc(state))
+ if (!dtrace_priv_proc(state, mstate))
return (0);
/*
@@ -2953,7 +3068,7 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v,
return ((uint64_t)curthread->t_procp->p_pidp->pid_id);
case DIF_VAR_PPID:
- if (!dtrace_priv_proc(state))
+ if (!dtrace_priv_proc(state, mstate))
return (0);
/*
@@ -2980,7 +3095,7 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v,
return ((uint64_t)curthread->t_tid);
case DIF_VAR_EXECNAME:
- if (!dtrace_priv_proc(state))
+ if (!dtrace_priv_proc(state, mstate))
return (0);
/*
@@ -3000,7 +3115,7 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v,
state, mstate));
case DIF_VAR_ZONENAME:
- if (!dtrace_priv_proc(state))
+ if (!dtrace_priv_proc(state, mstate))
return (0);
/*
@@ -3020,7 +3135,7 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v,
state, mstate));
case DIF_VAR_UID:
- if (!dtrace_priv_proc(state))
+ if (!dtrace_priv_proc(state, mstate))
return (0);
/*
@@ -3041,7 +3156,7 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v,
return ((uint64_t)curthread->t_procp->p_cred->cr_uid);
case DIF_VAR_GID:
- if (!dtrace_priv_proc(state))
+ if (!dtrace_priv_proc(state, mstate))
return (0);
/*
@@ -3063,7 +3178,7 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v,
case DIF_VAR_ERRNO: {
klwp_t *lwp;
- if (!dtrace_priv_proc(state))
+ if (!dtrace_priv_proc(state, mstate))
return (0);
/*
@@ -3403,7 +3518,7 @@ dtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs,
uint64_t size = tupregs[2].dttk_value;
if (!dtrace_destructive_disallow &&
- dtrace_priv_proc_control(state) &&
+ dtrace_priv_proc_control(state, mstate) &&
!dtrace_istoxic(kaddr, size)) {
DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
dtrace_copyout(kaddr, uaddr, size, flags);
@@ -3418,7 +3533,7 @@ dtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs,
uint64_t size = tupregs[2].dttk_value;
if (!dtrace_destructive_disallow &&
- dtrace_priv_proc_control(state) &&
+ dtrace_priv_proc_control(state, mstate) &&
!dtrace_istoxic(kaddr, size)) {
DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
dtrace_copyoutstr(kaddr, uaddr, size, flags);
@@ -3789,7 +3904,54 @@ dtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs,
break;
}
- case DIF_SUBR_GETMAJOR:
+ case DIF_SUBR_TOUPPER:
+ case DIF_SUBR_TOLOWER: {
+ uintptr_t s = tupregs[0].dttk_value;
+ uint64_t size = state->dts_options[DTRACEOPT_STRSIZE];
+ char *dest = (char *)mstate->dtms_scratch_ptr, c;
+ size_t len = dtrace_strlen((char *)s, size);
+ char lower, upper, convert;
+ int64_t i;
+
+ if (subr == DIF_SUBR_TOUPPER) {
+ lower = 'a';
+ upper = 'z';
+ convert = 'A';
+ } else {
+ lower = 'A';
+ upper = 'Z';
+ convert = 'a';
+ }
+
+ if (!dtrace_canload(s, len + 1, mstate, vstate)) {
+ regs[rd] = NULL;
+ break;
+ }
+
+ if (!DTRACE_INSCRATCH(mstate, size)) {
+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH);
+ regs[rd] = NULL;
+ break;
+ }
+
+ for (i = 0; i < size - 1; i++) {
+ if ((c = dtrace_load8(s + i)) == '\0')
+ break;
+
+ if (c >= lower && c <= upper)
+ c = convert + (c - lower);
+
+ dest[i] = c;
+ }
+
+ ASSERT(i < size);
+ dest[i] = '\0';
+ regs[rd] = (uintptr_t)dest;
+ mstate->dtms_scratch_ptr += size;
+ break;
+ }
+
+case DIF_SUBR_GETMAJOR:
#ifdef _LP64
regs[rd] = (tupregs[0].dttk_value >> NBITSMINOR64) & MAXMAJ64;
#else
@@ -4051,9 +4213,20 @@ dtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs,
case DIF_SUBR_LLTOSTR: {
int64_t i = (int64_t)tupregs[0].dttk_value;
- int64_t val = i < 0 ? i * -1 : i;
- uint64_t size = 22; /* enough room for 2^64 in decimal */
+ uint64_t val, digit;
+ uint64_t size = 65; /* enough room for 2^64 in binary */
char *end = (char *)mstate->dtms_scratch_ptr + size - 1;
+ int base = 10;
+
+ if (nargs > 1) {
+ if ((base = tupregs[1].dttk_value) <= 1 ||
+ base > ('z' - 'a' + 1) + ('9' - '0' + 1)) {
+ *flags |= CPU_DTRACE_ILLOP;
+ break;
+ }
+ }
+
+ val = (base == 10 && i < 0) ? i * -1 : i;
if (!DTRACE_INSCRATCH(mstate, size)) {
DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH);
@@ -4061,13 +4234,24 @@ dtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs,
break;
}
- for (*end-- = '\0'; val; val /= 10)
- *end-- = '0' + (val % 10);
+ for (*end-- = '\0'; val; val /= base) {
+ if ((digit = val % base) <= '9' - '0') {
+ *end-- = '0' + digit;
+ } else {
+ *end-- = 'a' + (digit - ('9' - '0') - 1);
+ }
+ }
+
+ if (i == 0 && base == 16)
+ *end-- = '0';
- if (i == 0)
+ if (base == 16)
+ *end-- = 'x';
+
+ if (i == 0 || base == 8 || base == 16)
*end-- = '0';
- if (i < 0)
+ if (i < 0 && base == 10)
*end-- = '-';
regs[rd] = (uintptr_t)end + 1;
@@ -5702,6 +5886,7 @@ dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1,
dtrace_buffer_t *aggbuf = &state->dts_aggbuffer[cpuid];
dtrace_vstate_t *vstate = &state->dts_vstate;
dtrace_provider_t *prov = probe->dtpr_provider;
+ uint64_t tracememsize = 0;
int committed = 0;
caddr_t tomax;
@@ -5722,6 +5907,7 @@ dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1,
#endif
mstate.dtms_present = DTRACE_MSTATE_ARGS | DTRACE_MSTATE_PROBE;
+ mstate.dtms_access = DTRACE_ACCESS_ARGS | DTRACE_ACCESS_PROC;
*flags &= ~CPU_DTRACE_ERROR;
if (prov == dtrace_provider) {
@@ -5759,65 +5945,8 @@ dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1,
}
}
- if (ecb->dte_cond) {
- /*
- * If the dte_cond bits indicate that this
- * consumer is only allowed to see user-mode firings
- * of this probe, call the provider's dtps_usermode()
- * entry point to check that the probe was fired
- * while in a user context. Skip this ECB if that's
- * not the case.
- */
- if ((ecb->dte_cond & DTRACE_COND_USERMODE) &&
- prov->dtpv_pops.dtps_usermode(prov->dtpv_arg,
- probe->dtpr_id, probe->dtpr_arg) == 0)
- continue;
-
- /*
- * This is more subtle than it looks. We have to be
- * absolutely certain that CRED() isn't going to
- * change out from under us so it's only legit to
- * examine that structure if we're in constrained
- * situations. Currently, the only times we'll this
- * check is if a non-super-user has enabled the
- * profile or syscall providers -- providers that
- * allow visibility of all processes. For the
- * profile case, the check above will ensure that
- * we're examining a user context.
- */
- if (ecb->dte_cond & DTRACE_COND_OWNER) {
- cred_t *cr;
- cred_t *s_cr =
- ecb->dte_state->dts_cred.dcr_cred;
- proc_t *proc;
-
- ASSERT(s_cr != NULL);
-
- if ((cr = CRED()) == NULL ||
- s_cr->cr_uid != cr->cr_uid ||
- s_cr->cr_uid != cr->cr_ruid ||
- s_cr->cr_uid != cr->cr_suid ||
- s_cr->cr_gid != cr->cr_gid ||
- s_cr->cr_gid != cr->cr_rgid ||
- s_cr->cr_gid != cr->cr_sgid ||
- (proc = ttoproc(curthread)) == NULL ||
- (proc->p_flag & SNOCD))
- continue;
- }
-
- if (ecb->dte_cond & DTRACE_COND_ZONEOWNER) {
- cred_t *cr;
- cred_t *s_cr =
- ecb->dte_state->dts_cred.dcr_cred;
-
- ASSERT(s_cr != NULL);
-
- if ((cr = CRED()) == NULL ||
- s_cr->cr_zone->zone_id !=
- cr->cr_zone->zone_id)
- continue;
- }
- }
+ if (ecb->dte_cond && !dtrace_priv_probe(state, &mstate, ecb))
+ continue;
if (now - state->dts_alive > dtrace_deadman_timeout) {
/*
@@ -5857,9 +5986,7 @@ dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1,
mstate.dtms_present |= DTRACE_MSTATE_EPID;
if (state->dts_cred.dcr_visible & DTRACE_CRV_KERNEL)
- mstate.dtms_access = DTRACE_ACCESS_KERNEL;
- else
- mstate.dtms_access = 0;
+ mstate.dtms_access |= DTRACE_ACCESS_KERNEL;
if (pred != NULL) {
dtrace_difo_t *dp = pred->dtp_difo;
@@ -5919,7 +6046,8 @@ dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1,
switch (act->dta_kind) {
case DTRACEACT_STOP:
- if (dtrace_priv_proc_destructive(state))
+ if (dtrace_priv_proc_destructive(state,
+ &mstate))
dtrace_action_stop();
continue;
@@ -5946,7 +6074,7 @@ dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1,
case DTRACEACT_JSTACK:
case DTRACEACT_USTACK:
- if (!dtrace_priv_proc(state))
+ if (!dtrace_priv_proc(state, &mstate))
continue;
/*
@@ -6032,7 +6160,8 @@ dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1,
continue;
case DTRACEACT_RAISE:
- if (dtrace_priv_proc_destructive(state))
+ if (dtrace_priv_proc_destructive(state,
+ &mstate))
dtrace_action_raise(val);
continue;
@@ -6059,6 +6188,11 @@ dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1,
case DTRACEACT_PRINTA:
case DTRACEACT_SYSTEM:
case DTRACEACT_FREOPEN:
+ case DTRACEACT_TRACEMEM:
+ break;
+
+ case DTRACEACT_TRACEMEM_DYNSIZE:
+ tracememsize = val;
break;
case DTRACEACT_SYM:
@@ -6072,7 +6206,7 @@ dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1,
case DTRACEACT_UADDR: {
struct pid *pid = curthread->t_procp->p_pidp;
- if (!dtrace_priv_proc(state))
+ if (!dtrace_priv_proc(state, &mstate))
continue;
DTRACE_STORE(uint64_t, tomax,
@@ -6124,6 +6258,12 @@ dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1,
if (dp->dtdo_rtype.dtdt_flags & DIF_TF_BYREF) {
uintptr_t end = valoffs + size;
+ if (tracememsize != 0 &&
+ valoffs + tracememsize < end) {
+ end = valoffs + tracememsize;
+ tracememsize = 0;
+ }
+
if (!dtrace_vcanload((void *)(uintptr_t)val,
&dp->dtdo_rtype, &mstate, vstate))
continue;
@@ -7004,9 +7144,9 @@ dtrace_register(const char *name, const dtrace_pattr_t *pap, uint32_t priv,
if ((priv & DTRACE_PRIV_KERNEL) &&
(priv & (DTRACE_PRIV_USER | DTRACE_PRIV_OWNER)) &&
- pops->dtps_usermode == NULL) {
+ pops->dtps_mode == NULL) {
cmn_err(CE_WARN, "failed to register provider '%s': need "
- "dtps_usermode() op for given privilege attributes", name);
+ "dtps_mode() op for given privilege attributes", name);
return (EINVAL);
}
@@ -9697,6 +9837,8 @@ dtrace_ecb_action_add(dtrace_ecb_t *ecb, dtrace_actdesc_t *desc)
/*FALLTHROUGH*/
case DTRACEACT_LIBACT:
case DTRACEACT_DIFEXPR:
+ case DTRACEACT_TRACEMEM:
+ case DTRACEACT_TRACEMEM_DYNSIZE:
if (dp == NULL)
return (EINVAL);
@@ -10229,14 +10371,17 @@ dtrace_buffer_activate(dtrace_state_t *state)
static int
dtrace_buffer_alloc(dtrace_buffer_t *bufs, size_t size, int flags,
- processorid_t cpu)
+ processorid_t cpu, int *factor)
{
cpu_t *cp;
dtrace_buffer_t *buf;
+ int allocated = 0, desired = 0;
ASSERT(MUTEX_HELD(&cpu_lock));
ASSERT(MUTEX_HELD(&dtrace_lock));
+ *factor = 1;
+
if (size > dtrace_nonroot_maxsize &&
!PRIV_POLICY_CHOICE(CRED(), PRIV_ALL, B_FALSE))
return (EFBIG);
@@ -10261,7 +10406,8 @@ dtrace_buffer_alloc(dtrace_buffer_t *bufs, size_t size, int flags,
ASSERT(buf->dtb_xamot == NULL);
- if ((buf->dtb_tomax = kmem_zalloc(size, KM_NOSLEEP)) == NULL)
+ if ((buf->dtb_tomax = kmem_zalloc(size,
+ KM_NOSLEEP | KM_NORMALPRI)) == NULL)
goto err;
buf->dtb_size = size;
@@ -10272,7 +10418,8 @@ dtrace_buffer_alloc(dtrace_buffer_t *bufs, size_t size, int flags,
if (flags & DTRACEBUF_NOSWITCH)
continue;
- if ((buf->dtb_xamot = kmem_zalloc(size, KM_NOSLEEP)) == NULL)
+ if ((buf->dtb_xamot = kmem_zalloc(size,
+ KM_NOSLEEP | KM_NORMALPRI)) == NULL)
goto err;
} while ((cp = cp->cpu_next) != cpu_list);
@@ -10286,16 +10433,19 @@ err:
continue;
buf = &bufs[cp->cpu_id];
+ desired += 2;
if (buf->dtb_xamot != NULL) {
ASSERT(buf->dtb_tomax != NULL);
ASSERT(buf->dtb_size == size);
kmem_free(buf->dtb_xamot, size);
+ allocated++;
}
if (buf->dtb_tomax != NULL) {
ASSERT(buf->dtb_size == size);
kmem_free(buf->dtb_tomax, size);
+ allocated++;
}
buf->dtb_tomax = NULL;
@@ -10303,6 +10453,8 @@ err:
buf->dtb_size = 0;
} while ((cp = cp->cpu_next) != cpu_list);
+ *factor = desired / (allocated > 0 ? allocated : 1);
+
return (ENOMEM);
}
@@ -12201,7 +12353,7 @@ dtrace_dstate_init(dtrace_dstate_t *dstate, size_t size)
if (size < (min = dstate->dtds_chunksize + sizeof (dtrace_dynhash_t)))
size = min;
- if ((base = kmem_zalloc(size, KM_NOSLEEP)) == NULL)
+ if ((base = kmem_zalloc(size, KM_NOSLEEP | KM_NORMALPRI)) == NULL)
return (ENOMEM);
dstate->dtds_size = size;
@@ -12563,7 +12715,7 @@ dtrace_state_buffer(dtrace_state_t *state, dtrace_buffer_t *buf, int which)
{
dtrace_optval_t *opt = state->dts_options, size;
processorid_t cpu;
- int flags = 0, rval;
+ int flags = 0, rval, factor, divisor = 1;
ASSERT(MUTEX_HELD(&dtrace_lock));
ASSERT(MUTEX_HELD(&cpu_lock));
@@ -12593,7 +12745,7 @@ dtrace_state_buffer(dtrace_state_t *state, dtrace_buffer_t *buf, int which)
flags |= DTRACEBUF_INACTIVE;
}
- for (size = opt[which]; size >= sizeof (uint64_t); size >>= 1) {
+ for (size = opt[which]; size >= sizeof (uint64_t); size /= divisor) {
/*
* The size must be 8-byte aligned. If the size is not 8-byte
* aligned, drop it down by the difference.
@@ -12611,7 +12763,7 @@ dtrace_state_buffer(dtrace_state_t *state, dtrace_buffer_t *buf, int which)
return (E2BIG);
}
- rval = dtrace_buffer_alloc(buf, size, flags, cpu);
+ rval = dtrace_buffer_alloc(buf, size, flags, cpu, &factor);
if (rval != ENOMEM) {
opt[which] = size;
@@ -12620,6 +12772,9 @@ dtrace_state_buffer(dtrace_state_t *state, dtrace_buffer_t *buf, int which)
if (opt[DTRACEOPT_BUFRESIZE] == DTRACEOPT_BUFRESIZE_MANUAL)
return (rval);
+
+ for (divisor = 2; divisor < factor; divisor <<= 1)
+ continue;
}
return (ENOMEM);
@@ -12719,7 +12874,8 @@ dtrace_state_go(dtrace_state_t *state, processorid_t *cpu)
goto out;
}
- spec = kmem_zalloc(nspec * sizeof (dtrace_speculation_t), KM_NOSLEEP);
+ spec = kmem_zalloc(nspec * sizeof (dtrace_speculation_t),
+ KM_NOSLEEP | KM_NORMALPRI);
if (spec == NULL) {
rval = ENOMEM;
@@ -12730,7 +12886,8 @@ dtrace_state_go(dtrace_state_t *state, processorid_t *cpu)
state->dts_nspeculations = (int)nspec;
for (i = 0; i < nspec; i++) {
- if ((buf = kmem_zalloc(bufsize, KM_NOSLEEP)) == NULL) {
+ if ((buf = kmem_zalloc(bufsize,
+ KM_NOSLEEP | KM_NORMALPRI)) == NULL) {
rval = ENOMEM;
goto err;
}