Home | History | Annotate | Line # | Download | only in sysmon
sysmon.c revision 1.28.18.1
      1  1.28.18.1  christos /*	$NetBSD: sysmon.c,v 1.28.18.1 2019/06/10 22:07:33 christos Exp $	*/
      2        1.1   thorpej 
      3        1.1   thorpej /*-
      4        1.1   thorpej  * Copyright (c) 2000 Zembu Labs, Inc.
      5        1.1   thorpej  * All rights reserved.
      6        1.1   thorpej  *
      7        1.1   thorpej  * Author: Jason R. Thorpe <thorpej (at) zembu.com>
      8        1.1   thorpej  *
      9        1.1   thorpej  * Redistribution and use in source and binary forms, with or without
     10        1.1   thorpej  * modification, are permitted provided that the following conditions
     11        1.1   thorpej  * are met:
     12        1.1   thorpej  * 1. Redistributions of source code must retain the above copyright
     13        1.1   thorpej  *    notice, this list of conditions and the following disclaimer.
     14        1.1   thorpej  * 2. Redistributions in binary form must reproduce the above copyright
     15        1.1   thorpej  *    notice, this list of conditions and the following disclaimer in the
     16        1.1   thorpej  *    documentation and/or other materials provided with the distribution.
     17        1.1   thorpej  * 3. All advertising materials mentioning features or use of this software
     18        1.1   thorpej  *    must display the following acknowledgement:
     19        1.1   thorpej  *	This product includes software developed by Zembu Labs, Inc.
     20        1.1   thorpej  * 4. Neither the name of Zembu Labs nor the names of its employees may
     21        1.1   thorpej  *    be used to endorse or promote products derived from this software
     22        1.1   thorpej  *    without specific prior written permission.
     23        1.1   thorpej  *
     24        1.1   thorpej  * THIS SOFTWARE IS PROVIDED BY ZEMBU LABS, INC. ``AS IS'' AND ANY EXPRESS
     25        1.1   thorpej  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WAR-
     26        1.1   thorpej  * RANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DIS-
     27        1.1   thorpej  * CLAIMED.  IN NO EVENT SHALL ZEMBU LABS BE LIABLE FOR ANY DIRECT, INDIRECT,
     28        1.1   thorpej  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     29        1.1   thorpej  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     30        1.1   thorpej  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     31        1.1   thorpej  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     32        1.1   thorpej  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     33        1.1   thorpej  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     34        1.1   thorpej  */
     35        1.1   thorpej 
     36        1.1   thorpej /*
     37        1.4   thorpej  * Clearing house for system monitoring hardware.  We currently
     38        1.8   thorpej  * handle environmental sensors, watchdog timers, and power management.
     39        1.1   thorpej  */
     40        1.5     lukem 
     41        1.5     lukem #include <sys/cdefs.h>
     42  1.28.18.1  christos __KERNEL_RCSID(0, "$NetBSD: sysmon.c,v 1.28.18.1 2019/06/10 22:07:33 christos Exp $");
     43        1.1   thorpej 
     44        1.1   thorpej #include <sys/param.h>
     45        1.1   thorpej #include <sys/conf.h>
     46        1.1   thorpej #include <sys/errno.h>
     47        1.1   thorpej #include <sys/fcntl.h>
     48        1.3   thorpej #include <sys/callout.h>
     49        1.3   thorpej #include <sys/kernel.h>
     50        1.3   thorpej #include <sys/systm.h>
     51        1.3   thorpej #include <sys/proc.h>
     52       1.20  pgoyette #include <sys/module.h>
     53       1.20  pgoyette #include <sys/mutex.h>
     54       1.20  pgoyette #include <sys/device.h>
     55       1.25  pgoyette #include <sys/once.h>
     56        1.1   thorpej 
     57        1.1   thorpej #include <dev/sysmon/sysmonvar.h>
     58        1.1   thorpej 
     59        1.6   gehenna dev_type_open(sysmonopen);
     60        1.6   gehenna dev_type_close(sysmonclose);
     61        1.6   gehenna dev_type_ioctl(sysmonioctl);
     62        1.8   thorpej dev_type_read(sysmonread);
     63        1.8   thorpej dev_type_poll(sysmonpoll);
     64        1.8   thorpej dev_type_kqfilter(sysmonkqfilter);
     65        1.6   gehenna 
     66        1.6   gehenna const struct cdevsw sysmon_cdevsw = {
     67       1.18  dholland 	.d_open = sysmonopen,
     68       1.18  dholland 	.d_close = sysmonclose,
     69       1.18  dholland 	.d_read = sysmonread,
     70       1.18  dholland 	.d_write = nowrite,
     71       1.18  dholland 	.d_ioctl = sysmonioctl,
     72       1.18  dholland 	.d_stop = nostop,
     73       1.18  dholland 	.d_tty = notty,
     74       1.18  dholland 	.d_poll = sysmonpoll,
     75       1.18  dholland 	.d_mmap = nommap,
     76       1.18  dholland 	.d_kqfilter = sysmonkqfilter,
     77       1.19  dholland 	.d_discard = nodiscard,
     78       1.18  dholland 	.d_flag = D_OTHER | D_MPSAFE
     79        1.6   gehenna };
     80        1.1   thorpej 
     81       1.20  pgoyette static int	sysmon_modcmd(modcmd_t, void *);
     82       1.25  pgoyette static int	sm_init_once(void);
     83       1.20  pgoyette 
     84       1.20  pgoyette /*
     85       1.20  pgoyette  * Info about our minor "devices"
     86       1.20  pgoyette  */
     87       1.20  pgoyette static struct sysmon_opvec	*sysmon_opvec_table[] = { NULL, NULL, NULL };
     88       1.20  pgoyette static int			sysmon_refcnt[] = { 0, 0, 0 };
     89       1.20  pgoyette static const char		*sysmon_mod[] = { "sysmon_envsys",
     90       1.20  pgoyette 						  "sysmon_wdog",
     91       1.20  pgoyette 						  "sysmon_power" };
     92       1.25  pgoyette static kmutex_t sysmon_minor_mtx;
     93       1.20  pgoyette 
     94       1.25  pgoyette #ifdef _MODULE
     95       1.25  pgoyette static bool	sm_is_attached;
     96       1.25  pgoyette #endif
     97       1.20  pgoyette 
     98       1.25  pgoyette ONCE_DECL(once_sm);
     99       1.20  pgoyette 
    100       1.20  pgoyette /*
    101       1.20  pgoyette  * sysmon_attach_minor
    102       1.20  pgoyette  *
    103       1.20  pgoyette  *	Attach a minor device for wdog, power, or envsys.  Manage a
    104       1.20  pgoyette  *	reference count so we can prevent the device from being
    105       1.20  pgoyette  *	detached if there are still users with the minor device opened.
    106       1.20  pgoyette  *
    107       1.20  pgoyette  *	If the opvec argument is NULL, this is a request to detach the
    108       1.20  pgoyette  *	minor device - make sure the refcnt is zero!
    109       1.20  pgoyette  */
    110       1.20  pgoyette int
    111       1.20  pgoyette sysmon_attach_minor(int minor, struct sysmon_opvec *opvec)
    112       1.20  pgoyette {
    113       1.20  pgoyette 	int ret;
    114       1.20  pgoyette 
    115       1.25  pgoyette 	mutex_enter(&sysmon_minor_mtx);
    116       1.20  pgoyette 	if (opvec) {
    117       1.20  pgoyette 		if (sysmon_opvec_table[minor] == NULL) {
    118       1.20  pgoyette 			sysmon_refcnt[minor] = 0;
    119       1.20  pgoyette 			sysmon_opvec_table[minor] = opvec;
    120       1.20  pgoyette 			ret = 0;
    121       1.20  pgoyette 		} else
    122       1.20  pgoyette 			ret = EEXIST;
    123       1.20  pgoyette 	} else {
    124       1.20  pgoyette 		if (sysmon_refcnt[minor] == 0) {
    125       1.20  pgoyette 			sysmon_opvec_table[minor] = NULL;
    126       1.20  pgoyette 			ret = 0;
    127       1.20  pgoyette 		} else
    128       1.20  pgoyette 			ret = EBUSY;
    129       1.20  pgoyette 	}
    130       1.20  pgoyette 
    131       1.25  pgoyette 	mutex_exit(&sysmon_minor_mtx);
    132       1.20  pgoyette 	return ret;
    133       1.20  pgoyette }
    134       1.20  pgoyette 
    135        1.1   thorpej /*
    136        1.1   thorpej  * sysmonopen:
    137        1.1   thorpej  *
    138        1.1   thorpej  *	Open the system monitor device.
    139        1.1   thorpej  */
    140        1.1   thorpej int
    141       1.11  christos sysmonopen(dev_t dev, int flag, int mode, struct lwp *l)
    142        1.1   thorpej {
    143        1.4   thorpej 	int error;
    144        1.3   thorpej 
    145       1.25  pgoyette 	mutex_enter(&sysmon_minor_mtx);
    146       1.20  pgoyette 
    147        1.3   thorpej 	switch (minor(dev)) {
    148        1.3   thorpej 	case SYSMON_MINOR_ENVSYS:
    149        1.3   thorpej 	case SYSMON_MINOR_WDOG:
    150        1.8   thorpej 	case SYSMON_MINOR_POWER:
    151       1.20  pgoyette 		if (sysmon_opvec_table[minor(dev)] == NULL) {
    152       1.25  pgoyette 			mutex_exit(&sysmon_minor_mtx);
    153       1.20  pgoyette 			error = module_autoload(sysmon_mod[minor(dev)],
    154       1.20  pgoyette 						MODULE_CLASS_MISC);
    155       1.28  pgoyette 			if (error)
    156       1.28  pgoyette 				return error;
    157       1.25  pgoyette 			mutex_enter(&sysmon_minor_mtx);
    158       1.26  pgoyette 			if (sysmon_opvec_table[minor(dev)] == NULL) {
    159       1.20  pgoyette 				error = ENODEV;
    160       1.26  pgoyette 				break;
    161       1.26  pgoyette 			}
    162       1.20  pgoyette 		}
    163       1.20  pgoyette 		error = (sysmon_opvec_table[minor(dev)]->so_open)(dev, flag,
    164       1.20  pgoyette 		    mode, l);
    165       1.20  pgoyette 		if (error == 0)
    166       1.20  pgoyette 			sysmon_refcnt[minor(dev)]++;
    167        1.8   thorpej 		break;
    168        1.3   thorpej 	default:
    169        1.3   thorpej 		error = ENODEV;
    170        1.3   thorpej 	}
    171        1.1   thorpej 
    172       1.25  pgoyette 	mutex_exit(&sysmon_minor_mtx);
    173       1.28  pgoyette 	return error;
    174        1.1   thorpej }
    175        1.1   thorpej 
    176        1.1   thorpej /*
    177        1.1   thorpej  * sysmonclose:
    178        1.1   thorpej  *
    179        1.1   thorpej  *	Close the system monitor device.
    180        1.1   thorpej  */
    181        1.1   thorpej int
    182       1.11  christos sysmonclose(dev_t dev, int flag, int mode, struct lwp *l)
    183        1.1   thorpej {
    184        1.4   thorpej 	int error;
    185        1.3   thorpej 
    186        1.3   thorpej 	switch (minor(dev)) {
    187        1.3   thorpej 	case SYSMON_MINOR_ENVSYS:
    188        1.3   thorpej 	case SYSMON_MINOR_WDOG:
    189        1.8   thorpej 	case SYSMON_MINOR_POWER:
    190       1.20  pgoyette 		if (sysmon_opvec_table[minor(dev)] == NULL)
    191       1.20  pgoyette 			error = ENODEV;
    192       1.20  pgoyette 		else {
    193       1.20  pgoyette 			error = (sysmon_opvec_table[minor(dev)]->so_close)(dev,
    194       1.20  pgoyette 			    flag, mode, l);
    195       1.20  pgoyette 			if (error == 0) {
    196       1.20  pgoyette 				sysmon_refcnt[minor(dev)]--;
    197       1.20  pgoyette 				KASSERT(sysmon_refcnt[minor(dev)] >= 0);
    198       1.20  pgoyette 			}
    199       1.20  pgoyette 		}
    200        1.8   thorpej 		break;
    201        1.3   thorpej 	default:
    202        1.3   thorpej 		error = ENODEV;
    203        1.3   thorpej 	}
    204        1.1   thorpej 
    205        1.3   thorpej 	return (error);
    206        1.1   thorpej }
    207        1.1   thorpej 
    208        1.1   thorpej /*
    209        1.1   thorpej  * sysmonioctl:
    210        1.1   thorpej  *
    211        1.1   thorpej  *	Perform a control request.
    212        1.1   thorpej  */
    213        1.1   thorpej int
    214       1.15  christos sysmonioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
    215        1.1   thorpej {
    216        1.3   thorpej 	int error;
    217        1.3   thorpej 
    218        1.3   thorpej 	switch (minor(dev)) {
    219        1.3   thorpej 	case SYSMON_MINOR_ENVSYS:
    220        1.3   thorpej 	case SYSMON_MINOR_WDOG:
    221        1.8   thorpej 	case SYSMON_MINOR_POWER:
    222       1.20  pgoyette 		if (sysmon_opvec_table[minor(dev)] == NULL)
    223       1.20  pgoyette 			error = ENODEV;
    224       1.20  pgoyette 		else
    225       1.20  pgoyette 			error = (sysmon_opvec_table[minor(dev)]->so_ioctl)(dev,
    226       1.20  pgoyette 			    cmd, data, flag, l);
    227        1.8   thorpej 		break;
    228        1.3   thorpej 	default:
    229        1.3   thorpej 		error = ENODEV;
    230        1.8   thorpej 	}
    231        1.8   thorpej 
    232        1.8   thorpej 	return (error);
    233        1.8   thorpej }
    234        1.8   thorpej 
    235        1.8   thorpej /*
    236        1.8   thorpej  * sysmonread:
    237        1.8   thorpej  *
    238        1.8   thorpej  *	Perform a read request.
    239        1.8   thorpej  */
    240        1.8   thorpej int
    241       1.14  christos sysmonread(dev_t dev, struct uio *uio, int flags)
    242        1.8   thorpej {
    243        1.8   thorpej 	int error;
    244        1.8   thorpej 
    245        1.8   thorpej 	switch (minor(dev)) {
    246        1.8   thorpej 	case SYSMON_MINOR_POWER:
    247       1.20  pgoyette 		if (sysmon_opvec_table[minor(dev)] == NULL)
    248       1.20  pgoyette 			error = ENODEV;
    249       1.20  pgoyette 		else
    250       1.20  pgoyette 			error = (sysmon_opvec_table[minor(dev)]->so_read)(dev,
    251       1.20  pgoyette 			    uio, flags);
    252        1.8   thorpej 		break;
    253        1.8   thorpej 	default:
    254        1.8   thorpej 		error = ENODEV;
    255        1.8   thorpej 	}
    256        1.8   thorpej 
    257        1.8   thorpej 	return (error);
    258        1.8   thorpej }
    259        1.8   thorpej 
    260        1.8   thorpej /*
    261        1.8   thorpej  * sysmonpoll:
    262        1.8   thorpej  *
    263        1.8   thorpej  *	Poll the system monitor device.
    264        1.8   thorpej  */
    265        1.8   thorpej int
    266       1.14  christos sysmonpoll(dev_t dev, int events, struct lwp *l)
    267        1.8   thorpej {
    268        1.8   thorpej 	int rv;
    269        1.8   thorpej 
    270        1.8   thorpej 	switch (minor(dev)) {
    271        1.8   thorpej 	case SYSMON_MINOR_POWER:
    272       1.20  pgoyette 		if (sysmon_opvec_table[minor(dev)] == NULL)
    273       1.20  pgoyette 			rv = events;
    274       1.20  pgoyette 		else
    275       1.20  pgoyette 			rv = (sysmon_opvec_table[minor(dev)]->so_poll)(dev,
    276       1.20  pgoyette 			    events, l);
    277        1.8   thorpej 		break;
    278        1.8   thorpej 	default:
    279        1.8   thorpej 		rv = events;
    280        1.8   thorpej 	}
    281        1.8   thorpej 
    282        1.8   thorpej 	return (rv);
    283        1.8   thorpej }
    284        1.8   thorpej 
    285        1.8   thorpej /*
    286        1.8   thorpej  * sysmonkqfilter:
    287        1.8   thorpej  *
    288        1.8   thorpej  *	Kqueue filter for the system monitor device.
    289        1.8   thorpej  */
    290        1.8   thorpej int
    291       1.14  christos sysmonkqfilter(dev_t dev, struct knote *kn)
    292        1.8   thorpej {
    293        1.8   thorpej 	int error;
    294        1.8   thorpej 
    295        1.8   thorpej 	switch (minor(dev)) {
    296        1.8   thorpej 	case SYSMON_MINOR_POWER:
    297       1.20  pgoyette 		if (sysmon_opvec_table[minor(dev)] == NULL)
    298       1.20  pgoyette 			error = ENODEV;
    299       1.20  pgoyette 		else
    300       1.20  pgoyette 			error = (sysmon_opvec_table[minor(dev)]->so_filter)(dev,
    301       1.20  pgoyette 			    kn);
    302        1.8   thorpej 		break;
    303        1.8   thorpej 	default:
    304        1.8   thorpej 		error = 1;
    305        1.3   thorpej 	}
    306        1.3   thorpej 
    307        1.3   thorpej 	return (error);
    308        1.1   thorpej }
    309       1.20  pgoyette 
    310  1.28.18.1  christos MODULE(MODULE_CLASS_DRIVER, sysmon, NULL);
    311       1.20  pgoyette 
    312       1.25  pgoyette static int
    313       1.25  pgoyette sm_init_once(void)
    314       1.25  pgoyette {
    315       1.25  pgoyette 
    316       1.25  pgoyette 	mutex_init(&sysmon_minor_mtx, MUTEX_DEFAULT, IPL_NONE);
    317       1.25  pgoyette 
    318       1.25  pgoyette 	return 0;
    319       1.25  pgoyette }
    320       1.25  pgoyette 
    321       1.20  pgoyette int
    322       1.20  pgoyette sysmon_init(void)
    323       1.20  pgoyette {
    324       1.25  pgoyette 	int error;
    325       1.21  pgoyette #ifdef _MODULE
    326       1.20  pgoyette 	devmajor_t bmajor, cmajor;
    327       1.21  pgoyette #endif
    328       1.20  pgoyette 
    329       1.25  pgoyette 	error = RUN_ONCE(&once_sm, sm_init_once);
    330       1.20  pgoyette 
    331       1.21  pgoyette #ifdef _MODULE
    332       1.25  pgoyette 	mutex_enter(&sysmon_minor_mtx);
    333       1.25  pgoyette 	if (!sm_is_attached) {
    334       1.25  pgoyette 		bmajor = cmajor = -1;
    335       1.25  pgoyette 		error = devsw_attach("sysmon", NULL, &bmajor,
    336       1.25  pgoyette 				&sysmon_cdevsw, &cmajor);
    337       1.25  pgoyette 		sm_is_attached = (error != 0);
    338       1.20  pgoyette 	}
    339       1.25  pgoyette 	mutex_exit(&sysmon_minor_mtx);
    340       1.21  pgoyette #endif
    341       1.20  pgoyette 
    342       1.20  pgoyette 	return error;
    343       1.20  pgoyette }
    344       1.20  pgoyette 
    345       1.20  pgoyette int
    346       1.20  pgoyette sysmon_fini(void)
    347       1.20  pgoyette {
    348       1.20  pgoyette 	int error = 0;
    349       1.20  pgoyette 
    350       1.25  pgoyette 	if ((sysmon_opvec_table[SYSMON_MINOR_ENVSYS] != NULL) ||
    351       1.25  pgoyette 	    (sysmon_opvec_table[SYSMON_MINOR_WDOG] != NULL) ||
    352       1.25  pgoyette 	    (sysmon_opvec_table[SYSMON_MINOR_POWER] != NULL))
    353       1.20  pgoyette 		error = EBUSY;
    354       1.20  pgoyette 
    355       1.25  pgoyette #ifdef _MODULE
    356       1.25  pgoyette 	if (error == 0) {
    357       1.25  pgoyette 		mutex_enter(&sysmon_minor_mtx);
    358       1.25  pgoyette 		sm_is_attached = false;
    359       1.25  pgoyette 		error = devsw_detach(NULL, &sysmon_cdevsw);
    360       1.25  pgoyette 		mutex_exit(&sysmon_minor_mtx);
    361       1.20  pgoyette 	}
    362       1.25  pgoyette #endif
    363       1.20  pgoyette 
    364       1.20  pgoyette 	return error;
    365       1.20  pgoyette }
    366       1.20  pgoyette 
    367       1.20  pgoyette static
    368       1.20  pgoyette int
    369       1.20  pgoyette sysmon_modcmd(modcmd_t cmd, void *arg)
    370       1.20  pgoyette {
    371       1.20  pgoyette 	int ret;
    372       1.20  pgoyette 
    373       1.20  pgoyette 	switch (cmd) {
    374       1.20  pgoyette 	case MODULE_CMD_INIT:
    375       1.20  pgoyette 		ret = sysmon_init();
    376       1.20  pgoyette 		break;
    377       1.20  pgoyette 
    378       1.20  pgoyette 	case MODULE_CMD_FINI:
    379       1.20  pgoyette 		ret = sysmon_fini();
    380       1.20  pgoyette 		break;
    381       1.20  pgoyette 
    382       1.20  pgoyette 	case MODULE_CMD_STAT:
    383       1.20  pgoyette 	default:
    384       1.20  pgoyette 		ret = ENOTTY;
    385       1.20  pgoyette 	}
    386       1.20  pgoyette 
    387       1.20  pgoyette 	return ret;
    388       1.20  pgoyette }
    389