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, "pb-%s-base", device->device->id);
289 if (!name || run_create_task(name, &target))
292 device->ramdisk->base = talloc_asprintf(device, "/dev/mapper/pb-%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, "pb-%s-origin", device->device->id);
329 if (!name || run_create_task(name, &target))
332 device->ramdisk->origin = talloc_asprintf(device,
333 "/dev/mapper/pb-%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;
356 if (!device->ramdisk || !device->ramdisk->base ||
357 !device->ramdisk->origin)
360 target.start_sector = 0;
361 target.end_sector = device->ramdisk->sectors;
363 target.ttype = talloc_asprintf(device, "snapshot");
364 target.params = talloc_asprintf(device, "%s %s P 8",
365 device->ramdisk->base, device->ramdisk->path);
366 if (!target.ttype || !target.params) {
367 pb_log("Failed to allocate snapshot parameters\n");
371 name = talloc_asprintf(device, "pb-%s", device->device->id);
372 if (!name || run_create_task(name, &target))
375 device->ramdisk->snapshot = talloc_asprintf(device, "/dev/mapper/pb-%s",
377 if (!device->ramdisk->snapshot) {
378 pb_log("Failed to track new device /dev/mapper/%s\n",
387 talloc_free(target.params);
388 talloc_free(target.ttype);
392 int devmapper_init_snapshot(struct device_handler *handler,
393 struct discover_device *device)
395 struct ramdisk_device *ramdisk;
397 if (config_get()->disable_snapshots)
400 ramdisk = device_handler_get_ramdisk(handler);
402 pb_log("No ramdisk available for snapshot %s\n",
407 ramdisk->sectors = get_block_sectors(device);
408 if (!ramdisk->sectors) {
409 pb_log("Error retreiving sectors for %s\n",
414 device->ramdisk = ramdisk;
416 /* Create linear map */
417 if (create_base(device)) {
418 pb_log("Error creating linear base\n");
422 /* Create snapshot-origin */
423 if (create_origin(device)) {
424 pb_log("Error creating snapshot-origin\n");
428 if (set_device_active(device->ramdisk->origin, false)) {
429 pb_log("Failed to suspend origin\n");
433 /* Create snapshot */
434 if (create_snapshot(device)) {
435 pb_log("Error creating snapshot\n");
439 if (set_device_active(device->ramdisk->origin, true)) {
440 pb_log("Failed to resume origin\n");
444 pb_log("Snapshot successfully created for %s\n", device->device->id);
449 pb_log("Error creating snapshot devices for %s\n", device->device->id);
450 devmapper_destroy_snapshot(device);
454 /* Destroy specific dm device */
455 static int destroy_device(const char *dm_name)
457 struct dm_task *task;
461 task = dm_task_create(DM_DEVICE_REMOVE);
463 pb_log("%s: could not create dm_task\n", __func__);
467 if (!dm_task_set_name(task, dm_name)) {
468 pb_log("No dm device named '%s'\n", dm_name);
472 if (!set_cookie(task, &cookie))
475 if (!dm_task_run(task)) {
476 pb_log("Unable to remove device '%s'\n", dm_name);
482 /* Wait for /dev/mapper/ entries to be removed */
483 dm_udev_wait(cookie);
486 dm_task_destroy(task);
490 /* Destroy all dm devices related to a discover_device's snapshot */
491 int devmapper_destroy_snapshot(struct discover_device *device)
495 if (!device->ramdisk)
498 if (device->mounted) {
499 pb_log("Can not remove snapshot: %s is mounted\n",
504 /* Clean up dm devices in order */
505 if (device->ramdisk->snapshot)
506 if (destroy_device(device->ramdisk->snapshot))
509 if (device->ramdisk->origin)
510 if (destroy_device(device->ramdisk->origin))
513 if (device->ramdisk->base)
514 if (destroy_device(device->ramdisk->base))
520 pb_log("Warning: %s snapshot not cleanly removed\n",
522 device_handler_release_ramdisk(device);
526 static int reload_snapshot(struct discover_device *device, bool merge)
528 struct target target;
529 struct dm_task *task;
532 target.start_sector = 0;
533 target.end_sector = device->ramdisk->sectors;
536 target.ttype = talloc_asprintf(device, "snapshot-merge");
537 target.params = talloc_asprintf(device, "%s %s P 8",
538 device->ramdisk->base, device->ramdisk->path);
540 target.ttype = talloc_asprintf(device, "snapshot-origin");
541 target.params = talloc_asprintf(device, "%s",
542 device->ramdisk->base);
544 if (!target.ttype || !target.params) {
545 pb_log("%s: failed to allocate parameters\n", __func__);
549 task = dm_task_create(DM_DEVICE_RELOAD);
551 pb_log("%s: Error creating task\n", __func__);
555 if (!dm_task_set_name(task, device->ramdisk->origin)) {
556 pb_log("No dm-device named '%s'\n", device->ramdisk->origin);
560 if (!dm_task_add_target(task, target.start_sector, target.end_sector,
561 target.ttype, target.params)) {
562 pb_log("%s: Failed to set target\n", __func__);
566 if (!dm_task_run(task)) {
567 pb_log("Failed to reload %s\n", device->ramdisk->origin);
573 dm_task_destroy(task);
575 talloc_free(target.ttype);
576 talloc_free(target.params);
580 int devmapper_merge_snapshot(struct discover_device *device)
582 if (device->mounted) {
583 pb_log("%s: %s still mounted\n", __func__, device->device->id);
587 /* Suspend origin device */
588 if (set_device_active(device->ramdisk->origin, false)) {
589 pb_log("%s: failed to suspend %s\n",
590 __func__, device->ramdisk->origin);
594 /* Destroy snapshot */
595 if (destroy_device(device->ramdisk->snapshot)) {
596 /* The state of the snapshot is unknown, but try to
597 * resume to allow the snapshot to be remounted */
598 set_device_active(device->ramdisk->origin, true);
601 talloc_free(device->ramdisk->snapshot);
602 device->ramdisk->snapshot = NULL;
604 /* Reload origin device for merging */
605 reload_snapshot(device, true);
607 /* Resume origin device */
608 set_device_active(device->ramdisk->origin, true);
610 /* Block until merge complete */
611 while (!snapshot_merge_complete(device->ramdisk->origin))
612 usleep(MERGE_INTERVAL_US);
614 /* Suspend origin device */
615 set_device_active(device->ramdisk->origin, false);
617 /* Reload origin device */
618 reload_snapshot(device, false);
620 /* Re-create snapshot */
621 if (create_snapshot(device))
624 /* Resume origin device */
625 return set_device_active(device->ramdisk->origin, true);