aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2007-01-01 23:51:53 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2007-01-03 21:38:09 -0500
commitee74baa7d83e9e0c2fdaff8122ee9cefd06cddc5 (patch)
tree3fb7f4331b3b60b933f1255bd43043cc83a20971 /net
parent3136dcb3cd6e5b4ed4bd34d422f8cdeec4da6836 (diff)
[PKTGEN]: Convert to kthread API.
Based upon a suggestion from Christoph Hellwig. This fixes various races in module load/unload handling too. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/core/pktgen.c156
1 files changed, 48 insertions, 108 deletions
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index 1897a3a385d8..04d4b93c68eb 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -148,6 +148,7 @@
148#include <linux/seq_file.h> 148#include <linux/seq_file.h>
149#include <linux/wait.h> 149#include <linux/wait.h>
150#include <linux/etherdevice.h> 150#include <linux/etherdevice.h>
151#include <linux/kthread.h>
151#include <net/checksum.h> 152#include <net/checksum.h>
152#include <net/ipv6.h> 153#include <net/ipv6.h>
153#include <net/addrconf.h> 154#include <net/addrconf.h>
@@ -360,8 +361,7 @@ struct pktgen_thread {
360 spinlock_t if_lock; 361 spinlock_t if_lock;
361 struct list_head if_list; /* All device here */ 362 struct list_head if_list; /* All device here */
362 struct list_head th_list; 363 struct list_head th_list;
363 int removed; 364 struct task_struct *tsk;
364 char name[32];
365 char result[512]; 365 char result[512];
366 u32 max_before_softirq; /* We'll call do_softirq to prevent starvation. */ 366 u32 max_before_softirq; /* We'll call do_softirq to prevent starvation. */
367 367
@@ -1689,7 +1689,7 @@ static int pktgen_thread_show(struct seq_file *seq, void *v)
1689 BUG_ON(!t); 1689 BUG_ON(!t);
1690 1690
1691 seq_printf(seq, "Name: %s max_before_softirq: %d\n", 1691 seq_printf(seq, "Name: %s max_before_softirq: %d\n",
1692 t->name, t->max_before_softirq); 1692 t->tsk->comm, t->max_before_softirq);
1693 1693
1694 seq_printf(seq, "Running: "); 1694 seq_printf(seq, "Running: ");
1695 1695
@@ -3112,7 +3112,7 @@ static void pktgen_rem_thread(struct pktgen_thread *t)
3112{ 3112{
3113 /* Remove from the thread list */ 3113 /* Remove from the thread list */
3114 3114
3115 remove_proc_entry(t->name, pg_proc_dir); 3115 remove_proc_entry(t->tsk->comm, pg_proc_dir);
3116 3116
3117 mutex_lock(&pktgen_thread_lock); 3117 mutex_lock(&pktgen_thread_lock);
3118 3118
@@ -3260,58 +3260,40 @@ out:;
3260 * Main loop of the thread goes here 3260 * Main loop of the thread goes here
3261 */ 3261 */
3262 3262
3263static void pktgen_thread_worker(struct pktgen_thread *t) 3263static int pktgen_thread_worker(void *arg)
3264{ 3264{
3265 DEFINE_WAIT(wait); 3265 DEFINE_WAIT(wait);
3266 struct pktgen_thread *t = arg;
3266 struct pktgen_dev *pkt_dev = NULL; 3267 struct pktgen_dev *pkt_dev = NULL;
3267 int cpu = t->cpu; 3268 int cpu = t->cpu;
3268 sigset_t tmpsig;
3269 u32 max_before_softirq; 3269 u32 max_before_softirq;
3270 u32 tx_since_softirq = 0; 3270 u32 tx_since_softirq = 0;
3271 3271
3272 daemonize("pktgen/%d", cpu); 3272 BUG_ON(smp_processor_id() != cpu);
3273
3274 /* Block all signals except SIGKILL, SIGSTOP and SIGTERM */
3275
3276 spin_lock_irq(&current->sighand->siglock);
3277 tmpsig = current->blocked;
3278 siginitsetinv(&current->blocked,
3279 sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGTERM));
3280
3281 recalc_sigpending();
3282 spin_unlock_irq(&current->sighand->siglock);
3283
3284 /* Migrate to the right CPU */
3285 set_cpus_allowed(current, cpumask_of_cpu(cpu));
3286 if (smp_processor_id() != cpu)
3287 BUG();
3288 3273
3289 init_waitqueue_head(&t->queue); 3274 init_waitqueue_head(&t->queue);
3290 3275
3291 t->control &= ~(T_TERMINATE);
3292 t->control &= ~(T_RUN);
3293 t->control &= ~(T_STOP);
3294 t->control &= ~(T_REMDEVALL);
3295 t->control &= ~(T_REMDEV);
3296
3297 t->pid = current->pid; 3276 t->pid = current->pid;
3298 3277
3299 PG_DEBUG(printk("pktgen: starting pktgen/%d: pid=%d\n", cpu, current->pid)); 3278 PG_DEBUG(printk("pktgen: starting pktgen/%d: pid=%d\n", cpu, current->pid));
3300 3279
3301 max_before_softirq = t->max_before_softirq; 3280 max_before_softirq = t->max_before_softirq;
3302 3281
3303 __set_current_state(TASK_INTERRUPTIBLE); 3282 set_current_state(TASK_INTERRUPTIBLE);
3304 mb();
3305 3283
3306 while (1) { 3284 while (!kthread_should_stop()) {
3307 3285 pkt_dev = next_to_run(t);
3308 __set_current_state(TASK_RUNNING);
3309 3286
3310 /* 3287 if (!pkt_dev &&
3311 * Get next dev to xmit -- if any. 3288 (t->control & (T_STOP | T_RUN | T_REMDEVALL | T_REMDEV))
3312 */ 3289 == 0) {
3290 prepare_to_wait(&(t->queue), &wait,
3291 TASK_INTERRUPTIBLE);
3292 schedule_timeout(HZ / 10);
3293 finish_wait(&(t->queue), &wait);
3294 }
3313 3295
3314 pkt_dev = next_to_run(t); 3296 __set_current_state(TASK_RUNNING);
3315 3297
3316 if (pkt_dev) { 3298 if (pkt_dev) {
3317 3299
@@ -3329,21 +3311,8 @@ static void pktgen_thread_worker(struct pktgen_thread *t)
3329 do_softirq(); 3311 do_softirq();
3330 tx_since_softirq = 0; 3312 tx_since_softirq = 0;
3331 } 3313 }
3332 } else {
3333 prepare_to_wait(&(t->queue), &wait, TASK_INTERRUPTIBLE);
3334 schedule_timeout(HZ / 10);
3335 finish_wait(&(t->queue), &wait);
3336 } 3314 }
3337 3315
3338 /*
3339 * Back from sleep, either due to the timeout or signal.
3340 * We check if we have any "posted" work for us.
3341 */
3342
3343 if (t->control & T_TERMINATE || signal_pending(current))
3344 /* we received a request to terminate ourself */
3345 break;
3346
3347 if (t->control & T_STOP) { 3316 if (t->control & T_STOP) {
3348 pktgen_stop(t); 3317 pktgen_stop(t);
3349 t->control &= ~(T_STOP); 3318 t->control &= ~(T_STOP);
@@ -3364,20 +3333,19 @@ static void pktgen_thread_worker(struct pktgen_thread *t)
3364 t->control &= ~(T_REMDEV); 3333 t->control &= ~(T_REMDEV);
3365 } 3334 }
3366 3335
3367 if (need_resched()) 3336 set_current_state(TASK_INTERRUPTIBLE);
3368 schedule();
3369 } 3337 }
3370 3338
3371 PG_DEBUG(printk("pktgen: %s stopping all device\n", t->name)); 3339 PG_DEBUG(printk("pktgen: %s stopping all device\n", t->tsk->comm));
3372 pktgen_stop(t); 3340 pktgen_stop(t);
3373 3341
3374 PG_DEBUG(printk("pktgen: %s removing all device\n", t->name)); 3342 PG_DEBUG(printk("pktgen: %s removing all device\n", t->tsk->comm));
3375 pktgen_rem_all_ifs(t); 3343 pktgen_rem_all_ifs(t);
3376 3344
3377 PG_DEBUG(printk("pktgen: %s removing thread.\n", t->name)); 3345 PG_DEBUG(printk("pktgen: %s removing thread.\n", t->tsk->comm));
3378 pktgen_rem_thread(t); 3346 pktgen_rem_thread(t);
3379 3347
3380 t->removed = 1; 3348 return 0;
3381} 3349}
3382 3350
3383static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, 3351static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t,
@@ -3495,37 +3463,11 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
3495 return add_dev_to_thread(t, pkt_dev); 3463 return add_dev_to_thread(t, pkt_dev);
3496} 3464}
3497 3465
3498static struct pktgen_thread *__init pktgen_find_thread(const char *name) 3466static int __init pktgen_create_thread(int cpu)
3499{ 3467{
3500 struct pktgen_thread *t; 3468 struct pktgen_thread *t;
3501
3502 mutex_lock(&pktgen_thread_lock);
3503
3504 list_for_each_entry(t, &pktgen_threads, th_list)
3505 if (strcmp(t->name, name) == 0) {
3506 mutex_unlock(&pktgen_thread_lock);
3507 return t;
3508 }
3509
3510 mutex_unlock(&pktgen_thread_lock);
3511 return NULL;
3512}
3513
3514static int __init pktgen_create_thread(const char *name, int cpu)
3515{
3516 int err;
3517 struct pktgen_thread *t = NULL;
3518 struct proc_dir_entry *pe; 3469 struct proc_dir_entry *pe;
3519 3470 struct task_struct *p;
3520 if (strlen(name) > 31) {
3521 printk("pktgen: ERROR: Thread name cannot be more than 31 characters.\n");
3522 return -EINVAL;
3523 }
3524
3525 if (pktgen_find_thread(name)) {
3526 printk("pktgen: ERROR: thread: %s already exists\n", name);
3527 return -EINVAL;
3528 }
3529 3471
3530 t = kzalloc(sizeof(struct pktgen_thread), GFP_KERNEL); 3472 t = kzalloc(sizeof(struct pktgen_thread), GFP_KERNEL);
3531 if (!t) { 3473 if (!t) {
@@ -3533,14 +3475,29 @@ static int __init pktgen_create_thread(const char *name, int cpu)
3533 return -ENOMEM; 3475 return -ENOMEM;
3534 } 3476 }
3535 3477
3536 strcpy(t->name, name);
3537 spin_lock_init(&t->if_lock); 3478 spin_lock_init(&t->if_lock);
3538 t->cpu = cpu; 3479 t->cpu = cpu;
3539 3480
3540 pe = create_proc_entry(t->name, 0600, pg_proc_dir); 3481 INIT_LIST_HEAD(&t->if_list);
3482
3483 list_add_tail(&t->th_list, &pktgen_threads);
3484
3485 p = kthread_create(pktgen_thread_worker, t, "kpktgend_%d", cpu);
3486 if (IS_ERR(p)) {
3487 printk("pktgen: kernel_thread() failed for cpu %d\n", t->cpu);
3488 list_del(&t->th_list);
3489 kfree(t);
3490 return PTR_ERR(p);
3491 }
3492 kthread_bind(p, cpu);
3493 t->tsk = p;
3494
3495 pe = create_proc_entry(t->tsk->comm, 0600, pg_proc_dir);
3541 if (!pe) { 3496 if (!pe) {
3542 printk("pktgen: cannot create %s/%s procfs entry.\n", 3497 printk("pktgen: cannot create %s/%s procfs entry.\n",
3543 PG_PROC_DIR, t->name); 3498 PG_PROC_DIR, t->tsk->comm);
3499 kthread_stop(p);
3500 list_del(&t->th_list);
3544 kfree(t); 3501 kfree(t);
3545 return -EINVAL; 3502 return -EINVAL;
3546 } 3503 }
@@ -3548,21 +3505,7 @@ static int __init pktgen_create_thread(const char *name, int cpu)
3548 pe->proc_fops = &pktgen_thread_fops; 3505 pe->proc_fops = &pktgen_thread_fops;
3549 pe->data = t; 3506 pe->data = t;
3550 3507
3551 INIT_LIST_HEAD(&t->if_list); 3508 wake_up_process(p);
3552
3553 list_add_tail(&t->th_list, &pktgen_threads);
3554
3555 t->removed = 0;
3556
3557 err = kernel_thread((void *)pktgen_thread_worker, (void *)t,
3558 CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
3559 if (err < 0) {
3560 printk("pktgen: kernel_thread() failed for cpu %d\n", t->cpu);
3561 remove_proc_entry(t->name, pg_proc_dir);
3562 list_del(&t->th_list);
3563 kfree(t);
3564 return err;
3565 }
3566 3509
3567 return 0; 3510 return 0;
3568} 3511}
@@ -3643,10 +3586,8 @@ static int __init pg_init(void)
3643 3586
3644 for_each_online_cpu(cpu) { 3587 for_each_online_cpu(cpu) {
3645 int err; 3588 int err;
3646 char buf[30];
3647 3589
3648 sprintf(buf, "kpktgend_%i", cpu); 3590 err = pktgen_create_thread(cpu);
3649 err = pktgen_create_thread(buf, cpu);
3650 if (err) 3591 if (err)
3651 printk("pktgen: WARNING: Cannot create thread for cpu %d (%d)\n", 3592 printk("pktgen: WARNING: Cannot create thread for cpu %d (%d)\n",
3652 cpu, err); 3593 cpu, err);
@@ -3674,9 +3615,8 @@ static void __exit pg_cleanup(void)
3674 3615
3675 list_for_each_safe(q, n, &pktgen_threads) { 3616 list_for_each_safe(q, n, &pktgen_threads) {
3676 t = list_entry(q, struct pktgen_thread, th_list); 3617 t = list_entry(q, struct pktgen_thread, th_list);
3677 t->control |= (T_TERMINATE); 3618 kthread_stop(t->tsk);
3678 3619 kfree(t);
3679 wait_event_interruptible_timeout(queue, (t->removed == 1), HZ);
3680 } 3620 }
3681 3621
3682 /* Un-register us from receiving netdevice events */ 3622 /* Un-register us from receiving netdevice events */