summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authormjg <mjg@FreeBSD.org>2014-08-17 07:16:03 +0000
committermjg <mjg@FreeBSD.org>2014-08-17 07:16:03 +0000
commit789b35542c82c8e4b795eb04c7b904644f307848 (patch)
tree7f78bcd7f127a720cc6d2b0f16f8b5e50f98ce7c /sys/kern
parent9e281fe64ef33438aca0b765c4245ab51441f1ab (diff)
downloadFreeBSD-src-789b35542c82c8e4b795eb04c7b904644f307848.zip
FreeBSD-src-789b35542c82c8e4b795eb04c7b904644f307848.tar.gz
MFC r264114, r264310, r268570:
r264114 by davidxu: Fix SIGIO delivery. Use fsetown() to handle file descriptor owner ioctl and use pgsigio() to send SIGIO. r264310 by davidxu: Add kqueue support for devctl. r268570: Clear nonblock and async on devctl close instaed of open. This is a purely cosmetic change.
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/subr_bus.c86
1 files changed, 55 insertions, 31 deletions
diff --git a/sys/kern/subr_bus.c b/sys/kern/subr_bus.c
index 2061449..e272acc 100644
--- a/sys/kern/subr_bus.c
+++ b/sys/kern/subr_bus.c
@@ -374,6 +374,7 @@ static d_close_t devclose;
static d_read_t devread;
static d_ioctl_t devioctl;
static d_poll_t devpoll;
+static d_kqfilter_t devkqfilter;
static struct cdevsw dev_cdevsw = {
.d_version = D_VERSION,
@@ -382,6 +383,7 @@ static struct cdevsw dev_cdevsw = {
.d_read = devread,
.d_ioctl = devioctl,
.d_poll = devpoll,
+ .d_kqfilter = devkqfilter,
.d_name = "devctl",
};
@@ -398,13 +400,23 @@ static struct dev_softc
int inuse;
int nonblock;
int queued;
+ int async;
struct mtx mtx;
struct cv cv;
struct selinfo sel;
struct devq devq;
- struct proc *async_proc;
+ struct sigio *sigio;
} devsoftc;
+static void filt_devctl_detach(struct knote *kn);
+static int filt_devctl_read(struct knote *kn, long hint);
+
+struct filterops devctl_rfiltops = {
+ .f_isfd = 1,
+ .f_detach = filt_devctl_detach,
+ .f_event = filt_devctl_read,
+};
+
static struct cdev *devctl_dev;
static void
@@ -415,6 +427,7 @@ devinit(void)
mtx_init(&devsoftc.mtx, "dev mtx", "devd", MTX_DEF);
cv_init(&devsoftc.cv, "dev cv");
TAILQ_INIT(&devsoftc.devq);
+ knlist_init_mtx(&devsoftc.sel.si_note, &devsoftc.mtx);
}
static int
@@ -428,8 +441,6 @@ devopen(struct cdev *dev, int oflags, int devtype, struct thread *td)
}
/* move to init */
devsoftc.inuse = 1;
- devsoftc.nonblock = 0;
- devsoftc.async_proc = NULL;
mtx_unlock(&devsoftc.mtx);
return (0);
}
@@ -440,8 +451,10 @@ devclose(struct cdev *dev, int fflag, int devtype, struct thread *td)
mtx_lock(&devsoftc.mtx);
devsoftc.inuse = 0;
- devsoftc.async_proc = NULL;
+ devsoftc.nonblock = 0;
+ devsoftc.async = 0;
cv_broadcast(&devsoftc.cv);
+ funsetown(&devsoftc.sigio);
mtx_unlock(&devsoftc.mtx);
return (0);
}
@@ -497,33 +510,21 @@ devioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *t
devsoftc.nonblock = 0;
return (0);
case FIOASYNC:
- /*
- * FIXME:
- * Since this is a simple assignment there is no guarantee that
- * devsoftc.async_proc consumers will get a valid pointer.
- *
- * Example scenario where things break (processes A and B):
- * 1. A opens devctl
- * 2. A sends fd to B
- * 3. B sets itself as async_proc
- * 4. B exits
- *
- * However, normally this requires root privileges and the only
- * in-tree consumer does not behave in a dangerous way so the
- * issue is not critical.
- */
if (*(int*)data)
- devsoftc.async_proc = td->td_proc;
+ devsoftc.async = 1;
else
- devsoftc.async_proc = NULL;
+ devsoftc.async = 0;
+ return (0);
+ case FIOSETOWN:
+ return fsetown(*(int *)data, &devsoftc.sigio);
+ case FIOGETOWN:
+ *(int *)data = fgetown(&devsoftc.sigio);
return (0);
/* (un)Support for other fcntl() calls. */
case FIOCLEX:
case FIONCLEX:
case FIONREAD:
- case FIOSETOWN:
- case FIOGETOWN:
default:
break;
}
@@ -547,6 +548,34 @@ devpoll(struct cdev *dev, int events, struct thread *td)
return (revents);
}
+static int
+devkqfilter(struct cdev *dev, struct knote *kn)
+{
+ int error;
+
+ if (kn->kn_filter == EVFILT_READ) {
+ kn->kn_fop = &devctl_rfiltops;
+ knlist_add(&devsoftc.sel.si_note, kn, 0);
+ error = 0;
+ } else
+ error = EINVAL;
+ return (error);
+}
+
+static void
+filt_devctl_detach(struct knote *kn)
+{
+
+ knlist_remove(&devsoftc.sel.si_note, kn, 0);
+}
+
+static int
+filt_devctl_read(struct knote *kn, long hint)
+{
+ kn->kn_data = devsoftc.queued;
+ return (kn->kn_data != 0);
+}
+
/**
* @brief Return whether the userland process is running
*/
@@ -567,7 +596,6 @@ void
devctl_queue_data_f(char *data, int flags)
{
struct dev_event_info *n1 = NULL, *n2 = NULL;
- struct proc *p;
if (strlen(data) == 0)
goto out;
@@ -595,15 +623,11 @@ devctl_queue_data_f(char *data, int flags)
TAILQ_INSERT_TAIL(&devsoftc.devq, n1, dei_link);
devsoftc.queued++;
cv_broadcast(&devsoftc.cv);
+ KNOTE_LOCKED(&devsoftc.sel.si_note, 0);
mtx_unlock(&devsoftc.mtx);
selwakeup(&devsoftc.sel);
- /* XXX see a comment in devioctl */
- p = devsoftc.async_proc;
- if (p != NULL) {
- PROC_LOCK(p);
- kern_psignal(p, SIGIO);
- PROC_UNLOCK(p);
- }
+ if (devsoftc.async && devsoftc.sigio != NULL)
+ pgsigio(&devsoftc.sigio, SIGIO, 0);
return;
out:
/*
OpenPOWER on IntegriCloud