mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-27 12:48:22 +00:00
fatfs: migrate to advanced buffer cache
This commit is contained in:
@@ -82,7 +82,7 @@ static int fatfs_mount(vfs_t **vfs, vnode_t *mp, vnode_t *backing, void *data) {
|
||||
bpb_t bpb;
|
||||
|
||||
size_t read_count;
|
||||
int error = vfs_read(backing, &bpb, sizeof(bpb), 0, &read_count, 0);
|
||||
int error = vfs_read(backing, &bpb, sizeof(bpb), 0, &read_count, V_FFLAGS_NOCACHE);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
@@ -182,6 +182,14 @@ static int fatfs_mount(vfs_t **vfs, vnode_t *mp, vnode_t *backing, void *data) {
|
||||
fatfs->fat_count = bpb.fat_count;
|
||||
fatfs->cluster_size = bpb.bytes_per_sector * bpb.sectors_per_cluster;
|
||||
|
||||
error = abc_init(&fatfs->abc, backing, bpb.bytes_per_sector);
|
||||
if (error) {
|
||||
VOP_RELEASE(backing);
|
||||
hashtable_destroy(&fatfs->vnode_map);
|
||||
free(fatfs);
|
||||
return error;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -191,6 +199,7 @@ static int fatfs_unmount(vfs_t *vfs) {
|
||||
|
||||
static int fatfs_sync(vfs_t *vfs) {
|
||||
fatfs_t *fatfs = (fatfs_t *)vfs;
|
||||
abc_sync(&fatfs->abc);
|
||||
VOP_LOCK(fatfs->backing);
|
||||
int error = mm_cache_sync_vnode(fatfs->backing, 0, UINT64_MAX);
|
||||
VOP_UNLOCK(fatfs->backing);
|
||||
@@ -256,6 +265,7 @@ static int fatfs_syncvnode(vnode_t *vnode) {
|
||||
|
||||
// sync file data
|
||||
int e = mm_cache_sync_vnode(vnode, 0, UINT64_MAX);
|
||||
abc_sync(&fs->abc);
|
||||
|
||||
VOP_LOCK(fs->backing);
|
||||
// sync the dent
|
||||
@@ -784,16 +794,13 @@ static int fatfs_rename(vnode_t *vsource_dir, vnode_t *vsource, char *old_name,
|
||||
memcpy(new_dent.short_name, target_dent.short_name, 11);
|
||||
|
||||
// already exists, switch it up
|
||||
size_t written;
|
||||
error = vfs_write(fatfs->backing, &new_dent, sizeof(new_dent), dent_disk_offset, &written, 0);
|
||||
error = fatfs_disk_rw(fatfs, &new_dent, sizeof(new_dent), dent_disk_offset, true, true);
|
||||
if (error) {
|
||||
VOP_UNLOCK(vtarget);
|
||||
VOP_RELEASE(vtarget);
|
||||
return error;
|
||||
}
|
||||
|
||||
__assert(written == sizeof(new_dent));
|
||||
|
||||
MUTEX_ACQUIRE(&fatfs->vnode_map_mutex);
|
||||
// remove from the vnode map
|
||||
__assert(hashtable_remove(&fatfs->vnode_map, &dent_disk_offset, sizeof(dent_disk_offset)) == 0);
|
||||
|
||||
@@ -45,12 +45,9 @@ static int directory_read_dent(fatfs_t *fatfs, fatnode_t *fatnode, fatfs_dent_t
|
||||
return error;
|
||||
|
||||
*entries_read = 1;
|
||||
size_t bytes_read;
|
||||
error = vfs_read(fatfs->backing, buffer, sizeof(fatfs_dent_t), *disk_offset, &bytes_read, 0);
|
||||
error = fatfs_disk_rw(fatfs, buffer, sizeof(fatfs_dent_t), *disk_offset, false, true);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
__assert(bytes_read == sizeof(fatfs_dent_t));
|
||||
} else {
|
||||
if (entry_offset >= fatfs->root_entry_count) {
|
||||
*entries_read = 0;
|
||||
@@ -58,14 +55,10 @@ static int directory_read_dent(fatfs_t *fatfs, fatnode_t *fatnode, fatfs_dent_t
|
||||
}
|
||||
|
||||
*entries_read = 1;
|
||||
size_t bytes_read;
|
||||
|
||||
int error = vfs_read(fatfs->backing, buffer, sizeof(fatfs_dent_t), fatfs->root_offset + entry_offset * sizeof(fatfs_dent_t), &bytes_read, 0);
|
||||
int error = fatfs_disk_rw(fatfs, buffer, sizeof(fatfs_dent_t), fatfs->root_offset + entry_offset * sizeof(fatfs_dent_t), false, true);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
__assert(bytes_read == sizeof(fatfs_dent_t));
|
||||
|
||||
*disk_offset = fatfs->root_offset + entry_offset * sizeof(fatfs_dent_t);
|
||||
}
|
||||
|
||||
@@ -84,16 +77,14 @@ static int directory_write_dents(fatfs_t *fatfs, fatnode_t *fatnode, fatfs_dent_
|
||||
|
||||
return error;
|
||||
} else {
|
||||
size_t bytes_written;
|
||||
size_t write_offset = fatfs->root_offset + entry_offset * sizeof(fatfs_dent_t);
|
||||
int error = vfs_write(fatfs->backing, buffer, entry_count * sizeof(fatfs_dent_t), write_offset, &bytes_written, 0);
|
||||
int error = fatfs_disk_rw(fatfs, buffer, entry_count * sizeof(fatfs_dent_t), write_offset, true, true);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (disk_offset)
|
||||
*disk_offset = write_offset;
|
||||
|
||||
__assert(bytes_written == entry_count * sizeof(fatfs_dent_t));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -440,15 +431,11 @@ int fatfs_directory_get_dent(fatfs_t *fatfs, fatnode_t *fatnode, size_t dent_off
|
||||
|
||||
int fatfs_update_dent(fatfs_t *fatfs, fatnode_t *fatnode) {
|
||||
fatfs_dent_t dent;
|
||||
size_t bytes_done;
|
||||
|
||||
if (fatfs->type == FATFS_FAT32 && fatnode == fatfs->root) {
|
||||
// fat32 root dir, update the start cluster
|
||||
int error = vfs_write(fatfs->backing, &fatnode->cluster, sizeof(fatnode->cluster), 44, &bytes_done, 0);
|
||||
int error = fatfs_disk_rw(fatfs, &fatnode->cluster, sizeof(fatnode->cluster), 44, true, true);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
__assert(bytes_done == 4);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -456,23 +443,19 @@ int fatfs_update_dent(fatfs_t *fatfs, fatnode_t *fatnode) {
|
||||
if (fatnode->dent_disk_offset == 0)
|
||||
return 0;
|
||||
|
||||
int error = vfs_read(fatfs->backing, &dent, sizeof(fatfs_dent_t), fatnode->dent_disk_offset, &bytes_done, 0);
|
||||
int error = fatfs_disk_rw(fatfs, &dent, sizeof(fatfs_dent_t), fatnode->dent_disk_offset, false, true);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
__assert(bytes_done == sizeof(fatfs_dent_t));
|
||||
|
||||
// directories have zero size
|
||||
dent.file_size_bytes = fatnode->vnode.type == V_TYPE_DIR ? 0 : fatnode->size;
|
||||
dent.cluster_low = fatnode->cluster & 0xffff;
|
||||
dent.cluster_high = (fatnode->cluster >> 16) & 0xffff;
|
||||
|
||||
error = vfs_write(fatfs->backing, &dent, sizeof(fatfs_dent_t), fatnode->dent_disk_offset, &bytes_done, 0);
|
||||
error = fatfs_disk_rw(fatfs, &dent, sizeof(fatfs_dent_t), fatnode->dent_disk_offset, true, true);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
__assert(bytes_done == sizeof(fatfs_dent_t));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,30 +35,22 @@ static bool fatfs_is_cluster_in_range(fatfs_t *fs, fatfs_cluster_t cluster) {
|
||||
int fatfs_next_cluster(fatfs_t *fatfs, fatfs_cluster_t cluster, fatfs_cluster_t *ret) {
|
||||
uint16_t cluster16;
|
||||
int error = 0;
|
||||
size_t bytes_read = 0;
|
||||
|
||||
switch (fatfs->type) {
|
||||
case FATFS_FAT32:
|
||||
error = vfs_read(fatfs->backing, ret, 4, fatfs->fat_offset + 4 * cluster, &bytes_read, 0);
|
||||
error = fatfs_disk_rw(fatfs, ret, 4, fatfs->fat_offset + 4 * cluster, false, true);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
__assert(bytes_read == 4);
|
||||
break;
|
||||
case FATFS_FAT16:
|
||||
error = vfs_read(fatfs->backing, &cluster16, 2, fatfs->fat_offset + 2 * cluster, &bytes_read, 0);
|
||||
error = fatfs_disk_rw(fatfs, &cluster16, 2, fatfs->fat_offset + 2 * cluster, false, true);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
__assert(bytes_read == 2);
|
||||
*ret = cluster16;
|
||||
break;
|
||||
case FATFS_FAT12:
|
||||
error = vfs_read(fatfs->backing, &cluster16, 2, fatfs->fat_offset + cluster + cluster / 2, &bytes_read, 0);
|
||||
error = fatfs_disk_rw(fatfs, &cluster16, 2, fatfs->fat_offset + cluster + cluster / 2, false, true);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
__assert(bytes_read == 2);
|
||||
*ret = ((cluster % 2) ? (cluster16 >> 4) : cluster16) & 0xfff;
|
||||
break;
|
||||
default:
|
||||
@@ -71,40 +63,31 @@ int fatfs_next_cluster(fatfs_t *fatfs, fatfs_cluster_t cluster, fatfs_cluster_t
|
||||
static int set_next_cluster(fatfs_t *fatfs, int fat, fatfs_cluster_t cluster, fatfs_cluster_t next) {
|
||||
uint16_t cluster16;
|
||||
int error = 0;
|
||||
size_t byte_count;
|
||||
|
||||
size_t fat_offset = fatfs->fat_offset + fat * fatfs->fat_size;
|
||||
|
||||
switch (fatfs->type) {
|
||||
case FATFS_FAT32:
|
||||
error = vfs_write(fatfs->backing, &next, 4, fat_offset + 4 * cluster, &byte_count, 0);
|
||||
error = fatfs_disk_rw(fatfs, &next, 4, fat_offset + 4 * cluster, true, true);
|
||||
if (error)
|
||||
goto leave;
|
||||
|
||||
__assert(byte_count == 4);
|
||||
break;
|
||||
case FATFS_FAT16:
|
||||
cluster16 = (uint16_t)next;
|
||||
error = vfs_write(fatfs->backing, &cluster16, 2, fat_offset + 2 * cluster, &byte_count, 0);
|
||||
error = fatfs_disk_rw(fatfs, &cluster16, 2, fat_offset + 2 * cluster, true, true);
|
||||
if (error)
|
||||
goto leave;
|
||||
|
||||
__assert(byte_count == 2);
|
||||
break;
|
||||
case FATFS_FAT12:
|
||||
next &= 0xfff;
|
||||
error = vfs_read(fatfs->backing, &cluster16, 2, fat_offset + cluster + cluster / 2, &byte_count, 0);
|
||||
error = fatfs_disk_rw(fatfs, &cluster16, 2, fat_offset + cluster + cluster / 2, false, true);
|
||||
if (error)
|
||||
goto leave;
|
||||
|
||||
__assert(byte_count == 2);
|
||||
if (cluster % 2)
|
||||
cluster16 = (cluster16 & 0x000f) | (next << 4);
|
||||
else
|
||||
cluster16 = (cluster16 & 0xf000) | (next & 0xfff);
|
||||
|
||||
error = vfs_write(fatfs->backing, &cluster16, 2, fat_offset + cluster + cluster / 2, &byte_count, 0);
|
||||
__assert(byte_count == 2);
|
||||
error = fatfs_disk_rw(fatfs, &cluster16, 2, fat_offset + cluster + cluster / 2, true, true);
|
||||
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -72,6 +72,61 @@ int fatfs_get_file_disk_offset(fatfs_t *fs, fatnode_t *node, size_t byte_offset,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fatfs_abc_rw_iovec(fatfs_t *fs, iovec_iterator_t *iovec_iterator, size_t count, uintmax_t offset, bool write) {
|
||||
while (count) {
|
||||
size_t block_offset = offset % fs->abc.block_size;
|
||||
size_t do_count = min(count, fs->abc.block_size - block_offset);
|
||||
|
||||
abc_block_t *block;
|
||||
int error = abc_get_block(&fs->abc, offset / fs->abc.block_size, &block);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
void *buffer = (void *)((uintptr_t)block->data + block_offset);
|
||||
error = write ?
|
||||
iovec_iterator_copy_to_buffer(iovec_iterator, buffer, do_count) :
|
||||
iovec_iterator_copy_from_buffer(iovec_iterator, buffer, do_count);
|
||||
if (error == 0 && write)
|
||||
abc_make_dirty(&fs->abc, block);
|
||||
|
||||
abc_release_block(&fs->abc, block);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
offset += do_count;
|
||||
count -= do_count;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fatfs_disk_rw_iovec(fatfs_t *fs, iovec_iterator_t *iovec_iterator, size_t count, uintmax_t offset, bool write, bool cache) {
|
||||
if (cache)
|
||||
return fatfs_abc_rw_iovec(fs, iovec_iterator, count, offset, write);
|
||||
|
||||
size_t done_count;
|
||||
int error = write ?
|
||||
vfs_write_iovec(fs->backing, iovec_iterator, count, offset, &done_count, V_FFLAGS_NOCACHE) :
|
||||
vfs_read_iovec(fs->backing, iovec_iterator, count, offset, &done_count, V_FFLAGS_NOCACHE);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
__assert(done_count == count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fatfs_disk_rw(fatfs_t *fs, void *buffer, size_t count, uintmax_t offset, bool write, bool cache) {
|
||||
iovec_t iovec = {
|
||||
.addr = buffer,
|
||||
.len = count
|
||||
};
|
||||
|
||||
iovec_iterator_t iovec_iterator;
|
||||
iovec_iterator_init(&iovec_iterator, &iovec, 1);
|
||||
|
||||
return fatfs_disk_rw_iovec(fs, &iovec_iterator, count, offset, write, cache);
|
||||
}
|
||||
|
||||
int fatfs_rw_clusters_iovec(fatfs_t *fs, fatnode_t *node, iovec_iterator_t *iovec_iterator, size_t count, uintmax_t index, bool write, bool cache) {
|
||||
fatfs_cluster_t cluster;
|
||||
int error = fatfs_get_cluster_from_index(fs, node, index, &cluster);
|
||||
@@ -107,15 +162,10 @@ int fatfs_rw_clusters_iovec(fatfs_t *fs, fatnode_t *node, iovec_iterator_t *iove
|
||||
|
||||
uintmax_t disk_offset = cluster_disk_offset(fs, cluster);
|
||||
size_t byte_count = cluster_count * fs->cluster_size;
|
||||
size_t done_count;
|
||||
error = write ?
|
||||
vfs_write_iovec(fs->backing, iovec_iterator, byte_count, disk_offset, &done_count, cache ? 0 : V_FFLAGS_NOCACHE) :
|
||||
vfs_read_iovec(fs->backing, iovec_iterator, byte_count, disk_offset, &done_count, cache ? 0 : V_FFLAGS_NOCACHE);
|
||||
|
||||
error = fatfs_disk_rw_iovec(fs, iovec_iterator, byte_count, disk_offset, write, cache);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
__assert(done_count == byte_count);
|
||||
i += cluster_count;
|
||||
|
||||
cluster = next_loop_cluster;
|
||||
@@ -136,16 +186,7 @@ int fatfs_rw_cluster_iovec(fatfs_t *fs, fatnode_t *node, iovec_iterator_t *iovec
|
||||
__assert(cluster && fatfs_is_cluster_eof(fs, cluster) == false);
|
||||
|
||||
uintmax_t disk_offset = cluster_disk_offset(fs, cluster) + offset;
|
||||
size_t done_count;
|
||||
error = write ?
|
||||
vfs_write_iovec(fs->backing, iovec_iterator, count, disk_offset, &done_count, cache ? 0 : V_FFLAGS_NOCACHE) :
|
||||
vfs_read_iovec(fs->backing, iovec_iterator, count, disk_offset, &done_count, cache ? 0 : V_FFLAGS_NOCACHE);
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
__assert(done_count == count);
|
||||
return error;
|
||||
return fatfs_disk_rw_iovec(fs, iovec_iterator, count, disk_offset, write, cache);
|
||||
}
|
||||
|
||||
int fatfs_rw_bytes_iovec(fatfs_t *fs, fatnode_t *node, iovec_iterator_t *iovec_iterator, size_t count, uintmax_t offset, bool write, bool cache) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define _FATFS_H
|
||||
|
||||
#include <kernel/vfs.h>
|
||||
#include <kernel/abc.h>
|
||||
#include <hashtable.h>
|
||||
|
||||
#define FATFS_FAT12 1
|
||||
@@ -69,6 +70,7 @@ typedef struct fatnode_t {
|
||||
typedef struct {
|
||||
vfs_t vfs;
|
||||
vnode_t *backing;
|
||||
abc_t abc;
|
||||
int type;
|
||||
|
||||
union {
|
||||
@@ -108,6 +110,8 @@ void fatfs_free_node(fatnode_t *node);
|
||||
int fatfs_get_cluster_from_index(fatfs_t *fs, fatnode_t *node, uintmax_t index, fatfs_cluster_t *cluster);
|
||||
int fatfs_resize_file(fatfs_t *fatfs, fatnode_t *fatnode, size_t new_size);
|
||||
int fatfs_update_dent(fatfs_t *fatfs, fatnode_t *fatnode);
|
||||
int fatfs_disk_rw_iovec(fatfs_t *fs, iovec_iterator_t *iovec_iterator, size_t count, uintmax_t offset, bool write, bool cache);
|
||||
int fatfs_disk_rw(fatfs_t *fs, void *buffer, size_t count, uintmax_t offset, bool write, bool cache);
|
||||
int fatfs_rw_clusters_iovec(fatfs_t *fs, fatnode_t *node, iovec_iterator_t *iovec_iterator, size_t count, uintmax_t index, bool write, bool cache);
|
||||
int fatfs_rw_cluster_iovec(fatfs_t *fs, fatnode_t *node, iovec_iterator_t *iovec_iterator, size_t count, uintmax_t offset, uintmax_t index, bool write, bool cache);
|
||||
int fatfs_rw_bytes_iovec(fatfs_t *fs, fatnode_t *node, iovec_iterator_t *iovec_iterator, size_t count, uintmax_t offset, bool write, bool cache);
|
||||
|
||||
Reference in New Issue
Block a user