Hi list, after upgrade on OpenBSD 5.2 we observe the following message from ntpd:
Oct 22 17:20:13 gg74 ntpd[2918]: ntpd [email protected] Tue Oct 16 20:26:47 UTC 2012 (1) Oct 22 17:20:13 gg74 ntpd[10103]: mlockall(): Cannot allocate memory Oct 22 17:20:13 gg74 ntpd[10103]: signal_no_reset: signal 13 had flags 12 Oct 22 17:20:13 gg74 ntpd[10103]: proto: precision = 6.390 usec ... This doesn't prevent ntpd from starting, however. We tried to debug this problem. This occurs when an application tries to set resource limits (more precisely, RLIMIT_MEMLOCK) to some relatively low value and then does mlockall(). The problem seems to be in uvm_map_pageable_all() function (sys/uvm/uvm_map.c). This function is a "special case of uvm_map_pageable", which tries to mlockall() all mapped memory regions. Prior to calling uvm_map_pageable_wire(), which actually does locking, it tries to count how many memory bytes will be locked, and compares this number with uvmexp.wiredmax, which is set by RLIMIT_MEMLOCK. The problem is that counting algorithm doesn't take into account that some pages have VM_PROT_NONE flag set and hence won't be locked anyway. Later in uvm_map_pageable_wire() these pages are skipped when doing actual job. Attached patch fixes the problem on OpenBSD 5.2. I'm also attaching a simple test application, that can be used to reproduce the bug. Just compile and run as root (otherwise mlockall() doesn't work anyway). On OpenBSD 5.2 the RLIMIT_MEMLOCK limit will be significantly higher than on OpenBSD 5.1. After applying my patch they will be almost the same. Thank you for your attention. // Ilya
--- /mount/blink/aegis/project/gg/history/os/src/sys/uvm/uvm_map.c 2012/10/17 12:56:27 1.58
+++ /mount/blink/aegis/project/gg/history/os/src/sys/uvm/uvm_map.c 2012/10/24 18:15:06 1.59
@@ -2207,7 +2207,8 @@ uvm_map_pageable_all(struct vm_map *map, int flags, vs
*/
size = 0;
RB_FOREACH(iter, uvm_map_addr, &map->addr) {
- if (VM_MAPENT_ISWIRED(iter) || UVM_ET_ISHOLE(iter))
+ if (VM_MAPENT_ISWIRED(iter) || UVM_ET_ISHOLE(iter)
+ || iter->protection == VM_PROT_NONE)
continue;
size += iter->end - iter->start;
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <err.h>
int
main(int argc, char **argv) {
printf("mlockall() test starting\n");
struct rlimit rl;
if (getrlimit(RLIMIT_MEMLOCK, &rl) == -1) {
err(1, "Cannot get RLIMIT_MEMLOCK");
}
printf("Current MLOCK limits: soft=%d, hard=%d\n",
rl.rlim_cur, rl.rlim_max);
uint32_t curlimit;
for (curlimit = 5140; curlimit < 1024 * 1024 * 1024; curlimit += 100) {
rl.rlim_cur = rl.rlim_max = curlimit;
if (setrlimit(RLIMIT_MEMLOCK, &rl) == -1) {
err(1, "limit=%d. Cannot set RLIMIT_MEMLOCK", curlimit);
}
if (mlockall(MCL_CURRENT|MCL_FUTURE) < 0) {
if (errno != ENOMEM) {
err(1, "Insufficient privs for mlockall()");
}
} else {
printf("limit=%d, Memory locked OK\n", curlimit);
break;
}
}
printf("Finished probing limits, last was %d\n", curlimit);
}
signature.asc
Description: This is a digitally signed message part.
