diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2010-11-21 13:26:44 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-11-21 13:26:44 -0500 |
commit | 551eaff1b384cc107eab6332ba8424b3ca1f304b (patch) | |
tree | 02c90fa7a5ea2f6ebdf34004ae20f9c403e5820c /net/core/pktgen.c | |
parent | 20a95a2169d1cd3da50cf65ba882d0e27a4a2d4f (diff) |
pktgen: allow faster module unload
Unloading pktgen module needs ~6 seconds on a 64 cpus machine, to stop
64 kthreads.
Add a pktgen_exiting variable to let kernel threads die faster, so that
kthread_stop() doesnt have to wait too long for them. This variable is
not tested in fast path.
Note : Before exiting from pktgen_thread_worker(), we must make sure
kthread_stop() is waiting for this thread to be stopped, like its done
in kernel/softirq.c
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core/pktgen.c')
-rw-r--r-- | net/core/pktgen.c | 17 |
1 files changed, 12 insertions, 5 deletions
diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 52fc1e08a7c4..2e57830cbeb2 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c | |||
@@ -395,6 +395,8 @@ struct pktgen_hdr { | |||
395 | __be32 tv_usec; | 395 | __be32 tv_usec; |
396 | }; | 396 | }; |
397 | 397 | ||
398 | static bool pktgen_exiting __read_mostly; | ||
399 | |||
398 | struct pktgen_thread { | 400 | struct pktgen_thread { |
399 | spinlock_t if_lock; /* for list of devices */ | 401 | spinlock_t if_lock; /* for list of devices */ |
400 | struct list_head if_list; /* All device here */ | 402 | struct list_head if_list; /* All device here */ |
@@ -3451,11 +3453,6 @@ static void pktgen_rem_thread(struct pktgen_thread *t) | |||
3451 | 3453 | ||
3452 | remove_proc_entry(t->tsk->comm, pg_proc_dir); | 3454 | remove_proc_entry(t->tsk->comm, pg_proc_dir); |
3453 | 3455 | ||
3454 | mutex_lock(&pktgen_thread_lock); | ||
3455 | |||
3456 | list_del(&t->th_list); | ||
3457 | |||
3458 | mutex_unlock(&pktgen_thread_lock); | ||
3459 | } | 3456 | } |
3460 | 3457 | ||
3461 | static void pktgen_resched(struct pktgen_dev *pkt_dev) | 3458 | static void pktgen_resched(struct pktgen_dev *pkt_dev) |
@@ -3602,6 +3599,8 @@ static int pktgen_thread_worker(void *arg) | |||
3602 | pkt_dev = next_to_run(t); | 3599 | pkt_dev = next_to_run(t); |
3603 | 3600 | ||
3604 | if (unlikely(!pkt_dev && t->control == 0)) { | 3601 | if (unlikely(!pkt_dev && t->control == 0)) { |
3602 | if (pktgen_exiting) | ||
3603 | break; | ||
3605 | wait_event_interruptible_timeout(t->queue, | 3604 | wait_event_interruptible_timeout(t->queue, |
3606 | t->control != 0, | 3605 | t->control != 0, |
3607 | HZ/10); | 3606 | HZ/10); |
@@ -3654,6 +3653,13 @@ static int pktgen_thread_worker(void *arg) | |||
3654 | pr_debug("%s removing thread\n", t->tsk->comm); | 3653 | pr_debug("%s removing thread\n", t->tsk->comm); |
3655 | pktgen_rem_thread(t); | 3654 | pktgen_rem_thread(t); |
3656 | 3655 | ||
3656 | /* Wait for kthread_stop */ | ||
3657 | while (!kthread_should_stop()) { | ||
3658 | set_current_state(TASK_INTERRUPTIBLE); | ||
3659 | schedule(); | ||
3660 | } | ||
3661 | __set_current_state(TASK_RUNNING); | ||
3662 | |||
3657 | return 0; | 3663 | return 0; |
3658 | } | 3664 | } |
3659 | 3665 | ||
@@ -3928,6 +3934,7 @@ static void __exit pg_cleanup(void) | |||
3928 | struct list_head *q, *n; | 3934 | struct list_head *q, *n; |
3929 | 3935 | ||
3930 | /* Stop all interfaces & threads */ | 3936 | /* Stop all interfaces & threads */ |
3937 | pktgen_exiting = true; | ||
3931 | 3938 | ||
3932 | list_for_each_safe(q, n, &pktgen_threads) { | 3939 | list_for_each_safe(q, n, &pktgen_threads) { |
3933 | t = list_entry(q, struct pktgen_thread, th_list); | 3940 | t = list_entry(q, struct pktgen_thread, th_list); |