summaryrefslogtreecommitdiffstats
path: root/cpukit/libblock/include/rtems/bdbuf.h
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/libblock/include/rtems/bdbuf.h')
-rw-r--r--cpukit/libblock/include/rtems/bdbuf.h230
1 files changed, 171 insertions, 59 deletions
diff --git a/cpukit/libblock/include/rtems/bdbuf.h b/cpukit/libblock/include/rtems/bdbuf.h
index 56dc9b44cb..52ee557054 100644
--- a/cpukit/libblock/include/rtems/bdbuf.h
+++ b/cpukit/libblock/include/rtems/bdbuf.h
@@ -1,7 +1,7 @@
/**
- * @file rtems/bdbuf.h
+ * @file
*
- * Block Device Buffer Management
+ * Block device buffer management.
*/
/*
@@ -28,21 +28,101 @@
#ifdef __cplusplus
extern "C" {
#endif
+
+/**
+ * @defgroup rtems_libblock Block Device Library
+ */
+/**
+ * @defgroup rtems_bdbuf Block Device Buffer Management
+ *
+ * @ingroup rtems_libblock
+ *
+ * The Block Device Buffer Management implements a cache between the disk
+ * devices and file systems. The code provides read ahead and write queuing to
+ * the drivers and fast cache look up using an AVL tree.
+ *
+ * The buffers are held in pools based on size. Each pool has buffers and the
+ * buffers follow this state machine:
+ *
+ * @dot
+ * digraph g {
+ * ready [label="Ready\nRead Ahead"];
+ * transfer [label="Transfer"];
+ * accessed [label="Accessed\nAccessed Modified"];
+ * modified [label="Modified\nSynchronized"];
+ * cached [label="Cached"];
+ * ready -> transfer [label="Read\nRead Ahead"];
+ * transfer -> ready [label="Read Ahead Complete"];
+ * ready -> accessed [label="Get"];
+ * transfer -> accessed [label="Read or Write\nComplete"];
+ * transfer -> cached [label="Read or Write\nComplete"];
+ * accessed -> cached [label="Release"];
+ * cached -> accessed [label="Get"];
+ * modified -> accessed [label="Get"];
+ * accessed -> modified [label="Modified"];
+ * accessed -> transfer [label="Swap"];
+ * }
+ * @enddot
+ *
+ * Empty buffers are added to the ready list and removed from this queue when a
+ * caller requests a buffer. This is referred to as getting a buffer in the
+ * code and the event get in the state diagram. The buffer is assigned to a
+ * block and inserted to the AVL based on the block/device key. If the block is
+ * to be read by the user and not in the cache (ready) it is transfered from
+ * the disk into memory. If no ready buffers exist the buffer is taken from the
+ * LRU list. If no buffers are on the LRU list the modified list is check. If
+ * no buffers are on the modified list the request blocks. If buffers are on
+ * the modified list the buffers hold timer is expired and the swap out task
+ * woken.
+ *
+ * A block being accessed is given to the file system layer and not accessable
+ * to another requester until released back to the cache. The same goes to a
+ * buffer in the transfer state. The transfer state means being read or
+ * written. If the file system has modifed the block and releases it as
+ * modified it placed on the pool's modified list and a hold timer
+ * initialised. The buffer is held for the hold time before being written to
+ * disk. Buffers are held for a configurable period of time on the modified
+ * list as a write sets the state to transfer and this locks the buffer out
+ * from the file system until the write complete. Buffers are often repeatable
+ * accessed and modified in a series of small updates so if sent to the disk
+ * when released as modified the user would have to block waiting until it had
+ * been written. This would be a performance problem.
+ *
+ * The code performs mulitple block reads and writes. Multiple block reads or
+ * read ahead increases performance with hardware that supports it. It also
+ * helps with a large cache as the disk head movement is reduced. It how-ever
+ * is a speculative operation so excessive use can remove valuable and needed
+ * blocks from the cache. The get call knows if a read is a for the file system
+ * or if it is a read ahead get. If the get is for a read ahead block and the
+ * block is already in the cache or no ready buffers are available the read
+ * ahead is stopped. The transfer occurs with the blocks so far. If a buffer is
+ * in the read ahead state and release it is placed on the ready list rather
+ * than the LRU list. This means these buffers are used before buffers used by
+ * the file system.
+ *
+ * The pool has the following lists of buffers:
+ * - @c ready: Empty buffers created when the pool is initialised.
+ * - @c modified: Buffers waiting to be written to disk.
+ * - @c sync: Buffers to be synced to disk.
+ * - @c lru: Accessed buffers released in least recently used order.
+ *
+ * @{
+ */
/**
* State of a buffer in the cache.
*/
typedef enum
{
- RTEMS_BDBUF_STATE_EMPTY = 0, /*< Not in use. */
- RTEMS_BDBUF_STATE_READ_AHEAD = 1, /*< Holds read ahead data only */
- RTEMS_BDBUF_STATE_CACHED = 2, /*< In the cache and available */
- RTEMS_BDBUF_STATE_ACCESS = 3, /*< The user has the buffer */
- RTEMS_BDBUF_STATE_MODIFIED = 4, /*< In the cache but modified */
- RTEMS_BDBUF_STATE_ACCESS_MODIFIED = 5, /*< With the user but modified */
- RTEMS_BDBUF_STATE_SYNC = 6, /*< Requested to be sync'ed */
- RTEMS_BDBUF_STATE_TRANSFER = 7 /*< Being transferred to or from disk */
+ RTEMS_BDBUF_STATE_EMPTY = 0, /**< Not in use. */
+ RTEMS_BDBUF_STATE_READ_AHEAD = 1, /**< Holds read ahead data only */
+ RTEMS_BDBUF_STATE_CACHED = 2, /**< In the cache and available */
+ RTEMS_BDBUF_STATE_ACCESS = 3, /**< The user has the buffer */
+ RTEMS_BDBUF_STATE_MODIFIED = 4, /**< In the cache but modified */
+ RTEMS_BDBUF_STATE_ACCESS_MODIFIED = 5, /**< With the user but modified */
+ RTEMS_BDBUF_STATE_SYNC = 6, /**< Requested to be sync'ed */
+ RTEMS_BDBUF_STATE_TRANSFER = 7 /**< Being transferred to or from disk */
} rtems_bdbuf_buf_state;
/**
@@ -57,27 +137,27 @@ typedef struct rtems_bdbuf_buffer
struct rtems_bdbuf_avl_node
{
- signed char cache; /*< Cache */
- struct rtems_bdbuf_buffer* left; /*< Left Child */
- struct rtems_bdbuf_buffer* right; /*< Right Child */
- signed char bal; /*< The balance of the sub-tree */
+ signed char cache; /**< Cache */
+ struct rtems_bdbuf_buffer* left; /**< Left Child */
+ struct rtems_bdbuf_buffer* right; /**< Right Child */
+ signed char bal; /**< The balance of the sub-tree */
} avl;
- dev_t dev; /*< device number */
- rtems_blkdev_bnum block; /*< block number on the device */
+ dev_t dev; /**< device number */
+ rtems_blkdev_bnum block; /**< block number on the device */
- unsigned char* buffer; /*< Pointer to the buffer memory area */
- int error; /*< If not 0 indicate an error value (errno)
+ unsigned char* buffer; /**< Pointer to the buffer memory area */
+ int error; /**< If not 0 indicate an error value (errno)
* which can be used by user later */
- volatile rtems_bdbuf_buf_state state; /*< State of the buffer. */
+ volatile rtems_bdbuf_buf_state state; /**< State of the buffer. */
- volatile uint32_t waiters; /*< The number of threads waiting on this
+ volatile uint32_t waiters; /**< The number of threads waiting on this
* buffer. */
- rtems_bdpool_id pool; /*< Identifier of buffer pool to which this buffer
+ rtems_bdpool_id pool; /**< Identifier of buffer pool to which this buffer
belongs */
- volatile uint32_t hold_timer; /*< Timer to indicate how long a buffer
+ volatile uint32_t hold_timer; /**< Timer to indicate how long a buffer
* has been held in the cache modified. */
} rtems_bdbuf_buffer;
@@ -87,38 +167,38 @@ typedef struct rtems_bdbuf_buffer
*/
typedef struct rtems_bdbuf_pool
{
- uint32_t blksize; /*< The size of the blocks (in bytes) */
- uint32_t nblks; /*< Number of blocks in this pool */
+ uint32_t blksize; /**< The size of the blocks (in bytes) */
+ uint32_t nblks; /**< Number of blocks in this pool */
- uint32_t flags; /*< Configuration flags */
+ uint32_t flags; /**< Configuration flags */
- rtems_id lock; /*< The pool lock. Lock this data and
+ rtems_id lock; /**< The pool lock. Lock this data and
* all BDs. */
- rtems_id sync_lock; /*< Sync calls lock writes. */
- bool sync_active; /*< True if a sync is active. */
- rtems_id sync_requester; /*< The sync requester. */
- dev_t sync_device; /*< The device to sync */
+ rtems_id sync_lock; /**< Sync calls lock writes. */
+ bool sync_active; /**< True if a sync is active. */
+ rtems_id sync_requester; /**< The sync requester. */
+ dev_t sync_device; /**< The device to sync */
- rtems_bdbuf_buffer* tree; /*< Buffer descriptor lookup AVL tree
+ rtems_bdbuf_buffer* tree; /**< Buffer descriptor lookup AVL tree
* root */
- rtems_chain_control ready; /*< Free buffers list (or read-ahead) */
- rtems_chain_control lru; /*< Last recently used list */
- rtems_chain_control modified; /*< Modified buffers list */
- rtems_chain_control sync; /*< Buffers to sync list */
+ rtems_chain_control ready; /**< Free buffers list (or read-ahead) */
+ rtems_chain_control lru; /**< Last recently used list */
+ rtems_chain_control modified; /**< Modified buffers list */
+ rtems_chain_control sync; /**< Buffers to sync list */
- rtems_id access; /*< Obtain if waiting for a buffer in the
+ rtems_id access; /**< Obtain if waiting for a buffer in the
* ACCESS state. */
- volatile uint32_t access_waiters; /*< Count of access blockers. */
- rtems_id transfer; /*< Obtain if waiting for a buffer in the
+ volatile uint32_t access_waiters; /**< Count of access blockers. */
+ rtems_id transfer; /**< Obtain if waiting for a buffer in the
* TRANSFER state. */
- volatile uint32_t transfer_waiters; /*< Count of transfer blockers. */
- rtems_id waiting; /*< Obtain if waiting for a buffer and the
+ volatile uint32_t transfer_waiters; /**< Count of transfer blockers. */
+ rtems_id waiting; /**< Obtain if waiting for a buffer and the
* none are available. */
- volatile uint32_t wait_waiters; /*< Count of waiting blockers. */
+ volatile uint32_t wait_waiters; /**< Count of waiting blockers. */
- rtems_bdbuf_buffer* bds; /*< Pointer to table of buffer descriptors
+ rtems_bdbuf_buffer* bds; /**< Pointer to table of buffer descriptors
* allocated for this buffer pool. */
- void* buffers; /*< The buffer's memory. */
+ void* buffers; /**< The buffer's memory. */
} rtems_bdbuf_pool;
/**
@@ -126,35 +206,46 @@ typedef struct rtems_bdbuf_pool
* location) for buffering layer pool.
*/
typedef struct rtems_bdbuf_pool_config {
- int size; /*< Size of block */
- int num; /*< Number of blocks of appropriate size */
- unsigned char* mem_area; /*< Pointer to the blocks location or NULL, in this
+ int size; /**< Size of block */
+ int num; /**< Number of blocks of appropriate size */
+ unsigned char* mem_area; /**< Pointer to the blocks location or NULL, in this
* case memory for blocks will be allocated by
* Buffering Layer with the help of RTEMS partition
* manager */
} rtems_bdbuf_pool_config;
/**
- * External references provided by the user for each pool in the system.
+ * External reference to the pool configuration table describing each pool in
+ * the system.
+ *
+ * The configuration table is provided by the application.
*/
extern rtems_bdbuf_pool_config rtems_bdbuf_pool_configuration[];
-extern int rtems_bdbuf_pool_configuration_size;
+
+/**
+ * External reference the size of the pool configuration table
+ * @ref rtems_bdbuf_pool_configuration.
+ *
+ * The configuration table size is provided by the application.
+ */
+extern size_t rtems_bdbuf_pool_configuration_size;
/**
* Buffering configuration definition. See confdefs.h for support on using this
* structure.
*/
typedef struct rtems_bdbuf_config {
- uint32_t max_read_ahead_blocks; /*< Number of blocks to read ahead. */
- uint32_t max_write_blocks; /*< Number of blocks to write at once. */
- rtems_task_priority swapout_priority; /*< Priority of the swap out task. */
- uint32_t swapout_period; /*< Period swapout checks buf timers. */
- uint32_t swap_block_hold; /*< Period a buffer is held. */
+ uint32_t max_read_ahead_blocks; /**< Number of blocks to read ahead. */
+ uint32_t max_write_blocks; /**< Number of blocks to write at once. */
+ rtems_task_priority swapout_priority; /**< Priority of the swap out task. */
+ uint32_t swapout_period; /**< Period swapout checks buf timers. */
+ uint32_t swap_block_hold; /**< Period a buffer is held. */
} rtems_bdbuf_config;
/**
- * External referernce to the configuration. The configuration is provided by
- * the user.
+ * External reference to the configuration.
+ *
+ * The configuration is provided by the application.
*/
extern rtems_bdbuf_config rtems_bdbuf_configuration;
@@ -163,10 +254,26 @@ extern rtems_bdbuf_config rtems_bdbuf_configuration;
* than this defined max. This stops thrashing in the cache.
*/
#define RTEMS_BDBUF_MAX_READ_AHEAD_BLOCKS_DEFAULT 32
+
+/**
+ * Default maximum number of blocks to write at once.
+ */
#define RTEMS_BDBUF_MAX_WRITE_BLOCKS_DEFAULT 16
+
+/**
+ * Default swap-out task priority.
+ */
#define RTEMS_BDBUF_SWAPOUT_TASK_PRIORITY_DEFAULT 15
-#define RTEMS_BDBUF_SWAPOUT_TASK_SWAP_PERIOD_DEFAULT 250 /* milli-seconds */
-#define RTEMS_BDBUF_SWAPOUT_TASK_BLOCK_HOLD_DEFAULT 1000 /* milli-seconds */
+
+/**
+ * Default swap-out task swap period in milli seconds.
+ */
+#define RTEMS_BDBUF_SWAPOUT_TASK_SWAP_PERIOD_DEFAULT 250
+
+/**
+ * Default swap-out task block hold time in milli seconds.
+ */
+#define RTEMS_BDBUF_SWAPOUT_TASK_BLOCK_HOLD_DEFAULT 1000
/**
* Prepare buffering layer to work - initialize buffer descritors and (if it is
@@ -335,8 +442,13 @@ rtems_bdbuf_find_pool (uint32_t block_size, rtems_bdpool_id *pool);
*
* @note Buffer pools enumerated continuously starting from 0.
*/
-rtems_status_code
-rtems_bdbuf_get_pool_info (rtems_bdpool_id pool, int *block_size, int *blocks);
+rtems_status_code rtems_bdbuf_get_pool_info(
+ rtems_bdpool_id pool,
+ uint32_t *block_size,
+ uint32_t *blocks
+);
+
+/** @} */
#ifdef __cplusplus
}