Esempio n. 1
0
/* Create list of PVs for allocation of replacement extents */
static struct dm_list *_get_allocatable_pvs(struct cmd_context *cmd, int argc,
					 char **argv, struct volume_group *vg,
					 struct physical_volume *pv,
					 alloc_policy_t alloc)
{
	struct dm_list *allocatable_pvs, *pvht, *pvh;
	struct pv_list *pvl;

	if (argc)
		allocatable_pvs = create_pv_list(cmd->mem, vg, argc, argv, 1);
	else
		allocatable_pvs = clone_pv_list(cmd->mem, &vg->pvs);

	if (!allocatable_pvs)
		return_NULL;

	dm_list_iterate_safe(pvh, pvht, allocatable_pvs) {
		pvl = dm_list_item(pvh, struct pv_list);

		/* Don't allocate onto the PV we're clearing! */
		if ((alloc != ALLOC_ANYWHERE) && (pvl->pv->dev == pv_dev(pv))) {
			dm_list_del(&pvl->list);
			continue;
		}

		/* Remove PV if full */
		if (pvl->pv->pe_count == pvl->pv->pe_alloc_count)
			dm_list_del(&pvl->list);
	}
Esempio n. 2
0
static int _pv_resize_single(struct cmd_context *cmd,
			     struct volume_group *vg,
			     struct physical_volume *pv,
			     const uint64_t new_size)
{
	struct pv_list *pvl;
	uint64_t size = 0;
	uint32_t new_pe_count = 0;
	int r = 0;
	struct dm_list mdas;
	const char *pv_name = pv_dev_name(pv);
	const char *vg_name;
	struct lvmcache_info *info;
	int mda_count = 0;
	struct volume_group *old_vg = vg;

	dm_list_init(&mdas);

	if (is_orphan_vg(pv_vg_name(pv))) {
		vg_name = VG_ORPHANS;
		if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) {
			log_error("Can't get lock for orphans");
			return 0;
		}

		if (!(pv = pv_read(cmd, pv_name, &mdas, NULL, 1, 0))) {
			unlock_vg(cmd, vg_name);
			log_error("Unable to read PV \"%s\"", pv_name);
			return 0;
		}

		mda_count = dm_list_size(&mdas);
	} else {
		vg_name = pv_vg_name(pv);

		vg = vg_read_for_update(cmd, vg_name, NULL, 0);

		if (vg_read_error(vg))
			goto bad;

		if (!(pvl = find_pv_in_vg(vg, pv_name))) {
			log_error("Unable to find \"%s\" in volume group \"%s\"",
				  pv_name, vg->name);
			goto bad;
		}

		pv = pvl->pv;

		if (!(info = info_from_pvid(pv->dev->pvid, 0))) {
			log_error("Can't get info for PV %s in volume group %s",
				  pv_name, vg->name);
			goto bad;
		}

		mda_count = dm_list_size(&info->mdas);

		if (!archive(vg))
			goto bad;
	}

	/* FIXME Create function to test compatibility properly */
	if (mda_count > 1) {
		log_error("%s: too many metadata areas for pvresize", pv_name);
		goto bad;
	}

	if (!(pv->fmt->features & FMT_RESIZE_PV)) {
		log_error("Physical volume %s format does not support resizing.",
			  pv_name);
		goto bad;
	}

	/* Get new size */
	if (!dev_get_size(pv_dev(pv), &size)) {
		log_error("%s: Couldn't get size.", pv_name);
		goto bad;
	}

	if (new_size) {
		if (new_size > size)
			log_warn("WARNING: %s: Overriding real size. "
				  "You could lose data.", pv_name);
		log_verbose("%s: Pretending size is %" PRIu64 " not %" PRIu64
			    " sectors.", pv_name, new_size, pv_size(pv));
		size = new_size;
	}

	if (size < PV_MIN_SIZE) {
		log_error("%s: Size must exceed minimum of %ld sectors.",
			  pv_name, PV_MIN_SIZE);
		goto bad;
	}

	if (size < pv_pe_start(pv)) {
		log_error("%s: Size must exceed physical extent start of "
			  "%" PRIu64 " sectors.", pv_name, pv_pe_start(pv));
		goto bad;
	}

	pv->size = size;

	if (vg) {
		pv->size -= pv_pe_start(pv);
		new_pe_count = pv_size(pv) / vg->extent_size;

 		if (!new_pe_count) {
			log_error("%s: Size must leave space for at "
				  "least one physical extent of "
				  "%" PRIu32 " sectors.", pv_name,
				  pv_pe_size(pv));
			goto bad;
		}

		if (!pv_resize(pv, vg, new_pe_count))
			goto_bad;
	}

	log_verbose("Resizing volume \"%s\" to %" PRIu64 " sectors.",
		    pv_name, pv_size(pv));

	log_verbose("Updating physical volume \"%s\"", pv_name);
	if (!is_orphan_vg(pv_vg_name(pv))) {
		if (!vg_write(vg) || !vg_commit(vg)) {
			log_error("Failed to store physical volume \"%s\" in "
				  "volume group \"%s\"", pv_name, vg->name);
			goto bad;
		}
		backup(vg);
	} else if (!(pv_write(cmd, pv, NULL, INT64_C(-1)))) {
		log_error("Failed to store physical volume \"%s\"",
			  pv_name);
		goto bad;;
	}

	log_print("Physical volume \"%s\" changed", pv_name);
	r = 1;

bad:
	unlock_vg(cmd, vg_name);
	if (!old_vg)
		vg_release(vg);
	return r;
}
Esempio n. 3
0
static int pvcreate_single(struct cmd_context *cmd, const char *pv_name,
			   void *handle)
{
	struct pvcreate_params *pp = (struct pvcreate_params *) handle;
	void *pv;
	void *existing_pv;
	struct id id, *idp = NULL;
	const char *uuid = NULL;
	uint64_t size = 0;
	struct device *dev;
	struct list mdas;
	int pvmetadatacopies;
	uint64_t pvmetadatasize;
	struct volume_group *vg;
	const char *restorefile;
	uint64_t pe_start = 0;
	uint32_t extent_count = 0, extent_size = 0;

	if (arg_count(cmd, uuidstr_ARG)) {
		uuid = arg_str_value(cmd, uuidstr_ARG, "");
		if (!id_read_format(&id, uuid))
			return EINVALID_CMD_LINE;
		if ((dev = device_from_pvid(cmd, &id)) &&
		    (dev != dev_cache_get(pv_name, cmd->filter))) {
			log_error("uuid %s already in use on \"%s\"", uuid,
				  dev_name(dev));
			return ECMD_FAILED;
		}
		idp = &id;
	}

	if (arg_count(cmd, restorefile_ARG)) {
		restorefile = arg_str_value(cmd, restorefile_ARG, "");
		/* The uuid won't already exist */
		init_partial(1);
		if (!(vg = backup_read_vg(cmd, NULL, restorefile))) {
			log_error("Unable to read volume group from %s",
				  restorefile);
			return ECMD_FAILED;
		}
		init_partial(0);
		if (!(existing_pv = find_pv_in_vg_by_uuid(vg, idp))) {
			log_error("Can't find uuid %s in backup file %s",
				  uuid, restorefile);
			return ECMD_FAILED;
		}
		pe_start = pv_pe_start(existing_pv);
		extent_size = pv_pe_size(existing_pv);
		extent_count = pv_pe_count(existing_pv);
	}

	if (!lock_vol(cmd, ORPHAN, LCK_VG_WRITE)) {
		log_error("Can't get lock for orphan PVs");
		return ECMD_FAILED;
	}

	if (!pvcreate_check(cmd, pv_name))
		goto error;

	if (sigint_caught())
		goto error;

	if (arg_sign_value(cmd, physicalvolumesize_ARG, 0) == SIGN_MINUS) {
		log_error("Physical volume size may not be negative");
		goto error;
	}
	size = arg_uint64_value(cmd, physicalvolumesize_ARG, UINT64_C(0)) * 2;

	if (arg_sign_value(cmd, metadatasize_ARG, 0) == SIGN_MINUS) {
		log_error("Metadata size may not be negative");
		goto error;
	}
	pvmetadatasize = arg_uint64_value(cmd, metadatasize_ARG, UINT64_C(0))
	    * 2;
	if (!pvmetadatasize)
		pvmetadatasize = find_config_tree_int(cmd,
						 "metadata/pvmetadatasize",
						 DEFAULT_PVMETADATASIZE);

	pvmetadatacopies = arg_int_value(cmd, metadatacopies_ARG, -1);
	if (pvmetadatacopies < 0)
		pvmetadatacopies = find_config_tree_int(cmd,
						   "metadata/pvmetadatacopies",
						   DEFAULT_PVMETADATACOPIES);

	if (!(dev = dev_cache_get(pv_name, cmd->filter))) {
		log_error("%s: Couldn't find device.  Check your filters?",
			  pv_name);
		goto error;
	}

	list_init(&mdas);
	if (!(pv = pv_create(cmd->fmt, dev, idp, size, pe_start,
			     extent_count, extent_size,
			     pvmetadatacopies, pvmetadatasize, &mdas))) {
		log_error("Failed to setup physical volume \"%s\"", pv_name);
		goto error;
	}

	log_verbose("Set up physical volume for \"%s\" with %" PRIu64
		    " available sectors", pv_name, pv_size(pv));

	/* Wipe existing label first */
	if (!label_remove(pv_dev(pv))) {
		log_error("Failed to wipe existing label on %s", pv_name);
		goto error;
	}

	if (pp->zero) {
		log_verbose("Zeroing start of device %s", pv_name);
		if (!dev_open_quiet(dev)) {
			log_error("%s not opened: device not zeroed", pv_name);
			goto error;
		}

		if (!dev_set(dev, UINT64_C(0), (size_t) 2048, 0)) {
			log_error("%s not wiped: aborting", pv_name);
			dev_close(dev);
			goto error;
		}
		dev_close(dev);
	}

	log_very_verbose("Writing physical volume data to disk \"%s\"",
			 pv_name);
	if (!(pv_write(cmd, (struct physical_volume *)pv, &mdas,
		       arg_int64_value(cmd, labelsector_ARG,
						       DEFAULT_LABELSECTOR)))) {
		log_error("Failed to write physical volume \"%s\"", pv_name);
		goto error;
	}

	log_print("Physical volume \"%s\" successfully created", pv_name);

	unlock_vg(cmd, ORPHAN);
	return ECMD_PROCESSED;

      error:
	unlock_vg(cmd, ORPHAN);
	return ECMD_FAILED;
}