Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F148544111
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
48 KB
Referenced Files
None
Subscribers
None
View Options
Index: stable/8/sys/dev/usb
===================================================================
--- stable/8/sys/dev/usb (revision 278292)
+++ stable/8/sys/dev/usb (revision 278293)
Property changes on: stable/8/sys/dev/usb
___________________________________________________________________
Modified: svn:mergeinfo
## -0,0 +0,1 ##
Merged /head/sys/dev/usb:r277179
Index: stable/8/sys/dev
===================================================================
--- stable/8/sys/dev (revision 278292)
+++ stable/8/sys/dev (revision 278293)
Property changes on: stable/8/sys/dev
___________________________________________________________________
Modified: svn:mergeinfo
## -0,0 +0,1 ##
Merged /head/sys/dev:r277179
Index: stable/8/sys/fs/devfs/devfs_int.h
===================================================================
--- stable/8/sys/fs/devfs/devfs_int.h (revision 278292)
+++ stable/8/sys/fs/devfs/devfs_int.h (revision 278293)
@@ -1,88 +1,89 @@
/*-
* Copyright (c) 2005 Poul-Henning Kamp. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
/*
* This file documents a private interface and it SHALL only be used
* by kern/kern_conf.c and fs/devfs/...
*/
#ifndef _FS_DEVFS_DEVFS_INT_H_
#define _FS_DEVFS_DEVFS_INT_H_
#include <sys/queue.h>
#ifdef _KERNEL
struct devfs_dirent;
struct cdev_privdata {
struct file *cdpd_fp;
void *cdpd_data;
void (*cdpd_dtr)(void *);
LIST_ENTRY(cdev_privdata) cdpd_list;
};
struct cdev_priv {
struct cdev cdp_c;
TAILQ_ENTRY(cdev_priv) cdp_list;
u_int cdp_inode;
u_int cdp_flags;
#define CDP_ACTIVE (1 << 0)
#define CDP_SCHED_DTR (1 << 1)
+#define CDP_UNREF_DTR (1 << 2)
u_int cdp_inuse;
u_int cdp_maxdirent;
struct devfs_dirent **cdp_dirents;
struct devfs_dirent *cdp_dirent0;
TAILQ_ENTRY(cdev_priv) cdp_dtr_list;
void (*cdp_dtr_cb)(void *);
void *cdp_dtr_cb_arg;
LIST_HEAD(, cdev_privdata) cdp_fdpriv;
};
#define cdev2priv(c) member2struct(cdev_priv, cdp_c, c)
struct cdev *devfs_alloc(int);
void devfs_free(struct cdev *);
void devfs_create(struct cdev *dev);
void devfs_destroy(struct cdev *dev);
void devfs_destroy_cdevpriv(struct cdev_privdata *p);
extern struct unrhdr *devfs_inos;
extern struct mtx devmtx;
extern struct mtx devfs_de_interlock;
extern struct sx clone_drain_lock;
extern struct mtx cdevpriv_mtx;
extern TAILQ_HEAD(cdev_priv_list, cdev_priv) cdevp_list;
#endif /* _KERNEL */
#endif /* !_FS_DEVFS_DEVFS_INT_H_ */
Index: stable/8/sys/fs
===================================================================
--- stable/8/sys/fs (revision 278292)
+++ stable/8/sys/fs (revision 278293)
Property changes on: stable/8/sys/fs
___________________________________________________________________
Modified: svn:mergeinfo
## -0,0 +0,1 ##
Merged /head/sys/fs:r277199,277391
Index: stable/8/sys/kern/kern_conf.c
===================================================================
--- stable/8/sys/kern/kern_conf.c (revision 278292)
+++ stable/8/sys/kern/kern_conf.c (revision 278293)
@@ -1,1305 +1,1343 @@
/*-
* Copyright (c) 1999-2002 Poul-Henning Kamp
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/bio.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/module.h>
#include <sys/malloc.h>
#include <sys/conf.h>
#include <sys/vnode.h>
#include <sys/queue.h>
#include <sys/poll.h>
#include <sys/sx.h>
#include <sys/ctype.h>
#include <sys/ucred.h>
#include <sys/taskqueue.h>
#include <machine/stdarg.h>
#include <fs/devfs/devfs_int.h>
#include <vm/vm.h>
static MALLOC_DEFINE(M_DEVT, "cdev", "cdev storage");
struct mtx devmtx;
static void destroy_devl(struct cdev *dev);
static int destroy_dev_sched_cbl(struct cdev *dev,
void (*cb)(void *), void *arg);
static int make_dev_credv(int flags, struct cdev **dres, struct cdevsw *devsw,
int unit, struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt,
va_list ap);
static struct cdev_priv_list cdevp_free_list =
TAILQ_HEAD_INITIALIZER(cdevp_free_list);
static SLIST_HEAD(free_cdevsw, cdevsw) cdevsw_gt_post_list =
SLIST_HEAD_INITIALIZER(cdevsw_gt_post_list);
void
dev_lock(void)
{
mtx_lock(&devmtx);
}
/*
* Free all the memory collected while the cdev mutex was
* locked. Since devmtx is after the system map mutex, free() cannot
* be called immediately and is postponed until cdev mutex can be
* dropped.
*/
static void
dev_unlock_and_free(void)
{
struct cdev_priv_list cdp_free;
struct free_cdevsw csw_free;
struct cdev_priv *cdp;
struct cdevsw *csw;
mtx_assert(&devmtx, MA_OWNED);
/*
* Make the local copy of the list heads while the dev_mtx is
* held. Free it later.
*/
TAILQ_INIT(&cdp_free);
TAILQ_CONCAT(&cdp_free, &cdevp_free_list, cdp_list);
csw_free = cdevsw_gt_post_list;
SLIST_INIT(&cdevsw_gt_post_list);
mtx_unlock(&devmtx);
while ((cdp = TAILQ_FIRST(&cdp_free)) != NULL) {
TAILQ_REMOVE(&cdp_free, cdp, cdp_list);
devfs_free(&cdp->cdp_c);
}
while ((csw = SLIST_FIRST(&csw_free)) != NULL) {
SLIST_REMOVE_HEAD(&csw_free, d_postfree_list);
free(csw, M_DEVT);
}
}
static void
dev_free_devlocked(struct cdev *cdev)
{
struct cdev_priv *cdp;
mtx_assert(&devmtx, MA_OWNED);
cdp = cdev2priv(cdev);
+ KASSERT((cdp->cdp_flags & CDP_UNREF_DTR) == 0,
+ ("destroy_dev() was not called after delist_dev(%p)", cdev));
TAILQ_INSERT_HEAD(&cdevp_free_list, cdp, cdp_list);
}
static void
cdevsw_free_devlocked(struct cdevsw *csw)
{
mtx_assert(&devmtx, MA_OWNED);
SLIST_INSERT_HEAD(&cdevsw_gt_post_list, csw, d_postfree_list);
}
void
dev_unlock(void)
{
mtx_unlock(&devmtx);
}
void
dev_ref(struct cdev *dev)
{
mtx_assert(&devmtx, MA_NOTOWNED);
mtx_lock(&devmtx);
dev->si_refcount++;
mtx_unlock(&devmtx);
}
void
dev_refl(struct cdev *dev)
{
mtx_assert(&devmtx, MA_OWNED);
dev->si_refcount++;
}
void
dev_rel(struct cdev *dev)
{
int flag = 0;
mtx_assert(&devmtx, MA_NOTOWNED);
dev_lock();
dev->si_refcount--;
KASSERT(dev->si_refcount >= 0,
("dev_rel(%s) gave negative count", devtoname(dev)));
#if 0
if (dev->si_usecount == 0 &&
(dev->si_flags & SI_CHEAPCLONE) && (dev->si_flags & SI_NAMED))
;
else
#endif
if (dev->si_devsw == NULL && dev->si_refcount == 0) {
LIST_REMOVE(dev, si_list);
flag = 1;
}
dev_unlock();
if (flag)
devfs_free(dev);
}
struct cdevsw *
dev_refthread(struct cdev *dev, int *ref)
{
struct cdevsw *csw;
struct cdev_priv *cdp;
mtx_assert(&devmtx, MA_NOTOWNED);
if ((dev->si_flags & SI_ETERNAL) != 0) {
*ref = 0;
return (dev->si_devsw);
}
dev_lock();
csw = dev->si_devsw;
if (csw != NULL) {
cdp = cdev2priv(dev);
if ((cdp->cdp_flags & CDP_SCHED_DTR) == 0)
dev->si_threadcount++;
else
csw = NULL;
}
dev_unlock();
*ref = 1;
return (csw);
}
struct cdevsw *
devvn_refthread(struct vnode *vp, struct cdev **devp, int *ref)
{
struct cdevsw *csw;
struct cdev_priv *cdp;
struct cdev *dev;
mtx_assert(&devmtx, MA_NOTOWNED);
if ((vp->v_vflag & VV_ETERNALDEV) != 0) {
dev = vp->v_rdev;
if (dev == NULL)
return (NULL);
KASSERT((dev->si_flags & SI_ETERNAL) != 0,
("Not eternal cdev"));
*ref = 0;
csw = dev->si_devsw;
KASSERT(csw != NULL, ("Eternal cdev is destroyed"));
*devp = dev;
return (csw);
}
csw = NULL;
dev_lock();
dev = vp->v_rdev;
if (dev == NULL) {
dev_unlock();
return (NULL);
}
cdp = cdev2priv(dev);
if ((cdp->cdp_flags & CDP_SCHED_DTR) == 0) {
csw = dev->si_devsw;
if (csw != NULL)
dev->si_threadcount++;
}
dev_unlock();
if (csw != NULL) {
*devp = dev;
*ref = 1;
}
return (csw);
}
void
dev_relthread(struct cdev *dev, int ref)
{
mtx_assert(&devmtx, MA_NOTOWNED);
if (!ref)
return;
dev_lock();
KASSERT(dev->si_threadcount > 0,
("%s threadcount is wrong", dev->si_name));
dev->si_threadcount--;
dev_unlock();
}
int
nullop(void)
{
return (0);
}
int
eopnotsupp(void)
{
return (EOPNOTSUPP);
}
static int
enxio(void)
{
return (ENXIO);
}
static int
enodev(void)
{
return (ENODEV);
}
/* Define a dead_cdevsw for use when devices leave unexpectedly. */
#define dead_open (d_open_t *)enxio
#define dead_close (d_close_t *)enxio
#define dead_read (d_read_t *)enxio
#define dead_write (d_write_t *)enxio
#define dead_ioctl (d_ioctl_t *)enxio
#define dead_poll (d_poll_t *)enodev
#define dead_mmap (d_mmap_t *)enodev
static void
dead_strategy(struct bio *bp)
{
biofinish(bp, NULL, ENXIO);
}
#define dead_dump (dumper_t *)enxio
#define dead_kqfilter (d_kqfilter_t *)enxio
#define dead_mmap_single (d_mmap_single_t *)enodev
static struct cdevsw dead_cdevsw = {
.d_version = D_VERSION,
.d_open = dead_open,
.d_close = dead_close,
.d_read = dead_read,
.d_write = dead_write,
.d_ioctl = dead_ioctl,
.d_poll = dead_poll,
.d_mmap = dead_mmap,
.d_strategy = dead_strategy,
.d_name = "dead",
.d_dump = dead_dump,
.d_kqfilter = dead_kqfilter,
.d_mmap_single = dead_mmap_single
};
/* Default methods if driver does not specify method */
#define null_open (d_open_t *)nullop
#define null_close (d_close_t *)nullop
#define no_read (d_read_t *)enodev
#define no_write (d_write_t *)enodev
#define no_ioctl (d_ioctl_t *)enodev
#define no_mmap (d_mmap2_t *)enodev
#define no_kqfilter (d_kqfilter_t *)enodev
#define no_mmap_single (d_mmap_single_t *)enodev
static void
no_strategy(struct bio *bp)
{
biofinish(bp, NULL, ENODEV);
}
static int
no_poll(struct cdev *dev __unused, int events, struct thread *td __unused)
{
return (poll_no_poll(events));
}
#define no_dump (dumper_t *)enodev
static int
giant_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
{
struct cdevsw *dsw;
int ref, retval;
dsw = dev_refthread(dev, &ref);
if (dsw == NULL)
return (ENXIO);
mtx_lock(&Giant);
retval = dsw->d_gianttrick->d_open(dev, oflags, devtype, td);
mtx_unlock(&Giant);
dev_relthread(dev, ref);
return (retval);
}
static int
giant_fdopen(struct cdev *dev, int oflags, struct thread *td, struct file *fp)
{
struct cdevsw *dsw;
int ref, retval;
dsw = dev_refthread(dev, &ref);
if (dsw == NULL)
return (ENXIO);
mtx_lock(&Giant);
retval = dsw->d_gianttrick->d_fdopen(dev, oflags, td, fp);
mtx_unlock(&Giant);
dev_relthread(dev, ref);
return (retval);
}
static int
giant_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
{
struct cdevsw *dsw;
int ref, retval;
dsw = dev_refthread(dev, &ref);
if (dsw == NULL)
return (ENXIO);
mtx_lock(&Giant);
retval = dsw->d_gianttrick->d_close(dev, fflag, devtype, td);
mtx_unlock(&Giant);
dev_relthread(dev, ref);
return (retval);
}
static void
giant_strategy(struct bio *bp)
{
struct cdevsw *dsw;
struct cdev *dev;
int ref;
dev = bp->bio_dev;
dsw = dev_refthread(dev, &ref);
if (dsw == NULL) {
biofinish(bp, NULL, ENXIO);
return;
}
mtx_lock(&Giant);
dsw->d_gianttrick->d_strategy(bp);
mtx_unlock(&Giant);
dev_relthread(dev, ref);
}
static int
giant_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
{
struct cdevsw *dsw;
int ref, retval;
dsw = dev_refthread(dev, &ref);
if (dsw == NULL)
return (ENXIO);
mtx_lock(&Giant);
retval = dsw->d_gianttrick->d_ioctl(dev, cmd, data, fflag, td);
mtx_unlock(&Giant);
dev_relthread(dev, ref);
return (retval);
}
static int
giant_read(struct cdev *dev, struct uio *uio, int ioflag)
{
struct cdevsw *dsw;
int ref, retval;
dsw = dev_refthread(dev, &ref);
if (dsw == NULL)
return (ENXIO);
mtx_lock(&Giant);
retval = dsw->d_gianttrick->d_read(dev, uio, ioflag);
mtx_unlock(&Giant);
dev_relthread(dev, ref);
return (retval);
}
static int
giant_write(struct cdev *dev, struct uio *uio, int ioflag)
{
struct cdevsw *dsw;
int ref, retval;
dsw = dev_refthread(dev, &ref);
if (dsw == NULL)
return (ENXIO);
mtx_lock(&Giant);
retval = dsw->d_gianttrick->d_write(dev, uio, ioflag);
mtx_unlock(&Giant);
dev_relthread(dev, ref);
return (retval);
}
static int
giant_poll(struct cdev *dev, int events, struct thread *td)
{
struct cdevsw *dsw;
int ref, retval;
dsw = dev_refthread(dev, &ref);
if (dsw == NULL)
return (ENXIO);
mtx_lock(&Giant);
retval = dsw->d_gianttrick->d_poll(dev, events, td);
mtx_unlock(&Giant);
dev_relthread(dev, ref);
return (retval);
}
static int
giant_kqfilter(struct cdev *dev, struct knote *kn)
{
struct cdevsw *dsw;
int ref, retval;
dsw = dev_refthread(dev, &ref);
if (dsw == NULL)
return (ENXIO);
mtx_lock(&Giant);
retval = dsw->d_gianttrick->d_kqfilter(dev, kn);
mtx_unlock(&Giant);
dev_relthread(dev, ref);
return (retval);
}
static int
giant_mmap(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot,
vm_memattr_t *memattr)
{
struct cdevsw *dsw;
int ref, retval;
dsw = dev_refthread(dev, &ref);
if (dsw == NULL)
return (ENXIO);
mtx_lock(&Giant);
if (dsw->d_gianttrick->d_flags & D_MMAP2)
retval = dsw->d_gianttrick->d_mmap2(dev, offset, paddr, nprot,
memattr);
else
retval = dsw->d_gianttrick->d_mmap(dev, offset, paddr, nprot);
mtx_unlock(&Giant);
dev_relthread(dev, ref);
return (retval);
}
static int
giant_mmap_single(struct cdev *dev, vm_ooffset_t *offset, vm_size_t size,
vm_object_t *object, int nprot)
{
struct cdevsw *dsw;
int ref, retval;
dsw = dev_refthread(dev, &ref);
if (dsw == NULL)
return (ENXIO);
mtx_lock(&Giant);
retval = dsw->d_gianttrick->d_mmap_single(dev, offset, size, object,
nprot);
mtx_unlock(&Giant);
dev_relthread(dev, ref);
return (retval);
}
static void
notify(struct cdev *dev, const char *ev, int flags)
{
static const char prefix[] = "cdev=";
char *data;
int namelen, mflags;
if (cold)
return;
mflags = (flags & MAKEDEV_NOWAIT) ? M_NOWAIT : M_WAITOK;
namelen = strlen(dev->si_name);
data = malloc(namelen + sizeof(prefix), M_TEMP, mflags);
if (data == NULL)
return;
memcpy(data, prefix, sizeof(prefix) - 1);
memcpy(data + sizeof(prefix) - 1, dev->si_name, namelen + 1);
devctl_notify_f("DEVFS", "CDEV", ev, data, mflags);
free(data, M_TEMP);
}
static void
notify_create(struct cdev *dev, int flags)
{
notify(dev, "CREATE", flags);
}
static void
notify_destroy(struct cdev *dev)
{
notify(dev, "DESTROY", MAKEDEV_WAITOK);
}
static struct cdev *
newdev(struct cdevsw *csw, int unit, struct cdev *si)
{
struct cdev *si2;
mtx_assert(&devmtx, MA_OWNED);
if (csw->d_flags & D_NEEDMINOR) {
/* We may want to return an existing device */
LIST_FOREACH(si2, &csw->d_devs, si_list) {
if (dev2unit(si2) == unit) {
dev_free_devlocked(si);
return (si2);
}
}
}
si->si_drv0 = unit;
si->si_devsw = csw;
LIST_INSERT_HEAD(&csw->d_devs, si, si_list);
return (si);
}
static void
fini_cdevsw(struct cdevsw *devsw)
{
struct cdevsw *gt;
if (devsw->d_gianttrick != NULL) {
gt = devsw->d_gianttrick;
memcpy(devsw, gt, sizeof *devsw);
cdevsw_free_devlocked(gt);
devsw->d_gianttrick = NULL;
}
devsw->d_flags &= ~D_INIT;
}
static int
prep_cdevsw(struct cdevsw *devsw, int flags)
{
struct cdevsw *dsw2;
mtx_assert(&devmtx, MA_OWNED);
if (devsw->d_flags & D_INIT)
return (0);
if (devsw->d_flags & D_NEEDGIANT) {
dev_unlock();
dsw2 = malloc(sizeof *dsw2, M_DEVT,
(flags & MAKEDEV_NOWAIT) ? M_NOWAIT : M_WAITOK);
dev_lock();
if (dsw2 == NULL && !(devsw->d_flags & D_INIT))
return (ENOMEM);
} else
dsw2 = NULL;
if (devsw->d_flags & D_INIT) {
if (dsw2 != NULL)
cdevsw_free_devlocked(dsw2);
return (0);
}
if (devsw->d_version != D_VERSION_01 &&
devsw->d_version != D_VERSION_02) {
printf(
"WARNING: Device driver \"%s\" has wrong version %s\n",
devsw->d_name == NULL ? "???" : devsw->d_name,
"and is disabled. Recompile KLD module.");
devsw->d_open = dead_open;
devsw->d_close = dead_close;
devsw->d_read = dead_read;
devsw->d_write = dead_write;
devsw->d_ioctl = dead_ioctl;
devsw->d_poll = dead_poll;
devsw->d_mmap = dead_mmap;
devsw->d_strategy = dead_strategy;
devsw->d_dump = dead_dump;
devsw->d_kqfilter = dead_kqfilter;
}
if (devsw->d_version == D_VERSION_01)
devsw->d_mmap_single = NULL;
if (devsw->d_flags & D_NEEDGIANT) {
if (devsw->d_gianttrick == NULL) {
memcpy(dsw2, devsw, sizeof *dsw2);
devsw->d_gianttrick = dsw2;
devsw->d_flags |= D_MMAP2;
dsw2 = NULL;
}
}
#define FIXUP(member, noop, giant) \
do { \
if (devsw->member == NULL) { \
devsw->member = noop; \
} else if (devsw->d_flags & D_NEEDGIANT) \
devsw->member = giant; \
} \
while (0)
FIXUP(d_open, null_open, giant_open);
FIXUP(d_fdopen, NULL, giant_fdopen);
FIXUP(d_close, null_close, giant_close);
FIXUP(d_read, no_read, giant_read);
FIXUP(d_write, no_write, giant_write);
FIXUP(d_ioctl, no_ioctl, giant_ioctl);
FIXUP(d_poll, no_poll, giant_poll);
FIXUP(d_mmap2, no_mmap, giant_mmap);
FIXUP(d_strategy, no_strategy, giant_strategy);
FIXUP(d_kqfilter, no_kqfilter, giant_kqfilter);
FIXUP(d_mmap_single, no_mmap_single, giant_mmap_single);
if (devsw->d_dump == NULL) devsw->d_dump = no_dump;
LIST_INIT(&devsw->d_devs);
devsw->d_flags |= D_INIT;
if (dsw2 != NULL)
cdevsw_free_devlocked(dsw2);
return (0);
}
static int
make_dev_credv(int flags, struct cdev **dres, struct cdevsw *devsw, int unit,
struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt,
va_list ap)
{
struct cdev *dev;
int i, res;
KASSERT((flags & MAKEDEV_WAITOK) == 0 || (flags & MAKEDEV_NOWAIT) == 0,
("make_dev_credv: both WAITOK and NOWAIT specified"));
dev = devfs_alloc(flags);
if (dev == NULL)
return (ENOMEM);
dev_lock();
res = prep_cdevsw(devsw, flags);
if (res != 0) {
dev_unlock();
devfs_free(dev);
return (res);
}
dev = newdev(devsw, unit, dev);
if (flags & MAKEDEV_REF)
dev_refl(dev);
if (flags & MAKEDEV_ETERNAL)
dev->si_flags |= SI_ETERNAL;
if (dev->si_flags & SI_CHEAPCLONE &&
dev->si_flags & SI_NAMED) {
/*
* This is allowed as it removes races and generally
* simplifies cloning devices.
* XXX: still ??
*/
dev_unlock_and_free();
*dres = dev;
return (0);
}
KASSERT(!(dev->si_flags & SI_NAMED),
("make_dev() by driver %s on pre-existing device (min=%x, name=%s)",
devsw->d_name, dev2unit(dev), devtoname(dev)));
i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap);
if (i > (sizeof dev->__si_namebuf - 1)) {
printf("WARNING: Device name truncated! (%s)\n",
dev->__si_namebuf);
}
dev->si_flags |= SI_NAMED;
if (cr != NULL)
dev->si_cred = crhold(cr);
dev->si_uid = uid;
dev->si_gid = gid;
dev->si_mode = mode;
devfs_create(dev);
clean_unrhdrl(devfs_inos);
dev_unlock_and_free();
notify_create(dev, flags);
*dres = dev;
return (0);
}
struct cdev *
make_dev(struct cdevsw *devsw, int unit, uid_t uid, gid_t gid, int mode,
const char *fmt, ...)
{
struct cdev *dev;
va_list ap;
int res;
va_start(ap, fmt);
res = make_dev_credv(0, &dev, devsw, unit, NULL, uid, gid, mode, fmt,
ap);
va_end(ap);
KASSERT(res == 0 && dev != NULL, ("make_dev: failed make_dev_credv"));
return (dev);
}
struct cdev *
make_dev_cred(struct cdevsw *devsw, int unit, struct ucred *cr, uid_t uid,
gid_t gid, int mode, const char *fmt, ...)
{
struct cdev *dev;
va_list ap;
int res;
va_start(ap, fmt);
res = make_dev_credv(0, &dev, devsw, unit, cr, uid, gid, mode, fmt, ap);
va_end(ap);
KASSERT(res == 0 && dev != NULL,
("make_dev_cred: failed make_dev_credv"));
return (dev);
}
struct cdev *
make_dev_credf(int flags, struct cdevsw *devsw, int unit, struct ucred *cr,
uid_t uid, gid_t gid, int mode, const char *fmt, ...)
{
struct cdev *dev;
va_list ap;
int res;
va_start(ap, fmt);
res = make_dev_credv(flags, &dev, devsw, unit, cr, uid, gid, mode,
fmt, ap);
va_end(ap);
KASSERT((flags & MAKEDEV_NOWAIT) != 0 || res == 0,
("make_dev_credf: failed make_dev_credv"));
return (res == 0 ? dev : NULL);
}
int
make_dev_p(int flags, struct cdev **cdev, struct cdevsw *devsw,
struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt, ...)
{
va_list ap;
int res;
va_start(ap, fmt);
res = make_dev_credv(flags, cdev, devsw, 0, cr, uid, gid, mode,
fmt, ap);
va_end(ap);
KASSERT((flags & MAKEDEV_NOWAIT) != 0 || res == 0,
("make_dev_p: failed make_dev_credv"));
return (res);
}
static void
dev_dependsl(struct cdev *pdev, struct cdev *cdev)
{
cdev->si_parent = pdev;
cdev->si_flags |= SI_CHILD;
LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings);
}
void
dev_depends(struct cdev *pdev, struct cdev *cdev)
{
dev_lock();
dev_dependsl(pdev, cdev);
dev_unlock();
}
struct cdev *
make_dev_alias(struct cdev *pdev, const char *fmt, ...)
{
struct cdev *dev;
va_list ap;
int i;
KASSERT(pdev != NULL, ("NULL pdev"));
dev = devfs_alloc(MAKEDEV_WAITOK);
dev_lock();
dev->si_flags |= SI_ALIAS;
dev->si_flags |= SI_NAMED;
va_start(ap, fmt);
i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap);
if (i > (sizeof dev->__si_namebuf - 1)) {
printf("WARNING: Device name truncated! (%s)\n",
dev->__si_namebuf);
}
va_end(ap);
devfs_create(dev);
dev_dependsl(pdev, dev);
clean_unrhdrl(devfs_inos);
dev_unlock();
notify_create(dev, MAKEDEV_WAITOK);
return (dev);
}
static void
destroy_devl(struct cdev *dev)
{
struct cdevsw *csw;
struct cdev_privdata *p;
+ struct cdev_priv *cdp;
mtx_assert(&devmtx, MA_OWNED);
KASSERT(dev->si_flags & SI_NAMED,
("WARNING: Driver mistake: destroy_dev on %d\n", dev2unit(dev)));
KASSERT((dev->si_flags & SI_ETERNAL) == 0,
("WARNING: Driver mistake: destroy_dev on eternal %d\n",
dev2unit(dev)));
- devfs_destroy(dev);
+ cdp = cdev2priv(dev);
+ if ((cdp->cdp_flags & CDP_UNREF_DTR) == 0) {
+ /*
+ * Avoid race with dev_rel(), e.g. from the populate
+ * loop. If CDP_UNREF_DTR flag is set, the reference
+ * to be dropped at the end of destroy_devl() was
+ * already taken by delist_dev_locked().
+ */
+ dev_refl(dev);
+ devfs_destroy(dev);
+ }
+
/* Remove name marking */
dev->si_flags &= ~SI_NAMED;
- dev->si_refcount++; /* Avoid race with dev_rel() */
-
/* If we are a child, remove us from the parents list */
if (dev->si_flags & SI_CHILD) {
LIST_REMOVE(dev, si_siblings);
dev->si_flags &= ~SI_CHILD;
}
/* Kill our children */
while (!LIST_EMPTY(&dev->si_children))
destroy_devl(LIST_FIRST(&dev->si_children));
/* Remove from clone list */
if (dev->si_flags & SI_CLONELIST) {
LIST_REMOVE(dev, si_clone);
dev->si_flags &= ~SI_CLONELIST;
}
csw = dev->si_devsw;
dev->si_devsw = NULL; /* already NULL for SI_ALIAS */
while (csw != NULL && csw->d_purge != NULL && dev->si_threadcount) {
csw->d_purge(dev);
msleep(csw, &devmtx, PRIBIO, "devprg", hz/10);
if (dev->si_threadcount)
printf("Still %lu threads in %s\n",
dev->si_threadcount, devtoname(dev));
}
while (dev->si_threadcount != 0) {
/* Use unique dummy wait ident */
msleep(&csw, &devmtx, PRIBIO, "devdrn", hz / 10);
}
dev_unlock();
notify_destroy(dev);
mtx_lock(&cdevpriv_mtx);
while ((p = LIST_FIRST(&cdev2priv(dev)->cdp_fdpriv)) != NULL) {
devfs_destroy_cdevpriv(p);
mtx_lock(&cdevpriv_mtx);
}
mtx_unlock(&cdevpriv_mtx);
dev_lock();
dev->si_drv1 = 0;
dev->si_drv2 = 0;
bzero(&dev->__si_u, sizeof(dev->__si_u));
if (!(dev->si_flags & SI_ALIAS)) {
/* Remove from cdevsw list */
LIST_REMOVE(dev, si_list);
/* If cdevsw has no more struct cdev *'s, clean it */
if (LIST_EMPTY(&csw->d_devs)) {
fini_cdevsw(csw);
wakeup(&csw->d_devs);
}
}
dev->si_flags &= ~SI_ALIAS;
- dev->si_refcount--; /* Avoid race with dev_rel() */
+ cdp->cdp_flags &= ~CDP_UNREF_DTR;
+ dev->si_refcount--;
- if (dev->si_refcount > 0) {
+ if (dev->si_refcount > 0)
LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list);
- } else {
+ else
dev_free_devlocked(dev);
- }
+}
+
+static void
+delist_dev_locked(struct cdev *dev)
+{
+ struct cdev_priv *cdp;
+ struct cdev *child;
+
+ mtx_assert(&devmtx, MA_OWNED);
+ cdp = cdev2priv(dev);
+ if ((cdp->cdp_flags & CDP_UNREF_DTR) != 0)
+ return;
+ cdp->cdp_flags |= CDP_UNREF_DTR;
+ dev_refl(dev);
+ devfs_destroy(dev);
+ LIST_FOREACH(child, &dev->si_children, si_siblings)
+ delist_dev_locked(child);
+}
+
+void
+delist_dev(struct cdev *dev)
+{
+
+ dev_lock();
+ delist_dev_locked(dev);
+ dev_unlock();
}
void
destroy_dev(struct cdev *dev)
{
WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "destroy_dev");
dev_lock();
destroy_devl(dev);
dev_unlock_and_free();
}
const char *
devtoname(struct cdev *dev)
{
return (dev->si_name);
}
int
dev_stdclone(char *name, char **namep, const char *stem, int *unit)
{
int u, i;
i = strlen(stem);
if (bcmp(stem, name, i) != 0)
return (0);
if (!isdigit(name[i]))
return (0);
u = 0;
if (name[i] == '0' && isdigit(name[i+1]))
return (0);
while (isdigit(name[i])) {
u *= 10;
u += name[i++] - '0';
}
if (u > 0xffffff)
return (0);
*unit = u;
if (namep)
*namep = &name[i];
if (name[i])
return (2);
return (1);
}
/*
* Helper functions for cloning device drivers.
*
* The objective here is to make it unnecessary for the device drivers to
* use rman or similar to manage their unit number space. Due to the way
* we do "on-demand" devices, using rman or other "private" methods
* will be very tricky to lock down properly once we lock down this file.
*
* Instead we give the drivers these routines which puts the struct cdev *'s
* that are to be managed on their own list, and gives the driver the ability
* to ask for the first free unit number or a given specified unit number.
*
* In addition these routines support paired devices (pty, nmdm and similar)
* by respecting a number of "flag" bits in the minor number.
*
*/
struct clonedevs {
LIST_HEAD(,cdev) head;
};
void
clone_setup(struct clonedevs **cdp)
{
*cdp = malloc(sizeof **cdp, M_DEVBUF, M_WAITOK | M_ZERO);
LIST_INIT(&(*cdp)->head);
}
int
clone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up,
struct cdev **dp, int extra)
{
struct clonedevs *cd;
struct cdev *dev, *ndev, *dl, *de;
int unit, low, u;
KASSERT(*cdp != NULL,
("clone_setup() not called in driver \"%s\"", csw->d_name));
KASSERT(!(extra & CLONE_UNITMASK),
("Illegal extra bits (0x%x) in clone_create", extra));
KASSERT(*up <= CLONE_UNITMASK,
("Too high unit (0x%x) in clone_create", *up));
KASSERT(csw->d_flags & D_NEEDMINOR,
("clone_create() on cdevsw without minor numbers"));
/*
* Search the list for a lot of things in one go:
* A preexisting match is returned immediately.
* The lowest free unit number if we are passed -1, and the place
* in the list where we should insert that new element.
* The place to insert a specified unit number, if applicable
* the end of the list.
*/
unit = *up;
ndev = devfs_alloc(MAKEDEV_WAITOK);
dev_lock();
prep_cdevsw(csw, MAKEDEV_WAITOK);
low = extra;
de = dl = NULL;
cd = *cdp;
LIST_FOREACH(dev, &cd->head, si_clone) {
KASSERT(dev->si_flags & SI_CLONELIST,
("Dev %p(%s) should be on clonelist", dev, dev->si_name));
u = dev2unit(dev);
if (u == (unit | extra)) {
*dp = dev;
dev_unlock();
devfs_free(ndev);
return (0);
}
if (unit == -1 && u == low) {
low++;
de = dev;
continue;
} else if (u < (unit | extra)) {
de = dev;
continue;
} else if (u > (unit | extra)) {
dl = dev;
break;
}
}
if (unit == -1)
unit = low & CLONE_UNITMASK;
dev = newdev(csw, unit | extra, ndev);
if (dev->si_flags & SI_CLONELIST) {
printf("dev %p (%s) is on clonelist\n", dev, dev->si_name);
printf("unit=%d, low=%d, extra=0x%x\n", unit, low, extra);
LIST_FOREACH(dev, &cd->head, si_clone) {
printf("\t%p %s\n", dev, dev->si_name);
}
panic("foo");
}
KASSERT(!(dev->si_flags & SI_CLONELIST),
("Dev %p(%s) should not be on clonelist", dev, dev->si_name));
if (dl != NULL)
LIST_INSERT_BEFORE(dl, dev, si_clone);
else if (de != NULL)
LIST_INSERT_AFTER(de, dev, si_clone);
else
LIST_INSERT_HEAD(&cd->head, dev, si_clone);
dev->si_flags |= SI_CLONELIST;
*up = unit;
dev_unlock_and_free();
return (1);
}
/*
* Kill everything still on the list. The driver should already have
* disposed of any softc hung of the struct cdev *'s at this time.
*/
void
clone_cleanup(struct clonedevs **cdp)
{
struct cdev *dev;
struct cdev_priv *cp;
struct clonedevs *cd;
cd = *cdp;
if (cd == NULL)
return;
dev_lock();
while (!LIST_EMPTY(&cd->head)) {
dev = LIST_FIRST(&cd->head);
LIST_REMOVE(dev, si_clone);
KASSERT(dev->si_flags & SI_CLONELIST,
("Dev %p(%s) should be on clonelist", dev, dev->si_name));
dev->si_flags &= ~SI_CLONELIST;
cp = cdev2priv(dev);
if (!(cp->cdp_flags & CDP_SCHED_DTR)) {
cp->cdp_flags |= CDP_SCHED_DTR;
KASSERT(dev->si_flags & SI_NAMED,
("Driver has goofed in cloning underways udev %x unit %x", dev2udev(dev), dev2unit(dev)));
destroy_devl(dev);
}
}
dev_unlock_and_free();
free(cd, M_DEVBUF);
*cdp = NULL;
}
static TAILQ_HEAD(, cdev_priv) dev_ddtr =
TAILQ_HEAD_INITIALIZER(dev_ddtr);
static struct task dev_dtr_task;
static void
destroy_dev_tq(void *ctx, int pending)
{
struct cdev_priv *cp;
struct cdev *dev;
void (*cb)(void *);
void *cb_arg;
dev_lock();
while (!TAILQ_EMPTY(&dev_ddtr)) {
cp = TAILQ_FIRST(&dev_ddtr);
dev = &cp->cdp_c;
KASSERT(cp->cdp_flags & CDP_SCHED_DTR,
("cdev %p in dev_destroy_tq without CDP_SCHED_DTR", cp));
TAILQ_REMOVE(&dev_ddtr, cp, cdp_dtr_list);
cb = cp->cdp_dtr_cb;
cb_arg = cp->cdp_dtr_cb_arg;
destroy_devl(dev);
dev_unlock_and_free();
dev_rel(dev);
if (cb != NULL)
cb(cb_arg);
dev_lock();
}
dev_unlock();
}
/*
* devmtx shall be locked on entry. devmtx will be unlocked after
* function return.
*/
static int
destroy_dev_sched_cbl(struct cdev *dev, void (*cb)(void *), void *arg)
{
struct cdev_priv *cp;
mtx_assert(&devmtx, MA_OWNED);
cp = cdev2priv(dev);
if (cp->cdp_flags & CDP_SCHED_DTR) {
dev_unlock();
return (0);
}
dev_refl(dev);
cp->cdp_flags |= CDP_SCHED_DTR;
cp->cdp_dtr_cb = cb;
cp->cdp_dtr_cb_arg = arg;
TAILQ_INSERT_TAIL(&dev_ddtr, cp, cdp_dtr_list);
dev_unlock();
taskqueue_enqueue(taskqueue_swi_giant, &dev_dtr_task);
return (1);
}
int
destroy_dev_sched_cb(struct cdev *dev, void (*cb)(void *), void *arg)
{
dev_lock();
return (destroy_dev_sched_cbl(dev, cb, arg));
}
int
destroy_dev_sched(struct cdev *dev)
{
return (destroy_dev_sched_cb(dev, NULL, NULL));
}
void
destroy_dev_drain(struct cdevsw *csw)
{
dev_lock();
while (!LIST_EMPTY(&csw->d_devs)) {
msleep(&csw->d_devs, &devmtx, PRIBIO, "devscd", hz/10);
}
dev_unlock();
}
void
drain_dev_clone_events(void)
{
sx_xlock(&clone_drain_lock);
sx_xunlock(&clone_drain_lock);
}
static void
devdtr_init(void *dummy __unused)
{
TASK_INIT(&dev_dtr_task, 0, destroy_dev_tq, NULL);
}
SYSINIT(devdtr, SI_SUB_DEVFS, SI_ORDER_SECOND, devdtr_init, NULL);
#include "opt_ddb.h"
#ifdef DDB
#include <sys/kernel.h>
#include <ddb/ddb.h>
DB_SHOW_COMMAND(cdev, db_show_cdev)
{
struct cdev_priv *cdp;
struct cdev *dev;
u_int flags;
char buf[512];
if (!have_addr) {
TAILQ_FOREACH(cdp, &cdevp_list, cdp_list) {
dev = &cdp->cdp_c;
db_printf("%s %p\n", dev->si_name, dev);
if (db_pager_quit)
break;
}
return;
}
dev = (struct cdev *)addr;
cdp = cdev2priv(dev);
db_printf("dev %s ref %d use %ld thr %ld inuse %u fdpriv %p\n",
dev->si_name, dev->si_refcount, dev->si_usecount,
dev->si_threadcount, cdp->cdp_inuse, cdp->cdp_fdpriv.lh_first);
db_printf("devsw %p si_drv0 %d si_drv1 %p si_drv2 %p\n",
dev->si_devsw, dev->si_drv0, dev->si_drv1, dev->si_drv2);
flags = dev->si_flags;
#define SI_FLAG(flag) do { \
if (flags & (flag)) { \
if (buf[0] != '\0') \
strlcat(buf, ", ", sizeof(buf)); \
strlcat(buf, (#flag) + 3, sizeof(buf)); \
flags &= ~(flag); \
} \
} while (0)
buf[0] = '\0';
SI_FLAG(SI_ETERNAL);
SI_FLAG(SI_ALIAS);
SI_FLAG(SI_NAMED);
SI_FLAG(SI_CHEAPCLONE);
SI_FLAG(SI_CHILD);
SI_FLAG(SI_DEVOPEN);
SI_FLAG(SI_CONSOPEN);
SI_FLAG(SI_DUMPDEV);
SI_FLAG(SI_CANDELETE);
SI_FLAG(SI_CLONELIST);
db_printf("si_flags %s\n", buf);
flags = cdp->cdp_flags;
#define CDP_FLAG(flag) do { \
if (flags & (flag)) { \
if (buf[0] != '\0') \
strlcat(buf, ", ", sizeof(buf)); \
strlcat(buf, (#flag) + 4, sizeof(buf)); \
flags &= ~(flag); \
} \
} while (0)
buf[0] = '\0';
CDP_FLAG(CDP_ACTIVE);
CDP_FLAG(CDP_SCHED_DTR);
db_printf("cdp_flags %s\n", buf);
}
#endif
Index: stable/8/sys/kern
===================================================================
--- stable/8/sys/kern (revision 278292)
+++ stable/8/sys/kern (revision 278293)
Property changes on: stable/8/sys/kern
___________________________________________________________________
Modified: svn:mergeinfo
## -0,0 +0,1 ##
Merged /head/sys/kern:r277179,277199,277391
Index: stable/8/sys/sys/conf.h
===================================================================
--- stable/8/sys/sys/conf.h (revision 278292)
+++ stable/8/sys/sys/conf.h (revision 278293)
@@ -1,348 +1,349 @@
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
* Copyright (c) 2000
* Poul-Henning Kamp. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)conf.h 8.5 (Berkeley) 1/9/95
* $FreeBSD$
*/
#ifndef _SYS_CONF_H_
#define _SYS_CONF_H_
#ifdef _KERNEL
#include <sys/eventhandler.h>
#else
#include <sys/queue.h>
#endif
struct snapdata;
struct devfs_dirent;
struct cdevsw;
struct file;
struct cdev {
void *__si_reserved;
u_int si_flags;
#define SI_ETERNAL 0x0001 /* never destroyed */
#define SI_ALIAS 0x0002 /* carrier of alias name */
#define SI_NAMED 0x0004 /* make_dev{_alias} has been called */
#define SI_CHEAPCLONE 0x0008 /* can be removed_dev'ed when vnode reclaims */
#define SI_CHILD 0x0010 /* child of another struct cdev **/
#define SI_DEVOPEN 0x0020 /* opened by device */
#define SI_CONSOPEN 0x0040 /* opened by console */
#define SI_DUMPDEV 0x0080 /* is kernel dumpdev */
#define SI_CANDELETE 0x0100 /* can do BIO_DELETE */
#define SI_CLONELIST 0x0200 /* on a clone list */
struct timespec si_atime;
struct timespec si_ctime;
struct timespec si_mtime;
uid_t si_uid;
gid_t si_gid;
mode_t si_mode;
struct ucred *si_cred; /* cached clone-time credential */
int si_drv0;
int si_refcount;
LIST_ENTRY(cdev) si_list;
LIST_ENTRY(cdev) si_clone;
LIST_HEAD(, cdev) si_children;
LIST_ENTRY(cdev) si_siblings;
struct cdev *si_parent;
char *si_name;
void *si_drv1, *si_drv2;
struct cdevsw *si_devsw;
int si_iosize_max; /* maximum I/O size (for physio &al) */
u_long si_usecount;
u_long si_threadcount;
union {
struct snapdata *__sid_snapdata;
} __si_u;
char __si_namebuf[SPECNAMELEN + 1];
};
#define si_snapdata __si_u.__sid_snapdata
#ifdef _KERNEL
/*
* Definitions of device driver entry switches
*/
struct bio;
struct buf;
struct thread;
struct uio;
struct knote;
struct clonedevs;
struct vm_object;
struct vnode;
/*
* Note: d_thread_t is provided as a transition aid for those drivers
* that treat struct proc/struct thread as an opaque data type and
* exist in substantially the same form in both 4.x and 5.x. Writers
* of drivers that dips into the d_thread_t structure should use
* struct thread or struct proc as appropriate for the version of the
* OS they are using. It is provided in lieu of each device driver
* inventing its own way of doing this. While it does violate style(9)
* in a number of ways, this violation is deemed to be less
* important than the benefits that a uniform API between releases
* gives.
*
* Users of struct thread/struct proc that aren't device drivers should
* not use d_thread_t.
*/
typedef struct thread d_thread_t;
typedef int d_open_t(struct cdev *dev, int oflags, int devtype, struct thread *td);
typedef int d_fdopen_t(struct cdev *dev, int oflags, struct thread *td, struct file *fp);
typedef int d_close_t(struct cdev *dev, int fflag, int devtype, struct thread *td);
typedef void d_strategy_t(struct bio *bp);
typedef int d_ioctl_t(struct cdev *dev, u_long cmd, caddr_t data,
int fflag, struct thread *td);
typedef int d_read_t(struct cdev *dev, struct uio *uio, int ioflag);
typedef int d_write_t(struct cdev *dev, struct uio *uio, int ioflag);
typedef int d_poll_t(struct cdev *dev, int events, struct thread *td);
typedef int d_kqfilter_t(struct cdev *dev, struct knote *kn);
typedef int d_mmap_t(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr,
int nprot);
typedef int d_mmap2_t(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr,
int nprot, vm_memattr_t *memattr);
typedef int d_mmap_single_t(struct cdev *cdev, vm_ooffset_t *offset,
vm_size_t size, struct vm_object **object, int nprot);
typedef void d_purge_t(struct cdev *dev);
typedef int dumper_t(
void *_priv, /* Private to the driver. */
void *_virtual, /* Virtual (mapped) address. */
vm_offset_t _physical, /* Physical address of virtual. */
off_t _offset, /* Byte-offset to write at. */
size_t _length); /* Number of bytes to dump. */
#endif /* _KERNEL */
/*
* Types for d_flags.
*/
#define D_TAPE 0x0001
#define D_DISK 0x0002
#define D_TTY 0x0004
#define D_MEM 0x0008
#ifdef _KERNEL
#define D_TYPEMASK 0xffff
/*
* Flags for d_flags which the drivers can set.
*/
#define D_TRACKCLOSE 0x00080000 /* track all closes */
#define D_MMAP_ANON 0x00100000 /* special treatment in vm_mmap.c */
#define D_PSEUDO 0x00200000 /* make_dev() can return NULL */
#define D_NEEDGIANT 0x00400000 /* driver want Giant */
#define D_NEEDMINOR 0x00800000 /* driver uses clone_create() */
#define D_MMAP2 0x01000000 /* driver uses d_mmap2() */
/*
* Version numbers.
*/
#define D_VERSION_00 0x20011966
#define D_VERSION_01 0x17032005 /* Add d_uid,gid,mode & kind */
#define D_VERSION_02 0x28042009 /* Add d_mmap_single */
#define D_VERSION D_VERSION_02
/*
* Flags used for internal housekeeping
*/
#define D_INIT 0x80000000 /* cdevsw initialized */
/*
* Character device switch table
*/
struct cdevsw {
int d_version;
u_int d_flags;
const char *d_name;
d_open_t *d_open;
d_fdopen_t *d_fdopen;
d_close_t *d_close;
d_read_t *d_read;
d_write_t *d_write;
d_ioctl_t *d_ioctl;
d_poll_t *d_poll;
union {
d_mmap_t *old;
d_mmap2_t *new;
} __d_mmap;
d_strategy_t *d_strategy;
dumper_t *d_dump;
d_kqfilter_t *d_kqfilter;
d_purge_t *d_purge;
d_mmap_single_t *d_mmap_single;
uid_t d_uid;
gid_t d_gid;
mode_t d_mode;
const char *d_kind;
/* These fields should not be messed with by drivers */
LIST_ENTRY(cdevsw) d_list;
LIST_HEAD(, cdev) d_devs;
int d_spare3;
union {
struct cdevsw *gianttrick;
SLIST_ENTRY(cdevsw) postfree_list;
} __d_giant;
};
#define d_mmap __d_mmap.old
#define d_mmap2 __d_mmap.new
#define d_gianttrick __d_giant.gianttrick
#define d_postfree_list __d_giant.postfree_list
struct module;
struct devsw_module_data {
int (*chainevh)(struct module *, int, void *); /* next handler */
void *chainarg; /* arg for next event handler */
/* Do not initialize fields hereafter */
};
#define DEV_MODULE(name, evh, arg) \
static moduledata_t name##_mod = { \
#name, \
evh, \
arg \
}; \
DECLARE_MODULE(name, name##_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE)
void clone_setup(struct clonedevs **cdp);
void clone_cleanup(struct clonedevs **);
#define CLONE_UNITMASK 0xfffff
#define CLONE_FLAG0 (CLONE_UNITMASK + 1)
int clone_create(struct clonedevs **, struct cdevsw *, int *unit, struct cdev **dev, int extra);
int count_dev(struct cdev *_dev);
+void delist_dev(struct cdev *_dev);
void destroy_dev(struct cdev *_dev);
int destroy_dev_sched(struct cdev *dev);
int destroy_dev_sched_cb(struct cdev *dev, void (*cb)(void *), void *arg);
void destroy_dev_drain(struct cdevsw *csw);
void drain_dev_clone_events(void);
struct cdevsw *dev_refthread(struct cdev *_dev, int *_ref);
struct cdevsw *devvn_refthread(struct vnode *vp, struct cdev **devp, int *_ref);
void dev_relthread(struct cdev *_dev, int _ref);
void dev_depends(struct cdev *_pdev, struct cdev *_cdev);
void dev_ref(struct cdev *dev);
void dev_refl(struct cdev *dev);
void dev_rel(struct cdev *dev);
void dev_strategy(struct cdev *dev, struct buf *bp);
struct cdev *make_dev(struct cdevsw *_devsw, int _unit, uid_t _uid, gid_t _gid,
int _perms, const char *_fmt, ...) __printflike(6, 7);
struct cdev *make_dev_cred(struct cdevsw *_devsw, int _unit,
struct ucred *_cr, uid_t _uid, gid_t _gid, int _perms,
const char *_fmt, ...) __printflike(7, 8);
#define MAKEDEV_REF 0x01
#define MAKEDEV_WHTOUT 0x02
#define MAKEDEV_NOWAIT 0x04
#define MAKEDEV_WAITOK 0x08
#define MAKEDEV_ETERNAL 0x10
struct cdev *make_dev_credf(int _flags,
struct cdevsw *_devsw, int _unit,
struct ucred *_cr, uid_t _uid, gid_t _gid, int _mode,
const char *_fmt, ...) __printflike(8, 9);
int make_dev_p(int _flags, struct cdev **_cdev, struct cdevsw *_devsw,
struct ucred *_cr, uid_t _uid, gid_t _gid, int _mode,
const char *_fmt, ...) __printflike(8, 9);
struct cdev *make_dev_alias(struct cdev *_pdev, const char *_fmt, ...)
__printflike(2, 3);
void dev_lock(void);
void dev_unlock(void);
void setconf(void);
#ifdef KLD_MODULE
#define MAKEDEV_ETERNAL_KLD 0
#else
#define MAKEDEV_ETERNAL_KLD MAKEDEV_ETERNAL
#endif
#define dev2unit(d) ((d)->si_drv0)
typedef void (*cdevpriv_dtr_t)(void *data);
int devfs_get_cdevpriv(void **datap);
int devfs_set_cdevpriv(void *priv, cdevpriv_dtr_t dtr);
void devfs_clear_cdevpriv(void);
void devfs_fpdrop(struct file *fp); /* XXX This is not public KPI */
ino_t devfs_alloc_cdp_inode(void);
void devfs_free_cdp_inode(ino_t ino);
#define UID_ROOT 0
#define UID_BIN 3
#define UID_UUCP 66
#define UID_NOBODY 65534
#define GID_WHEEL 0
#define GID_KMEM 2
#define GID_TTY 4
#define GID_OPERATOR 5
#define GID_BIN 7
#define GID_GAMES 13
#define GID_DIALER 68
#define GID_NOBODY 65534
typedef void (*dev_clone_fn)(void *arg, struct ucred *cred, char *name,
int namelen, struct cdev **result);
int dev_stdclone(char *_name, char **_namep, const char *_stem, int *_unit);
EVENTHANDLER_DECLARE(dev_clone, dev_clone_fn);
/* Stuff relating to kernel-dump */
struct dumperinfo {
dumper_t *dumper; /* Dumping function. */
void *priv; /* Private parts. */
u_int blocksize; /* Size of block in bytes. */
u_int maxiosize; /* Max size allowed for an individual I/O */
off_t mediaoffset; /* Initial offset in bytes. */
off_t mediasize; /* Space available in bytes. */
};
int set_dumper(struct dumperinfo *);
int dump_write(struct dumperinfo *, void *, vm_offset_t, off_t, size_t);
void dumpsys(struct dumperinfo *);
extern int dumping; /* system is dumping */
#endif /* _KERNEL */
#endif /* !_SYS_CONF_H_ */
Index: stable/8/sys/sys
===================================================================
--- stable/8/sys/sys (revision 278292)
+++ stable/8/sys/sys (revision 278293)
Property changes on: stable/8/sys/sys
___________________________________________________________________
Modified: svn:mergeinfo
## -0,0 +0,1 ##
Merged /head/sys/sys:r277179
Index: stable/8/sys
===================================================================
--- stable/8/sys (revision 278292)
+++ stable/8/sys (revision 278293)
Property changes on: stable/8/sys
___________________________________________________________________
Modified: svn:mergeinfo
## -0,0 +0,1 ##
Merged /head/sys:r277179,277199,277391
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Fri, Mar 20, 3:10 PM (2 d)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29967571
Default Alt Text
(48 KB)
Attached To
Mode
rS FreeBSD src repository - subversion
Attached
Detach File
Event Timeline
Log In to Comment