diff --git a/kernel-src/fs/fat/fatfs.c b/kernel-src/fs/fat/fatfs.c index d772ed05..24519324 100644 --- a/kernel-src/fs/fat/fatfs.c +++ b/kernel-src/fs/fat/fatfs.c @@ -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); diff --git a/kernel-src/fs/fat/fatfs_dir.c b/kernel-src/fs/fat/fatfs_dir.c index 78e95d4c..2e57ec86 100644 --- a/kernel-src/fs/fat/fatfs_dir.c +++ b/kernel-src/fs/fat/fatfs_dir.c @@ -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; } diff --git a/kernel-src/fs/fat/fatfs_fat.c b/kernel-src/fs/fat/fatfs_fat.c index 67e36dcd..26b8e689 100644 --- a/kernel-src/fs/fat/fatfs_fat.c +++ b/kernel-src/fs/fat/fatfs_fat.c @@ -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: diff --git a/kernel-src/fs/fat/fatfs_rw.c b/kernel-src/fs/fat/fatfs_rw.c index 0dc51f1c..451db50d 100644 --- a/kernel-src/fs/fat/fatfs_rw.c +++ b/kernel-src/fs/fat/fatfs_rw.c @@ -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) { diff --git a/kernel-src/include/kernel/fatfs.h b/kernel-src/include/kernel/fatfs.h index dfc927a1..c464c2a2 100644 --- a/kernel-src/include/kernel/fatfs.h +++ b/kernel-src/include/kernel/fatfs.h @@ -2,6 +2,7 @@ #define _FATFS_H #include +#include #include #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);