> On Jul 24, 2023, at 17:43, Qi Zheng <zhengqi.arch@xxxxxxxxxxxxx> wrote: > > Currently, we maintain two linear arrays per node per memcg, which are > shrinker_info::map and shrinker_info::nr_deferred. And we need to resize > them when the shrinker_nr_max is exceeded, that is, allocate a new array, > and then copy the old array to the new array, and finally free the old > array by RCU. > > For shrinker_info::map, we do set_bit() under the RCU lock, so we may set > the value into the old map which is about to be freed. This may cause the > value set to be lost. The current solution is not to copy the old map when > resizing, but to set all the corresponding bits in the new map to 1. This > solves the data loss problem, but bring the overhead of more pointless > loops while doing memcg slab shrink. > > For shrinker_info::nr_deferred, we will only modify it under the read lock > of shrinker_rwsem, so it will not run concurrently with the resizing. But > after we make memcg slab shrink lockless, there will be the same data loss > problem as shrinker_info::map, and we can't work around it like the map. > > For such resizable arrays, the most straightforward idea is to change it > to xarray, like we did for list_lru [1]. We need to do xa_store() in the > list_lru_add()-->set_shrinker_bit(), but this will cause memory > allocation, and the list_lru_add() doesn't accept failure. A possible > solution is to pre-allocate, but the location of pre-allocation is not > well determined. > > Therefore, this commit chooses to introduce a secondary array for > shrinker_info::{map, nr_deferred}, so that we only need to copy this > secondary array every time the size is resized. Then even if we get the > old secondary array under the RCU lock, the found map and nr_deferred are > also true, so no data is lost. > > [1]. https://lore.kernel.org/all/20220228122126.37293-13-songmuchun@xxxxxxxxxxxxx/ > > Signed-off-by: Qi Zheng <zhengqi.arch@xxxxxxxxxxxxx> Reviewed-by: Muchun Song <songmuchun@xxxxxxxxxxxxx>