dm zone: fix dm_revalidate_zones() memory allocation
authorDamien Le Moal <damien.lemoal@wdc.com>
Fri, 18 Jun 2021 23:15:19 +0000 (08:15 +0900)
committerMike Snitzer <snitzer@redhat.com>
Fri, 25 Jun 2021 19:25:23 +0000 (15:25 -0400)
Make sure that the zone write pointer offset array is allocated with a
vmalloc in dm_zone_revalidate_cb() by passing GFP_KERNEL gfp flag to
kvcalloc(). However, since we do not want to trigger IOs while
revalidating zones, change dm_revalidate_zones() to have the zone scan
done in GFP_NOIO context using memalloc_noio_save/restore calls.

Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
Fixes: bb37d77239af ("dm: introduce zone append emulation")
Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
drivers/md/dm-zone.c

index c2f2694..6d82a34 100644 (file)
@@ -205,7 +205,7 @@ static int dm_zone_revalidate_cb(struct blk_zone *zone, unsigned int idx,
                if (!md->zwp_offset) {
                        md->zwp_offset =
                                kvcalloc(q->nr_zones, sizeof(unsigned int),
-                                        GFP_NOIO);
+                                        GFP_KERNEL);
                        if (!md->zwp_offset)
                                return -ENOMEM;
                }
@@ -230,6 +230,7 @@ static int dm_zone_revalidate_cb(struct blk_zone *zone, unsigned int idx,
 static int dm_revalidate_zones(struct mapped_device *md, struct dm_table *t)
 {
        struct request_queue *q = md->queue;
+       unsigned int noio_flag;
        int ret;
 
        /*
@@ -241,9 +242,14 @@ static int dm_revalidate_zones(struct mapped_device *md, struct dm_table *t)
        if (md->nr_zones)
                return 0;
 
-       /* Scan all zones to initialize everything */
+       /*
+        * Scan all zones to initialize everything. Ensure that all vmalloc
+        * operations in this context are done as if GFP_NOIO was specified.
+        */
+       noio_flag = memalloc_noio_save();
        ret = dm_blk_do_report_zones(md, t, 0, q->nr_zones,
                                     dm_zone_revalidate_cb, md);
+       memalloc_noio_restore(noio_flag);
        if (ret < 0)
                goto err;
        if (ret != q->nr_zones) {