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.
This commit is contained in:
Sebastian Huber
2012-03-26 14:58:35 +02:00
parent 3d60c1b22a
commit b467782b53
6 changed files with 170 additions and 90 deletions

View File

@@ -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

View File

@@ -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.

View File

@@ -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;
}

View File

@@ -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
);
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) {
if (rv != 0) {
free(ctx);
sc = RTEMS_UNSATISFIED;
}
} else {
free(ctx);
sc = RTEMS_UNSATISFIED;
}
} else {
sc = RTEMS_NO_MEMORY;

View File

@@ -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;
break;
case RTEMS_BLKIO_GETSIZE:
*arg_size = dd->size;
break;
case RTEMS_BLKIO_SYNCDEV:
{
rtems_status_code sc = rtems_bdbuf_syncdev(dd);
sc = rtems_bdbuf_set_block_size(dd, *(uint32_t *) argp);
if (sc != RTEMS_SUCCESSFUL) {
errno = EIO;
rc = -1;
}
break;
case RTEMS_BLKIO_GETSIZE:
*(rtems_blkdev_bnum *) argp = dd->size;
break;
case RTEMS_BLKIO_SYNCDEV:
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;

View File

@@ -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;