1 /* $NetBSD: memlock.c,v 1.1.1.2 2009/12/02 00:26:25 haad Exp $ */ 2 3 /* 4 * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved. 5 * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. 6 * 7 * This file is part of LVM2. 8 * 9 * This copyrighted material is made available to anyone wishing to use, 10 * modify, copy, or redistribute it subject to the terms and conditions 11 * of the GNU Lesser General Public License v.2.1. 12 * 13 * You should have received a copy of the GNU Lesser General Public License 14 * along with this program; if not, write to the Free Software Foundation, 15 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 16 */ 17 18 #include "lib.h" 19 #include "memlock.h" 20 #include "defaults.h" 21 #include "config.h" 22 #include "toolcontext.h" 23 24 #include <limits.h> 25 #include <fcntl.h> 26 #include <unistd.h> 27 #include <sys/mman.h> 28 #include <sys/time.h> 29 #include <sys/resource.h> 30 31 #ifndef DEVMAPPER_SUPPORT 32 33 void memlock_inc(void) 34 { 35 return; 36 } 37 void memlock_dec(void) 38 { 39 return; 40 } 41 int memlock(void) 42 { 43 return 0; 44 } 45 void memlock_init(struct cmd_context *cmd) 46 { 47 return; 48 } 49 50 #else /* DEVMAPPER_SUPPORT */ 51 52 static size_t _size_stack; 53 static size_t _size_malloc_tmp; 54 static size_t _size_malloc = 2000000; 55 56 static void *_malloc_mem = NULL; 57 static int _memlock_count = 0; 58 static int _memlock_count_daemon = 0; 59 static int _priority; 60 static int _default_priority; 61 62 static void _touch_memory(void *mem, size_t size) 63 { 64 size_t pagesize = lvm_getpagesize(); 65 void *pos = mem; 66 void *end = mem + size - sizeof(long); 67 68 while (pos < end) { 69 *(long *) pos = 1; 70 pos += pagesize; 71 } 72 } 73 74 static void _allocate_memory(void) 75 { 76 void *stack_mem, *temp_malloc_mem; 77 78 if ((stack_mem = alloca(_size_stack))) 79 _touch_memory(stack_mem, _size_stack); 80 81 if ((temp_malloc_mem = malloc(_size_malloc_tmp))) 82 _touch_memory(temp_malloc_mem, _size_malloc_tmp); 83 84 if ((_malloc_mem = malloc(_size_malloc))) 85 _touch_memory(_malloc_mem, _size_malloc); 86 87 free(temp_malloc_mem); 88 } 89 90 static void _release_memory(void) 91 { 92 free(_malloc_mem); 93 } 94 95 /* Stop memory getting swapped out */ 96 static void _lock_mem(void) 97 { 98 #ifdef MCL_CURRENT 99 if (mlockall(MCL_CURRENT | MCL_FUTURE)) 100 log_sys_error("mlockall", ""); 101 else 102 log_very_verbose("Locking memory"); 103 #endif 104 _allocate_memory(); 105 106 errno = 0; 107 if (((_priority = getpriority(PRIO_PROCESS, 0)) == -1) && errno) 108 log_sys_error("getpriority", ""); 109 else 110 if (setpriority(PRIO_PROCESS, 0, _default_priority)) 111 log_error("setpriority %d failed: %s", 112 _default_priority, strerror(errno)); 113 } 114 115 static void _unlock_mem(void) 116 { 117 #ifdef MCL_CURRENT 118 if (munlockall()) 119 log_sys_error("munlockall", ""); 120 else 121 log_very_verbose("Unlocking memory"); 122 #endif 123 _release_memory(); 124 if (setpriority(PRIO_PROCESS, 0, _priority)) 125 log_error("setpriority %u failed: %s", _priority, 126 strerror(errno)); 127 } 128 129 static void _lock_mem_if_needed(void) { 130 if ((_memlock_count + _memlock_count_daemon) == 1) 131 _lock_mem(); 132 } 133 134 static void _unlock_mem_if_possible(void) { 135 if ((_memlock_count + _memlock_count_daemon) == 0) 136 _unlock_mem(); 137 } 138 139 void memlock_inc(void) 140 { 141 ++_memlock_count; 142 _lock_mem_if_needed(); 143 log_debug("memlock_count inc to %d", _memlock_count); 144 } 145 146 void memlock_dec(void) 147 { 148 if (!_memlock_count) 149 log_error("Internal error: _memlock_count has dropped below 0."); 150 --_memlock_count; 151 _unlock_mem_if_possible(); 152 log_debug("memlock_count dec to %d", _memlock_count); 153 } 154 155 /* 156 * The memlock_*_daemon functions will force the mlockall() call that we need 157 * to stay in memory, but they will have no effect on device scans (unlike 158 * normal memlock_inc and memlock_dec). Memory is kept locked as long as either 159 * of memlock or memlock_daemon is in effect. 160 */ 161 162 void memlock_inc_daemon(void) 163 { 164 ++_memlock_count_daemon; 165 _lock_mem_if_needed(); 166 log_debug("memlock_count_daemon inc to %d", _memlock_count_daemon); 167 } 168 169 void memlock_dec_daemon(void) 170 { 171 if (!_memlock_count_daemon) 172 log_error("Internal error: _memlock_count_daemon has dropped below 0."); 173 --_memlock_count_daemon; 174 _unlock_mem_if_possible(); 175 log_debug("memlock_count_daemon dec to %d", _memlock_count_daemon); 176 } 177 178 /* 179 * This disregards the daemon (dmeventd) locks, since we use memlock() to check 180 * whether it is safe to run a device scan, which would normally coincide with 181 * !memlock() -- but the daemon global memory lock breaks this assumption, so 182 * we do not take those into account here. 183 */ 184 int memlock(void) 185 { 186 return _memlock_count; 187 } 188 189 void memlock_init(struct cmd_context *cmd) 190 { 191 _size_stack = find_config_tree_int(cmd, 192 "activation/reserved_stack", 193 DEFAULT_RESERVED_STACK) * 1024; 194 _size_malloc_tmp = find_config_tree_int(cmd, 195 "activation/reserved_memory", 196 DEFAULT_RESERVED_MEMORY) * 1024; 197 _default_priority = find_config_tree_int(cmd, 198 "activation/process_priority", 199 DEFAULT_PROCESS_PRIORITY); 200 } 201 202 #endif 203