void free_ploop_copy_handle(struct ploop_copy_handle *h) { if (h == NULL) return; pthread_mutex_destroy(&h->sd.mutex); pthread_cond_destroy(&h->sd.cond); pthread_mutex_destroy(&h->sd.wait_mutex); pthread_cond_destroy(&h->sd.wait_cond); unregister_cleanup_hook(h->cl); free(h->iobuf[0]); free(h->iobuf[1]); free(h); }
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; }