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

Reorder fns in libdm-deptree.

Tweak dm_config interface and remove FIXMEs.
This commit is contained in:
Alasdair Kergon 2012-01-23 17:46:31 +00:00
parent cab1c8ade1
commit 5c9eae9647
5 changed files with 453 additions and 480 deletions

View File

@ -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)

View File

@ -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)
{

View File

@ -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;
}

View File

@ -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;
@ -1381,23 +1380,23 @@ int dm_config_parse(struct dm_config_tree *cft, const char *start, const char *e
void *dm_config_get_custom(struct dm_config_tree *cft);
void dm_config_set_custom(struct dm_config_tree *cft, void *custom);
/*
* When searching, first_cft is checked before second_cft.
*/
struct dm_config_tree *dm_config_insert_cascaded_tree(struct dm_config_tree *first_cft, struct dm_config_tree *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_remove_cascaded_tree(struct dm_config_tree *cft);
/*
* When searching, first_cft is checked before second_cft.
*/
struct dm_config_tree *dm_config_insert_cascaded_tree(struct dm_config_tree *first_cft, struct dm_config_tree *second_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

View File

@ -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,6 +531,200 @@ 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);
}
void dm_tree_node_set_udev_flags(struct dm_tree_node *dnode, uint16_t udev_flags)
{
struct dm_info *dinfo = &dnode->info;
if (udev_flags != dnode->udev_flags)
log_debug("Resetting %s (%" PRIu32 ":%" PRIu32
") udev_flags from 0x%x to 0x%x",
dnode->name, dinfo->major, dinfo->minor,
dnode->udev_flags, udev_flags);
dnode->udev_flags = udev_flags;
}
void dm_tree_node_set_read_ahead(struct dm_tree_node *dnode,
uint32_t read_ahead,
uint32_t read_ahead_flags)
{
dnode->props.read_ahead = read_ahead;
dnode->props.read_ahead_flags = read_ahead_flags;
}
void dm_tree_node_set_presuspend_node(struct dm_tree_node *node,
struct dm_tree_node *presuspend_node)
{
node->presuspend_node = presuspend_node;
}
const char *dm_tree_node_get_name(const struct dm_tree_node *node)
{
return node->info.exists ? node->name : "";
}
const char *dm_tree_node_get_uuid(const struct dm_tree_node *node)
{
return node->info.exists ? node->uuid : "";
}
const struct dm_info *dm_tree_node_get_info(const struct dm_tree_node *node)
{
return &node->info;
}
void *dm_tree_node_get_context(const struct dm_tree_node *node)
{
return node->context;
}
int dm_tree_node_size_changed(const struct dm_tree_node *dnode)
{
return dnode->props.size_changed;
}
int dm_tree_node_num_children(const struct dm_tree_node *node, uint32_t inverted)
{
if (inverted) {
if (_nodes_are_linked(&node->dtree->root, node))
return 0;
return dm_list_size(&node->used_by);
}
if (_nodes_are_linked(node, &node->dtree->root))
return 0;
return dm_list_size(&node->uses);
}
/*
* Returns 1 if no prefix supplied
*/
static int _uuid_prefix_matches(const char *uuid, const char *uuid_prefix, size_t uuid_prefix_len)
{
const char *default_uuid_prefix = dm_uuid_prefix();
size_t default_uuid_prefix_len = strlen(default_uuid_prefix);
if (!uuid_prefix)
return 1;
if (!strncmp(uuid, uuid_prefix, uuid_prefix_len))
return 1;
/* Handle transition: active device uuids might be missing the prefix */
if (uuid_prefix_len <= 4)
return 0;
if (!strncmp(uuid, default_uuid_prefix, default_uuid_prefix_len))
return 0;
if (strncmp(uuid_prefix, default_uuid_prefix, default_uuid_prefix_len))
return 0;
if (!strncmp(uuid, uuid_prefix + default_uuid_prefix_len, uuid_prefix_len - default_uuid_prefix_len))
return 1;
return 0;
}
/*
* Returns 1 if no children.
*/
static int _children_suspended(struct dm_tree_node *node,
uint32_t inverted,
const char *uuid_prefix,
size_t uuid_prefix_len)
{
struct dm_list *list;
struct dm_tree_link *dlink;
const struct dm_info *dinfo;
const char *uuid;
if (inverted) {
if (_nodes_are_linked(&node->dtree->root, node))
return 1;
list = &node->used_by;
} else {
if (_nodes_are_linked(node, &node->dtree->root))
return 1;
list = &node->uses;
}
dm_list_iterate_items(dlink, list) {
if (!(uuid = dm_tree_node_get_uuid(dlink->node))) {
stack;
continue;
}
/* Ignore if it doesn't belong to this VG */
if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
continue;
/* Ignore if parent node wants to presuspend this node */
if (dlink->node->presuspend_node == node)
continue;
if (!(dinfo = dm_tree_node_get_info(dlink->node))) {
stack; /* FIXME Is this normal? */
return 0;
}
if (!dinfo->suspended)
return 0;
}
return 1;
}
/*
* Set major and minor to zero for root of tree.
*/
struct dm_tree_node *dm_tree_find_node(struct dm_tree *dtree,
uint32_t major,
uint32_t minor)
{
if (!major && !minor)
return &dtree->root;
return _find_dm_tree_node(dtree, major, minor);
}
/*
* Set uuid to NULL for root of tree.
*/
struct dm_tree_node *dm_tree_find_node_by_uuid(struct dm_tree *dtree,
const char *uuid)
{
if (!uuid || !*uuid)
return &dtree->root;
return _find_dm_tree_node_by_uuid(dtree, uuid);
}
/*
* First time set *handle to NULL.
* Set inverted to invert the tree.
*/
struct dm_tree_node *dm_tree_next_child(void **handle,
const struct dm_tree_node *parent,
uint32_t inverted)
{
struct dm_list **dlink = (struct dm_list **) handle;
const struct dm_list *use_list;
if (inverted)
use_list = &parent->used_by;
else
use_list = &parent->uses;
if (!*dlink)
*dlink = dm_list_first(use_list);
else
*dlink = dm_list_next(use_list, *dlink);
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)
@ -591,70 +816,168 @@ failed:
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)
/*
* Deactivate a device with its dependencies if the uuid prefix matches.
*/
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)
{
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;
struct dm_task *dmt;
int r;
/* 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 (!(dmt = dm_task_create(DM_DEVICE_INFO))) {
log_error("_info_by_dev: dm_task creation failed");
return 0;
}
if (!_link_tree_nodes(parent, node)) {
node = NULL;
if (!dm_task_set_major(dmt, major) || !dm_task_set_minor(dmt, minor)) {
log_error("_info_by_dev: Failed to set device number");
dm_task_destroy(dmt);
return 0;
}
if (!with_open_count && !dm_task_no_open_count(dmt))
log_error("Failed to disable open_count");
if (!(r = dm_task_run(dmt)))
goto_out;
if (!(r = dm_task_get_info(dmt, info)))
goto_out;
if (name && !(*name = dm_pool_strdup(mem, dm_task_get_name(dmt)))) {
log_error("name pool_strdup failed");
r = 0;
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;
if (uuid && !(*uuid = dm_pool_strdup(mem, dm_task_get_uuid(dmt)))) {
log_error("uuid pool_strdup failed");
r = 0;
goto_out;
}
out:
if (dmt)
dm_task_destroy(dmt);
return node;
return r;
}
static int _check_device_not_in_use(const char *name, struct dm_info *info)
{
if (!info->exists)
return 1;
/* If sysfs is not used, use open_count information only. */
if (!*dm_sysfs_dir()) {
if (info->open_count) {
log_error("Device %s (%" PRIu32 ":%" PRIu32 ") in use",
name, info->major, info->minor);
return 0;
}
return 1;
}
if (dm_device_has_holders(info->major, info->minor)) {
log_error("Device %s (%" PRIu32 ":%" PRIu32 ") is used "
"by another device.", name, info->major, info->minor);
return 0;
}
if (dm_device_has_mounted_fs(info->major, info->minor)) {
log_error("Device %s (%" PRIu32 ":%" PRIu32 ") contains "
"a filesystem in use.", name, info->major, info->minor);
return 0;
}
return 1;
}
/* Check if all parent nodes of given node have open_count == 0 */
static int _node_has_closed_parents(struct dm_tree_node *node,
const char *uuid_prefix,
size_t uuid_prefix_len)
{
struct dm_tree_link *dlink;
const struct dm_info *dinfo;
struct dm_info info;
const char *uuid;
/* Iterate through parents of this node */
dm_list_iterate_items(dlink, &node->used_by) {
if (!(uuid = dm_tree_node_get_uuid(dlink->node))) {
stack;
continue;
}
/* Ignore if it doesn't belong to this VG */
if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
continue;
if (!(dinfo = dm_tree_node_get_info(dlink->node))) {
stack; /* FIXME Is this normal? */
return 0;
}
/* Refresh open_count */
if (!_info_by_dev(dinfo->major, dinfo->minor, 1, &info, NULL, NULL, NULL) ||
!info.exists)
continue;
if (info.open_count) {
log_debug("Node %s %d:%d has open_count %d", uuid_prefix,
dinfo->major, dinfo->minor, info.open_count);
return 0;
}
}
return 1;
}
// 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);
uint32_t *cookie, uint16_t udev_flags, int retry)
{
struct dm_task *dmt;
int r = 0;
log_verbose("Removing %s (%" PRIu32 ":%" PRIu32 ")", name, major, minor);
if (!(dmt = dm_task_create(DM_DEVICE_REMOVE))) {
log_error("Deactivation dm_task creation failed for %s", name);
return 0;
}
if (!dm_task_set_major(dmt, major) || !dm_task_set_minor(dmt, minor)) {
log_error("Failed to set device number for %s deactivation", name);
goto out;
}
if (!dm_task_no_open_count(dmt))
log_error("Failed to disable open_count");
if (cookie)
if (!dm_task_set_cookie(dmt, cookie, udev_flags))
goto out;
if (retry)
dm_task_retry_remove(dmt);
r = dm_task_run(dmt);
/* FIXME Until kernel returns actual name so dm-iface.c can handle it */
rm_dev_node(name, dmt->cookie_set && !(udev_flags & DM_UDEV_DISABLE_DM_RULES_FLAG),
dmt->cookie_set && (udev_flags & DM_UDEV_DISABLE_LIBRARY_FALLBACK));
/* FIXME Remove node from tree or mark invalid? */
out:
dm_task_destroy(dmt);
return r;
}
static int _node_clear_table(struct dm_tree_node *dnode, uint16_t udev_flags)
{
struct dm_task *dmt = NULL, *deps_dmt = NULL;
@ -826,31 +1149,62 @@ struct dm_tree_node *dm_tree_add_new_dev(struct dm_tree *dtree, const char *name
read_only, clear_inactive, context, 0);
}
void dm_tree_node_set_udev_flags(struct dm_tree_node *dnode, uint16_t udev_flags)
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_info *dinfo = &dnode->info;
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;
if (udev_flags != dnode->udev_flags)
log_debug("Resetting %s (%" PRIu32 ":%" PRIu32
") udev_flags from 0x%x to 0x%x",
dnode->name, dinfo->major, dinfo->minor,
dnode->udev_flags, udev_flags);
dnode->udev_flags = udev_flags;
}
/* 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;
void dm_tree_node_set_read_ahead(struct dm_tree_node *dnode,
uint32_t read_ahead,
uint32_t read_ahead_flags)
{
dnode->props.read_ahead = read_ahead;
dnode->props.read_ahead_flags = read_ahead_flags;
}
if (!(node = _create_dm_tree_node(dtree, name, uuid, &info,
NULL, udev_flags)))
goto_out;
new = 1;
}
void dm_tree_node_set_presuspend_node(struct dm_tree_node *node,
struct dm_tree_node *presuspend_node)
{
node->presuspend_node = presuspend_node;
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)
@ -864,335 +1218,6 @@ int dm_tree_add_dev_with_udev_flags(struct dm_tree *dtree, uint32_t major,
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 : "";
}
const char *dm_tree_node_get_uuid(const struct dm_tree_node *node)
{
return node->info.exists ? node->uuid : "";
}
const struct dm_info *dm_tree_node_get_info(const struct dm_tree_node *node)
{
return &node->info;
}
void *dm_tree_node_get_context(const struct dm_tree_node *node)
{
return node->context;
}
int dm_tree_node_size_changed(const struct dm_tree_node *dnode)
{
return dnode->props.size_changed;
}
int dm_tree_node_num_children(const struct dm_tree_node *node, uint32_t inverted)
{
if (inverted) {
if (_nodes_are_linked(&node->dtree->root, node))
return 0;
return dm_list_size(&node->used_by);
}
if (_nodes_are_linked(node, &node->dtree->root))
return 0;
return dm_list_size(&node->uses);
}
/*
* Returns 1 if no prefix supplied
*/
static int _uuid_prefix_matches(const char *uuid, const char *uuid_prefix, size_t uuid_prefix_len)
{
const char *default_uuid_prefix = dm_uuid_prefix();
size_t default_uuid_prefix_len = strlen(default_uuid_prefix);
if (!uuid_prefix)
return 1;
if (!strncmp(uuid, uuid_prefix, uuid_prefix_len))
return 1;
/* Handle transition: active device uuids might be missing the prefix */
if (uuid_prefix_len <= 4)
return 0;
if (!strncmp(uuid, default_uuid_prefix, default_uuid_prefix_len))
return 0;
if (strncmp(uuid_prefix, default_uuid_prefix, default_uuid_prefix_len))
return 0;
if (!strncmp(uuid, uuid_prefix + default_uuid_prefix_len, uuid_prefix_len - default_uuid_prefix_len))
return 1;
return 0;
}
/*
* Returns 1 if no children.
*/
static int _children_suspended(struct dm_tree_node *node,
uint32_t inverted,
const char *uuid_prefix,
size_t uuid_prefix_len)
{
struct dm_list *list;
struct dm_tree_link *dlink;
const struct dm_info *dinfo;
const char *uuid;
if (inverted) {
if (_nodes_are_linked(&node->dtree->root, node))
return 1;
list = &node->used_by;
} else {
if (_nodes_are_linked(node, &node->dtree->root))
return 1;
list = &node->uses;
}
dm_list_iterate_items(dlink, list) {
if (!(uuid = dm_tree_node_get_uuid(dlink->node))) {
stack;
continue;
}
/* Ignore if it doesn't belong to this VG */
if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
continue;
/* Ignore if parent node wants to presuspend this node */
if (dlink->node->presuspend_node == node)
continue;
if (!(dinfo = dm_tree_node_get_info(dlink->node))) {
stack; /* FIXME Is this normal? */
return 0;
}
if (!dinfo->suspended)
return 0;
}
return 1;
}
/*
* Set major and minor to zero for root of tree.
*/
struct dm_tree_node *dm_tree_find_node(struct dm_tree *dtree,
uint32_t major,
uint32_t minor)
{
if (!major && !minor)
return &dtree->root;
return _find_dm_tree_node(dtree, major, minor);
}
/*
* Set uuid to NULL for root of tree.
*/
struct dm_tree_node *dm_tree_find_node_by_uuid(struct dm_tree *dtree,
const char *uuid)
{
if (!uuid || !*uuid)
return &dtree->root;
return _find_dm_tree_node_by_uuid(dtree, uuid);
}
/*
* First time set *handle to NULL.
* Set inverted to invert the tree.
*/
struct dm_tree_node *dm_tree_next_child(void **handle,
const struct dm_tree_node *parent,
uint32_t inverted)
{
struct dm_list **dlink = (struct dm_list **) handle;
const struct dm_list *use_list;
if (inverted)
use_list = &parent->used_by;
else
use_list = &parent->uses;
if (!*dlink)
*dlink = dm_list_first(use_list);
else
*dlink = dm_list_next(use_list, *dlink);
return (*dlink) ? dm_list_item(*dlink, struct dm_tree_link)->node : NULL;
}
/*
* Deactivate a device with its dependencies if the uuid prefix matches.
*/
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)
{
struct dm_task *dmt;
int r;
if (!(dmt = dm_task_create(DM_DEVICE_INFO))) {
log_error("_info_by_dev: dm_task creation failed");
return 0;
}
if (!dm_task_set_major(dmt, major) || !dm_task_set_minor(dmt, minor)) {
log_error("_info_by_dev: Failed to set device number");
dm_task_destroy(dmt);
return 0;
}
if (!with_open_count && !dm_task_no_open_count(dmt))
log_error("Failed to disable open_count");
if (!(r = dm_task_run(dmt)))
goto_out;
if (!(r = dm_task_get_info(dmt, info)))
goto_out;
if (name && !(*name = dm_pool_strdup(mem, dm_task_get_name(dmt)))) {
log_error("name pool_strdup failed");
r = 0;
goto_out;
}
if (uuid && !(*uuid = dm_pool_strdup(mem, dm_task_get_uuid(dmt)))) {
log_error("uuid pool_strdup failed");
r = 0;
goto_out;
}
out:
dm_task_destroy(dmt);
return r;
}
static int _check_device_not_in_use(const char *name, struct dm_info *info)
{
if (!info->exists)
return 1;
/* If sysfs is not used, use open_count information only. */
if (!*dm_sysfs_dir()) {
if (info->open_count) {
log_error("Device %s (%" PRIu32 ":%" PRIu32 ") in use",
name, info->major, info->minor);
return 0;
}
return 1;
}
if (dm_device_has_holders(info->major, info->minor)) {
log_error("Device %s (%" PRIu32 ":%" PRIu32 ") is used "
"by another device.", name, info->major, info->minor);
return 0;
}
if (dm_device_has_mounted_fs(info->major, info->minor)) {
log_error("Device %s (%" PRIu32 ":%" PRIu32 ") contains "
"a filesystem in use.", name, info->major, info->minor);
return 0;
}
return 1;
}
/* Check if all parent nodes of given node have open_count == 0 */
static int _node_has_closed_parents(struct dm_tree_node *node,
const char *uuid_prefix,
size_t uuid_prefix_len)
{
struct dm_tree_link *dlink;
const struct dm_info *dinfo;
struct dm_info info;
const char *uuid;
/* Iterate through parents of this node */
dm_list_iterate_items(dlink, &node->used_by) {
if (!(uuid = dm_tree_node_get_uuid(dlink->node))) {
stack;
continue;
}
/* Ignore if it doesn't belong to this VG */
if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len))
continue;
if (!(dinfo = dm_tree_node_get_info(dlink->node))) {
stack; /* FIXME Is this normal? */
return 0;
}
/* Refresh open_count */
if (!_info_by_dev(dinfo->major, dinfo->minor, 1, &info, NULL, NULL, NULL) ||
!info.exists)
continue;
if (info.open_count) {
log_debug("Node %s %d:%d has open_count %d", uuid_prefix,
dinfo->major, dinfo->minor, info.open_count);
return 0;
}
}
return 1;
}
static int _deactivate_node(const char *name, uint32_t major, uint32_t minor,
uint32_t *cookie, uint16_t udev_flags, int retry)
{
struct dm_task *dmt;
int r = 0;
log_verbose("Removing %s (%" PRIu32 ":%" PRIu32 ")", name, major, minor);
if (!(dmt = dm_task_create(DM_DEVICE_REMOVE))) {
log_error("Deactivation dm_task creation failed for %s", name);
return 0;
}
if (!dm_task_set_major(dmt, major) || !dm_task_set_minor(dmt, minor)) {
log_error("Failed to set device number for %s deactivation", name);
goto out;
}
if (!dm_task_no_open_count(dmt))
log_error("Failed to disable open_count");
if (cookie)
if (!dm_task_set_cookie(dmt, cookie, udev_flags))
goto out;
if (retry)
dm_task_retry_remove(dmt);
r = dm_task_run(dmt);
/* FIXME Until kernel returns actual name so dm-iface.c can handle it */
rm_dev_node(name, dmt->cookie_set && !(udev_flags & DM_UDEV_DISABLE_DM_RULES_FLAG),
dmt->cookie_set && (udev_flags & DM_UDEV_DISABLE_LIBRARY_FALLBACK));
/* FIXME Remove node from tree or mark invalid? */
out:
dm_task_destroy(dmt);
return r;
}
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;
}