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: Shaun Tancheff <shaun.tancheff@seagate.com> Signed-off-by: Damien Le Moal <damien.lemoal@hgst.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com> Reviewed-by: Hannes Reinecke <hare@suse.com> Signed-off-by: Jens Axboe <axboe@fb.com>
This commit is contained in:
parent
6a0cb1bc10
commit
3ed05a987e
5 changed files with 162 additions and 0 deletions
|
@ -255,3 +255,96 @@ int blkdev_reset_zones(struct block_device *bdev,
|
|||
return 0;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -519,6 +519,10 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
|
|||
BLKDEV_DISCARD_SECURE);
|
||||
case BLKZEROOUT:
|
||||
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:
|
||||
return blkdev_getgeo(bdev, argp);
|
||||
case BLKRAGET:
|
||||
|
|
|
@ -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,
|
||||
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 */
|
||||
|
||||
struct request_queue {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#define _UAPI_BLKZONED_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/ioctl.h>
|
||||
|
||||
/**
|
||||
* enum blk_zone_type - Types of zones allowed in a zoned device.
|
||||
|
@ -100,4 +101,43 @@ struct blk_zone {
|
|||
__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 */
|
||||
|
|
|
@ -225,6 +225,10 @@ struct fsxattr {
|
|||
#define BLKSECDISCARD _IO(0x12,125)
|
||||
#define BLKROTATIONAL _IO(0x12,126)
|
||||
#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 FIBMAP _IO(0x00,1) /* bmap access */
|
||||
|
|
Loading…
Reference in a new issue