On Fri, Mar 08, 2019 at 03:14:15PM +1100, Tobin C. Harding wrote: > We have now in place a mechanism for adding callbacks to a cache in > order to be able to implement object migration. > > Add a function __move() that implements SMO by moving all objects in a > slab page using the isolate/migrate callback methods. > > Co-developed-by: Christoph Lameter <cl@xxxxxxxxx> > Signed-off-by: Tobin C. Harding <tobin@xxxxxxxxxx> > --- > mm/slub.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 85 insertions(+) > > diff --git a/mm/slub.c b/mm/slub.c > index 0133168d1089..6ce866b420f1 100644 > --- a/mm/slub.c > +++ b/mm/slub.c > @@ -4325,6 +4325,91 @@ int __kmem_cache_create(struct kmem_cache *s, slab_flags_t flags) > return err; > } > > +/* > + * Allocate a slab scratch space that is sufficient to keep pointers to > + * individual objects for all objects in cache and also a bitmap for the > + * objects (used to mark which objects are active). > + */ > +static inline void *alloc_scratch(struct kmem_cache *s) > +{ > + unsigned int size = oo_objects(s->max); > + > + return kmalloc(size * sizeof(void *) + > + BITS_TO_LONGS(size) * sizeof(unsigned long), > + GFP_KERNEL); I wonder how big this allocation can be? Given that the reason for migration is probably highly fragmented memory, we probably don't want to have a high-order allocation here. So maybe kvmalloc()? > +} > + > +/* > + * __move() - Move all objects in the given slab. > + * @page: The slab we are working on. > + * @scratch: Pointer to scratch space. > + * @node: The target node to move objects to. > + * > + * If the target node is not the current node then the object is moved > + * to the target node. If the target node is the current node then this > + * is an effective way of defragmentation since the current slab page > + * with its object is exempt from allocation. > + */ > +static void __move(struct page *page, void *scratch, int node) > +{ __move() isn't a very explanatory name. kmem_cache_move() (as in Christopher's version) is much better, IMO. Or maybe move_slab_objects()? Also, it's usually better to avoid adding new functions without calling them. Maybe it's possible to merge this patch with (9)? Thanks! > + unsigned long objects; > + struct kmem_cache *s; > + unsigned long flags; > + unsigned long *map; > + void *private; > + int count; > + void *p; > + void **vector = scratch; > + void *addr = page_address(page); > + > + local_irq_save(flags); > + slab_lock(page); > + > + BUG_ON(!PageSlab(page)); /* Must be s slab page */ > + BUG_ON(!page->frozen); /* Slab must have been frozen earlier */ > + > + s = page->slab_cache; > + objects = page->objects; > + map = scratch + objects * sizeof(void **); > + > + /* Determine used objects */ > + bitmap_fill(map, objects); > + for (p = page->freelist; p; p = get_freepointer(s, p)) > + __clear_bit(slab_index(p, s, addr), map); > + > + /* Build vector of pointers to objects */ > + count = 0; > + memset(vector, 0, objects * sizeof(void **)); > + for_each_object(p, s, addr, objects) > + if (test_bit(slab_index(p, s, addr), map)) > + vector[count++] = p; > + > + if (s->isolate) > + private = s->isolate(s, vector, count); > + else > + /* Objects do not need to be isolated */ > + private = NULL; > + > + /* > + * Pinned the objects. Now we can drop the slab lock. The slab > + * is frozen so it cannot vanish from under us nor will > + * allocations be performed on the slab. However, unlocking the > + * slab will allow concurrent slab_frees to proceed. So the > + * subsystem must have a way to tell from the content of the > + * object that it was freed. > + * > + * If neither RCU nor ctor is being used then the object may be > + * modified by the allocator after being freed which may disrupt > + * the ability of the migrate function to tell if the object is > + * free or not. > + */ > + slab_unlock(page); > + local_irq_restore(flags); > + > + /* Perform callback to move the objects */ > + s->migrate(s, vector, count, node, private); > +} > + > void kmem_cache_setup_mobility(struct kmem_cache *s, > kmem_cache_isolate_func isolate, > kmem_cache_migrate_func migrate) > -- > 2.21.0 >