2 * dm-device.c: create or remove device via device mapper API.
4 * Copyright (c) 2010 EMC Corporation, Haiying Tang <Tang_Haiying@emc.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include <sys/types.h>
30 #include <linux/kdev_t.h>
39 #include <libdevmapper.h>
41 #include "device-discovery.h"
43 #define DM_DEV_NAME_LEN 256
45 #ifndef DM_MAX_TYPE_NAME
46 #define DM_MAX_TYPE_NAME 16
49 #define DM_PARAMS_LEN 512 /* XXX: is this enough for target? */
50 #define TYPE_HAS_DEV(type) ((type == BLOCK_VOLUME_SIMPLE) || \
51 (type == BLOCK_VOLUME_PSEUDO))
56 char target_type[DM_MAX_TYPE_NAME];
57 char params[DM_PARAMS_LEN];
58 struct bl_dm_table *next;
64 struct bl_dm_tree *next;
67 static const char dm_name[] = "pnfs_vol_%u";
69 static unsigned int dev_count;
71 static inline struct bl_dm_table *bl_dm_table_alloc(void)
73 return (struct bl_dm_table *)calloc(1, sizeof(struct bl_dm_table));
76 static void bl_dm_table_free(struct bl_dm_table *bl_table_head)
78 struct bl_dm_table *p;
80 while (bl_table_head) {
81 p = bl_table_head->next;
87 static void add_to_bl_dm_table(struct bl_dm_table **bl_table_head,
88 struct bl_dm_table *table)
90 struct bl_dm_table *p;
92 if (!*bl_table_head) {
93 *bl_table_head = table;
102 struct bl_dm_tree *bl_tree_head;
104 static struct bl_dm_tree *find_bl_dm_tree(uint64_t dev)
106 struct bl_dm_tree *p;
108 for (p = bl_tree_head; p; p = p->next) {
115 static void del_from_bl_dm_tree(uint64_t dev)
117 struct bl_dm_tree *p, *pre = bl_tree_head;
119 for (p = pre; p; p = p->next) {
122 if (p == bl_tree_head)
123 bl_tree_head = bl_tree_head->next;
131 static void add_to_bl_dm_tree(struct bl_dm_tree *tree)
133 struct bl_dm_tree *p;
147 * Create device via device mapper
148 * return 0 when creation failed
149 * return dev no for created device
152 dm_device_create_mapped(const char *dev_name, struct bl_dm_table *p)
155 struct dm_info dminfo;
158 dmt = dm_task_create(DM_DEVICE_CREATE);
160 BL_LOG_ERR("Create dm_task for %s failed\n", dev_name);
163 ret = dm_task_set_name(dmt, dev_name);
169 dm_task_add_target(dmt, p->offset, p->size, p->target_type,
176 ret = dm_task_run(dmt) && dm_task_get_info(dmt, &dminfo)
182 dm_task_update_nodes();
185 dm_task_destroy(dmt);
188 BL_LOG_ERR("Create device %s failed\n", dev_name);
191 return MKDEV(dminfo.major, dminfo.minor);
194 static int dm_device_remove_byname(const char *dev_name)
199 BL_LOG_INFO("%s: %s\n", __func__, dev_name);
201 dmt = dm_task_create(DM_DEVICE_REMOVE);
205 ret = dm_task_set_name(dmt, dev_name) && dm_task_run(dmt);
207 dm_task_update_nodes();
208 dm_task_destroy(dmt);
213 int dm_device_remove(uint64_t dev)
216 struct dm_names *dmnames;
220 /* Look for dev_name via dev, if dev_name could be transferred here,
221 we could jump to DM_DEVICE_REMOVE directly */
223 dmt = dm_task_create(DM_DEVICE_LIST);
225 BL_LOG_ERR("dm_task creation failed\n");
229 ret = dm_task_run(dmt);
231 BL_LOG_ERR("dm_task_run failed\n");
235 dmnames = dm_task_get_names(dmt);
236 if (!dmnames || !dmnames->dev) {
237 BL_LOG_ERR("dm_task_get_names failed\n");
242 if (dmnames->dev == dev) {
243 name = strdup(dmnames->name);
246 dmnames = (void *)dmnames + dmnames->next;
250 BL_LOG_ERR("Could not find device\n");
254 dm_task_update_nodes();
258 dm_task_destroy(dmt);
260 /* Start to remove device */
262 ret = dm_device_remove_byname(name);
269 static void dm_devicelist_remove(unsigned int start, unsigned int end)
271 char dev_name[DM_DEV_NAME_LEN];
274 if (start >= dev_count || end <= 1 || start >= end - 1)
277 for (count = end - 1; count > start; count--) {
278 snprintf(dev_name, sizeof dev_name, dm_name, count - 1);
279 dm_device_remove_byname(dev_name);
285 static void bl_dm_remove_tree(uint64_t dev)
287 struct bl_dm_tree *p;
289 p = find_bl_dm_tree(dev);
293 dm_tree_free(p->tree);
294 del_from_bl_dm_tree(dev);
297 static int bl_dm_create_tree(uint64_t dev)
299 struct dm_tree *tree;
300 struct bl_dm_tree *bl_tree;
302 bl_tree = find_bl_dm_tree(dev);
306 tree = dm_tree_create();
310 if (!dm_tree_add_dev(tree, MAJOR(dev), MINOR(dev))) {
315 bl_tree = malloc(sizeof(struct bl_dm_tree));
322 bl_tree->tree = tree;
323 bl_tree->next = NULL;
324 add_to_bl_dm_tree(bl_tree);
329 int dm_device_remove_all(uint64_t *dev)
331 struct bl_dm_tree *p;
332 struct dm_tree_node *node;
335 uint32_t major, minor;
338 memcpy(&major, dev, sizeof(uint32_t));
339 memcpy(&minor, (void *)dev + sizeof(uint32_t), sizeof(uint32_t));
340 bl_dev = MKDEV(major, minor);
341 p = find_bl_dm_tree(bl_dev);
345 node = dm_tree_find_node(p->tree, MAJOR(bl_dev), MINOR(bl_dev));
349 uuid = dm_tree_node_get_uuid(node);
353 dm_device_remove(bl_dev);
354 ret = dm_tree_deactivate_children(node, uuid, strlen(uuid));
355 dm_task_update_nodes();
356 bl_dm_remove_tree(bl_dev);
361 static int dm_device_exists(char *dev_name)
363 char fullname[DM_DEV_NAME_LEN];
365 snprintf(fullname, sizeof fullname, "/dev/mapper/%s", dev_name);
366 return (access(fullname, F_OK) >= 0);
369 /* TODO: check the value for DM_DEV_NAME_LEN, DM_TYPE_LEN, DM_PARAMS_LEN */
370 uint64_t dm_device_create(struct bl_volume *vols, int num_vols)
372 uint64_t size, stripe_unit, dev = 0;
373 unsigned int count = dev_count;
375 struct bl_volume *node;
377 struct bl_dm_table *table = NULL;
378 struct bl_dm_table *bl_table_head = NULL;
380 char *dev_name = NULL;
382 /* Create pseudo device here */
383 for (volnum = 0; volnum < num_vols; volnum++) {
384 node = &vols[volnum];
385 switch (node->bv_type) {
386 case BLOCK_VOLUME_SIMPLE:
387 /* Do not need to create device here */
388 dev = node->param.bv_dev;
390 case BLOCK_VOLUME_SLICE:
391 table = bl_dm_table_alloc();
395 table->size = node->bv_size;
396 strcpy(table->target_type, "linear");
397 if (!TYPE_HAS_DEV(node->bv_vols[0]->bv_type)) {
401 dev = node->bv_vols[0]->param.bv_dev;
403 if (!dm_format_dev(tmp, DM_PARAMS_LEN,
404 MAJOR(dev), MINOR(dev))) {
409 sprintf(tmp, " %lu", node->param.bv_offset);
410 add_to_bl_dm_table(&bl_table_head, table);
412 case BLOCK_VOLUME_STRIPE:
413 table = bl_dm_table_alloc();
417 /* Truncate size to a stripe unit boundary */
418 stripe_unit = node->param.bv_stripe_unit;
420 node->bv_size - (node->bv_size % stripe_unit);
421 strcpy(table->target_type, "striped");
422 sprintf(table->params, "%d %llu %n", node->bv_vol_n,
423 (long long unsigned) stripe_unit, &pos);
424 /* Copy subdev major:minor to params */
425 tmp = table->params + pos;
426 len = DM_PARAMS_LEN - pos;
427 for (i = 0; i < node->bv_vol_n; i++) {
428 if (!TYPE_HAS_DEV(node->bv_vols[i]->bv_type)) {
432 dev = node->bv_vols[i]->param.bv_dev;
433 if (!dm_format_dev(tmp, len, MAJOR(dev),
441 sprintf(tmp, " %d ", 0);
445 add_to_bl_dm_table(&bl_table_head, table);
447 case BLOCK_VOLUME_CONCAT:
449 for (i = 0; i < node->bv_vol_n; i++) {
450 table = bl_dm_table_alloc();
453 table->offset = size;
454 table->size = node->bv_vols[i]->bv_size;
455 if (!TYPE_HAS_DEV(node->bv_vols[i]->bv_type)) {
459 strcpy(table->target_type, "linear");
461 dev = node->bv_vols[i]->param.bv_dev;
462 if (!dm_format_dev(tmp, DM_PARAMS_LEN,
463 MAJOR(dev), MINOR(dev))) {
468 sprintf(tmp, " %d", 0);
470 add_to_bl_dm_table(&bl_table_head, table);
474 /* Delete previous temporary devices */
475 dm_devicelist_remove(count, dev_count);
477 } /* end of swtich */
478 /* Create dev_name here. Name of device is pnfs_vol_XXX */
481 dev_name = (char *)calloc(DM_DEV_NAME_LEN, sizeof(char));
483 BL_LOG_ERR("%s: Out of memory\n", __func__);
487 snprintf(dev_name, DM_DEV_NAME_LEN, dm_name,
489 } while (dm_device_exists(dev_name));
491 dev = dm_device_create_mapped(dev_name, bl_table_head);
492 BL_LOG_INFO("%s: %d %s %d:%d\n", __func__, volnum, dev_name,
493 (int) MAJOR(dev), (int) MINOR(dev));
495 /* Delete previous temporary devices */
496 dm_devicelist_remove(count, dev_count);
499 node->param.bv_dev = dev;
500 /* TODO: extend use with PSEUDO later */
501 node->bv_type = BLOCK_VOLUME_PSEUDO;
505 bl_dm_table_free(bl_table_head);
506 bl_table_head = NULL;
510 bl_dm_table_free(bl_table_head);
511 bl_table_head = NULL;
514 bl_dm_create_tree(dev);