1 #include <talloc/talloc.h>
2 #include <types/types.h>
12 #include "libdevmapper.h"
13 #include "devmapper.h"
16 #define MERGE_INTERVAL_US 200000
19 uint64_t start_sector;
25 static unsigned long read_param_uint(struct discover_device *device,
28 unsigned long value = 0;
31 tmp = discover_device_get_param(device, param);
33 pb_debug("Could not retrieve parameter '%s' for %s\n",
34 param, device->device_path);
38 value = strtoul(tmp, NULL, 0);
41 /* Return errno and result directly */
45 /* Return the number of sectors on a block device. Zero represents an error */
46 static uint64_t get_block_sectors(struct discover_device *device)
48 unsigned long major, minor, sectors = 0;
49 char *attr, *buf = NULL;
54 sectors = read_param_uint(device, "ID_PART_ENTRY_SIZE");
56 return (uint64_t)sectors;
58 pb_debug("Error reading sector count for %s: %m\n",
61 /* Either the udev property is missing or we failed to parse it.
62 * Instead try to directly read the size attribute out of sysfs */
63 major = read_param_uint(device, "MAJOR");
65 pb_debug("Error reading %s major number\n", device->device_path);
68 minor = read_param_uint(device, "MINOR");
70 pb_debug("Error reading %s minor number\n", device->device_path);
74 attr = talloc_asprintf(device, "/sys/dev/block/%lu:%lu/size",
76 if (stat(attr, &sb)) {
77 pb_debug("Failed to stat %s, %m\n", attr);
81 fd = open(attr, O_RDONLY);
83 pb_debug("Failed to open sysfs attribute for %s\n",
88 buf = talloc_array(device, char, sb.st_size);
90 pb_debug("Failed to allocate space for attr\n");
94 sz = read(fd, buf, sb.st_size);
96 pb_debug("Failed to read sysfs attr: %m\n");
100 sectors = strtoul(buf, NULL, 0);
102 pb_debug("Failed to read sectors from sysfs: %m\n");
110 return (uint64_t)sectors;
114 * The system's libdm may or may not have udev sync support. Tell libdm
115 * to manage the creation of device nodes itself rather than waiting on udev
118 static inline int set_cookie(struct dm_task *task, uint32_t *cookie)
120 uint16_t udev_rules = 0;
123 dm_udev_set_sync_support(0);
124 udev_rules |= DM_UDEV_DISABLE_DM_RULES_FLAG |
125 DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG;
127 return dm_task_set_cookie(task, cookie, udev_rules);
130 static bool snapshot_merge_complete(const char *dm_name)
132 uint64_t sectors, meta_sectors;
133 char *params = NULL, *target_type = NULL;
134 uint64_t start, length;
135 struct dm_task *task;
139 task = dm_task_create(DM_DEVICE_STATUS);
141 pb_log_fn("Error creating task\n");
145 if (!dm_task_set_name(task, dm_name)) {
146 pb_log("No dm-device named '%s'\n", dm_name);
150 if (!dm_task_run(task)) {
151 pb_log("Unable to retrieve status for '%s'\n", dm_name);
155 dm_get_next_target(task, NULL, &start, &length, &target_type, ¶ms);
158 pb_log("Unable to retrieve params for '%s'\n", dm_name);
162 if (!strncmp(params, "Invalid", strlen("Invalid"))) {
163 pb_log("dm-device %s has become invalid\n", dm_name);
167 /* Merge is complete when metadata sectors are the only sectors
168 * allocated - see Documentation/device-mapper/snapshot.txt */
169 n = sscanf(params, "%" SCNu64 "/%*u %" SCNu64,
170 §ors, &meta_sectors);
172 pb_log("%s unexpected status: '%s'\n", dm_name, params);
175 result = sectors == meta_sectors;
177 pb_debug("%s merging; %" PRIu64 " sectors, %" PRIu64
178 " metadata sectors\n",
179 dm_name, sectors, meta_sectors);
182 /* In case of error or an invalid snapshot return true so callers will
183 * move on and catch the error */
184 dm_task_destroy(task);
188 /* Resume or suspend dm device */
189 static int set_device_active(const char *dm_name, bool active)
191 struct dm_task *task;
196 task = dm_task_create(DM_DEVICE_RESUME);
198 task = dm_task_create(DM_DEVICE_SUSPEND);
201 pb_log_fn("Could not create dm_task\n");
205 if (!dm_task_set_name(task, dm_name)) {
206 pb_log("No dm-device named '%s'\n", dm_name);
210 if (!set_cookie(task, &cookie))
213 if (!dm_task_run(task)) {
214 pb_log("Unable to %s device '%s'\n",
215 active ? "resume" : "suspend", dm_name);
221 /* Wait for /dev/mapper/ entries to be updated */
222 dm_udev_wait(cookie);
225 dm_task_destroy(task);
229 /* Run a DM_DEVICE_CREATE task with provided table (ttype and params) */
230 static int run_create_task(const char *dm_name, const struct target *target)
232 struct dm_task *task;
235 pb_debug("%s: %" PRIu64 " %" PRIu64 " '%s' '%s'\n", __func__,
236 target->start_sector, target->end_sector,
237 target->ttype, target->params);
239 task = dm_task_create(DM_DEVICE_CREATE);
241 pb_log("Error creating new dm-task\n");
245 if (!dm_task_set_name(task, dm_name))
248 if (!dm_task_add_target(task, target->start_sector, target->end_sector,
249 target->ttype, target->params))
252 if (!dm_task_set_add_node(task, DM_ADD_NODE_ON_CREATE))
255 if (!set_cookie(task, &cookie))
258 if (!dm_task_run(task)) {
259 pb_log("Error executing dm-task\n");
263 /* Wait for /dev/mapper/ entry to appear */
264 dm_udev_wait(cookie);
266 dm_task_destroy(task);
270 static int create_base(struct discover_device *device)
272 struct target target;
276 if (!device->ramdisk)
279 target.start_sector = 0;
280 target.end_sector = device->ramdisk->sectors;
282 target.ttype = talloc_asprintf(device, "linear");
283 target.params = talloc_asprintf(device, "%s 0", device->device_path);
284 if (!target.ttype || !target.params) {
285 pb_log("Failed to allocate map parameters\n");
289 name = talloc_asprintf(device, "pb-%s-base", device->device->id);
290 if (!name || run_create_task(name, &target))
293 device->ramdisk->base = talloc_asprintf(device, "/dev/mapper/pb-%s-base",
295 if (!device->ramdisk->base) {
296 pb_log("Failed to track new device /dev/mapper/%s-base\n",
305 talloc_free(target.params);
306 talloc_free(target.ttype);
310 static int create_origin(struct discover_device *device)
312 struct target target;
316 if (!device->ramdisk || !device->ramdisk->base)
319 target.start_sector = 0;
320 target.end_sector = device->ramdisk->sectors;
322 target.ttype = talloc_asprintf(device, "snapshot-origin");
323 target.params = talloc_asprintf(device, "%s", device->ramdisk->base);
324 if (!target.ttype || !target.params) {
325 pb_log("Failed to allocate map parameters\n");
329 name = talloc_asprintf(device, "pb-%s-origin", device->device->id);
330 if (!name || run_create_task(name, &target))
333 device->ramdisk->origin = talloc_asprintf(device,
334 "/dev/mapper/pb-%s-origin",
336 if (!device->ramdisk->origin) {
337 pb_log("Failed to track new device /dev/mapper/%s-origin\n",
346 talloc_free(target.params);
347 talloc_free(target.ttype);
351 static int create_snapshot(struct discover_device *device)
353 struct target target;
357 if (!device->ramdisk || !device->ramdisk->base ||
358 !device->ramdisk->origin)
361 target.start_sector = 0;
362 target.end_sector = device->ramdisk->sectors;
364 target.ttype = talloc_asprintf(device, "snapshot");
365 target.params = talloc_asprintf(device, "%s %s P 8",
366 device->ramdisk->base, device->ramdisk->path);
367 if (!target.ttype || !target.params) {
368 pb_log("Failed to allocate snapshot parameters\n");
372 name = talloc_asprintf(device, "pb-%s", device->device->id);
373 if (!name || run_create_task(name, &target))
376 device->ramdisk->snapshot = talloc_asprintf(device, "/dev/mapper/pb-%s",
378 if (!device->ramdisk->snapshot) {
379 pb_log("Failed to track new device /dev/mapper/%s\n",
388 talloc_free(target.params);
389 talloc_free(target.ttype);
393 int devmapper_init_snapshot(struct device_handler *handler,
394 struct discover_device *device)
396 struct ramdisk_device *ramdisk;
398 if (config_get()->disable_snapshots)
401 ramdisk = device_handler_get_ramdisk(handler);
403 pb_log("No ramdisk available for snapshot %s\n",
408 ramdisk->sectors = get_block_sectors(device);
409 if (!ramdisk->sectors) {
410 pb_log("Error retreiving sectors for %s\n",
415 device->ramdisk = ramdisk;
417 /* Create linear map */
418 if (create_base(device)) {
419 pb_log("Error creating linear base\n");
423 /* Create snapshot-origin */
424 if (create_origin(device)) {
425 pb_log("Error creating snapshot-origin\n");
429 if (set_device_active(device->ramdisk->origin, false)) {
430 pb_log("Failed to suspend origin\n");
434 /* Create snapshot */
435 if (create_snapshot(device)) {
436 pb_log("Error creating snapshot\n");
440 if (set_device_active(device->ramdisk->origin, true)) {
441 pb_log("Failed to resume origin\n");
445 pb_log("Snapshot successfully created for %s\n", device->device->id);
450 pb_log("Error creating snapshot devices for %s\n", device->device->id);
451 devmapper_destroy_snapshot(device);
455 /* Destroy specific dm device */
456 static int destroy_device(const char *dm_name)
458 struct dm_task *task;
463 task = dm_task_create(DM_DEVICE_REMOVE);
465 pb_debug_fn("could not create dm_task\n");
469 if (!dm_task_set_name(task, dm_name)) {
470 rc = dm_task_get_errno(task);
471 pb_debug_fn("Couldn't set name for %s, %s (%d)\n",
472 dm_name, strerror(rc), rc);
476 if (!set_cookie(task, &cookie)) {
477 rc = dm_task_get_errno(task);
478 pb_debug_fn("set_cookie failed, %s (%d)\n", strerror(rc), rc);
482 if (!dm_task_run(task)) {
483 rc = dm_task_get_errno(task);
484 pb_debug_fn("Unable to remove device '%s', %s (%d)\n",
485 dm_name, strerror(rc), rc);
491 /* Wait for /dev/mapper/ entries to be removed */
492 dm_udev_wait(cookie);
495 dm_task_destroy(task);
496 if (rc == EBUSY && retries < 5) {
497 pb_log_fn("Device busy, retry %d..\n", retries);
505 /* Destroy all dm devices related to a discover_device's snapshot */
506 int devmapper_destroy_snapshot(struct discover_device *device)
510 if (!device->ramdisk)
513 if (device->mounted) {
514 pb_log("Can not remove snapshot: %s is mounted\n",
519 /* Clean up dm devices in order */
520 if (device->ramdisk->snapshot)
521 if (destroy_device(device->ramdisk->snapshot))
524 if (device->ramdisk->origin)
525 if (destroy_device(device->ramdisk->origin))
528 if (device->ramdisk->base)
529 if (destroy_device(device->ramdisk->base))
535 pb_log("Warning: %s snapshot not cleanly removed\n",
537 device_handler_release_ramdisk(device);
541 static int reload_snapshot(struct discover_device *device, bool merge)
543 struct target target;
544 struct dm_task *task;
547 target.start_sector = 0;
548 target.end_sector = device->ramdisk->sectors;
551 target.ttype = talloc_asprintf(device, "snapshot-merge");
552 target.params = talloc_asprintf(device, "%s %s P 8",
553 device->ramdisk->base, device->ramdisk->path);
555 target.ttype = talloc_asprintf(device, "snapshot-origin");
556 target.params = talloc_asprintf(device, "%s",
557 device->ramdisk->base);
559 if (!target.ttype || !target.params) {
560 pb_log_fn("failed to allocate parameters\n");
564 task = dm_task_create(DM_DEVICE_RELOAD);
566 pb_log_fn("Error creating task\n");
570 if (!dm_task_set_name(task, device->ramdisk->origin)) {
571 pb_log("No dm-device named '%s'\n", device->ramdisk->origin);
575 if (!dm_task_add_target(task, target.start_sector, target.end_sector,
576 target.ttype, target.params)) {
577 pb_log_fn("Failed to set target\n");
581 if (!dm_task_run(task)) {
582 pb_log("Failed to reload %s\n", device->ramdisk->origin);
588 dm_task_destroy(task);
590 talloc_free(target.ttype);
591 talloc_free(target.params);
595 int devmapper_merge_snapshot(struct discover_device *device)
597 if (device->mounted) {
598 pb_log_fn("%s still mounted\n", device->device->id);
602 /* Suspend origin device */
603 if (set_device_active(device->ramdisk->origin, false)) {
604 pb_log("%s: failed to suspend %s\n",
605 __func__, device->ramdisk->origin);
609 /* Destroy snapshot */
610 if (destroy_device(device->ramdisk->snapshot)) {
611 /* The state of the snapshot is unknown, but try to
612 * resume to allow the snapshot to be remounted */
613 set_device_active(device->ramdisk->origin, true);
616 talloc_free(device->ramdisk->snapshot);
617 device->ramdisk->snapshot = NULL;
619 /* Reload origin device for merging */
620 reload_snapshot(device, true);
622 /* Resume origin device */
623 set_device_active(device->ramdisk->origin, true);
625 /* Block until merge complete */
626 while (!snapshot_merge_complete(device->ramdisk->origin))
627 usleep(MERGE_INTERVAL_US);
629 /* Suspend origin device */
630 set_device_active(device->ramdisk->origin, false);
632 /* Reload origin device */
633 reload_snapshot(device, false);
635 /* Re-create snapshot */
636 if (create_snapshot(device))
639 /* Resume origin device */
640 return set_device_active(device->ramdisk->origin, true);