static int reencrypt_init_by_passphrase(struct crypt_device *cd,
	const char *name,
	const char *passphrase,
	size_t passphrase_size,
	int keyslot_old,
	int keyslot_new,
	const char *cipher,
	const char *cipher_mode,
	const struct crypt_params_reencrypt *params)
{
	int r;
	crypt_reencrypt_info ri;
	struct volume_key *vks = NULL;
	uint32_t flags = params ? params->flags : 0;
	struct luks2_hdr *hdr = crypt_get_hdr(cd, CRYPT_LUKS2);

	/* short-circuit in recovery and finish immediately. */
	if (flags & CRYPT_REENCRYPT_RECOVERY)
		return reencrypt_recovery_by_passphrase(cd, hdr, keyslot_old, keyslot_new, passphrase, passphrase_size);

	if (cipher && !crypt_cipher_wrapped_key(cipher, cipher_mode)) {
		r = crypt_keyslot_get_key_size(cd, keyslot_new);
		if (r < 0)
			return r;
		r = LUKS2_check_cipher(cd, r, cipher, cipher_mode);
		if (r < 0)
			return r;
	}

	r = LUKS2_device_write_lock(cd, hdr, crypt_metadata_device(cd));
	if (r)
		return r;

	ri = LUKS2_reencrypt_status(hdr);
	if (ri == CRYPT_REENCRYPT_INVALID) {
		device_write_unlock(cd, crypt_metadata_device(cd));
		return -EINVAL;
	}

	if ((ri > CRYPT_REENCRYPT_NONE) && (flags & CRYPT_REENCRYPT_INITIALIZE_ONLY)) {
		device_write_unlock(cd, crypt_metadata_device(cd));
		log_err(cd, _("LUKS2 reencryption already initialized in metadata."));
		return -EBUSY;
	}

	if (ri == CRYPT_REENCRYPT_NONE && !(flags & CRYPT_REENCRYPT_RESUME_ONLY)) {
		r = reencrypt_init(cd, name, hdr, passphrase, passphrase_size, keyslot_old, keyslot_new, cipher, cipher_mode, params, &vks);
		if (r < 0)
			log_err(cd, _("Failed to initialize LUKS2 reencryption in metadata."));
	} else if (ri > CRYPT_REENCRYPT_NONE) {
		log_dbg(cd, "LUKS2 reencryption already initialized.");
		r = 0;
	}

	device_write_unlock(cd, crypt_metadata_device(cd));

	if (r < 0 || (flags & CRYPT_REENCRYPT_INITIALIZE_ONLY))
		goto out;

	r = reencrypt_load_by_passphrase(cd, name, passphrase, passphrase_size, keyslot_old, keyslot_new, &vks, params);
out:
	if (r < 0)
		crypt_drop_keyring_key(cd, vks);
	crypt_free_volume_key(vks);
	return r < 0 ? r : LUKS2_find_keyslot(hdr, "reencrypt");
}
static int reencrypt_init_by_passphrase(struct crypt_device *cd,
	const char *name,
	const char *passphrase,
	size_t passphrase_size,
	int keyslot_old,
	int keyslot_new,
	const char *cipher,
	const char *cipher_mode,
	const struct crypt_params_reencrypt *params)
{
	int r;
	crypt_reencrypt_info ri;
	struct volume_key *vks = NULL;
	uint32_t flags = params ? params->flags : 0;
	struct luks2_hdr *hdr = crypt_get_hdr(cd, CRYPT_LUKS2);

	 
	if (flags & CRYPT_REENCRYPT_RECOVERY)
		return reencrypt_recovery_by_passphrase(cd, hdr, keyslot_old, keyslot_new, passphrase, passphrase_size);

	if (cipher && !crypt_cipher_wrapped_key(cipher, cipher_mode)) {
		r = crypt_keyslot_get_key_size(cd, keyslot_new);
		if (r < 0)
			return r;
		r = LUKS2_check_cipher(cd, r, cipher, cipher_mode);
		if (r < 0)
			return r;
	}

	r = LUKS2_device_write_lock(cd, hdr, crypt_metadata_device(cd));
	if (r)
		return r;

	ri = LUKS2_reencrypt_status(hdr);
	if (ri == CRYPT_REENCRYPT_INVALID) {
		device_write_unlock(cd, crypt_metadata_device(cd));
		return -EINVAL;
	}

	if ((ri > CRYPT_REENCRYPT_NONE) && (flags & CRYPT_REENCRYPT_INITIALIZE_ONLY)) {
		device_write_unlock(cd, crypt_metadata_device(cd));
		log_err(cd, _("LUKS2 reencryption already initialized in metadata."));
		return -EBUSY;
	}

	if (ri == CRYPT_REENCRYPT_NONE && !(flags & CRYPT_REENCRYPT_RESUME_ONLY)) {
		r = reencrypt_init(cd, name, hdr, passphrase, passphrase_size, keyslot_old, keyslot_new, cipher, cipher_mode, params, &vks);
		if (r < 0)
			log_err(cd, _("Failed to initialize LUKS2 reencryption in metadata."));
	} else if (ri > CRYPT_REENCRYPT_NONE) {
		log_dbg(cd, "LUKS2 reencryption already initialized.");
		r = 0;
	}

	device_write_unlock(cd, crypt_metadata_device(cd));

	if (r < 0 || (flags & CRYPT_REENCRYPT_INITIALIZE_ONLY))
		goto out;

	r = reencrypt_load_by_passphrase(cd, name, passphrase, passphrase_size, keyslot_old, keyslot_new, &vks, params);
out:
	if (r < 0)
		crypt_drop_keyring_key(cd, vks);
	crypt_free_volume_key(vks);
	return r < 0 ? r : LUKS2_find_keyslot(hdr, "reencrypt");
}