diff options
author | Lars Ellenberg <lars.ellenberg@linbit.com> | 2012-09-26 08:18:51 -0400 |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2012-11-09 08:11:39 -0500 |
commit | bc891c9ae3fb2848922e0f0da22fd7de0d58dc1b (patch) | |
tree | 58353dfe6fb1257533959a56346b5d5a0a15ad4f | |
parent | a506c13a4d1ec5e1f2f9bc0123dacb5d123004d3 (diff) |
drbd: fix potential deadlock during bitmap (re-)allocation
The former comment arguing that GFP_KERNEL was good enough was wrong: it
did not take resize into account at all, and assumed the only path
leading here was the normal attach on a still secondary device, so no
deadlock would be possible.
Both resize on a Primary, or attach on a diskless Primary,
could potentially deadlock.
drbd_bm_resize() is called while IO to the respective device is
suspended, so we must use GFP_NOIO to avoid potential deadlock.
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_bitmap.c | 16 |
1 files changed, 9 insertions, 7 deletions
diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index 4a076b2553e6..e502535d2c4d 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c | |||
@@ -388,14 +388,16 @@ static struct page **bm_realloc_pages(struct drbd_bitmap *b, unsigned long want) | |||
388 | return old_pages; | 388 | return old_pages; |
389 | 389 | ||
390 | /* Trying kmalloc first, falling back to vmalloc. | 390 | /* Trying kmalloc first, falling back to vmalloc. |
391 | * GFP_KERNEL is ok, as this is done when a lower level disk is | 391 | * GFP_NOIO, as this is called while drbd IO is "suspended", |
392 | * "attached" to the drbd. Context is receiver thread or drbdsetup / | 392 | * and during resize or attach on diskless Primary, |
393 | * netlink process. As we have no disk yet, we are not in the IO path, | 393 | * we must not block on IO to ourselves. |
394 | * not even the IO path of the peer. */ | 394 | * Context is receiver thread or dmsetup. */ |
395 | bytes = sizeof(struct page *)*want; | 395 | bytes = sizeof(struct page *)*want; |
396 | new_pages = kmalloc(bytes, GFP_KERNEL); | 396 | new_pages = kmalloc(bytes, GFP_NOIO); |
397 | if (!new_pages) { | 397 | if (!new_pages) { |
398 | new_pages = vmalloc(bytes); | 398 | new_pages = __vmalloc(bytes, |
399 | GFP_NOIO | __GFP_HIGHMEM, | ||
400 | PAGE_KERNEL); | ||
399 | if (!new_pages) | 401 | if (!new_pages) |
400 | return NULL; | 402 | return NULL; |
401 | vmalloced = 1; | 403 | vmalloced = 1; |
@@ -406,7 +408,7 @@ static struct page **bm_realloc_pages(struct drbd_bitmap *b, unsigned long want) | |||
406 | for (i = 0; i < have; i++) | 408 | for (i = 0; i < have; i++) |
407 | new_pages[i] = old_pages[i]; | 409 | new_pages[i] = old_pages[i]; |
408 | for (; i < want; i++) { | 410 | for (; i < want; i++) { |
409 | page = alloc_page(GFP_HIGHUSER); | 411 | page = alloc_page(GFP_NOIO | __GFP_HIGHMEM); |
410 | if (!page) { | 412 | if (!page) { |
411 | bm_free_pages(new_pages + have, i - have); | 413 | bm_free_pages(new_pages + have, i - have); |
412 | bm_vk_free(new_pages, vmalloced); | 414 | bm_vk_free(new_pages, vmalloced); |