📄 bdbuf.c
字号:
*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_codebdbuf_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_codertems_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_codertems_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_codertems_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_codertems_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_codertems_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_codertems_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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -