Subject: Re: fdexpand() memory shortage check (Re: kern/14721)
To: Chuck Silvers <chuq@chuq.com>
From: Jaromir Dolecek <jdolecek@netbsd.org>
List: tech-kern
Date: 01/08/2002 22:05:42
--ELM716650414-2352-0_
Content-Transfer-Encoding: 7bit
Content-Type: text/plain; charset=US-ASCII
Chuck Silvers wrote:
> in the part of my previous mail after the part you quoted below,
> I explained how you can avoid using kmem_map space even for allocations
> smaller than a page. if you use that mechanism for allocating
> file descriptor structures, then there would not be any way to
> have problems with malloc() failing in this path. we should use
> that same mechanism for all memory allocations where we currently
> use malloc() to handle a variably-sized allocation but we don't need
> the interrupt-safe property.
Yes, it could be done using the pools, but it feels a bit icky to
me. It doesn't seem to be possible to stick this into current
malloc(9) and I don't think it's very reasonable to add completely
new nointr subpage allocator. Given these practical considerations,
it seems best to just use malloc() (and thus kmem_map) for <PAGE_SIZE
size, and uvm_km_alloc() for >= PAGE_SIZE.
I'm appending patch which does just this. It also adds change to kill
the program if memory allocation for file descriptor array fails.
Opinions?
Jaromir
--
Jaromir Dolecek <jdolecek@NetBSD.org> http://www.NetBSD.org/Ports/i386/ps2.html
-= Those who would give up liberty for a little temporary safety deserve =-
-= neither liberty nor safety, and will lose both. -- Benjamin Franklin =-
--ELM716650414-2352-0_
Content-Transfer-Encoding: 7bit
Content-Type: text/plain; charset=ISO-8859-2
Content-Disposition: attachment; filename=fdexp.diff
Index: kern_descrip.c
===================================================================
RCS file: /cvsroot/syssrc/sys/kern/kern_descrip.c,v
retrieving revision 1.83
diff -u -p -r1.83 kern_descrip.c
--- kern_descrip.c 2001/12/07 07:09:29 1.83
+++ kern_descrip.c 2002/01/08 21:01:45
@@ -61,6 +61,7 @@ __KERNEL_RCSID(0, "$NetBSD: kern_descrip
#include <sys/unistd.h>
#include <sys/resourcevar.h>
#include <sys/conf.h>
+#include <sys/wait.h>
#include <sys/mount.h>
#include <sys/syscallargs.h>
@@ -642,6 +643,7 @@ fdexpand(struct proc *p)
int i, nfiles;
struct file **newofile;
char *newofileflags;
+ vsize_t len;
fdp = p->p_fd;
@@ -649,21 +651,39 @@ fdexpand(struct proc *p)
nfiles = NDEXTENT;
else
nfiles = 2 * fdp->fd_nfiles;
- newofile = malloc(nfiles * OFILESIZE, M_FILEDESC, M_WAITOK);
+
+ if (__predict_true((len = nfiles * OFILESIZE) < PAGE_SIZE))
+ newofile = malloc(len, M_FILEDESC, M_WAITOK|M_CANFAIL|M_ZERO);
+ else {
+ newofile = (struct file **) uvm_km_alloc(kernel_map,
+ round_page(len));
+ }
+
+ if (__predict_false(newofile == NULL)) {
+ int uid = p->p_cred && p->p_ucred ? p->p_ucred->cr_uid : -1;
+ log(LOG_INFO, "pid %d (%s), uid %d: fdexpand() to %d files failed, process killed",
+ p->p_pid, p->p_comm, uid, nfiles);
+ exit1(p, W_EXITCODE(0, SIGKILL));
+ /* NOTREACHED */
+ }
+
newofileflags = (char *) &newofile[nfiles];
/*
- * Copy the existing ofile and ofileflags arrays
- * and zero the new portion of each array.
+ * Copy the existing ofile and ofileflags arrays.
+ * The new portion of each array were zeroed above.
*/
memcpy(newofile, fdp->fd_ofiles,
- (i = sizeof(struct file *) * fdp->fd_nfiles));
- memset((char *)newofile + i, 0,
- nfiles * sizeof(struct file *) - i);
+ (i = sizeof(struct file *) * fdp->fd_nfiles));
memcpy(newofileflags, fdp->fd_ofileflags,
(i = sizeof(char) * fdp->fd_nfiles));
- memset(newofileflags + i, 0, nfiles * sizeof(char) - i);
- if (fdp->fd_nfiles > NDFILE)
- free(fdp->fd_ofiles, M_FILEDESC);
+ if (fdp->fd_nfiles > NDFILE) {
+ if (__predict_true((fdp->fd_nfiles * OFILESIZE) < PAGE_SIZE))
+ free(fdp->fd_ofiles, M_FILEDESC);
+ else {
+ uvm_km_free(kernel_map, (vaddr_t) fdp->fd_ofiles,
+ round_page(fdp->fd_nfiles * OFILESIZE));
+ }
+ }
fdp->fd_ofiles = newofile;
fdp->fd_ofileflags = newofileflags;
fdp->fd_nfiles = nfiles;
--ELM716650414-2352-0_--