Fix SIGIO delivery. Use fsetown() to handle file descriptor owner

ioctl and use pgsigio() to send SIGIO.

Submitted by:	truckman
Reviewed by:	mjg
This commit is contained in:
David Xu 2014-04-04 12:31:13 +00:00
parent 605a34b065
commit 5055c92801

View File

@ -391,11 +391,12 @@ 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 struct cdev *devctl_dev;
@ -422,7 +423,7 @@ devopen(struct cdev *dev, int oflags, int devtype, struct thread *td)
/* move to init */
devsoftc.inuse = 1;
devsoftc.nonblock = 0;
devsoftc.async_proc = NULL;
devsoftc.async = 0;
mtx_unlock(&devsoftc.mtx);
return (0);
}
@ -433,8 +434,8 @@ devclose(struct cdev *dev, int fflag, int devtype, struct thread *td)
mtx_lock(&devsoftc.mtx);
devsoftc.inuse = 0;
devsoftc.async_proc = NULL;
cv_broadcast(&devsoftc.cv);
funsetown(&devsoftc.sigio);
mtx_unlock(&devsoftc.mtx);
return (0);
}
@ -490,33 +491,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;
}
@ -560,7 +549,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;
@ -590,13 +578,8 @@ devctl_queue_data_f(char *data, int flags)
cv_broadcast(&devsoftc.cv);
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:
/*