int ploop_copy_init(struct ploop_disk_images_data *di, struct ploop_copy_param *param, struct ploop_copy_handle **h) { int ret, err; int blocksize; char *image = NULL; char *format = NULL; char device[64]; char partdev[64]; struct ploop_copy_handle *_h = NULL; int is_remote; char mnt[PATH_MAX] = ""; is_remote = is_fd_socket(param->ofd); if (is_remote < 0) { ploop_err(0, "Invalid output fd %d: must be a file, " "a pipe or a socket", param->ofd); return SYSEXIT_PARAM; } if (param->ofd == STDOUT_FILENO) ploop_set_verbose_level(PLOOP_LOG_NOSTDOUT); else if (param->ofd == STDERR_FILENO) ploop_set_verbose_level(PLOOP_LOG_NOCONSOLE); if (ploop_lock_dd(di)) return SYSEXIT_LOCK; if (ploop_find_dev_by_dd(di, device, sizeof(device))) { ploop_err(0, "Can't find running ploop device"); ret = SYSEXIT_SYS; goto err; } ret = get_image_info(device, &image, &format, &blocksize); if (ret) goto err; _h = alloc_ploop_copy_handle(S2B(blocksize)); if (_h == NULL) { ploop_err(0, "alloc_ploop_copy_handle"); ret = SYSEXIT_MALLOC; goto err; } _h->raw = strcmp(format, "raw") == 0; _h->ofd = param->ofd; _h->is_remote = is_remote; _h->async = param->async; _h->devfd = open(device, O_RDONLY|O_CLOEXEC); if (_h->devfd == -1) { ploop_err(errno, "Can't open device %s", device); ret = SYSEXIT_DEVICE; goto err; } ret = get_partition_device_name(device, partdev, sizeof(partdev)); if (ret) goto err; _h->partfd = open(partdev, O_RDONLY|O_CLOEXEC); if (_h->partfd == -1) { ploop_err(errno, "Can't open device %s", partdev); ret = SYSEXIT_DEVICE; goto err; } ret = SYSEXIT_OPEN; err = ploop_get_mnt_by_dev(device, mnt, sizeof(mnt)); if (err == -1) goto err; else if (err == 0) { _h->mntfd = open(mnt, O_RDONLY|O_NONBLOCK|O_DIRECTORY); if (_h->mntfd < 0) { ploop_err(errno, "Can't open %s", mnt); goto err; } } ploop_log(0, "Send image %s dev=%s mnt=%s fmt=%s blocksize=%d local=%d", image, device, mnt, format, blocksize, !is_remote); if (open_delta(&_h->idelta, image, O_RDONLY|O_DIRECT, OD_ALLOW_DIRTY)) { ret = SYSEXIT_OPEN; goto err; } ret = complete_running_operation(di, device); if (ret) goto err; _h->cl = register_cleanup_hook(cancel_sender, _h); pthread_mutex_lock(&_h->sd.wait_mutex); err: if (ret) { ploop_copy_release(_h); free_ploop_copy_handle(_h); } else *h = _h; free(image); ploop_unlock_dd(di); return ret; }
static int __ploop_discard(struct ploop_disk_images_data *di, int fd, const char *device, const char *mount_point, __u64 minlen_b, __u32 cluster, __u32 to_free, __u64 blk_discard_range[2], const int *stop) { pid_t tpid; int err = 0, ret, status; __u32 size = 0; struct ploop_cleanup_hook *h; if (blk_discard_range != NULL) ploop_log(0, "Discard %s start=%" PRIu64 " length=%" PRIu64, device, (uint64_t)blk_discard_range[0], (uint64_t)blk_discard_range[1]); else ploop_log(3, "Trying to find free extents bigger than %" PRIu64 " bytes", (uint64_t)minlen_b); if (ploop_lock_di(di)) return SYSEXIT_LOCK; ret = ioctl_device(fd, PLOOP_IOC_DISCARD_INIT, NULL); ploop_unlock_di(di); if (ret) { ploop_err(errno, "Can't initialize discard mode"); return ret; } tpid = fork(); if (tpid < 0) { ploop_err(errno, "Can't fork"); ret = ioctl_device(fd, PLOOP_IOC_DISCARD_FINI, NULL); if (ret) { ploop_err(errno, "Can't finalize discard mode"); return ret; } } h = register_cleanup_hook(cancel_discard, (void *) device); if (tpid == 0) { if (blk_discard_range != NULL) ret = blk_discard(fd, cluster, blk_discard_range[0], blk_discard_range[1]); else ret = ploop_trim(mount_point, minlen_b, cluster); if (ioctl_device(fd, PLOOP_IOC_DISCARD_FINI, NULL)) ploop_err(errno, "Can't finalize discard mode"); exit(ret != 0); } while (1) { struct ploop_balloon_ctl b_ctl; ploop_log(3, "Waiting"); ret = ioctl(fd, PLOOP_IOC_DISCARD_WAIT, NULL); if (ret < 0) { ploop_err(errno, "Waiting for a discard request failed"); break; } else if (ret == 0) break; /* FIXME PLOOP_IOC_DISCARD_WAIT should return size */ ret = ioctl(fd, PLOOP_IOC_FBFILTER, 0); if (ret < 0) { ploop_err(errno, "Can't filter free blocks"); break; } else if (ret == 0) { /* Nothing to do */ ret = ioctl_device(fd, PLOOP_IOC_FBDROP, 0); if (ret) break; continue; } else size += ret; /* serialize ploop operations vs ploop_complete_running_operation() * NB: PLOOP_IOC_BALLOON may change mntn from PLOOP_MNTN_DISCARD: * to PLOOP_MNTN_FBLOADED */ if (ploop_lock_di(di)) { ret = SYSEXIT_LOCK; break; } memset(&b_ctl, 0, sizeof(b_ctl)); b_ctl.keep_intact = 1; ret = ioctl_device(fd, PLOOP_IOC_BALLOON, &b_ctl); if (ret) { ploop_unlock_di(di); break; } if (b_ctl.mntn_type == PLOOP_MNTN_OFF) { ploop_log(0, "Unexpected maintenance type 0x%x", b_ctl.mntn_type); ret = -1; ploop_unlock_di(di); break; } if (size >= to_free || (stop && *stop)) { ploop_log(3, "Killing the trim process %d", tpid); kill(tpid, SIGUSR1); ret = ioctl(fd, PLOOP_IOC_DISCARD_FINI); if (ret < 0 && errno != EBUSY) ploop_err(errno, "Can't finalize a discard mode"); } ploop_log(0, "Starting relocation"); ret = ploop_balloon_relocation(fd, &b_ctl, device); ploop_unlock_di(di); if (ret) break; } if (ret) { err = -1; ret = ioctl(fd, PLOOP_IOC_DISCARD_FINI); if (ret < 0) { if (errno == EBUSY) ploop_log(-1, "Discard finalized, but " "relocation is still not completed"); else ploop_err(errno, "Can't finalize discard mode"); } kill(tpid, SIGKILL); } else { ploop_log(0, "%d clusters have been relocated", size); } unregister_cleanup_hook(h); while ((ret = waitpid(tpid, &status, 0))) if (errno != EINTR) break; if (ret == -1) { if (errno != ECHILD) ploop_err(errno, "wait() failed"); err = -1; } else if (WIFEXITED(status)) { ret = WEXITSTATUS(status); if (ret) { ploop_err(0, "The trim process failed with code %d", ret); err = -1; } } else if (WIFSIGNALED(status)) { ploop_err(0, "The trim process killed by signal %d", WTERMSIG(status)); err = -1; } else { ploop_err(0, "The trim process died abnormally"); err = -1; } return err; }