Merge branch 'for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu into core/rcu
Pull the v5.9 RCU bits from Paul E. McKenney: - Documentation updates - Miscellaneous fixes - kfree_rcu updates - RCU tasks updates - Read-side scalability tests - SRCU updates - Torture-test updates Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
@@ -512,7 +512,7 @@ static inline void hlist_replace_rcu(struct hlist_node *old,
|
||||
* @right: The hlist head on the right
|
||||
*
|
||||
* The lists start out as [@left ][node1 ... ] and
|
||||
[@right ][node2 ... ]
|
||||
* [@right ][node2 ... ]
|
||||
* The lists end up as [@left ][node2 ... ]
|
||||
* [@right ][node1 ... ]
|
||||
*/
|
||||
|
@@ -162,7 +162,7 @@ static inline void hlist_nulls_add_fake(struct hlist_nulls_node *n)
|
||||
* The barrier() is needed to make sure compiler doesn't cache first element [1],
|
||||
* as this loop can be restarted [2]
|
||||
* [1] Documentation/core-api/atomic_ops.rst around line 114
|
||||
* [2] Documentation/RCU/rculist_nulls.txt around line 146
|
||||
* [2] Documentation/RCU/rculist_nulls.rst around line 146
|
||||
*/
|
||||
#define hlist_nulls_for_each_entry_rcu(tpos, pos, head, member) \
|
||||
for (({barrier();}), \
|
||||
|
@@ -828,17 +828,17 @@ static inline notrace void rcu_read_unlock_sched_notrace(void)
|
||||
|
||||
/*
|
||||
* Does the specified offset indicate that the corresponding rcu_head
|
||||
* structure can be handled by kfree_rcu()?
|
||||
* structure can be handled by kvfree_rcu()?
|
||||
*/
|
||||
#define __is_kfree_rcu_offset(offset) ((offset) < 4096)
|
||||
#define __is_kvfree_rcu_offset(offset) ((offset) < 4096)
|
||||
|
||||
/*
|
||||
* Helper macro for kfree_rcu() to prevent argument-expansion eyestrain.
|
||||
*/
|
||||
#define __kfree_rcu(head, offset) \
|
||||
#define __kvfree_rcu(head, offset) \
|
||||
do { \
|
||||
BUILD_BUG_ON(!__is_kfree_rcu_offset(offset)); \
|
||||
kfree_call_rcu(head, (rcu_callback_t)(unsigned long)(offset)); \
|
||||
BUILD_BUG_ON(!__is_kvfree_rcu_offset(offset)); \
|
||||
kvfree_call_rcu(head, (rcu_callback_t)(unsigned long)(offset)); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
@@ -857,7 +857,7 @@ static inline notrace void rcu_read_unlock_sched_notrace(void)
|
||||
* Because the functions are not allowed in the low-order 4096 bytes of
|
||||
* kernel virtual memory, offsets up to 4095 bytes can be accommodated.
|
||||
* If the offset is larger than 4095 bytes, a compile-time error will
|
||||
* be generated in __kfree_rcu(). If this error is triggered, you can
|
||||
* be generated in __kvfree_rcu(). If this error is triggered, you can
|
||||
* either fall back to use of call_rcu() or rearrange the structure to
|
||||
* position the rcu_head structure into the first 4096 bytes.
|
||||
*
|
||||
@@ -872,7 +872,46 @@ do { \
|
||||
typeof (ptr) ___p = (ptr); \
|
||||
\
|
||||
if (___p) \
|
||||
__kfree_rcu(&((___p)->rhf), offsetof(typeof(*(ptr)), rhf)); \
|
||||
__kvfree_rcu(&((___p)->rhf), offsetof(typeof(*(ptr)), rhf)); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* kvfree_rcu() - kvfree an object after a grace period.
|
||||
*
|
||||
* This macro consists of one or two arguments and it is
|
||||
* based on whether an object is head-less or not. If it
|
||||
* has a head then a semantic stays the same as it used
|
||||
* to be before:
|
||||
*
|
||||
* kvfree_rcu(ptr, rhf);
|
||||
*
|
||||
* where @ptr is a pointer to kvfree(), @rhf is the name
|
||||
* of the rcu_head structure within the type of @ptr.
|
||||
*
|
||||
* When it comes to head-less variant, only one argument
|
||||
* is passed and that is just a pointer which has to be
|
||||
* freed after a grace period. Therefore the semantic is
|
||||
*
|
||||
* kvfree_rcu(ptr);
|
||||
*
|
||||
* where @ptr is a pointer to kvfree().
|
||||
*
|
||||
* Please note, head-less way of freeing is permitted to
|
||||
* use from a context that has to follow might_sleep()
|
||||
* annotation. Otherwise, please switch and embed the
|
||||
* rcu_head structure within the type of @ptr.
|
||||
*/
|
||||
#define kvfree_rcu(...) KVFREE_GET_MACRO(__VA_ARGS__, \
|
||||
kvfree_rcu_arg_2, kvfree_rcu_arg_1)(__VA_ARGS__)
|
||||
|
||||
#define KVFREE_GET_MACRO(_1, _2, NAME, ...) NAME
|
||||
#define kvfree_rcu_arg_2(ptr, rhf) kfree_rcu(ptr, rhf)
|
||||
#define kvfree_rcu_arg_1(ptr) \
|
||||
do { \
|
||||
typeof(ptr) ___p = (ptr); \
|
||||
\
|
||||
if (___p) \
|
||||
kvfree_call_rcu(NULL, (rcu_callback_t) (___p)); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
|
@@ -36,8 +36,8 @@ void rcu_read_unlock_trace_special(struct task_struct *t, int nesting);
|
||||
/**
|
||||
* rcu_read_lock_trace - mark beginning of RCU-trace read-side critical section
|
||||
*
|
||||
* When synchronize_rcu_trace() is invoked by one task, then that task
|
||||
* is guaranteed to block until all other tasks exit their read-side
|
||||
* When synchronize_rcu_tasks_trace() is invoked by one task, then that
|
||||
* task is guaranteed to block until all other tasks exit their read-side
|
||||
* critical sections. Similarly, if call_rcu_trace() is invoked on one
|
||||
* task while other tasks are within RCU read-side critical sections,
|
||||
* invocation of the corresponding RCU callback is deferred until after
|
||||
|
@@ -34,9 +34,25 @@ static inline void synchronize_rcu_expedited(void)
|
||||
synchronize_rcu();
|
||||
}
|
||||
|
||||
static inline void kfree_call_rcu(struct rcu_head *head, rcu_callback_t func)
|
||||
/*
|
||||
* Add one more declaration of kvfree() here. It is
|
||||
* not so straight forward to just include <linux/mm.h>
|
||||
* where it is defined due to getting many compile
|
||||
* errors caused by that include.
|
||||
*/
|
||||
extern void kvfree(const void *addr);
|
||||
|
||||
static inline void kvfree_call_rcu(struct rcu_head *head, rcu_callback_t func)
|
||||
{
|
||||
call_rcu(head, func);
|
||||
if (head) {
|
||||
call_rcu(head, func);
|
||||
return;
|
||||
}
|
||||
|
||||
// kvfree_rcu(one_arg) call.
|
||||
might_sleep();
|
||||
synchronize_rcu();
|
||||
kvfree((void *) func);
|
||||
}
|
||||
|
||||
void rcu_qs(void);
|
||||
|
@@ -33,7 +33,7 @@ static inline void rcu_virt_note_context_switch(int cpu)
|
||||
}
|
||||
|
||||
void synchronize_rcu_expedited(void);
|
||||
void kfree_call_rcu(struct rcu_head *head, rcu_callback_t func);
|
||||
void kvfree_call_rcu(struct rcu_head *head, rcu_callback_t func);
|
||||
|
||||
void rcu_barrier(void);
|
||||
bool rcu_eqs_special_set(int cpu);
|
||||
|
@@ -55,6 +55,11 @@ struct torture_random_state {
|
||||
#define DEFINE_TORTURE_RANDOM_PERCPU(name) \
|
||||
DEFINE_PER_CPU(struct torture_random_state, name)
|
||||
unsigned long torture_random(struct torture_random_state *trsp);
|
||||
static inline void torture_random_init(struct torture_random_state *trsp)
|
||||
{
|
||||
trsp->trs_state = 0;
|
||||
trsp->trs_count = 0;
|
||||
}
|
||||
|
||||
/* Task shuffler, which causes CPUs to occasionally go idle. */
|
||||
void torture_shuffle_task_register(struct task_struct *tp);
|
||||
|
Reference in New Issue
Block a user