dosfs: Bugfix for disks of for example 100MB size

This commit is contained in:
Ralf Kirchner
2012-12-12 17:42:24 +01:00
committed by Sebastian Huber
parent 26d6eddb0d
commit 465b086534
2 changed files with 164 additions and 63 deletions

View File

@@ -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;
/* 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) {
/* 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;
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)
{

View File

@@ -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,17 +217,6 @@ static void test( void )
rv = msdos_format( dev_name, &rqdata );
rtems_test_assert( rv != 0 );
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.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 );
/* Optimized for read/write speed */
rqdata.OEMName = NULL;
rqdata.VolLabel = NULL;
@@ -245,6 +234,24 @@ static void test( void )
SECTOR_SIZE * rqdata.sectors_per_cluster,
rqdata.sectors_per_cluster );
/* 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 = 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;
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 );
@@ -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(