diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -71,6 +71,7 @@ #include #include #include +#include #include #include @@ -5193,8 +5194,59 @@ CTLFLAG_RWTUN | CTLFLAG_NOFETCH, &maxfilesperproc, 0, "Maximum files allowed open per process"); -SYSCTL_INT(_kern, KERN_MAXFILES, maxfiles, CTLFLAG_RWTUN | CTLFLAG_NOFETCH, - &maxfiles, 0, "Maximum number of files"); + +static u_int vnodes_to_files_leeway = 1000; + +SYSCTL_UINT(_debug, OID_AUTO, vnodes_to_files_leeway, + CTLFLAG_RWTUN | CTLFLAG_NOFETCH, + &vnodes_to_files_leeway, 0, "Vnodes reserved in excess of 'kern.maxfiles'"); + +void +clamp_and_set_maxfiles(int maxfiles_cand, vm_size_t pages) +{ + const vm_size_t maxfiles_clamp = pgtok(pages) / (1024 / 64); + const u_int leeway = vnodes_to_files_leeway; + int new_maxfiles = maxfiles_cand; + + /* 'desiredvnodes' is 0 at boot as 'maxfiles' is set before. */ + if (desiredvnodes != 0 && new_maxfiles + leeway > desiredvnodes) { + if (bootverbose) + printf("kern.maxfiles cannot exceed kern.maxvnodes, "); + new_maxfiles = imin(desiredvnodes, desiredvnodes - leeway); + } + + if (new_maxfiles > maxfiles_clamp) { + if (bootverbose) + printf("kern.maxfiles cannot exceed 64 files per MB, "); + new_maxfiles = maxfiles_clamp; + } + + if (maxfiles_cand > new_maxfiles) { + if (bootverbose) + printf("clamping to %d\n", new_maxfiles); + maxfiles_cand = new_maxfiles; + } + + maxfiles = maxfiles_cand; +} + +static int +sysctl_maxfiles(SYSCTL_HANDLER_ARGS) +{ + int error; + int tmp_maxfiles = maxfiles; + + error = sysctl_handle_int(oidp, &tmp_maxfiles, 0, req); + if (error != 0) + return (error); + + if (req->newptr != NULL) + clamp_and_set_maxfiles(tmp_maxfiles, vm_cnt.v_page_count); + return (error); +} + +SYSCTL_PROC(_kern, KERN_MAXFILES, maxfiles, CTLTYPE_INT | CTLFLAG_RWTUN | + CTLFLAG_NOFETCH, NULL, 0, &sysctl_maxfiles, "I", "Maximum number of files"); SYSCTL_INT(_kern, OID_AUTO, openfiles, CTLFLAG_RD, &openfiles, 0, "System-wide number of open files"); diff --git a/sys/kern/subr_param.c b/sys/kern/subr_param.c --- a/sys/kern/subr_param.c +++ b/sys/kern/subr_param.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -327,12 +328,7 @@ */ maxfiles = imax(MAXFILES, pgtok(physpages) / (1024 / 32)); TUNABLE_INT_FETCH("kern.maxfiles", &maxfiles); - { - const long maxfiles_clamp = pgtok(physpages) / (1024 / 64); - - if (maxfiles > maxfiles_clamp) - maxfiles = maxfiles_clamp; - } + clamp_and_set_maxfiles(maxfiles, physpages); maxfilesperproc = (maxfiles / 10) * 9; TUNABLE_INT_FETCH("kern.maxfilesperproc", &maxfilesperproc); diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -364,6 +364,7 @@ wantfreevnodes = desiredvnodes / 4; vnlru_recalc(); mtx_unlock(&vnode_list_mtx); + clamp_and_set_maxfiles(maxfiles, vm_cnt.v_page_count); /* * XXX There is no protection against multiple threads changing * desiredvnodes at the same time. Locking above only helps vnlru and @@ -778,6 +779,7 @@ desiredvnodes, MAXVNODES_MAX); desiredvnodes = MAXVNODES_MAX; } + clamp_and_set_maxfiles(maxfiles, vm_cnt.v_page_count); wantfreevnodes = desiredvnodes / 4; mtx_init(&mntid_mtx, "mntid", NULL, MTX_DEF); TAILQ_INIT(&vnode_list); diff --git a/sys/sys/file.h b/sys/sys/file.h --- a/sys/sys/file.h +++ b/sys/sys/file.h @@ -258,6 +258,8 @@ extern int maxfiles; /* kernel limit on number of open files */ extern int maxfilesperproc; /* per process limit on number of open files */ +void clamp_and_set_maxfiles(int maxfiles_cand, vm_size_t pages); + int fget(struct thread *td, int fd, cap_rights_t *rightsp, struct file **fpp); int fget_mmap(struct thread *td, int fd, cap_rights_t *rightsp, vm_prot_t *maxprotp, struct file **fpp);