Skip to content

Commit

Permalink
blk-zoned: implement ioctls
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Damien Le Moal <[email protected]>
Reviewed-by: Christoph Hellwig <[email protected]>
Reviewed-by: Martin K. Petersen <[email protected]>
Reviewed-by: Hannes Reinecke <[email protected]>
Signed-off-by: Jens Axboe <[email protected]>
  • Loading branch information
stancheff authored and axboe committed Oct 18, 2016
1 parent 6a0cb1b commit 3ed05a9
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 0 deletions.
93 changes: 93 additions & 0 deletions block/blk-zoned.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
4 changes: 4 additions & 0 deletions block/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
21 changes: 21 additions & 0 deletions include/linux/blkdev.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
40 changes: 40 additions & 0 deletions include/uapi/linux/blkzoned.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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 */
4 changes: 4 additions & 0 deletions include/uapi/linux/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down

0 comments on commit 3ed05a9

Please sign in to comment.