summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2012-03-26 14:58:35 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2012-04-12 10:42:43 +0200
commitb467782b5354c5d524f46bac84c5b70a8b4fa1f6 (patch)
tree82e37f50cb88569fad625d5c0f30ae9786fd31c5
parentlibblock: Change error status to fatal error (diff)
downloadrtems-b467782b5354c5d524f46bac84c5b70a8b4fa1f6.tar.bz2
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.
-rw-r--r--cpukit/libblock/include/rtems/bdbuf.h23
-rw-r--r--cpukit/libblock/include/rtems/diskdevs.h24
-rw-r--r--cpukit/libblock/src/bdbuf.c124
-rw-r--r--cpukit/libblock/src/blkdev-imfs.c27
-rw-r--r--cpukit/libblock/src/blkdev-ioctl.c23
-rw-r--r--cpukit/libblock/src/diskdevs.c29
6 files changed, 165 insertions, 85 deletions
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;
@@ -121,6 +123,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.
*/
rtems_block_device_ioctl ioctl;
@@ -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;