Changeset c21c850e in rtems for cpukit/libblock


Ignore:
Timestamp:
07/29/08 03:15:09 (16 years ago)
Author:
Chris Johns <chrisj@…>
Branches:
4.10, 4.11, 4.9, 5, master
Children:
021cf6b
Parents:
bafe97f4
Message:

2008-07-29 Chris Johns <chrisj@…>

  • libblock/include/rtems/bdbuf.h, cpukit/libblock/src/bdbuf.c: Update the comments.
Location:
cpukit/libblock
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • cpukit/libblock/include/rtems/bdbuf.h

    rbafe97f4 rc21c850e  
    22 * @file rtems/bdbuf.h
    33 *
    4  * block device buffer management
     4 * Block Device Buffer Management
    55 */
    66 
     
    99 * Author: Victor V. Vengerov <vvv@oktet.ru>
    1010 *
     11 * Copyright (C) 2008 Chris Johns <chrisj@rtems.org>
     12 *    Rewritten to remove score mutex access. Fixes many performance
     13 *    issues.
     14 *
    1115 * @(#) bdbuf.h,v 1.9 2005/02/02 00:06:18 joel Exp
    1216 */
     
    3135typedef enum
    3236{
    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 */
    4145} rtems_bdbuf_buf_state;
    4246
     
    5357  struct rtems_bdbuf_avl_node
    5458  {
    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 */
    5963  } avl;
    6064
    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)
    6670                                 * which can be used by user later */
    6771
    68   volatile rtems_bdbuf_buf_state state;  /* State of the buffer. */
    69 
    70   volatile uint32_t waiters;    /* The number of threads waiting on this
     72  volatile rtems_bdbuf_buf_state state;  /*< State of the buffer. */
     73
     74  volatile uint32_t waiters;    /*< The number of threads waiting on this
    7175                                 * buffer. */
    72   rtems_bdpool_id pool;         /* Identifier of buffer pool to which this buffer
     76  rtems_bdpool_id pool;         /*< Identifier of buffer pool to which this buffer
    7377                                    belongs */
    7478
    75   volatile uint32_t hold_timer; /* Timer to indicate how long a buffer
     79  volatile uint32_t hold_timer; /*< Timer to indicate how long a buffer
    7680                                 * has been held in the cache modified. */
    7781} rtems_bdbuf_buffer;
     
    8387typedef struct rtems_bdbuf_pool
    8488{
    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 and
     89  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
    9195                                          * 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 tree
     96  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
    98102                                         * 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 the
     103  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
    105109                                         * ACCESS state. */
    106   volatile uint32_t   access_waiters;   /* Count of access blockers. */
    107   rtems_id            transfer;         /* Obtain if waiting for a buffer in the
     110  volatile uint32_t   access_waiters;   /*< Count of access blockers. */
     111  rtems_id            transfer;         /*< Obtain if waiting for a buffer in the
    108112                                         * TRANSFER state. */
    109   volatile uint32_t   transfer_waiters; /* Count of transfer blockers. */
    110   rtems_id            waiting;          /* Obtain if waiting for a buffer and the
     113  volatile uint32_t   transfer_waiters; /*< Count of transfer blockers. */
     114  rtems_id            waiting;          /*< Obtain if waiting for a buffer and the
    111115                                         * none are available. */
    112   volatile uint32_t   wait_waiters;     /* Count of waiting blockers. */
    113 
    114   rtems_bdbuf_buffer* bds;              /* Pointer to table of buffer descriptors
     116  volatile uint32_t   wait_waiters;     /*< Count of waiting blockers. */
     117
     118  rtems_bdbuf_buffer* bds;              /*< Pointer to table of buffer descriptors
    115119                                         * allocated for this buffer pool. */
    116   void*               buffers;          /* The buffer's memory. */
     120  void*               buffers;          /*< The buffer's memory. */
    117121} rtems_bdbuf_pool;
    118122
     
    122126 */
    123127typedef 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 this
     128  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
    127131                             * case memory for blocks will be allocated by
    128132                             * Buffering Layer with the help of RTEMS partition
     
    141145 */
    142146typedef 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. */
    148152} rtems_bdbuf_config;
    149153
     
    164168#define RTEMS_BDBUF_SWAPOUT_TASK_BLOCK_HOLD_DEFAULT  1000 /* milli-seconds */
    165169
    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 */
     180rtems_status_code
     181rtems_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 */
     207rtems_status_code
     208rtems_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 */
     232rtems_status_code
     233rtems_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 */
     248rtems_status_code
     249rtems_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 */
     266rtems_status_code
     267rtems_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 */
     283rtems_status_code
     284rtems_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 */
     301rtems_status_code
     302rtems_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 */
     319rtems_status_code
     320rtems_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.
    172329 *
    173330 * 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 */
     337rtems_status_code
     338rtems_bdbuf_get_pool_info (rtems_bdpool_id pool, int *block_size, int *blocks);
    343339
    344340#ifdef __cplusplus
  • cpukit/libblock/src/bdbuf.c

    rbafe97f4 rc21c850e  
    88 *         Alexander Kukuta <kam@oktet.ru>
    99 *
     10 * Copyright (C) 2008 Chris Johns <chrisj@rtems.org>
     11 *    Rewritten to remove score mutex access. Fixes many performance
     12 *    issues.
     13 *
    1014 * @(#) bdbuf.c,v 1.14 2004/04/17 08:15:17 ralf Exp
    1115 */
     
    1418 * @file
    1519 *
    16  * The Buffer Descriptor Buffer code implement a cache between the disk
    17  * devices and file systems. The code provides a read ahead and qrite queuing
    18  * to 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.
    1923 *
    2024 * The buffers are held in pools based on size. Each pool has buffers and the
    2125 * buffers follow this state machine:
    22  *
    23  *                        read
     26 *                                 
     27 *                   read/read ahead
    2428 *          +-------------------------------+
    2529 *          |                               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 *                   |           |<-------------------------+
    4446 *                   +-----------+
    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.
    5683 *
    5784 * The pool have the following lists of buffers:
    5885 *
    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.
    6490 */
    6591
     
    88114 * The BD buffer context.
    89115 */
    90 /* Buffering layer context definition */
    91116typedef 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 */
    95120  boolean           swapout_enabled;
    96121} rtems_bdbuf_context;
     
    99124 * Fatal errors
    100125 */
    101 #define RTEMS_BLKDEV_FATAL_ERROR(n) (((uint32_t)'B' << 24) |         \
    102                                     ((uint32_t)(n) & (uint32_t)0x00FFFFFF))
     126#define RTEMS_BLKDEV_FATAL_ERROR(n) \
     127  (((uint32_t)'B' << 24) | ((uint32_t)(n) & (uint32_t)0x00FFFFFF))
    103128
    104129#define RTEMS_BLKDEV_FATAL_BDBUF_CONSISTENCY RTEMS_BLKDEV_FATAL_ERROR(1)
     
    115140#define BLKDEV_FATAL_BDBUF_SWAPOUT_TS        RTEMS_BLKDEV_FATAL_ERROR(12)
    116141
     142/**
     143 * The events used in this code. These should be system events rather than
     144 * application events.
     145 */
    117146#define RTEMS_BDBUF_TRANSFER_SYNC  RTEMS_EVENT_1
    118147#define RTEMS_BDBUF_SWAPOUT_SYNC   RTEMS_EVENT_2
    119148
     149/**
     150 * The swap out task size. Should be more than enough for most drivers with
     151 * tracing turned on.
     152 */
    120153#define SWAPOUT_TASK_STACK_SIZE (8 * 1024)
    121154
    122155/**
    123156 * Lock semaphore attributes. This is used for locking type mutexes.
     157 *
     158 * @warning Priority inheritance is on.
    124159 */
    125160#define RTEMS_BDBUF_POOL_LOCK_ATTRIBS \
     
    130165 * Waiter semaphore attributes.
    131166 *
    132  * @note Do not configure as inherit priority. If a driver is in the driver
    133  *       initialisation table this locked semaphore will have the IDLE task as
    134  *       the holder and a blocking task will raise the priority of the IDLE
    135  *       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.
    136171 */
    137172#define RTEMS_BDBUF_POOL_WAITER_ATTRIBS \
    138   (RTEMS_PRIORITY | RTEMS_BINARY_SEMAPHORE | \
     173  (RTEMS_PRIORITY | RTEMS_SIMPLE_BINARY_SEMAPHORE | \
    139174   RTEMS_NO_INHERIT_PRIORITY | RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL)
    140175
     
    211246  return p;
    212247}
    213 
    214 #if CCJ_REMOVE_IN_IN_CVS
    215 /**
    216  * Search in AVL tree for first modified buffer belongs to specified
    217  * disk device.
    218  *
    219  * @param root pointer to the root node of the AVL-Tree
    220  * @param dd - disk device descriptor
    221  * @retval NULL no modified blocks on the disk device
    222  * @return pointer to the modified node
    223  */
    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     else
    250     {
    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 #endif
    267248
    268249/**
     
    789770
    790771/**
    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 list
    793  * of tasks to be woken and this would require storgage and we do not
    794  * know the number of tasks 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.
    795776 *
    796777 * While we have the pool locked we can try and claim the semaphore and
     
    800781 * A counter is used to save the release call when no one is waiting.
    801782 *
    802  * The function assumes the pool is locked on entry and it will have locked
    803  * the pool on exit.
     783 * The function assumes the pool is locked on entry and it will be locked on
     784 * exit.
    804785 *
    805786 * @param pool The pool to wait for a buffer to return.
     
    880861 * Add a buffer descriptor to the modified list. This modified list is treated
    881862 * 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
    883872 * hold the sync lock. The sync lock is used to block writes while a sync is
    884873 * active.
    885874 *
    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.
    888877 */
    889878static void
     
    891880{
    892881  /*
    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))
    898889  {
    899890    rtems_bdbuf_unlock_pool (pool);
    900891    rtems_bdbuf_lock_sync (pool);
     892    rtems_bdbuf_unlock_sync (pool);
    901893    rtems_bdbuf_lock_pool (pool);
    902894  }
     
    905897
    906898  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 */
    912904static void
    913905rtems_bdbuf_wake_swapper ()
     
    919911}
    920912
    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.
    931921 */
    932922static rtems_status_code
     
    942932  pool = rtems_bdbuf_get_pool (pid);
    943933 
    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;
    948942
    949943  rtems_chain_initialize_empty (&pool->ready);
     
    952946  rtems_chain_initialize_empty (&pool->sync);
    953947
    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;
    957951  pool->transfer_waiters = 0;
    958   pool->waiting = 0;
    959   pool->wait_waiters = 0;
     952  pool->waiting          = 0;
     953  pool->wait_waiters     = 0;
    960954 
    961955  /*
     
    10081002  }
    10091003
    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,
    10121006                               &pool->sync_lock);
    10131007  if (sc != RTEMS_SUCCESSFUL)
     
    10611055}
    10621056
    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
    10711063 */
    10721064static rtems_status_code
     
    10881080}
    10891081
    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)
    11041091 */
    11051092rtems_status_code
     
    11851172 * Get a buffer for this device and block. This function returns a buffer once
    11861173 * 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.
    11891179 *
    11901180 * The AVL tree of buffers for the pool is searched and if not located check
    11911181 * 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 are
    1193  * in use buffers are taken from the LRU list with the least recently used
     1182 * 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
    11941184 * 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.
    12021197 *
    12031198 * A buffer located in the AVL tree means it is already in the cache and maybe
     
    12051200 *
    12061201 * # 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.
    12081203 * # Transfer. Is with the driver and part of a media transfer.
    12091204 *
    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.
    12131207 *
    12141208 * 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.
    12161211 *
    12171212 * @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)
    12311219 */
    12321220static rtems_bdbuf_buffer*
     
    12421230  /*
    12431231   * 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 wait
    1245    * until some return before proceeding. There is no timeout. If the buffer is
     1232   * 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
    12461234   * for a read ahead buffer return NULL.
    12471235   *
    12481236   * The search procedure is repeated as another thread could have pre-empted
    12491237   * 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.
    12511239   */
    12521240  do
     
    12641252     * the user. We cannot do much with the buffers with the user how-ever with
    12651253     * 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 to
    1267      * 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.
    12681256     */
    12691257    if (!bd)
     
    12721260       * Assign new buffer descriptor from the empty list if one is present. If
    12731261       * 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 wait
    1275        * until some are returned.
     1262       * LRU list is empty there are no available buffers check the modified
     1263       * list.
    12761264       */
    12771265      if (rtems_chain_is_empty (&pool->ready))
     
    12801268         * No unsed or read-ahead buffers.
    12811269         *
    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 be
    1284          * 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.
    12851273         */
    12861274        if (read_ahead)
     
    13041292          /*
    13051293           * 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.
    13071295           */
    13081296          if (!rtems_chain_is_empty (&pool->modified))
     
    13731361
    13741362  /*
    1375    * Loop waiting for the buffer to enter the cached state. If the buffer
    1376    * is in the 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.
    13771365   */
    13781366  available = FALSE;
     
    14151403
    14161404/**
    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)
    14301427 */
    14311428rtems_status_code
     
    14771474}
    14781475
    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
    14931485 */
    14941486static void
     
    15041496
    15051497/**
    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 */
    15171519rtems_status_code
    15181520rtems_bdbuf_read (dev_t                device,
     
    16051607
    16061608    /*
    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.
    16141615     */
    16151616    req->bufs[req->count].user   = bd;
     
    17041705
    17051706/**
    1706  * Release buffer that has been in use. The buffer could have been in the
    1707  * access state and so with a user of the cache or it was being transfered to
    1708  * or from the disk media and so with a driver. Wake any waiters. If no one is
    1709  * waiting and this is the only buffer on the LRU list see if anyone is
    1710  * 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  * @retval 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 */
    17181719rtems_status_code
    17191720rtems_bdbuf_release (rtems_bdbuf_buffer* bd)
     
    17391740  {
    17401741    /*
    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 the
    1743      * buffers furthermost 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.
    17441745     */
    17451746    if (bd->state == RTEMS_BDBUF_STATE_READ_AHEAD)
     
    17781779
    17791780/**
    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 */
    17921795rtems_status_code
    17931796rtems_bdbuf_release_modified (rtems_bdbuf_buffer* bd)
     
    18191822
    18201823/**
    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.
    18261828 *
    18271829 * @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 */
    18371837rtems_status_code
    18381838rtems_bdbuf_sync (rtems_bdbuf_buffer* bd)
     
    18881888}
    18891889
    1890 /* rtems_bdbuf_syncdev --
    1891  *     Synchronize with disk all buffers containing the blocks belonging to
    1892  *     specified device.
    1893  *
    1894  * PARAMETERS:
    1895  *     dev - block device number
    1896  *
    1897  * RETURNS:
    1898  *     RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
    1899  *     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)
    19001900 */
    19011901rtems_status_code
     
    19301930  rtems_bdbuf_lock_pool (pool); 
    19311931
     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   */
    19321939  pool->sync_active    = TRUE;
    19331940  pool->sync_requester = rtems_task_self ();
     
    19441951    rtems_fatal_error_occurred (BLKDEV_FATAL_BDBUF_SWAPOUT_RE);
    19451952     
    1946   rtems_bdbuf_lock_pool (pool);
    1947 
    1948   pool->sync_active = FALSE;
    1949 
    19501953  rtems_bdbuf_unlock_sync (pool);
    1951   rtems_bdbuf_unlock_pool (pool);
    19521954 
    19531955  return rtems_disk_release(dd);
    19541956}
    19551957
    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
    19701967 */
    19711968static void
     
    19811978
    19821979/**
    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.
    19851992 */
    19861993static void
     
    20052012      {
    20062013        /*
    2007          * Check if the buffer's hold timer has reached 0. If a sync
    2008          * is active force 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.
    20092016         *
    2010          * @note Lots of sync requests will skew this timer. It should
    2011          *       be based on 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 ?
    20122019         */
    20132020        if (sync_active)
     
    20332040        /*
    20342041         * 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 dev calls sets the dev to use.
     2042         * assumption. Cannot use the transfer list being empty the sync dev
     2043         * calls sets the dev to use.
    20372044         */
    20382045        if (*dev == -1)
     
    20572064
    20582065/**
    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.
    20602081 */
    20612082static boolean
     
    20692090  dev_t               dev = -1;
    20702091  rtems_disk_device*  dd;
    2071   boolean             result = TRUE;
     2092  boolean             transfered_buffers = TRUE;
    20722093
    20732094  rtems_chain_initialize_empty (&transfer);
     
    20752096  rtems_bdbuf_lock_pool (pool);
    20762097
     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   */
    20772103  if (pool->sync_active)
    20782104    dev = pool->sync_device;
    20792105
    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.
    20852109   */
    20862110  rtems_bdbuf_swapout_modified_processing (pid, &dev,
     
    21022126   * the pool can be unlocked because the state is set to TRANSFER.
    21032127   */
    2104 #endif
     2128
    21052129  rtems_bdbuf_unlock_pool (pool);
    21062130
     
    21092133   */
    21102134  if (rtems_chain_is_empty (&transfer))
    2111     result = FALSE;
     2135    transfered_buffers = FALSE;
    21122136  else
    21132137  {
     
    21182142    dd = rtems_disk_obtain (dev);
    21192143    if (dd == NULL)
    2120       result = FALSE;
     2144       transfered_buffers = FALSE;
    21212145    else
    21222146    {
     
    21282152     
    21292153      /*
    2130        * Take as many buffers are configured and pass to the driver. Note,
    2131        * the API to the drivers has the array of buffers and if a chain was
    2132        * passed we could have just passed the list. If the driver API is
    2133        * updated it should be possible to make this change with little effect
    2134        * in this code. The array that is passed is broken in design and
    2135        * should be removed. Merging to members of a struct into the first
    2136        * member is trouble 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.
    21372161       */
    21382162
     
    21512175       
    21522176        /*
    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.
    21582181         */
    21592182       
     
    21772200
    21782201        /*
    2179          * Perform the transfer if there are no more buffers, or the
    2180          * transfer size 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.
    21812204         */
    21822205
     
    21912214
    21922215          /*
    2193            * Perform the transfer. No pool locks, no preemption, only the
    2194            * disk device is being held.
     2216           * Perform the transfer. No pool locks, no preemption, only the disk
     2217           * device is being held.
    21952218           */
    21962219          result = dd->ioctl (dd->phys_dev->dev,
     
    22102233               * Place back on the pools modified queue and try again.
    22112234               *
    2212                * @warning Not sure this is the best option but I do
    2213                *          not know what else can be done.
     2235               * @warning Not sure this is the best option but I do not know
     2236               *          what else can be done.
    22142237               */
    22152238              rtems_chain_append (&pool->modified, &bd->link);
     
    22612284  }
    22622285
    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.
    22712302 */
    22722303static rtems_task
     
    23022333
    23032334  /*
    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.
    23052336   */
    23062337  timer_delta = period_in_msecs;
     
    23162347   
    23172348    /*
    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 than
    2320      * one devices buffers 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.
    23212352     */
    23222353    boolean transfered_buffers;
     
    23702401 * size.
    23712402 *
    2372  * PARAMETERS:
    2373  *     block_size - requested block size
    2374  *     pool       - placeholder for result
    2375  *
    2376  * RETURNS:
    2377  *     RTEMS status code: RTEMS_SUCCESSFUL if operation completed successfully,
    2378  *     RTEMS_INVALID_SIZE if specified block size is invalid (not a power
    2379  *     of 2), RTEMS_NOT_DEFINED if buffer pool for this or greater block size
    2380  *     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.
    23812412 */
    23822413rtems_status_code
     
    24212452 * Obtain characteristics of buffer pool with specified number.
    24222453 *
    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.
    24282458 *
    24292459 * 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.
    24352465 */
    24362466rtems_status_code
    2437 rtems_bdbuf_get_pool_info(rtems_bdpool_id pool, int* block_size, int* blocks)
     2467rtems_bdbuf_get_pool_info (rtems_bdpool_id pool, int* block_size, int* blocks)
    24382468{
    24392469  if (pool >= rtems_bdbuf_ctx.npools)
Note: See TracChangeset for help on using the changeset viewer.