diff options
author | Shaun Tancheff <shaun@tancheff.com> | 2016-10-18 02:40:35 -0400 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2016-10-18 12:05:42 -0400 |
commit | 3ed05a987e0f63b21e634101e0b460d32f3581c3 (patch) | |
tree | 5c5e4166fcba2cf6ceb8bc7d88e586ac752f1094 | |
parent | 6a0cb1bc106fc07ce0443303bcdb7f7da5131e5c (diff) |
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>
-rw-r--r-- | block/blk-zoned.c | 93 | ||||
-rw-r--r-- | block/ioctl.c | 4 | ||||
-rw-r--r-- | include/linux/blkdev.h | 21 | ||||
-rw-r--r-- | include/uapi/linux/blkzoned.h | 40 | ||||
-rw-r--r-- | include/uapi/linux/fs.h | 4 |
5 files changed, 162 insertions, 0 deletions
diff --git a/block/blk-zoned.c b/block/blk-zoned.c index 1603573f9605..667f95d86695 100644 --- a/block/blk-zoned.c +++ b/block/blk-zoned.c | |||
@@ -255,3 +255,96 @@ int blkdev_reset_zones(struct block_device *bdev, | |||
255 | return 0; | 255 | return 0; |
256 | } | 256 | } |
257 | EXPORT_SYMBOL_GPL(blkdev_reset_zones); | 257 | EXPORT_SYMBOL_GPL(blkdev_reset_zones); |
258 | |||
259 | /** | ||
260 | * BLKREPORTZONE ioctl processing. | ||
261 | * Called from blkdev_ioctl. | ||
262 | */ | ||
263 | int blkdev_report_zones_ioctl(struct block_device *bdev, fmode_t mode, | ||
264 | unsigned int cmd, unsigned long arg) | ||
265 | { | ||
266 | void __user *argp = (void __user *)arg; | ||
267 | struct request_queue *q; | ||
268 | struct blk_zone_report rep; | ||
269 | struct blk_zone *zones; | ||
270 | int ret; | ||
271 | |||
272 | if (!argp) | ||
273 | return -EINVAL; | ||
274 | |||
275 | q = bdev_get_queue(bdev); | ||
276 | if (!q) | ||
277 | return -ENXIO; | ||
278 | |||
279 | if (!blk_queue_is_zoned(q)) | ||
280 | return -ENOTTY; | ||
281 | |||
282 | if (!capable(CAP_SYS_ADMIN)) | ||
283 | return -EACCES; | ||
284 | |||
285 | if (copy_from_user(&rep, argp, sizeof(struct blk_zone_report))) | ||
286 | return -EFAULT; | ||
287 | |||
288 | if (!rep.nr_zones) | ||
289 | return -EINVAL; | ||
290 | |||
291 | zones = kcalloc(rep.nr_zones, sizeof(struct blk_zone), GFP_KERNEL); | ||
292 | if (!zones) | ||
293 | return -ENOMEM; | ||
294 | |||
295 | ret = blkdev_report_zones(bdev, rep.sector, | ||
296 | zones, &rep.nr_zones, | ||
297 | GFP_KERNEL); | ||
298 | if (ret) | ||
299 | goto out; | ||
300 | |||
301 | if (copy_to_user(argp, &rep, sizeof(struct blk_zone_report))) { | ||
302 | ret = -EFAULT; | ||
303 | goto out; | ||
304 | } | ||
305 | |||
306 | if (rep.nr_zones) { | ||
307 | if (copy_to_user(argp + sizeof(struct blk_zone_report), zones, | ||
308 | sizeof(struct blk_zone) * rep.nr_zones)) | ||
309 | ret = -EFAULT; | ||
310 | } | ||
311 | |||
312 | out: | ||
313 | kfree(zones); | ||
314 | |||
315 | return ret; | ||
316 | } | ||
317 | |||
318 | /** | ||
319 | * BLKRESETZONE ioctl processing. | ||
320 | * Called from blkdev_ioctl. | ||
321 | */ | ||
322 | int blkdev_reset_zones_ioctl(struct block_device *bdev, fmode_t mode, | ||
323 | unsigned int cmd, unsigned long arg) | ||
324 | { | ||
325 | void __user *argp = (void __user *)arg; | ||
326 | struct request_queue *q; | ||
327 | struct blk_zone_range zrange; | ||
328 | |||
329 | if (!argp) | ||
330 | return -EINVAL; | ||
331 | |||
332 | q = bdev_get_queue(bdev); | ||
333 | if (!q) | ||
334 | return -ENXIO; | ||
335 | |||
336 | if (!blk_queue_is_zoned(q)) | ||
337 | return -ENOTTY; | ||
338 | |||
339 | if (!capable(CAP_SYS_ADMIN)) | ||
340 | return -EACCES; | ||
341 | |||
342 | if (!(mode & FMODE_WRITE)) | ||
343 | return -EBADF; | ||
344 | |||
345 | if (copy_from_user(&zrange, argp, sizeof(struct blk_zone_range))) | ||
346 | return -EFAULT; | ||
347 | |||
348 | return blkdev_reset_zones(bdev, zrange.sector, zrange.nr_sectors, | ||
349 | GFP_KERNEL); | ||
350 | } | ||
diff --git a/block/ioctl.c b/block/ioctl.c index 755119c3c1b9..f856963204f4 100644 --- a/block/ioctl.c +++ b/block/ioctl.c | |||
@@ -519,6 +519,10 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, | |||
519 | BLKDEV_DISCARD_SECURE); | 519 | BLKDEV_DISCARD_SECURE); |
520 | case BLKZEROOUT: | 520 | case BLKZEROOUT: |
521 | return blk_ioctl_zeroout(bdev, mode, arg); | 521 | return blk_ioctl_zeroout(bdev, mode, arg); |
522 | case BLKREPORTZONE: | ||
523 | return blkdev_report_zones_ioctl(bdev, mode, cmd, arg); | ||
524 | case BLKRESETZONE: | ||
525 | return blkdev_reset_zones_ioctl(bdev, mode, cmd, arg); | ||
522 | case HDIO_GETGEO: | 526 | case HDIO_GETGEO: |
523 | return blkdev_getgeo(bdev, argp); | 527 | return blkdev_getgeo(bdev, argp); |
524 | case BLKRAGET: | 528 | case BLKRAGET: |
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 252043f7cd2c..90097dd8b8ed 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h | |||
@@ -316,6 +316,27 @@ extern int blkdev_report_zones(struct block_device *bdev, | |||
316 | extern int blkdev_reset_zones(struct block_device *bdev, sector_t sectors, | 316 | extern int blkdev_reset_zones(struct block_device *bdev, sector_t sectors, |
317 | sector_t nr_sectors, gfp_t gfp_mask); | 317 | sector_t nr_sectors, gfp_t gfp_mask); |
318 | 318 | ||
319 | extern int blkdev_report_zones_ioctl(struct block_device *bdev, fmode_t mode, | ||
320 | unsigned int cmd, unsigned long arg); | ||
321 | extern int blkdev_reset_zones_ioctl(struct block_device *bdev, fmode_t mode, | ||
322 | unsigned int cmd, unsigned long arg); | ||
323 | |||
324 | #else /* CONFIG_BLK_DEV_ZONED */ | ||
325 | |||
326 | static inline int blkdev_report_zones_ioctl(struct block_device *bdev, | ||
327 | fmode_t mode, unsigned int cmd, | ||
328 | unsigned long arg) | ||
329 | { | ||
330 | return -ENOTTY; | ||
331 | } | ||
332 | |||
333 | static inline int blkdev_reset_zones_ioctl(struct block_device *bdev, | ||
334 | fmode_t mode, unsigned int cmd, | ||
335 | unsigned long arg) | ||
336 | { | ||
337 | return -ENOTTY; | ||
338 | } | ||
339 | |||
319 | #endif /* CONFIG_BLK_DEV_ZONED */ | 340 | #endif /* CONFIG_BLK_DEV_ZONED */ |
320 | 341 | ||
321 | struct request_queue { | 342 | struct request_queue { |
diff --git a/include/uapi/linux/blkzoned.h b/include/uapi/linux/blkzoned.h index a3817214b0e0..40d1d7bff537 100644 --- a/include/uapi/linux/blkzoned.h +++ b/include/uapi/linux/blkzoned.h | |||
@@ -16,6 +16,7 @@ | |||
16 | #define _UAPI_BLKZONED_H | 16 | #define _UAPI_BLKZONED_H |
17 | 17 | ||
18 | #include <linux/types.h> | 18 | #include <linux/types.h> |
19 | #include <linux/ioctl.h> | ||
19 | 20 | ||
20 | /** | 21 | /** |
21 | * enum blk_zone_type - Types of zones allowed in a zoned device. | 22 | * enum blk_zone_type - Types of zones allowed in a zoned device. |
@@ -100,4 +101,43 @@ struct blk_zone { | |||
100 | __u8 reserved[36]; | 101 | __u8 reserved[36]; |
101 | }; | 102 | }; |
102 | 103 | ||
104 | /** | ||
105 | * struct blk_zone_report - BLKREPORTZONE ioctl request/reply | ||
106 | * | ||
107 | * @sector: starting sector of report | ||
108 | * @nr_zones: IN maximum / OUT actual | ||
109 | * @reserved: padding to 16 byte alignment | ||
110 | * @zones: Space to hold @nr_zones @zones entries on reply. | ||
111 | * | ||
112 | * The array of at most @nr_zones must follow this structure in memory. | ||
113 | */ | ||
114 | struct blk_zone_report { | ||
115 | __u64 sector; | ||
116 | __u32 nr_zones; | ||
117 | __u8 reserved[4]; | ||
118 | struct blk_zone zones[0]; | ||
119 | } __packed; | ||
120 | |||
121 | /** | ||
122 | * struct blk_zone_range - BLKRESETZONE ioctl request | ||
123 | * @sector: starting sector of the first zone to issue reset write pointer | ||
124 | * @nr_sectors: Total number of sectors of 1 or more zones to reset | ||
125 | */ | ||
126 | struct blk_zone_range { | ||
127 | __u64 sector; | ||
128 | __u64 nr_sectors; | ||
129 | }; | ||
130 | |||
131 | /** | ||
132 | * Zoned block device ioctl's: | ||
133 | * | ||
134 | * @BLKREPORTZONE: Get zone information. Takes a zone report as argument. | ||
135 | * The zone report will start from the zone containing the | ||
136 | * sector specified in the report request structure. | ||
137 | * @BLKRESETZONE: Reset the write pointer of the zones in the specified | ||
138 | * sector range. The sector range must be zone aligned. | ||
139 | */ | ||
140 | #define BLKREPORTZONE _IOWR(0x12, 130, struct blk_zone_report) | ||
141 | #define BLKRESETZONE _IOW(0x12, 131, struct blk_zone_range) | ||
142 | |||
103 | #endif /* _UAPI_BLKZONED_H */ | 143 | #endif /* _UAPI_BLKZONED_H */ |
diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h index acb2b6152ba0..c1d11df07b28 100644 --- a/include/uapi/linux/fs.h +++ b/include/uapi/linux/fs.h | |||
@@ -225,6 +225,10 @@ struct fsxattr { | |||
225 | #define BLKSECDISCARD _IO(0x12,125) | 225 | #define BLKSECDISCARD _IO(0x12,125) |
226 | #define BLKROTATIONAL _IO(0x12,126) | 226 | #define BLKROTATIONAL _IO(0x12,126) |
227 | #define BLKZEROOUT _IO(0x12,127) | 227 | #define BLKZEROOUT _IO(0x12,127) |
228 | /* | ||
229 | * A jump here: 130-131 are reserved for zoned block devices | ||
230 | * (see uapi/linux/blkzoned.h) | ||
231 | */ | ||
228 | 232 | ||
229 | #define BMAP_IOCTL 1 /* obsolete - kept for compatibility */ | 233 | #define BMAP_IOCTL 1 /* obsolete - kept for compatibility */ |
230 | #define FIBMAP _IO(0x00,1) /* bmap access */ | 234 | #define FIBMAP _IO(0x00,1) /* bmap access */ |