Пример #1
0
int ploop_discard(struct ploop_disk_images_data *di,
		struct ploop_discard_param *param)
{
	int ret;
	char dev[PATH_MAX];
	char mnt[PATH_MAX];
	int mounted = 0;

	if (ploop_lock_dd(di))
		return SYSEXIT_LOCK;

	ret = ploop_find_dev(di->runtime->component_name,
			di->images[0]->file, dev, sizeof(dev));
	if (ret == -1) {
		ploop_unlock_dd(di);
		return SYSEXIT_LOCK;
	} else if (ret == 0) {
		if (ploop_get_mnt_by_dev(dev, mnt, sizeof(mnt))) {
			ploop_err(0, "Unable to find mount point for %s", dev);
			ploop_unlock_dd(di);
			return SYSEXIT_PARAM;
		}
	} else {
		struct ploop_mount_param mount_param = {};

		if (!param->automount) {
			ploop_err(0, "Unable to discard: image is not mounted");
			ploop_unlock_dd(di);
			return SYSEXIT_PARAM;
		}
		ret = auto_mount_image(di, &mount_param);
		if (ret) {
			ploop_unlock_dd(di);
			return ret;
		}
		mounted = 1;
		snprintf(dev, sizeof(dev), "%s", mount_param.device);
		snprintf(mnt, sizeof(mnt), "%s", mount_param.target);

		free_mount_param(&mount_param);
	}
	ploop_unlock_dd(di);

	ret = do_ploop_discard(di, dev, mnt, param->minlen_b,
			param->to_free, param->stop);

	if (mounted && ploop_lock_dd(di) == 0) {
		ploop_umount(dev, di);
		ploop_unlock_dd(di);
	}

	return ret;
}
Пример #2
0
int ploop_create_snapshot(struct ploop_disk_images_data *di,
		struct ploop_snapshot_param *param)
{
	int ret;

	if (ploop_lock_dd(di))
		return SYSEXIT_LOCK;

	ret = do_create_snapshot(di, param->guid, param->snap_dir, 0);

	ploop_unlock_dd(di);

	return ret;
}
Пример #3
0
int ploop_delete_snapshot(struct ploop_disk_images_data *di, const char *guid)
{
	int ret;

	if (ploop_lock_dd(di))
		return SYSEXIT_LOCK;

	ret = do_delete_snapshot(di, guid);
	if (ret == 0)
		merge_temporary_snapshots(di);

	ploop_unlock_dd(di);

	return ret;
}
Пример #4
0
int ploop_create_snapshot_offline(struct ploop_disk_images_data *di,
		struct ploop_snapshot_param *param)
{
	int ret;

	if (ploop_lock_dd(di))
		return SYSEXIT_LOCK;

	ret = do_create_snapshot(di, param->guid, param->snap_dir,
			param->cbt_uuid, SNAP_TYPE_OFFLINE);

	ploop_unlock_dd(di);

	return ret;
}
Пример #5
0
static int ploop_get_dev_and_mnt(struct ploop_disk_images_data *di,
		char *dev, int dev_len, char *mnt, int mnt_len)
{
	if (ploop_lock_dd(di))
		return SYSEXIT_LOCK;

	if (ploop_find_dev(di->runtime->component_name,
			di->images[0]->file, dev, dev_len))
	{
		ploop_unlock_dd(di);
		return SYSEXIT_PARAM;
	}

	if (ploop_get_mnt_by_dev(dev, mnt, mnt_len)) {
		ploop_err(0, "Unable to find mount point for %s", dev);
		ploop_unlock_dd(di);
		return SYSEXIT_PARAM;
	}
	ploop_unlock_dd(di);

	return 0;
}
Пример #6
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;
}
Пример #7
0
int ploop_switch_snapshot_ex(struct ploop_disk_images_data *di,
		struct ploop_snapshot_switch_param *param)
{
	int ret;
	int fd;
	char dev[64];
	char uuid[UUID_SIZE];
	char file_uuid[UUID_SIZE];
	char new_top_delta_fname[PATH_MAX] = "";
	char *old_top_delta_fname = NULL;
	char conf[PATH_MAX];
	char conf_tmp[PATH_MAX];
	off_t size;
	const char *guid = param->guid;
	int flags = param->flags;
	__u32 blocksize;
	int version;
	int snap_id;

	if (!is_valid_guid(guid)) {
		ploop_err(0, "Incorrect guid %s", guid);
		return SYSEXIT_PARAM;
	}

	if (ploop_lock_dd(di))
		return SYSEXIT_LOCK;

	if (is_old_snapshot_format(di)) {
		ret = SYSEXIT_PARAM;
		goto err_cleanup1;

	}

	ret = SYSEXIT_PARAM;
	if (strcmp(di->top_guid, guid) == 0) {
		ploop_err(errno, "Nothing to do, already on %s snapshot",
				guid);
		goto err_cleanup1;
	}

	snap_id = find_snapshot_by_guid(di, guid);
	if (snap_id== -1) {
		ploop_err(0, "Can't find snapshot by uuid %s",
				guid);
		goto err_cleanup1;
	}

	if (di->snapshots[snap_id]->temporary) {
		ploop_err(0, "Snapshot %s is temporary", guid);
		goto err_cleanup1;
	}

	if (flags & PLOOP_SNAP_SKIP_TOPDELTA_CREATE) {
		ret = reset_top_delta(di, param);
		goto err_cleanup1;
	}

	// Read image param from snapshot we going to switch on
	ret = get_image_param(di, guid, &size, &blocksize, &version);
	if (ret)
		goto err_cleanup1;

	ret = gen_uuid_pair(uuid, sizeof(uuid), file_uuid, sizeof(file_uuid));
	if (ret) {
		ploop_err(errno, "Can't generate uuid");
		goto err_cleanup1;
	}

	if (!(flags & PLOOP_SNAP_SKIP_TOPDELTA_DESTROY)) {
		// device should be stopped
		ret = ploop_find_dev_by_dd(di, dev, sizeof(dev));
		if (ret == -1) {
			ret = SYSEXIT_SYS;
			goto err_cleanup1;
		} else if (ret == 0) {
			ret = SYSEXIT_PARAM;
			ploop_err(0, "Unable to perform switch to snapshot operation"
					" on running device (%s)",
					dev);
			goto err_cleanup1;
		}
		ret = ploop_di_remove_image(di, di->top_guid, 0, &old_top_delta_fname);
		if (ret)
			goto err_cleanup1;
	} else if (param->guid_old != NULL) {
		if (!is_valid_guid(param->guid_old)) {
			ret = SYSEXIT_PARAM;
			ploop_err(0, "Incorrect guid %s", param->guid_old);
			goto err_cleanup1;
		}

		if (find_snapshot_by_guid(di, param->guid_old) != -1) {
			ret = SYSEXIT_PARAM;
			ploop_err(0, "Incorrect guid_old %s: already exists",
					param->guid_old);
			goto err_cleanup1;
		}

		ploop_di_change_guid(di, di->top_guid, param->guid_old);
	}

	snprintf(new_top_delta_fname, sizeof(new_top_delta_fname), "%s.%s",
		di->images[0]->file, file_uuid);
	ret = ploop_di_add_image(di, new_top_delta_fname, TOPDELTA_UUID, guid);
	if (ret)
		goto err_cleanup1;

	get_disk_descriptor_fname(di, conf, sizeof(conf));
	snprintf(conf_tmp, sizeof(conf_tmp), "%s.tmp", conf);
	ret = ploop_store_diskdescriptor(conf_tmp, di);
	if (ret)
		goto err_cleanup1;

	// offline snapshot
	fd = create_snapshot_delta(new_top_delta_fname, blocksize, size, version);
	if (fd == -1) {
		ret = SYSEXIT_CREAT;
		goto err_cleanup2;
	}
	close(fd);

	if (rename(conf_tmp, conf)) {
		ploop_err(errno, "Can't rename %s %s",
				conf_tmp, conf);
		ret = SYSEXIT_RENAME;
		goto err_cleanup3;
	}

	/* destroy precached info */
	drop_statfs_info(di->images[0]->file);

	if (old_top_delta_fname != NULL) {
		ploop_log(0, "Removing %s", old_top_delta_fname);
		if (unlink(old_top_delta_fname) && errno != ENOENT)
			ploop_err(errno, "Can't unlink %s",
					old_top_delta_fname);
	}

	ploop_log(0, "ploop snapshot has been successfully switched");
err_cleanup3:
	if (ret && unlink(new_top_delta_fname))
		ploop_err(errno, "Can't unlink %s",
				conf_tmp);
err_cleanup2:
	if (ret && unlink(conf_tmp))
		ploop_err(errno, "Can't unlink %s",
				conf_tmp);
err_cleanup1:
	ploop_unlock_dd(di);
	free(old_top_delta_fname);

	return ret;
}
Пример #8
0
int ploop_create_temporary_snapshot(struct ploop_disk_images_data *di,
		struct ploop_tsnapshot_param *param, int *holder_fd)
{
	int ret;
	struct ploop_mount_param mount_param = { .ro = 1, };
	char component_name[PLOOP_COOKIE_SIZE];

	if (di == NULL || param == NULL)
		return SYSEXIT_PARAM;

	if (param->guid == NULL) {
		ploop_err(0, "Snapshot guid is not specified");
		return SYSEXIT_PARAM;
	}

	if (param->component_name == NULL) {
		ploop_err(0, "Component name is not specified");
		return SYSEXIT_PARAM;
	}

	if (ploop_lock_dd(di))
		return SYSEXIT_LOCK;

	ret = do_create_snapshot(di, param->guid, param->snap_dir, 1);
	if (ret)
		goto err_unlock;

	/* FIXME: should be processed from 'struct ploop_mount_param' only ?? */
	char *t = di->runtime->component_name;
	snprintf(component_name, sizeof(component_name), "%s%s",
			holder_fd == NULL ? TSNAPSHOT_MOUNT_LOCK_MARK : "",
			param->component_name);
	di->runtime->component_name = component_name;

	mount_param.guid = param->guid;
	mount_param.target = param->target;
	ret = mount_image(di, &mount_param);
	di->runtime->component_name = t;

	if (ret)
		goto err_merge;

	strncpy(param->device, mount_param.device, sizeof(param->device));
	param->device[sizeof(param->device) - 1] = '\0';

	if (holder_fd != NULL) {
		ret = open_snap_holder(param->device, holder_fd);
		if (ret)
			goto err;
	}

	ploop_unlock_dd(di);

	return 0;

err:
	ploop_umount(mount_param.device, di);

err_merge:
	ploop_merge_snapshot_by_guid(di, di->top_guid, NULL);

err_unlock:
	ploop_unlock_dd(di);

	return ret;
}

int is_device_inuse(const char *dev)
{
	int count;
	char fname[PATH_MAX];
	char cookie[PLOOP_COOKIE_SIZE] = "";

	if (ploop_get_attr(dev, "open_count", &count))
		return 1;

	/* detect if snapshot locked by ploop mount */
	snprintf(fname, sizeof(fname), "/sys/block/%s/pstate/cookie",
			memcmp(dev, "/dev/", 5) == 0 ? dev + 5 : dev);
	if (read_line_quiet(fname, cookie, sizeof(cookie)))
		return 1;

	if (!strncmp(cookie, TSNAPSHOT_MOUNT_LOCK_MARK,
				sizeof(TSNAPSHOT_MOUNT_LOCK_MARK)-1))
		return 1;

	/* snap holder + mount */
	if (count >= 2)
		return 1;

	/* if there single reference we should detect is holder is alive */
	if (count == 1 && ploop_get_mnt_by_dev(dev, fname, sizeof(fname)) != 0)
		return 1;

	return 0;
}