From b467782b5354c5d524f46bac84c5b70a8b4fa1f6 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 26 Mar 2012 14:58:35 +0200 Subject: libblock: Add rtems_bdbuf_set_block_size() The new function rtems_bdbuf_set_block_size() must be used to set the block size of a disk device. It will check if the block size is valid and set the new fields block_to_media_block_shift and bds_per_group of the rtems_disk_device structure. This helps to avoid complex arithmetic operations in the block device buffer get and read path. --- cpukit/libblock/include/rtems/bdbuf.h | 23 +++++- cpukit/libblock/include/rtems/diskdevs.h | 24 +++++- cpukit/libblock/src/bdbuf.c | 124 ++++++++++++++++++------------- cpukit/libblock/src/blkdev-imfs.c | 27 ++++--- cpukit/libblock/src/blkdev-ioctl.c | 23 +++--- cpukit/libblock/src/diskdevs.c | 29 ++++++-- 6 files changed, 165 insertions(+), 85 deletions(-) (limited to 'cpukit') diff --git a/cpukit/libblock/include/rtems/bdbuf.h b/cpukit/libblock/include/rtems/bdbuf.h index 8e672bbf73..134a0ceff5 100644 --- a/cpukit/libblock/include/rtems/bdbuf.h +++ b/cpukit/libblock/include/rtems/bdbuf.h @@ -479,7 +479,7 @@ rtems_bdbuf_init (void); * @param bd [out] Reference to the buffer descriptor pointer. * * @retval RTEMS_SUCCESSFUL Successful operation. - * @retval RTEMS_INVALID_NUMBER Invalid block size. + * @retval RTEMS_INVALID_ID Invalid block number. */ rtems_status_code rtems_bdbuf_get ( @@ -512,7 +512,7 @@ rtems_bdbuf_get ( * @param bd [out] Reference to the buffer descriptor pointer. * * @retval RTEMS_SUCCESSFUL Successful operation. - * @retval RTEMS_INVALID_NUMBER Invalid block size. + * @retval RTEMS_INVALID_ID Invalid block number. * @retval RTEMS_IO_ERROR IO error. */ rtems_status_code @@ -625,6 +625,25 @@ rtems_bdbuf_syncdev (const rtems_disk_device *dd); void rtems_bdbuf_purge_dev (const rtems_disk_device *dd); +/** + * @brief Sets the block size of a disk device. + * + * This will also change the block_to_media_block_shift and bds_per_group + * fields of the disk device. + * + * Before you can use this function, the rtems_bdbuf_init() routine must be + * called at least once to initialize the cache, otherwise a fatal error will + * occur. + * + * @param dd [in, out] The disk device. + * @param dd [in] The new block size. + * + * @retval RTEMS_SUCCESSFUL Successful operation. + * @retval RTEMS_INVALID_NUMBER Invalid block size. + */ +rtems_status_code +rtems_bdbuf_set_block_size (rtems_disk_device *dd, uint32_t block_size); + /** @} */ #ifdef __cplusplus diff --git a/cpukit/libblock/include/rtems/diskdevs.h b/cpukit/libblock/include/rtems/diskdevs.h index 8e59f36af3..8571daaa90 100644 --- a/cpukit/libblock/include/rtems/diskdevs.h +++ b/cpukit/libblock/include/rtems/diskdevs.h @@ -109,7 +109,9 @@ struct rtems_disk_device { /** * @brief Device block size in bytes. * - * This is the minimum transfer unit. It can be any size. + * This is the minimum transfer unit. It must be positive. + * + * @see rtems_bdbuf_set_block_size(). */ uint32_t block_size; @@ -120,6 +122,24 @@ struct rtems_disk_device { */ uint32_t media_block_size; + /** + * @brief Block to media block shift. + * + * In case this value is non-negative the media block of a block can be + * calculated as media block = block << block_to_media_block_shift, otherwise + * a 64-bit operation will be used. + * + * @see rtems_bdbuf_set_block_size(). + */ + int block_to_media_block_shift; + + /** + * @brief Buffer descriptors per group count. + * + * @see rtems_bdbuf_set_block_size(). + */ + size_t bds_per_group; + /** * @brief IO control handler for this disk. */ @@ -222,7 +242,7 @@ static inline rtems_blkdev_bnum rtems_disk_get_block_count( * @retval RTEMS_SUCCESSFUL Successful operation. * @retval RTEMS_NOT_CONFIGURED Cannot lock disk device operation mutex. * @retval RTEMS_INVALID_ADDRESS IO control handler is @c NULL. - * @retval RTEMS_INVALID_NUMBER Block size is zero. + * @retval RTEMS_INVALID_NUMBER Block size is invalid. * @retval RTEMS_NO_MEMORY Not enough memory. * @retval RTEMS_RESOURCE_IN_USE Disk device descriptor is already in use. * @retval RTEMS_UNSATISFIED Cannot create device node. diff --git a/cpukit/libblock/src/bdbuf.c b/cpukit/libblock/src/bdbuf.c index 5e135c44df..ad1112b517 100644 --- a/cpukit/libblock/src/bdbuf.c +++ b/cpukit/libblock/src/bdbuf.c @@ -822,22 +822,18 @@ rtems_bdbuf_set_state (rtems_bdbuf_buffer *bd, rtems_bdbuf_buf_state state) bd->state = state; } -/** - * Change the block number for the block size to the block number for the media - * block size. We have to use 64bit maths. There is no short cut here. - * - * @param block The logical block number in the block size terms. - * @param block_size The block size. - * @param media_block_size The block size of the media. - * @return rtems_blkdev_bnum The media block number. - */ static rtems_blkdev_bnum -rtems_bdbuf_media_block (rtems_blkdev_bnum block, - size_t block_size, - size_t media_block_size) +rtems_bdbuf_media_block (const rtems_disk_device *dd, rtems_blkdev_bnum block) { - return (rtems_blkdev_bnum) - ((((uint64_t) block) * block_size) / media_block_size); + if (dd->block_to_media_block_shift >= 0) + return block << dd->block_to_media_block_shift; + else + /* + * Change the block number for the block size to the block number for the media + * block size. We have to use 64bit maths. There is no short cut here. + */ + return (rtems_blkdev_bnum) + ((((uint64_t) block) * dd->block_size) / dd->media_block_size); } /** @@ -1743,40 +1739,22 @@ rtems_bdbuf_get_buffer_for_access (const rtems_disk_device *dd, } static rtems_status_code -rtems_bdbuf_obtain_disk (const rtems_disk_device *dd, - rtems_blkdev_bnum block, - rtems_blkdev_bnum *media_block_ptr, - size_t *bds_per_group_ptr) +rtems_bdbuf_get_media_block (const rtems_disk_device *dd, + rtems_blkdev_bnum block, + rtems_blkdev_bnum *media_block_ptr) { - if (media_block_ptr != NULL) + /* + * Compute the media block number. Drivers work with media block number not + * the block number a BD may have as this depends on the block size set by + * the user. + */ + rtems_blkdev_bnum mb = rtems_bdbuf_media_block (dd, block); + if (mb >= dd->size) { - /* - * Compute the media block number. Drivers work with media block number not - * the block number a BD may have as this depends on the block size set by - * the user. - */ - rtems_blkdev_bnum mb = rtems_bdbuf_media_block (block, - dd->block_size, - dd->media_block_size); - if (mb >= dd->size) - { - return RTEMS_INVALID_NUMBER; - } - - *media_block_ptr = mb + dd->start; + return RTEMS_INVALID_ID; } - if (bds_per_group_ptr != NULL) - { - size_t bds_per_group = rtems_bdbuf_bds_per_group (dd->block_size); - - if (bds_per_group == 0) - { - return RTEMS_INVALID_NUMBER; - } - - *bds_per_group_ptr = bds_per_group; - } + *media_block_ptr = mb + dd->start; return RTEMS_SUCCESSFUL; } @@ -1789,9 +1767,8 @@ rtems_bdbuf_get (const rtems_disk_device *dd, rtems_status_code sc = RTEMS_SUCCESSFUL; rtems_bdbuf_buffer *bd = NULL; rtems_blkdev_bnum media_block = 0; - size_t bds_per_group = 0; - sc = rtems_bdbuf_obtain_disk (dd, block, &media_block, &bds_per_group); + sc = rtems_bdbuf_get_media_block (dd, block, &media_block); if (sc != RTEMS_SUCCESSFUL) return sc; @@ -1804,7 +1781,7 @@ rtems_bdbuf_get (const rtems_disk_device *dd, printf ("bdbuf:get: %" PRIu32 " (%" PRIu32 ") (dev = %08x)\n", media_block, block, (unsigned) dd->dev); - bd = rtems_bdbuf_get_buffer_for_access (dd, media_block, bds_per_group); + bd = rtems_bdbuf_get_buffer_for_access (dd, media_block, dd->bds_per_group); switch (bd->state) { @@ -1870,7 +1847,9 @@ rtems_bdbuf_create_read_request (const rtems_disk_device *dd, { rtems_bdbuf_buffer *bd = NULL; rtems_blkdev_bnum media_block_end = dd->start + dd->size; - rtems_blkdev_bnum media_block_count = dd->block_size / dd->media_block_size; + rtems_blkdev_bnum media_block_count = dd->block_to_media_block_shift >= 0 ? + dd->block_size >> 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; @@ -2007,9 +1986,8 @@ rtems_bdbuf_read (const rtems_disk_device *dd, rtems_blkdev_request *req = NULL; rtems_bdbuf_buffer *bd = NULL; rtems_blkdev_bnum media_block = 0; - size_t bds_per_group = 0; - sc = rtems_bdbuf_obtain_disk (dd, block, &media_block, &bds_per_group); + sc = rtems_bdbuf_get_media_block (dd, block, &media_block); if (sc != RTEMS_SUCCESSFUL) return sc; @@ -2027,7 +2005,7 @@ rtems_bdbuf_read (const rtems_disk_device *dd, media_block + dd->start, block, (unsigned) dd->dev); rtems_bdbuf_lock_cache (); - rtems_bdbuf_create_read_request (dd, media_block, bds_per_group, req, &bd); + rtems_bdbuf_create_read_request (dd, media_block, dd->bds_per_group, req, &bd); if (req->bufnum > 0) { @@ -2902,3 +2880,47 @@ rtems_bdbuf_purge_dev (const rtems_disk_device *dd) rtems_bdbuf_purge_list (&purge_list); rtems_bdbuf_unlock_cache (); } + +rtems_status_code +rtems_bdbuf_set_block_size (rtems_disk_device *dd, uint32_t block_size) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + + rtems_bdbuf_lock_cache (); + + if (block_size > 0) + { + size_t bds_per_group = rtems_bdbuf_bds_per_group (block_size); + + if (bds_per_group != 0) + { + int block_to_media_block_shift = 0; + uint32_t media_blocks_per_block = block_size / dd->media_block_size; + uint32_t one = 1; + + while ((one << block_to_media_block_shift) < media_blocks_per_block) + { + ++block_to_media_block_shift; + } + + if ((dd->media_block_size << block_to_media_block_shift) != block_size) + block_to_media_block_shift = -1; + + dd->block_size = block_size; + dd->block_to_media_block_shift = block_to_media_block_shift; + dd->bds_per_group = bds_per_group; + } + else + { + sc = RTEMS_INVALID_NUMBER; + } + } + else + { + sc = RTEMS_INVALID_NUMBER; + } + + rtems_bdbuf_unlock_cache (); + + return sc; +} diff --git a/cpukit/libblock/src/blkdev-imfs.c b/cpukit/libblock/src/blkdev-imfs.c index 080ca2155e..fe7a80cc2c 100644 --- a/cpukit/libblock/src/blkdev-imfs.c +++ b/cpukit/libblock/src/blkdev-imfs.c @@ -268,19 +268,17 @@ rtems_status_code rtems_blkdev_create( { rtems_status_code sc = RTEMS_SUCCESSFUL; - if (block_size > 0 && block_count > 0) { + if (block_count > 0) { rtems_blkdev_imfs_context *ctx = calloc(1, sizeof(*ctx)); if (ctx != NULL) { rtems_disk_device *dd = &ctx->dd; - int rv; ctx->fd = -1; dd->phys_dev = dd; dd->size = block_count; dd->media_block_size = block_size; - dd->block_size = block_size; dd->ioctl = handler; dd->driver_data = driver_data; @@ -288,16 +286,21 @@ rtems_status_code rtems_blkdev_create( dd->capabilities = 0; } - rv = IMFS_make_generic_node( - device, - S_IFBLK | S_IRWXU | S_IRWXG | S_IRWXO, - &rtems_blkdev_imfs_control, - ctx - ); - - if (rv != 0) { + sc = rtems_bdbuf_set_block_size(dd, block_size); + if (sc == RTEMS_SUCCESSFUL) { + int rv = IMFS_make_generic_node( + device, + S_IFBLK | S_IRWXU | S_IRWXG | S_IRWXO, + &rtems_blkdev_imfs_control, + ctx + ); + + if (rv != 0) { + free(ctx); + sc = RTEMS_UNSATISFIED; + } + } else { free(ctx); - sc = RTEMS_UNSATISFIED; } } else { sc = RTEMS_NO_MEMORY; diff --git a/cpukit/libblock/src/blkdev-ioctl.c b/cpukit/libblock/src/blkdev-ioctl.c index 296f379451..52f19b58a0 100644 --- a/cpukit/libblock/src/blkdev-ioctl.c +++ b/cpukit/libblock/src/blkdev-ioctl.c @@ -23,43 +23,42 @@ int rtems_blkdev_ioctl(rtems_disk_device *dd, uint32_t req, void *argp) { - size_t *arg_size = argp; + rtems_status_code sc; int rc = 0; switch (req) { case RTEMS_BLKIO_GETMEDIABLKSIZE: - *arg_size = dd->media_block_size; + *(uint32_t *) argp = dd->media_block_size; break; case RTEMS_BLKIO_GETBLKSIZE: - *arg_size = dd->block_size; + *(uint32_t *) argp = dd->block_size; break; case RTEMS_BLKIO_SETBLKSIZE: - dd->block_size = *arg_size; + sc = rtems_bdbuf_set_block_size(dd, *(uint32_t *) argp); + if (sc != RTEMS_SUCCESSFUL) { + errno = EIO; + rc = -1; + } break; case RTEMS_BLKIO_GETSIZE: - *arg_size = dd->size; + *(rtems_blkdev_bnum *) argp = dd->size; break; case RTEMS_BLKIO_SYNCDEV: - { - rtems_status_code sc = rtems_bdbuf_syncdev(dd); + sc = rtems_bdbuf_syncdev(dd); if (sc != RTEMS_SUCCESSFUL) { errno = EIO; rc = -1; } break; - } case RTEMS_BLKIO_GETDISKDEV: - { - rtems_disk_device **dd_ptr = argp; - *dd_ptr = dd; + *(rtems_disk_device **) argp = dd; break; - } default: errno = EINVAL; diff --git a/cpukit/libblock/src/diskdevs.c b/cpukit/libblock/src/diskdevs.c index 08a6a9bf8c..500569fb4d 100644 --- a/cpukit/libblock/src/diskdevs.c +++ b/cpukit/libblock/src/diskdevs.c @@ -220,6 +220,15 @@ create_disk(dev_t dev, const char *name, rtems_disk_device **dd_ptr) return RTEMS_SUCCESSFUL; } +static int null_handler( + rtems_disk_device *dd, + uint32_t req, + void *argp +) +{ + return -1; +} + rtems_status_code rtems_disk_create_phys( dev_t dev, uint32_t block_size, @@ -236,10 +245,6 @@ rtems_status_code rtems_disk_create_phys( return RTEMS_INVALID_ADDRESS; } - if (block_size == 0) { - return RTEMS_INVALID_NUMBER; - } - sc = disk_lock(); if (sc != RTEMS_SUCCESSFUL) { return sc; @@ -255,7 +260,7 @@ rtems_status_code rtems_disk_create_phys( dd->phys_dev = dd; dd->start = 0; dd->size = block_count; - dd->block_size = dd->media_block_size = block_size; + dd->media_block_size = block_size; dd->ioctl = handler; dd->driver_data = driver_data; @@ -263,6 +268,15 @@ rtems_status_code rtems_disk_create_phys( dd->capabilities = 0; } + sc = rtems_bdbuf_set_block_size(dd, block_size); + if (sc != RTEMS_SUCCESSFUL) { + dd->ioctl = null_handler; + rtems_disk_delete(dev); + disk_unlock(); + + return sc; + } + disk_unlock(); return RTEMS_SUCCESSFUL; @@ -319,7 +333,10 @@ rtems_status_code rtems_disk_create_log( dd->phys_dev = physical_disk; dd->start = begin_block; dd->size = block_count; - dd->block_size = dd->media_block_size = physical_disk->block_size; + dd->block_size = physical_disk->block_size; + dd->media_block_size = physical_disk->media_block_size; + dd->block_to_media_block_shift = physical_disk->block_to_media_block_shift; + dd->bds_per_group = physical_disk->bds_per_group; dd->ioctl = physical_disk->ioctl; dd->driver_data = physical_disk->driver_data; -- cgit v1.2.3