Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f70b3511 authored by Philipp Reisner's avatar Philipp Reisner
Browse files

drbd: Do not try to free tl_hash in drbd_disconnect() when IO is suspended



We may not free tl_hash when IO is suspended, since we can not wait
until ap_bio_cnt reaches zero.

We can do this after susp reched 0, since then tl_clear was called

Signed-off-by: default avatarPhilipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: default avatarLars Ellenberg <lars.ellenberg@linbit.com>
parent 8f488156
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -1493,6 +1493,7 @@ extern void _drbd_wait_ee_list_empty(struct drbd_conf *mdev,
extern void drbd_set_recv_tcq(struct drbd_conf *mdev, int tcq_enabled);
extern void drbd_set_recv_tcq(struct drbd_conf *mdev, int tcq_enabled);
extern void _drbd_clear_done_ee(struct drbd_conf *mdev, struct list_head *to_be_freed);
extern void _drbd_clear_done_ee(struct drbd_conf *mdev, struct list_head *to_be_freed);
extern void drbd_flush_workqueue(struct drbd_conf *mdev);
extern void drbd_flush_workqueue(struct drbd_conf *mdev);
extern void drbd_free_tl_hash(struct drbd_conf *mdev);


/* yes, there is kernel_setsockopt, but only since 2.6.18. we don't need to
/* yes, there is kernel_setsockopt, but only since 2.6.18. we don't need to
 * mess with get_fs/set_fs, we know we are KERNEL_DS always. */
 * mess with get_fs/set_fs, we know we are KERNEL_DS always. */
+4 −0
Original line number Original line Diff line number Diff line
@@ -1409,6 +1409,10 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
	    (os.user_isp && !ns.user_isp))
	    (os.user_isp && !ns.user_isp))
		resume_next_sg(mdev);
		resume_next_sg(mdev);


	/* free tl_hash if we Got thawed and are C_STANDALONE */
	if (ns.conn == C_STANDALONE && ns.susp == 0 && mdev->tl_hash)
		drbd_free_tl_hash(mdev);

	/* Upon network connection, we need to start the receiver */
	/* Upon network connection, we need to start the receiver */
	if (os.conn == C_STANDALONE && ns.conn == C_UNCONNECTED)
	if (os.conn == C_STANDALONE && ns.conn == C_UNCONNECTED)
		drbd_thread_start(&mdev->receiver);
		drbd_thread_start(&mdev->receiver);
+2 −2
Original line number Original line Diff line number Diff line
@@ -1391,6 +1391,7 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
		}
		}
	}
	}


	drbd_flush_workqueue(mdev);
	spin_lock_irq(&mdev->req_lock);
	spin_lock_irq(&mdev->req_lock);
	if (mdev->net_conf != NULL) {
	if (mdev->net_conf != NULL) {
		retcode = ERR_NET_CONFIGURED;
		retcode = ERR_NET_CONFIGURED;
@@ -1429,10 +1430,9 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
	mdev->int_dig_out=int_dig_out;
	mdev->int_dig_out=int_dig_out;
	mdev->int_dig_in=int_dig_in;
	mdev->int_dig_in=int_dig_in;
	mdev->int_dig_vv=int_dig_vv;
	mdev->int_dig_vv=int_dig_vv;
	retcode = _drbd_set_state(_NS(mdev, conn, C_UNCONNECTED), CS_VERBOSE, NULL);
	spin_unlock_irq(&mdev->req_lock);
	spin_unlock_irq(&mdev->req_lock);


	retcode = _drbd_request_state(mdev, NS(conn, C_UNCONNECTED), CS_VERBOSE);

	kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE);
	kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE);
	reply->ret_code = retcode;
	reply->ret_code = retcode;
	drbd_reconfig_done(mdev);
	drbd_reconfig_done(mdev);
+36 −24
Original line number Original line Diff line number Diff line
@@ -3691,6 +3691,36 @@ void drbd_flush_workqueue(struct drbd_conf *mdev)
	wait_for_completion(&barr.done);
	wait_for_completion(&barr.done);
}
}


void drbd_free_tl_hash(struct drbd_conf *mdev)
{
	struct hlist_head *h;

	spin_lock_irq(&mdev->req_lock);

	if (!mdev->tl_hash || mdev->state.conn != C_STANDALONE) {
		spin_unlock_irq(&mdev->req_lock);
		return;
	}
	/* paranoia code */
	for (h = mdev->ee_hash; h < mdev->ee_hash + mdev->ee_hash_s; h++)
		if (h->first)
			dev_err(DEV, "ASSERT FAILED ee_hash[%u].first == %p, expected NULL\n",
				(int)(h - mdev->ee_hash), h->first);
	kfree(mdev->ee_hash);
	mdev->ee_hash = NULL;
	mdev->ee_hash_s = 0;

	/* paranoia code */
	for (h = mdev->tl_hash; h < mdev->tl_hash + mdev->tl_hash_s; h++)
		if (h->first)
			dev_err(DEV, "ASSERT FAILED tl_hash[%u] == %p, expected NULL\n",
				(int)(h - mdev->tl_hash), h->first);
	kfree(mdev->tl_hash);
	mdev->tl_hash = NULL;
	mdev->tl_hash_s = 0;
	spin_unlock_irq(&mdev->req_lock);
}

static void drbd_disconnect(struct drbd_conf *mdev)
static void drbd_disconnect(struct drbd_conf *mdev)
{
{
	enum drbd_fencing_p fp;
	enum drbd_fencing_p fp;
@@ -3774,32 +3804,14 @@ static void drbd_disconnect(struct drbd_conf *mdev)
	spin_unlock_irq(&mdev->req_lock);
	spin_unlock_irq(&mdev->req_lock);


	if (os.conn == C_DISCONNECTING) {
	if (os.conn == C_DISCONNECTING) {
		struct hlist_head *h;
		wait_event(mdev->net_cnt_wait, atomic_read(&mdev->net_cnt) == 0);
		wait_event(mdev->net_cnt_wait, atomic_read(&mdev->net_cnt) == 0);


		if (!mdev->state.susp) {
			/* we must not free the tl_hash
			/* we must not free the tl_hash
			 * while application io is still on the fly */
			 * while application io is still on the fly */
		wait_event(mdev->misc_wait, atomic_read(&mdev->ap_bio_cnt) == 0);
			wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_bio_cnt));

			drbd_free_tl_hash(mdev);
		spin_lock_irq(&mdev->req_lock);
		}
		/* paranoia code */
		for (h = mdev->ee_hash; h < mdev->ee_hash + mdev->ee_hash_s; h++)
			if (h->first)
				dev_err(DEV, "ASSERT FAILED ee_hash[%u].first == %p, expected NULL\n",
						(int)(h - mdev->ee_hash), h->first);
		kfree(mdev->ee_hash);
		mdev->ee_hash = NULL;
		mdev->ee_hash_s = 0;

		/* paranoia code */
		for (h = mdev->tl_hash; h < mdev->tl_hash + mdev->tl_hash_s; h++)
			if (h->first)
				dev_err(DEV, "ASSERT FAILED tl_hash[%u] == %p, expected NULL\n",
						(int)(h - mdev->tl_hash), h->first);
		kfree(mdev->tl_hash);
		mdev->tl_hash = NULL;
		mdev->tl_hash_s = 0;
		spin_unlock_irq(&mdev->req_lock);


		crypto_free_hash(mdev->cram_hmac_tfm);
		crypto_free_hash(mdev->cram_hmac_tfm);
		mdev->cram_hmac_tfm = NULL;
		mdev->cram_hmac_tfm = NULL;