[PATCH 8/8] dosfs: Cluster write optimization
Ralf Kirchner
ralf.kirchner at embedded-brains.de
Thu Nov 29 14:32:46 UTC 2012
Seperate cluster write from sector write for quick file write.
New test fstests/fsdosfswrite01.
---
cpukit/libfs/src/dosfs/fat.c | 240 +++++++++++++++-----
cpukit/libfs/src/dosfs/fat.h | 36 ++-
cpukit/libfs/src/dosfs/fat_fat_operations.c | 14 +-
cpukit/libfs/src/dosfs/fat_file.c | 231 +++++++++++++------
cpukit/libfs/src/dosfs/msdos_misc.c | 18 +-
testsuites/fstests/Makefile.am | 1 +
testsuites/fstests/configure.ac | 1 +
testsuites/fstests/fsdosfsformat01/init.c | 62 +++--
testsuites/fstests/fsdosfswrite01/Makefile.am | 19 ++
.../fstests/fsdosfswrite01/fsdosfswrite01.doc | 12 +
testsuites/fstests/fsdosfswrite01/init.c | 219 ++++++++++++++++++
11 Dateien geändert, 675 Zeilen hinzugefügt(+), 178 Zeilen entfernt(-)
create mode 100644 testsuites/fstests/fsdosfswrite01/Makefile.am
create mode 100644 testsuites/fstests/fsdosfswrite01/fsdosfswrite01.doc
create mode 100644 testsuites/fstests/fsdosfswrite01/fsdosfswrite01.scn
create mode 100644 testsuites/fstests/fsdosfswrite01/init.c
diff --git a/cpukit/libfs/src/dosfs/fat.c b/cpukit/libfs/src/dosfs/fat.c
index 033c15d..c82bf5a 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 48b1491..5d36fb4 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 291819d..7496c09 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 ddbe02c..43826c9 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 f4de0d5..5ebf257 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 7cf6571..5161380 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 3496de4..4993beb 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/fsdosfsformat01/init.c b/testsuites/fstests/fsdosfsformat01/init.c
index 14de46f..ca5e28f 100644
--- a/testsuites/fstests/fsdosfsformat01/init.c
+++ b/testsuites/fstests/fsdosfsformat01/init.c
@@ -19,12 +19,15 @@
#include "tmacros.h"
#include <fcntl.h>
+#include <inttypes.h>
#include <sys/statvfs.h>
#include <rtems/libio.h>
#include <rtems/blkdev.h>
#include <rtems/dosfs.h>
#include <rtems/sparse-disk.h>
+#include <bsp.h>
+
#define MAX_PATH_LENGTH 100 /* Maximum number of characters per path */
#define SECTOR_SIZE 512 /* sector size (bytes) */
#define FAT12_MAX_CLN 4085 /* maximum + 1 number of clusters for FAT12 */
@@ -79,47 +82,56 @@ test_disk_params (
rtems_test_assert(0 == rv);
}
+static void test_create_file(
+ const char *mount_dir,
+ uint32_t file_idx,
+ bool expect_ok
+)
+{
+ char file_name[MAX_PATH_LENGTH +1];
+ int fd;
+
+ snprintf (file_name, MAX_PATH_LENGTH, "%s/file%" PRIu32 ".txt", mount_dir, file_idx);
+ fd = open (file_name, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ if (expect_ok) {
+ int rv;
+
+ rtems_test_assert(fd >= 0);
+
+ rv = close(fd);
+ rtems_test_assert(rv == 0);
+ } else {
+ rtems_test_assert(fd == -1);
+ }
+}
+
static void
test_file_creation (
const char* dev_name,
const char* mount_dir,
- const unsigned int number_of_files
+ const uint32_t number_of_files
)
{
int rv;
- int file_idx = 0;
- int fildes[number_of_files + 1];
+ uint32_t file_idx;
char file_name[MAX_PATH_LENGTH +1];
- unsigned int files_created;
rv = mount (dev_name, mount_dir, RTEMS_FILESYSTEM_TYPE_DOSFS, RTEMS_FILESYSTEM_READ_WRITE, NULL);
rtems_test_assert(0 == rv);
- /* Create as many files as should be supported */
- do {
- snprintf (file_name, MAX_PATH_LENGTH, "%s/file%u.txt", mount_dir, file_idx);
- fildes[file_idx] = open (file_name, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
- rtems_test_assert(-1 != fildes[file_idx]);
-
- ++file_idx;
+ for (file_idx = 0; file_idx < number_of_files; ++file_idx) {
+ test_create_file(mount_dir, file_idx, true);
}
- while (number_of_files > file_idx);
-
- /* Try to create another file which should fail */
- snprintf (file_name, MAX_PATH_LENGTH, "%s/file%u.txt", mount_dir, file_idx);
- fildes[file_idx] = open (file_name, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
- rtems_test_assert(-1 == fildes[file_idx]);
-
- /* Tidy up again by closing and deleting all files */
- files_created = file_idx;
- for (file_idx = 0; file_idx < files_created; file_idx++)
- {
- snprintf (file_name, MAX_PATH_LENGTH, "%s/file%u.txt", mount_dir, file_idx);
- rv = close(fildes[file_idx]);
- rtems_test_assert(0 == rv);
+
+ test_create_file(mount_dir, file_idx, false);
+
+ for (file_idx = 0; file_idx < number_of_files; ++file_idx) {
+ snprintf (file_name, MAX_PATH_LENGTH, "%s/file%" PRIu32 ".txt", mount_dir, file_idx);
rv = unlink (file_name);
rtems_test_assert(0 == rv);
}
+
rv = unmount (mount_dir);
rtems_test_assert(0 == rv);
}
diff --git a/testsuites/fstests/fsdosfswrite01/Makefile.am b/testsuites/fstests/fsdosfswrite01/Makefile.am
new file mode 100644
index 0000000..2d21751
--- /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 at .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 0000000..269f65d
--- /dev/null
+++ b/testsuites/fstests/fsdosfswrite01/fsdosfswrite01.doc
@@ -0,0 +1,12 @@
+This file describes the directives and concepts tested by this test set.
+
+test set name: fsdosfswrite01
+
+directives:
+Verify that a write access does not result in uneccessary reads of the device:
+- 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
+
+concepts:
+- Avoiding uneccessary device reads is to make sure that writing to the device does not get slowed
+ down unneccesarily
diff --git a/testsuites/fstests/fsdosfswrite01/fsdosfswrite01.scn b/testsuites/fstests/fsdosfswrite01/fsdosfswrite01.scn
new file mode 100644
index 0000000..e69de29
diff --git a/testsuites/fstests/fsdosfswrite01/init.c b/testsuites/fstests/fsdosfswrite01/init.c
new file mode 100644
index 0000000..d500f7f
--- /dev/null
+++ b/testsuites/fstests/fsdosfswrite01/init.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2012 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Obere Lagerstr. 30
+ * 82178 Puchheim
+ * Germany
+ * <rtems at 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 */
+
+static void
+ test_file_write (
+ const char* dev_name,
+ const char* mount_dir,
+ uint8_t *blk_buf,
+ uint32_t block_size
+)
+{
+ int rv;
+ int fildes;
+ int devdes;
+ char file_name[MAX_PATH_LENGTH +1];
+ ssize_t num_bytes;
+ unsigned int value;
+ rtems_blkdev_stats blkdev_stats[2];
+ rtems_blkdev_stats *blkdev_stats_tmp = NULL;
+ rtems_blkdev_stats *blkdev_stats_before = &blkdev_stats[0];
+ rtems_blkdev_stats *blkdev_stats_after = &blkdev_stats[1];
+
+ memset(&blkdev_stats, 0, sizeof(blkdev_stats));
+ memset(blk_buf, 0xFE, block_size);
+
+ snprintf (file_name, MAX_PATH_LENGTH, "%s/file1.txt", mount_dir);
+
+ devdes = open(dev_name, O_RDONLY);
+ rtems_test_assert(devdes >= 0);
+
+ rv = mount (dev_name, mount_dir, RTEMS_FILESYSTEM_TYPE_DOSFS, RTEMS_FILESYSTEM_READ_WRITE, NULL);
+ rtems_test_assert(0 == rv);
+
+ fildes = open (file_name, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ rtems_test_assert(-1 != fildes);
+
+ rv = ioctl(devdes, RTEMS_BLKIO_GETDEVSTATS, blkdev_stats_before);
+ rtems_test_assert(0 == rv);
+
+ /* Write blocks of the size of bdufblocks correctly aligned. This should avoid reading from the device */
+ for (value = 0; value < 3; ++value) {
+ num_bytes = write (fildes, blk_buf, block_size);
+ rtems_test_assert((ssize_t) block_size == num_bytes);
+ }
+
+ rv = fsync(fildes);
+ rtems_test_assert(0 == rv);
+
+ rv = ioctl(devdes, RTEMS_BLKIO_GETDEVSTATS, blkdev_stats_after);
+ rtems_test_assert(0 == rv);
+ rtems_test_assert( ( blkdev_stats_after->write_blocks - blkdev_stats_before->write_blocks)
+ > (2 * (blkdev_stats_after->read_blocks - blkdev_stats_before->read_blocks)));
+
+ blkdev_stats_tmp = blkdev_stats_before;
+ blkdev_stats_before = blkdev_stats_after;
+ blkdev_stats_after = blkdev_stats_tmp;
+ memset(blkdev_stats_after, 0, sizeof(*blkdev_stats_after));
+
+ /* Append further bytes to the file. Appending should not require reading from the device */
+ for (value = 0; value < (block_size * 2 / 3); ++value) {
+ num_bytes = write (fildes, &value, sizeof(value));
+ rtems_test_assert(sizeof(value) == num_bytes);
+ }
+
+ rv = fsync(fildes);
+ rtems_test_assert(0 == rv);
+
+ rv = ioctl(devdes, RTEMS_BLKIO_GETDEVSTATS, blkdev_stats_after);
+ rtems_test_assert(0 == rv);
+ rtems_test_assert( ( blkdev_stats_after->write_blocks - blkdev_stats_before->write_blocks)
+ > (2 * (blkdev_stats_after->read_blocks - blkdev_stats_before->read_blocks)));
+
+ rv = close (fildes);
+ rtems_test_assert(0 == rv);
+
+ rv = unmount (mount_dir);
+ rtems_test_assert(0 == rv);
+
+ rv = close (devdes);
+ rtems_test_assert(0 == rv);
+
+}
+
+
+static void test(void)
+{
+ rtems_status_code sc;
+ int rv;
+ const char dev_name[] = "/dev/rda";
+ const char mount_dir[] = "/mnt";
+ rtems_sparse_disk *sparse_disk = NULL;
+ uint8_t blk_buf[SECTOR_SIZE * 2];
+
+ 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);
+
+
+
+ /* FAT12 */
+ /* For 1.44 MB disks */
+ sc = rtems_sparse_disk_create(
+ SECTOR_SIZE,
+ 64,
+ &sparse_disk
+ );
+ rtems_test_assert(RTEMS_SUCCESSFUL == sc);
+ sc = rtems_sparse_disk_register(
+ dev_name,
+ sparse_disk,
+ SECTOR_SIZE,
+ 2880,
+ 64,
+ rtems_sparse_disk_delete,
+ 0
+ );
+ rtems_test_assert(RTEMS_SUCCESSFUL == sc);
+
+ rv = msdos_format(dev_name, NULL);
+ rtems_test_assert(rv == 0);
+
+ test_file_write (dev_name, mount_dir, blk_buf, SECTOR_SIZE * 2);
+
+ rv = unlink (dev_name);
+ rtems_test_assert(rv == 0);
+
+
+
+ /* FAT32 */
+
+ sc = rtems_sparse_disk_create(
+ SECTOR_SIZE,
+ 1024,
+ &sparse_disk
+ );
+ rtems_test_assert(RTEMS_SUCCESSFUL == sc);
+ sc = rtems_sparse_disk_register(
+ dev_name,
+ sparse_disk,
+ SECTOR_SIZE,
+ (FAT16_MAX_CLN * FAT16_DEFAULT_SECTORS_PER_CLUSTER) + 41,
+ 1024,
+ rtems_sparse_disk_delete,
+ 0
+ );
+ rtems_test_assert(RTEMS_SUCCESSFUL == sc);
+
+ rv = msdos_format(dev_name, NULL);
+ rtems_test_assert(rv == 0);
+
+ test_file_write (dev_name, mount_dir, blk_buf, SECTOR_SIZE);
+
+ rv = unlink (dev_name);
+ rtems_test_assert(rv == 0);
+}
+
+static void Init(rtems_task_argument arg)
+{
+ puts("\n\n*** TEST fsdosfswrite01 ***");
+
+ test();
+
+ puts("*** END OF TEST fsdosfswrite01 ***");
+
+ 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 7
+
+#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>
--
1.7.10.4
More information about the devel
mailing list