summaryrefslogtreecommitdiffstats
path: root/cpukit/libfs/src/dosfs/fat.c
diff options
context:
space:
mode:
authorRalf Kirchner <ralf.kirchner@embedded-brains.de>2012-11-28 14:43:32 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2012-12-05 15:26:48 +0100
commita20fbe78ec1a84a557ed9bcf5412b1b7c530aa35 (patch)
tree83bb1d7d288143056a788344a768f3496a969801 /cpukit/libfs/src/dosfs/fat.c
parentfstests/fsdosfsformat01: New test (diff)
downloadrtems-a20fbe78ec1a84a557ed9bcf5412b1b7c530aa35.tar.bz2
dosfs: Block size optimization
Change block size of bdbuf to the cluster size if the data clusters are aligned on a cluster boundary. This enables fast access to data clusters.
Diffstat (limited to 'cpukit/libfs/src/dosfs/fat.c')
-rw-r--r--cpukit/libfs/src/dosfs/fat.c202
1 files changed, 108 insertions, 94 deletions
diff --git a/cpukit/libfs/src/dosfs/fat.c b/cpukit/libfs/src/dosfs/fat.c
index c2c3e89b26..033c15da86 100644
--- a/cpukit/libfs/src/dosfs/fat.c
+++ b/cpukit/libfs/src/dosfs/fat.c
@@ -17,88 +17,54 @@
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
+#include <stdint.h>
#include <rtems/libio_.h>
#include "fat.h"
#include "fat_fat_operations.h"
-int
-fat_buf_access(fat_fs_info_t *fs_info, uint32_t blk, int op_type,
- rtems_bdbuf_buffer **buf)
-{
- rtems_status_code sc = RTEMS_SUCCESSFUL;
- uint8_t i;
- bool sec_of_fat;
+static int
+ _fat_block_release(fat_fs_info_t *fs_info);
+static ssize_t
+ fat_cluster_read(fat_fs_info_t *fs_info,
+ uint32_t cln,
+ void *buff);
- if (fs_info->c.state == FAT_CACHE_EMPTY)
- {
- if (op_type == FAT_OP_TYPE_READ)
- sc = rtems_bdbuf_read(fs_info->vol.dd, blk, &fs_info->c.buf);
- else
- sc = rtems_bdbuf_get(fs_info->vol.dd, blk, &fs_info->c.buf);
- if (sc != RTEMS_SUCCESSFUL)
- rtems_set_errno_and_return_minus_one(EIO);
- fs_info->c.blk_num = blk;
- fs_info->c.modified = 0;
- fs_info->c.state = FAT_CACHE_ACTUAL;
- }
+static ssize_t
+ fat_cluster_write(fat_fs_info_t *fs_info,
+ uint32_t cln,
+ const void *buff);
- sec_of_fat = ((fs_info->c.blk_num >= fs_info->vol.fat_loc) &&
- (fs_info->c.blk_num < fs_info->vol.rdir_loc));
+int
+fat_buf_access(fat_fs_info_t *fs_info,
+ const uint32_t sec_num,
+ const int op_type,
+ uint8_t **sec_buf)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ uint32_t blk = fat_sector_num_to_block_num (fs_info,
+ sec_num);
+ uint32_t blk_ofs = fat_sector_offset_to_block_offset (fs_info,
+ sec_num,
+ 0);
- if (fs_info->c.blk_num != blk)
+ if (fs_info->c.state == FAT_CACHE_EMPTY || fs_info->c.blk_num != sec_num)
{
- if (fs_info->c.modified)
- {
- if (sec_of_fat && !fs_info->vol.mirror)
- memcpy(fs_info->sec_buf, fs_info->c.buf->buffer,
- fs_info->vol.bps);
-
- sc = rtems_bdbuf_release_modified(fs_info->c.buf);
- fs_info->c.state = FAT_CACHE_EMPTY;
- fs_info->c.modified = 0;
- if (sc != RTEMS_SUCCESSFUL)
- rtems_set_errno_and_return_minus_one(EIO);
-
- if (sec_of_fat && !fs_info->vol.mirror)
- {
- rtems_bdbuf_buffer *b;
+ fat_buf_release(fs_info);
- for (i = 1; i < fs_info->vol.fats; i++)
- {
- sc = rtems_bdbuf_get(fs_info->vol.dd,
- fs_info->c.blk_num +
- fs_info->vol.fat_length * i,
- &b);
- if ( sc != RTEMS_SUCCESSFUL)
- rtems_set_errno_and_return_minus_one(ENOMEM);
- memcpy(b->buffer, fs_info->sec_buf, fs_info->vol.bps);
- sc = rtems_bdbuf_release_modified(b);
- if ( sc != RTEMS_SUCCESSFUL)
- rtems_set_errno_and_return_minus_one(ENOMEM);
- }
- }
- }
- else
- {
- sc = rtems_bdbuf_release(fs_info->c.buf);
- fs_info->c.state = FAT_CACHE_EMPTY;
- if (sc != RTEMS_SUCCESSFUL)
- rtems_set_errno_and_return_minus_one(EIO);
-
- }
if (op_type == FAT_OP_TYPE_READ)
sc = rtems_bdbuf_read(fs_info->vol.dd, blk, &fs_info->c.buf);
else
sc = rtems_bdbuf_get(fs_info->vol.dd, blk, &fs_info->c.buf);
if (sc != RTEMS_SUCCESSFUL)
rtems_set_errno_and_return_minus_one(EIO);
- fs_info->c.blk_num = blk;
+ fs_info->c.blk_num = sec_num;
+ fs_info->c.modified = 0;
fs_info->c.state = FAT_CACHE_ACTUAL;
}
- *buf = fs_info->c.buf;
+ *sec_buf = &fs_info->c.buf->buffer[blk_ofs];
return RC_OK;
}
@@ -106,19 +72,24 @@ int
fat_buf_release(fat_fs_info_t *fs_info)
{
rtems_status_code sc = RTEMS_SUCCESSFUL;
- uint8_t i;
- bool sec_of_fat;
if (fs_info->c.state == FAT_CACHE_EMPTY)
return RC_OK;
- sec_of_fat = ((fs_info->c.blk_num >= fs_info->vol.fat_loc) &&
- (fs_info->c.blk_num < fs_info->vol.rdir_loc));
-
if (fs_info->c.modified)
{
+ uint32_t sec_num = fs_info->c.blk_num;
+ bool sec_of_fat = ((sec_num >= fs_info->vol.fat_loc) &&
+ (sec_num < fs_info->vol.rdir_loc));
+ uint32_t blk = fat_sector_num_to_block_num(fs_info, sec_num);
+ uint32_t blk_ofs = fat_sector_offset_to_block_offset(fs_info,
+ sec_num,
+ 0);
+
if (sec_of_fat && !fs_info->vol.mirror)
- memcpy(fs_info->sec_buf, fs_info->c.buf->buffer, fs_info->vol.bps);
+ memcpy(fs_info->sec_buf,
+ fs_info->c.buf->buffer + blk_ofs,
+ fs_info->vol.bps);
sc = rtems_bdbuf_release_modified(fs_info->c.buf);
if (sc != RTEMS_SUCCESSFUL)
@@ -127,18 +98,31 @@ fat_buf_release(fat_fs_info_t *fs_info)
if (sec_of_fat && !fs_info->vol.mirror)
{
- rtems_bdbuf_buffer *b;
+ uint8_t i;
for (i = 1; i < fs_info->vol.fats; i++)
{
- sc = rtems_bdbuf_get(fs_info->vol.dd,
- fs_info->c.blk_num +
- fs_info->vol.fat_length * i,
- &b);
+ rtems_bdbuf_buffer *bd;
+
+ sec_num = fs_info->c.blk_num + fs_info->vol.fat_length * i,
+ blk = fat_sector_num_to_block_num(fs_info, sec_num);
+ blk_ofs = fat_sector_offset_to_block_offset(fs_info,
+ sec_num,
+ 0);
+
+ if (blk_ofs == 0
+ && fs_info->vol.bps == fs_info->vol.bytes_per_block)
+ {
+ sc = rtems_bdbuf_get(fs_info->vol.dd, blk, &bd);
+ }
+ else
+ {
+ sc = rtems_bdbuf_read(fs_info->vol.dd, blk, &bd);
+ }
if ( sc != RTEMS_SUCCESSFUL)
rtems_set_errno_and_return_minus_one(ENOMEM);
- memcpy(b->buffer, fs_info->sec_buf, fs_info->vol.bps);
- sc = rtems_bdbuf_release_modified(b);
+ memcpy(bd->buffer + blk_ofs, fs_info->sec_buf, fs_info->vol.bps);
+ sc = rtems_bdbuf_release_modified(bd);
if ( sc != RTEMS_SUCCESSFUL)
rtems_set_errno_and_return_minus_one(ENOMEM);
}
@@ -182,23 +166,23 @@ _fat_block_read(
{
int rc = RC_OK;
ssize_t cmpltd = 0;
- uint32_t blk = start;
+ uint32_t sec_num = start;
uint32_t ofs = offset;
- rtems_bdbuf_buffer *block = NULL;
+ uint8_t *sec_buf;
uint32_t c = 0;
while (count > 0)
{
- rc = fat_buf_access(fs_info, blk, FAT_OP_TYPE_READ, &block);
+ rc = fat_buf_access(fs_info, sec_num, FAT_OP_TYPE_READ, &sec_buf);
if (rc != RC_OK)
return -1;
c = MIN(count, (fs_info->vol.bps - ofs));
- memcpy((buff + cmpltd), (block->buffer + ofs), c);
+ memcpy((buff + cmpltd), (sec_buf + ofs), c);
count -= c;
cmpltd += c;
- blk++;
+ sec_num++;
ofs = 0;
}
return cmpltd;
@@ -231,29 +215,29 @@ _fat_block_write(
{
int rc = RC_OK;
ssize_t cmpltd = 0;
- uint32_t blk = start;
+ uint32_t sec_num = start;
uint32_t ofs = offset;
- rtems_bdbuf_buffer *block = NULL;
+ uint8_t *sec_buf;
uint32_t c = 0;
while(count > 0)
{
c = MIN(count, (fs_info->vol.bps - ofs));
- if (c == fs_info->vol.bps)
- rc = fat_buf_access(fs_info, blk, FAT_OP_TYPE_GET, &block);
+ if (c == fs_info->vol.bytes_per_block)
+ rc = fat_buf_access(fs_info, sec_num, FAT_OP_TYPE_GET, &sec_buf);
else
- rc = fat_buf_access(fs_info, blk, FAT_OP_TYPE_READ, &block);
+ rc = fat_buf_access(fs_info, sec_num, FAT_OP_TYPE_READ, &sec_buf);
if (rc != RC_OK)
return -1;
- memcpy((block->buffer + ofs), (buff + cmpltd), c);
+ memcpy((sec_buf + ofs), (buff + cmpltd), c);
fat_buf_mark_modified(fs_info);
count -= c;
cmpltd +=c;
- blk++;
+ sec_num++;
ofs = 0;
}
return cmpltd;
@@ -267,9 +251,9 @@ _fat_block_zero(
uint32_t count)
{
int rc = RC_OK;
- uint32_t blk = start;
+ uint32_t sec_num = start;
uint32_t ofs = offset;
- rtems_bdbuf_buffer *block = NULL;
+ uint8_t *sec_buf;
uint32_t c = 0;
while(count > 0)
@@ -277,18 +261,18 @@ _fat_block_zero(
c = MIN(count, (fs_info->vol.bps - ofs));
if (c == fs_info->vol.bps)
- rc = fat_buf_access(fs_info, blk, FAT_OP_TYPE_GET, &block);
+ rc = fat_buf_access(fs_info, sec_num, FAT_OP_TYPE_GET, &sec_buf);
else
- rc = fat_buf_access(fs_info, blk, FAT_OP_TYPE_READ, &block);
+ rc = fat_buf_access(fs_info, sec_num, FAT_OP_TYPE_READ, &sec_buf);
if (rc != RC_OK)
return -1;
- memset((block->buffer + ofs), 0, c);
+ memset((block + ofs), 0, c);
fat_buf_mark_modified(fs_info);
count -= c;
- blk++;
+ sec_num++;
ofs = 0;
}
return 0;
@@ -364,6 +348,11 @@ fat_cluster_write(
fs_info->vol.spc << fs_info->vol.sec_log2, buff);
}
+static bool is_cluster_aligned(const fat_vol_t *vol, uint32_t sec_num)
+{
+ return (sec_num & (vol->spc - 1)) == 0;
+}
+
/* fat_init_volume_info --
* Get inforamtion about volume on which filesystem is mounted on
*
@@ -444,12 +433,15 @@ fat_init_volume_info(fat_fs_info_t *fs_info, const char *device)
close(vol->fd);
rtems_set_errno_and_return_minus_one( EINVAL );
}
-
for (vol->sec_mul = 0, i = (vol->bps >> FAT_SECTOR512_BITS); (i & 1) == 0;
i >>= 1, vol->sec_mul++);
for (vol->sec_log2 = 0, i = vol->bps; (i & 1) == 0;
i >>= 1, vol->sec_log2++);
+ vol->bytes_per_block = vol->bps;
+ vol->bytes_per_block_log2 = vol->sec_log2;
+ vol->sectors_per_block = 1;
+
vol->spc = FAT_GET_BR_SECTORS_PER_CLUSTER(boot_rec);
/*
* "sectors per cluster" of zero is invalid
@@ -638,6 +630,28 @@ fat_init_volume_info(fat_fs_info_t *fs_info, const char *device)
rtems_set_errno_and_return_minus_one( ENOMEM );
}
+ /*
+ * If possible we will use the cluster size as bdbuf block size for faster
+ * file access. This requires that certain sectors are aligned to cluster
+ * borders.
+ */
+ if (is_cluster_aligned(vol, vol->data_fsec)
+ && (FAT_FAT32 == vol->type || is_cluster_aligned(vol, vol->rdir_loc)))
+ {
+ vol->bytes_per_block = vol->bpc;
+ vol->bytes_per_block_log2 = vol->bpc_log2;
+ vol->sectors_per_block = vol->spc;
+ sc = rtems_bdbuf_set_block_size (vol->dd, vol->bytes_per_block, true);
+ if (RTEMS_SUCCESSFUL != sc)
+ {
+ close(vol->fd);
+ free(fs_info->vhash);
+ free(fs_info->rhash);
+ free(fs_info->uino);
+ rtems_set_errno_and_return_minus_one( EIO );
+ }
+ }
+
return RC_OK;
}