#include <sys/types.h>
#include <sys/errno.h>
#include <sys/sunddi.h>
#include <sys/systm.h>
#include <sys/mman.h>
#include <sys/cpupart.h>
#include <sys/lgrp.h>
#include <sys/lgrp_user.h>
#include <sys/promif.h>
#include <sys/sysmacros.h>
#include <sys/policy.h>
#include <vm/as.h>
#define VALID_ADDR 1
#define VALID_REQ 2
static int
meminfo(int addr_count, struct meminfo *mip)
{
size_t in_size, out_size, req_size, val_size;
struct as *as;
struct hat *hat;
int i, j, out_idx, info_count;
lgrp_t *lgrp;
pfn_t pfn;
ssize_t pgsz;
int *req_array, *val_array;
uint64_t *in_array, *out_array;
uint64_t addr, paddr;
uintptr_t vaddr;
int ret = 0;
struct meminfo minfo;
#if defined(_SYSCALL32_IMPL)
struct meminfo32 minfo32;
#endif
if (addr_count < 1)
return (set_errno(EINVAL));
else if (addr_count > MAX_MEMINFO_CNT)
addr_count = MAX_MEMINFO_CNT;
if (get_udatamodel() == DATAMODEL_NATIVE) {
if (copyin(mip, &minfo, sizeof (struct meminfo)))
return (set_errno(EFAULT));
}
#if defined(_SYSCALL32_IMPL)
else {
bzero(&minfo, sizeof (minfo));
if (copyin(mip, &minfo32, sizeof (struct meminfo32)))
return (set_errno(EFAULT));
minfo.mi_inaddr = (const uint64_t *)(uintptr_t)
minfo32.mi_inaddr;
minfo.mi_info_req = (const uint_t *)(uintptr_t)
minfo32.mi_info_req;
minfo.mi_info_count = minfo32.mi_info_count;
minfo.mi_outdata = (uint64_t *)(uintptr_t)
minfo32.mi_outdata;
minfo.mi_validity = (uint_t *)(uintptr_t)
minfo32.mi_validity;
}
#endif
info_count = minfo.mi_info_count;
if (info_count < 1 || info_count > MAX_MEMINFO_REQ)
return (set_errno(EINVAL));
in_size = sizeof (uint64_t) * addr_count;
in_array = kmem_alloc(in_size, KM_SLEEP);
if (copyin(minfo.mi_inaddr, in_array, in_size)) {
kmem_free(in_array, in_size);
return (set_errno(EFAULT));
}
req_size = sizeof (uint_t) * info_count;
req_array = kmem_alloc(req_size, KM_SLEEP);
if (copyin(minfo.mi_info_req, req_array, req_size)) {
kmem_free(req_array, req_size);
kmem_free(in_array, in_size);
return (set_errno(EFAULT));
}
for (i = 0; i < info_count; i++) {
switch (req_array[i] & MEMINFO_MASK) {
case MEMINFO_VLGRP:
case MEMINFO_VPAGESIZE:
break;
default:
if (secpolicy_meminfo(CRED()) != 0) {
kmem_free(req_array, req_size);
kmem_free(in_array, in_size);
return (set_errno(EPERM));
}
break;
}
}
out_size = sizeof (uint64_t) * addr_count * info_count;
out_array = kmem_alloc(out_size, KM_SLEEP);
val_size = sizeof (uint_t) * addr_count;
val_array = kmem_alloc(val_size, KM_SLEEP);
if ((req_array[0] & MEMINFO_MASK) == MEMINFO_PLGRP) {
for (i = 0; i < addr_count; i++) {
paddr = in_array[i];
pfn = btop(paddr);
lgrp = lgrp_pfn_to_lgrp(pfn);
if (lgrp) {
out_array[i] = lgrp->lgrp_id;
val_array[i] = VALID_ADDR | VALID_REQ;
} else {
out_array[i] = 0;
val_array[i] = 0;
}
}
} else {
as = curproc->p_as;
AS_LOCK_ENTER(as, RW_READER);
hat = as->a_hat;
for (i = out_idx = 0; i < addr_count; i++, out_idx +=
info_count) {
addr = in_array[i];
vaddr = (uintptr_t)(addr & ~PAGEOFFSET);
if (!as_segat(as, (caddr_t)vaddr)) {
val_array[i] = 0;
continue;
}
val_array[i] = VALID_ADDR;
pfn = hat_getpfnum(hat, (caddr_t)vaddr);
if (pfn != PFN_INVALID) {
paddr = (uint64_t)((pfn << PAGESHIFT) |
(addr & PAGEOFFSET));
for (j = 0; j < info_count; j++) {
switch (req_array[j] & MEMINFO_MASK) {
case MEMINFO_VPHYSICAL:
out_array[out_idx + j] = paddr;
val_array[i] |= VALID_REQ << j;
break;
case MEMINFO_VLGRP:
lgrp = lgrp_pfn_to_lgrp(pfn);
if (lgrp) {
out_array[out_idx + j] =
lgrp->lgrp_id;
val_array[i] |=
VALID_REQ << j;
}
break;
case MEMINFO_VPAGESIZE:
pgsz = hat_getpagesize(hat,
(caddr_t)vaddr);
if (pgsz != -1) {
out_array[out_idx + j] =
pgsz;
val_array[i] |=
VALID_REQ << j;
}
break;
case MEMINFO_VREPLCNT:
out_array[out_idx + j] = 0;
val_array[i] |= VALID_REQ << j;
break;
case MEMINFO_VREPL:
break;
case MEMINFO_VREPL_LGRP:
break;
case MEMINFO_PLGRP:
break;
default:
break;
}
}
}
}
AS_LOCK_EXIT(as);
}
if ((copyout(out_array, minfo.mi_outdata, out_size) != 0) ||
(copyout(val_array, minfo.mi_validity, val_size) != 0))
ret = set_errno(EFAULT);
kmem_free(in_array, in_size);
kmem_free(out_array, out_size);
kmem_free(req_array, req_size);
kmem_free(val_array, val_size);
return (ret);
}
void
lgrp_affinity_init(lgrp_affinity_t **bufaddr)
{
if (bufaddr)
*bufaddr = NULL;
}
void
lgrp_affinity_free(lgrp_affinity_t **bufaddr)
{
if (bufaddr && *bufaddr) {
kmem_free(*bufaddr, nlgrpsmax * sizeof (lgrp_affinity_t));
*bufaddr = NULL;
}
}
#define P_ANY -2
lgrp_affinity_t
lgrp_affinity_get_thread(proc_t *p, id_t lwpid, lgrp_id_t lgrp)
{
lgrp_affinity_t aff;
int found;
kthread_t *t;
ASSERT(MUTEX_HELD(&p->p_lock));
aff = LGRP_AFF_NONE;
found = 0;
t = p->p_tlist;
if (t == NULL)
return (set_errno(ESRCH));
do {
if (t->t_tid == lwpid || lwpid == P_ANY) {
thread_lock(t);
if (t->t_cid == 0 || !hasprocperm(t->t_cred, CRED())) {
thread_unlock(t);
return (set_errno(EPERM));
}
if (t->t_lgrp_affinity)
aff = t->t_lgrp_affinity[lgrp];
thread_unlock(t);
found = 1;
break;
}
} while ((t = t->t_forw) != p->p_tlist);
if (!found)
aff = set_errno(ESRCH);
return (aff);
}
lgrp_affinity_t
lgrp_affinity_get(lgrp_affinity_args_t *ap)
{
lgrp_affinity_t aff;
lgrp_affinity_args_t args;
id_t id;
idtype_t idtype;
lgrp_id_t lgrp;
proc_t *p;
kthread_t *t;
if (copyin(ap, &args, sizeof (lgrp_affinity_args_t)) != 0)
return (set_errno(EFAULT));
id = args.id;
idtype = args.idtype;
lgrp = args.lgrp;
if (lgrp < 0 || lgrp == LGRP_NONE)
return (set_errno(EINVAL));
if (lgrp > lgrp_alloc_max)
return (set_errno(ESRCH));
switch (idtype) {
case P_LWPID:
p = curproc;
mutex_enter(&p->p_lock);
if (id != P_MYID)
aff = lgrp_affinity_get_thread(p, id, lgrp);
else {
aff = LGRP_AFF_NONE;
t = curthread;
thread_lock(t);
if (t->t_lgrp_affinity)
aff = t->t_lgrp_affinity[lgrp];
thread_unlock(t);
}
mutex_exit(&p->p_lock);
break;
case P_PID:
mutex_enter(&pidlock);
if (id == P_MYID)
p = curproc;
else {
p = prfind(id);
if (p == NULL) {
mutex_exit(&pidlock);
return (set_errno(ESRCH));
}
}
mutex_enter(&p->p_lock);
aff = lgrp_affinity_get_thread(p, P_ANY, lgrp);
mutex_exit(&p->p_lock);
mutex_exit(&pidlock);
break;
default:
aff = set_errno(EINVAL);
break;
}
return (aff);
}
lpl_t *
lgrp_affinity_best(kthread_t *t, struct cpupart *cpupart, lgrp_id_t start,
boolean_t prefer_start)
{
lgrp_affinity_t *affs;
lgrp_affinity_t best_aff;
lpl_t *best_lpl;
lgrp_id_t finish;
lgrp_id_t home;
lgrp_id_t lgrpid;
lpl_t *lpl;
ASSERT(t != NULL);
ASSERT((MUTEX_HELD(&cpu_lock) || curthread->t_preempt > 0) ||
(MUTEX_HELD(&ttoproc(t)->p_lock) && THREAD_LOCK_HELD(t)));
ASSERT(cpupart != NULL);
if (t->t_lgrp_affinity == NULL)
return (NULL);
affs = t->t_lgrp_affinity;
if (t->t_bind_cpu != PBIND_NONE) {
cpu_t *cp;
cp = cpu[t->t_bind_cpu];
best_lpl = lpl = cp->cpu_lpl;
best_aff = affs[best_lpl->lpl_lgrpid];
while (lpl->lpl_parent != NULL) {
lpl = lpl->lpl_parent;
lgrpid = lpl->lpl_lgrpid;
if (affs[lgrpid] > best_aff) {
best_lpl = lpl;
best_aff = affs[lgrpid];
}
}
return (best_lpl);
}
ASSERT(start >= 0 && start <= lgrp_alloc_max);
home = t->t_lpl->lpl_lgrpid;
if (!prefer_start && LGRP_CPUS_IN_PART(home, cpupart))
lgrpid = home;
else if (start != LGRP_NONE && LGRP_CPUS_IN_PART(start, cpupart))
lgrpid = start;
else
lgrpid = LGRP_ROOTID;
best_lpl = &cpupart->cp_lgrploads[lgrpid];
best_aff = affs[lgrpid];
finish = lgrpid;
do {
if (!LGRP_CPUS_IN_PART(lgrpid, cpupart)) {
if (++lgrpid > lgrp_alloc_max)
lgrpid = 0;
continue;
}
lpl = &cpupart->cp_lgrploads[lgrpid];
if (affs[lgrpid] > best_aff) {
best_aff = affs[lgrpid];
best_lpl = lpl;
}
if (++lgrpid > lgrp_alloc_max)
lgrpid = 0;
} while (lgrpid != finish);
if (best_aff == LGRP_AFF_NONE)
return (NULL);
lgrpid = best_lpl->lpl_lgrpid;
ASSERT(LGRP_CPUS_IN_PART(lgrpid, cpupart) && best_lpl->lpl_ncpu > 0);
return (best_lpl);
}
int
lgrp_affinity_set_thread(kthread_t *t, lgrp_id_t lgrp, lgrp_affinity_t aff,
lgrp_affinity_t **aff_buf)
{
lgrp_affinity_t *affs;
lgrp_id_t best;
lpl_t *best_lpl;
lgrp_id_t home;
int retval;
ASSERT(t != NULL);
ASSERT(MUTEX_HELD(&ttoproc(t)->p_lock));
retval = 0;
thread_lock(t);
if (t->t_cid == 0 || !hasprocperm(t->t_cred, CRED())) {
thread_unlock(t);
return (set_errno(EPERM));
}
if (t->t_lgrp_affinity == NULL) {
if (aff == LGRP_AFF_NONE) {
thread_unlock(t);
return (0);
}
ASSERT(aff_buf != NULL && *aff_buf != NULL);
t->t_lgrp_affinity = *aff_buf;
*aff_buf = NULL;
}
affs = t->t_lgrp_affinity;
affs[lgrp] = aff;
best_lpl = lgrp_affinity_best(t, t->t_cpupart, lgrp, B_TRUE);
home = t->t_lpl->lpl_lgrpid;
if (best_lpl != NULL && best_lpl != t->t_lpl) {
best = best_lpl->lpl_lgrpid;
if (affs[best] > affs[home] || (affs[best] == affs[home] &&
best == lgrp))
lgrp_move_thread(t, best_lpl, 1);
}
thread_unlock(t);
return (retval);
}
int
lgrp_affinity_set_proc(proc_t *p, lgrp_id_t lgrp, lgrp_affinity_t aff,
lgrp_affinity_t **aff_buf_array)
{
lgrp_affinity_t *buf;
int err = 0;
int i;
int retval;
kthread_t *t;
ASSERT(MUTEX_HELD(&pidlock) && MUTEX_HELD(&p->p_lock));
ASSERT(aff_buf_array != NULL);
i = 0;
t = p->p_tlist;
if (t != NULL) {
do {
buf = aff_buf_array[i];
retval = lgrp_affinity_set_thread(t, lgrp, aff, &buf);
if (err == 0 && retval != 0)
err = retval;
if (buf == NULL) {
ASSERT(i < p->p_lwpcnt);
aff_buf_array[i] = NULL;
i++;
}
} while ((t = t->t_forw) != p->p_tlist);
}
return (err);
}
int
lgrp_affinity_set(lgrp_affinity_args_t *ap)
{
lgrp_affinity_t aff;
lgrp_affinity_t *aff_buf;
lgrp_affinity_args_t args;
id_t id;
idtype_t idtype;
lgrp_id_t lgrp;
int nthreads;
proc_t *p;
int retval;
if (copyin(ap, &args, sizeof (lgrp_affinity_args_t)) != 0)
return (set_errno(EFAULT));
idtype = args.idtype;
id = args.id;
lgrp = args.lgrp;
aff = args.aff;
if (lgrp < 0 || lgrp == LGRP_NONE)
return (set_errno(EINVAL));
if (lgrp > lgrp_alloc_max)
return (set_errno(ESRCH));
if (aff != LGRP_AFF_NONE && aff != LGRP_AFF_WEAK &&
aff != LGRP_AFF_STRONG)
return (set_errno(EINVAL));
if (idtype != P_LWPID && idtype != P_PID)
return (set_errno(EINVAL));
retval = EINVAL;
switch (idtype) {
case P_LWPID:
aff_buf = kmem_zalloc(nlgrpsmax * sizeof (lgrp_affinity_t),
KM_SLEEP);
p = curproc;
mutex_enter(&p->p_lock);
if (id == P_MYID) {
retval = lgrp_affinity_set_thread(curthread, lgrp, aff,
&aff_buf);
} else if (p->p_tlist == NULL) {
retval = set_errno(ESRCH);
} else {
int found = 0;
kthread_t *t;
t = p->p_tlist;
do {
if (t->t_tid == id) {
retval = lgrp_affinity_set_thread(t,
lgrp, aff, &aff_buf);
found = 1;
break;
}
} while ((t = t->t_forw) != p->p_tlist);
if (!found)
retval = set_errno(ESRCH);
}
mutex_exit(&p->p_lock);
if (aff_buf)
kmem_free(aff_buf,
nlgrpsmax * sizeof (lgrp_affinity_t));
break;
case P_PID:
do {
lgrp_affinity_t **aff_buf_array;
int i;
size_t size;
mutex_enter(&pidlock);
if (id == P_MYID)
p = curproc;
else
p = prfind(id);
if (p == NULL) {
mutex_exit(&pidlock);
return (set_errno(ESRCH));
}
mutex_enter(&p->p_lock);
nthreads = p->p_lwpcnt;
mutex_exit(&p->p_lock);
mutex_exit(&pidlock);
if (nthreads < 1)
return (set_errno(ESRCH));
aff_buf_array = kmem_zalloc(nthreads *
sizeof (lgrp_affinity_t *), KM_SLEEP);
size = nlgrpsmax * sizeof (lgrp_affinity_t);
for (i = 0; i < nthreads; i++)
aff_buf_array[i] = kmem_zalloc(size, KM_SLEEP);
mutex_enter(&pidlock);
if (id != P_MYID)
p = prfind(id);
if (p == NULL) {
mutex_exit(&pidlock);
for (i = 0; i < nthreads; i++)
kmem_free(aff_buf_array[i], size);
kmem_free(aff_buf_array,
nthreads * sizeof (lgrp_affinity_t *));
return (set_errno(ESRCH));
}
mutex_enter(&p->p_lock);
if (nthreads != p->p_lwpcnt) {
mutex_exit(&p->p_lock);
mutex_exit(&pidlock);
for (i = 0; i < nthreads; i++)
kmem_free(aff_buf_array[i], size);
kmem_free(aff_buf_array,
nthreads * sizeof (lgrp_affinity_t *));
continue;
}
retval = lgrp_affinity_set_proc(p, lgrp, aff,
aff_buf_array);
mutex_exit(&p->p_lock);
mutex_exit(&pidlock);
for (i = 0; i < nthreads; i++)
if (aff_buf_array[i] != NULL)
kmem_free(aff_buf_array[i], size);
kmem_free(aff_buf_array,
nthreads * sizeof (lgrp_affinity_t *));
break;
} while (nthreads != p->p_lwpcnt);
break;
default:
retval = set_errno(EINVAL);
break;
}
return (retval);
}
lgrp_gen_t
lgrp_generation(lgrp_view_t view)
{
cpupart_t *cpupart;
uint_t gen;
kpreempt_disable();
if (view == LGRP_VIEW_OS)
gen = lgrp_gen;
else {
cpupart = curthread->t_cpupart;
ASSERT(cpupart);
gen = lgrp_gen + cpupart->cp_gen;
}
kpreempt_enable();
return (gen);
}
lgrp_id_t
lgrp_home_thread(kthread_t *t)
{
lgrp_id_t home;
ASSERT(t != NULL);
ASSERT(MUTEX_HELD(&ttoproc(t)->p_lock));
thread_lock(t);
if (t->t_cid == 0 || !hasprocperm(t->t_cred, CRED())) {
thread_unlock(t);
return (set_errno(EPERM));
}
home = lgrp_home_id(t);
thread_unlock(t);
return (home);
}
lgrp_id_t
lgrp_home_get(idtype_t idtype, id_t id)
{
proc_t *p;
lgrp_id_t retval;
kthread_t *t;
switch (idtype) {
case P_LWPID:
p = curproc;
mutex_enter(&p->p_lock);
if (id == P_MYID) {
retval = lgrp_home_thread(curthread);
} else if (p->p_tlist == NULL) {
retval = set_errno(ESRCH);
} else {
int found = 0;
t = p->p_tlist;
do {
if (t->t_tid == id) {
retval = lgrp_home_thread(t);
found = 1;
break;
}
} while ((t = t->t_forw) != p->p_tlist);
if (!found)
retval = set_errno(ESRCH);
}
mutex_exit(&p->p_lock);
break;
case P_PID:
mutex_enter(&pidlock);
if (id == P_MYID)
p = curproc;
else
p = prfind(id);
if (p == NULL) {
mutex_exit(&pidlock);
return (set_errno(ESRCH));
}
mutex_enter(&p->p_lock);
t = p->p_tlist;
if (t == NULL)
retval = set_errno(ESRCH);
else
retval = lgrp_home_thread(t);
mutex_exit(&p->p_lock);
mutex_exit(&pidlock);
break;
default:
retval = set_errno(EINVAL);
break;
}
return (retval);
}
int
lgrp_latency(lgrp_id_t from, lgrp_id_t to)
{
lgrp_t *from_lgrp;
int i;
int latency;
int latency_max;
lgrp_t *to_lgrp;
ASSERT(MUTEX_HELD(&cpu_lock));
if (from < 0 || to < 0)
return (set_errno(EINVAL));
if (from > lgrp_alloc_max || to > lgrp_alloc_max)
return (set_errno(ESRCH));
from_lgrp = lgrp_table[from];
to_lgrp = lgrp_table[to];
if (!LGRP_EXISTS(from_lgrp) || !LGRP_EXISTS(to_lgrp)) {
return (set_errno(ESRCH));
}
if (from == to) {
latency = from_lgrp->lgrp_latency;
return (latency);
}
if (from_lgrp->lgrp_childcnt == 0 && to_lgrp->lgrp_childcnt == 0)
return (lgrp_plat_latency(from_lgrp->lgrp_plathand,
to_lgrp->lgrp_plathand));
latency_max = 0;
for (i = 0; i <= lgrp_alloc_max; i++) {
lgrp_t *from_rsrc;
int j;
lgrp_t *to_rsrc;
from_rsrc = lgrp_table[i];
if (!LGRP_EXISTS(from_rsrc) ||
!klgrpset_ismember(from_lgrp->lgrp_set[LGRP_RSRC_CPU], i))
continue;
for (j = 0; j <= lgrp_alloc_max; j++) {
to_rsrc = lgrp_table[j];
if (!LGRP_EXISTS(to_rsrc) ||
klgrpset_ismember(to_lgrp->lgrp_set[LGRP_RSRC_MEM],
j) == 0)
continue;
latency = lgrp_plat_latency(from_rsrc->lgrp_plathand,
to_rsrc->lgrp_plathand);
if (latency > latency_max)
latency_max = latency;
}
}
return (latency_max);
}
int
lgrp_version(int version)
{
if (version < LGRP_VER_NONE || version > LGRP_VER_CURRENT)
return (LGRP_VER_NONE);
if (version == LGRP_VER_NONE)
return (LGRP_VER_CURRENT);
return (version);
}
lgrp_snapshot_header_t *lgrp_snap = NULL;
static kmutex_t lgrp_snap_lock;
static int
lgrp_snapshot(void)
{
size_t bitmask_size;
size_t bitmasks_size;
size_t bufsize;
int cpu_index;
size_t cpuids_size;
int i;
int j;
size_t info_size;
size_t lats_size;
ulong_t *lgrp_children;
processorid_t *lgrp_cpuids;
lgrp_info_t *lgrp_info;
int **lgrp_lats;
ulong_t *lgrp_parents;
ulong_t *lgrp_rsets;
ulong_t *lgrpset;
int snap_ncpus;
int snap_nlgrps;
int snap_nlgrpsmax;
size_t snap_hdr_size;
#ifdef _SYSCALL32_IMPL
model_t model = DATAMODEL_NATIVE;
model = get_udatamodel();
if (model == DATAMODEL_ILP32 && lgrp_snap &&
lgrp_snap->ss_gen == lgrp_gen) {
snap_nlgrpsmax = lgrp_snap->ss_nlgrps_max;
snap_hdr_size = P2ROUNDUP(sizeof (lgrp_snapshot_header32_t),
sizeof (caddr32_t));
info_size =
P2ROUNDUP(snap_nlgrpsmax * sizeof (lgrp_info32_t),
sizeof (processorid_t));
cpuids_size =
P2ROUNDUP(lgrp_snap->ss_ncpus * sizeof (processorid_t),
sizeof (ulong_t));
bitmask_size = BT_SIZEOFMAP(snap_nlgrpsmax);
bitmasks_size = (((2 + LGRP_RSRC_COUNT) *
snap_nlgrpsmax) + 1) * bitmask_size;
lats_size = snap_nlgrpsmax * sizeof (caddr32_t) +
snap_nlgrpsmax * snap_nlgrpsmax * sizeof (int);
bufsize = snap_hdr_size + info_size + cpuids_size +
bitmasks_size + lats_size;
return (bufsize);
}
#endif
if (lgrp_snap) {
if (lgrp_snap->ss_gen == lgrp_gen)
return (lgrp_snap->ss_size);
kmem_free(lgrp_snap, lgrp_snap->ss_size);
lgrp_snap = NULL;
}
while (lgrp_snap == NULL) {
int old_generation;
mutex_enter(&cpu_lock);
old_generation = lgrp_gen;
snap_ncpus = ncpus_online;
snap_nlgrps = nlgrps;
snap_nlgrpsmax = nlgrpsmax;
mutex_exit(&cpu_lock);
snap_hdr_size = P2ROUNDUP(sizeof (lgrp_snapshot_header_t),
sizeof (void *));
info_size = P2ROUNDUP(snap_nlgrpsmax * sizeof (lgrp_info_t),
sizeof (processorid_t));
cpuids_size = P2ROUNDUP(snap_ncpus * sizeof (processorid_t),
sizeof (ulong_t));
bitmask_size = BT_SIZEOFMAP(snap_nlgrpsmax);
bitmasks_size = (((2 + LGRP_RSRC_COUNT) *
snap_nlgrpsmax) + 1) * bitmask_size;
lats_size = snap_nlgrpsmax * sizeof (int *) +
snap_nlgrpsmax * snap_nlgrpsmax * sizeof (int);
bufsize = snap_hdr_size + info_size + cpuids_size +
bitmasks_size + lats_size;
lgrp_snap = kmem_zalloc(bufsize, KM_NOSLEEP);
if (lgrp_snap == NULL)
return (set_errno(ENOMEM));
mutex_enter(&cpu_lock);
if (lgrp_gen == old_generation)
break;
mutex_exit(&cpu_lock);
kmem_free(lgrp_snap, bufsize);
lgrp_snap = NULL;
}
lgrp_snap->ss_version = LGRP_VER_CURRENT;
if (snap_nlgrps == 1)
lgrp_snap->ss_levels = 1;
else
lgrp_snap->ss_levels = 2;
lgrp_snap->ss_root = LGRP_ROOTID;
lgrp_snap->ss_nlgrps = lgrp_snap->ss_nlgrps_os = snap_nlgrps;
lgrp_snap->ss_nlgrps_max = snap_nlgrpsmax;
lgrp_snap->ss_ncpus = snap_ncpus;
lgrp_snap->ss_gen = lgrp_gen;
lgrp_snap->ss_view = LGRP_VIEW_OS;
lgrp_snap->ss_pset = 0;
lgrp_snap->ss_size = bufsize;
lgrp_snap->ss_magic = (uintptr_t)lgrp_snap;
lgrp_snap->ss_info = lgrp_info =
(lgrp_info_t *)((uintptr_t)lgrp_snap + snap_hdr_size);
lgrp_snap->ss_cpuids = lgrp_cpuids =
(processorid_t *)((uintptr_t)lgrp_info + info_size);
lgrp_snap->ss_lgrpset = lgrpset =
(ulong_t *)((uintptr_t)lgrp_cpuids + cpuids_size);
lgrp_snap->ss_parents = lgrp_parents =
(ulong_t *)((uintptr_t)lgrpset + bitmask_size);
lgrp_snap->ss_children = lgrp_children =
(ulong_t *)((uintptr_t)lgrp_parents + (snap_nlgrpsmax *
bitmask_size));
lgrp_snap->ss_rsets = lgrp_rsets =
(ulong_t *)((uintptr_t)lgrp_children + (snap_nlgrpsmax *
bitmask_size));
lgrp_snap->ss_latencies = lgrp_lats =
(int **)((uintptr_t)lgrp_rsets + (LGRP_RSRC_COUNT *
snap_nlgrpsmax * bitmask_size));
cpu_index = 0;
for (i = 0; i < snap_nlgrpsmax; i++) {
struct cpu *cp;
int cpu_count;
struct cpu *head;
int k;
lgrp_t *lgrp;
lgrp = lgrp_table[i];
if (!LGRP_EXISTS(lgrp)) {
bzero(&lgrp_info[i], sizeof (lgrp_info[i]));
lgrp_info[i].info_lgrpid = LGRP_NONE;
continue;
}
lgrp_info[i].info_lgrpid = i;
lgrp_info[i].info_latency = lgrp->lgrp_latency;
lgrp_info[i].info_parents =
(ulong_t *)((uintptr_t)lgrp_parents + (i * bitmask_size));
if (lgrp->lgrp_parent)
BT_SET(lgrp_info[i].info_parents,
lgrp->lgrp_parent->lgrp_id);
lgrp_info[i].info_children =
(ulong_t *)((uintptr_t)lgrp_children + (i * bitmask_size));
for (j = 0; j < snap_nlgrpsmax; j++)
if (klgrpset_ismember(lgrp->lgrp_children, j))
BT_SET(lgrp_info[i].info_children, j);
lgrp_info[i].info_rset =
(ulong_t *)((uintptr_t)lgrp_rsets +
(i * LGRP_RSRC_COUNT * bitmask_size));
for (j = 0; j < LGRP_RSRC_COUNT; j++) {
ulong_t *rset;
rset = (ulong_t *)((uintptr_t)lgrp_info[i].info_rset +
(j * bitmask_size));
for (k = 0; k < snap_nlgrpsmax; k++)
if (klgrpset_ismember(lgrp->lgrp_set[j], k))
BT_SET(rset, k);
}
cpu_count = 0;
lgrp_info[i].info_cpuids = NULL;
cp = head = lgrp->lgrp_cpu;
if (head != NULL) {
lgrp_info[i].info_cpuids = &lgrp_cpuids[cpu_index];
do {
lgrp_cpuids[cpu_index] = cp->cpu_id;
cpu_index++;
cpu_count++;
cp = cp->cpu_next_lgrp;
} while (cp != head);
}
ASSERT(cpu_count == lgrp->lgrp_cpucnt);
lgrp_info[i].info_ncpus = cpu_count;
if (klgrpset_ismember(lgrp->lgrp_set[LGRP_RSRC_MEM], i)) {
lgrp_info[i].info_mem_free =
lgrp_mem_size(i, LGRP_MEM_SIZE_FREE);
lgrp_info[i].info_mem_install =
lgrp_mem_size(i, LGRP_MEM_SIZE_INSTALL);
}
lgrp_lats[i] = (int *)((uintptr_t)lgrp_lats + snap_nlgrpsmax *
sizeof (int *) + i * snap_nlgrpsmax * sizeof (int));
for (j = 0; j < snap_nlgrpsmax; j++) {
lgrp_t *to;
to = lgrp_table[j];
if (!LGRP_EXISTS(to))
continue;
lgrp_lats[i][j] = lgrp_latency(lgrp->lgrp_id,
to->lgrp_id);
}
}
ASSERT(cpu_index == snap_ncpus);
mutex_exit(&cpu_lock);
#ifdef _SYSCALL32_IMPL
if (model == DATAMODEL_ILP32) {
snap_nlgrpsmax = lgrp_snap->ss_nlgrps_max;
snap_hdr_size = P2ROUNDUP(sizeof (lgrp_snapshot_header32_t),
sizeof (caddr32_t));
info_size =
P2ROUNDUP(snap_nlgrpsmax * sizeof (lgrp_info32_t),
sizeof (processorid_t));
cpuids_size =
P2ROUNDUP(lgrp_snap->ss_ncpus * sizeof (processorid_t),
sizeof (ulong_t));
bitmask_size = BT_SIZEOFMAP(snap_nlgrpsmax);
bitmasks_size = (((2 + LGRP_RSRC_COUNT) * snap_nlgrpsmax) +
1) * bitmask_size;
lats_size = (snap_nlgrpsmax * sizeof (caddr32_t)) +
(snap_nlgrpsmax * snap_nlgrpsmax * sizeof (int));
bufsize = snap_hdr_size + info_size + cpuids_size +
bitmasks_size + lats_size;
return (bufsize);
}
#endif
return (lgrp_snap->ss_size);
}
static int
lgrp_snapshot_copy(char *buf, size_t bufsize)
{
size_t bitmask_size;
int cpu_index;
size_t cpuids_size;
int i;
size_t info_size;
lgrp_info_t *lgrp_info;
int retval;
size_t snap_hdr_size;
int snap_ncpus;
int snap_nlgrpsmax;
lgrp_snapshot_header_t *user_snap;
lgrp_info_t *user_info;
lgrp_info_t *user_info_buffer;
processorid_t *user_cpuids;
ulong_t *user_lgrpset;
ulong_t *user_parents;
ulong_t *user_children;
int **user_lats;
int **user_lats_buffer;
ulong_t *user_rsets;
if (lgrp_snap == NULL)
return (0);
if (buf == NULL || bufsize <= 0)
return (lgrp_snap->ss_size);
if (bufsize < lgrp_snap->ss_size)
return (set_errno(EAGAIN));
snap_ncpus = lgrp_snap->ss_ncpus;
snap_nlgrpsmax = lgrp_snap->ss_nlgrps_max;
kpreempt_disable();
for (i = 0; i < snap_nlgrpsmax; i++) {
if (klgrpset_ismember(curthread->t_cpupart->cp_lgrpset,
i)) {
BT_SET(lgrp_snap->ss_lgrpset, i);
}
}
kpreempt_enable();
if (copyout(lgrp_snap, buf, lgrp_snap->ss_size) != 0)
return (set_errno(EFAULT));
snap_hdr_size = P2ROUNDUP(sizeof (lgrp_snapshot_header_t),
sizeof (void *));
info_size = P2ROUNDUP(snap_nlgrpsmax * sizeof (lgrp_info_t),
sizeof (processorid_t));
cpuids_size = P2ROUNDUP(snap_ncpus * sizeof (processorid_t),
sizeof (ulong_t));
bitmask_size = BT_SIZEOFMAP(snap_nlgrpsmax);
user_snap = (lgrp_snapshot_header_t *)buf;
user_info = (lgrp_info_t *)((uintptr_t)user_snap + snap_hdr_size);
user_cpuids = (processorid_t *)((uintptr_t)user_info + info_size);
user_lgrpset = (ulong_t *)((uintptr_t)user_cpuids + cpuids_size);
user_parents = (ulong_t *)((uintptr_t)user_lgrpset + bitmask_size);
user_children = (ulong_t *)((uintptr_t)user_parents +
(snap_nlgrpsmax * bitmask_size));
user_rsets = (ulong_t *)((uintptr_t)user_children +
(snap_nlgrpsmax * bitmask_size));
user_lats = (int **)((uintptr_t)user_rsets +
(LGRP_RSRC_COUNT * snap_nlgrpsmax * bitmask_size));
if (copyout(&buf, &user_snap->ss_magic, sizeof (buf)) != 0)
return (set_errno(EFAULT));
if (copyout(&user_info, &user_snap->ss_info, sizeof (user_info)) != 0)
return (set_errno(EFAULT));
if (copyout(&user_cpuids, &user_snap->ss_cpuids,
sizeof (user_cpuids)) != 0)
return (set_errno(EFAULT));
if (copyout(&user_lgrpset, &user_snap->ss_lgrpset,
sizeof (user_lgrpset)) != 0)
return (set_errno(EFAULT));
if (copyout(&user_parents, &user_snap->ss_parents,
sizeof (user_parents)) != 0)
return (set_errno(EFAULT));
if (copyout(&user_children, &user_snap->ss_children,
sizeof (user_children)) != 0)
return (set_errno(EFAULT));
if (copyout(&user_rsets, &user_snap->ss_rsets,
sizeof (user_rsets)) != 0)
return (set_errno(EFAULT));
if (copyout(&user_lats, &user_snap->ss_latencies,
sizeof (user_lats)) != 0)
return (set_errno(EFAULT));
user_info_buffer = kmem_zalloc(info_size, KM_NOSLEEP);
if (user_info_buffer == NULL)
return (set_errno(ENOMEM));
user_lats_buffer = kmem_zalloc(snap_nlgrpsmax * sizeof (int *),
KM_NOSLEEP);
if (user_lats_buffer == NULL) {
kmem_free(user_info_buffer, info_size);
return (set_errno(ENOMEM));
}
lgrp_info = (lgrp_info_t *)((uintptr_t)lgrp_snap + snap_hdr_size);
bcopy(lgrp_info, user_info_buffer, info_size);
cpu_index = 0;
for (i = 0; i < snap_nlgrpsmax; i++) {
ulong_t *snap_rset;
if (user_info_buffer[i].info_lgrpid == LGRP_NONE)
continue;
snap_rset = &lgrp_info[i].info_rset[LGRP_RSRC_MEM *
BT_BITOUL(snap_nlgrpsmax)];
if (BT_TEST(snap_rset, i))
user_info_buffer[i].info_mem_free =
lgrp_mem_size(i, LGRP_MEM_SIZE_FREE);
user_info_buffer[i].info_parents =
(ulong_t *)((uintptr_t)user_parents + (i * bitmask_size));
user_info_buffer[i].info_children =
(ulong_t *)((uintptr_t)user_children + (i * bitmask_size));
user_info_buffer[i].info_rset =
(ulong_t *)((uintptr_t)user_rsets +
(i * LGRP_RSRC_COUNT * bitmask_size));
user_lats_buffer[i] = (int *)((uintptr_t)user_lats +
(snap_nlgrpsmax * sizeof (int *)) + (i * snap_nlgrpsmax *
sizeof (int)));
if (user_info_buffer[i].info_ncpus == 0) {
user_info_buffer[i].info_cpuids = NULL;
continue;
}
user_info_buffer[i].info_cpuids = &user_cpuids[cpu_index];
cpu_index += user_info_buffer[i].info_ncpus;
}
ASSERT(cpu_index == snap_ncpus);
retval = lgrp_snap->ss_size;
if (copyout(user_info_buffer, user_info, info_size) != 0)
retval = set_errno(EFAULT);
kmem_free(user_info_buffer, info_size);
if (copyout(user_lats_buffer, user_lats, snap_nlgrpsmax *
sizeof (int *)) != 0)
retval = set_errno(EFAULT);
kmem_free(user_lats_buffer, snap_nlgrpsmax * sizeof (int *));
return (retval);
}
#ifdef _SYSCALL32_IMPL
static int
lgrp_snapshot_copy32(caddr32_t buf, size32_t bufsize)
{
size32_t bitmask_size;
size32_t bitmasks_size;
size32_t children_size;
int cpu_index;
size32_t cpuids_size;
int i;
int j;
size32_t info_size;
size32_t lats_size;
lgrp_info_t *lgrp_info;
lgrp_snapshot_header32_t *lgrp_snap32;
lgrp_info32_t *lgrp_info32;
processorid_t *lgrp_cpuids32;
caddr32_t *lgrp_lats32;
int **lgrp_lats32_kernel;
uint_t *lgrp_set32;
uint_t *lgrp_parents32;
uint_t *lgrp_children32;
uint_t *lgrp_rsets32;
size32_t parents_size;
size32_t rsets_size;
size32_t set_size;
size32_t snap_hdr_size;
int snap_ncpus;
int snap_nlgrpsmax;
size32_t snap_size;
if (lgrp_snap == NULL)
return (0);
snap_ncpus = lgrp_snap->ss_ncpus;
snap_nlgrpsmax = lgrp_snap->ss_nlgrps_max;
snap_hdr_size = P2ROUNDUP(sizeof (lgrp_snapshot_header32_t),
sizeof (caddr32_t));
info_size = P2ROUNDUP(snap_nlgrpsmax * sizeof (lgrp_info32_t),
sizeof (processorid_t));
cpuids_size = P2ROUNDUP(snap_ncpus * sizeof (processorid_t),
sizeof (ulong_t));
bitmask_size = BT_SIZEOFMAP32(snap_nlgrpsmax);
set_size = bitmask_size;
parents_size = snap_nlgrpsmax * bitmask_size;
children_size = snap_nlgrpsmax * bitmask_size;
rsets_size = P2ROUNDUP(LGRP_RSRC_COUNT * snap_nlgrpsmax *
(int)bitmask_size, sizeof (caddr32_t));
bitmasks_size = set_size + parents_size + children_size + rsets_size;
lats_size = (snap_nlgrpsmax * sizeof (caddr32_t)) +
(snap_nlgrpsmax * snap_nlgrpsmax * sizeof (int));
snap_size = snap_hdr_size + info_size + cpuids_size + bitmasks_size +
lats_size;
if (buf == 0 || bufsize <= 0) {
return (snap_size);
}
if (bufsize < snap_size)
return (set_errno(EAGAIN));
lgrp_snap32 = kmem_zalloc(snap_size, KM_NOSLEEP);
if (lgrp_snap32 == NULL)
return (set_errno(ENOMEM));
lgrp_info32 = (lgrp_info32_t *)((uintptr_t)lgrp_snap32 +
snap_hdr_size);
lgrp_cpuids32 = (processorid_t *)((uintptr_t)lgrp_info32 + info_size);
lgrp_set32 = (uint_t *)((uintptr_t)lgrp_cpuids32 + cpuids_size);
lgrp_parents32 = (uint_t *)((uintptr_t)lgrp_set32 + set_size);
lgrp_children32 = (uint_t *)((uintptr_t)lgrp_parents32 + parents_size);
lgrp_rsets32 = (uint_t *)((uintptr_t)lgrp_children32 + children_size);
lgrp_lats32 = (caddr32_t *)((uintptr_t)lgrp_rsets32 + rsets_size);
lgrp_lats32_kernel = kmem_zalloc(snap_nlgrpsmax * sizeof (int *),
KM_NOSLEEP);
if (lgrp_lats32_kernel == NULL) {
kmem_free(lgrp_snap32, snap_size);
return (set_errno(ENOMEM));
}
lgrp_snap32->ss_version = lgrp_snap->ss_version;
lgrp_snap32->ss_levels = lgrp_snap->ss_levels;
lgrp_snap32->ss_nlgrps = lgrp_snap32->ss_nlgrps_os =
lgrp_snap->ss_nlgrps;
lgrp_snap32->ss_nlgrps_max = snap_nlgrpsmax;
lgrp_snap32->ss_root = lgrp_snap->ss_root;
lgrp_snap32->ss_ncpus = lgrp_snap->ss_ncpus;
lgrp_snap32->ss_gen = lgrp_snap->ss_gen;
lgrp_snap32->ss_view = LGRP_VIEW_OS;
lgrp_snap32->ss_size = snap_size;
lgrp_snap32->ss_magic = buf;
lgrp_snap32->ss_info = buf + snap_hdr_size;
lgrp_snap32->ss_cpuids = lgrp_snap32->ss_info + info_size;
lgrp_snap32->ss_lgrpset = lgrp_snap32->ss_cpuids + cpuids_size;
lgrp_snap32->ss_parents = lgrp_snap32->ss_lgrpset + bitmask_size;
lgrp_snap32->ss_children = lgrp_snap32->ss_parents +
(snap_nlgrpsmax * bitmask_size);
lgrp_snap32->ss_rsets = lgrp_snap32->ss_children +
(snap_nlgrpsmax * bitmask_size);
lgrp_snap32->ss_latencies = lgrp_snap32->ss_rsets +
(LGRP_RSRC_COUNT * snap_nlgrpsmax * bitmask_size);
kpreempt_disable();
for (i = 0; i < snap_nlgrpsmax; i++) {
if (klgrpset_ismember(curthread->t_cpupart->cp_lgrpset,
i)) {
BT_SET32(lgrp_set32, i);
}
}
kpreempt_enable();
cpu_index = 0;
lgrp_info = lgrp_snap->ss_info;
for (i = 0; i < snap_nlgrpsmax; i++) {
uint_t *children;
uint_t *lgrp_rset;
uint_t *parents;
ulong_t *snap_rset;
if (lgrp_info[i].info_lgrpid == LGRP_NONE) {
bzero(&lgrp_info32[i], sizeof (lgrp_info32[i]));
lgrp_info32[i].info_lgrpid = LGRP_NONE;
continue;
}
parents = (uint_t *)((uintptr_t)lgrp_parents32 +
i * bitmask_size);
children = (uint_t *)((uintptr_t)lgrp_children32 +
i * bitmask_size);
snap_rset = (ulong_t *)((uintptr_t)lgrp_snap->ss_rsets +
(i * LGRP_RSRC_COUNT * BT_SIZEOFMAP(snap_nlgrpsmax)));
lgrp_rset = (uint_t *)((uintptr_t)lgrp_rsets32 +
(i * LGRP_RSRC_COUNT * bitmask_size));
lgrp_lats32_kernel[i] = (int *)((uintptr_t)lgrp_lats32 +
snap_nlgrpsmax * sizeof (caddr32_t) + i * snap_nlgrpsmax *
sizeof (int));
for (j = 0; j < snap_nlgrpsmax; j++) {
int k;
uint_t *rset;
if (BT_TEST(&lgrp_snap->ss_parents[i], j))
BT_SET32(parents, j);
if (BT_TEST(&lgrp_snap->ss_children[i], j))
BT_SET32(children, j);
for (k = 0; k < LGRP_RSRC_COUNT; k++) {
rset = (uint_t *)((uintptr_t)lgrp_rset +
k * bitmask_size);
if (BT_TEST(&snap_rset[k], j))
BT_SET32(rset, j);
}
lgrp_lats32_kernel[i][j] =
lgrp_snap->ss_latencies[i][j];
}
lgrp_lats32[i] = lgrp_snap32->ss_latencies +
snap_nlgrpsmax * sizeof (caddr32_t) + i * snap_nlgrpsmax *
sizeof (int);
lgrp_info32[i].info_parents = lgrp_snap32->ss_parents +
(i * bitmask_size);
lgrp_info32[i].info_children = lgrp_snap32->ss_children +
(i * bitmask_size);
lgrp_info32[i].info_rset = lgrp_snap32->ss_rsets +
(i * LGRP_RSRC_COUNT * bitmask_size);
snap_rset = &lgrp_info[i].info_rset[LGRP_RSRC_MEM *
BT_BITOUL(snap_nlgrpsmax)];
if (BT_TEST(snap_rset, i)) {
lgrp_info32[i].info_mem_free = lgrp_mem_size(i,
LGRP_MEM_SIZE_FREE);
lgrp_info32[i].info_mem_install =
lgrp_info[i].info_mem_install;
}
lgrp_info32[i].info_ncpus = lgrp_info[i].info_ncpus;
lgrp_info32[i].info_lgrpid = lgrp_info[i].info_lgrpid;
lgrp_info32[i].info_latency = lgrp_info[i].info_latency;
if (lgrp_info32[i].info_ncpus == 0) {
lgrp_info32[i].info_cpuids = 0;
continue;
}
lgrp_info32[i].info_cpuids = lgrp_snap32->ss_cpuids +
(cpu_index * sizeof (processorid_t));
cpu_index += lgrp_info32[i].info_ncpus;
}
ASSERT(cpu_index == snap_ncpus);
bcopy(lgrp_snap->ss_cpuids, lgrp_cpuids32, cpuids_size);
if (copyout(lgrp_snap32, (void *)(uintptr_t)buf, snap_size) != 0) {
kmem_free(lgrp_snap32, snap_size);
kmem_free(lgrp_lats32_kernel, snap_nlgrpsmax * sizeof (int *));
return (set_errno(EFAULT));
}
kmem_free(lgrp_snap32, snap_size);
kmem_free(lgrp_lats32_kernel, snap_nlgrpsmax * sizeof (int *));
return (snap_size);
}
#endif
int
lgrpsys(int subcode, long ia, void *ap)
{
size_t bufsize;
int latency;
switch (subcode) {
case LGRP_SYS_AFFINITY_GET:
return (lgrp_affinity_get((lgrp_affinity_args_t *)ap));
case LGRP_SYS_AFFINITY_SET:
return (lgrp_affinity_set((lgrp_affinity_args_t *)ap));
case LGRP_SYS_GENERATION:
return (lgrp_generation(ia));
case LGRP_SYS_HOME:
return (lgrp_home_get((idtype_t)ia, (id_t)(uintptr_t)ap));
case LGRP_SYS_LATENCY:
mutex_enter(&cpu_lock);
latency = lgrp_latency(ia, (lgrp_id_t)(uintptr_t)ap);
mutex_exit(&cpu_lock);
return (latency);
case LGRP_SYS_MEMINFO:
return (meminfo(ia, (struct meminfo *)ap));
case LGRP_SYS_VERSION:
return (lgrp_version(ia));
case LGRP_SYS_SNAPSHOT:
mutex_enter(&lgrp_snap_lock);
bufsize = lgrp_snapshot();
if (ap && ia > 0) {
if (get_udatamodel() == DATAMODEL_NATIVE)
bufsize = lgrp_snapshot_copy(ap, ia);
#ifdef _SYSCALL32_IMPL
else
bufsize = lgrp_snapshot_copy32(
(caddr32_t)(uintptr_t)ap, ia);
#endif
}
mutex_exit(&lgrp_snap_lock);
return (bufsize);
default:
break;
}
return (set_errno(EINVAL));
}