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