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

Commit 5107f9e8 authored by Ilya Dryomov's avatar Ilya Dryomov Committed by Greg Kroah-Hartman
Browse files

libceph: fix potential hang in ceph_osdc_notify()



commit e6e2843230799230fc5deb8279728a7218b0d63c upstream.

If the cluster becomes unavailable, ceph_osdc_notify() may hang even
with osd_request_timeout option set because linger_notify_finish_wait()
waits for MWatchNotify NOTIFY_COMPLETE message with no associated OSD
request in flight -- it's completely asynchronous.

Introduce an additional timeout, derived from the specified notify
timeout.  While at it, switch both waits to killable which is more
correct.

Cc: stable@vger.kernel.org
Signed-off-by: default avatarIlya Dryomov <idryomov@gmail.com>
Reviewed-by: default avatarDongsheng Yang <dongsheng.yang@easystack.cn>
Reviewed-by: default avatarXiubo Li <xiubli@redhat.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 6f14228e
Loading
Loading
Loading
Loading
+14 −6
Original line number Diff line number Diff line
@@ -3249,17 +3249,24 @@ static int linger_reg_commit_wait(struct ceph_osd_linger_request *lreq)
	int ret;

	dout("%s lreq %p linger_id %llu\n", __func__, lreq, lreq->linger_id);
	ret = wait_for_completion_interruptible(&lreq->reg_commit_wait);
	ret = wait_for_completion_killable(&lreq->reg_commit_wait);
	return ret ?: lreq->reg_commit_error;
}

static int linger_notify_finish_wait(struct ceph_osd_linger_request *lreq)
static int linger_notify_finish_wait(struct ceph_osd_linger_request *lreq,
				     unsigned long timeout)
{
	int ret;
	long left;

	dout("%s lreq %p linger_id %llu\n", __func__, lreq, lreq->linger_id);
	ret = wait_for_completion_interruptible(&lreq->notify_finish_wait);
	return ret ?: lreq->notify_finish_error;
	left = wait_for_completion_killable_timeout(&lreq->notify_finish_wait,
						ceph_timeout_jiffies(timeout));
	if (left <= 0)
		left = left ?: -ETIMEDOUT;
	else
		left = lreq->notify_finish_error; /* completed */

	return left;
}

/*
@@ -4875,7 +4882,8 @@ int ceph_osdc_notify(struct ceph_osd_client *osdc,
	linger_submit(lreq);
	ret = linger_reg_commit_wait(lreq);
	if (!ret)
		ret = linger_notify_finish_wait(lreq);
		ret = linger_notify_finish_wait(lreq,
				 msecs_to_jiffies(2 * timeout * MSEC_PER_SEC));
	else
		dout("lreq %p failed to initiate notify %d\n", lreq, ret);