Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
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;
}