forked from Imagelibrary/rtems
dosfs: Cluster write optimization
Separate cluster write from sector write for quick file write. New test fstests/fsdosfswrite01.
This commit is contained in:
committed by
Sebastian Huber
parent
a20fbe78ec
commit
42a22f0824
@@ -32,10 +32,23 @@ static ssize_t
|
||||
uint32_t cln,
|
||||
void *buff);
|
||||
|
||||
static ssize_t
|
||||
fat_cluster_write(fat_fs_info_t *fs_info,
|
||||
uint32_t cln,
|
||||
const void *buff);
|
||||
static inline uint32_t
|
||||
fat_cluster_num_to_block_num (const fat_fs_info_t *fs_info,
|
||||
uint32_t cln)
|
||||
{
|
||||
uint32_t blk;
|
||||
|
||||
if ( (cln == 0) && (fs_info->vol.type & (FAT_FAT12 | FAT_FAT16)) )
|
||||
blk = fat_sector_num_to_block_num(fs_info, fs_info->vol.rdir_loc);
|
||||
else
|
||||
{
|
||||
cln -= FAT_RSRVD_CLN;
|
||||
blk = cln << (fs_info->vol.bpc_log2 - fs_info->vol.bytes_per_block_log2);
|
||||
blk += fat_sector_num_to_block_num(fs_info, fs_info->vol.data_fsec);
|
||||
}
|
||||
|
||||
return blk;
|
||||
}
|
||||
|
||||
int
|
||||
fat_buf_access(fat_fs_info_t *fs_info,
|
||||
@@ -188,7 +201,44 @@ _fat_block_read(
|
||||
return cmpltd;
|
||||
}
|
||||
|
||||
/* _fat_block_write --
|
||||
static ssize_t
|
||||
fat_block_write(
|
||||
fat_fs_info_t *fs_info,
|
||||
const uint32_t start_blk,
|
||||
const uint32_t offset,
|
||||
const uint32_t count,
|
||||
const void *buf,
|
||||
const bool overwrite_block)
|
||||
{
|
||||
int rc = RC_OK;
|
||||
uint32_t bytes_to_write = MIN(count, (fs_info->vol.bytes_per_block - offset));
|
||||
uint8_t *blk_buf;
|
||||
uint32_t sec_num = fat_block_num_to_sector_num(fs_info, start_blk);
|
||||
|
||||
if (0 < bytes_to_write)
|
||||
{
|
||||
if ( overwrite_block
|
||||
|| (bytes_to_write == fs_info->vol.bytes_per_block))
|
||||
{
|
||||
rc = fat_buf_access(fs_info, sec_num, FAT_OP_TYPE_GET, &blk_buf);
|
||||
}
|
||||
else
|
||||
rc = fat_buf_access(fs_info, sec_num, FAT_OP_TYPE_READ, &blk_buf);
|
||||
|
||||
if (RC_OK == rc)
|
||||
{
|
||||
memcpy(blk_buf + offset, buf, bytes_to_write);
|
||||
|
||||
fat_buf_mark_modified(fs_info);
|
||||
}
|
||||
}
|
||||
if (RC_OK != rc)
|
||||
return rc;
|
||||
else
|
||||
return bytes_to_write;
|
||||
}
|
||||
|
||||
/* fat_sector_write --
|
||||
* This function write 'count' bytes to device filesystem is mounted on,
|
||||
* starts at 'start+offset' position where 'start' computed in sectors
|
||||
* and 'offset' is offset inside sector (writing may cross sectors
|
||||
@@ -206,7 +256,7 @@ _fat_block_read(
|
||||
* and errno set appropriately
|
||||
*/
|
||||
ssize_t
|
||||
_fat_block_write(
|
||||
fat_sector_write(
|
||||
fat_fs_info_t *fs_info,
|
||||
uint32_t start,
|
||||
uint32_t offset,
|
||||
@@ -243,39 +293,84 @@ _fat_block_write(
|
||||
return cmpltd;
|
||||
}
|
||||
|
||||
int
|
||||
_fat_block_zero(
|
||||
fat_fs_info_t *fs_info,
|
||||
uint32_t start,
|
||||
uint32_t offset,
|
||||
uint32_t count)
|
||||
static ssize_t
|
||||
fat_block_set (
|
||||
fat_fs_info_t *fs_info,
|
||||
const uint32_t start_blk,
|
||||
const uint32_t offset,
|
||||
const uint32_t count,
|
||||
const uint8_t pattern)
|
||||
{
|
||||
int rc = RC_OK;
|
||||
uint32_t sec_num = start;
|
||||
uint32_t ofs = offset;
|
||||
uint8_t *sec_buf;
|
||||
uint32_t c = 0;
|
||||
int rc = RC_OK;
|
||||
uint32_t bytes_to_write = MIN(count, (fs_info->vol.bytes_per_block - offset));
|
||||
uint8_t *blk_buf;
|
||||
uint32_t sec_num = fat_block_num_to_sector_num(fs_info, start_blk);
|
||||
|
||||
while(count > 0)
|
||||
if (0 < bytes_to_write)
|
||||
{
|
||||
c = MIN(count, (fs_info->vol.bps - ofs));
|
||||
|
||||
if (c == fs_info->vol.bps)
|
||||
rc = fat_buf_access(fs_info, sec_num, FAT_OP_TYPE_GET, &sec_buf);
|
||||
if (bytes_to_write == fs_info->vol.bytes_per_block)
|
||||
{
|
||||
rc = fat_buf_access(fs_info, sec_num, FAT_OP_TYPE_GET, &blk_buf);
|
||||
}
|
||||
else
|
||||
rc = fat_buf_access(fs_info, sec_num, FAT_OP_TYPE_READ, &sec_buf);
|
||||
if (rc != RC_OK)
|
||||
return -1;
|
||||
rc = fat_buf_access(fs_info, sec_num, FAT_OP_TYPE_READ, &blk_buf);
|
||||
|
||||
memset((block + ofs), 0, c);
|
||||
if (RC_OK == rc)
|
||||
{
|
||||
memset(blk_buf + offset, pattern, bytes_to_write);
|
||||
|
||||
fat_buf_mark_modified(fs_info);
|
||||
|
||||
count -= c;
|
||||
sec_num++;
|
||||
ofs = 0;
|
||||
fat_buf_mark_modified(fs_info);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
if (RC_OK != rc)
|
||||
return rc;
|
||||
else
|
||||
return bytes_to_write;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
fat_cluster_set(
|
||||
fat_fs_info_t *fs_info,
|
||||
const uint32_t start_cln,
|
||||
const uint32_t offset,
|
||||
const uint32_t count,
|
||||
const uint8_t pattern)
|
||||
{
|
||||
ssize_t rc = RC_OK;
|
||||
uint32_t bytes_to_write = MIN(count, (fs_info->vol.bpc - offset));
|
||||
uint32_t cur_blk = fat_cluster_num_to_block_num(fs_info, start_cln);
|
||||
uint32_t blocks_in_offset = offset >> fs_info->vol.bytes_per_block_log2;
|
||||
uint32_t ofs_blk = offset - (blocks_in_offset << fs_info->vol.bytes_per_block_log2);
|
||||
ssize_t bytes_written = 0;
|
||||
ssize_t ret;
|
||||
|
||||
cur_blk += blocks_in_offset;
|
||||
|
||||
while ( (RC_OK == rc)
|
||||
&& (0 < bytes_to_write))
|
||||
{
|
||||
uint32_t c = MIN(bytes_to_write, (fs_info->vol.bytes_per_block - ofs_blk));
|
||||
|
||||
ret = fat_block_set(
|
||||
fs_info,
|
||||
cur_blk,
|
||||
ofs_blk,
|
||||
c,
|
||||
pattern);
|
||||
if (c != ret)
|
||||
rc = -1;
|
||||
else
|
||||
{
|
||||
bytes_to_write -= ret;
|
||||
bytes_written += ret;
|
||||
++cur_blk;
|
||||
}
|
||||
ofs_blk = 0;
|
||||
}
|
||||
if (RC_OK != rc)
|
||||
return rc;
|
||||
else
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
/* _fat_block_release --
|
||||
@@ -322,12 +417,18 @@ fat_cluster_read(
|
||||
}
|
||||
|
||||
/* fat_cluster_write --
|
||||
* wrapper for writting a whole cluster at once
|
||||
* This function write 'count' bytes to device filesystem is mounted on,
|
||||
* starts at 'start+offset' position where 'start' computed in clusters
|
||||
* and 'offset' is offset inside cluster.
|
||||
* Writing will NOT cross cluster boundaries!
|
||||
*
|
||||
* PARAMETERS:
|
||||
* fs_info - FS info
|
||||
* cln - number of cluster to write
|
||||
* buff - buffer provided by user
|
||||
* fs_info - FS info
|
||||
* start_cln - cluster number to start writing to
|
||||
* offset - offset inside cluster 'start'
|
||||
* count - count of bytes to write
|
||||
* buff - buffer provided by user
|
||||
* overwrite_cluster - true if cluster can get overwritten, false if cluster content must be kept
|
||||
*
|
||||
* RETURNS:
|
||||
* bytes written on success, or -1 if error occured
|
||||
@@ -336,16 +437,50 @@ fat_cluster_read(
|
||||
ssize_t
|
||||
fat_cluster_write(
|
||||
fat_fs_info_t *fs_info,
|
||||
uint32_t cln,
|
||||
const void *buff
|
||||
)
|
||||
const uint32_t start_cln,
|
||||
const uint32_t offset,
|
||||
const uint32_t count,
|
||||
const void *buff,
|
||||
const bool overwrite_cluster)
|
||||
{
|
||||
uint32_t fsec = 0;
|
||||
ssize_t rc = RC_OK;
|
||||
uint32_t bytes_to_write = MIN(count, (fs_info->vol.bpc - offset));
|
||||
uint32_t cur_blk = fat_cluster_num_to_block_num(fs_info, start_cln);
|
||||
uint32_t blocks_in_offset = (offset >> fs_info->vol.bytes_per_block_log2);
|
||||
uint32_t ofs_blk = offset - (blocks_in_offset << fs_info->vol.bytes_per_block_log2);
|
||||
ssize_t bytes_written = 0;
|
||||
uint8_t *buffer = (uint8_t*)buff;
|
||||
ssize_t ret;
|
||||
uint32_t c;
|
||||
|
||||
fsec = fat_cluster_num_to_sector_num(fs_info, cln);
|
||||
cur_blk += blocks_in_offset;
|
||||
|
||||
return _fat_block_write(fs_info, fsec, 0,
|
||||
fs_info->vol.spc << fs_info->vol.sec_log2, buff);
|
||||
while ( (RC_OK == rc)
|
||||
&& (0 < bytes_to_write))
|
||||
{
|
||||
c = MIN(bytes_to_write, (fs_info->vol.bytes_per_block - ofs_blk));
|
||||
|
||||
ret = fat_block_write(
|
||||
fs_info,
|
||||
cur_blk,
|
||||
ofs_blk,
|
||||
c,
|
||||
&buffer[bytes_written],
|
||||
overwrite_cluster);
|
||||
if (c != ret)
|
||||
rc = -1;
|
||||
else
|
||||
{
|
||||
bytes_to_write -= ret;
|
||||
bytes_written += ret;
|
||||
++cur_blk;
|
||||
}
|
||||
ofs_blk = 0;
|
||||
}
|
||||
if (RC_OK != rc)
|
||||
return rc;
|
||||
else
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
static bool is_cluster_aligned(const fat_vol_t *vol, uint32_t sec_num)
|
||||
@@ -680,7 +815,7 @@ fat_fat32_update_fsinfo_sector(fat_fs_info_t *fs_info)
|
||||
|
||||
fs_info->vol.free_cls_in_fs_info = free_count;
|
||||
|
||||
ret1 = _fat_block_write(fs_info,
|
||||
ret1 = fat_sector_write(fs_info,
|
||||
fs_info->vol.info_sec,
|
||||
FAT_FSINFO_FREE_CLUSTER_COUNT_OFFSET,
|
||||
sizeof(le_free_count),
|
||||
@@ -693,7 +828,7 @@ fat_fat32_update_fsinfo_sector(fat_fs_info_t *fs_info)
|
||||
|
||||
fs_info->vol.next_cl_in_fs_info = next_free;
|
||||
|
||||
ret2 = _fat_block_write(fs_info,
|
||||
ret2 = fat_sector_write(fs_info,
|
||||
fs_info->vol.info_sec,
|
||||
FAT_FSINFO_NEXT_FREE_CLUSTER_OFFSET,
|
||||
sizeof(le_next_free),
|
||||
@@ -794,30 +929,23 @@ fat_init_clusters_chain(
|
||||
int rc = RC_OK;
|
||||
ssize_t ret = 0;
|
||||
uint32_t cur_cln = start_cln;
|
||||
char *buf;
|
||||
|
||||
buf = calloc(fs_info->vol.bpc, sizeof(char));
|
||||
if ( buf == NULL )
|
||||
rtems_set_errno_and_return_minus_one( EIO );
|
||||
|
||||
while ((cur_cln & fs_info->vol.mask) < fs_info->vol.eoc_val)
|
||||
{
|
||||
ret = fat_cluster_write(fs_info, cur_cln, buf);
|
||||
if ( ret == -1 )
|
||||
ret = fat_cluster_set(fs_info, cur_cln, 0, fs_info->vol.bpc, 0);
|
||||
if ( ret != fs_info->vol.bpc )
|
||||
{
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = fat_get_fat_cluster(fs_info, cur_cln, &cur_cln);
|
||||
if ( rc != RC_OK )
|
||||
{
|
||||
free(buf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
}
|
||||
free(buf);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@@ -439,6 +439,20 @@ fat_cluster_num_to_sector512_num(
|
||||
fs_info->vol.sec_mul);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
fat_block_num_to_cluster_num (const fat_fs_info_t *fs_info,
|
||||
const uint32_t block_number)
|
||||
{
|
||||
return block_number >> (fs_info->vol.bpc_log2 - fs_info->vol.bytes_per_block_log2);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
fat_block_num_to_sector_num (const fat_fs_info_t *fs_info,
|
||||
const uint32_t block_number)
|
||||
{
|
||||
return block_number << (fs_info->vol.bytes_per_block_log2 - fs_info->vol.sec_log2);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
fat_sector_num_to_block_num (const fat_fs_info_t *fs_info,
|
||||
const uint32_t sector_number)
|
||||
@@ -481,18 +495,26 @@ _fat_block_read(fat_fs_info_t *fs_info,
|
||||
void *buff);
|
||||
|
||||
ssize_t
|
||||
_fat_block_write(fat_fs_info_t *fs_info,
|
||||
fat_cluster_write(fat_fs_info_t *fs_info,
|
||||
uint32_t start_cln,
|
||||
uint32_t offset,
|
||||
uint32_t count,
|
||||
const void *buff,
|
||||
bool overwrite_cluster);
|
||||
|
||||
ssize_t
|
||||
fat_sector_write(fat_fs_info_t *fs_info,
|
||||
uint32_t start,
|
||||
uint32_t offset,
|
||||
uint32_t count,
|
||||
const void *buff);
|
||||
|
||||
int
|
||||
_fat_block_zero(fat_fs_info_t *fs_info,
|
||||
uint32_t start,
|
||||
uint32_t offset,
|
||||
uint32_t count);
|
||||
|
||||
ssize_t
|
||||
fat_cluster_set(fat_fs_info_t *fs_info,
|
||||
uint32_t start,
|
||||
uint32_t offset,
|
||||
uint32_t count,
|
||||
uint8_t pattern);
|
||||
|
||||
|
||||
int
|
||||
|
||||
@@ -54,6 +54,7 @@ fat_scan_fat_for_free_clusters(
|
||||
uint32_t save_cln = 0;
|
||||
uint32_t data_cls_val = fs_info->vol.data_cls + 2;
|
||||
uint32_t i = 2;
|
||||
ssize_t bytes_written;
|
||||
|
||||
*cls_added = 0;
|
||||
|
||||
@@ -114,13 +115,14 @@ fat_scan_fat_for_free_clusters(
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (zero_fill) {
|
||||
uint32_t sec = fat_cluster_num_to_sector_num(fs_info,
|
||||
cl4find);
|
||||
|
||||
rc = _fat_block_zero(fs_info, sec, 0, fs_info->vol.bpc);
|
||||
if ( rc != RC_OK )
|
||||
if (zero_fill)
|
||||
{
|
||||
bytes_written = fat_cluster_set (fs_info, cl4find, 0, fs_info->vol.bpc, 0);
|
||||
if (fs_info->vol.bpc != bytes_written)
|
||||
{
|
||||
rc = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
save_cln = cl4find;
|
||||
|
||||
@@ -339,6 +339,110 @@ fat_file_read(
|
||||
return cmpltd;
|
||||
}
|
||||
|
||||
/* fat_is_fat12_or_fat16_root_dir --
|
||||
* Returns true for FAT12 root directories respectively FAT16
|
||||
* root directories. Returns false for everything else.
|
||||
*
|
||||
* PARAMETERS:
|
||||
* fat_fd - fat-file descriptor
|
||||
* volume_type - type of fat volume: FAT_FAT12 or FAT_FAT16 or FAT_FAT32
|
||||
*
|
||||
* RETURNS:
|
||||
* true if conditions for FAT12 root directory or FAT16 root directory
|
||||
* match, false if not
|
||||
*/
|
||||
static bool
|
||||
fat_is_fat12_or_fat16_root_dir (const fat_file_fd_t *fat_fd,
|
||||
const uint8_t volume_type)
|
||||
{
|
||||
return (FAT_FD_OF_ROOT_DIR(fat_fd)) && (volume_type & (FAT_FAT12 | FAT_FAT16));
|
||||
}
|
||||
|
||||
/* fat_file_write_fat32_or_non_root_dir --
|
||||
* Execute fat file write for FAT32 respectively for non-root
|
||||
* directories of FAT12 or FAT16
|
||||
*
|
||||
* PARAMETERS:
|
||||
* fs_info - FS info
|
||||
* fat_fd - fat-file descriptor
|
||||
* start - offset(in bytes) to write from
|
||||
* count - count
|
||||
* buf - buffer provided by user
|
||||
* file_cln_initial - initial current cluster number of the file
|
||||
*
|
||||
* RETURNS:
|
||||
* number of bytes actually written to the file on success, or -1 if
|
||||
* error occured (errno set appropriately)
|
||||
*/
|
||||
static ssize_t
|
||||
fat_file_write_fat32_or_non_root_dir(
|
||||
fat_fs_info_t *fs_info,
|
||||
fat_file_fd_t *fat_fd,
|
||||
const uint32_t start,
|
||||
const uint32_t count,
|
||||
const uint8_t *buf,
|
||||
const uint32_t file_cln_initial)
|
||||
{
|
||||
int rc = RC_OK;
|
||||
uint32_t cmpltd = 0;
|
||||
uint32_t cur_cln = 0;
|
||||
uint32_t save_cln = 0; /* FIXME: This might be incorrect, cf. below */
|
||||
uint32_t start_cln = start >> fs_info->vol.bpc_log2;
|
||||
uint32_t ofs_cln = start - (start_cln << fs_info->vol.bpc_log2);
|
||||
uint32_t ofs_cln_save = ofs_cln;
|
||||
uint32_t bytes_to_write = count;
|
||||
uint32_t file_cln_cnt;
|
||||
ssize_t ret;
|
||||
uint32_t c;
|
||||
bool overwrite_cluster = false;
|
||||
|
||||
rc = fat_file_lseek(fs_info, fat_fd, start_cln, &cur_cln);
|
||||
if (RC_OK == rc)
|
||||
{
|
||||
file_cln_cnt = cur_cln - fat_fd->cln;
|
||||
while ( (RC_OK == rc)
|
||||
&& (bytes_to_write > 0))
|
||||
{
|
||||
c = MIN(bytes_to_write, (fs_info->vol.bpc - ofs_cln));
|
||||
|
||||
if (file_cln_initial < file_cln_cnt)
|
||||
overwrite_cluster = true;
|
||||
|
||||
ret = fat_cluster_write(fs_info,
|
||||
cur_cln,
|
||||
ofs_cln,
|
||||
c,
|
||||
&buf[cmpltd],
|
||||
overwrite_cluster);
|
||||
if (0 > ret)
|
||||
rc = -1;
|
||||
|
||||
if (RC_OK == rc)
|
||||
{
|
||||
++file_cln_cnt;
|
||||
bytes_to_write -= ret;
|
||||
cmpltd += ret;
|
||||
save_cln = cur_cln;
|
||||
if (0 < bytes_to_write)
|
||||
rc = fat_get_fat_cluster(fs_info, cur_cln, &cur_cln);
|
||||
|
||||
ofs_cln = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* update cache */
|
||||
/* XXX: check this - I'm not sure :( */
|
||||
fat_fd->map.file_cln = start_cln +
|
||||
((ofs_cln_save + cmpltd - 1) >> fs_info->vol.bpc_log2);
|
||||
fat_fd->map.disk_cln = save_cln;
|
||||
}
|
||||
|
||||
if (RC_OK != rc)
|
||||
return rc;
|
||||
else
|
||||
return cmpltd;
|
||||
}
|
||||
|
||||
/* fat_file_write --
|
||||
* Write 'count' bytes of data from user supplied buffer to fat-file
|
||||
* starting at offset 'start'. This interface hides the architecture
|
||||
@@ -364,18 +468,15 @@ fat_file_write(
|
||||
const uint8_t *buf
|
||||
)
|
||||
{
|
||||
int rc = 0;
|
||||
ssize_t ret = 0;
|
||||
int rc = RC_OK;
|
||||
ssize_t ret;
|
||||
uint32_t cmpltd = 0;
|
||||
uint32_t cur_cln = 0;
|
||||
uint32_t save_cln = 0; /* FIXME: This might be incorrect, cf. below */
|
||||
uint32_t cl_start = 0;
|
||||
uint32_t ofs = 0;
|
||||
uint32_t save_ofs;
|
||||
uint32_t sec = 0;
|
||||
uint32_t byte = 0;
|
||||
uint32_t byte;
|
||||
uint32_t c = 0;
|
||||
bool zero_fill = start > fat_fd->fat_file_size;
|
||||
uint32_t file_cln_initial = fat_fd->map.file_cln;
|
||||
uint32_t cln;
|
||||
|
||||
|
||||
if ( count == 0 )
|
||||
return cmpltd;
|
||||
@@ -387,66 +488,51 @@ fat_file_write(
|
||||
count = fat_fd->size_limit - start;
|
||||
|
||||
rc = fat_file_extend(fs_info, fat_fd, zero_fill, start + count, &c);
|
||||
if (rc != RC_OK)
|
||||
return rc;
|
||||
|
||||
/*
|
||||
* check whether there was enough room on device to locate
|
||||
* file of 'start + count' bytes
|
||||
*/
|
||||
if (c != (start + count))
|
||||
count = c - start;
|
||||
|
||||
if ((FAT_FD_OF_ROOT_DIR(fat_fd)) &&
|
||||
(fs_info->vol.type & (FAT_FAT12 | FAT_FAT16)))
|
||||
if (RC_OK == rc)
|
||||
{
|
||||
sec = fat_cluster_num_to_sector_num(fs_info, fat_fd->cln);
|
||||
sec += (start >> fs_info->vol.sec_log2);
|
||||
byte = start & (fs_info->vol.bps - 1);
|
||||
/*
|
||||
* check whether there was enough room on device to locate
|
||||
* file of 'start + count' bytes
|
||||
*/
|
||||
if (c != (start + count))
|
||||
count = c - start;
|
||||
|
||||
ret = _fat_block_write(fs_info, sec, byte, count, buf);
|
||||
if ( ret < 0 )
|
||||
return -1;
|
||||
/* for the root directory of FAT12 and FAT16 we need this special handling */
|
||||
if (fat_is_fat12_or_fat16_root_dir(fat_fd, fs_info->vol.type))
|
||||
{
|
||||
cln = fat_fd->cln;
|
||||
cln += (start >> fs_info->vol.bpc_log2);
|
||||
byte = start & (fs_info->vol.bpc -1);
|
||||
|
||||
return ret;
|
||||
ret = fat_cluster_write(fs_info,
|
||||
cln,
|
||||
byte,
|
||||
count,
|
||||
buf,
|
||||
false);
|
||||
if (0 > ret)
|
||||
rc = -1;
|
||||
else
|
||||
cmpltd = ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = fat_file_write_fat32_or_non_root_dir(fs_info,
|
||||
fat_fd,
|
||||
start,
|
||||
count,
|
||||
buf,
|
||||
file_cln_initial);
|
||||
if (0 > ret)
|
||||
rc = -1;
|
||||
else
|
||||
cmpltd = ret;
|
||||
}
|
||||
}
|
||||
|
||||
cl_start = start >> fs_info->vol.bpc_log2;
|
||||
save_ofs = ofs = start & (fs_info->vol.bpc - 1);
|
||||
|
||||
rc = fat_file_lseek(fs_info, fat_fd, cl_start, &cur_cln);
|
||||
if (rc != RC_OK)
|
||||
if (RC_OK != rc)
|
||||
return rc;
|
||||
|
||||
while (count > 0)
|
||||
{
|
||||
c = MIN(count, (fs_info->vol.bpc - ofs));
|
||||
|
||||
sec = fat_cluster_num_to_sector_num(fs_info, cur_cln);
|
||||
sec += (ofs >> fs_info->vol.sec_log2);
|
||||
byte = ofs & (fs_info->vol.bps - 1);
|
||||
|
||||
ret = _fat_block_write(fs_info, sec, byte, c, buf + cmpltd);
|
||||
if ( ret < 0 )
|
||||
return -1;
|
||||
|
||||
count -= c;
|
||||
cmpltd += c;
|
||||
save_cln = cur_cln;
|
||||
rc = fat_get_fat_cluster(fs_info, cur_cln, &cur_cln);
|
||||
if ( rc != RC_OK )
|
||||
return rc;
|
||||
|
||||
ofs = 0;
|
||||
}
|
||||
|
||||
/* update cache */
|
||||
/* XXX: check this - I'm not sure :( */
|
||||
fat_fd->map.file_cln = cl_start +
|
||||
((save_ofs + cmpltd - 1) >> fs_info->vol.bpc_log2);
|
||||
fat_fd->map.disk_cln = save_cln;
|
||||
|
||||
return cmpltd;
|
||||
else
|
||||
return cmpltd;
|
||||
}
|
||||
|
||||
/* fat_file_extend --
|
||||
@@ -482,6 +568,7 @@ fat_file_extend(
|
||||
uint32_t last_cl = 0;
|
||||
uint32_t bytes_remain = 0;
|
||||
uint32_t cls_added;
|
||||
ssize_t bytes_written;
|
||||
|
||||
*a_length = new_length;
|
||||
|
||||
@@ -508,20 +595,14 @@ fat_file_extend(
|
||||
uint32_t cl_start = start >> fs_info->vol.bpc_log2;
|
||||
uint32_t ofs = start & (fs_info->vol.bpc - 1);
|
||||
uint32_t cur_cln;
|
||||
uint32_t sec;
|
||||
uint32_t byte;
|
||||
|
||||
rc = fat_file_lseek(fs_info, fat_fd, cl_start, &cur_cln);
|
||||
if (rc != RC_OK)
|
||||
return rc;
|
||||
|
||||
sec = fat_cluster_num_to_sector_num(fs_info, cur_cln);
|
||||
sec += ofs >> fs_info->vol.sec_log2;
|
||||
byte = ofs & (fs_info->vol.bps - 1);
|
||||
|
||||
rc = _fat_block_zero(fs_info, sec, byte, bytes_remain);
|
||||
if (rc != RC_OK)
|
||||
return rc;
|
||||
bytes_written = fat_cluster_set (fs_info, cur_cln, ofs, bytes_remain, 0);
|
||||
if (bytes_remain != bytes_written)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -641,7 +641,7 @@ msdos_set_dir_wrt_time_and_date(
|
||||
msdos_date_unix2dos(fat_fd->mtime, &date, &time_val);
|
||||
|
||||
/*
|
||||
* calculate input for _fat_block_write: convert (cluster num, offset) to
|
||||
* calculate input for fat_sector_write: convert (cluster num, offset) to
|
||||
* (sector num, new offset)
|
||||
*/
|
||||
sec = fat_cluster_num_to_sector_num(&fs_info->fat, fat_fd->dir_pos.sname.cln);
|
||||
@@ -650,12 +650,12 @@ msdos_set_dir_wrt_time_and_date(
|
||||
byte = fat_fd->dir_pos.sname.ofs & (fs_info->fat.vol.bps - 1);
|
||||
|
||||
time_val = CT_LE_W(time_val);
|
||||
ret1 = _fat_block_write(&fs_info->fat, sec, byte + MSDOS_FILE_WTIME_OFFSET,
|
||||
ret1 = fat_sector_write(&fs_info->fat, sec, byte + MSDOS_FILE_WTIME_OFFSET,
|
||||
2, (char *)(&time_val));
|
||||
date = CT_LE_W(date);
|
||||
ret2 = _fat_block_write(&fs_info->fat, sec, byte + MSDOS_FILE_WDATE_OFFSET,
|
||||
ret2 = fat_sector_write(&fs_info->fat, sec, byte + MSDOS_FILE_WDATE_OFFSET,
|
||||
2, (char *)(&date));
|
||||
ret3 = _fat_block_write(&fs_info->fat, sec, byte + MSDOS_FILE_ADATE_OFFSET,
|
||||
ret3 = fat_sector_write(&fs_info->fat, sec, byte + MSDOS_FILE_ADATE_OFFSET,
|
||||
2, (char *)(&date));
|
||||
|
||||
if ( (ret1 < 0) || (ret2 < 0) || (ret3 < 0) )
|
||||
@@ -691,7 +691,7 @@ msdos_set_first_cluster_num(
|
||||
uint32_t byte = 0;
|
||||
|
||||
/*
|
||||
* calculate input for _fat_block_write: convert (cluster num, offset) to
|
||||
* calculate input for fat_sector_write: convert (cluster num, offset) to
|
||||
* (sector num, new offset)
|
||||
*/
|
||||
sec = fat_cluster_num_to_sector_num(&fs_info->fat, fat_fd->dir_pos.sname.cln);
|
||||
@@ -700,11 +700,11 @@ msdos_set_first_cluster_num(
|
||||
byte = fat_fd->dir_pos.sname.ofs & (fs_info->fat.vol.bps - 1);
|
||||
|
||||
le_cl_low = CT_LE_W((uint16_t )(new_cln & 0x0000FFFF));
|
||||
ret1 = _fat_block_write(&fs_info->fat, sec,
|
||||
ret1 = fat_sector_write(&fs_info->fat, sec,
|
||||
byte + MSDOS_FIRST_CLUSTER_LOW_OFFSET, 2,
|
||||
(char *)(&le_cl_low));
|
||||
le_cl_hi = CT_LE_W((uint16_t )((new_cln & 0xFFFF0000) >> 16));
|
||||
ret2 = _fat_block_write(&fs_info->fat, sec,
|
||||
ret2 = fat_sector_write(&fs_info->fat, sec,
|
||||
byte + MSDOS_FIRST_CLUSTER_HI_OFFSET, 2,
|
||||
(char *)(&le_cl_hi));
|
||||
if ( (ret1 < 0) || (ret2 < 0) )
|
||||
@@ -742,7 +742,7 @@ msdos_set_file_size(
|
||||
byte = (fat_fd->dir_pos.sname.ofs & (fs_info->fat.vol.bps - 1));
|
||||
|
||||
le_new_length = CT_LE_L((fat_fd->fat_file_size));
|
||||
ret = _fat_block_write(&fs_info->fat, sec, byte + MSDOS_FILE_SIZE_OFFSET, 4,
|
||||
ret = fat_sector_write(&fs_info->fat, sec, byte + MSDOS_FILE_SIZE_OFFSET, 4,
|
||||
(char *)(&le_new_length));
|
||||
if ( ret < 0 )
|
||||
return -1;
|
||||
@@ -802,7 +802,7 @@ msdos_set_first_char4file_name(
|
||||
(start.ofs >> fs_info->fat.vol.sec_log2));
|
||||
uint32_t byte = (start.ofs & (fs_info->fat.vol.bps - 1));
|
||||
|
||||
ret = _fat_block_write(&fs_info->fat, sec, byte + MSDOS_FILE_NAME_OFFSET,
|
||||
ret = fat_sector_write(&fs_info->fat, sec, byte + MSDOS_FILE_NAME_OFFSET,
|
||||
1, &fchar);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
ACLOCAL_AMFLAGS = -I ../aclocal
|
||||
|
||||
SUBDIRS =
|
||||
SUBDIRS += fsdosfswrite01
|
||||
SUBDIRS += fsdosfsformat01
|
||||
SUBDIRS += fsfseeko01
|
||||
SUBDIRS += fsdosfssync01
|
||||
|
||||
@@ -77,6 +77,7 @@ AC_CHECK_SIZEOF([blkcnt_t])
|
||||
|
||||
# Explicitly list all Makefiles here
|
||||
AC_CONFIG_FILES([Makefile
|
||||
fsdosfswrite01/Makefile
|
||||
fsdosfsformat01/Makefile
|
||||
fsfseeko01/Makefile
|
||||
fsdosfssync01/Makefile
|
||||
|
||||
19
testsuites/fstests/fsdosfswrite01/Makefile.am
Normal file
19
testsuites/fstests/fsdosfswrite01/Makefile.am
Normal file
@@ -0,0 +1,19 @@
|
||||
rtems_tests_PROGRAMS = fsdosfswrite01
|
||||
fsdosfswrite01_SOURCES = init.c
|
||||
|
||||
dist_rtems_tests_DATA = fsdosfswrite01.scn fsdosfswrite01.doc
|
||||
|
||||
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
|
||||
include $(top_srcdir)/../automake/compile.am
|
||||
include $(top_srcdir)/../automake/leaf.am
|
||||
|
||||
AM_CPPFLAGS += -I$(top_srcdir)/../support/include
|
||||
|
||||
LINK_OBJS = $(fsdosfswrite01_OBJECTS)
|
||||
LINK_LIBS = $(fsdosfswrite01_LDLIBS)
|
||||
|
||||
fsdosfswrite01$(EXEEXT): $(fsdosfswrite01_OBJECTS) $(fsdosfswrite01_DEPENDENCIES)
|
||||
@rm -f fsdosfswrite01$(EXEEXT)
|
||||
$(make-exe)
|
||||
|
||||
include $(top_srcdir)/../automake/local.am
|
||||
15
testsuites/fstests/fsdosfswrite01/fsdosfswrite01.doc
Normal file
15
testsuites/fstests/fsdosfswrite01/fsdosfswrite01.doc
Normal file
@@ -0,0 +1,15 @@
|
||||
This file describes the directives and concepts tested by this test set.
|
||||
|
||||
test set name: fsdosfswrite01
|
||||
|
||||
directives:
|
||||
- fat_file_write()
|
||||
- fat_file_write_fat32_or_non_root_dir()
|
||||
|
||||
concepts:
|
||||
- Avoiding uneccessary device reads is to make sure that writing to the device
|
||||
does not get slowed down unneccesarily.
|
||||
- Verify that appending data to a file does not result in reading the new
|
||||
clusters from device.
|
||||
- Verify writing a whole cluster does not result in reading the cluster from
|
||||
device.
|
||||
296
testsuites/fstests/fsdosfswrite01/init.c
Normal file
296
testsuites/fstests/fsdosfswrite01/init.c
Normal file
@@ -0,0 +1,296 @@
|
||||
/*
|
||||
* Copyright (c) 2012 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Obere Lagerstr. 30
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.com/license/LICENSE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "tmacros.h"
|
||||
#include <fcntl.h>
|
||||
#include <rtems/dosfs.h>
|
||||
#include <rtems/sparse-disk.h>
|
||||
#include <rtems/blkdev.h>
|
||||
#include <bsp.h>
|
||||
|
||||
#define MAX_PATH_LENGTH 100 /* Maximum number of characters per path */
|
||||
#define SECTOR_SIZE 512 /* sector size (bytes) */
|
||||
#define FAT16_MAX_CLN 65525 /* maximum + 1 number of clusters for FAT16 */
|
||||
#define FAT16_DEFAULT_SECTORS_PER_CLUSTER 32 /* Default number of sectors per cluster for FAT16 */
|
||||
#define SECTORS_PER_CLUSTER 2
|
||||
|
||||
static void format_and_mount( const char *dev_name, const char *mount_dir )
|
||||
{
|
||||
static const msdos_format_request_param_t rqdata = {
|
||||
.sectors_per_cluster = SECTORS_PER_CLUSTER,
|
||||
.quick_format = true
|
||||
};
|
||||
|
||||
int rv;
|
||||
|
||||
|
||||
rv = msdos_format( dev_name, &rqdata );
|
||||
rtems_test_assert( rv == 0 );
|
||||
|
||||
rv = mount( dev_name,
|
||||
mount_dir,
|
||||
RTEMS_FILESYSTEM_TYPE_DOSFS,
|
||||
RTEMS_FILESYSTEM_READ_WRITE,
|
||||
NULL );
|
||||
rtems_test_assert( rv == 0 );
|
||||
}
|
||||
|
||||
static void do_fsync( const char *file )
|
||||
{
|
||||
int rv;
|
||||
int fd;
|
||||
|
||||
|
||||
fd = open( file, O_RDONLY );
|
||||
rtems_test_assert( fd >= 0 );
|
||||
|
||||
rv = fsync( fd );
|
||||
rtems_test_assert( rv == 0 );
|
||||
|
||||
rv = close( fd );
|
||||
rtems_test_assert( rv == 0 );
|
||||
}
|
||||
|
||||
static void check_block_stats( const char *dev_name,
|
||||
const char *mount_dir,
|
||||
const rtems_blkdev_stats *expected_stats )
|
||||
{
|
||||
int fd;
|
||||
int rv;
|
||||
rtems_blkdev_stats actual_stats;
|
||||
|
||||
|
||||
do_fsync( mount_dir );
|
||||
|
||||
fd = open( dev_name, O_RDONLY );
|
||||
rtems_test_assert( fd >= 0 );
|
||||
|
||||
rv = ioctl( fd, RTEMS_BLKIO_GETDEVSTATS, &actual_stats );
|
||||
rtems_test_assert( rv == 0 );
|
||||
rtems_test_assert( memcmp( &actual_stats, expected_stats,
|
||||
sizeof( actual_stats ) ) == 0 );
|
||||
|
||||
rv = close( fd );
|
||||
rtems_test_assert( rv == 0 );
|
||||
}
|
||||
|
||||
static void reset_block_stats( const char *dev_name, const char *mount_dir )
|
||||
{
|
||||
int fd;
|
||||
int rv;
|
||||
|
||||
|
||||
do_fsync( mount_dir );
|
||||
|
||||
fd = open( dev_name, O_RDONLY );
|
||||
rtems_test_assert( fd >= 0 );
|
||||
|
||||
rv = ioctl( fd, RTEMS_BLKIO_PURGEDEV );
|
||||
rtems_test_assert( rv == 0 );
|
||||
|
||||
rv = ioctl( fd, RTEMS_BLKIO_RESETDEVSTATS );
|
||||
rtems_test_assert( rv == 0 );
|
||||
|
||||
rv = close( fd );
|
||||
rtems_test_assert( rv == 0 );
|
||||
}
|
||||
|
||||
static int create_file( const char *file_name )
|
||||
{
|
||||
mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
|
||||
|
||||
|
||||
return creat( file_name, mode );
|
||||
}
|
||||
|
||||
static void test_normal_file_write(
|
||||
const char *dev_name,
|
||||
const char *mount_dir,
|
||||
const char *file_name )
|
||||
{
|
||||
static const rtems_blkdev_stats complete_block_stats = {
|
||||
.read_hits = 0,
|
||||
.read_misses = 0,
|
||||
.read_ahead_transfers = 0,
|
||||
.read_blocks = 0,
|
||||
.read_errors = 0,
|
||||
.write_transfers = 1,
|
||||
.write_blocks = 1,
|
||||
.write_errors = 0
|
||||
};
|
||||
static const rtems_blkdev_stats new_block_stats = {
|
||||
.read_hits = 8,
|
||||
.read_misses = 2,
|
||||
.read_ahead_transfers = 0,
|
||||
.read_blocks = 2,
|
||||
.read_errors = 0,
|
||||
.write_transfers = 1,
|
||||
.write_blocks = 4,
|
||||
.write_errors = 0
|
||||
};
|
||||
|
||||
int rv;
|
||||
int fd;
|
||||
ssize_t num_bytes;
|
||||
uint8_t cluster_buf[SECTOR_SIZE
|
||||
* SECTORS_PER_CLUSTER];
|
||||
uint32_t cluster_size = sizeof( cluster_buf );
|
||||
off_t off;
|
||||
|
||||
|
||||
memset( cluster_buf, 0xFE, cluster_size );
|
||||
|
||||
format_and_mount( dev_name, mount_dir );
|
||||
|
||||
fd = create_file( file_name );
|
||||
rtems_test_assert( fd >= 0 );
|
||||
|
||||
num_bytes = write( fd, cluster_buf, cluster_size );
|
||||
rtems_test_assert( (ssize_t) cluster_size == num_bytes );
|
||||
|
||||
off = lseek( fd, 0, SEEK_SET );
|
||||
rtems_test_assert( off == 0 );
|
||||
|
||||
reset_block_stats( dev_name, mount_dir );
|
||||
|
||||
/* Write a complete cluster into an existing file space */
|
||||
num_bytes = write( fd, cluster_buf, cluster_size );
|
||||
rtems_test_assert( (ssize_t) cluster_size == num_bytes );
|
||||
|
||||
check_block_stats( dev_name, mount_dir, &complete_block_stats );
|
||||
reset_block_stats( dev_name, mount_dir );
|
||||
|
||||
num_bytes = write( fd, cluster_buf, cluster_size );
|
||||
rtems_test_assert( (ssize_t) cluster_size == num_bytes );
|
||||
|
||||
/* Write a new partial cluster into a new file space */
|
||||
num_bytes = write( fd, cluster_buf, 1 );
|
||||
rtems_test_assert( num_bytes == 1 );
|
||||
|
||||
check_block_stats( dev_name, mount_dir, &new_block_stats );
|
||||
|
||||
rv = close( fd );
|
||||
rtems_test_assert( 0 == rv );
|
||||
|
||||
rv = unmount( mount_dir );
|
||||
rtems_test_assert( 0 == rv );
|
||||
}
|
||||
|
||||
static void test_fat12_root_directory_write( const char *dev_name,
|
||||
const char *mount_dir,
|
||||
const char *file_name )
|
||||
{
|
||||
static const rtems_blkdev_stats fat12_root_dir_stats = {
|
||||
.read_hits = 11,
|
||||
.read_misses = 2,
|
||||
.read_ahead_transfers = 0,
|
||||
.read_blocks = 2,
|
||||
.read_errors = 0,
|
||||
.write_transfers = 1,
|
||||
.write_blocks = 1,
|
||||
.write_errors = 0
|
||||
};
|
||||
|
||||
int fd;
|
||||
int rv;
|
||||
|
||||
|
||||
format_and_mount( dev_name, mount_dir );
|
||||
|
||||
reset_block_stats( dev_name, mount_dir );
|
||||
|
||||
fd = create_file( file_name );
|
||||
rtems_test_assert( fd >= 0 );
|
||||
|
||||
rv = close( fd );
|
||||
rtems_test_assert( rv == 0 );
|
||||
|
||||
check_block_stats( dev_name, mount_dir, &fat12_root_dir_stats );
|
||||
|
||||
rv = unmount( mount_dir );
|
||||
rtems_test_assert( rv == 0 );
|
||||
}
|
||||
|
||||
static void test( void )
|
||||
{
|
||||
static const char dev_name[] = "/dev/sda";
|
||||
static const char mount_dir[] = "/mnt";
|
||||
static const char file_name[] = "/mnt/file.txt";
|
||||
|
||||
rtems_status_code sc;
|
||||
int rv;
|
||||
|
||||
|
||||
sc = rtems_disk_io_initialize();
|
||||
rtems_test_assert( sc == RTEMS_SUCCESSFUL );
|
||||
|
||||
rv = mkdir( mount_dir, S_IRWXU | S_IRWXG | S_IRWXO );
|
||||
rtems_test_assert( 0 == rv );
|
||||
|
||||
/* A 1.44 MB disk */
|
||||
sc = rtems_sparse_disk_create_and_register(
|
||||
dev_name,
|
||||
SECTOR_SIZE,
|
||||
64,
|
||||
2880,
|
||||
0
|
||||
);
|
||||
rtems_test_assert( RTEMS_SUCCESSFUL == sc );
|
||||
|
||||
test_fat12_root_directory_write( dev_name, mount_dir, file_name );
|
||||
|
||||
test_normal_file_write( dev_name, mount_dir, file_name );
|
||||
|
||||
rv = unlink( dev_name );
|
||||
rtems_test_assert( rv == 0 );
|
||||
}
|
||||
|
||||
static void Init( rtems_task_argument arg )
|
||||
{
|
||||
puts( "\n\n*** TEST FSDOSFSWRITE 1 ***" );
|
||||
|
||||
test();
|
||||
|
||||
puts( "*** END OF TEST FSDOSFSWRITE 1 ***" );
|
||||
|
||||
rtems_test_exit( 0 );
|
||||
}
|
||||
|
||||
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
|
||||
#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
|
||||
#define CONFIGURE_APPLICATION_NEEDS_LIBBLOCK
|
||||
|
||||
#define CONFIGURE_USE_IMFS_AS_BASE_FILESYSTEM
|
||||
|
||||
#define CONFIGURE_FILESYSTEM_DOSFS
|
||||
|
||||
/* 1 device file for blkstats + 1 file for writing + 1 mount_dir + stdin + stdout + stderr + device file when mounted */
|
||||
#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS 8
|
||||
|
||||
#define CONFIGURE_UNLIMITED_OBJECTS
|
||||
#define CONFIGURE_UNIFIED_WORK_AREAS
|
||||
|
||||
#define CONFIGURE_INIT_TASK_STACK_SIZE ( 32 * 1024 )
|
||||
|
||||
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
|
||||
|
||||
#define CONFIGURE_BDBUF_BUFFER_MAX_SIZE ( 32 * 1024 )
|
||||
|
||||
#define CONFIGURE_INIT
|
||||
|
||||
#include <rtems/confdefs.h>
|
||||
Reference in New Issue
Block a user