Hi list, after upgrade on OpenBSD 5.2 we observe the following message from ntpd:
Oct 22 17:20:13 gg74 ntpd[2918]: ntpd 4.2.6p2@1.2194-o 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.