diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 154dbf8..e3efe8c 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -1323,8 +1323,17 @@ err_exit: int exec_alloc_args(struct image_args *args) { + void *buf; - args->buf = (char *)kmap_alloc_wait(exec_map, PATH_MAX + ARG_MAX); + critical_enter(); + if ((buf = PCPU_GET(execbuf)) == NULL) { + critical_exit(); + buf = (char *)kmap_alloc_wait(exec_map, PATH_MAX + ARG_MAX); + } else { + PCPU_SET(execbuf, NULL); + critical_exit(); + } + args->buf = buf; return (args->buf != NULL ? 0 : ENOMEM); } @@ -1333,8 +1342,15 @@ exec_free_args(struct image_args *args) { if (args->buf != NULL) { - kmap_free_wakeup(exec_map, (vm_offset_t)args->buf, - PATH_MAX + ARG_MAX); + critical_enter(); + if (PCPU_GET(execbuf) == NULL) { + PCPU_SET(execbuf, args->buf); + critical_exit(); + } else { + critical_exit(); + kmap_free_wakeup(exec_map, (vm_offset_t)args->buf, + PATH_MAX + ARG_MAX); + } args->buf = NULL; } if (args->fname_buf != NULL) { diff --git a/sys/sys/pcpu.h b/sys/sys/pcpu.h index d6d1b3d..a71ebd3 100644 --- a/sys/sys/pcpu.h +++ b/sys/sys/pcpu.h @@ -166,6 +166,7 @@ struct pcpu { int pc_domain; /* Memory domain. */ struct rm_queue pc_rm_queue; /* rmlock list of trackers */ uintptr_t pc_dynamic; /* Dynamic per-cpu data area */ + void *pc_execbuf; /* Buffer for exec args */ /* * Keep MD fields last, so that CPU-specific variations on a diff --git a/sys/vm/vm_init.c b/sys/vm/vm_init.c index e664585..0a50a5c 100644 --- a/sys/vm/vm_init.c +++ b/sys/vm/vm_init.c @@ -91,10 +91,6 @@ __FBSDID("$FreeBSD$"); long physmem; -static int exec_map_entries = 16; -SYSCTL_INT(_vm, OID_AUTO, exec_map_entries, CTLFLAG_RDTUN, &exec_map_entries, 0, - "Maximum number of simultaneous execs"); - /* * System initialization */ @@ -262,7 +258,11 @@ again: /* * Allocate the pageable submaps. + * + * One exec map entry may be cached per CPU. We must allocate at least + * ncpu+1 entries to avoid deadlock. */ + int exec_map_entries = mp_ncpus * 2; exec_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr, exec_map_entries * round_page(PATH_MAX + ARG_MAX), FALSE); pipe_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr, maxpipekva,