aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2010-11-21 13:26:44 -0500
committerDavid S. Miller <davem@davemloft.net>2010-11-21 13:26:44 -0500
commit551eaff1b384cc107eab6332ba8424b3ca1f304b (patch)
tree02c90fa7a5ea2f6ebdf34004ae20f9c403e5820c /net
parent20a95a2169d1cd3da50cf65ba882d0e27a4a2d4f (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')
-rw-r--r--net/core/pktgen.c17
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
398static bool pktgen_exiting __read_mostly;
399
398struct pktgen_thread { 400struct 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
3461static void pktgen_resched(struct pktgen_dev *pkt_dev) 3458static 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);