1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-01-07 21:18:59 +03:00

activation: split priority from memory locking

When entering any critical section, lvm2 used to lock process memory
and raised task priority to avoid problem with page swapping and minimize
time of having non-resumed devices in table.

With this patch, memory locking which which is expensive is only used when
entering  'suspending' section as only in this section there is risk
lvm could be suspending a device which later can be needed for paging.

Raised priority is still kept for all section entrances as this is
low-cost operation and may accelerate table resumes - although the real
impact can be still considered later.
This commit is contained in:
Zdenek Kabelac 2017-12-01 11:50:14 +01:00
parent c489dd2e17
commit c086dfadc3
2 changed files with 67 additions and 33 deletions

View File

@ -1,5 +1,6 @@
Version 2.02.177 -
====================================
Command will lock memory only when suspending volumes.
Merge segments when pvmove is finished.
Remove label_verify that has never been used.
Ensure very large numbers used as arguments are not casted to lower values.

View File

@ -85,6 +85,7 @@ static size_t _size_malloc = 2000000;
static void *_malloc_mem = NULL;
static int _mem_locked = 0;
static int _priority_raised = 0;
static int _critical_section = 0;
static int _memlock_count_daemon = 0;
static int _priority;
@ -465,6 +466,38 @@ static int _restore_mmap(void)
#endif /* ARCH_X86 */
return 1;
}
static void _raise_priority(struct cmd_context *cmd)
{
if (_priority_raised)
return;
_priority_raised = 1;
errno = 0;
if (((_priority = getpriority(PRIO_PROCESS, 0)) == -1) && errno)
log_sys_debug("getpriority", "");
else if (_default_priority < _priority) {
if (setpriority(PRIO_PROCESS, 0, _default_priority) == 0)
log_debug_activation("Raised task priority %d -> %d.",
_priority, _default_priority);
else
log_warn("WARNING: setpriority %d failed: %s.",
_default_priority, strerror(errno));
}
}
static void _restore_priority_if_possible(struct cmd_context *cmd)
{
if (!_priority_raised || _critical_section || _memlock_count_daemon)
return;
if (setpriority(PRIO_PROCESS, 0, _priority) == 0)
log_debug_activation("Restoring original task priority %d.", _priority);
else
log_warn("WARNING: setpriority %u failed: %s.",
_priority, strerror(errno));
_priority_raised = 0;
}
/* Stop memory getting swapped out */
static void _lock_mem(struct cmd_context *cmd)
@ -502,14 +535,6 @@ static void _lock_mem(struct cmd_context *cmd)
if (!_memlock_maps(cmd, LVM_MLOCK, &_mstats))
stack;
errno = 0;
if (((_priority = getpriority(PRIO_PROCESS, 0)) == -1) && errno)
log_sys_error("getpriority", "");
else
if (setpriority(PRIO_PROCESS, 0, _default_priority))
log_error("setpriority %d failed: %s",
_default_priority, strerror(errno));
}
static void _unlock_mem(struct cmd_context *cmd)
@ -539,16 +564,15 @@ static void _unlock_mem(struct cmd_context *cmd)
}
}
if (setpriority(PRIO_PROCESS, 0, _priority))
log_error("setpriority %u failed: %s", _priority,
strerror(errno));
_restore_priority_if_possible(cmd);
_release_memory();
}
static void _lock_mem_if_needed(struct cmd_context *cmd)
{
log_debug_mem("Lock: Memlock counters: locked:%d critical:%d daemon:%d suspended:%d",
_mem_locked, _critical_section, _memlock_count_daemon, dm_get_suspended_counter());
log_debug_mem("Lock: Memlock counters: prioritized:%d locked:%d critical:%d daemon:%d suspended:%d",
_priority_raised, _mem_locked, _critical_section, _memlock_count_daemon, dm_get_suspended_counter());
if (!_mem_locked &&
((_critical_section + _memlock_count_daemon) == 1)) {
_mem_locked = 1;
@ -558,8 +582,8 @@ static void _lock_mem_if_needed(struct cmd_context *cmd)
static void _unlock_mem_if_possible(struct cmd_context *cmd)
{
log_debug_mem("Unlock: Memlock counters: locked:%d critical:%d daemon:%d suspended:%d",
_mem_locked, _critical_section, _memlock_count_daemon, dm_get_suspended_counter());
log_debug_mem("Unlock: Memlock counters: prioritized:%d locked:%d critical:%d daemon:%d suspended:%d",
_priority_raised, _mem_locked, _critical_section, _memlock_count_daemon, dm_get_suspended_counter());
if (_mem_locked &&
!_critical_section &&
!_memlock_count_daemon) {
@ -568,29 +592,41 @@ static void _unlock_mem_if_possible(struct cmd_context *cmd)
}
}
/*
* Critical section is only triggered with suspending reason.
* Other reasons only raise process priority so the table manipulation
* remains fast.
*
* Memory stays locked until 'memlock_unlock()' is called so when possible
* it may stay locked across multiple crictical section entrances.
*/
void critical_section_inc(struct cmd_context *cmd, const char *reason)
{
/*
* Profiles are loaded on-demand so make sure that before
* entering the critical section all needed profiles are
* loaded to avoid the disk access later.
*/
(void) load_pending_profiles(cmd);
if (!_critical_section) {
if (!_critical_section && (strcmp(reason, "suspending") == 0)) {
/*
* Profiles are loaded on-demand so make sure that before
* entering the critical section all needed profiles are
* loaded to avoid the disk access later.
*/
(void) load_pending_profiles(cmd);
_critical_section = 1;
log_debug_mem("Entering critical section (%s).", reason);
}
log_debug_activation("Entering critical section (%s).", reason);
_lock_mem_if_needed(cmd);
} else
log_debug_activation("Entering prioritized section (%s).", reason);
_lock_mem_if_needed(cmd);
_raise_priority(cmd);
}
void critical_section_dec(struct cmd_context *cmd, const char *reason)
{
if (_critical_section && !dm_get_suspended_counter()) {
_critical_section = 0;
log_debug_mem("Leaving critical section (%s).", reason);
}
log_debug_activation("Leaving critical section (%s).", reason);
} else
log_debug_activation("Leaving section (%s).", reason);
_restore_priority_if_possible(cmd);
}
int critical_section(void)
@ -612,6 +648,7 @@ void memlock_inc_daemon(struct cmd_context *cmd)
log_error(INTERNAL_ERROR "_memlock_inc_daemon used in critical section.");
log_debug_mem("memlock_count_daemon inc to %d", _memlock_count_daemon);
_lock_mem_if_needed(cmd);
_raise_priority(cmd);
}
void memlock_dec_daemon(struct cmd_context *cmd)
@ -620,11 +657,6 @@ void memlock_dec_daemon(struct cmd_context *cmd)
log_error(INTERNAL_ERROR "_memlock_count_daemon has dropped below 0.");
--_memlock_count_daemon;
log_debug_mem("memlock_count_daemon dec to %d", _memlock_count_daemon);
if (!_memlock_count_daemon && _critical_section && _mem_locked) {
log_error("Unlocking daemon memory in critical section.");
_unlock_mem(cmd);
_mem_locked = 0;
}
_unlock_mem_if_possible(cmd);
}
@ -641,6 +673,7 @@ void memlock_reset(void)
{
log_debug_mem("memlock reset.");
_mem_locked = 0;
_priority_raised = 0;
_critical_section = 0;
_memlock_count_daemon = 0;
}