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; }
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 void *sender_thread(void *data) { struct ploop_copy_handle *h = data; struct sender_data *sd = &h->sd; int done; pthread_mutex_lock(&sd->mutex); ploop_dbg(3, "start sender_thread"); pthread_barrier_wait(&sd->barrier); do { pthread_cond_wait(&sd->cond, &sd->mutex); wakeup(&sd->wait_mutex, &sd->wait_cond); sd->ret = send_buf(h, sd->buf, sd->len, sd->pos); if (sd->ret) sd->err_no = errno; done = (sd->len == 0 && sd->pos == 0); } while (!done); pthread_mutex_unlock(&sd->mutex); ploop_log(3, "send_thread exited ret=%d", sd->ret); return NULL; }
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"); }
static int send_image_block(struct ploop_copy_handle *h, __u64 size, __u64 pos, ssize_t *nread) { struct delta *idelta = &h->idelta; void *iobuf = get_free_iobuf(h); ploop_dbg(4, "READ size=%llu pos=%llu", size, pos); *nread = pread(idelta->fd, iobuf, size, pos); if (*nread == 0) return 0; if (*nread < 0) { ploop_err(errno, "Error from read"); return SYSEXIT_READ; } return send_async(h, iobuf, *nread, pos); }
static int freeze_fs(struct ploop_copy_handle *h) { int ret; if (h->mntfd != -1) { /* Sync fs */ ploop_log(0, "Freezing fs..."); if (sys_syncfs(h->mntfd)) { ploop_err(errno, "syncfs() failed"); return SYSEXIT_FSYNC; } /* Flush journal and freeze fs (this also clears the fs dirty bit) */ ploop_dbg(3, "FIFREEZE"); ret = ioctl_device(h->mntfd, FIFREEZE, 0); if (ret) return ret; h->fs_frozen = 1; } return 0; }
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_receiver(struct ploop_copy_receive_param *arg) { int ofd, ret; __u64 cluster = 0; void *iobuf = NULL; int n; struct pcopy_pkt_desc desc; if (!arg) return SYSEXIT_PARAM; if (is_fd_socket(arg->ifd) != 1) { ploop_err(errno, "Invalid input fd %d: must be " "a pipe or a socket", arg->ifd); return SYSEXIT_PARAM; } ofd = open(arg->file, O_WRONLY|O_CREAT|O_TRUNC, 0600); if (ofd < 0) { ploop_err(errno, "Can't open %s", arg->file); return SYSEXIT_CREAT; } ploop_dbg(3, "RCV start %s", arg->file); for (;;) { if (nread(arg->ifd, &desc, sizeof(desc)) < 0) { ploop_err(errno, "Error in nread(desc)"); ret = SYSEXIT_READ; goto out; } if (desc.marker != PCOPY_MARKER) { ploop_err(0, "Stream corrupted"); ret = SYSEXIT_PROTOCOL; goto out; } if (desc.size > cluster) { free(iobuf); iobuf = NULL; cluster = desc.size; if (p_memalign(&iobuf, 4096, cluster)) { ret = SYSEXIT_MALLOC; goto out; } } if (desc.size == 0) break; if (nread(arg->ifd, iobuf, desc.size)) { ploop_err(errno, "Error in nread data"); ret = SYSEXIT_READ; goto out; } ploop_log(3, "RCV type=%d len=%d pos=%" PRIu64, desc.type, desc.size, (uint64_t)desc.pos); ret = 0; switch (desc.type) { case PCOPY_PKT_DATA: case PCOPY_PKT_DATA_ASYNC: { n = TEMP_FAILURE_RETRY(pwrite(ofd, iobuf, desc.size, desc.pos)); if (n != desc.size) { if (n < 0) ploop_err(errno, "Error in pwrite"); else ploop_err(0, "Error: short pwrite"); ret = SYSEXIT_WRITE; goto out; } break; } case PCOPY_PKT_CMD: { unsigned int cmd = ((unsigned int *) iobuf)[0]; switch(cmd) { case PCOPY_CMD_SYNC: ret = data_sync(ofd); if (ret) goto out; break; default: ploop_err(0, "ploop_copy_receiver: unsupported command %d", cmd); ret = SYSEXIT_PARAM; } break; } default: ploop_err(0, "ploop_copy_receiver: unsupported command type%d", desc.type); ret = SYSEXIT_PARAM; break; } /* send reply */ if (desc.type != PCOPY_PKT_DATA_ASYNC && nwrite(arg->ifd, &ret, sizeof(int))) { ret = SYSEXIT_WRITE; ploop_err(errno, "failed to send reply"); goto out; } } ret = data_sync(ofd); if (ret) goto out; ploop_dbg(3, "RCV exited"); /* send final reply */ ret = 0; if (nwrite(arg->ifd, &ret, sizeof(int))) { ret = SYSEXIT_WRITE; ploop_err(errno, "failed to send reply"); goto out; } out: if (close(ofd)) { ploop_err(errno, "Error in close"); if (!ret) ret = SYSEXIT_WRITE; } if (ret) unlink(arg->file); free(iobuf); return ret; }