summaryrefslogblamecommitdiff
path: root/sos-code-article6.5/sos/kmem_slab.h
blob: 1f28ff9f659bd57eb61b518d6c97259dab5ffa87 (plain) (tree)













































































































































































































                                                                                      
/* Copyright (C) 2000 Thomas Petazzoni
   Copyright (C) 2004 David Decotigny

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License
   as published by the Free Software Foundation; either version 2
   of the License, or (at your option) any later version.
   
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
   USA. 
*/
#ifndef _SOS_KMEM_SLAB_H_
#define _SOS_KMEM_SLAB_H_

/**
 * @file kmem_slab.h
 *
 * Kernel Memory Allocator based on Bonwick's slab llocator (Solaris
 * 2.4, Linux 2.4). This allocator achieves good memory utilization
 * ratio (memory effectively used / memory requested) ie limited
 * fragmentation, while elegantly handling cache-effect considerations
 * (TLB locality through the notion of "cache" of slabs, and the
 * dcache utilization through the notion of cache colouring to
 * decrease the conflicts in the dcache for accesses to different data
 * in the same cache).
 *
 * This allocator relies on the range allocator (kmem_vmm.h) to
 * allocate the slabs, which itself relies on the slab allocator to
 * allocate its "range" data structures, thus leading to a
 * chicken-and-egg problem. We solve this problem by introducing the
 * notion of "min_free_objs" for the slab caches, in order for the cache
 * of ranges to always have enough ranges in reserve to complete the
 * range allocation before being urged to allocate a new slab of
 * ranges, which would require the allocation of a new range.
 *
 * Compared to Bonwick's recommendations, we don't handle ctor/dtor
 * routines on the objects, so that we can alter the objects once they
 * are set free. Thus, the list of free object is stored in the free
 * objects themselves, not alongside the objects (this also implies that
 * the SOS_KSLAB_CREATE_MAP flag below is meaningless). We also don't
 * implement the cache colouring (trivial to add, but we omit it for
 * readability reasons), and the only alignment constraint we respect
 * is that allocated objects are aligned on a 4B boundary: for other
 * alignment constraints, the user must integrate them in the
 * "object_size" parameter to "sos_kmem_cache_create()".
 *
 * References :
 * - J. Bonwick's paper, "The slab allocator: An object-caching kernel
 *   memory allocator", In USENIX Summer 1994 Technical Conference
 * - The bible, aka "Unix internals : the new frontiers" (section
 *   12.10), Uresh Vahalia, Prentice Hall 1996, ISBN 0131019082
 * - "The Linux slab allocator", B. Fitzgibbons,
 *   http://www.cc.gatech.edu/people/home/bradf/cs7001/proj2/
 * - The Kos, http://kos.enix.org/
 */
#include <sos/types.h>
#include <sos/errno.h>

/** Opaque data structure that defines a Cache of slabs */
struct sos_kslab_cache;

/** Opaque data structure that defines a slab. Exported only to
    kmem_vmm.h */
struct sos_kslab;

#include "kmem_vmm.h"


/** The maximum  allowed pages for each slab */
#define MAX_PAGES_PER_SLAB 32 /* 128 kB */


/**
 * Initialize the slab cache of slab caches, and prepare the cache of
 * kmem_range for kmem_vmm.
 *
 * @param kernel_core_base The virtual address of the first byte used
 * by the kernel code/data
 *
 * @param kernel_core_top The virtual address of the first byte after
 * the kernel code/data.
 *
 * @param sizeof_struct_range the size of the objects (aka "struct
 * sos_kmem_vmm_ranges") to be allocated in the cache of ranges
 *
 * @param first_struct_slab_of_caches (output value) the virtual
 * address of the first slab structure that gets allocated for the
 * cache of caches. The function actually manually allocate the first
 * slab of the cache of caches because of a chicken-and-egg thing. The
 * address of the slab is used by the kmem_vmm_setup routine to
 * finalize the allocation of the slab, in order for it to behave like
 * a real slab afterwards.
 *
 * @param first_slab_of_caches_base (output value) the virtual address
 * of the slab associated to the slab structure.
 *
 * @param first_slab_of_caches_nb_pages (output value) the number of
 * (virtual) pages used by the first slab of the cache of caches.
 *
 * @param first_struct_slab_of_ranges (output value) the virtual address
 * of the first slab that gets allocated for the cache of ranges. Same
 * explanation as above.
 *
 * @param first_slab_of_ranges_base (output value) the virtual address
 * of the slab associated to the slab structure.
 *
 * @param first_slab_of_ranges_nb_pages (output value) the number of
 * (virtual) pages used by the first slab of the cache of ranges.
 *
 * @return the cache of kmem_range immediatly usable
 */
struct sos_kslab_cache *
sos_kmem_cache_subsystem_setup_prepare(sos_vaddr_t kernel_core_base,
				       sos_vaddr_t kernel_core_top,
				       sos_size_t  sizeof_struct_range,
				       /* results */
				       struct sos_kslab **first_struct_slab_of_caches,
				       sos_vaddr_t *first_slab_of_caches_base,
				       sos_count_t *first_slab_of_caches_nb_pages,
				       struct sos_kslab **first_struct_slab_of_ranges,
				       sos_vaddr_t *first_slab_of_ranges_base,
				       sos_count_t *first_slab_of_ranges_nb_pages);

/**
 * Update the configuration of the cache subsystem once the vmm
 * subsystem has been fully initialized
 */
sos_ret_t
sos_kmem_cache_subsystem_setup_commit(struct sos_kslab *first_struct_slab_of_caches,
				      struct sos_kmem_range *first_range_of_caches,
				      struct sos_kslab *first_struct_slab_of_ranges,
				      struct sos_kmem_range *first_range_of_ranges);


/*
 * Flags for sos_kmem_cache_create()
 */
/** The slabs should be initially mapped in physical memory */
#define SOS_KSLAB_CREATE_MAP  (1<<0)
/** The object should always be set to zero at allocation (implies
    SOS_KSLAB_CREATE_MAP) */
#define SOS_KSLAB_CREATE_ZERO (1<<1)

/**
 * @note this function MAY block (involved allocations are not atomic)
 * @param name must remain valid during the whole cache's life
 *             (shallow copy) !
 * @param cache_flags An or-ed combination of the SOS_KSLAB_CREATE_* flags
 */
struct sos_kslab_cache *
sos_kmem_cache_create(const char* name,
		      sos_size_t  object_size,
		      sos_count_t pages_per_slab,
		      sos_count_t min_free_objects,
		      sos_ui32_t  cache_flags);

sos_ret_t sos_kmem_cache_destroy(struct sos_kslab_cache *kslab_cache);


/*
 * Flags for sos_kmem_cache_alloc()
 */
/** Allocation should either succeed or fail, without blocking */
#define SOS_KSLAB_ALLOC_ATOMIC (1<<0)

/**
 * Allocate an object from the given cache.
 *
 * @param alloc_flags An or-ed combination of the SOS_KSLAB_ALLOC_* flags
 */
sos_vaddr_t sos_kmem_cache_alloc(struct sos_kslab_cache *kslab_cache,
				 sos_ui32_t alloc_flags);


/**
 * Free an object (assumed to be already allocated and not already
 * free) at the given virtual address.
 */
sos_ret_t sos_kmem_cache_free(sos_vaddr_t vaddr);


/*
 * Function reserved to kmem_vmm.c. Does almost everything
 * sos_kmem_cache_free() does, except it does not call
 * sos_kmem_vmm_del_range() if it needs to. This is aimed at avoiding
 * large recursion when a range is freed with
 * sos_kmem_vmm_del_range().
 *
 * @param the_range The range structure to free
 *
 * @return NULL when the range containing 'the_range' still contains
 * other ranges, or the address of the range which owned 'the_range'
 * if it becomes empty.
 */
struct sos_kmem_range *
sos_kmem_cache_release_struct_range(struct sos_kmem_range *the_range);


#endif /* _SOS_KMEM_SLAB_H_ */