Re: [RFC PATCH 3/3] mm/vmalloc.c: change _vm_unmap_aliases() to do purge firstly

Thomas Gleixner
2023-05-22T20:22:15Z

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