summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_descrip.c
diff options
context:
space:
mode:
authormjg <mjg@FreeBSD.org>2014-08-17 07:00:47 +0000
committermjg <mjg@FreeBSD.org>2014-08-17 07:00:47 +0000
commitce59684e4d3b1070bd191b87caba0fd4cd628ce0 (patch)
tree9e20ff6024a8e162558e3a6a2b2ededd8d56aa5d /sys/kern/kern_descrip.c
parent8fa92f4d0bcf1f1e08a74527ec90f63c26d5b3c4 (diff)
downloadFreeBSD-src-ce59684e4d3b1070bd191b87caba0fd4cd628ce0.zip
FreeBSD-src-ce59684e4d3b1070bd191b87caba0fd4cd628ce0.tar.gz
MFC r268505, r268507:
Avoid relocking filedesc lock when closing fds during fdp destruction. Don't call bzero nor fdunused from fdfree for such cases. It would do unnecessary work and complain that the lock is not taken. ======= Don't zero fd_nfiles during fdp destruction. Code trying to take a look has to check fd_refcnt and it is 0 by that time. This is a follow up to r268505, without this the code would leak memory for tables bigger than the default.
Diffstat (limited to 'sys/kern/kern_descrip.c')
-rw-r--r--sys/kern/kern_descrip.c48
1 files changed, 31 insertions, 17 deletions
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index 8491d84..bb9ecb5 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -295,18 +295,36 @@ fdunused(struct filedesc *fdp, int fd)
/*
* Free a file descriptor.
+ *
+ * Avoid some work if fdp is about to be destroyed.
*/
static inline void
-fdfree(struct filedesc *fdp, int fd)
+_fdfree(struct filedesc *fdp, int fd, int last)
{
struct filedescent *fde;
fde = &fdp->fd_ofiles[fd];
filecaps_free(&fde->fde_caps);
+ if (last)
+ return;
bzero(fde, sizeof(*fde));
fdunused(fdp, fd);
}
+static inline void
+fdfree(struct filedesc *fdp, int fd)
+{
+
+ _fdfree(fdp, fd, 0);
+}
+
+static inline void
+fdfree_last(struct filedesc *fdp, int fd)
+{
+
+ _fdfree(fdp, fd, 1);
+}
+
/*
* System calls on descriptors.
*/
@@ -2044,36 +2062,32 @@ fdescfree(struct thread *td)
FILEDESC_XLOCK(fdp);
i = --fdp->fd_refcnt;
- FILEDESC_XUNLOCK(fdp);
- if (i > 0)
+ if (i > 0) {
+ FILEDESC_XUNLOCK(fdp);
return;
+ }
+
+ cdir = fdp->fd_cdir;
+ fdp->fd_cdir = NULL;
+ rdir = fdp->fd_rdir;
+ fdp->fd_rdir = NULL;
+ jdir = fdp->fd_jdir;
+ fdp->fd_jdir = NULL;
+ FILEDESC_XUNLOCK(fdp);
for (i = 0; i <= fdp->fd_lastfile; i++) {
fp = fdp->fd_ofiles[i].fde_file;
if (fp != NULL) {
- FILEDESC_XLOCK(fdp);
- fdfree(fdp, i);
- FILEDESC_XUNLOCK(fdp);
+ fdfree_last(fdp, i);
(void) closef(fp, td);
}
}
- FILEDESC_XLOCK(fdp);
if (fdp->fd_nfiles > NDFILE)
free(fdp->fd_ofiles, M_FILEDESC);
if (NDSLOTS(fdp->fd_nfiles) > NDSLOTS(NDFILE))
free(fdp->fd_map, M_FILEDESC);
- fdp->fd_nfiles = 0;
-
- cdir = fdp->fd_cdir;
- fdp->fd_cdir = NULL;
- rdir = fdp->fd_rdir;
- fdp->fd_rdir = NULL;
- jdir = fdp->fd_jdir;
- fdp->fd_jdir = NULL;
- FILEDESC_XUNLOCK(fdp);
-
if (cdir != NULL)
vrele(cdir);
if (rdir != NULL)
OpenPOWER on IntegriCloud