1 #include <talloc/talloc.h>
2 #include <types/types.h>
7 #include "libdevmapper.h"
10 #define MERGE_INTERVAL_US 200000
13 long unsigned int start_sector;
14 long unsigned int end_sector;
19 /* Return the number of sectors on a block device. Zero represents an error */
20 static unsigned int get_block_sectors(struct discover_device *device)
23 long unsigned int sectors;
25 tmp = discover_device_get_param(device, "ID_PART_ENTRY_SIZE");
27 pb_debug("Could not retrieve ID_PART_ENTRY_SIZE for %s\n",
33 sectors = strtoul(tmp, NULL, 0);
35 pb_debug("Error reading sector count for %s: %s\n",
36 device->device_path, strerror(errno));
44 * The system's libdm may or may not have udev sync support. Tell libdm
45 * to manage the creation of device nodes itself rather than waiting on udev
48 static inline int set_cookie(struct dm_task *task, uint32_t *cookie)
50 uint16_t udev_rules = 0;
53 dm_udev_set_sync_support(0);
54 udev_rules |= DM_UDEV_DISABLE_DM_RULES_FLAG |
55 DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG;
57 return dm_task_set_cookie(task, cookie, udev_rules);
60 static bool snapshot_merge_complete(const char *dm_name)
62 long long unsigned int sectors, meta_sectors;
63 char *params = NULL, *target_type = NULL;
64 uint64_t start, length;
69 task = dm_task_create(DM_DEVICE_STATUS);
71 pb_log("%s: Error creating task\n", __func__);
75 if (!dm_task_set_name(task, dm_name)) {
76 pb_log("No dm-device named '%s'\n", dm_name);
80 if (!dm_task_run(task)) {
81 pb_log("Unable to retrieve status for '%s'\n", dm_name);
85 dm_get_next_target(task, NULL, &start, &length, &target_type, ¶ms);
88 pb_log("Unable to retrieve params for '%s'\n", dm_name);
92 if (!strncmp(params, "Invalid", strlen("Invalid"))) {
93 pb_log("dm-device %s has become invalid\n", dm_name);
97 /* Merge is complete when metadata sectors are the only sectors
98 * allocated - see Documentation/device-mapper/snapshot.txt */
99 n = sscanf(params, "%llu/%*u %llu", §ors, &meta_sectors);
101 pb_log("%s unexpected status: '%s'\n", dm_name, params);
104 result = sectors == meta_sectors;
106 pb_debug("%s merging; %llu sectors, %llu metadata sectors\n",
107 dm_name, sectors, meta_sectors);
110 /* In case of error or an invalid snapshot return true so callers will
111 * move on and catch the error */
112 dm_task_destroy(task);
116 /* Resume or suspend dm device */
117 static int set_device_active(const char *dm_name, bool active)
119 struct dm_task *task;
124 task = dm_task_create(DM_DEVICE_RESUME);
126 task = dm_task_create(DM_DEVICE_SUSPEND);
129 pb_log("%s: Could not create dm_task\n", __func__);
133 if (!dm_task_set_name(task, dm_name)) {
134 pb_log("No dm-device named '%s'\n", dm_name);
138 if (!set_cookie(task, &cookie))
141 if (!dm_task_run(task)) {
142 pb_log("Unable to %s device '%s'\n",
143 active ? "resume" : "suspend", dm_name);
149 /* Wait for /dev/mapper/ entries to be updated */
150 dm_udev_wait(cookie);
153 dm_task_destroy(task);
157 /* Run a DM_DEVICE_CREATE task with provided table (ttype and params) */
158 static int run_create_task(const char *dm_name, const struct target *target)
160 struct dm_task *task;
163 pb_debug("%s: %lu %lu '%s' '%s'\n", __func__,
164 target->start_sector, target->end_sector,
165 target->ttype, target->params);
167 task = dm_task_create(DM_DEVICE_CREATE);
169 pb_log("Error creating new dm-task\n");
173 if (!dm_task_set_name(task, dm_name))
176 if (!dm_task_add_target(task, target->start_sector, target->end_sector,
177 target->ttype, target->params))
180 if (!dm_task_set_add_node(task, DM_ADD_NODE_ON_CREATE))
183 if (!set_cookie(task, &cookie))
186 if (!dm_task_run(task)) {
187 pb_log("Error executing dm-task\n");
191 /* Wait for /dev/mapper/ entry to appear */
192 dm_udev_wait(cookie);
194 dm_task_destroy(task);
198 static int create_base(struct discover_device *device)
200 struct target target;
204 if (!device->ramdisk)
207 target.start_sector = 0;
208 target.end_sector = device->ramdisk->sectors;
210 target.ttype = talloc_asprintf(device, "linear");
211 target.params = talloc_asprintf(device, "%s 0", device->device_path);
212 if (!target.ttype || !target.params) {
213 pb_log("Failed to allocate map parameters\n");
217 name = talloc_asprintf(device, "%s-base", device->device->id);
218 if (!name || run_create_task(name, &target))
221 device->ramdisk->base = talloc_asprintf(device, "/dev/mapper/%s-base",
223 if (!device->ramdisk->base) {
224 pb_log("Failed to track new device /dev/mapper/%s-base\n",
233 talloc_free(target.params);
234 talloc_free(target.ttype);
238 static int create_origin(struct discover_device *device)
240 struct target target;
244 if (!device->ramdisk || !device->ramdisk->base)
247 target.start_sector = 0;
248 target.end_sector = device->ramdisk->sectors;
250 target.ttype = talloc_asprintf(device, "snapshot-origin");
251 target.params = talloc_asprintf(device, "%s", device->ramdisk->base);
252 if (!target.ttype || !target.params) {
253 pb_log("Failed to allocate map parameters\n");
257 name = talloc_asprintf(device, "%s-origin", device->device->id);
258 if (!name || run_create_task(name, &target))
261 device->ramdisk->origin = talloc_asprintf(device,
262 "/dev/mapper/%s-origin",
264 if (!device->ramdisk->origin) {
265 pb_log("Failed to track new device /dev/mapper/%s-origin\n",
274 talloc_free(target.params);
275 talloc_free(target.ttype);
279 static int create_snapshot(struct discover_device *device)
281 struct target target;
284 if (!device->ramdisk || !device->ramdisk->base ||
285 !device->ramdisk->origin)
288 target.start_sector = 0;
289 target.end_sector = device->ramdisk->sectors;
291 target.ttype = talloc_asprintf(device, "snapshot");
292 target.params = talloc_asprintf(device, "%s %s P 8",
293 device->ramdisk->base, device->ramdisk->path);
294 if (!target.ttype || !target.params) {
295 pb_log("Failed to allocate snapshot parameters\n");
299 if (run_create_task(device->device->id, &target))
302 device->ramdisk->snapshot = talloc_asprintf(device, "/dev/mapper/%s",
304 if (!device->ramdisk->snapshot) {
305 pb_log("Failed to track new device /dev/mapper/%s\n",
313 talloc_free(target.params);
314 talloc_free(target.ttype);
318 int devmapper_init_snapshot(struct device_handler *handler,
319 struct discover_device *device)
321 struct ramdisk_device *ramdisk;
323 ramdisk = device_handler_get_ramdisk(handler);
325 pb_log("No ramdisk available for snapshot %s\n",
330 ramdisk->sectors = get_block_sectors(device);
331 if (!ramdisk->sectors) {
332 pb_log("Error retreiving sectors for %s\n",
337 device->ramdisk = ramdisk;
339 /* Create linear map */
340 if (create_base(device)) {
341 pb_log("Error creating linear base\n");
345 /* Create snapshot-origin */
346 if (create_origin(device)) {
347 pb_log("Error creating snapshot-origin\n");
351 if (set_device_active(device->ramdisk->origin, false)) {
352 pb_log("Failed to suspend origin\n");
356 /* Create snapshot */
357 if (create_snapshot(device)) {
358 pb_log("Error creating snapshot\n");
362 if (set_device_active(device->ramdisk->origin, true)) {
363 pb_log("Failed to resume origin\n");
367 pb_log("Snapshot successfully created for %s\n", device->device->id);
372 pb_log("Error creating snapshot devices for %s\n", device->device->id);
373 devmapper_destroy_snapshot(device);
377 /* Destroy specific dm device */
378 static int destroy_device(const char *dm_name)
380 struct dm_task *task;
384 task = dm_task_create(DM_DEVICE_REMOVE);
386 pb_log("%s: could not create dm_task\n", __func__);
390 if (!dm_task_set_name(task, dm_name)) {
391 pb_log("No dm device named '%s'\n", dm_name);
395 if (!set_cookie(task, &cookie))
398 if (!dm_task_run(task)) {
399 pb_log("Unable to remove device '%s'\n", dm_name);
405 /* Wait for /dev/mapper/ entries to be removed */
406 dm_udev_wait(cookie);
409 dm_task_destroy(task);
413 /* Destroy all dm devices related to a discover_device's snapshot */
414 int devmapper_destroy_snapshot(struct discover_device *device)
418 if (!device->ramdisk)
421 if (device->mounted) {
422 pb_log("Can not remove snapshot: %s is mounted\n",
427 /* Clean up dm devices in order */
428 if (device->ramdisk->snapshot)
429 if (destroy_device(device->ramdisk->snapshot))
432 if (device->ramdisk->origin)
433 if (destroy_device(device->ramdisk->origin))
436 if (device->ramdisk->base)
437 if (destroy_device(device->ramdisk->base))
443 pb_log("Warning: %s snapshot not cleanly removed\n",
445 device_handler_release_ramdisk(device);
449 static int reload_snapshot(struct discover_device *device, bool merge)
451 struct target target;
452 struct dm_task *task;
455 target.start_sector = 0;
456 target.end_sector = device->ramdisk->sectors;
459 target.ttype = talloc_asprintf(device, "snapshot-merge");
460 target.params = talloc_asprintf(device, "%s %s P 8",
461 device->ramdisk->base, device->ramdisk->path);
463 target.ttype = talloc_asprintf(device, "snapshot-origin");
464 target.params = talloc_asprintf(device, "%s",
465 device->ramdisk->base);
467 if (!target.ttype || !target.params) {
468 pb_log("%s: failed to allocate parameters\n", __func__);
472 task = dm_task_create(DM_DEVICE_RELOAD);
474 pb_log("%s: Error creating task\n", __func__);
478 if (!dm_task_set_name(task, device->ramdisk->origin)) {
479 pb_log("No dm-device named '%s'\n", device->ramdisk->origin);
483 if (!dm_task_add_target(task, target.start_sector, target.end_sector,
484 target.ttype, target.params)) {
485 pb_log("%s: Failed to set target\n", __func__);
489 if (!dm_task_run(task)) {
490 pb_log("Failed to reload %s\n", device->ramdisk->origin);
496 dm_task_destroy(task);
498 talloc_free(target.ttype);
499 talloc_free(target.params);
503 int devmapper_merge_snapshot(struct discover_device *device)
505 if (device->mounted) {
506 pb_log("%s: %s still mounted\n", __func__, device->device->id);
510 /* Suspend origin device */
511 if (set_device_active(device->ramdisk->origin, false)) {
512 pb_log("%s: failed to suspend %s\n",
513 __func__, device->ramdisk->origin);
517 /* Destroy snapshot */
518 if (destroy_device(device->ramdisk->snapshot)) {
519 /* The state of the snapshot is unknown, but try to
520 * resume to allow the snapshot to be remounted */
521 set_device_active(device->ramdisk->origin, true);
524 talloc_free(device->ramdisk->snapshot);
525 device->ramdisk->snapshot = NULL;
527 /* Reload origin device for merging */
528 reload_snapshot(device, true);
530 /* Resume origin device */
531 set_device_active(device->ramdisk->origin, true);
533 /* Block until merge complete */
534 while (!snapshot_merge_complete(device->ramdisk->origin))
535 usleep(MERGE_INTERVAL_US);
537 /* Suspend origin device */
538 set_device_active(device->ramdisk->origin, false);
540 /* Reload origin device */
541 reload_snapshot(device, false);
543 /* Re-create snapshot */
544 if (create_snapshot(device))
547 /* Resume origin device */
548 return set_device_active(device->ramdisk->origin, true);