1 #include <talloc/talloc.h>
2 #include <types/types.h>
7 #include "libdevmapper.h"
11 #define MERGE_INTERVAL_US 200000
14 uint64_t start_sector;
20 /* Return the number of sectors on a block device. Zero represents an error */
21 static uint64_t get_block_sectors(struct discover_device *device)
23 unsigned long long sectors;
26 tmp = discover_device_get_param(device, "ID_PART_ENTRY_SIZE");
28 pb_debug("Could not retrieve ID_PART_ENTRY_SIZE for %s\n",
34 sectors = strtoull(tmp, NULL, 0);
36 pb_debug("Error reading sector count for %s: %s\n",
37 device->device_path, strerror(errno));
41 return (uint64_t)sectors;
45 * The system's libdm may or may not have udev sync support. Tell libdm
46 * to manage the creation of device nodes itself rather than waiting on udev
49 static inline int set_cookie(struct dm_task *task, uint32_t *cookie)
51 uint16_t udev_rules = 0;
54 dm_udev_set_sync_support(0);
55 udev_rules |= DM_UDEV_DISABLE_DM_RULES_FLAG |
56 DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG;
58 return dm_task_set_cookie(task, cookie, udev_rules);
61 static bool snapshot_merge_complete(const char *dm_name)
63 uint64_t sectors, meta_sectors;
64 char *params = NULL, *target_type = NULL;
65 uint64_t start, length;
70 task = dm_task_create(DM_DEVICE_STATUS);
72 pb_log("%s: Error creating task\n", __func__);
76 if (!dm_task_set_name(task, dm_name)) {
77 pb_log("No dm-device named '%s'\n", dm_name);
81 if (!dm_task_run(task)) {
82 pb_log("Unable to retrieve status for '%s'\n", dm_name);
86 dm_get_next_target(task, NULL, &start, &length, &target_type, ¶ms);
89 pb_log("Unable to retrieve params for '%s'\n", dm_name);
93 if (!strncmp(params, "Invalid", strlen("Invalid"))) {
94 pb_log("dm-device %s has become invalid\n", dm_name);
98 /* Merge is complete when metadata sectors are the only sectors
99 * allocated - see Documentation/device-mapper/snapshot.txt */
100 n = sscanf(params, "%" SCNu64 "/%*u %" SCNu64,
101 §ors, &meta_sectors);
103 pb_log("%s unexpected status: '%s'\n", dm_name, params);
106 result = sectors == meta_sectors;
108 pb_debug("%s merging; %" PRIu64 " sectors, %" PRIu64
109 " metadata sectors\n",
110 dm_name, sectors, meta_sectors);
113 /* In case of error or an invalid snapshot return true so callers will
114 * move on and catch the error */
115 dm_task_destroy(task);
119 /* Resume or suspend dm device */
120 static int set_device_active(const char *dm_name, bool active)
122 struct dm_task *task;
127 task = dm_task_create(DM_DEVICE_RESUME);
129 task = dm_task_create(DM_DEVICE_SUSPEND);
132 pb_log("%s: Could not create dm_task\n", __func__);
136 if (!dm_task_set_name(task, dm_name)) {
137 pb_log("No dm-device named '%s'\n", dm_name);
141 if (!set_cookie(task, &cookie))
144 if (!dm_task_run(task)) {
145 pb_log("Unable to %s device '%s'\n",
146 active ? "resume" : "suspend", dm_name);
152 /* Wait for /dev/mapper/ entries to be updated */
153 dm_udev_wait(cookie);
156 dm_task_destroy(task);
160 /* Run a DM_DEVICE_CREATE task with provided table (ttype and params) */
161 static int run_create_task(const char *dm_name, const struct target *target)
163 struct dm_task *task;
166 pb_debug("%s: %lu %lu '%s' '%s'\n", __func__,
167 target->start_sector, target->end_sector,
168 target->ttype, target->params);
170 task = dm_task_create(DM_DEVICE_CREATE);
172 pb_log("Error creating new dm-task\n");
176 if (!dm_task_set_name(task, dm_name))
179 if (!dm_task_add_target(task, target->start_sector, target->end_sector,
180 target->ttype, target->params))
183 if (!dm_task_set_add_node(task, DM_ADD_NODE_ON_CREATE))
186 if (!set_cookie(task, &cookie))
189 if (!dm_task_run(task)) {
190 pb_log("Error executing dm-task\n");
194 /* Wait for /dev/mapper/ entry to appear */
195 dm_udev_wait(cookie);
197 dm_task_destroy(task);
201 static int create_base(struct discover_device *device)
203 struct target target;
207 if (!device->ramdisk)
210 target.start_sector = 0;
211 target.end_sector = device->ramdisk->sectors;
213 target.ttype = talloc_asprintf(device, "linear");
214 target.params = talloc_asprintf(device, "%s 0", device->device_path);
215 if (!target.ttype || !target.params) {
216 pb_log("Failed to allocate map parameters\n");
220 name = talloc_asprintf(device, "%s-base", device->device->id);
221 if (!name || run_create_task(name, &target))
224 device->ramdisk->base = talloc_asprintf(device, "/dev/mapper/%s-base",
226 if (!device->ramdisk->base) {
227 pb_log("Failed to track new device /dev/mapper/%s-base\n",
236 talloc_free(target.params);
237 talloc_free(target.ttype);
241 static int create_origin(struct discover_device *device)
243 struct target target;
247 if (!device->ramdisk || !device->ramdisk->base)
250 target.start_sector = 0;
251 target.end_sector = device->ramdisk->sectors;
253 target.ttype = talloc_asprintf(device, "snapshot-origin");
254 target.params = talloc_asprintf(device, "%s", device->ramdisk->base);
255 if (!target.ttype || !target.params) {
256 pb_log("Failed to allocate map parameters\n");
260 name = talloc_asprintf(device, "%s-origin", device->device->id);
261 if (!name || run_create_task(name, &target))
264 device->ramdisk->origin = talloc_asprintf(device,
265 "/dev/mapper/%s-origin",
267 if (!device->ramdisk->origin) {
268 pb_log("Failed to track new device /dev/mapper/%s-origin\n",
277 talloc_free(target.params);
278 talloc_free(target.ttype);
282 static int create_snapshot(struct discover_device *device)
284 struct target target;
287 if (!device->ramdisk || !device->ramdisk->base ||
288 !device->ramdisk->origin)
291 target.start_sector = 0;
292 target.end_sector = device->ramdisk->sectors;
294 target.ttype = talloc_asprintf(device, "snapshot");
295 target.params = talloc_asprintf(device, "%s %s P 8",
296 device->ramdisk->base, device->ramdisk->path);
297 if (!target.ttype || !target.params) {
298 pb_log("Failed to allocate snapshot parameters\n");
302 if (run_create_task(device->device->id, &target))
305 device->ramdisk->snapshot = talloc_asprintf(device, "/dev/mapper/%s",
307 if (!device->ramdisk->snapshot) {
308 pb_log("Failed to track new device /dev/mapper/%s\n",
316 talloc_free(target.params);
317 talloc_free(target.ttype);
321 int devmapper_init_snapshot(struct device_handler *handler,
322 struct discover_device *device)
324 struct ramdisk_device *ramdisk;
326 if (config_get()->disable_snapshots)
329 ramdisk = device_handler_get_ramdisk(handler);
331 pb_log("No ramdisk available for snapshot %s\n",
336 ramdisk->sectors = get_block_sectors(device);
337 if (!ramdisk->sectors) {
338 pb_log("Error retreiving sectors for %s\n",
343 device->ramdisk = ramdisk;
345 /* Create linear map */
346 if (create_base(device)) {
347 pb_log("Error creating linear base\n");
351 /* Create snapshot-origin */
352 if (create_origin(device)) {
353 pb_log("Error creating snapshot-origin\n");
357 if (set_device_active(device->ramdisk->origin, false)) {
358 pb_log("Failed to suspend origin\n");
362 /* Create snapshot */
363 if (create_snapshot(device)) {
364 pb_log("Error creating snapshot\n");
368 if (set_device_active(device->ramdisk->origin, true)) {
369 pb_log("Failed to resume origin\n");
373 pb_log("Snapshot successfully created for %s\n", device->device->id);
378 pb_log("Error creating snapshot devices for %s\n", device->device->id);
379 devmapper_destroy_snapshot(device);
383 /* Destroy specific dm device */
384 static int destroy_device(const char *dm_name)
386 struct dm_task *task;
390 task = dm_task_create(DM_DEVICE_REMOVE);
392 pb_log("%s: could not create dm_task\n", __func__);
396 if (!dm_task_set_name(task, dm_name)) {
397 pb_log("No dm device named '%s'\n", dm_name);
401 if (!set_cookie(task, &cookie))
404 if (!dm_task_run(task)) {
405 pb_log("Unable to remove device '%s'\n", dm_name);
411 /* Wait for /dev/mapper/ entries to be removed */
412 dm_udev_wait(cookie);
415 dm_task_destroy(task);
419 /* Destroy all dm devices related to a discover_device's snapshot */
420 int devmapper_destroy_snapshot(struct discover_device *device)
424 if (!device->ramdisk)
427 if (device->mounted) {
428 pb_log("Can not remove snapshot: %s is mounted\n",
433 /* Clean up dm devices in order */
434 if (device->ramdisk->snapshot)
435 if (destroy_device(device->ramdisk->snapshot))
438 if (device->ramdisk->origin)
439 if (destroy_device(device->ramdisk->origin))
442 if (device->ramdisk->base)
443 if (destroy_device(device->ramdisk->base))
449 pb_log("Warning: %s snapshot not cleanly removed\n",
451 device_handler_release_ramdisk(device);
455 static int reload_snapshot(struct discover_device *device, bool merge)
457 struct target target;
458 struct dm_task *task;
461 target.start_sector = 0;
462 target.end_sector = device->ramdisk->sectors;
465 target.ttype = talloc_asprintf(device, "snapshot-merge");
466 target.params = talloc_asprintf(device, "%s %s P 8",
467 device->ramdisk->base, device->ramdisk->path);
469 target.ttype = talloc_asprintf(device, "snapshot-origin");
470 target.params = talloc_asprintf(device, "%s",
471 device->ramdisk->base);
473 if (!target.ttype || !target.params) {
474 pb_log("%s: failed to allocate parameters\n", __func__);
478 task = dm_task_create(DM_DEVICE_RELOAD);
480 pb_log("%s: Error creating task\n", __func__);
484 if (!dm_task_set_name(task, device->ramdisk->origin)) {
485 pb_log("No dm-device named '%s'\n", device->ramdisk->origin);
489 if (!dm_task_add_target(task, target.start_sector, target.end_sector,
490 target.ttype, target.params)) {
491 pb_log("%s: Failed to set target\n", __func__);
495 if (!dm_task_run(task)) {
496 pb_log("Failed to reload %s\n", device->ramdisk->origin);
502 dm_task_destroy(task);
504 talloc_free(target.ttype);
505 talloc_free(target.params);
509 int devmapper_merge_snapshot(struct discover_device *device)
511 if (device->mounted) {
512 pb_log("%s: %s still mounted\n", __func__, device->device->id);
516 /* Suspend origin device */
517 if (set_device_active(device->ramdisk->origin, false)) {
518 pb_log("%s: failed to suspend %s\n",
519 __func__, device->ramdisk->origin);
523 /* Destroy snapshot */
524 if (destroy_device(device->ramdisk->snapshot)) {
525 /* The state of the snapshot is unknown, but try to
526 * resume to allow the snapshot to be remounted */
527 set_device_active(device->ramdisk->origin, true);
530 talloc_free(device->ramdisk->snapshot);
531 device->ramdisk->snapshot = NULL;
533 /* Reload origin device for merging */
534 reload_snapshot(device, true);
536 /* Resume origin device */
537 set_device_active(device->ramdisk->origin, true);
539 /* Block until merge complete */
540 while (!snapshot_merge_complete(device->ramdisk->origin))
541 usleep(MERGE_INTERVAL_US);
543 /* Suspend origin device */
544 set_device_active(device->ramdisk->origin, false);
546 /* Reload origin device */
547 reload_snapshot(device, false);
549 /* Re-create snapshot */
550 if (create_snapshot(device))
553 /* Resume origin device */
554 return set_device_active(device->ramdisk->origin, true);