[Devel] [PATCH rh7 4/5] cbt: fix page allocation

Maxim Patlasov mpatlasov at virtuozzo.com
Fri Apr 8 18:51:01 PDT 2016


It's not valid to call alloc_page with disabled irqs:

[   86.959856] BUG: sleeping function called from invalid context at mm/page_alloc.c:2732
[   86.961467] in_atomic(): 1, irqs_disabled(): 0, pid: 8721, name: cbti
[   86.962242] 1 lock held by cbti/8721:
[   86.962729]  #0:  (cbt_mutex){+.+.+.}, at: [<ffffffff8135c1e7>] blk_cbt_ioctl+0x1c7/0x660
[   86.963818] CPU: 4 PID: 8721 Comm: cbti ve: 0 Not tainted 3.10.0-327.10.1.vz7.12.3 #24 custom
[   86.964874] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.8.1-20150318_183358- 04/01/2014
[   86.966055]  0000000000000aac 00000000ffb482d1 ffff8800aa81fb98 ffffffff816ee3d7
[   86.967030]  ffff8800aa81fbc0 ffffffff810cc3f3 0000000000000010 0000000000000002
[   86.968016]  0000000000000000 ffff8800aa81fc78 ffffffff811c76bb ffffffff82c3cc40
[   86.968964] Call Trace:
[   86.969267]  [<ffffffff816ee3d7>] dump_stack+0x19/0x1b
[   86.969963]  [<ffffffff810cc3f3>] __might_sleep+0x173/0x230
[   86.970651]  [<ffffffff811c76bb>] __alloc_pages_nodemask+0x3db/0x5f0
[   86.971174]  [<ffffffff8111e249>] ? mark_held_locks+0xb9/0x140
[   86.971944]  [<ffffffff812130c9>] alloc_pages_current+0xa9/0x170
[   86.972795]  [<ffffffff8135b613>] __blk_cbt_set+0x193/0x440
[   86.973537]  [<ffffffff8135b8c0>] ? __blk_cbt_set+0x440/0x440
[   86.974235]  [<ffffffff8135b8c0>] ? __blk_cbt_set+0x440/0x440
[   86.974923]  [<ffffffff8135b8eb>] __cbt_flush_cpu_cache+0x2b/0x40
[   86.975678]  [<ffffffff81128aba>] on_each_cpu+0x4a/0xa0
[   86.976339]  [<ffffffff8135c22d>] blk_cbt_ioctl+0x20d/0x660

Signed-off-by: Maxim Patlasov <mpatlasov at virtuozzo.com>
---
 block/blk-cbt.c |   50 +++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 45 insertions(+), 5 deletions(-)

diff --git a/block/blk-cbt.c b/block/blk-cbt.c
index f83eb96..4bf9666 100644
--- a/block/blk-cbt.c
+++ b/block/blk-cbt.c
@@ -405,21 +405,61 @@ static int cbt_ioc_stop(struct block_device *bdev)
 	return 0;
 }
 
+struct flush_ctx {
+	struct cbt_info *cbt;
+	unsigned long pages_missed;
+	unsigned long idx_first;
+};
+
 static inline void __cbt_flush_cpu_cache(void *ptr)
 {
-	struct cbt_info *cbt = (struct cbt_info *) ptr;
+	struct flush_ctx *ctx = (struct flush_ctx *)ptr;
+	struct cbt_info *cbt = ctx->cbt;
 	struct cbt_extent *ex = this_cpu_ptr(cbt->cache);
 
 	if (ex->len) {
-		__blk_cbt_set(cbt, ex->start, ex->len, 0, 1, NULL, NULL);
-		ex->start += ex->len;
-		ex->len = 0;
+		int ret = __blk_cbt_set(cbt, ex->start, ex->len, 0, 1,
+					&ctx->pages_missed,
+					&ctx->idx_first);
+		if (!ret) {
+			ex->start += ex->len;
+			ex->len = 0;
+		}
 	}
 }
 
 static void cbt_flush_cache(struct cbt_info *cbt)
 {
-	on_each_cpu(__cbt_flush_cpu_cache, cbt, 1);
+	for (;;) {
+		struct flush_ctx ctx;
+		unsigned long i;
+try_again:
+		ctx.cbt = cbt;
+		ctx.pages_missed = 0;
+		ctx.idx_first = 0;
+
+		on_each_cpu(__cbt_flush_cpu_cache, &ctx, 1);
+
+		if (likely(!ctx.pages_missed))
+			return;
+
+		for (i = ctx.idx_first; i < NR_PAGES(cbt->block_max); i++) {
+			int ret;
+
+			if (cbt->map[i] != CBT_PAGE_MISSED)
+				continue;
+
+			ret = cbt_page_alloc(&cbt, i, 0);
+			if (ret == -EAGAIN) /* new cbt */
+				goto try_again;
+			else if (ret) /* dead cbt or alloc_page failed */
+				return;
+
+			/* cbt_page_alloc succeeded ... */
+			if (!--ctx.pages_missed)
+				break;
+		}
+	}
 }
 
 static void cbt_find_next_extent(struct cbt_info *cbt, blkcnt_t block, struct cbt_extent *ex)



More information about the Devel mailing list