aboutsummaryrefslogtreecommitdiff
path: root/sys/kern/vfs_aio.c
diff options
context:
space:
mode:
authorMatthew Dillon <dillon@FreeBSD.org>2000-11-18 21:01:04 +0000
committerMatthew Dillon <dillon@FreeBSD.org>2000-11-18 21:01:04 +0000
commit279d7226048c39b48b788e5ea5607c0dbc042acd (patch)
tree8d32488eeb453793eb19bb380ffcc26e97ca77fd /sys/kern/vfs_aio.c
parentd641426e5acce54fd775c3be86ddb9c2e78e8540 (diff)
downloadsrc-279d7226048c39b48b788e5ea5607c0dbc042acd.tar.gz
src-279d7226048c39b48b788e5ea5607c0dbc042acd.zip
This patchset fixes a large number of file descriptor race conditions.
Pre-rfork code assumed inherent locking of a process's file descriptor array. However, with the advent of rfork() the file descriptor table could be shared between processes. This patch closes over a dozen serious race conditions related to one thread manipulating the table (e.g. closing or dup()ing a descriptor) while another is blocked in an open(), close(), fcntl(), read(), write(), etc... PR: kern/11629 Discussed with: Alexander Viro <viro@math.psu.edu>
Notes
Notes: svn path=/head/; revision=68883
Diffstat (limited to 'sys/kern/vfs_aio.c')
-rw-r--r--sys/kern/vfs_aio.c37
1 files changed, 32 insertions, 5 deletions
diff --git a/sys/kern/vfs_aio.c b/sys/kern/vfs_aio.c
index a56488613ef3..d4a226c75e4b 100644
--- a/sys/kern/vfs_aio.c
+++ b/sys/kern/vfs_aio.c
@@ -589,6 +589,11 @@ aio_process(struct aiocblist *aiocbe)
inblock_st = mycp->p_stats->p_ru.ru_inblock;
oublock_st = mycp->p_stats->p_ru.ru_oublock;
+ /*
+ * Temporarily bump the ref count while reading to avoid the
+ * descriptor being ripped out from under us.
+ */
+ fhold(fp);
if (cb->aio_lio_opcode == LIO_READ) {
auio.uio_rw = UIO_READ;
error = fo_read(fp, &auio, fp->f_cred, FOF_OFFSET, mycp);
@@ -596,6 +601,7 @@ aio_process(struct aiocblist *aiocbe)
auio.uio_rw = UIO_WRITE;
error = fo_write(fp, &auio, fp->f_cred, FOF_OFFSET, mycp);
}
+ fdrop(fp, mycp);
inblock_end = mycp->p_stats->p_ru.ru_inblock;
oublock_end = mycp->p_stats->p_ru.ru_oublock;
@@ -986,6 +992,8 @@ aio_qphysio(struct proc *p, struct aiocblist *aiocbe)
if (ki->kaio_buffer_count >= ki->kaio_ballowed_count)
return (-1);
+ fhold(fp);
+
ki->kaio_buffer_count++;
lj = aiocbe->lio;
@@ -1074,6 +1082,7 @@ aio_qphysio(struct proc *p, struct aiocblist *aiocbe)
splx(s);
if (notify)
KNOTE(&aiocbe->klist, 0);
+ fdrop(fp, p);
return 0;
doerror:
@@ -1082,6 +1091,7 @@ doerror:
lj->lioj_buffer_count--;
aiocbe->bp = NULL;
relpbuf(bp, NULL);
+ fdrop(fp, p);
return error;
}
@@ -1291,6 +1301,8 @@ _aio_aqueue(struct proc *p, struct aiocb *job, struct aio_liojob *lj, int type)
return EINVAL;
}
+ fhold(fp);
+
/*
* XXX
* Figure out how to do this properly. This currently won't
@@ -1326,7 +1338,7 @@ aqueue_fail:
TAILQ_INSERT_HEAD(&aio_freejobs, aiocbe, list);
if (type == 0)
suword(&job->_aiocb_private.error, error);
- return (error);
+ goto done;
}
no_kqueue:
}
@@ -1363,18 +1375,19 @@ no_kqueue:
ki->kaio_queue_count++;
num_queue_count++;
splx(s);
- return 0;
+ error = 0;
+ goto done;
}
splx(s);
}
if ((error = aio_qphysio(p, aiocbe)) == 0)
- return 0;
- else if (error > 0) {
+ goto done;
+ if (error > 0) {
suword(&job->_aiocb_private.status, 0);
aiocbe->uaiocb._aiocb_private.error = error;
suword(&job->_aiocb_private.error, error);
- return error;
+ goto done;
}
/* No buffer for daemon I/O. */
@@ -1418,6 +1431,8 @@ retryproc:
num_aio_resv_start--;
}
splx(s);
+done:
+ fdrop(fp, p);
return error;
}
@@ -1907,7 +1922,13 @@ aio_read(struct proc *p, struct aio_read_args *uap)
auio.uio_procp = p;
cnt = iocb.aio_nbytes;
+ /*
+ * Temporarily bump the ref count while reading to avoid the
+ * descriptor being ripped out from under us.
+ */
+ fhold(fp);
error = fo_read(fp, &auio, fp->f_cred, FOF_OFFSET, p);
+ fdrop(fp, p);
if (error && (auio.uio_resid != cnt) && (error == ERESTART || error ==
EINTR || error == EWOULDBLOCK))
error = 0;
@@ -1974,7 +1995,13 @@ aio_write(struct proc *p, struct aio_write_args *uap)
auio.uio_procp = p;
cnt = iocb.aio_nbytes;
+ /*
+ * Temporarily bump the ref count while writing to avoid the
+ * descriptor being ripped out from under us.
+ */
+ fhold(fp);
error = fo_write(fp, &auio, fp->f_cred, FOF_OFFSET, p);
+ fdrop(fp, p);
if (error) {
if (auio.uio_resid != cnt) {
if (error == ERESTART || error == EINTR || error ==