Re: [PATCH slab/for-next v4 6/8] mm/slab: introduce struct kvfree_rcu_head for kvfree_rcu batching

Harry Yoo <[email protected]> Wed, 22 Jul 2026 16:42:46 +0900
Newsgroups org.kernel.vger.rcu,dev.linux.lists.linux-rt-devel,org.kernel.vger.bpf,org.kernel.vger.linux-kernel,org.kvack.linux-mm
Message-ID <[email protected]>

On 7/21/26 8:06 PM, Vlastimil Babka (SUSE) wrote:
> On 7/20/26 14:44, Harry Yoo (Oracle) wrote:
>> rcu_head is overkill for kvfree_rcu() because the callback
>> function is always either kfree(), vfree(), or free_large_kmalloc(),
>> and thus there is no need for a function pointer.
>>
>> kvfree_rcu batching reuses the field to store the start address
>> of an object, however, this is not strictly needed because we can
>> calculate the start address in the slowpath. For the purpose of
>> kvfree_rcu batching, it is sufficient to implement a linked list using
>> a single pointer.
>>
>> Introduce a new struct called kvfree_rcu_head (the name was suggested
>> by Vlastimil Babka), which is similar to rcu_head but is only a single
>> pointer to build a linked list, without a function pointer, when
>> CONFIG_KVFREE_RCU_BATCHED=y.
>>
>> When kvfree_rcu is not batched, kvfree_rcu_head is the same size
>> as rcu_head. Note that shrinking struct kvfree_rcu_head on
>> CONFIG_KVFREE_RCU_BATCHED=n kernels would inevitably require additional
>> complexity and also some sort of batching (which defeats the purpose of
>> the config option) because it cannot fall back to call_rcu().
>>
>> For now there are no user-visible changes to the API. k[v]free_rcu()
>> simply casts rcu_head to kvfree_rcu_head. While this does not affect
>> the API, it allows kfree_rcu_nolock() to reuse kvfree_rcu batching
>> as a fallback when trylock or sheaf allocation fails.
>>
>> Stop storing the object pointer in rcu_head.func and instead calculate
>> the object's start address in kvfree_rcu_list(). Factor out the existing
>> logic to calculate the start address from kvfree_rcu_cb() to
>> kvmalloc_obj_start_addr().
>>
>> Signed-off-by: Harry Yoo (Oracle) <[email protected]>
> 
> Nice.
> 
> Reviewed-by: Vlastimil Babka (SUSE) <[email protected]>

Thanks!

> Nit:
> 
>> --- a/mm/slab.h
>> +++ b/mm/slab.h
>> @@ -351,6 +351,33 @@ static inline int objs_per_slab(const struct kmem_cache *cache,
>>  	return slab->objects;
>>  }
>>  
>> +/* kvfree_rcu_head offset can be only less than page size */
>> +static inline void *kvmalloc_obj_start_addr(void *head)
>> +{
>> +	void *obj = head;
>> +
>> +	if (unlikely(is_vmalloc_addr(obj))) {
>> +		obj = (void *) PAGE_ALIGN_DOWN((unsigned long)obj);
>> +	} else {
>> +		struct page *page = virt_to_page(obj);
>> +		struct slab *slab = page_slab(page);
> 
> Can use virt_to_slab().

Ah, right. We don't call free_large_kmalloc() here.

>> +
>> +		if (!slab) {
>> +			obj = (void *) PAGE_ALIGN_DOWN((unsigned long)obj);
>> +		} else if (is_kfence_address(obj)) {
>> +			obj = kfence_object_start(obj);
>> +		} else {
>> +			struct kmem_cache *s = slab->slab_cache;
>> +			unsigned int idx = __obj_to_index(s, slab_address(slab), obj);
>> +
>> +			obj = slab_address(slab) + s->size * idx;
>> +			obj = fixup_red_left(s, obj);
>> +		}
>> +	}
>> +
>> +	return obj;
>> +}
>> +
>>  /*
>>   * State of the slab allocator.
>>   *

-- 
Cheers,
Harry / Hyeonggon
OpenPGP_signature.asc (application/pgp-signature, 228 B)
-----BEGIN PGP SIGNATURE-----

iHUEARYKAB0WIQQQ1ub6gR5ogjaKRmOGXBN6rc5S1gUCamB0dwAKCRCGXBN6rc5S
1obAAQCqHfelJX+qi5duTvHrT8jGkOgRfpF+LiWvdac7y5+2pAEAryoulTJ2FIDf
tKqBX1pWil296y3KUUzK/9SUjWszIAk=
=N3ce
-----END PGP SIGNATURE-----