[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