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 extern struct idr ib_uverbs_ah_idr; 100 extern struct idr ib_uverbs_cq_idr; 101 extern struct idr ib_uverbs_qp_idr; 102 103 void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context); 104 void ib_uverbs_cq_event_handler(struct ib_event *event, void *context_ptr); 105 void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr); 106 107 int ib_umem_get(struct ib_device *dev, struct ib_umem *mem, 108 void *addr, size_t size, int write); ··· 133 IB_UVERBS_DECLARE_CMD(destroy_qp); 134 IB_UVERBS_DECLARE_CMD(attach_mcast); 135 IB_UVERBS_DECLARE_CMD(detach_mcast); 136 137 #endif /* UVERBS_H */
··· 99 extern struct idr ib_uverbs_ah_idr; 100 extern struct idr ib_uverbs_cq_idr; 101 extern struct idr ib_uverbs_qp_idr; 102 + extern struct idr ib_uverbs_srq_idr; 103 104 void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context); 105 void ib_uverbs_cq_event_handler(struct ib_event *event, void *context_ptr); 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); 108 109 int ib_umem_get(struct ib_device *dev, struct ib_umem *mem, 110 void *addr, size_t size, int write); ··· 131 IB_UVERBS_DECLARE_CMD(destroy_qp); 132 IB_UVERBS_DECLARE_CMD(attach_mcast); 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); 137 138 #endif /* UVERBS_H */
+180 -2
drivers/infiniband/core/uverbs_cmd.c
··· 724 struct ib_uobject *uobj; 725 struct ib_pd *pd; 726 struct ib_cq *scq, *rcq; 727 struct ib_qp *qp; 728 struct ib_qp_init_attr attr; 729 int ret; ··· 748 pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle); 749 scq = idr_find(&ib_uverbs_cq_idr, cmd.send_cq_handle); 750 rcq = idr_find(&ib_uverbs_cq_idr, cmd.recv_cq_handle); 751 752 if (!pd || pd->uobject->context != file->ucontext || 753 !scq || scq->uobject->context != file->ucontext || 754 - !rcq || rcq->uobject->context != file->ucontext) { 755 ret = -EINVAL; 756 goto err_up; 757 } ··· 762 attr.qp_context = file; 763 attr.send_cq = scq; 764 attr.recv_cq = rcq; 765 - attr.srq = NULL; 766 attr.sq_sig_type = cmd.sq_sig_all ? IB_SIGNAL_ALL_WR : IB_SIGNAL_REQ_WR; 767 attr.qp_type = cmd.qp_type; 768 ··· 1003 if (qp && qp->uobject->context == file->ucontext) 1004 ret = ib_detach_mcast(qp, (union ib_gid *) cmd.gid, cmd.mlid); 1005 1006 up(&ib_uverbs_idr_mutex); 1007 1008 return ret ? ret : in_len;
··· 724 struct ib_uobject *uobj; 725 struct ib_pd *pd; 726 struct ib_cq *scq, *rcq; 727 + struct ib_srq *srq; 728 struct ib_qp *qp; 729 struct ib_qp_init_attr attr; 730 int ret; ··· 747 pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle); 748 scq = idr_find(&ib_uverbs_cq_idr, cmd.send_cq_handle); 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 752 if (!pd || pd->uobject->context != file->ucontext || 753 !scq || scq->uobject->context != file->ucontext || 754 + !rcq || rcq->uobject->context != file->ucontext || 755 + (cmd.is_srq && (!srq || srq->uobject->context != file->ucontext))) { 756 ret = -EINVAL; 757 goto err_up; 758 } ··· 759 attr.qp_context = file; 760 attr.send_cq = scq; 761 attr.recv_cq = rcq; 762 + attr.srq = srq; 763 attr.sq_sig_type = cmd.sq_sig_all ? IB_SIGNAL_ALL_WR : IB_SIGNAL_REQ_WR; 764 attr.qp_type = cmd.qp_type; 765 ··· 1000 if (qp && qp->uobject->context == file->ucontext) 1001 ret = ib_detach_mcast(qp, (union ib_gid *) cmd.gid, cmd.mlid); 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: 1178 up(&ib_uverbs_idr_mutex); 1179 1180 return ret ? ret : in_len;
+19 -1
drivers/infiniband/core/uverbs_main.c
··· 69 DEFINE_IDR(ib_uverbs_ah_idr); 70 DEFINE_IDR(ib_uverbs_cq_idr); 71 DEFINE_IDR(ib_uverbs_qp_idr); 72 73 static spinlock_t map_lock; 74 static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES); ··· 94 [IB_USER_VERBS_CMD_DESTROY_QP] = ib_uverbs_destroy_qp, 95 [IB_USER_VERBS_CMD_ATTACH_MCAST] = ib_uverbs_attach_mcast, 96 [IB_USER_VERBS_CMD_DETACH_MCAST] = ib_uverbs_detach_mcast, 97 }; 98 99 static struct vfsmount *uverbs_event_mnt; ··· 131 kfree(uobj); 132 } 133 134 - /* XXX Free SRQs */ 135 /* XXX Free MWs */ 136 137 list_for_each_entry_safe(uobj, tmp, &context->mr_list, list) { ··· 354 { 355 ib_uverbs_async_handler(context_ptr, 356 event->element.qp->uobject->user_handle, 357 event->event); 358 } 359
··· 69 DEFINE_IDR(ib_uverbs_ah_idr); 70 DEFINE_IDR(ib_uverbs_cq_idr); 71 DEFINE_IDR(ib_uverbs_qp_idr); 72 + DEFINE_IDR(ib_uverbs_srq_idr); 73 74 static spinlock_t map_lock; 75 static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES); ··· 93 [IB_USER_VERBS_CMD_DESTROY_QP] = ib_uverbs_destroy_qp, 94 [IB_USER_VERBS_CMD_ATTACH_MCAST] = ib_uverbs_attach_mcast, 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, 99 }; 100 101 static struct vfsmount *uverbs_event_mnt; ··· 127 kfree(uobj); 128 } 129 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 + 138 /* XXX Free MWs */ 139 140 list_for_each_entry_safe(uobj, tmp, &context->mr_list, list) { ··· 343 { 344 ib_uverbs_async_handler(context_ptr, 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, 353 event->event); 354 } 355
+34 -1
drivers/infiniband/include/ib_user_verbs.h
··· 78 IB_USER_VERBS_CMD_POST_SEND, 79 IB_USER_VERBS_CMD_POST_RECV, 80 IB_USER_VERBS_CMD_ATTACH_MCAST, 81 - IB_USER_VERBS_CMD_DETACH_MCAST 82 }; 83 84 /* ··· 389 __u16 mlid; 390 __u16 reserved; 391 __u64 driver_data[0]; 392 }; 393 394 #endif /* IB_USER_VERBS_H */
··· 78 IB_USER_VERBS_CMD_POST_SEND, 79 IB_USER_VERBS_CMD_POST_RECV, 80 IB_USER_VERBS_CMD_ATTACH_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 87 }; 88 89 /* ··· 384 __u16 mlid; 385 __u16 reserved; 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; 415 }; 416 417 #endif /* IB_USER_VERBS_H */