#include <linux/rbtree.h>
#include <linux/blkdev.h>
#include <linux/blk-mq.h>
+#include <linux/sched/mm.h>
#include "blk.h"
}
static int blk_report_zones(struct gendisk *disk, sector_t sector,
- struct blk_zone *zones, unsigned int *nr_zones,
- gfp_t gfp_mask)
+ struct blk_zone *zones, unsigned int *nr_zones)
{
struct request_queue *q = disk->queue;
unsigned int z = 0, n, nrz = *nr_zones;
while (z < nrz && sector < capacity) {
n = nrz - z;
- ret = disk->fops->report_zones(disk, sector, &zones[z], &n,
- gfp_mask);
+ ret = disk->fops->report_zones(disk, sector, &zones[z], &n);
if (ret)
return ret;
if (!n)
* @sector: Sector from which to report zones
* @zones: Array of zone structures where to return the zones information
* @nr_zones: Number of zone structures in the zone array
- * @gfp_mask: Memory allocation flags (for bio_alloc)
*
* Description:
* Get zone information starting from the zone containing @sector.
* The number of zone information reported may be less than the number
* requested by @nr_zones. The number of zones actually reported is
* returned in @nr_zones.
+ * The caller must use memalloc_noXX_save/restore() calls to control
+ * memory allocations done within this function (zone array and command
+ * buffer allocation by the device driver).
*/
int blkdev_report_zones(struct block_device *bdev, sector_t sector,
- struct blk_zone *zones, unsigned int *nr_zones,
- gfp_t gfp_mask)
+ struct blk_zone *zones, unsigned int *nr_zones)
{
struct request_queue *q = bdev_get_queue(bdev);
unsigned int i, nrz;
nrz = min(*nr_zones,
__blkdev_nr_zones(q, bdev->bd_part->nr_sects - sector));
ret = blk_report_zones(bdev->bd_disk, get_start_sect(bdev) + sector,
- zones, &nrz, gfp_mask);
+ zones, &nrz);
if (ret)
return ret;
if (!zones)
return -ENOMEM;
- ret = blkdev_report_zones(bdev, rep.sector,
- zones, &rep.nr_zones,
- GFP_KERNEL);
+ ret = blkdev_report_zones(bdev, rep.sector, zones, &rep.nr_zones);
if (ret)
goto out;
unsigned long *seq_zones_wlock = NULL, *seq_zones_bitmap = NULL;
unsigned int i, rep_nr_zones = 0, z = 0, nrz;
struct blk_zone *zones = NULL;
+ unsigned int noio_flag;
sector_t sector = 0;
int ret = 0;
return 0;
}
+ /*
+ * Ensure that all memory allocations in this context are done as
+ * if GFP_NOIO was specified.
+ */
+ noio_flag = memalloc_noio_save();
+
if (!blk_queue_is_zoned(q) || !nr_zones) {
nr_zones = 0;
goto update;
while (z < nr_zones) {
nrz = min(nr_zones - z, rep_nr_zones);
- ret = blk_report_zones(disk, sector, zones, &nrz, GFP_NOIO);
+ ret = blk_report_zones(disk, sector, zones, &nrz);
if (ret)
goto out;
if (!nrz)
blk_mq_unfreeze_queue(q);
out:
+ memalloc_noio_restore(noio_flag);
+
free_pages((unsigned long)zones,
get_order(rep_nr_zones * sizeof(struct blk_zone)));
kfree(seq_zones_wlock);
int null_zone_init(struct nullb_device *dev);
void null_zone_exit(struct nullb_device *dev);
int null_zone_report(struct gendisk *disk, sector_t sector,
- struct blk_zone *zones, unsigned int *nr_zones,
- gfp_t gfp_mask);
+ struct blk_zone *zones, unsigned int *nr_zones);
void null_zone_write(struct nullb_cmd *cmd, sector_t sector,
unsigned int nr_sectors);
void null_zone_reset(struct nullb_cmd *cmd, sector_t sector);
}
int null_zone_report(struct gendisk *disk, sector_t sector,
- struct blk_zone *zones, unsigned int *nr_zones,
- gfp_t gfp_mask)
+ struct blk_zone *zones, unsigned int *nr_zones)
{
struct nullb *nullb = disk->private_data;
struct nullb_device *dev = nullb->dev;
#ifdef CONFIG_BLK_DEV_ZONED
static int flakey_report_zones(struct dm_target *ti, sector_t sector,
- struct blk_zone *zones, unsigned int *nr_zones,
- gfp_t gfp_mask)
+ struct blk_zone *zones, unsigned int *nr_zones)
{
struct flakey_c *fc = ti->private;
int ret;
/* Do report and remap it */
ret = blkdev_report_zones(fc->dev->bdev, flakey_map_sector(ti, sector),
- zones, nr_zones, gfp_mask);
+ zones, nr_zones);
if (ret != 0)
return ret;
#ifdef CONFIG_BLK_DEV_ZONED
static int linear_report_zones(struct dm_target *ti, sector_t sector,
- struct blk_zone *zones, unsigned int *nr_zones,
- gfp_t gfp_mask)
+ struct blk_zone *zones, unsigned int *nr_zones)
{
struct linear_c *lc = (struct linear_c *) ti->private;
int ret;
/* Do report and remap it */
ret = blkdev_report_zones(lc->dev->bdev, linear_map_sector(ti, sector),
- zones, nr_zones, gfp_mask);
+ zones, nr_zones);
if (ret != 0)
return ret;
#include <linux/module.h>
#include <linux/crc32.h>
+#include <linux/sched/mm.h>
#define DM_MSG_PREFIX "zoned metadata"
while (sector < dev->capacity) {
/* Get zone information */
nr_blkz = DMZ_REPORT_NR_ZONES;
- ret = blkdev_report_zones(dev->bdev, sector, blkz,
- &nr_blkz, GFP_KERNEL);
+ ret = blkdev_report_zones(dev->bdev, sector, blkz, &nr_blkz);
if (ret) {
dmz_dev_err(dev, "Report zones failed %d", ret);
goto out;
static int dmz_update_zone(struct dmz_metadata *zmd, struct dm_zone *zone)
{
unsigned int nr_blkz = 1;
+ unsigned int noio_flag;
struct blk_zone blkz;
int ret;
- /* Get zone information from disk */
+ /*
+ * Get zone information from disk. Since blkdev_report_zones() uses
+ * GFP_KERNEL by default for memory allocations, set the per-task
+ * PF_MEMALLOC_NOIO flag so that all allocations are done as if
+ * GFP_NOIO was specified.
+ */
+ noio_flag = memalloc_noio_save();
ret = blkdev_report_zones(zmd->dev->bdev, dmz_start_sect(zmd, zone),
- &blkz, &nr_blkz, GFP_NOIO);
+ &blkz, &nr_blkz);
+ memalloc_noio_restore(noio_flag);
if (!nr_blkz)
ret = -EIO;
if (ret) {
}
static int dm_blk_report_zones(struct gendisk *disk, sector_t sector,
- struct blk_zone *zones, unsigned int *nr_zones,
- gfp_t gfp_mask)
+ struct blk_zone *zones, unsigned int *nr_zones)
{
#ifdef CONFIG_BLK_DEV_ZONED
struct mapped_device *md = disk->private_data;
* So there is no need to loop here trying to fill the entire array
* of zones.
*/
- ret = tgt->type->report_zones(tgt, sector, zones,
- nr_zones, gfp_mask);
+ ret = tgt->type->report_zones(tgt, sector, zones, nr_zones);
out:
dm_put_live_table(md, srcu_idx);
extern void sd_zbc_complete(struct scsi_cmnd *cmd, unsigned int good_bytes,
struct scsi_sense_hdr *sshdr);
extern int sd_zbc_report_zones(struct gendisk *disk, sector_t sector,
- struct blk_zone *zones, unsigned int *nr_zones,
- gfp_t gfp_mask);
+ struct blk_zone *zones, unsigned int *nr_zones);
#else /* CONFIG_BLK_DEV_ZONED */
* @sector: Start 512B sector of the report
* @zones: Array of zone descriptors
* @nr_zones: Number of descriptors in the array
- * @gfp_mask: Memory allocation mask
*
* Execute a report zones command on the target disk.
*/
int sd_zbc_report_zones(struct gendisk *disk, sector_t sector,
- struct blk_zone *zones, unsigned int *nr_zones,
- gfp_t gfp_mask)
+ struct blk_zone *zones, unsigned int *nr_zones)
{
struct scsi_disk *sdkp = scsi_disk(disk);
unsigned int i, buflen, nrz = *nr_zones;
*/
buflen = min(queue_max_hw_sectors(disk->queue) << 9,
roundup((nrz + 1) * 64, 512));
- buf = kmalloc(buflen, gfp_mask);
+ buf = kmalloc(buflen, GFP_KERNEL);
if (!buf)
return -ENOMEM;
while (zones && sector < nr_sectors) {
nr_zones = F2FS_REPORT_NR_ZONES;
- err = blkdev_report_zones(bdev, sector,
- zones, &nr_zones,
- GFP_KERNEL);
+ err = blkdev_report_zones(bdev, sector, zones, &nr_zones);
if (err)
break;
if (!nr_zones) {
extern unsigned int blkdev_nr_zones(struct block_device *bdev);
extern int blkdev_report_zones(struct block_device *bdev,
sector_t sector, struct blk_zone *zones,
- unsigned int *nr_zones, gfp_t gfp_mask);
+ unsigned int *nr_zones);
extern int blkdev_reset_zones(struct block_device *bdev, sector_t sectors,
sector_t nr_sectors, gfp_t gfp_mask);
extern int blk_revalidate_disk_zones(struct gendisk *disk);
/* this callback is with swap_lock and sometimes page table lock held */
void (*swap_slot_free_notify) (struct block_device *, unsigned long);
int (*report_zones)(struct gendisk *, sector_t sector,
- struct blk_zone *zones, unsigned int *nr_zones,
- gfp_t gfp_mask);
+ struct blk_zone *zones, unsigned int *nr_zones);
struct module *owner;
const struct pr_ops *pr_ops;
};
typedef int (*dm_report_zones_fn) (struct dm_target *ti, sector_t sector,
struct blk_zone *zones,
- unsigned int *nr_zones,
- gfp_t gfp_mask);
+ unsigned int *nr_zones);
/*
* These iteration functions are typically used to check (and combine)