summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_descrip.c
diff options
context:
space:
mode:
authordwmalone <dwmalone@FreeBSD.org>2003-10-19 20:41:07 +0000
committerdwmalone <dwmalone@FreeBSD.org>2003-10-19 20:41:07 +0000
commitbe405a4cbded7cdf17be85da15ed406cd32d25cf (patch)
tree005101ab125d7c43f5a5366aaad1dafbe9eb3c26 /sys/kern/kern_descrip.c
parent676085d67110550e1f32ca4a1a3b4b1faf055dc5 (diff)
downloadFreeBSD-src-be405a4cbded7cdf17be85da15ed406cd32d25cf.zip
FreeBSD-src-be405a4cbded7cdf17be85da15ed406cd32d25cf.tar.gz
falloc allocates a file structure and adds it to the file descriptor
table, acquiring the necessary locks as it works. It usually returns two references to the new descriptor: one in the descriptor table and one via a pointer argument. As falloc releases the FILEDESC lock before returning, there is a potential for a process to close the reference in the file descriptor table before falloc's caller gets to use the file. I don't think this can happen in practice at the moment, because Giant indirectly protects closes. To stop the file being completly closed in this situation, this change makes falloc set the refcount to two when both references are returned. This makes life easier for several of falloc's callers, because the first thing they previously did was grab an extra reference on the file. Reviewed by: iedowse Idea run past: jhb
Diffstat (limited to 'sys/kern/kern_descrip.c')
-rw-r--r--sys/kern/kern_descrip.c24
1 files changed, 22 insertions, 2 deletions
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index 1ed5140..5e00b53 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -1163,6 +1163,10 @@ fdavail(td, n)
/*
* Create a new open file structure and allocate
* a file decriptor for the process that refers to it.
+ * We add one reference to the file for the descriptor table
+ * and one reference for resultfp. This is to prevent us being
+ * prempted and the entry in the descriptor table closed after
+ * we release the FILEDESC lock.
*/
int
falloc(td, resultfp, resultfd)
@@ -1198,6 +1202,8 @@ falloc(td, resultfp, resultfd)
*/
fp->f_mtxp = mtx_pool_alloc(mtxpool_sleep);
fp->f_count = 1;
+ if (resultfp)
+ fp->f_count++;
fp->f_cred = crhold(td->td_ucred);
fp->f_ops = &badfileops;
FILEDESC_LOCK(p->p_fd);
@@ -1210,6 +1216,8 @@ falloc(td, resultfp, resultfd)
if ((error = fdalloc(td, 0, &i))) {
FILEDESC_UNLOCK(p->p_fd);
fdrop(fp, td);
+ if (resultfp)
+ fdrop(fp, td);
return (error);
}
p->p_fd->fd_ofiles[i] = fp;
@@ -1676,7 +1684,7 @@ fdcheckstd(td)
struct filedesc *fdp;
struct file *fp;
register_t retval;
- int fd, i, error, flags, devnull;
+ int fd, i, error, flags, devnull, extraref;
fdp = td->td_proc->p_fd;
if (fdp == NULL)
@@ -1690,16 +1698,28 @@ fdcheckstd(td)
error = falloc(td, &fp, &fd);
if (error != 0)
break;
+ /* Note extra ref on `fp' held for us by falloc(). */
KASSERT(fd == i, ("oof, we didn't get our fd"));
NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, "/dev/null",
td);
flags = FREAD | FWRITE;
error = vn_open(&nd, &flags, 0, -1);
if (error != 0) {
+ /*
+ * Someone may have closed the entry in the
+ * file descriptor table, so check it hasn't
+ * changed before dropping the reference count.
+ */
+ extraref = 0;
FILEDESC_LOCK(fdp);
- fdp->fd_ofiles[fd] = NULL;
+ if (fdp->fd_ofiles[fd] == fp) {
+ fdp->fd_ofiles[fd] = NULL;
+ extraref = 1;
+ }
FILEDESC_UNLOCK(fdp);
fdrop(fp, td);
+ if (extraref)
+ fdrop(fp, td);
break;
}
NDFREE(&nd, NDF_ONLY_PNBUF);
OpenPOWER on IntegriCloud