static int _reload_device_with_integrity(struct crypt_device *cd,
	const char *name,
	const char *iname,
	const char *ipath,
	struct crypt_dm_active_device *sdmd,
	struct crypt_dm_active_device *sdmdi)
{
	int r;
	struct crypt_dm_active_device tdmd, tdmdi = {};
	struct dm_target *src, *srci, *tgt = &tdmd.segment, *tgti = &tdmdi.segment;
	struct device *data_device = NULL;
	bool clear = false;

	if (!cd || !cd->type || !name || !iname || !(sdmd->flags & CRYPT_ACTIVATE_REFRESH))
		return -EINVAL;

	r = dm_query_device(cd, name, DM_ACTIVE_DEVICE | DM_ACTIVE_CRYPT_CIPHER |
				  DM_ACTIVE_UUID | DM_ACTIVE_CRYPT_KEYSIZE |
				  DM_ACTIVE_CRYPT_KEY, &tdmd);
	if (r < 0) {
		log_err(cd, _("Device %s is not active."), name);
		return -EINVAL;
	}

	if (!single_segment(&tdmd) || tgt->type != DM_CRYPT || !tgt->u.crypt.tag_size) {
		log_err(cd, _("Unsupported parameters on device %s."), name);
		r = -ENOTSUP;
		goto out;
	}

	r = dm_query_device(cd, iname, DM_ACTIVE_DEVICE | DM_ACTIVE_UUID, &tdmdi);
	if (r < 0) {
		log_err(cd, _("Device %s is not active."), iname);
		r = -EINVAL;
		goto out;
	}

	if (!single_segment(&tdmdi) || tgti->type != DM_INTEGRITY) {
		log_err(cd, _("Unsupported parameters on device %s."), iname);
		r = -ENOTSUP;
		goto out;
	}

	r = crypt_compare_dm_devices(cd, sdmdi, &tdmdi);
	if (r) {
		log_err(cd, _("Mismatching parameters on device %s."), iname);
		goto out;
	}

	src = &sdmd->segment;
	srci = &sdmdi->segment;

	r = device_alloc(cd, &data_device, ipath);
	if (r < 0)
		goto out;

	r = device_block_adjust(cd, srci->data_device, DEV_OK,
				srci->u.integrity.offset, &sdmdi->size, NULL);
	if (r)
		goto out;

	src->data_device = data_device;

	r = crypt_compare_dm_devices(cd, sdmd, &tdmd);
	if (r) {
		log_err(cd, _("Crypt devices mismatch."));
		goto out;
	}

	/* Changing read only flag for active device makes no sense */
	if (tdmd.flags & CRYPT_ACTIVATE_READONLY)
		sdmd->flags |= CRYPT_ACTIVATE_READONLY;
	else
		sdmd->flags &= ~CRYPT_ACTIVATE_READONLY;

	if (tdmdi.flags & CRYPT_ACTIVATE_READONLY)
		sdmdi->flags |= CRYPT_ACTIVATE_READONLY;
	else
		sdmdi->flags &= ~CRYPT_ACTIVATE_READONLY;

	if (sdmd->flags & CRYPT_ACTIVATE_KEYRING_KEY) {
		r = crypt_volume_key_set_description(tgt->u.crypt.vk, src->u.crypt.vk->key_description);
		if (r)
			goto out;
	} else {
		crypt_free_volume_key(tgt->u.crypt.vk);
		tgt->u.crypt.vk = crypt_alloc_volume_key(src->u.crypt.vk->keylength, src->u.crypt.vk->key);
		if (!tgt->u.crypt.vk) {
			r = -ENOMEM;
			goto out;
		}
	}

	r = device_block_adjust(cd, src->data_device, DEV_OK,
				src->u.crypt.offset, &sdmd->size, NULL);
	if (r)
		goto out;

	tdmd.flags = sdmd->flags;
	tdmd.size = sdmd->size;

	if ((r = dm_reload_device(cd, iname, sdmdi, 0, 0))) {
		log_err(cd, _("Failed to reload device %s."), iname);
		goto out;
	}

	if ((r = dm_reload_device(cd, name, &tdmd, 0, 0))) {
		log_err(cd, _("Failed to reload device %s."), name);
		clear = true;
		goto out;
	}

	if ((r = dm_suspend_device(cd, name, 0))) {
		log_err(cd, _("Failed to suspend device %s."), name);
		clear = true;
		goto out;
	}

	if ((r = dm_suspend_device(cd, iname, 0))) {
		log_err(cd, _("Failed to suspend device %s."), iname);
		clear = true;
		goto out;
	}

	if ((r = dm_resume_device(cd, iname, act2dmflags(sdmdi->flags)))) {
		log_err(cd, _("Failed to resume device %s."), iname);
		clear = true;
		goto out;
	}

	r = dm_resume_device(cd, name, act2dmflags(tdmd.flags));
	if (!r)
		goto out;

	/*
	 * This is worst case scenario. We have active underlying dm-integrity device with
	 * new table but dm-crypt resume failed for some reason. Tear everything down and
	 * burn it for good.
	 */

	log_err(cd, _("Fatal error while reloading device %s (on top of device %s)."), name, iname);

	if (dm_error_device(cd, name))
		log_err(cd, _("Failed to switch device %s to dm-error."), name);
	if (dm_error_device(cd, iname))
		log_err(cd, _("Failed to switch device %s to dm-error."), iname);
out:
	if (clear) {
		dm_clear_device(cd, name);
		dm_clear_device(cd, iname);

		if (dm_status_suspended(cd, name) > 0)
			dm_resume_device(cd, name, 0);
		if (dm_status_suspended(cd, iname) > 0)
			dm_resume_device(cd, iname, 0);
	}

	dm_targets_free(cd, &tdmd);
	dm_targets_free(cd, &tdmdi);
	free(CONST_CAST(void*)tdmdi.uuid);
	free(CONST_CAST(void*)tdmd.uuid);
	device_free(cd, data_device);

	return r;
}