diff options
-rw-r--r-- | lib/commands/toolcontext.c | 9 | ||||
-rw-r--r-- | lib/config/config.c | 3 | ||||
-rw-r--r-- | lib/metadata/thin_manip.c | 2 | ||||
-rw-r--r-- | libdm/libdevmapper.h | 75 | ||||
-rw-r--r-- | libdm/libdm-deptree.c | 724 |
5 files changed, 393 insertions, 420 deletions
diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c index 16c6d228e..3a5beb923 100644 --- a/lib/commands/toolcontext.c +++ b/lib/commands/toolcontext.c @@ -620,7 +620,6 @@ static struct dm_config_tree *_destroy_tag_configs(struct cmd_context *cmd) struct config_tree_list *cfl; struct dm_config_tree *cft_cmdline = NULL, *cft; -// FIXME No need for this - only one config tree now cft = dm_config_remove_cascaded_tree(cmd->cft); if (cft) { cft_cmdline = cmd->cft; @@ -1452,7 +1451,7 @@ int refresh_toolcontext(struct cmd_context *cmd) } dev_cache_exit(); _destroy_tags(cmd); -// FIXME Use cmd->cft_cmdline instead here. + cft_cmdline = _destroy_tag_configs(cmd); cmd->config_valid = 0; @@ -1465,7 +1464,6 @@ int refresh_toolcontext(struct cmd_context *cmd) /* Temporary duplicate cft pointer holding lvm.conf - replaced later */ cft_tmp = cmd->cft; if (cft_cmdline) -// FIXME Use cmd->cft_cmdline (convert string to cft again?) and merge instead cmd->cft = dm_config_insert_cascaded_tree(cft_cmdline, cft_tmp); /* Uses cmd->cft i.e. cft_cmdline + lvm.conf */ @@ -1479,15 +1477,11 @@ int refresh_toolcontext(struct cmd_context *cmd) if (!_init_tag_configs(cmd)) return 0; -// FIXME Will need to use a fresh copy of the lvm.conf cft as the original -// FIXME got destroyed when cft_cmdline was merged into it /* Merge all the tag config files with lvm.conf, returning a * fresh cft pointer in place of cft_tmp. */ if (!(cmd->cft = _merge_config_files(cmd, cft_tmp))) return 0; -// FIXME Merge instead - but keep a clean copy of cmd->cft at this point -// FIXME so we can easily 'remove' the effect of cft_cmdline after each cmd /* Finally we can make the proper, fully-merged, cmd->cft */ if (cft_cmdline) cmd->cft = dm_config_insert_cascaded_tree(cft_cmdline, cmd->cft); @@ -1539,7 +1533,6 @@ void destroy_toolcontext(struct cmd_context *cmd) dev_cache_exit(); _destroy_tags(cmd); -// FIXME destroy_tag_configs handles this itself again if ((cft_cmdline = _destroy_tag_configs(cmd))) dm_config_destroy(cft_cmdline); if (cmd->libmem) diff --git a/lib/config/config.c b/lib/config/config.c index aa99321be..27abb1aa6 100644 --- a/lib/config/config.c +++ b/lib/config/config.c @@ -160,7 +160,6 @@ void config_file_destroy(struct dm_config_tree *cft) */ struct dm_config_tree *remove_overridden_config_tree(struct cmd_context *cmd) { -// FIXME Replace cmd->cft with clean copy of merged lvm*.conf tree struct dm_config_tree *old_cft = cmd->cft; struct dm_config_tree *cft = dm_config_remove_cascaded_tree(cmd->cft); @@ -172,8 +171,6 @@ struct dm_config_tree *remove_overridden_config_tree(struct cmd_context *cmd) return old_cft; } -// FIXME Retain a copy of the string (or tree?) in cmd->cft_cmdline -// FIXME and merge into cmd->cft int override_config_tree_from_string(struct cmd_context *cmd, const char *config_settings) { diff --git a/lib/metadata/thin_manip.c b/lib/metadata/thin_manip.c index ef54b020f..e6a8dd748 100644 --- a/lib/metadata/thin_manip.c +++ b/lib/metadata/thin_manip.c @@ -234,7 +234,7 @@ uint32_t get_free_pool_device_id(struct lv_segment *thin_pool_seg) max_id = sl->seg->device_id; if (++max_id > DM_THIN_MAX_DEVICE_ID) { - // FIXME: try to find empty holes.... + /* FIXME Find empty holes instead of aborting! */ log_error("Cannot find free device_id."); return 0; } diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h index 851e57843..4ebee2fb5 100644 --- a/libdm/libdevmapper.h +++ b/libdm/libdevmapper.h @@ -1337,26 +1337,26 @@ int dm_report_field_uint64(struct dm_report *rh, struct dm_report_field *field, void dm_report_field_set_value(struct dm_report_field *field, const void *value, const void *sortvalue); - /************************* * config file parse/print *************************/ -// FIXME AGK Review this interface before inclusion in a release. -enum { - DM_CFG_STRING, - DM_CFG_FLOAT, +typedef enum { DM_CFG_INT, + DM_CFG_FLOAT, + DM_CFG_STRING, DM_CFG_EMPTY_ARRAY -}; +} dm_config_value_type_t; struct dm_config_value { - int type; + dm_config_value_type_t type; + union { int64_t i; float f; - double d; /* For completeness. (Unused.) */ + double d; /* Unused. */ const char *str; } v; + struct dm_config_value *next; /* For arrays */ }; @@ -1366,7 +1366,6 @@ struct dm_config_node { struct dm_config_value *v; }; -/* FIXME Move cascade to dm_config_node and remove this struct */ struct dm_config_tree { struct dm_config_node *root; struct dm_config_tree *cascade; @@ -1382,22 +1381,22 @@ void *dm_config_get_custom(struct dm_config_tree *cft); void dm_config_set_custom(struct dm_config_tree *cft, void *custom); /* - * If there's a cascaded dm_config_tree, remove the top layer - * and return the layer below. Otherwise return NULL. + * When searching, first_cft is checked before second_cft. */ -struct dm_config_tree *dm_config_remove_cascaded_tree(struct dm_config_tree *cft); +struct dm_config_tree *dm_config_insert_cascaded_tree(struct dm_config_tree *first_cft, struct dm_config_tree *second_cft); /* - * When searching, first_cft is checked before second_cft. + * If there's a cascaded dm_config_tree, remove the top layer + * and return the layer below. Otherwise return NULL. */ -struct dm_config_tree *dm_config_insert_cascaded_tree(struct dm_config_tree *first_cft, struct dm_config_tree *second_cft); +struct dm_config_tree *dm_config_remove_cascaded_tree(struct dm_config_tree *cft); void dm_config_destroy(struct dm_config_tree *cft); typedef int (*dm_putline_fn)(const char *line, void *baton); int dm_config_write_node(const struct dm_config_node *cn, dm_putline_fn putline, void *baton); -struct dm_config_node *dm_config_find_node(struct dm_config_node *cn, const char *path); +struct dm_config_node *dm_config_find_node(const struct dm_config_node *cn, const char *path); int dm_config_has_node(const struct dm_config_node *cn, const char *path); const char *dm_config_find_str(const struct dm_config_node *cn, const char *path, const char *fail); const char *dm_config_find_str_allow_empty(const struct dm_config_node *cn, const char *path, const char *fail); @@ -1405,18 +1404,12 @@ int dm_config_find_int(const struct dm_config_node *cn, const char *path, int fa float dm_config_find_float(const struct dm_config_node *cn, const char *path, float fail); const struct dm_config_node *dm_config_tree_find_node(const struct dm_config_tree *cft, const char *path); -const char *dm_config_tree_find_str(const struct dm_config_tree *cft, - const char *path, const char *fail); -const char *dm_config_tree_find_str_allow_empty(const struct dm_config_tree *cft, - const char *path, const char *fail); -int dm_config_tree_find_int(const struct dm_config_tree *cft, - const char *path, int fail); -int64_t dm_config_tree_find_int64(const struct dm_config_tree *cft, - const char *path, int64_t fail); -float dm_config_tree_find_float(const struct dm_config_tree *cft, - const char *path, float fail); -int dm_config_tree_find_bool(const struct dm_config_tree *cft, - const char *path, int fail); +const char *dm_config_tree_find_str(const struct dm_config_tree *cft, const char *path, const char *fail); +const char *dm_config_tree_find_str_allow_empty(const struct dm_config_tree *cft, const char *path, const char *fail); +int dm_config_tree_find_int(const struct dm_config_tree *cft, const char *path, int fail); +int64_t dm_config_tree_find_int64(const struct dm_config_tree *cft, const char *path, int64_t fail); +float dm_config_tree_find_float(const struct dm_config_tree *cft, const char *path, float fail); +int dm_config_tree_find_bool(const struct dm_config_tree *cft, const char *path, int fail); /* * Understands (0, ~0), (y, n), (yes, no), (on, @@ -1424,36 +1417,25 @@ int dm_config_tree_find_bool(const struct dm_config_tree *cft, */ int dm_config_find_bool(const struct dm_config_node *cn, const char *path, int fail); -int dm_config_get_uint32(const struct dm_config_node *cn, const char *path, - uint32_t *result); - -int dm_config_get_uint64(const struct dm_config_node *cn, const char *path, - uint64_t *result); - -int dm_config_get_str(const struct dm_config_node *cn, const char *path, - const char **result); -int dm_config_get_list(const struct dm_config_node *cn, const char *path, - const struct dm_config_value **result); -int dm_config_get_section(const struct dm_config_node *cn, const char *path, - const struct dm_config_node **result); +int dm_config_get_uint32(const struct dm_config_node *cn, const char *path, uint32_t *result); +int dm_config_get_uint64(const struct dm_config_node *cn, const char *path, uint64_t *result); +int dm_config_get_str(const struct dm_config_node *cn, const char *path, const char **result); +int dm_config_get_list(const struct dm_config_node *cn, const char *path, const struct dm_config_value **result); +int dm_config_get_section(const struct dm_config_node *cn, const char *path, const struct dm_config_node **result); unsigned dm_config_maybe_section(const char *str, unsigned len); const char *dm_config_parent_name(const struct dm_config_node *n); -struct dm_config_node *dm_config_clone_node_with_mem(struct dm_pool *mem, - const struct dm_config_node *node, - int siblings); +struct dm_config_node *dm_config_clone_node_with_mem(struct dm_pool *mem, const struct dm_config_node *node, int siblings); struct dm_config_node *dm_config_create_node(struct dm_config_tree *cft, const char *key); struct dm_config_value *dm_config_create_value(struct dm_config_tree *cft); -struct dm_config_node *dm_config_clone_node(struct dm_config_tree *cft, - const struct dm_config_node *cn, - int siblings); +struct dm_config_node *dm_config_clone_node(struct dm_config_tree *cft, const struct dm_config_node *cn, int siblings); struct dm_pool *dm_config_memory(struct dm_config_tree *cft); - /* Cookie prefixes. + * * The cookie value consists of a prefix (16 bits) and a base (16 bits). * We can use the prefix to store the flags. These flags are sent to * kernel within given dm task. When returned back to userspace in @@ -1461,6 +1443,7 @@ struct dm_pool *dm_config_memory(struct dm_config_tree *cft); * of udev rules we use by decoding the cookie prefix. When doing the * notification, we replace the cookie prefix with DM_COOKIE_MAGIC, * so we notify the right semaphore. + * * It is still possible to use cookies for passing the flags to udev * rules even when udev_sync is disabled. The base part of the cookie * will be zero (there's no notification semaphore) and prefix will be diff --git a/libdm/libdm-deptree.c b/libdm/libdm-deptree.c index fb7a119f7..1581f35e5 100644 --- a/libdm/libdm-deptree.c +++ b/libdm/libdm-deptree.c @@ -276,6 +276,9 @@ struct dm_tree { uint32_t cookie; }; +/* + * Tree functions. + */ struct dm_tree *dm_tree_create(void) { struct dm_pool *dmem; @@ -322,6 +325,34 @@ void dm_tree_free(struct dm_tree *dtree) dm_pool_destroy(dtree->mem); } +void dm_tree_set_cookie(struct dm_tree_node *node, uint32_t cookie) +{ + node->dtree->cookie = cookie; +} + +uint32_t dm_tree_get_cookie(struct dm_tree_node *node) +{ + return node->dtree->cookie; +} + +void dm_tree_skip_lockfs(struct dm_tree_node *dnode) +{ + dnode->dtree->skip_lockfs = 1; +} + +void dm_tree_use_no_flush_suspend(struct dm_tree_node *dnode) +{ + dnode->dtree->no_flush = 1; +} + +void dm_tree_retry_remove(struct dm_tree_node *dnode) +{ + dnode->dtree->retry_remove = 1; +} + +/* + * Node functions. + */ static int _nodes_are_linked(const struct dm_tree_node *parent, const struct dm_tree_node *child) { @@ -500,332 +531,6 @@ static struct dm_tree_node *_find_dm_tree_node_by_uuid(struct dm_tree *dtree, return dm_hash_lookup(dtree->uuids, uuid + default_uuid_prefix_len); } -static int _deps(struct dm_task **dmt, struct dm_pool *mem, uint32_t major, uint32_t minor, - const char **name, const char **uuid, unsigned inactive_table, - struct dm_info *info, struct dm_deps **deps) -{ - memset(info, 0, sizeof(*info)); - - if (!dm_is_dm_major(major)) { - if (name) - *name = ""; - if (uuid) - *uuid = ""; - *deps = NULL; - info->major = major; - info->minor = minor; - info->exists = 0; - info->live_table = 0; - info->inactive_table = 0; - info->read_only = 0; - return 1; - } - - if (!(*dmt = dm_task_create(DM_DEVICE_DEPS))) { - log_error("deps dm_task creation failed"); - return 0; - } - - if (!dm_task_set_major(*dmt, major)) { - log_error("_deps: failed to set major for (%" PRIu32 ":%" PRIu32 ")", - major, minor); - goto failed; - } - - if (!dm_task_set_minor(*dmt, minor)) { - log_error("_deps: failed to set minor for (%" PRIu32 ":%" PRIu32 ")", - major, minor); - goto failed; - } - - if (inactive_table && !dm_task_query_inactive_table(*dmt)) { - log_error("_deps: failed to set inactive table for (%" PRIu32 ":%" PRIu32 ")", - major, minor); - goto failed; - } - - if (!dm_task_run(*dmt)) { - log_error("_deps: task run failed for (%" PRIu32 ":%" PRIu32 ")", - major, minor); - goto failed; - } - - if (!dm_task_get_info(*dmt, info)) { - log_error("_deps: failed to get info for (%" PRIu32 ":%" PRIu32 ")", - major, minor); - goto failed; - } - - if (!info->exists) { - if (name) - *name = ""; - if (uuid) - *uuid = ""; - *deps = NULL; - } else { - if (info->major != major) { - log_error("Inconsistent dtree major number: %u != %u", - major, info->major); - goto failed; - } - if (info->minor != minor) { - log_error("Inconsistent dtree minor number: %u != %u", - minor, info->minor); - goto failed; - } - if (name && !(*name = dm_pool_strdup(mem, dm_task_get_name(*dmt)))) { - log_error("name pool_strdup failed"); - goto failed; - } - if (uuid && !(*uuid = dm_pool_strdup(mem, dm_task_get_uuid(*dmt)))) { - log_error("uuid pool_strdup failed"); - goto failed; - } - *deps = dm_task_get_deps(*dmt); - } - - return 1; - -failed: - dm_task_destroy(*dmt); - return 0; -} - -static struct dm_tree_node *_add_dev(struct dm_tree *dtree, - struct dm_tree_node *parent, - uint32_t major, uint32_t minor, - uint16_t udev_flags) -{ - struct dm_task *dmt = NULL; - struct dm_info info; - struct dm_deps *deps = NULL; - const char *name = NULL; - const char *uuid = NULL; - struct dm_tree_node *node = NULL; - uint32_t i; - int new = 0; - - /* Already in tree? */ - if (!(node = _find_dm_tree_node(dtree, major, minor))) { - if (!_deps(&dmt, dtree->mem, major, minor, &name, &uuid, 0, &info, &deps)) - return_NULL; - - if (!(node = _create_dm_tree_node(dtree, name, uuid, &info, - NULL, udev_flags))) - goto_out; - new = 1; - } - - if (!_link_tree_nodes(parent, node)) { - node = NULL; - goto_out; - } - - /* If node was already in tree, no need to recurse. */ - if (!new) - goto out; - - /* Can't recurse if not a mapped device or there are no dependencies */ - if (!node->info.exists || !deps->count) { - if (!_add_to_bottomlevel(node)) { - stack; - node = NULL; - } - goto out; - } - - /* Add dependencies to tree */ - for (i = 0; i < deps->count; i++) - if (!_add_dev(dtree, node, MAJOR(deps->device[i]), - MINOR(deps->device[i]), udev_flags)) { - node = NULL; - goto_out; - } - -out: - if (dmt) - dm_task_destroy(dmt); - - return node; -} - -// FIXME Move fn group down. -static int _info_by_dev(uint32_t major, uint32_t minor, int with_open_count, - struct dm_info *info, struct dm_pool *mem, - const char **name, const char **uuid); -static int _deactivate_node(const char *name, uint32_t major, uint32_t minor, - uint32_t *cookie, uint16_t udev_flags, int retry); -static int _node_clear_table(struct dm_tree_node *dnode, uint16_t udev_flags) -{ - struct dm_task *dmt = NULL, *deps_dmt = NULL; - struct dm_info *info, deps_info; - struct dm_deps *deps = NULL; - const char *name, *uuid; - const char *default_uuid_prefix; - size_t default_uuid_prefix_len; - uint32_t i; - int r = 0; - - if (!(info = &dnode->info)) { - log_error("_node_clear_table failed: missing info"); - return 0; - } - - if (!(name = dm_tree_node_get_name(dnode))) { - log_error("_node_clear_table failed: missing name"); - return 0; - } - - /* Is there a table? */ - if (!info->exists || !info->inactive_table) - return 1; - - /* Get devices used by inactive table that's about to be deleted. */ - if (!_deps(&deps_dmt, dnode->dtree->mem, info->major, info->minor, NULL, NULL, 1, info, &deps)) { - log_error("Failed to obtain dependencies for %s before clearing table.", name); - return 0; - } - - log_verbose("Clearing inactive table %s (%" PRIu32 ":%" PRIu32 ")", - name, info->major, info->minor); - - if (!(dmt = dm_task_create(DM_DEVICE_CLEAR))) { - log_error("Table clear dm_task creation failed for %s", name); - goto_out; - } - - if (!dm_task_set_major(dmt, info->major) || - !dm_task_set_minor(dmt, info->minor)) { - log_error("Failed to set device number for %s table clear", name); - goto_out; - } - - r = dm_task_run(dmt); - - if (!dm_task_get_info(dmt, info)) { - log_error("_node_clear_table failed: info missing after running task for %s", name); - r = 0; - } - - if (!r || !deps) - goto_out; - - /* - * Remove (incomplete) devices that the inactive table referred to but - * which are not in the tree, no longer referenced and don't have a live - * table. - */ - default_uuid_prefix = dm_uuid_prefix(); - default_uuid_prefix_len = strlen(default_uuid_prefix); - - for (i = 0; i < deps->count; i++) { - /* If already in tree, assume it's under control */ - if (_find_dm_tree_node(dnode->dtree, MAJOR(deps->device[i]), MINOR(deps->device[i]))) - continue; - - if (!_info_by_dev(MAJOR(deps->device[i]), MINOR(deps->device[i]), 1, - &deps_info, dnode->dtree->mem, &name, &uuid)) - continue; - - /* Proceed if device is an 'orphan' - unreferenced and without a live table. */ - if (!deps_info.exists || deps_info.live_table || deps_info.open_count) - continue; - - if (strncmp(uuid, default_uuid_prefix, default_uuid_prefix_len)) - continue; - - /* Remove device. */ - if (!_deactivate_node(name, deps_info.major, deps_info.minor, &dnode->dtree->cookie, udev_flags, 0)) { - log_error("Failed to deactivate no-longer-used device %s (%" - PRIu32 ":%" PRIu32 ")", name, deps_info.major, deps_info.minor); - } else if (deps_info.suspended) - dec_suspended(); - } - -out: - if (dmt) - dm_task_destroy(dmt); - - if (deps_dmt) - dm_task_destroy(deps_dmt); - - return r; -} - -struct dm_tree_node *dm_tree_add_new_dev_with_udev_flags(struct dm_tree *dtree, - const char *name, - const char *uuid, - uint32_t major, - uint32_t minor, - int read_only, - int clear_inactive, - void *context, - uint16_t udev_flags) -{ - struct dm_tree_node *dnode; - struct dm_info info; - const char *name2; - const char *uuid2; - - /* Do we need to add node to tree? */ - if (!(dnode = dm_tree_find_node_by_uuid(dtree, uuid))) { - if (!(name2 = dm_pool_strdup(dtree->mem, name))) { - log_error("name pool_strdup failed"); - return NULL; - } - if (!(uuid2 = dm_pool_strdup(dtree->mem, uuid))) { - log_error("uuid pool_strdup failed"); - return NULL; - } - - info.major = 0; - info.minor = 0; - info.exists = 0; - info.live_table = 0; - info.inactive_table = 0; - info.read_only = 0; - - if (!(dnode = _create_dm_tree_node(dtree, name2, uuid2, &info, - context, 0))) - return_NULL; - - /* Attach to root node until a table is supplied */ - if (!_add_to_toplevel(dnode) || !_add_to_bottomlevel(dnode)) - return_NULL; - - dnode->props.major = major; - dnode->props.minor = minor; - dnode->props.new_name = NULL; - dnode->props.size_changed = 0; - } else if (strcmp(name, dnode->name)) { - /* Do we need to rename node? */ - if (!(dnode->props.new_name = dm_pool_strdup(dtree->mem, name))) { - log_error("name pool_strdup failed"); - return NULL; - } - } - - dnode->props.read_only = read_only ? 1 : 0; - dnode->props.read_ahead = DM_READ_AHEAD_AUTO; - dnode->props.read_ahead_flags = 0; - - if (clear_inactive && !_node_clear_table(dnode, udev_flags)) - return_NULL; - - dnode->context = context; - dnode->udev_flags = udev_flags; - - return dnode; -} - -struct dm_tree_node *dm_tree_add_new_dev(struct dm_tree *dtree, const char *name, - const char *uuid, uint32_t major, uint32_t minor, - int read_only, int clear_inactive, void *context) -{ - return dm_tree_add_new_dev_with_udev_flags(dtree, name, uuid, major, minor, - read_only, clear_inactive, context, 0); -} - void dm_tree_node_set_udev_flags(struct dm_tree_node *dnode, uint16_t udev_flags) { @@ -853,17 +558,6 @@ void dm_tree_node_set_presuspend_node(struct dm_tree_node *node, node->presuspend_node = presuspend_node; } -int dm_tree_add_dev(struct dm_tree *dtree, uint32_t major, uint32_t minor) -{ - return _add_dev(dtree, &dtree->root, major, minor, 0) ? 1 : 0; -} - -int dm_tree_add_dev_with_udev_flags(struct dm_tree *dtree, uint32_t major, - uint32_t minor, uint16_t udev_flags) -{ - return _add_dev(dtree, &dtree->root, major, minor, udev_flags) ? 1 : 0; -} - const char *dm_tree_node_get_name(const struct dm_tree_node *node) { return node->info.exists ? node->name : ""; @@ -1031,6 +725,97 @@ struct dm_tree_node *dm_tree_next_child(void **handle, return (*dlink) ? dm_list_item(*dlink, struct dm_tree_link)->node : NULL; } +static int _deps(struct dm_task **dmt, struct dm_pool *mem, uint32_t major, uint32_t minor, + const char **name, const char **uuid, unsigned inactive_table, + struct dm_info *info, struct dm_deps **deps) +{ + memset(info, 0, sizeof(*info)); + + if (!dm_is_dm_major(major)) { + if (name) + *name = ""; + if (uuid) + *uuid = ""; + *deps = NULL; + info->major = major; + info->minor = minor; + info->exists = 0; + info->live_table = 0; + info->inactive_table = 0; + info->read_only = 0; + return 1; + } + + if (!(*dmt = dm_task_create(DM_DEVICE_DEPS))) { + log_error("deps dm_task creation failed"); + return 0; + } + + if (!dm_task_set_major(*dmt, major)) { + log_error("_deps: failed to set major for (%" PRIu32 ":%" PRIu32 ")", + major, minor); + goto failed; + } + + if (!dm_task_set_minor(*dmt, minor)) { + log_error("_deps: failed to set minor for (%" PRIu32 ":%" PRIu32 ")", + major, minor); + goto failed; + } + + if (inactive_table && !dm_task_query_inactive_table(*dmt)) { + log_error("_deps: failed to set inactive table for (%" PRIu32 ":%" PRIu32 ")", + major, minor); + goto failed; + } + + if (!dm_task_run(*dmt)) { + log_error("_deps: task run failed for (%" PRIu32 ":%" PRIu32 ")", + major, minor); + goto failed; + } + + if (!dm_task_get_info(*dmt, info)) { + log_error("_deps: failed to get info for (%" PRIu32 ":%" PRIu32 ")", + major, minor); + goto failed; + } + + if (!info->exists) { + if (name) + *name = ""; + if (uuid) + *uuid = ""; + *deps = NULL; + } else { + if (info->major != major) { + log_error("Inconsistent dtree major number: %u != %u", + major, info->major); + goto failed; + } + if (info->minor != minor) { + log_error("Inconsistent dtree minor number: %u != %u", + minor, info->minor); + goto failed; + } + if (name && !(*name = dm_pool_strdup(mem, dm_task_get_name(*dmt)))) { + log_error("name pool_strdup failed"); + goto failed; + } + if (uuid && !(*uuid = dm_pool_strdup(mem, dm_task_get_uuid(*dmt)))) { + log_error("uuid pool_strdup failed"); + goto failed; + } + *deps = dm_task_get_deps(*dmt); + } + + return 1; + +failed: + dm_task_destroy(*dmt); + return 0; +} + /* * Deactivate a device with its dependencies if the uuid prefix matches. */ @@ -1193,6 +978,246 @@ out: return r; } +static int _node_clear_table(struct dm_tree_node *dnode, uint16_t udev_flags) +{ + struct dm_task *dmt = NULL, *deps_dmt = NULL; + struct dm_info *info, deps_info; + struct dm_deps *deps = NULL; + const char *name, *uuid; + const char *default_uuid_prefix; + size_t default_uuid_prefix_len; + uint32_t i; + int r = 0; + + if (!(info = &dnode->info)) { + log_error("_node_clear_table failed: missing info"); + return 0; + } + + if (!(name = dm_tree_node_get_name(dnode))) { + log_error("_node_clear_table failed: missing name"); + return 0; + } + + /* Is there a table? */ + if (!info->exists || !info->inactive_table) + return 1; + + /* Get devices used by inactive table that's about to be deleted. */ + if (!_deps(&deps_dmt, dnode->dtree->mem, info->major, info->minor, NULL, NULL, 1, info, &deps)) { + log_error("Failed to obtain dependencies for %s before clearing table.", name); + return 0; + } + + log_verbose("Clearing inactive table %s (%" PRIu32 ":%" PRIu32 ")", + name, info->major, info->minor); + + if (!(dmt = dm_task_create(DM_DEVICE_CLEAR))) { + log_error("Table clear dm_task creation failed for %s", name); + goto_out; + } + + if (!dm_task_set_major(dmt, info->major) || + !dm_task_set_minor(dmt, info->minor)) { + log_error("Failed to set device number for %s table clear", name); + goto_out; + } + + r = dm_task_run(dmt); + + if (!dm_task_get_info(dmt, info)) { + log_error("_node_clear_table failed: info missing after running task for %s", name); + r = 0; + } + + if (!r || !deps) + goto_out; + + /* + * Remove (incomplete) devices that the inactive table referred to but + * which are not in the tree, no longer referenced and don't have a live + * table. + */ + default_uuid_prefix = dm_uuid_prefix(); + default_uuid_prefix_len = strlen(default_uuid_prefix); + + for (i = 0; i < deps->count; i++) { + /* If already in tree, assume it's under control */ + if (_find_dm_tree_node(dnode->dtree, MAJOR(deps->device[i]), MINOR(deps->device[i]))) + continue; + + if (!_info_by_dev(MAJOR(deps->device[i]), MINOR(deps->device[i]), 1, + &deps_info, dnode->dtree->mem, &name, &uuid)) + continue; + + /* Proceed if device is an 'orphan' - unreferenced and without a live table. */ + if (!deps_info.exists || deps_info.live_table || deps_info.open_count) + continue; + + if (strncmp(uuid, default_uuid_prefix, default_uuid_prefix_len)) + continue; + + /* Remove device. */ + if (!_deactivate_node(name, deps_info.major, deps_info.minor, &dnode->dtree->cookie, udev_flags, 0)) { + log_error("Failed to deactivate no-longer-used device %s (%" + PRIu32 ":%" PRIu32 ")", name, deps_info.major, deps_info.minor); + } else if (deps_info.suspended) + dec_suspended(); + } + +out: + if (dmt) + dm_task_destroy(dmt); + + if (deps_dmt) + dm_task_destroy(deps_dmt); + + return r; +} + +struct dm_tree_node *dm_tree_add_new_dev_with_udev_flags(struct dm_tree *dtree, + const char *name, + const char *uuid, + uint32_t major, + uint32_t minor, + int read_only, + int clear_inactive, + void *context, + uint16_t udev_flags) +{ + struct dm_tree_node *dnode; + struct dm_info info; + const char *name2; + const char *uuid2; + + /* Do we need to add node to tree? */ + if (!(dnode = dm_tree_find_node_by_uuid(dtree, uuid))) { + if (!(name2 = dm_pool_strdup(dtree->mem, name))) { + log_error("name pool_strdup failed"); + return NULL; + } + if (!(uuid2 = dm_pool_strdup(dtree->mem, uuid))) { + log_error("uuid pool_strdup failed"); + return NULL; + } + + info.major = 0; + info.minor = 0; + info.exists = 0; + info.live_table = 0; + info.inactive_table = 0; + info.read_only = 0; + + if (!(dnode = _create_dm_tree_node(dtree, name2, uuid2, &info, + context, 0))) + return_NULL; + + /* Attach to root node until a table is supplied */ + if (!_add_to_toplevel(dnode) || !_add_to_bottomlevel(dnode)) + return_NULL; + + dnode->props.major = major; + dnode->props.minor = minor; + dnode->props.new_name = NULL; + dnode->props.size_changed = 0; + } else if (strcmp(name, dnode->name)) { + /* Do we need to rename node? */ + if (!(dnode->props.new_name = dm_pool_strdup(dtree->mem, name))) { + log_error("name pool_strdup failed"); + return NULL; + } + } + + dnode->props.read_only = read_only ? 1 : 0; + dnode->props.read_ahead = DM_READ_AHEAD_AUTO; + dnode->props.read_ahead_flags = 0; + + if (clear_inactive && !_node_clear_table(dnode, udev_flags)) + return_NULL; + + dnode->context = context; + dnode->udev_flags = udev_flags; + + return dnode; +} + +struct dm_tree_node *dm_tree_add_new_dev(struct dm_tree *dtree, const char *name, + const char *uuid, uint32_t major, uint32_t minor, + int read_only, int clear_inactive, void *context) +{ + return dm_tree_add_new_dev_with_udev_flags(dtree, name, uuid, major, minor, + read_only, clear_inactive, context, 0); +} + +static struct dm_tree_node *_add_dev(struct dm_tree *dtree, + struct dm_tree_node *parent, + uint32_t major, uint32_t minor, + uint16_t udev_flags) +{ + struct dm_task *dmt = NULL; + struct dm_info info; + struct dm_deps *deps = NULL; + const char *name = NULL; + const char *uuid = NULL; + struct dm_tree_node *node = NULL; + uint32_t i; + int new = 0; + + /* Already in tree? */ + if (!(node = _find_dm_tree_node(dtree, major, minor))) { + if (!_deps(&dmt, dtree->mem, major, minor, &name, &uuid, 0, &info, &deps)) + return_NULL; + + if (!(node = _create_dm_tree_node(dtree, name, uuid, &info, + NULL, udev_flags))) + goto_out; + new = 1; + } + + if (!_link_tree_nodes(parent, node)) { + node = NULL; + goto_out; + } + + /* If node was already in tree, no need to recurse. */ + if (!new) + goto out; + + /* Can't recurse if not a mapped device or there are no dependencies */ + if (!node->info.exists || !deps->count) { + if (!_add_to_bottomlevel(node)) { + stack; + node = NULL; + } + goto out; + } + + /* Add dependencies to tree */ + for (i = 0; i < deps->count; i++) + if (!_add_dev(dtree, node, MAJOR(deps->device[i]), + MINOR(deps->device[i]), udev_flags)) { + node = NULL; + goto_out; + } + +out: + if (dmt) + dm_task_destroy(dmt); + + return node; +} + +int dm_tree_add_dev(struct dm_tree *dtree, uint32_t major, uint32_t minor) +{ + return _add_dev(dtree, &dtree->root, major, minor, 0) ? 1 : 0; +} + +int dm_tree_add_dev_with_udev_flags(struct dm_tree *dtree, uint32_t major, + uint32_t minor, uint16_t udev_flags) +{ + return _add_dev(dtree, &dtree->root, major, minor, udev_flags) ? 1 : 0; +} + static int _rename_node(const char *old_name, const char *new_name, uint32_t major, uint32_t minor, uint32_t *cookie, uint16_t udev_flags) { @@ -1588,21 +1613,6 @@ int dm_tree_deactivate_children(struct dm_tree_node *dnode, return _dm_tree_deactivate_children(dnode, uuid_prefix, uuid_prefix_len, 0); } -void dm_tree_skip_lockfs(struct dm_tree_node *dnode) -{ - dnode->dtree->skip_lockfs = 1; -} - -void dm_tree_use_no_flush_suspend(struct dm_tree_node *dnode) -{ - dnode->dtree->no_flush = 1; -} - -void dm_tree_retry_remove(struct dm_tree_node *dnode) -{ - dnode->dtree->retry_remove = 1; -} - int dm_tree_suspend_children(struct dm_tree_node *dnode, const char *uuid_prefix, size_t uuid_prefix_len) @@ -3254,13 +3264,3 @@ int dm_tree_node_add_null_area(struct dm_tree_node *node, uint64_t offset) return 1; } - -void dm_tree_set_cookie(struct dm_tree_node *node, uint32_t cookie) -{ - node->dtree->cookie = cookie; -} - -uint32_t dm_tree_get_cookie(struct dm_tree_node *node) -{ - return node->dtree->cookie; -} |