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));
43 /* Petitboot's libdm isn't compiled with --enable-udev_sync, so we set
44 * empty cookie and flags unconditionally */
45 static inline int set_cookie(struct dm_task *task, uint32_t *cookie)
48 return dm_task_set_cookie(task, cookie, 0);
51 static bool snapshot_merge_complete(const char *dm_name)
53 long long unsigned int sectors, meta_sectors;
54 char *params = NULL, *target_type = NULL;
55 uint64_t start, length;
60 task = dm_task_create(DM_DEVICE_STATUS);
62 pb_log("%s: Error creating task\n", __func__);
66 if (!dm_task_set_name(task, dm_name)) {
67 pb_log("No dm-device named '%s'\n", dm_name);
71 if (!dm_task_run(task)) {
72 pb_log("Unable to retrieve status for '%s'\n", dm_name);
76 dm_get_next_target(task, NULL, &start, &length, &target_type, ¶ms);
79 pb_log("Unable to retrieve params for '%s'\n", dm_name);
83 if (!strncmp(params, "Invalid", strlen("Invalid"))) {
84 pb_log("dm-device %s has become invalid\n", dm_name);
88 /* Merge is complete when metadata sectors are the only sectors
89 * allocated - see Documentation/device-mapper/snapshot.txt */
90 n = sscanf(params, "%llu/%*u %llu", §ors, &meta_sectors);
92 pb_log("%s unexpected status: '%s'\n", dm_name, params);
95 result = sectors == meta_sectors;
97 pb_debug("%s merging; %llu sectors, %llu metadata sectors\n",
98 dm_name, sectors, meta_sectors);
101 /* In case of error or an invalid snapshot return true so callers will
102 * move on and catch the error */
103 dm_task_destroy(task);
107 /* Resume or suspend dm device */
108 static int set_device_active(const char *dm_name, bool active)
110 struct dm_task *task;
115 task = dm_task_create(DM_DEVICE_RESUME);
117 task = dm_task_create(DM_DEVICE_SUSPEND);
120 pb_log("%s: Could not create dm_task\n", __func__);
124 if (!dm_task_set_name(task, dm_name)) {
125 pb_log("No dm-device named '%s'\n", dm_name);
129 if (!set_cookie(task, &cookie))
132 if (!dm_task_run(task)) {
133 pb_log("Unable to %s device '%s'\n",
134 active ? "resume" : "suspend", dm_name);
140 /* Wait for /dev/mapper/ entries to be updated */
141 dm_udev_wait(cookie);
144 dm_task_destroy(task);
148 /* Run a DM_DEVICE_CREATE task with provided table (ttype and params) */
149 static int run_create_task(const char *dm_name, const struct target *target)
151 struct dm_task *task;
154 pb_debug("%s: %lu %lu '%s' '%s'\n", __func__,
155 target->start_sector, target->end_sector,
156 target->ttype, target->params);
158 task = dm_task_create(DM_DEVICE_CREATE);
160 pb_log("Error creating new dm-task\n");
164 if (!dm_task_set_name(task, dm_name))
167 if (!dm_task_add_target(task, target->start_sector, target->end_sector,
168 target->ttype, target->params))
171 if (!dm_task_set_add_node(task, DM_ADD_NODE_ON_CREATE))
174 if (!set_cookie(task, &cookie))
177 if (!dm_task_run(task)) {
178 pb_log("Error executing dm-task\n");
182 /* Wait for /dev/mapper/ entry to appear */
183 dm_udev_wait(cookie);
185 dm_task_destroy(task);
189 static int create_base(struct discover_device *device)
191 struct target target;
195 if (!device->ramdisk)
198 target.start_sector = 0;
199 target.end_sector = device->ramdisk->sectors;
201 target.ttype = talloc_asprintf(device, "linear");
202 target.params = talloc_asprintf(device, "%s 0", device->device_path);
203 if (!target.ttype || !target.params) {
204 pb_log("Failed to allocate map parameters\n");
208 name = talloc_asprintf(device, "%s-base", device->device->id);
209 if (!name || run_create_task(name, &target))
212 device->ramdisk->base = talloc_asprintf(device, "/dev/mapper/%s-base",
214 if (!device->ramdisk->base) {
215 pb_log("Failed to track new device /dev/mapper/%s-base\n",
224 talloc_free(target.params);
225 talloc_free(target.ttype);
229 static int create_origin(struct discover_device *device)
231 struct target target;
235 if (!device->ramdisk || !device->ramdisk->base)
238 target.start_sector = 0;
239 target.end_sector = device->ramdisk->sectors;
241 target.ttype = talloc_asprintf(device, "snapshot-origin");
242 target.params = talloc_asprintf(device, "%s", device->ramdisk->base);
243 if (!target.ttype || !target.params) {
244 pb_log("Failed to allocate map parameters\n");
248 name = talloc_asprintf(device, "%s-origin", device->device->id);
249 if (!name || run_create_task(name, &target))
252 device->ramdisk->origin = talloc_asprintf(device,
253 "/dev/mapper/%s-origin",
255 if (!device->ramdisk->origin) {
256 pb_log("Failed to track new device /dev/mapper/%s-origin\n",
265 talloc_free(target.params);
266 talloc_free(target.ttype);
270 static int create_snapshot(struct discover_device *device)
272 struct target target;
275 if (!device->ramdisk || !device->ramdisk->base ||
276 !device->ramdisk->origin)
279 target.start_sector = 0;
280 target.end_sector = device->ramdisk->sectors;
282 target.ttype = talloc_asprintf(device, "snapshot");
283 target.params = talloc_asprintf(device, "%s %s P 8",
284 device->ramdisk->base, device->ramdisk->path);
285 if (!target.ttype || !target.params) {
286 pb_log("Failed to allocate snapshot parameters\n");
290 if (run_create_task(device->device->id, &target))
293 device->ramdisk->snapshot = talloc_asprintf(device, "/dev/mapper/%s",
295 if (!device->ramdisk->snapshot) {
296 pb_log("Failed to track new device /dev/mapper/%s\n",
304 talloc_free(target.params);
305 talloc_free(target.ttype);
309 int devmapper_init_snapshot(struct device_handler *handler,
310 struct discover_device *device)
312 struct ramdisk_device *ramdisk;
314 ramdisk = device_handler_get_ramdisk(handler);
316 pb_log("No ramdisk available for snapshot %s\n",
321 ramdisk->sectors = get_block_sectors(device);
322 if (!ramdisk->sectors) {
323 pb_log("Error retreiving sectors for %s\n",
328 device->ramdisk = ramdisk;
330 /* Create linear map */
331 if (create_base(device)) {
332 pb_log("Error creating linear base\n");
336 /* Create snapshot-origin */
337 if (create_origin(device)) {
338 pb_log("Error creating snapshot-origin\n");
342 if (set_device_active(device->ramdisk->origin, false)) {
343 pb_log("Failed to suspend origin\n");
347 /* Create snapshot */
348 if (create_snapshot(device)) {
349 pb_log("Error creating snapshot\n");
353 if (set_device_active(device->ramdisk->origin, true)) {
354 pb_log("Failed to resume origin\n");
358 pb_log("Snapshot successfully created for %s\n", device->device->id);
363 pb_log("Error creating snapshot devices for %s\n", device->device->id);
364 devmapper_destroy_snapshot(device);
368 /* Destroy specific dm device */
369 static int destroy_device(const char *dm_name)
371 struct dm_task *task;
375 task = dm_task_create(DM_DEVICE_REMOVE);
377 pb_log("%s: could not create dm_task\n", __func__);
381 if (!dm_task_set_name(task, dm_name)) {
382 pb_log("No dm device named '%s'\n", dm_name);
386 if (!set_cookie(task, &cookie))
389 if (!dm_task_run(task)) {
390 pb_log("Unable to remove device '%s'\n", dm_name);
396 /* Wait for /dev/mapper/ entries to be removed */
397 dm_udev_wait(cookie);
400 dm_task_destroy(task);
404 /* Destroy all dm devices related to a discover_device's snapshot */
405 int devmapper_destroy_snapshot(struct discover_device *device)
409 if (!device->ramdisk)
412 if (device->mounted) {
413 pb_log("Can not remove snapshot: %s is mounted\n",
418 /* Clean up dm devices in order */
419 if (device->ramdisk->snapshot)
420 if (destroy_device(device->ramdisk->snapshot))
423 if (device->ramdisk->origin)
424 if (destroy_device(device->ramdisk->origin))
427 if (device->ramdisk->base)
428 if (destroy_device(device->ramdisk->base))
434 pb_log("Warning: %s snapshot not cleanly removed\n",
436 device_handler_release_ramdisk(device);
440 static int reload_snapshot(struct discover_device *device, bool merge)
442 struct target target;
443 struct dm_task *task;
446 target.start_sector = 0;
447 target.end_sector = device->ramdisk->sectors;
450 target.ttype = talloc_asprintf(device, "snapshot-merge");
451 target.params = talloc_asprintf(device, "%s %s P 8",
452 device->ramdisk->base, device->ramdisk->path);
454 target.ttype = talloc_asprintf(device, "snapshot-origin");
455 target.params = talloc_asprintf(device, "%s",
456 device->ramdisk->base);
458 if (!target.ttype || !target.params) {
459 pb_log("%s: failed to allocate parameters\n", __func__);
463 task = dm_task_create(DM_DEVICE_RELOAD);
465 pb_log("%s: Error creating task\n", __func__);
469 if (!dm_task_set_name(task, device->ramdisk->origin)) {
470 pb_log("No dm-device named '%s'\n", device->ramdisk->origin);
474 if (!dm_task_add_target(task, target.start_sector, target.end_sector,
475 target.ttype, target.params)) {
476 pb_log("%s: Failed to set target\n", __func__);
480 if (!dm_task_run(task)) {
481 pb_log("Failed to reload %s\n", device->ramdisk->origin);
487 dm_task_destroy(task);
489 talloc_free(target.ttype);
490 talloc_free(target.params);
494 int devmapper_merge_snapshot(struct discover_device *device)
496 if (device->mounted) {
497 pb_log("%s: %s still mounted\n", __func__, device->device->id);
501 /* Suspend origin device */
502 if (set_device_active(device->ramdisk->origin, false)) {
503 pb_log("%s: failed to suspend %s\n",
504 __func__, device->ramdisk->origin);
508 /* Destroy snapshot */
509 if (destroy_device(device->ramdisk->snapshot)) {
510 /* The state of the snapshot is unknown, but try to
511 * resume to allow the snapshot to be remounted */
512 set_device_active(device->ramdisk->origin, true);
515 talloc_free(device->ramdisk->snapshot);
516 device->ramdisk->snapshot = NULL;
518 /* Reload origin device for merging */
519 reload_snapshot(device, true);
521 /* Resume origin device */
522 set_device_active(device->ramdisk->origin, true);
524 /* Block until merge complete */
525 while (!snapshot_merge_complete(device->ramdisk->origin))
526 usleep(MERGE_INTERVAL_US);
528 /* Suspend origin device */
529 set_device_active(device->ramdisk->origin, false);
531 /* Reload origin device */
532 reload_snapshot(device, false);
534 /* Re-create snapshot */
535 if (create_snapshot(device))
538 /* Resume origin device */
539 return set_device_active(device->ramdisk->origin, true);