Index: cpukit/libblock/src/bdbuf.c
===================================================================
--- cpukit/libblock/src/bdbuf.c	(revision 3899a5379f4bfa067e73b4612a547a308a6634ec)
+++ cpukit/libblock/src/bdbuf.c	(revision c21c850ec746dc6a26a07a466e72eee354edc5a7)
@@ -8,4 +8,8 @@
  *         Alexander Kukuta <kam@oktet.ru>
  *
+ * Copyright (C) 2008 Chris Johns <chrisj@rtems.org>
+ *    Rewritten to remove score mutex access. Fixes many performance
+ *    issues.
+ * 
  * @(#) bdbuf.c,v 1.14 2004/04/17 08:15:17 ralf Exp
  */
@@ -14,52 +18,74 @@
  * @file
  *
- * The Buffer Descriptor Buffer code implement a cache between the disk
- * devices and file systems. The code provides a read ahead and qrite queuing
- * to the drivers and fast cache look up using an AVL tree.
+ * The Buffer Descriptor Buffer code implements a cache between the disk
+ * devices and file systems. The code provides read ahead and write queuing to
+ * the drivers and fast cache look up using an AVL tree.
  *
  * The buffers are held in pools based on size. Each pool has buffers and the
  * buffers follow this state machine:
- *
- *                        read
+ *                                  
+ *                   read/read ahead
  *          +-------------------------------+
  *          |                               v
- *     +-----------+   read complete +------------+
- *     |           |  write complete |            |---------+
- *     |   EMPTY   |       +---------|  TRANSFER  |         |
- *     |           |       |         |            |<--+     |
- *     +-----------+       |         +------------+   |     |
- *          ^   | get      v                     swap |     |
- *          |   |    +-----------+ modified  +------------+ |
- *          |   +--->|           |---------->|            | |
- *          |        |  ACCESSED |<----------|  MODIFIED  | |
- *          |   +----|           |<--+   get |            | |
- *          |   |    +-----------+   |       +------------+ |
- *          |   |                    |                      |
- *          |   | release        get |                      |
- *          |   |                    |                      |
- *          |   |    +-----------+   |                      |
- *   expire |   +--->|           |---+        read complete |
- *          |        |   CACHED  |           write complete |
- *          +--------|           |<-------------------------+
+ *     +-----------+ read ahead      +------------+
+ *     | READY,    |  complete       |            |---------+
+ *     |  READ     |<----------------|  TRANSFER  |         |
+ *     |   AHEAD   |   +-------------|            |<--+     |
+ *     +-----------+   | read/write  +------------+   |     |
+ *              | get  v complete                swap |     |
+ *              |    +-----------+ modified  +------------+ |
+ *              +--->| ACCESSED, |---------->|  MODIFIED, | |
+ *                   | ACCESSED  |<----------|  SYNC      | |
+ *              +----|  MODIFIED |<--+   get |            | |
+ *              |    +-----------+   |       +------------+ |
+ *              | release        get |                      |
+ *              |    +-----------+   |                      |
+ *              +--->|           |---+        read complete |
+ *                   |   CACHED  |           write complete |
+ *                   |           |<-------------------------+
  *                   +-----------+
- *
- * Empty buffers are added to the empty list and removed from this queue when a
- * caller wishes to access a buffer. This is referred to getting a buffer in
- * the code and the event get in the state diagram. The buffer is assigned to a
- * block and inserted to the AVL. If the block is to be read by the user and
- * not in the cache (empty) it is transfered from the disk into memory. If no
- * empty buffers exist the buffer is expired from the cache. Currently the
- * least recently used block is expired first. A block being accessed is given
- * to the file system layer and not accessable to another requester until
- * released back to the cache. If the user has modifed the block it is
- * transfered to disk then placed on the LRU list.
+ *         
+ * Empty buffers are added to the ready list and removed from this queue when a
+ * caller requests a buffer. This is referred to as getting a buffer in the
+ * code and the event get in the state diagram. The buffer is assigned to a
+ * block and inserted to the AVL based on the block/device key. If the block is
+ * to be read by the user and not in the cache (ready) it is transfered from
+ * the disk into memory. If no ready buffers exist the buffer is taken from the
+ * LRU list. If no buffers are on the LRU list the modified list is check. If
+ * no buffers are on the modified list the request blocks. If buffers are on
+ * the modified list the buffers hold timer is expired and the swap out task
+ * woken.
+ *
+ * A block being accessed is given to the file system layer and not accessable
+ * to another requester until released back to the cache. The same goes to a
+ * buffer in the transfer state. The transfer state means being read or
+ * written. If the file system has modifed the block and releases it as
+ * modified it placed on the pool's modified list and a hold timer
+ * initialised. The buffer is held for the hold time before being written to
+ * disk. Buffers are held for a configurable period of time on the modified
+ * list as a write sets the state to transfer and this locks the buffer out
+ * from the file system until the write complete. Buffers are often repeatable
+ * accessed and modified in a series of small updates so if sent to the disk
+ * when released as modified the user would have to block waiting until it had
+ * been written. This would be a performance problem.
+ *
+ * The code performs mulitple block reads and writes. Multiple block reads or
+ * read ahead increases performance with hardware that supports it. It also
+ * helps with a large cache as the disk head movement is reduced. It how-ever
+ * is a speculative operation so excessive use can remove valuable and needed
+ * blocks from the cache. The get call knows if a read is a for the file system
+ * or if it is a read ahead get. If the get is for a read ahead block and the
+ * block is already in the cache or no ready buffers are available the read
+ * ahead is stopped. The transfer occurs with the blocks so far. If a buffer is
+ * in the read ahead state and release it is placed on the ready list rather
+ * than the LRU list. This means these buffers are used before buffers used by
+ * the file system.
  *
  * The pool have the following lists of buffers:
  *
- *   empty        - Empty buffers created when the pool is initialised.
- *   modided      - Buffers waiting to be written to disk.
- *   cached_lru   - Accessed buffers released in least recently used order.
- *   cached_unsed - Read ahead buffers that have not been accessed.
- *
+ *   ready        - Empty buffers created when the pool is initialised.
+ *   modified     - Buffers waiting to be written to disk.
+ *   sync         - Buffers to be synced to disk.
+ *   lru          - Accessed buffers released in least recently used order.
  */
 
@@ -88,9 +114,8 @@
  * The BD buffer context.
  */
-/* Buffering layer context definition */
 typedef struct rtems_bdbuf_context {
-  rtems_bdbuf_pool* pool;      /* Table of buffer pools */
-  int               npools;    /* Number of entries in pool table */
-  rtems_id          swapout;   /* Swapout task ID */
+  rtems_bdbuf_pool* pool;      /*< Table of buffer pools */
+  int               npools;    /*< Number of entries in pool table */
+  rtems_id          swapout;   /*< Swapout task ID */
   boolean           swapout_enabled;
 } rtems_bdbuf_context;
@@ -99,6 +124,6 @@
  * Fatal errors
  */
-#define RTEMS_BLKDEV_FATAL_ERROR(n) (((uint32_t)'B' << 24) |         \
-                                     ((uint32_t)(n) & (uint32_t)0x00FFFFFF))
+#define RTEMS_BLKDEV_FATAL_ERROR(n) \
+  (((uint32_t)'B' << 24) | ((uint32_t)(n) & (uint32_t)0x00FFFFFF))
 
 #define RTEMS_BLKDEV_FATAL_BDBUF_CONSISTENCY RTEMS_BLKDEV_FATAL_ERROR(1)
@@ -115,11 +140,21 @@
 #define BLKDEV_FATAL_BDBUF_SWAPOUT_TS        RTEMS_BLKDEV_FATAL_ERROR(12)
 
+/**
+ * The events used in this code. These should be system events rather than
+ * application events.
+ */
 #define RTEMS_BDBUF_TRANSFER_SYNC  RTEMS_EVENT_1
 #define RTEMS_BDBUF_SWAPOUT_SYNC   RTEMS_EVENT_2
 
+/**
+ * The swap out task size. Should be more than enough for most drivers with
+ * tracing turned on.
+ */
 #define SWAPOUT_TASK_STACK_SIZE (8 * 1024)
 
 /**
  * Lock semaphore attributes. This is used for locking type mutexes.
+ *
+ * @warning Priority inheritance is on.
  */
 #define RTEMS_BDBUF_POOL_LOCK_ATTRIBS \
@@ -130,11 +165,11 @@
  * Waiter semaphore attributes.
  *
- * @note Do not configure as inherit priority. If a driver is in the driver
- *       initialisation table this locked semaphore will have the IDLE task as
- *       the holder and a blocking task will raise the priority of the IDLE
- *       task which can cause unsual side effects.
+ * @warning Do not configure as inherit priority. If a driver is in the driver
+ *          initialisation table this locked semaphore will have the IDLE task
+ *          as the holder and a blocking task will raise the priority of the
+ *          IDLE task which can cause unsual side effects.
  */
 #define RTEMS_BDBUF_POOL_WAITER_ATTRIBS \
-  (RTEMS_PRIORITY | RTEMS_BINARY_SEMAPHORE | \
+  (RTEMS_PRIORITY | RTEMS_SIMPLE_BINARY_SEMAPHORE | \
    RTEMS_NO_INHERIT_PRIORITY | RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL)
 
@@ -211,58 +246,4 @@
   return p;
 }
-
-#if CCJ_REMOVE_IN_IN_CVS
-/**
- * Search in AVL tree for first modified buffer belongs to specified
- * disk device.
- *
- * @param root pointer to the root node of the AVL-Tree
- * @param dd - disk device descriptor
- * @retval NULL no modified blocks on the disk device
- * @return pointer to the modified node
- */
-static rtems_bdbuf_buffer *
-rtems_bdbuf_avl_search_for_sync (rtems_bdbuf_buffer** root,
-                                 rtems_disk_device*   dd)
-{
-  dev_t                dev = dd->phys_dev->dev;
-  rtems_blkdev_bnum    block_start = dd->start;
-  rtems_blkdev_bnum    block_end = dd->start + dd->size - 1;
-  rtems_bdbuf_buffer*  buf_stack[RTEMS_BDBUF_AVL_MAX_HEIGHT];
-  rtems_bdbuf_buffer** buf_prev = buf_stack;
-  rtems_bdbuf_buffer*  p = *root;
-
-  while (p != NULL)
-  {
-    if ((p->dev < dev) || ((p->dev == dev) && (p->block < block_start)))
-    {
-      p = p->avl.right;
-    }
-    else if ((p->dev > dev) || ((p->dev == dev) && (p->block > block_end)))
-    {
-      p = p->avl.left;
-    }
-    else if (p->state == RTEMS_BDBUF_STATE_MODIFIED)
-    {
-      return p;
-    }
-    else
-    {
-      if (p->avl.right != NULL)
-      {
-        *buf_prev++ = p->avl.right;
-      }
-      p = p->avl.left;
-    }
-
-    if ((p == NULL) && (buf_prev > buf_stack))
-    {
-      p = *--buf_prev;
-    }
-  }
-
-  return p;
-}
-#endif
 
 /**
@@ -789,8 +770,8 @@
 
 /**
- * Wait until woken. Semaphores are used so a number of tasks can wait and
- * can be woken at once. Task events would require we maintain a list
- * of tasks to be woken and this would require storgage and we do not
- * know the number of tasks that could be waiting.
+ * Wait until woken. Semaphores are used so a number of tasks can wait and can
+ * be woken at once. Task events would require we maintain a list of tasks to
+ * be woken and this would require storgage and we do not know the number of
+ * tasks that could be waiting.
  *
  * While we have the pool locked we can try and claim the semaphore and
@@ -800,6 +781,6 @@
  * A counter is used to save the release call when no one is waiting.
  *
- * The function assumes the pool is locked on entry and it will have locked
- * the pool on exit.
+ * The function assumes the pool is locked on entry and it will be locked on
+ * exit.
  *
  * @param pool The pool to wait for a buffer to return.
@@ -880,10 +861,18 @@
  * Add a buffer descriptor to the modified list. This modified list is treated
  * a litte differently to the other lists. To access it you must have the pool
- * locked and this is assumed to be the case on entry to this call and you must
+ * locked and this is assumed to be the case on entry to this call.
+ *
+ * If the pool has a device being sync'ed and the bd is for that device the
+ * call must block and wait until the sync is over before adding the bd to the
+ * modified list. Once a sync happens for a device no bd's can be added the
+ * modified list. The disk image is forced to be snapshot at that moment in
+ * time.
+ *
+ * and you must
  * hold the sync lock. The sync lock is used to block writes while a sync is
  * active.
  *
- * @param sema The semaphore to release.
- * @param waiters The wait counter for this semaphore.
+ * @param pool The pool the bd belongs to.
+ * @param bd The bd to queue to the pool's modified list.
  */
 static void
@@ -891,12 +880,15 @@
 {
   /*
-   * Take a copy of the sync_active variable as it will change after
-   * we unlock the pool and wait for the sync to finish.
-   */
-  int sync_active = pool->sync_active;
-  if (0 && sync_active)
+   * If the pool has a device being sync'ed check if this bd is for that
+   * device. If it is unlock the pool and block on the sync lock. once we have
+   * the sync lock reelase it.
+   *
+   * If the 
+   */
+  if (pool->sync_active && (pool->sync_device == bd->dev))
   {
     rtems_bdbuf_unlock_pool (pool);
     rtems_bdbuf_lock_sync (pool);
+    rtems_bdbuf_unlock_sync (pool);
     rtems_bdbuf_lock_pool (pool);
   }
@@ -905,9 +897,9 @@
 
   rtems_chain_append (&pool->modified, &bd->link);
-
-  if (0 && sync_active)
-    rtems_bdbuf_unlock_sync (pool);
-}
-
+}
+
+/**
+ * Wait the swapper task.
+ */
 static void
 rtems_bdbuf_wake_swapper ()
@@ -919,14 +911,12 @@
 }
 
-/* bdbuf_initialize_pool --
- *      Initialize single buffer pool.
- *
- * PARAMETERS:
- *     config - buffer pool configuration
- *     pool   - pool number
- *
- * RETURNS:
- *     RTEMS_SUCCESSFUL, if buffer pool initialized successfully, or error
- *     code if error occured.
+/**
+ * Initialize single buffer pool.
+ *
+ * @param config Buffer pool configuration
+ * @param pid Pool number
+ *
+ * @return RTEMS_SUCCESSFUL, if buffer pool initialized successfully, or error
+ *         code if error occured.
  */
 static rtems_status_code
@@ -942,8 +932,12 @@
   pool = rtems_bdbuf_get_pool (pid);
   
-  pool->blksize = config->size;
-  pool->nblks   = config->num;
-  pool->tree    = NULL;
-  pool->buffers = NULL;
+  pool->blksize        = config->size;
+  pool->nblks          = config->num;
+  pool->flags          = 0;
+  pool->sync_active    = FALSE;
+  pool->sync_device    = -1;
+  pool->sync_requester = 0;
+  pool->tree           = NULL;
+  pool->buffers        = NULL;
 
   rtems_chain_initialize_empty (&pool->ready);
@@ -952,10 +946,10 @@
   rtems_chain_initialize_empty (&pool->sync);
 
-  pool->access = 0;
-  pool->access_waiters = 0;
-  pool->transfer = 0;
+  pool->access           = 0;
+  pool->access_waiters   = 0;
+  pool->transfer         = 0;
   pool->transfer_waiters = 0;
-  pool->waiting = 0;
-  pool->wait_waiters = 0;
+  pool->waiting          = 0;
+  pool->wait_waiters     = 0;
   
   /*
@@ -1008,6 +1002,6 @@
   }
 
-  sc = rtems_semaphore_create (rtems_build_name ('B', 'P', '0' + pid, 's'),
-                               0, RTEMS_BDBUF_POOL_WAITER_ATTRIBS, 0,
+  sc = rtems_semaphore_create (rtems_build_name ('B', 'P', '0' + pid, 'S'),
+                               1, RTEMS_BDBUF_POOL_LOCK_ATTRIBS, 0,
                                &pool->sync_lock);
   if (sc != RTEMS_SUCCESSFUL)
@@ -1061,12 +1055,10 @@
 }
 
-/* bdbuf_release_pool --
- *     Free resources allocated for buffer pool with specified number.
- *
- * PARAMETERS:
- *     pool - buffer pool number
- *
- * RETURNS:
- *     RTEMS_SUCCESSFUL
+/**
+ * Free resources allocated for buffer pool with specified number.
+ *
+ * @param pid Buffer pool number
+ *
+ * @retval RTEMS_SUCCESSFUL
  */
 static rtems_status_code
@@ -1088,18 +1080,13 @@
 }
 
-/* rtems_bdbuf_init --
- *     Prepare buffering layer to work - initialize buffer descritors
- *     and (if it is neccessary) buffers. Buffers will be allocated according
- *     to the configuration table, each entry describes kind of block and
- *     amount requested. After initialization all blocks are placed onto
- *     empty elements lists.
- *
- * PARAMETERS:
- *     conf_table - pointer to the buffers configuration table
- *     size       - number of entries in configuration table
- *
- * RETURNS:
- *     RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
- *     or error code if error is occured)
+/**
+ * Prepare buffering layer to work - initialize buffer descritors and (if it is
+ * neccessary) buffers. Buffers will be allocated accoriding to the
+ * configuration table, each entry describes the size of block and the size of
+ * the pool. After initialization all blocks is placed into the ready state.
+ * lists.
+ *
+ * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed
+ *         successfully or error code if error is occured)
  */
 rtems_status_code
@@ -1185,19 +1172,27 @@
  * Get a buffer for this device and block. This function returns a buffer once
  * placed into the AVL tree. If no buffer is available and it is not a read
- * ahead request wait until one is available. If the buffer is for a read ahead
- * transfer return NULL if there is not buffer or it is in the cache.
+ * ahead request and no buffers are waiting to the written to disk wait until
+ * one is available. If buffers are waiting to be written to disk and non are
+ * available expire the hold timer and wake the swap out task. If the buffer is
+ * for a read ahead transfer return NULL if there is not buffer or it is in the
+ * cache.
  *
  * The AVL tree of buffers for the pool is searched and if not located check
  * obtain a buffer and insert it into the AVL tree. Buffers are first obtained
- * from the ready list until all empty buffers are used. Once all buffers are
- * in use buffers are taken from the LRU list with the least recently used
+ * from the ready list until all empty/ready buffers are used. Once all buffers
+ * are in use buffers are taken from the LRU list with the least recently used
  * buffer taken first. A buffer taken from the LRU list is removed from the AVL
- * tree. The empty list or LRU list buffer is initialised to this device and
- * block. If no buffers are available due to the empty and LRU lists being
- * empty the caller is blocked on the waiting semaphore and counter. When
- * buffers return from the upper layers (access) or lower driver (transfer) the
- * blocked caller task is woken and this procedure is repeated. The repeat
- * handles a case of a another thread pre-empting getting a buffer first and
- * adding it to the AVL tree.
+ * tree. The ready list or LRU list buffer is initialised to this device and
+ * block. If no buffers are available due to the ready and LRU lists being
+ * empty a check is made of the modified list. Buffers may be queued waiting
+ * for the hold timer to expire. These buffers should be written to disk and
+ * returned to the LRU list where they can be used rather than this call
+ * blocking. If buffers are on the modified list the max. write block size of
+ * buffers have their hold timer expired and the swap out task woken. The
+ * caller then blocks on the waiting semaphore and counter. When buffers return
+ * from the upper layers (access) or lower driver (transfer) the blocked caller
+ * task is woken and this procedure is repeated. The repeat handles a case of a
+ * another thread pre-empting getting a buffer first and adding it to the AVL
+ * tree.
  *
  * A buffer located in the AVL tree means it is already in the cache and maybe
@@ -1205,28 +1200,21 @@
  *
  * # Cached. Not being accessed or part of a media transfer.
- * # Access. Is with an upper layer being accessed.
+ * # Access or modifed access. Is with an upper layer being accessed.
  * # Transfer. Is with the driver and part of a media transfer.
  *
- * If cached we assign the state new state extract it from any list it maybe
- * part of and return to the user. The buffer could be part of the LRU list or
- * the modifed list waiting to be swapped out by the swap out task.
+ * If cached we assign the new state, extract it from any list it maybe part of
+ * and return to the user.
  *
  * This function assumes the pool the buffer is being taken from is locked and
- * it insure the pool is locked when it returns.
+ * it will make sure the pool is locked when it returns. The pool will be
+ * unlocked if the call could block.
  *
  * @param device The physical disk device
- * @param block  Linear media block number
- * @param
- * @param bd     Address to store of found descriptor
-
- * RETURNS:
- *     RTEMS status code ( if operation completed successfully
- *     or error code if error is occured)
- *
- * SIDE EFFEECTS:
- *     bufget_sema may be obtained by this primitive
- *
- * NOTE:
- *     It is assumed that primitive invoked when thread preemption is disabled.
+ * @param pool The pool reference
+ * @param block Absolute media block number
+ * @param read_ahead The get is for a read ahead buffer
+ *
+ * @return RTEMS status code ( if operation completed successfully or error
+ *         code if error is occured)
  */
 static rtems_bdbuf_buffer*
@@ -1242,11 +1230,11 @@
   /*
    * Loop until we get a buffer. Under load we could find no buffers are
-   * available so in the case of the required block this task needs to wait
-   * until some return before proceeding. There is no timeout. If the buffer is
+   * available requiring this task to wait until some become available before
+   * proceeding. There is no timeout. If the call is to block and the buffer is
    * for a read ahead buffer return NULL.
    *
    * The search procedure is repeated as another thread could have pre-empted
    * us while we waited for a buffer, obtained an empty buffer and loaded the
-   * AVL tree with it.
+   * AVL tree with the one we are after.
    */
   do
@@ -1264,6 +1252,6 @@
      * the user. We cannot do much with the buffers with the user how-ever with
      * the modified buffers waiting to be written to disk flush the maximum
-     * number transfered in a block to disk. After this all that be done is to
-     * wait for a buffer to return to the cache.
+     * number transfered in a block to disk. After this all that can be done is
+     * to wait for a buffer to return to the cache.
      */
     if (!bd)
@@ -1272,6 +1260,6 @@
        * Assign new buffer descriptor from the empty list if one is present. If
        * the empty queue is empty get the oldest buffer from LRU list. If the
-       * LRU list is empty there are no available buffers so we need to wait
-       * until some are returned.
+       * LRU list is empty there are no available buffers check the modified
+       * list.
        */
       if (rtems_chain_is_empty (&pool->ready))
@@ -1280,7 +1268,7 @@
          * No unsed or read-ahead buffers.
          *
-         * If this is a read ahead buffer just return. No need to place
-         * further pressure on the cache by reading something that may be
-         * needed when we have data in the cache that was needed.
+         * If this is a read ahead buffer just return. No need to place further
+         * pressure on the cache by reading something that may be needed when
+         * we have data in the cache that was needed and may still be.
          */
         if (read_ahead)
@@ -1304,5 +1292,5 @@
           /*
            * If there are buffers on the modified list expire the hold timer
-           * and wake the swap out task.
+           * and wake the swap out task then wait else just go and wait.
            */
           if (!rtems_chain_is_empty (&pool->modified))
@@ -1373,6 +1361,6 @@
 
   /*
-   * Loop waiting for the buffer to enter the cached state. If the buffer
-   * is in the access or transfer state then wait until it is not.
+   * Loop waiting for the buffer to enter the cached state. If the buffer is in
+   * the access or transfer state then wait until it is not.
    */
   available = FALSE;
@@ -1415,17 +1403,26 @@
 
 /**
- * Obtain block buffer. If specified block already cached (i.e. there's block
- * in the _modified_, or _recently_used_), return address of appropriate buffer
- * descriptor. If block is not cached, allocate new buffer and return it. Data
- * shouldn't be read to the buffer from media; buffer may contains arbitrary
- * data. This primitive may be blocked if there are no free buffer descriptors
- * available and there are no unused non-modified (or synchronized with media)
- * buffers available.
- *
- * @param device device number (constructed of major and minor device number)
- * @param block linear media block number
- * @param bd address of variable to store pointer to the buffer descriptor
- * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
- *         or error code if error is occured)
+ * Get block buffer for data to be written into. The buffers is set to the
+ * access or modifed access state. If the buffer is in the cache and modified
+ * the state is access modified else the state is access. This buffer contents
+ * are not initialised if the buffer is not already in the cache. If the block
+ * is already resident in memory it is returned how-ever if not in memory the
+ * buffer is not read from disk. This call is used when writing the whole block
+ * on a disk rather than just changing a part of it. If there is no buffers
+ * available this call will block. A buffer obtained with this call will not be
+ * involved in a transfer request and will not be returned to another user
+ * until released. If the buffer is already with a user when this call is made
+ * the call is blocked until the buffer is returned. The highest priority
+ * waiter will obtain the buffer first.
+ *
+ * The block number is the linear block number. This is relative to the start
+ * of the partition on the media.
+ *
+ * @param device Device number (constructed of major and minor device number)
+ * @param block  Linear media block number
+ * @param bd     Reference to the buffer descriptor pointer.
+ *
+ * @return       RTEMS status code (RTEMS_SUCCESSFUL if operation completed
+ *               successfully or error code if error is occured)
  */
 rtems_status_code
@@ -1477,18 +1474,13 @@
 }
 
-/* bdbuf_read_transfer_done --
- *     Callout function. Invoked by block device driver when data transfer
- *     from device (read) is completed. This function may be invoked from
- *     interrupt handler.
- *
- * PARAMETERS:
- *     arg    - arbitrary argument specified in block device request
- *              structure (in this case - pointer to the appropriate
- *              bdbuf_buffer buffer descriptor structure).
- *     status - I/O completion status
- *     error  - errno error code if status != RTEMS_SUCCESSFUL
- *
- * RETURNS:
- *     none
+/**
+ * Call back handler called by the low level driver when the transfer has
+ * completed. This function may be invoked from interrupt handler.
+ *
+ * @param arg Arbitrary argument specified in block device request
+ *            structure (in this case - pointer to the appropriate
+ *            block device request structure).
+ * @param status I/O completion status
+ * @param error errno error code if status != RTEMS_SUCCESSFUL
  */
 static void
@@ -1504,15 +1496,25 @@
 
 /**
- * Read a block into memory. If the block is not is the cache it is read into
- * memory. The caller is blocked until the block is read and placed into the
- * cache.
- *
- * @param device The device number (consists of major and minor device number)
- * @param block Linear media block number
- * @param bd Pointer to the buffer BD address.
- * @retval RTEMS_SUCCESSFUL Operation completed successfully.
- * @return rtems_status_code An error code. Buffer still passed to caller.
- */
-
+ * Get the block buffer and if not already in the cache read from the disk. If
+ * specified block already cached return. The buffer is set to the access or
+ * modifed access state. If the buffer is in the cache and modified the state
+ * is access modified else the state is access. If block is already being read
+ * from disk for being written to disk this call blocks. If the buffer is
+ * waiting to be written it is removed from modified queue and returned to the
+ * user. If the buffer is not in the cache a new buffer is obtained and the
+ * data read from disk. The call may block until these operations complete. A
+ * buffer obtained with this call will not be involved in a transfer request
+ * and will not be returned to another user until released. If the buffer is
+ * already with a user when this call is made the call is blocked until the
+ * buffer is returned. The highest priority waiter will obtain the buffer
+ * first. 
+ *
+ * @param device Device number (constructed of major and minor device number)
+ * @param block  Linear media block number
+ * @param bd     Reference to the buffer descriptor pointer.
+ *
+ * @return       RTEMS status code (RTEMS_SUCCESSFUL if operation completed
+ *               successfully or error code if error is occured)
+ */
 rtems_status_code
 rtems_bdbuf_read (dev_t                device,
@@ -1605,11 +1607,10 @@
 
     /*
-     * @todo The use of these req blocks is not a great design.
-     *       The req is a struct with a single 'bufs' declared in the
-     *       req struct and the others are added in the outer level
-     *       struct. This relies on the structs joining as a single
-     *       array and that assumes the compiler packs the structs.
-     *       Why not just place on a list ? The BD has a node that
-     *       can be used.
+     * @todo The use of these req blocks is not a great design. The req is a
+     *       struct with a single 'bufs' declared in the req struct and the
+     *       others are added in the outer level struct. This relies on the
+     *       structs joining as a single array and that assumes the compiler
+     *       packs the structs. Why not just place on a list ? The BD has a
+     *       node that can be used.
      */
     req->bufs[req->count].user   = bd;
@@ -1704,16 +1705,16 @@
 
 /**
- * Release buffer that has been in use. The buffer could have been in the
- * access state and so with a user of the cache or it was being transfered to
- * or from the disk media and so with a driver. Wake any waiters. If no one is
- * waiting and this is the only buffer on the LRU list see if anyone is
- * waiting. Wake them if they are.
- *
- * If the buffer has been modified use the modified release call.
- *
- * @param bd The buffer to return to the pool.
- * @retval RTEMS_SUCCESSFUL This operation always succeeds.
- */
-
+ * Release the buffer obtained by a read call back to the cache. If the buffer
+ * was obtained by a get call and was not already in the cache the release
+ * modified call should be used. A buffer released with this call obtained by a
+ * get call may not be in sync with the contents on disk. If the buffer was in
+ * the cache and modified before this call it will be returned to the modified
+ * queue. The buffers is returned to the end of the LRU list.
+ *
+ * @param bd Reference to the buffer descriptor.
+ *
+ * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed
+ *         successfully or error code if error is occured)
+ */
 rtems_status_code
 rtems_bdbuf_release (rtems_bdbuf_buffer* bd)
@@ -1739,7 +1740,7 @@
   {
     /*
-     * If this is a read ahead buffer place the ready queue. Buffers are
-     * taken from here first. If we prepend then get from the queue the
-     * buffers furthermost from the read buffer will be used.
+     * If this is a read ahead buffer place the ready queue. Buffers are taken
+     * from here first. If we prepend then get from the queue the buffers
+     * furthermost from the read buffer will be used.
      */
     if (bd->state == RTEMS_BDBUF_STATE_READ_AHEAD)
@@ -1778,16 +1779,18 @@
 
 /**
- * Release buffer that has been in use and has been modified. The buffer could
- * have been in the access state and so with a user of the cache or it was
- * being transfered to or from the disk media and so with a driver. Wake any
- * waiters. If no one is waiting and this is the only buffer on the LRU list
- * see if anyone is waiting. Wake them if they are.
- *
- * If the buffer has been modified use the modified release call.
- *
- * @param bd The buffer to return to the pool.
- * @retval RTEMS_SUCCESSFUL This operation always succeeds.
- */
-
+ * Release the buffer allocated with a get or read call placing it on the
+ * modidied list.  If the buffer was not released modified before the hold
+ * timer is set to the configuration value. If the buffer had been released
+ * modified before but not written to disk the hold timer is not updated. The
+ * buffer will be written to disk when the hold timer has expired, there are
+ * not more buffers available in the cache and a get or read buffer needs one
+ * or a sync call has been made. If the buffer is obtained with a get or read
+ * before the hold timer has expired the buffer will be returned to the user.
+ *
+ * @param bd Reference to the buffer descriptor.
+ *
+ * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed
+ *         successfully or error code if error is occured)
+ */
 rtems_status_code
 rtems_bdbuf_release_modified (rtems_bdbuf_buffer* bd)
@@ -1819,20 +1822,17 @@
 
 /**
- * Wait until specified buffer synchronized with disk. Invoked on exchanges
- * critical for data consistency on the media. The buffer is placed on the sync
- * list and the swapper is woken. No sync lock is taken as the buffers on the
- * sync list are taken first and passed to the driver before buffers on the
- * modified list.
+ * Release the buffer as modified and wait until it has been synchronized with
+ * the disk by writing it. This buffer will be the first to be transfer to disk
+ * and other buffers may also be written if the maximum number of blocks in a
+ * requests allows it.
  *
  * @note This code does not lock the sync mutex and stop additions to the
- *       modified queue. This means the buffer could be written and then
- *       returned to the modified list but will not happen as the buffer's
- *       state is sync.
- *
- * @param bd Pointer to the bdbuf_buffer structure previously obtained using
- *           get/read primitive.
- * @retval RTEMS_SUCCESSFUL Always returned.
- */
-
+ *       modified queue.
+ *
+ * @param bd Reference to the buffer descriptor.
+ *
+ * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed
+ *         successfully or error code if error is occured)
+ */
 rtems_status_code
 rtems_bdbuf_sync (rtems_bdbuf_buffer* bd)
@@ -1888,14 +1888,14 @@
 }
 
-/* rtems_bdbuf_syncdev --
- *     Synchronize with disk all buffers containing the blocks belonging to
- *     specified device.
- *
- * PARAMETERS:
- *     dev - block device number
- *
- * RETURNS:
- *     RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
- *     or error code if error is occured)
+/**
+ * Synchronize all modified buffers for this device with the disk and wait
+ * until the transfers have completed. The sync mutex for the pool is locked
+ * stopping the addition of any further modifed buffers. It is only the
+ * currently modified buffers that are written.
+ *
+ * @param dev Block device number
+ *
+ * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed
+ *         successfully or error code if error is occured)
  */
 rtems_status_code
@@ -1930,4 +1930,11 @@
   rtems_bdbuf_lock_pool (pool);  
 
+  /*
+   * Set the pool to have a sync active for a specific device and let the swap
+   * out task know the id of the requester to wake when done.
+   *
+   * The swap out task will negate the sync active flag when no more buffers
+   * for the device are held on the modified for sync queues.
+   */
   pool->sync_active    = TRUE;
   pool->sync_requester = rtems_task_self ();
@@ -1944,28 +1951,18 @@
     rtems_fatal_error_occurred (BLKDEV_FATAL_BDBUF_SWAPOUT_RE);
       
-  rtems_bdbuf_lock_pool (pool);
-
-  pool->sync_active = FALSE;
-
   rtems_bdbuf_unlock_sync (pool);
-  rtems_bdbuf_unlock_pool (pool);
   
   return rtems_disk_release(dd);
 }
 
-/* bdbuf_write_transfer_done --
- *     Callout function. Invoked by block device driver when data transfer
- *     to device (write) is completed. This function may be invoked from
- *     interrupt handler.
- *
- * PARAMETERS:
- *     arg    - arbitrary argument specified in block device request
- *              structure (in this case - pointer to the appropriate
- *              bdbuf_buffer buffer descriptor structure).
- *     status - I/O completion status
- *     error  - errno error code if status != RTEMS_SUCCESSFUL
- *
- * RETURNS:
- *     none
+/**
+ * Call back handler called by the low level driver when the transfer has
+ * completed. This function may be invoked from interrupt handler.
+ *
+ * @param arg Arbitrary argument specified in block device request
+ *            structure (in this case - pointer to the appropriate
+ *            block device request structure).
+ * @param status I/O completion status
+ * @param error errno error code if status != RTEMS_SUCCESSFUL
  */
 static void
@@ -1981,6 +1978,16 @@
 
 /**
- * Process the modified list of buffers. We can have a sync or modified
- * list that needs to be handled.
+ * Process the modified list of buffers. There us a sync or modified list that
+ * needs to be handled.
+ *
+ * @param pid The pool id to process modified buffers on.
+ * @param dev The device to handle. If -1 no device is selected so select the
+ *            device of the first buffer to be written to disk.
+ * @param chain The modified chain to process.
+ * @param transfer The chain to append buffers to be written too.
+ * @param sync_active If TRUE this is a sync operation so expire all timers.
+ * @param update_timers If TRUE update the timers.
+ * @param timer_delta It update_timers is TRUE update the timers by this
+ *                    amount.
  */
 static void
@@ -2005,9 +2012,9 @@
       {
         /*
-         * Check if the buffer's hold timer has reached 0. If a sync
-         * is active force all the timers to 0.
+         * Check if the buffer's hold timer has reached 0. If a sync is active
+         * force all the timers to 0.
          *
-         * @note Lots of sync requests will skew this timer. It should
-         *       be based on TOD to be accurate. Does it matter ?
+         * @note Lots of sync requests will skew this timer. It should be based
+         *       on TOD to be accurate. Does it matter ?
          */
         if (sync_active)
@@ -2033,6 +2040,6 @@
         /*
          * This assumes we can set dev_t to -1 which is just an
-         * assumption. Cannot use the transfer list being empty
-         * the sync dev calls sets the dev to use.
+         * assumption. Cannot use the transfer list being empty the sync dev
+         * calls sets the dev to use.
          */
         if (*dev == -1)
@@ -2057,5 +2064,19 @@
 
 /**
- * Process the pool.
+ * Process a pool's modified buffers. Check the sync list first then the
+ * modified list extracting the buffers suitable to be written to disk. We have
+ * a device at a time. The task level loop will repeat this operation while
+ * there are buffers to be written. If the transfer fails place the buffers
+ * back on the modified list and try again later. The pool is unlocked while
+ * the buffers are beign written to disk.
+ *
+ * @param pid The pool id to process modified buffers on.
+ * @param timer_delta It update_timers is TRUE update the timers by this
+ *                    amount.
+ * @param update_timers If TRUE update the timers.
+ * @param write_req The write request structure. There is only one.
+ *
+ * @retval TRUE Buffers where written to disk so scan again.
+ * @retval FALSE No buffers where written to disk.
  */
 static boolean
@@ -2069,5 +2090,5 @@
   dev_t               dev = -1;
   rtems_disk_device*  dd;
-  boolean             result = TRUE;
+  boolean             transfered_buffers = TRUE;
 
   rtems_chain_initialize_empty (&transfer);
@@ -2075,12 +2096,15 @@
   rtems_bdbuf_lock_pool (pool);
 
+  /*
+   * When the sync is for a device limit the sync to that device. If the sync
+   * is for a buffer handle the devices in the order on the sync list. This
+   * means the dev is -1.
+   */
   if (pool->sync_active)
     dev = pool->sync_device;
 
-#if 1
-  /*
-   * If we have any buffers in the sync queue move then to the
-   * modified list. The first sync buffer will select the
-   * device we use.
+  /*
+   * If we have any buffers in the sync queue move then to the modified
+   * list. The first sync buffer will select the device we use.
    */
   rtems_bdbuf_swapout_modified_processing (pid, &dev,
@@ -2102,5 +2126,5 @@
    * the pool can be unlocked because the state is set to TRANSFER.
    */
-#endif
+
   rtems_bdbuf_unlock_pool (pool);
 
@@ -2109,5 +2133,5 @@
    */
   if (rtems_chain_is_empty (&transfer))
-    result = FALSE;
+    transfered_buffers = FALSE;
   else
   {
@@ -2118,5 +2142,5 @@
     dd = rtems_disk_obtain (dev);
     if (dd == NULL)
-      result = FALSE;
+       transfered_buffers = FALSE;
     else
     {
@@ -2128,11 +2152,11 @@
       
       /*
-       * Take as many buffers are configured and pass to the driver. Note,
-       * the API to the drivers has the array of buffers and if a chain was
-       * passed we could have just passed the list. If the driver API is
-       * updated it should be possible to make this change with little effect
-       * in this code. The array that is passed is broken in design and
-       * should be removed. Merging to members of a struct into the first
-       * member is trouble waiting to happen.
+       * Take as many buffers as configured and pass to the driver. Note, the
+       * API to the drivers has the array of buffers and if a chain was passed
+       * we could have just passed the list. If the driver API is updated it
+       * should be possible to make this change with little effect in this
+       * code. The array that is passed is broken in design and should be
+       * removed. Merging to members of a struct into the first member is
+       * trouble waiting to happen.
        */
 
@@ -2151,9 +2175,8 @@
         
         /*
-         * If the device only accepts sequential buffers and
-         * this is not the first buffer (the first is always
-         * sequential, and the buffer is not sequential then
-         * put the buffer back on the transfer chain and
-         * write the committed buffers.
+         * If the device only accepts sequential buffers and this is not the
+         * first buffer (the first is always sequential, and the buffer is not
+         * sequential then put the buffer back on the transfer chain and write
+         * the committed buffers.
          */
         
@@ -2177,6 +2200,6 @@
 
         /*
-         * Perform the transfer if there are no more buffers, or the
-         * transfer size has reached the configured max. value.
+         * Perform the transfer if there are no more buffers, or the transfer
+         * size has reached the configured max. value.
          */
 
@@ -2191,6 +2214,6 @@
 
           /*
-           * Perform the transfer. No pool locks, no preemption, only the
-           * disk device is being held.
+           * Perform the transfer. No pool locks, no preemption, only the disk
+           * device is being held.
            */
           result = dd->ioctl (dd->phys_dev->dev,
@@ -2210,6 +2233,6 @@
                * Place back on the pools modified queue and try again.
                *
-               * @warning Not sure this is the best option but I do
-               *          not know what else can be done.
+               * @warning Not sure this is the best option but I do not know
+               *          what else can be done.
                */
               rtems_chain_append (&pool->modified, &bd->link);
@@ -2261,12 +2284,20 @@
   }
 
-  if (pool->sync_active)
-    rtems_event_send (pool->sync_requester, RTEMS_BDBUF_TRANSFER_SYNC);
-  
-  return result;
-}
-
-/**
- * Body of task which take care on flushing modified buffers to the disk.
+  if (pool->sync_active && !  transfered_buffers)
+  {
+    rtems_id sync_requester = pool->sync_requester;
+    pool->sync_active = FALSE;
+    pool->sync_requester = 0;
+    if (sync_requester)
+      rtems_event_send (sync_requester, RTEMS_BDBUF_TRANSFER_SYNC);
+  }
+  
+  return  transfered_buffers;
+}
+
+/**
+ * Body of task which takes care on flushing modified buffers to the disk.
+ *
+ * @param arg The task argument which is the context.
  */
 static rtems_task
@@ -2302,5 +2333,5 @@
 
   /*
-   * This is temporary. Needs to be changed to use the real clock.
+   * This is temporary. Needs to be changed to use the real time clock.
    */
   timer_delta = period_in_msecs;
@@ -2316,7 +2347,7 @@
     
     /*
-     * If we write buffers to any disk perform a check again. We only
-     * write a single device at a time and a pool may have more than
-     * one devices buffers modified waiting to be written.
+     * If we write buffers to any disk perform a check again. We only write a
+     * single device at a time and a pool may have more than one devices
+     * buffers modified waiting to be written.
      */
     boolean transfered_buffers;
@@ -2370,13 +2401,13 @@
  * size.
  *
- * PARAMETERS:
- *     block_size - requested block size
- *     pool       - placeholder for result
- *
- * RETURNS:
- *     RTEMS status code: RTEMS_SUCCESSFUL if operation completed successfully,
- *     RTEMS_INVALID_SIZE if specified block size is invalid (not a power
- *     of 2), RTEMS_NOT_DEFINED if buffer pool for this or greater block size
- *     is not configured.
+ * @param block_size Requested block size
+ * @param pool The pool to use for the requested pool size.
+ *
+ * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed
+ *         successfully or error code if error is occured)
+ * @retval RTEMS_INVALID_SIZE The specified block size is invalid (not a power
+ *         of 2)
+ * @retval RTEMS_NOT_DEFINED The buffer pool for this or greater block size
+ *         is not configured.
  */
 rtems_status_code
@@ -2421,19 +2452,18 @@
  * Obtain characteristics of buffer pool with specified number.
  *
- * PARAMETERS:
- *     pool       - buffer pool number
- *     block_size - block size for which buffer pool is configured returned
- *                  there
- *     blocks     - number of buffers in buffer pool returned there
+ * @param pool Buffer pool number
+ * @param block_size Block size for which buffer pool is configured returned
+ *                   there
+ * @param blocks Number of buffers in buffer pool.
  *
  * RETURNS:
- *     RTEMS status code: RTEMS_SUCCESSFUL if operation completed successfully,
- *     RTEMS_INVALID_NUMBER if appropriate buffer pool is not configured.
- *
- * NOTE:
- *     Buffer pools enumerated contiguously starting from 0.
+ * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed
+ *         successfully or error code if error is occured)
+ * @retval RTEMS_INVALID_SIZE The appropriate buffer pool is not configured.
+ *
+ * @note Buffer pools enumerated continuously starting from 0.
  */
 rtems_status_code
-rtems_bdbuf_get_pool_info(rtems_bdpool_id pool, int* block_size, int* blocks)
+rtems_bdbuf_get_pool_info (rtems_bdpool_id pool, int* block_size, int* blocks)
 {
   if (pool >= rtems_bdbuf_ctx.npools)
