Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3ed05a98 authored by Shaun Tancheff's avatar Shaun Tancheff Committed by Jens Axboe
Browse files

blk-zoned: implement ioctls



Adds the new BLKREPORTZONE and BLKRESETZONE ioctls for respectively
obtaining the zone configuration of a zoned block device and resetting
the write pointer of sequential zones of a zoned block device.

The BLKREPORTZONE ioctl maps directly to a single call of the function
blkdev_report_zones. The zone information result is passed as an array
of struct blk_zone identical to the structure used internally for
processing the REQ_OP_ZONE_REPORT operation.  The BLKRESETZONE ioctl
maps to a single call of the blkdev_reset_zones function.

Signed-off-by: default avatarShaun Tancheff <shaun.tancheff@seagate.com>
Signed-off-by: default avatarDamien Le Moal <damien.lemoal@hgst.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: default avatarHannes Reinecke <hare@suse.com>
Signed-off-by: default avatarJens Axboe <axboe@fb.com>
parent 6a0cb1bc
Loading
Loading
Loading
Loading
+93 −0
Original line number Original line Diff line number Diff line
@@ -255,3 +255,96 @@ int blkdev_reset_zones(struct block_device *bdev,
	return 0;
	return 0;
}
}
EXPORT_SYMBOL_GPL(blkdev_reset_zones);
EXPORT_SYMBOL_GPL(blkdev_reset_zones);

/**
 * BLKREPORTZONE ioctl processing.
 * Called from blkdev_ioctl.
 */
int blkdev_report_zones_ioctl(struct block_device *bdev, fmode_t mode,
			      unsigned int cmd, unsigned long arg)
{
	void __user *argp = (void __user *)arg;
	struct request_queue *q;
	struct blk_zone_report rep;
	struct blk_zone *zones;
	int ret;

	if (!argp)
		return -EINVAL;

	q = bdev_get_queue(bdev);
	if (!q)
		return -ENXIO;

	if (!blk_queue_is_zoned(q))
		return -ENOTTY;

	if (!capable(CAP_SYS_ADMIN))
		return -EACCES;

	if (copy_from_user(&rep, argp, sizeof(struct blk_zone_report)))
		return -EFAULT;

	if (!rep.nr_zones)
		return -EINVAL;

	zones = kcalloc(rep.nr_zones, sizeof(struct blk_zone), GFP_KERNEL);
	if (!zones)
		return -ENOMEM;

	ret = blkdev_report_zones(bdev, rep.sector,
				  zones, &rep.nr_zones,
				  GFP_KERNEL);
	if (ret)
		goto out;

	if (copy_to_user(argp, &rep, sizeof(struct blk_zone_report))) {
		ret = -EFAULT;
		goto out;
	}

	if (rep.nr_zones) {
		if (copy_to_user(argp + sizeof(struct blk_zone_report), zones,
				 sizeof(struct blk_zone) * rep.nr_zones))
			ret = -EFAULT;
	}

 out:
	kfree(zones);

	return ret;
}

/**
 * BLKRESETZONE ioctl processing.
 * Called from blkdev_ioctl.
 */
int blkdev_reset_zones_ioctl(struct block_device *bdev, fmode_t mode,
			     unsigned int cmd, unsigned long arg)
{
	void __user *argp = (void __user *)arg;
	struct request_queue *q;
	struct blk_zone_range zrange;

	if (!argp)
		return -EINVAL;

	q = bdev_get_queue(bdev);
	if (!q)
		return -ENXIO;

	if (!blk_queue_is_zoned(q))
		return -ENOTTY;

	if (!capable(CAP_SYS_ADMIN))
		return -EACCES;

	if (!(mode & FMODE_WRITE))
		return -EBADF;

	if (copy_from_user(&zrange, argp, sizeof(struct blk_zone_range)))
		return -EFAULT;

	return blkdev_reset_zones(bdev, zrange.sector, zrange.nr_sectors,
				  GFP_KERNEL);
}
+4 −0
Original line number Original line Diff line number Diff line
@@ -519,6 +519,10 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
				BLKDEV_DISCARD_SECURE);
				BLKDEV_DISCARD_SECURE);
	case BLKZEROOUT:
	case BLKZEROOUT:
		return blk_ioctl_zeroout(bdev, mode, arg);
		return blk_ioctl_zeroout(bdev, mode, arg);
	case BLKREPORTZONE:
		return blkdev_report_zones_ioctl(bdev, mode, cmd, arg);
	case BLKRESETZONE:
		return blkdev_reset_zones_ioctl(bdev, mode, cmd, arg);
	case HDIO_GETGEO:
	case HDIO_GETGEO:
		return blkdev_getgeo(bdev, argp);
		return blkdev_getgeo(bdev, argp);
	case BLKRAGET:
	case BLKRAGET:
+21 −0
Original line number Original line Diff line number Diff line
@@ -316,6 +316,27 @@ extern int blkdev_report_zones(struct block_device *bdev,
extern int blkdev_reset_zones(struct block_device *bdev, sector_t sectors,
extern int blkdev_reset_zones(struct block_device *bdev, sector_t sectors,
			      sector_t nr_sectors, gfp_t gfp_mask);
			      sector_t nr_sectors, gfp_t gfp_mask);


extern int blkdev_report_zones_ioctl(struct block_device *bdev, fmode_t mode,
				     unsigned int cmd, unsigned long arg);
extern int blkdev_reset_zones_ioctl(struct block_device *bdev, fmode_t mode,
				    unsigned int cmd, unsigned long arg);

#else /* CONFIG_BLK_DEV_ZONED */

static inline int blkdev_report_zones_ioctl(struct block_device *bdev,
					    fmode_t mode, unsigned int cmd,
					    unsigned long arg)
{
	return -ENOTTY;
}

static inline int blkdev_reset_zones_ioctl(struct block_device *bdev,
					   fmode_t mode, unsigned int cmd,
					   unsigned long arg)
{
	return -ENOTTY;
}

#endif /* CONFIG_BLK_DEV_ZONED */
#endif /* CONFIG_BLK_DEV_ZONED */


struct request_queue {
struct request_queue {
+40 −0
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@
#define _UAPI_BLKZONED_H
#define _UAPI_BLKZONED_H


#include <linux/types.h>
#include <linux/types.h>
#include <linux/ioctl.h>


/**
/**
 * enum blk_zone_type - Types of zones allowed in a zoned device.
 * enum blk_zone_type - Types of zones allowed in a zoned device.
@@ -100,4 +101,43 @@ struct blk_zone {
	__u8	reserved[36];
	__u8	reserved[36];
};
};


/**
 * struct blk_zone_report - BLKREPORTZONE ioctl request/reply
 *
 * @sector: starting sector of report
 * @nr_zones: IN maximum / OUT actual
 * @reserved: padding to 16 byte alignment
 * @zones: Space to hold @nr_zones @zones entries on reply.
 *
 * The array of at most @nr_zones must follow this structure in memory.
 */
struct blk_zone_report {
	__u64		sector;
	__u32		nr_zones;
	__u8		reserved[4];
	struct blk_zone zones[0];
} __packed;

/**
 * struct blk_zone_range - BLKRESETZONE ioctl request
 * @sector: starting sector of the first zone to issue reset write pointer
 * @nr_sectors: Total number of sectors of 1 or more zones to reset
 */
struct blk_zone_range {
	__u64		sector;
	__u64		nr_sectors;
};

/**
 * Zoned block device ioctl's:
 *
 * @BLKREPORTZONE: Get zone information. Takes a zone report as argument.
 *                 The zone report will start from the zone containing the
 *                 sector specified in the report request structure.
 * @BLKRESETZONE: Reset the write pointer of the zones in the specified
 *                sector range. The sector range must be zone aligned.
 */
#define BLKREPORTZONE	_IOWR(0x12, 130, struct blk_zone_report)
#define BLKRESETZONE	_IOW(0x12, 131, struct blk_zone_range)

#endif /* _UAPI_BLKZONED_H */
#endif /* _UAPI_BLKZONED_H */
+4 −0
Original line number Original line Diff line number Diff line
@@ -225,6 +225,10 @@ struct fsxattr {
#define BLKSECDISCARD _IO(0x12,125)
#define BLKSECDISCARD _IO(0x12,125)
#define BLKROTATIONAL _IO(0x12,126)
#define BLKROTATIONAL _IO(0x12,126)
#define BLKZEROOUT _IO(0x12,127)
#define BLKZEROOUT _IO(0x12,127)
/*
 * A jump here: 130-131 are reserved for zoned block devices
 * (see uapi/linux/blkzoned.h)
 */


#define BMAP_IOCTL 1		/* obsolete - kept for compatibility */
#define BMAP_IOCTL 1		/* obsolete - kept for compatibility */
#define FIBMAP	   _IO(0x00,1)	/* bmap access */
#define FIBMAP	   _IO(0x00,1)	/* bmap access */