LCOV - code coverage report
Current view: top level - misc/kabi/lvm2.git/lib/mm - memlock.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 7 148 4.7 %
Date: 2010-04-13 Functions: 2 15 13.3 %
Branches: 0 92 0.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
       3                 :            :  * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
       4                 :            :  *
       5                 :            :  * This file is part of LVM2.
       6                 :            :  *
       7                 :            :  * This copyrighted material is made available to anyone wishing to use,
       8                 :            :  * modify, copy, or redistribute it subject to the terms and conditions
       9                 :            :  * of the GNU Lesser General Public License v.2.1.
      10                 :            :  *
      11                 :            :  * You should have received a copy of the GNU Lesser General Public License
      12                 :            :  * along with this program; if not, write to the Free Software Foundation,
      13                 :            :  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      14                 :            :  */
      15                 :            : 
      16                 :            : #include "lib.h"
      17                 :            : #include "memlock.h"
      18                 :            : #include "defaults.h"
      19                 :            : #include "config.h"
      20                 :            : #include "toolcontext.h"
      21                 :            : 
      22                 :            : #include <limits.h>
      23                 :            : #include <fcntl.h>
      24                 :            : #include <unistd.h>
      25                 :            : #include <sys/mman.h>
      26                 :            : #include <sys/time.h>
      27                 :            : #include <sys/resource.h>
      28                 :            : 
      29                 :            : #ifndef DEVMAPPER_SUPPORT
      30                 :            : 
      31                 :            : void memlock_inc(struct cmd_context *cmd)
      32                 :            : {
      33                 :            :         return;
      34                 :            : }
      35                 :            : void memlock_dec(struct cmd_context *cmd)
      36                 :            : {
      37                 :            :         return;
      38                 :            : }
      39                 :            : int memlock(void)
      40                 :            : {
      41                 :            :         return 0;
      42                 :            : }
      43                 :            : void memlock_init(struct cmd_context *cmd)
      44                 :            : {
      45                 :            :         return;
      46                 :            : }
      47                 :            : 
      48                 :            : #else                           /* DEVMAPPER_SUPPORT */
      49                 :            : 
      50                 :            : static size_t _size_stack;
      51                 :            : static size_t _size_malloc_tmp;
      52                 :            : static size_t _size_malloc = 2000000;
      53                 :            : 
      54                 :            : static void *_malloc_mem = NULL;
      55                 :            : static int _memlock_count = 0;
      56                 :            : static int _memlock_count_daemon = 0;
      57                 :            : static int _priority;
      58                 :            : static int _default_priority;
      59                 :            : 
      60                 :            : /* list of maps, that are unconditionaly ignored */
      61                 :            : static const char * const _ignore_maps[] = {
      62                 :            :     "[vdso]",
      63                 :            :     "[vsyscall]",
      64                 :            : };
      65                 :            : 
      66                 :            : /* default blacklist for maps */
      67                 :            : static const char * const _blacklist_maps[] = {
      68                 :            :     "locale/locale-archive",
      69                 :            :     "gconv/gconv-modules.cache",
      70                 :            :     "/libreadline.so.",       /* not using readline during mlock */
      71                 :            :     "/libncurses.so.",        /* not using readline during mlock */
      72                 :            :     "/libdl-",                /* not using dlopen,dlsym during mlock */
      73                 :            :     /* "/libdevmapper-event.so" */
      74                 :            : };
      75                 :            : 
      76                 :            : typedef enum { LVM_MLOCK, LVM_MUNLOCK } lvmlock_t;
      77                 :            : 
      78                 :            : static unsigned _use_mlockall;
      79                 :            : static FILE *_mapsh;
      80                 :            : static char _procselfmaps[PATH_MAX] = "";
      81                 :            : #define SELF_MAPS "/self/maps"
      82                 :            : 
      83                 :            : static size_t _mstats; /* statistic for maps locking */
      84                 :            : 
      85                 :          0 : static void _touch_memory(void *mem, size_t size)
      86                 :            : {
      87                 :          0 :         size_t pagesize = lvm_getpagesize();
      88                 :          0 :         void *pos = mem;
      89                 :          0 :         void *end = mem + size - sizeof(long);
      90                 :            : 
      91         [ #  # ]:          0 :         while (pos < end) {
      92                 :          0 :                 *(long *) pos = 1;
      93                 :          0 :                 pos += pagesize;
      94                 :            :         }
      95                 :          0 : }
      96                 :            : 
      97                 :          0 : static void _allocate_memory(void)
      98                 :            : {
      99                 :            :         void *stack_mem, *temp_malloc_mem;
     100                 :            : 
     101                 :          0 :         if ((stack_mem = alloca(_size_stack)))
     102                 :          0 :                 _touch_memory(stack_mem, _size_stack);
     103                 :            : 
     104         [ #  # ]:          0 :         if ((temp_malloc_mem = malloc(_size_malloc_tmp)))
     105                 :          0 :                 _touch_memory(temp_malloc_mem, _size_malloc_tmp);
     106                 :            : 
     107         [ #  # ]:          0 :         if ((_malloc_mem = malloc(_size_malloc)))
     108                 :          0 :                 _touch_memory(_malloc_mem, _size_malloc);
     109                 :            : 
     110                 :          0 :         free(temp_malloc_mem);
     111                 :          0 : }
     112                 :            : 
     113                 :          0 : static void _release_memory(void)
     114                 :            : {
     115                 :          0 :         free(_malloc_mem);
     116                 :          0 : }
     117                 :            : 
     118                 :            : /*
     119                 :            :  * mlock/munlock memory areas from /proc/self/maps
     120                 :            :  * format described in kernel/Documentation/filesystem/proc.txt
     121                 :            :  */
     122                 :          0 : static int _maps_line(struct cmd_context *cmd, lvmlock_t lock,
     123                 :            :                       const char* line, size_t* mstats)
     124                 :            : {
     125                 :            :         const struct config_node *cn;
     126                 :            :         struct config_value *cv;
     127                 :            :         long from, to;
     128                 :            :         int pos, i;
     129                 :            :         char fr, fw, fx, fp;
     130                 :            :         size_t sz;
     131                 :            : 
     132         [ #  # ]:          0 :         if (sscanf(line, "%lx-%lx %c%c%c%c%n",
     133                 :            :                    &from, &to, &fr, &fw, &fx, &fp, &pos) != 6) {
     134                 :          0 :                 log_error("Failed to parse maps line: %s", line);
     135                 :          0 :                 return 0;
     136                 :            :         }
     137                 :            : 
     138                 :            :         /* Select readable maps */
     139         [ #  # ]:          0 :         if (fr != 'r') {
     140                 :          0 :                 log_debug("mlock area unreadable '%s': Skipping.", line);
     141                 :          0 :                 return 1;
     142                 :            :         }
     143                 :            : 
     144                 :            :         /* always ignored areas */
     145         [ #  # ]:          0 :         for (i = 0; i < sizeof(_ignore_maps) / sizeof(_ignore_maps[0]); ++i)
     146         [ #  # ]:          0 :                 if (strstr(line + pos, _ignore_maps[i])) {
     147                 :          0 :                         log_debug("mlock ignore filter '%s' matches '%s': Skipping.",
     148                 :            :                                   _ignore_maps[i], line);
     149                 :          0 :                         return 1;
     150                 :            :                 }
     151                 :            : 
     152                 :          0 :         sz = to - from;
     153         [ #  # ]:          0 :         if (!(cn = find_config_tree_node(cmd, "activation/mlock_filter"))) {
     154                 :            :                 /* If no blacklist configured, use an internal set */
     155         [ #  # ]:          0 :                 for (i = 0; i < sizeof(_blacklist_maps) / sizeof(_blacklist_maps[0]); ++i)
     156         [ #  # ]:          0 :                         if (strstr(line + pos, _blacklist_maps[i])) {
     157                 :          0 :                                 log_debug("mlock default filter '%s' matches '%s': Skipping.",
     158                 :            :                                           _blacklist_maps[i], line);
     159                 :          0 :                                 return 1;
     160                 :            :                         }
     161                 :            :         } else {
     162         [ #  # ]:          0 :                 for (cv = cn->v; cv; cv = cv->next) {
     163 [ #  # ][ #  # ]:          0 :                         if ((cv->type != CFG_STRING) || !cv->v.str[0])
     164                 :          0 :                                 continue;
     165         [ #  # ]:          0 :                         if (strstr(line + pos, cv->v.str)) {
     166                 :          0 :                                 log_debug("mlock_filter '%s' matches '%s': Skipping.",
     167                 :            :                                           cv->v.str, line);
     168                 :          0 :                                 return 1;
     169                 :            :                         }
     170                 :            :                 }
     171                 :            :         }
     172                 :            : 
     173                 :          0 :         *mstats += sz;
     174         [ #  # ]:          0 :         log_debug("%s %10ldKiB %12lx - %12lx %c%c%c%c %s",
     175                 :            :                   (lock == LVM_MLOCK) ? "mlock" : "munlock",
     176                 :            :                   ((long)sz + 1023) / 1024, from, to, fr, fw, fx, fp, line + pos);
     177                 :            : 
     178         [ #  # ]:          0 :         if (lock == LVM_MLOCK) {
     179         [ #  # ]:          0 :                 if (mlock((const void*)from, sz) < 0) {
     180                 :          0 :                         log_sys_error("mlock", line);
     181                 :          0 :                         return 0;
     182                 :            :                 }
     183                 :            :         } else {
     184         [ #  # ]:          0 :                 if (munlock((const void*)from, sz) < 0) {
     185                 :          0 :                         log_sys_error("munlock", line);
     186                 :          0 :                         return 0;
     187                 :            :                 }
     188                 :            :         }
     189                 :            : 
     190                 :          0 :         return 1;
     191                 :            : }
     192                 :            : 
     193                 :          0 : static int _memlock_maps(struct cmd_context *cmd, lvmlock_t lock, size_t *mstats)
     194                 :            : {
     195                 :          0 :         char *line = NULL;
     196                 :            :         size_t len;
     197                 :            :         ssize_t n;
     198                 :          0 :         int ret = 1;
     199                 :            : 
     200         [ #  # ]:          0 :         if (_use_mlockall) {
     201                 :            : #ifdef MCL_CURRENT
     202         [ #  # ]:          0 :                 if (lock == LVM_MLOCK) {
     203         [ #  # ]:          0 :                         if (mlockall(MCL_CURRENT | MCL_FUTURE)) {
     204                 :          0 :                                 log_sys_error("mlockall", "");
     205                 :          0 :                                 return 0;
     206                 :            :                         }
     207                 :            :                 } else {
     208         [ #  # ]:          0 :                         if (munlockall()) {
     209                 :          0 :                                 log_sys_error("munlockall", "");
     210                 :          0 :                                 return 0;
     211                 :            :                         }
     212                 :            :                 }
     213                 :          0 :                 return 1;
     214                 :            : #else
     215                 :            :                 return 0;
     216                 :            : #endif
     217                 :            :         }
     218                 :            : 
     219                 :            :         /* Reset statistic counters */
     220                 :          0 :         *mstats = 0;
     221                 :          0 :         rewind(_mapsh);
     222                 :            : 
     223         [ #  # ]:          0 :         while ((n = getline(&line, &len, _mapsh)) != -1) {
     224         [ #  # ]:          0 :                 line[n > 0 ? n - 1 : 0] = '\0'; /* remove \n */
     225         [ #  # ]:          0 :                 if (!_maps_line(cmd, lock, line, mstats))
     226                 :          0 :                         ret = 0;
     227                 :            :         }
     228                 :            : 
     229                 :          0 :         free(line);
     230                 :            : 
     231         [ #  # ]:          0 :         log_debug("%socked %ld bytes",
     232                 :            :                   (lock == LVM_MLOCK) ? "L" : "Unl", (long)*mstats);
     233                 :            : 
     234                 :          0 :         return ret;
     235                 :            : }
     236                 :            : 
     237                 :            : /* Stop memory getting swapped out */
     238                 :          0 : static void _lock_mem(struct cmd_context *cmd)
     239                 :            : {
     240                 :          0 :         _allocate_memory();
     241                 :            : 
     242                 :            :         /*
     243                 :            :          * For daemon we need to use mlockall()
     244                 :            :          * so even future adition of thread which may not even use lvm lib
     245                 :            :          * will not block memory locked thread
     246                 :            :          * Note: assuming _memlock_count_daemon is updated before _memlock_count
     247                 :            :          */
     248         [ #  # ]:          0 :         _use_mlockall = _memlock_count_daemon ? 1 :
     249                 :          0 :                 find_config_tree_bool(cmd, "activation/use_mlockall", DEFAULT_USE_MLOCKALL);
     250                 :            : 
     251         [ #  # ]:          0 :         if (!_use_mlockall) {
     252   [ #  #  #  # ]:          0 :                 if (!*_procselfmaps &&
     253                 :            :                     dm_snprintf(_procselfmaps, sizeof(_procselfmaps),
     254                 :          0 :                                 "%s" SELF_MAPS, cmd->proc_dir) < 0) {
     255                 :          0 :                         log_error("proc_dir too long");
     256                 :          0 :                         return;
     257                 :            :                 }
     258                 :            : 
     259         [ #  # ]:          0 :                 if (!(_mapsh = fopen(_procselfmaps, "r"))) {
     260                 :          0 :                         log_sys_error("fopen", _procselfmaps);
     261                 :          0 :                         return;
     262                 :            :                 }
     263                 :            :         }
     264                 :            : 
     265                 :          0 :         log_very_verbose("Locking memory");
     266         [ #  # ]:          0 :         if (!_memlock_maps(cmd, LVM_MLOCK, &_mstats))
     267                 :          0 :                 stack;
     268                 :            : 
     269                 :          0 :         errno = 0;
     270   [ #  #  #  # ]:          0 :         if (((_priority = getpriority(PRIO_PROCESS, 0)) == -1) && errno)
     271                 :          0 :                 log_sys_error("getpriority", "");
     272                 :            :         else
     273         [ #  # ]:          0 :                 if (setpriority(PRIO_PROCESS, 0, _default_priority))
     274                 :          0 :                         log_error("setpriority %d failed: %s",
     275                 :            :                                   _default_priority, strerror(errno));
     276                 :            : }
     277                 :            : 
     278                 :          0 : static void _unlock_mem(struct cmd_context *cmd)
     279                 :            : {
     280                 :            :         size_t unlock_mstats;
     281                 :            : 
     282                 :          0 :         log_very_verbose("Unlocking memory");
     283                 :            : 
     284         [ #  # ]:          0 :         if (!_memlock_maps(cmd, LVM_MUNLOCK, &unlock_mstats))
     285                 :          0 :                 stack;
     286                 :            : 
     287         [ #  # ]:          0 :         if (!_use_mlockall) {
     288         [ #  # ]:          0 :                 if (fclose(_mapsh))
     289                 :          0 :                         log_sys_error("fclose", _procselfmaps);
     290                 :            : 
     291         [ #  # ]:          0 :                 if (_mstats < unlock_mstats)
     292                 :          0 :                         log_error(INTERNAL_ERROR "Maps lock %ld < unlock %ld",
     293                 :            :                                   (long)_mstats, (long)unlock_mstats);
     294                 :            :         }
     295                 :            : 
     296         [ #  # ]:          0 :         if (setpriority(PRIO_PROCESS, 0, _priority))
     297                 :          0 :                 log_error("setpriority %u failed: %s", _priority,
     298                 :            :                           strerror(errno));
     299                 :          0 :         _release_memory();
     300                 :          0 : }
     301                 :            : 
     302                 :          0 : static void _lock_mem_if_needed(struct cmd_context *cmd)
     303                 :            : {
     304         [ #  # ]:          0 :         if ((_memlock_count + _memlock_count_daemon) == 1)
     305                 :          0 :                 _lock_mem(cmd);
     306                 :          0 : }
     307                 :            : 
     308                 :          0 : static void _unlock_mem_if_possible(struct cmd_context *cmd)
     309                 :            : {
     310         [ #  # ]:          0 :         if ((_memlock_count + _memlock_count_daemon) == 0)
     311                 :          0 :                 _unlock_mem(cmd);
     312                 :          0 : }
     313                 :            : 
     314                 :          0 : void memlock_inc(struct cmd_context *cmd)
     315                 :            : {
     316                 :          0 :         ++_memlock_count;
     317                 :          0 :         _lock_mem_if_needed(cmd);
     318                 :          0 :         log_debug("memlock_count inc to %d", _memlock_count);
     319                 :          0 : }
     320                 :            : 
     321                 :          0 : void memlock_dec(struct cmd_context *cmd)
     322                 :            : {
     323         [ #  # ]:          0 :         if (!_memlock_count)
     324                 :          0 :                 log_error(INTERNAL_ERROR "_memlock_count has dropped below 0.");
     325                 :          0 :         --_memlock_count;
     326                 :          0 :         _unlock_mem_if_possible(cmd);
     327                 :          0 :         log_debug("memlock_count dec to %d", _memlock_count);
     328                 :          0 : }
     329                 :            : 
     330                 :            : /*
     331                 :            :  * The memlock_*_daemon functions will force the mlockall() call that we need
     332                 :            :  * to stay in memory, but they will have no effect on device scans (unlike
     333                 :            :  * normal memlock_inc and memlock_dec). Memory is kept locked as long as either
     334                 :            :  * of memlock or memlock_daemon is in effect.
     335                 :            :  */
     336                 :            : 
     337                 :          0 : void memlock_inc_daemon(struct cmd_context *cmd)
     338                 :            : {
     339                 :          0 :         ++_memlock_count_daemon;
     340 [ #  # ][ #  # ]:          0 :         if (_memlock_count_daemon == 1 && _memlock_count > 0)
     341                 :          0 :                 log_error(INTERNAL_ERROR "_memlock_inc_daemon used after _memlock_inc.");
     342                 :          0 :         _lock_mem_if_needed(cmd);
     343                 :          0 :         log_debug("memlock_count_daemon inc to %d", _memlock_count_daemon);
     344                 :          0 : }
     345                 :            : 
     346                 :          0 : void memlock_dec_daemon(struct cmd_context *cmd)
     347                 :            : {
     348         [ #  # ]:          0 :         if (!_memlock_count_daemon)
     349                 :          0 :                 log_error(INTERNAL_ERROR "_memlock_count_daemon has dropped below 0.");
     350                 :          0 :         --_memlock_count_daemon;
     351                 :          0 :         _unlock_mem_if_possible(cmd);
     352                 :          0 :         log_debug("memlock_count_daemon dec to %d", _memlock_count_daemon);
     353                 :          0 : }
     354                 :            : 
     355                 :            : /*
     356                 :            :  * This disregards the daemon (dmeventd) locks, since we use memlock() to check
     357                 :            :  * whether it is safe to run a device scan, which would normally coincide with
     358                 :            :  * !memlock() -- but the daemon global memory lock breaks this assumption, so
     359                 :            :  * we do not take those into account here.
     360                 :            :  */
     361                 :          4 : int memlock(void)
     362                 :            : {
     363                 :          4 :         return _memlock_count;
     364                 :            : }
     365                 :            : 
     366                 :          1 : void memlock_init(struct cmd_context *cmd)
     367                 :            : {
     368                 :          1 :         _size_stack = find_config_tree_int(cmd,
     369                 :            :                                       "activation/reserved_stack",
     370                 :            :                                       DEFAULT_RESERVED_STACK) * 1024;
     371                 :          1 :         _size_malloc_tmp = find_config_tree_int(cmd,
     372                 :            :                                            "activation/reserved_memory",
     373                 :            :                                            DEFAULT_RESERVED_MEMORY) * 1024;
     374                 :          1 :         _default_priority = find_config_tree_int(cmd,
     375                 :            :                                             "activation/process_priority",
     376                 :            :                                             DEFAULT_PROCESS_PRIORITY);
     377                 :          1 : }
     378                 :            : 
     379                 :            : #endif

Generated by: LCOV version 1.8