aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Ellenberg <lars.ellenberg@linbit.com>2012-09-26 08:18:51 -0400
committerPhilipp Reisner <philipp.reisner@linbit.com>2012-11-09 08:11:39 -0500
commitbc891c9ae3fb2848922e0f0da22fd7de0d58dc1b (patch)
tree58353dfe6fb1257533959a56346b5d5a0a15ad4f
parenta506c13a4d1ec5e1f2f9bc0123dacb5d123004d3 (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.c16
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);