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("%s: Error creating task\n", __func__);
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("%s: Could not create dm_task\n", __func__);
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;
462 task = dm_task_create(DM_DEVICE_REMOVE);
464 pb_log("%s: could not create dm_task\n", __func__);
468 if (!dm_task_set_name(task, dm_name)) {
469 pb_log("No dm device named '%s'\n", dm_name);
473 if (!set_cookie(task, &cookie))
476 if (!dm_task_run(task)) {
477 pb_log("Unable to remove device '%s'\n", dm_name);
483 /* Wait for /dev/mapper/ entries to be removed */
484 dm_udev_wait(cookie);
487 dm_task_destroy(task);
491 /* Destroy all dm devices related to a discover_device's snapshot */
492 int devmapper_destroy_snapshot(struct discover_device *device)
496 if (!device->ramdisk)
499 if (device->mounted) {
500 pb_log("Can not remove snapshot: %s is mounted\n",
505 /* Clean up dm devices in order */
506 if (device->ramdisk->snapshot)
507 if (destroy_device(device->ramdisk->snapshot))
510 if (device->ramdisk->origin)
511 if (destroy_device(device->ramdisk->origin))
514 if (device->ramdisk->base)
515 if (destroy_device(device->ramdisk->base))
521 pb_log("Warning: %s snapshot not cleanly removed\n",
523 device_handler_release_ramdisk(device);
527 static int reload_snapshot(struct discover_device *device, bool merge)
529 struct target target;
530 struct dm_task *task;
533 target.start_sector = 0;
534 target.end_sector = device->ramdisk->sectors;
537 target.ttype = talloc_asprintf(device, "snapshot-merge");
538 target.params = talloc_asprintf(device, "%s %s P 8",
539 device->ramdisk->base, device->ramdisk->path);
541 target.ttype = talloc_asprintf(device, "snapshot-origin");
542 target.params = talloc_asprintf(device, "%s",
543 device->ramdisk->base);
545 if (!target.ttype || !target.params) {
546 pb_log("%s: failed to allocate parameters\n", __func__);
550 task = dm_task_create(DM_DEVICE_RELOAD);
552 pb_log("%s: Error creating task\n", __func__);
556 if (!dm_task_set_name(task, device->ramdisk->origin)) {
557 pb_log("No dm-device named '%s'\n", device->ramdisk->origin);
561 if (!dm_task_add_target(task, target.start_sector, target.end_sector,
562 target.ttype, target.params)) {
563 pb_log("%s: Failed to set target\n", __func__);
567 if (!dm_task_run(task)) {
568 pb_log("Failed to reload %s\n", device->ramdisk->origin);
574 dm_task_destroy(task);
576 talloc_free(target.ttype);
577 talloc_free(target.params);
581 int devmapper_merge_snapshot(struct discover_device *device)
583 if (device->mounted) {
584 pb_log("%s: %s still mounted\n", __func__, device->device->id);
588 /* Suspend origin device */
589 if (set_device_active(device->ramdisk->origin, false)) {
590 pb_log("%s: failed to suspend %s\n",
591 __func__, device->ramdisk->origin);
595 /* Destroy snapshot */
596 if (destroy_device(device->ramdisk->snapshot)) {
597 /* The state of the snapshot is unknown, but try to
598 * resume to allow the snapshot to be remounted */
599 set_device_active(device->ramdisk->origin, true);
602 talloc_free(device->ramdisk->snapshot);
603 device->ramdisk->snapshot = NULL;
605 /* Reload origin device for merging */
606 reload_snapshot(device, true);
608 /* Resume origin device */
609 set_device_active(device->ramdisk->origin, true);
611 /* Block until merge complete */
612 while (!snapshot_merge_complete(device->ramdisk->origin))
613 usleep(MERGE_INTERVAL_US);
615 /* Suspend origin device */
616 set_device_active(device->ramdisk->origin, false);
618 /* Reload origin device */
619 reload_snapshot(device, false);
621 /* Re-create snapshot */
622 if (create_snapshot(device))
625 /* Resume origin device */
626 return set_device_active(device->ramdisk->origin, true);