summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRalf Kirchner <ralf.kirchner@embedded-brains.de>2012-12-05 13:43:34 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2012-12-05 15:26:48 +0100
commit42a22f0824c4618b864582804ce1440b548a462f (patch)
tree835abe13c7d2140f3efa8cf8c256928c0b32e1a0
parentdosfs: Block size optimization (diff)
downloadrtems-42a22f0824c4618b864582804ce1440b548a462f.tar.bz2
dosfs: Cluster write optimization
Separate cluster write from sector write for quick file write. New test fstests/fsdosfswrite01.
-rw-r--r--cpukit/libfs/src/dosfs/fat.c240
-rw-r--r--cpukit/libfs/src/dosfs/fat.h36
-rw-r--r--cpukit/libfs/src/dosfs/fat_fat_operations.c14
-rw-r--r--cpukit/libfs/src/dosfs/fat_file.c231
-rw-r--r--cpukit/libfs/src/dosfs/msdos_misc.c18
-rw-r--r--testsuites/fstests/Makefile.am1
-rw-r--r--testsuites/fstests/configure.ac1
-rw-r--r--testsuites/fstests/fsdosfswrite01/Makefile.am19
-rw-r--r--testsuites/fstests/fsdosfswrite01/fsdosfswrite01.doc15
-rw-r--r--testsuites/fstests/fsdosfswrite01/fsdosfswrite01.scn0
-rw-r--r--testsuites/fstests/fsdosfswrite01/init.c296
11 files changed, 718 insertions, 153 deletions
diff --git a/cpukit/libfs/src/dosfs/fat.c b/cpukit/libfs/src/dosfs/fat.c
index 033c15da86..c82bf5ac8b 100644
--- a/cpukit/libfs/src/dosfs/fat.c
+++ b/cpukit/libfs/src/dosfs/fat.c
@@ -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);
+ fat_buf_mark_modified(fs_info);
+ }
+ }
+ if (RC_OK != rc)
+ return rc;
+ else
+ return bytes_to_write;
+}
- count -= c;
- sec_num++;
- ofs = 0;
+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;
}
- return 0;
+ 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;
-
- fsec = fat_cluster_num_to_sector_num(fs_info, cln);
-
- return _fat_block_write(fs_info, fsec, 0,
- fs_info->vol.spc << fs_info->vol.sec_log2, buff);
+ 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;
+
+ cur_blk += blocks_in_offset;
+
+ 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;
}
diff --git a/cpukit/libfs/src/dosfs/fat.h b/cpukit/libfs/src/dosfs/fat.h
index 48b149199d..5d36fb45c0 100644
--- a/cpukit/libfs/src/dosfs/fat.h
+++ b/cpukit/libfs/src/dosfs/fat.h
@@ -440,6 +440,20 @@ fat_cluster_num_to_sector512_num(
}
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
diff --git a/cpukit/libfs/src/dosfs/fat_fat_operations.c b/cpukit/libfs/src/dosfs/fat_fat_operations.c
index 291819d343..7496c09272 100644
--- a/cpukit/libfs/src/dosfs/fat_fat_operations.c
+++ b/cpukit/libfs/src/dosfs/fat_fat_operations.c
@@ -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;
diff --git a/cpukit/libfs/src/dosfs/fat_file.c b/cpukit/libfs/src/dosfs/fat_file.c
index ddbe02ceb8..43826c9205 100644
--- a/cpukit/libfs/src/dosfs/fat_file.c
+++ b/cpukit/libfs/src/dosfs/fat_file.c
@@ -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);
-
- ret = _fat_block_write(fs_info, sec, byte, count, buf);
- if ( ret < 0 )
- return -1;
-
- return ret;
+ /*
+ * check whether there was enough room on device to locate
+ * file of 'start + count' bytes
+ */
+ if (c != (start + count))
+ count = c - start;
+
+ /* 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);
+
+ 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;
}
/*
diff --git a/cpukit/libfs/src/dosfs/msdos_misc.c b/cpukit/libfs/src/dosfs/msdos_misc.c
index f4de0d5915..5ebf257b5a 100644
--- a/cpukit/libfs/src/dosfs/msdos_misc.c
+++ b/cpukit/libfs/src/dosfs/msdos_misc.c
@@ -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;
diff --git a/testsuites/fstests/Makefile.am b/testsuites/fstests/Makefile.am
index 7cf65710d2..516138027b 100644
--- a/testsuites/fstests/Makefile.am
+++ b/testsuites/fstests/Makefile.am
@@ -1,6 +1,7 @@
ACLOCAL_AMFLAGS = -I ../aclocal
SUBDIRS =
+SUBDIRS += fsdosfswrite01
SUBDIRS += fsdosfsformat01
SUBDIRS += fsfseeko01
SUBDIRS += fsdosfssync01
diff --git a/testsuites/fstests/configure.ac b/testsuites/fstests/configure.ac
index 3496de4e15..4993beb7c5 100644
--- a/testsuites/fstests/configure.ac
+++ b/testsuites/fstests/configure.ac
@@ -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
diff --git a/testsuites/fstests/fsdosfswrite01/Makefile.am b/testsuites/fstests/fsdosfswrite01/Makefile.am
new file mode 100644
index 0000000000..2d21751178
--- /dev/null
+++ b/testsuites/fstests/fsdosfswrite01/Makefile.am
@@ -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
diff --git a/testsuites/fstests/fsdosfswrite01/fsdosfswrite01.doc b/testsuites/fstests/fsdosfswrite01/fsdosfswrite01.doc
new file mode 100644
index 0000000000..e18bf06a39
--- /dev/null
+++ b/testsuites/fstests/fsdosfswrite01/fsdosfswrite01.doc
@@ -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.
diff --git a/testsuites/fstests/fsdosfswrite01/fsdosfswrite01.scn b/testsuites/fstests/fsdosfswrite01/fsdosfswrite01.scn
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/testsuites/fstests/fsdosfswrite01/fsdosfswrite01.scn
diff --git a/testsuites/fstests/fsdosfswrite01/init.c b/testsuites/fstests/fsdosfswrite01/init.c
new file mode 100644
index 0000000000..1b231497ec
--- /dev/null
+++ b/testsuites/fstests/fsdosfswrite01/init.c
@@ -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> \ No newline at end of file