static int freeze(struct ploop_copy_handle *h) { int ret; ret = ioctl(h->partfd, PLOOP_IOC_FREEZE); if (ret) { if (errno == EINVAL) ret = freeze_fs(h); else ploop_err(errno, "Failed to freeze device"); if (ret) goto err; } else { ploop_log(0, "Freezing device..."); h->dev_frozen = 1; } ploop_dbg(3, "IOC_SYNC"); ret = ioctl_device(h->devfd, PLOOP_IOC_SYNC, 0); if (ret) goto err; return 0; err: ploop_copy_release(h); return ret; }
static int freeze_fs(struct ploop_copy_handle *h) { int ret; if (h->mntfd != -1) { /* Sync fs */ ploop_dbg(4, "SYNCFS"); if (sys_syncfs(h->mntfd)) { ploop_err(errno, "syncfs() failed"); ret = SYSEXIT_FSYNC; goto err; } /* Flush journal and freeze fs (this also clears the fs dirty bit) */ ploop_dbg(4, "FIFREEZE"); ret = ioctl_device(h->mntfd, FIFREEZE, 0); if (ret) goto err; h->fs_frozen = 1; } ploop_dbg(4, "IOC_SYNC"); ret = ioctl_device(h->devfd, PLOOP_IOC_SYNC, 0); if (ret) goto err; return 0; err: ploop_copy_release(h); return ret; }
int ploop_copy_start(struct ploop_copy_handle *h, struct ploop_copy_stat *stat) { int ret; struct ploop_track_extent e; ssize_t n; __u64 pos; ret = pthread_create(&h->send_th, NULL, sender_thread, h); if (ret) { ploop_err(ret, "Can't create send thread"); ret = SYSEXIT_SYS; goto err; } pthread_barrier_wait(&h->sd.barrier); ploop_dbg(3, "pcopy track init"); ret = ioctl_device(h->devfd, PLOOP_IOC_TRACK_INIT, &e); if (ret) goto err; h->tracker_on = 1; h->trackend = e.end; ploop_log(3, "pcopy start %s e.end=%" PRIu64, h->async ? "async" : "", (uint64_t)e.end); for (pos = 0; pos <= h->trackend; ) { h->trackpos = pos + h->cluster; ret = ioctl_device(h->devfd, PLOOP_IOC_TRACK_SETPOS, &h->trackpos); if (ret) goto err; ret = send_image_block(h, h->cluster, pos, &n); if (ret) goto err; if (n == 0) /* EOF */ break; pos += n; if (pos > h->eof_offset) h->eof_offset = pos; } wait_sender(h); stat->xferred_total = stat->xferred = pos; send_cmd(h, PCOPY_CMD_SYNC); ploop_dbg(3, "pcopy start finished"); return 0; err: ploop_copy_release(h); return ret; }
void ploop_copy_deinit(struct ploop_copy_handle *h) { if (h == NULL) return; ploop_dbg(4, "pcopy deinit"); pthread_mutex_unlock(&h->sd.wait_mutex); if (h->send_th) { pthread_cancel(h->send_th); pthread_join(h->send_th, NULL); h->send_th = 0; } ploop_copy_release(h); free_ploop_copy_handle(h); ploop_dbg(3, "pcopy deinit done"); }
int ploop_copy_stop(struct ploop_copy_handle *h, struct ploop_copy_stat *stat) { int ret; int iter; ploop_log(3, "pcopy last"); ret = freeze(h); if (ret) goto err; iter = 1; for (;;) { ret = ploop_copy_next_iteration(h, stat); if (ret) goto err; else if (stat->xferred == 0) break; if (iter++ > 2) { ploop_err(0, "Too many iterations on frozen FS, aborting"); return SYSEXIT_LOOP; } } if (!h->raw) { /* Must clear dirty flag on ploop1 image. */ struct ploop_pvd_header *vh = get_free_iobuf(h); if (PREAD(&h->idelta, vh, 4096, 0)) { ret = SYSEXIT_READ; goto err; } vh->m_DiskInUse = 0; ploop_dbg(3, "Update header"); ret = send_buf(h, vh, 4096, 0); if (ret) goto err; ret = send_optional_header(h); if (ret) goto err; } ploop_dbg(4, "IOCTL TRACK_STOP"); ret = ioctl(h->devfd, PLOOP_IOC_TRACK_STOP, 0); if (ret) goto err; h->tracker_on = 0; ploop_dbg(3, "SEND 0 0 (close)"); send_async(h, NULL, 0, 0); pthread_join(h->send_th, NULL); h->send_th = 0; ploop_dbg(3, "pcopy stop done"); err: ploop_copy_release(h); return ret; }
int ploop_copy_next_iteration(struct ploop_copy_handle *h, struct ploop_copy_stat *stat) { struct ploop_track_extent e; int ret = 0; int done = 0; __u64 pos; __u64 iterpos = 0; stat->xferred = 0; ploop_dbg(3, "pcopy iter %d", h->niter); do { if (ioctl(h->devfd, PLOOP_IOC_TRACK_READ, &e)) { if (errno == EAGAIN) /* no more dirty blocks */ break; ploop_err(errno, "PLOOP_IOC_TRACK_READ"); ret = SYSEXIT_DEVIOC; goto err; } if (e.end > h->trackend) h->trackend = e.end; if (e.start < iterpos) done = 1; iterpos = e.end; stat->xferred += e.end - e.start; for (pos = e.start; pos < e.end; ) { ssize_t n; __u64 copy = e.end - pos; if (copy > h->cluster) copy = h->cluster; if (pos + copy > h->trackpos) { h->trackpos = pos + copy; if (ioctl(h->devfd, PLOOP_IOC_TRACK_SETPOS, &h->trackpos)) { ploop_err(errno, "PLOOP_IOC_TRACK_SETPOS"); ret = SYSEXIT_DEVIOC; goto err; } } ret = send_image_block(h, copy, pos, &n); if (ret) goto err; if (n != copy) { ploop_err(errno, "Short read"); ret = SYSEXIT_READ; goto err; } pos += n; if (pos > h->eof_offset) h->eof_offset = pos; } } while (!done); wait_sender(h); /* sync after each iteration */ ret = send_cmd(h, PCOPY_CMD_SYNC); if (ret) goto err; stat->xferred_total += stat->xferred; ploop_log(3, "pcopy iter %d xferred=%" PRIu64, h->niter++, (uint64_t)stat->xferred); return 0; err: ploop_copy_release(h); return ret; }
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; }