Exemplo n.º 1
0
static int reset_top_delta(struct ploop_disk_images_data *di,
		struct ploop_snapshot_switch_param *param)
{
	int ret;
	char *old_top_delta_fname = NULL;
	char conf[PATH_MAX];
	char conf_tmp[PATH_MAX];
	const char *guid = param->guid;

	ret = ploop_di_remove_image(di, di->top_guid, 0, &old_top_delta_fname);
	if (ret)
		return ret;

	ploop_di_change_guid(di, guid, TOPDELTA_UUID);

	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;

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

	/* 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))
			ploop_err(errno, "Can't unlink %s",
					old_top_delta_fname);
	}

err:
	if (ret && unlink(conf_tmp))
		ploop_err(errno, "Can't unlink %s", conf_tmp);

	free(old_top_delta_fname);

	return ret;
}
Exemplo n.º 2
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;
}
Exemplo n.º 3
0
static int do_create_snapshot(struct ploop_disk_images_data *di,
		const char *guid, const char *snap_dir, int temporary)
{
	int ret;
	int fd;
	char dev[64];
	char snap_guid[UUID_SIZE];
	char file_guid[UUID_SIZE];
	char fname[PATH_MAX];
	char conf[PATH_MAX];
	char conf_tmp[PATH_MAX];
	int online = 0;
	int n;
	off_t size;
	__u32 blocksize;
	int version;

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

	if (is_old_snapshot_format(di))
		return SYSEXIT_PARAM;

	ret = gen_uuid_pair(snap_guid, sizeof(snap_guid),
			file_guid, sizeof(file_guid));
	if (ret) {
		ploop_err(errno, "Can't generate uuid");
		return ret;
	}

	if (guid != NULL) {
		if (find_snapshot_by_guid(di, guid) != -1) {
			ploop_err(0, "The snapshot %s already exist",
				guid);
			return SYSEXIT_PARAM;
		}
		strcpy(snap_guid, guid);
	}
	n = get_snapshot_count(di);
	if (n == -1) {
		return SYSEXIT_PARAM;
	} else if (n > 128-2) {
		/* The number of images limited by 128
		   so the snapshot limit 128 - base_image - one_reserverd
		 */
		ploop_err(errno, "Unable to create a snapshot."
			" The maximum number of snapshots (%d) has been reached",
			n-1);
		return SYSEXIT_PARAM;
	}

	ret = ploop_find_dev_by_dd(di, dev, sizeof(dev));
	if (ret == -1)
		return SYSEXIT_SYS;
	else if (ret == 0) {
		online = 1;
		ret = complete_running_operation(di, dev);
		if (ret)
			return ret;
	} else {
		ret = get_image_param_offline(di, di->top_guid, &size, &blocksize, &version);
		if (ret == SYSEXIT_OPEN && errno == EBUSY) {
			/* repair top delta */
			char *topdelta[] = {find_image_by_guid(di, di->top_guid), NULL};
			blocksize = di->blocksize;

			ret = check_deltas(di, topdelta, 0, &blocksize);
			if (ret)
				return ret;

			ret = get_image_param_offline(di, di->top_guid, &size, &blocksize, &version);
		}

		if (ret)
			return ret;
	}

	ret = merge_temporary_snapshots(di);
	if (ret)
		return ret;

	if (snap_dir != NULL) {
		char *name;
		char *dir;

		dir = realpath(snap_dir, NULL);
		if (dir == NULL) {
			ploop_err(errno, "Error in realpath(%s)", snap_dir);
			return SYSEXIT_CREAT;
		}

		name = strrchr(di->images[0]->file, '/');
		if (name != NULL)
			name++;
		else
			name = di->images[0]->file;
		snprintf(fname, sizeof(fname), "%s/%s.%s",
				dir, name,	file_guid);
		free(dir);
	} else
		snprintf(fname, sizeof(fname), "%s.%s",
				di->images[0]->file, file_guid);

	ploop_di_change_guid(di, di->top_guid, snap_guid);
	if (temporary)
		ploop_di_set_temporary(di, snap_guid);

	ret = ploop_di_add_image(di, fname, TOPDELTA_UUID, snap_guid);
	if (ret)
		return ret;

	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)
		return ret;

	if (!online) {
		// offline snapshot
		fd = create_snapshot_delta(fname, blocksize, size, version);
		if (fd < 0) {
			ret = SYSEXIT_CREAT;
			goto err;
		}
		close(fd);
	} else {
		// Always sync fs
		ret = create_snapshot(dev, fname, 1);
		if (ret)
			goto err;
	}

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

	if (ret && !online && unlink(fname))
		ploop_err(errno, "Can't unlink %s",
				fname);

	ploop_log(0, "ploop %s %s has been successfully created",
			get_snap_str(temporary), snap_guid);
err:
	if (ret && unlink(conf_tmp))
		ploop_err(errno, "Can't unlink %s", conf_tmp);

	return ret;
}
Exemplo n.º 4
0
/* delete snapshot by guid
 * 1) if guid is not active and last -> delete guid
 * 2) if guid is not last merge with child -> delete child
 */
static int do_delete_snapshot(struct ploop_disk_images_data *di, const char *guid)
{
	int ret;
	char conf[PATH_MAX];
	int nelem = 0;
	char dev[64];
	int snap_id;

	if (is_old_snapshot_format(di))
		return SYSEXIT_PARAM;

	snap_id = find_snapshot_by_guid(di, guid);
	if (snap_id == -1) {
		ploop_err(0, "Can't find snapshot by uuid %s",
				guid);
		return SYSEXIT_NOSNAP;
	}
	ret = ploop_find_dev_by_dd(di, dev, sizeof(dev));
	if (ret == -1)
		return SYSEXIT_SYS;
	else if (ret == 0 && strcmp(di->top_guid, guid) == 0) {
		ret = SYSEXIT_PARAM;
		ploop_err(0, "Unable to delete active snapshot %s",
				guid);
		return SYSEXIT_PARAM;
	}

	nelem = ploop_get_child_count_by_uuid(di, guid);
	if (nelem == 0) {
		struct ploop_snapshot_data *snap =  di->snapshots[snap_id];

		if (strcmp(snap->parent_guid, NONE_UUID) == 0) {
			ploop_err(0, "Unable to delete base image");
			return SYSEXIT_PARAM;
		}

		if (strcmp(di->top_guid, guid) == 0) {
			int id = find_snapshot_by_guid(di, snap->parent_guid);
			if (id == -1) {
				ploop_err(0, "Can't find snapshot by uuid %s",
						snap->parent_guid);
				return SYSEXIT_PARAM;
			}

			if (di->snapshots[id]->temporary) {
				ploop_err(0, "Unable to delete top delta,"
						" parent snapshot is temporary");
				return SYSEXIT_PARAM;
			}
		}

		char *fname = find_image_by_guid(di, guid);
		if (fname == NULL) {
			ploop_err(0, "Unable to find image by uuid %s",
					guid);
			return SYSEXIT_PARAM;
		}

		ret = check_snapshot_mount(di, guid, fname, snap->temporary);
		if (ret)
			return ret;

		fname = NULL;
		/* snapshot is not active and last -> delete */
		ret = ploop_di_remove_image(di, guid, 1, &fname);
		if (ret)
			return ret;
		get_disk_descriptor_fname(di, conf, sizeof(conf));
		ret = ploop_store_diskdescriptor(conf, di);
		if (ret) {
			free(fname);
			return ret;
		}
		ploop_log(0, "Removing %s", fname);
		if (fname != NULL && unlink(fname)) {
			ploop_err(errno, "unlink %s", fname);
			free(fname);
			return SYSEXIT_UNLINK;
		}

		free(fname);
		if (ret == 0)
			ploop_log(0, "ploop snapshot %s has been successfully deleted",
				guid);
	} else if (nelem == 1) {
		const char *child_guid = ploop_find_child_by_guid(di, guid);
		if (child_guid == NULL) {
			ploop_err(0, "Can't find child of uuid %s", guid);
			return SYSEXIT_PARAM;
		}
		ret = ploop_merge_snapshot_by_guid(di, child_guid, NULL);
	} else if (!di->snapshots[snap_id]->temporary) {
		ploop_log(1, "Warning: Unable to delete snapshot %s as there are %d references"
				" to it; marking it as temporary instead",
				guid, nelem);
		di->snapshots[snap_id]->temporary = 1;
		get_disk_descriptor_fname(di, conf, sizeof(conf));
		ret = ploop_store_diskdescriptor(conf, di);
	}

	return ret;
}
Exemplo n.º 5
0
int do_create_snapshot(struct ploop_disk_images_data *di,
		const char *guid, const char *snap_dir,
		const char *cbt_uuid, int flags)
{
	int ret, rc;
	int fd;
	char dev[64];
	char snap_guid[UUID_SIZE];
	char top_guid[UUID_SIZE];
	char file_guid[UUID_SIZE];
	char fname[PATH_MAX];
	const char *prev_fname = NULL;
	char conf[PATH_MAX];
	char conf_tmp[PATH_MAX];
	int online = 0;
	int temporary = flags & SNAP_TYPE_TEMPORARY;
	int n;
	off_t size;
	__u32 blocksize;
	int version;
	uuid_t u;
	const __u8 *cbt_u = NULL;

	if (cbt_uuid != NULL) {
		ploop_log(0, "Create snapshot CBT uuid=%s", cbt_uuid);
		if (uuid_parse(cbt_uuid, u)) {
			ploop_log(-1, "Incorrect cbt uuid is specified %s",
					cbt_uuid);
			return SYSEXIT_PARAM;
		}
		cbt_u = u;
	}

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

	if (is_old_snapshot_format(di))
		return SYSEXIT_PARAM;

	ret = gen_uuid_pair(snap_guid, sizeof(snap_guid),
			file_guid, sizeof(file_guid));
	if (ret)
		return ret;

	if (di->vol && di->vol->parent) {
	        ret = ploop_uuid_generate(top_guid, sizeof(top_guid));
        	if (ret)
                	return ret;
	} else
		strcpy(top_guid, TOPDELTA_UUID);

	if (guid != NULL) {
		if (find_snapshot_by_guid(di, guid) != -1) {
			ploop_err(0, "The snapshot %s already exist",
				guid);
			return SYSEXIT_PARAM;
		}
		strcpy(snap_guid, guid);
	}
	n = get_snapshot_count(di);
	if (n == -1) {
		return SYSEXIT_PARAM;
	} else if (n > 128-2) {
		/* The number of images limited by 128
		   so the snapshot limit 128 - base_image - one_reserverd
		 */
		ploop_err(errno, "Unable to create a snapshot."
			" The maximum number of snapshots (%d) has been reached",
			n-1);
		return SYSEXIT_PARAM;
	}

	rc = ploop_find_dev_by_dd(di, dev, sizeof(dev));
	if (rc == -1)
		return SYSEXIT_SYS;

	if (rc == 0) {
		if (flags & SNAP_TYPE_OFFLINE) {
			ret = get_image_param_online(dev, &size,
					&blocksize, &version);
		} else {
			online = 1;
			ret = complete_running_operation(di, dev);
		}
		if (ret)
			return ret;
	} else {
		ret = get_image_param_offline(di, di->top_guid, &size, &blocksize, &version);
		if (ret == SYSEXIT_OPEN && errno == EBUSY) {
			/* repair top delta */
			char *topdelta[] = {find_image_by_guid(di, di->top_guid), NULL};
			blocksize = di->blocksize;

			ret = check_deltas(di, topdelta, 0, &blocksize, NULL);
			if (ret)
				return ret;

			ret = get_image_param_offline(di, di->top_guid, &size, &blocksize, &version);
		}

		if (ret)
			return ret;
	}

	ret = merge_temporary_snapshots(di);
	if (ret)
		return ret;

	if (snap_dir != NULL) {
		char *name;
		char *dir;

		dir = realpath(snap_dir, NULL);
		if (dir == NULL) {
			ploop_err(errno, "Error in realpath(%s)", snap_dir);
			return SYSEXIT_CREAT;
		}

		name = strrchr(di->images[0]->file, '/');
		if (name != NULL)
			name++;
		else
			name = di->images[0]->file;
		snprintf(fname, sizeof(fname), "%s/%s.%s",
				dir, name,	file_guid);
		free(dir);
	} else
		snprintf(fname, sizeof(fname), "%s.%s",
				di->images[0]->file, file_guid);

	prev_fname = find_image_by_guid(di, di->top_guid);
	if (prev_fname == NULL) {
		ploop_err(0, "Unable to find image by uuid %s",
				di->top_guid);
		return SYSEXIT_PARAM;
	}

	ploop_di_change_guid(di, di->top_guid, snap_guid);
	if (temporary)
		ploop_di_set_temporary(di, snap_guid);

	ret = ploop_di_add_image(di, fname, top_guid, snap_guid);
	if (ret)
		return ret;

	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)
		return ret;

	if (!online) {
		// offline snapshot
		ret = 0;
		fd = create_snapshot_delta(fname, blocksize, size, version);
		if (fd < 0) {
			ret = SYSEXIT_CREAT;
			goto err;
		}
		close(fd);

		if (cbt_u != NULL)
			ret = write_empty_cbt_to_image(fname, prev_fname, cbt_u);
		else if (di->mode != PLOOP_RAW_MODE) {
			if (rc == 0)
				ret = cbt_dump(di, dev, fname);
			else
				ret = ploop_move_cbt(fname, prev_fname);
		}
		if (ret)
			goto err;
	} else {
		// Always sync fs
		ret = create_snapshot(dev, fname, 1, cbt_u, prev_fname);
		if (ret)
			goto err;
	}

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

	if (ret && !online && unlink(fname))
		ploop_err(errno, "Can't unlink %s",
				fname);

	ploop_log(0, "ploop %s %s has been successfully created",
			get_snap_str(temporary), snap_guid);
err:
	if (ret && unlink(conf_tmp))
		ploop_err(errno, "Can't unlink %s", conf_tmp);

	return ret;
}