Changeset c21c850e in rtems for cpukit/libblock
- Timestamp:
- 07/29/08 03:15:09 (16 years ago)
- Branches:
- 4.10, 4.11, 4.9, 5, master
- Children:
- 021cf6b
- Parents:
- bafe97f4
- Location:
- cpukit/libblock
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
cpukit/libblock/include/rtems/bdbuf.h
rbafe97f4 rc21c850e 2 2 * @file rtems/bdbuf.h 3 3 * 4 * block device buffer management4 * Block Device Buffer Management 5 5 */ 6 6 … … 9 9 * Author: Victor V. Vengerov <vvv@oktet.ru> 10 10 * 11 * Copyright (C) 2008 Chris Johns <chrisj@rtems.org> 12 * Rewritten to remove score mutex access. Fixes many performance 13 * issues. 14 * 11 15 * @(#) bdbuf.h,v 1.9 2005/02/02 00:06:18 joel Exp 12 16 */ … … 31 35 typedef enum 32 36 { 33 RTEMS_BDBUF_STATE_EMPTY = 0, /* Not in use. */34 RTEMS_BDBUF_STATE_READ_AHEAD = 1, /* Holds read ahead data only */35 RTEMS_BDBUF_STATE_CACHED = 2, /* In the cache and available */36 RTEMS_BDBUF_STATE_ACCESS = 3, /* The user has the buffer */37 RTEMS_BDBUF_STATE_MODIFIED = 4, /* In the cache but modified */38 RTEMS_BDBUF_STATE_ACCESS_MODIFIED = 5, /* With the user but modified */39 RTEMS_BDBUF_STATE_SYNC = 6, /* Requested to be sync'ed */40 RTEMS_BDBUF_STATE_TRANSFER = 7 /* Being transferred to or from disk */37 RTEMS_BDBUF_STATE_EMPTY = 0, /*< Not in use. */ 38 RTEMS_BDBUF_STATE_READ_AHEAD = 1, /*< Holds read ahead data only */ 39 RTEMS_BDBUF_STATE_CACHED = 2, /*< In the cache and available */ 40 RTEMS_BDBUF_STATE_ACCESS = 3, /*< The user has the buffer */ 41 RTEMS_BDBUF_STATE_MODIFIED = 4, /*< In the cache but modified */ 42 RTEMS_BDBUF_STATE_ACCESS_MODIFIED = 5, /*< With the user but modified */ 43 RTEMS_BDBUF_STATE_SYNC = 6, /*< Requested to be sync'ed */ 44 RTEMS_BDBUF_STATE_TRANSFER = 7 /*< Being transferred to or from disk */ 41 45 } rtems_bdbuf_buf_state; 42 46 … … 53 57 struct rtems_bdbuf_avl_node 54 58 { 55 signed char cache; /* Cache */56 struct rtems_bdbuf_buffer* left; /* Left Child */57 struct rtems_bdbuf_buffer* right; /* Right Child */58 signed char bal; /* The balance of the sub-tree */59 signed char cache; /*< Cache */ 60 struct rtems_bdbuf_buffer* left; /*< Left Child */ 61 struct rtems_bdbuf_buffer* right; /*< Right Child */ 62 signed char bal; /*< The balance of the sub-tree */ 59 63 } avl; 60 64 61 dev_t dev; /* device number */62 rtems_blkdev_bnum block; /* block number on the device */63 64 unsigned char* buffer; /* Pointer to the buffer memory area */65 int error; /* If not 0 indicate an error value (errno)65 dev_t dev; /*< device number */ 66 rtems_blkdev_bnum block; /*< block number on the device */ 67 68 unsigned char* buffer; /*< Pointer to the buffer memory area */ 69 int error; /*< If not 0 indicate an error value (errno) 66 70 * which can be used by user later */ 67 71 68 volatile rtems_bdbuf_buf_state state; /* State of the buffer. */69 70 volatile uint32_t waiters; /* The number of threads waiting on this72 volatile rtems_bdbuf_buf_state state; /*< State of the buffer. */ 73 74 volatile uint32_t waiters; /*< The number of threads waiting on this 71 75 * buffer. */ 72 rtems_bdpool_id pool; /* Identifier of buffer pool to which this buffer76 rtems_bdpool_id pool; /*< Identifier of buffer pool to which this buffer 73 77 belongs */ 74 78 75 volatile uint32_t hold_timer; /* Timer to indicate how long a buffer79 volatile uint32_t hold_timer; /*< Timer to indicate how long a buffer 76 80 * has been held in the cache modified. */ 77 81 } rtems_bdbuf_buffer; … … 83 87 typedef struct rtems_bdbuf_pool 84 88 { 85 int blksize; /* The size of the blocks (in bytes) */86 int nblks; /* Number of blocks in this pool */87 88 uint32_t flags; /* Configuration flags */89 90 rtems_id lock; /* The pool lock. Lock this data and89 int blksize; /*< The size of the blocks (in bytes) */ 90 int nblks; /*< Number of blocks in this pool */ 91 92 uint32_t flags; /*< Configuration flags */ 93 94 rtems_id lock; /*< The pool lock. Lock this data and 91 95 * all BDs. */ 92 rtems_id sync_lock; /* Sync calls lock writes. */93 boolean sync_active; /* True if a sync is active. */94 rtems_id sync_requester; /* The sync requester. */95 dev_t sync_device; /* The device to sync */96 97 rtems_bdbuf_buffer* tree; /* Buffer descriptor lookup AVL tree96 rtems_id sync_lock; /*< Sync calls lock writes. */ 97 boolean sync_active; /*< True if a sync is active. */ 98 rtems_id sync_requester; /*< The sync requester. */ 99 dev_t sync_device; /*< The device to sync */ 100 101 rtems_bdbuf_buffer* tree; /*< Buffer descriptor lookup AVL tree 98 102 * root */ 99 rtems_chain_control ready; /* Free buffers list (or read-ahead) */100 rtems_chain_control lru; /* Last recently used list */101 rtems_chain_control modified; /* Modified buffers list */102 rtems_chain_control sync; /* Buffers to sync list */103 104 rtems_id access; /* Obtain if waiting for a buffer in the103 rtems_chain_control ready; /*< Free buffers list (or read-ahead) */ 104 rtems_chain_control lru; /*< Last recently used list */ 105 rtems_chain_control modified; /*< Modified buffers list */ 106 rtems_chain_control sync; /*< Buffers to sync list */ 107 108 rtems_id access; /*< Obtain if waiting for a buffer in the 105 109 * ACCESS state. */ 106 volatile uint32_t access_waiters; /* Count of access blockers. */107 rtems_id transfer; /* Obtain if waiting for a buffer in the110 volatile uint32_t access_waiters; /*< Count of access blockers. */ 111 rtems_id transfer; /*< Obtain if waiting for a buffer in the 108 112 * TRANSFER state. */ 109 volatile uint32_t transfer_waiters; /* Count of transfer blockers. */110 rtems_id waiting; /* Obtain if waiting for a buffer and the113 volatile uint32_t transfer_waiters; /*< Count of transfer blockers. */ 114 rtems_id waiting; /*< Obtain if waiting for a buffer and the 111 115 * none are available. */ 112 volatile uint32_t wait_waiters; /* Count of waiting blockers. */113 114 rtems_bdbuf_buffer* bds; /* Pointer to table of buffer descriptors116 volatile uint32_t wait_waiters; /*< Count of waiting blockers. */ 117 118 rtems_bdbuf_buffer* bds; /*< Pointer to table of buffer descriptors 115 119 * allocated for this buffer pool. */ 116 void* buffers; /* The buffer's memory. */120 void* buffers; /*< The buffer's memory. */ 117 121 } rtems_bdbuf_pool; 118 122 … … 122 126 */ 123 127 typedef struct rtems_bdbuf_pool_config { 124 int size; /* Size of block */125 int num; /* Number of blocks of appropriate size */126 unsigned char* mem_area; /* Pointer to the blocks location or NULL, in this128 int size; /*< Size of block */ 129 int num; /*< Number of blocks of appropriate size */ 130 unsigned char* mem_area; /*< Pointer to the blocks location or NULL, in this 127 131 * case memory for blocks will be allocated by 128 132 * Buffering Layer with the help of RTEMS partition … … 141 145 */ 142 146 typedef struct rtems_bdbuf_config { 143 int max_read_ahead_blocks; /*< <Number of blocks to read ahead. */144 int max_write_blocks; /*< <Number of blocks to write at once. */145 rtems_task_priority swapout_priority; /*< <Priority of the swap out task. */146 uint32_t swapout_period; /*< <Period swapout checks buf timers. */147 uint32_t swap_block_hold; /*< <Period a buffer is held. */147 int max_read_ahead_blocks; /*< Number of blocks to read ahead. */ 148 int max_write_blocks; /*< Number of blocks to write at once. */ 149 rtems_task_priority swapout_priority; /*< Priority of the swap out task. */ 150 uint32_t swapout_period; /*< Period swapout checks buf timers. */ 151 uint32_t swap_block_hold; /*< Period a buffer is held. */ 148 152 } rtems_bdbuf_config; 149 153 … … 164 168 #define RTEMS_BDBUF_SWAPOUT_TASK_BLOCK_HOLD_DEFAULT 1000 /* milli-seconds */ 165 169 166 /* rtems_bdbuf_init -- 167 * Prepare buffering layer to work - initialize buffer descritors 168 * and (if it is neccessary) buffers. Buffers will be allocated accoriding 169 * to the configuration table, each entry describes kind of block and 170 * amount requested. After initialization all blocks is placed into 171 * free elements lists. 170 /** 171 * Prepare buffering layer to work - initialize buffer descritors and (if it is 172 * neccessary) buffers. Buffers will be allocated accoriding to the 173 * configuration table, each entry describes the size of block and the size of 174 * the pool. After initialization all blocks is placed into the ready state. 175 * lists. 176 * 177 * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed 178 * successfully or error code if error is occured) 179 */ 180 rtems_status_code 181 rtems_bdbuf_init (); 182 183 /** 184 * Get block buffer for data to be written into. The buffers is set to the 185 * access or modifed access state. If the buffer is in the cache and modified 186 * the state is access modified else the state is access. This buffer contents 187 * are not initialised if the buffer is not already in the cache. If the block 188 * is already resident in memory it is returned how-ever if not in memory the 189 * buffer is not read from disk. This call is used when writing the whole block 190 * on a disk rather than just changing a part of it. If there is no buffers 191 * available this call will block. A buffer obtained with this call will not be 192 * involved in a transfer request and will not be returned to another user 193 * until released. If the buffer is already with a user when this call is made 194 * the call is blocked until the buffer is returned. The highest priority 195 * waiter will obtain the buffer first. 196 * 197 * The block number is the linear block number. This is relative to the start 198 * of the partition on the media. 199 * 200 * @param device Device number (constructed of major and minor device number) 201 * @param block Linear media block number 202 * @param bd Reference to the buffer descriptor pointer. 203 * 204 * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed 205 * successfully or error code if error is occured) 206 */ 207 rtems_status_code 208 rtems_bdbuf_get (dev_t device, rtems_blkdev_bnum block, rtems_bdbuf_buffer** bd); 209 210 /** 211 * Get the block buffer and if not already in the cache read from the disk. If 212 * specified block already cached return. The buffer is set to the access or 213 * modifed access state. If the buffer is in the cache and modified the state 214 * is access modified else the state is access. If block is already being read 215 * from disk for being written to disk this call blocks. If the buffer is 216 * waiting to be written it is removed from modified queue and returned to the 217 * user. If the buffer is not in the cache a new buffer is obtained and the 218 * data read from disk. The call may block until these operations complete. A 219 * buffer obtained with this call will not be involved in a transfer request 220 * and will not be returned to another user until released. If the buffer is 221 * already with a user when this call is made the call is blocked until the 222 * buffer is returned. The highest priority waiter will obtain the buffer 223 * first. 224 * 225 * @param device Device number (constructed of major and minor device number) 226 * @param block Linear media block number 227 * @param bd Reference to the buffer descriptor pointer. 228 * 229 * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed 230 * successfully or error code if error is occured) 231 */ 232 rtems_status_code 233 rtems_bdbuf_read (dev_t device, rtems_blkdev_bnum block, rtems_bdbuf_buffer** bd); 234 235 /** 236 * Release the buffer obtained by a read call back to the cache. If the buffer 237 * was obtained by a get call and was not already in the cache the release 238 * modified call should be used. A buffer released with this call obtained by a 239 * get call may not be in sync with the contents on disk. If the buffer was in 240 * the cache and modified before this call it will be returned to the modified 241 * queue. The buffers is returned to the end of the LRU list. 242 * 243 * @param bd Reference to the buffer descriptor. 244 * 245 * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed 246 * successfully or error code if error is occured) 247 */ 248 rtems_status_code 249 rtems_bdbuf_release (rtems_bdbuf_buffer* bd); 250 251 /** 252 * Release the buffer allocated with a get or read call placing it on the 253 * modidied list. If the buffer was not released modified before the hold 254 * timer is set to the configuration value. If the buffer had been released 255 * modified before but not written to disk the hold timer is not updated. The 256 * buffer will be written to disk when the hold timer has expired, there are 257 * not more buffers available in the cache and a get or read buffer needs one 258 * or a sync call has been made. If the buffer is obtained with a get or read 259 * before the hold timer has expired the buffer will be returned to the user. 260 * 261 * @param bd Reference to the buffer descriptor. 262 * 263 * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed 264 * successfully or error code if error is occured) 265 */ 266 rtems_status_code 267 rtems_bdbuf_release_modified (rtems_bdbuf_buffer* bd); 268 269 /** 270 * Release the buffer as modified and wait until it has been synchronized with 271 * the disk by writing it. This buffer will be the first to be transfer to disk 272 * and other buffers may also be written if the maximum number of blocks in a 273 * requests allows it. 274 * 275 * @note This code does not lock the sync mutex and stop additions to the 276 * modified queue. 277 278 * @param bd Reference to the buffer descriptor. 279 * 280 * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed 281 * successfully or error code if error is occured) 282 */ 283 rtems_status_code 284 rtems_bdbuf_sync (rtems_bdbuf_buffer* bd); 285 286 /** 287 * Synchronize all modified buffers for this device with the disk and wait 288 * until the transfers have completed. The sync mutex for the pool is locked 289 * stopping the addition of any further modifed buffers. It is only the 290 * currently modified buffers that are written. 291 * 292 * @note Nesting calls to sync multiple devices attached to a single pool will 293 * be handled sequentially. A nested call will be blocked until the first sync 294 * request has complete. This is only true for device using the same pool. 295 * 296 * @param dev Block device number 297 * 298 * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed 299 * successfully or error code if error is occured) 300 */ 301 rtems_status_code 302 rtems_bdbuf_syncdev (dev_t dev); 303 304 /** 305 * Find first appropriate buffer pool. This primitive returns the index of 306 * first buffer pool which block size is greater than or equal to specified 307 * size. 308 * 309 * @param block_size Requested block size 310 * @param pool The pool to use for the requested pool size. 311 * 312 * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed 313 * successfully or error code if error is occured) 314 * @retval RTEMS_INVALID_SIZE The specified block size is invalid (not a power 315 * of 2) 316 * @retval RTEMS_NOT_DEFINED The buffer pool for this or greater block size 317 * is not configured. 318 */ 319 rtems_status_code 320 rtems_bdbuf_find_pool (int block_size, rtems_bdpool_id *pool); 321 322 /** 323 * Obtain characteristics of buffer pool with specified number. 324 * 325 * @param pool Buffer pool number 326 * @param block_size Block size for which buffer pool is configured returned 327 * there 328 * @param blocks Number of buffers in buffer pool. 172 329 * 173 330 * RETURNS: 174 * RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully 175 * or error code if error is occured) 176 */ 177 rtems_status_code 178 rtems_bdbuf_init (); 179 180 /* rtems_bdbuf_get -- 181 * Obtain block buffer. If specified block already cached (i.e. there's 182 * block in the _modified_, or _recently_used_), return address 183 * of appropriate buffer descriptor and increment reference counter to 1. 184 * If block is not cached, allocate new buffer and return it. Data 185 * shouldn't be read to the buffer from media; buffer may contains 186 * arbitrary data. This primitive may be blocked if there are no free 187 * buffer descriptors available and there are no unused non-modified 188 * (or synchronized with media) buffers available. 189 * 190 * PARAMETERS: 191 * device - device number (constructed of major and minor device number) 192 * block - linear media block number 193 * bd - address of variable to store pointer to the buffer descriptor 194 * 195 * RETURNS: 196 * RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully 197 * or error code if error is occured) 198 * 199 * SIDE EFFECTS: 200 * bufget_sema semaphore obtained by this primitive. 201 */ 202 rtems_status_code 203 rtems_bdbuf_get(dev_t device, rtems_blkdev_bnum block, rtems_bdbuf_buffer** bd); 204 205 /* rtems_bdbuf_read -- 206 * (Similar to the rtems_bdbuf_get, except reading data from media) 207 * Obtain block buffer. If specified block already cached, return address 208 * of appropriate buffer and increment reference counter to 1. If block is 209 * not cached, allocate new buffer and read data to it from the media. 210 * This primitive may be blocked on waiting until data to be read from 211 * media, if there are no free buffer descriptors available and there are 212 * no unused non-modified (or synchronized with media) buffers available. 213 * 214 * PARAMETERS: 215 * device - device number (consists of major and minor device number) 216 * block - linear media block number 217 * bd - address of variable to store pointer to the buffer descriptor 218 * 219 * RETURNS: 220 * RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully 221 * or error code if error is occured) 222 * 223 * SIDE EFFECTS: 224 * bufget_sema and transfer_sema semaphores obtained by this primitive. 225 */ 226 rtems_status_code 227 rtems_bdbuf_read(dev_t device, rtems_blkdev_bnum block, rtems_bdbuf_buffer** bd); 228 229 /* rtems_bdbuf_release -- 230 * Release buffer allocated before. This primitive decrease the 231 * usage counter. If it is zero, further destiny of buffer depends on 232 * 'modified' status. If buffer was modified, it is placed to the end of 233 * mod list and flush task waken up. If buffer was not modified, 234 * it is placed to the end of lru list, and bufget_sema released, allowing 235 * to reuse this buffer. 236 * 237 * PARAMETERS: 238 * bd_buf - pointer to the bdbuf_buffer structure previously obtained using 239 * get/read primitive. 240 * 241 * RETURNS: 242 * RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully 243 * or error code if error is occured) 244 * 245 * SIDE EFFECTS: 246 * flush_sema and bufget_sema semaphores may be released by this primitive. 247 */ 248 rtems_status_code 249 rtems_bdbuf_release(rtems_bdbuf_buffer* bd); 250 251 /* rtems_bdbuf_release_modified -- 252 * Release buffer allocated before, assuming that it is _modified_ by 253 * it's owner. This primitive decrease usage counter for buffer, mark 254 * buffer descriptor as modified. If usage counter is 0, insert it at 255 * end of mod chain and release flush_sema semaphore to activate the 256 * flush task. 257 * 258 * PARAMETERS: 259 * bd_buf - pointer to the bdbuf_buffer structure previously obtained using 260 * get/read primitive. 261 * 262 * RETURNS: 263 * RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully 264 * or error code if error is occured) 265 * 266 * SIDE EFFECTS: 267 * flush_sema semaphore may be released by this primitive. 268 */ 269 rtems_status_code 270 rtems_bdbuf_release_modified(rtems_bdbuf_buffer* bd); 271 272 /* rtems_bdbuf_sync -- 273 * Wait until specified buffer synchronized with disk. Invoked on exchanges 274 * critical for data consistency on the media. This primitive mark owned 275 * block as modified, decrease usage counter. If usage counter is 0, 276 * block inserted to the mod chain and flush_sema semaphore released. 277 * Finally, primitives blocked on transfer_sema semaphore. 278 * 279 * PARAMETERS: 280 * bd_buf - pointer to the bdbuf_buffer structure previously obtained using 281 * get/read primitive. 282 * 283 * RETURNS: 284 * RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully 285 * or error code if error is occured) 286 * 287 * SIDE EFFECTS: 288 * Primitive may be blocked on transfer_sema semaphore. 289 */ 290 rtems_status_code 291 rtems_bdbuf_sync(rtems_bdbuf_buffer* bd); 292 293 /* rtems_bdbuf_syncdev -- 294 * Synchronize with disk all buffers containing the blocks belonging to 295 * specified device. 296 * 297 * PARAMETERS: 298 * dev - block device number 299 * 300 * RETURNS: 301 * RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully 302 * or error code if error is occured) 303 */ 304 rtems_status_code 305 rtems_bdbuf_syncdev(dev_t dev); 306 307 /* rtems_bdbuf_find_pool -- 308 * Find first appropriate buffer pool. This primitive returns the index 309 * of first buffer pool which block size is greater than or equal to 310 * specified size. 311 * 312 * PARAMETERS: 313 * block_size - requested block size 314 * pool - placeholder for result 315 * 316 * RETURNS: 317 * RTEMS status code: RTEMS_SUCCESSFUL if operation completed successfully, 318 * RTEMS_INVALID_SIZE if specified block size is invalid (not a power 319 * of 2), RTEMS_NOT_DEFINED if buffer pool for this or greater block size 320 * is not configured. 321 */ 322 rtems_status_code 323 rtems_bdbuf_find_pool(int block_size, rtems_bdpool_id *pool); 324 325 /* rtems_bdbuf_get_pool_info -- 326 * Obtain characteristics of buffer pool with specified number. 327 * 328 * PARAMETERS: 329 * pool - buffer pool number 330 * block_size - block size for which buffer pool is configured returned 331 * there 332 * blocks - number of buffers in buffer pool returned there 333 * 334 * RETURNS: 335 * RTEMS status code: RTEMS_SUCCESSFUL if operation completed successfully, 336 * RTEMS_INVALID_NUMBER if appropriate buffer pool is not configured. 337 * 338 * NOTE: 339 * Buffer pools enumerated contiguously starting from 0. 340 */ 341 rtems_status_code 342 rtems_bdbuf_get_pool_info(rtems_bdpool_id pool, int *block_size, int *blocks); 331 * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed 332 * successfully or error code if error is occured) 333 * @retval RTEMS_INVALID_SIZE The appropriate buffer pool is not configured. 334 * 335 * @note Buffer pools enumerated continuously starting from 0. 336 */ 337 rtems_status_code 338 rtems_bdbuf_get_pool_info (rtems_bdpool_id pool, int *block_size, int *blocks); 343 339 344 340 #ifdef __cplusplus -
cpukit/libblock/src/bdbuf.c
rbafe97f4 rc21c850e 8 8 * Alexander Kukuta <kam@oktet.ru> 9 9 * 10 * Copyright (C) 2008 Chris Johns <chrisj@rtems.org> 11 * Rewritten to remove score mutex access. Fixes many performance 12 * issues. 13 * 10 14 * @(#) bdbuf.c,v 1.14 2004/04/17 08:15:17 ralf Exp 11 15 */ … … 14 18 * @file 15 19 * 16 * The Buffer Descriptor Buffer code implement a cache between the disk17 * devices and file systems. The code provides a read ahead and qrite queuing18 * t o the drivers and fast cache look up using an AVL tree.20 * The Buffer Descriptor Buffer code implements a cache between the disk 21 * devices and file systems. The code provides read ahead and write queuing to 22 * the drivers and fast cache look up using an AVL tree. 19 23 * 20 24 * The buffers are held in pools based on size. Each pool has buffers and the 21 25 * buffers follow this state machine: 22 * 23 * read26 * 27 * read/read ahead 24 28 * +-------------------------------+ 25 29 * | v 26 * +-----------+ read complete +------------+ 27 * | | write complete | |---------+ 28 * | EMPTY | +---------| TRANSFER | | 29 * | | | | |<--+ | 30 * +-----------+ | +------------+ | | 31 * ^ | get v swap | | 32 * | | +-----------+ modified +------------+ | 33 * | +--->| |---------->| | | 34 * | | ACCESSED |<----------| MODIFIED | | 35 * | +----| |<--+ get | | | 36 * | | +-----------+ | +------------+ | 37 * | | | | 38 * | | release get | | 39 * | | | | 40 * | | +-----------+ | | 41 * expire | +--->| |---+ read complete | 42 * | | CACHED | write complete | 43 * +--------| |<-------------------------+ 30 * +-----------+ read ahead +------------+ 31 * | READY, | complete | |---------+ 32 * | READ |<----------------| TRANSFER | | 33 * | AHEAD | +-------------| |<--+ | 34 * +-----------+ | read/write +------------+ | | 35 * | get v complete swap | | 36 * | +-----------+ modified +------------+ | 37 * +--->| ACCESSED, |---------->| MODIFIED, | | 38 * | ACCESSED |<----------| SYNC | | 39 * +----| MODIFIED |<--+ get | | | 40 * | +-----------+ | +------------+ | 41 * | release get | | 42 * | +-----------+ | | 43 * +--->| |---+ read complete | 44 * | CACHED | write complete | 45 * | |<-------------------------+ 44 46 * +-----------+ 45 * 46 * Empty buffers are added to the empty list and removed from this queue when a 47 * caller wishes to access a buffer. This is referred to getting a buffer in 48 * the code and the event get in the state diagram. The buffer is assigned to a 49 * block and inserted to the AVL. If the block is to be read by the user and 50 * not in the cache (empty) it is transfered from the disk into memory. If no 51 * empty buffers exist the buffer is expired from the cache. Currently the 52 * least recently used block is expired first. A block being accessed is given 53 * to the file system layer and not accessable to another requester until 54 * released back to the cache. If the user has modifed the block it is 55 * transfered to disk then placed on the LRU list. 47 * 48 * Empty buffers are added to the ready list and removed from this queue when a 49 * caller requests a buffer. This is referred to as getting a buffer in the 50 * code and the event get in the state diagram. The buffer is assigned to a 51 * block and inserted to the AVL based on the block/device key. If the block is 52 * to be read by the user and not in the cache (ready) it is transfered from 53 * the disk into memory. If no ready buffers exist the buffer is taken from the 54 * LRU list. If no buffers are on the LRU list the modified list is check. If 55 * no buffers are on the modified list the request blocks. If buffers are on 56 * the modified list the buffers hold timer is expired and the swap out task 57 * woken. 58 * 59 * A block being accessed is given to the file system layer and not accessable 60 * to another requester until released back to the cache. The same goes to a 61 * buffer in the transfer state. The transfer state means being read or 62 * written. If the file system has modifed the block and releases it as 63 * modified it placed on the pool's modified list and a hold timer 64 * initialised. The buffer is held for the hold time before being written to 65 * disk. Buffers are held for a configurable period of time on the modified 66 * list as a write sets the state to transfer and this locks the buffer out 67 * from the file system until the write complete. Buffers are often repeatable 68 * accessed and modified in a series of small updates so if sent to the disk 69 * when released as modified the user would have to block waiting until it had 70 * been written. This would be a performance problem. 71 * 72 * The code performs mulitple block reads and writes. Multiple block reads or 73 * read ahead increases performance with hardware that supports it. It also 74 * helps with a large cache as the disk head movement is reduced. It how-ever 75 * is a speculative operation so excessive use can remove valuable and needed 76 * blocks from the cache. The get call knows if a read is a for the file system 77 * or if it is a read ahead get. If the get is for a read ahead block and the 78 * block is already in the cache or no ready buffers are available the read 79 * ahead is stopped. The transfer occurs with the blocks so far. If a buffer is 80 * in the read ahead state and release it is placed on the ready list rather 81 * than the LRU list. This means these buffers are used before buffers used by 82 * the file system. 56 83 * 57 84 * The pool have the following lists of buffers: 58 85 * 59 * empty - Empty buffers created when the pool is initialised. 60 * modided - Buffers waiting to be written to disk. 61 * cached_lru - Accessed buffers released in least recently used order. 62 * cached_unsed - Read ahead buffers that have not been accessed. 63 * 86 * ready - Empty buffers created when the pool is initialised. 87 * modified - Buffers waiting to be written to disk. 88 * sync - Buffers to be synced to disk. 89 * lru - Accessed buffers released in least recently used order. 64 90 */ 65 91 … … 88 114 * The BD buffer context. 89 115 */ 90 /* Buffering layer context definition */91 116 typedef struct rtems_bdbuf_context { 92 rtems_bdbuf_pool* pool; /* Table of buffer pools */93 int npools; /* Number of entries in pool table */94 rtems_id swapout; /* Swapout task ID */117 rtems_bdbuf_pool* pool; /*< Table of buffer pools */ 118 int npools; /*< Number of entries in pool table */ 119 rtems_id swapout; /*< Swapout task ID */ 95 120 boolean swapout_enabled; 96 121 } rtems_bdbuf_context; … … 99 124 * Fatal errors 100 125 */ 101 #define RTEMS_BLKDEV_FATAL_ERROR(n) (((uint32_t)'B' << 24) |\102 126 #define RTEMS_BLKDEV_FATAL_ERROR(n) \ 127 (((uint32_t)'B' << 24) | ((uint32_t)(n) & (uint32_t)0x00FFFFFF)) 103 128 104 129 #define RTEMS_BLKDEV_FATAL_BDBUF_CONSISTENCY RTEMS_BLKDEV_FATAL_ERROR(1) … … 115 140 #define BLKDEV_FATAL_BDBUF_SWAPOUT_TS RTEMS_BLKDEV_FATAL_ERROR(12) 116 141 142 /** 143 * The events used in this code. These should be system events rather than 144 * application events. 145 */ 117 146 #define RTEMS_BDBUF_TRANSFER_SYNC RTEMS_EVENT_1 118 147 #define RTEMS_BDBUF_SWAPOUT_SYNC RTEMS_EVENT_2 119 148 149 /** 150 * The swap out task size. Should be more than enough for most drivers with 151 * tracing turned on. 152 */ 120 153 #define SWAPOUT_TASK_STACK_SIZE (8 * 1024) 121 154 122 155 /** 123 156 * Lock semaphore attributes. This is used for locking type mutexes. 157 * 158 * @warning Priority inheritance is on. 124 159 */ 125 160 #define RTEMS_BDBUF_POOL_LOCK_ATTRIBS \ … … 130 165 * Waiter semaphore attributes. 131 166 * 132 * @ noteDo not configure as inherit priority. If a driver is in the driver133 * initialisation table this locked semaphore will have the IDLE task as134 * the holder and a blocking task will raise the priority of the IDLE135 * task which can cause unsual side effects.167 * @warning Do not configure as inherit priority. If a driver is in the driver 168 * initialisation table this locked semaphore will have the IDLE task 169 * as the holder and a blocking task will raise the priority of the 170 * IDLE task which can cause unsual side effects. 136 171 */ 137 172 #define RTEMS_BDBUF_POOL_WAITER_ATTRIBS \ 138 (RTEMS_PRIORITY | RTEMS_ BINARY_SEMAPHORE | \173 (RTEMS_PRIORITY | RTEMS_SIMPLE_BINARY_SEMAPHORE | \ 139 174 RTEMS_NO_INHERIT_PRIORITY | RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL) 140 175 … … 211 246 return p; 212 247 } 213 214 #if CCJ_REMOVE_IN_IN_CVS215 /**216 * Search in AVL tree for first modified buffer belongs to specified217 * disk device.218 *219 * @param root pointer to the root node of the AVL-Tree220 * @param dd - disk device descriptor221 * @retval NULL no modified blocks on the disk device222 * @return pointer to the modified node223 */224 static rtems_bdbuf_buffer *225 rtems_bdbuf_avl_search_for_sync (rtems_bdbuf_buffer** root,226 rtems_disk_device* dd)227 {228 dev_t dev = dd->phys_dev->dev;229 rtems_blkdev_bnum block_start = dd->start;230 rtems_blkdev_bnum block_end = dd->start + dd->size - 1;231 rtems_bdbuf_buffer* buf_stack[RTEMS_BDBUF_AVL_MAX_HEIGHT];232 rtems_bdbuf_buffer** buf_prev = buf_stack;233 rtems_bdbuf_buffer* p = *root;234 235 while (p != NULL)236 {237 if ((p->dev < dev) || ((p->dev == dev) && (p->block < block_start)))238 {239 p = p->avl.right;240 }241 else if ((p->dev > dev) || ((p->dev == dev) && (p->block > block_end)))242 {243 p = p->avl.left;244 }245 else if (p->state == RTEMS_BDBUF_STATE_MODIFIED)246 {247 return p;248 }249 else250 {251 if (p->avl.right != NULL)252 {253 *buf_prev++ = p->avl.right;254 }255 p = p->avl.left;256 }257 258 if ((p == NULL) && (buf_prev > buf_stack))259 {260 p = *--buf_prev;261 }262 }263 264 return p;265 }266 #endif267 248 268 249 /** … … 789 770 790 771 /** 791 * Wait until woken. Semaphores are used so a number of tasks can wait and 792 * can be woken at once. Task events would require we maintain a list793 * of tasks to be woken and this would require storgage and we do not794 * know the number oftasks that could be waiting.772 * Wait until woken. Semaphores are used so a number of tasks can wait and can 773 * be woken at once. Task events would require we maintain a list of tasks to 774 * be woken and this would require storgage and we do not know the number of 775 * tasks that could be waiting. 795 776 * 796 777 * While we have the pool locked we can try and claim the semaphore and … … 800 781 * A counter is used to save the release call when no one is waiting. 801 782 * 802 * The function assumes the pool is locked on entry and it will have locked803 * the pool onexit.783 * The function assumes the pool is locked on entry and it will be locked on 784 * exit. 804 785 * 805 786 * @param pool The pool to wait for a buffer to return. … … 880 861 * Add a buffer descriptor to the modified list. This modified list is treated 881 862 * a litte differently to the other lists. To access it you must have the pool 882 * locked and this is assumed to be the case on entry to this call and you must 863 * locked and this is assumed to be the case on entry to this call. 864 * 865 * If the pool has a device being sync'ed and the bd is for that device the 866 * call must block and wait until the sync is over before adding the bd to the 867 * modified list. Once a sync happens for a device no bd's can be added the 868 * modified list. The disk image is forced to be snapshot at that moment in 869 * time. 870 * 871 * and you must 883 872 * hold the sync lock. The sync lock is used to block writes while a sync is 884 873 * active. 885 874 * 886 * @param sema The semaphore to release.887 * @param waiters The wait counter for this semaphore.875 * @param pool The pool the bd belongs to. 876 * @param bd The bd to queue to the pool's modified list. 888 877 */ 889 878 static void … … 891 880 { 892 881 /* 893 * Take a copy of the sync_active variable as it will change after 894 * we unlock the pool and wait for the sync to finish. 895 */ 896 int sync_active = pool->sync_active; 897 if (0 && sync_active) 882 * If the pool has a device being sync'ed check if this bd is for that 883 * device. If it is unlock the pool and block on the sync lock. once we have 884 * the sync lock reelase it. 885 * 886 * If the 887 */ 888 if (pool->sync_active && (pool->sync_device == bd->dev)) 898 889 { 899 890 rtems_bdbuf_unlock_pool (pool); 900 891 rtems_bdbuf_lock_sync (pool); 892 rtems_bdbuf_unlock_sync (pool); 901 893 rtems_bdbuf_lock_pool (pool); 902 894 } … … 905 897 906 898 rtems_chain_append (&pool->modified, &bd->link); 907 908 if (0 && sync_active) 909 rtems_bdbuf_unlock_sync (pool); 910 } 911 899 } 900 901 /** 902 * Wait the swapper task. 903 */ 912 904 static void 913 905 rtems_bdbuf_wake_swapper () … … 919 911 } 920 912 921 /* bdbuf_initialize_pool -- 922 * Initialize single buffer pool. 923 * 924 * PARAMETERS: 925 * config - buffer pool configuration 926 * pool - pool number 927 * 928 * RETURNS: 929 * RTEMS_SUCCESSFUL, if buffer pool initialized successfully, or error 930 * code if error occured. 913 /** 914 * Initialize single buffer pool. 915 * 916 * @param config Buffer pool configuration 917 * @param pid Pool number 918 * 919 * @return RTEMS_SUCCESSFUL, if buffer pool initialized successfully, or error 920 * code if error occured. 931 921 */ 932 922 static rtems_status_code … … 942 932 pool = rtems_bdbuf_get_pool (pid); 943 933 944 pool->blksize = config->size; 945 pool->nblks = config->num; 946 pool->tree = NULL; 947 pool->buffers = NULL; 934 pool->blksize = config->size; 935 pool->nblks = config->num; 936 pool->flags = 0; 937 pool->sync_active = FALSE; 938 pool->sync_device = -1; 939 pool->sync_requester = 0; 940 pool->tree = NULL; 941 pool->buffers = NULL; 948 942 949 943 rtems_chain_initialize_empty (&pool->ready); … … 952 946 rtems_chain_initialize_empty (&pool->sync); 953 947 954 pool->access = 0;955 pool->access_waiters = 0;956 pool->transfer = 0;948 pool->access = 0; 949 pool->access_waiters = 0; 950 pool->transfer = 0; 957 951 pool->transfer_waiters = 0; 958 pool->waiting = 0;959 pool->wait_waiters = 0;952 pool->waiting = 0; 953 pool->wait_waiters = 0; 960 954 961 955 /* … … 1008 1002 } 1009 1003 1010 sc = rtems_semaphore_create (rtems_build_name ('B', 'P', '0' + pid, ' s'),1011 0, RTEMS_BDBUF_POOL_WAITER_ATTRIBS, 0,1004 sc = rtems_semaphore_create (rtems_build_name ('B', 'P', '0' + pid, 'S'), 1005 1, RTEMS_BDBUF_POOL_LOCK_ATTRIBS, 0, 1012 1006 &pool->sync_lock); 1013 1007 if (sc != RTEMS_SUCCESSFUL) … … 1061 1055 } 1062 1056 1063 /* bdbuf_release_pool -- 1064 * Free resources allocated for buffer pool with specified number. 1065 * 1066 * PARAMETERS: 1067 * pool - buffer pool number 1068 * 1069 * RETURNS: 1070 * RTEMS_SUCCESSFUL 1057 /** 1058 * Free resources allocated for buffer pool with specified number. 1059 * 1060 * @param pid Buffer pool number 1061 * 1062 * @retval RTEMS_SUCCESSFUL 1071 1063 */ 1072 1064 static rtems_status_code … … 1088 1080 } 1089 1081 1090 /* rtems_bdbuf_init -- 1091 * Prepare buffering layer to work - initialize buffer descritors 1092 * and (if it is neccessary) buffers. Buffers will be allocated according 1093 * to the configuration table, each entry describes kind of block and 1094 * amount requested. After initialization all blocks are placed onto 1095 * empty elements lists. 1096 * 1097 * PARAMETERS: 1098 * conf_table - pointer to the buffers configuration table 1099 * size - number of entries in configuration table 1100 * 1101 * RETURNS: 1102 * RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully 1103 * or error code if error is occured) 1082 /** 1083 * Prepare buffering layer to work - initialize buffer descritors and (if it is 1084 * neccessary) buffers. Buffers will be allocated accoriding to the 1085 * configuration table, each entry describes the size of block and the size of 1086 * the pool. After initialization all blocks is placed into the ready state. 1087 * lists. 1088 * 1089 * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed 1090 * successfully or error code if error is occured) 1104 1091 */ 1105 1092 rtems_status_code … … 1185 1172 * Get a buffer for this device and block. This function returns a buffer once 1186 1173 * placed into the AVL tree. If no buffer is available and it is not a read 1187 * ahead request wait until one is available. If the buffer is for a read ahead 1188 * transfer return NULL if there is not buffer or it is in the cache. 1174 * ahead request and no buffers are waiting to the written to disk wait until 1175 * one is available. If buffers are waiting to be written to disk and non are 1176 * available expire the hold timer and wake the swap out task. If the buffer is 1177 * for a read ahead transfer return NULL if there is not buffer or it is in the 1178 * cache. 1189 1179 * 1190 1180 * The AVL tree of buffers for the pool is searched and if not located check 1191 1181 * obtain a buffer and insert it into the AVL tree. Buffers are first obtained 1192 * from the ready list until all empty buffers are used. Once all buffers are1193 * in use buffers are taken from the LRU list with the least recently used1182 * from the ready list until all empty/ready buffers are used. Once all buffers 1183 * are in use buffers are taken from the LRU list with the least recently used 1194 1184 * buffer taken first. A buffer taken from the LRU list is removed from the AVL 1195 * tree. The empty list or LRU list buffer is initialised to this device and 1196 * block. If no buffers are available due to the empty and LRU lists being 1197 * empty the caller is blocked on the waiting semaphore and counter. When 1198 * buffers return from the upper layers (access) or lower driver (transfer) the 1199 * blocked caller task is woken and this procedure is repeated. The repeat 1200 * handles a case of a another thread pre-empting getting a buffer first and 1201 * adding it to the AVL tree. 1185 * tree. The ready list or LRU list buffer is initialised to this device and 1186 * block. If no buffers are available due to the ready and LRU lists being 1187 * empty a check is made of the modified list. Buffers may be queued waiting 1188 * for the hold timer to expire. These buffers should be written to disk and 1189 * returned to the LRU list where they can be used rather than this call 1190 * blocking. If buffers are on the modified list the max. write block size of 1191 * buffers have their hold timer expired and the swap out task woken. The 1192 * caller then blocks on the waiting semaphore and counter. When buffers return 1193 * from the upper layers (access) or lower driver (transfer) the blocked caller 1194 * task is woken and this procedure is repeated. The repeat handles a case of a 1195 * another thread pre-empting getting a buffer first and adding it to the AVL 1196 * tree. 1202 1197 * 1203 1198 * A buffer located in the AVL tree means it is already in the cache and maybe … … 1205 1200 * 1206 1201 * # Cached. Not being accessed or part of a media transfer. 1207 * # Access . Is with an upper layer being accessed.1202 * # Access or modifed access. Is with an upper layer being accessed. 1208 1203 * # Transfer. Is with the driver and part of a media transfer. 1209 1204 * 1210 * If cached we assign the state new state extract it from any list it maybe 1211 * part of and return to the user. The buffer could be part of the LRU list or 1212 * the modifed list waiting to be swapped out by the swap out task. 1205 * If cached we assign the new state, extract it from any list it maybe part of 1206 * and return to the user. 1213 1207 * 1214 1208 * This function assumes the pool the buffer is being taken from is locked and 1215 * it insure the pool is locked when it returns. 1209 * it will make sure the pool is locked when it returns. The pool will be 1210 * unlocked if the call could block. 1216 1211 * 1217 1212 * @param device The physical disk device 1218 * @param block Linear media block number 1219 * @param 1220 * @param bd Address to store of found descriptor 1221 1222 * RETURNS: 1223 * RTEMS status code ( if operation completed successfully 1224 * or error code if error is occured) 1225 * 1226 * SIDE EFFEECTS: 1227 * bufget_sema may be obtained by this primitive 1228 * 1229 * NOTE: 1230 * It is assumed that primitive invoked when thread preemption is disabled. 1213 * @param pool The pool reference 1214 * @param block Absolute media block number 1215 * @param read_ahead The get is for a read ahead buffer 1216 * 1217 * @return RTEMS status code ( if operation completed successfully or error 1218 * code if error is occured) 1231 1219 */ 1232 1220 static rtems_bdbuf_buffer* … … 1242 1230 /* 1243 1231 * Loop until we get a buffer. Under load we could find no buffers are 1244 * available so in the case of the required block this task needs to wait1245 * until some return before proceeding. There is no timeout. Ifthe buffer is1232 * available requiring this task to wait until some become available before 1233 * proceeding. There is no timeout. If the call is to block and the buffer is 1246 1234 * for a read ahead buffer return NULL. 1247 1235 * 1248 1236 * The search procedure is repeated as another thread could have pre-empted 1249 1237 * us while we waited for a buffer, obtained an empty buffer and loaded the 1250 * AVL tree with it.1238 * AVL tree with the one we are after. 1251 1239 */ 1252 1240 do … … 1264 1252 * the user. We cannot do much with the buffers with the user how-ever with 1265 1253 * the modified buffers waiting to be written to disk flush the maximum 1266 * number transfered in a block to disk. After this all that be done is to1267 * wait for a buffer to return to the cache.1254 * number transfered in a block to disk. After this all that can be done is 1255 * to wait for a buffer to return to the cache. 1268 1256 */ 1269 1257 if (!bd) … … 1272 1260 * Assign new buffer descriptor from the empty list if one is present. If 1273 1261 * the empty queue is empty get the oldest buffer from LRU list. If the 1274 * LRU list is empty there are no available buffers so we need to wait1275 * until some are returned.1262 * LRU list is empty there are no available buffers check the modified 1263 * list. 1276 1264 */ 1277 1265 if (rtems_chain_is_empty (&pool->ready)) … … 1280 1268 * No unsed or read-ahead buffers. 1281 1269 * 1282 * If this is a read ahead buffer just return. No need to place 1283 * further pressure on the cache by reading something that may be1284 * needed when we have data in the cache that was needed.1270 * If this is a read ahead buffer just return. No need to place further 1271 * pressure on the cache by reading something that may be needed when 1272 * we have data in the cache that was needed and may still be. 1285 1273 */ 1286 1274 if (read_ahead) … … 1304 1292 /* 1305 1293 * If there are buffers on the modified list expire the hold timer 1306 * and wake the swap out task .1294 * and wake the swap out task then wait else just go and wait. 1307 1295 */ 1308 1296 if (!rtems_chain_is_empty (&pool->modified)) … … 1373 1361 1374 1362 /* 1375 * Loop waiting for the buffer to enter the cached state. If the buffer 1376 * is inthe access or transfer state then wait until it is not.1363 * Loop waiting for the buffer to enter the cached state. If the buffer is in 1364 * the access or transfer state then wait until it is not. 1377 1365 */ 1378 1366 available = FALSE; … … 1415 1403 1416 1404 /** 1417 * Obtain block buffer. If specified block already cached (i.e. there's block 1418 * in the _modified_, or _recently_used_), return address of appropriate buffer 1419 * descriptor. If block is not cached, allocate new buffer and return it. Data 1420 * shouldn't be read to the buffer from media; buffer may contains arbitrary 1421 * data. This primitive may be blocked if there are no free buffer descriptors 1422 * available and there are no unused non-modified (or synchronized with media) 1423 * buffers available. 1424 * 1425 * @param device device number (constructed of major and minor device number) 1426 * @param block linear media block number 1427 * @param bd address of variable to store pointer to the buffer descriptor 1428 * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully 1429 * or error code if error is occured) 1405 * Get block buffer for data to be written into. The buffers is set to the 1406 * access or modifed access state. If the buffer is in the cache and modified 1407 * the state is access modified else the state is access. This buffer contents 1408 * are not initialised if the buffer is not already in the cache. If the block 1409 * is already resident in memory it is returned how-ever if not in memory the 1410 * buffer is not read from disk. This call is used when writing the whole block 1411 * on a disk rather than just changing a part of it. If there is no buffers 1412 * available this call will block. A buffer obtained with this call will not be 1413 * involved in a transfer request and will not be returned to another user 1414 * until released. If the buffer is already with a user when this call is made 1415 * the call is blocked until the buffer is returned. The highest priority 1416 * waiter will obtain the buffer first. 1417 * 1418 * The block number is the linear block number. This is relative to the start 1419 * of the partition on the media. 1420 * 1421 * @param device Device number (constructed of major and minor device number) 1422 * @param block Linear media block number 1423 * @param bd Reference to the buffer descriptor pointer. 1424 * 1425 * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed 1426 * successfully or error code if error is occured) 1430 1427 */ 1431 1428 rtems_status_code … … 1477 1474 } 1478 1475 1479 /* bdbuf_read_transfer_done -- 1480 * Callout function. Invoked by block device driver when data transfer 1481 * from device (read) is completed. This function may be invoked from 1482 * interrupt handler. 1483 * 1484 * PARAMETERS: 1485 * arg - arbitrary argument specified in block device request 1486 * structure (in this case - pointer to the appropriate 1487 * bdbuf_buffer buffer descriptor structure). 1488 * status - I/O completion status 1489 * error - errno error code if status != RTEMS_SUCCESSFUL 1490 * 1491 * RETURNS: 1492 * none 1476 /** 1477 * Call back handler called by the low level driver when the transfer has 1478 * completed. This function may be invoked from interrupt handler. 1479 * 1480 * @param arg Arbitrary argument specified in block device request 1481 * structure (in this case - pointer to the appropriate 1482 * block device request structure). 1483 * @param status I/O completion status 1484 * @param error errno error code if status != RTEMS_SUCCESSFUL 1493 1485 */ 1494 1486 static void … … 1504 1496 1505 1497 /** 1506 * Read a block into memory. If the block is not is the cache it is read into 1507 * memory. The caller is blocked until the block is read and placed into the 1508 * cache. 1509 * 1510 * @param device The device number (consists of major and minor device number) 1511 * @param block Linear media block number 1512 * @param bd Pointer to the buffer BD address. 1513 * @retval RTEMS_SUCCESSFUL Operation completed successfully. 1514 * @return rtems_status_code An error code. Buffer still passed to caller. 1515 */ 1516 1498 * Get the block buffer and if not already in the cache read from the disk. If 1499 * specified block already cached return. The buffer is set to the access or 1500 * modifed access state. If the buffer is in the cache and modified the state 1501 * is access modified else the state is access. If block is already being read 1502 * from disk for being written to disk this call blocks. If the buffer is 1503 * waiting to be written it is removed from modified queue and returned to the 1504 * user. If the buffer is not in the cache a new buffer is obtained and the 1505 * data read from disk. The call may block until these operations complete. A 1506 * buffer obtained with this call will not be involved in a transfer request 1507 * and will not be returned to another user until released. If the buffer is 1508 * already with a user when this call is made the call is blocked until the 1509 * buffer is returned. The highest priority waiter will obtain the buffer 1510 * first. 1511 * 1512 * @param device Device number (constructed of major and minor device number) 1513 * @param block Linear media block number 1514 * @param bd Reference to the buffer descriptor pointer. 1515 * 1516 * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed 1517 * successfully or error code if error is occured) 1518 */ 1517 1519 rtems_status_code 1518 1520 rtems_bdbuf_read (dev_t device, … … 1605 1607 1606 1608 /* 1607 * @todo The use of these req blocks is not a great design. 1608 * The req is a struct with a single 'bufs' declared in the 1609 * req struct and the others are added in the outer level 1610 * struct. This relies on the structs joining as a single 1611 * array and that assumes the compiler packs the structs. 1612 * Why not just place on a list ? The BD has a node that 1613 * can be used. 1609 * @todo The use of these req blocks is not a great design. The req is a 1610 * struct with a single 'bufs' declared in the req struct and the 1611 * others are added in the outer level struct. This relies on the 1612 * structs joining as a single array and that assumes the compiler 1613 * packs the structs. Why not just place on a list ? The BD has a 1614 * node that can be used. 1614 1615 */ 1615 1616 req->bufs[req->count].user = bd; … … 1704 1705 1705 1706 /** 1706 * Release buffer that has been in use. The buffer could have been in the1707 * access state and so with a user of the cache or it was being transfered to1708 * or from the disk media and so with a driver. Wake any waiters. If no one is1709 * waiting and this is the only buffer on the LRU list see if anyone is1710 * waiting. Wake them if they are.1711 * 1712 * If the buffer has been modified use the modified release call.1713 * 1714 * @param bd The buffer to return to the pool.1715 * @ret val RTEMS_SUCCESSFUL This operation always succeeds.1716 * /1717 1707 * Release the buffer obtained by a read call back to the cache. If the buffer 1708 * was obtained by a get call and was not already in the cache the release 1709 * modified call should be used. A buffer released with this call obtained by a 1710 * get call may not be in sync with the contents on disk. If the buffer was in 1711 * the cache and modified before this call it will be returned to the modified 1712 * queue. The buffers is returned to the end of the LRU list. 1713 * 1714 * @param bd Reference to the buffer descriptor. 1715 * 1716 * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed 1717 * successfully or error code if error is occured) 1718 */ 1718 1719 rtems_status_code 1719 1720 rtems_bdbuf_release (rtems_bdbuf_buffer* bd) … … 1739 1740 { 1740 1741 /* 1741 * If this is a read ahead buffer place the ready queue. Buffers are 1742 * taken from here first. If we prepend then get from the queue the1743 * buffersfurthermost from the read buffer will be used.1742 * If this is a read ahead buffer place the ready queue. Buffers are taken 1743 * from here first. If we prepend then get from the queue the buffers 1744 * furthermost from the read buffer will be used. 1744 1745 */ 1745 1746 if (bd->state == RTEMS_BDBUF_STATE_READ_AHEAD) … … 1778 1779 1779 1780 /** 1780 * Release buffer that has been in use and has been modified. The buffer could 1781 * have been in the access state and so with a user of the cache or it was 1782 * being transfered to or from the disk media and so with a driver. Wake any 1783 * waiters. If no one is waiting and this is the only buffer on the LRU list 1784 * see if anyone is waiting. Wake them if they are. 1785 * 1786 * If the buffer has been modified use the modified release call. 1787 * 1788 * @param bd The buffer to return to the pool. 1789 * @retval RTEMS_SUCCESSFUL This operation always succeeds. 1790 */ 1791 1781 * Release the buffer allocated with a get or read call placing it on the 1782 * modidied list. If the buffer was not released modified before the hold 1783 * timer is set to the configuration value. If the buffer had been released 1784 * modified before but not written to disk the hold timer is not updated. The 1785 * buffer will be written to disk when the hold timer has expired, there are 1786 * not more buffers available in the cache and a get or read buffer needs one 1787 * or a sync call has been made. If the buffer is obtained with a get or read 1788 * before the hold timer has expired the buffer will be returned to the user. 1789 * 1790 * @param bd Reference to the buffer descriptor. 1791 * 1792 * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed 1793 * successfully or error code if error is occured) 1794 */ 1792 1795 rtems_status_code 1793 1796 rtems_bdbuf_release_modified (rtems_bdbuf_buffer* bd) … … 1819 1822 1820 1823 /** 1821 * Wait until specified buffer synchronized with disk. Invoked on exchanges 1822 * critical for data consistency on the media. The buffer is placed on the sync 1823 * list and the swapper is woken. No sync lock is taken as the buffers on the 1824 * sync list are taken first and passed to the driver before buffers on the 1825 * modified list. 1824 * Release the buffer as modified and wait until it has been synchronized with 1825 * the disk by writing it. This buffer will be the first to be transfer to disk 1826 * and other buffers may also be written if the maximum number of blocks in a 1827 * requests allows it. 1826 1828 * 1827 1829 * @note This code does not lock the sync mutex and stop additions to the 1828 * modified queue. This means the buffer could be written and then 1829 * returned to the modified list but will not happen as the buffer's 1830 * state is sync. 1831 * 1832 * @param bd Pointer to the bdbuf_buffer structure previously obtained using 1833 * get/read primitive. 1834 * @retval RTEMS_SUCCESSFUL Always returned. 1835 */ 1836 1830 * modified queue. 1831 * 1832 * @param bd Reference to the buffer descriptor. 1833 * 1834 * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed 1835 * successfully or error code if error is occured) 1836 */ 1837 1837 rtems_status_code 1838 1838 rtems_bdbuf_sync (rtems_bdbuf_buffer* bd) … … 1888 1888 } 1889 1889 1890 /* rtems_bdbuf_syncdev --1891 * Synchronize with disk all buffers containing the blocks belonging to1892 * specified device.1893 * 1894 * PARAMETERS:1895 * dev - block device number1896 * 1897 * RETURNS:1898 * RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully1899 * or error code if error is occured)1890 /** 1891 * Synchronize all modified buffers for this device with the disk and wait 1892 * until the transfers have completed. The sync mutex for the pool is locked 1893 * stopping the addition of any further modifed buffers. It is only the 1894 * currently modified buffers that are written. 1895 * 1896 * @param dev Block device number 1897 * 1898 * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed 1899 * successfully or error code if error is occured) 1900 1900 */ 1901 1901 rtems_status_code … … 1930 1930 rtems_bdbuf_lock_pool (pool); 1931 1931 1932 /* 1933 * Set the pool to have a sync active for a specific device and let the swap 1934 * out task know the id of the requester to wake when done. 1935 * 1936 * The swap out task will negate the sync active flag when no more buffers 1937 * for the device are held on the modified for sync queues. 1938 */ 1932 1939 pool->sync_active = TRUE; 1933 1940 pool->sync_requester = rtems_task_self (); … … 1944 1951 rtems_fatal_error_occurred (BLKDEV_FATAL_BDBUF_SWAPOUT_RE); 1945 1952 1946 rtems_bdbuf_lock_pool (pool);1947 1948 pool->sync_active = FALSE;1949 1950 1953 rtems_bdbuf_unlock_sync (pool); 1951 rtems_bdbuf_unlock_pool (pool);1952 1954 1953 1955 return rtems_disk_release(dd); 1954 1956 } 1955 1957 1956 /* bdbuf_write_transfer_done -- 1957 * Callout function. Invoked by block device driver when data transfer 1958 * to device (write) is completed. This function may be invoked from 1959 * interrupt handler. 1960 * 1961 * PARAMETERS: 1962 * arg - arbitrary argument specified in block device request 1963 * structure (in this case - pointer to the appropriate 1964 * bdbuf_buffer buffer descriptor structure). 1965 * status - I/O completion status 1966 * error - errno error code if status != RTEMS_SUCCESSFUL 1967 * 1968 * RETURNS: 1969 * none 1958 /** 1959 * Call back handler called by the low level driver when the transfer has 1960 * completed. This function may be invoked from interrupt handler. 1961 * 1962 * @param arg Arbitrary argument specified in block device request 1963 * structure (in this case - pointer to the appropriate 1964 * block device request structure). 1965 * @param status I/O completion status 1966 * @param error errno error code if status != RTEMS_SUCCESSFUL 1970 1967 */ 1971 1968 static void … … 1981 1978 1982 1979 /** 1983 * Process the modified list of buffers. We can have a sync or modified 1984 * list that needs to be handled. 1980 * Process the modified list of buffers. There us a sync or modified list that 1981 * needs to be handled. 1982 * 1983 * @param pid The pool id to process modified buffers on. 1984 * @param dev The device to handle. If -1 no device is selected so select the 1985 * device of the first buffer to be written to disk. 1986 * @param chain The modified chain to process. 1987 * @param transfer The chain to append buffers to be written too. 1988 * @param sync_active If TRUE this is a sync operation so expire all timers. 1989 * @param update_timers If TRUE update the timers. 1990 * @param timer_delta It update_timers is TRUE update the timers by this 1991 * amount. 1985 1992 */ 1986 1993 static void … … 2005 2012 { 2006 2013 /* 2007 * Check if the buffer's hold timer has reached 0. If a sync 2008 * is activeforce all the timers to 0.2014 * Check if the buffer's hold timer has reached 0. If a sync is active 2015 * force all the timers to 0. 2009 2016 * 2010 * @note Lots of sync requests will skew this timer. It should 2011 * be basedon TOD to be accurate. Does it matter ?2017 * @note Lots of sync requests will skew this timer. It should be based 2018 * on TOD to be accurate. Does it matter ? 2012 2019 */ 2013 2020 if (sync_active) … … 2033 2040 /* 2034 2041 * This assumes we can set dev_t to -1 which is just an 2035 * assumption. Cannot use the transfer list being empty 2036 * the sync devcalls sets the dev to use.2042 * assumption. Cannot use the transfer list being empty the sync dev 2043 * calls sets the dev to use. 2037 2044 */ 2038 2045 if (*dev == -1) … … 2057 2064 2058 2065 /** 2059 * Process the pool. 2066 * Process a pool's modified buffers. Check the sync list first then the 2067 * modified list extracting the buffers suitable to be written to disk. We have 2068 * a device at a time. The task level loop will repeat this operation while 2069 * there are buffers to be written. If the transfer fails place the buffers 2070 * back on the modified list and try again later. The pool is unlocked while 2071 * the buffers are beign written to disk. 2072 * 2073 * @param pid The pool id to process modified buffers on. 2074 * @param timer_delta It update_timers is TRUE update the timers by this 2075 * amount. 2076 * @param update_timers If TRUE update the timers. 2077 * @param write_req The write request structure. There is only one. 2078 * 2079 * @retval TRUE Buffers where written to disk so scan again. 2080 * @retval FALSE No buffers where written to disk. 2060 2081 */ 2061 2082 static boolean … … 2069 2090 dev_t dev = -1; 2070 2091 rtems_disk_device* dd; 2071 boolean result= TRUE;2092 boolean transfered_buffers = TRUE; 2072 2093 2073 2094 rtems_chain_initialize_empty (&transfer); … … 2075 2096 rtems_bdbuf_lock_pool (pool); 2076 2097 2098 /* 2099 * When the sync is for a device limit the sync to that device. If the sync 2100 * is for a buffer handle the devices in the order on the sync list. This 2101 * means the dev is -1. 2102 */ 2077 2103 if (pool->sync_active) 2078 2104 dev = pool->sync_device; 2079 2105 2080 #if 1 2081 /* 2082 * If we have any buffers in the sync queue move then to the 2083 * modified list. The first sync buffer will select the 2084 * device we use. 2106 /* 2107 * If we have any buffers in the sync queue move then to the modified 2108 * list. The first sync buffer will select the device we use. 2085 2109 */ 2086 2110 rtems_bdbuf_swapout_modified_processing (pid, &dev, … … 2102 2126 * the pool can be unlocked because the state is set to TRANSFER. 2103 2127 */ 2104 #endif 2128 2105 2129 rtems_bdbuf_unlock_pool (pool); 2106 2130 … … 2109 2133 */ 2110 2134 if (rtems_chain_is_empty (&transfer)) 2111 result= FALSE;2135 transfered_buffers = FALSE; 2112 2136 else 2113 2137 { … … 2118 2142 dd = rtems_disk_obtain (dev); 2119 2143 if (dd == NULL) 2120 result= FALSE;2144 transfered_buffers = FALSE; 2121 2145 else 2122 2146 { … … 2128 2152 2129 2153 /* 2130 * Take as many buffers a re configured and pass to the driver. Note,2131 * the API to the drivers has the array of buffers and if a chain was2132 * passed we could have just passed the list. If the driver API is2133 * updated it should be possible to make this change with little effect2134 * in this code. The array that is passed is broken in design and2135 * should be removed. Merging to members of a struct into the first2136 * member istrouble waiting to happen.2154 * Take as many buffers as configured and pass to the driver. Note, the 2155 * API to the drivers has the array of buffers and if a chain was passed 2156 * we could have just passed the list. If the driver API is updated it 2157 * should be possible to make this change with little effect in this 2158 * code. The array that is passed is broken in design and should be 2159 * removed. Merging to members of a struct into the first member is 2160 * trouble waiting to happen. 2137 2161 */ 2138 2162 … … 2151 2175 2152 2176 /* 2153 * If the device only accepts sequential buffers and 2154 * this is not the first buffer (the first is always 2155 * sequential, and the buffer is not sequential then 2156 * put the buffer back on the transfer chain and 2157 * write the committed buffers. 2177 * If the device only accepts sequential buffers and this is not the 2178 * first buffer (the first is always sequential, and the buffer is not 2179 * sequential then put the buffer back on the transfer chain and write 2180 * the committed buffers. 2158 2181 */ 2159 2182 … … 2177 2200 2178 2201 /* 2179 * Perform the transfer if there are no more buffers, or the 2180 * transfersize has reached the configured max. value.2202 * Perform the transfer if there are no more buffers, or the transfer 2203 * size has reached the configured max. value. 2181 2204 */ 2182 2205 … … 2191 2214 2192 2215 /* 2193 * Perform the transfer. No pool locks, no preemption, only the 2194 * d isk device is being held.2216 * Perform the transfer. No pool locks, no preemption, only the disk 2217 * device is being held. 2195 2218 */ 2196 2219 result = dd->ioctl (dd->phys_dev->dev, … … 2210 2233 * Place back on the pools modified queue and try again. 2211 2234 * 2212 * @warning Not sure this is the best option but I do 2213 * not knowwhat else can be done.2235 * @warning Not sure this is the best option but I do not know 2236 * what else can be done. 2214 2237 */ 2215 2238 rtems_chain_append (&pool->modified, &bd->link); … … 2261 2284 } 2262 2285 2263 if (pool->sync_active) 2264 rtems_event_send (pool->sync_requester, RTEMS_BDBUF_TRANSFER_SYNC); 2265 2266 return result; 2267 } 2268 2269 /** 2270 * Body of task which take care on flushing modified buffers to the disk. 2286 if (pool->sync_active && ! transfered_buffers) 2287 { 2288 rtems_id sync_requester = pool->sync_requester; 2289 pool->sync_active = FALSE; 2290 pool->sync_requester = 0; 2291 if (sync_requester) 2292 rtems_event_send (sync_requester, RTEMS_BDBUF_TRANSFER_SYNC); 2293 } 2294 2295 return transfered_buffers; 2296 } 2297 2298 /** 2299 * Body of task which takes care on flushing modified buffers to the disk. 2300 * 2301 * @param arg The task argument which is the context. 2271 2302 */ 2272 2303 static rtems_task … … 2302 2333 2303 2334 /* 2304 * This is temporary. Needs to be changed to use the real clock.2335 * This is temporary. Needs to be changed to use the real time clock. 2305 2336 */ 2306 2337 timer_delta = period_in_msecs; … … 2316 2347 2317 2348 /* 2318 * If we write buffers to any disk perform a check again. We only 2319 * write a single device at a time and a pool may have more than2320 * one devicesbuffers modified waiting to be written.2349 * If we write buffers to any disk perform a check again. We only write a 2350 * single device at a time and a pool may have more than one devices 2351 * buffers modified waiting to be written. 2321 2352 */ 2322 2353 boolean transfered_buffers; … … 2370 2401 * size. 2371 2402 * 2372 * PARAMETERS:2373 * block_size - requested block size2374 * pool - placeholder for result2375 * 2376 * RETURNS:2377 * RTEMS status code: RTEMS_SUCCESSFUL if operation completed successfully,2378 * RTEMS_INVALID_SIZE if specified block size is invalid (not a power2379 * of 2), RTEMS_NOT_DEFINED ifbuffer pool for this or greater block size2380 * is not configured.2403 * @param block_size Requested block size 2404 * @param pool The pool to use for the requested pool size. 2405 * 2406 * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed 2407 * successfully or error code if error is occured) 2408 * @retval RTEMS_INVALID_SIZE The specified block size is invalid (not a power 2409 * of 2) 2410 * @retval RTEMS_NOT_DEFINED The buffer pool for this or greater block size 2411 * is not configured. 2381 2412 */ 2382 2413 rtems_status_code … … 2421 2452 * Obtain characteristics of buffer pool with specified number. 2422 2453 * 2423 * PARAMETERS: 2424 * pool - buffer pool number 2425 * block_size - block size for which buffer pool is configured returned 2426 * there 2427 * blocks - number of buffers in buffer pool returned there 2454 * @param pool Buffer pool number 2455 * @param block_size Block size for which buffer pool is configured returned 2456 * there 2457 * @param blocks Number of buffers in buffer pool. 2428 2458 * 2429 2459 * RETURNS: 2430 * RTEMS status code: RTEMS_SUCCESSFUL if operation completed successfully,2431 * RTEMS_INVALID_NUMBER if appropriate buffer pool is not configured.2432 * 2433 * NOTE:2434 * Buffer pools enumerated contiguously starting from 0.2460 * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed 2461 * successfully or error code if error is occured) 2462 * @retval RTEMS_INVALID_SIZE The appropriate buffer pool is not configured. 2463 * 2464 * @note Buffer pools enumerated continuously starting from 0. 2435 2465 */ 2436 2466 rtems_status_code 2437 rtems_bdbuf_get_pool_info (rtems_bdpool_id pool, int* block_size, int* blocks)2467 rtems_bdbuf_get_pool_info (rtems_bdpool_id pool, int* block_size, int* blocks) 2438 2468 { 2439 2469 if (pool >= rtems_bdbuf_ctx.npools)
Note: See TracChangeset
for help on using the changeset viewer.