NASD Programmer's Documentation
In-core extents

Most components of the drive represent ranges of blocks as extents. The in-core representation of an extent has type nasd_odc_exlist_ent_t. The range field of this structure is a nasd_od_extent_t, which is also the out-of-core representation of an extent. Additionally, a nasd_odc_exlist_ent_t has next and prev pointers for forming linked and doubly-linked lists of this type.

Lists of in-core extents are often maintained by the list structure nasd_odc_exlist_t. This structure contains a lock for serializing accesses to the list. It also caches the number of blocks in the list in the num field. List entries themselves are doubly-linked off the head field, which is a dummy nasd_odc_exlist_ent_t whose only valid fields are next and prev.

Most of the code that implements extent-list management is in nasd_free.c. This module implements basic extent-list management. It also contains the lists used by the drive to keep track of unallocated regions on the drive, and manages them.

Extent lists

To create a managed list of extents (nasd_odc_exlist_t), use nasd_odc_exlist_get(). This takes an indirect pointer to a nasd_odc_exlist_t, which it fills in with a pointer to an empty list.

nasd_status_t nasd_odc_exlist_get(nasd_odc_exlist_t **exlp)

This list may be deallocated with

void nasd_odc_exlist_free(nasd_odc_exlist_t *exl) However, this only deallocates the list structure itself.

Alternatively, a caller may use

nasd_status_t nasd_odc_init_exlist(nasd_odc_exlist_t *exl) to initialize a nasd_odc_exlist_t to a valid, empty state, provided that the caller allocates the memory for the nasd_odc_exlist_t. In that case, nasd_status_t nasd_odc_destroy_exlist(nasd_odc_exlist_t *exl) deallocates resources used to maintain the list, without deallocating its contents. Additionally, void nasd_odc_shutdown_exlist(void *arg) both deallocates resources used to maintain the list and the list contents. This function takes a void pointer, but a pointer to a nasd_odc_exlist_t should be passed. The declared type of this pointer is void so this may easily be used as a shutdown procedure.

To allocate a single list entry, use

nasd_status_t nasd_odc_get_extent_list(nasd_odc_exlist_ent_t **exlp) To free a list of entries, use: void nasd_odc_release_extent_list(nasd_odc_exlist_ent_t *ent) This traverses ent as a NULL-terminated singly-linked list of entries linked on the next field, freeing each entry.

To add a set of block to a nasd_odc_exlist_t, use

nasd_status_t nasd_odc_free_release_blocks_to_list(
  nasd_odc_exlist_t      *exl,
  nasd_odc_exlist_ent_t  *release,
  nasd_blkcnt_t          *release_cnt_p)
This function takes release as a NULL-terminated singly-linked list of entries (linked on the next field) to add to exl. The memory occupied by entries in the release list will either be reused or deallocated (that is, the caller is surrendering the entries in this list). The number of blocks contained in the release list will be returned in nasd_release_cnt_p.

To retrieve blocks from a nasd_odc_exlist_t, use

nasd_status_t nasd_odc_exlist_get_blocks(
  nasd_odc_exlist_t       *exl,
  nasd_blkcnt_t            nblocks,
  nasd_blkno_t             first,
  nasd_blkno_t             last,
  int                      partial_single_range,
  nasd_odc_exlist_ent_t  **exlp,
  nasd_blkcnt_t           *blocks_allocated_p)
This function retrieves up to nblocks blocks from exl, returning them in a singly-linked list at *exlp. If first is nonzero, this function begins looking for free blocks whose block number is greater than or equal to first. If last is nonzero, blocks numbered greater than last will not be returned. If last is zero, and less than nblocks blocks are availble from first to the end of exl, then some entries in *exlp may represent blocks before first. *exlp is sorted on order-of-finding within exl, so if this wraparound is necessary, blocks before first will follow those blocks after first in *exlp. If partial_single_range is nonzero, then *exlp will contain at most one entry, even if this does not contain nblocks blocks. The number of blocks at *exlp is returned in *blocks_allocated_p.

Calling nasd_odc_exlist_get_blocks() can often be too heavyweight when only a single block is desired. In such cases, it may be useful to use

nasd_status_t nasd_odc_exlist_get_oneblock(
  nasd_odc_exlist_t  *exl,
  nasd_blkno_t        first,
  nasd_blkno_t       *blkp)
instead. This searches exl starting with first for a single block, wrapping to the beginning of exl if and only if necessary. The block found is returned in *blkp.

To add a single block to a nasd_odc_exlist_t, use

nasd_status_t nasd_odc_exlist_release_oneblock(
  nasd_odc_exlist_t  *exl,
  nasd_blkno_t        blknum)

The function

nasd_status_t
nasd_odc_exlist_get_contig(
  nasd_odc_exlist_t       *exl,
  nasd_blkno_t             first,
  nasd_blkcnt_t            nblocks,
  nasd_odc_exlist_ent_t  **exlp)
searches exl starting with block first for the smallest contiguous range of blocks which is at least nblocks long. If successful, the first nblocks of that range are returned in *exlp.

Drive free blocks

The same module which provides extent lists uses them to track unallocated drive blocks. At drive initialization time, nasd_odc_freeblock_build_lists() examines the physical reference counts, and tracks those blocks whose refcnt is zero. A separate set of interfaces, described below, performs allocations and deallocations on this list of extents. The primary users of these interfaces are the layout policy modules. Most other parts of the drive use the layout module to perform block allocations and deallocations. nasd_status_t nasd_odc_free_get_range(
  nasd_blkcnt_t            nblocks,
  nasd_blkno_t             first,
  nasd_odc_exlist_ent_t  **exlp,
  nasd_blkcnt_t           *blocks_allocated_p)
uses nasd_odc_exlist_get_blocks() to obtain a set of these blocks. nasd_status_t nasd_odc_free_get_range_bounded_partial(
  nasd_blkcnt_t            nblocks,
  nasd_blkno_t             first,
  nasd_blkno_t             last,
  nasd_odc_exlist_ent_t  **exlp,
  nasd_blkcnt_t           *blocks_allocated_p)
performs a nasd_odc_exlist_get_blocks() on the set of unallocated blocks with partial_single_range set nonzero.

If a single range of unallocated blocks is desired and where they may be located is less restrictive, the caller may wish to use

nasd_status_t nasd_odc_free_get_partial_range(
  nasd_blkcnt_t            nblocks,
  nasd_blkno_t             first,
  nasd_odc_exlist_ent_t  **exlp)
which will start looking for blocks at first, but may wrap around. At most one range of blocks will be returned, even if this does not satisfy nblocks.

To return a single block to the list of unallocated blocks, use

nasd_status_t nasd_odc_free_release_oneblock(nasd_blkno_t blknum)

Finally, when debugging it may be useful to call nasd_odc_free_dump() (which takes no arguments and returns void). This function will print all ranges of unallocated blocks.


<--- ---> ^<br>|<br>|
Inodes Cache NASD Programmer's Documentation