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. * @param bd [out] Reference to the buffer descriptor pointer.
* *
* @retval RTEMS_SUCCESSFUL Successful operation. * @retval RTEMS_SUCCESSFUL Successful operation.
* @retval RTEMS_INVALID_NUMBER Invalid block size. * @retval RTEMS_INVALID_ID Invalid block number.
*/ */
rtems_status_code rtems_status_code
rtems_bdbuf_get ( rtems_bdbuf_get (
@@ -512,7 +512,7 @@ rtems_bdbuf_get (
* @param bd [out] Reference to the buffer descriptor pointer. * @param bd [out] Reference to the buffer descriptor pointer.
* *
* @retval RTEMS_SUCCESSFUL Successful operation. * @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. * @retval RTEMS_IO_ERROR IO error.
*/ */
rtems_status_code rtems_status_code
@@ -625,6 +625,25 @@ rtems_bdbuf_syncdev (const rtems_disk_device *dd);
void void
rtems_bdbuf_purge_dev (const rtems_disk_device *dd); 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 #ifdef __cplusplus

View File

@@ -109,7 +109,9 @@ struct rtems_disk_device {
/** /**
* @brief Device block size in bytes. * @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; uint32_t block_size;
@@ -120,6 +122,24 @@ struct rtems_disk_device {
*/ */
uint32_t media_block_size; 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. * @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_SUCCESSFUL Successful operation.
* @retval RTEMS_NOT_CONFIGURED Cannot lock disk device operation mutex. * @retval RTEMS_NOT_CONFIGURED Cannot lock disk device operation mutex.
* @retval RTEMS_INVALID_ADDRESS IO control handler is @c NULL. * @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_NO_MEMORY Not enough memory.
* @retval RTEMS_RESOURCE_IN_USE Disk device descriptor is already in use. * @retval RTEMS_RESOURCE_IN_USE Disk device descriptor is already in use.
* @retval RTEMS_UNSATISFIED Cannot create device node. * @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; 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 static rtems_blkdev_bnum
rtems_bdbuf_media_block (rtems_blkdev_bnum block, rtems_bdbuf_media_block (const rtems_disk_device *dd, rtems_blkdev_bnum block)
size_t block_size,
size_t media_block_size)
{ {
return (rtems_blkdev_bnum) if (dd->block_to_media_block_shift >= 0)
((((uint64_t) block) * block_size) / media_block_size); 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 static rtems_status_code
rtems_bdbuf_obtain_disk (const rtems_disk_device *dd, rtems_bdbuf_get_media_block (const rtems_disk_device *dd,
rtems_blkdev_bnum block, rtems_blkdev_bnum block,
rtems_blkdev_bnum *media_block_ptr, rtems_blkdev_bnum *media_block_ptr)
size_t *bds_per_group_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)
{ {
/* return RTEMS_INVALID_ID;
* 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;
} }
if (bds_per_group_ptr != NULL) *media_block_ptr = mb + dd->start;
{
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;
}
return RTEMS_SUCCESSFUL; return RTEMS_SUCCESSFUL;
} }
@@ -1789,9 +1767,8 @@ rtems_bdbuf_get (const rtems_disk_device *dd,
rtems_status_code sc = RTEMS_SUCCESSFUL; rtems_status_code sc = RTEMS_SUCCESSFUL;
rtems_bdbuf_buffer *bd = NULL; rtems_bdbuf_buffer *bd = NULL;
rtems_blkdev_bnum media_block = 0; 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) if (sc != RTEMS_SUCCESSFUL)
return sc; return sc;
@@ -1804,7 +1781,7 @@ rtems_bdbuf_get (const rtems_disk_device *dd,
printf ("bdbuf:get: %" PRIu32 " (%" PRIu32 ") (dev = %08x)\n", printf ("bdbuf:get: %" PRIu32 " (%" PRIu32 ") (dev = %08x)\n",
media_block, block, (unsigned) dd->dev); 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) switch (bd->state)
{ {
@@ -1870,7 +1847,9 @@ rtems_bdbuf_create_read_request (const rtems_disk_device *dd,
{ {
rtems_bdbuf_buffer *bd = NULL; rtems_bdbuf_buffer *bd = NULL;
rtems_blkdev_bnum media_block_end = dd->start + dd->size; 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 block_size = dd->block_size;
uint32_t transfer_index = 1; uint32_t transfer_index = 1;
uint32_t transfer_count = bdbuf_config.max_read_ahead_blocks + 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_blkdev_request *req = NULL;
rtems_bdbuf_buffer *bd = NULL; rtems_bdbuf_buffer *bd = NULL;
rtems_blkdev_bnum media_block = 0; 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) if (sc != RTEMS_SUCCESSFUL)
return sc; return sc;
@@ -2027,7 +2005,7 @@ rtems_bdbuf_read (const rtems_disk_device *dd,
media_block + dd->start, block, (unsigned) dd->dev); media_block + dd->start, block, (unsigned) dd->dev);
rtems_bdbuf_lock_cache (); 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) 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_purge_list (&purge_list);
rtems_bdbuf_unlock_cache (); 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; 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)); rtems_blkdev_imfs_context *ctx = calloc(1, sizeof(*ctx));
if (ctx != NULL) { if (ctx != NULL) {
rtems_disk_device *dd = &ctx->dd; rtems_disk_device *dd = &ctx->dd;
int rv;
ctx->fd = -1; ctx->fd = -1;
dd->phys_dev = dd; dd->phys_dev = dd;
dd->size = block_count; dd->size = block_count;
dd->media_block_size = block_size; dd->media_block_size = block_size;
dd->block_size = block_size;
dd->ioctl = handler; dd->ioctl = handler;
dd->driver_data = driver_data; dd->driver_data = driver_data;
@@ -288,16 +286,21 @@ rtems_status_code rtems_blkdev_create(
dd->capabilities = 0; dd->capabilities = 0;
} }
rv = IMFS_make_generic_node( sc = rtems_bdbuf_set_block_size(dd, block_size);
device, if (sc == RTEMS_SUCCESSFUL) {
S_IFBLK | S_IRWXU | S_IRWXG | S_IRWXO, int rv = IMFS_make_generic_node(
&rtems_blkdev_imfs_control, device,
ctx 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); free(ctx);
sc = RTEMS_UNSATISFIED;
} }
} else { } else {
sc = RTEMS_NO_MEMORY; sc = RTEMS_NO_MEMORY;

View File

@@ -23,43 +23,42 @@
int int
rtems_blkdev_ioctl(rtems_disk_device *dd, uint32_t req, void *argp) rtems_blkdev_ioctl(rtems_disk_device *dd, uint32_t req, void *argp)
{ {
size_t *arg_size = argp; rtems_status_code sc;
int rc = 0; int rc = 0;
switch (req) switch (req)
{ {
case RTEMS_BLKIO_GETMEDIABLKSIZE: case RTEMS_BLKIO_GETMEDIABLKSIZE:
*arg_size = dd->media_block_size; *(uint32_t *) argp = dd->media_block_size;
break; break;
case RTEMS_BLKIO_GETBLKSIZE: case RTEMS_BLKIO_GETBLKSIZE:
*arg_size = dd->block_size; *(uint32_t *) argp = dd->block_size;
break; break;
case RTEMS_BLKIO_SETBLKSIZE: case RTEMS_BLKIO_SETBLKSIZE:
dd->block_size = *arg_size; sc = rtems_bdbuf_set_block_size(dd, *(uint32_t *) argp);
break; if (sc != RTEMS_SUCCESSFUL) {
errno = EIO;
case RTEMS_BLKIO_GETSIZE: rc = -1;
*arg_size = dd->size; }
break; break;
case RTEMS_BLKIO_SYNCDEV: case RTEMS_BLKIO_GETSIZE:
{ *(rtems_blkdev_bnum *) argp = dd->size;
rtems_status_code sc = rtems_bdbuf_syncdev(dd); break;
case RTEMS_BLKIO_SYNCDEV:
sc = rtems_bdbuf_syncdev(dd);
if (sc != RTEMS_SUCCESSFUL) { if (sc != RTEMS_SUCCESSFUL) {
errno = EIO; errno = EIO;
rc = -1; rc = -1;
} }
break; break;
}
case RTEMS_BLKIO_GETDISKDEV: case RTEMS_BLKIO_GETDISKDEV:
{ *(rtems_disk_device **) argp = dd;
rtems_disk_device **dd_ptr = argp;
*dd_ptr = dd;
break; break;
}
default: default:
errno = EINVAL; errno = EINVAL;

View File

@@ -220,6 +220,15 @@ create_disk(dev_t dev, const char *name, rtems_disk_device **dd_ptr)
return RTEMS_SUCCESSFUL; 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( rtems_status_code rtems_disk_create_phys(
dev_t dev, dev_t dev,
uint32_t block_size, uint32_t block_size,
@@ -236,10 +245,6 @@ rtems_status_code rtems_disk_create_phys(
return RTEMS_INVALID_ADDRESS; return RTEMS_INVALID_ADDRESS;
} }
if (block_size == 0) {
return RTEMS_INVALID_NUMBER;
}
sc = disk_lock(); sc = disk_lock();
if (sc != RTEMS_SUCCESSFUL) { if (sc != RTEMS_SUCCESSFUL) {
return sc; return sc;
@@ -255,7 +260,7 @@ rtems_status_code rtems_disk_create_phys(
dd->phys_dev = dd; dd->phys_dev = dd;
dd->start = 0; dd->start = 0;
dd->size = block_count; dd->size = block_count;
dd->block_size = dd->media_block_size = block_size; dd->media_block_size = block_size;
dd->ioctl = handler; dd->ioctl = handler;
dd->driver_data = driver_data; dd->driver_data = driver_data;
@@ -263,6 +268,15 @@ rtems_status_code rtems_disk_create_phys(
dd->capabilities = 0; 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(); disk_unlock();
return RTEMS_SUCCESSFUL; return RTEMS_SUCCESSFUL;
@@ -319,7 +333,10 @@ rtems_status_code rtems_disk_create_log(
dd->phys_dev = physical_disk; dd->phys_dev = physical_disk;
dd->start = begin_block; dd->start = begin_block;
dd->size = block_count; 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->ioctl = physical_disk->ioctl;
dd->driver_data = physical_disk->driver_data; dd->driver_data = physical_disk->driver_data;