[rtems commit] dosfs: Bugfix for disks of for example 100MB size

Sebastian Huber sebh at rtems.org
Thu Dec 13 10:35:13 UTC 2012


Module:    rtems
Branch:    master
Commit:    465b086534a97c3f73745c3ea173a0f8d3294c52
Changeset: http://git.rtems.org/rtems/commit/?id=465b086534a97c3f73745c3ea173a0f8d3294c52

Author:    Ralf Kirchner <ralf.kirchner at embedded-brains.de>
Date:      Wed Dec 12 17:42:24 2012 +0100

dosfs: Bugfix for disks of for example 100MB size

---

 cpukit/libfs/src/dosfs/msdos_format.c     |  150 +++++++++++++++++++----------
 testsuites/fstests/fsdosfsformat01/init.c |   71 ++++++++++++--
 2 files changed, 161 insertions(+), 60 deletions(-)

diff --git a/cpukit/libfs/src/dosfs/msdos_format.c b/cpukit/libfs/src/dosfs/msdos_format.c
index cde9c21..9e9d234 100644
--- a/cpukit/libfs/src/dosfs/msdos_format.c
+++ b/cpukit/libfs/src/dosfs/msdos_format.c
@@ -376,12 +376,10 @@ static int msdos_format_eval_sectors_per_cluster
      */
     if (fattype == FAT_FAT12) {
       if (MS_BYTES_PER_CLUSTER_LIMIT_FAT12 < (sectors_per_cluster * bytes_per_sector)) {
-        ret_val = EINVAL;
         finished = true;
       }
     } else if ((sectors_per_cluster * bytes_per_sector)
 	> MS_BYTES_PER_CLUSTER_LIMIT) {
-      ret_val = EINVAL;
       finished = true;
     }
   } while (!finished);
@@ -396,6 +394,82 @@ static int msdos_format_eval_sectors_per_cluster
   return 0;
 }
 
+static uint8_t
+msdos_get_fat_type( const uint32_t bytes_per_sector,
+                    const uint32_t sectors_per_cluster,
+                    const uint32_t number_of_clusters )
+{
+  uint32_t ms_sectors_per_cluster_limit_FAT12 =
+    ( MS_BYTES_PER_CLUSTER_LIMIT_FAT12 +1 ) / bytes_per_sector;
+  uint32_t ms_sectors_per_cluster_limit_FAT16 =
+    ( MS_BYTES_PER_CLUSTER_LIMIT +1 ) / bytes_per_sector;
+  uint8_t fattype = FAT_FAT32;
+
+  if (   number_of_clusters < FAT_FAT12_MAX_CLN
+      && sectors_per_cluster <= ms_sectors_per_cluster_limit_FAT12 ) {
+    fattype = FAT_FAT12;
+  }
+  else if (   number_of_clusters < FAT_FAT16_MAX_CLN
+           && sectors_per_cluster <= ms_sectors_per_cluster_limit_FAT16 ) {
+    fattype = FAT_FAT16;
+  }
+
+  return fattype;
+}
+
+static int
+msdos_set_sectors_per_cluster_from_request(
+  const msdos_format_request_param_t *rqdata,
+  msdos_format_param_t               *fmt_params )
+{
+  int      ret_val = -1;
+  uint32_t onebit;
+
+  if ( rqdata != NULL && rqdata->sectors_per_cluster > 0 ) {
+    fmt_params->sectors_per_cluster = rqdata->sectors_per_cluster;
+  }
+  /*
+   * check sectors per cluster.
+   * must be power of 2
+   * must be smaller than or equal to 128
+   * sectors_per_cluster*bytes_per_sector must not be bigger than 32K
+   */
+  for ( onebit = 128; onebit >= 1; onebit = onebit >> 1 ) {
+    if ( fmt_params->sectors_per_cluster >= onebit ) {
+      fmt_params->sectors_per_cluster = onebit;
+      if (   fmt_params->sectors_per_cluster
+          <= 32768L / fmt_params->bytes_per_sector ) {
+        /* value is small enough so this value is ok */
+        onebit = 1;
+        ret_val = 0;
+      }
+    }
+  }
+  return ret_val;
+}
+
+static void
+msdos_set_default_sectors_per_cluster_for_fattype(
+  msdos_format_param_t *fmt_params,
+  const uint64_t        total_size )
+{
+  if (   fmt_params->fattype == FAT_FAT12
+      || fmt_params->fattype == FAT_FAT16 ) {
+    /* start trying with small clusters */
+    fmt_params->sectors_per_cluster = 2;
+  }
+  else {
+    #define ONE_GB ( 1024L * 1024L * 1024L )
+    uint32_t gigs = ( total_size + ONE_GB ) / ONE_GB;
+    int b;
+    /* scale with the size of disk... */
+    for ( b = 31; b > 0; b-- ) {
+      if ( (gigs & ( 1 << b) ) != 0 )
+        break;
+    }
+    fmt_params->sectors_per_cluster = 1 << b;
+  }
+}
 
 /*=========================================================================*\
 | Function:                                                                 |
@@ -418,7 +492,6 @@ static int msdos_format_determine_fmt_params
 \*=========================================================================*/
 {
   int ret_val = 0;
-  uint32_t onebit;
   uint32_t sectors_per_cluster_adj = 0;
   uint64_t total_size = 0;
   uint32_t data_clusters_cnt;
@@ -535,29 +608,18 @@ static int msdos_format_determine_fmt_params
       fmt_params->sectors_per_cluster = 1 << b;
     }
 
-    while (ret_val == 0 && fmt_params->fattype != fat_type) {
-      /*
-       * try to use user requested cluster size
-       */
-      if (rqdata != NULL && rqdata->sectors_per_cluster > 0) {
-        fmt_params->sectors_per_cluster = rqdata->sectors_per_cluster;
-      }
-      /*
-       * check sectors per cluster.
-       * must be power of 2
-       * must be smaller than or equal to 128
-       * sectors_per_cluster*bytes_per_sector must not be bigger than 32K
-       */
-      for (onebit = 128; onebit >= 1; onebit = onebit >> 1) {
-        if (fmt_params->sectors_per_cluster >= onebit) {
-          fmt_params->sectors_per_cluster = onebit;
-          if (fmt_params->sectors_per_cluster <= 32768L / fmt_params->bytes_per_sector) {
-            /* value is small enough so this value is ok */
-            onebit = 1;
-          }
-        }
-      }
+    ret_val = msdos_set_sectors_per_cluster_from_request( rqdata, fmt_params );
 
+    /* For now we will estimate the number of data clusters to the total number
+     *  of clusters */
+    if (ret_val == 0) {
+      data_clusters_cnt =
+        fmt_params->totl_sector_cnt / fmt_params->sectors_per_cluster;
+    }
+
+    while(   ret_val == 0
+          && fmt_params->fattype != fat_type
+          && fmt_params->totl_sector_cnt > 0 ) {
       /*
        * Skip aligning structures or d align them
        */
@@ -628,31 +690,19 @@ static int msdos_format_determine_fmt_params
                                                         &data_clusters_cnt);
         fmt_params->sectors_per_cluster = sectors_per_cluster_adj;
         fat_type = fmt_params->fattype;
-        if (data_clusters_cnt < FAT_FAT12_MAX_CLN ) {
-          fmt_params->fattype = FAT_FAT12;
-          if (fat_type != fmt_params->fattype) {
-            /* start trying with small clusters */
-            fmt_params->sectors_per_cluster = 2;
-          }
-        }
-        else if (data_clusters_cnt < FAT_FAT16_MAX_CLN) {
-          fmt_params->fattype = FAT_FAT16;
-          if (fat_type != fmt_params->fattype) {
-            /* start trying with small clusters */
-            fmt_params->sectors_per_cluster = 2;
-          }
-        }
-        else {
-          fmt_params->fattype = FAT_FAT32;
+
+        /* Correct the FAT type according to the new data cluster count */
+        if ( ret_val == 0 ) {
+          fmt_params->fattype = msdos_get_fat_type(
+            fmt_params->bytes_per_sector,
+            fmt_params->sectors_per_cluster,
+            data_clusters_cnt );
+          /* Correct sectors per cluster to the fat type specific default value */
           if (fat_type != fmt_params->fattype) {
-            #define ONE_GB (1024L * 1024L * 1024L)
-            uint32_t gigs = (total_size + ONE_GB) / ONE_GB;
-            int b;
-            /* scale with the size of disk... */
-            for (b = 31; b > 0; b--)
-              if ((gigs & (1 << b)) != 0)
-                break;
-            fmt_params->sectors_per_cluster = 1 << b;
+            msdos_set_default_sectors_per_cluster_for_fattype( fmt_params,
+                                                               total_size );
+            ret_val = msdos_set_sectors_per_cluster_from_request( rqdata,
+                                                                  fmt_params );
           }
         }
         if (fat_type != fmt_params->fattype && 1 < iteration_cnt) {
@@ -664,6 +714,8 @@ static int msdos_format_determine_fmt_params
       ++iteration_cnt;
     }
   }
+  if ( fmt_params->totl_sector_cnt == 0 )
+    ret_val = EINVAL;
 
   if (0 == ret_val)
   {
diff --git a/testsuites/fstests/fsdosfsformat01/init.c b/testsuites/fstests/fsdosfsformat01/init.c
index 1af9be8..6299c9b 100644
--- a/testsuites/fstests/fsdosfsformat01/init.c
+++ b/testsuites/fstests/fsdosfsformat01/init.c
@@ -159,7 +159,7 @@ static void test( void )
   const char                   dev_name[]  = "/dev/rda";
   const char                   mount_dir[] = "/mnt";
   msdos_format_request_param_t rqdata;
-
+  rtems_blkdev_bnum            media_block_count;
 
   memset( &rqdata, 0, sizeof( rqdata ) );
 
@@ -217,23 +217,30 @@ static void test( void )
   rv                         = msdos_format( dev_name, &rqdata );
   rtems_test_assert( rv != 0 );
 
+  /* Optimized for read/write speed */
   rqdata.OEMName             = NULL;
   rqdata.VolLabel            = NULL;
-  rqdata.sectors_per_cluster = 16; /* Invalid number of sectors per cluster for FAT12 */
-  rqdata.fat_num             = 1;
-  rqdata.files_per_root_dir  = 32;
+  rqdata.sectors_per_cluster = 8;
+  rqdata.fat_num             = 0;
+  rqdata.files_per_root_dir  = 0;
   rqdata.media               = 0; /* Media code. 0 == Default */
   rqdata.quick_format        = true;
   rqdata.skip_alignment      = false;
   rv                         = msdos_format( dev_name, &rqdata );
-  rtems_test_assert( rv != 0 );
+  rtems_test_assert( rv == 0 );
+  test_disk_params( dev_name,
+                    mount_dir,
+                    SECTOR_SIZE,
+                    SECTOR_SIZE * rqdata.sectors_per_cluster,
+                    rqdata.sectors_per_cluster );
 
-  /* Optimized for read/write speed */
+  /* The same disk formatted with FAT16 because sectors per cluster is too high
+   * for FAT12 */
   rqdata.OEMName             = NULL;
   rqdata.VolLabel            = NULL;
-  rqdata.sectors_per_cluster = 8;
-  rqdata.fat_num             = 0;
-  rqdata.files_per_root_dir  = 0;
+  rqdata.sectors_per_cluster = 16;
+  rqdata.fat_num             = 1;
+  rqdata.files_per_root_dir  = 32;
   rqdata.media               = 0; /* Media code. 0 == Default */
   rqdata.quick_format        = true;
   rqdata.skip_alignment      = false;
@@ -275,7 +282,7 @@ static void test( void )
     dev_name,
     SECTOR_SIZE,
     1024,
-    ( FAT16_MAX_CLN * FAT16_DEFAULT_SECTORS_PER_CLUSTER ) - 1L,
+    ( FAT12_MAX_CLN * FAT12_DEFAULT_SECTORS_PER_CLUSTER ) + 1L,
     0
     );
   rtems_test_assert( RTEMS_SUCCESSFUL == sc );
@@ -291,7 +298,11 @@ static void test( void )
   rqdata.skip_alignment      = true;
   rv                         = msdos_format( dev_name, &rqdata );
   rtems_test_assert( rv == 0 );
-  test_disk_params( dev_name, mount_dir, SECTOR_SIZE, SECTOR_SIZE, 1 );
+  test_disk_params( dev_name,
+                    mount_dir,
+                    SECTOR_SIZE,
+                    rqdata.sectors_per_cluster * SECTOR_SIZE,
+                    rqdata.sectors_per_cluster );
 
   rv = unlink( dev_name );
   rtems_test_assert( rv == 0 );
@@ -361,6 +372,44 @@ static void test( void )
   rv = unlink( dev_name );
   rtems_test_assert( rv == 0 );
 
+  /* Format some disks from 1MB up to 128GB */
+  rqdata.OEMName             = NULL;
+  rqdata.VolLabel            = NULL;
+  rqdata.sectors_per_cluster = 64;
+  rqdata.fat_num             = 0;
+  rqdata.files_per_root_dir  = 0;
+  rqdata.media               = 0;
+  rqdata.quick_format        = true;
+  rqdata.skip_alignment      = false;
+  for (
+    media_block_count = 1 * 1024 * ( 1024 / SECTOR_SIZE );
+    media_block_count <= 128 * 1024 * 1024 * ( 1024 / SECTOR_SIZE );
+    media_block_count *= 2
+  ) {
+    sc = rtems_sparse_disk_create_and_register(
+      dev_name,
+      SECTOR_SIZE,
+      64,
+      media_block_count,
+      0
+    );
+    rtems_test_assert( sc == RTEMS_SUCCESSFUL );
+
+    rv = msdos_format( dev_name, &rqdata );
+    rtems_test_assert( rv == 0 );
+
+    test_disk_params(
+      dev_name,
+      mount_dir,
+      SECTOR_SIZE,
+      SECTOR_SIZE * rqdata.sectors_per_cluster,
+      rqdata.sectors_per_cluster
+    );
+
+    rv = unlink( dev_name );
+    rtems_test_assert( rv == 0 );
+  }
+
   /* FAT32 */
 
   sc = rtems_sparse_disk_create_and_register(




More information about the vc mailing list