Commit ee74baa7 authored by David S. Miller's avatar David S. Miller

[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: default avatarDavid S. Miller <davem@davemloft.net>
parent 3136dcb3
...@@ -148,6 +148,7 @@ ...@@ -148,6 +148,7 @@
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/kthread.h>
#include <net/checksum.h> #include <net/checksum.h>
#include <net/ipv6.h> #include <net/ipv6.h>
#include <net/addrconf.h> #include <net/addrconf.h>
...@@ -360,8 +361,7 @@ struct pktgen_thread { ...@@ -360,8 +361,7 @@ struct pktgen_thread {
spinlock_t if_lock; spinlock_t if_lock;
struct list_head if_list; /* All device here */ struct list_head if_list; /* All device here */
struct list_head th_list; struct list_head th_list;
int removed; struct task_struct *tsk;
char name[32];
char result[512]; char result[512];
u32 max_before_softirq; /* We'll call do_softirq to prevent starvation. */ u32 max_before_softirq; /* We'll call do_softirq to prevent starvation. */
...@@ -1689,7 +1689,7 @@ static int pktgen_thread_show(struct seq_file *seq, void *v) ...@@ -1689,7 +1689,7 @@ static int pktgen_thread_show(struct seq_file *seq, void *v)
BUG_ON(!t); BUG_ON(!t);
seq_printf(seq, "Name: %s max_before_softirq: %d\n", seq_printf(seq, "Name: %s max_before_softirq: %d\n",
t->name, t->max_before_softirq); t->tsk->comm, t->max_before_softirq);
seq_printf(seq, "Running: "); seq_printf(seq, "Running: ");
...@@ -3112,7 +3112,7 @@ static void pktgen_rem_thread(struct pktgen_thread *t) ...@@ -3112,7 +3112,7 @@ static void pktgen_rem_thread(struct pktgen_thread *t)
{ {
/* Remove from the thread list */ /* Remove from the thread list */
remove_proc_entry(t->name, pg_proc_dir); remove_proc_entry(t->tsk->comm, pg_proc_dir);
mutex_lock(&pktgen_thread_lock); mutex_lock(&pktgen_thread_lock);
...@@ -3260,58 +3260,40 @@ out:; ...@@ -3260,58 +3260,40 @@ out:;
* Main loop of the thread goes here * Main loop of the thread goes here
*/ */
static void pktgen_thread_worker(struct pktgen_thread *t) static int pktgen_thread_worker(void *arg)
{ {
DEFINE_WAIT(wait); DEFINE_WAIT(wait);
struct pktgen_thread *t = arg;
struct pktgen_dev *pkt_dev = NULL; struct pktgen_dev *pkt_dev = NULL;
int cpu = t->cpu; int cpu = t->cpu;
sigset_t tmpsig;
u32 max_before_softirq; u32 max_before_softirq;
u32 tx_since_softirq = 0; u32 tx_since_softirq = 0;
daemonize("pktgen/%d", cpu); BUG_ON(smp_processor_id() != cpu);
/* Block all signals except SIGKILL, SIGSTOP and SIGTERM */
spin_lock_irq(&current->sighand->siglock);
tmpsig = current->blocked;
siginitsetinv(&current->blocked,
sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGTERM));
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
/* Migrate to the right CPU */
set_cpus_allowed(current, cpumask_of_cpu(cpu));
if (smp_processor_id() != cpu)
BUG();
init_waitqueue_head(&t->queue); init_waitqueue_head(&t->queue);
t->control &= ~(T_TERMINATE);
t->control &= ~(T_RUN);
t->control &= ~(T_STOP);
t->control &= ~(T_REMDEVALL);
t->control &= ~(T_REMDEV);
t->pid = current->pid; t->pid = current->pid;
PG_DEBUG(printk("pktgen: starting pktgen/%d: pid=%d\n", cpu, current->pid)); PG_DEBUG(printk("pktgen: starting pktgen/%d: pid=%d\n", cpu, current->pid));
max_before_softirq = t->max_before_softirq; max_before_softirq = t->max_before_softirq;
__set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
mb();
while (1) { while (!kthread_should_stop()) {
pkt_dev = next_to_run(t);
__set_current_state(TASK_RUNNING);
/* if (!pkt_dev &&
* Get next dev to xmit -- if any. (t->control & (T_STOP | T_RUN | T_REMDEVALL | T_REMDEV))
*/ == 0) {
prepare_to_wait(&(t->queue), &wait,
TASK_INTERRUPTIBLE);
schedule_timeout(HZ / 10);
finish_wait(&(t->queue), &wait);
}
pkt_dev = next_to_run(t); __set_current_state(TASK_RUNNING);
if (pkt_dev) { if (pkt_dev) {
...@@ -3329,21 +3311,8 @@ static void pktgen_thread_worker(struct pktgen_thread *t) ...@@ -3329,21 +3311,8 @@ static void pktgen_thread_worker(struct pktgen_thread *t)
do_softirq(); do_softirq();
tx_since_softirq = 0; tx_since_softirq = 0;
} }
} else {
prepare_to_wait(&(t->queue), &wait, TASK_INTERRUPTIBLE);
schedule_timeout(HZ / 10);
finish_wait(&(t->queue), &wait);
} }
/*
* Back from sleep, either due to the timeout or signal.
* We check if we have any "posted" work for us.
*/
if (t->control & T_TERMINATE || signal_pending(current))
/* we received a request to terminate ourself */
break;
if (t->control & T_STOP) { if (t->control & T_STOP) {
pktgen_stop(t); pktgen_stop(t);
t->control &= ~(T_STOP); t->control &= ~(T_STOP);
...@@ -3364,20 +3333,19 @@ static void pktgen_thread_worker(struct pktgen_thread *t) ...@@ -3364,20 +3333,19 @@ static void pktgen_thread_worker(struct pktgen_thread *t)
t->control &= ~(T_REMDEV); t->control &= ~(T_REMDEV);
} }
if (need_resched()) set_current_state(TASK_INTERRUPTIBLE);
schedule();
} }
PG_DEBUG(printk("pktgen: %s stopping all device\n", t->name)); PG_DEBUG(printk("pktgen: %s stopping all device\n", t->tsk->comm));
pktgen_stop(t); pktgen_stop(t);
PG_DEBUG(printk("pktgen: %s removing all device\n", t->name)); PG_DEBUG(printk("pktgen: %s removing all device\n", t->tsk->comm));
pktgen_rem_all_ifs(t); pktgen_rem_all_ifs(t);
PG_DEBUG(printk("pktgen: %s removing thread.\n", t->name)); PG_DEBUG(printk("pktgen: %s removing thread.\n", t->tsk->comm));
pktgen_rem_thread(t); pktgen_rem_thread(t);
t->removed = 1; return 0;
} }
static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, static 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,37 +3463,11 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
return add_dev_to_thread(t, pkt_dev); return add_dev_to_thread(t, pkt_dev);
} }
static struct pktgen_thread *__init pktgen_find_thread(const char *name) static int __init pktgen_create_thread(int cpu)
{ {
struct pktgen_thread *t; struct pktgen_thread *t;
mutex_lock(&pktgen_thread_lock);
list_for_each_entry(t, &pktgen_threads, th_list)
if (strcmp(t->name, name) == 0) {
mutex_unlock(&pktgen_thread_lock);
return t;
}
mutex_unlock(&pktgen_thread_lock);
return NULL;
}
static int __init pktgen_create_thread(const char *name, int cpu)
{
int err;
struct pktgen_thread *t = NULL;
struct proc_dir_entry *pe; struct proc_dir_entry *pe;
struct task_struct *p;
if (strlen(name) > 31) {
printk("pktgen: ERROR: Thread name cannot be more than 31 characters.\n");
return -EINVAL;
}
if (pktgen_find_thread(name)) {
printk("pktgen: ERROR: thread: %s already exists\n", name);
return -EINVAL;
}
t = kzalloc(sizeof(struct pktgen_thread), GFP_KERNEL); t = kzalloc(sizeof(struct pktgen_thread), GFP_KERNEL);
if (!t) { if (!t) {
...@@ -3533,14 +3475,29 @@ static int __init pktgen_create_thread(const char *name, int cpu) ...@@ -3533,14 +3475,29 @@ static int __init pktgen_create_thread(const char *name, int cpu)
return -ENOMEM; return -ENOMEM;
} }
strcpy(t->name, name);
spin_lock_init(&t->if_lock); spin_lock_init(&t->if_lock);
t->cpu = cpu; t->cpu = cpu;
pe = create_proc_entry(t->name, 0600, pg_proc_dir); INIT_LIST_HEAD(&t->if_list);
list_add_tail(&t->th_list, &pktgen_threads);
p = kthread_create(pktgen_thread_worker, t, "kpktgend_%d", cpu);
if (IS_ERR(p)) {
printk("pktgen: kernel_thread() failed for cpu %d\n", t->cpu);
list_del(&t->th_list);
kfree(t);
return PTR_ERR(p);
}
kthread_bind(p, cpu);
t->tsk = p;
pe = create_proc_entry(t->tsk->comm, 0600, pg_proc_dir);
if (!pe) { if (!pe) {
printk("pktgen: cannot create %s/%s procfs entry.\n", printk("pktgen: cannot create %s/%s procfs entry.\n",
PG_PROC_DIR, t->name); PG_PROC_DIR, t->tsk->comm);
kthread_stop(p);
list_del(&t->th_list);
kfree(t); kfree(t);
return -EINVAL; return -EINVAL;
} }
...@@ -3548,21 +3505,7 @@ static int __init pktgen_create_thread(const char *name, int cpu) ...@@ -3548,21 +3505,7 @@ static int __init pktgen_create_thread(const char *name, int cpu)
pe->proc_fops = &pktgen_thread_fops; pe->proc_fops = &pktgen_thread_fops;
pe->data = t; pe->data = t;
INIT_LIST_HEAD(&t->if_list); wake_up_process(p);
list_add_tail(&t->th_list, &pktgen_threads);
t->removed = 0;
err = kernel_thread((void *)pktgen_thread_worker, (void *)t,
CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
if (err < 0) {
printk("pktgen: kernel_thread() failed for cpu %d\n", t->cpu);
remove_proc_entry(t->name, pg_proc_dir);
list_del(&t->th_list);
kfree(t);
return err;
}
return 0; return 0;
} }
...@@ -3643,10 +3586,8 @@ static int __init pg_init(void) ...@@ -3643,10 +3586,8 @@ static int __init pg_init(void)
for_each_online_cpu(cpu) { for_each_online_cpu(cpu) {
int err; int err;
char buf[30];
sprintf(buf, "kpktgend_%i", cpu); err = pktgen_create_thread(cpu);
err = pktgen_create_thread(buf, cpu);
if (err) if (err)
printk("pktgen: WARNING: Cannot create thread for cpu %d (%d)\n", printk("pktgen: WARNING: Cannot create thread for cpu %d (%d)\n",
cpu, err); cpu, err);
...@@ -3674,9 +3615,8 @@ static void __exit pg_cleanup(void) ...@@ -3674,9 +3615,8 @@ static void __exit pg_cleanup(void)
list_for_each_safe(q, n, &pktgen_threads) { list_for_each_safe(q, n, &pktgen_threads) {
t = list_entry(q, struct pktgen_thread, th_list); t = list_entry(q, struct pktgen_thread, th_list);
t->control |= (T_TERMINATE); kthread_stop(t->tsk);
kfree(t);
wait_event_interruptible_timeout(queue, (t->removed == 1), HZ);
} }
/* Un-register us from receiving netdevice events */ /* Un-register us from receiving netdevice events */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment