Ejemplo n.º 1
0
Archivo: di.c Proyecto: grze/ploop
int ploop_add_snapshot_entry(struct ploop_disk_images_data *di, const char *guid,
		const char *parent_guid, int temporary)
{
	struct ploop_snapshot_data **tmp;
	struct ploop_snapshot_data *data;

	if (!is_valid_guid(guid)) {
		ploop_err(0, "ploop_add_snapshot_entry: invalid guid %s",
				guid);
		return SYSEXIT_PARAM;
	}
	if (!is_valid_guid(parent_guid)) {
		ploop_err(0, "ploop_add_snapshot_entry: invalid parent guid %s",
				parent_guid);
		return SYSEXIT_PARAM;
	}

	data = calloc(1, sizeof(struct ploop_snapshot_data));
	if (data == NULL) {
		ploop_err(ENOMEM, "calloc failed");
		return SYSEXIT_MALLOC;
	}

	tmp = realloc(di->snapshots, sizeof(struct ploop_snapshot_data *) * (di->nsnapshots+1));
	if (tmp == NULL) {
		ploop_err(ENOMEM, "realloc failed");
		free(data);
		return SYSEXIT_MALLOC;
	}
	di->snapshots = tmp;
	data->guid = strdup(guid);
	data->parent_guid = strdup(parent_guid);
	data->temporary = temporary;

	if (data->guid == NULL || data->parent_guid == NULL) {
		ploop_err(ENOMEM, "strdup failed");
		free_snapshot_data(data);
		return SYSEXIT_MALLOC;
	}

	di->snapshots[di->nsnapshots] = data;
	di->nsnapshots++;

	return 0;
}
Ejemplo n.º 2
0
static int validate_disk_descriptor(struct ploop_disk_images_data *di)
{
	if (di->nimages == 0) {
		ploop_err(0, "No images found in %s",
				di->runtime->xml_fname);
		return -1;
	}
	if (!is_valid_blocksize(di->blocksize)) {
		ploop_err(0, "Invalid block size %d", di->blocksize);
		return -1;
	}
	// FIXME: compatibility issue have to be removed before BETA
	if (di->nimages != di->nsnapshots) {
		int ret;

		ret = ploop_add_snapshot_entry(di, TOPDELTA_UUID, NONE_UUID, 0);
		if (ret)
			return ret;
		if (di->top_guid == NULL)
			di->top_guid = strdup(TOPDELTA_UUID);
	}
	if (di->top_guid == NULL && find_snapshot_by_guid(di, TOPDELTA_UUID) != -1) {
		/* Parallels VM compatibility.
		 * The top delta is hardcoded {5fbaabe3-6958-40ff-92a7-860e329aab41}
		 */
		di->top_guid = strdup(TOPDELTA_UUID);
	}


	if (!is_valid_guid(di->top_guid)) {
		ploop_err(0, "Validation of %s failed: invalid top delta %s",
				di->runtime->xml_fname, di->top_guid);
		return -1;
	}

	int i = find_snapshot_by_guid(di, di->top_guid);
	if (i == -1) {
		ploop_err(0, "Validation of %s failed: top delta %s is not found",
				di->runtime->xml_fname, di->top_guid);
		return -1;
	}

	if (di->snapshots[i]->temporary) {
		ploop_err(0, "Validation of %s failed: top delta %s is temporary",
				di->runtime->xml_fname, di->top_guid);
		return -1;
	}

	if (di->nimages != di->nsnapshots) {
		ploop_err(0, "Validation of %s failed: images(%d) != snapshots(%d)",
				di->runtime->xml_fname, di->nimages, di->nsnapshots);
		return -1;
	}
	return 0;
}
Ejemplo n.º 3
0
Archivo: di.c Proyecto: grze/ploop
int ploop_add_image_entry(struct ploop_disk_images_data *di, const char *fname, const char *guid)
{
	struct ploop_image_data **tmp;
	struct ploop_image_data *image;

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

	image = calloc(1, sizeof(struct ploop_image_data));
	if (image == NULL) {
		ploop_err(0, "calloc failed");
		return SYSEXIT_MALLOC;
	}

	tmp = realloc(di->images, sizeof(struct ploop_image_data *) * (di->nimages+1));
	if (tmp == NULL) {
		ploop_err(0, "realloc failed");
		free(image);
		return SYSEXIT_MALLOC;
	}
	di->images = tmp;
	image->guid = strdup(guid);
	image->file = strdup(fname);

	if (image->guid == NULL || image->file == NULL) {
		ploop_err(ENOMEM, "strdup failed");
		free_image_data(image);
		return SYSEXIT_MALLOC;
	}

	di->images[di->nimages] = image;
	di->nimages++;

	return 0;
}
Ejemplo n.º 4
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;
}
Ejemplo n.º 5
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;
}
Ejemplo n.º 6
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;
}