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:
parent
605a34b065
commit
5055c92801
@ -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:
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user