1 #include <talloc/talloc.h>
2 #include <types/types.h>
11 #include "libdevmapper.h"
12 #include "devmapper.h"
15 #define MERGE_INTERVAL_US 200000
18 uint64_t start_sector;
24 static unsigned long read_param_uint(struct discover_device *device,
27 unsigned long value = 0;
30 tmp = discover_device_get_param(device, param);
32 pb_debug("Could not retrieve parameter '%s' for %s\n",
33 param, device->device_path);
37 value = strtoul(tmp, NULL, 0);
40 /* Return errno and result directly */
44 /* Return the number of sectors on a block device. Zero represents an error */
45 static uint64_t get_block_sectors(struct discover_device *device)
47 unsigned long major, minor, sectors = 0;
48 char *attr, *buf = NULL;
53 sectors = read_param_uint(device, "ID_PART_ENTRY_SIZE");
55 return (uint64_t)sectors;
57 pb_debug("Error reading sector count for %s: %m\n",
60 /* Either the udev property is missing or we failed to parse it.
61 * Instead try to directly read the size attribute out of sysfs */
62 major = read_param_uint(device, "MAJOR");
64 pb_debug("Error reading %s major number\n", device->device_path);
67 minor = read_param_uint(device, "MINOR");
69 pb_debug("Error reading %s minor number\n", device->device_path);
73 attr = talloc_asprintf(device, "/sys/dev/block/%lu:%lu/size",
75 if (stat(attr, &sb)) {
76 pb_debug("Failed to stat %s, %m\n", attr);
80 fd = open(attr, O_RDONLY);
82 pb_debug("Failed to open sysfs attribute for %s\n",
87 buf = talloc_array(device, char, sb.st_size);
89 pb_debug("Failed to allocate space for attr\n");
93 sz = read(fd, buf, sb.st_size);
95 pb_debug("Failed to read sysfs attr: %m\n");
99 sectors = strtoul(buf, NULL, 0);
101 pb_debug("Failed to read sectors from sysfs: %m\n");
109 return (uint64_t)sectors;
113 * The system's libdm may or may not have udev sync support. Tell libdm
114 * to manage the creation of device nodes itself rather than waiting on udev
117 static inline int set_cookie(struct dm_task *task, uint32_t *cookie)
119 uint16_t udev_rules = 0;
122 dm_udev_set_sync_support(0);
123 udev_rules |= DM_UDEV_DISABLE_DM_RULES_FLAG |
124 DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG;
126 return dm_task_set_cookie(task, cookie, udev_rules);
129 static bool snapshot_merge_complete(const char *dm_name)
131 uint64_t sectors, meta_sectors;
132 char *params = NULL, *target_type = NULL;
133 uint64_t start, length;
134 struct dm_task *task;
138 task = dm_task_create(DM_DEVICE_STATUS);
140 pb_log("%s: Error creating task\n", __func__);
144 if (!dm_task_set_name(task, dm_name)) {
145 pb_log("No dm-device named '%s'\n", dm_name);
149 if (!dm_task_run(task)) {
150 pb_log("Unable to retrieve status for '%s'\n", dm_name);
154 dm_get_next_target(task, NULL, &start, &length, &target_type, ¶ms);
157 pb_log("Unable to retrieve params for '%s'\n", dm_name);
161 if (!strncmp(params, "Invalid", strlen("Invalid"))) {
162 pb_log("dm-device %s has become invalid\n", dm_name);
166 /* Merge is complete when metadata sectors are the only sectors
167 * allocated - see Documentation/device-mapper/snapshot.txt */
168 n = sscanf(params, "%" SCNu64 "/%*u %" SCNu64,
169 §ors, &meta_sectors);
171 pb_log("%s unexpected status: '%s'\n", dm_name, params);
174 result = sectors == meta_sectors;
176 pb_debug("%s merging; %" PRIu64 " sectors, %" PRIu64
177 " metadata sectors\n",
178 dm_name, sectors, meta_sectors);
181 /* In case of error or an invalid snapshot return true so callers will
182 * move on and catch the error */
183 dm_task_destroy(task);
187 /* Resume or suspend dm device */
188 static int set_device_active(const char *dm_name, bool active)
190 struct dm_task *task;
195 task = dm_task_create(DM_DEVICE_RESUME);
197 task = dm_task_create(DM_DEVICE_SUSPEND);
200 pb_log("%s: Could not create dm_task\n", __func__);
204 if (!dm_task_set_name(task, dm_name)) {
205 pb_log("No dm-device named '%s'\n", dm_name);
209 if (!set_cookie(task, &cookie))
212 if (!dm_task_run(task)) {
213 pb_log("Unable to %s device '%s'\n",
214 active ? "resume" : "suspend", dm_name);
220 /* Wait for /dev/mapper/ entries to be updated */
221 dm_udev_wait(cookie);
224 dm_task_destroy(task);
228 /* Run a DM_DEVICE_CREATE task with provided table (ttype and params) */
229 static int run_create_task(const char *dm_name, const struct target *target)
231 struct dm_task *task;
234 pb_debug("%s: %lu %lu '%s' '%s'\n", __func__,
235 target->start_sector, target->end_sector,
236 target->ttype, target->params);
238 task = dm_task_create(DM_DEVICE_CREATE);
240 pb_log("Error creating new dm-task\n");
244 if (!dm_task_set_name(task, dm_name))
247 if (!dm_task_add_target(task, target->start_sector, target->end_sector,
248 target->ttype, target->params))
251 if (!dm_task_set_add_node(task, DM_ADD_NODE_ON_CREATE))
254 if (!set_cookie(task, &cookie))
257 if (!dm_task_run(task)) {
258 pb_log("Error executing dm-task\n");
262 /* Wait for /dev/mapper/ entry to appear */
263 dm_udev_wait(cookie);
265 dm_task_destroy(task);
269 static int create_base(struct discover_device *device)
271 struct target target;
275 if (!device->ramdisk)
278 target.start_sector = 0;
279 target.end_sector = device->ramdisk->sectors;
281 target.ttype = talloc_asprintf(device, "linear");
282 target.params = talloc_asprintf(device, "%s 0", device->device_path);
283 if (!target.ttype || !target.params) {
284 pb_log("Failed to allocate map parameters\n");
288 name = talloc_asprintf(device, "%s-base", device->device->id);
289 if (!name || run_create_task(name, &target))
292 device->ramdisk->base = talloc_asprintf(device, "/dev/mapper/%s-base",
294 if (!device->ramdisk->base) {
295 pb_log("Failed to track new device /dev/mapper/%s-base\n",
304 talloc_free(target.params);
305 talloc_free(target.ttype);
309 static int create_origin(struct discover_device *device)
311 struct target target;
315 if (!device->ramdisk || !device->ramdisk->base)
318 target.start_sector = 0;
319 target.end_sector = device->ramdisk->sectors;
321 target.ttype = talloc_asprintf(device, "snapshot-origin");
322 target.params = talloc_asprintf(device, "%s", device->ramdisk->base);
323 if (!target.ttype || !target.params) {
324 pb_log("Failed to allocate map parameters\n");
328 name = talloc_asprintf(device, "%s-origin", device->device->id);
329 if (!name || run_create_task(name, &target))
332 device->ramdisk->origin = talloc_asprintf(device,
333 "/dev/mapper/%s-origin",
335 if (!device->ramdisk->origin) {
336 pb_log("Failed to track new device /dev/mapper/%s-origin\n",
345 talloc_free(target.params);
346 talloc_free(target.ttype);
350 static int create_snapshot(struct discover_device *device)
352 struct target target;
355 if (!device->ramdisk || !device->ramdisk->base ||
356 !device->ramdisk->origin)
359 target.start_sector = 0;
360 target.end_sector = device->ramdisk->sectors;
362 target.ttype = talloc_asprintf(device, "snapshot");
363 target.params = talloc_asprintf(device, "%s %s P 8",
364 device->ramdisk->base, device->ramdisk->path);
365 if (!target.ttype || !target.params) {
366 pb_log("Failed to allocate snapshot parameters\n");
370 if (run_create_task(device->device->id, &target))
373 device->ramdisk->snapshot = talloc_asprintf(device, "/dev/mapper/%s",
375 if (!device->ramdisk->snapshot) {
376 pb_log("Failed to track new device /dev/mapper/%s\n",
384 talloc_free(target.params);
385 talloc_free(target.ttype);
389 int devmapper_init_snapshot(struct device_handler *handler,
390 struct discover_device *device)
392 struct ramdisk_device *ramdisk;
394 if (config_get()->disable_snapshots)
397 ramdisk = device_handler_get_ramdisk(handler);
399 pb_log("No ramdisk available for snapshot %s\n",
404 ramdisk->sectors = get_block_sectors(device);
405 if (!ramdisk->sectors) {
406 pb_log("Error retreiving sectors for %s\n",
411 device->ramdisk = ramdisk;
413 /* Create linear map */
414 if (create_base(device)) {
415 pb_log("Error creating linear base\n");
419 /* Create snapshot-origin */
420 if (create_origin(device)) {
421 pb_log("Error creating snapshot-origin\n");
425 if (set_device_active(device->ramdisk->origin, false)) {
426 pb_log("Failed to suspend origin\n");
430 /* Create snapshot */
431 if (create_snapshot(device)) {
432 pb_log("Error creating snapshot\n");
436 if (set_device_active(device->ramdisk->origin, true)) {
437 pb_log("Failed to resume origin\n");
441 pb_log("Snapshot successfully created for %s\n", device->device->id);
446 pb_log("Error creating snapshot devices for %s\n", device->device->id);
447 devmapper_destroy_snapshot(device);
451 /* Destroy specific dm device */
452 static int destroy_device(const char *dm_name)
454 struct dm_task *task;
458 task = dm_task_create(DM_DEVICE_REMOVE);
460 pb_log("%s: could not create dm_task\n", __func__);
464 if (!dm_task_set_name(task, dm_name)) {
465 pb_log("No dm device named '%s'\n", dm_name);
469 if (!set_cookie(task, &cookie))
472 if (!dm_task_run(task)) {
473 pb_log("Unable to remove device '%s'\n", dm_name);
479 /* Wait for /dev/mapper/ entries to be removed */
480 dm_udev_wait(cookie);
483 dm_task_destroy(task);
487 /* Destroy all dm devices related to a discover_device's snapshot */
488 int devmapper_destroy_snapshot(struct discover_device *device)
492 if (!device->ramdisk)
495 if (device->mounted) {
496 pb_log("Can not remove snapshot: %s is mounted\n",
501 /* Clean up dm devices in order */
502 if (device->ramdisk->snapshot)
503 if (destroy_device(device->ramdisk->snapshot))
506 if (device->ramdisk->origin)
507 if (destroy_device(device->ramdisk->origin))
510 if (device->ramdisk->base)
511 if (destroy_device(device->ramdisk->base))
517 pb_log("Warning: %s snapshot not cleanly removed\n",
519 device_handler_release_ramdisk(device);
523 static int reload_snapshot(struct discover_device *device, bool merge)
525 struct target target;
526 struct dm_task *task;
529 target.start_sector = 0;
530 target.end_sector = device->ramdisk->sectors;
533 target.ttype = talloc_asprintf(device, "snapshot-merge");
534 target.params = talloc_asprintf(device, "%s %s P 8",
535 device->ramdisk->base, device->ramdisk->path);
537 target.ttype = talloc_asprintf(device, "snapshot-origin");
538 target.params = talloc_asprintf(device, "%s",
539 device->ramdisk->base);
541 if (!target.ttype || !target.params) {
542 pb_log("%s: failed to allocate parameters\n", __func__);
546 task = dm_task_create(DM_DEVICE_RELOAD);
548 pb_log("%s: Error creating task\n", __func__);
552 if (!dm_task_set_name(task, device->ramdisk->origin)) {
553 pb_log("No dm-device named '%s'\n", device->ramdisk->origin);
557 if (!dm_task_add_target(task, target.start_sector, target.end_sector,
558 target.ttype, target.params)) {
559 pb_log("%s: Failed to set target\n", __func__);
563 if (!dm_task_run(task)) {
564 pb_log("Failed to reload %s\n", device->ramdisk->origin);
570 dm_task_destroy(task);
572 talloc_free(target.ttype);
573 talloc_free(target.params);
577 int devmapper_merge_snapshot(struct discover_device *device)
579 if (device->mounted) {
580 pb_log("%s: %s still mounted\n", __func__, device->device->id);
584 /* Suspend origin device */
585 if (set_device_active(device->ramdisk->origin, false)) {
586 pb_log("%s: failed to suspend %s\n",
587 __func__, device->ramdisk->origin);
591 /* Destroy snapshot */
592 if (destroy_device(device->ramdisk->snapshot)) {
593 /* The state of the snapshot is unknown, but try to
594 * resume to allow the snapshot to be remounted */
595 set_device_active(device->ramdisk->origin, true);
598 talloc_free(device->ramdisk->snapshot);
599 device->ramdisk->snapshot = NULL;
601 /* Reload origin device for merging */
602 reload_snapshot(device, true);
604 /* Resume origin device */
605 set_device_active(device->ramdisk->origin, true);
607 /* Block until merge complete */
608 while (!snapshot_merge_complete(device->ramdisk->origin))
609 usleep(MERGE_INTERVAL_US);
611 /* Suspend origin device */
612 set_device_active(device->ramdisk->origin, false);
614 /* Reload origin device */
615 reload_snapshot(device, false);
617 /* Re-create snapshot */
618 if (create_snapshot(device))
621 /* Resume origin device */
622 return set_device_active(device->ramdisk->origin, true);