aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband
diff options
context:
space:
mode:
authorSean Hefty <sean.hefty@intel.com>2011-05-24 11:33:46 -0400
committerRoland Dreier <roland@purestorage.com>2011-10-13 12:21:24 -0400
commit53d0bd1e7ff2fc626321f337c609fb76ae5d12c9 (patch)
tree92f117b0356cebeb56c42cc76f0fb7ab84cc779a /drivers/infiniband
parentd3d72d909e783d048ee39046aa7b4fa798a4dda8 (diff)
RDMA/uverbs: Export XRC domains to user space
Allow user space to create XRC domains. Because XRCDs are expected to be shared among multiple processes, we use inodes to identify an XRCD. Based on patches by Jack Morgenstein <jackm@dev.mellanox.co.il> Signed-off-by: Sean Hefty <sean.hefty@intel.com> Signed-off-by: Roland Dreier <roland@purestorage.com>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r--drivers/infiniband/core/uverbs.h11
-rw-r--r--drivers/infiniband/core/uverbs_cmd.c318
-rw-r--r--drivers/infiniband/core/uverbs_main.c17
-rw-r--r--drivers/infiniband/core/verbs.c1
4 files changed, 347 insertions, 0 deletions
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h
index a078e5624d22..461e2f357c1e 100644
--- a/drivers/infiniband/core/uverbs.h
+++ b/drivers/infiniband/core/uverbs.h
@@ -76,6 +76,8 @@ struct ib_uverbs_device {
76 struct ib_device *ib_dev; 76 struct ib_device *ib_dev;
77 int devnum; 77 int devnum;
78 struct cdev cdev; 78 struct cdev cdev;
79 struct rb_root xrcd_tree;
80 struct mutex xrcd_tree_mutex;
79}; 81};
80 82
81struct ib_uverbs_event_file { 83struct ib_uverbs_event_file {
@@ -120,6 +122,11 @@ struct ib_uevent_object {
120 u32 events_reported; 122 u32 events_reported;
121}; 123};
122 124
125struct ib_uxrcd_object {
126 struct ib_uobject uobject;
127 atomic_t refcnt;
128};
129
123struct ib_uqp_object { 130struct ib_uqp_object {
124 struct ib_uevent_object uevent; 131 struct ib_uevent_object uevent;
125 struct list_head mcast_list; 132 struct list_head mcast_list;
@@ -142,6 +149,7 @@ extern struct idr ib_uverbs_ah_idr;
142extern struct idr ib_uverbs_cq_idr; 149extern struct idr ib_uverbs_cq_idr;
143extern struct idr ib_uverbs_qp_idr; 150extern struct idr ib_uverbs_qp_idr;
144extern struct idr ib_uverbs_srq_idr; 151extern struct idr ib_uverbs_srq_idr;
152extern struct idr ib_uverbs_xrcd_idr;
145 153
146void idr_remove_uobj(struct idr *idp, struct ib_uobject *uobj); 154void idr_remove_uobj(struct idr *idp, struct ib_uobject *uobj);
147 155
@@ -161,6 +169,7 @@ void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr);
161void ib_uverbs_srq_event_handler(struct ib_event *event, void *context_ptr); 169void ib_uverbs_srq_event_handler(struct ib_event *event, void *context_ptr);
162void ib_uverbs_event_handler(struct ib_event_handler *handler, 170void ib_uverbs_event_handler(struct ib_event_handler *handler,
163 struct ib_event *event); 171 struct ib_event *event);
172void ib_uverbs_dealloc_xrcd(struct ib_uverbs_device *dev, struct ib_xrcd *xrcd);
164 173
165#define IB_UVERBS_DECLARE_CMD(name) \ 174#define IB_UVERBS_DECLARE_CMD(name) \
166 ssize_t ib_uverbs_##name(struct ib_uverbs_file *file, \ 175 ssize_t ib_uverbs_##name(struct ib_uverbs_file *file, \
@@ -195,5 +204,7 @@ IB_UVERBS_DECLARE_CMD(create_srq);
195IB_UVERBS_DECLARE_CMD(modify_srq); 204IB_UVERBS_DECLARE_CMD(modify_srq);
196IB_UVERBS_DECLARE_CMD(query_srq); 205IB_UVERBS_DECLARE_CMD(query_srq);
197IB_UVERBS_DECLARE_CMD(destroy_srq); 206IB_UVERBS_DECLARE_CMD(destroy_srq);
207IB_UVERBS_DECLARE_CMD(open_xrcd);
208IB_UVERBS_DECLARE_CMD(close_xrcd);
198 209
199#endif /* UVERBS_H */ 210#endif /* UVERBS_H */
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index 48d21d09afe7..c8b2a843fa00 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -47,6 +47,7 @@ static struct lock_class_key cq_lock_key;
47static struct lock_class_key qp_lock_key; 47static struct lock_class_key qp_lock_key;
48static struct lock_class_key ah_lock_key; 48static struct lock_class_key ah_lock_key;
49static struct lock_class_key srq_lock_key; 49static struct lock_class_key srq_lock_key;
50static struct lock_class_key xrcd_lock_key;
50 51
51#define INIT_UDATA(udata, ibuf, obuf, ilen, olen) \ 52#define INIT_UDATA(udata, ibuf, obuf, ilen, olen) \
52 do { \ 53 do { \
@@ -255,6 +256,18 @@ static void put_srq_read(struct ib_srq *srq)
255 put_uobj_read(srq->uobject); 256 put_uobj_read(srq->uobject);
256} 257}
257 258
259static struct ib_xrcd *idr_read_xrcd(int xrcd_handle, struct ib_ucontext *context,
260 struct ib_uobject **uobj)
261{
262 *uobj = idr_read_uobj(&ib_uverbs_xrcd_idr, xrcd_handle, context, 0);
263 return *uobj ? (*uobj)->object : NULL;
264}
265
266static void put_xrcd_read(struct ib_uobject *uobj)
267{
268 put_uobj_read(uobj);
269}
270
258ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file, 271ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file,
259 const char __user *buf, 272 const char __user *buf,
260 int in_len, int out_len) 273 int in_len, int out_len)
@@ -298,6 +311,7 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file,
298 INIT_LIST_HEAD(&ucontext->qp_list); 311 INIT_LIST_HEAD(&ucontext->qp_list);
299 INIT_LIST_HEAD(&ucontext->srq_list); 312 INIT_LIST_HEAD(&ucontext->srq_list);
300 INIT_LIST_HEAD(&ucontext->ah_list); 313 INIT_LIST_HEAD(&ucontext->ah_list);
314 INIT_LIST_HEAD(&ucontext->xrcd_list);
301 ucontext->closing = 0; 315 ucontext->closing = 0;
302 316
303 resp.num_comp_vectors = file->device->num_comp_vectors; 317 resp.num_comp_vectors = file->device->num_comp_vectors;
@@ -579,6 +593,310 @@ ssize_t ib_uverbs_dealloc_pd(struct ib_uverbs_file *file,
579 return in_len; 593 return in_len;
580} 594}
581 595
596struct xrcd_table_entry {
597 struct rb_node node;
598 struct ib_xrcd *xrcd;
599 struct inode *inode;
600};
601
602static int xrcd_table_insert(struct ib_uverbs_device *dev,
603 struct inode *inode,
604 struct ib_xrcd *xrcd)
605{
606 struct xrcd_table_entry *entry, *scan;
607 struct rb_node **p = &dev->xrcd_tree.rb_node;
608 struct rb_node *parent = NULL;
609
610 entry = kmalloc(sizeof *entry, GFP_KERNEL);
611 if (!entry)
612 return -ENOMEM;
613
614 entry->xrcd = xrcd;
615 entry->inode = inode;
616
617 while (*p) {
618 parent = *p;
619 scan = rb_entry(parent, struct xrcd_table_entry, node);
620
621 if (inode < scan->inode) {
622 p = &(*p)->rb_left;
623 } else if (inode > scan->inode) {
624 p = &(*p)->rb_right;
625 } else {
626 kfree(entry);
627 return -EEXIST;
628 }
629 }
630
631 rb_link_node(&entry->node, parent, p);
632 rb_insert_color(&entry->node, &dev->xrcd_tree);
633 igrab(inode);
634 return 0;
635}
636
637static struct xrcd_table_entry *xrcd_table_search(struct ib_uverbs_device *dev,
638 struct inode *inode)
639{
640 struct xrcd_table_entry *entry;
641 struct rb_node *p = dev->xrcd_tree.rb_node;
642
643 while (p) {
644 entry = rb_entry(p, struct xrcd_table_entry, node);
645
646 if (inode < entry->inode)
647 p = p->rb_left;
648 else if (inode > entry->inode)
649 p = p->rb_right;
650 else
651 return entry;
652 }
653
654 return NULL;
655}
656
657static struct ib_xrcd *find_xrcd(struct ib_uverbs_device *dev, struct inode *inode)
658{
659 struct xrcd_table_entry *entry;
660
661 entry = xrcd_table_search(dev, inode);
662 if (!entry)
663 return NULL;
664
665 return entry->xrcd;
666}
667
668static void xrcd_table_delete(struct ib_uverbs_device *dev,
669 struct inode *inode)
670{
671 struct xrcd_table_entry *entry;
672
673 entry = xrcd_table_search(dev, inode);
674 if (entry) {
675 iput(inode);
676 rb_erase(&entry->node, &dev->xrcd_tree);
677 kfree(entry);
678 }
679}
680
681ssize_t ib_uverbs_open_xrcd(struct ib_uverbs_file *file,
682 const char __user *buf, int in_len,
683 int out_len)
684{
685 struct ib_uverbs_open_xrcd cmd;
686 struct ib_uverbs_open_xrcd_resp resp;
687 struct ib_udata udata;
688 struct ib_uxrcd_object *obj;
689 struct ib_xrcd *xrcd = NULL;
690 struct file *f = NULL;
691 struct inode *inode = NULL;
692 int ret = 0;
693 int new_xrcd = 0;
694
695 if (out_len < sizeof resp)
696 return -ENOSPC;
697
698 if (copy_from_user(&cmd, buf, sizeof cmd))
699 return -EFAULT;
700
701 INIT_UDATA(&udata, buf + sizeof cmd,
702 (unsigned long) cmd.response + sizeof resp,
703 in_len - sizeof cmd, out_len - sizeof resp);
704
705 mutex_lock(&file->device->xrcd_tree_mutex);
706
707 if (cmd.fd != -1) {
708 /* search for file descriptor */
709 f = fget(cmd.fd);
710 if (!f) {
711 ret = -EBADF;
712 goto err_tree_mutex_unlock;
713 }
714
715 inode = f->f_dentry->d_inode;
716 if (!inode) {
717 ret = -EBADF;
718 goto err_tree_mutex_unlock;
719 }
720
721 xrcd = find_xrcd(file->device, inode);
722 if (!xrcd && !(cmd.oflags & O_CREAT)) {
723 /* no file descriptor. Need CREATE flag */
724 ret = -EAGAIN;
725 goto err_tree_mutex_unlock;
726 }
727
728 if (xrcd && cmd.oflags & O_EXCL) {
729 ret = -EINVAL;
730 goto err_tree_mutex_unlock;
731 }
732 }
733
734 obj = kmalloc(sizeof *obj, GFP_KERNEL);
735 if (!obj) {
736 ret = -ENOMEM;
737 goto err_tree_mutex_unlock;
738 }
739
740 init_uobj(&obj->uobject, 0, file->ucontext, &xrcd_lock_key);
741
742 down_write(&obj->uobject.mutex);
743
744 if (!xrcd) {
745 xrcd = file->device->ib_dev->alloc_xrcd(file->device->ib_dev,
746 file->ucontext, &udata);
747 if (IS_ERR(xrcd)) {
748 ret = PTR_ERR(xrcd);
749 goto err;
750 }
751
752 xrcd->inode = inode;
753 xrcd->device = file->device->ib_dev;
754 atomic_set(&xrcd->usecnt, 0);
755 mutex_init(&xrcd->tgt_qp_mutex);
756 INIT_LIST_HEAD(&xrcd->tgt_qp_list);
757 new_xrcd = 1;
758 }
759
760 atomic_set(&obj->refcnt, 0);
761 obj->uobject.object = xrcd;
762 ret = idr_add_uobj(&ib_uverbs_xrcd_idr, &obj->uobject);
763 if (ret)
764 goto err_idr;
765
766 memset(&resp, 0, sizeof resp);
767 resp.xrcd_handle = obj->uobject.id;
768
769 if (inode) {
770 if (new_xrcd) {
771 /* create new inode/xrcd table entry */
772 ret = xrcd_table_insert(file->device, inode, xrcd);
773 if (ret)
774 goto err_insert_xrcd;
775 }
776 atomic_inc(&xrcd->usecnt);
777 }
778
779 if (copy_to_user((void __user *) (unsigned long) cmd.response,
780 &resp, sizeof resp)) {
781 ret = -EFAULT;
782 goto err_copy;
783 }
784
785 if (f)
786 fput(f);
787
788 mutex_lock(&file->mutex);
789 list_add_tail(&obj->uobject.list, &file->ucontext->xrcd_list);
790 mutex_unlock(&file->mutex);
791
792 obj->uobject.live = 1;
793 up_write(&obj->uobject.mutex);
794
795 mutex_unlock(&file->device->xrcd_tree_mutex);
796 return in_len;
797
798err_copy:
799 if (inode) {
800 if (new_xrcd)
801 xrcd_table_delete(file->device, inode);
802 atomic_dec(&xrcd->usecnt);
803 }
804
805err_insert_xrcd:
806 idr_remove_uobj(&ib_uverbs_xrcd_idr, &obj->uobject);
807
808err_idr:
809 ib_dealloc_xrcd(xrcd);
810
811err:
812 put_uobj_write(&obj->uobject);
813
814err_tree_mutex_unlock:
815 if (f)
816 fput(f);
817
818 mutex_unlock(&file->device->xrcd_tree_mutex);
819
820 return ret;
821}
822
823ssize_t ib_uverbs_close_xrcd(struct ib_uverbs_file *file,
824 const char __user *buf, int in_len,
825 int out_len)
826{
827 struct ib_uverbs_close_xrcd cmd;
828 struct ib_uobject *uobj;
829 struct ib_xrcd *xrcd = NULL;
830 struct inode *inode = NULL;
831 struct ib_uxrcd_object *obj;
832 int live;
833 int ret = 0;
834
835 if (copy_from_user(&cmd, buf, sizeof cmd))
836 return -EFAULT;
837
838 mutex_lock(&file->device->xrcd_tree_mutex);
839 uobj = idr_write_uobj(&ib_uverbs_xrcd_idr, cmd.xrcd_handle, file->ucontext);
840 if (!uobj) {
841 ret = -EINVAL;
842 goto out;
843 }
844
845 xrcd = uobj->object;
846 inode = xrcd->inode;
847 obj = container_of(uobj, struct ib_uxrcd_object, uobject);
848 if (atomic_read(&obj->refcnt)) {
849 put_uobj_write(uobj);
850 ret = -EBUSY;
851 goto out;
852 }
853
854 if (!inode || atomic_dec_and_test(&xrcd->usecnt)) {
855 ret = ib_dealloc_xrcd(uobj->object);
856 if (!ret)
857 uobj->live = 0;
858 }
859
860 live = uobj->live;
861 if (inode && ret)
862 atomic_inc(&xrcd->usecnt);
863
864 put_uobj_write(uobj);
865
866 if (ret)
867 goto out;
868
869 if (inode && !live)
870 xrcd_table_delete(file->device, inode);
871
872 idr_remove_uobj(&ib_uverbs_xrcd_idr, uobj);
873 mutex_lock(&file->mutex);
874 list_del(&uobj->list);
875 mutex_unlock(&file->mutex);
876
877 put_uobj(uobj);
878 ret = in_len;
879
880out:
881 mutex_unlock(&file->device->xrcd_tree_mutex);
882 return ret;
883}
884
885void ib_uverbs_dealloc_xrcd(struct ib_uverbs_device *dev,
886 struct ib_xrcd *xrcd)
887{
888 struct inode *inode;
889
890 inode = xrcd->inode;
891 if (inode && !atomic_dec_and_test(&xrcd->usecnt))
892 return;
893
894 ib_dealloc_xrcd(xrcd);
895
896 if (inode)
897 xrcd_table_delete(dev, inode);
898}
899
582ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file, 900ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
583 const char __user *buf, int in_len, 901 const char __user *buf, int in_len,
584 int out_len) 902 int out_len)
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index 56898b6578a4..bb9dcea8fede 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -72,6 +72,7 @@ DEFINE_IDR(ib_uverbs_ah_idr);
72DEFINE_IDR(ib_uverbs_cq_idr); 72DEFINE_IDR(ib_uverbs_cq_idr);
73DEFINE_IDR(ib_uverbs_qp_idr); 73DEFINE_IDR(ib_uverbs_qp_idr);
74DEFINE_IDR(ib_uverbs_srq_idr); 74DEFINE_IDR(ib_uverbs_srq_idr);
75DEFINE_IDR(ib_uverbs_xrcd_idr);
75 76
76static DEFINE_SPINLOCK(map_lock); 77static DEFINE_SPINLOCK(map_lock);
77static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES); 78static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES);
@@ -107,6 +108,8 @@ static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file,
107 [IB_USER_VERBS_CMD_MODIFY_SRQ] = ib_uverbs_modify_srq, 108 [IB_USER_VERBS_CMD_MODIFY_SRQ] = ib_uverbs_modify_srq,
108 [IB_USER_VERBS_CMD_QUERY_SRQ] = ib_uverbs_query_srq, 109 [IB_USER_VERBS_CMD_QUERY_SRQ] = ib_uverbs_query_srq,
109 [IB_USER_VERBS_CMD_DESTROY_SRQ] = ib_uverbs_destroy_srq, 110 [IB_USER_VERBS_CMD_DESTROY_SRQ] = ib_uverbs_destroy_srq,
111 [IB_USER_VERBS_CMD_OPEN_XRCD] = ib_uverbs_open_xrcd,
112 [IB_USER_VERBS_CMD_CLOSE_XRCD] = ib_uverbs_close_xrcd,
110}; 113};
111 114
112static void ib_uverbs_add_one(struct ib_device *device); 115static void ib_uverbs_add_one(struct ib_device *device);
@@ -241,6 +244,18 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
241 kfree(uobj); 244 kfree(uobj);
242 } 245 }
243 246
247 mutex_lock(&file->device->xrcd_tree_mutex);
248 list_for_each_entry_safe(uobj, tmp, &context->xrcd_list, list) {
249 struct ib_xrcd *xrcd = uobj->object;
250 struct ib_uxrcd_object *uxrcd =
251 container_of(uobj, struct ib_uxrcd_object, uobject);
252
253 idr_remove_uobj(&ib_uverbs_xrcd_idr, uobj);
254 ib_uverbs_dealloc_xrcd(file->device, xrcd);
255 kfree(uxrcd);
256 }
257 mutex_unlock(&file->device->xrcd_tree_mutex);
258
244 list_for_each_entry_safe(uobj, tmp, &context->pd_list, list) { 259 list_for_each_entry_safe(uobj, tmp, &context->pd_list, list) {
245 struct ib_pd *pd = uobj->object; 260 struct ib_pd *pd = uobj->object;
246 261
@@ -741,6 +756,8 @@ static void ib_uverbs_add_one(struct ib_device *device)
741 756
742 kref_init(&uverbs_dev->ref); 757 kref_init(&uverbs_dev->ref);
743 init_completion(&uverbs_dev->comp); 758 init_completion(&uverbs_dev->comp);
759 uverbs_dev->xrcd_tree = RB_ROOT;
760 mutex_init(&uverbs_dev->xrcd_tree_mutex);
744 761
745 spin_lock(&map_lock); 762 spin_lock(&map_lock);
746 devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES); 763 devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES);
diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c
index 8c6da5bda4c6..a6d95e635699 100644
--- a/drivers/infiniband/core/verbs.c
+++ b/drivers/infiniband/core/verbs.c
@@ -1096,6 +1096,7 @@ struct ib_xrcd *ib_alloc_xrcd(struct ib_device *device)
1096 xrcd = device->alloc_xrcd(device, NULL, NULL); 1096 xrcd = device->alloc_xrcd(device, NULL, NULL);
1097 if (!IS_ERR(xrcd)) { 1097 if (!IS_ERR(xrcd)) {
1098 xrcd->device = device; 1098 xrcd->device = device;
1099 xrcd->inode = NULL;
1099 atomic_set(&xrcd->usecnt, 0); 1100 atomic_set(&xrcd->usecnt, 0);
1100 mutex_init(&xrcd->tgt_qp_mutex); 1101 mutex_init(&xrcd->tgt_qp_mutex);
1101 INIT_LIST_HEAD(&xrcd->tgt_qp_list); 1102 INIT_LIST_HEAD(&xrcd->tgt_qp_list);