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:
parent
cab1c8ade1
commit
5c9eae9647
@ -620,7 +620,6 @@ static struct dm_config_tree *_destroy_tag_configs(struct cmd_context *cmd)
|
|||||||
struct config_tree_list *cfl;
|
struct config_tree_list *cfl;
|
||||||
struct dm_config_tree *cft_cmdline = NULL, *cft;
|
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);
|
cft = dm_config_remove_cascaded_tree(cmd->cft);
|
||||||
if (cft) {
|
if (cft) {
|
||||||
cft_cmdline = cmd->cft;
|
cft_cmdline = cmd->cft;
|
||||||
@ -1452,7 +1451,7 @@ int refresh_toolcontext(struct cmd_context *cmd)
|
|||||||
}
|
}
|
||||||
dev_cache_exit();
|
dev_cache_exit();
|
||||||
_destroy_tags(cmd);
|
_destroy_tags(cmd);
|
||||||
// FIXME Use cmd->cft_cmdline instead here.
|
|
||||||
cft_cmdline = _destroy_tag_configs(cmd);
|
cft_cmdline = _destroy_tag_configs(cmd);
|
||||||
|
|
||||||
cmd->config_valid = 0;
|
cmd->config_valid = 0;
|
||||||
@ -1465,7 +1464,6 @@ int refresh_toolcontext(struct cmd_context *cmd)
|
|||||||
/* Temporary duplicate cft pointer holding lvm.conf - replaced later */
|
/* Temporary duplicate cft pointer holding lvm.conf - replaced later */
|
||||||
cft_tmp = cmd->cft;
|
cft_tmp = cmd->cft;
|
||||||
if (cft_cmdline)
|
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);
|
cmd->cft = dm_config_insert_cascaded_tree(cft_cmdline, cft_tmp);
|
||||||
|
|
||||||
/* Uses cmd->cft i.e. cft_cmdline + lvm.conf */
|
/* 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))
|
if (!_init_tag_configs(cmd))
|
||||||
return 0;
|
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
|
/* Merge all the tag config files with lvm.conf, returning a
|
||||||
* fresh cft pointer in place of cft_tmp. */
|
* fresh cft pointer in place of cft_tmp. */
|
||||||
if (!(cmd->cft = _merge_config_files(cmd, cft_tmp)))
|
if (!(cmd->cft = _merge_config_files(cmd, cft_tmp)))
|
||||||
return 0;
|
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 */
|
/* Finally we can make the proper, fully-merged, cmd->cft */
|
||||||
if (cft_cmdline)
|
if (cft_cmdline)
|
||||||
cmd->cft = dm_config_insert_cascaded_tree(cft_cmdline, cmd->cft);
|
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();
|
dev_cache_exit();
|
||||||
_destroy_tags(cmd);
|
_destroy_tags(cmd);
|
||||||
|
|
||||||
// FIXME destroy_tag_configs handles this itself again
|
|
||||||
if ((cft_cmdline = _destroy_tag_configs(cmd)))
|
if ((cft_cmdline = _destroy_tag_configs(cmd)))
|
||||||
dm_config_destroy(cft_cmdline);
|
dm_config_destroy(cft_cmdline);
|
||||||
if (cmd->libmem)
|
if (cmd->libmem)
|
||||||
|
@ -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)
|
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 *old_cft = cmd->cft;
|
||||||
struct dm_config_tree *cft = dm_config_remove_cascaded_tree(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;
|
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,
|
int override_config_tree_from_string(struct cmd_context *cmd,
|
||||||
const char *config_settings)
|
const char *config_settings)
|
||||||
{
|
{
|
||||||
|
@ -234,7 +234,7 @@ uint32_t get_free_pool_device_id(struct lv_segment *thin_pool_seg)
|
|||||||
max_id = sl->seg->device_id;
|
max_id = sl->seg->device_id;
|
||||||
|
|
||||||
if (++max_id > DM_THIN_MAX_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.");
|
log_error("Cannot find free device_id.");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -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,
|
void dm_report_field_set_value(struct dm_report_field *field, const void *value,
|
||||||
const void *sortvalue);
|
const void *sortvalue);
|
||||||
|
|
||||||
|
|
||||||
/*************************
|
/*************************
|
||||||
* config file parse/print
|
* config file parse/print
|
||||||
*************************/
|
*************************/
|
||||||
// FIXME AGK Review this interface before inclusion in a release.
|
typedef enum {
|
||||||
enum {
|
|
||||||
DM_CFG_STRING,
|
|
||||||
DM_CFG_FLOAT,
|
|
||||||
DM_CFG_INT,
|
DM_CFG_INT,
|
||||||
|
DM_CFG_FLOAT,
|
||||||
|
DM_CFG_STRING,
|
||||||
DM_CFG_EMPTY_ARRAY
|
DM_CFG_EMPTY_ARRAY
|
||||||
};
|
} dm_config_value_type_t;
|
||||||
|
|
||||||
struct dm_config_value {
|
struct dm_config_value {
|
||||||
int type;
|
dm_config_value_type_t type;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
int64_t i;
|
int64_t i;
|
||||||
float f;
|
float f;
|
||||||
double d; /* For completeness. (Unused.) */
|
double d; /* Unused. */
|
||||||
const char *str;
|
const char *str;
|
||||||
} v;
|
} v;
|
||||||
|
|
||||||
struct dm_config_value *next; /* For arrays */
|
struct dm_config_value *next; /* For arrays */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1366,7 +1366,6 @@ struct dm_config_node {
|
|||||||
struct dm_config_value *v;
|
struct dm_config_value *v;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* FIXME Move cascade to dm_config_node and remove this struct */
|
|
||||||
struct dm_config_tree {
|
struct dm_config_tree {
|
||||||
struct dm_config_node *root;
|
struct dm_config_node *root;
|
||||||
struct dm_config_tree *cascade;
|
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_get_custom(struct dm_config_tree *cft);
|
||||||
void dm_config_set_custom(struct dm_config_tree *cft, void *custom);
|
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
|
* If there's a cascaded dm_config_tree, remove the top layer
|
||||||
* and return the layer below. Otherwise return NULL.
|
* and return the layer below. Otherwise return NULL.
|
||||||
*/
|
*/
|
||||||
struct dm_config_tree *dm_config_remove_cascaded_tree(struct dm_config_tree *cft);
|
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);
|
void dm_config_destroy(struct dm_config_tree *cft);
|
||||||
|
|
||||||
typedef int (*dm_putline_fn)(const char *line, void *baton);
|
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);
|
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);
|
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(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);
|
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);
|
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 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 *dm_config_tree_find_str(const struct dm_config_tree *cft, const char *path, const char *fail);
|
||||||
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);
|
||||||
const char *dm_config_tree_find_str_allow_empty(const struct dm_config_tree *cft,
|
int dm_config_tree_find_int(const struct dm_config_tree *cft, const char *path, int fail);
|
||||||
const char *path, const char *fail);
|
int64_t dm_config_tree_find_int64(const struct dm_config_tree *cft, const char *path, int64_t fail);
|
||||||
int dm_config_tree_find_int(const struct dm_config_tree *cft,
|
float dm_config_tree_find_float(const struct dm_config_tree *cft, const char *path, float fail);
|
||||||
const char *path, int fail);
|
int dm_config_tree_find_bool(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,
|
* 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_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,
|
int dm_config_get_uint32(const struct dm_config_node *cn, const char *path, uint32_t *result);
|
||||||
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_uint64(const struct dm_config_node *cn, const char *path,
|
int dm_config_get_list(const struct dm_config_node *cn, const char *path, const struct dm_config_value **result);
|
||||||
uint64_t *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_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);
|
unsigned dm_config_maybe_section(const char *str, unsigned len);
|
||||||
|
|
||||||
const char *dm_config_parent_name(const struct dm_config_node *n);
|
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,
|
struct dm_config_node *dm_config_clone_node_with_mem(struct dm_pool *mem, const struct dm_config_node *node, int siblings);
|
||||||
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_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_value *dm_config_create_value(struct dm_config_tree *cft);
|
||||||
struct dm_config_node *dm_config_clone_node(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);
|
||||||
const struct dm_config_node *cn,
|
|
||||||
int siblings);
|
|
||||||
|
|
||||||
struct dm_pool *dm_config_memory(struct dm_config_tree *cft);
|
struct dm_pool *dm_config_memory(struct dm_config_tree *cft);
|
||||||
|
|
||||||
|
|
||||||
/* Cookie prefixes.
|
/* Cookie prefixes.
|
||||||
|
*
|
||||||
* The cookie value consists of a prefix (16 bits) and a base (16 bits).
|
* 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
|
* 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
|
* 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
|
* of udev rules we use by decoding the cookie prefix. When doing the
|
||||||
* notification, we replace the cookie prefix with DM_COOKIE_MAGIC,
|
* notification, we replace the cookie prefix with DM_COOKIE_MAGIC,
|
||||||
* so we notify the right semaphore.
|
* so we notify the right semaphore.
|
||||||
|
*
|
||||||
* It is still possible to use cookies for passing the flags to udev
|
* 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
|
* 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
|
* will be zero (there's no notification semaphore) and prefix will be
|
||||||
|
@ -276,6 +276,9 @@ struct dm_tree {
|
|||||||
uint32_t cookie;
|
uint32_t cookie;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tree functions.
|
||||||
|
*/
|
||||||
struct dm_tree *dm_tree_create(void)
|
struct dm_tree *dm_tree_create(void)
|
||||||
{
|
{
|
||||||
struct dm_pool *dmem;
|
struct dm_pool *dmem;
|
||||||
@ -322,6 +325,34 @@ void dm_tree_free(struct dm_tree *dtree)
|
|||||||
dm_pool_destroy(dtree->mem);
|
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,
|
static int _nodes_are_linked(const struct dm_tree_node *parent,
|
||||||
const struct dm_tree_node *child)
|
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);
|
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,
|
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,
|
const char **name, const char **uuid, unsigned inactive_table,
|
||||||
struct dm_info *info, struct dm_deps **deps)
|
struct dm_info *info, struct dm_deps **deps)
|
||||||
@ -591,70 +816,168 @@ failed:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct dm_tree_node *_add_dev(struct dm_tree *dtree,
|
/*
|
||||||
struct dm_tree_node *parent,
|
* Deactivate a device with its dependencies if the uuid prefix matches.
|
||||||
uint32_t major, uint32_t minor,
|
*/
|
||||||
uint16_t udev_flags)
|
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_task *dmt;
|
||||||
struct dm_info info;
|
int r;
|
||||||
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 (!(dmt = dm_task_create(DM_DEVICE_INFO))) {
|
||||||
if (!(node = _find_dm_tree_node(dtree, major, minor))) {
|
log_error("_info_by_dev: dm_task creation failed");
|
||||||
if (!_deps(&dmt, dtree->mem, major, minor, &name, &uuid, 0, &info, &deps))
|
return 0;
|
||||||
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)) {
|
if (!dm_task_set_major(dmt, major) || !dm_task_set_minor(dmt, minor)) {
|
||||||
node = NULL;
|
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;
|
goto_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If node was already in tree, no need to recurse. */
|
if (uuid && !(*uuid = dm_pool_strdup(mem, dm_task_get_uuid(dmt)))) {
|
||||||
if (!new)
|
log_error("uuid pool_strdup failed");
|
||||||
goto out;
|
r = 0;
|
||||||
|
goto_out;
|
||||||
|
}
|
||||||
|
|
||||||
/* Can't recurse if not a mapped device or there are no dependencies */
|
out:
|
||||||
if (!node->info.exists || !deps->count) {
|
dm_task_destroy(dmt);
|
||||||
if (!_add_to_bottomlevel(node)) {
|
|
||||||
stack;
|
return r;
|
||||||
node = NULL;
|
}
|
||||||
|
|
||||||
|
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;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add dependencies to tree */
|
if (!dm_task_no_open_count(dmt))
|
||||||
for (i = 0; i < deps->count; i++)
|
log_error("Failed to disable open_count");
|
||||||
if (!_add_dev(dtree, node, MAJOR(deps->device[i]),
|
|
||||||
MINOR(deps->device[i]), udev_flags)) {
|
if (cookie)
|
||||||
node = NULL;
|
if (!dm_task_set_cookie(dmt, cookie, udev_flags))
|
||||||
goto_out;
|
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:
|
out:
|
||||||
if (dmt)
|
dm_task_destroy(dmt);
|
||||||
dm_task_destroy(dmt);
|
|
||||||
|
|
||||||
return node;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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)
|
static int _node_clear_table(struct dm_tree_node *dnode, uint16_t udev_flags)
|
||||||
{
|
{
|
||||||
struct dm_task *dmt = NULL, *deps_dmt = NULL;
|
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);
|
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)
|
/* Already in tree? */
|
||||||
log_debug("Resetting %s (%" PRIu32 ":%" PRIu32
|
if (!(node = _find_dm_tree_node(dtree, major, minor))) {
|
||||||
") udev_flags from 0x%x to 0x%x",
|
if (!_deps(&dmt, dtree->mem, major, minor, &name, &uuid, 0, &info, &deps))
|
||||||
dnode->name, dinfo->major, dinfo->minor,
|
return_NULL;
|
||||||
dnode->udev_flags, udev_flags);
|
|
||||||
dnode->udev_flags = udev_flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dm_tree_node_set_read_ahead(struct dm_tree_node *dnode,
|
if (!(node = _create_dm_tree_node(dtree, name, uuid, &info,
|
||||||
uint32_t read_ahead,
|
NULL, udev_flags)))
|
||||||
uint32_t read_ahead_flags)
|
goto_out;
|
||||||
{
|
new = 1;
|
||||||
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,
|
if (!_link_tree_nodes(parent, node)) {
|
||||||
struct dm_tree_node *presuspend_node)
|
node = NULL;
|
||||||
{
|
goto_out;
|
||||||
node->presuspend_node = presuspend_node;
|
}
|
||||||
|
|
||||||
|
/* 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)
|
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;
|
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,
|
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)
|
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);
|
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,
|
int dm_tree_suspend_children(struct dm_tree_node *dnode,
|
||||||
const char *uuid_prefix,
|
const char *uuid_prefix,
|
||||||
size_t uuid_prefix_len)
|
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;
|
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;
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user