diff options
Diffstat (limited to 'kernel/rcu/tiny.c')
| -rw-r--r-- | kernel/rcu/tiny.c | 28 | 
1 files changed, 27 insertions, 1 deletions
| diff --git a/kernel/rcu/tiny.c b/kernel/rcu/tiny.c index 477b4eb44af5..dd572ce7c747 100644 --- a/kernel/rcu/tiny.c +++ b/kernel/rcu/tiny.c @@ -22,6 +22,7 @@  #include <linux/time.h>  #include <linux/cpu.h>  #include <linux/prefetch.h> +#include <linux/slab.h>  #include "rcu.h" @@ -73,6 +74,31 @@ void rcu_sched_clock_irq(int user)  	}  } +/* + * Reclaim the specified callback, either by invoking it for non-kfree cases or + * freeing it directly (for kfree). Return true if kfreeing, false otherwise. + */ +static inline bool rcu_reclaim_tiny(struct rcu_head *head) +{ +	rcu_callback_t f; +	unsigned long offset = (unsigned long)head->func; + +	rcu_lock_acquire(&rcu_callback_map); +	if (__is_kfree_rcu_offset(offset)) { +		trace_rcu_invoke_kfree_callback("", head, offset); +		kfree((void *)head - offset); +		rcu_lock_release(&rcu_callback_map); +		return true; +	} + +	trace_rcu_invoke_callback("", head); +	f = head->func; +	WRITE_ONCE(head->func, (rcu_callback_t)0L); +	f(head); +	rcu_lock_release(&rcu_callback_map); +	return false; +} +  /* Invoke the RCU callbacks whose grace period has elapsed.  */  static __latent_entropy void rcu_process_callbacks(struct softirq_action *unused)  { @@ -100,7 +126,7 @@ static __latent_entropy void rcu_process_callbacks(struct softirq_action *unused  		prefetch(next);  		debug_rcu_head_unqueue(list);  		local_bh_disable(); -		__rcu_reclaim("", list); +		rcu_reclaim_tiny(list);  		local_bh_enable();  		list = next;  	} | 
