Message ID | 20211004134650.4031813-1-willy@infradead.org (mailing list archive) |
---|---|
Headers | show |
Series | Separate struct slab from struct page | expand |
On Mon, Oct 04, 2021 at 02:45:48PM +0100, Matthew Wilcox (Oracle) wrote: > This is an offshoot of the folio work, although it does not depend on any > of the outstanding pieces of folio work. One of the more complex parts > of the struct page definition is the parts used by the slab allocators. > It would be good for the MM in general if struct slab were its own data > type, and it also helps to prevent tail pages from slipping in anywhere. > > The slub conversion is done "properly", ie in individually reviewable, > bisectable chunks. The slab & slob conversions are slapdash. The > patches to switch bootmem & zsmalloc away from slab elements are also > expedient instead of well thought through. The KASAN and memcg parts > would also benefit from a more thoughtful approach. This looks great to me. It's a huge step in disentangling struct page, and it's already showing very cool downstream effects in somewhat unexpected places like the memory cgroup controller. > I'm not entirely happy with slab_test_cache() for a predicate name. > I actually liked SlabAllocation() better, but then I remembered that we're > trying to get away from InterCapping, and somehow slab_test_allocation() > didn't feel right either. I touched on this in the reply to the memcg patch, but I wonder if it would be better to not have this test against struct slab at all. It's basically a type test that means slab_is_slab(), and its existence implies that if you see 'struct slab' somewhere, you don't know for sure - without having more context - whether it's been vetted or not. This makes 'struct slab' and option/maybe type that needs a method of self-identification. Right now it can use the PG_slab bit in the flags field shared with the page, but if it were separately allocated some day, that would occupy dedicated memory. And describing memory, that's struct page's role: to identify what's sitting behind a random pfn or an address. "struct page should be a pointer and a type tag", or something like that ;-) If instead of this: slab = virt_to_slab(p); if (!slab_test_cache(slab)) { page = (struct page *)slab; do_page_things(page); } else { ... } you wrote it like this: page = virt_to_page(p); if (PageSlab(page)) { /* page->type */ slab = page_slab(page); /* page->pointer */ do_slab_things(slab); } else { do_bypass_things(page); } it would keep the ambiguity and type resolution in the domain of the page, and it would make struct slab a strong type that doesn't need to self-identify.
On Mon, Oct 11, 2021 at 04:07:14PM -0400, Johannes Weiner wrote: > This looks great to me. It's a huge step in disentangling struct page, > and it's already showing very cool downstream effects in somewhat > unexpected places like the memory cgroup controller. Thanks! > > I'm not entirely happy with slab_test_cache() for a predicate name. > > I actually liked SlabAllocation() better, but then I remembered that we're > > trying to get away from InterCapping, and somehow slab_test_allocation() > > didn't feel right either. > > I touched on this in the reply to the memcg patch, but I wonder if it > would be better to not have this test against struct slab at all. > > It's basically a type test that means slab_is_slab(), and its > existence implies that if you see 'struct slab' somewhere, you don't > know for sure - without having more context - whether it's been vetted > or not. This makes 'struct slab' and option/maybe type that needs a > method of self-identification. Right now it can use the PG_slab bit in > the flags field shared with the page, but if it were separately > allocated some day, that would occupy dedicated memory. > > And describing memory, that's struct page's role: to identify what's > sitting behind a random pfn or an address. "struct page should be a > pointer and a type tag", or something like that ;-) > > If instead of this: > > slab = virt_to_slab(p); > if (!slab_test_cache(slab)) { > page = (struct page *)slab; > do_page_things(page); > } else { > ... > } > > you wrote it like this: > > page = virt_to_page(p); > if (PageSlab(page)) { /* page->type */ > slab = page_slab(page); /* page->pointer */ > do_slab_things(slab); > } else { > do_bypass_things(page); > } > > it would keep the ambiguity and type resolution in the domain of the > page, and it would make struct slab a strong type that doesn't need to > self-identify. ... yeah. I'm absolutely on board with the goal of moving to each struct page being very small and having essentially a single discriminated pointer to its descriptor. eg all 2^N pages allocated to a slab would have a bit pattern of 0110 in the bottom 4 bits. So PageSlab would still make sense, and calling page_slab() on something that wasn't tagged with 0110 would cause some kind of error. But until we get to that goal, it's hard to write code that's going to work in either scenario. We do need to keep the PG_slab bit to distinguish slab pages from other kinds of memory. And we don't want to be unnecessarily calling compound_head() (although I'm willing to do that for the sake of better looking code). What if we replicated the PG_slab bit across all the tail pages today? So we could call PageSlab() on any page and instead of it doing a compound_head() lookup, it just looked at the tail->flags. Then page_slab() does the actual compound_head() lookup. I think it should be fairly cheap to set the extra bits at allocation because we just set tail->compound_head, so the lines should still be in cache. (PageSlab is marked as PF_NO_TAIL, so it calls compound_head() on every access).