Changeset 3899a537 in rtems for cpukit/libblock/src/bdbuf.c


Ignore:
Timestamp:
Jul 29, 2008, 2:21:15 AM (12 years ago)
Author:
Chris Johns <chrisj@…>
Branches:
4.10, 4.11, 4.9, 5, master
Children:
c4bd98c
Parents:
1b39f18
Message:

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

  • libblock/Makefile.am: Removed src/show_bdbuf.c.
  • libblock/src/show_bdbuf.c: Removed.
  • libblock/include/rtems/bdbuf.h, cpukit/libblock/src/bdbuf.c: Rewritten the bdbuf code. Remove pre-emption disable, score access, fixed many bugs and increased performance.
  • libblock/include/rtems/blkdev.h: Added RTEMS_BLKDEV_CAPABILITIES block device request. Cleaned up comments. Added block and user fields to the sg buffer request. Move to rtems_* namespace.
  • libblock/include/rtems/diskdevs.h, cpukit/libblock/src/diskdevs.c: Move to rtems_* namespace. Add a capabilities field for drivers. Change rtems_disk_lookup to rtems_disk_obtain to match the release call. You do not lookup and release a disk, you obtain and release a disk.
  • libblock/include/rtems/ide_part_table.h, libblock/include/rtems/ramdisk.h, libblock/src/ide_part_table.c: Move to rtems_* namespace.
  • libblock/include/rtems/nvdisk.h: Formatting change.
  • libblock/src/blkdev.c: Move to rtems_* namespace. Change rtems_disk_lookup to rtems_disk_obtain
  • libblock/src/flashdisk.c: Move to rtems_* namespace. Use the new support for the block number in the scatter/grather request struct. This allows non-continuous buffer requests for those drivers that can support increasing performance.
  • libblock/src/nvdisk.c: Move to rtems_* namespace. Removed warnings. Added better error checking. Fixed some comments.
  • libblock/src/ramdisk.c: Move to rtems_* namespace. Added some trace functions to help debugging upper layers. Use the new support for the block number in the scatter/grather request struct. This allows non-continuous buffer requests for those drivers that can support increasing performance.
  • libfs/src/dosfs/fat.c, libfs/src/dosfs/fat.h: Use new chains API. Removed temporary hack and changed set_errno_and_return_minus_one to rtems_set_errno_and_return_minus_one. Move fat_buf_access from header and stopped it being inlined. Updated to libblock changes.
  • libfs/src/dosfs/fat_fat_operations.c, libfs/src/dosfs/fat_file.c, libfs/src/dosfs/msdos_create.c, libfs/src/dosfs/msdos_dir.c, libfs/src/dosfs/msdos_eval.c, libfs/src/dosfs/msdos_file.c, libfs/src/dosfs/msdos_format.c, libfs/src/dosfs/msdos_free.c, libfs/src/dosfs/msdos_initsupp.c, libfs/src/dosfs/msdos_misc.c, libfs/src/dosfs/msdos_mknod.c: Use new chains API. Removed temporary hack and changed set_errno_and_return_minus_one to rtems_set_errno_and_return_minus_one. Updated to libblock changes.
  • libmisc/Makefile.am: Add new ls and rm command files.
  • libmisc/shell/cmp-ls.c, libmisc/shell/extern-ls.h, libmisc/shell/filemode.c, libmisc/shell/print-ls.c, libmisc/shell/pwcache.c, libmisc/shell/utils-ls.c, libmisc/shell/vis.c, shell/vis.h: New.
  • libmisc/shell/extern-cp.h, libmisc/shell/main_cp.c, libmisc/shell/utils-cp.c: Fixed the usage call bug.
  • libmisc/shell/main_blksync.c: Updated to the new block IO ioctl command.
  • libmisc/shell/main_ls.c, libmisc/shell/main_rm.c: Updated to BSD commands with more features.
  • score/src/coremutex.c: Fix the strick order mutex code.
  • libmisc/shell/shell.c: Change shell tasks mode to be timeslice and no ASR.
  • sapi/include/confdefs.h: Change ata_driver_task_priority to rtems_ata_driver_task_priority. Add the new BD buf cache parameters with defaults.
  • score/src/interr.c: Do not return if the CPU halt call returns.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • cpukit/libblock/src/bdbuf.c

    r1b39f18 r3899a537  
    1111 */
    1212
     13/**
     14 * @file
     15 *
     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.
     19 *
     20 * The buffers are held in pools based on size. Each pool has buffers and the
     21 * buffers follow this state machine:
     22 *
     23 *                        read
     24 *          +-------------------------------+
     25 *          |                               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 *          +--------|           |<-------------------------+
     44 *                   +-----------+
     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.
     56 *
     57 * The pool have the following lists of buffers:
     58 *
     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 *
     64 */
     65
     66/**
     67 * Set to 1 to enable debug tracing.
     68 */
     69#define RTEMS_BDBUF_TRACE 0
     70
    1371#if HAVE_CONFIG_H
    1472#include "config.h"
    1573#endif
    1674
    17 #define __RTEMS_VIOLATE_KERNEL_VISIBILITY__
    1875#include <rtems.h>
     76#include <rtems/error.h>
    1977#include <limits.h>
    2078#include <errno.h>
    2179#include <assert.h>
    2280
     81#if RTEMS_BDBUF_TRACE
     82#include <stdio.h>
     83#endif
     84
    2385#include "rtems/bdbuf.h"
    2486
    25 /* Fatal errors: */
    26 #define BLKDEV_FATAL_ERROR(n) (((uint32_t)'B' << 24) | ((uint32_t)(n) & (uint32_t)0x00FFFFFF))
    27 #define BLKDEV_FATAL_BDBUF_CONSISTENCY BLKDEV_FATAL_ERROR(1)
    28 #define BLKDEV_FATAL_BDBUF_SWAPOUT     BLKDEV_FATAL_ERROR(2)
    29 
    30 
    31 #define SWAPOUT_TASK_STACK_SIZE (RTEMS_MINIMUM_STACK_SIZE * 2)
    32 
    33 #define READ_MULTIPLE
    34 
    35 #if defined(READ_MULTIPLE)
    36 #define READ_AHEAD_MAX_BLK_CNT 32
    37 typedef struct {
    38   blkdev_request   req;
    39   blkdev_sg_buffer sg[READ_AHEAD_MAX_BLK_CNT];
    40 } blkdev_request_read_ahead;
     87/**
     88 * The BD buffer context.
     89 */
     90/* Buffering layer context definition */
     91typedef 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 */
     95  boolean           swapout_enabled;
     96} rtems_bdbuf_context;
     97
     98/**
     99 * Fatal errors
     100 */
     101#define RTEMS_BLKDEV_FATAL_ERROR(n) (((uint32_t)'B' << 24) |         \
     102                                     ((uint32_t)(n) & (uint32_t)0x00FFFFFF))
     103
     104#define RTEMS_BLKDEV_FATAL_BDBUF_CONSISTENCY RTEMS_BLKDEV_FATAL_ERROR(1)
     105#define RTEMS_BLKDEV_FATAL_BDBUF_SWAPOUT     RTEMS_BLKDEV_FATAL_ERROR(2)
     106#define RTEMS_BLKDEV_FATAL_BDBUF_SYNC_LOCK   RTEMS_BLKDEV_FATAL_ERROR(3)
     107#define RTEMS_BLKDEV_FATAL_BDBUF_SYNC_UNLOCK RTEMS_BLKDEV_FATAL_ERROR(4)
     108#define RTEMS_BLKDEV_FATAL_BDBUF_POOL_LOCK   RTEMS_BLKDEV_FATAL_ERROR(5)
     109#define RTEMS_BLKDEV_FATAL_BDBUF_POOL_UNLOCK RTEMS_BLKDEV_FATAL_ERROR(6)
     110#define RTEMS_BLKDEV_FATAL_BDBUF_POOL_WAIT   RTEMS_BLKDEV_FATAL_ERROR(7)
     111#define RTEMS_BLKDEV_FATAL_BDBUF_POOL_WAKE   RTEMS_BLKDEV_FATAL_ERROR(8)
     112#define RTEMS_BLKDEV_FATAL_BDBUF_SO_WAKE     RTEMS_BLKDEV_FATAL_ERROR(9)
     113#define RTEMS_BLKDEV_FATAL_BDBUF_SO_NOMEM    RTEMS_BLKDEV_FATAL_ERROR(10)
     114#define BLKDEV_FATAL_BDBUF_SWAPOUT_RE        RTEMS_BLKDEV_FATAL_ERROR(11)
     115#define BLKDEV_FATAL_BDBUF_SWAPOUT_TS        RTEMS_BLKDEV_FATAL_ERROR(12)
     116
     117#define RTEMS_BDBUF_TRANSFER_SYNC  RTEMS_EVENT_1
     118#define RTEMS_BDBUF_SWAPOUT_SYNC   RTEMS_EVENT_2
     119
     120#define SWAPOUT_TASK_STACK_SIZE (8 * 1024)
     121
     122/**
     123 * Lock semaphore attributes. This is used for locking type mutexes.
     124 */
     125#define RTEMS_BDBUF_POOL_LOCK_ATTRIBS \
     126  (RTEMS_PRIORITY | RTEMS_BINARY_SEMAPHORE | \
     127   RTEMS_INHERIT_PRIORITY | RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL)
     128
     129/**
     130 * Waiter semaphore attributes.
     131 *
     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.
     136 */
     137#define RTEMS_BDBUF_POOL_WAITER_ATTRIBS \
     138  (RTEMS_PRIORITY | RTEMS_BINARY_SEMAPHORE | \
     139   RTEMS_NO_INHERIT_PRIORITY | RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL)
     140
    41141/*
    42  * list of bd_bufs related to one transfer request
    43  */
    44 typedef struct {
    45   int cnt;
    46   bdbuf_buffer *bd_bufs[READ_AHEAD_MAX_BLK_CNT];
    47 } read_ahead_bd_buf_group;
     142 * The swap out task.
     143 */
     144static rtems_task rtems_bdbuf_swapout_task(rtems_task_argument arg);
     145
     146/**
     147 * The context of buffering layer.
     148 */
     149static rtems_bdbuf_context rtems_bdbuf_ctx;
     150
     151/**
     152 * Print a message to the bdbuf trace output and flush it.
     153 *
     154 * @param format The format string. See printf for details.
     155 * @param ... The arguments for the format text.
     156 * @return int The number of bytes written to the output.
     157 */
     158#if RTEMS_BDBUF_TRACE
     159boolean rtems_bdbuf_tracer;
     160static void
     161rtems_bdbuf_printf (const char *format, ...)
     162{
     163  va_list args;
     164  va_start (args, format);
     165  if (rtems_bdbuf_tracer)
     166  {
     167    fprintf (stdout, "bdbuf:");
     168    vfprintf (stdout, format, args);
     169    fflush (stdout);
     170  }
     171}
    48172#endif
    49173
    50 typedef struct {
    51   blkdev_request *req;
    52   bdbuf_buffer   **write_store;
    53 } write_tfer_done_arg_t;
    54 
    55 static rtems_task bdbuf_swapout_task(rtems_task_argument unused);
    56 
    57 static rtems_status_code bdbuf_release(bdbuf_buffer *bd_buf);
    58 /*
    59  * maximum number of blocks that might be chained together to one
    60  * write driver call
    61  */
    62 #define SWAP_OUT_MAX_BLK_CNT 32
    63 /*#define SWAP_OUT_MAX_BLK_CNT 1 */
    64 /*
    65  * XXX: this is a global buffer. It is used in the swapout task
    66  * and currently will be reused only after it is no longer in use
    67  *
    68  */
    69 static bdbuf_buffer *bd_buf_write_store[SWAP_OUT_MAX_BLK_CNT];
    70 
    71 /* Block device request with a single buffer provided */
    72 typedef struct blkdev_request1 {
    73     blkdev_request   req;
    74     blkdev_sg_buffer sg[1];
    75 } blkdev_request1;
    76 
    77 /* The context of buffering layer */
    78 struct bdbuf_context rtems_bdbuf_ctx;
    79 
    80 #define SAFE
    81 #ifdef SAFE
    82 typedef rtems_mode preemption_key;
    83 
    84 #define DISABLE_PREEMPTION(key) \
    85     do {                                                               \
    86         rtems_task_mode(RTEMS_NO_PREEMPT, RTEMS_PREEMPT_MASK, &(key)); \
    87     } while (0)
    88 
    89 #define ENABLE_PREEMPTION(key) \
    90     do {                                                        \
    91         rtems_mode temp;                                        \
    92         rtems_task_mode((key), RTEMS_PREEMPT_MASK, &temp);      \
    93     } while (0)
    94 
    95 #else
    96 
    97 typedef boolean preemption_key;
    98 
    99 #define DISABLE_PREEMPTION(key) \
    100     do {                                             \
    101         (key) = _Thread_Executing->is_preemptible;   \
    102         _Thread_Executing->is_preemptible = 0;       \
    103     } while (0)
    104 
    105 #define ENABLE_PREEMPTION(key) \
    106     do {                                             \
    107         _Thread_Executing->is_preemptible = (key);   \
    108         if (_Thread_Evaluate_mode())                 \
    109             _Thread_Dispatch();                      \
    110     } while (0)
    111 
     174/**
     175 * The default maximum height of 32 allows for AVL trees having between
     176 * 5,704,880 and 4,294,967,295 nodes, depending on order of insertion.  You may
     177 * change this compile-time constant as you wish.
     178 */
     179#ifndef RTEMS_BDBUF_AVL_MAX_HEIGHT
     180#define RTEMS_BDBUF_AVL_MAX_HEIGHT (32)
    112181#endif
    113182
    114 
    115 /* The default maximum height of 32 allows for AVL trees having
    116    between 5,704,880 and 4,294,967,295 nodes, depending on order of
    117    insertion.  You may change this compile-time constant as you
    118    wish. */
    119 #ifndef AVL_MAX_HEIGHT
    120 #define AVL_MAX_HEIGHT  32
     183/**
     184 * Searches for the node with specified dev/block.
     185 *
     186 * @param root pointer to the root node of the AVL-Tree
     187 * @param dev device search key
     188 * @param block block search key
     189 * @retval NULL node with the specified dev/block is not found
     190 * @return pointer to the node with specified dev/block
     191 */
     192static rtems_bdbuf_buffer *
     193rtems_bdbuf_avl_search (rtems_bdbuf_buffer** root,
     194                        dev_t                dev,
     195                        rtems_blkdev_bnum    block)
     196{
     197  rtems_bdbuf_buffer* p = *root;
     198
     199  while ((p != NULL) && ((p->dev != dev) || (p->block != block)))
     200  {
     201    if ((p->dev < dev) || ((p->dev == dev) && (p->block < block)))
     202    {
     203      p = p->avl.right;
     204    }
     205    else
     206    {
     207      p = p->avl.left;
     208    }
     209  }
     210
     211  return p;
     212}
     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 */
     224static rtems_bdbuf_buffer *
     225rtems_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}
    121266#endif
    122267
    123 /*
    124  * avl_search --
    125  *     Searches for the node with specified dev/block.
     268/**
     269 * Inserts the specified node to the AVl-Tree.
     270 *
     271 * @param root pointer to the root node of the AVL-Tree
     272 * @param node Pointer to the node to add.
     273 * @retval 0 The node added successfully
     274 * @retval -1 An error occured
     275 */
     276static int
     277rtems_bdbuf_avl_insert(rtems_bdbuf_buffer** root,
     278                       rtems_bdbuf_buffer*  node)
     279{
     280  dev_t             dev = node->dev;
     281  rtems_blkdev_bnum block = node->block;
     282
     283  rtems_bdbuf_buffer*  p = *root;
     284  rtems_bdbuf_buffer*  q;
     285  rtems_bdbuf_buffer*  p1;
     286  rtems_bdbuf_buffer*  p2;
     287  rtems_bdbuf_buffer*  buf_stack[RTEMS_BDBUF_AVL_MAX_HEIGHT];
     288  rtems_bdbuf_buffer** buf_prev = buf_stack;
     289
     290  boolean modified = FALSE;
     291
     292  if (p == NULL)
     293  {
     294    *root = node;
     295    node->avl.left = NULL;
     296    node->avl.right = NULL;
     297    node->avl.bal = 0;
     298    return 0;
     299  }
     300
     301  while (p != NULL)
     302  {
     303    *buf_prev++ = p;
     304
     305    if ((p->dev < dev) || ((p->dev == dev) && (p->block < block)))
     306    {
     307      p->avl.cache = 1;
     308      q = p->avl.right;
     309      if (q == NULL)
     310      {
     311        q = node;
     312        p->avl.right = q = node;
     313        break;
     314      }
     315    }
     316    else if ((p->dev != dev) || (p->block != block))
     317    {
     318      p->avl.cache = -1;
     319      q = p->avl.left;
     320      if (q == NULL)
     321      {
     322        q = node;
     323        p->avl.left = q;
     324        break;
     325      }
     326    }
     327    else
     328    {
     329      return -1;
     330    }
     331
     332    p = q;
     333  }
     334
     335  q->avl.left = q->avl.right = NULL;
     336  q->avl.bal = 0;
     337  modified = TRUE;
     338  buf_prev--;
     339
     340  while (modified)
     341  {
     342    if (p->avl.cache == -1)
     343    {
     344      switch (p->avl.bal)
     345      {
     346        case 1:
     347          p->avl.bal = 0;
     348          modified = FALSE;
     349          break;
     350
     351        case 0:
     352          p->avl.bal = -1;
     353          break;
     354
     355        case -1:
     356          p1 = p->avl.left;
     357          if (p1->avl.bal == -1) /* simple LL-turn */
     358          {
     359            p->avl.left = p1->avl.right;
     360            p1->avl.right = p;
     361            p->avl.bal = 0;
     362            p = p1;
     363          }
     364          else /* double LR-turn */
     365          {
     366            p2 = p1->avl.right;
     367            p1->avl.right = p2->avl.left;
     368            p2->avl.left = p1;
     369            p->avl.left = p2->avl.right;
     370            p2->avl.right = p;
     371            if (p2->avl.bal == -1) p->avl.bal = +1; else p->avl.bal = 0;
     372            if (p2->avl.bal == +1) p1->avl.bal = -1; else p1->avl.bal = 0;
     373            p = p2;
     374          }
     375          p->avl.bal = 0;
     376          modified = FALSE;
     377          break;
     378
     379        default:
     380          break;
     381      }
     382    }
     383    else
     384    {
     385      switch (p->avl.bal)
     386      {
     387        case -1:
     388          p->avl.bal = 0;
     389          modified = FALSE;
     390          break;
     391
     392        case 0:
     393          p->avl.bal = 1;
     394          break;
     395
     396        case 1:
     397          p1 = p->avl.right;
     398          if (p1->avl.bal == 1) /* simple RR-turn */
     399          {
     400            p->avl.right = p1->avl.left;
     401            p1->avl.left = p;
     402            p->avl.bal = 0;
     403            p = p1;
     404          }
     405          else /* double RL-turn */
     406          {
     407            p2 = p1->avl.left;
     408            p1->avl.left = p2->avl.right;
     409            p2->avl.right = p1;
     410            p->avl.right = p2->avl.left;
     411            p2->avl.left = p;
     412            if (p2->avl.bal == +1) p->avl.bal = -1; else p->avl.bal = 0;
     413            if (p2->avl.bal == -1) p1->avl.bal = +1; else p1->avl.bal = 0;
     414            p = p2;
     415          }
     416          p->avl.bal = 0;
     417          modified = FALSE;
     418          break;
     419
     420        default:
     421          break;
     422      }
     423    }
     424    q = p;
     425    if (buf_prev > buf_stack)
     426    {
     427      p = *--buf_prev;
     428
     429      if (p->avl.cache == -1)
     430      {
     431        p->avl.left = q;
     432      }
     433      else
     434      {
     435        p->avl.right = q;
     436      }
     437    }
     438    else
     439    {
     440      *root = p;
     441      break;
     442    }
     443  };
     444
     445  return 0;
     446}
     447
     448
     449/**
     450 * Removes the node from the tree.
     451 *
     452 * @param root_addr Pointer to pointer to the root node
     453 * @param node Pointer to the node to remove
     454 * @retval 0 Item removed
     455 * @retval -1 No such item found
     456 */
     457static int
     458rtems_bdbuf_avl_remove(rtems_bdbuf_buffer**      root,
     459                       const rtems_bdbuf_buffer* node)
     460{
     461  dev_t             dev = node->dev;
     462  rtems_blkdev_bnum block = node->block;
     463
     464  rtems_bdbuf_buffer*  p = *root;
     465  rtems_bdbuf_buffer*  q;
     466  rtems_bdbuf_buffer*  r;
     467  rtems_bdbuf_buffer*  s;
     468  rtems_bdbuf_buffer*  p1;
     469  rtems_bdbuf_buffer*  p2;
     470  rtems_bdbuf_buffer*  buf_stack[RTEMS_BDBUF_AVL_MAX_HEIGHT];
     471  rtems_bdbuf_buffer** buf_prev = buf_stack;
     472
     473  boolean modified = FALSE;
     474
     475  memset (buf_stack, 0, sizeof(buf_stack));
     476
     477  while (p != NULL)
     478  {
     479    *buf_prev++ = p;
     480
     481    if ((p->dev < dev) || ((p->dev == dev) && (p->block < block)))
     482    {
     483      p->avl.cache = 1;
     484      p = p->avl.right;
     485    }
     486    else if ((p->dev != dev) || (p->block != block))
     487    {
     488      p->avl.cache = -1;
     489      p = p->avl.left;
     490    }
     491    else
     492    {
     493      /* node found */
     494      break;
     495    }
     496  }
     497
     498  if (p == NULL)
     499  {
     500    /* there is no such node */
     501    return -1;
     502  }
     503
     504  q = p;
     505
     506  buf_prev--;
     507  if (buf_prev > buf_stack)
     508  {
     509    p = *(buf_prev - 1);
     510  }
     511  else
     512  {
     513    p = NULL;
     514  }
     515
     516  /* at this moment q - is a node to delete, p is q's parent */
     517  if (q->avl.right == NULL)
     518  {
     519    r = q->avl.left;
     520    if (r != NULL)
     521    {
     522      r->avl.bal = 0;
     523    }
     524    q = r;
     525  }
     526  else
     527  {
     528    rtems_bdbuf_buffer **t;
     529
     530    r = q->avl.right;
     531
     532    if (r->avl.left == NULL)
     533    {
     534      r->avl.left = q->avl.left;
     535      r->avl.bal = q->avl.bal;
     536      r->avl.cache = 1;
     537      *buf_prev++ = q = r;
     538    }
     539    else
     540    {
     541      t = buf_prev++;
     542      s = r;
     543
     544      while (s->avl.left != NULL)
     545      {
     546        *buf_prev++ = r = s;
     547        s = r->avl.left;
     548        r->avl.cache = -1;
     549      }
     550
     551      s->avl.left = q->avl.left;
     552      r->avl.left = s->avl.right;
     553      s->avl.right = q->avl.right;
     554      s->avl.bal = q->avl.bal;
     555      s->avl.cache = 1;
     556
     557      *t = q = s;
     558    }
     559  }
     560
     561  if (p != NULL)
     562  {
     563    if (p->avl.cache == -1)
     564    {
     565      p->avl.left = q;
     566    }
     567    else
     568    {
     569      p->avl.right = q;
     570    }
     571  }
     572  else
     573  {
     574    *root = q;
     575  }
     576
     577  modified = TRUE;
     578
     579  while (modified)
     580  {
     581    if (buf_prev > buf_stack)
     582    {
     583      p = *--buf_prev;
     584    }
     585    else
     586    {
     587      break;
     588    }
     589
     590    if (p->avl.cache == -1)
     591    {
     592      /* rebalance left branch */
     593      switch (p->avl.bal)
     594      {
     595        case -1:
     596          p->avl.bal = 0;
     597          break;
     598        case  0:
     599          p->avl.bal = 1;
     600          modified = FALSE;
     601          break;
     602
     603        case +1:
     604          p1 = p->avl.right;
     605
     606          if (p1->avl.bal >= 0) /* simple RR-turn */
     607          {
     608            p->avl.right = p1->avl.left;
     609            p1->avl.left = p;
     610
     611            if (p1->avl.bal == 0)
     612            {
     613              p1->avl.bal = -1;
     614              modified = FALSE;
     615            }
     616            else
     617            {
     618              p->avl.bal = 0;
     619              p1->avl.bal = 0;
     620            }
     621            p = p1;
     622          }
     623          else /* double RL-turn */
     624          {
     625            p2 = p1->avl.left;
     626
     627            p1->avl.left = p2->avl.right;
     628            p2->avl.right = p1;
     629            p->avl.right = p2->avl.left;
     630            p2->avl.left = p;
     631
     632            if (p2->avl.bal == +1) p->avl.bal = -1; else p->avl.bal = 0;
     633            if (p2->avl.bal == -1) p1->avl.bal = 1; else p1->avl.bal = 0;
     634
     635            p = p2;
     636            p2->avl.bal = 0;
     637          }
     638          break;
     639
     640        default:
     641          break;
     642      }
     643    }
     644    else
     645    {
     646      /* rebalance right branch */
     647      switch (p->avl.bal)
     648      {
     649        case +1:
     650          p->avl.bal = 0;
     651          break;
     652
     653        case  0:
     654          p->avl.bal = -1;
     655          modified = FALSE;
     656          break;
     657
     658        case -1:
     659          p1 = p->avl.left;
     660
     661          if (p1->avl.bal <= 0) /* simple LL-turn */
     662          {
     663            p->avl.left = p1->avl.right;
     664            p1->avl.right = p;
     665            if (p1->avl.bal == 0)
     666            {
     667              p1->avl.bal = 1;
     668              modified = FALSE;
     669            }
     670            else
     671            {
     672              p->avl.bal = 0;
     673              p1->avl.bal = 0;
     674            }
     675            p = p1;
     676          }
     677          else /* double LR-turn */
     678          {
     679            p2 = p1->avl.right;
     680
     681            p1->avl.right = p2->avl.left;
     682            p2->avl.left = p1;
     683            p->avl.left = p2->avl.right;
     684            p2->avl.right = p;
     685
     686            if (p2->avl.bal == -1) p->avl.bal = 1; else p->avl.bal = 0;
     687            if (p2->avl.bal == +1) p1->avl.bal = -1; else p1->avl.bal = 0;
     688
     689            p = p2;
     690            p2->avl.bal = 0;
     691          }
     692          break;
     693
     694        default:
     695          break;
     696      }
     697    }
     698
     699    if (buf_prev > buf_stack)
     700    {
     701      q = *(buf_prev - 1);
     702
     703      if (q->avl.cache == -1)
     704      {
     705        q->avl.left = p;
     706      }
     707      else
     708      {
     709        q->avl.right = p;
     710      }
     711    }
     712    else
     713    {
     714      *root = p;
     715      break;
     716    }
     717
     718  }
     719
     720  return 0;
     721}
     722
     723/**
     724 * Get the pool for the device.
     725 *
     726 * @param pdd Physical disk device.
     727 */
     728static rtems_bdbuf_pool*
     729rtems_bdbuf_get_pool (const rtems_bdpool_id pid)
     730{
     731  return &rtems_bdbuf_ctx.pool[pid];
     732}
     733
     734/**
     735 * Lock the pool. A single task can nest calls.
     736 *
     737 * @param pool The pool to lock.
     738 */
     739static void
     740rtems_bdbuf_lock_pool (rtems_bdbuf_pool* pool)
     741{
     742  rtems_status_code sc = rtems_semaphore_obtain (pool->lock,
     743                                                 RTEMS_WAIT,
     744                                                 RTEMS_NO_TIMEOUT);
     745  if (sc != RTEMS_SUCCESSFUL)
     746    rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_POOL_LOCK);
     747}
     748
     749/**
     750 * Unlock the pool.
     751 *
     752 * @param pool The pool to unlock.
     753 */
     754static void
     755rtems_bdbuf_unlock_pool (rtems_bdbuf_pool* pool)
     756{
     757  rtems_status_code sc = rtems_semaphore_release (pool->lock);
     758  if (sc != RTEMS_SUCCESSFUL)
     759    rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_POOL_UNLOCK);
     760}
     761
     762/**
     763 * Lock the pool's sync. A single task can nest calls.
     764 *
     765 * @param pool The pool's sync to lock.
     766 */
     767static void
     768rtems_bdbuf_lock_sync (rtems_bdbuf_pool* pool)
     769{
     770  rtems_status_code sc = rtems_semaphore_obtain (pool->sync_lock,
     771                                                 RTEMS_WAIT,
     772                                                 RTEMS_NO_TIMEOUT);
     773  if (sc != RTEMS_SUCCESSFUL)
     774    rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_SYNC_LOCK);
     775}
     776
     777/**
     778 * Unlock the pool's sync.
     779 *
     780 * @param pool The pool's sync to unlock.
     781 */
     782static void
     783rtems_bdbuf_unlock_sync (rtems_bdbuf_pool* pool)
     784{
     785  rtems_status_code sc = rtems_semaphore_release (pool->sync_lock);
     786  if (sc != RTEMS_SUCCESSFUL)
     787    rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_SYNC_UNLOCK);
     788}
     789
     790/**
     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.
     795 *
     796 * While we have the pool locked we can try and claim the semaphore and
     797 * therefore know when we release the lock to the pool we will block until the
     798 * semaphore is released. This may even happen before we get to block.
     799 *
     800 * A counter is used to save the release call when no one is waiting.
     801 *
     802 * The function assumes the pool is locked on entry and it will have locked
     803 * the pool on exit.
     804 *
     805 * @param pool The pool to wait for a buffer to return.
     806 * @param sema The semaphore to block on and wait.
     807 * @param waiters The wait counter for this semaphore.
     808 */
     809static void
     810rtems_bdbuf_wait (rtems_bdbuf_pool* pool, rtems_id* sema,
     811                  volatile uint32_t* waiters)
     812{
     813  rtems_status_code sc;
     814  rtems_mode        prev_mode;
     815 
     816  /*
     817   * Indicate we are waiting.
     818   */
     819  *waiters += 1;
     820
     821  /*
     822   * Disable preemption then unlock the pool and block.
     823   * There is no POSIX condition variable in the core API so
     824   * this is a work around.
     825   *
     826   * The issue is a task could preempt after the pool is unlocked
     827   * because it is blocking or just hits that window, and before
     828   * this task has blocked on the semaphore. If the preempting task
     829   * flushes the queue this task will not see the flush and may
     830   * block for ever or until another transaction flushes this
     831   * semaphore.
     832   */
     833  sc = rtems_task_mode (RTEMS_NO_PREEMPT, RTEMS_PREEMPT_MASK, &prev_mode);
     834
     835  if (sc != RTEMS_SUCCESSFUL)
     836    rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_POOL_WAIT);
     837 
     838  /*
     839   * Unlock the pool, wait, and lock the pool when we return.
     840   */
     841  rtems_bdbuf_unlock_pool (pool);
     842
     843  sc = rtems_semaphore_obtain (*sema, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
     844 
     845  if (sc != RTEMS_UNSATISFIED)
     846    rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_POOL_WAIT);
     847 
     848  rtems_bdbuf_lock_pool (pool);
     849
     850  sc = rtems_task_mode (prev_mode, RTEMS_ALL_MODE_MASKS, &prev_mode);
     851
     852  if (sc != RTEMS_SUCCESSFUL)
     853    rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_POOL_WAIT);
     854 
     855  *waiters -= 1;
     856}
     857
     858/**
     859 * Wake a blocked resource. The resource has a counter that lets us know if
     860 * there are any waiters.
     861 *
     862 * @param sema The semaphore to release.
     863 * @param waiters The wait counter for this semaphore.
     864 */
     865static void
     866rtems_bdbuf_wake (rtems_id sema, volatile uint32_t* waiters)
     867{
     868  if (*waiters)
     869  {
     870    rtems_status_code sc;
     871
     872    sc = rtems_semaphore_flush (sema);
     873 
     874    if (sc != RTEMS_SUCCESSFUL)
     875      rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_POOL_WAKE);
     876  }
     877}
     878
     879/**
     880 * Add a buffer descriptor to the modified list. This modified list is treated
     881 * 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
     883 * hold the sync lock. The sync lock is used to block writes while a sync is
     884 * active.
     885 *
     886 * @param sema The semaphore to release.
     887 * @param waiters The wait counter for this semaphore.
     888 */
     889static void
     890rtems_bdbuf_append_modified (rtems_bdbuf_pool* pool, rtems_bdbuf_buffer* bd)
     891{
     892  /*
     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)
     898  {
     899    rtems_bdbuf_unlock_pool (pool);
     900    rtems_bdbuf_lock_sync (pool);
     901    rtems_bdbuf_lock_pool (pool);
     902  }
     903     
     904  bd->state = RTEMS_BDBUF_STATE_MODIFIED;
     905
     906  rtems_chain_append (&pool->modified, &bd->link);
     907
     908  if (0 && sync_active)
     909    rtems_bdbuf_unlock_sync (pool);
     910}
     911
     912static void
     913rtems_bdbuf_wake_swapper ()
     914{
     915  rtems_status_code sc = rtems_event_send (rtems_bdbuf_ctx.swapout,
     916                                           RTEMS_BDBUF_SWAPOUT_SYNC);
     917  if (sc != RTEMS_SUCCESSFUL)
     918    rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_SO_WAKE);
     919}
     920
     921/* bdbuf_initialize_pool --
     922 *      Initialize single buffer pool.
    126923 *
    127924 * PARAMETERS:
    128  *     root - pointer to the root node of the AVL-Tree.
    129  *     dev, block - search key
     925 *     config - buffer pool configuration
     926 *     pool   - pool number
    130927 *
    131928 * RETURNS:
    132  *     NULL if node with specified dev/block not found
    133  *     non-NULL - pointer to the node with specified dev/block
    134  */
    135 static bdbuf_buffer *
    136 avl_search(bdbuf_buffer **root, dev_t dev, blkdev_bnum block)
    137 {
    138     bdbuf_buffer *p = *root;
    139 
    140     while ((p != NULL) && ((p->dev != dev) || (p->block != block)))
    141     {
    142         if ((p->dev < dev) || ((p->dev == dev) && (p->block < block)))
     929 *     RTEMS_SUCCESSFUL, if buffer pool initialized successfully, or error
     930 *     code if error occured.
     931 */
     932static rtems_status_code
     933rtems_bdbuf_initialize_pool (rtems_bdbuf_pool_config* config,
     934                             rtems_bdpool_id          pid)
     935{
     936  unsigned char*      buffer = config->mem_area;
     937  rtems_bdbuf_pool*   pool;
     938  rtems_bdbuf_buffer* bd;
     939  rtems_status_code   sc;
     940  int                 b;
     941
     942  pool = rtems_bdbuf_get_pool (pid);
     943 
     944  pool->blksize = config->size;
     945  pool->nblks   = config->num;
     946  pool->tree    = NULL;
     947  pool->buffers = NULL;
     948
     949  rtems_chain_initialize_empty (&pool->ready);
     950  rtems_chain_initialize_empty (&pool->lru);
     951  rtems_chain_initialize_empty (&pool->modified);
     952  rtems_chain_initialize_empty (&pool->sync);
     953
     954  pool->access = 0;
     955  pool->access_waiters = 0;
     956  pool->transfer = 0;
     957  pool->transfer_waiters = 0;
     958  pool->waiting = 0;
     959  pool->wait_waiters = 0;
     960 
     961  /*
     962   * Allocate memory for buffer descriptors
     963   */
     964  pool->bds = calloc (config->num, sizeof (rtems_bdbuf_buffer));
     965 
     966  if (!pool->bds)
     967    return RTEMS_NO_MEMORY;
     968
     969  /*
     970   * Allocate memory for buffers if required.
     971   */
     972  if (buffer == NULL)
     973  {
     974    buffer = pool->buffers = malloc (config->num * config->size);
     975    if (!pool->buffers)
     976    {
     977      free (pool->bds);
     978      return RTEMS_NO_MEMORY;
     979    }
     980  }
     981
     982  for (b = 0, bd = pool->bds;
     983       b < pool->nblks;
     984       b++, bd++, buffer += pool->blksize)
     985  {
     986    bd->dev        = -1;
     987    bd->block      = 0;
     988    bd->buffer     = buffer;
     989    bd->avl.left   = NULL;
     990    bd->avl.right  = NULL;
     991    bd->state      = RTEMS_BDBUF_STATE_EMPTY;
     992    bd->pool       = pid;
     993    bd->error      = 0;
     994    bd->waiters    = 0;
     995    bd->hold_timer = 0;
     996   
     997    rtems_chain_append (&pool->ready, &bd->link);
     998  }
     999
     1000  sc = rtems_semaphore_create (rtems_build_name ('B', 'P', '0' + pid, 'L'),
     1001                               1, RTEMS_BDBUF_POOL_LOCK_ATTRIBS, 0,
     1002                               &pool->lock);
     1003  if (sc != RTEMS_SUCCESSFUL)
     1004  {
     1005    free (pool->buffers);
     1006    free (pool->bds);
     1007    return sc;
     1008  }
     1009
     1010  sc = rtems_semaphore_create (rtems_build_name ('B', 'P', '0' + pid, 's'),
     1011                               0, RTEMS_BDBUF_POOL_WAITER_ATTRIBS, 0,
     1012                               &pool->sync_lock);
     1013  if (sc != RTEMS_SUCCESSFUL)
     1014  {
     1015    rtems_semaphore_delete (pool->lock);
     1016    free (pool->buffers);
     1017    free (pool->bds);
     1018    return sc;
     1019  }
     1020 
     1021  sc = rtems_semaphore_create (rtems_build_name ('B', 'P', '0' + pid, 'a'),
     1022                               0, RTEMS_BDBUF_POOL_WAITER_ATTRIBS, 0,
     1023                               &pool->access);
     1024  if (sc != RTEMS_SUCCESSFUL)
     1025  {
     1026    rtems_semaphore_delete (pool->sync_lock);
     1027    rtems_semaphore_delete (pool->lock);
     1028    free (pool->buffers);
     1029    free (pool->bds);
     1030    return sc;
     1031  }
     1032
     1033  sc = rtems_semaphore_create (rtems_build_name ('B', 'P', '0' + pid, 't'),
     1034                               0, RTEMS_BDBUF_POOL_WAITER_ATTRIBS, 0,
     1035                               &pool->transfer);
     1036  if (sc != RTEMS_SUCCESSFUL)
     1037  {
     1038    rtems_semaphore_delete (pool->access);
     1039    rtems_semaphore_delete (pool->sync_lock);
     1040    rtems_semaphore_delete (pool->lock);
     1041    free (pool->buffers);
     1042    free (pool->bds);
     1043    return sc;
     1044  }
     1045
     1046  sc = rtems_semaphore_create (rtems_build_name ('B', 'P', '0' + pid, 'w'),
     1047                               0, RTEMS_BDBUF_POOL_WAITER_ATTRIBS, 0,
     1048                               &pool->waiting);
     1049  if (sc != RTEMS_SUCCESSFUL)
     1050  {
     1051    rtems_semaphore_delete (pool->transfer);
     1052    rtems_semaphore_delete (pool->access);
     1053    rtems_semaphore_delete (pool->sync_lock);
     1054    rtems_semaphore_delete (pool->lock);
     1055    free (pool->buffers);
     1056    free (pool->bds);
     1057    return sc;
     1058  }
     1059
     1060  return RTEMS_SUCCESSFUL;
     1061}
     1062
     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
     1071 */
     1072static rtems_status_code
     1073rtems_bdbuf_release_pool (rtems_bdpool_id pid)
     1074{
     1075  rtems_bdbuf_pool* pool = rtems_bdbuf_get_pool (pid);
     1076 
     1077  rtems_bdbuf_lock_pool (pool);
     1078
     1079  rtems_semaphore_delete (pool->waiting);
     1080  rtems_semaphore_delete (pool->transfer);
     1081  rtems_semaphore_delete (pool->access);
     1082  rtems_semaphore_delete (pool->lock);
     1083 
     1084  free (pool->buffers);
     1085  free (pool->bds);
     1086 
     1087  return RTEMS_SUCCESSFUL;
     1088}
     1089
     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)
     1104 */
     1105rtems_status_code
     1106rtems_bdbuf_init ()
     1107{
     1108  rtems_bdpool_id   p;
     1109  rtems_status_code sc;
     1110
     1111#if RTEMS_BDBUF_TRACE
     1112  rtems_bdbuf_printf ("init\n");
     1113#endif
     1114
     1115  if (rtems_bdbuf_pool_configuration_size <= 0)
     1116    return RTEMS_INVALID_SIZE;
     1117
     1118  if (rtems_bdbuf_ctx.npools)
     1119    return RTEMS_RESOURCE_IN_USE;
     1120
     1121  rtems_bdbuf_ctx.npools = rtems_bdbuf_pool_configuration_size;
     1122
     1123  /*
     1124   * Allocate memory for buffer pool descriptors
     1125   */
     1126  rtems_bdbuf_ctx.pool = calloc (rtems_bdbuf_pool_configuration_size,
     1127                                 sizeof (rtems_bdbuf_pool));
     1128 
     1129  if (rtems_bdbuf_ctx.pool == NULL)
     1130    return RTEMS_NO_MEMORY;
     1131
     1132  /*
     1133   * Initialize buffer pools and roll out if something failed,
     1134   */
     1135  for (p = 0; p < rtems_bdbuf_ctx.npools; p++)
     1136  {
     1137    sc = rtems_bdbuf_initialize_pool (&rtems_bdbuf_pool_configuration[p], p);
     1138    if (sc != RTEMS_SUCCESSFUL)
     1139    {
     1140      rtems_bdpool_id j;
     1141      for (j = 0; j < p - 1; j++)
     1142        rtems_bdbuf_release_pool (j);
     1143      return sc;
     1144    }
     1145  }
     1146
     1147  /*
     1148   * Create and start swapout task
     1149   */
     1150
     1151  rtems_bdbuf_ctx.swapout_enabled = TRUE;
     1152 
     1153  sc = rtems_task_create (rtems_build_name('B', 'S', 'W', 'P'),
     1154                          (rtems_bdbuf_configuration.swapout_priority ?
     1155                           rtems_bdbuf_configuration.swapout_priority :
     1156                           RTEMS_BDBUF_SWAPOUT_TASK_PRIORITY_DEFAULT),
     1157                          SWAPOUT_TASK_STACK_SIZE,
     1158                          RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR,
     1159                          RTEMS_LOCAL | RTEMS_NO_FLOATING_POINT,
     1160                          &rtems_bdbuf_ctx.swapout);
     1161  if (sc != RTEMS_SUCCESSFUL)
     1162  {
     1163    for (p = 0; p < rtems_bdbuf_ctx.npools; p++)
     1164      rtems_bdbuf_release_pool (p);
     1165    free (rtems_bdbuf_ctx.pool);
     1166    return sc;
     1167  }
     1168
     1169  sc = rtems_task_start (rtems_bdbuf_ctx.swapout,
     1170                         rtems_bdbuf_swapout_task,
     1171                         (rtems_task_argument) &rtems_bdbuf_ctx);
     1172  if (sc != RTEMS_SUCCESSFUL)
     1173  {
     1174    rtems_task_delete (rtems_bdbuf_ctx.swapout);
     1175    for (p = 0; p < rtems_bdbuf_ctx.npools; p++)
     1176      rtems_bdbuf_release_pool (p);
     1177    free (rtems_bdbuf_ctx.pool);
     1178    return sc;
     1179  }
     1180
     1181  return RTEMS_SUCCESSFUL;
     1182}
     1183
     1184/**
     1185 * Get a buffer for this device and block. This function returns a buffer once
     1186 * 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.
     1189 *
     1190 * The AVL tree of buffers for the pool is searched and if not located check
     1191 * 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
     1194 * 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.
     1202 *
     1203 * A buffer located in the AVL tree means it is already in the cache and maybe
     1204 * in use somewhere. The buffer can be either:
     1205 *
     1206 * # Cached. Not being accessed or part of a media transfer.
     1207 * # Access. Is with an upper layer being accessed.
     1208 * # Transfer. Is with the driver and part of a media transfer.
     1209 *
     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.
     1213 *
     1214 * This function assumes the pool the buffer is being taken from is locked and
     1215 * it insure the pool is locked when it returns.
     1216 *
     1217 * @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.
     1231 */
     1232static rtems_bdbuf_buffer*
     1233rtems_bdbuf_get_buffer (rtems_disk_device* pdd,
     1234                        rtems_bdbuf_pool*  pool,
     1235                        rtems_blkdev_bnum  block,
     1236                        boolean            read_ahead)
     1237{
     1238  dev_t               device = pdd->dev;
     1239  rtems_bdbuf_buffer* bd;
     1240  boolean             available;
     1241
     1242  /*
     1243   * 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
     1246   * for a read ahead buffer return NULL.
     1247   *
     1248   * The search procedure is repeated as another thread could have pre-empted
     1249   * us while we waited for a buffer, obtained an empty buffer and loaded the
     1250   * AVL tree with it.
     1251   */
     1252  do
     1253  {
     1254    /*
     1255     * Search for buffer descriptor for this dev/block key.
     1256     */
     1257    bd = rtems_bdbuf_avl_search (&pool->tree, device, block);
     1258
     1259    /*
     1260     * No buffer in the cache for this block. We need to obtain a buffer and
     1261     * this means take a buffer that is ready to use. If all buffers are in use
     1262     * take the least recently used buffer. If there are none then the cache is
     1263     * empty. All the buffers are either queued to be written to disk or with
     1264     * the user. We cannot do much with the buffers with the user how-ever with
     1265     * 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.
     1268     */
     1269    if (!bd)
     1270    {
     1271      /*
     1272       * Assign new buffer descriptor from the empty list if one is present. If
     1273       * 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.
     1276       */
     1277      if (rtems_chain_is_empty (&pool->ready))
     1278      {
     1279        /*
     1280         * No unsed or read-ahead buffers.
     1281         *
     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.
     1285         */
     1286        if (read_ahead)
     1287          return NULL;
     1288
     1289        /*
     1290         * Check the LRU list.
     1291         */
     1292        bd = (rtems_bdbuf_buffer *) rtems_chain_get (&pool->lru);
     1293       
     1294        if (bd)
    1431295        {
    144             p = p->avl.right;
     1296          /*
     1297           * Remove the buffer from the AVL tree.
     1298           */
     1299          if (rtems_bdbuf_avl_remove (&pool->tree, bd) != 0)
     1300            rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_CONSISTENCY);
    1451301        }
    1461302        else
    1471303        {
    148             p = p->avl.left;
     1304          /*
     1305           * If there are buffers on the modified list expire the hold timer
     1306           * and wake the swap out task.
     1307           */
     1308          if (!rtems_chain_is_empty (&pool->modified))
     1309          {
     1310            rtems_chain_node* node = rtems_chain_head (&pool->modified);
     1311            int               write_blocks = 0;
     1312           
     1313            node = node->next;
     1314            while ((write_blocks < rtems_bdbuf_configuration.max_write_blocks) &&
     1315                   !rtems_chain_is_tail (&pool->modified, node))
     1316            {
     1317              rtems_bdbuf_buffer* bd = (rtems_bdbuf_buffer*) node;
     1318              bd->hold_timer = 0;
     1319              write_blocks++;
     1320              node = node->next;
     1321            }
     1322
     1323            rtems_bdbuf_wake_swapper ();
     1324          }
     1325         
     1326          /*
     1327           * Wait for a buffer to be returned to the pool. The buffer will be
     1328           * placed on the LRU list.
     1329           */
     1330          rtems_bdbuf_wait (pool, &pool->waiting, &pool->wait_waiters);
    1491331        }
    150     }
    151 
    152     return p;
    153 }
    154 
    155 
    156 /* avl_search_for_sync --
    157  *     Search in AVL tree for first modified buffer belongs to specified
    158  *     disk device.
    159  *
    160  * PARAMETERS:
    161  *     root - pointer to tree root
    162  *     dd - disk device descriptor
    163  *
    164  * RETURNS:
    165  *     Block buffer, or NULL if no modified blocks on specified device
    166  *     exists.
    167  */
    168 static bdbuf_buffer *
    169 avl_search_for_sync(bdbuf_buffer **root, disk_device *dd)
    170 {
    171     dev_t dev = dd->phys_dev->dev;
    172     blkdev_bnum block_start = dd->start;
    173     blkdev_bnum block_end = dd->start + dd->size - 1;
    174 
    175     bdbuf_buffer *buf_stack[AVL_MAX_HEIGHT];
    176     bdbuf_buffer **buf_prev = buf_stack;
    177     bdbuf_buffer *p = *root;
    178 
    179     while (p != NULL)
    180     {
    181         if ((p->dev < dev) || ((p->dev == dev) && (p->block < block_start)))
     1332      }
     1333      else
     1334      {
     1335        bd = (rtems_bdbuf_buffer *) rtems_chain_get (&(pool->ready));
     1336
     1337        if ((bd->state != RTEMS_BDBUF_STATE_EMPTY) &&
     1338            (bd->state != RTEMS_BDBUF_STATE_READ_AHEAD))
     1339          rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_CONSISTENCY);
     1340
     1341        if (bd->state == RTEMS_BDBUF_STATE_READ_AHEAD)
    1821342        {
    183             p = p->avl.right;
     1343          if (rtems_bdbuf_avl_remove (&pool->tree, bd) != 0)
     1344            rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_CONSISTENCY);
    1841345        }
    185         else if ((p->dev > dev) || ((p->dev == dev) && (p->block > block_end)))
    186         {
    187             p = p->avl.left;
    188         }
    189         else if (p->modified)
    190         {
    191             return p;
    192         }
    193         else
    194         {
    195             if (p->avl.right != NULL)
    196             {
    197                 *buf_prev++ = p->avl.right;
    198             }
    199             p = p->avl.left;
    200         }
    201 
    202         if ((p == NULL) && (buf_prev > buf_stack))
    203         {
    204             p = *--buf_prev;
    205         }
    206     }
    207 
    208     return p;
    209 }
    210 
    211 
    212 /*
    213  * avl_insert --
    214  *     Inserts the specified node to the AVl-Tree.
    215  *
    216  * PARAMETERS:
    217  *     root - Pointer to pointer to the root node
    218  *     node - Pointer to the node to add.
    219  *
    220  * RETURNS:
    221  *     0 - The node added successfully
    222  *    -1 - An error occured
    223  */
    224 static int
    225 avl_insert(bdbuf_buffer **root, bdbuf_buffer *node)
    226 {
    227     dev_t dev = node->dev;
    228     blkdev_bnum block = node->block;
    229 
    230     bdbuf_buffer *p = *root;
    231     bdbuf_buffer *q, *p1, *p2;
    232     bdbuf_buffer *buf_stack[AVL_MAX_HEIGHT];
    233     bdbuf_buffer **buf_prev = buf_stack;
    234 
    235     boolean modified = FALSE;
    236 
    237     if (p == NULL)
    238     {
    239         *root = node;
    240         node->avl.left = NULL;
    241         node->avl.right = NULL;
    242         node->avl.bal = 0;
    243         return 0;
    244     }
    245 
    246     while (p != NULL)
    247     {
    248         *buf_prev++ = p;
    249 
    250         if ((p->dev < dev) || ((p->dev == dev) && (p->block < block)))
    251         {
    252             p->avl.cache = 1;
    253             q = p->avl.right;
    254             if (q == NULL)
    255             {
    256                 q = node;
    257                 p->avl.right = q = node;
    258                 break;
    259             }
    260         }
    261         else if ((p->dev != dev) || (p->block != block))
    262         {
    263             p->avl.cache = -1;
    264             q = p->avl.left;
    265             if (q == NULL)
    266             {
    267                 q = node;
    268                 p->avl.left = q;
    269                 break;
    270             }
    271         }
    272         else
    273         {
    274             return -1;
    275         }
    276 
    277         p = q;
    278     }
    279 
    280     q->avl.left = q->avl.right = NULL;
    281     q->avl.bal = 0;
    282     modified = TRUE;
    283     buf_prev--;
    284 
    285     while (modified)
    286     {
    287         if (p->avl.cache == -1)
    288         {
    289             switch (p->avl.bal)
    290             {
    291                 case 1:
    292                     p->avl.bal = 0;
    293                     modified = FALSE;
    294                     break;
    295 
    296                 case 0:
    297                     p->avl.bal = -1;
    298                     break;
    299 
    300                 case -1:
    301                     p1 = p->avl.left;
    302                     if (p1->avl.bal == -1) /* simple LL-turn */
    303                     {
    304                         p->avl.left = p1->avl.right;
    305                         p1->avl.right = p;
    306                         p->avl.bal = 0;
    307                         p = p1;
    308                     }
    309                     else /* double LR-turn */
    310                     {
    311                         p2 = p1->avl.right;
    312                         p1->avl.right = p2->avl.left;
    313                         p2->avl.left = p1;
    314                         p->avl.left = p2->avl.right;
    315                         p2->avl.right = p;
    316                         if (p2->avl.bal == -1) p->avl.bal = +1; else p->avl.bal = 0;
    317                         if (p2->avl.bal == +1) p1->avl.bal = -1; else p1->avl.bal = 0;
    318                         p = p2;
    319                     }
    320                     p->avl.bal = 0;
    321                     modified = FALSE;
    322                     break;
    323 
    324                 default:
    325                     break;
    326             }
    327         }
    328         else
    329         {
    330             switch (p->avl.bal)
    331             {
    332                 case -1:
    333                     p->avl.bal = 0;
    334                     modified = FALSE;
    335                     break;
    336 
    337                 case 0:
    338                     p->avl.bal = 1;
    339                     break;
    340 
    341                 case 1:
    342                     p1 = p->avl.right;
    343                     if (p1->avl.bal == 1) /* simple RR-turn */
    344                     {
    345                         p->avl.right = p1->avl.left;
    346                         p1->avl.left = p;
    347                         p->avl.bal = 0;
    348                         p = p1;
    349                     }
    350                     else /* double RL-turn */
    351                     {
    352                         p2 = p1->avl.left;
    353                         p1->avl.left = p2->avl.right;
    354                         p2->avl.right = p1;
    355                         p->avl.right = p2->avl.left;
    356                         p2->avl.left = p;
    357                         if (p2->avl.bal == +1) p->avl.bal = -1; else p->avl.bal = 0;
    358                         if (p2->avl.bal == -1) p1->avl.bal = +1; else p1->avl.bal = 0;
    359                         p = p2;
    360                     }
    361                     p->avl.bal = 0;
    362                     modified = FALSE;
    363                     break;
    364 
    365                 default:
    366                     break;
    367             }
    368         }
    369         q = p;
    370         if (buf_prev > buf_stack)
    371         {
    372             p = *--buf_prev;
    373 
    374             if (p->avl.cache == -1)
    375             {
    376                 p->avl.left = q;
    377             }
    378             else
    379             {
    380                 p->avl.right = q;
    381             }
    382         }
    383         else
    384         {
    385             *root = p;
    386             break;
    387         }
    388     };
    389 
    390     return 0;
    391 }
    392 
    393 
    394 /* avl_remove --
    395  *     removes the node from the tree.
    396  *
    397  * PARAMETERS:
    398  *     root_addr - Pointer to pointer to the root node
    399  *     node      - Pointer to the node to remove
    400  *
    401  * RETURNS:
    402  *     0 - Item removed
    403  *    -1 - No such item found
    404  */
    405 static int
    406 avl_remove(bdbuf_buffer **root, const bdbuf_buffer *node)
    407 {
    408     dev_t dev = node->dev;
    409     blkdev_bnum block = node->block;
    410 
    411     bdbuf_buffer *p = *root;
    412     bdbuf_buffer *q, *r, *s, *p1, *p2;
    413     bdbuf_buffer *buf_stack[AVL_MAX_HEIGHT];
    414     bdbuf_buffer **buf_prev = buf_stack;
    415 
    416     boolean modified = FALSE;
    417 
    418     memset(buf_stack, 0, sizeof(buf_stack));
    419 
    420     while (p != NULL)
    421     {
    422         *buf_prev++ = p;
    423 
    424         if ((p->dev < dev) || ((p->dev == dev) && (p->block < block)))
    425         {
    426             p->avl.cache = 1;
    427             p = p->avl.right;
    428         }
    429         else if ((p->dev != dev) || (p->block != block))
    430         {
    431             p->avl.cache = -1;
    432             p = p->avl.left;
    433         }
    434         else
    435         {
    436             /* node found */
    437             break;
    438         }
    439     }
    440 
    441     if (p == NULL)
    442     {
    443         /* there is no such node */
    444         return -1;
    445     }
    446 
    447     q = p;
    448 
    449     buf_prev--;
    450     if (buf_prev > buf_stack)
    451     {
    452         p = *(buf_prev - 1);
    453     }
    454     else
    455     {
    456         p = NULL;
    457     }
    458 
    459     /* at this moment q - is a node to delete, p is q's parent */
    460     if (q->avl.right == NULL)
    461     {
    462         r = q->avl.left;
    463         if (r != NULL)
    464         {
    465             r->avl.bal = 0;
    466         }
    467         q = r;
    468     }
    469     else
    470     {
    471         bdbuf_buffer **t;
    472 
    473         r = q->avl.right;
    474 
    475         if (r->avl.left == NULL)
    476         {
    477             r->avl.left = q->avl.left;
    478             r->avl.bal = q->avl.bal;
    479             r->avl.cache = 1;
    480             *buf_prev++ = q = r;
    481         }
    482         else
    483         {
    484             t = buf_prev++;
    485             s = r;
    486 
    487             while (s->avl.left != NULL)
    488             {
    489                 *buf_prev++ = r = s;
    490                 s = r->avl.left;
    491                 r->avl.cache = -1;
    492             }
    493 
    494             s->avl.left = q->avl.left;
    495             r->avl.left = s->avl.right;
    496             s->avl.right = q->avl.right;
    497             s->avl.bal = q->avl.bal;
    498             s->avl.cache = 1;
    499 
    500             *t = q = s;
    501         }
    502     }
    503 
    504     if (p != NULL)
    505     {
    506         if (p->avl.cache == -1)
    507         {
    508             p->avl.left = q;
    509         }
    510         else
    511         {
    512             p->avl.right = q;
    513         }
    514     }
    515     else
    516     {
    517         *root = q;
    518     }
    519 
    520     modified = TRUE;
    521 
    522     while (modified)
    523     {
    524         if (buf_prev > buf_stack)
    525         {
    526             p = *--buf_prev;
    527         }
    528         else
    529         {
    530             break;
    531         }
    532 
    533         if (p->avl.cache == -1)
    534         {
    535             /* rebalance left branch */
    536             switch (p->avl.bal)
    537             {
    538                 case -1:
    539                     p->avl.bal = 0;
    540                     break;
    541                 case  0:
    542                     p->avl.bal = 1;
    543                     modified = FALSE;
    544                     break;
    545 
    546                 case +1:
    547                     p1 = p->avl.right;
    548 
    549                     if (p1->avl.bal >= 0) /* simple RR-turn */
    550                     {
    551                         p->avl.right = p1->avl.left;
    552                         p1->avl.left = p;
    553 
    554                         if (p1->avl.bal == 0)
    555                         {
    556                             p1->avl.bal = -1;
    557                             modified = FALSE;
    558                         }
    559                         else
    560                         {
    561                             p->avl.bal = 0;
    562                             p1->avl.bal = 0;
    563                         }
    564                         p = p1;
    565                     }
    566                     else /* double RL-turn */
    567                     {
    568                         p2 = p1->avl.left;
    569 
    570                         p1->avl.left = p2->avl.right;
    571                         p2->avl.right = p1;
    572                         p->avl.right = p2->avl.left;
    573                         p2->avl.left = p;
    574 
    575                         if (p2->avl.bal == +1) p->avl.bal = -1; else p->avl.bal = 0;
    576                         if (p2->avl.bal == -1) p1->avl.bal = 1; else p1->avl.bal = 0;
    577 
    578                         p = p2;
    579                         p2->avl.bal = 0;
    580                     }
    581                     break;
    582 
    583                 default:
    584                     break;
    585             }
    586         }
    587         else
    588         {
    589             /* rebalance right branch */
    590             switch (p->avl.bal)
    591             {
    592                 case +1:
    593                     p->avl.bal = 0;
    594                     break;
    595 
    596                 case  0:
    597                     p->avl.bal = -1;
    598                     modified = FALSE;
    599                     break;
    600 
    601                 case -1:
    602                     p1 = p->avl.left;
    603 
    604                     if (p1->avl.bal <= 0) /* simple LL-turn */
    605                     {
    606                         p->avl.left = p1->avl.right;
    607                         p1->avl.right = p;
    608                         if (p1->avl.bal == 0)
    609                         {
    610                             p1->avl.bal = 1;
    611                             modified = FALSE;
    612                         }
    613                         else
    614                         {
    615                             p->avl.bal = 0;
    616                             p1->avl.bal = 0;
    617                         }
    618                         p = p1;
    619                     }
    620                     else /* double LR-turn */
    621                     {
    622                         p2 = p1->avl.right;
    623 
    624                         p1->avl.right = p2->avl.left;
    625                         p2->avl.left = p1;
    626                         p->avl.left = p2->avl.right;
    627                         p2->avl.right = p;
    628 
    629                         if (p2->avl.bal == -1) p->avl.bal = 1; else p->avl.bal = 0;
    630                         if (p2->avl.bal == +1) p1->avl.bal = -1; else p1->avl.bal = 0;
    631 
    632                         p = p2;
    633                         p2->avl.bal = 0;
    634                     }
    635                     break;
    636 
    637                 default:
    638                     break;
    639             }
    640         }
    641 
    642         if (buf_prev > buf_stack)
    643         {
    644             q = *(buf_prev - 1);
    645 
    646             if (q->avl.cache == -1)
    647             {
    648                 q->avl.left = p;
    649             }
    650             else
    651             {
    652                 q->avl.right = p;
    653             }
    654         }
    655         else
    656         {
    657             *root = p;
    658             break;
    659         }
    660 
    661     }
    662 
    663     return 0;
    664 }
    665 
    666 /* bdbuf_initialize_pool --
    667  *      Initialize single buffer pool.
    668  *
    669  * PARAMETERS:
    670  *     config - buffer pool configuration
    671  *     pool   - pool number
    672  *
    673  * RETURNS:
    674  *     RTEMS_SUCCESSFUL, if buffer pool initialized successfully, or error
    675  *     code if error occured.
    676  */
    677 static rtems_status_code
    678 bdbuf_initialize_pool(rtems_bdbuf_config *config, int pool)
    679 {
    680     bdbuf_pool *p = rtems_bdbuf_ctx.pool + pool;
    681     unsigned char *bufs;
    682     bdbuf_buffer *b;
    683     rtems_status_code rc;
    684     int i;
    685 
    686     p->blksize = config->size;
    687     p->nblks = config->num;
    688     p->tree = NULL;
    689 
    690     rtems_chain_initialize_empty(&p->free);
    691     rtems_chain_initialize_empty(&p->lru);
    692 
    693     /* Allocate memory for buffer descriptors */
    694     p->bdbufs = calloc(config->num, sizeof(bdbuf_buffer));
    695     if (p->bdbufs == NULL)
    696     {
    697         return RTEMS_NO_MEMORY;
    698     }
    699 
    700     /* Allocate memory for buffers if required */
    701     if (config->mem_area == NULL)
    702     {
    703         bufs = p->mallocd_bufs = malloc(config->num * config->size);
    704         if (bufs == NULL)
    705         {
    706             free(p->bdbufs);
    707             return RTEMS_NO_MEMORY;
    708         }
    709     }
    710     else
    711     {
    712         bufs = config->mem_area;
    713         p->mallocd_bufs = NULL;
    714     }
    715 
    716     for (i = 0, b = p->bdbufs; i < p->nblks; i++, b++, bufs += p->blksize)
    717     {
    718         b->dev = -1; b->block = 0;
    719         b->buffer = bufs;
    720         b->actual = b->modified = b->in_progress = FALSE;
    721         b->use_count = 0;
    722         b->pool = pool;
    723         rtems_chain_append(&p->free, &b->link);
    724     }
    725 
    726     rc = rtems_semaphore_create(
    727         rtems_build_name('B', 'U', 'F', 'G'),
    728         p->nblks,
    729         RTEMS_FIFO | RTEMS_COUNTING_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY |
    730         RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL,
    731         0,
    732         &p->bufget_sema);
    733 
    734     if (rc != RTEMS_SUCCESSFUL)
    735     {
    736         free(p->bdbufs);
    737         free(p->mallocd_bufs);
    738         return rc;
    739     }
    740 
    741     return RTEMS_SUCCESSFUL;
    742 }
    743 
    744 /* bdbuf_release_pool --
    745  *     Free resources allocated for buffer pool with specified number.
    746  *
    747  * PARAMETERS:
    748  *     pool - buffer pool number
    749  *
    750  * RETURNS:
    751  *     RTEMS_SUCCESSFUL
    752  */
    753 static rtems_status_code
    754 bdbuf_release_pool(rtems_bdpool_id pool)
    755 {
    756     bdbuf_pool *p = rtems_bdbuf_ctx.pool + pool;
    757     rtems_semaphore_delete(p->bufget_sema);
    758     free(p->bdbufs);
    759     free(p->mallocd_bufs);
    760     return RTEMS_SUCCESSFUL;
    761 }
    762 
    763 /* rtems_bdbuf_init --
    764  *     Prepare buffering layer to work - initialize buffer descritors
    765  *     and (if it is neccessary)buffers. Buffers will be allocated accoriding
    766  *     to the configuration table, each entry describes kind of block and
    767  *     amount requested. After initialization all blocks is placed into
    768  *     free elements lists.
    769  *
    770  * PARAMETERS:
    771  *     conf_table - pointer to the buffers configuration table
    772  *     size       - number of entries in configuration table
    773  *
    774  * RETURNS:
    775  *     RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
    776  *     or error code if error is occured)
     1346      }
     1347
     1348      if (bd)
     1349      {
     1350        bd->dev       = device;
     1351        bd->block     = block;
     1352        bd->avl.left  = NULL;
     1353        bd->avl.right = NULL;
     1354        bd->state     = RTEMS_BDBUF_STATE_EMPTY;
     1355        bd->error     = 0;
     1356        bd->waiters   = 0;
     1357
     1358        if (rtems_bdbuf_avl_insert (&pool->tree, bd) != 0)
     1359          rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_CONSISTENCY);
     1360
     1361        return bd;
     1362      }
     1363    }
     1364  }
     1365  while (!bd);
     1366
     1367  /*
     1368   * If the buffer is for read ahead and it exists in the AVL cache or is being
     1369   * accessed or being transfered then return NULL.
     1370   */
     1371  if (read_ahead)
     1372    return NULL;
     1373
     1374  /*
     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.
     1377   */
     1378  available = FALSE;
     1379  while (!available)
     1380  {
     1381    switch (bd->state)
     1382    {
     1383      case RTEMS_BDBUF_STATE_CACHED:
     1384      case RTEMS_BDBUF_STATE_MODIFIED:
     1385      case RTEMS_BDBUF_STATE_READ_AHEAD:
     1386        available = TRUE;
     1387        break;
     1388
     1389      case RTEMS_BDBUF_STATE_ACCESS:
     1390      case RTEMS_BDBUF_STATE_ACCESS_MODIFIED:
     1391        bd->waiters++;
     1392        rtems_bdbuf_wait (pool, &pool->access, &pool->access_waiters);
     1393        bd->waiters--;
     1394        break;
     1395
     1396      case RTEMS_BDBUF_STATE_SYNC:
     1397      case RTEMS_BDBUF_STATE_TRANSFER:
     1398        bd->waiters++;
     1399        rtems_bdbuf_wait (pool, &pool->transfer, &pool->transfer_waiters);
     1400        bd->waiters--;
     1401        break;
     1402
     1403      default:
     1404        rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_CONSISTENCY);
     1405    }
     1406  }
     1407
     1408  /*
     1409   * Buffer is linked to the LRU, modifed, or sync lists. Remove it from there.
     1410   */
     1411  rtems_chain_extract (&bd->link);
     1412
     1413  return bd;
     1414}
     1415
     1416/**
     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)
    7771430 */
    7781431rtems_status_code
    779 rtems_bdbuf_init(rtems_bdbuf_config *conf_table, int size)
    780 {
    781     rtems_bdpool_id i;
    782     rtems_status_code rc;
    783 
    784     if (size <= 0)
    785         return RTEMS_INVALID_SIZE;
    786 
    787     rtems_bdbuf_ctx.npools = size;
    788 
    789     /*
    790      * Allocate memory for buffer pool descriptors
    791      */
    792     rtems_bdbuf_ctx.pool = calloc(size, sizeof(bdbuf_pool));
    793     if (rtems_bdbuf_ctx.pool == NULL)
    794     {
    795         return RTEMS_NO_MEMORY;
    796     }
    797 
    798     rtems_chain_initialize_empty(&rtems_bdbuf_ctx.mod);
    799 
    800     /* Initialize buffer pools and roll out if something failed */
    801     for (i = 0; i < size; i++)
    802     {
    803         rc = bdbuf_initialize_pool(conf_table + i, i);
    804         if (rc != RTEMS_SUCCESSFUL)
    805         {
    806              rtems_bdpool_id j;
    807              for (j = 0; j < i - 1; j++)
    808              {
    809                  bdbuf_release_pool(j);
    810              }
    811              return rc;
    812         }
    813     }
    814 
    815     /* Create buffer flush semaphore */
    816     rc = rtems_semaphore_create(
    817         rtems_build_name('B', 'F', 'L', 'U'), 0,
    818         RTEMS_FIFO | RTEMS_COUNTING_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY |
    819         RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL, 0,
    820         &rtems_bdbuf_ctx.flush_sema);
    821     if (rc != RTEMS_SUCCESSFUL)
    822     {
    823         for (i = 0; i < size; i++)
    824             bdbuf_release_pool(i);
    825         free(rtems_bdbuf_ctx.pool);
    826         return rc;
    827     }
    828 
    829     /* Create and start swapout task */
    830     rc = rtems_task_create(
    831         rtems_build_name('B', 'S', 'W', 'P'),   
    832         ((swapout_task_priority > 0)
    833          ? swapout_task_priority
    834          : SWAPOUT_TASK_DEFAULT_PRIORITY),
    835         SWAPOUT_TASK_STACK_SIZE,
    836         RTEMS_DEFAULT_MODES | RTEMS_NO_PREEMPT,
    837         RTEMS_DEFAULT_ATTRIBUTES,
    838         &rtems_bdbuf_ctx.swapout_task);
    839     if (rc != RTEMS_SUCCESSFUL)
    840     {
    841         rtems_semaphore_delete(rtems_bdbuf_ctx.flush_sema);
    842         for (i = 0; i < size; i++)
    843             bdbuf_release_pool(i);
    844         free(rtems_bdbuf_ctx.pool);
    845         return rc;
    846     }
    847 
    848     rc = rtems_task_start(rtems_bdbuf_ctx.swapout_task, bdbuf_swapout_task, 0);
    849     if (rc != RTEMS_SUCCESSFUL)
    850     {
    851         rtems_task_delete(rtems_bdbuf_ctx.swapout_task);
    852         rtems_semaphore_delete(rtems_bdbuf_ctx.flush_sema);
    853         for (i = 0; i < size; i++)
    854             bdbuf_release_pool(i);
    855         free(rtems_bdbuf_ctx.pool);
    856         return rc;
    857     }
    858 
    859     return RTEMS_SUCCESSFUL;
    860 }
    861 
    862 /* find_or_assign_buffer --
    863  *     Looks for buffer already assigned for this dev/block. If one is found
    864  *     obtain block buffer. If specified block already cached (i.e. there's
    865  *     block in the _modified_, or _recently_used_), return address
    866  *     of appropriate buffer descriptor and increment reference counter to 1.
    867  *     If block is not cached, allocate new buffer and return it. Data
    868  *     shouldn't be read to the buffer from media; buffer contains arbitrary
    869  *     data. This primitive may be blocked if there are no free buffer
    870  *     descriptors available and there are no unused non-modified (or
    871  *     synchronized with media) buffers available.
    872  *
    873  * PARAMETERS:
    874  *     device - device number (constructed of major and minor device number
    875  *     block  - linear media block number
    876  *     ret_buf - address of the variable to store address of found descriptor
    877  *
    878  * RETURNS:
    879  *     RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
    880  *     or error code if error is occured)
    881  *
    882  * SIDE EFFEECTS:
    883  *     bufget_sema may be obtained by this primitive
    884  *
    885  * NOTE:
    886  *     It is assumed that primitive invoked when thread preemption is disabled.
    887  */
    888 static rtems_status_code
    889 find_or_assign_buffer(disk_device *dd,
    890                       blkdev_bnum block,
    891                       bdbuf_buffer **ret_buf)
    892 {
    893     bdbuf_buffer *bd_buf;
    894     bdbuf_pool   *bd_pool;
    895     rtems_status_code rc;
    896     dev_t         device;
    897     ISR_Level     level;
    898 
    899     int blksize;
    900 
    901     device = dd->dev;
    902     bd_pool = rtems_bdbuf_ctx.pool + dd->pool;
    903     blksize = dd->block_size;
    904 
    905 again:
    906     /* Looking for buffer descriptor used for this dev/block. */
    907     bd_buf = avl_search(&bd_pool->tree, device, block);
    908 
    909     if (bd_buf == NULL)
    910     {
    911         /* Try to obtain semaphore without waiting first. It is the most
    912            frequent case when reasonable number of buffers configured. If
    913            it is failed, obtain semaphore blocking on it. In this case
    914            it should be checked that appropriate buffer hasn't been loaded
    915            by another thread, because this thread is preempted */
    916         rc = rtems_semaphore_obtain(bd_pool->bufget_sema, RTEMS_NO_WAIT, 0);
    917         if (rc == RTEMS_UNSATISFIED)
    918         {
    919             rc = rtems_semaphore_obtain(bd_pool->bufget_sema,
    920                                         RTEMS_WAIT, RTEMS_NO_TIMEOUT);
    921             bd_buf = avl_search(&bd_pool->tree, device, block);
    922             if (bd_buf != NULL)
    923                 rtems_semaphore_release(bd_pool->bufget_sema);
    924         }
    925     }
    926 
    927     if (bd_buf == NULL)
    928     {
    929         /* Assign new buffer descriptor */
    930         if (rtems_chain_is_empty(&bd_pool->free))
    931         {
    932             bd_buf = (bdbuf_buffer *)rtems_chain_get(&bd_pool->lru);
    933             if (bd_buf != NULL)
    934             {
    935                 int avl_result;
    936                 avl_result = avl_remove(&bd_pool->tree, bd_buf);
    937                 if (avl_result != 0)
    938                 {
    939                     rtems_fatal_error_occurred(BLKDEV_FATAL_BDBUF_CONSISTENCY);
    940                     return RTEMS_INTERNAL_ERROR;
    941                 }
    942             }
    943         }
    944         else
    945         {
    946             bd_buf = (bdbuf_buffer *)rtems_chain_get(&(bd_pool->free));
    947         }
    948 
    949         if (bd_buf == NULL)
    950         {
    951             goto again;
    952         }
    953         else
    954         {
    955             bd_buf->dev = device;
    956             bd_buf->block = block;
    957 #ifdef AVL_GPL
    958             bd_buf->avl.link[0] = NULL;
    959             bd_buf->avl.link[1] = NULL;
    960 #else
    961             bd_buf->avl.left = NULL;
    962             bd_buf->avl.right = NULL;
     1432rtems_bdbuf_get (dev_t                device,
     1433                 rtems_blkdev_bnum    block,
     1434                 rtems_bdbuf_buffer** bdp)
     1435{
     1436  rtems_disk_device*  dd;
     1437  rtems_bdbuf_pool*   pool;
     1438  rtems_bdbuf_buffer* bd;
     1439
     1440  /*
     1441   * Do not hold the pool lock when obtaining the disk table.
     1442   */
     1443  dd = rtems_disk_obtain (device);
     1444  if (dd == NULL)
     1445    return RTEMS_INVALID_ID;
     1446
     1447  if (block >= dd->size)
     1448  {
     1449    rtems_disk_release (dd);
     1450    return RTEMS_INVALID_NUMBER;
     1451  }
     1452
     1453  block += dd->start;
     1454
     1455  pool = rtems_bdbuf_get_pool (dd->phys_dev->pool);
     1456 
     1457  rtems_disk_release(dd);
     1458
     1459  rtems_bdbuf_lock_pool (pool);
     1460
     1461#if RTEMS_BDBUF_TRACE
     1462  rtems_bdbuf_printf ("get: %d (dev = %08x)\n", block, device);
    9631463#endif
    964             bd_buf->use_count = 1;
    965             bd_buf->modified = bd_buf->actual = bd_buf->in_progress = FALSE;
    966             bd_buf->status = RTEMS_SUCCESSFUL;
    967 
    968             if (avl_insert(&bd_pool->tree, bd_buf) != 0)
    969             {
    970                 rtems_fatal_error_occurred(BLKDEV_FATAL_BDBUF_CONSISTENCY);
    971                 return RTEMS_INTERNAL_ERROR;
    972             }
    973 
    974             *ret_buf = bd_buf;
    975 
    976             return RTEMS_SUCCESSFUL;
    977         }
    978     }
    979     else
    980     {
    981         /* Buffer descriptor already assigned for this dev/block */
    982         if (bd_buf->use_count == 0)
    983         {
    984             /* If we are removing from lru list, obtain the bufget_sema
    985              * first. If we are removing from mod list, obtain flush sema.
    986              * It should be obtained without blocking because we know
    987              * that our buffer descriptor is in the list. */
    988             if (bd_buf->modified)
    989             {
    990                 rc = rtems_semaphore_obtain(rtems_bdbuf_ctx.flush_sema,
    991                                             RTEMS_NO_WAIT, 0);
    992             }
    993             else
    994             {
    995                 rc = rtems_semaphore_obtain(bd_pool->bufget_sema,
    996                                             RTEMS_NO_WAIT, 0);
    997             }
    998             /* It is possible that we couldn't obtain flush or bufget sema
    999              * although buffer in the appropriate chain is available:
    1000              * semaphore may be released to swapout task, but this task
    1001              * actually did not start to process it. */
    1002             if (rc == RTEMS_UNSATISFIED)
    1003                 rc = RTEMS_SUCCESSFUL;
    1004             if (rc != RTEMS_SUCCESSFUL)
    1005             {
    1006                 rtems_fatal_error_occurred(BLKDEV_FATAL_BDBUF_CONSISTENCY);
    1007                 return RTEMS_INTERNAL_ERROR;
    1008             }
    1009 
    1010             /* Buffer descriptor is linked to the lru or mod chain. Remove
    1011                it from there. */
    1012             rtems_chain_extract(&bd_buf->link);
    1013         }
    1014         bd_buf->use_count++;
    1015         while (bd_buf->in_progress != 0)
    1016         {
    1017             rtems_interrupt_disable(level);
    1018             _CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE,
    1019                               WATCHDOG_NO_TIMEOUT, level);
    1020         }
    1021 
    1022         *ret_buf = bd_buf;
    1023         return RTEMS_SUCCESSFUL;
    1024     }
    1025 }
    1026 
    1027 /* rtems_bdbuf_get --
    1028  *     Obtain block buffer. If specified block already cached (i.e. there's
    1029  *     block in the _modified_, or _recently_used_), return address
    1030  *     of appropriate buffer descriptor and increment reference counter to 1.
    1031  *     If block is not cached, allocate new buffer and return it. Data
    1032  *     shouldn't be read to the buffer from media; buffer may contains
    1033  *     arbitrary data. This primitive may be blocked if there are no free
    1034  *     buffer descriptors available and there are no unused non-modified
    1035  *     (or synchronized with media) buffers available.
    1036  *
    1037  * PARAMETERS:
    1038  *     device - device number (constructed of major and minor device number)
    1039  *     block  - linear media block number
    1040  *     bd     - address of variable to store pointer to the buffer descriptor
    1041  *
    1042  * RETURNS:
    1043  *     RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
    1044  *     or error code if error is occured)
    1045  *
    1046  * SIDE EFFECTS:
    1047  *     bufget_sema semaphore obtained by this primitive.
    1048  */
    1049 rtems_status_code
    1050 rtems_bdbuf_get(dev_t device, blkdev_bnum block, bdbuf_buffer **bd)
    1051 {
    1052     rtems_status_code rc;
    1053     disk_device *dd;
    1054     disk_device *pdd;
    1055     preemption_key key;
    1056 
    1057     /*
    1058      * Convert logical dev/block to physical one
    1059      */
    1060     dd = rtems_disk_lookup(device);
    1061     if (dd == NULL)
    1062         return RTEMS_INVALID_ID;
    1063 
    1064     if (block >= dd->size)
    1065     {
    1066         rtems_disk_release(dd);
    1067         return RTEMS_INVALID_NUMBER;
    1068     }
    1069 
    1070     pdd = dd->phys_dev;
    1071     block += dd->start;
    1072     rtems_disk_release(dd);
    1073 
    1074     DISABLE_PREEMPTION(key);
    1075     rc = find_or_assign_buffer(pdd, block, bd);
    1076     ENABLE_PREEMPTION(key);
    1077 
    1078     if (rc != RTEMS_SUCCESSFUL)
    1079         return rc;
    1080 
    1081     return RTEMS_SUCCESSFUL;
    1082 }
    1083 
    1084 /* bdbuf_initialize_transfer_sema --
    1085  *     Initialize transfer_sema mutex semaphore associated with buffer
    1086  *     descriptor.
    1087  */
    1088 static inline void
    1089 bdbuf_initialize_transfer_sema(bdbuf_buffer *bd_buf)
    1090 {
    1091     CORE_mutex_Attributes mutex_attr;
    1092     mutex_attr.lock_nesting_behavior = CORE_MUTEX_NESTING_BLOCKS;
    1093     mutex_attr.only_owner_release = FALSE;
    1094     mutex_attr.discipline = CORE_MUTEX_DISCIPLINES_FIFO;
    1095     mutex_attr.priority_ceiling = 0;
    1096 
    1097     _CORE_mutex_Initialize(&bd_buf->transfer_sema,
    1098                            &mutex_attr, CORE_MUTEX_LOCKED);
    1099 }
    1100 
    1101 /* bdbuf_write_transfer_done --
     1464
     1465  bd = rtems_bdbuf_get_buffer (dd->phys_dev, pool, block, FALSE);
     1466
     1467  if (bd->state == RTEMS_BDBUF_STATE_MODIFIED)
     1468    bd->state = RTEMS_BDBUF_STATE_ACCESS_MODIFIED;
     1469  else
     1470    bd->state = RTEMS_BDBUF_STATE_ACCESS;
     1471 
     1472  rtems_bdbuf_unlock_pool (pool);
     1473
     1474  *bdp = bd;
     1475 
     1476  return RTEMS_SUCCESSFUL;
     1477}
     1478
     1479/* bdbuf_read_transfer_done --
    11021480 *     Callout function. Invoked by block device driver when data transfer
    1103  *     to device (write) is completed. This function may be invoked from
     1481 *     from device (read) is completed. This function may be invoked from
    11041482 *     interrupt handler.
    11051483 *
     
    11151493 */
    11161494static void
    1117 bdbuf_write_transfer_done(void *arg, rtems_status_code status, int error)
    1118 {
    1119     int i;
    1120     write_tfer_done_arg_t *wtd_arg = arg;
    1121     blkdev_request *req = wtd_arg->req;
    1122     bdbuf_buffer **bd_buf_write_store = wtd_arg->write_store;
    1123     bdbuf_buffer *bd_buf;
    1124     for (i = 0;i < req->count;i++) {
    1125       bd_buf = bd_buf_write_store[i];
    1126       bd_buf->status = status;
    1127       bd_buf->error = RTEMS_IO_ERROR;
     1495rtems_bdbuf_read_done (void* arg, rtems_status_code status, int error)
     1496{
     1497  rtems_blkdev_request* req = (rtems_blkdev_request*) arg;
     1498
     1499  req->error = error;
     1500  req->status = status;
     1501
     1502  rtems_event_send (req->io_task, RTEMS_BDBUF_TRANSFER_SYNC);
     1503}
     1504
     1505/**
     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
     1517rtems_status_code
     1518rtems_bdbuf_read (dev_t                device,
     1519                  rtems_blkdev_bnum    block,
     1520                  rtems_bdbuf_buffer** bdp)
     1521{
     1522  rtems_disk_device*    dd;
     1523  rtems_bdbuf_pool*     pool;
     1524  rtems_bdbuf_buffer*   bd = NULL;
     1525  int                   read_ahead_count;
     1526  rtems_blkdev_request* req;
     1527 
     1528  /*
     1529   * @todo This type of request structure is wrong and should be removed.
     1530   */
     1531#define bdbuf_alloc(size) __builtin_alloca (size)
     1532
     1533  req = bdbuf_alloc (sizeof (rtems_blkdev_request) +
     1534                     (sizeof ( rtems_blkdev_sg_buffer) *
     1535                      rtems_bdbuf_configuration.max_read_ahead_blocks));
     1536
     1537  /*
     1538   * Do not hold the pool lock when obtaining the disk table.
     1539   */
     1540  dd = rtems_disk_obtain (device);
     1541  if (dd == NULL)
     1542    return RTEMS_INVALID_ID;
     1543
     1544  block += dd->start;
     1545 
     1546#if RTEMS_BDBUF_TRACE
     1547  rtems_bdbuf_printf ("read: %d (dev = %08x)\n", block, device);
     1548#endif
     1549 
     1550  if (block >= dd->size)
     1551  {
     1552    rtems_disk_release(dd);
     1553    return RTEMS_INVALID_NUMBER;
     1554  }
     1555
     1556  req->count = 0;
     1557  req->bufnum = 0;
     1558
     1559  /*
     1560   * Read the block plus the required number of blocks ahead. The number of
     1561   * blocks to read ahead is configured by the user and limited by the size of
     1562   * the disk or reaching a read ahead block that is also cached.
     1563   *
     1564   * Limit the blocks read by the size of the disk.
     1565   */
     1566  if ((rtems_bdbuf_configuration.max_read_ahead_blocks + block) < dd->size)
     1567    read_ahead_count = rtems_bdbuf_configuration.max_read_ahead_blocks;
     1568  else
     1569    read_ahead_count = dd->size - block;
     1570
     1571  pool = rtems_bdbuf_get_pool (dd->phys_dev->pool);
     1572
     1573  rtems_bdbuf_lock_pool (pool);
     1574
     1575  while (req->count < read_ahead_count)
     1576  {
     1577    /*
     1578     * Get the buffer for the requested block. If the block is cached then
     1579     * return it. If it is not cached transfer the block from the disk media
     1580     * into memory.
     1581     *
     1582     * We need to clean up any buffers allocated and not passed back to the
     1583     * caller.
     1584     */
     1585    bd = rtems_bdbuf_get_buffer (dd->phys_dev, pool,
     1586                                 block + req->count,
     1587                                 req->count == 0 ? FALSE : TRUE);
     1588
     1589    /*
     1590     * Read ahead buffer is in the cache or none available. Read what we
     1591     * can.
     1592     */
     1593    if (!bd)
     1594      break;
     1595
     1596    /*
     1597     * Is the block we are interested in the cache ?
     1598     */
     1599    if ((bd->state == RTEMS_BDBUF_STATE_CACHED) ||
     1600        (bd->state == RTEMS_BDBUF_STATE_MODIFIED))
     1601      break;
     1602
     1603    bd->state = RTEMS_BDBUF_STATE_TRANSFER;
     1604    bd->error = 0;
     1605
     1606    /*
     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.
     1614     */
     1615    req->bufs[req->count].user   = bd;
     1616    req->bufs[req->count].block  = bd->block;
     1617    req->bufs[req->count].length = dd->block_size;
     1618    req->bufs[req->count].buffer = bd->buffer;
     1619    req->count++;
     1620    req->bufnum++;
     1621  }
     1622
     1623  /*
     1624   * Transfer any requested buffers. If the request count is 0 we have found
     1625   * the block in the cache so return it.
     1626   */
     1627  if (req->count)
     1628  {
     1629    /*
     1630     * Unlock the pool. We have the buffer for the block and it will be in the
     1631     * access or transfer state. We may also have a number of read ahead blocks
     1632     * if we need to transfer data. At this point any other threads can gain
     1633     * access to the pool and if they are after any of the buffers we have they
     1634     * will block and be woken when the buffer is returned to the pool.
     1635     *
     1636     * If a transfer is needed the I/O operation will occur with pre-emption
     1637     * enabled and the pool unlocked. This is a change to the previous version
     1638     * of the bdbuf code.
     1639     */
     1640    int result;
     1641    int b;
     1642   
     1643    rtems_bdbuf_unlock_pool (pool);
     1644
     1645    req->req = RTEMS_BLKDEV_REQ_READ;
     1646    req->req_done = rtems_bdbuf_read_done;
     1647    req->done_arg = req;
     1648    req->io_task = rtems_task_self ();
     1649    req->status = RTEMS_RESOURCE_IN_USE;
     1650    req->error = 0;
     1651    req->start = dd->start;
     1652 
     1653    result = dd->ioctl (dd->phys_dev->dev, RTEMS_BLKIO_REQUEST, req);
     1654
     1655    /*
     1656     * Inspection of the DOS FS code shows the result from this function is
     1657     * handled and a buffer must be returned.
     1658     */
     1659    if (result < 0)
     1660    {
     1661      req->error = errno;
     1662      req->status = RTEMS_IO_ERROR;
     1663    }
     1664    else
     1665    {
     1666      rtems_status_code sc;
     1667      rtems_event_set   out;
     1668      sc = rtems_event_receive (RTEMS_BDBUF_TRANSFER_SYNC,
     1669                                RTEMS_EVENT_ALL | RTEMS_WAIT,
     1670                                0, &out);
     1671
     1672      if (sc != RTEMS_SUCCESSFUL)
     1673        rtems_fatal_error_occurred (BLKDEV_FATAL_BDBUF_SWAPOUT_RE);
     1674    }
     1675
     1676    rtems_bdbuf_lock_pool (pool);
     1677
     1678    for (b = 1; b < req->count; b++)
     1679    {
     1680      bd = req->bufs[b].user;
     1681      bd->error = req->error;
     1682      bd->state = RTEMS_BDBUF_STATE_READ_AHEAD;
     1683      rtems_bdbuf_release (bd);
     1684    }
     1685
     1686    bd = req->bufs[0].user;
     1687  }
     1688
     1689  /*
     1690   * The data for this block is cached in the buffer.
     1691   */
     1692  if (bd->state == RTEMS_BDBUF_STATE_MODIFIED)
     1693    bd->state = RTEMS_BDBUF_STATE_ACCESS_MODIFIED;
     1694  else
     1695    bd->state = RTEMS_BDBUF_STATE_ACCESS;
     1696
     1697  rtems_bdbuf_unlock_pool (pool);
     1698  rtems_disk_release (dd);
     1699
     1700  *bdp = bd;
     1701
     1702  return RTEMS_SUCCESSFUL;
     1703}
     1704
     1705/**
     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
     1718rtems_status_code
     1719rtems_bdbuf_release (rtems_bdbuf_buffer* bd)
     1720{
     1721  rtems_bdbuf_pool* pool;
     1722
     1723  if (bd == NULL)
     1724    return RTEMS_INVALID_ADDRESS;
     1725
     1726  pool = rtems_bdbuf_get_pool (bd->pool);
     1727
     1728  rtems_bdbuf_lock_pool (pool);
     1729
     1730#if RTEMS_BDBUF_TRACE
     1731  rtems_bdbuf_printf ("release: %d\n", bd->block);
     1732#endif
     1733 
     1734  if (bd->state == RTEMS_BDBUF_STATE_ACCESS_MODIFIED)
     1735  {
     1736    rtems_bdbuf_append_modified (pool, bd);
     1737  }
     1738  else
     1739  {
     1740    /*
     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.
     1744     */
     1745    if (bd->state == RTEMS_BDBUF_STATE_READ_AHEAD)
     1746      rtems_chain_prepend (&pool->ready, &bd->link);
     1747    else
     1748    {
     1749      bd->state = RTEMS_BDBUF_STATE_CACHED;
     1750      rtems_chain_append (&pool->lru, &bd->link);
     1751    }
     1752  }
     1753 
     1754  /*
     1755   * If there are threads waiting to access the buffer wake them. Wake any
     1756   * waiters if this is the first buffer to placed back onto the queue.
     1757   */
     1758  if (bd->waiters)
     1759    rtems_bdbuf_wake (pool->access, &pool->access_waiters);
     1760  else
     1761  {
     1762    if (bd->state == RTEMS_BDBUF_STATE_READ_AHEAD)
     1763    {
     1764      if (rtems_chain_has_only_one_node (&pool->ready))
     1765        rtems_bdbuf_wake (pool->waiting, &pool->wait_waiters);
     1766    }
     1767    else
     1768    {
     1769      if (rtems_chain_has_only_one_node (&pool->lru))
     1770        rtems_bdbuf_wake (pool->waiting, &pool->wait_waiters);
     1771    }
     1772  }
     1773 
     1774  rtems_bdbuf_unlock_pool (pool);
     1775
     1776  return RTEMS_SUCCESSFUL;
     1777}
     1778
     1779/**
     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
     1792rtems_status_code
     1793rtems_bdbuf_release_modified (rtems_bdbuf_buffer* bd)
     1794{
     1795  rtems_bdbuf_pool* pool;
     1796
     1797  if (bd == NULL)
     1798    return RTEMS_INVALID_ADDRESS;
     1799
     1800  pool = rtems_bdbuf_get_pool (bd->pool);
     1801
     1802  rtems_bdbuf_lock_pool (pool);
     1803
     1804#if RTEMS_BDBUF_TRACE
     1805  rtems_bdbuf_printf ("release modified: %d\n", bd->block);
     1806#endif
     1807
     1808  bd->hold_timer = rtems_bdbuf_configuration.swap_block_hold;
     1809 
     1810  rtems_bdbuf_append_modified (pool, bd);
     1811
     1812  if (bd->waiters)
     1813    rtems_bdbuf_wake (pool->access, &pool->access_waiters);
     1814 
     1815  rtems_bdbuf_unlock_pool (pool);
     1816
     1817  return RTEMS_SUCCESSFUL;
     1818}
     1819
     1820/**
     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.
     1826 *
     1827 * @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
     1837rtems_status_code
     1838rtems_bdbuf_sync (rtems_bdbuf_buffer* bd)
     1839{
     1840  rtems_bdbuf_pool* pool;
     1841  boolean           available;
     1842
     1843#if RTEMS_BDBUF_TRACE
     1844  rtems_bdbuf_printf ("sync: %d\n", bd->block);
     1845#endif
     1846 
     1847  if (bd == NULL)
     1848    return RTEMS_INVALID_ADDRESS;
     1849
     1850  pool = rtems_bdbuf_get_pool (bd->pool);
     1851
     1852  rtems_bdbuf_lock_pool (pool);
     1853
     1854  bd->state = RTEMS_BDBUF_STATE_SYNC;
     1855
     1856  rtems_chain_append (&pool->sync, &bd->link);
     1857
     1858  rtems_bdbuf_wake_swapper ();
     1859
     1860  available = FALSE;
     1861  while (!available)
     1862  {
     1863    switch (bd->state)
     1864    {
     1865      case RTEMS_BDBUF_STATE_CACHED:
     1866      case RTEMS_BDBUF_STATE_READ_AHEAD:
     1867      case RTEMS_BDBUF_STATE_MODIFIED:
     1868      case RTEMS_BDBUF_STATE_ACCESS:
     1869      case RTEMS_BDBUF_STATE_ACCESS_MODIFIED:
     1870        available = TRUE;
     1871        break;
     1872
     1873      case RTEMS_BDBUF_STATE_SYNC:
     1874      case RTEMS_BDBUF_STATE_TRANSFER:
     1875        bd->waiters++;
     1876        rtems_bdbuf_wait (pool, &pool->transfer, &pool->transfer_waiters);
     1877        bd->waiters--;
     1878        break;
     1879
     1880      default:
     1881        rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_CONSISTENCY);
     1882    }
     1883  }
     1884
     1885  rtems_bdbuf_unlock_pool (pool);
     1886 
     1887  return RTEMS_SUCCESSFUL;
     1888}
     1889
     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)
     1900 */
     1901rtems_status_code
     1902rtems_bdbuf_syncdev (dev_t dev)
     1903{
     1904  rtems_disk_device*  dd;
     1905  rtems_bdbuf_pool*   pool;
     1906  rtems_status_code   sc;
     1907  rtems_event_set     out;
     1908
     1909#if RTEMS_BDBUF_TRACE
     1910  rtems_bdbuf_printf ("syncdev: %08x\n", dev);
     1911#endif
     1912
     1913  /*
     1914   * Do not hold the pool lock when obtaining the disk table.
     1915   */
     1916  dd = rtems_disk_obtain (dev);
     1917  if (dd == NULL)
     1918    return RTEMS_INVALID_ID;
     1919
     1920  pool = rtems_bdbuf_get_pool (dd->pool);
     1921
     1922  /*
     1923   * Take the sync lock before locking the pool. Once we have the sync lock
     1924   * we can lock the pool. If another thread has the sync lock it will cause
     1925   * this thread to block until it owns the sync lock then it can own the
     1926   * pool. The sync lock can only be obtained with the pool unlocked.
     1927   */
     1928 
     1929  rtems_bdbuf_lock_sync (pool);
     1930  rtems_bdbuf_lock_pool (pool); 
     1931
     1932  pool->sync_active    = TRUE;
     1933  pool->sync_requester = rtems_task_self ();
     1934  pool->sync_device    = dev;
     1935 
     1936  rtems_bdbuf_wake_swapper ();
     1937  rtems_bdbuf_unlock_pool (pool);
     1938 
     1939  sc = rtems_event_receive (RTEMS_BDBUF_TRANSFER_SYNC,
     1940                            RTEMS_EVENT_ALL | RTEMS_WAIT,
     1941                            0, &out);
     1942
     1943  if (sc != RTEMS_SUCCESSFUL)
     1944    rtems_fatal_error_occurred (BLKDEV_FATAL_BDBUF_SWAPOUT_RE);
    11281945     
    1129       bd_buf->in_progress = FALSE;
    1130       _CORE_mutex_Surrender(&bd_buf->transfer_sema, 0, NULL);
    1131       _CORE_mutex_Flush(&bd_buf->transfer_sema, NULL,
    1132                         CORE_MUTEX_STATUS_SUCCESSFUL);
    1133     }
    1134 }
    1135 
    1136 /* bdbuf_read_transfer_done --
     1946  rtems_bdbuf_lock_pool (pool);
     1947
     1948  pool->sync_active = FALSE;
     1949
     1950  rtems_bdbuf_unlock_sync (pool);
     1951  rtems_bdbuf_unlock_pool (pool);
     1952 
     1953  return rtems_disk_release(dd);
     1954}
     1955
     1956/* bdbuf_write_transfer_done --
    11371957 *     Callout function. Invoked by block device driver when data transfer
    1138  *     from device (read) is completed. This function may be invoked from
     1958 *     to device (write) is completed. This function may be invoked from
    11391959 *     interrupt handler.
    11401960 *
     
    11501970 */
    11511971static void
    1152 bdbuf_read_transfer_done(void *arg, rtems_status_code status, int error)
    1153 {
    1154 #if defined(READ_MULTIPLE) 
    1155  
    1156   read_ahead_bd_buf_group *bd_buf_group = arg;
    1157   bdbuf_buffer *bd_buf;
    1158   int i;
    1159   for (i = 0;i < bd_buf_group->cnt;i++) {
    1160     bd_buf = bd_buf_group->bd_bufs[i];
    1161 
    1162     bd_buf->status = status;
    1163     bd_buf->error = RTEMS_IO_ERROR;
    1164     _CORE_mutex_Surrender(&bd_buf->transfer_sema, 0, NULL);
    1165     _CORE_mutex_Flush(&bd_buf->transfer_sema, NULL,
    1166                       CORE_MUTEX_STATUS_SUCCESSFUL);
    1167   }
    1168 #else
    1169     bdbuf_buffer *bd_buf = arg;
    1170     bd_buf->status = status;
    1171     bd_buf->error = RTEMS_IO_ERROR;
    1172     _CORE_mutex_Surrender(&bd_buf->transfer_sema, 0, NULL);
    1173     _CORE_mutex_Flush(&bd_buf->transfer_sema, NULL,
    1174                       CORE_MUTEX_STATUS_SUCCESSFUL);
    1175 #endif
    1176 }
    1177 
    1178 /* rtems_bdbuf_read --
    1179  *     (Similar to the rtems_bdbuf_get, except reading data from media)
    1180  *     Obtain block buffer. If specified block already cached, return address
    1181  *     of appropriate buffer and increment reference counter to 1. If block is
    1182  *     not cached, allocate new buffer and read data to it from the media.
    1183  *     This primitive may be blocked on waiting until data to be read from
    1184  *     media, if there are no free buffer descriptors available and there are
    1185  *     no unused non-modified (or synchronized with media) buffers available.
    1186  *
    1187  * PARAMETERS:
    1188  *     device - device number (consists of major and minor device number)
    1189  *     block  - linear media block number
    1190  *     bd     - address of variable to store pointer to the buffer descriptor
    1191  *
    1192  * RETURNS:
    1193  *     RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
    1194  *     or error code if error is occured)
    1195  *
    1196  * SIDE EFFECTS:
    1197  *     bufget_sema and transfer_sema semaphores obtained by this primitive.
    1198  */
    1199 #if !defined(READ_MULTIPLE)
    1200 rtems_status_code
    1201 rtems_bdbuf_read(dev_t device,
    1202                  blkdev_bnum block,
    1203                  bdbuf_buffer **bd)
    1204 {
    1205     preemption_key key;
    1206     ISR_Level level;
    1207 
    1208     bdbuf_buffer *bd_buf;
    1209     rtems_status_code rc;
    1210     int result;
    1211     disk_device *dd;
    1212     disk_device *pdd;
    1213     blkdev_request1 req;
    1214 
    1215     dd = rtems_disk_lookup(device);
    1216     if (dd == NULL)
    1217         return RTEMS_INVALID_ID;
    1218 
    1219     if (block >= dd->size)
    1220     {
    1221         rtems_disk_release(dd);
    1222         return RTEMS_INVALID_NUMBER;
    1223     }
    1224 
    1225     pdd = dd->phys_dev;
    1226     block += dd->start;
    1227 
    1228     DISABLE_PREEMPTION(key);
    1229     rc = find_or_assign_buffer(pdd, block, &bd_buf);
    1230 
    1231     if (rc != RTEMS_SUCCESSFUL)
    1232     {
    1233         ENABLE_PREEMPTION(key);
    1234         rtems_disk_release(dd);
    1235         return rc;
    1236     }
    1237 
    1238     if (!bd_buf->actual)
    1239     {
    1240         bd_buf->in_progress = 1;
    1241 
    1242         req.req.req = BLKDEV_REQ_READ;
    1243         req.req.req_done = bdbuf_read_transfer_done;
    1244         req.req.done_arg = bd_buf;
    1245         req.req.start = block;
    1246         req.req.count = 1;
    1247         req.req.bufnum = 1;
    1248         req.req.bufs[0].length = dd->block_size;
    1249         req.req.bufs[0].buffer = bd_buf->buffer;
    1250 
    1251         bdbuf_initialize_transfer_sema(bd_buf);
    1252         result = dd->ioctl(pdd->dev, BLKIO_REQUEST, &req);
    1253         if (result == -1)
     1972rtems_bdbuf_write_done(void *arg, rtems_status_code status, int error)
     1973{
     1974  rtems_blkdev_request* req = (rtems_blkdev_request*) arg;
     1975
     1976  req->error = error;
     1977  req->status = status;
     1978
     1979  rtems_event_send (req->io_task, RTEMS_BDBUF_TRANSFER_SYNC);
     1980}
     1981
     1982/**
     1983 * Process the modified list of buffers. We can have a sync or modified
     1984 * list that needs to be handled.
     1985 */
     1986static void
     1987rtems_bdbuf_swapout_modified_processing (rtems_bdpool_id      pid,
     1988                                         dev_t*               dev,
     1989                                         rtems_chain_control* chain,
     1990                                         rtems_chain_control* transfer,
     1991                                         boolean              sync_active,
     1992                                         boolean              update_timers,
     1993                                         uint32_t             timer_delta)
     1994{
     1995  if (!rtems_chain_is_empty (chain))
     1996  {
     1997    rtems_chain_node* node = rtems_chain_head (chain);
     1998    node = node->next;
     1999
     2000    while (!rtems_chain_is_tail (chain, node))
     2001    {
     2002      rtems_bdbuf_buffer* bd = (rtems_bdbuf_buffer*) node;
     2003   
     2004      if (bd->pool == pid)
     2005      {
     2006        /*
     2007         * Check if the buffer's hold timer has reached 0. If a sync
     2008         * is active force all the timers to 0.
     2009         *
     2010         * @note Lots of sync requests will skew this timer. It should
     2011         *       be based on TOD to be accurate. Does it matter ?
     2012         */
     2013        if (sync_active)
     2014          bd->hold_timer = 0;
     2015 
     2016        if (bd->hold_timer)
    12542017        {
    1255             bd_buf->status = RTEMS_IO_ERROR;
    1256             bd_buf->error = errno;
    1257             bd_buf->actual = FALSE;
     2018          if (update_timers)
     2019          {
     2020            if (bd->hold_timer > timer_delta)
     2021              bd->hold_timer -= timer_delta;
     2022            else
     2023              bd->hold_timer = 0;
     2024          }
     2025
     2026          if (bd->hold_timer)
     2027          {
     2028            node = node->next;
     2029            continue;
     2030          }
     2031        }
     2032
     2033        /*
     2034         * 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.
     2037         */
     2038        if (*dev == -1)
     2039          *dev = bd->dev;
     2040
     2041        if (bd->dev == *dev)
     2042        {
     2043          rtems_chain_node* next_node = node->next;
     2044          rtems_chain_extract (node);
     2045          rtems_chain_append (transfer, node);
     2046          node = next_node;
     2047          bd->state = RTEMS_BDBUF_STATE_TRANSFER;
    12582048        }
    12592049        else
    12602050        {
    1261             rtems_interrupt_disable(level);
    1262             _CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE,
    1263                               WATCHDOG_NO_TIMEOUT, level);
    1264             bd_buf->actual = TRUE;
     2051          node = node->next;
    12652052        }
    1266         bd_buf->in_progress = FALSE;
    1267     }
    1268     rtems_disk_release(dd);
    1269 
    1270     ENABLE_PREEMPTION(key);
    1271 
    1272     *bd = bd_buf;
    1273            
    1274     return RTEMS_SUCCESSFUL;
    1275 }
    1276 #else /* READ_MULTIPLE */
    1277 rtems_status_code
    1278 rtems_bdbuf_read(dev_t device,
    1279                  blkdev_bnum block,
    1280                  bdbuf_buffer **bd)
    1281 {
    1282     preemption_key key;
    1283     ISR_Level level;
    1284 
    1285     bdbuf_buffer *bd_buf,*first_bd_buf;
    1286     rtems_status_code rc;
    1287     int result;
    1288     disk_device *dd;
    1289     disk_device *pdd;
    1290     blkdev_request_read_ahead req;
    1291     read_ahead_bd_buf_group bd_buf_group;
    1292     boolean find_more_buffers;
    1293     int i;
    1294 
    1295     dd = rtems_disk_lookup(device);
     2053      }
     2054    }
     2055  }
     2056}
     2057
     2058/**
     2059 * Process the pool.
     2060 */
     2061static boolean
     2062rtems_bdbuf_swapout_pool_processing (rtems_bdpool_id       pid,
     2063                                     unsigned long         timer_delta,
     2064                                     boolean               update_timers,
     2065                                     rtems_blkdev_request* write_req)
     2066{
     2067  rtems_bdbuf_pool*   pool = rtems_bdbuf_get_pool (pid);
     2068  rtems_chain_control transfer;
     2069  dev_t               dev = -1;
     2070  rtems_disk_device*  dd;
     2071  boolean             result = TRUE;
     2072
     2073  rtems_chain_initialize_empty (&transfer);
     2074   
     2075  rtems_bdbuf_lock_pool (pool);
     2076
     2077  if (pool->sync_active)
     2078    dev = pool->sync_device;
     2079
     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.
     2085   */
     2086  rtems_bdbuf_swapout_modified_processing (pid, &dev,
     2087                                           &pool->sync, &transfer,
     2088                                           TRUE, FALSE,
     2089                                           timer_delta);
     2090
     2091  /*
     2092   * Process the pool's modified list.
     2093   */
     2094  rtems_bdbuf_swapout_modified_processing (pid, &dev,
     2095                                           &pool->modified, &transfer,
     2096                                           pool->sync_active,
     2097                                           update_timers,
     2098                                           timer_delta);
     2099
     2100  /*
     2101   * We have all the buffers that have been modified for this device so
     2102   * the pool can be unlocked because the state is set to TRANSFER.
     2103   */
     2104#endif
     2105  rtems_bdbuf_unlock_pool (pool);
     2106
     2107  /*
     2108   * If there are buffers to transfer to the media tranfer them.
     2109   */
     2110  if (rtems_chain_is_empty (&transfer))
     2111    result = FALSE;
     2112  else
     2113  {
     2114    /*
     2115     * Obtain the disk device. Release the pool mutex to avoid a dead
     2116     * lock.
     2117     */
     2118    dd = rtems_disk_obtain (dev);
    12962119    if (dd == NULL)
    1297         return RTEMS_INVALID_ID;
    1298      
    1299     if (block >= dd->size)
    1300     {
    1301         rtems_disk_release(dd);
    1302         return RTEMS_INVALID_NUMBER;
    1303     }
    1304    
    1305     pdd = dd->phys_dev;
    1306     block += dd->start;
    1307 
    1308     DISABLE_PREEMPTION(key);
    1309     rc = find_or_assign_buffer(pdd, block, &first_bd_buf);
    1310 
    1311     if (rc != RTEMS_SUCCESSFUL)
    1312     {
    1313         ENABLE_PREEMPTION(key);
    1314         rtems_disk_release(dd);
    1315         return rc;
    1316     }
    1317     if (!first_bd_buf->actual)
    1318     {
    1319 
    1320         bd_buf_group.bd_bufs[0] = first_bd_buf;
    1321         bd_buf_group.cnt = 1;
    1322 
    1323         first_bd_buf->in_progress = TRUE;
    1324 
    1325         req.req.req = BLKDEV_REQ_READ;
    1326         req.req.req_done = bdbuf_read_transfer_done;
    1327         req.req.done_arg = &bd_buf_group;
    1328         req.req.start = block;
    1329         req.req.count = 1;
    1330         req.req.bufnum = 1;
    1331         req.req.bufs[0].length = dd->block_size;
    1332         req.req.bufs[0].buffer = first_bd_buf->buffer;
     2120      result = FALSE;
     2121    else
     2122    {
     2123      /*
     2124       * The last block number used when the driver only supports
     2125       * continuous blocks in a single request.
     2126       */
     2127      uint32_t last_block = 0;
     2128     
     2129      /*
     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.
     2137       */
     2138
     2139      write_req->status = RTEMS_RESOURCE_IN_USE;
     2140      write_req->start = dd->start;
     2141      write_req->error = 0;
     2142      write_req->count = 0;
     2143      write_req->bufnum = 0;
     2144
     2145      while (!rtems_chain_is_empty (&transfer))
     2146      {
     2147        rtems_bdbuf_buffer* bd =
     2148          (rtems_bdbuf_buffer*) rtems_chain_get (&transfer);
     2149
     2150        boolean write = FALSE;
    13332151       
    1334         bdbuf_initialize_transfer_sema(first_bd_buf);
    1335         /*
    1336          * FIXME: check for following blocks to be:
    1337          *   - still in range of partition size
    1338          *   - not yet assigned
    1339          *   - buffer available
    1340          * allocate for read call, if possible
    1341          */
    1342         find_more_buffers = TRUE;
    1343         while (find_more_buffers) {       
    1344           block++;
    1345           /*
    1346            * still bd_buf_group entries free and
    1347            * still in range of this disk?
    1348            */
    1349           if ((bd_buf_group.cnt >= READ_AHEAD_MAX_BLK_CNT) ||
    1350               (block >= dd->size)) {
    1351             find_more_buffers = FALSE;
    1352           }
    1353           if (find_more_buffers) {
    1354             rc = find_or_assign_buffer(pdd, block, &bd_buf);
    1355             if (rc != RTEMS_SUCCESSFUL) {
    1356               find_more_buffers = FALSE;
    1357             }     
    1358             else if (bd_buf->actual) {
    1359               find_more_buffers = FALSE;
    1360           bdbuf_release(bd_buf);
    1361             }     
    1362           }
    1363           if (find_more_buffers) {
    1364             bdbuf_initialize_transfer_sema(bd_buf);
    1365             bd_buf->in_progress = TRUE;
    1366 
    1367             req.req.bufs[req.req.count].length = dd->block_size;
    1368             req.req.bufs[req.req.count].buffer = bd_buf->buffer;
    1369             req.req.count++;
    1370             req.req.bufnum++;
    1371             bd_buf_group.bd_bufs[bd_buf_group.cnt] = bd_buf;
    1372             bd_buf_group.cnt++;
    1373           }
    1374         }           
    1375 
    1376         /* do the actual read call here
    1377          */
    1378         result = dd->ioctl(pdd->dev, BLKIO_REQUEST, &req);
    1379 
    1380         /*
    1381          * cleanup:
    1382          * wait, until all bd_bufs are processed
    1383          * set status in all bd_bufs
    1384          */
    1385         for (i = 0;i < bd_buf_group.cnt;i++) {
    1386           bd_buf = bd_buf_group.bd_bufs[i];
    1387           if (result == -1)
    1388             {
    1389               bd_buf->status = RTEMS_IO_ERROR;
    1390               bd_buf->error = errno;
    1391               bd_buf->actual = FALSE;
    1392             }
    1393           else
    1394             {
    1395               rtems_interrupt_disable(level);
    1396               _CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE,
    1397                                 WATCHDOG_NO_TIMEOUT, level);
    1398               bd_buf->actual = TRUE;
    1399             }   
    1400           bd_buf->in_progress = FALSE;
    1401           /* release any pre-read buffers */
    1402           if (i > 0) {
    1403             bdbuf_release(bd_buf);
    1404           }
    1405         }
    1406     }
    1407     rtems_disk_release(dd);
    1408    
    1409     ENABLE_PREEMPTION(key);
    1410 
    1411     *bd = first_bd_buf;
    1412            
    1413     return RTEMS_SUCCESSFUL;
    1414 }
    1415 #endif /* READ_MULTIPLE */
    1416 
    1417 
    1418 /* bdbuf_release --
    1419  *     Release buffer. Decrease buffer usage counter. If it is zero, further
    1420  *     processing depends on modified attribute. If buffer was modified, it
    1421  *     is inserted into mod chain and swapout task waken up. If buffer was
    1422  *     not modified, it is returned to the end of lru chain making it available
    1423  *     for further use.
    1424  *
    1425  * PARAMETERS:
    1426  *     bd_buf - pointer to the released buffer descriptor.
    1427  *
    1428  * RETURNS:
    1429  *     RTEMS_SUCCESSFUL if buffer released successfully, or error code if
    1430  *     error occured.
    1431  *
    1432  * NOTE:
    1433  *     This is internal function. It is assumed that task made non-preemptive
    1434  *     before its invocation.
    1435  */
    1436 static rtems_status_code
    1437 bdbuf_release(bdbuf_buffer *bd_buf)
    1438 {
    1439     bdbuf_pool *bd_pool;
    1440     rtems_status_code rc = RTEMS_SUCCESSFUL;
    1441 
    1442     if (bd_buf->use_count <= 0)
    1443         return RTEMS_INTERNAL_ERROR;
    1444 
    1445     bd_pool = rtems_bdbuf_ctx.pool + bd_buf->pool;
    1446 
    1447     bd_buf->use_count--;
    1448 
    1449     if (bd_buf->use_count == 0)
    1450     {
    1451         if (bd_buf->modified)
     2152        /*
     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.
     2158         */
     2159       
     2160        if ((dd->capabilities & RTEMS_BLKDEV_CAP_MULTISECTOR_CONT) &&
     2161            write_req->count &&
     2162            (bd->block != (last_block + 1)))
    14522163        {
    1453 
    1454             /* Buffer was modified. Insert buffer to the modified buffers
    1455              * list and initiate flushing. */
    1456             rtems_chain_append(&rtems_bdbuf_ctx.mod, &bd_buf->link);
    1457 
    1458             /* Release the flush_sema */
    1459             rc = rtems_semaphore_release(rtems_bdbuf_ctx.flush_sema);
     2164          rtems_chain_prepend (&transfer, &bd->link);
     2165          write = TRUE;
    14602166        }
    14612167        else
    14622168        {
    1463             /* Buffer was not modified. Add this descriptor to the
    1464              * end of lru chain and make it available for reuse. */
    1465             rtems_chain_append(&bd_pool->lru, &bd_buf->link);
    1466             rc = rtems_semaphore_release(bd_pool->bufget_sema);
     2169          write_req->bufs[write_req->count].user   = bd;
     2170          write_req->bufs[write_req->count].block  = bd->block;
     2171          write_req->bufs[write_req->count].length = dd->block_size;
     2172          write_req->bufs[write_req->count].buffer = bd->buffer;
     2173          write_req->count++;
     2174          write_req->bufnum++;
     2175          last_block = bd->block;
    14672176        }
    1468     }
    1469     return rc;
    1470 }
    1471 
    1472 
    1473 /* rtems_bdbuf_release --
    1474  *     Release buffer allocated before. This primitive decrease the
    1475  *     usage counter. If it is zero, further destiny of buffer depends on
    1476  *     'modified' status. If buffer was modified, it is placed to the end of
    1477  *     mod list and flush task waken up. If buffer was not modified,
    1478  *     it is placed to the end of lru list, and bufget_sema released, allowing
    1479  *     to reuse this buffer.
    1480  *
    1481  * PARAMETERS:
    1482  *     bd_buf - pointer to the bdbuf_buffer structure previously obtained using
    1483  *              get/read primitive.
    1484  *
    1485  * RETURNS:
    1486  *     RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
    1487  *     or error code if error is occured)
    1488  *
    1489  * SIDE EFFECTS:
    1490  *     flush_sema and bufget_sema semaphores may be released by this primitive.
    1491  */
    1492 rtems_status_code
    1493 rtems_bdbuf_release(bdbuf_buffer *bd_buf)
    1494 {
    1495     preemption_key key;
    1496     rtems_status_code rc = RTEMS_SUCCESSFUL;
    1497 
    1498     if (bd_buf == NULL)
    1499         return RTEMS_INVALID_ADDRESS;
    1500 
    1501     DISABLE_PREEMPTION(key);
    1502 
    1503     rc = bdbuf_release(bd_buf);
    1504 
    1505     ENABLE_PREEMPTION(key);
    1506 
    1507     return rc;
    1508 }
    1509 
    1510 /* rtems_bdbuf_release_modified --
    1511  *     Release buffer allocated before, assuming that it is _modified_ by
    1512  *     it's owner. This primitive decrease usage counter for buffer, mark
    1513  *     buffer descriptor as modified. If usage counter is 0, insert it at
    1514  *     end of mod chain and release flush_sema semaphore to activate the
    1515  *     flush task.
    1516  *
    1517  * PARAMETERS:
    1518  *     bd_buf - pointer to the bdbuf_buffer structure previously obtained using
    1519  *              get/read primitive.
    1520  *
    1521  * RETURNS:
    1522  *     RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
    1523  *     or error code if error is occured)
    1524  *
    1525  * SIDE EFFECTS:
    1526  *     flush_sema semaphore may be released by this primitive.
    1527  */
    1528 rtems_status_code
    1529 rtems_bdbuf_release_modified(bdbuf_buffer *bd_buf)
    1530 {
    1531     preemption_key key;
    1532     rtems_status_code rc = RTEMS_SUCCESSFUL;
    1533 
    1534     if (bd_buf == NULL)
    1535         return RTEMS_INVALID_ADDRESS;
    1536 
    1537     DISABLE_PREEMPTION(key);
    1538 
    1539     if (!bd_buf->modified)
    1540     {
    1541         bdbuf_initialize_transfer_sema(bd_buf);
    1542     }
    1543     bd_buf->modified = TRUE;
    1544     bd_buf->actual = TRUE;
    1545     rc = bdbuf_release(bd_buf);
    1546 
    1547     ENABLE_PREEMPTION(key);
    1548 
    1549     return rc;
    1550 }
    1551 
    1552 /* rtems_bdbuf_sync --
    1553  *     Wait until specified buffer synchronized with disk. Invoked on exchanges
    1554  *     critical for data consistency on the media. This primitive mark owned
    1555  *     block as modified, decrease usage counter. If usage counter is 0,
    1556  *     block inserted to the mod chain and flush_sema semaphore released.
    1557  *     Finally, primitives blocked on transfer_sema semaphore.
    1558  *
    1559  * PARAMETERS:
    1560  *     bd_buf - pointer to the bdbuf_buffer structure previously obtained using
    1561  *              get/read primitive.
    1562  *
    1563  * RETURNS:
    1564  *     RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
    1565  *     or error code if error is occured)
    1566  *
    1567  * SIDE EFFECTS:
    1568  *     Primitive may be blocked on transfer_sema semaphore.
    1569  */
    1570 rtems_status_code
    1571 rtems_bdbuf_sync(bdbuf_buffer *bd_buf)
    1572 {
    1573     preemption_key key;
    1574     ISR_Level level;
    1575     rtems_status_code rc = RTEMS_SUCCESSFUL;
    1576 
    1577     if (bd_buf == NULL)
    1578         return RTEMS_INVALID_ADDRESS;
    1579 
    1580     DISABLE_PREEMPTION(key);
    1581 
    1582     if (!bd_buf->modified)
    1583     {
    1584         bdbuf_initialize_transfer_sema(bd_buf);
    1585     }
    1586     bd_buf->modified = TRUE;
    1587     bd_buf->actual = TRUE;
    1588 
    1589     rc = bdbuf_release(bd_buf);
    1590 
    1591     if (rc == RTEMS_SUCCESSFUL)
    1592     {
    1593         rtems_interrupt_disable(level);
    1594         _CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE,
    1595                           WATCHDOG_NO_TIMEOUT, level);
    1596     }
    1597 
    1598     ENABLE_PREEMPTION(key);
    1599 
    1600     return rc;
    1601 }
    1602 
    1603 /* rtems_bdbuf_syncdev --
    1604  *     Synchronize with disk all buffers containing the blocks belonging to
    1605  *     specified device.
    1606  *
    1607  * PARAMETERS:
    1608  *     dev - block device number
    1609  *
    1610  * RETURNS:
    1611  *     RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
    1612  *     or error code if error is occured)
    1613  */
    1614 rtems_status_code
    1615 rtems_bdbuf_syncdev(dev_t dev)
    1616 {
    1617     preemption_key key;
    1618     ISR_Level level;
    1619 
    1620     bdbuf_buffer *bd_buf;
    1621     disk_device *dd;
    1622     bdbuf_pool  *pool;
    1623 
    1624     dd = rtems_disk_lookup(dev);
    1625     if (dd == NULL)
    1626         return RTEMS_INVALID_ID;
    1627 
    1628     pool = rtems_bdbuf_ctx.pool + dd->pool;
    1629 
    1630     DISABLE_PREEMPTION(key);
    1631     do {
    1632         bd_buf = avl_search_for_sync(&pool->tree, dd);
    1633         if (bd_buf != NULL /* && bd_buf->modified */)
     2177
     2178        /*
     2179         * Perform the transfer if there are no more buffers, or the
     2180         * transfer size has reached the configured max. value.
     2181         */
     2182
     2183        if (rtems_chain_is_empty (&transfer) ||
     2184            (write_req->count >= rtems_bdbuf_configuration.max_write_blocks))
     2185          write = TRUE;
     2186
     2187        if (write)
    16342188        {
    1635             rtems_interrupt_disable(level);
    1636             _CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE,
    1637                               WATCHDOG_NO_TIMEOUT, level);
     2189          int result;
     2190          int b;
     2191
     2192          /*
     2193           * Perform the transfer. No pool locks, no preemption, only the
     2194           * disk device is being held.
     2195           */
     2196          result = dd->ioctl (dd->phys_dev->dev,
     2197                              RTEMS_BLKIO_REQUEST, write_req);
     2198
     2199          if (result < 0)
     2200          {
     2201            rtems_bdbuf_lock_pool (pool);
     2202             
     2203            for (b = 0; b < write_req->count; b++)
     2204            {
     2205              bd = write_req->bufs[b].user;
     2206              bd->state  = RTEMS_BDBUF_STATE_MODIFIED;
     2207              bd->error = errno;
     2208
     2209              /*
     2210               * Place back on the pools modified queue and try again.
     2211               *
     2212               * @warning Not sure this is the best option but I do
     2213               *          not know what else can be done.
     2214               */
     2215              rtems_chain_append (&pool->modified, &bd->link);
     2216            }
     2217          }
     2218          else
     2219          {
     2220            rtems_status_code sc = 0;
     2221            rtems_event_set   out;
     2222
     2223            sc = rtems_event_receive (RTEMS_BDBUF_TRANSFER_SYNC,
     2224                                      RTEMS_EVENT_ALL | RTEMS_WAIT,
     2225                                      0, &out);
     2226
     2227            if (sc != RTEMS_SUCCESSFUL)
     2228              rtems_fatal_error_occurred (BLKDEV_FATAL_BDBUF_SWAPOUT_RE);
     2229
     2230            rtems_bdbuf_lock_pool (pool);
     2231
     2232            for (b = 0; b < write_req->count; b++)
     2233            {
     2234              bd = write_req->bufs[b].user;
     2235              bd->state = RTEMS_BDBUF_STATE_CACHED;
     2236              bd->error = 0;
     2237
     2238              rtems_chain_append (&pool->lru, &bd->link);
     2239             
     2240              if (bd->waiters)
     2241                rtems_bdbuf_wake (pool->transfer, &pool->transfer_waiters);
     2242              else
     2243              {
     2244                if (rtems_chain_has_only_one_node (&pool->lru))
     2245                  rtems_bdbuf_wake (pool->waiting, &pool->wait_waiters);
     2246              }
     2247            }
     2248          }
     2249
     2250          rtems_bdbuf_unlock_pool (pool);
     2251
     2252          write_req->status = RTEMS_RESOURCE_IN_USE;
     2253          write_req->error = 0;
     2254          write_req->count = 0;
     2255          write_req->bufnum = 0;
    16382256        }
    1639     } while (bd_buf != NULL);
    1640     ENABLE_PREEMPTION(key);
    1641     return rtems_disk_release(dd);
    1642 }
    1643 
    1644 /* bdbuf_swapout_task --
    1645  *     Body of task which take care on flushing modified buffers to the
    1646  *     disk.
     2257      }
     2258         
     2259      rtems_disk_release (dd);
     2260    }
     2261  }
     2262
     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.
    16472271 */
    16482272static rtems_task
    1649 bdbuf_swapout_task(rtems_task_argument unused)
    1650 {
    1651     rtems_status_code rc;
    1652     int result;
    1653     int i;
    1654     ISR_Level level;
    1655     bdbuf_buffer *bd_buf;
    1656     bdbuf_buffer *nxt_bd_buf;
    1657     bdbuf_pool *bd_pool = NULL;
    1658     disk_device *dd = NULL;
    1659     struct {
    1660       blkdev_request   req;
    1661       blkdev_sg_buffer sg[SWAP_OUT_MAX_BLK_CNT];
    1662     } req;
    1663     write_tfer_done_arg_t write_tfer_done_arg;
     2273rtems_bdbuf_swapout_task (rtems_task_argument arg)
     2274{
     2275  rtems_bdbuf_context*  context = (rtems_bdbuf_context*) arg;
     2276  rtems_blkdev_request* write_req;
     2277  uint32_t              period_in_ticks;
     2278  const uint32_t        period_in_msecs = rtems_bdbuf_configuration.swapout_period;
     2279  uint32_t              timer_delta;
     2280  rtems_status_code     sc;
     2281
     2282  /*
     2283   * @note chrisj The rtems_blkdev_request and the array at the end is a hack.
     2284   * I am disappointment at finding code like this in RTEMS. The request should
     2285   * have been a rtems_chain_control. Simple, fast and less storage as the node
     2286   * is already part of the buffer structure.
     2287   */
     2288  write_req =
     2289    malloc (sizeof (rtems_blkdev_request) +
     2290            (rtems_bdbuf_configuration.max_write_blocks *
     2291             sizeof (rtems_blkdev_sg_buffer)));
     2292
     2293  if (!write_req)
     2294    rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_SO_NOMEM);
     2295
     2296  write_req->req = RTEMS_BLKDEV_REQ_WRITE;
     2297  write_req->req_done = rtems_bdbuf_write_done;
     2298  write_req->done_arg = write_req;
     2299  write_req->io_task = rtems_task_self ();
     2300
     2301  period_in_ticks = TOD_MICROSECONDS_TO_TICKS (period_in_msecs * 1000);
     2302
     2303  /*
     2304   * This is temporary. Needs to be changed to use the real clock.
     2305   */
     2306  timer_delta = period_in_msecs;
     2307
     2308  while (context->swapout_enabled)
     2309  {
     2310    rtems_event_set out;
    16642311
    16652312    /*
    1666      * provide info needed for write_transfer_done function
     2313     * Only update the timers once in the processing cycle.
    16672314     */
    1668     write_tfer_done_arg.req         = (blkdev_request *)&req.req;
    1669     write_tfer_done_arg.write_store =  bd_buf_write_store;
    1670     nxt_bd_buf = NULL;
    1671     while (1)
    1672     {
    1673         req.req.req = BLKDEV_REQ_WRITE;
    1674         req.req.req_done = bdbuf_write_transfer_done;
    1675         req.req.done_arg = &write_tfer_done_arg;
    1676         req.req.count = 0;
    1677         req.req.bufnum = 0;
    1678         bd_buf = NULL;
    1679         do {
    1680           /*
    1681            * if a buffer was left over from last loop, then use this buffer
    1682            * otherwise fetch new buffer from chain.
    1683            * Wait for buffer, if this is the first one of the request,
    1684            * otherwise do not wait, if no buffer available
    1685            */
    1686           if (nxt_bd_buf == NULL) {
    1687             rc = rtems_semaphore_obtain(rtems_bdbuf_ctx.flush_sema,
    1688                                         (req.req.count == 0)
    1689                                         ? RTEMS_WAIT
    1690                                         : RTEMS_NO_WAIT,
    1691                                         0);
    1692             if (rc == RTEMS_SUCCESSFUL) {
    1693               nxt_bd_buf = (bdbuf_buffer *)rtems_chain_get(&rtems_bdbuf_ctx.mod);
    1694           if (nxt_bd_buf != NULL) {
    1695                 nxt_bd_buf->in_progress = TRUE;
    1696             /* IMD try: clear "modified" bit early             */
    1697             /* (and not in bdbuf_write_transfer_done) to allow */
    1698             /* another modification during write processing    */
    1699             nxt_bd_buf->modified    = FALSE;
    1700 
    1701                 nxt_bd_buf->use_count++;
    1702                   }
    1703             }
    1704             else if ((rc != RTEMS_UNSATISFIED) &&
    1705                      (rc != RTEMS_TIMEOUT)) {
    1706               rtems_fatal_error_occurred(BLKDEV_FATAL_BDBUF_SWAPOUT);
    1707             }
    1708           }
    1709           /*
    1710            * It is possible that flush_sema semaphore will be released, but
    1711            * buffer to be removed from mod chain before swapout task start
    1712            * its processing.
    1713            */
    1714           if ((req.req.count == 0)  || /* first bd_buf for this request */
    1715               ((nxt_bd_buf        != NULL)            &&
    1716                (nxt_bd_buf->dev   == bd_buf->dev)     && /* same device */
    1717                (nxt_bd_buf->block == bd_buf->block+1))) {/* next block  */
    1718             bd_buf     = nxt_bd_buf;
    1719             nxt_bd_buf = NULL;
    1720           }
    1721           else {
    1722             bd_buf = NULL;
    1723           }
    1724           /*
    1725            * here we have three possible states:
    1726            * bd_buf == NULL, nxt_bd_buf == NULL: no further block available
    1727            * bd_buf != NULL, nxt_bd_buf == NULL: append bd_buf to request
    1728            * bd_buf == NULL, nxt_bd_buf != NULL: nxt_bd_buf canot be appended
    1729            *                                     to current request, keep it
    1730            *                                     for next main loop
    1731            */
    1732           if (bd_buf != NULL) {
    1733             bd_pool = rtems_bdbuf_ctx.pool + bd_buf->pool;
    1734             if (req.req.count == 0) {
    1735               /*
    1736                * this is the first block, so use its address
    1737                */
    1738               dd = rtems_disk_lookup(bd_buf->dev);
    1739               req.req.start = bd_buf->block + dd->start;
    1740             }
    1741             req.req.bufs[req.req.bufnum].length = dd->block_size;
    1742             req.req.bufs[req.req.bufnum].buffer = bd_buf->buffer;
    1743             /*
    1744              * keep bd_buf for postprocessing
    1745              */
    1746             bd_buf_write_store[req.req.bufnum] = bd_buf;
    1747             req.req.count++;
    1748             req.req.bufnum++;
    1749           }
    1750         } while ((bd_buf != NULL) &&
    1751                  (req.req.count < SWAP_OUT_MAX_BLK_CNT));
    1752                  
    1753         /* transfer_sema initialized when bd_buf inserted in the mod chain
    1754            first time */
    1755         result = dd->ioctl(dd->phys_dev->dev, BLKIO_REQUEST, &req);
    1756 
    1757         rtems_disk_release(dd);
    1758        
    1759         for (i = 0;i < req.req.count;i++) {
    1760           bd_buf = bd_buf_write_store[i];
    1761           if (result == -1)
    1762             {
    1763              
    1764               bd_buf->status = RTEMS_IO_ERROR;
    1765               bd_buf->error = errno;
    1766               /* Release tasks waiting on syncing this buffer */
    1767               _CORE_mutex_Flush(&bd_buf->transfer_sema, NULL,
    1768                                 CORE_MUTEX_STATUS_SUCCESSFUL);
    1769             }
    1770           else
    1771             {
    1772               if (bd_buf->in_progress)
    1773                 {
    1774                   rtems_interrupt_disable(level);
    1775                   _CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE, 0, level);
    1776                 }
    1777             }
    1778           bd_buf->use_count--;
    1779 
    1780           /* Another task have chance to use this buffer, or even
    1781            * modify it. If buffer is not in use, insert it in appropriate chain
    1782            * and release semaphore */
    1783           if (bd_buf->use_count == 0)
    1784             {
    1785               if (bd_buf->modified)
    1786                 {
    1787                   rtems_chain_append(&rtems_bdbuf_ctx.mod, &bd_buf->link);
    1788                   rc = rtems_semaphore_release(rtems_bdbuf_ctx.flush_sema);
    1789                 }
    1790               else
    1791                 {
    1792                   rtems_chain_append(&bd_pool->lru, &bd_buf->link);
    1793                   rc = rtems_semaphore_release(bd_pool->bufget_sema);
    1794                 }
    1795             }
     2315    boolean update_timers = TRUE;
     2316   
     2317    /*
     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.
     2321     */
     2322    boolean transfered_buffers;
     2323
     2324    do
     2325    {
     2326      rtems_bdpool_id pid;
     2327   
     2328      transfered_buffers = FALSE;
     2329
     2330      /*
     2331       * Loop over each pool extacting all the buffers we find for a specific
     2332       * device. The device is the first one we find on a modified list of a
     2333       * pool. Process the sync queue of buffers first.
     2334       */
     2335      for (pid = 0; pid < context->npools; pid++)
     2336      {
     2337        if (rtems_bdbuf_swapout_pool_processing (pid,
     2338                                                 timer_delta,
     2339                                                 update_timers,
     2340                                                 write_req))
     2341        {
     2342          transfered_buffers = TRUE;
    17962343        }
    1797     }
    1798 }
    1799 
    1800 /* rtems_bdbuf_find_pool --
    1801  *     Find first appropriate buffer pool. This primitive returns the index
    1802  *     of first buffer pool which block size is greater than or equal to
    1803  *     specified size.
     2344      }
     2345
     2346      /*
     2347       * Only update the timers once.
     2348       */
     2349      update_timers = FALSE;
     2350    }
     2351    while (transfered_buffers);
     2352
     2353    sc = rtems_event_receive (RTEMS_BDBUF_SWAPOUT_SYNC,
     2354                              RTEMS_EVENT_ALL | RTEMS_WAIT,
     2355                              period_in_ticks,
     2356                              &out);
     2357
     2358    if ((sc != RTEMS_SUCCESSFUL) && (sc != RTEMS_TIMEOUT))
     2359      rtems_fatal_error_occurred (BLKDEV_FATAL_BDBUF_SWAPOUT_RE);
     2360  }
     2361
     2362  free (write_req);
     2363
     2364  rtems_task_delete (RTEMS_SELF);
     2365}
     2366
     2367/**
     2368 * Find first appropriate buffer pool. This primitive returns the index of
     2369 * first buffer pool which block size is greater than or equal to specified
     2370 * size.
    18042371 *
    18052372 * PARAMETERS:
     
    18142381 */
    18152382rtems_status_code
    1816 rtems_bdbuf_find_pool(int block_size, rtems_bdpool_id *pool)
    1817 {
    1818     rtems_bdpool_id i;
    1819     bdbuf_pool *p;
    1820     int cursize = INT_MAX;
    1821     rtems_bdpool_id curid = -1;
    1822     rtems_boolean found = FALSE;
    1823     int j;
    1824 
    1825     for (j = block_size; (j != 0) && ((j & 1) == 0); j >>= 1);
    1826     if (j != 1)
    1827         return RTEMS_INVALID_SIZE;
    1828 
    1829     for (i = 0, p = rtems_bdbuf_ctx.pool; i < rtems_bdbuf_ctx.npools; i++, p++)
    1830     {
    1831         if ((p->blksize >= block_size) &&
    1832             (p->blksize < cursize))
    1833         {
    1834             curid = i;
    1835             cursize = p->blksize;
    1836             found = TRUE;
    1837         }
    1838     }
    1839 
    1840     if (found)
    1841     {
    1842         if (pool != NULL)
    1843             *pool = curid;
    1844         return RTEMS_SUCCESSFUL;
    1845     }
    1846     else
    1847     {
    1848         return RTEMS_NOT_DEFINED;
    1849     }
    1850 }
    1851 
    1852 /* rtems_bdbuf_get_pool_info --
    1853  *     Obtain characteristics of buffer pool with specified number.
     2383rtems_bdbuf_find_pool (int block_size, rtems_bdpool_id *pool)
     2384{
     2385  rtems_bdbuf_pool* p;
     2386  rtems_bdpool_id   i;
     2387  rtems_bdpool_id   curid = -1;
     2388  rtems_boolean     found = FALSE;
     2389  int               cursize = INT_MAX;
     2390  int               j;
     2391
     2392  for (j = block_size; (j != 0) && ((j & 1) == 0); j >>= 1);
     2393  if (j != 1)
     2394    return RTEMS_INVALID_SIZE;
     2395
     2396  for (i = 0; i < rtems_bdbuf_ctx.npools; i++)
     2397  {
     2398    p = rtems_bdbuf_get_pool (i);
     2399    if ((p->blksize >= block_size) &&
     2400        (p->blksize < cursize))
     2401    {
     2402      curid = i;
     2403      cursize = p->blksize;
     2404      found = TRUE;
     2405    }
     2406  }
     2407
     2408  if (found)
     2409  {
     2410    if (pool != NULL)
     2411      *pool = curid;
     2412    return RTEMS_SUCCESSFUL;
     2413  }
     2414  else
     2415  {
     2416    return RTEMS_NOT_DEFINED;
     2417  }
     2418}
     2419
     2420/**
     2421 * Obtain characteristics of buffer pool with specified number.
    18542422 *
    18552423 * PARAMETERS:
     
    18672435 */
    18682436rtems_status_code
    1869 rtems_bdbuf_get_pool_info(rtems_bdpool_id pool, int *block_size,
    1870                           int *blocks)
    1871 {
    1872     if (pool >= rtems_bdbuf_ctx.npools)
    1873         return RTEMS_INVALID_NUMBER;
    1874 
    1875     if (block_size != NULL)
    1876     {
    1877         *block_size = rtems_bdbuf_ctx.pool[pool].blksize;
    1878     }
    1879 
    1880     if (blocks != NULL)
    1881     {
    1882         *blocks = rtems_bdbuf_ctx.pool[pool].nblks;
    1883     }
    1884 
    1885     return RTEMS_SUCCESSFUL;
    1886 }
     2437rtems_bdbuf_get_pool_info(rtems_bdpool_id pool, int* block_size, int* blocks)
     2438{
     2439  if (pool >= rtems_bdbuf_ctx.npools)
     2440    return RTEMS_INVALID_NUMBER;
     2441
     2442  if (block_size != NULL)
     2443  {
     2444    *block_size = rtems_bdbuf_ctx.pool[pool].blksize;
     2445  }
     2446
     2447  if (blocks != NULL)
     2448  {
     2449    *blocks = rtems_bdbuf_ctx.pool[pool].nblks;
     2450  }
     2451
     2452  return RTEMS_SUCCESSFUL;
     2453}
Note: See TracChangeset for help on using the changeset viewer.