36
36
#include <linux/inet.h>
37
37
#include <linux/configfs.h>
38
38
#include <linux/etherdevice.h>
39
+ #include <linux/u64_stats_sync.h>
39
40
#include <linux/utsname.h>
40
41
#include <linux/rtnetlink.h>
41
42
@@ -90,13 +91,20 @@ static DEFINE_MUTEX(target_cleanup_list_lock);
90
91
*/
91
92
static struct console netconsole_ext ;
92
93
94
+ struct netconsole_target_stats {
95
+ u64_stats_t xmit_drop_count ;
96
+ u64_stats_t enomem_count ;
97
+ struct u64_stats_sync syncp ;
98
+ };
99
+
93
100
/**
94
101
* struct netconsole_target - Represents a configured netconsole target.
95
102
* @list: Links this target into the target_list.
96
103
* @group: Links us into the configfs subsystem hierarchy.
97
104
* @userdata_group: Links to the userdata configfs hierarchy
98
105
* @userdata_complete: Cached, formatted string of append
99
106
* @userdata_length: String length of userdata_complete
107
+ * @stats: Packet send stats for the target. Used for debugging.
100
108
* @enabled: On / off knob to enable / disable target.
101
109
* Visible from userspace (read-write).
102
110
* We maintain a strict 1:1 correspondence between this and
@@ -124,6 +132,7 @@ struct netconsole_target {
124
132
char userdata_complete [MAX_USERDATA_ENTRY_LENGTH * MAX_USERDATA_ITEMS ];
125
133
size_t userdata_length ;
126
134
#endif
135
+ struct netconsole_target_stats stats ;
127
136
bool enabled ;
128
137
bool extended ;
129
138
bool release ;
@@ -262,6 +271,7 @@ static void netconsole_process_cleanups_core(void)
262
271
* | remote_ip
263
272
* | local_mac
264
273
* | remote_mac
274
+ * | transmit_errors
265
275
* | userdata/
266
276
* | <key>/
267
277
* | value
@@ -371,6 +381,21 @@ static ssize_t remote_mac_show(struct config_item *item, char *buf)
371
381
return sysfs_emit (buf , "%pM\n" , to_target (item )-> np .remote_mac );
372
382
}
373
383
384
+ static ssize_t transmit_errors_show (struct config_item * item , char * buf )
385
+ {
386
+ struct netconsole_target * nt = to_target (item );
387
+ u64 xmit_drop_count , enomem_count ;
388
+ unsigned int start ;
389
+
390
+ do {
391
+ start = u64_stats_fetch_begin (& nt -> stats .syncp );
392
+ xmit_drop_count = u64_stats_read (& nt -> stats .xmit_drop_count );
393
+ enomem_count = u64_stats_read (& nt -> stats .enomem_count );
394
+ } while (u64_stats_fetch_retry (& nt -> stats .syncp , start ));
395
+
396
+ return sysfs_emit (buf , "%llu\n" , xmit_drop_count + enomem_count );
397
+ }
398
+
374
399
/*
375
400
* This one is special -- targets created through the configfs interface
376
401
* are not enabled (and the corresponding netpoll activated) by default.
@@ -842,6 +867,7 @@ CONFIGFS_ATTR(, remote_ip);
842
867
CONFIGFS_ATTR_RO (, local_mac );
843
868
CONFIGFS_ATTR (, remote_mac );
844
869
CONFIGFS_ATTR (, release );
870
+ CONFIGFS_ATTR_RO (, transmit_errors );
845
871
846
872
static struct configfs_attribute * netconsole_target_attrs [] = {
847
873
& attr_enabled ,
@@ -854,6 +880,7 @@ static struct configfs_attribute *netconsole_target_attrs[] = {
854
880
& attr_remote_ip ,
855
881
& attr_local_mac ,
856
882
& attr_remote_mac ,
883
+ & attr_transmit_errors ,
857
884
NULL ,
858
885
};
859
886
@@ -1058,6 +1085,33 @@ static struct notifier_block netconsole_netdev_notifier = {
1058
1085
.notifier_call = netconsole_netdev_event ,
1059
1086
};
1060
1087
1088
+ /**
1089
+ * send_udp - Wrapper for netpoll_send_udp that counts errors
1090
+ * @nt: target to send message to
1091
+ * @msg: message to send
1092
+ * @len: length of message
1093
+ *
1094
+ * Calls netpoll_send_udp and classifies the return value. If an error
1095
+ * occurred it increments statistics in nt->stats accordingly.
1096
+ * Only calls netpoll_send_udp if CONFIG_NETCONSOLE_DYNAMIC is disabled.
1097
+ */
1098
+ static void send_udp (struct netconsole_target * nt , const char * msg , int len )
1099
+ {
1100
+ int result = netpoll_send_udp (& nt -> np , msg , len );
1101
+
1102
+ if (IS_ENABLED (CONFIG_NETCONSOLE_DYNAMIC )) {
1103
+ if (result == NET_XMIT_DROP ) {
1104
+ u64_stats_update_begin (& nt -> stats .syncp );
1105
+ u64_stats_inc (& nt -> stats .xmit_drop_count );
1106
+ u64_stats_update_end (& nt -> stats .syncp );
1107
+ } else if (result == - ENOMEM ) {
1108
+ u64_stats_update_begin (& nt -> stats .syncp );
1109
+ u64_stats_inc (& nt -> stats .enomem_count );
1110
+ u64_stats_update_end (& nt -> stats .syncp );
1111
+ }
1112
+ }
1113
+ }
1114
+
1061
1115
static void send_msg_no_fragmentation (struct netconsole_target * nt ,
1062
1116
const char * msg ,
1063
1117
int msg_len ,
@@ -1085,7 +1139,7 @@ static void send_msg_no_fragmentation(struct netconsole_target *nt,
1085
1139
MAX_PRINT_CHUNK - msg_len ,
1086
1140
"%s" , userdata );
1087
1141
1088
- netpoll_send_udp ( & nt -> np , buf , msg_len );
1142
+ send_udp ( nt , buf , msg_len );
1089
1143
}
1090
1144
1091
1145
static void append_release (char * buf )
@@ -1178,7 +1232,7 @@ static void send_fragmented_body(struct netconsole_target *nt, char *buf,
1178
1232
this_offset += this_chunk ;
1179
1233
}
1180
1234
1181
- netpoll_send_udp ( & nt -> np , buf , this_header + this_offset );
1235
+ send_udp ( nt , buf , this_header + this_offset );
1182
1236
offset += this_offset ;
1183
1237
}
1184
1238
}
@@ -1288,7 +1342,7 @@ static void write_msg(struct console *con, const char *msg, unsigned int len)
1288
1342
tmp = msg ;
1289
1343
for (left = len ; left ;) {
1290
1344
frag = min (left , MAX_PRINT_CHUNK );
1291
- netpoll_send_udp ( & nt -> np , tmp , frag );
1345
+ send_udp ( nt , tmp , frag );
1292
1346
tmp += frag ;
1293
1347
left -= frag ;
1294
1348
}
0 commit comments