Browse Source

vfs/fs write

master
Mathieu Serandour 7 months ago
parent
commit
03d5c826fd
  1. 4
      kernel/fs/fat32/fat32.c
  2. 8
      kernel/fs/fs.h
  3. 26
      kernel/fs/vfs_dirs.c
  4. 132
      kernel/fs/vfs_files.c
  5. 5
      tests/disk_tb.c
  6. 3
      tests/tests.h
  7. 6
      tests/vfs/Makefile
  8. BIN
      tests/vfs/vfs
  9. 74
      tests/vfs/vfs.c

4
kernel/fs/fat32/fat32.c

@ -462,7 +462,7 @@ fs_t* fat32_mount(disk_part_t* part) {
fs->file_access_granularity = block_size(part);
fs->n_open_files = 0;
fs->cacheable = 1;
fs->cacheable = 0;
fs->read_only = 0;
fs->seekable = 1;
@ -473,8 +473,6 @@ fs_t* fat32_mount(disk_part_t* part) {
* functions take file_t instead
* of void*
*/
//fs->open_file = (void*)fat32_open_file;
//fs->close_file = (void*)fat32_close_file;
fs->read_file_sectors = fat32_read_file_sectors;
fs->write_file_sectors = fat32_write_file_sectors;
fs->read_dir = fat32_read_dir;

8
kernel/fs/fs.h

@ -80,7 +80,7 @@ typedef struct dirent {
typedef struct fast_dirent {
ino_t ino; /* Inode number */
size_t file_size; /* Length of this record */
unsigned char type; /* Type of file; not supported
unsigned char type; /* Type of file; not supported
by all filesystem types */
} fast_dirent_t;
@ -231,6 +231,12 @@ typedef struct fs {
void (*free_dirents)(dirent_t* dir);
/*
int create_dirent(uint64_t parent_dir_addr, unsigned type);
int move_dirent(uint64_t addr, uint64_t src_parent_addr, uint64_t dst_parent_addr);
int remove_dirent(uint64_t addr, uint64_t src_parent_addr);
*/
/**
* @brief destruct this structure,
* cleanup every allocated memory

26
kernel/fs/vfs_dirs.c

@ -553,6 +553,7 @@ static vdir_t **get_vchildren(const char *path, int *n)
}
}
/**
* find a child with a given name
*
@ -594,6 +595,7 @@ static int find_fs_child(
return found;
}
// path in cannonical form
// return NULL if empty / conflict
static dir_cache_ent_t *get_cache_entry(const char *path)
@ -720,19 +722,23 @@ static void log_tree(const char *path, int level)
vfs_closedir(dir);
}
// read & seek test function
static inline
void test_file(void) {
void test_file_read_seek(void) {
file_handle_t* f = vfs_open_file("/fs/file.dat");
assert(f);
//assert(!vfs_seek_file(f, 512, SEEK_SET));
//log_warn("FILE SIZE = %u", vfs_tell_file(f));
vfs_seek_file(f, 50, SEEK_CUR);
vfs_write_file("Une balle pourtant, mieux ajustée ou plus traître que les autres, finit par atteindre l'enfant feu follet. On vit Gavroche chanceler, puis il s'affaissa. Toute la barricade poussa un cri ; mais il y avait de l'Antée dans ce pygmée ; pour le gamin toucher le pavé, c'est comme pour le géant toucher la terre ; Gavroche n'était tombé que pour se redresser ; il resta assis sur son séant, un long filet de sang rayait son visage, il éleva ses deux bras en l'air, regarda du côté d'où était venu le coup, et se mit à",
512, 1, f);
vfs_close_file(f);
return;
#define SIZE 512
vfs_seek_file(f, 0, SEEK_END);
size_t fsz = vfs_tell_file(f);
log_warn("vfs_tell_file(f) = %lu", vfs_tell_file(f));
vfs_seek_file(f, 0, SEEK_SET);
@ -746,13 +752,6 @@ file_handle_t* f = vfs_open_file("/fs/file.dat");
for(int i = 0; i < 200; i++)
{
size_t seek = 0;
int rd = SIZE;
if(fsz > i * SIZE)
seek = fsz - i * SIZE;
else
rd = i * SIZE - fsz;
x = (x * 411 + 1431) % (1024 * 1024 / 4 - SIZE);
@ -767,7 +766,7 @@ file_handle_t* f = vfs_open_file("/fs/file.dat");
buf[read] = 0;
uint32_t* chunk = buf;
uint32_t* chunk = (uint32_t*)buf;
for(unsigned j = 0; j < SIZE / 4; j++) {
if(chunk[j] != j + x) {
log_warn("chunk[j]=%x, j + x=%x", chunk[j], j+x);
@ -820,6 +819,7 @@ int vfs_mount(disk_part_t *part, const char *path)
new->fs = fs;
//test_file_read_seek();
return 1;
@ -837,7 +837,7 @@ int vfs_unmount(const char *path)
if (!vdir)
return 0;
log_info("unmounting %s", path);
return unmount(vdir);
}

132
kernel/fs/vfs_files.c

@ -228,7 +228,8 @@ size_t vfs_read_file(void *ptr, size_t size, size_t nmemb,
// offset of the end of the read buffer
unsigned end_offset = bsize % granularity;
unsigned end_offset = must_read % granularity;
unsigned read_buf_size = read_blocks * granularity;
@ -284,20 +285,137 @@ size_t vfs_read_file(void *ptr, size_t size, size_t nmemb,
size_t vfs_write_file(const void *ptr, size_t size, size_t nmemb,
file_handle_t *stream)
{
(void)size;
assert(stream);
assert(ptr);
assert(0);
void *const buf = stream->sector_buff;
fs_t *fs = stream->fs;
uint64_t file_size = stream->file_size;
unsigned granularity = fs->file_access_granularity;
unsigned cachable = fs->cacheable;
unsigned bsize = size * nmemb;
if(bsize == 0)
return 0;
unsigned must_write = stream->sector_offset + bsize;
size_t write_blocks = CEIL_DIV(must_write, granularity);
void* write_buf;
int unaligned = 0;
// offset of the end of the read buffer
unsigned end_offset = must_write % granularity;
unsigned write_buf_size = write_blocks * granularity;
// if the selected read is perfectly aligned,
// the we don't need another buffer
if(stream->sector_offset == 0 && end_offset == 0) {
write_buf = ptr;
}
/*
sc = stream->sector_count
storage blocks (for n = 5):
|---------|---------|---------|---------|---------|
| sc | sc+1 | sc+2 | sc+3 | sc+4 |
|---------|---------|---------|---------|---------|
we want to write:
|------===|=========|=========|=========|==-------|
| sc | | sc+1 | sc+2 | sc+3 | | sc+4 |
|------===|=========|=========|=========|==-------|
<-----> <->
stream->sector_offset end_offset
to do so, we have to first read sc and
sc + n - 1 blocks.
if fs->cachable = 1 and stream->buffer_valid,
then we don't need to read sc block
we still have to read sc+4 though.
We can then put sc+4 in the cache buffer
we set write_buf:
|=========|=========|=========|=========|=========|
| sc | sc+1 | sc+2 | sc+3 | sc+4 |
|=========|=========|=========|=========|=========|
*/
else {
unaligned = 1;
write_buf = malloc(write_buf_size);
// unaligned beginning
if(stream->sector_offset != 0) {
if(!stream->buffer_valid || !cachable) {
// must read before writing
fs->read_file_sectors(
fs,
stream->file,
write_buf,
stream->sector_count,
1
);
}
else // buf contains cached data of sc block
memcpy(write_buf, buf, stream->sector_offset);
}
// unaligned end
if(end_offset != 0) {
fs->read_file_sectors(
fs,
stream->file,
write_buf + write_buf_size - granularity,
stream->sector_count,
1
);
}
memcpy(write_buf + stream->sector_offset, ptr, bsize);
}
fs->write_file_sectors(
fs,
stream->file,
write_buf,
stream->sector_count,
write_blocks
);
if(unaligned)
free(write_buf);
// advance the cursor
stream->sector_offset = end_offset;
stream->file_offset += bsize;
stream->sector_count = stream->file_offset / granularity;
return nmemb;
}
int vfs_seek_file(file_handle_t *restrict stream, uint64_t offset, int whence)
{
(void)stream;
(void)offset;
(void)whence;
// real file offset: to be
// calculated with the whence field
@ -332,5 +450,5 @@ int vfs_seek_file(file_handle_t *restrict stream, uint64_t offset, int whence)
long vfs_tell_file(file_handle_t *restrict stream)
{
return stream->file_size;
return stream->file_offset;
}

5
tests/disk_tb.c

@ -27,10 +27,7 @@ void dread(struct driver* this,
fseek(data->f, lba * size, SEEK_SET);
assert(fread(buf, size, count, data->f) == count);
printf("DREAD %lu %lu\n", size, size*count);
//dump(buf, size*count, 32, DUMP_HEX8);
//printf(buf);
//fwrite(, size, count, stdout);
printf("DREAD");
}
static

3
tests/tests.h

@ -0,0 +1,3 @@
#pragma once
#define TEST(EX) do{printf("test: %s\n", #EX);EX;}while(0)

6
tests/vfs/Makefile

@ -3,6 +3,7 @@
.PHONY = run all clean
EXE = ./vfs
DISKFILE := ./disk.bin
CC := gcc
LD := gcc
@ -13,7 +14,9 @@ PY := python3
KERNEL=../../kernel/
CFLAGS = -Wall -Wextra -O0 -pipe -I$(KERNEL) -DTEST -fno-inline -g
DEFINES := -DDISKFILE=\"$(DISKFILE)\" -DTEST
CFLAGS = -Wall -Wextra -O0 -pipe -I$(KERNEL) $(DEFINES) -fno-inline -g
CFILES := $(shell find ./ -type f -name '*.c')
@ -44,6 +47,7 @@ run: all
all: $(EXE)
cp ../../disk.bin $(DISKFILE)
$(EXE): $(OBJ)

BIN
tests/vfs/vfs

Binary file not shown.

74
tests/vfs/vfs.c

@ -5,6 +5,7 @@
#include <lib/logging.h>
#include <lib/dump.h>
#include <stdlib.h>
#include "../tests.h"
void disk_tb_install(const char* path);
@ -44,57 +45,70 @@ static void log_tree(const char *path, int level)
// read & seek test function
static inline
void test_file_read_seek(void) {
file_handle_t* f = vfs_open_file("/fs/file.dat");
void test_write(void) {
file_handle_t* f = vfs_open_file("/fs/file.dat");
assert(f);
assert(!vfs_seek_file(f, 512, SEEK_SET));
assert(!vfs_seek_file(f, 0, SEEK_END));
log_warn("FILE SIZE = %u", vfs_tell_file(f));
vfs_seek_file(f, 50, SEEK_CUR);
vfs_seek_file(f, 234567, SEEK_SET);
char rd[513];
assert(vfs_read_file(rd, 512, 1, f) == 1);
rd[512] = 0;
printf("READ: %512s", rd);
dump(rd, 512, 32, DUMP_HEX8);
vfs_seek_file(f, 50, SEEK_CUR);
char buf[512] =
uint8_t buf[512] = {0xff};
for(int i = 0; i < 512; i++)
buf[i] = 0xff;
/*
"Une balle pourtant, mieux ajustée ou plus traître que les autres, finit par atteindre "
"l'enfant feu follet. On vit Gavroche chanceler, puis il s'affaissa. Toute la barricade "
"poussa un cri ; mais il y avait de l'Antée dans ce pygmée ; pour le gamin toucher le "
"pavé, c'est comme pour le géant toucher la terre ; Gavroche n'était tombé que pour se "
"redresser ; il resta assis sur son séant, un long filet de sang rayait son visage,"
"il éleva ses deux bras en l'air, regarda du côté d'où était venu le coup, et se mit à";
"il éleva ses deux bras en l'air, regarda du côté d'où était venu le coup";
*/
vfs_write_file(buf, 512, 1, f);
vfs_seek_file(f, 234567, SEEK_SET);
char rd[1025];
assert(vfs_read_file(rd, 1024, 1, f) == 1);
rd[1024] = 0;
printf("READ: %s\n\n", rd);
printf("READ: %c\n\n", *rd);
dump(rd, 1024, 32, DUMP_HEX8);
vfs_close_file(f);
return;
#define SIZE 512
/*
}
int read_seek_big_file(size_t SIZE) {
assert(SIZE < 1024 * 1024);
file_handle_t* f = vfs_open_file("/fs/file.dat");
vfs_seek_file(f, 0, SEEK_END);
assert(vfs_tell_file(f) == 1024*1024);
vfs_seek_file(f, 0, SEEK_SET);
char* buf = malloc(SIZE+1);
int read = 0;
int x = 531;
for(int i = 0; i < 200; i++)
{
x = (x * 411 + 1431) % (1024 * 1024 / 4 - SIZE);
x = (x * 411 + 1431) % (1024 * 1024 / 4 - SIZE / 4);
size_t y = x*4;
//x < 1024 * 1024 / 4 - SIZE
///y < 1024 * 1024 - SIZE*4 < 1024**2
log_info("test %u", y);
vfs_seek_file(f, y, SEEK_SET);
@ -115,19 +129,31 @@ file_handle_t* f = vfs_open_file("/fs/file.dat");
//dump(buf, SIZE, 8, DUMP_DEC32);
}
vfs_close_file(f);
*/
}
#ifndef DISKFILE
#error DISKFILE should be defined.
#endif
int main() {
vfs_init();
disk_tb_install("../../disk.bin");
disk_tb_install(DISKFILE);
disk_part_t* part = search_partition("Bincows");
assert(part);
printf("MOUNT");
vfs_mount(part, "/fs");
test_file_read_seek();
//TEST(read_seek_big_file(1));
//TEST(read_seek_big_file(234));
//TEST(read_seek_big_file(512));
//TEST(read_seek_big_file(513));
//TEST(read_seek_big_file(456523));
//TEST(read_seek_big_file(145652));
test_write();
shutdown();
}

Loading…
Cancel
Save