mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-15 17:43:59 +00:00
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>
This commit is contained in:
parent
8f488156c0
commit
f70b351159
@ -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. */
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
|
||||||
/* we must not free the tl_hash
|
if (!mdev->state.susp) {
|
||||||
* while application io is still on the fly */
|
/* we must not free the tl_hash
|
||||||
wait_event(mdev->misc_wait, atomic_read(&mdev->ap_bio_cnt) == 0);
|
* while application io is still on the fly */
|
||||||
|
wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_bio_cnt));
|
||||||
spin_lock_irq(&mdev->req_lock);
|
drbd_free_tl_hash(mdev);
|
||||||
/* 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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user