⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 libdm-deptree.c

📁 Linux Device Mapper Source Code
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved. * * This file is part of the device-mapper userspace tools. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License v.2.1. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */#include "lib.h"#include "libdm-targets.h"#include "libdm-common.h"#include "list.h"#include "kdev_t.h"#include <stdarg.h>#include <sys/param.h>#include <linux/dm-ioctl.h>#define MAX_TARGET_PARAMSIZE 500000/* FIXME Fix interface so this is used only by LVM */#define UUID_PREFIX "LVM-"/* Supported segment types */enum {	SEG_ERROR, 	SEG_LINEAR,	SEG_MIRRORED,	SEG_SNAPSHOT,	SEG_SNAPSHOT_ORIGIN,	SEG_STRIPED,	SEG_ZERO,};/* FIXME Add crypt and multipath support */struct {	unsigned type;	const char *target;} dm_segtypes[] = {	{ SEG_ERROR, "error" },	{ SEG_LINEAR, "linear" },	{ SEG_MIRRORED, "mirror" },	{ SEG_SNAPSHOT, "snapshot" },	{ SEG_SNAPSHOT_ORIGIN, "snapshot-origin" },	{ SEG_STRIPED, "striped" },	{ SEG_ZERO, "zero"},};/* Some segment types have a list of areas of other devices attached */struct seg_area {	struct list list;	struct dm_tree_node *dev_node;	uint64_t offset;};/* Per-segment properties */struct load_segment {	struct list list;	unsigned type;	uint64_t size;	unsigned area_count;		/* Linear + Striped + Mirrored */	struct list areas;		/* Linear + Striped + Mirrored */	uint32_t stripe_size;		/* Striped */	int persistent;			/* Snapshot */	uint32_t chunk_size;		/* Snapshot */	struct dm_tree_node *cow;	/* Snapshot */	struct dm_tree_node *origin;	/* Snapshot + Snapshot origin */	struct dm_tree_node *log;	/* Mirror */	uint32_t region_size;		/* Mirror */	unsigned clustered;		/* Mirror */	unsigned mirror_area_count;	/* Mirror */	uint32_t flags;			/* Mirror log */	char *uuid;			/* Clustered mirror log */};/* Per-device properties */struct load_properties {	int read_only;	uint32_t major;	uint32_t minor;	unsigned segment_count;	struct list segs;	const char *new_name;};/* Two of these used to join two nodes with uses and used_by. */struct dm_tree_link {	struct list list;	struct dm_tree_node *node;};struct dm_tree_node {	struct dm_tree *dtree;        const char *name;        const char *uuid;        struct dm_info info;        struct list uses;       	/* Nodes this node uses */        struct list used_by;    	/* Nodes that use this node */	int activation_priority;	/* 0 gets activated first */	void *context;			/* External supplied context */	struct load_properties props;	/* For creation/table (re)load */};struct dm_tree {	struct dm_pool *mem;	struct dm_hash_table *devs;	struct dm_hash_table *uuids;	struct dm_tree_node root;	int skip_lockfs;		/* 1 skips lockfs (for non-snapshots) */	int no_flush;		/* 1 sets noflush (mirrors/multipath) */};/* FIXME Consider exporting this */static int _dm_snprintf(char *buf, size_t bufsize, const char *format, ...){        int n;        va_list ap;        va_start(ap, format);        n = vsnprintf(buf, bufsize, format, ap);        va_end(ap);        if (n < 0 || (n > (int) bufsize - 1))                return -1;        return n;}struct dm_tree *dm_tree_create(void){	struct dm_tree *dtree;	if (!(dtree = dm_malloc(sizeof(*dtree)))) {		log_error("dm_tree_create malloc failed");		return NULL;	}	memset(dtree, 0, sizeof(*dtree));	dtree->root.dtree = dtree;	list_init(&dtree->root.uses);	list_init(&dtree->root.used_by);	dtree->skip_lockfs = 0;	dtree->no_flush = 0;	if (!(dtree->mem = dm_pool_create("dtree", 1024))) {		log_error("dtree pool creation failed");		dm_free(dtree);		return NULL;	}	if (!(dtree->devs = dm_hash_create(8))) {		log_error("dtree hash creation failed");		dm_pool_destroy(dtree->mem);		dm_free(dtree);		return NULL;	}	if (!(dtree->uuids = dm_hash_create(32))) {		log_error("dtree uuid hash creation failed");		dm_hash_destroy(dtree->devs);		dm_pool_destroy(dtree->mem);		dm_free(dtree);		return NULL;	}	return dtree;}void dm_tree_free(struct dm_tree *dtree){	if (!dtree)		return;	dm_hash_destroy(dtree->uuids);	dm_hash_destroy(dtree->devs);	dm_pool_destroy(dtree->mem);	dm_free(dtree);}static int _nodes_are_linked(struct dm_tree_node *parent,			     struct dm_tree_node *child){	struct dm_tree_link *dlink;	list_iterate_items(dlink, &parent->uses)		if (dlink->node == child)			return 1;	return 0;}static int _link(struct list *list, struct dm_tree_node *node){	struct dm_tree_link *dlink;	if (!(dlink = dm_pool_alloc(node->dtree->mem, sizeof(*dlink)))) {		log_error("dtree link allocation failed");		return 0;	}	dlink->node = node;	list_add(list, &dlink->list);	return 1;}static int _link_nodes(struct dm_tree_node *parent,		       struct dm_tree_node *child){	if (_nodes_are_linked(parent, child))		return 1;	if (!_link(&parent->uses, child))		return 0;	if (!_link(&child->used_by, parent))		return 0;	return 1;}static void _unlink(struct list *list, struct dm_tree_node *node){	struct dm_tree_link *dlink;	list_iterate_items(dlink, list)		if (dlink->node == node) {			list_del(&dlink->list);			break;		}}static void _unlink_nodes(struct dm_tree_node *parent,			  struct dm_tree_node *child){	if (!_nodes_are_linked(parent, child))		return;	_unlink(&parent->uses, child);	_unlink(&child->used_by, parent);}static int _add_to_toplevel(struct dm_tree_node *node){	return _link_nodes(&node->dtree->root, node);}static void _remove_from_toplevel(struct dm_tree_node *node){	return _unlink_nodes(&node->dtree->root, node);}static int _add_to_bottomlevel(struct dm_tree_node *node){	return _link_nodes(node, &node->dtree->root);}static void _remove_from_bottomlevel(struct dm_tree_node *node){	return _unlink_nodes(node, &node->dtree->root);}static int _link_tree_nodes(struct dm_tree_node *parent, struct dm_tree_node *child){	/* Don't link to root node if child already has a parent */	if ((parent == &parent->dtree->root)) {		if (dm_tree_node_num_children(child, 1))			return 1;	} else		_remove_from_toplevel(child);	if ((child == &child->dtree->root)) {		if (dm_tree_node_num_children(parent, 0))			return 1;	} else		_remove_from_bottomlevel(parent);	return _link_nodes(parent, child);}static struct dm_tree_node *_create_dm_tree_node(struct dm_tree *dtree,						 const char *name,						 const char *uuid,						 struct dm_info *info,						 void *context){	struct dm_tree_node *node;	uint64_t dev;	if (!(node = dm_pool_zalloc(dtree->mem, sizeof(*node)))) {		log_error("_create_dm_tree_node alloc failed");		return NULL;	}	node->dtree = dtree;	node->name = name;	node->uuid = uuid;	node->info = *info;	node->context = context;	node->activation_priority = 0;	list_init(&node->uses);	list_init(&node->used_by);	list_init(&node->props.segs);	dev = MKDEV(info->major, info->minor);	if (!dm_hash_insert_binary(dtree->devs, (const char *) &dev,				sizeof(dev), node)) {		log_error("dtree node hash insertion failed");		dm_pool_free(dtree->mem, node);		return NULL;	}	if (uuid && *uuid &&	    !dm_hash_insert(dtree->uuids, uuid, node)) {		log_error("dtree uuid hash insertion failed");		dm_hash_remove_binary(dtree->devs, (const char *) &dev,				      sizeof(dev));		dm_pool_free(dtree->mem, node);		return NULL;	}	return node;}static struct dm_tree_node *_find_dm_tree_node(struct dm_tree *dtree,					       uint32_t major, uint32_t minor){	uint64_t dev = MKDEV(major, minor);	return dm_hash_lookup_binary(dtree->devs, (const char *) &dev,				  sizeof(dev));}static struct dm_tree_node *_find_dm_tree_node_by_uuid(struct dm_tree *dtree,						       const char *uuid){	struct dm_tree_node *node;	if ((node = dm_hash_lookup(dtree->uuids, uuid)))		return node;	if (strncmp(uuid, UUID_PREFIX, sizeof(UUID_PREFIX) - 1))		return NULL;	return dm_hash_lookup(dtree->uuids, uuid + sizeof(UUID_PREFIX) - 1);}static int _deps(struct dm_task **dmt, struct dm_pool *mem, uint32_t major, uint32_t minor,		 const char **name, const char **uuid,		 struct dm_info *info, struct dm_deps **deps){	memset(info, 0, sizeof(*info));	if (!dm_is_dm_major(major)) {		*name = "";		*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 (!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) {		*name = "";		*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 = dm_pool_strdup(mem, dm_task_get_name(*dmt)))) {			log_error("name pool_strdup failed");			goto failed;		}		if (!(*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){	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, &info, &deps))			return_NULL;		if (!(node = _create_dm_tree_node(dtree, name, uuid,						  &info, NULL)))			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]))) {			node = NULL;			goto_out;		}out:	if (dmt)		dm_task_destroy(dmt);	return node;}static int _node_clear_table(struct dm_tree_node *dnode){	struct dm_task *dmt;	struct dm_info *info;	const char *name;	int r;	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;	log_verbose("Clearing inactive table %s (%" PRIu32 ":%" PRIu32 ")",		    name, info->major, info->minor);	if (!(dmt = dm_task_create(DM_DEVICE_CLEAR))) {		dm_task_destroy(dmt);		log_error("Table clear dm_task creation failed for %s", name);		return 0;	}	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);		dm_task_destroy(dmt);		return 0;	}	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;	}	dm_task_destroy(dmt);	return r;}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){	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)))			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;	} 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 0;		}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -