1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

dev-cache: fix mem corruption on refresh context

When lvm2 command works with clvmd and uses locking in wrong way,
it may 'leak' certain file descriptors in opened (incorrect) state.

dev_cache_exit then destroys memory pool of cached devices, while
_open_devices list in dev-io.c was still referencing them if they
were still opened.

Patch properly calls _close() function to 'self-heal' from this
invalid state, but it will report internal error (so execution
with abort_on_internal_error causes immediate death). On the
normal 'execution', error is only reported, but memory state is
corrected, and linked list is not referencing devices from
released mempool.

For crash see: https://bugzilla.redhat.com/show_bug.cgi?id=1073886
This commit is contained in:
Zdenek Kabelac 2014-03-25 10:53:42 +01:00
parent d29fe919e6
commit 68d13b2517
4 changed files with 31 additions and 9 deletions

View File

@ -1,5 +1,6 @@
Version 2.02.106 - Version 2.02.106 -
==================================== ====================================
Fix memory corruption in cmd context refresh if clvmd leaks opened device.
Reinitialise lvmcache properly on fork to fix premature polldaemon exit. Reinitialise lvmcache properly on fork to fix premature polldaemon exit.
Add 'lvm dumpconfig --type diff' to show differences from defaults. Add 'lvm dumpconfig --type diff' to show differences from defaults.
Fix swap signature detection for devices smaller then 2MB. Fix swap signature detection for devices smaller then 2MB.

View File

@ -1604,7 +1604,8 @@ int refresh_toolcontext(struct cmd_context *cmd)
cmd->filter->destroy(cmd->filter); cmd->filter->destroy(cmd->filter);
cmd->filter = NULL; cmd->filter = NULL;
} }
dev_cache_exit(); if (!dev_cache_exit())
stack;
_destroy_dev_types(cmd); _destroy_dev_types(cmd);
_destroy_tags(cmd); _destroy_tags(cmd);

View File

@ -760,21 +760,38 @@ int dev_cache_init(struct cmd_context *cmd)
return 0; return 0;
} }
static void _check_closed(struct device *dev) static int _check_for_open_devices(int close_immediate)
{ {
if (dev->fd >= 0) struct device *dev;
log_error("Device '%s' has been left open.", dev_name(dev)); struct dm_hash_node *n;
int r = 0;
dm_hash_iterate(n, _cache.names) {
dev = (struct device *) dm_hash_get_data(_cache.names, n);
if (dev->fd >= 0) {
log_error("Device '%s' has been left open (%d).",
dev_name(dev), dev->open_count);
r++;
if (close_immediate)
dev_close_immediate(dev);
}
} }
static void _check_for_open_devices(void) return r;
{
dm_hash_iter(_cache.names, (dm_hash_iterate_fn) _check_closed);
} }
void dev_cache_exit(void) int dev_cache_check_for_open_devices(void)
{ {
return _check_for_open_devices(0);
}
int dev_cache_exit(void)
{
int cnt = 0;
if (_cache.names) if (_cache.names)
_check_for_open_devices(); if ((cnt = _check_for_open_devices(1)) > 0)
log_error(INTERNAL_ERROR "%d device(s) have been closed.", cnt);
if (_cache.preferred_names_matcher) if (_cache.preferred_names_matcher)
_cache.preferred_names_matcher = NULL; _cache.preferred_names_matcher = NULL;
@ -793,6 +810,8 @@ void dev_cache_exit(void)
_cache.has_scanned = 0; _cache.has_scanned = 0;
dm_list_init(&_cache.dirs); dm_list_init(&_cache.dirs);
dm_list_init(&_cache.files); dm_list_init(&_cache.files);
return (cnt == 0);
} }
int dev_cache_add_dir(const char *path) int dev_cache_add_dir(const char *path)

View File

@ -36,7 +36,8 @@ struct dev_filter {
*/ */
struct cmd_context; struct cmd_context;
int dev_cache_init(struct cmd_context *cmd); int dev_cache_init(struct cmd_context *cmd);
void dev_cache_exit(void); int dev_cache_check_for_open_devices(void);
int dev_cache_exit(void);
/* Trigger(1) or avoid(0) a scan */ /* Trigger(1) or avoid(0) a scan */
void dev_cache_scan(int do_scan); void dev_cache_scan(int do_scan);