Skip to contentSkip to conversation

rbd: drop an unsafe assertion

PATCH In review Alex Elder 3 participants 8 messages Mar 26, 2014 – Mar 29, 2014

Subsystems (2)
lore
Share & tools
lore

Alex Elder

author
#0 lore raw

PATCH 1/1 rbd: drop an unsafe assertion

Olivier Bonvalet reported having repeated crashes due to a failed assertion he was hitting in rbd_img_obj_callback():

Assertion failure in rbd_img_obj_callback() at line 2165:
rbd_assert(which == img_request->next_completion);

With a lot of help from Olivier with reproducing the problem we were able to determine the object and image requests had already been completed (and often freed) at the point the assertion failed.

There was a great deal of discussion on the ceph-devel mailing list about this. The problem only arose when there were two (or more) object requests in an image request, and the problem was always seen when the second request was being completed.

The problem is due to a race in the window between setting the "done" flag on an object request and checking the image request's next completion value. When the first object request completes, it checks to see if its successor request is marked "done", and if so, that request is also completed. In the process, the image request's next_completion value is updated to reflect that both the first and second requests are completed. By the time the second request is able to check the next_completion value, it has been set to a value *greater* than its own "which" value, which caused an assertion to fail.

Fix this problem by skipping over any completion processing unless the completing object request is the next one expected. Test only for inequality (not >=), and eliminate the bad assertion.

---
 drivers/block/rbd.c |    3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/block/rbd.c +1 -2
index f044fab..4c95b50 100644
@@ -2125,10 +2125,9 @@ static void rbd_img_obj_callback(struct rbd_obj_request *obj_request)
 	rbd_assert(which < img_request->obj_request_count);
 
 	spin_lock_irq(&img_request->completion_lock);
-	if (which > img_request->next_completion)
+	if (which != img_request->next_completion)
 		goto out;
 
-	rbd_assert(which == img_request->next_completion);
 	for_each_obj_request_from(img_request, obj_request) {
 		rbd_assert(more);
 		rbd_assert(which < img_request->obj_request_count);
Signature · 1 line
1.7.9.5
#1 lore raw

Hi Alex, Ilya,

I've added this and the previous patch to a for-linus branch to send to Linux for 3.14. The net of the two patches is simply removing the assert, however... the first changes several lines that then get changed back. Should we squash them?

Thanks!
sage

Quoted 63 lines · Alex Elder

Olivier Bonvalet reported having repeated crashes due to a failed assertion he was hitting in rbd_img_obj_callback():

Assertion failure in rbd_img_obj_callback() at line 2165:
rbd_assert(which == img_request->next_completion);

With a lot of help from Olivier with reproducing the problem we were able to determine the object and image requests had already been completed (and often freed) at the point the assertion failed.

There was a great deal of discussion on the ceph-devel mailing list about this. The problem only arose when there were two (or more) object requests in an image request, and the problem was always seen when the second request was being completed.

The problem is due to a race in the window between setting the "done" flag on an object request and checking the image request's next completion value. When the first object request completes, it checks to see if its successor request is marked "done", and if so, that request is also completed. In the process, the image request's next_completion value is updated to reflect that both the first and second requests are completed. By the time the second request is able to check the next_completion value, it has been set to a value *greater* than its own "which" value, which caused an assertion to fail.

Fix this problem by skipping over any completion processing unless the completing object request is the next one expected. Test only for inequality (not >=), and eliminate the bad assertion.

---
 drivers/block/rbd.c |    3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/block/rbd.c +1 -2
index f044fab..4c95b50 100644
@@ -2125,10 +2125,9 @@ static void rbd_img_obj_callback(struct rbd_obj_request *obj_request)
 	rbd_assert(which < img_request->obj_request_count);
 
 	spin_lock_irq(&img_request->completion_lock);
-	if (which > img_request->next_completion)
+	if (which != img_request->next_completion)
 		goto out;
 
-	rbd_assert(which == img_request->next_completion);
 	for_each_obj_request_from(img_request, obj_request) {
 		rbd_assert(more);
 		rbd_assert(which < img_request->obj_request_count);
Signature · 6 lines
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe ceph-devel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
author
#2 lore raw
Quoted 6 lines · Sage Weil

Hi Alex, Ilya,

I've added this and the previous patch to a for-linus branch to send to Linux for 3.14. The net of the two patches is simply removing the assert, however... the first changes several lines that then get changed back. Should we squash them?

In my opinion, yes. Ilya's movement of the assert within the spinlock was solving one problem, but ultimately that assertion should go away.

-Alex

Quoted 69 lines

Thanks!
sage

Quoted 63 lines · Alex Elder

Olivier Bonvalet reported having repeated crashes due to a failed assertion he was hitting in rbd_img_obj_callback():

Assertion failure in rbd_img_obj_callback() at line 2165:
rbd_assert(which == img_request->next_completion);

With a lot of help from Olivier with reproducing the problem we were able to determine the object and image requests had already been completed (and often freed) at the point the assertion failed.

There was a great deal of discussion on the ceph-devel mailing list about this. The problem only arose when there were two (or more) object requests in an image request, and the problem was always seen when the second request was being completed.

The problem is due to a race in the window between setting the "done" flag on an object request and checking the image request's next completion value. When the first object request completes, it checks to see if its successor request is marked "done", and if so, that request is also completed. In the process, the image request's next_completion value is updated to reflect that both the first and second requests are completed. By the time the second request is able to check the next_completion value, it has been set to a value *greater* than its own "which" value, which caused an assertion to fail.

Fix this problem by skipping over any completion processing unless the completing object request is the next one expected. Test only for inequality (not >=), and eliminate the bad assertion.

---
 drivers/block/rbd.c |    3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/block/rbd.c +1 -2
index f044fab..4c95b50 100644
@@ -2125,10 +2125,9 @@ static void rbd_img_obj_callback(struct rbd_obj_request *obj_request)
 	rbd_assert(which < img_request->obj_request_count);
 
 	spin_lock_irq(&img_request->completion_lock);
-	if (which > img_request->next_completion)
+	if (which != img_request->next_completion)
 		goto out;
 
-	rbd_assert(which == img_request->next_completion);
 	for_each_obj_request_from(img_request, obj_request) {
 		rbd_assert(more);
 		rbd_assert(which < img_request->obj_request_count);
Signature · 6 lines
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe ceph-devel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#3 lore raw
Quoted 11 lines · Alex Elder
Quoted 6 lines · Sage Weil

Hi Alex, Ilya,

I've added this and the previous patch to a for-linus branch to send to Linux for 3.14. The net of the two patches is simply removing the assert, however... the first changes several lines that then get changed back. Should we squash them?

In my opinion, yes. Ilya's movement of the assert within the spinlock was solving one problem, but ultimately that assertion should go away.

Sage, the way you squashed it we lost Alex's authorship and ended up with his Signed-off-by, my Reviewed-by and me as an Author. Since you haven't pulled it into kernel.org yet, I did

git commit --amend --author='Alex Elder <[email protected]>'

on for-linus to restore justice ;)

Thanks,

Ilya

#4 lore raw
Quoted 13 lines · Ilya Dryomov
Quoted 11 lines · Alex Elder
Quoted 6 lines · Sage Weil

Hi Alex, Ilya,

I've added this and the previous patch to a for-linus branch to send to Linux for 3.14. The net of the two patches is simply removing the assert, however... the first changes several lines that then get changed back. Should we squash them?

In my opinion, yes. Ilya's movement of the assert within the spinlock was solving one problem, but ultimately that assertion should go away.

Quoted 7 lines

Sage, the way you squashed it we lost Alex's authorship and ended up with his Signed-off-by, my Reviewed-by and me as an Author. Since you haven't pulled it into kernel.org yet, I did

git commit --amend --author='Alex Elder <[email protected]>'

on for-linus to restore justice ;)

Thanks! I'm noticing now that the commit description doesn't make much sense, though, since it is talking about the conditions after the first patch.. might just send the originals, unless Alex wants to rewrite it.

sage

#5 lore raw
Quoted 18 lines · Sage Weil
Quoted 17 lines · Ilya Dryomov
Quoted 11 lines · Alex Elder
Quoted 6 lines · Sage Weil

Hi Alex, Ilya,

I've added this and the previous patch to a for-linus branch to send to Linux for 3.14. The net of the two patches is simply removing the assert, however... the first changes several lines that then get changed back. Should we squash them?

In my opinion, yes. Ilya's movement of the assert within the spinlock was solving one problem, but ultimately that assertion should go away.

Sage, the way you squashed it we lost Alex's authorship and ended up with his Signed-off-by, my Reviewed-by and me as an Author. Since you haven't pulled it into kernel.org yet, I did

Quoted 7 lines
Quoted 3 lines

git commit --amend --author='Alex Elder <[email protected]>'

on for-linus to restore justice ;)

Thanks! I'm noticing now that the commit description doesn't make much sense, though, since it is talking about the conditions after the first patch.. might just send the originals, unless Alex wants to rewrite it.

I don't see it that way. The conditions it is talking about are true even w/o the first patch, it's just the first patch made it a lot easier to hit the bug.

Thanks,

Ilya

#6 lore raw
Quoted 23 lines · Ilya Dryomov
Quoted 22 lines · Sage Weil
Quoted 20 lines · Ilya Dryomov
Quoted 11 lines · Alex Elder
Quoted 6 lines · Sage Weil

Hi Alex, Ilya,

I've added this and the previous patch to a for-linus branch to send to Linux for 3.14. The net of the two patches is simply removing the assert, however... the first changes several lines that then get changed back. Should we squash them?

In my opinion, yes. Ilya's movement of the assert within the spinlock was solving one problem, but ultimately that assertion should go away.

Sage, the way you squashed it we lost Alex's authorship and ended up with his Signed-off-by, my Reviewed-by and me as an Author. Since you haven't pulled it into kernel.org yet, I did

git commit --amend --author='Alex Elder <[email protected]>'

on for-linus to restore justice ;)

Quoted 7 lines
Quoted 3 lines

Thanks! I'm noticing now that the commit description doesn't make much sense, though, since it is talking about the conditions after the first patch.. might just send the originals, unless Alex wants to rewrite it.

I don't see it that way. The conditions it is talking about are true even w/o the first patch, it's just the first patch made it a lot easier to hit the bug.

Ah, you're right, the last part is fine. It's just the failed assertion says == instead of >=; changed that. Look ok?

sage

#7 lore raw
Quoted 28 lines · Sage Weil
Quoted 27 lines · Ilya Dryomov
Quoted 25 lines · Sage Weil
Quoted 13 lines · Ilya Dryomov
Quoted 11 lines · Alex Elder
Quoted 6 lines · Sage Weil

Hi Alex, Ilya,

I've added this and the previous patch to a for-linus branch to send to Linux for 3.14. The net of the two patches is simply removing the assert, however... the first changes several lines that then get changed back. Should we squash them?

In my opinion, yes. Ilya's movement of the assert within the spinlock was solving one problem, but ultimately that assertion should go away.

Quoted 7 lines

Sage, the way you squashed it we lost Alex's authorship and ended up with his Signed-off-by, my Reviewed-by and me as an Author. Since you haven't pulled it into kernel.org yet, I did

git commit --amend --author='Alex Elder <[email protected]>'

on for-linus to restore justice ;)

Thanks! I'm noticing now that the commit description doesn't make much sense, though, since it is talking about the conditions after the first patch.. might just send the originals, unless Alex wants to rewrite it.

Quoted 6 lines
Quoted 3 lines

I don't see it that way. The conditions it is talking about are true even w/o the first patch, it's just the first patch made it a lot easier to hit the bug.

Ah, you're right, the last part is fine. It's just the failed assertion says == instead of >=; changed that. Look ok?

I think so.

Thanks,

Ilya