NAME
extent,
extent_create,
extent_destroy,
extent_alloc,
extent_alloc_subregion,
extent_alloc1,
extent_alloc_subregion1,
extent_alloc_region,
extent_free,
extent_print —
general purpose extent
manager
SYNOPSIS
#include <sys/malloc.h>
#include <sys/extent.h>
struct extent *
extent_create(
char
*name,
u_long start,
u_long end,
void *storage,
size_t storagesize,
int flags);
void
extent_destroy(
struct
extent *ex);
int
extent_alloc(
struct
extent *ex,
u_long
size,
u_long
alignment,
u_long
boundary,
int flags,
u_long *result);
int
extent_alloc_subregion(
struct
extent *ex,
u_long
substart,
u_long
subend,
u_long size,
u_long alignment,
u_long boundary,
u_long flags,
u_long *result);
int
extent_alloc1(
struct
extent *ex,
u_long
size,
u_long
alignment,
u_long
skew,
u_long
boundary,
int flags,
u_long *result);
int
extent_alloc_subregion1(
struct extent
*ex,
u_long substart,
u_long
subend,
u_long size,
u_long
alignment,
u_long skew,
u_long
boundary,
u_long flags,
u_long
*result);
int
extent_alloc_region(
struct
extent *ex,
u_long
start,
u_long size,
int flags);
int
extent_free(
struct
extent *ex,
u_long
start,
u_long size,
int flags);
void
extent_print(
struct
extent *ex);
DESCRIPTION
The
NetBSD extent manager provides management of areas
of memory or other number spaces (such as I/O ports). An opaque structure
called an
extent map keeps track of allocated regions within
the number space.
extent_create() creates an extent map managing the space from
start to
end inclusive. The extent
map will have the name
name, used for identification in
case of an error. If the flag
EX_NOCOALESCE
is
specified, only entire regions may be freed within the extent map, but
internal coalescing of regions is disabled so that
extent_free() will never have to allocate a region
descriptor and therefore will never fail. The caller must specify one of the
flags
EX_NOWAIT
or
EX_WAITOK
,
specifying whether it is okay to wait for memory allocated for extent map
overhead.
There are some applications which may want to use an extent map but can't use
malloc() and
free(). These applications
may provide pre-allocated storage for all descriptor overhead with the
arguments
storage and
storagesize.
An extent of this type is called a
fixed extent. If the
application can safely use
malloc() and
free(),
storage should be
NULL
. A fixed extent has a fixed number of region
descriptors, so care should be taken to provide enough storage for them;
alternatively, the flag
EX_MALLOCOK
may be passed to
allocation requests to indicate that a fixed extent map may be extended using
a call to
malloc().
extent_destroy() destroys the extent map
ex, freeing all allocated regions. If the extent is not
a fixed extent, the region and internal extent descriptors themselves are
freed. This function always succeeds.
extent_alloc() allocates a region in extent
ex of size
size that fits the
provided parameters. There are two distinct allocation policies, which are
selected by the
flags argument:
-
-
EX_FAST
- Allocate the first region that fits the provided
parameters, regardless of resulting extent fragmentation.
-
-
- default
- Allocate the smallest region that is capable of holding the
request, thus minimizing fragmentation of the extent.
The caller must specify if waiting for space in the extent is allowed using the
flag
EX_WAITSPACE
. If
EX_WAITSPACE
is not specified, the allocation will
fail if the request can not be satisfied without sleeping. The caller must
also specify, using the
EX_NOWAIT
or
EX_WAITOK
flags, if waiting for overhead allocation is
allowed. The request will be aligned to
alignment
boundaries. Alignment values must be a power of 2. If no alignment is
necessary, the value 1 should be specified. If
boundary
is nonzero, the allocated region will not cross any of the numbers which are a
multiple of
boundary. If the caller specifies the
EX_BOUNDZERO
flag, the boundary lines begin at zero.
Otherwise, the boundary lines begin at the beginning of the extent. The
allocated region may begin on a boundary address, but the end of the region
will not touch nor cross it. A boundary argument smaller than the size of the
request is invalid. Upon successful completion,
*result
will contain the start of the allocated region.
extent_alloc_subregion() is similar to
extent_alloc(), but it allows the caller to specify that the
allocated region must fall within the subregion from
substart to
subend inclusive. The
other arguments and the return values of
extent_alloc_subregion() are otherwise the same as those of
extent_alloc().
extent_alloc_region() allocates the specific region in the
extent map
ex beginning at
start
with the size
size. The caller must specify whether it
is okay to wait for the indicated region to be free using the flag
EX_WAITSPACE
. If
EX_WAITSPACE
is not specified, the allocation will fail if the request can not be satisfied
without sleeping. The caller must also specify, using the
EX_NOWAIT
or
EX_WAITOK
flags,
if waiting for overhead allocation is allowed.
The
extent_alloc1() and
extent_alloc_subregion1() functions are extensions that take
one additional argument,
skew, that modifies the
requested alignment result in the following way: the value
(
result -
skew) is aligned to
alignment
boundaries.
skew must be a smaller number than
alignment. Also, a boundary argument smaller than the
sum of the requested skew and the size of the request is invalid.
extent_free() frees a region of
size
bytes in extent
ex starting at
start. If the extent has the
EX_NOCOALESCE
property, only entire regions may be
freed. If the extent has the
EX_NOCOALESCE
property
and the caller attempts to free a partial region, behavior is undefined. The
caller must specify one of the flags
EX_NOWAIT
or
EX_WAITOK
to specify whether waiting for memory is
okay; these flags have meaning in the event that allocation of a region
descriptor is required during the freeing process. This situation occurs only
when a partial region that begins and ends in the middle of another region is
freed. Behavior is undefined if invalid arguments are provided.
extent_print() Print out information about extent
ex. This function always succeeds. Behavior is undefined
if invalid arguments are provided.
LOCKING
The extent manager performs all necessary locking on the extent map itself, and
any other data structures internal to the extent manager. The locks used by
the extent manager are simplelocks, and will never sleep (see
lock(9)). This should be taken
into account when designing the locking protocol for users of the extent
manager.
RETURN VALUES
The behavior of all extent manager functions is undefined if given invalid
arguments.
extent_create() returns the extent map on
success, or
NULL
if it fails to allocate storage for
the extent map. It always succeeds when creating a fixed extent or when given
the flag
EX_WAITOK
.
extent_alloc(),
extent_alloc_region(),
extent_alloc_subregion(), and
extent_free() return one of the following values:
-
-
0
- Operation was successful.
-
-
ENOMEM
- If
EX_NOWAIT
is specified, the
extent manager was not able to allocate a region descriptor for the new
region or to split a region when freeing a partial region.
-
-
EAGAIN
- Requested region is not available and
EX_WAITSPACE
was not specified.
-
-
EINTR
- Process received a signal while waiting for the requested
region to become available in the extent. Does not apply to
extent_free().
EXAMPLES
Here is an example of a (useless) function that uses several of the extent
manager routines.
void
func()
{
struct extent *foo_ex;
u_long region_start;
int error;
/*
* Extent "foo" manages a 256k region starting at 0x0 and
* only allows complete regions to be freed so that
* extent_free() never needs to allocate memory.
*/
foo_ex = extent_create("foo", 0x0, 0x3ffff, M_DEVBUF,
NULL, 0, EX_WAITOK | EX_NOCOALESCE);
/*
* Allocate an 8k region, aligned to a 4k boundary, which
* does not cross any of the 3 64k boundaries (at 64k,
* 128k, and 192k) within the extent.
*/
error = extent_alloc(foo_ex, 0x2000, 0x1000, 0x10000,
EX_NOWAIT, ®ion_start);
if (error)
panic("you lose");
/*
* Give up the extent.
*/
extent_destroy(foo_ex);
}
CODE REFERENCES
The extent manager itself is implemented within the file
sys/kern/subr_extent.c. Function prototypes for the
framework are located in
sys/sys/extent.h.
The i386 bus management code uses the extent manager for managing I/O ports and
I/O memory. This code is in the file
sys/arch/i386/i386/machdep.c.
SEE ALSO
malloc(9)
HISTORY
The
NetBSD extent manager appeared in
NetBSD 1.3.
AUTHORS
The
NetBSD extent manager was architected and
implemented by
Jason R. Thorpe
⟨thorpej@NetBSD.org⟩.
Matthias Drochner
⟨drochner@zelux6.zel.kfa-juelich.de⟩ contributed to the initial
testing and optimization of the implementation.
Chris Demetriou ⟨cgd@NetBSD.org⟩
contributed many architectural suggestions.