/*
|
/*
|
* Disk I/O buffering
|
* Disk I/O buffering
|
* Buffer managment
|
* Buffer managment
|
*
|
*
|
* Copyright (C) 2001 OKTET Ltd., St.-Peterburg, Russia
|
* Copyright (C) 2001 OKTET Ltd., St.-Peterburg, Russia
|
* Author: Andrey G. Ivanov <Andrey.Ivanov@oktet.ru>
|
* Author: Andrey G. Ivanov <Andrey.Ivanov@oktet.ru>
|
* Victor V. Vengerov <vvv@oktet.ru>
|
* Victor V. Vengerov <vvv@oktet.ru>
|
* Alexander Kukuta <kam@oktet.ru>
|
* Alexander Kukuta <kam@oktet.ru>
|
*
|
*
|
* @(#) bdbuf.c,v 1.3 2002/07/01 22:37:58 joel Exp
|
* @(#) bdbuf.c,v 1.3 2002/07/01 22:37:58 joel Exp
|
*/
|
*/
|
|
|
#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__
|
#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__
|
#include <rtems.h>
|
#include <rtems.h>
|
#include <limits.h>
|
#include <limits.h>
|
#include <errno.h>
|
#include <errno.h>
|
#include <assert.h>
|
#include <assert.h>
|
|
|
#include "rtems/bdbuf.h"
|
#include "rtems/bdbuf.h"
|
|
|
/* Fatal errors: */
|
/* Fatal errors: */
|
#define BLKDEV_FATAL_ERROR(n) (('B' << 24) | ((n) & 0x00FFFFFF))
|
#define BLKDEV_FATAL_ERROR(n) (('B' << 24) | ((n) & 0x00FFFFFF))
|
#define BLKDEV_FATAL_BDBUF_CONSISTENCY BLKDEV_FATAL_ERROR(1)
|
#define BLKDEV_FATAL_BDBUF_CONSISTENCY BLKDEV_FATAL_ERROR(1)
|
#define BLKDEV_FATAL_BDBUF_SWAPOUT BLKDEV_FATAL_ERROR(2)
|
#define BLKDEV_FATAL_BDBUF_SWAPOUT BLKDEV_FATAL_ERROR(2)
|
|
|
|
|
#define SWAPOUT_PRIORITY 15
|
#define SWAPOUT_PRIORITY 15
|
#define SWAPOUT_STACK_SIZE (RTEMS_MINIMUM_STACK_SIZE * 2)
|
#define SWAPOUT_STACK_SIZE (RTEMS_MINIMUM_STACK_SIZE * 2)
|
|
|
static rtems_task bdbuf_swapout_task(rtems_task_argument unused);
|
static rtems_task bdbuf_swapout_task(rtems_task_argument unused);
|
|
|
/*
|
/*
|
* The groups of the blocks with the same size are collected in the
|
* The groups of the blocks with the same size are collected in the
|
* bd_pool. Note that a several of the buffer's groups with the
|
* bd_pool. Note that a several of the buffer's groups with the
|
* same size can exists.
|
* same size can exists.
|
*/
|
*/
|
typedef struct bdbuf_pool
|
typedef struct bdbuf_pool
|
{
|
{
|
bdbuf_buffer *tree; /* Buffer descriptor lookup AVL tree root */
|
bdbuf_buffer *tree; /* Buffer descriptor lookup AVL tree root */
|
|
|
Chain_Control free; /* Free buffers list */
|
Chain_Control free; /* Free buffers list */
|
Chain_Control lru; /* Last recently used list */
|
Chain_Control lru; /* Last recently used list */
|
|
|
int blksize; /* The size of the blocks (in bytes) */
|
int blksize; /* The size of the blocks (in bytes) */
|
int nblks; /* Number of blocks in this pool */
|
int nblks; /* Number of blocks in this pool */
|
rtems_id bufget_sema; /* Buffer obtain counting semaphore */
|
rtems_id bufget_sema; /* Buffer obtain counting semaphore */
|
void *mallocd_bufs; /* Pointer to the malloc'd buffer memory,
|
void *mallocd_bufs; /* Pointer to the malloc'd buffer memory,
|
or NULL, if buffer memory provided in
|
or NULL, if buffer memory provided in
|
buffer configuration */
|
buffer configuration */
|
bdbuf_buffer *bdbufs; /* Pointer to table of buffer descriptors
|
bdbuf_buffer *bdbufs; /* Pointer to table of buffer descriptors
|
allocated for this buffer pool. */
|
allocated for this buffer pool. */
|
} bdbuf_pool;
|
} bdbuf_pool;
|
|
|
/* Buffering layer context definition */
|
/* Buffering layer context definition */
|
struct bdbuf_context {
|
struct bdbuf_context {
|
bdbuf_pool *pool; /* Table of buffer pools */
|
bdbuf_pool *pool; /* Table of buffer pools */
|
int npools; /* Number of entries in pool table */
|
int npools; /* Number of entries in pool table */
|
|
|
Chain_Control mod; /* Modified buffers list */
|
Chain_Control mod; /* Modified buffers list */
|
rtems_id flush_sema; /* Buffer flush semaphore; counting
|
rtems_id flush_sema; /* Buffer flush semaphore; counting
|
semaphore; incremented when buffer
|
semaphore; incremented when buffer
|
flushed to the disk; decremented when
|
flushed to the disk; decremented when
|
buffer modified */
|
buffer modified */
|
rtems_id swapout_task; /* Swapout task ID */
|
rtems_id swapout_task; /* Swapout task ID */
|
};
|
};
|
|
|
/* Block device request with a single buffer provided */
|
/* Block device request with a single buffer provided */
|
typedef struct blkdev_request1 {
|
typedef struct blkdev_request1 {
|
blkdev_request req;
|
blkdev_request req;
|
blkdev_sg_buffer sg[1];
|
blkdev_sg_buffer sg[1];
|
} blkdev_request1;
|
} blkdev_request1;
|
|
|
/* The static context of buffering layer */
|
/* The static context of buffering layer */
|
static struct bdbuf_context bd_ctx;
|
static struct bdbuf_context bd_ctx;
|
|
|
#define SAFE
|
#define SAFE
|
#ifdef SAFE
|
#ifdef SAFE
|
typedef rtems_mode preemption_key;
|
typedef rtems_mode preemption_key;
|
|
|
#define DISABLE_PREEMPTION(key) \
|
#define DISABLE_PREEMPTION(key) \
|
do { \
|
do { \
|
rtems_task_mode(RTEMS_PREEMPT_MASK, RTEMS_NO_PREEMPT, &(key)); \
|
rtems_task_mode(RTEMS_PREEMPT_MASK, RTEMS_NO_PREEMPT, &(key)); \
|
} while (0)
|
} while (0)
|
|
|
#define ENABLE_PREEMPTION(key) \
|
#define ENABLE_PREEMPTION(key) \
|
do { \
|
do { \
|
rtems_mode temp; \
|
rtems_mode temp; \
|
rtems_task_mode(RTEMS_PREEMPT_MASK, (key), &temp); \
|
rtems_task_mode(RTEMS_PREEMPT_MASK, (key), &temp); \
|
} while (0)
|
} while (0)
|
|
|
#else
|
#else
|
|
|
typedef boolean preemption_key;
|
typedef boolean preemption_key;
|
|
|
#define DISABLE_PREEMPTION(key) \
|
#define DISABLE_PREEMPTION(key) \
|
do { \
|
do { \
|
(key) = _Thread_Executing->is_preemptible; \
|
(key) = _Thread_Executing->is_preemptible; \
|
_Thread_Executing->is_preemptible = 0; \
|
_Thread_Executing->is_preemptible = 0; \
|
} while (0)
|
} while (0)
|
|
|
#define ENABLE_PREEMPTION(key) \
|
#define ENABLE_PREEMPTION(key) \
|
do { \
|
do { \
|
_Thread_Executing->is_preemptible = (key); \
|
_Thread_Executing->is_preemptible = (key); \
|
if (_Thread_Evaluate_mode()) \
|
if (_Thread_Evaluate_mode()) \
|
_Thread_Dispatch(); \
|
_Thread_Dispatch(); \
|
} while (0)
|
} while (0)
|
|
|
#endif
|
#endif
|
|
|
|
|
/* The default maximum height of 32 allows for AVL trees having
|
/* The default maximum height of 32 allows for AVL trees having
|
between 5,704,880 and 4,294,967,295 nodes, depending on order of
|
between 5,704,880 and 4,294,967,295 nodes, depending on order of
|
insertion. You may change this compile-time constant as you
|
insertion. You may change this compile-time constant as you
|
wish. */
|
wish. */
|
#ifndef AVL_MAX_HEIGHT
|
#ifndef AVL_MAX_HEIGHT
|
#define AVL_MAX_HEIGHT 32
|
#define AVL_MAX_HEIGHT 32
|
#endif
|
#endif
|
|
|
/*
|
/*
|
* avl_search --
|
* avl_search --
|
* Searches for the node with specified dev/block.
|
* Searches for the node with specified dev/block.
|
*
|
*
|
* PARAMETERS:
|
* PARAMETERS:
|
* root - pointer to the root node of the AVL-Tree.
|
* root - pointer to the root node of the AVL-Tree.
|
* dev, block - search key
|
* dev, block - search key
|
*
|
*
|
* RETURNS:
|
* RETURNS:
|
* NULL if node with specified dev/block not found
|
* NULL if node with specified dev/block not found
|
* non-NULL - pointer to the node with specified dev/block
|
* non-NULL - pointer to the node with specified dev/block
|
*/
|
*/
|
static bdbuf_buffer *
|
static bdbuf_buffer *
|
avl_search(bdbuf_buffer **root, dev_t dev, blkdev_bnum block)
|
avl_search(bdbuf_buffer **root, dev_t dev, blkdev_bnum block)
|
{
|
{
|
bdbuf_buffer *p = *root;
|
bdbuf_buffer *p = *root;
|
|
|
while ((p != NULL) && ((p->dev != dev) || (p->block != block)))
|
while ((p != NULL) && ((p->dev != dev) || (p->block != block)))
|
{
|
{
|
if ((p->dev < dev) || ((p->dev == dev) && (p->block < block)))
|
if ((p->dev < dev) || ((p->dev == dev) && (p->block < block)))
|
{
|
{
|
p = p->avl.right;
|
p = p->avl.right;
|
}
|
}
|
else
|
else
|
{
|
{
|
p = p->avl.left;
|
p = p->avl.left;
|
}
|
}
|
}
|
}
|
|
|
return p;
|
return p;
|
}
|
}
|
|
|
|
|
/* avl_search_for_sync --
|
/* avl_search_for_sync --
|
* Search in AVL tree for first modified buffer belongs to specified
|
* Search in AVL tree for first modified buffer belongs to specified
|
* disk device.
|
* disk device.
|
*
|
*
|
* PARAMETERS:
|
* PARAMETERS:
|
* root - pointer to tree root
|
* root - pointer to tree root
|
* dd - disk device descriptor
|
* dd - disk device descriptor
|
*
|
*
|
* RETURNS:
|
* RETURNS:
|
* Block buffer, or NULL if no modified blocks on specified device
|
* Block buffer, or NULL if no modified blocks on specified device
|
* exists.
|
* exists.
|
*/
|
*/
|
static bdbuf_buffer *
|
static bdbuf_buffer *
|
avl_search_for_sync(bdbuf_buffer **root, disk_device *dd)
|
avl_search_for_sync(bdbuf_buffer **root, disk_device *dd)
|
{
|
{
|
dev_t dev = dd->phys_dev->dev;
|
dev_t dev = dd->phys_dev->dev;
|
blkdev_bnum block_start = dd->start;
|
blkdev_bnum block_start = dd->start;
|
blkdev_bnum block_end = dd->start + dd->size - 1;
|
blkdev_bnum block_end = dd->start + dd->size - 1;
|
|
|
bdbuf_buffer *buf_stack[AVL_MAX_HEIGHT];
|
bdbuf_buffer *buf_stack[AVL_MAX_HEIGHT];
|
bdbuf_buffer **buf_prev = buf_stack;
|
bdbuf_buffer **buf_prev = buf_stack;
|
bdbuf_buffer *p = *root;
|
bdbuf_buffer *p = *root;
|
|
|
while (p != NULL)
|
while (p != NULL)
|
{
|
{
|
if ((p->dev < dev) || ((p->dev == dev) && (p->block < block_start)))
|
if ((p->dev < dev) || ((p->dev == dev) && (p->block < block_start)))
|
{
|
{
|
p = p->avl.right;
|
p = p->avl.right;
|
}
|
}
|
else if ((p->dev > dev) || ((p->dev == dev) && (p->block > block_end)))
|
else if ((p->dev > dev) || ((p->dev == dev) && (p->block > block_end)))
|
{
|
{
|
p = p->avl.left;
|
p = p->avl.left;
|
}
|
}
|
else if (p->modified)
|
else if (p->modified)
|
{
|
{
|
return p;
|
return p;
|
}
|
}
|
else
|
else
|
{
|
{
|
if (p->avl.right != NULL)
|
if (p->avl.right != NULL)
|
{
|
{
|
*buf_prev++ = p->avl.right;
|
*buf_prev++ = p->avl.right;
|
}
|
}
|
p = p->avl.left;
|
p = p->avl.left;
|
}
|
}
|
|
|
if ((p == NULL) && (buf_prev > buf_stack))
|
if ((p == NULL) && (buf_prev > buf_stack))
|
{
|
{
|
p = *--buf_prev;
|
p = *--buf_prev;
|
}
|
}
|
}
|
}
|
|
|
return p;
|
return p;
|
}
|
}
|
|
|
|
|
/*
|
/*
|
* avl_insert --
|
* avl_insert --
|
* Inserts the specified node to the AVl-Tree.
|
* Inserts the specified node to the AVl-Tree.
|
*
|
*
|
* PARAMETERS:
|
* PARAMETERS:
|
* root - Pointer to pointer to the root node
|
* root - Pointer to pointer to the root node
|
* node - Pointer to the node to add.
|
* node - Pointer to the node to add.
|
*
|
*
|
* RETURNS:
|
* RETURNS:
|
* 0 - The node added successfully
|
* 0 - The node added successfully
|
* -1 - An error occured
|
* -1 - An error occured
|
*/
|
*/
|
static int
|
static int
|
avl_insert(bdbuf_buffer **root, bdbuf_buffer *node)
|
avl_insert(bdbuf_buffer **root, bdbuf_buffer *node)
|
{
|
{
|
dev_t dev = node->dev;
|
dev_t dev = node->dev;
|
blkdev_bnum block = node->block;
|
blkdev_bnum block = node->block;
|
|
|
bdbuf_buffer *p = *root;
|
bdbuf_buffer *p = *root;
|
bdbuf_buffer *q, *p1, *p2;
|
bdbuf_buffer *q, *p1, *p2;
|
bdbuf_buffer *buf_stack[AVL_MAX_HEIGHT];
|
bdbuf_buffer *buf_stack[AVL_MAX_HEIGHT];
|
bdbuf_buffer **buf_prev = buf_stack;
|
bdbuf_buffer **buf_prev = buf_stack;
|
|
|
boolean modified = FALSE;
|
boolean modified = FALSE;
|
|
|
if (p == NULL)
|
if (p == NULL)
|
{
|
{
|
*root = node;
|
*root = node;
|
node->avl.left = NULL;
|
node->avl.left = NULL;
|
node->avl.right = NULL;
|
node->avl.right = NULL;
|
node->avl.bal = 0;
|
node->avl.bal = 0;
|
return 0;
|
return 0;
|
}
|
}
|
|
|
while (p != NULL)
|
while (p != NULL)
|
{
|
{
|
*buf_prev++ = p;
|
*buf_prev++ = p;
|
|
|
if ((p->dev < dev) || ((p->dev == dev) && (p->block < block)))
|
if ((p->dev < dev) || ((p->dev == dev) && (p->block < block)))
|
{
|
{
|
p->avl.cache = 1;
|
p->avl.cache = 1;
|
q = p->avl.right;
|
q = p->avl.right;
|
if (q == NULL)
|
if (q == NULL)
|
{
|
{
|
q = node;
|
q = node;
|
p->avl.right = q = node;
|
p->avl.right = q = node;
|
break;
|
break;
|
}
|
}
|
}
|
}
|
else if ((p->dev != dev) || (p->block != block))
|
else if ((p->dev != dev) || (p->block != block))
|
{
|
{
|
p->avl.cache = -1;
|
p->avl.cache = -1;
|
q = p->avl.left;
|
q = p->avl.left;
|
if (q == NULL)
|
if (q == NULL)
|
{
|
{
|
q = node;
|
q = node;
|
p->avl.left = q;
|
p->avl.left = q;
|
break;
|
break;
|
}
|
}
|
}
|
}
|
else
|
else
|
{
|
{
|
return -1;
|
return -1;
|
}
|
}
|
|
|
p = q;
|
p = q;
|
}
|
}
|
|
|
q->avl.left = q->avl.right = NULL;
|
q->avl.left = q->avl.right = NULL;
|
q->avl.bal = 0;
|
q->avl.bal = 0;
|
modified = TRUE;
|
modified = TRUE;
|
buf_prev--;
|
buf_prev--;
|
|
|
while (modified)
|
while (modified)
|
{
|
{
|
if (p->avl.cache == -1)
|
if (p->avl.cache == -1)
|
{
|
{
|
switch (p->avl.bal)
|
switch (p->avl.bal)
|
{
|
{
|
case 1:
|
case 1:
|
p->avl.bal = 0;
|
p->avl.bal = 0;
|
modified = FALSE;
|
modified = FALSE;
|
break;
|
break;
|
|
|
case 0:
|
case 0:
|
p->avl.bal = -1;
|
p->avl.bal = -1;
|
break;
|
break;
|
|
|
case -1:
|
case -1:
|
p1 = p->avl.left;
|
p1 = p->avl.left;
|
if (p1->avl.bal == -1) /* simple LL-turn */
|
if (p1->avl.bal == -1) /* simple LL-turn */
|
{
|
{
|
p->avl.left = p1->avl.right;
|
p->avl.left = p1->avl.right;
|
p1->avl.right = p;
|
p1->avl.right = p;
|
p->avl.bal = 0;
|
p->avl.bal = 0;
|
p = p1;
|
p = p1;
|
}
|
}
|
else /* double LR-turn */
|
else /* double LR-turn */
|
{
|
{
|
p2 = p1->avl.right;
|
p2 = p1->avl.right;
|
p1->avl.right = p2->avl.left;
|
p1->avl.right = p2->avl.left;
|
p2->avl.left = p1;
|
p2->avl.left = p1;
|
p->avl.left = p2->avl.right;
|
p->avl.left = p2->avl.right;
|
p2->avl.right = p;
|
p2->avl.right = p;
|
if (p2->avl.bal == -1) p->avl.bal = +1; else p->avl.bal = 0;
|
if (p2->avl.bal == -1) p->avl.bal = +1; else p->avl.bal = 0;
|
if (p2->avl.bal == +1) p1->avl.bal = -1; else p1->avl.bal = 0;
|
if (p2->avl.bal == +1) p1->avl.bal = -1; else p1->avl.bal = 0;
|
p = p2;
|
p = p2;
|
}
|
}
|
p->avl.bal = 0;
|
p->avl.bal = 0;
|
modified = FALSE;
|
modified = FALSE;
|
break;
|
break;
|
|
|
default:
|
default:
|
break;
|
break;
|
}
|
}
|
}
|
}
|
else
|
else
|
{
|
{
|
switch (p->avl.bal)
|
switch (p->avl.bal)
|
{
|
{
|
case -1:
|
case -1:
|
p->avl.bal = 0;
|
p->avl.bal = 0;
|
modified = FALSE;
|
modified = FALSE;
|
break;
|
break;
|
|
|
case 0:
|
case 0:
|
p->avl.bal = 1;
|
p->avl.bal = 1;
|
break;
|
break;
|
|
|
case 1:
|
case 1:
|
p1 = p->avl.right;
|
p1 = p->avl.right;
|
if (p1->avl.bal == 1) /* simple RR-turn */
|
if (p1->avl.bal == 1) /* simple RR-turn */
|
{
|
{
|
p->avl.right = p1->avl.left;
|
p->avl.right = p1->avl.left;
|
p1->avl.left = p;
|
p1->avl.left = p;
|
p->avl.bal = 0;
|
p->avl.bal = 0;
|
p = p1;
|
p = p1;
|
}
|
}
|
else /* double RL-turn */
|
else /* double RL-turn */
|
{
|
{
|
p2 = p1->avl.left;
|
p2 = p1->avl.left;
|
p1->avl.left = p2->avl.right;
|
p1->avl.left = p2->avl.right;
|
p2->avl.right = p1;
|
p2->avl.right = p1;
|
p->avl.right = p2->avl.left;
|
p->avl.right = p2->avl.left;
|
p2->avl.left = p;
|
p2->avl.left = p;
|
if (p2->avl.bal == +1) p->avl.bal = -1; else p->avl.bal = 0;
|
if (p2->avl.bal == +1) p->avl.bal = -1; else p->avl.bal = 0;
|
if (p2->avl.bal == -1) p1->avl.bal = +1; else p1->avl.bal = 0;
|
if (p2->avl.bal == -1) p1->avl.bal = +1; else p1->avl.bal = 0;
|
p = p2;
|
p = p2;
|
}
|
}
|
p->avl.bal = 0;
|
p->avl.bal = 0;
|
modified = FALSE;
|
modified = FALSE;
|
break;
|
break;
|
|
|
default:
|
default:
|
break;
|
break;
|
}
|
}
|
}
|
}
|
q = p;
|
q = p;
|
if (buf_prev > buf_stack)
|
if (buf_prev > buf_stack)
|
{
|
{
|
p = *--buf_prev;
|
p = *--buf_prev;
|
|
|
if (p->avl.cache == -1)
|
if (p->avl.cache == -1)
|
{
|
{
|
p->avl.left = q;
|
p->avl.left = q;
|
}
|
}
|
else
|
else
|
{
|
{
|
p->avl.right = q;
|
p->avl.right = q;
|
}
|
}
|
}
|
}
|
else
|
else
|
{
|
{
|
*root = p;
|
*root = p;
|
break;
|
break;
|
}
|
}
|
};
|
};
|
|
|
return 0;
|
return 0;
|
}
|
}
|
|
|
|
|
/* avl_remove --
|
/* avl_remove --
|
* removes the node from the tree.
|
* removes the node from the tree.
|
*
|
*
|
* PARAMETERS:
|
* PARAMETERS:
|
* root_addr - Pointer to pointer to the root node
|
* root_addr - Pointer to pointer to the root node
|
* node - Pointer to the node to remove
|
* node - Pointer to the node to remove
|
*
|
*
|
* RETURNS:
|
* RETURNS:
|
* 0 - Item removed
|
* 0 - Item removed
|
* -1 - No such item found
|
* -1 - No such item found
|
*/
|
*/
|
static int
|
static int
|
avl_remove(bdbuf_buffer **root, const bdbuf_buffer *node)
|
avl_remove(bdbuf_buffer **root, const bdbuf_buffer *node)
|
{
|
{
|
dev_t dev = node->dev;
|
dev_t dev = node->dev;
|
blkdev_bnum block = node->block;
|
blkdev_bnum block = node->block;
|
|
|
bdbuf_buffer *p = *root;
|
bdbuf_buffer *p = *root;
|
bdbuf_buffer *q, *r, *s, *p1, *p2;
|
bdbuf_buffer *q, *r, *s, *p1, *p2;
|
bdbuf_buffer *buf_stack[AVL_MAX_HEIGHT];
|
bdbuf_buffer *buf_stack[AVL_MAX_HEIGHT];
|
bdbuf_buffer **buf_prev = buf_stack;
|
bdbuf_buffer **buf_prev = buf_stack;
|
|
|
boolean modified = FALSE;
|
boolean modified = FALSE;
|
|
|
memset(buf_stack, 0, sizeof(buf_stack));
|
memset(buf_stack, 0, sizeof(buf_stack));
|
|
|
while (p != NULL)
|
while (p != NULL)
|
{
|
{
|
*buf_prev++ = p;
|
*buf_prev++ = p;
|
|
|
if ((p->dev < dev) || ((p->dev == dev) && (p->block < block)))
|
if ((p->dev < dev) || ((p->dev == dev) && (p->block < block)))
|
{
|
{
|
p->avl.cache = 1;
|
p->avl.cache = 1;
|
p = p->avl.right;
|
p = p->avl.right;
|
}
|
}
|
else if ((p->dev != dev) || (p->block != block))
|
else if ((p->dev != dev) || (p->block != block))
|
{
|
{
|
p->avl.cache = -1;
|
p->avl.cache = -1;
|
p = p->avl.left;
|
p = p->avl.left;
|
}
|
}
|
else
|
else
|
{
|
{
|
/* node found */
|
/* node found */
|
break;
|
break;
|
}
|
}
|
}
|
}
|
|
|
if (p == NULL)
|
if (p == NULL)
|
{
|
{
|
/* there is no such node */
|
/* there is no such node */
|
return -1;
|
return -1;
|
}
|
}
|
|
|
q = p;
|
q = p;
|
|
|
buf_prev--;
|
buf_prev--;
|
if (buf_prev > buf_stack)
|
if (buf_prev > buf_stack)
|
{
|
{
|
p = *(buf_prev - 1);
|
p = *(buf_prev - 1);
|
}
|
}
|
else
|
else
|
{
|
{
|
p = NULL;
|
p = NULL;
|
}
|
}
|
|
|
/* at this moment q - is a node to delete, p is q's parent */
|
/* at this moment q - is a node to delete, p is q's parent */
|
if (q->avl.right == NULL)
|
if (q->avl.right == NULL)
|
{
|
{
|
r = q->avl.left;
|
r = q->avl.left;
|
if (r != NULL)
|
if (r != NULL)
|
{
|
{
|
r->avl.bal = 0;
|
r->avl.bal = 0;
|
}
|
}
|
q = r;
|
q = r;
|
}
|
}
|
else
|
else
|
{
|
{
|
bdbuf_buffer **t;
|
bdbuf_buffer **t;
|
|
|
r = q->avl.right;
|
r = q->avl.right;
|
|
|
if (r->avl.left == NULL)
|
if (r->avl.left == NULL)
|
{
|
{
|
r->avl.left = q->avl.left;
|
r->avl.left = q->avl.left;
|
r->avl.bal = q->avl.bal;
|
r->avl.bal = q->avl.bal;
|
r->avl.cache = 1;
|
r->avl.cache = 1;
|
*buf_prev++ = q = r;
|
*buf_prev++ = q = r;
|
}
|
}
|
else
|
else
|
{
|
{
|
t = buf_prev++;
|
t = buf_prev++;
|
s = r;
|
s = r;
|
|
|
while (s->avl.left != NULL)
|
while (s->avl.left != NULL)
|
{
|
{
|
*buf_prev++ = r = s;
|
*buf_prev++ = r = s;
|
s = r->avl.left;
|
s = r->avl.left;
|
r->avl.cache = -1;
|
r->avl.cache = -1;
|
}
|
}
|
|
|
s->avl.left = q->avl.left;
|
s->avl.left = q->avl.left;
|
r->avl.left = s->avl.right;
|
r->avl.left = s->avl.right;
|
s->avl.right = q->avl.right;
|
s->avl.right = q->avl.right;
|
s->avl.bal = q->avl.bal;
|
s->avl.bal = q->avl.bal;
|
s->avl.cache = 1;
|
s->avl.cache = 1;
|
|
|
*t = q = s;
|
*t = q = s;
|
}
|
}
|
}
|
}
|
|
|
if (p != NULL)
|
if (p != NULL)
|
{
|
{
|
if (p->avl.cache == -1)
|
if (p->avl.cache == -1)
|
{
|
{
|
p->avl.left = q;
|
p->avl.left = q;
|
}
|
}
|
else
|
else
|
{
|
{
|
p->avl.right = q;
|
p->avl.right = q;
|
}
|
}
|
}
|
}
|
else
|
else
|
{
|
{
|
*root = q;
|
*root = q;
|
}
|
}
|
|
|
modified = TRUE;
|
modified = TRUE;
|
|
|
while (modified)
|
while (modified)
|
{
|
{
|
if (buf_prev > buf_stack)
|
if (buf_prev > buf_stack)
|
{
|
{
|
p = *--buf_prev;
|
p = *--buf_prev;
|
}
|
}
|
else
|
else
|
{
|
{
|
break;
|
break;
|
}
|
}
|
|
|
if (p->avl.cache == -1)
|
if (p->avl.cache == -1)
|
{
|
{
|
/* rebalance left branch */
|
/* rebalance left branch */
|
switch (p->avl.bal)
|
switch (p->avl.bal)
|
{
|
{
|
case -1:
|
case -1:
|
p->avl.bal = 0;
|
p->avl.bal = 0;
|
break;
|
break;
|
case 0:
|
case 0:
|
p->avl.bal = 1;
|
p->avl.bal = 1;
|
modified = FALSE;
|
modified = FALSE;
|
break;
|
break;
|
|
|
case +1:
|
case +1:
|
p1 = p->avl.right;
|
p1 = p->avl.right;
|
|
|
if (p1->avl.bal >= 0) /* simple RR-turn */
|
if (p1->avl.bal >= 0) /* simple RR-turn */
|
{
|
{
|
p->avl.right = p1->avl.left;
|
p->avl.right = p1->avl.left;
|
p1->avl.left = p;
|
p1->avl.left = p;
|
|
|
if (p1->avl.bal == 0)
|
if (p1->avl.bal == 0)
|
{
|
{
|
p1->avl.bal = -1;
|
p1->avl.bal = -1;
|
modified = FALSE;
|
modified = FALSE;
|
}
|
}
|
else
|
else
|
{
|
{
|
p->avl.bal = 0;
|
p->avl.bal = 0;
|
p1->avl.bal = 0;
|
p1->avl.bal = 0;
|
}
|
}
|
p = p1;
|
p = p1;
|
}
|
}
|
else /* double RL-turn */
|
else /* double RL-turn */
|
{
|
{
|
p2 = p1->avl.left;
|
p2 = p1->avl.left;
|
|
|
p1->avl.left = p2->avl.right;
|
p1->avl.left = p2->avl.right;
|
p2->avl.right = p1;
|
p2->avl.right = p1;
|
p->avl.right = p2->avl.left;
|
p->avl.right = p2->avl.left;
|
p2->avl.left = p;
|
p2->avl.left = p;
|
|
|
if (p2->avl.bal == +1) p->avl.bal = -1; else p->avl.bal = 0;
|
if (p2->avl.bal == +1) p->avl.bal = -1; else p->avl.bal = 0;
|
if (p2->avl.bal == -1) p1->avl.bal = 1; else p1->avl.bal = 0;
|
if (p2->avl.bal == -1) p1->avl.bal = 1; else p1->avl.bal = 0;
|
|
|
p = p2;
|
p = p2;
|
p2->avl.bal = 0;
|
p2->avl.bal = 0;
|
}
|
}
|
break;
|
break;
|
|
|
default:
|
default:
|
break;
|
break;
|
}
|
}
|
}
|
}
|
else
|
else
|
{
|
{
|
/* rebalance right branch */
|
/* rebalance right branch */
|
switch (p->avl.bal)
|
switch (p->avl.bal)
|
{
|
{
|
case +1:
|
case +1:
|
p->avl.bal = 0;
|
p->avl.bal = 0;
|
break;
|
break;
|
|
|
case 0:
|
case 0:
|
p->avl.bal = -1;
|
p->avl.bal = -1;
|
modified = FALSE;
|
modified = FALSE;
|
break;
|
break;
|
|
|
case -1:
|
case -1:
|
p1 = p->avl.left;
|
p1 = p->avl.left;
|
|
|
if (p1->avl.bal <= 0) /* simple LL-turn */
|
if (p1->avl.bal <= 0) /* simple LL-turn */
|
{
|
{
|
p->avl.left = p1->avl.right;
|
p->avl.left = p1->avl.right;
|
p1->avl.right = p;
|
p1->avl.right = p;
|
if (p1->avl.bal == 0)
|
if (p1->avl.bal == 0)
|
{
|
{
|
p1->avl.bal = 1;
|
p1->avl.bal = 1;
|
modified = FALSE;
|
modified = FALSE;
|
}
|
}
|
else
|
else
|
{
|
{
|
p->avl.bal = 0;
|
p->avl.bal = 0;
|
p1->avl.bal = 0;
|
p1->avl.bal = 0;
|
}
|
}
|
p = p1;
|
p = p1;
|
}
|
}
|
else /* double LR-turn */
|
else /* double LR-turn */
|
{
|
{
|
p2 = p1->avl.right;
|
p2 = p1->avl.right;
|
|
|
p1->avl.right = p2->avl.left;
|
p1->avl.right = p2->avl.left;
|
p2->avl.left = p1;
|
p2->avl.left = p1;
|
p->avl.left = p2->avl.right;
|
p->avl.left = p2->avl.right;
|
p2->avl.right = p;
|
p2->avl.right = p;
|
|
|
if (p2->avl.bal == -1) p->avl.bal = 1; else p->avl.bal = 0;
|
if (p2->avl.bal == -1) p->avl.bal = 1; else p->avl.bal = 0;
|
if (p2->avl.bal == +1) p1->avl.bal = -1; else p1->avl.bal = 0;
|
if (p2->avl.bal == +1) p1->avl.bal = -1; else p1->avl.bal = 0;
|
|
|
p = p2;
|
p = p2;
|
p2->avl.bal = 0;
|
p2->avl.bal = 0;
|
}
|
}
|
break;
|
break;
|
|
|
default:
|
default:
|
break;
|
break;
|
}
|
}
|
}
|
}
|
|
|
if (buf_prev > buf_stack)
|
if (buf_prev > buf_stack)
|
{
|
{
|
q = *(buf_prev - 1);
|
q = *(buf_prev - 1);
|
|
|
if (q->avl.cache == -1)
|
if (q->avl.cache == -1)
|
{
|
{
|
q->avl.left = p;
|
q->avl.left = p;
|
}
|
}
|
else
|
else
|
{
|
{
|
q->avl.right = p;
|
q->avl.right = p;
|
}
|
}
|
}
|
}
|
else
|
else
|
{
|
{
|
*root = p;
|
*root = p;
|
break;
|
break;
|
}
|
}
|
|
|
}
|
}
|
|
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* bdbuf_initialize_pool --
|
/* bdbuf_initialize_pool --
|
* Initialize single buffer pool.
|
* Initialize single buffer pool.
|
*
|
*
|
* PARAMETERS:
|
* PARAMETERS:
|
* config - buffer pool configuration
|
* config - buffer pool configuration
|
* pool - pool number
|
* pool - pool number
|
*
|
*
|
* RETURNS:
|
* RETURNS:
|
* RTEMS_SUCCESSFUL, if buffer pool initialized successfully, or error
|
* RTEMS_SUCCESSFUL, if buffer pool initialized successfully, or error
|
* code if error occured.
|
* code if error occured.
|
*/
|
*/
|
static rtems_status_code
|
static rtems_status_code
|
bdbuf_initialize_pool(rtems_bdbuf_config *config, int pool)
|
bdbuf_initialize_pool(rtems_bdbuf_config *config, int pool)
|
{
|
{
|
bdbuf_pool *p = bd_ctx.pool + pool;
|
bdbuf_pool *p = bd_ctx.pool + pool;
|
unsigned char *bufs;
|
unsigned char *bufs;
|
bdbuf_buffer *b;
|
bdbuf_buffer *b;
|
rtems_status_code rc;
|
rtems_status_code rc;
|
int i;
|
int i;
|
|
|
p->blksize = config->size;
|
p->blksize = config->size;
|
p->nblks = config->num;
|
p->nblks = config->num;
|
p->tree = NULL;
|
p->tree = NULL;
|
|
|
Chain_Initialize_empty(&p->free);
|
Chain_Initialize_empty(&p->free);
|
Chain_Initialize_empty(&p->lru);
|
Chain_Initialize_empty(&p->lru);
|
|
|
/* Allocate memory for buffer descriptors */
|
/* Allocate memory for buffer descriptors */
|
p->bdbufs = calloc(config->num, sizeof(bdbuf_buffer));
|
p->bdbufs = calloc(config->num, sizeof(bdbuf_buffer));
|
if (p->bdbufs == NULL)
|
if (p->bdbufs == NULL)
|
{
|
{
|
return RTEMS_NO_MEMORY;
|
return RTEMS_NO_MEMORY;
|
}
|
}
|
|
|
/* Allocate memory for buffers if required */
|
/* Allocate memory for buffers if required */
|
if (config->mem_area == NULL)
|
if (config->mem_area == NULL)
|
{
|
{
|
bufs = p->mallocd_bufs = malloc(config->num * config->size);
|
bufs = p->mallocd_bufs = malloc(config->num * config->size);
|
if (bufs == NULL)
|
if (bufs == NULL)
|
{
|
{
|
free(p->bdbufs);
|
free(p->bdbufs);
|
return RTEMS_NO_MEMORY;
|
return RTEMS_NO_MEMORY;
|
}
|
}
|
}
|
}
|
else
|
else
|
{
|
{
|
bufs = config->mem_area;
|
bufs = config->mem_area;
|
p->mallocd_bufs = NULL;
|
p->mallocd_bufs = NULL;
|
}
|
}
|
|
|
for (i = 0, b = p->bdbufs; i < p->nblks; i++, b++, bufs += p->blksize)
|
for (i = 0, b = p->bdbufs; i < p->nblks; i++, b++, bufs += p->blksize)
|
{
|
{
|
b->dev = -1; b->block = 0;
|
b->dev = -1; b->block = 0;
|
b->buffer = bufs;
|
b->buffer = bufs;
|
b->actual = b->modified = b->in_progress = FALSE;
|
b->actual = b->modified = b->in_progress = FALSE;
|
b->use_count = 0;
|
b->use_count = 0;
|
b->pool = pool;
|
b->pool = pool;
|
_Chain_Append(&p->free, &b->link);
|
_Chain_Append(&p->free, &b->link);
|
}
|
}
|
|
|
rc = rtems_semaphore_create(
|
rc = rtems_semaphore_create(
|
rtems_build_name('B', 'U', 'F', 'G'),
|
rtems_build_name('B', 'U', 'F', 'G'),
|
p->nblks,
|
p->nblks,
|
RTEMS_FIFO | RTEMS_COUNTING_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY |
|
RTEMS_FIFO | RTEMS_COUNTING_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY |
|
RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL,
|
RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL,
|
0,
|
0,
|
&p->bufget_sema);
|
&p->bufget_sema);
|
|
|
if (rc != RTEMS_SUCCESSFUL)
|
if (rc != RTEMS_SUCCESSFUL)
|
{
|
{
|
free(p->bdbufs);
|
free(p->bdbufs);
|
free(p->mallocd_bufs);
|
free(p->mallocd_bufs);
|
return rc;
|
return rc;
|
}
|
}
|
|
|
return RTEMS_SUCCESSFUL;
|
return RTEMS_SUCCESSFUL;
|
}
|
}
|
|
|
/* bdbuf_release_pool --
|
/* bdbuf_release_pool --
|
* Free resources allocated for buffer pool with specified number.
|
* Free resources allocated for buffer pool with specified number.
|
*
|
*
|
* PARAMETERS:
|
* PARAMETERS:
|
* pool - buffer pool number
|
* pool - buffer pool number
|
*
|
*
|
* RETURNS:
|
* RETURNS:
|
* RTEMS_SUCCESSFUL
|
* RTEMS_SUCCESSFUL
|
*/
|
*/
|
static rtems_status_code
|
static rtems_status_code
|
bdbuf_release_pool(rtems_bdpool_id pool)
|
bdbuf_release_pool(rtems_bdpool_id pool)
|
{
|
{
|
bdbuf_pool *p = bd_ctx.pool + pool;
|
bdbuf_pool *p = bd_ctx.pool + pool;
|
rtems_semaphore_delete(p->bufget_sema);
|
rtems_semaphore_delete(p->bufget_sema);
|
free(p->bdbufs);
|
free(p->bdbufs);
|
free(p->mallocd_bufs);
|
free(p->mallocd_bufs);
|
return RTEMS_SUCCESSFUL;
|
return RTEMS_SUCCESSFUL;
|
}
|
}
|
|
|
/* rtems_bdbuf_init --
|
/* rtems_bdbuf_init --
|
* Prepare buffering layer to work - initialize buffer descritors
|
* Prepare buffering layer to work - initialize buffer descritors
|
* and (if it is neccessary)buffers. Buffers will be allocated accoriding
|
* and (if it is neccessary)buffers. Buffers will be allocated accoriding
|
* to the configuration table, each entry describes kind of block and
|
* to the configuration table, each entry describes kind of block and
|
* amount requested. After initialization all blocks is placed into
|
* amount requested. After initialization all blocks is placed into
|
* free elements lists.
|
* free elements lists.
|
*
|
*
|
* PARAMETERS:
|
* PARAMETERS:
|
* conf_table - pointer to the buffers configuration table
|
* conf_table - pointer to the buffers configuration table
|
* size - number of entries in configuration table
|
* size - number of entries in configuration table
|
*
|
*
|
* RETURNS:
|
* RETURNS:
|
* RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
|
* RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
|
* or error code if error is occured)
|
* or error code if error is occured)
|
*/
|
*/
|
rtems_status_code
|
rtems_status_code
|
rtems_bdbuf_init(rtems_bdbuf_config *conf_table, int size)
|
rtems_bdbuf_init(rtems_bdbuf_config *conf_table, int size)
|
{
|
{
|
rtems_bdpool_id i;
|
rtems_bdpool_id i;
|
rtems_status_code rc;
|
rtems_status_code rc;
|
|
|
if (size <= 0)
|
if (size <= 0)
|
return RTEMS_INVALID_SIZE;
|
return RTEMS_INVALID_SIZE;
|
|
|
bd_ctx.npools = size;
|
bd_ctx.npools = size;
|
|
|
/*
|
/*
|
* Allocate memory for buffer pool descriptors
|
* Allocate memory for buffer pool descriptors
|
*/
|
*/
|
bd_ctx.pool = calloc(size, sizeof(bdbuf_pool));
|
bd_ctx.pool = calloc(size, sizeof(bdbuf_pool));
|
if (bd_ctx.pool == NULL)
|
if (bd_ctx.pool == NULL)
|
{
|
{
|
return RTEMS_NO_MEMORY;
|
return RTEMS_NO_MEMORY;
|
}
|
}
|
|
|
Chain_Initialize_empty(&bd_ctx.mod);
|
Chain_Initialize_empty(&bd_ctx.mod);
|
|
|
/* Initialize buffer pools and roll out if something failed */
|
/* Initialize buffer pools and roll out if something failed */
|
for (i = 0; i < size; i++)
|
for (i = 0; i < size; i++)
|
{
|
{
|
rc = bdbuf_initialize_pool(conf_table + i, i);
|
rc = bdbuf_initialize_pool(conf_table + i, i);
|
if (rc != RTEMS_SUCCESSFUL)
|
if (rc != RTEMS_SUCCESSFUL)
|
{
|
{
|
rtems_bdpool_id j;
|
rtems_bdpool_id j;
|
for (j = 0; j < i - 1; j++)
|
for (j = 0; j < i - 1; j++)
|
{
|
{
|
bdbuf_release_pool(j);
|
bdbuf_release_pool(j);
|
}
|
}
|
return rc;
|
return rc;
|
}
|
}
|
}
|
}
|
|
|
/* Create buffer flush semaphore */
|
/* Create buffer flush semaphore */
|
rc = rtems_semaphore_create(
|
rc = rtems_semaphore_create(
|
rtems_build_name('B', 'F', 'L', 'U'), 0,
|
rtems_build_name('B', 'F', 'L', 'U'), 0,
|
RTEMS_FIFO | RTEMS_COUNTING_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY |
|
RTEMS_FIFO | RTEMS_COUNTING_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY |
|
RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL, 0,
|
RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL, 0,
|
&bd_ctx.flush_sema);
|
&bd_ctx.flush_sema);
|
if (rc != RTEMS_SUCCESSFUL)
|
if (rc != RTEMS_SUCCESSFUL)
|
{
|
{
|
for (i = 0; i < size; i++)
|
for (i = 0; i < size; i++)
|
bdbuf_release_pool(i);
|
bdbuf_release_pool(i);
|
free(bd_ctx.pool);
|
free(bd_ctx.pool);
|
return rc;
|
return rc;
|
}
|
}
|
|
|
/* Create and start swapout task */
|
/* Create and start swapout task */
|
rc = rtems_task_create(
|
rc = rtems_task_create(
|
rtems_build_name('B', 'S', 'W', 'P'),
|
rtems_build_name('B', 'S', 'W', 'P'),
|
SWAPOUT_PRIORITY,
|
SWAPOUT_PRIORITY,
|
SWAPOUT_STACK_SIZE,
|
SWAPOUT_STACK_SIZE,
|
RTEMS_DEFAULT_MODES | RTEMS_NO_PREEMPT,
|
RTEMS_DEFAULT_MODES | RTEMS_NO_PREEMPT,
|
RTEMS_DEFAULT_ATTRIBUTES,
|
RTEMS_DEFAULT_ATTRIBUTES,
|
&bd_ctx.swapout_task);
|
&bd_ctx.swapout_task);
|
if (rc != RTEMS_SUCCESSFUL)
|
if (rc != RTEMS_SUCCESSFUL)
|
{
|
{
|
rtems_semaphore_delete(bd_ctx.flush_sema);
|
rtems_semaphore_delete(bd_ctx.flush_sema);
|
for (i = 0; i < size; i++)
|
for (i = 0; i < size; i++)
|
bdbuf_release_pool(i);
|
bdbuf_release_pool(i);
|
free(bd_ctx.pool);
|
free(bd_ctx.pool);
|
return rc;
|
return rc;
|
}
|
}
|
|
|
rc = rtems_task_start(bd_ctx.swapout_task, bdbuf_swapout_task, 0);
|
rc = rtems_task_start(bd_ctx.swapout_task, bdbuf_swapout_task, 0);
|
if (rc != RTEMS_SUCCESSFUL)
|
if (rc != RTEMS_SUCCESSFUL)
|
{
|
{
|
rtems_task_delete(bd_ctx.swapout_task);
|
rtems_task_delete(bd_ctx.swapout_task);
|
rtems_semaphore_delete(bd_ctx.flush_sema);
|
rtems_semaphore_delete(bd_ctx.flush_sema);
|
for (i = 0; i < size; i++)
|
for (i = 0; i < size; i++)
|
bdbuf_release_pool(i);
|
bdbuf_release_pool(i);
|
free(bd_ctx.pool);
|
free(bd_ctx.pool);
|
return rc;
|
return rc;
|
}
|
}
|
|
|
return RTEMS_SUCCESSFUL;
|
return RTEMS_SUCCESSFUL;
|
}
|
}
|
|
|
/* find_or_assign_buffer --
|
/* find_or_assign_buffer --
|
* Looks for buffer already assigned for this dev/block. If one is found
|
* Looks for buffer already assigned for this dev/block. If one is found
|
* obtain block buffer. If specified block already cached (i.e. there's
|
* obtain block buffer. If specified block already cached (i.e. there's
|
* block in the _modified_, or _recently_used_), return address
|
* block in the _modified_, or _recently_used_), return address
|
* of appropriate buffer descriptor and increment reference counter to 1.
|
* of appropriate buffer descriptor and increment reference counter to 1.
|
* If block is not cached, allocate new buffer and return it. Data
|
* If block is not cached, allocate new buffer and return it. Data
|
* shouldn't be read to the buffer from media; buffer contains arbitrary
|
* shouldn't be read to the buffer from media; buffer contains arbitrary
|
* data. This primitive may be blocked if there are no free buffer
|
* data. This primitive may be blocked if there are no free buffer
|
* descriptors available and there are no unused non-modified (or
|
* descriptors available and there are no unused non-modified (or
|
* synchronized with media) buffers available.
|
* synchronized with media) buffers available.
|
*
|
*
|
* PARAMETERS:
|
* PARAMETERS:
|
* device - device number (constructed of major and minor device number
|
* device - device number (constructed of major and minor device number
|
* block - linear media block number
|
* block - linear media block number
|
* ret_buf - address of the variable to store address of found descriptor
|
* ret_buf - address of the variable to store address of found descriptor
|
*
|
*
|
* RETURNS:
|
* RETURNS:
|
* RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
|
* RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
|
* or error code if error is occured)
|
* or error code if error is occured)
|
*
|
*
|
* SIDE EFFEECTS:
|
* SIDE EFFEECTS:
|
* bufget_sema may be obtained by this primitive
|
* bufget_sema may be obtained by this primitive
|
*
|
*
|
* NOTE:
|
* NOTE:
|
* It is assumed that primitive invoked when thread preemption is disabled.
|
* It is assumed that primitive invoked when thread preemption is disabled.
|
*/
|
*/
|
static rtems_status_code
|
static rtems_status_code
|
find_or_assign_buffer(disk_device *dd,
|
find_or_assign_buffer(disk_device *dd,
|
blkdev_bnum block,
|
blkdev_bnum block,
|
bdbuf_buffer **ret_buf)
|
bdbuf_buffer **ret_buf)
|
{
|
{
|
bdbuf_buffer *bd_buf;
|
bdbuf_buffer *bd_buf;
|
bdbuf_pool *bd_pool;
|
bdbuf_pool *bd_pool;
|
rtems_status_code rc;
|
rtems_status_code rc;
|
dev_t device;
|
dev_t device;
|
ISR_Level level;
|
ISR_Level level;
|
|
|
int blksize;
|
int blksize;
|
|
|
device = dd->dev;
|
device = dd->dev;
|
bd_pool = bd_ctx.pool + dd->pool;
|
bd_pool = bd_ctx.pool + dd->pool;
|
blksize = dd->block_size;
|
blksize = dd->block_size;
|
|
|
again:
|
again:
|
/* Looking for buffer descriptor used for this dev/block. */
|
/* Looking for buffer descriptor used for this dev/block. */
|
bd_buf = avl_search(&bd_pool->tree, device, block);
|
bd_buf = avl_search(&bd_pool->tree, device, block);
|
|
|
if (bd_buf == NULL)
|
if (bd_buf == NULL)
|
{
|
{
|
/* Try to obtain semaphore without waiting first. It is the most
|
/* Try to obtain semaphore without waiting first. It is the most
|
frequent case when reasonable number of buffers configured. If
|
frequent case when reasonable number of buffers configured. If
|
it is failed, obtain semaphore blocking on it. In this case
|
it is failed, obtain semaphore blocking on it. In this case
|
it should be checked that appropriate buffer hasn't been loaded
|
it should be checked that appropriate buffer hasn't been loaded
|
by another thread, because this thread is preempted */
|
by another thread, because this thread is preempted */
|
rc = rtems_semaphore_obtain(bd_pool->bufget_sema, RTEMS_NO_WAIT, 0);
|
rc = rtems_semaphore_obtain(bd_pool->bufget_sema, RTEMS_NO_WAIT, 0);
|
if (rc == RTEMS_UNSATISFIED)
|
if (rc == RTEMS_UNSATISFIED)
|
{
|
{
|
rc = rtems_semaphore_obtain(bd_pool->bufget_sema,
|
rc = rtems_semaphore_obtain(bd_pool->bufget_sema,
|
RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
bd_buf = avl_search(&bd_pool->tree, device, block);
|
bd_buf = avl_search(&bd_pool->tree, device, block);
|
if (bd_buf != NULL)
|
if (bd_buf != NULL)
|
rtems_semaphore_release(bd_pool->bufget_sema);
|
rtems_semaphore_release(bd_pool->bufget_sema);
|
}
|
}
|
}
|
}
|
|
|
if (bd_buf == NULL)
|
if (bd_buf == NULL)
|
{
|
{
|
/* Assign new buffer descriptor */
|
/* Assign new buffer descriptor */
|
if (_Chain_Is_empty(&bd_pool->free))
|
if (_Chain_Is_empty(&bd_pool->free))
|
{
|
{
|
bd_buf = (bdbuf_buffer *)Chain_Get(&bd_pool->lru);
|
bd_buf = (bdbuf_buffer *)Chain_Get(&bd_pool->lru);
|
if (bd_buf != NULL)
|
if (bd_buf != NULL)
|
{
|
{
|
int avl_result;
|
int avl_result;
|
avl_result = avl_remove(&bd_pool->tree, bd_buf);
|
avl_result = avl_remove(&bd_pool->tree, bd_buf);
|
if (avl_result != 0)
|
if (avl_result != 0)
|
{
|
{
|
rtems_fatal_error_occurred(BLKDEV_FATAL_BDBUF_CONSISTENCY);
|
rtems_fatal_error_occurred(BLKDEV_FATAL_BDBUF_CONSISTENCY);
|
return RTEMS_INTERNAL_ERROR;
|
return RTEMS_INTERNAL_ERROR;
|
}
|
}
|
}
|
}
|
}
|
}
|
else
|
else
|
{
|
{
|
bd_buf = (bdbuf_buffer *)Chain_Get(&(bd_pool->free));
|
bd_buf = (bdbuf_buffer *)Chain_Get(&(bd_pool->free));
|
}
|
}
|
|
|
if (bd_buf == NULL)
|
if (bd_buf == NULL)
|
{
|
{
|
goto again;
|
goto again;
|
}
|
}
|
else
|
else
|
{
|
{
|
bd_buf->dev = device;
|
bd_buf->dev = device;
|
bd_buf->block = block;
|
bd_buf->block = block;
|
#ifdef AVL_GPL
|
#ifdef AVL_GPL
|
bd_buf->avl.link[0] = NULL;
|
bd_buf->avl.link[0] = NULL;
|
bd_buf->avl.link[1] = NULL;
|
bd_buf->avl.link[1] = NULL;
|
#else
|
#else
|
bd_buf->avl.left = NULL;
|
bd_buf->avl.left = NULL;
|
bd_buf->avl.right = NULL;
|
bd_buf->avl.right = NULL;
|
#endif
|
#endif
|
bd_buf->use_count = 1;
|
bd_buf->use_count = 1;
|
bd_buf->modified = bd_buf->actual = bd_buf->in_progress = FALSE;
|
bd_buf->modified = bd_buf->actual = bd_buf->in_progress = FALSE;
|
bd_buf->status = RTEMS_SUCCESSFUL;
|
bd_buf->status = RTEMS_SUCCESSFUL;
|
|
|
if (avl_insert(&bd_pool->tree, bd_buf) != 0)
|
if (avl_insert(&bd_pool->tree, bd_buf) != 0)
|
{
|
{
|
rtems_fatal_error_occurred(BLKDEV_FATAL_BDBUF_CONSISTENCY);
|
rtems_fatal_error_occurred(BLKDEV_FATAL_BDBUF_CONSISTENCY);
|
return RTEMS_INTERNAL_ERROR;
|
return RTEMS_INTERNAL_ERROR;
|
}
|
}
|
|
|
*ret_buf = bd_buf;
|
*ret_buf = bd_buf;
|
|
|
return RTEMS_SUCCESSFUL;
|
return RTEMS_SUCCESSFUL;
|
}
|
}
|
}
|
}
|
else
|
else
|
{
|
{
|
/* Buffer descriptor already assigned for this dev/block */
|
/* Buffer descriptor already assigned for this dev/block */
|
if (bd_buf->use_count == 0)
|
if (bd_buf->use_count == 0)
|
{
|
{
|
/* If we are removing from lru list, obtain the bufget_sema
|
/* If we are removing from lru list, obtain the bufget_sema
|
* first. If we are removing from mod list, obtain flush sema.
|
* first. If we are removing from mod list, obtain flush sema.
|
* It should be obtained without blocking because we know
|
* It should be obtained without blocking because we know
|
* that our buffer descriptor is in the list. */
|
* that our buffer descriptor is in the list. */
|
if (bd_buf->modified)
|
if (bd_buf->modified)
|
{
|
{
|
rc = rtems_semaphore_obtain(bd_ctx.flush_sema,
|
rc = rtems_semaphore_obtain(bd_ctx.flush_sema,
|
RTEMS_NO_WAIT, 0);
|
RTEMS_NO_WAIT, 0);
|
}
|
}
|
else
|
else
|
{
|
{
|
rc = rtems_semaphore_obtain(bd_pool->bufget_sema,
|
rc = rtems_semaphore_obtain(bd_pool->bufget_sema,
|
RTEMS_NO_WAIT, 0);
|
RTEMS_NO_WAIT, 0);
|
}
|
}
|
/* It is possible that we couldn't obtain flush or bufget sema
|
/* It is possible that we couldn't obtain flush or bufget sema
|
* although buffer in the appropriate chain is available:
|
* although buffer in the appropriate chain is available:
|
* semaphore may be released to swapout task, but this task
|
* semaphore may be released to swapout task, but this task
|
* actually did not start to process it. */
|
* actually did not start to process it. */
|
if (rc == RTEMS_UNSATISFIED)
|
if (rc == RTEMS_UNSATISFIED)
|
rc = RTEMS_SUCCESSFUL;
|
rc = RTEMS_SUCCESSFUL;
|
if (rc != RTEMS_SUCCESSFUL)
|
if (rc != RTEMS_SUCCESSFUL)
|
{
|
{
|
rtems_fatal_error_occurred(BLKDEV_FATAL_BDBUF_CONSISTENCY);
|
rtems_fatal_error_occurred(BLKDEV_FATAL_BDBUF_CONSISTENCY);
|
return RTEMS_INTERNAL_ERROR;
|
return RTEMS_INTERNAL_ERROR;
|
}
|
}
|
|
|
/* Buffer descriptor is linked to the lru or mod chain. Remove
|
/* Buffer descriptor is linked to the lru or mod chain. Remove
|
it from there. */
|
it from there. */
|
Chain_Extract(&bd_buf->link);
|
Chain_Extract(&bd_buf->link);
|
}
|
}
|
bd_buf->use_count++;
|
bd_buf->use_count++;
|
while (bd_buf->in_progress != 0)
|
while (bd_buf->in_progress != 0)
|
{
|
{
|
rtems_interrupt_disable(level);
|
rtems_interrupt_disable(level);
|
_CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE,
|
_CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE,
|
WATCHDOG_NO_TIMEOUT, level);
|
WATCHDOG_NO_TIMEOUT, level);
|
}
|
}
|
|
|
*ret_buf = bd_buf;
|
*ret_buf = bd_buf;
|
return RTEMS_SUCCESSFUL;
|
return RTEMS_SUCCESSFUL;
|
}
|
}
|
}
|
}
|
|
|
/* rtems_bdbuf_get --
|
/* rtems_bdbuf_get --
|
* Obtain block buffer. If specified block already cached (i.e. there's
|
* Obtain block buffer. If specified block already cached (i.e. there's
|
* block in the _modified_, or _recently_used_), return address
|
* block in the _modified_, or _recently_used_), return address
|
* of appropriate buffer descriptor and increment reference counter to 1.
|
* of appropriate buffer descriptor and increment reference counter to 1.
|
* If block is not cached, allocate new buffer and return it. Data
|
* If block is not cached, allocate new buffer and return it. Data
|
* shouldn't be read to the buffer from media; buffer may contains
|
* shouldn't be read to the buffer from media; buffer may contains
|
* arbitrary data. This primitive may be blocked if there are no free
|
* arbitrary data. This primitive may be blocked if there are no free
|
* buffer descriptors available and there are no unused non-modified
|
* buffer descriptors available and there are no unused non-modified
|
* (or synchronized with media) buffers available.
|
* (or synchronized with media) buffers available.
|
*
|
*
|
* PARAMETERS:
|
* PARAMETERS:
|
* device - device number (constructed of major and minor device number)
|
* device - device number (constructed of major and minor device number)
|
* block - linear media block number
|
* block - linear media block number
|
* bd - address of variable to store pointer to the buffer descriptor
|
* bd - address of variable to store pointer to the buffer descriptor
|
*
|
*
|
* RETURNS:
|
* RETURNS:
|
* RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
|
* RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
|
* or error code if error is occured)
|
* or error code if error is occured)
|
*
|
*
|
* SIDE EFFECTS:
|
* SIDE EFFECTS:
|
* bufget_sema semaphore obtained by this primitive.
|
* bufget_sema semaphore obtained by this primitive.
|
*/
|
*/
|
rtems_status_code
|
rtems_status_code
|
rtems_bdbuf_get(dev_t device, blkdev_bnum block, bdbuf_buffer **bd)
|
rtems_bdbuf_get(dev_t device, blkdev_bnum block, bdbuf_buffer **bd)
|
{
|
{
|
rtems_status_code rc;
|
rtems_status_code rc;
|
disk_device *dd;
|
disk_device *dd;
|
disk_device *pdd;
|
disk_device *pdd;
|
preemption_key key;
|
preemption_key key;
|
|
|
/*
|
/*
|
* Convert logical dev/block to physical one
|
* Convert logical dev/block to physical one
|
*/
|
*/
|
dd = rtems_disk_lookup(device);
|
dd = rtems_disk_lookup(device);
|
if (dd == NULL)
|
if (dd == NULL)
|
return RTEMS_INVALID_ID;
|
return RTEMS_INVALID_ID;
|
|
|
if (block >= dd->size)
|
if (block >= dd->size)
|
{
|
{
|
rtems_disk_release(dd);
|
rtems_disk_release(dd);
|
return RTEMS_INVALID_NUMBER;
|
return RTEMS_INVALID_NUMBER;
|
}
|
}
|
|
|
pdd = dd->phys_dev;
|
pdd = dd->phys_dev;
|
block += dd->start;
|
block += dd->start;
|
rtems_disk_release(dd);
|
rtems_disk_release(dd);
|
|
|
DISABLE_PREEMPTION(key);
|
DISABLE_PREEMPTION(key);
|
rc = find_or_assign_buffer(pdd, block, bd);
|
rc = find_or_assign_buffer(pdd, block, bd);
|
ENABLE_PREEMPTION(key);
|
ENABLE_PREEMPTION(key);
|
|
|
if (rc != RTEMS_SUCCESSFUL)
|
if (rc != RTEMS_SUCCESSFUL)
|
return rc;
|
return rc;
|
|
|
return RTEMS_SUCCESSFUL;
|
return RTEMS_SUCCESSFUL;
|
}
|
}
|
|
|
/* bdbuf_initialize_transfer_sema --
|
/* bdbuf_initialize_transfer_sema --
|
* Initialize transfer_sema mutex semaphore associated with buffer
|
* Initialize transfer_sema mutex semaphore associated with buffer
|
* descriptor.
|
* descriptor.
|
*/
|
*/
|
static inline void
|
static inline void
|
bdbuf_initialize_transfer_sema(bdbuf_buffer *bd_buf)
|
bdbuf_initialize_transfer_sema(bdbuf_buffer *bd_buf)
|
{
|
{
|
CORE_mutex_Attributes mutex_attr;
|
CORE_mutex_Attributes mutex_attr;
|
mutex_attr.lock_nesting_behavior = CORE_MUTEX_NESTING_BLOCKS;
|
mutex_attr.lock_nesting_behavior = CORE_MUTEX_NESTING_BLOCKS;
|
mutex_attr.only_owner_release = FALSE;
|
mutex_attr.only_owner_release = FALSE;
|
mutex_attr.discipline = CORE_MUTEX_DISCIPLINES_FIFO;
|
mutex_attr.discipline = CORE_MUTEX_DISCIPLINES_FIFO;
|
mutex_attr.priority_ceiling = 0;
|
mutex_attr.priority_ceiling = 0;
|
|
|
_CORE_mutex_Initialize(&bd_buf->transfer_sema,
|
_CORE_mutex_Initialize(&bd_buf->transfer_sema,
|
&mutex_attr, CORE_MUTEX_LOCKED);
|
&mutex_attr, CORE_MUTEX_LOCKED);
|
}
|
}
|
|
|
/* bdbuf_write_transfer_done --
|
/* bdbuf_write_transfer_done --
|
* Callout function. Invoked by block device driver when data transfer
|
* Callout function. Invoked by block device driver when data transfer
|
* to device (write) is completed. This function may be invoked from
|
* to device (write) is completed. This function may be invoked from
|
* interrupt handler.
|
* interrupt handler.
|
*
|
*
|
* PARAMETERS:
|
* PARAMETERS:
|
* arg - arbitrary argument specified in block device request
|
* arg - arbitrary argument specified in block device request
|
* structure (in this case - pointer to the appropriate
|
* structure (in this case - pointer to the appropriate
|
* bdbuf_buffer buffer descriptor structure).
|
* bdbuf_buffer buffer descriptor structure).
|
* status - I/O completion status
|
* status - I/O completion status
|
* error - errno error code if status != RTEMS_SUCCESSFUL
|
* error - errno error code if status != RTEMS_SUCCESSFUL
|
*
|
*
|
* RETURNS:
|
* RETURNS:
|
* none
|
* none
|
*/
|
*/
|
static void
|
static void
|
bdbuf_write_transfer_done(void *arg, rtems_status_code status, int error)
|
bdbuf_write_transfer_done(void *arg, rtems_status_code status, int error)
|
{
|
{
|
bdbuf_buffer *bd_buf = arg;
|
bdbuf_buffer *bd_buf = arg;
|
bd_buf->status = status;
|
bd_buf->status = status;
|
bd_buf->error = error;
|
bd_buf->error = error;
|
bd_buf->in_progress = bd_buf->modified = FALSE;
|
bd_buf->in_progress = bd_buf->modified = FALSE;
|
_CORE_mutex_Surrender(&bd_buf->transfer_sema, 0, NULL);
|
_CORE_mutex_Surrender(&bd_buf->transfer_sema, 0, NULL);
|
_CORE_mutex_Flush(&bd_buf->transfer_sema, NULL,
|
_CORE_mutex_Flush(&bd_buf->transfer_sema, NULL,
|
CORE_MUTEX_STATUS_SUCCESSFUL);
|
CORE_MUTEX_STATUS_SUCCESSFUL);
|
}
|
}
|
|
|
/* bdbuf_read_transfer_done --
|
/* bdbuf_read_transfer_done --
|
* Callout function. Invoked by block device driver when data transfer
|
* Callout function. Invoked by block device driver when data transfer
|
* from device (read) is completed. This function may be invoked from
|
* from device (read) is completed. This function may be invoked from
|
* interrupt handler.
|
* interrupt handler.
|
*
|
*
|
* PARAMETERS:
|
* PARAMETERS:
|
* arg - arbitrary argument specified in block device request
|
* arg - arbitrary argument specified in block device request
|
* structure (in this case - pointer to the appropriate
|
* structure (in this case - pointer to the appropriate
|
* bdbuf_buffer buffer descriptor structure).
|
* bdbuf_buffer buffer descriptor structure).
|
* status - I/O completion status
|
* status - I/O completion status
|
* error - errno error code if status != RTEMS_SUCCESSFUL
|
* error - errno error code if status != RTEMS_SUCCESSFUL
|
*
|
*
|
* RETURNS:
|
* RETURNS:
|
* none
|
* none
|
*/
|
*/
|
static void
|
static void
|
bdbuf_read_transfer_done(void *arg, rtems_status_code status, int error)
|
bdbuf_read_transfer_done(void *arg, rtems_status_code status, int error)
|
{
|
{
|
bdbuf_buffer *bd_buf = arg;
|
bdbuf_buffer *bd_buf = arg;
|
bd_buf->status = status;
|
bd_buf->status = status;
|
bd_buf->error = error;
|
bd_buf->error = error;
|
_CORE_mutex_Surrender(&bd_buf->transfer_sema, 0, NULL);
|
_CORE_mutex_Surrender(&bd_buf->transfer_sema, 0, NULL);
|
_CORE_mutex_Flush(&bd_buf->transfer_sema, NULL,
|
_CORE_mutex_Flush(&bd_buf->transfer_sema, NULL,
|
CORE_MUTEX_STATUS_SUCCESSFUL);
|
CORE_MUTEX_STATUS_SUCCESSFUL);
|
}
|
}
|
|
|
/* rtems_bdbuf_read --
|
/* rtems_bdbuf_read --
|
* (Similar to the rtems_bdbuf_get, except reading data from media)
|
* (Similar to the rtems_bdbuf_get, except reading data from media)
|
* Obtain block buffer. If specified block already cached, return address
|
* Obtain block buffer. If specified block already cached, return address
|
* of appropriate buffer and increment reference counter to 1. If block is
|
* of appropriate buffer and increment reference counter to 1. If block is
|
* not cached, allocate new buffer and read data to it from the media.
|
* not cached, allocate new buffer and read data to it from the media.
|
* This primitive may be blocked on waiting until data to be read from
|
* This primitive may be blocked on waiting until data to be read from
|
* media, if there are no free buffer descriptors available and there are
|
* media, if there are no free buffer descriptors available and there are
|
* no unused non-modified (or synchronized with media) buffers available.
|
* no unused non-modified (or synchronized with media) buffers available.
|
*
|
*
|
* PARAMETERS:
|
* PARAMETERS:
|
* device - device number (consists of major and minor device number)
|
* device - device number (consists of major and minor device number)
|
* block - linear media block number
|
* block - linear media block number
|
* bd - address of variable to store pointer to the buffer descriptor
|
* bd - address of variable to store pointer to the buffer descriptor
|
*
|
*
|
* RETURNS:
|
* RETURNS:
|
* RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
|
* RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
|
* or error code if error is occured)
|
* or error code if error is occured)
|
*
|
*
|
* SIDE EFFECTS:
|
* SIDE EFFECTS:
|
* bufget_sema and transfer_sema semaphores obtained by this primitive.
|
* bufget_sema and transfer_sema semaphores obtained by this primitive.
|
*/
|
*/
|
rtems_status_code
|
rtems_status_code
|
rtems_bdbuf_read(dev_t device,
|
rtems_bdbuf_read(dev_t device,
|
blkdev_bnum block,
|
blkdev_bnum block,
|
bdbuf_buffer **bd)
|
bdbuf_buffer **bd)
|
{
|
{
|
preemption_key key;
|
preemption_key key;
|
ISR_Level level;
|
ISR_Level level;
|
|
|
bdbuf_buffer *bd_buf;
|
bdbuf_buffer *bd_buf;
|
rtems_status_code rc;
|
rtems_status_code rc;
|
int result;
|
int result;
|
disk_device *dd;
|
disk_device *dd;
|
disk_device *pdd;
|
disk_device *pdd;
|
blkdev_request1 req;
|
blkdev_request1 req;
|
|
|
dd = rtems_disk_lookup(device);
|
dd = rtems_disk_lookup(device);
|
if (dd == NULL)
|
if (dd == NULL)
|
return RTEMS_INVALID_ID;
|
return RTEMS_INVALID_ID;
|
|
|
if (block >= dd->size)
|
if (block >= dd->size)
|
{
|
{
|
rtems_disk_release(dd);
|
rtems_disk_release(dd);
|
return RTEMS_INVALID_NUMBER;
|
return RTEMS_INVALID_NUMBER;
|
}
|
}
|
|
|
pdd = dd->phys_dev;
|
pdd = dd->phys_dev;
|
block += dd->start;
|
block += dd->start;
|
|
|
DISABLE_PREEMPTION(key);
|
DISABLE_PREEMPTION(key);
|
rc = find_or_assign_buffer(pdd, block, &bd_buf);
|
rc = find_or_assign_buffer(pdd, block, &bd_buf);
|
|
|
if (rc != RTEMS_SUCCESSFUL)
|
if (rc != RTEMS_SUCCESSFUL)
|
{
|
{
|
ENABLE_PREEMPTION(key);
|
ENABLE_PREEMPTION(key);
|
rtems_disk_release(dd);
|
rtems_disk_release(dd);
|
return rc;
|
return rc;
|
}
|
}
|
|
|
if (!bd_buf->actual)
|
if (!bd_buf->actual)
|
{
|
{
|
bd_buf->in_progress = 1;
|
bd_buf->in_progress = 1;
|
|
|
req.req.req = BLKDEV_REQ_READ;
|
req.req.req = BLKDEV_REQ_READ;
|
req.req.req_done = bdbuf_read_transfer_done;
|
req.req.req_done = bdbuf_read_transfer_done;
|
req.req.done_arg = bd_buf;
|
req.req.done_arg = bd_buf;
|
req.req.start = block;
|
req.req.start = block;
|
req.req.count = 1;
|
req.req.count = 1;
|
req.req.bufnum = 1;
|
req.req.bufnum = 1;
|
req.req.bufs[0].length = dd->block_size;
|
req.req.bufs[0].length = dd->block_size;
|
req.req.bufs[0].buffer = bd_buf->buffer;
|
req.req.bufs[0].buffer = bd_buf->buffer;
|
|
|
bdbuf_initialize_transfer_sema(bd_buf);
|
bdbuf_initialize_transfer_sema(bd_buf);
|
result = dd->ioctl(device, BLKIO_REQUEST, &req);
|
result = dd->ioctl(device, BLKIO_REQUEST, &req);
|
if (result == -1)
|
if (result == -1)
|
{
|
{
|
bd_buf->status = RTEMS_IO_ERROR;
|
bd_buf->status = RTEMS_IO_ERROR;
|
bd_buf->error = errno;
|
bd_buf->error = errno;
|
bd_buf->actual = FALSE;
|
bd_buf->actual = FALSE;
|
}
|
}
|
else
|
else
|
{
|
{
|
rtems_interrupt_disable(level);
|
rtems_interrupt_disable(level);
|
_CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE,
|
_CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE,
|
WATCHDOG_NO_TIMEOUT, level);
|
WATCHDOG_NO_TIMEOUT, level);
|
bd_buf->actual = TRUE;
|
bd_buf->actual = TRUE;
|
}
|
}
|
bd_buf->in_progress = FALSE;
|
bd_buf->in_progress = FALSE;
|
}
|
}
|
rtems_disk_release(dd);
|
rtems_disk_release(dd);
|
|
|
ENABLE_PREEMPTION(key);
|
ENABLE_PREEMPTION(key);
|
|
|
*bd = bd_buf;
|
*bd = bd_buf;
|
|
|
return RTEMS_SUCCESSFUL;
|
return RTEMS_SUCCESSFUL;
|
}
|
}
|
|
|
|
|
/* bdbuf_release --
|
/* bdbuf_release --
|
* Release buffer. Decrease buffer usage counter. If it is zero, further
|
* Release buffer. Decrease buffer usage counter. If it is zero, further
|
* processing depends on modified attribute. If buffer was modified, it
|
* processing depends on modified attribute. If buffer was modified, it
|
* is inserted into mod chain and swapout task waken up. If buffer was
|
* is inserted into mod chain and swapout task waken up. If buffer was
|
* not modified, it is returned to the end of lru chain making it available
|
* not modified, it is returned to the end of lru chain making it available
|
* for further use.
|
* for further use.
|
*
|
*
|
* PARAMETERS:
|
* PARAMETERS:
|
* bd_buf - pointer to the released buffer descriptor.
|
* bd_buf - pointer to the released buffer descriptor.
|
*
|
*
|
* RETURNS:
|
* RETURNS:
|
* RTEMS_SUCCESSFUL if buffer released successfully, or error code if
|
* RTEMS_SUCCESSFUL if buffer released successfully, or error code if
|
* error occured.
|
* error occured.
|
*
|
*
|
* NOTE:
|
* NOTE:
|
* This is internal function. It is assumed that task made non-preemptive
|
* This is internal function. It is assumed that task made non-preemptive
|
* before its invocation.
|
* before its invocation.
|
*/
|
*/
|
static rtems_status_code
|
static rtems_status_code
|
bdbuf_release(bdbuf_buffer *bd_buf)
|
bdbuf_release(bdbuf_buffer *bd_buf)
|
{
|
{
|
bdbuf_pool *bd_pool;
|
bdbuf_pool *bd_pool;
|
rtems_status_code rc = RTEMS_SUCCESSFUL;
|
rtems_status_code rc = RTEMS_SUCCESSFUL;
|
|
|
if (bd_buf->use_count <= 0)
|
if (bd_buf->use_count <= 0)
|
return RTEMS_INTERNAL_ERROR;
|
return RTEMS_INTERNAL_ERROR;
|
|
|
bd_pool = bd_ctx.pool + bd_buf->pool;
|
bd_pool = bd_ctx.pool + bd_buf->pool;
|
|
|
bd_buf->use_count--;
|
bd_buf->use_count--;
|
|
|
if (bd_buf->use_count == 0)
|
if (bd_buf->use_count == 0)
|
{
|
{
|
if (bd_buf->modified)
|
if (bd_buf->modified)
|
{
|
{
|
|
|
/* Buffer was modified. Insert buffer to the modified buffers
|
/* Buffer was modified. Insert buffer to the modified buffers
|
* list and initiate flushing. */
|
* list and initiate flushing. */
|
Chain_Append(&bd_ctx.mod, &bd_buf->link);
|
Chain_Append(&bd_ctx.mod, &bd_buf->link);
|
|
|
/* Release the flush_sema */
|
/* Release the flush_sema */
|
rc = rtems_semaphore_release(bd_ctx.flush_sema);
|
rc = rtems_semaphore_release(bd_ctx.flush_sema);
|
}
|
}
|
else
|
else
|
{
|
{
|
/* Buffer was not modified. Add this descriptor to the
|
/* Buffer was not modified. Add this descriptor to the
|
* end of lru chain and make it available for reuse. */
|
* end of lru chain and make it available for reuse. */
|
Chain_Append(&bd_pool->lru, &bd_buf->link);
|
Chain_Append(&bd_pool->lru, &bd_buf->link);
|
rc = rtems_semaphore_release(bd_pool->bufget_sema);
|
rc = rtems_semaphore_release(bd_pool->bufget_sema);
|
}
|
}
|
}
|
}
|
return rc;
|
return rc;
|
}
|
}
|
|
|
|
|
/* rtems_bdbuf_release --
|
/* rtems_bdbuf_release --
|
* Release buffer allocated before. This primitive decrease the
|
* Release buffer allocated before. This primitive decrease the
|
* usage counter. If it is zero, further destiny of buffer depends on
|
* usage counter. If it is zero, further destiny of buffer depends on
|
* 'modified' status. If buffer was modified, it is placed to the end of
|
* 'modified' status. If buffer was modified, it is placed to the end of
|
* mod list and flush task waken up. If buffer was not modified,
|
* mod list and flush task waken up. If buffer was not modified,
|
* it is placed to the end of lru list, and bufget_sema released, allowing
|
* it is placed to the end of lru list, and bufget_sema released, allowing
|
* to reuse this buffer.
|
* to reuse this buffer.
|
*
|
*
|
* PARAMETERS:
|
* PARAMETERS:
|
* bd_buf - pointer to the bdbuf_buffer structure previously obtained using
|
* bd_buf - pointer to the bdbuf_buffer structure previously obtained using
|
* get/read primitive.
|
* get/read primitive.
|
*
|
*
|
* RETURNS:
|
* RETURNS:
|
* RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
|
* RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
|
* or error code if error is occured)
|
* or error code if error is occured)
|
*
|
*
|
* SIDE EFFECTS:
|
* SIDE EFFECTS:
|
* flush_sema and bufget_sema semaphores may be released by this primitive.
|
* flush_sema and bufget_sema semaphores may be released by this primitive.
|
*/
|
*/
|
rtems_status_code
|
rtems_status_code
|
rtems_bdbuf_release(bdbuf_buffer *bd_buf)
|
rtems_bdbuf_release(bdbuf_buffer *bd_buf)
|
{
|
{
|
preemption_key key;
|
preemption_key key;
|
rtems_status_code rc = RTEMS_SUCCESSFUL;
|
rtems_status_code rc = RTEMS_SUCCESSFUL;
|
|
|
if (bd_buf == NULL)
|
if (bd_buf == NULL)
|
return RTEMS_INVALID_ADDRESS;
|
return RTEMS_INVALID_ADDRESS;
|
|
|
DISABLE_PREEMPTION(key);
|
DISABLE_PREEMPTION(key);
|
|
|
rc = bdbuf_release(bd_buf);
|
rc = bdbuf_release(bd_buf);
|
|
|
ENABLE_PREEMPTION(key);
|
ENABLE_PREEMPTION(key);
|
|
|
return rc;
|
return rc;
|
}
|
}
|
|
|
/* rtems_bdbuf_release_modified --
|
/* rtems_bdbuf_release_modified --
|
* Release buffer allocated before, assuming that it is _modified_ by
|
* Release buffer allocated before, assuming that it is _modified_ by
|
* it's owner. This primitive decrease usage counter for buffer, mark
|
* it's owner. This primitive decrease usage counter for buffer, mark
|
* buffer descriptor as modified. If usage counter is 0, insert it at
|
* buffer descriptor as modified. If usage counter is 0, insert it at
|
* end of mod chain and release flush_sema semaphore to activate the
|
* end of mod chain and release flush_sema semaphore to activate the
|
* flush task.
|
* flush task.
|
*
|
*
|
* PARAMETERS:
|
* PARAMETERS:
|
* bd_buf - pointer to the bdbuf_buffer structure previously obtained using
|
* bd_buf - pointer to the bdbuf_buffer structure previously obtained using
|
* get/read primitive.
|
* get/read primitive.
|
*
|
*
|
* RETURNS:
|
* RETURNS:
|
* RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
|
* RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
|
* or error code if error is occured)
|
* or error code if error is occured)
|
*
|
*
|
* SIDE EFFECTS:
|
* SIDE EFFECTS:
|
* flush_sema semaphore may be released by this primitive.
|
* flush_sema semaphore may be released by this primitive.
|
*/
|
*/
|
rtems_status_code
|
rtems_status_code
|
rtems_bdbuf_release_modified(bdbuf_buffer *bd_buf)
|
rtems_bdbuf_release_modified(bdbuf_buffer *bd_buf)
|
{
|
{
|
preemption_key key;
|
preemption_key key;
|
rtems_status_code rc = RTEMS_SUCCESSFUL;
|
rtems_status_code rc = RTEMS_SUCCESSFUL;
|
|
|
if (bd_buf == NULL)
|
if (bd_buf == NULL)
|
return RTEMS_INVALID_ADDRESS;
|
return RTEMS_INVALID_ADDRESS;
|
|
|
DISABLE_PREEMPTION(key);
|
DISABLE_PREEMPTION(key);
|
|
|
if (!bd_buf->modified)
|
if (!bd_buf->modified)
|
{
|
{
|
bdbuf_initialize_transfer_sema(bd_buf);
|
bdbuf_initialize_transfer_sema(bd_buf);
|
}
|
}
|
bd_buf->modified = TRUE;
|
bd_buf->modified = TRUE;
|
bd_buf->actual = TRUE;
|
bd_buf->actual = TRUE;
|
rc = bdbuf_release(bd_buf);
|
rc = bdbuf_release(bd_buf);
|
|
|
ENABLE_PREEMPTION(key);
|
ENABLE_PREEMPTION(key);
|
|
|
return rc;
|
return rc;
|
}
|
}
|
|
|
/* rtems_bdbuf_sync --
|
/* rtems_bdbuf_sync --
|
* Wait until specified buffer synchronized with disk. Invoked on exchanges
|
* Wait until specified buffer synchronized with disk. Invoked on exchanges
|
* critical for data consistency on the media. This primitive mark owned
|
* critical for data consistency on the media. This primitive mark owned
|
* block as modified, decrease usage counter. If usage counter is 0,
|
* block as modified, decrease usage counter. If usage counter is 0,
|
* block inserted to the mod chain and flush_sema semaphore released.
|
* block inserted to the mod chain and flush_sema semaphore released.
|
* Finally, primitives blocked on transfer_sema semaphore.
|
* Finally, primitives blocked on transfer_sema semaphore.
|
*
|
*
|
* PARAMETERS:
|
* PARAMETERS:
|
* bd_buf - pointer to the bdbuf_buffer structure previously obtained using
|
* bd_buf - pointer to the bdbuf_buffer structure previously obtained using
|
* get/read primitive.
|
* get/read primitive.
|
*
|
*
|
* RETURNS:
|
* RETURNS:
|
* RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
|
* RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
|
* or error code if error is occured)
|
* or error code if error is occured)
|
*
|
*
|
* SIDE EFFECTS:
|
* SIDE EFFECTS:
|
* Primitive may be blocked on transfer_sema semaphore.
|
* Primitive may be blocked on transfer_sema semaphore.
|
*/
|
*/
|
rtems_status_code
|
rtems_status_code
|
rtems_bdbuf_sync(bdbuf_buffer *bd_buf)
|
rtems_bdbuf_sync(bdbuf_buffer *bd_buf)
|
{
|
{
|
preemption_key key;
|
preemption_key key;
|
ISR_Level level;
|
ISR_Level level;
|
rtems_status_code rc = RTEMS_SUCCESSFUL;
|
rtems_status_code rc = RTEMS_SUCCESSFUL;
|
|
|
if (bd_buf == NULL)
|
if (bd_buf == NULL)
|
return RTEMS_INVALID_ADDRESS;
|
return RTEMS_INVALID_ADDRESS;
|
|
|
DISABLE_PREEMPTION(key);
|
DISABLE_PREEMPTION(key);
|
|
|
if (!bd_buf->modified)
|
if (!bd_buf->modified)
|
{
|
{
|
bdbuf_initialize_transfer_sema(bd_buf);
|
bdbuf_initialize_transfer_sema(bd_buf);
|
}
|
}
|
bd_buf->modified = TRUE;
|
bd_buf->modified = TRUE;
|
bd_buf->actual = TRUE;
|
bd_buf->actual = TRUE;
|
|
|
rc = bdbuf_release(bd_buf);
|
rc = bdbuf_release(bd_buf);
|
|
|
if (rc == RTEMS_SUCCESSFUL)
|
if (rc == RTEMS_SUCCESSFUL)
|
{
|
{
|
rtems_interrupt_disable(level);
|
rtems_interrupt_disable(level);
|
_CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE,
|
_CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE,
|
WATCHDOG_NO_TIMEOUT, level);
|
WATCHDOG_NO_TIMEOUT, level);
|
}
|
}
|
|
|
ENABLE_PREEMPTION(key);
|
ENABLE_PREEMPTION(key);
|
|
|
return rc;
|
return rc;
|
}
|
}
|
|
|
/* rtems_bdbuf_syncdev --
|
/* rtems_bdbuf_syncdev --
|
* Synchronize with disk all buffers containing the blocks belonging to
|
* Synchronize with disk all buffers containing the blocks belonging to
|
* specified device.
|
* specified device.
|
*
|
*
|
* PARAMETERS:
|
* PARAMETERS:
|
* dev - block device number
|
* dev - block device number
|
*
|
*
|
* RETURNS:
|
* RETURNS:
|
* RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
|
* RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully
|
* or error code if error is occured)
|
* or error code if error is occured)
|
*/
|
*/
|
rtems_status_code
|
rtems_status_code
|
rtems_bdbuf_syncdev(dev_t dev)
|
rtems_bdbuf_syncdev(dev_t dev)
|
{
|
{
|
preemption_key key;
|
preemption_key key;
|
ISR_Level level;
|
ISR_Level level;
|
|
|
bdbuf_buffer *bd_buf;
|
bdbuf_buffer *bd_buf;
|
disk_device *dd;
|
disk_device *dd;
|
bdbuf_pool *pool;
|
bdbuf_pool *pool;
|
|
|
dd = rtems_disk_lookup(dev);
|
dd = rtems_disk_lookup(dev);
|
if (dd == NULL)
|
if (dd == NULL)
|
return RTEMS_INVALID_ID;
|
return RTEMS_INVALID_ID;
|
|
|
pool = bd_ctx.pool + dd->pool;
|
pool = bd_ctx.pool + dd->pool;
|
|
|
DISABLE_PREEMPTION(key);
|
DISABLE_PREEMPTION(key);
|
do {
|
do {
|
bd_buf = avl_search_for_sync(&pool->tree, dd);
|
bd_buf = avl_search_for_sync(&pool->tree, dd);
|
if (bd_buf != NULL /* && bd_buf->modified */)
|
if (bd_buf != NULL /* && bd_buf->modified */)
|
{
|
{
|
rtems_interrupt_disable(level);
|
rtems_interrupt_disable(level);
|
_CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE,
|
_CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE,
|
WATCHDOG_NO_TIMEOUT, level);
|
WATCHDOG_NO_TIMEOUT, level);
|
}
|
}
|
} while (bd_buf != NULL);
|
} while (bd_buf != NULL);
|
ENABLE_PREEMPTION(key);
|
ENABLE_PREEMPTION(key);
|
return rtems_disk_release(dd);
|
return rtems_disk_release(dd);
|
}
|
}
|
|
|
/* bdbuf_swapout_task --
|
/* bdbuf_swapout_task --
|
* Body of task which take care on flushing modified buffers to the
|
* Body of task which take care on flushing modified buffers to the
|
* disk.
|
* disk.
|
*/
|
*/
|
static rtems_task
|
static rtems_task
|
bdbuf_swapout_task(rtems_task_argument unused)
|
bdbuf_swapout_task(rtems_task_argument unused)
|
{
|
{
|
rtems_status_code rc;
|
rtems_status_code rc;
|
int result;
|
int result;
|
ISR_Level level;
|
ISR_Level level;
|
bdbuf_buffer *bd_buf;
|
bdbuf_buffer *bd_buf;
|
bdbuf_pool *bd_pool;
|
bdbuf_pool *bd_pool;
|
disk_device *dd;
|
disk_device *dd;
|
blkdev_request1 req;
|
blkdev_request1 req;
|
|
|
while (1)
|
while (1)
|
{
|
{
|
rc = rtems_semaphore_obtain(bd_ctx.flush_sema, RTEMS_WAIT, 0);
|
rc = rtems_semaphore_obtain(bd_ctx.flush_sema, RTEMS_WAIT, 0);
|
if (rc != RTEMS_SUCCESSFUL)
|
if (rc != RTEMS_SUCCESSFUL)
|
{
|
{
|
rtems_fatal_error_occurred(BLKDEV_FATAL_BDBUF_SWAPOUT);
|
rtems_fatal_error_occurred(BLKDEV_FATAL_BDBUF_SWAPOUT);
|
}
|
}
|
|
|
bd_buf = (bdbuf_buffer *)Chain_Get(&bd_ctx.mod);
|
bd_buf = (bdbuf_buffer *)Chain_Get(&bd_ctx.mod);
|
if (bd_buf == NULL)
|
if (bd_buf == NULL)
|
{
|
{
|
/* It is possible that flush_sema semaphore will be released, but
|
/* It is possible that flush_sema semaphore will be released, but
|
* buffer to be removed from mod chain before swapout task start
|
* buffer to be removed from mod chain before swapout task start
|
* its processing. */
|
* its processing. */
|
continue;
|
continue;
|
}
|
}
|
|
|
bd_buf->in_progress = TRUE;
|
bd_buf->in_progress = TRUE;
|
bd_buf->use_count++;
|
bd_buf->use_count++;
|
bd_pool = bd_ctx.pool + bd_buf->pool;
|
bd_pool = bd_ctx.pool + bd_buf->pool;
|
dd = rtems_disk_lookup(bd_buf->dev);
|
dd = rtems_disk_lookup(bd_buf->dev);
|
|
|
req.req.req = BLKDEV_REQ_WRITE;
|
req.req.req = BLKDEV_REQ_WRITE;
|
req.req.req_done = bdbuf_write_transfer_done;
|
req.req.req_done = bdbuf_write_transfer_done;
|
req.req.done_arg = bd_buf;
|
req.req.done_arg = bd_buf;
|
req.req.start = bd_buf->block + dd->start;
|
req.req.start = bd_buf->block + dd->start;
|
req.req.count = 1;
|
req.req.count = 1;
|
req.req.bufnum = 1;
|
req.req.bufnum = 1;
|
req.req.bufs[0].length = dd->block_size;
|
req.req.bufs[0].length = dd->block_size;
|
req.req.bufs[0].buffer = bd_buf->buffer;
|
req.req.bufs[0].buffer = bd_buf->buffer;
|
|
|
/* transfer_sema initialized when bd_buf inserted in the mod chain
|
/* transfer_sema initialized when bd_buf inserted in the mod chain
|
first time */
|
first time */
|
result = dd->ioctl(dd->phys_dev->dev, BLKIO_REQUEST, &req);
|
result = dd->ioctl(dd->phys_dev->dev, BLKIO_REQUEST, &req);
|
|
|
rtems_disk_release(dd);
|
rtems_disk_release(dd);
|
|
|
if (result == -1)
|
if (result == -1)
|
{
|
{
|
bd_buf->status = RTEMS_IO_ERROR;
|
bd_buf->status = RTEMS_IO_ERROR;
|
bd_buf->error = errno;
|
bd_buf->error = errno;
|
/* Release tasks waiting on syncing this buffer */
|
/* Release tasks waiting on syncing this buffer */
|
_CORE_mutex_Flush(&bd_buf->transfer_sema, NULL,
|
_CORE_mutex_Flush(&bd_buf->transfer_sema, NULL,
|
CORE_MUTEX_STATUS_SUCCESSFUL);
|
CORE_MUTEX_STATUS_SUCCESSFUL);
|
}
|
}
|
else
|
else
|
{
|
{
|
if (bd_buf->in_progress)
|
if (bd_buf->in_progress)
|
{
|
{
|
rtems_interrupt_disable(level);
|
rtems_interrupt_disable(level);
|
_CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE, 0, level);
|
_CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE, 0, level);
|
}
|
}
|
}
|
}
|
bd_buf->use_count--;
|
bd_buf->use_count--;
|
|
|
/* Another task have chance to use this buffer, or even
|
/* Another task have chance to use this buffer, or even
|
* modify it. If buffer is not in use, insert it in appropriate chain
|
* modify it. If buffer is not in use, insert it in appropriate chain
|
* and release semaphore */
|
* and release semaphore */
|
if (bd_buf->use_count == 0)
|
if (bd_buf->use_count == 0)
|
{
|
{
|
if (bd_buf->modified)
|
if (bd_buf->modified)
|
{
|
{
|
Chain_Append(&bd_ctx.mod, &bd_buf->link);
|
Chain_Append(&bd_ctx.mod, &bd_buf->link);
|
rc = rtems_semaphore_release(bd_ctx.flush_sema);
|
rc = rtems_semaphore_release(bd_ctx.flush_sema);
|
}
|
}
|
else
|
else
|
{
|
{
|
Chain_Append(&bd_pool->lru, &bd_buf->link);
|
Chain_Append(&bd_pool->lru, &bd_buf->link);
|
rc = rtems_semaphore_release(bd_pool->bufget_sema);
|
rc = rtems_semaphore_release(bd_pool->bufget_sema);
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
/* rtems_bdbuf_find_pool --
|
/* rtems_bdbuf_find_pool --
|
* Find first appropriate buffer pool. This primitive returns the index
|
* Find first appropriate buffer pool. This primitive returns the index
|
* of first buffer pool which block size is greater than or equal to
|
* of first buffer pool which block size is greater than or equal to
|
* specified size.
|
* specified size.
|
*
|
*
|
* PARAMETERS:
|
* PARAMETERS:
|
* block_size - requested block size
|
* block_size - requested block size
|
* pool - placeholder for result
|
* pool - placeholder for result
|
*
|
*
|
* RETURNS:
|
* RETURNS:
|
* RTEMS status code: RTEMS_SUCCESSFUL if operation completed successfully,
|
* RTEMS status code: RTEMS_SUCCESSFUL if operation completed successfully,
|
* RTEMS_INVALID_SIZE if specified block size is invalid (not a power
|
* RTEMS_INVALID_SIZE if specified block size is invalid (not a power
|
* of 2), RTEMS_NOT_DEFINED if buffer pool for this or greater block size
|
* of 2), RTEMS_NOT_DEFINED if buffer pool for this or greater block size
|
* is not configured.
|
* is not configured.
|
*/
|
*/
|
rtems_status_code
|
rtems_status_code
|
rtems_bdbuf_find_pool(int block_size, rtems_bdpool_id *pool)
|
rtems_bdbuf_find_pool(int block_size, rtems_bdpool_id *pool)
|
{
|
{
|
rtems_bdpool_id i;
|
rtems_bdpool_id i;
|
bdbuf_pool *p;
|
bdbuf_pool *p;
|
int cursize = INT_MAX;
|
int cursize = INT_MAX;
|
rtems_bdpool_id curid = -1;
|
rtems_bdpool_id curid = -1;
|
rtems_boolean found = FALSE;
|
rtems_boolean found = FALSE;
|
int j;
|
int j;
|
|
|
for (j = block_size; (j != 0) && ((j & 1) == 0); j >>= 1);
|
for (j = block_size; (j != 0) && ((j & 1) == 0); j >>= 1);
|
if (j != 1)
|
if (j != 1)
|
return RTEMS_INVALID_SIZE;
|
return RTEMS_INVALID_SIZE;
|
|
|
for (i = 0, p = bd_ctx.pool; i < bd_ctx.npools; i++, p++)
|
for (i = 0, p = bd_ctx.pool; i < bd_ctx.npools; i++, p++)
|
{
|
{
|
if ((p->blksize >= block_size) &&
|
if ((p->blksize >= block_size) &&
|
(p->blksize < cursize))
|
(p->blksize < cursize))
|
{
|
{
|
curid = i;
|
curid = i;
|
cursize = p->blksize;
|
cursize = p->blksize;
|
found = TRUE;
|
found = TRUE;
|
}
|
}
|
}
|
}
|
|
|
if (found)
|
if (found)
|
{
|
{
|
if (pool != NULL)
|
if (pool != NULL)
|
*pool = curid;
|
*pool = curid;
|
return RTEMS_SUCCESSFUL;
|
return RTEMS_SUCCESSFUL;
|
}
|
}
|
else
|
else
|
{
|
{
|
return RTEMS_NOT_DEFINED;
|
return RTEMS_NOT_DEFINED;
|
}
|
}
|
}
|
}
|
|
|
/* rtems_bdbuf_get_pool_info --
|
/* rtems_bdbuf_get_pool_info --
|
* Obtain characteristics of buffer pool with specified number.
|
* Obtain characteristics of buffer pool with specified number.
|
*
|
*
|
* PARAMETERS:
|
* PARAMETERS:
|
* pool - buffer pool number
|
* pool - buffer pool number
|
* block_size - block size for which buffer pool is configured returned
|
* block_size - block size for which buffer pool is configured returned
|
* there
|
* there
|
* blocks - number of buffers in buffer pool returned there
|
* blocks - number of buffers in buffer pool returned there
|
*
|
*
|
* RETURNS:
|
* RETURNS:
|
* RTEMS status code: RTEMS_SUCCESSFUL if operation completed successfully,
|
* RTEMS status code: RTEMS_SUCCESSFUL if operation completed successfully,
|
* RTEMS_INVALID_NUMBER if appropriate buffer pool is not configured.
|
* RTEMS_INVALID_NUMBER if appropriate buffer pool is not configured.
|
*
|
*
|
* NOTE:
|
* NOTE:
|
* Buffer pools enumerated contiguously starting from 0.
|
* Buffer pools enumerated contiguously starting from 0.
|
*/
|
*/
|
rtems_status_code
|
rtems_status_code
|
rtems_bdbuf_get_pool_info(rtems_bdpool_id pool, int *block_size,
|
rtems_bdbuf_get_pool_info(rtems_bdpool_id pool, int *block_size,
|
int *blocks)
|
int *blocks)
|
{
|
{
|
if (pool >= bd_ctx.npools)
|
if (pool >= bd_ctx.npools)
|
return RTEMS_INVALID_NUMBER;
|
return RTEMS_INVALID_NUMBER;
|
|
|
if (block_size != NULL)
|
if (block_size != NULL)
|
{
|
{
|
*block_size = bd_ctx.pool[pool].blksize;
|
*block_size = bd_ctx.pool[pool].blksize;
|
}
|
}
|
|
|
if (blocks != NULL)
|
if (blocks != NULL)
|
{
|
{
|
*blocks = bd_ctx.pool[pool].nblks;
|
*blocks = bd_ctx.pool[pool].nblks;
|
}
|
}
|
|
|
return RTEMS_SUCCESSFUL;
|
return RTEMS_SUCCESSFUL;
|
}
|
}
|
|
|