netns xfrm: /proc/net/xfrm_stat in netns
[safe/jmp/linux-2.6] / kernel / workqueue.c
index 714afad..d4dc69d 100644 (file)
@@ -62,6 +62,7 @@ struct workqueue_struct {
        const char *name;
        int singlethread;
        int freezeable;         /* Freeze threads during suspend */
+       int rt;
 #ifdef CONFIG_LOCKDEP
        struct lockdep_map lockdep_map;
 #endif
@@ -766,6 +767,7 @@ init_cpu_workqueue(struct workqueue_struct *wq, int cpu)
 
 static int create_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu)
 {
+       struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
        struct workqueue_struct *wq = cwq->wq;
        const char *fmt = is_single_threaded(wq) ? "%s" : "%s/%d";
        struct task_struct *p;
@@ -781,7 +783,8 @@ static int create_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu)
         */
        if (IS_ERR(p))
                return PTR_ERR(p);
-
+       if (cwq->wq->rt)
+               sched_setscheduler_nocheck(p, SCHED_FIFO, &param);
        cwq->thread = p;
 
        return 0;
@@ -801,6 +804,7 @@ static void start_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu)
 struct workqueue_struct *__create_workqueue_key(const char *name,
                                                int singlethread,
                                                int freezeable,
+                                               int rt,
                                                struct lock_class_key *key,
                                                const char *lock_name)
 {
@@ -822,6 +826,7 @@ struct workqueue_struct *__create_workqueue_key(const char *name,
        lockdep_init_map(&wq->lockdep_map, lock_name, key, 0);
        wq->singlethread = singlethread;
        wq->freezeable = freezeable;
+       wq->rt = rt;
        INIT_LIST_HEAD(&wq->list);
 
        if (singlethread) {
@@ -965,6 +970,51 @@ undo:
        return ret;
 }
 
+#ifdef CONFIG_SMP
+struct work_for_cpu {
+       struct work_struct work;
+       long (*fn)(void *);
+       void *arg;
+       long ret;
+};
+
+static void do_work_for_cpu(struct work_struct *w)
+{
+       struct work_for_cpu *wfc = container_of(w, struct work_for_cpu, work);
+
+       wfc->ret = wfc->fn(wfc->arg);
+}
+
+/**
+ * work_on_cpu - run a function in user context on a particular cpu
+ * @cpu: the cpu to run on
+ * @fn: the function to run
+ * @arg: the function arg
+ *
+ * This will return -EINVAL in the cpu is not online, or the return value
+ * of @fn otherwise.
+ */
+long work_on_cpu(unsigned int cpu, long (*fn)(void *), void *arg)
+{
+       struct work_for_cpu wfc;
+
+       INIT_WORK(&wfc.work, do_work_for_cpu);
+       wfc.fn = fn;
+       wfc.arg = arg;
+       get_online_cpus();
+       if (unlikely(!cpu_online(cpu)))
+               wfc.ret = -EINVAL;
+       else {
+               schedule_work_on(cpu, &wfc.work);
+               flush_work(&wfc.work);
+       }
+       put_online_cpus();
+
+       return wfc.ret;
+}
+EXPORT_SYMBOL_GPL(work_on_cpu);
+#endif /* CONFIG_SMP */
+
 void __init init_workqueues(void)
 {
        cpu_populated_map = cpu_online_map;