/*
* Copyright (c) 2010-2014 Richard Braun.
*
* 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 3 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, see .
*/
#ifndef _KERN_KMEM_I_H
#define _KERN_KMEM_I_H
#include
#include
#if SLAB_USE_CPU_POOLS
/*
* L1 cache line size.
*/
#define CPU_L1_SIZE (1 << CPU_L1_SHIFT)
/*
* Per-processor cache of pre-constructed objects.
*
* The flags member is a read-only CPU-local copy of the parent cache flags.
*/
struct kmem_cpu_pool {
simple_lock_data_t lock;
int flags;
int size;
int transfer_size;
int nr_objs;
void **array;
} __aligned(CPU_L1_SIZE);
/*
* When a cache is created, its CPU pool type is determined from the buffer
* size. For small buffer sizes, many objects can be cached in a CPU pool.
* Conversely, for large buffer sizes, this would incur much overhead, so only
* a few objects are stored in a CPU pool.
*/
struct kmem_cpu_pool_type {
size_t buf_size;
int array_size;
size_t array_align;
struct kmem_cache *array_cache;
};
#endif /* SLAB_USE_CPU_POOLS */
/*
* Buffer descriptor.
*
* For normal caches (i.e. without KMEM_CF_VERIFY), bufctls are located at the
* end of (but inside) each buffer. If KMEM_CF_VERIFY is set, bufctls are
* located after each buffer.
*
* When an object is allocated to a client, its bufctl isn't used. This memory
* is instead used for redzoning if cache debugging is in effect.
*/
union kmem_bufctl {
union kmem_bufctl *next;
unsigned long redzone;
};
/*
* Redzone guard word.
*/
#ifdef __LP64__
#ifdef _HOST_BIG_ENDIAN
#define KMEM_REDZONE_WORD 0xfeedfacefeedfaceUL
#else /* _HOST_BIG_ENDIAN */
#define KMEM_REDZONE_WORD 0xcefaedfecefaedfeUL
#endif /* _HOST_BIG_ENDIAN */
#else /* __LP64__ */
#ifdef _HOST_BIG_ENDIAN
#define KMEM_REDZONE_WORD 0xfeedfaceUL
#else /* _HOST_BIG_ENDIAN */
#define KMEM_REDZONE_WORD 0xcefaedfeUL
#endif /* _HOST_BIG_ENDIAN */
#endif /* __LP64__ */
/*
* Redzone byte for padding.
*/
#define KMEM_REDZONE_BYTE 0xbb
/*
* Buffer tag.
*
* This structure is only used for KMEM_CF_VERIFY caches. It is located after
* the bufctl and includes information about the state of the buffer it
* describes (allocated or not). It should be thought of as a debugging
* extension of the bufctl.
*/
struct kmem_buftag {
unsigned long state;
};
/*
* Values the buftag state member can take.
*/
#ifdef __LP64__
#ifdef _HOST_BIG_ENDIAN
#define KMEM_BUFTAG_ALLOC 0xa110c8eda110c8edUL
#define KMEM_BUFTAG_FREE 0xf4eeb10cf4eeb10cUL
#else /* _HOST_BIG_ENDIAN */
#define KMEM_BUFTAG_ALLOC 0xedc810a1edc810a1UL
#define KMEM_BUFTAG_FREE 0x0cb1eef40cb1eef4UL
#endif /* _HOST_BIG_ENDIAN */
#else /* __LP64__ */
#ifdef _HOST_BIG_ENDIAN
#define KMEM_BUFTAG_ALLOC 0xa110c8edUL
#define KMEM_BUFTAG_FREE 0xf4eeb10cUL
#else /* _HOST_BIG_ENDIAN */
#define KMEM_BUFTAG_ALLOC 0xedc810a1UL
#define KMEM_BUFTAG_FREE 0x0cb1eef4UL
#endif /* _HOST_BIG_ENDIAN */
#endif /* __LP64__ */
/*
* Free and uninitialized patterns.
*
* These values are unconditionnally 64-bit wide since buffers are at least
* 8-byte aligned.
*/
#ifdef _HOST_BIG_ENDIAN
#define KMEM_FREE_PATTERN 0xdeadbeefdeadbeefULL
#define KMEM_UNINIT_PATTERN 0xbaddcafebaddcafeULL
#else /* _HOST_BIG_ENDIAN */
#define KMEM_FREE_PATTERN 0xefbeaddeefbeaddeULL
#define KMEM_UNINIT_PATTERN 0xfecaddbafecaddbaULL
#endif /* _HOST_BIG_ENDIAN */
/*
* Page-aligned collection of unconstructed buffers.
*
* This structure is either allocated from the slab cache, or, when internal
* fragmentation allows it, or if forced by the cache creator, from the slab
* it describes.
*/
struct kmem_slab {
struct list node;
unsigned long nr_refs;
union kmem_bufctl *first_free;
void *addr;
};
/*
* Cache name buffer size. The size is chosen so that struct
* kmem_cache fits into two cache lines. The size of a cache line on
* a typical CPU is 64 bytes.
*/
#define KMEM_CACHE_NAME_SIZE 24
/*
* Cache flags.
*
* The flags don't change once set and can be tested without locking.
*/
#define KMEM_CF_NO_CPU_POOL 0x1 /* CPU pool layer disabled */
#define KMEM_CF_SLAB_EXTERNAL 0x2 /* Slab data is off slab */
#define KMEM_CF_VERIFY 0x4 /* Debugging facilities enabled */
#define KMEM_CF_DIRECT 0x8 /* Quick buf-to-slab lookup */
/*
* Cache of objects.
*
* Locking order : cpu_pool -> cache. CPU pools locking is ordered by CPU ID.
*
* The partial slabs list is sorted by slab references. Slabs with a high
* number of references are placed first on the list to reduce fragmentation.
* Sorting occurs at insertion/removal of buffers in a slab. As the list
* is maintained sorted, and the number of references only changes by one,
* this is a very cheap operation in the average case and the worst (linear)
* case is very unlikely.
*/
struct kmem_cache {
#if SLAB_USE_CPU_POOLS
/* CPU pool layer */
struct kmem_cpu_pool cpu_pools[NCPUS];
struct kmem_cpu_pool_type *cpu_pool_type;
#endif /* SLAB_USE_CPU_POOLS */
/* Slab layer */
simple_lock_data_t lock;
struct list node; /* Cache list linkage */
struct list partial_slabs;
struct list free_slabs;
int flags;
size_t bufctl_dist; /* Distance from buffer to bufctl */
size_t slab_size;
unsigned int slab_order;
unsigned long bufs_per_slab;
unsigned long nr_objs; /* Number of allocated objects */
unsigned long nr_free_slabs;
kmem_ctor_fn_t ctor;
/* All fields below are cold */
size_t obj_size; /* User-provided size */
/* Assuming ! SLAB_USE_CPU_POOLS, here is the cacheline boundary */
size_t align;
size_t buf_size; /* Aligned object size */
size_t color;
size_t color_max;
unsigned long nr_bufs; /* Total number of buffers */
unsigned long nr_slabs;
char name[KMEM_CACHE_NAME_SIZE];
size_t buftag_dist; /* Distance from buffer to buftag */
size_t redzone_pad; /* Bytes from end of object to redzone word */
} __cacheline_aligned;
#endif /* _KERN_KMEM_I_H */