/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/
/*
* kernel statistics driver
*/
#include <sys/sysmacros.h>
static int
{
#ifdef _MULTI_DATAMODEL
#endif
int error = 0;
#ifdef _MULTI_DATAMODEL
case DDI_MODEL_ILP32:
return (EFAULT);
break;
#endif
default:
case DDI_MODEL_NONE:
return (EFAULT);
}
/*
* There is no kstat with the specified KID
*/
return (ENXIO);
}
/*
* The kstat exists, but is momentarily in some
* indeterminate state (e.g. the data section is not
* yet initialized). Try again in a few milliseconds.
*/
return (EAGAIN);
}
/*
* If it's a fixed-size kstat, allocate the buffer now, so we
* don't have to do it under the kstat's data lock. (If it's a
* var-size kstat or one with long strings, we don't know the size
* until after the update routine is called, so we can't do this
* optimization.)
* The allocator relies on this behavior to prevent recursive
* mutex_enter in its (fixed-size) kstat update routine.
* It's a zalloc to prevent unintentional exposure of random
* juicy morsels of (old) kernel data.
*/
return (EAGAIN);
}
}
return (error);
}
} else {
} else {
}
}
/*
* The following info must be returned to user level,
* even if the the update or snapshot failed. This allows
* kstat readers to get a handle on variable-size kstats,
* detect dormant kstats, etc.
*/
*rvalp = kstat_chain_id;
goto out;
/*
* Copy the buffer containing the kstat back to userland.
*/
switch (model) {
int i;
#ifdef _MULTI_DATAMODEL
kstat_t *k;
case DDI_MODEL_ILP32:
/*
* Named statistics have fields of type 'long'.
* For a 32-bit application looking at a 64-bit
* kernel, forcibly truncate these 64-bit
* quantities to 32-bit values.
*/
case KSTAT_DATA_LONG:
break;
case KSTAT_DATA_ULONG:
break;
/*
* Long strings must be massaged before being
* copied out to userland. Do that here.
*/
case KSTAT_DATA_STRING:
break;
/*
* If the string lies outside of kbuf
* copy it there and update the pointer.
*/
if (KSTAT_NAMED_STR_PTR(kn) <
(char *)kbuf ||
strbuf +=
(char *)kbuf +
kbufsize + 1);
}
/*
* The offsets within the buffers are
* the same, so add the offset to the
* beginning of the new buffer to fix
* the pointer.
*/
(char *)user_kstat.ks_data +
(char *)kbuf);
/*
* Make sure the string pointer lies
* within the allocated buffer.
*/
((char *)user_kstat.ks_data +
ubufsize));
(char *)((kstat_named_t *)
/*
* Cast 64-bit ptr to 32-bit.
*/
break;
default:
break;
}
}
if (user_kstat.ks_kid != 0)
break;
/*
* This is the special case of the kstat header
* list for the entire system. Reshape the
* array in place, then copy it out.
*/
k = kbuf;
if (k->ks_data_size > UINT32_MAX) {
break;
}
}
/*
* XXX In this case we copy less data than is
* claimed in the header.
*/
break;
#endif /* _MULTI_DATAMODEL */
default:
case DDI_MODEL_NONE:
#ifdef _LP64
case KSTAT_DATA_LONG:
break;
case KSTAT_DATA_ULONG:
break;
#endif /* _LP64 */
case KSTAT_DATA_STRING:
break;
/*
* If the string lies outside of kbuf
* copy it there and update the pointer.
*/
if (KSTAT_NAMED_STR_PTR(kn) <
(char *)kbuf ||
strbuf +=
(char *)kbuf +
kbufsize + 1);
}
(char *)user_kstat.ks_data +
(char *)kbuf);
((char *)user_kstat.ks_data +
ubufsize));
(char *)((kstat_named_t *)
break;
default:
break;
}
}
break;
}
if (error == 0 &&
out:
/*
* We have modified the ks_ndata, ks_data_size, ks_flags, and
* ks_snaptime fields of the user kstat; now copy it back to userland.
*/
switch (model) {
#ifdef _MULTI_DATAMODEL
case DDI_MODEL_ILP32:
if (kbufsize > UINT32_MAX) {
break;
}
error == 0)
break;
#endif
default:
case DDI_MODEL_NONE:
error == 0)
break;
}
return (error);
}
static int
{
int error = 0;
return (EPERM);
#ifdef _MULTI_DATAMODEL
case DDI_MODEL_ILP32:
return (EFAULT);
/*
* These are the only fields we actually look at.
*/
break;
#endif
default:
case DDI_MODEL_NONE:
return (EFAULT);
}
return (EAGAIN);
return (EFAULT);
}
return (ENXIO);
}
return (EAGAIN);
}
return (EACCES);
}
/*
* With KSTAT_FLAG_VAR_SIZE, one must call the kstat's update callback
* routine to ensure ks_data_size is up to date.
* In this case it makes sense to do it anyhow, as it will be shortly
* followed by a KSTAT_SNAPSHOT().
*/
}
/*
* We have to ensure that we don't accidentally change the type of
* existing kstat_named statistics when writing over them.
* Since read_kstat_data() modifies some of the types on their way
* out, we need to be sure to handle these types seperately.
*/
void *kbuf;
int i;
#ifdef _MULTI_DATAMODEL
#endif
/*
* Since ksp->ks_data may be NULL, we need to take a snapshot
* of the published data to look at the types.
*/
return (EAGAIN);
}
if (error) {
return (error);
}
/*
* read_kstat_data() changes the types of
* KSTAT_DATA_LONG / KSTAT_DATA_ULONG, so we need to
* make sure that these (modified) types are considered
* valid.
*/
#ifdef _MULTI_DATAMODEL
case KSTAT_DATA_LONG:
switch (model) {
case DDI_MODEL_ILP32:
}
break;
default:
case DDI_MODEL_NONE:
#ifdef _LP64
}
#endif /* _LP64 */
break;
}
break;
case KSTAT_DATA_ULONG:
switch (model) {
case DDI_MODEL_ILP32:
}
break;
default:
case DDI_MODEL_NONE:
#ifdef _LP64
}
#endif /* _LP64 */
break;
}
break;
#endif /* _MULTI_DATAMODEL */
case KSTAT_DATA_STRING:
return (EINVAL);
}
#ifdef _MULTI_DATAMODEL
if (model == DDI_MODEL_ILP32)
(char *)(uintptr_t)
#endif
/*
* Nothing special for NULL
*/
break;
/*
* Check to see that the pointers all point
* to within the buffer and after the array
* of kstat_named_t's.
*/
if (KSTAT_NAMED_STR_PTR(knew) <
(char *)
return (EINVAL);
}
if (KSTAT_NAMED_STR_PTR(knew) +
((char *)user_kstat.ks_data +
ksp->ks_data_size)) {
return (EINVAL);
}
/*
* Update the pointers within the buffer
*/
(char *)buf +
(char *)user_kstat.ks_data);
break;
default:
break;
}
}
/*
* Now make sure the types are what we expected them to be.
*/
return (EINVAL);
}
}
if (!error)
*rvalp = kstat_chain_id;
return (error);
}
/*ARGSUSED*/
static int
{
int rc = 0;
switch (cmd) {
case KSTAT_IOC_CHAIN_ID:
*rvalp = kstat_chain_id;
break;
case KSTAT_IOC_READ:
break;
case KSTAT_IOC_WRITE:
break;
default:
/* invalid request */
}
return (rc);
}
/* ARGSUSED */
static int
void **result)
{
switch (infocmd) {
case DDI_INFO_DEVT2DEVINFO:
*result = kstat_devi;
return (DDI_SUCCESS);
case DDI_INFO_DEVT2INSTANCE:
return (DDI_SUCCESS);
}
return (DDI_FAILURE);
}
static int
{
if (cmd != DDI_ATTACH)
return (DDI_FAILURE);
return (DDI_FAILURE);
}
kstat_devi = devi;
return (DDI_SUCCESS);
}
static int
{
if (cmd != DDI_DETACH)
return (DDI_FAILURE);
return (DDI_SUCCESS);
}
nulldev, /* open */
nulldev, /* close */
nodev, /* strategy */
nodev, /* print */
nodev, /* dump */
nodev, /* read */
nodev, /* write */
kstat_ioctl, /* ioctl */
nodev, /* devmap */
nodev, /* mmap */
nodev, /* segmap */
nochpoll, /* poll */
ddi_prop_op, /* prop_op */
0, /* streamtab */
};
DEVO_REV, /* devo_rev, */
0, /* refcnt */
kstat_info, /* get_dev_info */
nulldev, /* identify */
nulldev, /* probe */
kstat_attach, /* attach */
kstat_detach, /* detach */
nodev, /* reset */
&kstat_cb_ops, /* driver operations */
(struct bus_ops *)0, /* no bus operations */
NULL, /* power */
ddi_quiesce_not_needed, /* quiesce */
};
};
};
int
_init(void)
{
return (mod_install(&modlinkage));
}
int
_fini(void)
{
return (mod_remove(&modlinkage));
}
int
{
}