📄 libdm-deptree.c
字号:
} dnode->props.read_only = read_only ? 1 : 0; if (clear_inactive && !_node_clear_table(dnode)) return_NULL; dnode->context = context; return dnode;}int dm_tree_add_dev(struct dm_tree *dtree, uint32_t major, uint32_t minor){ return _add_dev(dtree, &dtree->root, major, minor) ? 1 : 0;}const char *dm_tree_node_get_name(struct dm_tree_node *node){ return node->info.exists ? node->name : "";}const char *dm_tree_node_get_uuid(struct dm_tree_node *node){ return node->info.exists ? node->uuid : "";}const struct dm_info *dm_tree_node_get_info(struct dm_tree_node *node){ return &node->info;}void *dm_tree_node_get_context(struct dm_tree_node *node){ return node->context;}int dm_tree_node_num_children(struct dm_tree_node *node, uint32_t inverted){ if (inverted) { if (_nodes_are_linked(&node->dtree->root, node)) return 0; return list_size(&node->used_by); } if (_nodes_are_linked(node, &node->dtree->root)) return 0; return 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){ 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, UUID_PREFIX, sizeof(UUID_PREFIX) - 1)) return 0; if (strncmp(uuid_prefix, UUID_PREFIX, sizeof(UUID_PREFIX) - 1)) return 0; if (!strncmp(uuid, uuid_prefix + sizeof(UUID_PREFIX) - 1, uuid_prefix_len - (sizeof(UUID_PREFIX) - 1))) 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 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; } 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; 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, struct dm_tree_node *parent, uint32_t inverted){ struct list **dlink = (struct list **) handle; struct list *use_list; if (inverted) use_list = &parent->used_by; else use_list = &parent->uses; if (!*dlink) *dlink = list_first(use_list); else *dlink = list_next(use_list, *dlink); return (*dlink) ? 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_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))) r = dm_task_get_info(dmt, info); dm_task_destroy(dmt); return r;}static int _deactivate_node(const char *name, uint32_t major, uint32_t minor){ struct dm_task *dmt; int r; 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); dm_task_destroy(dmt); return 0; } if (!dm_task_no_open_count(dmt)) log_error("Failed to disable open_count"); r = dm_task_run(dmt); /* FIXME Until kernel returns actual name so dm-ioctl.c can handle it */ rm_dev_node(name); /* FIXME Remove node from tree or mark invalid? */ dm_task_destroy(dmt); return r;}static int _rename_node(const char *old_name, const char *new_name, uint32_t major, uint32_t minor){ struct dm_task *dmt; int r = 0; log_verbose("Renaming %s (%" PRIu32 ":%" PRIu32 ") to %s", old_name, major, minor, new_name); if (!(dmt = dm_task_create(DM_DEVICE_RENAME))) { log_error("Rename dm_task creation failed for %s", old_name); return 0; } if (!dm_task_set_name(dmt, old_name)) { log_error("Failed to set name for %s rename.", old_name); goto out; } if (!dm_task_set_newname(dmt, new_name)) goto_out; if (!dm_task_no_open_count(dmt)) log_error("Failed to disable open_count"); r = dm_task_run(dmt);out: dm_task_destroy(dmt); return r;}/* FIXME Merge with _suspend_node? */static int _resume_node(const char *name, uint32_t major, uint32_t minor, struct dm_info *newinfo){ struct dm_task *dmt; int r; log_verbose("Resuming %s (%" PRIu32 ":%" PRIu32 ")", name, major, minor); if (!(dmt = dm_task_create(DM_DEVICE_RESUME))) { log_error("Suspend 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 resumption.", name); dm_task_destroy(dmt); return 0; } if (!dm_task_no_open_count(dmt)) log_error("Failed to disable open_count"); if ((r = dm_task_run(dmt))) r = dm_task_get_info(dmt, newinfo); dm_task_destroy(dmt); return r;}static int _suspend_node(const char *name, uint32_t major, uint32_t minor, int skip_lockfs, int no_flush, struct dm_info *newinfo){ struct dm_task *dmt; int r; log_verbose("Suspending %s (%" PRIu32 ":%" PRIu32 ")%s%s", name, major, minor, skip_lockfs ? "" : " with filesystem sync", no_flush ? "" : " without device flush"); if (!(dmt = dm_task_create(DM_DEVICE_SUSPEND))) { log_error("Suspend 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 suspension.", name); dm_task_destroy(dmt); return 0; } if (!dm_task_no_open_count(dmt)) log_error("Failed to disable open_count"); if (skip_lockfs && !dm_task_skip_lockfs(dmt)) log_error("Failed to set skip_lockfs flag."); if (no_flush && !dm_task_no_flush(dmt)) log_error("Failed to set no_flush flag."); if ((r = dm_task_run(dmt))) r = dm_task_get_info(dmt, newinfo); dm_task_destroy(dmt); return r;}int dm_tree_deactivate_children(struct dm_tree_node *dnode, const char *uuid_prefix, size_t uuid_prefix_len){ void *handle = NULL; struct dm_tree_node *child = dnode; struct dm_info info; const struct dm_info *dinfo; const char *name; const char *uuid; while ((child = dm_tree_next_child(&handle, dnode, 0))) { if (!(dinfo = dm_tree_node_get_info(child))) { stack; continue; } if (!(name = dm_tree_node_get_name(child))) { stack; continue; } if (!(uuid = dm_tree_node_get_uuid(child))) { stack; continue; } /* Ignore if it doesn't belong to this VG */ if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len)) continue; /* Refresh open_count */ if (!_info_by_dev(dinfo->major, dinfo->minor, 1, &info) || !info.exists || info.open_count) continue; if (!_deactivate_node(name, info.major, info.minor)) { log_error("Unable to deactivate %s (%" PRIu32 ":%" PRIu32 ")", name, info.major, info.minor); continue; } if (dm_tree_node_num_children(child, 0)) dm_tree_deactivate_children(child, uuid_prefix, uuid_prefix_len); } return 1;}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;}int dm_tree_suspend_children(struct dm_tree_node *dnode, const char *uuid_prefix, size_t uuid_prefix_len){ void *handle = NULL; struct dm_tree_node *child = dnode; struct dm_info info, newinfo; const struct dm_info *dinfo; const char *name; const char *uuid; /* Suspend nodes at this level of the tree */ while ((child = dm_tree_next_child(&handle, dnode, 0))) { if (!(dinfo = dm_tree_node_get_info(child))) { stack; continue; } if (!(name = dm_tree_node_get_name(child))) { stack; continue; } if (!(uuid = dm_tree_node_get_uuid(child))) { stack; continue; } /* Ignore if it doesn't belong to this VG */ if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len)) continue; /* Ensure immediate parents are already suspended */ if (!_children_suspended(child, 1, uuid_prefix, uuid_prefix_len)) continue; if (!_info_by_dev(dinfo->major, dinfo->minor, 0, &info) || !info.exists || info.suspended) continue; if (!_suspend_node(name, info.major, info.minor, child->dtree->skip_lockfs, child->dtree->no_flush, &newinfo)) { log_error("Unable to suspend %s (%" PRIu32 ":%" PRIu32 ")", name, info.major, info.minor); continue; } /* Update cached info */ child->info = newinfo; } /* Then suspend any child nodes */ handle = NULL; while ((child = dm_tree_next_child(&handle, dnode, 0))) { if (!(uuid = dm_tree_node_get_uuid(child))) { stack; continue; } /* Ignore if it doesn't belong to this VG */ if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len)) continue; if (dm_tree_node_num_children(child, 0)) dm_tree_suspend_children(child, uuid_prefix, uuid_prefix_len); } return 1;}int dm_tree_activate_children(struct dm_tree_node *dnode, const char *uuid_prefix, size_t uuid_prefix_len){ void *handle = NULL; struct dm_tree_node *child = dnode; struct dm_info newinfo; const char *name; const char *uuid; int priority; /* Activate children first */ while ((child = dm_tree_next_child(&handle, dnode, 0))) { if (!(uuid = dm_tree_node_get_uuid(child))) { stack; continue; } if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len)) continue; if (dm_tree_node_num_children(child, 0)) dm_tree_activate_children(child, uuid_prefix, uuid_prefix_len); } handle = NULL; for (priority = 0; priority < 2; priority++) { while ((child = dm_tree_next_child(&handle, dnode, 0))) { if (!(uuid = dm_tree_node_get_uuid(child))) { stack; continue; } if (!_uuid_prefix_matches(uuid, uuid_prefix, uuid_prefix_len)) continue; if (priority != child->activation_priority) continue; if (!(name = dm_tree_node_get_name(child))) { stack; continue; } /* Rename? */ if (child->props.new_name) { if (!_rename_node(name, child->props.new_name, child->info.major, child->info.minor)) { log_error("Failed to rename %s (%" PRIu32 ":%" PRIu32 ") to %s", name, child->info.major, child->info.minor, child->props.new_name); return 0; } child->name = child->props.new_name; child->props.new_name = NULL; } if (!child->info.inactive_table && !child->info.suspended) continue; if (!_resume_node(name, child->info.major, child->info.minor, &newinfo)) { log_error("Unable to resume %s (%" PRIu32 ":%" PRIu32 ")", name, child->info.major, child->info.minor); continue; } /* Update cached info */ child->info = newinfo; } } handle = NULL; return 1;}static int _create_node(struct dm_tree_node *dnode){ int r = 0; struct dm_task *dmt; log_verbose("Creating %s", dnode->name); if (!(dmt = dm_task_create(DM_DEVICE_CREATE))) { log_error("Create dm_task creation failed for %s", dnode->name); return 0; } if (!dm_task_set_name(dmt, dnode->name)) { log_error("Failed to set device name for %s", dnode->name); goto out; } if (!dm_task_set_uuid(dmt, dnode->uuid)) { log_error("Failed to set uuid for %s", dnode->name); goto out; } if (dnode->props.major && (!dm_task_set_major(dmt, dnode->props.major) || !dm_task_set_minor(dmt, dnode->props.minor))) { log_error("Failed to set device number for %s creation.", dnode->name); goto out; } if (dnode->props.read_only && !dm_task_set_ro(dmt)) { log_error("Failed to set read only flag for %s", dnode->name); goto out; } if (!dm_task_no_open_count(dmt)) log_error("Failed to disable open_count"); if ((r = dm_task_run(dmt))) r = dm_task_get_info(dmt, &dnode->info);out: dm_task_destroy(dmt); return r;}static int _build_dev_string(char *devbuf, size_t bufsize, struct dm_tree_node *node){ if (!dm_format_dev(devbuf, bufsize, node->info.major, node->info.minor)) { log_error("Failed to format %s device number for %s as dm " "target (%u,%u)", node->name, node->uuid, node->info.major, node->info.minor); return 0; } return 1;}static int _emit_areas_line(struct dm_task *dmt __attribute((unused)), struct load_segment *seg, char *params,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -