diff options
-rw-r--r-- | net/Kconfig | 2 | ||||
-rw-r--r-- | net/core/drop_monitor.c | 46 |
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 | ||
298 | config NET_DROP_MONITOR | 298 | config 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 | ||
428 | late_initcall(init_net_drop_monitor); | 438 | static 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 | |||
466 | module_init(init_net_drop_monitor); | ||
467 | module_exit(exit_net_drop_monitor); | ||
468 | |||
469 | MODULE_LICENSE("GPL v2"); | ||
470 | MODULE_AUTHOR("Neil Horman <nhorman@tuxdriver.com>"); | ||