Exemplo n.º 1
0
/*
 * Lock a list of LVs.
 * On failure to lock any LV, calls vg_revert() if vg_to_revert is set and 
 * then unlocks any LVs on the list already successfully locked.
 */
int suspend_lvs(struct cmd_context *cmd, struct dm_list *lvs,
		struct volume_group *vg_to_revert)
{
	struct lv_list *lvl;

	dm_list_iterate_items(lvl, lvs) {
		if (!suspend_lv(cmd, lvl->lv)) {
			log_error("Failed to suspend %s", lvl->lv->name);
			if (vg_to_revert)
				vg_revert(vg_to_revert);
			/*
			 * FIXME Should be
			 * 	dm_list_uniterate(lvh, lvs, &lvl->list) {
			 *	lvl = dm_list_item(lvh, struct lv_list);
			 * but revert would need fixing to use identical tree deps first.
			 */
			dm_list_iterate_items(lvl, lvs)
				if (!revert_lv(cmd, lvl->lv))
					stack;

			return 0;
		}
	}
Exemplo n.º 2
0
static int lvchange_readahead(struct cmd_context *cmd,
			      struct logical_volume *lv)
{
	unsigned read_ahead = 0;
	unsigned pagesize = (unsigned) lvm_getpagesize() >> SECTOR_SHIFT;
	int r = 0;

	read_ahead = arg_uint_value(cmd, readahead_ARG, 0);

	if (read_ahead != DM_READ_AHEAD_AUTO &&
	    (lv->vg->fid->fmt->features & FMT_RESTRICTED_READAHEAD) &&
	    (read_ahead < 2 || read_ahead > 120)) {
		log_error("Metadata only supports readahead values between 2 and 120.");
		return 0;
	}

	if (read_ahead != DM_READ_AHEAD_AUTO &&
	    read_ahead != DM_READ_AHEAD_NONE && read_ahead % pagesize) {
		if (read_ahead < pagesize)
			read_ahead = pagesize;
		else
			read_ahead = (read_ahead / pagesize) * pagesize;
		log_warn("WARNING: Overriding readahead to %u sectors, a multiple "
			    "of %uK page size.", read_ahead, pagesize >> 1);
	}

	if (lv->read_ahead == read_ahead) {
		if (read_ahead == DM_READ_AHEAD_AUTO)
			log_error("Read ahead is already auto for \"%s\"", lv->name);
		else
			log_error("Read ahead is already %u for \"%s\"",
				  read_ahead, lv->name);
		return 0;
	}

	lv->read_ahead = read_ahead;

	log_verbose("Setting read ahead to %u for \"%s\"", read_ahead,
		    lv->name);

	log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
	if (!vg_write(lv->vg))
		return_0;

	if (!suspend_lv(cmd, lv)) {
		log_error("Failed to lock %s", lv->name);
		vg_revert(lv->vg);
		goto out;
	}

	if (!vg_commit(lv->vg)) {
		if (!resume_lv(cmd, lv))
			stack;
		goto_out;
	}

	log_very_verbose("Updating permissions for \"%s\" in kernel", lv->name);
	if (!resume_lv(cmd, lv)) {
		log_error("Problem reactivating %s", lv->name);
		goto out;
	}

	r = 1;
out:
	backup(lv->vg);
	return r;
}
Exemplo n.º 3
0
static int lvchange_permission(struct cmd_context *cmd,
			       struct logical_volume *lv)
{
	uint32_t lv_access;
	struct lvinfo info;
	int r = 0;

	lv_access = arg_uint_value(cmd, permission_ARG, 0);

	if ((lv_access & LVM_WRITE) && (lv->status & LVM_WRITE)) {
		log_error("Logical volume \"%s\" is already writable",
			  lv->name);
		return 0;
	}

	if (!(lv_access & LVM_WRITE) && !(lv->status & LVM_WRITE)) {
		log_error("Logical volume \"%s\" is already read only",
			  lv->name);
		return 0;
	}

	if ((lv->status & MIRRORED) && (vg_is_clustered(lv->vg)) &&
	    lv_info(cmd, lv, 0, &info, 0, 0) && info.exists) {
		log_error("Cannot change permissions of mirror \"%s\" "
			  "while active.", lv->name);
		return 0;
	}

	/* Not allowed to change permissions on RAID sub-LVs directly */
	if ((lv->status & RAID_META) || (lv->status & RAID_IMAGE)) {
		log_error("Cannot change permissions of RAID %s \"%s\"",
			  (lv->status & RAID_IMAGE) ? "image" :
			  "metadata area", lv->name);
		return 0;
	}

	if (lv_access & LVM_WRITE) {
		lv->status |= LVM_WRITE;
		log_verbose("Setting logical volume \"%s\" read/write",
			    lv->name);
	} else {
		lv->status &= ~LVM_WRITE;
		log_verbose("Setting logical volume \"%s\" read-only",
			    lv->name);
	}

	log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
	if (!vg_write(lv->vg))
		return_0;

	if (!suspend_lv(cmd, lv)) {
		log_error("Failed to lock %s", lv->name);
		vg_revert(lv->vg);
		goto out;
	}

	if (!vg_commit(lv->vg)) {
		if (!resume_lv(cmd, lv))
			stack;
		goto_out;
	}

	log_very_verbose("Updating permissions for \"%s\" in kernel", lv->name);
	if (!resume_lv(cmd, lv)) {
		log_error("Problem reactivating %s", lv->name);
		goto out;
	}

	r = 1;
out:
	backup(lv->vg);
	return r;
}
Exemplo n.º 4
0
int vg_remove_snapshot(struct logical_volume *cow)
{
	int merging_snapshot = 0;
	struct logical_volume *origin = origin_from_cow(cow);
	int is_origin_active = lv_is_active(origin);

	if (is_origin_active &&
	    lv_is_virtual_origin(origin)) {
		if (!deactivate_lv(origin->vg->cmd, origin)) {
			log_error("Failed to deactivate logical volume \"%s\"",
				  origin->name);
			return 0;
		}
		is_origin_active = 0;
	}

	dm_list_del(&cow->snapshot->origin_list);
	origin->origin_count--;

	if (lv_is_merging_origin(origin) &&
	    (find_snapshot(origin) == find_snapshot(cow))) {
		clear_snapshot_merge(origin);
		/*
		 * preload origin IFF "snapshot-merge" target is active
		 * - IMPORTANT: avoids preload if inactivate merge is pending
		 */
		if (lv_has_target_type(origin->vg->vgmem, origin, NULL,
				       TARGET_NAME_SNAPSHOT_MERGE)) {
			/*
			 * preload origin to:
			 * - allow proper release of -cow
			 * - avoid allocations with other devices suspended
			 *   when transitioning from "snapshot-merge" to
			 *   "snapshot-origin after a merge completes.
			 */
			merging_snapshot = 1;
		}
	}

	if (!lv_remove(cow->snapshot->lv)) {
		log_error("Failed to remove internal snapshot LV %s",
			  cow->snapshot->lv->name);
		return 0;
	}

	cow->snapshot = NULL;
	lv_set_visible(cow);

	/* format1 must do the change in one step, with the commit last. */
	if (!(origin->vg->fid->fmt->features & FMT_MDAS)) {
		/* Get the lock for COW volume */
		if (is_origin_active && !activate_lv(cow->vg->cmd, cow)) {
			log_error("Unable to activate logical volume \"%s\"",
				  cow->name);
			return 0;
		}
		return 1;
	}

	if (!vg_write(origin->vg))
		return_0;

	/* Skip call suspend, if device is not active */
	if (is_origin_active && !suspend_lv(origin->vg->cmd, origin)) {
		log_error("Failed to refresh %s without snapshot.",
			  origin->name);
		vg_revert(origin->vg);
		return 0;
	}
	if (!vg_commit(origin->vg))
		return_0;

	if (is_origin_active) {
		/*
		 * If the snapshot was active and the COW LV is taken away
		 * the LV lock on cluster has to be grabbed, so use
		 * activate_lv() which resumes suspend cow device.
		 */
		if (!merging_snapshot && !activate_lv(cow->vg->cmd, cow)) {
			log_error("Failed to activate %s.", cow->name);
			return 0;
		}

		if (!resume_lv(origin->vg->cmd, origin)) {
			log_error("Failed to resume %s.", origin->name);
			return 0;
		}

		/*
		 * For merged snapshot and clustered VG activate cow LV so
		 * the following call to deactivate_lv() can clean-up table
		 * entries. For this clustered lock need to be held.
		 */
		if (vg_is_clustered(cow->vg) &&
		    merging_snapshot && !activate_lv(cow->vg->cmd, cow)) {
			log_error("Failed to activate %s.", cow->name);
			return 0;
		}
	}

	return 1;
}
Exemplo n.º 5
0
static int lvchange_pool_update(struct cmd_context *cmd,
				struct logical_volume *lv)
{
	int r = 0;
	int update = 0;
	unsigned val;
	thin_discards_t discards;

	if (!lv_is_thin_pool(lv)) {
		log_error("Logical volume \"%s\" is not a thin pool.", lv->name);
		return 0;
	}

	if (arg_count(cmd, discards_ARG)) {
		discards = (thin_discards_t) arg_uint_value(cmd, discards_ARG, THIN_DISCARDS_IGNORE);
		if (discards != first_seg(lv)->discards) {
			if ((discards != THIN_DISCARDS_IGNORE) &&
				 (first_seg(lv)->chunk_size &
				  (first_seg(lv)->chunk_size - 1)))
				log_error("Cannot change discards state for "
					  "logical volume \"%s\" "
					  "with non power of 2 chunk size.", lv->name);
			else if (((discards == THIN_DISCARDS_IGNORE) ||
			     (first_seg(lv)->discards == THIN_DISCARDS_IGNORE)) &&
			    lv_is_active(lv))
				log_error("Cannot change discards state for active "
					  "logical volume \"%s\".", lv->name);
			else {
				first_seg(lv)->discards = discards;
				update++;
			}
		} else
			log_error("Logical volume \"%s\" already uses --discards %s.",
				  lv->name, get_pool_discards_name(discards));
	}

	if (arg_count(cmd, zero_ARG)) {
		val = arg_uint_value(cmd, zero_ARG, 1);
		if (val != first_seg(lv)->zero_new_blocks) {
			first_seg(lv)->zero_new_blocks = val;
			update++;
		} else
			log_error("Logical volume \"%s\" already %szero new blocks.",
				  lv->name, val ? "" : "does not ");
	}

	if (!update)
		return 0;

	log_very_verbose("Updating logical volume \"%s\" on disk(s).", lv->name);
	if (!vg_write(lv->vg))
		return_0;

	if (!suspend_lv_origin(cmd, lv)) {
		log_error("Failed to update active %s/%s (deactivation is needed).",
			  lv->vg->name, lv->name);
		vg_revert(lv->vg);
		goto out;
	}

	if (!vg_commit(lv->vg)) {
		if (!resume_lv_origin(cmd, lv))
			stack;
		goto_out;
	}

	if (!resume_lv_origin(cmd, lv)) {
		log_error("Problem reactivating %s.", lv->name);
		goto out;
	}

	r = 1;
out:
	backup(lv->vg);
	return r;
}