summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRalf Kirchner <ralf.kirchner@embedded-brains.de>2012-12-12 17:42:24 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2012-12-13 11:38:52 +0100
commit465b086534a97c3f73745c3ea173a0f8d3294c52 (patch)
treebc25825f4d42788c2872a065661d4de8f31ca8d0
parentdosfs: Whitespace change (diff)
downloadrtems-465b086534a97c3f73745c3ea173a0f8d3294c52.tar.bz2
dosfs: Bugfix for disks of for example 100MB size
-rw-r--r--cpukit/libfs/src/dosfs/msdos_format.c150
-rw-r--r--testsuites/fstests/fsdosfsformat01/init.c71
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 cde9c21c19..9e9d234270 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 1af9be8cf5..6299c9b50a 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(