diff --git a/sys/fs/devfs/devfs_vnops.c b/sys/fs/devfs/devfs_vnops.c index d9565ee..fd3c2c4 100644 --- a/sys/fs/devfs/devfs_vnops.c +++ b/sys/fs/devfs/devfs_vnops.c @@ -77,6 +77,8 @@ struct mtx devfs_de_interlock; MTX_SYSINIT(devfs_de_interlock, &devfs_de_interlock, "devfs interlock", MTX_DEF); struct sx clone_drain_lock; SX_SYSINIT(clone_drain_lock, &clone_drain_lock, "clone events drain lock"); +static struct mtx cdevpriv_mtx; +MTX_SYSINIT(cdevpriv_mtx, &cdevpriv_mtx, "cdevpriv lock", MTX_DEF); static int devfs_fp_check(struct file *fp, struct cdev **devp, struct cdevsw **dswp) @@ -92,9 +94,74 @@ devfs_fp_check(struct file *fp, struct cdev **devp, struct cdevsw **dswp) ("devfs: un-referenced struct cdev *(%s)", devtoname(*devp))); if (*dswp == NULL) return (ENXIO); + curthread->td_fpop = fp; return (0); } +int +devfs_get_cdevpriv(void **datap) +{ + struct file *fp; + + fp = curthread->td_fpop; + if (fp == NULL) + return (EBADF); + mtx_lock(&cdevpriv_mtx); + *datap = fp->f_cdevpriv; + mtx_unlock(&cdevpriv_mtx); + return (0); +} + +int +devfs_set_cdevpriv(void *priv, cdevpriv_dtr_t priv_dtr) +{ + struct file *fp; + int error; + + fp = curthread->td_fpop; + if (fp == NULL) + return (ENOENT); + mtx_lock(&cdevpriv_mtx); + if (fp->f_cdevpriv == NULL) { + error = 0; + fp->f_cdevpriv = priv; + fp->f_cdevpriv_dtr = (void (*)(void *, void *))priv_dtr; + } else + error = EBUSY; + mtx_unlock(&cdevpriv_mtx); + return (error); +} + +void +devfs_clear_cdevpriv(void) +{ + struct file *fp; + struct cdev *dev; + struct cdevsw *dsw; + void *priv; + void (*dtr)(void *, void *); + int error; + + fp = curthread->td_fpop; + if (fp == NULL) + return; + error = devfs_fp_check(fp, &dev, &dsw); + curthread->td_fpop = NULL; + if (error) + dev = NULL; + mtx_lock(&cdevpriv_mtx); + if (fp->f_cdevpriv_dtr != NULL) { + priv = fp->f_cdevpriv; + dtr = fp->f_cdevpriv_dtr; + fp->f_cdevpriv = NULL; + mtx_unlock(&cdevpriv_mtx); + dtr(dev, priv); + } else + mtx_unlock(&cdevpriv_mtx); + if (error == 0) + dev_relthread(dev); +} + /* * Construct the fully qualified path name relative to the mountpoint */ @@ -380,8 +447,12 @@ devfs_close(struct vop_close_args *ap) static int devfs_close_f(struct file *fp, struct thread *td) { + int error; - return (vnops.fo_close(fp, td)); + curthread->td_fpop = fp; + error = vnops.fo_close(fp, td); + curthread->td_fpop = NULL; + return (error); } /* ARGSUSED */ @@ -478,6 +549,7 @@ devfs_ioctl_f(struct file *fp, u_long com, void *data, struct ucred *cred, struc if (com == FIODTYPE) { *(int *)data = dsw->d_flags & D_TYPEMASK; + td->td_fpop = NULL; dev_relthread(dev); return (0); } else if (com == FIODGNAME) { @@ -488,10 +560,12 @@ devfs_ioctl_f(struct file *fp, u_long com, void *data, struct ucred *cred, struc error = EINVAL; else error = copyout(p, fgn->buf, i); + td->td_fpop = NULL; dev_relthread(dev); return (error); } error = dsw->d_ioctl(dev, com, data, fp->f_flag, td); + td->td_fpop = NULL; dev_relthread(dev); if (error == ENOIOCTL) error = ENOTTY; @@ -535,6 +609,7 @@ devfs_kqfilter_f(struct file *fp, struct knote *kn) if (error) return (error); error = dsw->d_kqfilter(dev, kn); + curthread->td_fpop = NULL; dev_relthread(dev); return (error); } @@ -772,6 +847,7 @@ devfs_open(struct vop_open_args *ap) VOP_UNLOCK(vp, 0); + td->td_fpop = fp; if(!(dsw->d_flags & D_NEEDGIANT)) { DROP_GIANT(); if (dsw->d_fdopen != NULL) @@ -785,6 +861,7 @@ devfs_open(struct vop_open_args *ap) else error = dsw->d_open(dev, ap->a_mode, S_IFCHR, td); } + td->td_fpop = NULL; vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); @@ -840,6 +917,7 @@ devfs_poll_f(struct file *fp, int events, struct ucred *cred, struct thread *td) if (error) return (error); error = dsw->d_poll(dev, events, td); + curthread->td_fpop = NULL; dev_relthread(dev); return(error); } @@ -877,6 +955,7 @@ devfs_read_f(struct file *fp, struct uio *uio, struct ucred *cred, int flags, st error = dsw->d_read(dev, uio, ioflag); if (uio->uio_resid != resid || (error == 0 && resid != 0)) vfs_timestamp(&dev->si_atime); + curthread->td_fpop = NULL; dev_relthread(dev); if ((flags & FOF_OFFSET) == 0) @@ -1313,6 +1392,7 @@ devfs_write_f(struct file *fp, struct uio *uio, struct ucred *cred, int flags, s vfs_timestamp(&dev->si_ctime); dev->si_mtime = dev->si_ctime; } + curthread->td_fpop = NULL; dev_relthread(dev); if ((flags & FOF_OFFSET) == 0) diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index c440832..805b760 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -2221,6 +2221,10 @@ _fdrop(struct file *fp, struct thread *td) panic("fdrop: count %d", fp->f_count); if (fp->f_ops != &badfileops) error = fo_close(fp, td); + if (fp->f_cdevpriv != NULL) { + curthread->td_fpop = fp; + devfs_clear_cdevpriv(); + } atomic_subtract_int(&openfiles, 1); crfree(fp->f_cred); uma_zfree(file_zone, fp); diff --git a/sys/sys/conf.h b/sys/sys/conf.h index 22d7abc..49863b7 100644 --- a/sys/sys/conf.h +++ b/sys/sys/conf.h @@ -281,6 +281,11 @@ int unit2minor(int _unit); u_int minor2unit(u_int _minor); void setconf(void); +typedef void (*cdevpriv_dtr_t)(struct cdev *, void *data); +int devfs_get_cdevpriv(void **datap); +int devfs_set_cdevpriv(void *priv, cdevpriv_dtr_t dtr); +void devfs_clear_cdevpriv(void); + #define UID_ROOT 0 #define UID_BIN 3 #define UID_UUCP 66 diff --git a/sys/sys/file.h b/sys/sys/file.h index 6833445..4c79f53 100644 --- a/sys/sys/file.h +++ b/sys/sys/file.h @@ -129,6 +129,11 @@ struct file { * Mandatory Access control information. */ void *f_label; /* Place-holder for MAC label. */ + /* + * Per-fd private data for the cdev. + */ + void *f_cdevpriv; + void (*f_cdevpriv_dtr)(void *, void *); }; #define FOFFSET_LOCKED 0x1 diff --git a/sys/sys/proc.h b/sys/sys/proc.h index 358dcbc..d83c3f7 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -229,6 +229,7 @@ struct thread { u_long td_profil_addr; /* (k) Temporary addr until AST. */ u_int td_profil_ticks; /* (k) Temporary ticks until AST. */ char td_name[MAXCOMLEN + 1]; /* (*) Thread name. */ + struct file *td_fpop; /* (k) file referencing cdev under op */ #define td_endzero td_base_pri /* Copied during fork1() or thread_sched_upcall(). */