diff options
author | jonathan <jonathan@FreeBSD.org> | 2011-06-30 15:22:49 +0000 |
---|---|---|
committer | jonathan <jonathan@FreeBSD.org> | 2011-06-30 15:22:49 +0000 |
commit | 4d4c5b3285343962855e4ac2e891fc6711595b64 (patch) | |
tree | 4b19a6b5ba55297faa43ed1032e7a8e77c16403d | |
parent | 8c932faae446ada0bed49a41fbb164c821227122 (diff) | |
download | FreeBSD-src-4d4c5b3285343962855e4ac2e891fc6711595b64.zip FreeBSD-src-4d4c5b3285343962855e4ac2e891fc6711595b64.tar.gz |
When Capsicum starts creating capabilities to wrap existing file
descriptors, we will want to allocate a new descriptor without installing
it in the FD array.
Split falloc() into falloc_noinstall() and finstall(), and rewrite
falloc() to call them with appropriate atomicity.
Approved by: mentor (rwatson), re (bz)
-rw-r--r-- | sys/kern/kern_descrip.c | 85 | ||||
-rw-r--r-- | sys/sys/filedesc.h | 2 |
2 files changed, 60 insertions, 27 deletions
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index 180d598..7f32d47 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -1561,54 +1561,85 @@ fdavail(struct thread *td, int n) int falloc(struct thread *td, struct file **resultfp, int *resultfd, int flags) { - struct proc *p = td->td_proc; struct file *fp; - int error, i; + int error, fd; + + error = falloc_noinstall(td, &fp); + if (error) + return (error); /* no reference held on error */ + + error = finstall(td, fp, &fd, flags); + if (error) { + fdrop(fp, td); /* one reference (fp only) */ + return (error); + } + + if (resultfp != NULL) + *resultfp = fp; /* copy out result */ + else + fdrop(fp, td); /* release local reference */ + + if (resultfd != NULL) + *resultfd = fd; + + return (0); +} + +/* + * Create a new open file structure without allocating a file descriptor. + */ +int +falloc_noinstall(struct thread *td, struct file **resultfp) +{ + struct file *fp; int maxuserfiles = maxfiles - (maxfiles / 20); static struct timeval lastfail; static int curfail; - fp = uma_zalloc(file_zone, M_WAITOK | M_ZERO); + KASSERT(resultfp != NULL, ("%s: resultfp == NULL", __func__)); + if ((openfiles >= maxuserfiles && priv_check(td, PRIV_MAXFILES) != 0) || openfiles >= maxfiles) { if (ppsratecheck(&lastfail, &curfail, 1)) { - printf("kern.maxfiles limit exceeded by uid %i, please see tuning(7).\n", - td->td_ucred->cr_ruid); + printf("kern.maxfiles limit exceeded by uid %i, " + "please see tuning(7).\n", td->td_ucred->cr_ruid); } - uma_zfree(file_zone, fp); return (ENFILE); } atomic_add_int(&openfiles, 1); - - /* - * If the process has file descriptor zero open, add the new file - * descriptor to the list of open files at that point, otherwise - * put it at the front of the list of open files. - */ + fp = uma_zalloc(file_zone, M_WAITOK | M_ZERO); refcount_init(&fp->f_count, 1); - if (resultfp) - fhold(fp); fp->f_cred = crhold(td->td_ucred); fp->f_ops = &badfileops; fp->f_data = NULL; fp->f_vnode = NULL; - FILEDESC_XLOCK(p->p_fd); - if ((error = fdalloc(td, 0, &i))) { - FILEDESC_XUNLOCK(p->p_fd); - fdrop(fp, td); - if (resultfp) - fdrop(fp, td); + *resultfp = fp; + return (0); +} + +/* + * Install a file in a file descriptor table. + */ +int +finstall(struct thread *td, struct file *fp, int *fd, int flags) +{ + struct filedesc *fdp = td->td_proc->p_fd; + int error; + + KASSERT(fd != NULL, ("%s: fd == NULL", __func__)); + KASSERT(fp != NULL, ("%s: fp == NULL", __func__)); + + FILEDESC_XLOCK(fdp); + if ((error = fdalloc(td, 0, fd))) { + FILEDESC_XUNLOCK(fdp); return (error); } - p->p_fd->fd_ofiles[i] = fp; + fhold(fp); + fdp->fd_ofiles[*fd] = fp; if ((flags & O_CLOEXEC) != 0) - p->p_fd->fd_ofileflags[i] |= UF_EXCLOSE; - FILEDESC_XUNLOCK(p->p_fd); - if (resultfp) - *resultfp = fp; - if (resultfd) - *resultfd = i; + fdp->fd_ofileflags[*fd] |= UF_EXCLOSE; + FILEDESC_XUNLOCK(fdp); return (0); } diff --git a/sys/sys/filedesc.h b/sys/sys/filedesc.h index 33dddca..2dab741 100644 --- a/sys/sys/filedesc.h +++ b/sys/sys/filedesc.h @@ -113,6 +113,8 @@ int dupfdopen(struct thread *td, struct filedesc *fdp, int indx, int dfd, int mode, int error); int falloc(struct thread *td, struct file **resultfp, int *resultfd, int flags); +int falloc_noinstall(struct thread *td, struct file **resultfp); +int finstall(struct thread *td, struct file *fp, int *resultfp, int flags); int fdalloc(struct thread *td, int minfd, int *result); int fdavail(struct thread *td, int n); int fdcheckstd(struct thread *td); |