Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] IB: userspace SRQ support

Add SRQ support to userspace verbs module. This adds several commands
and associated structures, but it's OK to do this without bumping the
ABI version because the commands are added at the end of the list so
they don't change the existing numbering. There are two cases to
worry about:

1. New kernel, old userspace. This is OK because old userspace simply
won't try to use the new SRQ commands. None of the old commands are
changed.

2. Old kernel, new userspace. This works perfectly as long as
userspace doesn't try to use SRQ commands. If userspace tries to
use SRQ commands, it will get EINVAL, which is perfectly
reasonable: the kernel doesn't support SRQs, so we couldn't do any
better.

Signed-off-by: Roland Dreier <rolandd@cisco.com>

authored by

Roland Dreier and committed by
Roland Dreier
f520ba5a d41fcc67

+238 -4
+5
drivers/infiniband/core/uverbs.h
··· 99 99 extern struct idr ib_uverbs_ah_idr; 100 100 extern struct idr ib_uverbs_cq_idr; 101 101 extern struct idr ib_uverbs_qp_idr; 102 + extern struct idr ib_uverbs_srq_idr; 102 103 103 104 void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context); 104 105 void ib_uverbs_cq_event_handler(struct ib_event *event, void *context_ptr); 105 106 void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr); 107 + void ib_uverbs_srq_event_handler(struct ib_event *event, void *context_ptr); 106 108 107 109 int ib_umem_get(struct ib_device *dev, struct ib_umem *mem, 108 110 void *addr, size_t size, int write); ··· 133 131 IB_UVERBS_DECLARE_CMD(destroy_qp); 134 132 IB_UVERBS_DECLARE_CMD(attach_mcast); 135 133 IB_UVERBS_DECLARE_CMD(detach_mcast); 134 + IB_UVERBS_DECLARE_CMD(create_srq); 135 + IB_UVERBS_DECLARE_CMD(modify_srq); 136 + IB_UVERBS_DECLARE_CMD(destroy_srq); 136 137 137 138 #endif /* UVERBS_H */
+180 -2
drivers/infiniband/core/uverbs_cmd.c
··· 724 724 struct ib_uobject *uobj; 725 725 struct ib_pd *pd; 726 726 struct ib_cq *scq, *rcq; 727 + struct ib_srq *srq; 727 728 struct ib_qp *qp; 728 729 struct ib_qp_init_attr attr; 729 730 int ret; ··· 748 747 pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle); 749 748 scq = idr_find(&ib_uverbs_cq_idr, cmd.send_cq_handle); 750 749 rcq = idr_find(&ib_uverbs_cq_idr, cmd.recv_cq_handle); 750 + srq = cmd.is_srq ? idr_find(&ib_uverbs_srq_idr, cmd.srq_handle) : NULL; 751 751 752 752 if (!pd || pd->uobject->context != file->ucontext || 753 753 !scq || scq->uobject->context != file->ucontext || 754 - !rcq || rcq->uobject->context != file->ucontext) { 754 + !rcq || rcq->uobject->context != file->ucontext || 755 + (cmd.is_srq && (!srq || srq->uobject->context != file->ucontext))) { 755 756 ret = -EINVAL; 756 757 goto err_up; 757 758 } ··· 762 759 attr.qp_context = file; 763 760 attr.send_cq = scq; 764 761 attr.recv_cq = rcq; 765 - attr.srq = NULL; 762 + attr.srq = srq; 766 763 attr.sq_sig_type = cmd.sq_sig_all ? IB_SIGNAL_ALL_WR : IB_SIGNAL_REQ_WR; 767 764 attr.qp_type = cmd.qp_type; 768 765 ··· 1003 1000 if (qp && qp->uobject->context == file->ucontext) 1004 1001 ret = ib_detach_mcast(qp, (union ib_gid *) cmd.gid, cmd.mlid); 1005 1002 1003 + up(&ib_uverbs_idr_mutex); 1004 + 1005 + return ret ? ret : in_len; 1006 + } 1007 + 1008 + ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file, 1009 + const char __user *buf, int in_len, 1010 + int out_len) 1011 + { 1012 + struct ib_uverbs_create_srq cmd; 1013 + struct ib_uverbs_create_srq_resp resp; 1014 + struct ib_udata udata; 1015 + struct ib_uobject *uobj; 1016 + struct ib_pd *pd; 1017 + struct ib_srq *srq; 1018 + struct ib_srq_init_attr attr; 1019 + int ret; 1020 + 1021 + if (out_len < sizeof resp) 1022 + return -ENOSPC; 1023 + 1024 + if (copy_from_user(&cmd, buf, sizeof cmd)) 1025 + return -EFAULT; 1026 + 1027 + INIT_UDATA(&udata, buf + sizeof cmd, 1028 + (unsigned long) cmd.response + sizeof resp, 1029 + in_len - sizeof cmd, out_len - sizeof resp); 1030 + 1031 + uobj = kmalloc(sizeof *uobj, GFP_KERNEL); 1032 + if (!uobj) 1033 + return -ENOMEM; 1034 + 1035 + down(&ib_uverbs_idr_mutex); 1036 + 1037 + pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle); 1038 + 1039 + if (!pd || pd->uobject->context != file->ucontext) { 1040 + ret = -EINVAL; 1041 + goto err_up; 1042 + } 1043 + 1044 + attr.event_handler = ib_uverbs_srq_event_handler; 1045 + attr.srq_context = file; 1046 + attr.attr.max_wr = cmd.max_wr; 1047 + attr.attr.max_sge = cmd.max_sge; 1048 + attr.attr.srq_limit = cmd.srq_limit; 1049 + 1050 + uobj->user_handle = cmd.user_handle; 1051 + uobj->context = file->ucontext; 1052 + 1053 + srq = pd->device->create_srq(pd, &attr, &udata); 1054 + if (IS_ERR(srq)) { 1055 + ret = PTR_ERR(srq); 1056 + goto err_up; 1057 + } 1058 + 1059 + srq->device = pd->device; 1060 + srq->pd = pd; 1061 + srq->uobject = uobj; 1062 + srq->event_handler = attr.event_handler; 1063 + srq->srq_context = attr.srq_context; 1064 + atomic_inc(&pd->usecnt); 1065 + atomic_set(&srq->usecnt, 0); 1066 + 1067 + memset(&resp, 0, sizeof resp); 1068 + 1069 + retry: 1070 + if (!idr_pre_get(&ib_uverbs_srq_idr, GFP_KERNEL)) { 1071 + ret = -ENOMEM; 1072 + goto err_destroy; 1073 + } 1074 + 1075 + ret = idr_get_new(&ib_uverbs_srq_idr, srq, &uobj->id); 1076 + 1077 + if (ret == -EAGAIN) 1078 + goto retry; 1079 + if (ret) 1080 + goto err_destroy; 1081 + 1082 + resp.srq_handle = uobj->id; 1083 + 1084 + spin_lock_irq(&file->ucontext->lock); 1085 + list_add_tail(&uobj->list, &file->ucontext->srq_list); 1086 + spin_unlock_irq(&file->ucontext->lock); 1087 + 1088 + if (copy_to_user((void __user *) (unsigned long) cmd.response, 1089 + &resp, sizeof resp)) { 1090 + ret = -EFAULT; 1091 + goto err_list; 1092 + } 1093 + 1094 + up(&ib_uverbs_idr_mutex); 1095 + 1096 + return in_len; 1097 + 1098 + err_list: 1099 + spin_lock_irq(&file->ucontext->lock); 1100 + list_del(&uobj->list); 1101 + spin_unlock_irq(&file->ucontext->lock); 1102 + 1103 + err_destroy: 1104 + ib_destroy_srq(srq); 1105 + 1106 + err_up: 1107 + up(&ib_uverbs_idr_mutex); 1108 + 1109 + kfree(uobj); 1110 + return ret; 1111 + } 1112 + 1113 + ssize_t ib_uverbs_modify_srq(struct ib_uverbs_file *file, 1114 + const char __user *buf, int in_len, 1115 + int out_len) 1116 + { 1117 + struct ib_uverbs_modify_srq cmd; 1118 + struct ib_srq *srq; 1119 + struct ib_srq_attr attr; 1120 + int ret; 1121 + 1122 + if (copy_from_user(&cmd, buf, sizeof cmd)) 1123 + return -EFAULT; 1124 + 1125 + down(&ib_uverbs_idr_mutex); 1126 + 1127 + srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle); 1128 + if (!srq || srq->uobject->context != file->ucontext) { 1129 + ret = -EINVAL; 1130 + goto out; 1131 + } 1132 + 1133 + attr.max_wr = cmd.max_wr; 1134 + attr.max_sge = cmd.max_sge; 1135 + attr.srq_limit = cmd.srq_limit; 1136 + 1137 + ret = ib_modify_srq(srq, &attr, cmd.attr_mask); 1138 + 1139 + out: 1140 + up(&ib_uverbs_idr_mutex); 1141 + 1142 + return ret ? ret : in_len; 1143 + } 1144 + 1145 + ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file, 1146 + const char __user *buf, int in_len, 1147 + int out_len) 1148 + { 1149 + struct ib_uverbs_destroy_srq cmd; 1150 + struct ib_srq *srq; 1151 + struct ib_uobject *uobj; 1152 + int ret = -EINVAL; 1153 + 1154 + if (copy_from_user(&cmd, buf, sizeof cmd)) 1155 + return -EFAULT; 1156 + 1157 + down(&ib_uverbs_idr_mutex); 1158 + 1159 + srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle); 1160 + if (!srq || srq->uobject->context != file->ucontext) 1161 + goto out; 1162 + 1163 + uobj = srq->uobject; 1164 + 1165 + ret = ib_destroy_srq(srq); 1166 + if (ret) 1167 + goto out; 1168 + 1169 + idr_remove(&ib_uverbs_srq_idr, cmd.srq_handle); 1170 + 1171 + spin_lock_irq(&file->ucontext->lock); 1172 + list_del(&uobj->list); 1173 + spin_unlock_irq(&file->ucontext->lock); 1174 + 1175 + kfree(uobj); 1176 + 1177 + out: 1006 1178 up(&ib_uverbs_idr_mutex); 1007 1179 1008 1180 return ret ? ret : in_len;
+19 -1
drivers/infiniband/core/uverbs_main.c
··· 69 69 DEFINE_IDR(ib_uverbs_ah_idr); 70 70 DEFINE_IDR(ib_uverbs_cq_idr); 71 71 DEFINE_IDR(ib_uverbs_qp_idr); 72 + DEFINE_IDR(ib_uverbs_srq_idr); 72 73 73 74 static spinlock_t map_lock; 74 75 static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES); ··· 94 93 [IB_USER_VERBS_CMD_DESTROY_QP] = ib_uverbs_destroy_qp, 95 94 [IB_USER_VERBS_CMD_ATTACH_MCAST] = ib_uverbs_attach_mcast, 96 95 [IB_USER_VERBS_CMD_DETACH_MCAST] = ib_uverbs_detach_mcast, 96 + [IB_USER_VERBS_CMD_CREATE_SRQ] = ib_uverbs_create_srq, 97 + [IB_USER_VERBS_CMD_MODIFY_SRQ] = ib_uverbs_modify_srq, 98 + [IB_USER_VERBS_CMD_DESTROY_SRQ] = ib_uverbs_destroy_srq, 97 99 }; 98 100 99 101 static struct vfsmount *uverbs_event_mnt; ··· 131 127 kfree(uobj); 132 128 } 133 129 134 - /* XXX Free SRQs */ 130 + list_for_each_entry_safe(uobj, tmp, &context->srq_list, list) { 131 + struct ib_srq *srq = idr_find(&ib_uverbs_srq_idr, uobj->id); 132 + idr_remove(&ib_uverbs_srq_idr, uobj->id); 133 + ib_destroy_srq(srq); 134 + list_del(&uobj->list); 135 + kfree(uobj); 136 + } 137 + 135 138 /* XXX Free MWs */ 136 139 137 140 list_for_each_entry_safe(uobj, tmp, &context->mr_list, list) { ··· 354 343 { 355 344 ib_uverbs_async_handler(context_ptr, 356 345 event->element.qp->uobject->user_handle, 346 + event->event); 347 + } 348 + 349 + void ib_uverbs_srq_event_handler(struct ib_event *event, void *context_ptr) 350 + { 351 + ib_uverbs_async_handler(context_ptr, 352 + event->element.srq->uobject->user_handle, 357 353 event->event); 358 354 } 359 355
+34 -1
drivers/infiniband/include/ib_user_verbs.h
··· 78 78 IB_USER_VERBS_CMD_POST_SEND, 79 79 IB_USER_VERBS_CMD_POST_RECV, 80 80 IB_USER_VERBS_CMD_ATTACH_MCAST, 81 - IB_USER_VERBS_CMD_DETACH_MCAST 81 + IB_USER_VERBS_CMD_DETACH_MCAST, 82 + IB_USER_VERBS_CMD_CREATE_SRQ, 83 + IB_USER_VERBS_CMD_MODIFY_SRQ, 84 + IB_USER_VERBS_CMD_QUERY_SRQ, 85 + IB_USER_VERBS_CMD_DESTROY_SRQ, 86 + IB_USER_VERBS_CMD_POST_SRQ_RECV 82 87 }; 83 88 84 89 /* ··· 389 384 __u16 mlid; 390 385 __u16 reserved; 391 386 __u64 driver_data[0]; 387 + }; 388 + 389 + struct ib_uverbs_create_srq { 390 + __u64 response; 391 + __u64 user_handle; 392 + __u32 pd_handle; 393 + __u32 max_wr; 394 + __u32 max_sge; 395 + __u32 srq_limit; 396 + __u64 driver_data[0]; 397 + }; 398 + 399 + struct ib_uverbs_create_srq_resp { 400 + __u32 srq_handle; 401 + }; 402 + 403 + struct ib_uverbs_modify_srq { 404 + __u32 srq_handle; 405 + __u32 attr_mask; 406 + __u32 max_wr; 407 + __u32 max_sge; 408 + __u32 srq_limit; 409 + __u32 reserved; 410 + __u64 driver_data[0]; 411 + }; 412 + 413 + struct ib_uverbs_destroy_srq { 414 + __u32 srq_handle; 392 415 }; 393 416 394 417 #endif /* IB_USER_VERBS_H */