Add zoned storage support to ublk: report_zones and operations: - REQ_OP_ZONE_OPEN - REQ_OP_ZONE_CLOSE - REQ_OP_ZONE_FINISH - REQ_OP_ZONE_RESET - REQ_OP_ZONE_APPEND The zone append feature uses the `addr` field of `struct ublksrv_io_cmd` to communicate ALBA back to the kernel. Therefore ublk must be used with the user copy feature (UBLK_F_USER_COPY) for zoned storage support to be available. Without this feature, ublk will not allow zoned storage support.
Unified · Split
| @@ -56,16 +56,21 @@ · 55 unmodified lines | |||
| 56 | | UBLK_F_USER_RECOVERY_REISSUE \ | 56 | | UBLK_F_USER_RECOVERY_REISSUE \ |
| 57 | | UBLK_F_UNPRIVILEGED_DEV \ | 57 | | UBLK_F_UNPRIVILEGED_DEV \ |
| 58 | | UBLK_F_CMD_IOCTL_ENCODE \ | 58 | | UBLK_F_CMD_IOCTL_ENCODE \ |
| 59 | | UBLK_F_USER_COPY) | 59 | | UBLK_F_USER_COPY \ |
| 60 | | UBLK_F_ZONED) | ||
| 60 | 61 | ||
| 61 | /* All UBLK_PARAM_TYPE_* should be included here */ | 62 | /* All UBLK_PARAM_TYPE_* should be included here */ |
| 62 | #define UBLK_PARAM_TYPE_ALL (UBLK_PARAM_TYPE_BASIC | \ | 63 | #define UBLK_PARAM_TYPE_ALL \ |
| 63 | UBLK_PARAM_TYPE_DISCARD | UBLK_PARAM_TYPE_DEVT) | 64 | (UBLK_PARAM_TYPE_BASIC | UBLK_PARAM_TYPE_DISCARD | \ |
| 65 | UBLK_PARAM_TYPE_DEVT | UBLK_PARAM_TYPE_ZONED) | ||
| 64 | 66 | ||
| 65 | struct ublk_rq_data { | 67 | struct ublk_rq_data { |
| 66 | struct llist_node node; | 68 | struct llist_node node; |
| 67 | 69 | ||
| 68 | struct kref ref; | 70 | struct kref ref; |
| 71 | __u64 sector; | ||
| 72 | __u32 operation; | ||
| 73 | __u32 nr_zones; | ||
| 69 | }; | 74 | }; |
| 70 | 75 | ||
| 71 | struct ublk_uring_cmd_pdu { | 76 | struct ublk_uring_cmd_pdu { |
| @@ -185,11 +190,263 @@ struct ublk_params_header { · 113 unmodified lines | |||
| 185 | __u32 types; | 190 | __u32 types; |
| 186 | }; | 191 | }; |
| 187 | 192 | ||
| 193 | static inline unsigned int ublk_req_build_flags(struct request *req); | ||
| 194 | static inline struct ublksrv_io_desc *ublk_get_iod(struct ublk_queue *ubq, | ||
| 195 | int tag); | ||
| 196 | |||
| 188 | static inline bool ublk_dev_is_user_copy(const struct ublk_device *ub) | 197 | static inline bool ublk_dev_is_user_copy(const struct ublk_device *ub) |
| 189 | { | 198 | { |
| 190 | return ub->dev_info.flags & UBLK_F_USER_COPY; | 199 | return ub->dev_info.flags & UBLK_F_USER_COPY; |
| 191 | } | 200 | } |
| 192 | 201 | ||
| 202 | static inline bool ublk_dev_is_zoned(const struct ublk_device *ub) | ||
| 203 | { | ||
| 204 | return ub->dev_info.flags & UBLK_F_ZONED; | ||
| 205 | } | ||
| 206 | |||
| 207 | static inline bool ublk_queue_is_zoned(struct ublk_queue *ubq) | ||
| 208 | { | ||
| 209 | return ubq->flags & UBLK_F_ZONED; | ||
| 210 | } | ||
| 211 | |||
| 212 | #ifdef CONFIG_BLK_DEV_ZONED | ||
| 213 | |||
| 214 | static int ublk_get_nr_zones(const struct ublk_device *ub) | ||
| 215 | { | ||
| 216 | const struct ublk_param_basic *p = &ub->params.basic; | ||
| 217 | |||
| 218 | /* Zone size is a power of 2 */ | ||
| 219 | return p->dev_sectors >> ilog2(p->chunk_sectors); | ||
| 220 | } | ||
| 221 | |||
| 222 | static int ublk_revalidate_disk_zones(struct ublk_device *ub) | ||
| 223 | { | ||
| 224 | return blk_revalidate_disk_zones(ub->ub_disk, NULL); | ||
| 225 | } | ||
| 226 | |||
| 227 | static int ublk_dev_param_zoned_validate(const struct ublk_device *ub) | ||
| 228 | { | ||
| 229 | const struct ublk_param_zoned *p = &ub->params.zoned; | ||
| 230 | int nr_zones; | ||
| 231 | |||
| 232 | if (!ublk_dev_is_zoned(ub)) | ||
| 233 | return -EINVAL; | ||
| 234 | |||
| 235 | if (!p->max_zone_append_sectors) | ||
| 236 | return -EINVAL; | ||
| 237 | |||
| 238 | nr_zones = ublk_get_nr_zones(ub); | ||
| 239 | |||
| 240 | if (p->max_active_zones > nr_zones) | ||
| 241 | return -EINVAL; | ||
| 242 | |||
| 243 | if (p->max_open_zones > nr_zones) | ||
| 244 | return -EINVAL; | ||
| 245 | |||
| 246 | return 0; | ||
| 247 | } | ||
| 248 | |||
| 249 | static int ublk_dev_param_zoned_apply(struct ublk_device *ub) | ||
| 250 | { | ||
| 251 | const struct ublk_param_zoned *p = &ub->params.zoned; | ||
| 252 | |||
| 253 | disk_set_zoned(ub->ub_disk, BLK_ZONED_HM); | ||
| 254 | blk_queue_required_elevator_features(ub->ub_disk->queue, | ||
| 255 | ELEVATOR_F_ZBD_SEQ_WRITE); | ||
| 256 | disk_set_max_active_zones(ub->ub_disk, p->max_active_zones); | ||
| 257 | disk_set_max_open_zones(ub->ub_disk, p->max_open_zones); | ||
| 258 | blk_queue_max_zone_append_sectors(ub->ub_disk->queue, p->max_zone_append_sectors); | ||
| 259 | |||
| 260 | ub->ub_disk->nr_zones = ublk_get_nr_zones(ub); | ||
| 261 | |||
| 262 | return 0; | ||
| 263 | } | ||
| 264 | |||
| 265 | /* Based on virtblk_alloc_report_buffer */ | ||
| 266 | static void *ublk_alloc_report_buffer(struct ublk_device *ublk, | ||
| 267 | unsigned int nr_zones, size_t *buflen) | ||
| 268 | { | ||
| 269 | struct request_queue *q = ublk->ub_disk->queue; | ||
| 270 | size_t bufsize; | ||
| 271 | void *buf; | ||
| 272 | |||
| 273 | nr_zones = min_t(unsigned int, nr_zones, | ||
| 274 | ublk->ub_disk->nr_zones); | ||
| 275 | |||
| 276 | bufsize = nr_zones * sizeof(struct blk_zone); | ||
| 277 | bufsize = | ||
| 278 | min_t(size_t, bufsize, queue_max_hw_sectors(q) << SECTOR_SHIFT); | ||
| 279 | |||
| 280 | while (bufsize >= sizeof(struct blk_zone)) { | ||
| 281 | buf = kvmalloc(bufsize, GFP_KERNEL | __GFP_NORETRY); | ||
| 282 | if (buf) { | ||
| 283 | *buflen = bufsize; | ||
| 284 | return buf; | ||
| 285 | } | ||
| 286 | bufsize >>= 1; | ||
| 287 | } | ||
| 288 | |||
| 289 | *buflen = 0; | ||
| 290 | return NULL; | ||
| 291 | } | ||
| 292 | |||
| 293 | static int ublk_report_zones(struct gendisk *disk, sector_t sector, | ||
| 294 | unsigned int nr_zones, report_zones_cb cb, void *data) | ||
| 295 | { | ||
| 296 | struct ublk_device *ub = disk->private_data; | ||
| 297 | unsigned int zone_size_sectors = disk->queue->limits.chunk_sectors; | ||
| 298 | unsigned int first_zone = sector >> ilog2(zone_size_sectors); | ||
| 299 | unsigned int done_zones = 0; | ||
| 300 | unsigned int max_zones_per_request; | ||
| 301 | int ret; | ||
| 302 | struct blk_zone *buffer; | ||
| 303 | size_t buffer_length; | ||
| 304 | |||
| 305 | nr_zones = min_t(unsigned int, ub->ub_disk->nr_zones - first_zone, | ||
| 306 | nr_zones); | ||
| 307 | |||
| 308 | buffer = ublk_alloc_report_buffer(ub, nr_zones, &buffer_length); | ||
| 309 | if (!buffer) | ||
| 310 | return -ENOMEM; | ||
| 311 | |||
| 312 | max_zones_per_request = buffer_length / sizeof(struct blk_zone); | ||
| 313 | |||
| 314 | while (done_zones < nr_zones) { | ||
| 315 | unsigned int remaining_zones = nr_zones - done_zones; | ||
| 316 | unsigned int zones_in_request = | ||
| 317 | min_t(unsigned int, remaining_zones, max_zones_per_request); | ||
| 318 | struct request *req; | ||
| 319 | struct ublk_rq_data *pdu; | ||
| 320 | blk_status_t status; | ||
| 321 | |||
| 322 | memset(buffer, 0, buffer_length); | ||
| 323 | |||
| 324 | req = blk_mq_alloc_request(disk->queue, REQ_OP_DRV_IN, 0); | ||
| 325 | if (IS_ERR(req)) { | ||
| 326 | ret = PTR_ERR(req); | ||
| 327 | goto out; | ||
| 328 | } | ||
| 329 | |||
| 330 | pdu = blk_mq_rq_to_pdu(req); | ||
| 331 | pdu->operation = UBLK_IO_OP_REPORT_ZONES; | ||
| 332 | pdu->sector = sector; | ||
| 333 | pdu->nr_zones = zones_in_request; | ||
| 334 | |||
| 335 | ret = blk_rq_map_kern(disk->queue, req, buffer, buffer_length, | ||
| 336 | GFP_KERNEL); | ||
| 337 | if (ret) { | ||
| 338 | blk_mq_free_request(req); | ||
| 339 | goto out; | ||
| 340 | } | ||
| 341 | |||
| 342 | status = blk_execute_rq(req, 0); | ||
| 343 | ret = blk_status_to_errno(status); | ||
| 344 | blk_mq_free_request(req); | ||
| 345 | if (ret) | ||
| 346 | goto out; | ||
| 347 | |||
| 348 | for (unsigned int i = 0; i < zones_in_request; i++) { | ||
| 349 | struct blk_zone *zone = buffer + i; | ||
| 350 | |||
| 351 | /* A zero length zone means no more zones in this response */ | ||
| 352 | if (!zone->len) | ||
| 353 | break; | ||
| 354 | |||
| 355 | ret = cb(zone, i, data); | ||
| 356 | if (ret) | ||
| 357 | goto out; | ||
| 358 | |||
| 359 | done_zones++; | ||
| 360 | sector += zone_size_sectors; | ||
| 361 | |||
| 362 | } | ||
| 363 | } | ||
| 364 | |||
| 365 | ret = done_zones; | ||
| 366 | |||
| 367 | out: | ||
| 368 | kvfree(buffer); | ||
| 369 | return ret; | ||
| 370 | } | ||
| 371 | |||
| 372 | static blk_status_t ublk_setup_iod_zoned(struct ublk_queue *ubq, | ||
| 373 | struct request *req) | ||
| 374 | { | ||
| 375 | struct ublksrv_io_desc *iod = ublk_get_iod(ubq, req->tag); | ||
| 376 | struct ublk_io *io = &ubq->ios[req->tag]; | ||
| 377 | struct ublk_rq_data *pdu = blk_mq_rq_to_pdu(req); | ||
| 378 | u32 ublk_op; | ||
| 379 | |||
| 380 | switch (req_op(req)) { | ||
| 381 | case REQ_OP_ZONE_OPEN: | ||
| 382 | ublk_op = UBLK_IO_OP_ZONE_OPEN; | ||
| 383 | break; | ||
| 384 | case REQ_OP_ZONE_CLOSE: | ||
| 385 | ublk_op = UBLK_IO_OP_ZONE_CLOSE; | ||
| 386 | break; | ||
| 387 | case REQ_OP_ZONE_FINISH: | ||
| 388 | ublk_op = UBLK_IO_OP_ZONE_FINISH; | ||
| 389 | break; | ||
| 390 | case REQ_OP_ZONE_RESET: | ||
| 391 | ublk_op = UBLK_IO_OP_ZONE_RESET; | ||
| 392 | break; | ||
| 393 | case REQ_OP_ZONE_APPEND: | ||
| 394 | ublk_op = UBLK_IO_OP_ZONE_APPEND; | ||
| 395 | break; | ||
| 396 | case REQ_OP_DRV_IN: | ||
| 397 | ublk_op = pdu->operation; | ||
| 398 | switch (ublk_op) { | ||
| 399 | case UBLK_IO_OP_REPORT_ZONES: | ||
| 400 | iod->op_flags = ublk_op | ublk_req_build_flags(req); | ||
| 401 | iod->nr_zones = pdu->nr_zones; | ||
| 402 | iod->start_sector = pdu->sector; | ||
| 403 | return BLK_STS_OK; | ||
| 404 | default: | ||
| 405 | return BLK_STS_IOERR; | ||
| 406 | } | ||
| 407 | case REQ_OP_ZONE_RESET_ALL: | ||
| 408 | case REQ_OP_DRV_OUT: | ||
| 409 | /* We do not support reset_all and drv_out */ | ||
| 410 | return BLK_STS_NOTSUPP; | ||
| 411 | default: | ||
| 412 | return BLK_STS_IOERR; | ||
| 413 | } | ||
| 414 | |||
| 415 | iod->op_flags = ublk_op | ublk_req_build_flags(req); | ||
| 416 | iod->nr_sectors = blk_rq_sectors(req); | ||
| 417 | iod->start_sector = blk_rq_pos(req); | ||
| 418 | iod->addr = io->addr; | ||
| 419 | |||
| 420 | return BLK_STS_OK; | ||
| 421 | } | ||
| 422 | |||
| 423 | #else | ||
| 424 | |||
| 425 | #define ublk_report_zones (NULL) | ||
| 426 | |||
| 427 | static int ublk_dev_param_zoned_validate(const struct ublk_device *ub) | ||
| 428 | { | ||
| 429 | return -EOPNOTSUPP; | ||
| 430 | } | ||
| 431 | |||
| 432 | static int ublk_dev_param_zoned_apply(struct ublk_device *ub) | ||
| 433 | { | ||
| 434 | return -EOPNOTSUPP; | ||
| 435 | } | ||
| 436 | |||
| 437 | static int ublk_revalidate_disk_zones(struct ublk_device *ub) | ||
| 438 | { | ||
| 439 | return 0; | ||
| 440 | } | ||
| 441 | |||
| 442 | static blk_status_t ublk_setup_iod_zoned(struct ublk_queue *ubq, | ||
| 443 | struct request *req) | ||
| 444 | { | ||
| 445 | return -EOPNOTSUPP; | ||
| 446 | } | ||
| 447 | |||
| 448 | #endif | ||
| 449 | |||
| 193 | static inline void __ublk_complete_rq(struct request *req); | 450 | static inline void __ublk_complete_rq(struct request *req); |
| 194 | static void ublk_complete_rq(struct kref *ref); | 451 | static void ublk_complete_rq(struct kref *ref); |
| 195 | 452 | ||
| @@ -286,6 +543,9 @@ static int ublk_validate_params(const struct ublk_device *ub) · 90 unmodified lines | |||
| 286 | 543 | ||
| 287 | if (p->max_sectors > (ub->dev_info.max_io_buf_bytes >> 9)) | 544 | if (p->max_sectors > (ub->dev_info.max_io_buf_bytes >> 9)) |
| 288 | return -EINVAL; | 545 | return -EINVAL; |
| 546 | |||
| 547 | if (ublk_dev_is_zoned(ub) && !p->chunk_sectors) | ||
| 548 | return -EINVAL; | ||
| 289 | } else | 549 | } else |
| 290 | return -EINVAL; | 550 | return -EINVAL; |
| 291 | 551 | ||
| @@ -304,6 +564,11 @@ static int ublk_validate_params(const struct ublk_device *ub) · 12 unmodified lines | |||
| 304 | if (ub->params.types & UBLK_PARAM_TYPE_DEVT) | 564 | if (ub->params.types & UBLK_PARAM_TYPE_DEVT) |
| 305 | return -EINVAL; | 565 | return -EINVAL; |
| 306 | 566 | ||
| 567 | if (ub->params.types & UBLK_PARAM_TYPE_ZONED) | ||
| 568 | return ublk_dev_param_zoned_validate(ub); | ||
| 569 | else if (ublk_dev_is_zoned(ub)) | ||
| 570 | return -EINVAL; | ||
| 571 | |||
| 307 | return 0; | 572 | return 0; |
| 308 | } | 573 | } |
| 309 | 574 | ||
| @@ -317,6 +582,9 @@ static int ublk_apply_params(struct ublk_device *ub) · 7 unmodified lines | |||
| 317 | if (ub->params.types & UBLK_PARAM_TYPE_DISCARD) | 582 | if (ub->params.types & UBLK_PARAM_TYPE_DISCARD) |
| 318 | ublk_dev_param_discard_apply(ub); | 583 | ublk_dev_param_discard_apply(ub); |
| 319 | 584 | ||
| 585 | if (ub->params.types & UBLK_PARAM_TYPE_ZONED) | ||
| 586 | return ublk_dev_param_zoned_apply(ub); | ||
| 587 | |||
| 320 | return 0; | 588 | return 0; |
| 321 | } | 589 | } |
| 322 | 590 | ||
| @@ -487,6 +755,7 @@ static const struct block_device_operations ub_fops = { · 164 unmodified lines | |||
| 487 | .owner = THIS_MODULE, | 755 | .owner = THIS_MODULE, |
| 488 | .open = ublk_open, | 756 | .open = ublk_open, |
| 489 | .free_disk = ublk_free_disk, | 757 | .free_disk = ublk_free_disk, |
| 758 | .report_zones = ublk_report_zones, | ||
| 490 | }; | 759 | }; |
| 491 | 760 | ||
| 492 | #define UBLK_MAX_PIN_PAGES 32 | 761 | #define UBLK_MAX_PIN_PAGES 32 |
| @@ -601,7 +870,8 @@ static inline bool ublk_need_map_req(const struct request *req) · 108 unmodified lines | |||
| 601 | 870 | ||
| 602 | static inline bool ublk_need_unmap_req(const struct request *req) | 871 | static inline bool ublk_need_unmap_req(const struct request *req) |
| 603 | { | 872 | { |
| 604 | return ublk_rq_has_data(req) && req_op(req) == REQ_OP_READ; | 873 | return ublk_rq_has_data(req) && |
| 874 | (req_op(req) == REQ_OP_READ || req_op(req) == REQ_OP_DRV_IN); | ||
| 605 | } | 875 | } |
| 606 | 876 | ||
| 607 | static int ublk_map_io(const struct ublk_queue *ubq, const struct request *req, | 877 | static int ublk_map_io(const struct ublk_queue *ubq, const struct request *req, |
| @@ -685,8 +955,13 @@ static blk_status_t ublk_setup_iod(struct ublk_queue *ubq, struct request *req) · 77 unmodified lines | |||
| 685 | { | 955 | { |
| 686 | struct ublksrv_io_desc *iod = ublk_get_iod(ubq, req->tag); | 956 | struct ublksrv_io_desc *iod = ublk_get_iod(ubq, req->tag); |
| 687 | struct ublk_io *io = &ubq->ios[req->tag]; | 957 | struct ublk_io *io = &ubq->ios[req->tag]; |
| 958 | enum req_op op = req_op(req); | ||
| 688 | u32 ublk_op; | 959 | u32 ublk_op; |
| 689 | 960 | ||
| 961 | if (!ublk_queue_is_zoned(ubq) && | ||
| 962 | (op_is_zone_mgmt(op) || op == REQ_OP_ZONE_APPEND)) | ||
| 963 | return -EIO; | ||
| 964 | |||
| 690 | switch (req_op(req)) { | 965 | switch (req_op(req)) { |
| 691 | case REQ_OP_READ: | 966 | case REQ_OP_READ: |
| 692 | ublk_op = UBLK_IO_OP_READ; | 967 | ublk_op = UBLK_IO_OP_READ; |
| @@ -704,6 +979,8 @@ static blk_status_t ublk_setup_iod(struct ublk_queue *ubq, struct request *req) · 11 unmodified lines | |||
| 704 | ublk_op = UBLK_IO_OP_WRITE_ZEROES; | 979 | ublk_op = UBLK_IO_OP_WRITE_ZEROES; |
| 705 | break; | 980 | break; |
| 706 | default: | 981 | default: |
| 982 | if (ublk_queue_is_zoned(ubq)) | ||
| 983 | return ublk_setup_iod_zoned(ubq, req); | ||
| 707 | return BLK_STS_IOERR; | 984 | return BLK_STS_IOERR; |
| 708 | } | 985 | } |
| 709 | 986 | ||
| @@ -756,7 +1033,8 @@ static inline void __ublk_complete_rq(struct request *req) · 46 unmodified lines | |||
| 756 | * | 1033 | * |
| 757 | * Both the two needn't unmap. | 1034 | * Both the two needn't unmap. |
| 758 | */ | 1035 | */ |
| 759 | if (req_op(req) != REQ_OP_READ && req_op(req) != REQ_OP_WRITE) | 1036 | if (req_op(req) != REQ_OP_READ && req_op(req) != REQ_OP_WRITE && |
| 1037 | req_op(req) != REQ_OP_DRV_IN) | ||
| 760 | goto exit; | 1038 | goto exit; |
| 761 | 1039 | ||
| 762 | /* for READ request, writing data in iod->addr to rq buffers */ | 1040 | /* for READ request, writing data in iod->addr to rq buffers */ |
| @@ -1120,6 +1398,9 @@ static void ublk_commit_completion(struct ublk_device *ub, · 357 unmodified lines | |||
| 1120 | /* find the io request and complete */ | 1398 | /* find the io request and complete */ |
| 1121 | req = blk_mq_tag_to_rq(ub->tag_set.tags[qid], tag); | 1399 | req = blk_mq_tag_to_rq(ub->tag_set.tags[qid], tag); |
| 1122 | 1400 | ||
| 1401 | if (req_op(req) == REQ_OP_ZONE_APPEND) | ||
| 1402 | req->__sector = ub_cmd->zone_append_lba; | ||
| 1403 | |||
| 1123 | if (req && likely(!blk_should_fake_timeout(req->q))) | 1404 | if (req && likely(!blk_should_fake_timeout(req->q))) |
| 1124 | ublk_put_req_ref(ubq, req); | 1405 | ublk_put_req_ref(ubq, req); |
| 1125 | } | 1406 | } |
| @@ -1468,8 +1749,11 @@ static int __ublk_ch_uring_cmd(struct io_uring_cmd *cmd, · 342 unmodified lines | |||
| 1468 | if (!ub_cmd->addr && (!ublk_need_get_data(ubq) || | 1749 | if (!ub_cmd->addr && (!ublk_need_get_data(ubq) || |
| 1469 | req_op(req) == REQ_OP_READ)) | 1750 | req_op(req) == REQ_OP_READ)) |
| 1470 | goto out; | 1751 | goto out; |
| 1471 | } else if (ub_cmd->addr) { | 1752 | } else if (req_op(req) != REQ_OP_ZONE_APPEND && ub_cmd->addr) { |
| 1472 | /* User copy requires addr to be unset */ | 1753 | /* |
| 1754 | * User copy requires addr to be unset when command is | ||
| 1755 | * not zone append | ||
| 1756 | */ | ||
| 1473 | ret = -EINVAL; | 1757 | ret = -EINVAL; |
| 1474 | goto out; | 1758 | goto out; |
| 1475 | } | 1759 | } |
| @@ -1546,11 +1830,14 @@ static inline bool ublk_check_ubuf_dir(const struct request *req, · 70 unmodified lines | |||
| 1546 | int ubuf_dir) | 1830 | int ubuf_dir) |
| 1547 | { | 1831 | { |
| 1548 | /* copy ubuf to request pages */ | 1832 | /* copy ubuf to request pages */ |
| 1549 | if (req_op(req) == REQ_OP_READ && ubuf_dir == ITER_SOURCE) | 1833 | if ((req_op(req) == REQ_OP_READ || req_op(req) == REQ_OP_DRV_IN) && |
| 1834 | ubuf_dir == ITER_SOURCE) | ||
| 1550 | return true; | 1835 | return true; |
| 1551 | 1836 | ||
| 1552 | /* copy request pages to ubuf */ | 1837 | /* copy request pages to ubuf */ |
| 1553 | if (req_op(req) == REQ_OP_WRITE && ubuf_dir == ITER_DEST) | 1838 | if ((req_op(req) == REQ_OP_WRITE || |
| 1839 | req_op(req) == REQ_OP_ZONE_APPEND) && | ||
| 1840 | ubuf_dir == ITER_DEST) | ||
| 1554 | return true; | 1841 | return true; |
| 1555 | 1842 | ||
| 1556 | return false; | 1843 | return false; |
| @@ -1889,17 +2176,24 @@ static int ublk_ctrl_start_dev(struct ublk_device *ub, struct io_uring_cmd *cmd) · 332 unmodified lines | |||
| 1889 | 2176 | ||
| 1890 | get_device(&ub->cdev_dev); | 2177 | get_device(&ub->cdev_dev); |
| 1891 | ub->dev_info.state = UBLK_S_DEV_LIVE; | 2178 | ub->dev_info.state = UBLK_S_DEV_LIVE; |
| 2179 | |||
| 2180 | if (ublk_dev_is_zoned(ub)) { | ||
| 2181 | ret = ublk_revalidate_disk_zones(ub); | ||
| 2182 | if (ret) | ||
| 2183 | goto out_put_cdev; | ||
| 2184 | } | ||
| 2185 | |||
| 1892 | ret = add_disk(disk); | 2186 | ret = add_disk(disk); |
| 2187 | if (ret) | ||
| 2188 | goto out_put_cdev; | ||
| 2189 | |||
| 2190 | set_bit(UB_STATE_USED, &ub->state); | ||
| 2191 | |||
| 2192 | out_put_cdev: | ||
| 1893 | if (ret) { | 2193 | if (ret) { |
| 1894 | /* | ||
| 1895 | * Has to drop the reference since ->free_disk won't be | ||
| 1896 | * called in case of add_disk failure. | ||
| 1897 | */ | ||
| 1898 | ub->dev_info.state = UBLK_S_DEV_DEAD; | 2194 | ub->dev_info.state = UBLK_S_DEV_DEAD; |
| 1899 | ublk_put_device(ub); | 2195 | ublk_put_device(ub); |
| 1900 | goto out_put_disk; | ||
| 1901 | } | 2196 | } |
| 1902 | set_bit(UB_STATE_USED, &ub->state); | ||
| 1903 | out_put_disk: | 2197 | out_put_disk: |
| 1904 | if (ret) | 2198 | if (ret) |
| 1905 | put_disk(disk); | 2199 | put_disk(disk); |
| @@ -2049,6 +2343,13 @@ static int ublk_ctrl_add_dev(struct io_uring_cmd *cmd) · 143 unmodified lines | |||
| 2049 | if (ublk_dev_is_user_copy(ub)) | 2343 | if (ublk_dev_is_user_copy(ub)) |
| 2050 | ub->dev_info.flags &= ~UBLK_F_NEED_GET_DATA; | 2344 | ub->dev_info.flags &= ~UBLK_F_NEED_GET_DATA; |
| 2051 | 2345 | ||
| 2346 | /* Zoned storage support requires user copy feature */ | ||
| 2347 | if (ublk_dev_is_zoned(ub) && | ||
| 2348 | (!IS_ENABLED(CONFIG_BLK_DEV_ZONED) || !ublk_dev_is_user_copy(ub))) { | ||
| 2349 | ret = -EINVAL; | ||
| 2350 | goto out_free_dev_number; | ||
| 2351 | } | ||
| 2352 | |||
| 2052 | /* We are not ready to support zero copy */ | 2353 | /* We are not ready to support zero copy */ |
| 2053 | ub->dev_info.flags &= ~UBLK_F_SUPPORT_ZERO_COPY; | 2354 | ub->dev_info.flags &= ~UBLK_F_SUPPORT_ZERO_COPY; |
| 2054 | 2355 | ||
| @@ -176,6 +176,12 @@ · 175 unmodified lines | |||
| 176 | /* Copy between request and user buffer by pread()/pwrite() */ | 176 | /* Copy between request and user buffer by pread()/pwrite() */ |
| 177 | #define UBLK_F_USER_COPY (1UL << 7) | 177 | #define UBLK_F_USER_COPY (1UL << 7) |
| 178 | 178 | ||
| 179 | /* | ||
| 180 | * User space sets this flag when setting up the device to request zoned storage support. Kernel may | ||
| 181 | * deny the request by returning an error. | ||
| 182 | */ | ||
| 183 | #define UBLK_F_ZONED (1ULL << 8) | ||
| 184 | |||
| 179 | /* device state */ | 185 | /* device state */ |
| 180 | #define UBLK_S_DEV_DEAD 0 | 186 | #define UBLK_S_DEV_DEAD 0 |
| 181 | #define UBLK_S_DEV_LIVE 1 | 187 | #define UBLK_S_DEV_LIVE 1 |
| @@ -232,9 +238,26 @@ struct ublksrv_ctrl_dev_info { · 50 unmodified lines | |||
| 232 | #define UBLK_IO_OP_READ 0 | 238 | #define UBLK_IO_OP_READ 0 |
| 233 | #define UBLK_IO_OP_WRITE 1 | 239 | #define UBLK_IO_OP_WRITE 1 |
| 234 | #define UBLK_IO_OP_FLUSH 2 | 240 | #define UBLK_IO_OP_FLUSH 2 |
| 235 | #define UBLK_IO_OP_DISCARD 3 | 241 | #define UBLK_IO_OP_DISCARD 3 |
| 236 | #define UBLK_IO_OP_WRITE_SAME 4 | 242 | #define UBLK_IO_OP_WRITE_SAME 4 |
| 237 | #define UBLK_IO_OP_WRITE_ZEROES 5 | 243 | #define UBLK_IO_OP_WRITE_ZEROES 5 |
| 244 | #define UBLK_IO_OP_ZONE_OPEN 10 | ||
| 245 | #define UBLK_IO_OP_ZONE_CLOSE 11 | ||
| 246 | #define UBLK_IO_OP_ZONE_FINISH 12 | ||
| 247 | #define UBLK_IO_OP_ZONE_APPEND 13 | ||
| 248 | #define UBLK_IO_OP_ZONE_RESET 15 | ||
| 249 | /* | ||
| 250 | * Construct a zone report. The report request is carried in `struct | ||
| 251 | * ublksrv_io_desc`. The `start_sector` field must be the first sector of a zone | ||
| 252 | * and shall indicate the first zone of the report. The `nr_zones` shall | ||
| 253 | * indicate how many zones should be reported at most. The report shall be | ||
| 254 | * delivered as a `struct blk_zone` array. To report fewer zones than requested, | ||
| 255 | * zero the last entry of the returned array. | ||
| 256 | * | ||
| 257 | * Related definitions(blk_zone, blk_zone_cond, blk_zone_type, ...) in | ||
| 258 | * include/uapi/linux/blkzoned.h are part of ublk UAPI. | ||
| 259 | */ | ||
| 260 | #define UBLK_IO_OP_REPORT_ZONES 18 | ||
| 238 | 261 | ||
| 239 | #define UBLK_IO_F_FAILFAST_DEV (1U << 8) | 262 | #define UBLK_IO_F_FAILFAST_DEV (1U << 8) |
| 240 | #define UBLK_IO_F_FAILFAST_TRANSPORT (1U << 9) | 263 | #define UBLK_IO_F_FAILFAST_TRANSPORT (1U << 9) |
| @@ -255,7 +278,10 @@ struct ublksrv_io_desc { · 14 unmodified lines | |||
| 255 | /* op: bit 0-7, flags: bit 8-31 */ | 278 | /* op: bit 0-7, flags: bit 8-31 */ |
| 256 | __u32 op_flags; | 279 | __u32 op_flags; |
| 257 | 280 | ||
| 258 | __u32 nr_sectors; | 281 | union { |
| 282 | __u32 nr_sectors; | ||
| 283 | __u32 nr_zones; /* for UBLK_IO_OP_REPORT_ZONES */ | ||
| 284 | }; | ||
| 259 | 285 | ||
| 260 | /* start sector for this io */ | 286 | /* start sector for this io */ |
| 261 | __u64 start_sector; | 287 | __u64 start_sector; |
| @@ -284,11 +310,21 @@ struct ublksrv_io_cmd { · 22 unmodified lines | |||
| 284 | /* io result, it is valid for COMMIT* command only */ | 310 | /* io result, it is valid for COMMIT* command only */ |
| 285 | __s32 result; | 311 | __s32 result; |
| 286 | 312 | ||
| 287 | /* | 313 | union { |
| 288 | * userspace buffer address in ublksrv daemon process, valid for | 314 | /* |
| 289 | * FETCH* command only | 315 | * userspace buffer address in ublksrv daemon process, valid for |
| 290 | */ | 316 | * FETCH* command only |
| 291 | __u64 addr; | 317 | * |
| 318 | * `addr` should not be used when UBLK_F_USER_COPY is enabled, | ||
| 319 | * because userspace handles data copy by pread()/pwrite() over | ||
| 320 | * /dev/ublkcN. But in case of UBLK_F_ZONED, this union is | ||
| 321 | * re-used to pass back the allocated LBA for | ||
| 322 | * UBLK_IO_OP_ZONE_APPEND which actually depends on | ||
| 323 | * UBLK_F_USER_COPY | ||
| 324 | */ | ||
| 325 | __u64 addr; | ||
| 326 | __u64 zone_append_lba; | ||
| 327 | }; | ||
| 292 | }; | 328 | }; |
| 293 | 329 | ||
| 294 | struct ublk_param_basic { | 330 | struct ublk_param_basic { |
| @@ -331,6 +367,13 @@ struct ublk_param_devt { · 36 unmodified lines | |||
| 331 | __u32 disk_minor; | 367 | __u32 disk_minor; |
| 332 | }; | 368 | }; |
| 333 | 369 | ||
| 370 | struct ublk_param_zoned { | ||
| 371 | __u32 max_open_zones; | ||
| 372 | __u32 max_active_zones; | ||
| 373 | __u32 max_zone_append_sectors; | ||
| 374 | __u8 reserved[20]; | ||
| 375 | }; | ||
| 376 | |||
| 334 | struct ublk_params { | 377 | struct ublk_params { |
| 335 | /* | 378 | /* |
| 336 | * Total length of parameters, userspace has to set 'len' for both | 379 | * Total length of parameters, userspace has to set 'len' for both |
| @@ -342,11 +385,13 @@ struct ublk_params { · 5 unmodified lines | |||
| 342 | #define UBLK_PARAM_TYPE_BASIC (1 << 0) | 385 | #define UBLK_PARAM_TYPE_BASIC (1 << 0) |
| 343 | #define UBLK_PARAM_TYPE_DISCARD (1 << 1) | 386 | #define UBLK_PARAM_TYPE_DISCARD (1 << 1) |
| 344 | #define UBLK_PARAM_TYPE_DEVT (1 << 2) | 387 | #define UBLK_PARAM_TYPE_DEVT (1 << 2) |
| 388 | #define UBLK_PARAM_TYPE_ZONED (1 << 3) | ||
| 345 | __u32 types; /* types of parameter included */ | 389 | __u32 types; /* types of parameter included */ |
| 346 | 390 | ||
| 347 | struct ublk_param_basic basic; | 391 | struct ublk_param_basic basic; |
| 348 | struct ublk_param_discard discard; | 392 | struct ublk_param_discard discard; |
| 349 | struct ublk_param_devt devt; | 393 | struct ublk_param_devt devt; |
| 394 | struct ublk_param_zoned zoned; | ||
| 350 | }; | 395 | }; |
| 351 | 396 | ||
| 352 | #endif | 397 | #endif |