Skip to content

Commit 3042f83

Browse files
urezkipaulmckrcu
authored andcommitted
rcu: Support reclaim for head-less object
Update the kvfree_call_rcu() function with head-less support. This allows RCU to reclaim objects without an embedded rcu_head. tree-RCU: We introduce two chains of arrays to store SLAB-backed and vmalloc pointers, each. Storage in either of these arrays does not require embedding an rcu_head within the object. Maintaining the arrays may become impossible due to high memory pressure. For such cases there is an emergency path. Objects with rcu_head inside are just queued on a backup rcu_head list. Later on that list is drained. As for the head-less variant, as the current context can sleep, the following emergency measures are applied: a) Synchronously wait until a grace period has elapsed. b) Call kvfree(). tiny-RCU: For double argument calls, there are no new changes in behavior. For single argument call, kvfree() is directly inlined on the current stack after a synchronize_rcu() call. Note that for tiny-RCU, any call to synchronize_rcu() is actually a quiescent state, therefore it does nothing. Reviewed-by: Joel Fernandes (Google) <[email protected]> Signed-off-by: Uladzislau Rezki (Sony) <[email protected]> Signed-off-by: Joel Fernandes (Google) <[email protected]> Co-developed-by: Joel Fernandes (Google) <[email protected]> Signed-off-by: Paul E. McKenney <[email protected]>
1 parent ce4dce1 commit 3042f83

File tree

2 files changed

+60
-3
lines changed

2 files changed

+60
-3
lines changed

include/linux/rcutiny.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,25 @@ static inline void synchronize_rcu_expedited(void)
3434
synchronize_rcu();
3535
}
3636

37+
/*
38+
* Add one more declaration of kvfree() here. It is
39+
* not so straight forward to just include <linux/mm.h>
40+
* where it is defined due to getting many compile
41+
* errors caused by that include.
42+
*/
43+
extern void kvfree(const void *addr);
44+
3745
static inline void kvfree_call_rcu(struct rcu_head *head, rcu_callback_t func)
3846
{
39-
call_rcu(head, func);
47+
if (head) {
48+
call_rcu(head, func);
49+
return;
50+
}
51+
52+
// kvfree_rcu(one_arg) call.
53+
might_sleep();
54+
synchronize_rcu();
55+
kvfree((void *) func);
4056
}
4157

4258
void rcu_qs(void);

kernel/rcu/tree.c

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3314,6 +3314,13 @@ kvfree_call_rcu_add_ptr_to_bulk(struct kfree_rcu_cpu *krcp, void *ptr)
33143314
if (IS_ENABLED(CONFIG_PREEMPT_RT))
33153315
return false;
33163316

3317+
/*
3318+
* NOTE: For one argument of kvfree_rcu() we can
3319+
* drop the lock and get the page in sleepable
3320+
* context. That would allow to maintain an array
3321+
* for the CONFIG_PREEMPT_RT as well if no cached
3322+
* pages are available.
3323+
*/
33173324
bnode = (struct kvfree_rcu_bulk_data *)
33183325
__get_free_page(GFP_NOWAIT | __GFP_NOWARN);
33193326
}
@@ -3353,27 +3360,50 @@ void kvfree_call_rcu(struct rcu_head *head, rcu_callback_t func)
33533360
{
33543361
unsigned long flags;
33553362
struct kfree_rcu_cpu *krcp;
3363+
bool success;
33563364
void *ptr;
33573365

3366+
if (head) {
3367+
ptr = (void *) head - (unsigned long) func;
3368+
} else {
3369+
/*
3370+
* Please note there is a limitation for the head-less
3371+
* variant, that is why there is a clear rule for such
3372+
* objects: it can be used from might_sleep() context
3373+
* only. For other places please embed an rcu_head to
3374+
* your data.
3375+
*/
3376+
might_sleep();
3377+
ptr = (unsigned long *) func;
3378+
}
3379+
33583380
krcp = krc_this_cpu_lock(&flags);
3359-
ptr = (void *)head - (unsigned long)func;
33603381

33613382
// Queue the object but don't yet schedule the batch.
33623383
if (debug_rcu_head_queue(ptr)) {
33633384
// Probable double kfree_rcu(), just leak.
33643385
WARN_ONCE(1, "%s(): Double-freed call. rcu_head %p\n",
33653386
__func__, head);
3387+
3388+
// Mark as success and leave.
3389+
success = true;
33663390
goto unlock_return;
33673391
}
33683392

33693393
/*
33703394
* Under high memory pressure GFP_NOWAIT can fail,
33713395
* in that case the emergency path is maintained.
33723396
*/
3373-
if (unlikely(!kvfree_call_rcu_add_ptr_to_bulk(krcp, ptr))) {
3397+
success = kvfree_call_rcu_add_ptr_to_bulk(krcp, ptr);
3398+
if (!success) {
3399+
if (head == NULL)
3400+
// Inline if kvfree_rcu(one_arg) call.
3401+
goto unlock_return;
3402+
33743403
head->func = func;
33753404
head->next = krcp->head;
33763405
krcp->head = head;
3406+
success = true;
33773407
}
33783408

33793409
WRITE_ONCE(krcp->count, krcp->count + 1);
@@ -3387,6 +3417,17 @@ void kvfree_call_rcu(struct rcu_head *head, rcu_callback_t func)
33873417

33883418
unlock_return:
33893419
krc_this_cpu_unlock(krcp, flags);
3420+
3421+
/*
3422+
* Inline kvfree() after synchronize_rcu(). We can do
3423+
* it from might_sleep() context only, so the current
3424+
* CPU can pass the QS state.
3425+
*/
3426+
if (!success) {
3427+
debug_rcu_head_unqueue((struct rcu_head *) ptr);
3428+
synchronize_rcu();
3429+
kvfree(ptr);
3430+
}
33903431
}
33913432
EXPORT_SYMBOL_GPL(kvfree_call_rcu);
33923433

0 commit comments

Comments
 (0)