linuxkpi: Add rcu_work functions
The rcu_work function helps to queue some work after waiting for a grace period. This is needed by DRM drivers. Sponsored-by: The FreeBSD Foundation Reviewed by: hselasky Differential Revision: https://reviews.freebsd.org/D24942
This commit is contained in:
parent
cb7c78fd28
commit
2491b25c3a
@ -72,6 +72,13 @@ struct work_struct {
|
|||||||
atomic_t state;
|
atomic_t state;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct rcu_work {
|
||||||
|
struct work_struct work;
|
||||||
|
struct rcu_head rcu;
|
||||||
|
|
||||||
|
struct workqueue_struct *wq;
|
||||||
|
};
|
||||||
|
|
||||||
#define DECLARE_WORK(name, fn) \
|
#define DECLARE_WORK(name, fn) \
|
||||||
struct work_struct name; \
|
struct work_struct name; \
|
||||||
static void name##_init(void *arg) \
|
static void name##_init(void *arg) \
|
||||||
@ -112,6 +119,9 @@ do { \
|
|||||||
TASK_INIT(&(work)->work_task, 0, linux_work_fn, (work)); \
|
TASK_INIT(&(work)->work_task, 0, linux_work_fn, (work)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
#define INIT_RCU_WORK(_work, _fn) \
|
||||||
|
INIT_WORK(&(_work)->work, (_fn))
|
||||||
|
|
||||||
#define INIT_WORK_ONSTACK(work, fn) \
|
#define INIT_WORK_ONSTACK(work, fn) \
|
||||||
INIT_WORK(work, fn)
|
INIT_WORK(work, fn)
|
||||||
|
|
||||||
@ -192,6 +202,12 @@ do { \
|
|||||||
#define flush_work(work) \
|
#define flush_work(work) \
|
||||||
linux_flush_work(work)
|
linux_flush_work(work)
|
||||||
|
|
||||||
|
#define queue_rcu_work(wq, rwork) \
|
||||||
|
linux_queue_rcu_work(wq, rwork)
|
||||||
|
|
||||||
|
#define flush_rcu_work(rwork) \
|
||||||
|
linux_flush_rcu_work(rwork)
|
||||||
|
|
||||||
#define flush_delayed_work(dwork) \
|
#define flush_delayed_work(dwork) \
|
||||||
linux_flush_delayed_work(dwork)
|
linux_flush_delayed_work(dwork)
|
||||||
|
|
||||||
@ -237,5 +253,7 @@ extern bool linux_flush_delayed_work(struct delayed_work *);
|
|||||||
extern bool linux_work_pending(struct work_struct *);
|
extern bool linux_work_pending(struct work_struct *);
|
||||||
extern bool linux_work_busy(struct work_struct *);
|
extern bool linux_work_busy(struct work_struct *);
|
||||||
extern struct work_struct *linux_current_work(void);
|
extern struct work_struct *linux_current_work(void);
|
||||||
|
extern bool linux_queue_rcu_work(struct workqueue_struct *wq, struct rcu_work *rwork);
|
||||||
|
extern bool linux_flush_rcu_work(struct rcu_work *rwork);
|
||||||
|
|
||||||
#endif /* _LINUX_WORKQUEUE_H_ */
|
#endif /* _LINUX_WORKQUEUE_H_ */
|
||||||
|
@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <linux/wait.h>
|
#include <linux/wait.h>
|
||||||
#include <linux/compat.h>
|
#include <linux/compat.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/rcupdate.h>
|
||||||
|
|
||||||
#include <sys/kernel.h>
|
#include <sys/kernel.h>
|
||||||
|
|
||||||
@ -155,6 +156,53 @@ linux_queue_work_on(int cpu __unused, struct workqueue_struct *wq,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Callback func for linux_queue_rcu_work
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
rcu_work_func(struct rcu_head *rcu)
|
||||||
|
{
|
||||||
|
struct rcu_work *rwork;
|
||||||
|
|
||||||
|
rwork = container_of(rcu, struct rcu_work, rcu);
|
||||||
|
linux_queue_work_on(WORK_CPU_UNBOUND, rwork->wq, &rwork->work);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function queue a work after a grace period
|
||||||
|
* If the work was already pending it returns false,
|
||||||
|
* if not it calls call_rcu and returns true.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
linux_queue_rcu_work(struct workqueue_struct *wq, struct rcu_work *rwork)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!linux_work_pending(&rwork->work)) {
|
||||||
|
rwork->wq = wq;
|
||||||
|
linux_call_rcu(RCU_TYPE_REGULAR, &rwork->rcu, rcu_work_func);
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function waits for the last execution of a work and then
|
||||||
|
* flush the work.
|
||||||
|
* It returns true if the work was pending and we waited, it returns
|
||||||
|
* false otherwise.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
linux_flush_rcu_work(struct rcu_work *rwork)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (linux_work_pending(&rwork->work)) {
|
||||||
|
linux_rcu_barrier(RCU_TYPE_REGULAR);
|
||||||
|
linux_flush_work(&rwork->work);
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
return (linux_flush_work(&rwork->work));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function queues the given work structure on the given
|
* This function queues the given work structure on the given
|
||||||
* workqueue after a given delay in ticks. It returns non-zero if the
|
* workqueue after a given delay in ticks. It returns non-zero if the
|
||||||
|
Loading…
Reference in New Issue
Block a user