diff options
author | Philipp Reisner <philipp.reisner@linbit.com> | 2010-06-24 08:34:40 -0400 |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2010-10-14 09:08:27 -0400 |
commit | f70b3511599c49a3dc20ae349d6cdc5af47659df (patch) | |
tree | 1d5971f48f5fe95988df64f5ab1f22333c492dc9 | |
parent | 8f488156c0635dcc9c668737d05386113a745ef9 (diff) |
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: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
-rw-r--r-- | drivers/block/drbd/drbd_int.h | 1 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_main.c | 4 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_nl.c | 4 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_receiver.c | 60 |
4 files changed, 43 insertions, 26 deletions
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index aa9bb213fe70..f84ffb17a7e5 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h | |||
@@ -1493,6 +1493,7 @@ extern void _drbd_wait_ee_list_empty(struct drbd_conf *mdev, | |||
1493 | extern void drbd_set_recv_tcq(struct drbd_conf *mdev, int tcq_enabled); | 1493 | extern void drbd_set_recv_tcq(struct drbd_conf *mdev, int tcq_enabled); |
1494 | extern void _drbd_clear_done_ee(struct drbd_conf *mdev, struct list_head *to_be_freed); | 1494 | extern void _drbd_clear_done_ee(struct drbd_conf *mdev, struct list_head *to_be_freed); |
1495 | extern void drbd_flush_workqueue(struct drbd_conf *mdev); | 1495 | extern void drbd_flush_workqueue(struct drbd_conf *mdev); |
1496 | extern void drbd_free_tl_hash(struct drbd_conf *mdev); | ||
1496 | 1497 | ||
1497 | /* yes, there is kernel_setsockopt, but only since 2.6.18. we don't need to | 1498 | /* yes, there is kernel_setsockopt, but only since 2.6.18. we don't need to |
1498 | * mess with get_fs/set_fs, we know we are KERNEL_DS always. */ | 1499 | * mess with get_fs/set_fs, we know we are KERNEL_DS always. */ |
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 9fe9bdd9e33d..8d14635e7faf 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c | |||
@@ -1409,6 +1409,10 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, | |||
1409 | (os.user_isp && !ns.user_isp)) | 1409 | (os.user_isp && !ns.user_isp)) |
1410 | resume_next_sg(mdev); | 1410 | resume_next_sg(mdev); |
1411 | 1411 | ||
1412 | /* free tl_hash if we Got thawed and are C_STANDALONE */ | ||
1413 | if (ns.conn == C_STANDALONE && ns.susp == 0 && mdev->tl_hash) | ||
1414 | drbd_free_tl_hash(mdev); | ||
1415 | |||
1412 | /* Upon network connection, we need to start the receiver */ | 1416 | /* Upon network connection, we need to start the receiver */ |
1413 | if (os.conn == C_STANDALONE && ns.conn == C_UNCONNECTED) | 1417 | if (os.conn == C_STANDALONE && ns.conn == C_UNCONNECTED) |
1414 | drbd_thread_start(&mdev->receiver); | 1418 | drbd_thread_start(&mdev->receiver); |
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index dc0a9acbfdf1..6c08e637e25c 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c | |||
@@ -1391,6 +1391,7 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, | |||
1391 | } | 1391 | } |
1392 | } | 1392 | } |
1393 | 1393 | ||
1394 | drbd_flush_workqueue(mdev); | ||
1394 | spin_lock_irq(&mdev->req_lock); | 1395 | spin_lock_irq(&mdev->req_lock); |
1395 | if (mdev->net_conf != NULL) { | 1396 | if (mdev->net_conf != NULL) { |
1396 | retcode = ERR_NET_CONFIGURED; | 1397 | retcode = ERR_NET_CONFIGURED; |
@@ -1429,10 +1430,9 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, | |||
1429 | mdev->int_dig_out=int_dig_out; | 1430 | mdev->int_dig_out=int_dig_out; |
1430 | mdev->int_dig_in=int_dig_in; | 1431 | mdev->int_dig_in=int_dig_in; |
1431 | mdev->int_dig_vv=int_dig_vv; | 1432 | mdev->int_dig_vv=int_dig_vv; |
1433 | retcode = _drbd_set_state(_NS(mdev, conn, C_UNCONNECTED), CS_VERBOSE, NULL); | ||
1432 | spin_unlock_irq(&mdev->req_lock); | 1434 | spin_unlock_irq(&mdev->req_lock); |
1433 | 1435 | ||
1434 | retcode = _drbd_request_state(mdev, NS(conn, C_UNCONNECTED), CS_VERBOSE); | ||
1435 | |||
1436 | kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE); | 1436 | kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE); |
1437 | reply->ret_code = retcode; | 1437 | reply->ret_code = retcode; |
1438 | drbd_reconfig_done(mdev); | 1438 | drbd_reconfig_done(mdev); |
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 22d74d79ba42..5e49ee75d3c9 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c | |||
@@ -3691,6 +3691,36 @@ void drbd_flush_workqueue(struct drbd_conf *mdev) | |||
3691 | wait_for_completion(&barr.done); | 3691 | wait_for_completion(&barr.done); |
3692 | } | 3692 | } |
3693 | 3693 | ||
3694 | void drbd_free_tl_hash(struct drbd_conf *mdev) | ||
3695 | { | ||
3696 | struct hlist_head *h; | ||
3697 | |||
3698 | spin_lock_irq(&mdev->req_lock); | ||
3699 | |||
3700 | if (!mdev->tl_hash || mdev->state.conn != C_STANDALONE) { | ||
3701 | spin_unlock_irq(&mdev->req_lock); | ||
3702 | return; | ||
3703 | } | ||
3704 | /* paranoia code */ | ||
3705 | for (h = mdev->ee_hash; h < mdev->ee_hash + mdev->ee_hash_s; h++) | ||
3706 | if (h->first) | ||
3707 | dev_err(DEV, "ASSERT FAILED ee_hash[%u].first == %p, expected NULL\n", | ||
3708 | (int)(h - mdev->ee_hash), h->first); | ||
3709 | kfree(mdev->ee_hash); | ||
3710 | mdev->ee_hash = NULL; | ||
3711 | mdev->ee_hash_s = 0; | ||
3712 | |||
3713 | /* paranoia code */ | ||
3714 | for (h = mdev->tl_hash; h < mdev->tl_hash + mdev->tl_hash_s; h++) | ||
3715 | if (h->first) | ||
3716 | dev_err(DEV, "ASSERT FAILED tl_hash[%u] == %p, expected NULL\n", | ||
3717 | (int)(h - mdev->tl_hash), h->first); | ||
3718 | kfree(mdev->tl_hash); | ||
3719 | mdev->tl_hash = NULL; | ||
3720 | mdev->tl_hash_s = 0; | ||
3721 | spin_unlock_irq(&mdev->req_lock); | ||
3722 | } | ||
3723 | |||
3694 | static void drbd_disconnect(struct drbd_conf *mdev) | 3724 | static void drbd_disconnect(struct drbd_conf *mdev) |
3695 | { | 3725 | { |
3696 | enum drbd_fencing_p fp; | 3726 | enum drbd_fencing_p fp; |
@@ -3774,32 +3804,14 @@ static void drbd_disconnect(struct drbd_conf *mdev) | |||
3774 | spin_unlock_irq(&mdev->req_lock); | 3804 | spin_unlock_irq(&mdev->req_lock); |
3775 | 3805 | ||
3776 | if (os.conn == C_DISCONNECTING) { | 3806 | if (os.conn == C_DISCONNECTING) { |
3777 | struct hlist_head *h; | ||
3778 | wait_event(mdev->net_cnt_wait, atomic_read(&mdev->net_cnt) == 0); | 3807 | wait_event(mdev->net_cnt_wait, atomic_read(&mdev->net_cnt) == 0); |
3779 | 3808 | ||
3780 | /* we must not free the tl_hash | 3809 | if (!mdev->state.susp) { |
3781 | * while application io is still on the fly */ | 3810 | /* we must not free the tl_hash |
3782 | wait_event(mdev->misc_wait, atomic_read(&mdev->ap_bio_cnt) == 0); | 3811 | * while application io is still on the fly */ |
3783 | 3812 | wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_bio_cnt)); | |
3784 | spin_lock_irq(&mdev->req_lock); | 3813 | drbd_free_tl_hash(mdev); |
3785 | /* paranoia code */ | 3814 | } |
3786 | for (h = mdev->ee_hash; h < mdev->ee_hash + mdev->ee_hash_s; h++) | ||
3787 | if (h->first) | ||
3788 | dev_err(DEV, "ASSERT FAILED ee_hash[%u].first == %p, expected NULL\n", | ||
3789 | (int)(h - mdev->ee_hash), h->first); | ||
3790 | kfree(mdev->ee_hash); | ||
3791 | mdev->ee_hash = NULL; | ||
3792 | mdev->ee_hash_s = 0; | ||
3793 | |||
3794 | /* paranoia code */ | ||
3795 | for (h = mdev->tl_hash; h < mdev->tl_hash + mdev->tl_hash_s; h++) | ||
3796 | if (h->first) | ||
3797 | dev_err(DEV, "ASSERT FAILED tl_hash[%u] == %p, expected NULL\n", | ||
3798 | (int)(h - mdev->tl_hash), h->first); | ||
3799 | kfree(mdev->tl_hash); | ||
3800 | mdev->tl_hash = NULL; | ||
3801 | mdev->tl_hash_s = 0; | ||
3802 | spin_unlock_irq(&mdev->req_lock); | ||
3803 | 3815 | ||
3804 | crypto_free_hash(mdev->cram_hmac_tfm); | 3816 | crypto_free_hash(mdev->cram_hmac_tfm); |
3805 | mdev->cram_hmac_tfm = NULL; | 3817 | mdev->cram_hmac_tfm = NULL; |