It is not possible to get 64-bit results from the passthru commands, what prevents from getting for the Capabilities (CAP) property value. As a result, it is not possible to implement IOL's NVMe Conformance test 4.3 Case 1 for Fabrics targets [1] (page 123). This issue has been already discussed [2], but without a solution. This patch solves the problem by adding new ioctls with a new passthru structure, including 64-bit results. The older ioctls stay unchanged. [1] https://www.iol.unh.edu/sites/default/files/testsuites/nvme/UNH-IOL_NVMe_Conformance_Test_Suite_v11.0.pdf [2] http://lists.infradead.org/pipermail/linux-nvme/2018-June/018791.html
Unified · Split
| @@ -850,7 +850,7 @@ out: · 849 unmodified lines | ||
| 850 | 850 | static int nvme_submit_user_cmd(struct request_queue *q, |
| 851 | 851 | struct nvme_command *cmd, void __user *ubuffer, |
| 852 | 852 | unsigned bufflen, void __user *meta_buffer, unsigned meta_len, |
| 853 | − u32 meta_seed, u32 *result, unsigned timeout) | |
| 853 | + u32 meta_seed, u64 *result, unsigned timeout) | |
| 854 | 854 | { |
| 855 | 855 | bool write = nvme_is_write(cmd); |
| 856 | 856 | struct nvme_ns *ns = q->queuedata; |
| @@ -891,7 +891,7 @@ static int nvme_submit_user_cmd(struct request_queue *q, · 34 unmodified lines | ||
| 891 | 891 | else |
| 892 | 892 | ret = nvme_req(req)->status; |
| 893 | 893 | if (result) |
| 894 | − *result = le32_to_cpu(nvme_req(req)->result.u32); | |
| 894 | + *result = le64_to_cpu(nvme_req(req)->result.u64); | |
| 895 | 895 | if (meta && !ret && !write) { |
| 896 | 896 | if (copy_to_user(meta_buffer, meta, meta_len)) |
| 897 | 897 | ret = -EFAULT; |
| @@ -1338,6 +1338,54 @@ static int nvme_user_cmd(struct nvme_ctrl *ctrl, struct nvme_ns *ns, · 440 unmodified lines | ||
| 1338 | 1338 | struct nvme_command c; |
| 1339 | 1339 | unsigned timeout = 0; |
| 1340 | 1340 | u32 effects; |
| 1341 | + u64 result; | |
| 1342 | + int status; | |
| 1343 | + | |
| 1344 | + if (!capable(CAP_SYS_ADMIN)) | |
| 1345 | + return -EACCES; | |
| 1346 | + if (copy_from_user(&cmd, ucmd, sizeof(cmd))) | |
| 1347 | + return -EFAULT; | |
| 1348 | + if (cmd.flags) | |
| 1349 | + return -EINVAL; | |
| 1350 | + | |
| 1351 | + memset(&c, 0, sizeof(c)); | |
| 1352 | + c.common.opcode = cmd.opcode; | |
| 1353 | + c.common.flags = cmd.flags; | |
| 1354 | + c.common.nsid = cpu_to_le32(cmd.nsid); | |
| 1355 | + c.common.cdw2[0] = cpu_to_le32(cmd.cdw2); | |
| 1356 | + c.common.cdw2[1] = cpu_to_le32(cmd.cdw3); | |
| 1357 | + c.common.cdw10 = cpu_to_le32(cmd.cdw10); | |
| 1358 | + c.common.cdw11 = cpu_to_le32(cmd.cdw11); | |
| 1359 | + c.common.cdw12 = cpu_to_le32(cmd.cdw12); | |
| 1360 | + c.common.cdw13 = cpu_to_le32(cmd.cdw13); | |
| 1361 | + c.common.cdw14 = cpu_to_le32(cmd.cdw14); | |
| 1362 | + c.common.cdw15 = cpu_to_le32(cmd.cdw15); | |
| 1363 | + | |
| 1364 | + if (cmd.timeout_ms) | |
| 1365 | + timeout = msecs_to_jiffies(cmd.timeout_ms); | |
| 1366 | + | |
| 1367 | + effects = nvme_passthru_start(ctrl, ns, cmd.opcode); | |
| 1368 | + status = nvme_submit_user_cmd(ns ? ns->queue : ctrl->admin_q, &c, | |
| 1369 | + (void __user *)(uintptr_t)cmd.addr, cmd.data_len, | |
| 1370 | + (void __user *)(uintptr_t)cmd.metadata, | |
| 1371 | + cmd.metadata_len, 0, &result, timeout); | |
| 1372 | + nvme_passthru_end(ctrl, effects); | |
| 1373 | + | |
| 1374 | + if (status >= 0) { | |
| 1375 | + if (put_user(result, &ucmd->result)) | |
| 1376 | + return -EFAULT; | |
| 1377 | + } | |
| 1378 | + | |
| 1379 | + return status; | |
| 1380 | +} | |
| 1381 | + | |
| 1382 | +static int nvme_user_cmd64(struct nvme_ctrl *ctrl, struct nvme_ns *ns, | |
| 1383 | + struct nvme_passthru_cmd64 __user *ucmd) | |
| 1384 | +{ | |
| 1385 | + struct nvme_passthru_cmd64 cmd; | |
| 1386 | + struct nvme_command c; | |
| 1387 | + unsigned timeout = 0; | |
| 1388 | + u32 effects; | |
| 1341 | 1389 | int status; |
| 1342 | 1390 | |
| 1343 | 1391 | if (!capable(CAP_SYS_ADMIN)) |
| @@ -1408,6 +1456,41 @@ static void nvme_put_ns_from_disk(struct nvme_ns_head *head, int idx) · 64 unmodified lines | ||
| 1408 | 1456 | srcu_read_unlock(&head->srcu, idx); |
| 1409 | 1457 | } |
| 1410 | 1458 | |
| 1459 | +static bool is_ctrl_ioctl(unsigned int cmd) | |
| 1460 | +{ | |
| 1461 | + if (cmd == NVME_IOCTL_ADMIN_CMD || cmd == NVME_IOCTL_ADMIN64_CMD) | |
| 1462 | + return true; | |
| 1463 | + if (is_sed_ioctl(cmd)) | |
| 1464 | + return true; | |
| 1465 | + return false; | |
| 1466 | +} | |
| 1467 | + | |
| 1468 | +static int nvme_handle_ctrl_ioctl(struct nvme_ns *ns, unsigned int cmd, | |
| 1469 | + void __user *argp, | |
| 1470 | + struct nvme_ns_head *head, | |
| 1471 | + int srcu_idx) | |
| 1472 | +{ | |
| 1473 | + struct nvme_ctrl *ctrl = ns->ctrl; | |
| 1474 | + int ret; | |
| 1475 | + | |
| 1476 | + nvme_get_ctrl(ns->ctrl); | |
| 1477 | + nvme_put_ns_from_disk(head, srcu_idx); | |
| 1478 | + | |
| 1479 | + switch (cmd) { | |
| 1480 | + case NVME_IOCTL_ADMIN_CMD: | |
| 1481 | + ret = nvme_user_cmd(ctrl, NULL, argp); | |
| 1482 | + break; | |
| 1483 | + case NVME_IOCTL_ADMIN64_CMD: | |
| 1484 | + ret = nvme_user_cmd64(ctrl, NULL, argp); | |
| 1485 | + break; | |
| 1486 | + default: | |
| 1487 | + ret = sed_ioctl(ctrl->opal_dev, cmd, argp); | |
| 1488 | + break; | |
| 1489 | + } | |
| 1490 | + nvme_put_ctrl(ctrl); | |
| 1491 | + return ret; | |
| 1492 | +} | |
| 1493 | + | |
| 1411 | 1494 | static int nvme_ioctl(struct block_device *bdev, fmode_t mode, |
| 1412 | 1495 | unsigned int cmd, unsigned long arg) |
| 1413 | 1496 | { |
| @@ -1425,20 +1508,8 @@ static int nvme_ioctl(struct block_device *bdev, fmode_t mode, · 11 unmodified lines | ||
| 1425 | 1508 | * seperately and drop the ns SRCU reference early. This avoids a |
| 1426 | 1509 | * deadlock when deleting namespaces using the passthrough interface. |
| 1427 | 1510 | */ |
| 1428 | − if (cmd == NVME_IOCTL_ADMIN_CMD || is_sed_ioctl(cmd)) { | |
| 1429 | − struct nvme_ctrl *ctrl = ns->ctrl; | |
| 1430 | − | |
| 1431 | − nvme_get_ctrl(ns->ctrl); | |
| 1432 | − nvme_put_ns_from_disk(head, srcu_idx); | |
| 1433 | − | |
| 1434 | − if (cmd == NVME_IOCTL_ADMIN_CMD) | |
| 1435 | − ret = nvme_user_cmd(ctrl, NULL, argp); | |
| 1436 | − else | |
| 1437 | − ret = sed_ioctl(ctrl->opal_dev, cmd, argp); | |
| 1438 | − | |
| 1439 | − nvme_put_ctrl(ctrl); | |
| 1440 | − return ret; | |
| 1441 | − } | |
| 1511 | + if (is_ctrl_ioctl(cmd)) | |
| 1512 | + return nvme_handle_ctrl_ioctl(ns, cmd, argp, head, srcu_idx); | |
| 1442 | 1513 | |
| 1443 | 1514 | switch (cmd) { |
| 1444 | 1515 | case NVME_IOCTL_ID: |
| @@ -1451,6 +1522,9 @@ static int nvme_ioctl(struct block_device *bdev, fmode_t mode, · 6 unmodified lines | ||
| 1451 | 1522 | case NVME_IOCTL_SUBMIT_IO: |
| 1452 | 1523 | ret = nvme_submit_io(ns, argp); |
| 1453 | 1524 | break; |
| 1525 | + case NVME_IOCTL_IO64_CMD: | |
| 1526 | + ret = nvme_user_cmd64(ns->ctrl, ns, argp); | |
| 1527 | + break; | |
| 1454 | 1528 | default: |
| 1455 | 1529 | if (ns->ndev) |
| 1456 | 1530 | ret = nvme_nvm_ioctl(ns, cmd, arg); |
| @@ -2852,6 +2926,8 @@ static long nvme_dev_ioctl(struct file *file, unsigned int cmd, · 1395 unmodified lines | ||
| 2852 | 2926 | switch (cmd) { |
| 2853 | 2927 | case NVME_IOCTL_ADMIN_CMD: |
| 2854 | 2928 | return nvme_user_cmd(ctrl, NULL, argp); |
| 2929 | + case NVME_IOCTL_ADMIN64_CMD: | |
| 2930 | + return nvme_user_cmd64(ctrl, NULL, argp); | |
| 2855 | 2931 | case NVME_IOCTL_IO_CMD: |
| 2856 | 2932 | return nvme_dev_user_cmd(ctrl, argp); |
| 2857 | 2933 | case NVME_IOCTL_RESET: |
| @@ -45,6 +45,27 @@ struct nvme_passthru_cmd { · 44 unmodified lines | ||
| 45 | 45 | __u32 result; |
| 46 | 46 | }; |
| 47 | 47 | |
| 48 | +struct nvme_passthru_cmd64 { | |
| 49 | + __u8 opcode; | |
| 50 | + __u8 flags; | |
| 51 | + __u16 rsvd1; | |
| 52 | + __u32 nsid; | |
| 53 | + __u32 cdw2; | |
| 54 | + __u32 cdw3; | |
| 55 | + __u64 metadata; | |
| 56 | + __u64 addr; | |
| 57 | + __u32 metadata_len; | |
| 58 | + __u32 data_len; | |
| 59 | + __u32 cdw10; | |
| 60 | + __u32 cdw11; | |
| 61 | + __u32 cdw12; | |
| 62 | + __u32 cdw13; | |
| 63 | + __u32 cdw14; | |
| 64 | + __u32 cdw15; | |
| 65 | + __u32 timeout_ms; | |
| 66 | + __u64 result; | |
| 67 | +}; | |
| 68 | + | |
| 48 | 69 | #define nvme_admin_cmd nvme_passthru_cmd |
| 49 | 70 | |
| 50 | 71 | #define NVME_IOCTL_ID _IO('N', 0x40) |
| @@ -54,5 +75,7 @@ struct nvme_passthru_cmd { · 3 unmodified lines | ||
| 54 | 75 | #define NVME_IOCTL_RESET _IO('N', 0x44) |
| 55 | 76 | #define NVME_IOCTL_SUBSYS_RESET _IO('N', 0x45) |
| 56 | 77 | #define NVME_IOCTL_RESCAN _IO('N', 0x46) |
| 78 | +#define NVME_IOCTL_ADMIN64_CMD _IOWR('N', 0x47, struct nvme_passthru_cmd64) | |
| 79 | +#define NVME_IOCTL_IO64_CMD _IOWR('N', 0x48, struct nvme_passthru_cmd64) | |
| 57 | 80 | |
| 58 | 81 | #endif /* _UAPI_LINUX_NVME_IOCTL_H */ |