Ejemplo n.º 1
0
/*
 * VG locking is by VG name.
 * FIXME This should become VG uuid.
 */
static int _lock_vol(struct cmd_context *cmd, const char *resource,
		     uint32_t flags, lv_operation_t lv_op, struct logical_volume *lv)
{
	uint32_t lck_type = flags & LCK_TYPE_MASK;
	uint32_t lck_scope = flags & LCK_SCOPE_MASK;
	int ret = 0;

	_block_signals(flags);
	_lock_memory(cmd, lv_op);

	assert(resource);

	if (!*resource) {
		log_error(INTERNAL_ERROR "Use of P_orphans is deprecated.");
		return 0;
	}

	if ((is_orphan_vg(resource) || is_global_vg(resource)) && (flags & LCK_CACHE)) {
		log_error(INTERNAL_ERROR "P_%s referenced", resource);
		return 0;
	}

	if (cmd->metadata_read_only && lck_type == LCK_WRITE &&
	    strcmp(resource, VG_GLOBAL)) {
		log_error("Operation prohibited while global/metadata_read_only is set.");
		return 0;
	}

	if ((ret = _locking.lock_resource(cmd, resource, flags, lv))) {
		if (lck_scope == LCK_VG && !(flags & LCK_CACHE)) {
			if (lck_type != LCK_UNLOCK)
				lvmcache_lock_vgname(resource, lck_type == LCK_READ);
			dev_reset_error_count(cmd);
		}

		_update_vg_lock_count(resource, flags);
	} else
		stack;

	/* If unlocking, always remove lock from lvmcache even if operation failed. */
	if (lck_scope == LCK_VG && !(flags & LCK_CACHE) && lck_type == LCK_UNLOCK) {
		lvmcache_unlock_vgname(resource);
		if (!ret)
			_update_vg_lock_count(resource, flags);
	}

	_unlock_memory(cmd, lv_op);
	_unblock_signals();

	return ret;
}
Ejemplo n.º 2
0
int lock_resource(struct cmd_context *cmd, const char *resource, uint32_t flags)
#endif
{
	char lockname[PATH_MAX];
	int clvmd_cmd = 0;
	const char *lock_scope;
	const char *lock_type = "";

	assert(strlen(resource) < sizeof(lockname));
	assert(resource);

	switch (flags & LCK_SCOPE_MASK) {
	case LCK_VG:
		if (flags == LCK_VG_BACKUP) {
			log_very_verbose("Requesting backup of VG metadata for %s",
					 resource);
			return _lock_for_cluster(cmd, CLVMD_CMD_VG_BACKUP,
						 LCK_CLUSTER_VG, resource);
		}

		/* If the VG name is empty then lock the unused PVs */
		if (is_orphan_vg(resource) || is_global_vg(resource) || (flags & LCK_CACHE))
			dm_snprintf(lockname, sizeof(lockname), "P_%s",
				    resource);
		else
			dm_snprintf(lockname, sizeof(lockname), "V_%s",
				    resource);

		lock_scope = "VG";
		clvmd_cmd = CLVMD_CMD_LOCK_VG;
		/*
		 * Old clvmd does not expect LCK_HOLD which was already processed
		 * in lock_vol, mask it for compatibility reasons.
		 */
		if (flags != LCK_VG_COMMIT && flags != LCK_VG_REVERT)
			flags &= ~LCK_HOLD;

		break;

	case LCK_LV:
		clvmd_cmd = CLVMD_CMD_LOCK_LV;
		strcpy(lockname, resource);
		lock_scope = "LV";
		flags &= ~LCK_HOLD;	/* Mask off HOLD flag */
		break;

	default:
		log_error("Unrecognised lock scope: %d",
			  flags & LCK_SCOPE_MASK);
		return 0;
	}

	switch(flags & LCK_TYPE_MASK) {
	case LCK_UNLOCK:
		lock_type = "UN";
		break;
	case LCK_NULL:
		lock_type = "NL";
		break;
	case LCK_READ:
		lock_type = "CR";
		break;
	case LCK_PREAD:
		lock_type = "PR";
		break;
	case LCK_WRITE:
		lock_type = "PW";
		break;
	case LCK_EXCL:
		lock_type = "EX";
		break;
	default:
		log_error("Unrecognised lock type: %u",
			  flags & LCK_TYPE_MASK);
		return 0;
	}

	log_very_verbose("Locking %s %s %s (%s%s%s%s%s%s) (0x%x)", lock_scope, lockname,
			 lock_type, lock_scope,
			 flags & LCK_NONBLOCK ? "|NONBLOCK" : "",
			 flags & LCK_HOLD ? "|HOLD" : "",
			 flags & LCK_LOCAL ? "|LOCAL" : "",
			 flags & LCK_CLUSTER_VG ? "|CLUSTER" : "",
			 flags & LCK_CACHE ? "|CACHE" : "",
			 flags);

	/* Send a message to the cluster manager */
	return _lock_for_cluster(cmd, clvmd_cmd, flags, lockname);
}
Ejemplo n.º 3
0
int lock_vol(struct cmd_context *cmd, const char *vol, uint32_t flags, struct logical_volume *lv)
{
	char resource[258] __attribute__((aligned(8)));
	lv_operation_t lv_op;
	int lck_type = flags & LCK_TYPE_MASK;

	switch (flags & (LCK_SCOPE_MASK | LCK_TYPE_MASK)) {
		case LCK_LV_SUSPEND:
				lv_op = LV_SUSPEND;
				break;
		case LCK_LV_RESUME:
				lv_op = LV_RESUME;
				break;
		default:	lv_op = LV_NOOP;
	}


	if (flags == LCK_NONE) {
		log_debug_locking(INTERNAL_ERROR "%s: LCK_NONE lock requested", vol);
		return 1;
	}

	switch (flags & LCK_SCOPE_MASK) {
	case LCK_VG:
		if (!_blocking_supported)
			flags |= LCK_NONBLOCK;

		/* Global VG_ORPHANS lock covers all orphan formats. */
		if (is_orphan_vg(vol))
			vol = VG_ORPHANS;
		/* VG locks alphabetical, ORPHAN lock last */
		if ((lck_type != LCK_UNLOCK) &&
		    !(flags & LCK_CACHE) &&
		    !lvmcache_verify_lock_order(vol))
			return_0;

		/* Lock VG to change on-disk metadata. */
		/* If LVM1 driver knows about the VG, it can't be accessed. */
		if (!check_lvm1_vg_inactive(cmd, vol))
			return_0;
		break;
	case LCK_LV:
		/* All LV locks are non-blocking. */
		flags |= LCK_NONBLOCK;
		break;
	default:
		log_error("Unrecognised lock scope: %d",
			  flags & LCK_SCOPE_MASK);
		return 0;
	}

	strncpy(resource, vol, sizeof(resource) - 1);
	resource[sizeof(resource) - 1] = '\0';

	if (!_lock_vol(cmd, resource, flags, lv_op, lv))
		return_0;

	/*
	 * If a real lock was acquired (i.e. not LCK_CACHE),
	 * perform an immediate unlock unless LCK_HOLD was requested.
	 */
	if ((lck_type == LCK_NULL) || (lck_type == LCK_UNLOCK) ||
	    (flags & (LCK_CACHE | LCK_HOLD)))
		return 1;

	if (!_lock_vol(cmd, resource, (flags & ~LCK_TYPE_MASK) | LCK_UNLOCK, lv_op, lv))
		return_0;

	return 1;
}
Ejemplo n.º 4
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;
}
Ejemplo n.º 5
0
static int _file_lock_resource(struct cmd_context *cmd, const char *resource,
			       uint32_t flags, struct logical_volume *lv)
{
	char lockfile[PATH_MAX];
	unsigned origin_only = (flags & LCK_ORIGIN_ONLY) ? 1 : 0;
	unsigned revert = (flags & LCK_REVERT) ? 1 : 0;

	switch (flags & LCK_SCOPE_MASK) {
	case LCK_ACTIVATION:
		if (dm_snprintf(lockfile, sizeof(lockfile),
				"%s/A_%s", _lock_dir, resource + 1) < 0) {
			log_error("Too long locking filename %s/A_%s.", _lock_dir, resource + 1);
			return 0;
		}

		if (!lock_file(lockfile, flags))
			return_0;
		break;
	case LCK_VG:
		/* Skip cache refresh for VG_GLOBAL - the caller handles it */
		if (strcmp(resource, VG_GLOBAL))
			lvmcache_drop_metadata(resource, 0);

		if (!strcmp(resource, VG_SYNC_NAMES))
			fs_unlock();

		/* LCK_CACHE does not require a real lock */
		if (flags & LCK_CACHE)
			break;

		if (is_orphan_vg(resource) || is_global_vg(resource)) {
			if (dm_snprintf(lockfile, sizeof(lockfile),
					"%s/P_%s", _lock_dir, resource + 1) < 0) {
				log_error("Too long locking filename %s/P_%s.",
					  _lock_dir, resource + 1);
				return 0;
			}
		} else
			if (dm_snprintf(lockfile, sizeof(lockfile),
					"%s/V_%s", _lock_dir, resource) < 0) {
				log_error("Too long locking filename %s/V_%s.",
					  _lock_dir, resource);
				return 0;
			}

		if (!lock_file(lockfile, flags))
			return_0;
		break;
	case LCK_LV:
		switch (flags & LCK_TYPE_MASK) {
		case LCK_UNLOCK:
			log_very_verbose("Unlocking LV %s%s%s", resource, origin_only ? " without snapshots" : "", revert ? " (reverting)" : "");
			if (!lv_resume_if_active(cmd, resource, origin_only, 0, revert, lv_ondisk(lv)))
				return 0;
			break;
		case LCK_NULL:
			log_very_verbose("Locking LV %s (NL)", resource);
			if (!lv_deactivate(cmd, resource, lv_ondisk(lv)))
				return 0;
			break;
		case LCK_READ:
			log_very_verbose("Locking LV %s (R)", resource);
			if (!lv_activate_with_filter(cmd, resource, 0, lv->status & LV_NOSCAN ? 1 : 0,
						     lv->status & LV_TEMPORARY ? 1 : 0, lv_ondisk(lv)))
				return 0;
			break;
		case LCK_PREAD:
			log_very_verbose("Locking LV %s (PR) - ignored", resource);
			break;
		case LCK_WRITE:
			log_very_verbose("Locking LV %s (W)%s", resource, origin_only ? " without snapshots" : "");
			if (!lv_suspend_if_active(cmd, resource, origin_only, 0, lv_ondisk(lv), lv))
				return 0;
			break;
		case LCK_EXCL:
			log_very_verbose("Locking LV %s (EX)", resource);
			if (!lv_activate_with_filter(cmd, resource, 1, lv->status & LV_NOSCAN ? 1 : 0,
						     lv->status & LV_TEMPORARY ? 1 : 0, lv_ondisk(lv)))
				return 0;
			break;
		default:
			break;
		}
		break;
	default:
		log_error("Unrecognised lock scope: %d",
			  flags & LCK_SCOPE_MASK);
		return 0;
	}

	return 1;
}