The commit is pushed to "branch-rh7-3.10.0-327.10.1.vz7.12.x-ovz" and will 
appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-327.10.1.vz7.12.7
------>
commit cf34ac99365fe20dae856c08ec7e90ea9a9f6d35
Author: Maxim Patlasov <[email protected]>
Date:   Tue Apr 12 14:24:16 2016 +0400

    cbt: fix page allocation
    
    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 <[email protected]>
    Acked-by: Dmitry Monakhov <[email protected]>
---
 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)
_______________________________________________
Devel mailing list
[email protected]
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to