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 33void memlock_inc(void) 34{ 35 return; 36} 37void memlock_dec(void) 38{ 39 return; 40} 41int memlock(void) 42{ 43 return 0; 44} 45void memlock_init(struct cmd_context *cmd) 46{ 47 return; 48} 49 50#else /* DEVMAPPER_SUPPORT */ 51 52static size_t _size_stack; 53static size_t _size_malloc_tmp; 54static size_t _size_malloc = 2000000; 55 56static void *_malloc_mem = NULL; 57static int _memlock_count = 0; 58static int _memlock_count_daemon = 0; 59static int _priority; 60static int _default_priority; 61 62static 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 74static 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 90static void _release_memory(void) 91{ 92 free(_malloc_mem); 93} 94 95/* Stop memory getting swapped out */ 96static 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 115static 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 129static void _lock_mem_if_needed(void) { 130 if ((_memlock_count + _memlock_count_daemon) == 1) 131 _lock_mem(); 132} 133 134static void _unlock_mem_if_possible(void) { 135 if ((_memlock_count + _memlock_count_daemon) == 0) 136 _unlock_mem(); 137} 138 139void memlock_inc(void) 140{ 141 ++_memlock_count; 142 _lock_mem_if_needed(); 143 log_debug("memlock_count inc to %d", _memlock_count); 144} 145 146void 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 162void 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 169void 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 */ 184int memlock(void) 185{ 186 return _memlock_count; 187} 188 189void 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