|
@@ -125,6 +125,7 @@
|
|
|
#include <linux/capability.h>
|
|
|
#include <linux/delay.h>
|
|
|
#include <linux/timer.h>
|
|
|
+#include <linux/list.h>
|
|
|
#include <linux/init.h>
|
|
|
#include <linux/skbuff.h>
|
|
|
#include <linux/netdevice.h>
|
|
@@ -330,7 +331,8 @@ struct pktgen_hdr {
|
|
|
struct pktgen_thread {
|
|
|
spinlock_t if_lock;
|
|
|
struct pktgen_dev *if_list; /* All device here */
|
|
|
- struct pktgen_thread *next;
|
|
|
+ struct list_head th_list;
|
|
|
+ int removed;
|
|
|
char name[32];
|
|
|
char result[512];
|
|
|
u32 max_before_softirq; /* We'll call do_softirq to prevent starvation. */
|
|
@@ -492,7 +494,7 @@ static int pg_clone_skb_d;
|
|
|
static int debug;
|
|
|
|
|
|
static DECLARE_MUTEX(pktgen_sem);
|
|
|
-static struct pktgen_thread *pktgen_threads = NULL;
|
|
|
+static LIST_HEAD(pktgen_threads);
|
|
|
|
|
|
static struct notifier_block pktgen_notifier_block = {
|
|
|
.notifier_call = pktgen_device_event,
|
|
@@ -1522,9 +1524,7 @@ static struct pktgen_dev *__pktgen_NN_threads(const char *ifname, int remove)
|
|
|
struct pktgen_thread *t;
|
|
|
struct pktgen_dev *pkt_dev = NULL;
|
|
|
|
|
|
- t = pktgen_threads;
|
|
|
-
|
|
|
- while (t) {
|
|
|
+ list_for_each_entry(t, &pktgen_threads, th_list) {
|
|
|
pkt_dev = pktgen_find_dev(t, ifname);
|
|
|
if (pkt_dev) {
|
|
|
if (remove) {
|
|
@@ -1535,7 +1535,6 @@ static struct pktgen_dev *__pktgen_NN_threads(const char *ifname, int remove)
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
- t = t->next;
|
|
|
}
|
|
|
return pkt_dev;
|
|
|
}
|
|
@@ -2455,15 +2454,15 @@ static void pktgen_run(struct pktgen_thread *t)
|
|
|
|
|
|
static void pktgen_stop_all_threads_ifs(void)
|
|
|
{
|
|
|
- struct pktgen_thread *t = pktgen_threads;
|
|
|
+ struct pktgen_thread *t;
|
|
|
|
|
|
PG_DEBUG(printk("pktgen: entering pktgen_stop_all_threads_ifs.\n"));
|
|
|
|
|
|
thread_lock();
|
|
|
- while (t) {
|
|
|
+
|
|
|
+ list_for_each_entry(t, &pktgen_threads, th_list)
|
|
|
t->control |= T_STOP;
|
|
|
- t = t->next;
|
|
|
- }
|
|
|
+
|
|
|
thread_unlock();
|
|
|
}
|
|
|
|
|
@@ -2503,40 +2502,36 @@ signal:
|
|
|
|
|
|
static int pktgen_wait_all_threads_run(void)
|
|
|
{
|
|
|
- struct pktgen_thread *t = pktgen_threads;
|
|
|
+ struct pktgen_thread *t;
|
|
|
int sig = 1;
|
|
|
|
|
|
- while (t) {
|
|
|
+ thread_lock();
|
|
|
+
|
|
|
+ list_for_each_entry(t, &pktgen_threads, th_list) {
|
|
|
sig = pktgen_wait_thread_run(t);
|
|
|
if (sig == 0)
|
|
|
break;
|
|
|
- thread_lock();
|
|
|
- t = t->next;
|
|
|
- thread_unlock();
|
|
|
}
|
|
|
- if (sig == 0) {
|
|
|
- thread_lock();
|
|
|
- while (t) {
|
|
|
+
|
|
|
+ if (sig == 0)
|
|
|
+ list_for_each_entry(t, &pktgen_threads, th_list)
|
|
|
t->control |= (T_STOP);
|
|
|
- t = t->next;
|
|
|
- }
|
|
|
- thread_unlock();
|
|
|
- }
|
|
|
+
|
|
|
+ thread_unlock();
|
|
|
return sig;
|
|
|
}
|
|
|
|
|
|
static void pktgen_run_all_threads(void)
|
|
|
{
|
|
|
- struct pktgen_thread *t = pktgen_threads;
|
|
|
+ struct pktgen_thread *t;
|
|
|
|
|
|
PG_DEBUG(printk("pktgen: entering pktgen_run_all_threads.\n"));
|
|
|
|
|
|
thread_lock();
|
|
|
|
|
|
- while (t) {
|
|
|
+ list_for_each_entry(t, &pktgen_threads, th_list)
|
|
|
t->control |= (T_RUN);
|
|
|
- t = t->next;
|
|
|
- }
|
|
|
+
|
|
|
thread_unlock();
|
|
|
|
|
|
schedule_timeout_interruptible(msecs_to_jiffies(125)); /* Propagate thread->control */
|
|
@@ -2693,24 +2688,12 @@ static void pktgen_rem_thread(struct pktgen_thread *t)
|
|
|
{
|
|
|
/* Remove from the thread list */
|
|
|
|
|
|
- struct pktgen_thread *tmp = pktgen_threads;
|
|
|
-
|
|
|
remove_proc_entry(t->name, pg_proc_dir);
|
|
|
|
|
|
thread_lock();
|
|
|
|
|
|
- if (tmp == t)
|
|
|
- pktgen_threads = tmp->next;
|
|
|
- else {
|
|
|
- while (tmp) {
|
|
|
- if (tmp->next == t) {
|
|
|
- tmp->next = t->next;
|
|
|
- t->next = NULL;
|
|
|
- break;
|
|
|
- }
|
|
|
- tmp = tmp->next;
|
|
|
- }
|
|
|
- }
|
|
|
+ list_del(&t->th_list);
|
|
|
+
|
|
|
thread_unlock();
|
|
|
}
|
|
|
|
|
@@ -2969,6 +2952,8 @@ static void pktgen_thread_worker(struct pktgen_thread *t)
|
|
|
|
|
|
PG_DEBUG(printk("pktgen: %s removing thread.\n", t->name));
|
|
|
pktgen_rem_thread(t);
|
|
|
+
|
|
|
+ t->removed = 1;
|
|
|
}
|
|
|
|
|
|
static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t,
|
|
@@ -3081,19 +3066,18 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
|
|
|
|
|
|
static struct pktgen_thread *__init pktgen_find_thread(const char *name)
|
|
|
{
|
|
|
- struct pktgen_thread *t = NULL;
|
|
|
+ struct pktgen_thread *t;
|
|
|
|
|
|
thread_lock();
|
|
|
|
|
|
- t = pktgen_threads;
|
|
|
- while (t) {
|
|
|
- if (strcmp(t->name, name) == 0)
|
|
|
- break;
|
|
|
+ list_for_each_entry(t, &pktgen_threads, th_list)
|
|
|
+ if (strcmp(t->name, name) == 0) {
|
|
|
+ thread_unlock();
|
|
|
+ return t;
|
|
|
+ }
|
|
|
|
|
|
- t = t->next;
|
|
|
- }
|
|
|
thread_unlock();
|
|
|
- return t;
|
|
|
+ return NULL;
|
|
|
}
|
|
|
|
|
|
static int __init pktgen_create_thread(const char *name, int cpu)
|
|
@@ -3132,8 +3116,9 @@ static int __init pktgen_create_thread(const char *name, int cpu)
|
|
|
pe->proc_fops = &pktgen_thread_fops;
|
|
|
pe->data = t;
|
|
|
|
|
|
- t->next = pktgen_threads;
|
|
|
- pktgen_threads = t;
|
|
|
+ list_add_tail(&t->th_list, &pktgen_threads);
|
|
|
+
|
|
|
+ t->removed = 0;
|
|
|
|
|
|
if (kernel_thread((void *)pktgen_thread_worker, (void *)t,
|
|
|
CLONE_FS | CLONE_FILES | CLONE_SIGHAND) < 0)
|
|
@@ -3234,17 +3219,18 @@ static int __init pg_init(void)
|
|
|
|
|
|
static void __exit pg_cleanup(void)
|
|
|
{
|
|
|
+ struct pktgen_thread *t;
|
|
|
+ struct list_head *q, *n;
|
|
|
wait_queue_head_t queue;
|
|
|
init_waitqueue_head(&queue);
|
|
|
|
|
|
/* Stop all interfaces & threads */
|
|
|
|
|
|
- while (pktgen_threads) {
|
|
|
- struct pktgen_thread *t = pktgen_threads;
|
|
|
- pktgen_threads->control |= (T_TERMINATE);
|
|
|
+ list_for_each_safe(q, n, &pktgen_threads) {
|
|
|
+ t = list_entry(q, struct pktgen_thread, th_list);
|
|
|
+ t->control |= (T_TERMINATE);
|
|
|
|
|
|
- wait_event_interruptible_timeout(queue, (t != pktgen_threads),
|
|
|
- HZ);
|
|
|
+ wait_event_interruptible_timeout(queue, (t->removed == 1), HZ);
|
|
|
}
|
|
|
|
|
|
/* Un-register us from receiving netdevice events */
|