On Mon, May 22 2023 at 22:34, Baoquan He wrote: > On 05/22/23 at 02:02pm, Thomas Gleixner wrote: >> > @@ -1736,6 +1737,14 @@ static bool __purge_vmap_area_lazy(unsigned long start, unsigned long end) >> > list_replace_init(&purge_vmap_area_list, &local_purge_list); >> > spin_unlock(&purge_vmap_area_lock); >> > >> > + vb = container_of(va, struct vmap_block, va); >> >> This cannot work vmap_area is not embedded in vmap_block. vmap_block::va >> is a pointer. vmap_area does not link back to vmap_block, so there is no >> way to find it based on a vmap_area. > > Oh, the code is buggy. va->flags can tell if it's vmap_block, then we > can deduce the vb pointer. No. It _CANNOT_ work whether you check the flags or not. struct foo { ..... struct bar bar; }; container_of(ptr_to_bar, struct foo, bar) returns the pointer to the struct foo which has struct bar embedded. But struct foo { ..... struct bar *bar; }; cannot do that because ptr_to_bar points to some object which is completely disconnected from struct foo. Care to look at the implementation of container_of()? Here is what it boils down to: void *member_pointer = bar; p = (struct foo *)(member_pointer - offsetof(struct foo, bar); So it uses the pointer to bar and subtracts the offset of bar in struct foo. This obviously can only work when struct bar is embedded in struct foo. Lets assume that *bar is the first member of foo, i.e. offset of *bar in struct foo is 0 p = (struct foo *)(member_pointer - 0); So you end up with p == member_pointer == bar But you won't get there because the static_assert() in container_of() will catch that and the compiler will tell you in colourful ways. Once the vmap area is handed over for cleaning up the vmap block is gone and even if you let it stay around then the vmap area does not have any information where to find the block. You'd need to have a pointer to the vmap block in vmap area or embed vmap area into vmap block. See? Thanks, tglx