summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorAndrew Morton <akpm@osdl.org>2004-06-23 18:50:18 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-06-23 18:50:18 -0700
commit8c1ce9d6d628945ff23f844dbe9f21f5d5383b99 (patch)
tree030e150c11f9a3252fd7a1d0c36bd6912ff9eada /kernel
parentb659a6fbb927a79acd606c4466d03cb615879f9f (diff)
[PATCH] rcu: avoid passing an argument to the callback function
From: Dipankar Sarma <dipankar@in.ibm.com> This patch changes the call_rcu() API and avoids passing an argument to the callback function as suggested by Rusty. Instead, it is assumed that the user has embedded the rcu head into a structure that is useful in the callback and the rcu_head pointer is passed to the callback. The callback can use container_of() to get the pointer to its structure and work with it. Together with the rcu-singly-link patch, it reduces the rcu_head size by 50%. Considering that we use these in things like struct dentry and struct dst_entry, this is good savings in space. An example : struct my_struct { struct rcu_head rcu; int x; int y; }; void my_rcu_callback(struct rcu_head *head) { struct my_struct *p = container_of(head, struct my_struct, rcu); free(p); } void my_delete(struct my_struct *p) { ... call_rcu(&p->rcu, my_rcu_callback); ... } Signed-Off-By: Dipankar Sarma <dipankar@in.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/auditsc.c7
-rw-r--r--kernel/rcupdate.c26
2 files changed, 20 insertions, 13 deletions
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 342b57141fd9..e688c73f6a9e 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -177,9 +177,10 @@ static inline int audit_add_rule(struct audit_entry *entry,
return 0;
}
-static void audit_free_rule(void *arg)
+static void audit_free_rule(struct rcu_head *head)
{
- kfree(arg);
+ struct audit_entry *e = container_of(head, struct audit_entry, rcu);
+ kfree(e);
}
/* Note that audit_add_rule and audit_del_rule are called via
@@ -195,7 +196,7 @@ static inline int audit_del_rule(struct audit_rule *rule,
list_for_each_entry(e, list, list) {
if (!audit_compare_rule(rule, &e->rule)) {
list_del_rcu(&e->list);
- call_rcu(&e->rcu, audit_free_rule, e);
+ call_rcu(&e->rcu, audit_free_rule);
return 0;
}
}
diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c
index cdb59f12a5fa..7282889a5fd9 100644
--- a/kernel/rcupdate.c
+++ b/kernel/rcupdate.c
@@ -68,20 +68,19 @@ static DEFINE_PER_CPU(struct tasklet_struct, rcu_tasklet) = {NULL};
* call_rcu - Queue an RCU update request.
* @head: structure to be used for queueing the RCU updates.
* @func: actual update function to be invoked after the grace period
- * @arg: argument to be passed to the update function
*
* The update function will be invoked as soon as all CPUs have performed
* a context switch or been seen in the idle loop or in a user process.
* The read-side of critical section that use call_rcu() for updation must
* be protected by rcu_read_lock()/rcu_read_unlock().
*/
-void fastcall call_rcu(struct rcu_head *head, void (*func)(void *arg), void *arg)
+void fastcall call_rcu(struct rcu_head *head,
+ void (*func)(struct rcu_head *rcu))
{
int cpu;
unsigned long flags;
head->func = func;
- head->arg = arg;
head->next = NULL;
local_irq_save(flags);
cpu = smp_processor_id();
@@ -100,7 +99,7 @@ static void rcu_do_batch(struct rcu_head *list)
while (list) {
next = list->next;
- list->func(list->arg);
+ list->func(list);
list = next;
}
}
@@ -358,11 +357,18 @@ void __init rcu_init(void)
register_cpu_notifier(&rcu_nb);
}
+struct rcu_synchronize {
+ struct rcu_head head;
+ struct completion completion;
+};
/* Because of FASTCALL declaration of complete, we use this wrapper */
-static void wakeme_after_rcu(void *completion)
+static void wakeme_after_rcu(struct rcu_head *head)
{
- complete(completion);
+ struct rcu_synchronize *rcu;
+
+ rcu = container_of(head, struct rcu_synchronize, head);
+ complete(&rcu->completion);
}
/**
@@ -371,14 +377,14 @@ static void wakeme_after_rcu(void *completion)
*/
void synchronize_kernel(void)
{
- struct rcu_head rcu;
- DECLARE_COMPLETION(completion);
+ struct rcu_synchronize rcu;
+ init_completion(&rcu.completion);
/* Will wake me after RCU finished */
- call_rcu(&rcu, wakeme_after_rcu, &completion);
+ call_rcu(&rcu.head, wakeme_after_rcu);
/* Wait for it */
- wait_for_completion(&completion);
+ wait_for_completion(&rcu.completion);
}