aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/Kconfig2
-rw-r--r--net/core/drop_monitor.c46
2 files changed, 45 insertions, 3 deletions
diff --git a/net/Kconfig b/net/Kconfig
index 4c06c7c513a4..da1282359303 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -296,7 +296,7 @@ config NET_TCPPROBE
296 module will be called tcp_probe. 296 module will be called tcp_probe.
297 297
298config NET_DROP_MONITOR 298config NET_DROP_MONITOR
299 boolean "Network packet drop alerting service" 299 tristate "Network packet drop alerting service"
300 depends on INET && EXPERIMENTAL && TRACEPOINTS 300 depends on INET && EXPERIMENTAL && TRACEPOINTS
301 ---help--- 301 ---help---
302 This feature provides an alerting service to userspace in the 302 This feature provides an alerting service to userspace in the
diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c
index eca00a96bcf3..3252e7e0a005 100644
--- a/net/core/drop_monitor.c
+++ b/net/core/drop_monitor.c
@@ -24,6 +24,7 @@
24#include <linux/timer.h> 24#include <linux/timer.h>
25#include <linux/bitops.h> 25#include <linux/bitops.h>
26#include <linux/slab.h> 26#include <linux/slab.h>
27#include <linux/module.h>
27#include <net/genetlink.h> 28#include <net/genetlink.h>
28#include <net/netevent.h> 29#include <net/netevent.h>
29 30
@@ -263,9 +264,15 @@ static int set_all_monitor_traces(int state)
263 264
264 switch (state) { 265 switch (state) {
265 case TRACE_ON: 266 case TRACE_ON:
267 if (!try_module_get(THIS_MODULE)) {
268 rc = -ENODEV;
269 break;
270 }
271
266 rc |= register_trace_kfree_skb(trace_kfree_skb_hit, NULL); 272 rc |= register_trace_kfree_skb(trace_kfree_skb_hit, NULL);
267 rc |= register_trace_napi_poll(trace_napi_poll_hit, NULL); 273 rc |= register_trace_napi_poll(trace_napi_poll_hit, NULL);
268 break; 274 break;
275
269 case TRACE_OFF: 276 case TRACE_OFF:
270 rc |= unregister_trace_kfree_skb(trace_kfree_skb_hit, NULL); 277 rc |= unregister_trace_kfree_skb(trace_kfree_skb_hit, NULL);
271 rc |= unregister_trace_napi_poll(trace_napi_poll_hit, NULL); 278 rc |= unregister_trace_napi_poll(trace_napi_poll_hit, NULL);
@@ -281,6 +288,9 @@ static int set_all_monitor_traces(int state)
281 kfree_rcu(new_stat, rcu); 288 kfree_rcu(new_stat, rcu);
282 } 289 }
283 } 290 }
291
292 module_put(THIS_MODULE);
293
284 break; 294 break;
285 default: 295 default:
286 rc = 1; 296 rc = 1;
@@ -406,7 +416,7 @@ static int __init init_net_drop_monitor(void)
406 416
407 rc = 0; 417 rc = 0;
408 418
409 for_each_present_cpu(cpu) { 419 for_each_possible_cpu(cpu) {
410 data = &per_cpu(dm_cpu_data, cpu); 420 data = &per_cpu(dm_cpu_data, cpu);
411 data->cpu = cpu; 421 data->cpu = cpu;
412 INIT_WORK(&data->dm_alert_work, send_dm_alert); 422 INIT_WORK(&data->dm_alert_work, send_dm_alert);
@@ -425,4 +435,36 @@ out:
425 return rc; 435 return rc;
426} 436}
427 437
428late_initcall(init_net_drop_monitor); 438static void exit_net_drop_monitor(void)
439{
440 struct per_cpu_dm_data *data;
441 int cpu;
442
443 BUG_ON(unregister_netdevice_notifier(&dropmon_net_notifier));
444
445 /*
446 * Because of the module_get/put we do in the trace state change path
447 * we are guarnateed not to have any current users when we get here
448 * all we need to do is make sure that we don't have any running timers
449 * or pending schedule calls
450 */
451
452 for_each_possible_cpu(cpu) {
453 data = &per_cpu(dm_cpu_data, cpu);
454 del_timer_sync(&data->send_timer);
455 cancel_work_sync(&data->dm_alert_work);
456 /*
457 * At this point, we should have exclusive access
458 * to this struct and can free the skb inside it
459 */
460 kfree_skb(data->skb);
461 }
462
463 BUG_ON(genl_unregister_family(&net_drop_monitor_family));
464}
465
466module_init(init_net_drop_monitor);
467module_exit(exit_net_drop_monitor);
468
469MODULE_LICENSE("GPL v2");
470MODULE_AUTHOR("Neil Horman <nhorman@tuxdriver.com>");