When handling multiple concurrent dm-ploop requests, large bio_vec arrays
can be allocated during request processing. These allocations are currently
done with kmalloc_array(GFP_ATOMIC), which can fail under memory pressure
for higher orders (order >= 6, ~256KB). Such failures result in partial or
corrupted I/O, leading to EXT4 directory checksum errors and read-only
remounts under heavy parallel workloads.

This patch uses kvmalloc_array with correct flags depending on context.
In atomic context GFP_ATOMIC is used which makes kvmalloc_array fallback
to kmalloc_array. This avoids high-order GFP_ATOMIC allocations from atomic
context and ensures more reliable memory allocation behavior.

Signed-off-by: Vasileios Almpanis <[email protected]>
Feature: dm-ploop: ploop target driver
---
 drivers/md/dm-ploop-map.c | 32 ++++++++++++++++++++------------
 1 file changed, 20 insertions(+), 12 deletions(-)

diff --git a/drivers/md/dm-ploop-map.c b/drivers/md/dm-ploop-map.c
index 3fb841f8bcea..f94da5add7d6 100644
--- a/drivers/md/dm-ploop-map.c
+++ b/drivers/md/dm-ploop-map.c
@@ -194,7 +194,7 @@ static void ploop_prq_endio(struct pio *pio, void *prq_ptr,
        struct request *rq = prq->rq;
 
        if (prq->bvec)
-               kfree(prq->bvec);
+               kvfree(prq->bvec);
        if (prq->css)
                css_put(prq->css);
        /*
@@ -1963,7 +1963,7 @@ void ploop_index_wb_submit(struct ploop *ploop, struct 
ploop_index_wb *piwb)
        ploop_runners_add_work(ploop, pio);
 }
 
-static struct bio_vec *ploop_create_bvec_from_rq(struct request *rq)
+static struct bio_vec *ploop_create_bvec_from_rq(struct request *rq, gfp_t 
flags)
 {
        struct bio_vec bv, *bvec, *tmp;
        struct req_iterator rq_iter;
@@ -1972,24 +1972,27 @@ static struct bio_vec *ploop_create_bvec_from_rq(struct 
request *rq)
        rq_for_each_bvec(bv, rq, rq_iter)
                nr_bvec++;
 
-       bvec = kmalloc_array(nr_bvec, sizeof(struct bio_vec),
-                            GFP_ATOMIC);
-       if (!bvec)
-               goto out;
+       bvec = kvmalloc_array(nr_bvec, sizeof(struct bio_vec), flags);
+       if (!bvec) {
+               if (flags & GFP_ATOMIC)
+                       return ERR_PTR(-EAGAIN);
+               else
+                       return ERR_PTR(-ENOMEM);
+       }
 
        tmp = bvec;
        rq_for_each_bvec(bv, rq, rq_iter) {
                *tmp = bv;
                tmp++;
        }
-out:
        return bvec;
 }
 ALLOW_ERROR_INJECTION(ploop_create_bvec_from_rq, NULL);
 
 static void ploop_prepare_one_embedded_pio(struct ploop *ploop,
                                           struct pio *pio,
-                                          struct llist_head *lldeferred_pios)
+                                          struct llist_head *lldeferred_pios,
+                                          gfp_t flag)
 {
        struct ploop_rq *prq = pio->endio_cb_data;
        struct request *rq = prq->rq;
@@ -2003,9 +2006,14 @@ static void ploop_prepare_one_embedded_pio(struct ploop 
*ploop,
                 * Transform a set of bvec arrays related to bios
                 * into a single bvec array (which we can iterate).
                 */
-               bvec = ploop_create_bvec_from_rq(rq);
-               if (!bvec)
+               bvec = ploop_create_bvec_from_rq(rq, flag);
+               if (IS_ERR(bvec)) {
+                       if (PTR_ERR(bvec) == -EAGAIN) {
+                               llist_add((struct llist_node *)(&pio->list), 
&ploop->pios[PLOOP_LIST_PREPARE]);
+                               return;
+                       }
                        goto err_nomem;
+               }
                prq->bvec = bvec;
 skip_bvec:
                pio->bi_iter.bi_size = blk_rq_bytes(rq);
@@ -2044,7 +2052,7 @@ static void ploop_prepare_embedded_pios(struct ploop 
*ploop,
                pio = list_entry((struct list_head *)pos, typeof(*pio), list);
                INIT_LIST_HEAD(&pio->list); /* until type is changed */
                if (pio->queue_list_id != PLOOP_LIST_FLUSH)
-                       ploop_prepare_one_embedded_pio(ploop, pio, 
deferred_pios);
+                       ploop_prepare_one_embedded_pio(ploop, pio, 
deferred_pios, GFP_NOIO);
                else
                        llist_add((struct llist_node *)(&pio->list),
                                  &ploop->pios[PLOOP_LIST_FLUSH]);
@@ -2615,7 +2623,7 @@ static void ploop_submit_embedded_pio(struct ploop 
*ploop, struct pio *pio)
                goto out;
        }
 
-       ploop_prepare_one_embedded_pio(ploop, pio, &deferred_pios);
+       ploop_prepare_one_embedded_pio(ploop, pio, &deferred_pios, GFP_ATOMIC | 
__GFP_NOWARN);
        /*
         * Disable fast path due to rcu lockups fs -> ploop -> fs - fses are 
not reentrant
         * we can however try another fast path skip dispatcher thread and pass 
directly to
-- 
2.43.0

_______________________________________________
Devel mailing list
[email protected]
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to