add open and close functions, clean up ref_count=0 inodes and blocks

This commit is contained in:
ІО-23 Шмуляр Олег 2025-04-26 14:41:43 +03:00
parent 447a1448ad
commit ef7f9ff553
4 changed files with 168 additions and 20 deletions

View File

@ -1,6 +1,7 @@
#ifndef CONFIG_FILE #ifndef CONFIG_FILE
#define CONFIG_FILE #define CONFIG_FILE
/* Global config options */ /* Global config options */
#define DEBUG 1 #define DEBUG 1
#define LOG_LEVEL 4 #define LOG_LEVEL 4
@ -23,6 +24,7 @@
#define FS_BLOCK_SIZE 4096 #define FS_BLOCK_SIZE 4096
#define FS_MAX_BITMAP_SIZE 64 #define FS_MAX_BITMAP_SIZE 64
#define FS_MAX_PATH_LEN 512 #define FS_MAX_PATH_LEN 512
#define FS_MAX_OPEN_FD 32
#endif #endif

View File

@ -41,6 +41,11 @@ struct fs_directory_record {
unsigned int inode_no; unsigned int inode_no;
}; };
struct fs_file_description {
unsigned int inode;
unsigned int rw_offset;
};
char *fs_get_cwd(void); char *fs_get_cwd(void);
int fs_create(void *d); int fs_create(void *d);
@ -50,5 +55,7 @@ int fs_mkfs(void *d);
int fs_ls(void *d); int fs_ls(void *d);
int fs_la(void *d); int fs_la(void *d);
int fs_rm(void *d); int fs_rm(void *d);
int fs_open(void *d);
int fs_close(void *d);
int fs_allow_write(void *d); int fs_allow_write(void *d);
int fs_prohibit_write(void *d); int fs_prohibit_write(void *d);

View File

@ -15,9 +15,16 @@ static const struct CliCommandEntry cmd[] = {
// mandatory commands // mandatory commands
{"mkfs", 1, (enum CliArgType[]) {INT}, fs_mkfs}, {"mkfs", 1, (enum CliArgType[]) {INT}, fs_mkfs},
{"create", 1, (enum CliArgType[]) {STR}, fs_create}, {"create", 1, (enum CliArgType[]) {STR}, fs_create},
//{"stat", 1, (enum CliArgType[]) {STR}, fs_stat},
{"ls", 0, NULL, fs_ls}, {"ls", 0, NULL, fs_ls},
{"ln", 2, (enum CliArgType[]) {STR, STR}, fs_ln}, {"ln", 2, (enum CliArgType[]) {STR, STR}, fs_ln},
{"rm", 1, (enum CliArgType[]) {STR}, fs_rm}, {"rm", 1, (enum CliArgType[]) {STR}, fs_rm},
//{"truncate", 2, (enum CliArgType[]) {STR, INT}, fs_truncate},
{"open", 1, (enum CliArgType[]) {STR}, fs_open},
//{"seek", 2, (enum CliArgType[]) {INT, INT}, fs_seek},
//{"read", 2, (enum CliArgType[]) {INT, INT}, fs_read},
//{"write", 2, (enum CliArgType[]) {INT, STR}, fs_write},
{"close", 1, (enum CliArgType[]) {INT}, fs_close},
// custom commands // custom commands
{"use", 1, (enum CliArgType[]) {STR}, fs_use}, {"use", 1, (enum CliArgType[]) {STR}, fs_use},

142
src/fs.c
View File

@ -21,6 +21,8 @@ static int write_permitted;
static char fs_cwd[FS_MAX_PATH_LEN+1]; static char fs_cwd[FS_MAX_PATH_LEN+1];
static unsigned int fs_cwd_inode_ptr; static unsigned int fs_cwd_inode_ptr;
static struct fs_file_description fs_file_descriptions[FS_MAX_OPEN_FD];
static int read_block(unsigned int block_no, void *data) static int read_block(unsigned int block_no, void *data)
{ {
@ -384,9 +386,10 @@ static int *find_filename_in_directory(unsigned int dir_inode_ptr, char *fname)
continue; continue;
// filename found // filename found
int *r = malloc(sizeof(int) * 2); int *r = malloc(sizeof(int) * 3);
r[0] = i; r[0] = i;
r[1] = k; r[1] = k;
r[2] = recs[k].inode_no;
return r; return r;
} }
} }
@ -477,16 +480,22 @@ static int fs_remove_fname_from_directory(unsigned int dir_inode_ptr, char *fnam
for (int i = 0; i < BLOCK_ADDRESSES_PER_INODE; i++) { for (int i = 0; i < BLOCK_ADDRESSES_PER_INODE; i++) {
struct fs_directory_record recs[DIRECTORY_RECORDS_PER_BLOCK]; struct fs_directory_record recs[DIRECTORY_RECORDS_PER_BLOCK];
if (dir.blocks[i]) { if (!dir.blocks[i])
continue;
read_block(dir.blocks[i], (void *) &recs); read_block(dir.blocks[i], (void *) &recs);
for (int k = 0; k < DIRECTORY_RECORDS_PER_BLOCK; k++) { for (int k = 0; k < DIRECTORY_RECORDS_PER_BLOCK; k++) {
if (!recs[k].inode_no) if (!recs[k].inode_no)
continue; continue;
if (!strcmp(fname, recs[k].fname)) { if (strcmp(fname, recs[k].fname))
continue;
pr("Directory record for '%s' found in block=%d, record=%d, removing\n", fname, i, k); pr("Directory record for '%s' found in block=%d, record=%d, removing\n", fname, i, k);
unsigned int inode_location_cache = read_inode_ptr(recs[k].inode_no);
// decrement ref_count // decrement ref_count
struct fs_inode f; struct fs_inode f;
read_block(read_inode_ptr(recs[k].inode_no), (void *) &f); read_block(read_inode_ptr(recs[k].inode_no), (void *) &f);
@ -497,6 +506,44 @@ static int fs_remove_fname_from_directory(unsigned int dir_inode_ptr, char *fnam
if (!f.ref_count) { if (!f.ref_count) {
pr("ref_count=0, clearing inode_ptr\n"); pr("ref_count=0, clearing inode_ptr\n");
write_inode_ptr(recs[k].inode_no, 0); write_inode_ptr(recs[k].inode_no, 0);
// if no fd reference this inode, clean it up altogether
int i;
for (i = 0; i < FS_MAX_OPEN_FD; i++)
if (fs_file_descriptions[i].inode == inode_location_cache)
break;
if (i == FS_MAX_OPEN_FD) {
pr("No open fd reference inode %d, cleaning up\n", inode_location_cache);
struct fs_inode f;
read_block(inode_location_cache, (void *) &f);
// clear blocks referenced in base inode
for (int i = 0; i < BLOCK_ADDRESSES_PER_INODE; i++) {
if (f.blocks[i])
mark_free(f.blocks[i]);
}
mark_free(inode_location_cache);
// clear blocks referenced in inode extensions
struct fs_inode_extension ext;
unsigned int next_extension = f.next_extension;
while (next_extension) {
mark_free(next_extension);
read_block(next_extension, (void *) &ext);
next_extension = ext.next_extension;
for (int i = 0; i < BLOCK_ADDRESSES_PER_INODE_EXTENSION; i++) {
if (ext.blocks[i])
mark_free(ext.blocks[i]);
}
}
} else {
pr("Inode %d is still referenced by fd %d, not removing it\n",
inode_location_cache, i);
}
} }
// clear directory record inode_ptr // clear directory record inode_ptr
@ -506,8 +553,6 @@ static int fs_remove_fname_from_directory(unsigned int dir_inode_ptr, char *fnam
goto fs_remove_fname_from_directory_finish; goto fs_remove_fname_from_directory_finish;
} }
} }
}
}
// list entries from inode extension // list entries from inode extension
// TODO // TODO
@ -520,6 +565,93 @@ fs_remove_fname_from_directory_finish:
return 0; return 0;
} }
int fs_open(void *d)
{
char *fname = *((char **) d);
// find file inode
struct fs_file_description fd;
{
int *r = find_filename_in_directory(fs_cwd_inode_ptr, fname);
if (!r) {
pr_err("no such file: '%s'\n", fname);
return 0;
}
fd.inode = read_inode_ptr(r[2]);
free(r);
}
fd.rw_offset = 0;
// find free file descriptor
int free_fd;
for (free_fd = 0; (free_fd < FS_MAX_OPEN_FD) && (fs_file_descriptions[free_fd].inode); free_fd++);
if (free_fd == FS_MAX_OPEN_FD) {
pr_err("no free file descriptor found\n");
return 0;
}
memcpy(&(fs_file_descriptions[free_fd]), &fd, sizeof(struct fs_file_description));
pr_stdout("%d\n", free_fd);
return 0;
}
int fs_close(void *d)
{
int fd = *((int *) d);
// remove inode number from fd
if (!fs_file_descriptions[fd].inode) {
pr_err("fd %d is not open\n", fd);
return 0;
}
unsigned int inode_location_cache = fs_file_descriptions[fd].inode;
fs_file_descriptions[fd].inode = 0;
pr("fd %d closed\n", fd);
// cleanup file data on disk if ref_count=0
// and no other open descriptor references it's inode
struct fs_inode f;
read_block(inode_location_cache, (void *) &f);
if (f.ref_count)
return 0;
for (int i = 0; i < FS_MAX_OPEN_FD; i++)
if (fs_file_descriptions[i].inode == inode_location_cache)
return 0;
// if ended up here, the inode is not referenced anywhere
pr("No open fd reference inode %d, cleaning up\n", inode_location_cache);
// clear blocks referenced in base inode
for (int i = 0; i < BLOCK_ADDRESSES_PER_INODE; i++) {
if (f.blocks[i])
mark_free(f.blocks[i]);
}
mark_free(inode_location_cache);
// clear blocks referenced in inode extensions
struct fs_inode_extension ext;
unsigned int next_extension = f.next_extension;
while (next_extension) {
mark_free(next_extension);
read_block(next_extension, (void *) &ext);
next_extension = ext.next_extension;
for (int i = 0; i < BLOCK_ADDRESSES_PER_INODE_EXTENSION; i++) {
if (ext.blocks[i])
mark_free(ext.blocks[i]);
}
}
}
int fs_create(void *d) int fs_create(void *d)
{ {
if (!write_permitted) { if (!write_permitted) {