summaryrefslogtreecommitdiffstats
path: root/cpukit/libfs/src/dosfs/fat_file.c
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 /cpukit/libfs/src/dosfs/fat_file.c
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.
Diffstat (limited to 'cpukit/libfs/src/dosfs/fat_file.c')
-rw-r--r--cpukit/libfs/src/dosfs/fat_file.c231
1 files changed, 156 insertions, 75 deletions
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;
}
/*