LCOV - code coverage report
Current view: top level - misc/kabi/lvm2.git/lib/locking - file_locking.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 103 174 59.2 %
Date: 2010-04-13 Functions: 10 12 83.3 %
Branches: 48 116 41.4 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
       3                 :            :  * Copyright (C) 2004-2007 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 "locking.h"
      18                 :            : #include "locking_types.h"
      19                 :            : #include "activate.h"
      20                 :            : #include "config.h"
      21                 :            : #include "defaults.h"
      22                 :            : #include "lvm-file.h"
      23                 :            : #include "lvm-string.h"
      24                 :            : #include "lvmcache.h"
      25                 :            : 
      26                 :            : #include <limits.h>
      27                 :            : #include <unistd.h>
      28                 :            : #include <sys/stat.h>
      29                 :            : #include <sys/file.h>
      30                 :            : #include <fcntl.h>
      31                 :            : #include <signal.h>
      32                 :            : 
      33                 :            : struct lock_list {
      34                 :            :         struct dm_list list;
      35                 :            :         int lf;
      36                 :            :         char *res;
      37                 :            : };
      38                 :            : 
      39                 :            : static struct dm_list _lock_list;
      40                 :            : static char _lock_dir[NAME_LEN];
      41                 :            : static int _prioritise_write_locks;
      42                 :            : 
      43                 :            : static sig_t _oldhandler;
      44                 :            : static sigset_t _fullsigset, _intsigset;
      45                 :            : static volatile sig_atomic_t _handler_installed;
      46                 :            : 
      47                 :          2 : static void _undo_flock(const char *file, int fd)
      48                 :            : {
      49                 :            :         struct stat buf1, buf2;
      50                 :            : 
      51                 :          2 :         log_debug("_undo_flock %s", file);
      52 [ +  -  +  -  + :          6 :         if (!flock(fd, LOCK_NB | LOCK_EX) &&
                -  +  - ]
                 [ +  - ]
      53                 :          2 :             !stat(file, &buf1) &&
      54                 :          2 :             !fstat(fd, &buf2) &&
      55                 :          4 :             is_same_inode(buf1, buf2))
      56         [ -  + ]:          2 :                 if (unlink(file))
      57                 :          0 :                         log_sys_error("unlink", file);
      58                 :            : 
      59         [ -  + ]:          2 :         if (close(fd) < 0)
      60                 :          0 :                 log_sys_error("close", file);
      61                 :          2 : }
      62                 :            : 
      63                 :          2 : static int _release_lock(const char *file, int unlock)
      64                 :            : {
      65                 :            :         struct lock_list *ll;
      66                 :            :         struct dm_list *llh, *llt;
      67                 :            : 
      68         [ +  + ]:          2 :         dm_list_iterate_safe(llh, llt, &_lock_list) {
      69                 :          1 :                 ll = dm_list_item(llh, struct lock_list);
      70                 :            : 
      71 [ +  - ][ +  - ]:          1 :                 if (!file || !strcmp(ll->res, file)) {
      72                 :          1 :                         dm_list_del(llh);
      73         [ +  - ]:          1 :                         if (unlock) {
      74                 :          1 :                                 log_very_verbose("Unlocking %s", ll->res);
      75         [ -  + ]:          1 :                                 if (flock(ll->lf, LOCK_NB | LOCK_UN))
      76                 :          0 :                                         log_sys_error("flock", ll->res);
      77                 :            :                         }
      78                 :            : 
      79                 :          1 :                         _undo_flock(ll->res, ll->lf);
      80                 :            : 
      81                 :          1 :                         dm_free(ll->res);
      82                 :          1 :                         dm_free(llh);
      83                 :            : 
      84         [ +  - ]:          1 :                         if (file)
      85                 :          1 :                                 return 1;
      86                 :            :                 }
      87                 :            :         }
      88                 :            : 
      89                 :          2 :         return 0;
      90                 :            : }
      91                 :            : 
      92                 :          1 : static void _fin_file_locking(void)
      93                 :            : {
      94                 :          1 :         _release_lock(NULL, 1);
      95                 :          1 : }
      96                 :            : 
      97                 :          0 : static void _reset_file_locking(void)
      98                 :            : {
      99                 :          0 :         _release_lock(NULL, 0);
     100                 :          0 : }
     101                 :            : 
     102                 :          2 : static void _remove_ctrl_c_handler(void)
     103                 :            : {
     104                 :          2 :         siginterrupt(SIGINT, 0);
     105         [ -  + ]:          2 :         if (!_handler_installed)
     106                 :          0 :                 return;
     107                 :            : 
     108                 :          2 :         _handler_installed = 0;
     109                 :            : 
     110                 :          2 :         sigprocmask(SIG_SETMASK, &_fullsigset, NULL);
     111         [ -  + ]:          2 :         if (signal(SIGINT, _oldhandler) == SIG_ERR)
     112                 :          2 :                 log_sys_error("signal", "_remove_ctrl_c_handler");
     113                 :            : }
     114                 :            : 
     115                 :          0 : static void _trap_ctrl_c(int sig __attribute((unused)))
     116                 :            : {
     117                 :          0 :         _remove_ctrl_c_handler();
     118                 :          0 :         log_error("CTRL-c detected: giving up waiting for lock");
     119                 :          0 : }
     120                 :            : 
     121                 :          2 : static void _install_ctrl_c_handler()
     122                 :            : {
     123                 :          2 :         _handler_installed = 1;
     124                 :            : 
     125         [ -  + ]:          2 :         if ((_oldhandler = signal(SIGINT, _trap_ctrl_c)) == SIG_ERR) {
     126                 :          0 :                 _handler_installed = 0;
     127                 :          0 :                 return;
     128                 :            :         }
     129                 :            : 
     130                 :          2 :         sigprocmask(SIG_SETMASK, &_intsigset, NULL);
     131                 :          2 :         siginterrupt(SIGINT, 1);
     132                 :            : }
     133                 :            : 
     134                 :          2 : static int _do_flock(const char *file, int *fd, int operation, uint32_t nonblock)
     135                 :            : {
     136                 :          2 :         int r = 1;
     137                 :            :         int old_errno;
     138                 :            :         struct stat buf1, buf2;
     139                 :            : 
     140 [ -  + ][ +  + ]:          2 :         log_debug("_do_flock %s %c%c",
     141                 :            :                   file, operation == LOCK_EX ? 'W' : 'R', nonblock ? ' ' : 'B');
     142                 :            :         do {
     143 [ -  + ][ #  # ]:          2 :                 if ((*fd > -1) && close(*fd))
     144                 :          0 :                         log_sys_error("close", file);
     145                 :            : 
     146         [ -  + ]:          2 :                 if ((*fd = open(file, O_CREAT | O_APPEND | O_RDWR, 0777)) < 0) {
     147                 :          0 :                         log_sys_error("open", file);
     148                 :          0 :                         return 0;
     149                 :            :                 }
     150                 :            : 
     151         [ -  + ]:          2 :                 if (nonblock)
     152                 :          0 :                         operation |= LOCK_NB;
     153                 :            :                 else
     154                 :          2 :                         _install_ctrl_c_handler();
     155                 :            : 
     156                 :          2 :                 r = flock(*fd, operation);
     157                 :          2 :                 old_errno = errno;
     158         [ +  - ]:          2 :                 if (!nonblock)
     159                 :          2 :                         _remove_ctrl_c_handler();
     160                 :            : 
     161         [ -  + ]:          2 :                 if (r) {
     162                 :          0 :                         errno = old_errno;
     163                 :          0 :                         log_sys_error("flock", file);
     164                 :          0 :                         close(*fd);
     165                 :          0 :                         return 0;
     166                 :            :                 }
     167                 :            : 
     168 [ +  - ][ +  - ]:          2 :                 if (!stat(file, &buf1) && !fstat(*fd, &buf2) &&
         [ +  - ][ +  - ]
     169                 :          4 :                     is_same_inode(buf1, buf2))
     170                 :          2 :                         return 1;
     171         [ #  # ]:          0 :         } while (!nonblock);
     172                 :            : 
     173                 :          2 :         return_0;
     174                 :            : }
     175                 :            : 
     176                 :            : #define AUX_LOCK_SUFFIX ":aux"
     177                 :            : 
     178                 :          1 : static int _do_write_priority_flock(const char *file, int *fd, int operation, uint32_t nonblock)
     179                 :            : {
     180                 :          1 :         int r, fd_aux = -1;
     181                 :          1 :         char *file_aux = alloca(strlen(file) + sizeof(AUX_LOCK_SUFFIX));
     182                 :            : 
     183                 :          1 :         strcpy(file_aux, file);
     184                 :          1 :         strcat(file_aux, AUX_LOCK_SUFFIX);
     185                 :            : 
     186         [ +  - ]:          1 :         if ((r = _do_flock(file_aux, &fd_aux, LOCK_EX, 0))) {
     187         [ -  + ]:          1 :                 if (operation == LOCK_EX) {
     188                 :          0 :                         r = _do_flock(file, fd, operation, nonblock);
     189                 :          0 :                         _undo_flock(file_aux, fd_aux);
     190                 :            :                 } else {
     191                 :          1 :                         _undo_flock(file_aux, fd_aux);
     192                 :          1 :                         r = _do_flock(file, fd, operation, nonblock);
     193                 :            :                 }
     194                 :            :         }
     195                 :            : 
     196                 :          1 :         return r;
     197                 :            : }
     198                 :            : 
     199                 :          2 : static int _lock_file(const char *file, uint32_t flags)
     200                 :            : {
     201                 :            :         int operation;
     202                 :          2 :         uint32_t nonblock = flags & LCK_NONBLOCK;
     203                 :            :         int r;
     204                 :            : 
     205                 :            :         struct lock_list *ll;
     206                 :            :         char state;
     207                 :            : 
     208   [ +  -  +  - ]:          2 :         switch (flags & LCK_TYPE_MASK) {
     209                 :            :         case LCK_READ:
     210                 :          1 :                 operation = LOCK_SH;
     211                 :          1 :                 state = 'R';
     212                 :          1 :                 break;
     213                 :            :         case LCK_WRITE:
     214                 :          0 :                 operation = LOCK_EX;
     215                 :          0 :                 state = 'W';
     216                 :          0 :                 break;
     217                 :            :         case LCK_UNLOCK:
     218                 :          1 :                 return _release_lock(file, 1);
     219                 :            :         default:
     220                 :          0 :                 log_error("Unrecognised lock type: %d", flags & LCK_TYPE_MASK);
     221                 :          0 :                 return 0;
     222                 :            :         }
     223                 :            : 
     224         [ -  + ]:          1 :         if (!(ll = dm_malloc(sizeof(struct lock_list))))
     225                 :          0 :                 return_0;
     226                 :            : 
     227         [ -  + ]:          1 :         if (!(ll->res = dm_strdup(file))) {
     228                 :          0 :                 dm_free(ll);
     229                 :          0 :                 return_0;
     230                 :            :         }
     231                 :            : 
     232                 :          1 :         ll->lf = -1;
     233                 :            : 
     234         [ -  + ]:          1 :         log_very_verbose("Locking %s %c%c", ll->res, state,
     235                 :            :                          nonblock ? ' ' : 'B');
     236                 :            : 
     237         [ +  - ]:          1 :         if (_prioritise_write_locks)
     238                 :          1 :                 r = _do_write_priority_flock(file, &ll->lf, operation, nonblock);
     239                 :            :         else 
     240                 :          0 :                 r = _do_flock(file, &ll->lf, operation, nonblock);
     241                 :            : 
     242         [ +  - ]:          1 :         if (r)
     243                 :          1 :                 dm_list_add(&_lock_list, &ll->list);
     244                 :            :         else {
     245                 :          0 :                 dm_free(ll->res);
     246                 :          0 :                 dm_free(ll);
     247                 :          0 :                 stack;
     248                 :            :         }
     249                 :            : 
     250                 :          2 :         return r;
     251                 :            : }
     252                 :            : 
     253                 :          2 : static int _file_lock_resource(struct cmd_context *cmd, const char *resource,
     254                 :            :                                uint32_t flags)
     255                 :            : {
     256                 :            :         char lockfile[PATH_MAX];
     257                 :            : 
     258      [ +  -  - ]:          2 :         switch (flags & LCK_SCOPE_MASK) {
     259                 :            :         case LCK_VG:
     260                 :            :                 /* Skip cache refresh for VG_GLOBAL - the caller handles it */
     261         [ -  + ]:          2 :                 if (strcmp(resource, VG_GLOBAL))
     262                 :          0 :                         lvmcache_drop_metadata(resource, 0);
     263                 :            : 
     264                 :            :                 /* LCK_CACHE does not require a real lock */
     265         [ -  + ]:          2 :                 if (flags & LCK_CACHE)
     266                 :          0 :                         break;
     267                 :            : 
     268         [ +  - ]:          2 :                 if (*resource == '#')
     269                 :          2 :                         dm_snprintf(lockfile, sizeof(lockfile),
     270                 :            :                                      "%s/P_%s", _lock_dir, resource + 1);
     271                 :            :                 else
     272                 :          0 :                         dm_snprintf(lockfile, sizeof(lockfile),
     273                 :            :                                      "%s/V_%s", _lock_dir, resource);
     274                 :            : 
     275         [ -  + ]:          2 :                 if (!_lock_file(lockfile, flags))
     276                 :          0 :                         return_0;
     277                 :          2 :                 break;
     278                 :            :         case LCK_LV:
     279 [ #  #  #  #  # :          0 :                 switch (flags & LCK_TYPE_MASK) {
                   #  # ]
     280                 :            :                 case LCK_UNLOCK:
     281                 :          0 :                         log_very_verbose("Unlocking LV %s", resource);
     282         [ #  # ]:          0 :                         if (!lv_resume_if_active(cmd, resource))
     283                 :          0 :                                 return 0;
     284                 :          0 :                         break;
     285                 :            :                 case LCK_NULL:
     286                 :          0 :                         log_very_verbose("Locking LV %s (NL)", resource);
     287         [ #  # ]:          0 :                         if (!lv_deactivate(cmd, resource))
     288                 :          0 :                                 return 0;
     289                 :          0 :                         break;
     290                 :            :                 case LCK_READ:
     291                 :          0 :                         log_very_verbose("Locking LV %s (R)", resource);
     292         [ #  # ]:          0 :                         if (!lv_activate_with_filter(cmd, resource, 0))
     293                 :          0 :                                 return 0;
     294                 :          0 :                         break;
     295                 :            :                 case LCK_PREAD:
     296                 :          0 :                         log_very_verbose("Locking LV %s (PR) - ignored", resource);
     297                 :          0 :                         break;
     298                 :            :                 case LCK_WRITE:
     299                 :          0 :                         log_very_verbose("Locking LV %s (W)", resource);
     300         [ #  # ]:          0 :                         if (!lv_suspend_if_active(cmd, resource))
     301                 :          0 :                                 return 0;
     302                 :          0 :                         break;
     303                 :            :                 case LCK_EXCL:
     304                 :          0 :                         log_very_verbose("Locking LV %s (EX)", resource);
     305         [ #  # ]:          0 :                         if (!lv_activate_with_filter(cmd, resource, 1))
     306                 :          0 :                                 return 0;
     307                 :            :                         break;
     308                 :            :                 default:
     309                 :            :                         break;
     310                 :            :                 }
     311                 :          0 :                 break;
     312                 :            :         default:
     313                 :          0 :                 log_error("Unrecognised lock scope: %d",
     314                 :            :                           flags & LCK_SCOPE_MASK);
     315                 :          0 :                 return 0;
     316                 :            :         }
     317                 :            : 
     318                 :          2 :         return 1;
     319                 :            : }
     320                 :            : 
     321                 :          1 : int init_file_locking(struct locking_type *locking, struct cmd_context *cmd)
     322                 :            : {
     323                 :          1 :         locking->lock_resource = _file_lock_resource;
     324                 :          1 :         locking->reset_locking = _reset_file_locking;
     325                 :          1 :         locking->fin_locking = _fin_file_locking;
     326                 :          1 :         locking->flags = 0;
     327                 :            : 
     328                 :            :         /* Get lockfile directory from config file */
     329                 :          1 :         strncpy(_lock_dir, find_config_tree_str(cmd, "global/locking_dir",
     330                 :            :                                                 DEFAULT_LOCK_DIR),
     331                 :            :                 sizeof(_lock_dir));
     332                 :            : 
     333                 :          1 :         _prioritise_write_locks =
     334                 :          1 :             find_config_tree_bool(cmd, "global/prioritise_write_locks",
     335                 :            :                                   DEFAULT_PRIORITISE_WRITE_LOCKS);
     336                 :            : 
     337         [ -  + ]:          1 :         if (!dm_create_dir(_lock_dir))
     338                 :          0 :                 return 0;
     339                 :            : 
     340                 :            :         /* Trap a read-only file system */
     341 [ -  + ][ #  # ]:          1 :         if ((access(_lock_dir, R_OK | W_OK | X_OK) == -1) && (errno == EROFS))
     342                 :          0 :                 return 0;
     343                 :            : 
     344                 :          1 :         dm_list_init(&_lock_list);
     345                 :            : 
     346   [ +  -  -  + ]:          1 :         if (sigfillset(&_intsigset) || sigfillset(&_fullsigset)) {
     347                 :          0 :                 log_sys_error("sigfillset", "init_file_locking");
     348                 :          0 :                 return 0;
     349                 :            :         }
     350                 :            : 
     351         [ -  + ]:          1 :         if (sigdelset(&_intsigset, SIGINT)) {
     352                 :          0 :                 log_sys_error("sigdelset", "init_file_locking");
     353                 :          0 :                 return 0;
     354                 :            :         }
     355                 :            : 
     356                 :          1 :         return 1;
     357                 :            : }

Generated by: LCOV version 1.8