forked from Imagelibrary/rtems
dosfs: Bugfix for disks of for example 100MB size
This commit is contained in:
committed by
Sebastian Huber
parent
26d6eddb0d
commit
465b086534
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user