diff options
Diffstat (limited to 'cpukit/libblock/src/bdbuf.c')
-rw-r--r-- | cpukit/libblock/src/bdbuf.c | 347 |
1 files changed, 226 insertions, 121 deletions
diff --git a/cpukit/libblock/src/bdbuf.c b/cpukit/libblock/src/bdbuf.c index 4c53ff38c1..424b9a3481 100644 --- a/cpukit/libblock/src/bdbuf.c +++ b/cpukit/libblock/src/bdbuf.c @@ -134,6 +134,9 @@ typedef struct rtems_bdbuf_cache size_t group_count; /**< The number of groups. */ rtems_bdbuf_group* groups; /**< The groups. */ + rtems_id read_ahead_task; /**< Read-ahead task */ + rtems_chain_control read_ahead_chain; /**< Read-ahead request chain */ + bool read_ahead_enabled; /**< Read-ahead enabled */ bool initialised; /**< Initialised state. */ } rtems_bdbuf_cache; @@ -180,6 +183,7 @@ typedef struct rtems_bdbuf_cache #define RTEMS_BLKDEV_FATAL_BDBUF_STATE_0 RTEMS_BLKDEV_FATAL_ERROR(28) #define RTEMS_BLKDEV_FATAL_BDBUF_STATE_1 RTEMS_BLKDEV_FATAL_ERROR(29) #define RTEMS_BLKDEV_FATAL_BDBUF_STATE_2 RTEMS_BLKDEV_FATAL_ERROR(30) +#define RTEMS_BLKDEV_FATAL_BDBUF_RA_WAKE_UP RTEMS_BLKDEV_FATAL_ERROR(31) /** * The events used in this code. These should be system events rather than @@ -187,6 +191,7 @@ typedef struct rtems_bdbuf_cache */ #define RTEMS_BDBUF_TRANSFER_SYNC RTEMS_EVENT_1 #define RTEMS_BDBUF_SWAPOUT_SYNC RTEMS_EVENT_2 +#define RTEMS_BDBUF_READ_AHEAD_WAKE_UP RTEMS_EVENT_1 /** * Lock semaphore attributes. This is used for locking type mutexes. @@ -219,11 +224,10 @@ typedef struct rtems_bdbuf_cache (TOD_MICROSECONDS_TO_TICKS (20000000)) #endif -/* - * The swap out task. - */ static rtems_task rtems_bdbuf_swapout_task(rtems_task_argument arg); +static rtems_task rtems_bdbuf_read_ahead_task(rtems_task_argument arg); + /** * The Buffer Descriptor cache. */ @@ -1365,6 +1369,7 @@ rtems_bdbuf_init (void) rtems_chain_initialize_empty (&bdbuf_cache.lru); rtems_chain_initialize_empty (&bdbuf_cache.modified); rtems_chain_initialize_empty (&bdbuf_cache.sync); + rtems_chain_initialize_empty (&bdbuf_cache.read_ahead_chain); /* * Create the locks for the cache. @@ -1486,12 +1491,28 @@ rtems_bdbuf_init (void) if (sc != RTEMS_SUCCESSFUL) goto error; + if (bdbuf_config.max_read_ahead_blocks > 0) + { + bdbuf_cache.read_ahead_enabled = true; + sc = rtems_bdbuf_create_task (rtems_build_name('B', 'R', 'D', 'A'), + bdbuf_config.read_ahead_priority, + RTEMS_BDBUF_READ_AHEAD_TASK_PRIORITY_DEFAULT, + rtems_bdbuf_read_ahead_task, + 0, + &bdbuf_cache.read_ahead_task); + if (sc != RTEMS_SUCCESSFUL) + goto error; + } + rtems_bdbuf_unlock_cache (); return RTEMS_SUCCESSFUL; error: + if (bdbuf_cache.read_ahead_task != 0) + rtems_task_delete (bdbuf_cache.read_ahead_task); + if (bdbuf_cache.swapout != 0) rtems_task_delete (bdbuf_cache.swapout); @@ -1852,81 +1873,6 @@ rtems_bdbuf_transfer_done (void* arg, rtems_status_code status) rtems_event_send (req->io_task, RTEMS_BDBUF_TRANSFER_SYNC); } -static void -rtems_bdbuf_create_read_request (const rtems_disk_device *dd, - rtems_blkdev_bnum media_block, - rtems_blkdev_request *req, - rtems_bdbuf_buffer **bd_ptr) -{ - rtems_bdbuf_buffer *bd = NULL; - rtems_blkdev_bnum media_block_end = dd->start + dd->size; - rtems_blkdev_bnum media_block_count = dd->block_to_media_block_shift >= 0 ? - 1U << dd->block_to_media_block_shift - : dd->block_size / dd->media_block_size; - uint32_t block_size = dd->block_size; - uint32_t transfer_index = 1; - uint32_t transfer_count = bdbuf_config.max_read_ahead_blocks + 1; - - if (media_block_end - media_block < transfer_count) - transfer_count = media_block_end - media_block; - - req->req = RTEMS_BLKDEV_REQ_READ; - req->req_done = rtems_bdbuf_transfer_done; - req->done_arg = req; - req->io_task = rtems_task_self (); - req->status = RTEMS_RESOURCE_IN_USE; - req->bufnum = 0; - - bd = rtems_bdbuf_get_buffer_for_access (dd, media_block); - - *bd_ptr = bd; - - req->bufs [0].user = bd; - req->bufs [0].block = media_block; - req->bufs [0].length = block_size; - req->bufs [0].buffer = bd->buffer; - - if (rtems_bdbuf_tracer) - rtems_bdbuf_show_users ("read", bd); - - switch (bd->state) - { - case RTEMS_BDBUF_STATE_CACHED: - case RTEMS_BDBUF_STATE_MODIFIED: - return; - case RTEMS_BDBUF_STATE_EMPTY: - rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_TRANSFER); - break; - default: - rtems_bdbuf_fatal (bd->state, RTEMS_BLKDEV_FATAL_BDBUF_STATE_1); - break; - } - - while (transfer_index < transfer_count) - { - media_block += media_block_count; - - bd = rtems_bdbuf_get_buffer_for_read_ahead (dd, media_block); - - if (bd == NULL) - break; - - rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_TRANSFER); - - req->bufs [transfer_index].user = bd; - req->bufs [transfer_index].block = media_block; - req->bufs [transfer_index].length = block_size; - req->bufs [transfer_index].buffer = bd->buffer; - - if (rtems_bdbuf_tracer) - rtems_bdbuf_show_users ("read-ahead", bd); - - ++transfer_index; - } - - req->bufnum = transfer_index; -} - static rtems_status_code rtems_bdbuf_execute_transfer_request (const rtems_disk_device *dd, rtems_blkdev_request *req, @@ -1989,15 +1935,16 @@ rtems_bdbuf_execute_transfer_request (const rtems_disk_device *dd, return RTEMS_IO_ERROR; } -rtems_status_code -rtems_bdbuf_read (rtems_disk_device *dd, - rtems_blkdev_bnum block, - rtems_bdbuf_buffer **bd_ptr) +static rtems_status_code +rtems_bdbuf_execute_read_request (const rtems_disk_device *dd, + rtems_bdbuf_buffer *bd, + uint32_t transfer_count) { - rtems_status_code sc = RTEMS_SUCCESSFUL; rtems_blkdev_request *req = NULL; - rtems_bdbuf_buffer *bd = NULL; - rtems_blkdev_bnum media_block; + rtems_blkdev_bnum media_block = bd->block; + uint32_t media_blocks_per_block = dd->media_blocks_per_block; + uint32_t block_size = dd->block_size; + uint32_t transfer_index = 1; /* * TODO: This type of request structure is wrong and should be removed. @@ -2005,8 +1952,113 @@ rtems_bdbuf_read (rtems_disk_device *dd, #define bdbuf_alloc(size) __builtin_alloca (size) req = bdbuf_alloc (sizeof (rtems_blkdev_request) + - sizeof (rtems_blkdev_sg_buffer) * - (bdbuf_config.max_read_ahead_blocks + 1)); + sizeof (rtems_blkdev_sg_buffer) * transfer_count); + + req->req = RTEMS_BLKDEV_REQ_READ; + req->req_done = rtems_bdbuf_transfer_done; + req->done_arg = req; + req->io_task = rtems_task_self (); + req->status = RTEMS_RESOURCE_IN_USE; + req->bufnum = 0; + + rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_TRANSFER); + + req->bufs [0].user = bd; + req->bufs [0].block = media_block; + req->bufs [0].length = block_size; + req->bufs [0].buffer = bd->buffer; + + if (rtems_bdbuf_tracer) + rtems_bdbuf_show_users ("read", bd); + + while (transfer_index < transfer_count) + { + media_block += media_blocks_per_block; + + bd = rtems_bdbuf_get_buffer_for_read_ahead (dd, media_block); + + if (bd == NULL) + break; + + rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_TRANSFER); + + req->bufs [transfer_index].user = bd; + req->bufs [transfer_index].block = media_block; + req->bufs [transfer_index].length = block_size; + req->bufs [transfer_index].buffer = bd->buffer; + + if (rtems_bdbuf_tracer) + rtems_bdbuf_show_users ("read", bd); + + ++transfer_index; + } + + req->bufnum = transfer_index; + + return rtems_bdbuf_execute_transfer_request (dd, req, true); +} + +static bool +rtems_bdbuf_is_read_ahead_active (const rtems_disk_device *dd) +{ + return !rtems_chain_is_node_off_chain (&dd->read_ahead.node); +} + +static void +rtems_bdbuf_read_ahead_cancel (rtems_disk_device *dd) +{ + if (rtems_bdbuf_is_read_ahead_active (dd)) + { + rtems_chain_extract_unprotected (&dd->read_ahead.node); + rtems_chain_set_off_chain (&dd->read_ahead.node); + } +} + +static void +rtems_bdbuf_read_ahead_reset (rtems_disk_device *dd) +{ + rtems_bdbuf_read_ahead_cancel (dd); + dd->read_ahead.trigger = RTEMS_DISK_READ_AHEAD_NO_TRIGGER; +} + +static void +rtems_bdbuf_check_read_ahead_trigger (rtems_disk_device *dd, + rtems_blkdev_bnum block) +{ + if (dd->read_ahead.trigger == block + && !rtems_bdbuf_is_read_ahead_active (dd)) + { + rtems_status_code sc; + rtems_chain_control *chain = &bdbuf_cache.read_ahead_chain; + + rtems_chain_append_unprotected (chain, &dd->read_ahead.node); + sc = rtems_event_send (bdbuf_cache.read_ahead_task, + RTEMS_BDBUF_READ_AHEAD_WAKE_UP); + if (sc != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_RA_WAKE_UP); + } +} + +static void +rtems_bdbuf_set_read_ahead_trigger (rtems_disk_device *dd, + rtems_blkdev_bnum block) +{ + if (dd->read_ahead.trigger != block) + { + rtems_bdbuf_read_ahead_cancel (dd); + dd->read_ahead.trigger = block + 1; + dd->read_ahead.next = block + 2; + } +} + +rtems_status_code +rtems_bdbuf_read (rtems_disk_device *dd, + rtems_blkdev_bnum block, + rtems_bdbuf_buffer **bd_ptr) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + rtems_bdbuf_buffer *bd = NULL; + rtems_blkdev_bnum media_block; rtems_bdbuf_lock_cache (); @@ -2017,42 +2069,33 @@ rtems_bdbuf_read (rtems_disk_device *dd, printf ("bdbuf:read: %" PRIu32 " (%" PRIu32 ") (dev = %08x)\n", media_block + dd->start, block, (unsigned) dd->dev); - rtems_bdbuf_create_read_request (dd, media_block, req, &bd); - - if (req->bufnum > 0) - { - sc = rtems_bdbuf_execute_transfer_request (dd, req, true); - if (sc == RTEMS_SUCCESSFUL) - { - rtems_chain_extract_unprotected (&bd->link); - rtems_bdbuf_group_obtain (bd); - } - } - - if (sc == RTEMS_SUCCESSFUL) + rtems_bdbuf_check_read_ahead_trigger (dd, block); + bd = rtems_bdbuf_get_buffer_for_access (dd, media_block); + switch (bd->state) { - switch (bd->state) - { - case RTEMS_BDBUF_STATE_CACHED: + case RTEMS_BDBUF_STATE_CACHED: + rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_ACCESS_CACHED); + break; + case RTEMS_BDBUF_STATE_MODIFIED: + rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_ACCESS_MODIFIED); + break; + case RTEMS_BDBUF_STATE_EMPTY: + rtems_bdbuf_set_read_ahead_trigger (dd, block); + sc = rtems_bdbuf_execute_read_request (dd, bd, 1); + if (sc == RTEMS_SUCCESSFUL) + { rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_ACCESS_CACHED); - break; - case RTEMS_BDBUF_STATE_MODIFIED: - rtems_bdbuf_set_state (bd, RTEMS_BDBUF_STATE_ACCESS_MODIFIED); - break; - default: - rtems_bdbuf_fatal (bd->state, RTEMS_BLKDEV_FATAL_BDBUF_STATE_4); - break; - } - - if (rtems_bdbuf_tracer) - { - rtems_bdbuf_show_users ("read", bd); - rtems_bdbuf_show_usage (); - } - } - else - { - bd = NULL; + rtems_chain_extract_unprotected (&bd->link); + rtems_bdbuf_group_obtain (bd); + } + else + { + bd = NULL; + } + break; + default: + rtems_bdbuf_fatal (bd->state, RTEMS_BLKDEV_FATAL_BDBUF_STATE_4); + break; } } @@ -2884,6 +2927,7 @@ rtems_bdbuf_purge_dev (rtems_disk_device *dd) rtems_chain_initialize_empty (&purge_list); rtems_bdbuf_lock_cache (); + rtems_bdbuf_read_ahead_reset (dd); rtems_bdbuf_gather_for_purge (&purge_list, dd); rtems_bdbuf_purge_list (&purge_list); rtems_bdbuf_unlock_cache (); @@ -2919,6 +2963,8 @@ rtems_bdbuf_set_block_size (rtems_disk_device *dd, uint32_t block_size) dd->media_blocks_per_block = media_blocks_per_block; dd->block_to_media_block_shift = block_to_media_block_shift; dd->bds_per_group = bds_per_group; + + rtems_bdbuf_read_ahead_reset (dd); } else { @@ -2934,3 +2980,62 @@ rtems_bdbuf_set_block_size (rtems_disk_device *dd, uint32_t block_size) return sc; } + +static rtems_task +rtems_bdbuf_read_ahead_task (rtems_task_argument arg) +{ + rtems_chain_control *chain = &bdbuf_cache.read_ahead_chain; + + while (bdbuf_cache.read_ahead_enabled) + { + rtems_chain_node *node; + + rtems_bdbuf_wait_for_event (RTEMS_BDBUF_READ_AHEAD_WAKE_UP); + rtems_bdbuf_lock_cache (); + + while ((node = rtems_chain_get_unprotected (chain)) != NULL) + { + rtems_disk_device *dd = (rtems_disk_device *) + ((char *) node - offsetof (rtems_disk_device, read_ahead.node)); + rtems_blkdev_bnum block = dd->read_ahead.next; + rtems_blkdev_bnum media_block = 0; + rtems_status_code sc = + rtems_bdbuf_get_media_block (dd, block, &media_block); + + rtems_chain_set_off_chain (&dd->read_ahead.node); + + if (sc == RTEMS_SUCCESSFUL) + { + rtems_bdbuf_buffer *bd = + rtems_bdbuf_get_buffer_for_read_ahead (dd, media_block); + + if (bd != NULL) + { + uint32_t transfer_count = dd->block_count - block; + uint32_t max_transfer_count = bdbuf_config.max_read_ahead_blocks; + + if (transfer_count >= max_transfer_count) + { + transfer_count = max_transfer_count; + dd->read_ahead.trigger += max_transfer_count / 2 + 1; + dd->read_ahead.next += max_transfer_count; + } + else + { + dd->read_ahead.trigger = RTEMS_DISK_READ_AHEAD_NO_TRIGGER; + } + + rtems_bdbuf_execute_read_request (dd, bd, transfer_count); + } + } + else + { + dd->read_ahead.trigger = RTEMS_DISK_READ_AHEAD_NO_TRIGGER; + } + } + + rtems_bdbuf_unlock_cache (); + } + + rtems_task_delete (RTEMS_SELF); +} |