1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-03-10 16:58:47 +03:00

Fix memory lock imbalance in locking code.

(This affects only cluster locking because only cluster
locking module set LCK_PRE_MEMLOCK.)

With currect code you get
# vgchange -a n
  Internal error: _memlock_count has dropped below 0.
when using cluster locking.

It is caused by _unlock_memory calls here

  if ((flags & (LCK_SCOPE_MASK | LCK_TYPE_MASK)) == LCK_LV_RESUME)
     memlock_dec();

Unfortunately it is also (wrongly) called in immediate unlock
(when LCK_HOLD is not set) from lock_vol
(LCK_UNLOCK is misinterpreted as LCK_LV_RESUME).

Avoid this by comparing original flags and provide memlock
code type of operation (suspend/resume).
This commit is contained in:
Milan Broz 2009-11-23 10:55:14 +00:00
parent a4893bc377
commit 6b8304ab43
2 changed files with 29 additions and 9 deletions

View File

@ -1,5 +1,6 @@
Version 2.02.56 -
====================================
Fix memory lock imbalance in locking code.
Revert vg_read_internal change, clvmd cannot use vg_read now. (2.02.55)
Version 2.02.55 - 19th November 2009

View File

@ -42,6 +42,12 @@ static volatile sig_atomic_t _handler_installed;
static struct sigaction _oldhandler;
static int _oldmasked;
typedef enum {
LV_NOOP,
LV_SUSPEND,
LV_RESUME
} lv_operation_t;
static void _catch_sigint(int unused __attribute__((unused)))
{
_sigint_caught = 1;
@ -159,21 +165,21 @@ static void _unblock_signals(void)
return;
}
static void _lock_memory(uint32_t flags)
static void _lock_memory(lv_operation_t lv_op)
{
if (!(_locking.flags & LCK_PRE_MEMLOCK))
return;
if ((flags & (LCK_SCOPE_MASK | LCK_TYPE_MASK)) == LCK_LV_SUSPEND)
if (lv_op == LV_SUSPEND)
memlock_inc();
}
static void _unlock_memory(uint32_t flags)
static void _unlock_memory(lv_operation_t lv_op)
{
if (!(_locking.flags & LCK_PRE_MEMLOCK))
return;
if ((flags & (LCK_SCOPE_MASK | LCK_TYPE_MASK)) == LCK_LV_RESUME)
if (lv_op == LV_RESUME)
memlock_dec();
}
@ -336,12 +342,13 @@ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname)
* VG locking is by VG name.
* FIXME This should become VG uuid.
*/
static int _lock_vol(struct cmd_context *cmd, const char *resource, uint32_t flags)
static int _lock_vol(struct cmd_context *cmd, const char *resource,
uint32_t flags, lv_operation_t lv_op)
{
int ret = 0;
_block_signals(flags);
_lock_memory(flags);
_lock_memory(lv_op);
assert(resource);
@ -368,7 +375,7 @@ static int _lock_vol(struct cmd_context *cmd, const char *resource, uint32_t fla
_update_vg_lock_count(resource, flags);
}
_unlock_memory(flags);
_unlock_memory(lv_op);
_unblock_signals();
return ret;
@ -377,6 +384,18 @@ static int _lock_vol(struct cmd_context *cmd, const char *resource, uint32_t fla
int lock_vol(struct cmd_context *cmd, const char *vol, uint32_t flags)
{
char resource[258] __attribute((aligned(8)));
lv_operation_t lv_op;
switch (flags & (LCK_SCOPE_MASK | LCK_TYPE_MASK)) {
case LCK_LV_SUSPEND:
lv_op = LV_SUSPEND;
break;
case LCK_LV_RESUME:
lv_op = LV_RESUME;
break;
default: lv_op = LV_NOOP;
}
if (flags == LCK_NONE) {
log_debug("Internal error: %s: LCK_NONE lock requested", vol);
@ -416,7 +435,7 @@ int lock_vol(struct cmd_context *cmd, const char *vol, uint32_t flags)
strncpy(resource, vol, sizeof(resource));
if (!_lock_vol(cmd, resource, flags))
if (!_lock_vol(cmd, resource, flags, lv_op))
return 0;
/*
@ -426,7 +445,7 @@ int lock_vol(struct cmd_context *cmd, const char *vol, uint32_t flags)
if (!(flags & LCK_CACHE) && !(flags & LCK_HOLD) &&
((flags & LCK_TYPE_MASK) != LCK_UNLOCK)) {
if (!_lock_vol(cmd, resource,
(flags & ~LCK_TYPE_MASK) | LCK_UNLOCK))
(flags & ~LCK_TYPE_MASK) | LCK_UNLOCK, lv_op))
return 0;
}