diff options
Diffstat (limited to 'drivers/infiniband/core/uverbs_main.c')
-rw-r--r-- | drivers/infiniband/core/uverbs_main.c | 127 |
1 files changed, 98 insertions, 29 deletions
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 2df31f68ea09..189d99e76d9f 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c | |||
@@ -115,11 +115,16 @@ static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file, | |||
115 | [IB_USER_VERBS_CMD_CLOSE_XRCD] = ib_uverbs_close_xrcd, | 115 | [IB_USER_VERBS_CMD_CLOSE_XRCD] = ib_uverbs_close_xrcd, |
116 | [IB_USER_VERBS_CMD_CREATE_XSRQ] = ib_uverbs_create_xsrq, | 116 | [IB_USER_VERBS_CMD_CREATE_XSRQ] = ib_uverbs_create_xsrq, |
117 | [IB_USER_VERBS_CMD_OPEN_QP] = ib_uverbs_open_qp, | 117 | [IB_USER_VERBS_CMD_OPEN_QP] = ib_uverbs_open_qp, |
118 | }; | ||
119 | |||
118 | #ifdef CONFIG_INFINIBAND_EXPERIMENTAL_UVERBS_FLOW_STEERING | 120 | #ifdef CONFIG_INFINIBAND_EXPERIMENTAL_UVERBS_FLOW_STEERING |
119 | [IB_USER_VERBS_CMD_CREATE_FLOW] = ib_uverbs_create_flow, | 121 | static int (*uverbs_ex_cmd_table[])(struct ib_uverbs_file *file, |
120 | [IB_USER_VERBS_CMD_DESTROY_FLOW] = ib_uverbs_destroy_flow | 122 | struct ib_udata *ucore, |
121 | #endif /* CONFIG_INFINIBAND_EXPERIMENTAL_UVERBS_FLOW_STEERING */ | 123 | struct ib_udata *uhw) = { |
124 | [IB_USER_VERBS_EX_CMD_CREATE_FLOW] = ib_uverbs_ex_create_flow, | ||
125 | [IB_USER_VERBS_EX_CMD_DESTROY_FLOW] = ib_uverbs_ex_destroy_flow | ||
122 | }; | 126 | }; |
127 | #endif /* CONFIG_INFINIBAND_EXPERIMENTAL_UVERBS_FLOW_STEERING */ | ||
123 | 128 | ||
124 | static void ib_uverbs_add_one(struct ib_device *device); | 129 | static void ib_uverbs_add_one(struct ib_device *device); |
125 | static void ib_uverbs_remove_one(struct ib_device *device); | 130 | static void ib_uverbs_remove_one(struct ib_device *device); |
@@ -589,6 +594,7 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, | |||
589 | { | 594 | { |
590 | struct ib_uverbs_file *file = filp->private_data; | 595 | struct ib_uverbs_file *file = filp->private_data; |
591 | struct ib_uverbs_cmd_hdr hdr; | 596 | struct ib_uverbs_cmd_hdr hdr; |
597 | __u32 flags; | ||
592 | 598 | ||
593 | if (count < sizeof hdr) | 599 | if (count < sizeof hdr) |
594 | return -EINVAL; | 600 | return -EINVAL; |
@@ -596,45 +602,108 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, | |||
596 | if (copy_from_user(&hdr, buf, sizeof hdr)) | 602 | if (copy_from_user(&hdr, buf, sizeof hdr)) |
597 | return -EFAULT; | 603 | return -EFAULT; |
598 | 604 | ||
599 | if (hdr.command >= ARRAY_SIZE(uverbs_cmd_table) || | 605 | flags = (hdr.command & |
600 | !uverbs_cmd_table[hdr.command]) | 606 | IB_USER_VERBS_CMD_FLAGS_MASK) >> IB_USER_VERBS_CMD_FLAGS_SHIFT; |
601 | return -EINVAL; | ||
602 | 607 | ||
603 | if (!file->ucontext && | 608 | if (!flags) { |
604 | hdr.command != IB_USER_VERBS_CMD_GET_CONTEXT) | 609 | __u32 command; |
605 | return -EINVAL; | ||
606 | 610 | ||
607 | if (!(file->device->ib_dev->uverbs_cmd_mask & (1ull << hdr.command))) | 611 | if (hdr.command & ~(__u32)(IB_USER_VERBS_CMD_FLAGS_MASK | |
608 | return -ENOSYS; | 612 | IB_USER_VERBS_CMD_COMMAND_MASK)) |
613 | return -EINVAL; | ||
609 | 614 | ||
610 | #ifdef CONFIG_INFINIBAND_EXPERIMENTAL_UVERBS_FLOW_STEERING | 615 | command = hdr.command & IB_USER_VERBS_CMD_COMMAND_MASK; |
611 | if (hdr.command >= IB_USER_VERBS_CMD_THRESHOLD) { | ||
612 | struct ib_uverbs_cmd_hdr_ex hdr_ex; | ||
613 | 616 | ||
614 | if (copy_from_user(&hdr_ex, buf, sizeof(hdr_ex))) | 617 | if (command >= ARRAY_SIZE(uverbs_cmd_table) || |
615 | return -EFAULT; | 618 | !uverbs_cmd_table[command]) |
619 | return -EINVAL; | ||
616 | 620 | ||
617 | if (((hdr_ex.in_words + hdr_ex.provider_in_words) * 4) != count) | 621 | if (!file->ucontext && |
622 | command != IB_USER_VERBS_CMD_GET_CONTEXT) | ||
618 | return -EINVAL; | 623 | return -EINVAL; |
619 | 624 | ||
620 | return uverbs_cmd_table[hdr.command](file, | 625 | if (!(file->device->ib_dev->uverbs_cmd_mask & (1ull << command))) |
621 | buf + sizeof(hdr_ex), | 626 | return -ENOSYS; |
622 | (hdr_ex.in_words + | 627 | |
623 | hdr_ex.provider_in_words) * 4, | ||
624 | (hdr_ex.out_words + | ||
625 | hdr_ex.provider_out_words) * 4); | ||
626 | } else { | ||
627 | #endif /* CONFIG_INFINIBAND_EXPERIMENTAL_UVERBS_FLOW_STEERING */ | ||
628 | if (hdr.in_words * 4 != count) | 628 | if (hdr.in_words * 4 != count) |
629 | return -EINVAL; | 629 | return -EINVAL; |
630 | 630 | ||
631 | return uverbs_cmd_table[hdr.command](file, | 631 | return uverbs_cmd_table[command](file, |
632 | buf + sizeof(hdr), | 632 | buf + sizeof(hdr), |
633 | hdr.in_words * 4, | 633 | hdr.in_words * 4, |
634 | hdr.out_words * 4); | 634 | hdr.out_words * 4); |
635 | |||
635 | #ifdef CONFIG_INFINIBAND_EXPERIMENTAL_UVERBS_FLOW_STEERING | 636 | #ifdef CONFIG_INFINIBAND_EXPERIMENTAL_UVERBS_FLOW_STEERING |
637 | |||
638 | } else if (flags == IB_USER_VERBS_CMD_FLAG_EXTENDED) { | ||
639 | __u32 command; | ||
640 | |||
641 | struct ib_uverbs_ex_cmd_hdr ex_hdr; | ||
642 | struct ib_udata ucore; | ||
643 | struct ib_udata uhw; | ||
644 | int err; | ||
645 | size_t written_count = count; | ||
646 | |||
647 | if (hdr.command & ~(__u32)(IB_USER_VERBS_CMD_FLAGS_MASK | | ||
648 | IB_USER_VERBS_CMD_COMMAND_MASK)) | ||
649 | return -EINVAL; | ||
650 | |||
651 | command = hdr.command & IB_USER_VERBS_CMD_COMMAND_MASK; | ||
652 | |||
653 | if (command >= ARRAY_SIZE(uverbs_ex_cmd_table) || | ||
654 | !uverbs_ex_cmd_table[command]) | ||
655 | return -ENOSYS; | ||
656 | |||
657 | if (!file->ucontext) | ||
658 | return -EINVAL; | ||
659 | |||
660 | if (!(file->device->ib_dev->uverbs_ex_cmd_mask & (1ull << command))) | ||
661 | return -ENOSYS; | ||
662 | |||
663 | if (count < (sizeof(hdr) + sizeof(ex_hdr))) | ||
664 | return -EINVAL; | ||
665 | |||
666 | if (copy_from_user(&ex_hdr, buf + sizeof(hdr), sizeof(ex_hdr))) | ||
667 | return -EFAULT; | ||
668 | |||
669 | count -= sizeof(hdr) + sizeof(ex_hdr); | ||
670 | buf += sizeof(hdr) + sizeof(ex_hdr); | ||
671 | |||
672 | if ((hdr.in_words + ex_hdr.provider_in_words) * 8 != count) | ||
673 | return -EINVAL; | ||
674 | |||
675 | if (ex_hdr.response) { | ||
676 | if (!hdr.out_words && !ex_hdr.provider_out_words) | ||
677 | return -EINVAL; | ||
678 | } else { | ||
679 | if (hdr.out_words || ex_hdr.provider_out_words) | ||
680 | return -EINVAL; | ||
681 | } | ||
682 | |||
683 | INIT_UDATA(&ucore, | ||
684 | (hdr.in_words) ? buf : 0, | ||
685 | (unsigned long)ex_hdr.response, | ||
686 | hdr.in_words * 8, | ||
687 | hdr.out_words * 8); | ||
688 | |||
689 | INIT_UDATA(&uhw, | ||
690 | (ex_hdr.provider_in_words) ? buf + ucore.inlen : 0, | ||
691 | (ex_hdr.provider_out_words) ? (unsigned long)ex_hdr.response + ucore.outlen : 0, | ||
692 | ex_hdr.provider_in_words * 8, | ||
693 | ex_hdr.provider_out_words * 8); | ||
694 | |||
695 | err = uverbs_ex_cmd_table[command](file, | ||
696 | &ucore, | ||
697 | &uhw); | ||
698 | |||
699 | if (err) | ||
700 | return err; | ||
701 | |||
702 | return written_count; | ||
636 | } | 703 | } |
637 | #endif /* CONFIG_INFINIBAND_EXPERIMENTAL_UVERBS_FLOW_STEERING */ | 704 | #endif /* CONFIG_INFINIBAND_EXPERIMENTAL_UVERBS_FLOW_STEERING */ |
705 | |||
706 | return -ENOSYS; | ||
638 | } | 707 | } |
639 | 708 | ||
640 | static int ib_uverbs_mmap(struct file *filp, struct vm_area_struct *vma) | 709 | static int ib_uverbs_mmap(struct file *filp, struct vm_area_struct *vma) |