[PATCH 4/4] libblock: Add rtems_bdbuf_set_block_size()

sebastian.huber at embedded-brains.de sebastian.huber at embedded-brains.de
Wed Mar 28 13:30:28 UTC 2012


From: Sebastian Huber <sebastian.huber at embedded-brains.de>

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    |   15 ++++
 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, 159 insertions(+), 83 deletions(-)

diff --git a/cpukit/libblock/include/rtems/bdbuf.h b/cpukit/libblock/include/rtems/bdbuf.h
index c2fe0dd..cdac89d 100644
--- a/cpukit/libblock/include/rtems/bdbuf.h
+++ b/cpukit/libblock/include/rtems/bdbuf.h
@@ -589,6 +589,21 @@ 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.
+ *
+ * @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 8e59f36..8571daa 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 bfbf9f0..f6d9327 100644
--- a/cpukit/libblock/src/bdbuf.c
+++ b/cpukit/libblock/src/bdbuf.c
@@ -815,22 +815,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);
 }
 
 /**
@@ -1736,40 +1732,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_NUMBER;
   }
 
-  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;
 }
@@ -1782,9 +1760,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;
 
@@ -1797,7 +1774,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)
   {
@@ -1863,7 +1840,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;
@@ -2000,9 +1979,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;
 
@@ -2020,7 +1998,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)
   {
@@ -2895,3 +2873,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 080ca21..fe7a80c 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 296f379..52f19b5 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 08a6a9b..500569f 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;
 
-- 
1.6.4.2




More information about the devel mailing list