summaryrefslogtreecommitdiffstats
path: root/sys/fs/devfs/devfs_vnops.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/fs/devfs/devfs_vnops.c')
-rw-r--r--sys/fs/devfs/devfs_vnops.c110
1 files changed, 109 insertions, 1 deletions
diff --git a/sys/fs/devfs/devfs_vnops.c b/sys/fs/devfs/devfs_vnops.c
index 21d8ba9..6c3f8fb 100644
--- a/sys/fs/devfs/devfs_vnops.c
+++ b/sys/fs/devfs/devfs_vnops.c
@@ -73,10 +73,14 @@ static struct fileops devfs_ops_f;
#include <security/mac/mac_framework.h>
+static MALLOC_DEFINE(M_CDEVPDATA, "DEVFSP", "Metainfo for cdev-fp data");
+
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");
+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 +96,97 @@ 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;
+ struct cdev_privdata *p;
+ int error;
+
+ fp = curthread->td_fpop;
+ if (fp == NULL)
+ return (EBADF);
+ mtx_lock(&cdevpriv_mtx);
+ p = fp->f_cdevpriv;
+ mtx_unlock(&cdevpriv_mtx);
+ if (p != NULL) {
+ error = 0;
+ *datap = p->cdpd_data;
+ } else
+ error = ENOENT;
+ return (error);
+}
+
+int
+devfs_set_cdevpriv(void *priv, cdevpriv_dtr_t priv_dtr)
+{
+ struct file *fp;
+ struct cdev_priv *cdp;
+ struct cdev_privdata *p;
+ int error;
+
+ fp = curthread->td_fpop;
+ if (fp == NULL)
+ return (ENOENT);
+ cdp = ((struct cdev *)fp->f_data)->si_priv;
+ p = malloc(sizeof(struct cdev_privdata), M_CDEVPDATA, M_WAITOK);
+ p->cdpd_data = priv;
+ p->cdpd_dtr = priv_dtr;
+ p->cdpd_fp = fp;
+ mtx_lock(&cdevpriv_mtx);
+ if (fp->f_cdevpriv == NULL) {
+ LIST_INSERT_HEAD(&cdp->cdp_fdpriv, p, cdpd_list);
+ fp->f_cdevpriv = p;
+ mtx_unlock(&cdevpriv_mtx);
+ error = 0;
+ } else {
+ mtx_unlock(&cdevpriv_mtx);
+ free(p, M_CDEVPDATA);
+ error = EBUSY;
+ }
+ return (error);
+}
+
+void
+devfs_destroy_cdevpriv(struct cdev_privdata *p)
+{
+
+ mtx_assert(&cdevpriv_mtx, MA_OWNED);
+ p->cdpd_fp->f_cdevpriv = NULL;
+ LIST_REMOVE(p, cdpd_list);
+ mtx_unlock(&cdevpriv_mtx);
+ (p->cdpd_dtr)(p->cdpd_data);
+ free(p, M_CDEVPDATA);
+}
+
+void
+devfs_fpdrop(struct file *fp)
+{
+ struct cdev_privdata *p;
+
+ mtx_lock(&cdevpriv_mtx);
+ if ((p = fp->f_cdevpriv) == NULL) {
+ mtx_unlock(&cdevpriv_mtx);
+ return;
+ }
+ devfs_destroy_cdevpriv(p);
+}
+
+void
+devfs_clear_cdevpriv(void)
+{
+ struct file *fp;
+
+ fp = curthread->td_fpop;
+ if (fp == NULL)
+ return;
+ devfs_fpdrop(fp);
+}
+
/*
* Construct the fully qualified path name relative to the mountpoint
*/
@@ -374,8 +466,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 */
@@ -472,6 +568,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) {
@@ -482,10 +579,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;
@@ -529,6 +628,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);
}
@@ -766,10 +866,15 @@ devfs_open(struct vop_open_args *ap)
VOP_UNLOCK(vp, 0);
+ if (fp != NULL) {
+ td->td_fpop = fp;
+ fp->f_data = dev;
+ }
if (dsw->d_fdopen != NULL)
error = dsw->d_fdopen(dev, ap->a_mode, td, fp);
else
error = dsw->d_open(dev, ap->a_mode, S_IFCHR, td);
+ td->td_fpop = NULL;
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
@@ -825,6 +930,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);
}
@@ -862,6 +968,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)
@@ -1298,6 +1405,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)
OpenPOWER on IntegriCloud