Chapter3:MemoryManagement
The fifth and last part (statistics fields that are of no further interest for our purposes) ofstruct
kmem_cacheconsists of two further elements:
❑ nameis a string containing a human-readable name for the cache. It is used, for example, to list
the available caches in/proc/slabinfo.
❑ nextis a standard list element to keep all instances ofkmem_cacheon the global listcache_chain.
Initialization
At first sight, initialization of the slab system does not appear to be especially complicated because the
buddy system is already fully enabled and no other particular restrictions are imposed on the kernel.
Nevertheless, there is achicken-and-eggproblem^34 because of the structure of the slab allocator.
To initialize the slab data structures, the kernel needs memory blocks that are much smaller than a com-
plete page and are therefore best allocated bykmalloc. And here’s the crux:kmalloconly functions if the
slab system is already enabled.
To be more accurate, the problem lies with the initialization of the per-CPU caches forkmalloc.Before
these caches can be initialized,kmallocmust be available to reserve the required memory space, and
kmallocitself is just in the process of being initialized. In other words,kmalloccan only be initialized
oncekmallochas been initialized — an impossible scenario. The kernel must therefore resort to a few
tricks.
Thekmem_cache_initfunction is used to initialize the slab allocator. It is invoked during the kernel
initialization phase (start_kernel) once the buddy system is enabled. However, on multiprocessor
systems, the boot CPU is running and the other CPUs are not yet initialized.kmem_cache_initemploys
a multistep process to activate the slab allocator step-by-step:
- kmem_cache_initcreates the first slab cache in the system to generate memory for instances
ofkmem_cache. To this end, the kernel uses mainly static data created at compilation time; in
fact, a static data structure (initarray_cache) is used as a per-CPU array. The name of this
cache iscache_cache. - kmem_cache_initthen initializes the general caches that serve as a source forkmalloc.For
this purpose,kmem_cache_createis invoked for each cache size required. The function first
needs only thecache_cachecache already created; however, when the per-CPU caches are
to be initialized, the function must resort tokmalloc, and this is not yet possible.
To resolve this problem, the kernel uses theg_cpucache_upvariable, which can accept one
of four values (NONE,PARTIAL_AC,PARTIAL_L3,orFULL) to reflect the state ofkmallocinitial-
ization.
Initially the state of the kernel isNONE. When the smallestkmalloccache (which provides
memory blocks of 32 bytes on machines with 4 KiB memory pages; if other page sizes are
used, the smallest allocation size is 64 bytes; the exact definition of existing sizes is given
in Section 3.6.5) is initialized, a static variable is again used for the per-CPU cache data.
(^34) Chicken-and-egg problemsare encountered where something cannot happen until a second thing does, and the second thing cannot
happen until the first does. For example, B must be present in orderto initialize A, but A must be present to initialize B. It’s the age-
old question of which came first, the chicken or the egg?
If you are a scientist, you can also use the termcausality dilemma, which expresses exactly the same, but sounds much more
educated....