@@ -250,6 +250,7 @@ struct usdt_manager {
250250
251251 bool has_bpf_cookie ;
252252 bool has_sema_refcnt ;
253+ bool has_uprobe_multi ;
253254};
254255
255256struct usdt_manager * usdt_manager_new (struct bpf_object * obj )
@@ -284,6 +285,11 @@ struct usdt_manager *usdt_manager_new(struct bpf_object *obj)
284285 */
285286 man -> has_sema_refcnt = faccessat (AT_FDCWD , ref_ctr_sysfs_path , F_OK , AT_EACCESS ) == 0 ;
286287
288+ /*
289+ * Detect kernel support for uprobe multi link to be used for attaching
290+ * usdt probes.
291+ */
292+ man -> has_uprobe_multi = kernel_supports (obj , FEAT_UPROBE_MULTI_LINK );
287293 return man ;
288294}
289295
@@ -808,6 +814,8 @@ struct bpf_link_usdt {
808814 long abs_ip ;
809815 struct bpf_link * link ;
810816 } * uprobes ;
817+
818+ struct bpf_link * multi_link ;
811819};
812820
813821static int bpf_link_usdt_detach (struct bpf_link * link )
@@ -816,6 +824,9 @@ static int bpf_link_usdt_detach(struct bpf_link *link)
816824 struct usdt_manager * man = usdt_link -> usdt_man ;
817825 int i ;
818826
827+ bpf_link__destroy (usdt_link -> multi_link );
828+
829+ /* When having multi_link, uprobe_cnt is 0 */
819830 for (i = 0 ; i < usdt_link -> uprobe_cnt ; i ++ ) {
820831 /* detach underlying uprobe link */
821832 bpf_link__destroy (usdt_link -> uprobes [i ].link );
@@ -946,11 +957,13 @@ struct bpf_link *usdt_manager_attach_usdt(struct usdt_manager *man, const struct
946957 const char * usdt_provider , const char * usdt_name ,
947958 __u64 usdt_cookie )
948959{
960+ unsigned long * offsets = NULL , * ref_ctr_offsets = NULL ;
949961 int i , err , spec_map_fd , ip_map_fd ;
950962 LIBBPF_OPTS (bpf_uprobe_opts , opts );
951963 struct hashmap * specs_hash = NULL ;
952964 struct bpf_link_usdt * link = NULL ;
953965 struct usdt_target * targets = NULL ;
966+ __u64 * cookies = NULL ;
954967 struct elf_fd elf_fd ;
955968 size_t target_cnt ;
956969
@@ -997,10 +1010,21 @@ struct bpf_link *usdt_manager_attach_usdt(struct usdt_manager *man, const struct
9971010 link -> link .detach = & bpf_link_usdt_detach ;
9981011 link -> link .dealloc = & bpf_link_usdt_dealloc ;
9991012
1000- link -> uprobes = calloc (target_cnt , sizeof (* link -> uprobes ));
1001- if (!link -> uprobes ) {
1002- err = - ENOMEM ;
1003- goto err_out ;
1013+ if (man -> has_uprobe_multi ) {
1014+ offsets = calloc (target_cnt , sizeof (* offsets ));
1015+ cookies = calloc (target_cnt , sizeof (* cookies ));
1016+ ref_ctr_offsets = calloc (target_cnt , sizeof (* ref_ctr_offsets ));
1017+
1018+ if (!offsets || !ref_ctr_offsets || !cookies ) {
1019+ err = - ENOMEM ;
1020+ goto err_out ;
1021+ }
1022+ } else {
1023+ link -> uprobes = calloc (target_cnt , sizeof (* link -> uprobes ));
1024+ if (!link -> uprobes ) {
1025+ err = - ENOMEM ;
1026+ goto err_out ;
1027+ }
10041028 }
10051029
10061030 for (i = 0 ; i < target_cnt ; i ++ ) {
@@ -1041,20 +1065,48 @@ struct bpf_link *usdt_manager_attach_usdt(struct usdt_manager *man, const struct
10411065 goto err_out ;
10421066 }
10431067
1044- opts .ref_ctr_offset = target -> sema_off ;
1045- opts .bpf_cookie = man -> has_bpf_cookie ? spec_id : 0 ;
1046- uprobe_link = bpf_program__attach_uprobe_opts (prog , pid , path ,
1047- target -> rel_ip , & opts );
1048- err = libbpf_get_error (uprobe_link );
1049- if (err ) {
1050- pr_warn ("usdt: failed to attach uprobe #%d for '%s:%s' in '%s': %d\n" ,
1051- i , usdt_provider , usdt_name , path , err );
1068+ if (man -> has_uprobe_multi ) {
1069+ offsets [i ] = target -> rel_ip ;
1070+ ref_ctr_offsets [i ] = target -> sema_off ;
1071+ cookies [i ] = spec_id ;
1072+ } else {
1073+ opts .ref_ctr_offset = target -> sema_off ;
1074+ opts .bpf_cookie = man -> has_bpf_cookie ? spec_id : 0 ;
1075+ uprobe_link = bpf_program__attach_uprobe_opts (prog , pid , path ,
1076+ target -> rel_ip , & opts );
1077+ err = libbpf_get_error (uprobe_link );
1078+ if (err ) {
1079+ pr_warn ("usdt: failed to attach uprobe #%d for '%s:%s' in '%s': %d\n" ,
1080+ i , usdt_provider , usdt_name , path , err );
1081+ goto err_out ;
1082+ }
1083+
1084+ link -> uprobes [i ].link = uprobe_link ;
1085+ link -> uprobes [i ].abs_ip = target -> abs_ip ;
1086+ link -> uprobe_cnt ++ ;
1087+ }
1088+ }
1089+
1090+ if (man -> has_uprobe_multi ) {
1091+ LIBBPF_OPTS (bpf_uprobe_multi_opts , opts_multi ,
1092+ .ref_ctr_offsets = ref_ctr_offsets ,
1093+ .offsets = offsets ,
1094+ .cookies = cookies ,
1095+ .cnt = target_cnt ,
1096+ );
1097+
1098+ link -> multi_link = bpf_program__attach_uprobe_multi (prog , pid , path ,
1099+ NULL , & opts_multi );
1100+ if (!link -> multi_link ) {
1101+ err = - errno ;
1102+ pr_warn ("usdt: failed to attach uprobe multi for '%s:%s' in '%s': %d\n" ,
1103+ usdt_provider , usdt_name , path , err );
10521104 goto err_out ;
10531105 }
10541106
1055- link -> uprobes [ i ]. link = uprobe_link ;
1056- link -> uprobes [ i ]. abs_ip = target -> abs_ip ;
1057- link -> uprobe_cnt ++ ;
1107+ free ( offsets ) ;
1108+ free ( ref_ctr_offsets ) ;
1109+ free ( cookies ) ;
10581110 }
10591111
10601112 free (targets );
@@ -1063,6 +1115,10 @@ struct bpf_link *usdt_manager_attach_usdt(struct usdt_manager *man, const struct
10631115 return & link -> link ;
10641116
10651117err_out :
1118+ free (offsets );
1119+ free (ref_ctr_offsets );
1120+ free (cookies );
1121+
10661122 if (link )
10671123 bpf_link__destroy (& link -> link );
10681124 free (targets );
0 commit comments