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

Commit bc891c9a authored by Lars Ellenberg's avatar Lars Ellenberg Committed by Philipp Reisner
Browse files

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: default avatarPhilipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: default avatarLars Ellenberg <lars.ellenberg@linbit.com>
parent a506c13a
Loading
Loading
Loading
Loading
+9 −7
Original line number Diff line number Diff line
@@ -388,14 +388,16 @@ static struct page **bm_realloc_pages(struct drbd_bitmap *b, unsigned long want)
		return old_pages;

	/* Trying kmalloc first, falling back to vmalloc.
	 * GFP_KERNEL is ok, as this is done when a lower level disk is
	 * "attached" to the drbd.  Context is receiver thread or drbdsetup /
	 * netlink process.  As we have no disk yet, we are not in the IO path,
	 * not even the IO path of the peer. */
	 * GFP_NOIO, as this is called while drbd IO is "suspended",
	 * and during resize or attach on diskless Primary,
	 * we must not block on IO to ourselves.
	 * Context is receiver thread or dmsetup. */
	bytes = sizeof(struct page *)*want;
	new_pages = kmalloc(bytes, GFP_KERNEL);
	new_pages = kmalloc(bytes, GFP_NOIO);
	if (!new_pages) {
		new_pages = vmalloc(bytes);
		new_pages = __vmalloc(bytes,
				GFP_NOIO | __GFP_HIGHMEM,
				PAGE_KERNEL);
		if (!new_pages)
			return NULL;
		vmalloced = 1;
@@ -406,7 +408,7 @@ static struct page **bm_realloc_pages(struct drbd_bitmap *b, unsigned long want)
		for (i = 0; i < have; i++)
			new_pages[i] = old_pages[i];
		for (; i < want; i++) {
			page = alloc_page(GFP_HIGHUSER);
			page = alloc_page(GFP_NOIO | __GFP_HIGHMEM);
			if (!page) {
				bm_free_pages(new_pages + have, i - have);
				bm_vk_free(new_pages, vmalloced);