@@ -773,22 +773,46 @@ static int __init cpumf_pmu_init(void)
773
773
* counter set via normal file operations.
774
774
*/
775
775
776
- static atomic_t cfset_opencnt = ATOMIC_INIT (0 ); /* Excl. access */
776
+ static atomic_t cfset_opencnt = ATOMIC_INIT (0 ); /* Access count */
777
777
static DEFINE_MUTEX (cfset_ctrset_mutex );/* Synchronize access to hardware */
778
778
struct cfset_call_on_cpu_parm { /* Parm struct for smp_call_on_cpu */
779
779
unsigned int sets ; /* Counter set bit mask */
780
780
atomic_t cpus_ack ; /* # CPUs successfully executed func */
781
781
};
782
782
783
- static struct cfset_request { /* CPUs and counter set bit mask */
783
+ static struct cfset_session { /* CPUs and counter set bit mask */
784
+ struct list_head head ; /* Head of list of active processes */
785
+ } cfset_session = {
786
+ .head = LIST_HEAD_INIT (cfset_session .head )
787
+ };
788
+
789
+ struct cfset_request { /* CPUs and counter set bit mask */
784
790
unsigned long ctrset ; /* Bit mask of counter set to read */
785
791
cpumask_t mask ; /* CPU mask to read from */
786
- } cfset_request ;
792
+ struct list_head node ; /* Chain to cfset_session.head */
793
+ };
794
+
795
+ static void cfset_session_init (void )
796
+ {
797
+ INIT_LIST_HEAD (& cfset_session .head );
798
+ }
799
+
800
+ /* Remove current request from global bookkeeping. Maintain a counter set bit
801
+ * mask on a per CPU basis.
802
+ * Done in process context under mutex protection.
803
+ */
804
+ static void cfset_session_del (struct cfset_request * p )
805
+ {
806
+ list_del (& p -> node );
807
+ }
787
808
788
- static void cfset_ctrset_clear (void )
809
+ /* Add current request to global bookkeeping. Maintain a counter set bit mask
810
+ * on a per CPU basis.
811
+ * Done in process context under mutex protection.
812
+ */
813
+ static void cfset_session_add (struct cfset_request * p )
789
814
{
790
- cpumask_clear (& cfset_request .mask );
791
- cfset_request .ctrset = 0 ;
815
+ list_add (& p -> node , & cfset_session .head );
792
816
}
793
817
794
818
/* The /dev/hwctr device access uses PMU_F_IN_USE to mark the device access
@@ -827,15 +851,23 @@ static void cfset_ioctl_off(void *parm)
827
851
struct cfset_call_on_cpu_parm * p = parm ;
828
852
int rc ;
829
853
830
- cpuhw -> dev_state = 0 ;
854
+ /* Check if any counter set used by /dev/hwc */
831
855
for (rc = CPUMF_CTR_SET_BASIC ; rc < CPUMF_CTR_SET_MAX ; ++ rc )
832
- if ((p -> sets & cpumf_ctr_ctl [rc ]))
833
- atomic_dec (& cpuhw -> ctr_set [rc ]);
834
- rc = lcctl (cpuhw -> state ); /* Keep perf_event_open counter sets */
856
+ if ((p -> sets & cpumf_ctr_ctl [rc ])) {
857
+ if (!atomic_dec_return (& cpuhw -> ctr_set [rc ])) {
858
+ ctr_set_disable (& cpuhw -> dev_state ,
859
+ cpumf_ctr_ctl [rc ]);
860
+ ctr_set_stop (& cpuhw -> dev_state ,
861
+ cpumf_ctr_ctl [rc ]);
862
+ }
863
+ }
864
+ /* Keep perf_event_open counter sets */
865
+ rc = lcctl (cpuhw -> dev_state | cpuhw -> state );
835
866
if (rc )
836
867
pr_err ("Counter set stop %#llx of /dev/%s failed rc=%i\n" ,
837
868
cpuhw -> state , S390_HWCTR_DEVICE , rc );
838
- cpuhw -> flags &= ~PMU_F_IN_USE ;
869
+ if (!cpuhw -> dev_state )
870
+ cpuhw -> flags &= ~PMU_F_IN_USE ;
839
871
debug_sprintf_event (cf_dbg , 4 , "%s rc %d state %#llx dev_state %#llx\n" ,
840
872
__func__ , rc , cpuhw -> state , cpuhw -> dev_state );
841
873
}
@@ -870,66 +902,76 @@ static void cfset_release_cpu(void *p)
870
902
871
903
debug_sprintf_event (cf_dbg , 4 , "%s state %#llx dev_state %#llx\n" ,
872
904
__func__ , cpuhw -> state , cpuhw -> dev_state );
905
+ cpuhw -> dev_state = 0 ;
873
906
rc = lcctl (cpuhw -> state ); /* Keep perf_event_open counter sets */
874
907
if (rc )
875
908
pr_err ("Counter set release %#llx of /dev/%s failed rc=%i\n" ,
876
909
cpuhw -> state , S390_HWCTR_DEVICE , rc );
877
- cpuhw -> dev_state = 0 ;
910
+ }
911
+
912
+ /* This modifies the process CPU mask to adopt it to the currently online
913
+ * CPUs. Offline CPUs can not be addresses. This call terminates the access
914
+ * and is usually followed by close() or a new iotcl(..., START, ...) which
915
+ * creates a new request structure.
916
+ */
917
+ static void cfset_all_stop (struct cfset_request * req )
918
+ {
919
+ struct cfset_call_on_cpu_parm p = {
920
+ .sets = req -> ctrset ,
921
+ };
922
+
923
+ cpumask_and (& req -> mask , & req -> mask , cpu_online_mask );
924
+ on_each_cpu_mask (& req -> mask , cfset_ioctl_off , & p , 1 );
878
925
}
879
926
880
927
/* Release function is also called when application gets terminated without
881
928
* doing a proper ioctl(..., S390_HWCTR_STOP, ...) command.
882
929
*/
883
930
static int cfset_release (struct inode * inode , struct file * file )
884
931
{
885
- on_each_cpu (cfset_release_cpu , NULL , 1 );
932
+ mutex_lock (& cfset_ctrset_mutex );
933
+ /* Open followed by close/exit has no private_data */
934
+ if (file -> private_data ) {
935
+ cfset_all_stop (file -> private_data );
936
+ cfset_session_del (file -> private_data );
937
+ kfree (file -> private_data );
938
+ file -> private_data = NULL ;
939
+ }
940
+ if (!atomic_dec_return (& cfset_opencnt ))
941
+ on_each_cpu (cfset_release_cpu , NULL , 1 );
942
+ mutex_unlock (& cfset_ctrset_mutex );
943
+
886
944
hw_perf_event_destroy (NULL );
887
- cfset_ctrset_clear ();
888
- atomic_set (& cfset_opencnt , 0 );
889
945
return 0 ;
890
946
}
891
947
892
948
static int cfset_open (struct inode * inode , struct file * file )
893
949
{
894
950
if (!capable (CAP_SYS_ADMIN ))
895
951
return - EPERM ;
896
- /* Only one user space program can open /dev/hwctr */
897
- if (atomic_xchg (& cfset_opencnt , 1 ))
898
- return - EBUSY ;
952
+ mutex_lock (& cfset_ctrset_mutex );
953
+ if (atomic_inc_return (& cfset_opencnt ) == 1 )
954
+ cfset_session_init ();
955
+ mutex_unlock (& cfset_ctrset_mutex );
899
956
900
957
cpumf_hw_inuse ();
901
958
file -> private_data = NULL ;
902
959
/* nonseekable_open() never fails */
903
960
return nonseekable_open (inode , file );
904
961
}
905
962
906
- static int cfset_all_stop ( void )
963
+ static int cfset_all_start ( struct cfset_request * req )
907
964
{
908
965
struct cfset_call_on_cpu_parm p = {
909
- .sets = cfset_request .ctrset ,
910
- };
911
- cpumask_var_t mask ;
912
-
913
- if (!alloc_cpumask_var (& mask , GFP_KERNEL ))
914
- return - ENOMEM ;
915
- cpumask_and (mask , & cfset_request .mask , cpu_online_mask );
916
- on_each_cpu_mask (mask , cfset_ioctl_off , & p , 1 );
917
- free_cpumask_var (mask );
918
- return 0 ;
919
- }
920
-
921
- static int cfset_all_start (void )
922
- {
923
- struct cfset_call_on_cpu_parm p = {
924
- .sets = cfset_request .ctrset ,
966
+ .sets = req -> ctrset ,
925
967
.cpus_ack = ATOMIC_INIT (0 ),
926
968
};
927
969
cpumask_var_t mask ;
928
970
int rc = 0 ;
929
971
930
972
if (!alloc_cpumask_var (& mask , GFP_KERNEL ))
931
973
return - ENOMEM ;
932
- cpumask_and (mask , & cfset_request . mask , cpu_online_mask );
974
+ cpumask_and (mask , & req -> mask , cpu_online_mask );
933
975
on_each_cpu_mask (mask , cfset_ioctl_on , & p , 1 );
934
976
if (atomic_read (& p .cpus_ack ) != cpumask_weight (mask )) {
935
977
on_each_cpu_mask (mask , cfset_ioctl_off , & p , 1 );
@@ -1045,7 +1087,7 @@ static void cfset_cpu_read(void *parm)
1045
1087
cpuhw -> sets , cpuhw -> used );
1046
1088
}
1047
1089
1048
- static int cfset_all_read (unsigned long arg )
1090
+ static int cfset_all_read (unsigned long arg , struct cfset_request * req )
1049
1091
{
1050
1092
struct cfset_call_on_cpu_parm p ;
1051
1093
cpumask_var_t mask ;
@@ -1054,46 +1096,53 @@ static int cfset_all_read(unsigned long arg)
1054
1096
if (!alloc_cpumask_var (& mask , GFP_KERNEL ))
1055
1097
return - ENOMEM ;
1056
1098
1057
- p .sets = cfset_request . ctrset ;
1058
- cpumask_and (mask , & cfset_request . mask , cpu_online_mask );
1099
+ p .sets = req -> ctrset ;
1100
+ cpumask_and (mask , & req -> mask , cpu_online_mask );
1059
1101
on_each_cpu_mask (mask , cfset_cpu_read , & p , 1 );
1060
1102
rc = cfset_all_copy (arg , mask );
1061
1103
free_cpumask_var (mask );
1062
1104
return rc ;
1063
1105
}
1064
1106
1065
- static long cfset_ioctl_read (unsigned long arg )
1107
+ static long cfset_ioctl_read (unsigned long arg , struct cfset_request * req )
1066
1108
{
1067
1109
struct s390_ctrset_read read ;
1068
- int ret = 0 ;
1110
+ int ret = - ENODATA ;
1069
1111
1070
- if (copy_from_user (& read , (char __user * )arg , sizeof (read )))
1071
- return - EFAULT ;
1072
- ret = cfset_all_read (arg );
1112
+ if (req && req -> ctrset ) {
1113
+ if (copy_from_user (& read , (char __user * )arg , sizeof (read )))
1114
+ return - EFAULT ;
1115
+ ret = cfset_all_read (arg , req );
1116
+ }
1073
1117
return ret ;
1074
1118
}
1075
1119
1076
- static long cfset_ioctl_stop (void )
1120
+ static long cfset_ioctl_stop (struct file * file )
1077
1121
{
1078
- int ret = ENXIO ;
1079
-
1080
- if (cfset_request .ctrset ) {
1081
- ret = cfset_all_stop ();
1082
- cfset_ctrset_clear ();
1122
+ struct cfset_request * req = file -> private_data ;
1123
+ int ret = - ENXIO ;
1124
+
1125
+ if (req ) {
1126
+ cfset_all_stop (req );
1127
+ cfset_session_del (req );
1128
+ kfree (req );
1129
+ file -> private_data = NULL ;
1130
+ ret = 0 ;
1083
1131
}
1084
1132
return ret ;
1085
1133
}
1086
1134
1087
- static long cfset_ioctl_start (unsigned long arg )
1135
+ static long cfset_ioctl_start (unsigned long arg , struct file * file )
1088
1136
{
1089
1137
struct s390_ctrset_start __user * ustart ;
1090
1138
struct s390_ctrset_start start ;
1139
+ struct cfset_request * preq ;
1091
1140
void __user * umask ;
1092
1141
unsigned int len ;
1093
1142
int ret = 0 ;
1094
1143
size_t need ;
1095
1144
1096
- if (cfset_request . ctrset )
1145
+ if (file -> private_data )
1097
1146
return - EBUSY ;
1098
1147
ustart = (struct s390_ctrset_start __user * )arg ;
1099
1148
if (copy_from_user (& start , ustart , sizeof (start )))
@@ -1108,25 +1157,36 @@ static long cfset_ioctl_start(unsigned long arg)
1108
1157
return - EINVAL ; /* Invalid counter set */
1109
1158
if (!start .counter_sets )
1110
1159
return - EINVAL ; /* No counter set at all? */
1111
- cpumask_clear (& cfset_request .mask );
1160
+
1161
+ preq = kzalloc (sizeof (* preq ), GFP_KERNEL );
1162
+ if (!preq )
1163
+ return - ENOMEM ;
1164
+ cpumask_clear (& preq -> mask );
1112
1165
len = min_t (u64 , start .cpumask_len , cpumask_size ());
1113
1166
umask = (void __user * )start .cpumask ;
1114
- if (copy_from_user (& cfset_request .mask , umask , len ))
1167
+ if (copy_from_user (& preq -> mask , umask , len )) {
1168
+ kfree (preq );
1115
1169
return - EFAULT ;
1116
- if (cpumask_empty (& cfset_request .mask ))
1170
+ }
1171
+ if (cpumask_empty (& preq -> mask )) {
1172
+ kfree (preq );
1117
1173
return - EINVAL ;
1174
+ }
1118
1175
need = cfset_needspace (start .counter_sets );
1119
- if (put_user (need , & ustart -> data_bytes ))
1120
- ret = - EFAULT ;
1121
- if (ret )
1122
- goto out ;
1123
- cfset_request .ctrset = start .counter_sets ;
1124
- ret = cfset_all_start ();
1125
- out :
1126
- if (ret )
1127
- cfset_ctrset_clear ();
1128
- debug_sprintf_event (cf_dbg , 4 , "%s sets %#lx need %ld ret %d\n" ,
1129
- __func__ , cfset_request .ctrset , need , ret );
1176
+ if (put_user (need , & ustart -> data_bytes )) {
1177
+ kfree (preq );
1178
+ return - EFAULT ;
1179
+ }
1180
+ preq -> ctrset = start .counter_sets ;
1181
+ ret = cfset_all_start (preq );
1182
+ if (!ret ) {
1183
+ cfset_session_add (preq );
1184
+ file -> private_data = preq ;
1185
+ debug_sprintf_event (cf_dbg , 4 , "%s set %#lx need %ld ret %d\n" ,
1186
+ __func__ , preq -> ctrset , need , ret );
1187
+ } else {
1188
+ kfree (preq );
1189
+ }
1130
1190
return ret ;
1131
1191
}
1132
1192
@@ -1136,7 +1196,7 @@ static long cfset_ioctl_start(unsigned long arg)
1136
1196
* counter set keeps running until explicitly stopped. Returns the number
1137
1197
* of bytes needed to store the counter values. If another S390_HWCTR_START
1138
1198
* ioctl subcommand is called without a previous S390_HWCTR_STOP stop
1139
- * command, -EBUSY is returned.
1199
+ * command on the same file descriptor , -EBUSY is returned.
1140
1200
* S390_HWCTR_READ: Read the counter set values from specified CPU list given
1141
1201
* with the S390_HWCTR_START command.
1142
1202
* S390_HWCTR_STOP: Stops the counter sets on the CPU list given with the
@@ -1150,13 +1210,13 @@ static long cfset_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1150
1210
mutex_lock (& cfset_ctrset_mutex );
1151
1211
switch (cmd ) {
1152
1212
case S390_HWCTR_START :
1153
- ret = cfset_ioctl_start (arg );
1213
+ ret = cfset_ioctl_start (arg , file );
1154
1214
break ;
1155
1215
case S390_HWCTR_STOP :
1156
- ret = cfset_ioctl_stop ();
1216
+ ret = cfset_ioctl_stop (file );
1157
1217
break ;
1158
1218
case S390_HWCTR_READ :
1159
- ret = cfset_ioctl_read (arg );
1219
+ ret = cfset_ioctl_read (arg , file -> private_data );
1160
1220
break ;
1161
1221
default :
1162
1222
ret = - ENOTTY ;
@@ -1182,29 +1242,41 @@ static struct miscdevice cfset_dev = {
1182
1242
.fops = & cfset_fops ,
1183
1243
};
1184
1244
1245
+ /* Hotplug add of a CPU. Scan through all active processes and add
1246
+ * that CPU to the list of CPUs supplied with ioctl(..., START, ...).
1247
+ */
1185
1248
int cfset_online_cpu (unsigned int cpu )
1186
1249
{
1187
1250
struct cfset_call_on_cpu_parm p ;
1251
+ struct cfset_request * rp ;
1188
1252
1189
1253
mutex_lock (& cfset_ctrset_mutex );
1190
- if (cfset_request .ctrset ) {
1191
- p .sets = cfset_request .ctrset ;
1192
- cfset_ioctl_on (& p );
1193
- cpumask_set_cpu (cpu , & cfset_request .mask );
1254
+ if (!list_empty (& cfset_session .head )) {
1255
+ list_for_each_entry (rp , & cfset_session .head , node ) {
1256
+ p .sets = rp -> ctrset ;
1257
+ cfset_ioctl_on (& p );
1258
+ cpumask_set_cpu (cpu , & rp -> mask );
1259
+ }
1194
1260
}
1195
1261
mutex_unlock (& cfset_ctrset_mutex );
1196
1262
return 0 ;
1197
1263
}
1198
1264
1265
+ /* Hotplug remove of a CPU. Scan through all active processes and clear
1266
+ * that CPU from the list of CPUs supplied with ioctl(..., START, ...).
1267
+ */
1199
1268
int cfset_offline_cpu (unsigned int cpu )
1200
1269
{
1201
1270
struct cfset_call_on_cpu_parm p ;
1271
+ struct cfset_request * rp ;
1202
1272
1203
1273
mutex_lock (& cfset_ctrset_mutex );
1204
- if (cfset_request .ctrset ) {
1205
- p .sets = cfset_request .ctrset ;
1206
- cfset_ioctl_off (& p );
1207
- cpumask_clear_cpu (cpu , & cfset_request .mask );
1274
+ if (!list_empty (& cfset_session .head )) {
1275
+ list_for_each_entry (rp , & cfset_session .head , node ) {
1276
+ p .sets = rp -> ctrset ;
1277
+ cfset_ioctl_off (& p );
1278
+ cpumask_clear_cpu (cpu , & rp -> mask );
1279
+ }
1208
1280
}
1209
1281
mutex_unlock (& cfset_ctrset_mutex );
1210
1282
return 0 ;
0 commit comments