提交 bc891c9a 编写于 作者: L Lars Ellenberg 提交者: Philipp Reisner

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: NPhilipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: NLars Ellenberg <lars.ellenberg@linbit.com>
上级 a506c13a
...@@ -388,14 +388,16 @@ static struct page **bm_realloc_pages(struct drbd_bitmap *b, unsigned long want) ...@@ -388,14 +388,16 @@ static struct page **bm_realloc_pages(struct drbd_bitmap *b, unsigned long want)
return old_pages; return old_pages;
/* Trying kmalloc first, falling back to vmalloc. /* Trying kmalloc first, falling back to vmalloc.
* GFP_KERNEL is ok, as this is done when a lower level disk is * GFP_NOIO, as this is called while drbd IO is "suspended",
* "attached" to the drbd. Context is receiver thread or drbdsetup / * and during resize or attach on diskless Primary,
* netlink process. As we have no disk yet, we are not in the IO path, * we must not block on IO to ourselves.
* not even the IO path of the peer. */ * Context is receiver thread or dmsetup. */
bytes = sizeof(struct page *)*want; bytes = sizeof(struct page *)*want;
new_pages = kmalloc(bytes, GFP_KERNEL); new_pages = kmalloc(bytes, GFP_NOIO);
if (!new_pages) { if (!new_pages) {
new_pages = vmalloc(bytes); new_pages = __vmalloc(bytes,
GFP_NOIO | __GFP_HIGHMEM,
PAGE_KERNEL);
if (!new_pages) if (!new_pages)
return NULL; return NULL;
vmalloced = 1; vmalloced = 1;
...@@ -406,7 +408,7 @@ static struct page **bm_realloc_pages(struct drbd_bitmap *b, unsigned long want) ...@@ -406,7 +408,7 @@ static struct page **bm_realloc_pages(struct drbd_bitmap *b, unsigned long want)
for (i = 0; i < have; i++) for (i = 0; i < have; i++)
new_pages[i] = old_pages[i]; new_pages[i] = old_pages[i];
for (; i < want; i++) { for (; i < want; i++) {
page = alloc_page(GFP_HIGHUSER); page = alloc_page(GFP_NOIO | __GFP_HIGHMEM);
if (!page) { if (!page) {
bm_free_pages(new_pages + have, i - have); bm_free_pages(new_pages + have, i - have);
bm_vk_free(new_pages, vmalloced); bm_vk_free(new_pages, vmalloced);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册