No, this isn't a joke.  No, it doesn't even really have anything to do
with my employer ;-)

What it is about is saving some stack space in the slub allocator.
You see, slub has some bitfields embedded in struct page which it wants
to be able to access as a single unsigned int.  To avoid repeating the
definition of the bitfield, it allocates a struct page on the stack
which costs 64 bytes at a time.

If only we could embed a named struct in an unnamed way.  Well,
gcc has two extensions that let us do that; -fms-extensions and
-fplan9-extensions.  I'd prefer to use -fplan9-extensions (because they
enable some amazing other improvements), but they weren't added until
gcc-4.6, while -fms-extensions were added back in the egcs days.

Here's what it looks like for slub, but as Johannes pointed out to me,
this is something that networking already does with some amazing macro
preprocessing tricks, and it'd be nice for those to go away as well.

diff --git a/Makefile b/Makefile
index e811e0c509c5..53265a92f689 100644
--- a/Makefile
+++ b/Makefile
@@ -422,7 +422,7 @@ KBUILD_CFLAGS   := -Wall -Wundef -Wstrict-prototypes 
-Wno-trigraphs \
                   -fno-strict-aliasing -fno-common -fshort-wchar \
                   -Werror-implicit-function-declaration \
                   -Wno-format-security \
-                  -std=gnu89
+                  -std=gnu89 -fms-extensions
 KBUILD_CPPFLAGS := -D__KERNEL__
 KBUILD_AFLAGS_KERNEL :=
 KBUILD_CFLAGS_KERNEL :=
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 21612347d311..ee2c59ff4cd5 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -65,15 +65,20 @@ struct hmm;
  */
 #ifdef CONFIG_HAVE_ALIGNED_STRUCT_PAGE
 #define _struct_page_alignment __aligned(2 * sizeof(unsigned long))
-#if defined(CONFIG_HAVE_CMPXCHG_DOUBLE)
-#define _slub_counter_t                unsigned long
 #else
-#define _slub_counter_t                unsigned int
-#endif
-#else /* !CONFIG_HAVE_ALIGNED_STRUCT_PAGE */
 #define _struct_page_alignment
-#define _slub_counter_t                unsigned int
-#endif /* !CONFIG_HAVE_ALIGNED_STRUCT_PAGE */
+#endif
+
+struct slub_counters {
+       union {
+               unsigned long counters;
+               struct {
+                       unsigned inuse:16;
+                       unsigned objects:15;
+                       unsigned frozen:1;
+               };
+       };
+};
 
 struct page {
        /* First double word block */
@@ -96,13 +101,8 @@ struct page {
        };
 
        union {
-               _slub_counter_t counters;
                unsigned int active;            /* SLAB */
-               struct {                        /* SLUB */
-                       unsigned inuse:16;
-                       unsigned objects:15;
-                       unsigned frozen:1;
-               };
+               struct slub_counters;
                int units;                      /* SLOB */
 
                struct {                        /* Page cache */
diff --git a/mm/slub.c b/mm/slub.c
index 44aa7847324a..2071a10c667d 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -356,9 +356,14 @@ static __always_inline void slab_unlock(struct page *page)
        __bit_spin_unlock(PG_locked, &page->flags);
 }
 
+struct slub_freelist {
+       void *freelist;
+       struct slub_counters;
+};
+
 static inline void set_page_slub_counters(struct page *page, unsigned long 
counters_new)
 {
-       struct page tmp;
+       struct slub_counters tmp;
        tmp.counters = counters_new;
        /*
         * page->counters can cover frozen/inuse/objects as well
@@ -1782,7 +1787,7 @@ static inline void *acquire_slab(struct kmem_cache *s,
 {
        void *freelist;
        unsigned long counters;
-       struct page new;
+       struct slub_freelist new;
 
        lockdep_assert_held(&n->list_lock);
 
@@ -2032,8 +2037,8 @@ static void deactivate_slab(struct kmem_cache *s, struct 
page *page,
        enum slab_modes l = M_NONE, m = M_NONE;
        void *nextfree;
        int tail = DEACTIVATE_TO_HEAD;
-       struct page new;
-       struct page old;
+       struct slub_freelist new;
+       struct slub_freelist old;
 
        if (page->freelist) {
                stat(s, DEACTIVATE_REMOTE_FREES);
@@ -2183,8 +2188,8 @@ static void unfreeze_partials(struct kmem_cache *s,
        struct page *page, *discard_page = NULL;
 
        while ((page = c->partial)) {
-               struct page new;
-               struct page old;
+               struct slub_freelist new;
+               struct slub_freelist old;
 
                c->partial = page->next;
 
@@ -2491,7 +2496,7 @@ static inline bool pfmemalloc_match(struct page *page, 
gfp_t gfpflags)
  */
 static inline void *get_freelist(struct kmem_cache *s, struct page *page)
 {
-       struct page new;
+       struct slub_counters new;
        unsigned long counters;
        void *freelist;
 
@@ -2815,7 +2820,7 @@ static void __slab_free(struct kmem_cache *s, struct page 
*page,
 {
        void *prior;
        int was_frozen;
-       struct page new;
+       struct slub_counters new;
        unsigned long counters;
        struct kmem_cache_node *n = NULL;
        unsigned long uninitialized_var(flags);

Reply via email to