summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbdrewery <bdrewery@FreeBSD.org>2014-03-02 16:25:56 +0000
committerbdrewery <bdrewery@FreeBSD.org>2014-03-02 16:25:56 +0000
commitee7a8407e1a8f9666ede2bfd3eaefecff7cc0d90 (patch)
tree54c1e9243d37b95b9f07bfc8522bcd95dd4fd2f4
parent1e9cbfb2bdf6972b7d65cbf64a616630bb5ab07e (diff)
downloadFreeBSD-src-ee7a8407e1a8f9666ede2bfd3eaefecff7cc0d90.zip
FreeBSD-src-ee7a8407e1a8f9666ede2bfd3eaefecff7cc0d90.tar.gz
MFC r262006,r262328:
r262006: Fix M_FILEDESC leak in fdgrowtable() introduced in r244510. fdgrowtable() now only reallocates fd_map when necessary. r262328: Style. Approved by: bapt (mentor, implicit)
-rw-r--r--sys/kern/kern_descrip.c32
1 files changed, 21 insertions, 11 deletions
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index 908de94..7fb39cc 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -1522,7 +1522,7 @@ fdgrowtable(struct filedesc *fdp, int nfd)
return;
/*
- * Allocate a new table and map. We need enough space for the
+ * Allocate a new table. We need enough space for the
* file entries themselves and the struct freetable we will use
* when we decommission the table and place it on the freelist.
* We place the struct freetable in the middle so we don't have
@@ -1530,16 +1530,22 @@ fdgrowtable(struct filedesc *fdp, int nfd)
*/
ntable = malloc(nnfiles * sizeof(ntable[0]) + sizeof(struct freetable),
M_FILEDESC, M_ZERO | M_WAITOK);
- nmap = malloc(NDSLOTS(nnfiles) * NDSLOTSIZE, M_FILEDESC,
- M_ZERO | M_WAITOK);
-
/* copy the old data over and point at the new tables */
memcpy(ntable, otable, onfiles * sizeof(*otable));
- memcpy(nmap, omap, NDSLOTS(onfiles) * sizeof(*omap));
-
- /* update the pointers and counters */
fdp->fd_ofiles = ntable;
- fdp->fd_map = nmap;
+
+ /*
+ * Allocate a new map only if the old is not large enough. It will
+ * grow at a slower rate than the table as it can map more
+ * entries than the table can hold.
+ */
+ if (NDSLOTS(nnfiles) > NDSLOTS(onfiles)) {
+ nmap = malloc(NDSLOTS(nnfiles) * NDSLOTSIZE, M_FILEDESC,
+ M_ZERO | M_WAITOK);
+ /* copy over the old data and update the pointer */
+ memcpy(nmap, omap, NDSLOTS(onfiles) * sizeof(*omap));
+ fdp->fd_map = nmap;
+ }
/*
* In order to have a valid pattern for fget_unlocked()
@@ -1555,8 +1561,6 @@ fdgrowtable(struct filedesc *fdp, int nfd)
* reference entries within it. Instead, place it on a freelist
* which will be processed when the struct filedesc is released.
*
- * Do, however, free the old map.
- *
* Note that if onfiles == NDFILE, we're dealing with the original
* static allocation contained within (struct filedesc0 *)fdp,
* which must not be freed.
@@ -1566,8 +1570,14 @@ fdgrowtable(struct filedesc *fdp, int nfd)
fdp0 = (struct filedesc0 *)fdp;
ft->ft_table = otable;
SLIST_INSERT_HEAD(&fdp0->fd_free, ft, ft_next);
- free(omap, M_FILEDESC);
}
+ /*
+ * The map does not have the same possibility of threads still
+ * holding references to it. So always free it as long as it
+ * does not reference the original static allocation.
+ */
+ if (NDSLOTS(onfiles) > NDSLOTS(NDFILE))
+ free(omap, M_FILEDESC);
}
/*
OpenPOWER on IntegriCloud