@@ -620,22 +620,44 @@ static int be64_gt(__be64 a, __be64 b)
620
620
return (__force u64 ) a > (__force u64 ) b ;
621
621
}
622
622
623
- static struct cm_id_private * cm_insert_listen (struct cm_id_private * cm_id_priv )
623
+ /*
624
+ * Inserts a new cm_id_priv into the listen_service_table. Returns cm_id_priv
625
+ * if the new ID was inserted, NULL if it could not be inserted due to a
626
+ * collision, or the existing cm_id_priv ready for shared usage.
627
+ */
628
+ static struct cm_id_private * cm_insert_listen (struct cm_id_private * cm_id_priv ,
629
+ ib_cm_handler shared_handler )
624
630
{
625
631
struct rb_node * * link = & cm .listen_service_table .rb_node ;
626
632
struct rb_node * parent = NULL ;
627
633
struct cm_id_private * cur_cm_id_priv ;
628
634
__be64 service_id = cm_id_priv -> id .service_id ;
629
635
__be64 service_mask = cm_id_priv -> id .service_mask ;
636
+ unsigned long flags ;
630
637
638
+ spin_lock_irqsave (& cm .lock , flags );
631
639
while (* link ) {
632
640
parent = * link ;
633
641
cur_cm_id_priv = rb_entry (parent , struct cm_id_private ,
634
642
service_node );
635
643
if ((cur_cm_id_priv -> id .service_mask & service_id ) ==
636
644
(service_mask & cur_cm_id_priv -> id .service_id ) &&
637
- (cm_id_priv -> id .device == cur_cm_id_priv -> id .device ))
645
+ (cm_id_priv -> id .device == cur_cm_id_priv -> id .device )) {
646
+ /*
647
+ * Sharing an ib_cm_id with different handlers is not
648
+ * supported
649
+ */
650
+ if (cur_cm_id_priv -> id .cm_handler != shared_handler ||
651
+ cur_cm_id_priv -> id .context ||
652
+ WARN_ON (!cur_cm_id_priv -> id .cm_handler )) {
653
+ spin_unlock_irqrestore (& cm .lock , flags );
654
+ return NULL ;
655
+ }
656
+ refcount_inc (& cur_cm_id_priv -> refcount );
657
+ cur_cm_id_priv -> listen_sharecount ++ ;
658
+ spin_unlock_irqrestore (& cm .lock , flags );
638
659
return cur_cm_id_priv ;
660
+ }
639
661
640
662
if (cm_id_priv -> id .device < cur_cm_id_priv -> id .device )
641
663
link = & (* link )-> rb_left ;
@@ -648,9 +670,11 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv)
648
670
else
649
671
link = & (* link )-> rb_right ;
650
672
}
673
+ cm_id_priv -> listen_sharecount ++ ;
651
674
rb_link_node (& cm_id_priv -> service_node , parent , link );
652
675
rb_insert_color (& cm_id_priv -> service_node , & cm .listen_service_table );
653
- return NULL ;
676
+ spin_unlock_irqrestore (& cm .lock , flags );
677
+ return cm_id_priv ;
654
678
}
655
679
656
680
static struct cm_id_private * cm_find_listen (struct ib_device * device ,
@@ -807,9 +831,9 @@ static void cm_reject_sidr_req(struct cm_id_private *cm_id_priv,
807
831
ib_send_cm_sidr_rep (& cm_id_priv -> id , & param );
808
832
}
809
833
810
- struct ib_cm_id * ib_create_cm_id (struct ib_device * device ,
811
- ib_cm_handler cm_handler ,
812
- void * context )
834
+ static struct cm_id_private * cm_alloc_id_priv (struct ib_device * device ,
835
+ ib_cm_handler cm_handler ,
836
+ void * context )
813
837
{
814
838
struct cm_id_private * cm_id_priv ;
815
839
u32 id ;
@@ -840,15 +864,37 @@ struct ib_cm_id *ib_create_cm_id(struct ib_device *device,
840
864
if (ret )
841
865
goto error ;
842
866
cm_id_priv -> id .local_id = (__force __be32 )id ^ cm .random_id_operand ;
843
- xa_store_irq (& cm .local_id_table , cm_local_id (cm_id_priv -> id .local_id ),
844
- cm_id_priv , GFP_KERNEL );
845
867
846
- return & cm_id_priv -> id ;
868
+ return cm_id_priv ;
847
869
848
870
error :
849
871
kfree (cm_id_priv );
850
872
return ERR_PTR (ret );
851
873
}
874
+
875
+ /*
876
+ * Make the ID visible to the MAD handlers and other threads that use the
877
+ * xarray.
878
+ */
879
+ static void cm_finalize_id (struct cm_id_private * cm_id_priv )
880
+ {
881
+ xa_store_irq (& cm .local_id_table , cm_local_id (cm_id_priv -> id .local_id ),
882
+ cm_id_priv , GFP_KERNEL );
883
+ }
884
+
885
+ struct ib_cm_id * ib_create_cm_id (struct ib_device * device ,
886
+ ib_cm_handler cm_handler ,
887
+ void * context )
888
+ {
889
+ struct cm_id_private * cm_id_priv ;
890
+
891
+ cm_id_priv = cm_alloc_id_priv (device , cm_handler , context );
892
+ if (IS_ERR (cm_id_priv ))
893
+ return ERR_CAST (cm_id_priv );
894
+
895
+ cm_finalize_id (cm_id_priv );
896
+ return & cm_id_priv -> id ;
897
+ }
852
898
EXPORT_SYMBOL (ib_create_cm_id );
853
899
854
900
static struct cm_work * cm_dequeue_work (struct cm_id_private * cm_id_priv )
@@ -1092,8 +1138,27 @@ void ib_destroy_cm_id(struct ib_cm_id *cm_id)
1092
1138
}
1093
1139
EXPORT_SYMBOL (ib_destroy_cm_id );
1094
1140
1141
+ static int cm_init_listen (struct cm_id_private * cm_id_priv , __be64 service_id ,
1142
+ __be64 service_mask )
1143
+ {
1144
+ service_mask = service_mask ? service_mask : ~cpu_to_be64 (0 );
1145
+ service_id &= service_mask ;
1146
+ if ((service_id & IB_SERVICE_ID_AGN_MASK ) == IB_CM_ASSIGN_SERVICE_ID &&
1147
+ (service_id != IB_CM_ASSIGN_SERVICE_ID ))
1148
+ return - EINVAL ;
1149
+
1150
+ if (service_id == IB_CM_ASSIGN_SERVICE_ID ) {
1151
+ cm_id_priv -> id .service_id = cpu_to_be64 (cm .listen_service_id ++ );
1152
+ cm_id_priv -> id .service_mask = ~cpu_to_be64 (0 );
1153
+ } else {
1154
+ cm_id_priv -> id .service_id = service_id ;
1155
+ cm_id_priv -> id .service_mask = service_mask ;
1156
+ }
1157
+ return 0 ;
1158
+ }
1159
+
1095
1160
/**
1096
- * __ib_cm_listen - Initiates listening on the specified service ID for
1161
+ * ib_cm_listen - Initiates listening on the specified service ID for
1097
1162
* connection and service ID resolution requests.
1098
1163
* @cm_id: Connection identifier associated with the listen request.
1099
1164
* @service_id: Service identifier matched against incoming connection
@@ -1105,51 +1170,33 @@ EXPORT_SYMBOL(ib_destroy_cm_id);
1105
1170
* exactly. This parameter is ignored if %service_id is set to
1106
1171
* IB_CM_ASSIGN_SERVICE_ID.
1107
1172
*/
1108
- static int __ib_cm_listen (struct ib_cm_id * cm_id , __be64 service_id ,
1109
- __be64 service_mask )
1173
+ int ib_cm_listen (struct ib_cm_id * cm_id , __be64 service_id , __be64 service_mask )
1110
1174
{
1111
- struct cm_id_private * cm_id_priv , * cur_cm_id_priv ;
1112
- int ret = 0 ;
1113
-
1114
- service_mask = service_mask ? service_mask : ~cpu_to_be64 (0 );
1115
- service_id &= service_mask ;
1116
- if ((service_id & IB_SERVICE_ID_AGN_MASK ) == IB_CM_ASSIGN_SERVICE_ID &&
1117
- (service_id != IB_CM_ASSIGN_SERVICE_ID ))
1118
- return - EINVAL ;
1119
-
1120
- cm_id_priv = container_of (cm_id , struct cm_id_private , id );
1121
- if (cm_id -> state != IB_CM_IDLE )
1122
- return - EINVAL ;
1123
-
1124
- cm_id -> state = IB_CM_LISTEN ;
1125
- ++ cm_id_priv -> listen_sharecount ;
1175
+ struct cm_id_private * cm_id_priv =
1176
+ container_of (cm_id , struct cm_id_private , id );
1177
+ unsigned long flags ;
1178
+ int ret ;
1126
1179
1127
- if (service_id == IB_CM_ASSIGN_SERVICE_ID ) {
1128
- cm_id -> service_id = cpu_to_be64 (cm .listen_service_id ++ );
1129
- cm_id -> service_mask = ~cpu_to_be64 (0 );
1130
- } else {
1131
- cm_id -> service_id = service_id ;
1132
- cm_id -> service_mask = service_mask ;
1180
+ spin_lock_irqsave (& cm_id_priv -> lock , flags );
1181
+ if (cm_id_priv -> id .state != IB_CM_IDLE ) {
1182
+ ret = - EINVAL ;
1183
+ goto out ;
1133
1184
}
1134
- cur_cm_id_priv = cm_insert_listen (cm_id_priv );
1135
1185
1136
- if (cur_cm_id_priv ) {
1137
- cm_id -> state = IB_CM_IDLE ;
1138
- -- cm_id_priv -> listen_sharecount ;
1186
+ ret = cm_init_listen (cm_id_priv , service_id , service_mask );
1187
+ if (ret )
1188
+ goto out ;
1189
+
1190
+ if (!cm_insert_listen (cm_id_priv , NULL )) {
1139
1191
ret = - EBUSY ;
1192
+ goto out ;
1140
1193
}
1141
- return ret ;
1142
- }
1143
1194
1144
- int ib_cm_listen (struct ib_cm_id * cm_id , __be64 service_id , __be64 service_mask )
1145
- {
1146
- unsigned long flags ;
1147
- int ret ;
1148
-
1149
- spin_lock_irqsave (& cm .lock , flags );
1150
- ret = __ib_cm_listen (cm_id , service_id , service_mask );
1151
- spin_unlock_irqrestore (& cm .lock , flags );
1195
+ cm_id_priv -> id .state = IB_CM_LISTEN ;
1196
+ ret = 0 ;
1152
1197
1198
+ out :
1199
+ spin_unlock_irqrestore (& cm_id_priv -> lock , flags );
1153
1200
return ret ;
1154
1201
}
1155
1202
EXPORT_SYMBOL (ib_cm_listen );
@@ -1174,52 +1221,38 @@ struct ib_cm_id *ib_cm_insert_listen(struct ib_device *device,
1174
1221
ib_cm_handler cm_handler ,
1175
1222
__be64 service_id )
1176
1223
{
1224
+ struct cm_id_private * listen_id_priv ;
1177
1225
struct cm_id_private * cm_id_priv ;
1178
- struct ib_cm_id * cm_id ;
1179
- unsigned long flags ;
1180
1226
int err = 0 ;
1181
1227
1182
1228
/* Create an ID in advance, since the creation may sleep */
1183
- cm_id = ib_create_cm_id (device , cm_handler , NULL );
1184
- if (IS_ERR (cm_id ))
1185
- return cm_id ;
1186
-
1187
- spin_lock_irqsave (& cm .lock , flags );
1229
+ cm_id_priv = cm_alloc_id_priv (device , cm_handler , NULL );
1230
+ if (IS_ERR (cm_id_priv ))
1231
+ return ERR_CAST (cm_id_priv );
1188
1232
1189
- if (service_id == IB_CM_ASSIGN_SERVICE_ID )
1190
- goto new_id ;
1233
+ err = cm_init_listen (cm_id_priv , service_id , 0 );
1234
+ if (err )
1235
+ return ERR_PTR (err );
1191
1236
1192
- /* Find an existing ID */
1193
- cm_id_priv = cm_find_listen (device , service_id );
1194
- if (cm_id_priv ) {
1195
- if (cm_id_priv -> id .cm_handler != cm_handler ||
1196
- cm_id_priv -> id .context ) {
1197
- /* Sharing an ib_cm_id with different handlers is not
1198
- * supported */
1199
- spin_unlock_irqrestore (& cm .lock , flags );
1200
- ib_destroy_cm_id (cm_id );
1237
+ spin_lock_irq (& cm_id_priv -> lock );
1238
+ listen_id_priv = cm_insert_listen (cm_id_priv , cm_handler );
1239
+ if (listen_id_priv != cm_id_priv ) {
1240
+ spin_unlock_irq (& cm_id_priv -> lock );
1241
+ ib_destroy_cm_id (& cm_id_priv -> id );
1242
+ if (!listen_id_priv )
1201
1243
return ERR_PTR (- EINVAL );
1202
- }
1203
- refcount_inc (& cm_id_priv -> refcount );
1204
- ++ cm_id_priv -> listen_sharecount ;
1205
- spin_unlock_irqrestore (& cm .lock , flags );
1206
-
1207
- ib_destroy_cm_id (cm_id );
1208
- cm_id = & cm_id_priv -> id ;
1209
- return cm_id ;
1244
+ return & listen_id_priv -> id ;
1210
1245
}
1246
+ cm_id_priv -> id .state = IB_CM_LISTEN ;
1247
+ spin_unlock_irq (& cm_id_priv -> lock );
1211
1248
1212
- new_id :
1213
- /* Use newly created ID */
1214
- err = __ib_cm_listen ( cm_id , service_id , 0 );
1215
-
1216
- spin_unlock_irqrestore ( & cm . lock , flags );
1249
+ /*
1250
+ * A listen ID does not need to be in the xarray since it does not
1251
+ * receive mads, is not placed in the remote_id or remote_qpn rbtree,
1252
+ * and does not enter timewait.
1253
+ */
1217
1254
1218
- if (err ) {
1219
- ib_destroy_cm_id (cm_id );
1220
- return ERR_PTR (err );
1221
- }
1222
- return cm_id ;
1255
+ return & cm_id_priv -> id ;
1223
1256
}
1224
1257
EXPORT_SYMBOL (ib_cm_insert_listen );
1225
1258
0 commit comments