VFS: design for the name cache system

This commit is contained in:
Mathieu Maret 2024-05-23 00:21:41 +02:00
parent 778999c8f4
commit 3ecb5b9d66
6 changed files with 404 additions and 0 deletions

13
core/fs.c Normal file
View File

@ -0,0 +1,13 @@
#include "fs.h"
int fsInodeUnref(struct inode *inode)
{
(void)inode;
return 0;
};
int fsInodeRef(struct inode *inode)
{
(void)inode;
return 0;
};

7
core/fs.h Normal file
View File

@ -0,0 +1,7 @@
#pragma once
struct inode {//TODO
};
int fsInodeUnref(struct inode *inode);
int fsInodeRef(struct inode *inode);

133
core/fsEntry.c Normal file
View File

@ -0,0 +1,133 @@
#include "alloc.h"
#include "assert.h"
#include "fsEntry.h"
#include "errno.h"
#include "list.h"
#include "mem.h"
#include "stdint.h"
bool_t pstringSplipPath(struct pstr *path, struct pstr *upper, struct pstr *lower)
{
typeof(path->name) curPos = path->name;
typeof(path->len) curLen = path->len;
typeof(path->len) upperLen = 0;
// Skip leading /
while (curLen > 0 && curPos[0] == '/') {
curPos++;
curLen--;
}
upper->name = curPos;
// Find first non /
while (curLen > 0 && curPos[0] != '/') {
upperLen++;
curLen--;
curPos++;
}
upper->len = upperLen;
while (curLen > 0 && curPos[0] == '/') {
curPos++;
curLen--;
}
lower->name = curPos;
lower->len = path->len - (lower->name - path->name);
return lower->len > 0;
}
bool_t pstringIsEq(struct pstr *p1, struct pstr *p2)
{
return p1->len == p2->len && (memcmp(p1, p2, p1->len) == 0);
}
int fsEntryRef(struct fsEntry *entry)
{
entry->ref++;
return 0;
}
int fsEntryUnref(struct fsEntry **entry)
{
struct fsEntry *toDelete = NULL, *entryTmp;
entryTmp = *entry;
*entry = NULL;
while (entryTmp) {
assert(entryTmp->ref > 0);
entryTmp->ref--;
if (entryTmp->ref > 0)
break;
if (entryTmp == *entry)
entry = NULL;
if (entryTmp->parent) {
struct fsEntry *parent = entryTmp->parent;
assert(entryTmp->parent->ref >= 1);
list_delete_named(parent->childs, entryTmp, prevSiblings, nextSiblings);
// At next iteration we will decrement parent's ref cnt
}
// Avoid recursivity in kernel by using a list of entry to suppress
list_add_tail_named(toDelete, entryTmp, prevSiblings, nextSiblings);
// now, unref parent
entryTmp = entryTmp->parent;
}
// free 0 ref entries
while (!list_is_empty_named(toDelete, prevSiblings, nextSiblings)) {
entryTmp = list_pop_head_named(toDelete, prevSiblings, nextSiblings);
fsInodeUnref(entryTmp->node);
free(entryTmp);
}
return 0;
}
int fsEntryNewChild(struct fsEntry *parent, const struct pstr *name, struct inode *inode,
struct fsEntry **result)
{
struct fsEntry *entry = malloc(sizeof(struct fsEntry));
if (!entry)
return -ENOMEM;
if (name && name->len > 0) {
char *allocName = malloc(name->len);
if (!allocName) {
free(entry);
return -ENOMEM;
}
memcpy(allocName, name->name, name->len);
entry->name.len = name->len;
entry->name.name = allocName;
}
entry->ref = 1;
entry->node = inode;
entry->parent = parent;
fsInodeRef(inode);
if (parent) {
fsEntryRef(parent);
list_add_head_named(parent->childs, entry, prevSiblings, nextSiblings);
}
*result = entry;
return 0;
}
int fsEntrySetup(void){
return allocBookSlab(sizeof(struct fsEntry), PAGE_SIZE, 0, 0);
}

118
core/fsEntry.h Normal file
View File

@ -0,0 +1,118 @@
#pragma once
#include "fs.h"
#include "stdint.h"
#include "stddef.h"
/**
* Those structures aimes to represent VFS directory entries in memory.
* It's the equivalent of the Linux dentry or SimpleOs sos_fs_nscache_node.
*/
/**
* Path or Pascal String
* */
struct pstr {
size_t len;
const char *name;
};
#define PSTR_INIT(n, l) \
{ \
.len = l, .name = n \
}
/**
* @brief Structure representing a file system entry.
*
* This structure holds information about a file system entry,
* including its name, associated inode, relationships within
* the file system hierarchy, and reference count.
*/
struct fsEntry {
struct pstr name;
struct inode *node;
struct fsEntry *parent; // parent directory
struct fsEntry *mountpoint; // if this is a mounted fs, point to mountpoint
struct fsEntry *mountedFs; // Fs possibly mounted on this fsEntry
struct fsEntry *childs; // point to the list of children
struct fsEntry *nextSiblings, *prevSiblings; // Sibling at the same level
uint ref; // reference counter
};
/**
* @brief Splits a pstr path into upper and lower components.
*
* This function takes a path and splits it into an upper component
* (the first segment of the path) and a lower component (the rest of the path).
*
* @param path Pointer to the input pstr structure representing the path.
* @param upper Pointer to the pstr structure to store the upper component.
* @param lower Pointer to the pstr structure to store the lower component.
* @return bool_t Returns true if there is a lower component, false otherwise.
*/
bool_t pstringSplipPath(struct pstr *path, struct pstr *upper, struct pstr *lower);
/**
* @brief Compares two pstr structures to check if they are equal.
*
* This function compares the length and the content of the strings
* in the two provided pstr structures.
*
* @param a Pointer to the first pstr structure.
* @param b Pointer to the second pstr structure.
* @return int Returns 1 if the structures are equal, 0 otherwise.
*/
bool_t pstringIsEq(struct pstr *p1, struct pstr *p2);
/**
* @brief Increments the reference count of a file system entry.
*
* This function increments the reference count of the given file system
* entry. It is typically used to manage the lifecycle of file system
* entries, ensuring that they are not prematurely deallocated.
*
* @param entry Pointer to the fsEntry structure whose reference count will be incremented.
* @return int Returns 0 on success.
*/
int fsEntryRef(struct fsEntry *entry);
/**
* @brief Decrements the reference count of a file system entry.
*
* This function decrements the reference count of the given file system
* entry. It is typically used to manage the lifecycle of file system
* entries, ensuring that they are not prematurely deallocated.
*
* @param entry Pointer to the fsEntry structure whose reference count will be incremented.
* @return int Returns 0 on success.
*/
int fsEntryUnref(struct fsEntry **entry);
/**
* @brief Creates a new child fsEntry under the specified parent.
*
* This function allocates and initializes a new fsEntry structure
* representing a file system entry. The new entry is added as a child
* of the specified parent. It also handles reference counting for
* the parent entry and the associated inode.
*
* @param parent Pointer to the parent fsEntry. Can be NULL if the new entry has no parent.
* @param name Pointer to the pstr structure representing the name of the new entry. Can be NULL.
* @param inode Pointer to the inode associated with the new entry.
* @param result Pointer to a location where the pointer to the newly created fsEntry will be stored.
* @return int Returns 0 on success, or a negative error code on failure.
* -ENOMEM if memory allocation fails.
*/
int fsEntryNewChild(struct fsEntry *parent, const struct pstr *name, struct inode *inode,
struct fsEntry **result);
/**
* @brief Setup the fsEntry subsystem
*
*/
int fsEntrySetup(void);

View File

@ -3,6 +3,7 @@
#include "ata.h"
#include "elf.h"
#include "exception.h"
#include "fsEntry.h"
#include "gdt.h"
#include "idt.h"
#include "interrupt.h"
@ -259,6 +260,9 @@ void kmain(unsigned long magic, unsigned long addr)
irqSetRoutine(IRQ_TIMER, pit_handler);
ATAInit();
// VFS name caching
fsEntrySetup();
#ifdef RUN_TEST
run_test();
#endif

View File

@ -3,8 +3,11 @@
#include "ata.h"
#include "assert.h"
#include "cpu_context.h"
#include "fsEntry.h"
#include "kernel.h"
#include "klibc.h"
#include "stddef.h"
#include "stdint.h"
#include "thread.h"
#include "list.h"
#include "mem.h"
@ -493,8 +496,134 @@ void testRingBuffer()
ringbufferDestroy(inst);
}
void printPstr(struct pstr *str){
for(uint i = 0; i < str->len; i++){
putc(str->name[i]);
}
}
void printPstrln(struct pstr *str){
printPstr(str);
putc('\n');
}
void testFsPstring()
{
bool_t result;
struct pstr path, upper, lower, lower2, lower3;
// Test 1
path.name = "/usr/local/bin";
path.len = 14;
result = pstringSplipPath(&path, &upper, &lower);
printf("Test 1:\n");
printPstrln(&path);
printPstrln(&upper);
printPstrln(&lower);
printf("Result: %s\n\n", result ? "true" : "false");
// Test 2
path.name = "/home/user";
path.len = 10;
result = pstringSplipPath(&path, &upper, &lower);
printf("Test 2:\n");
printPstrln(&path);
printPstrln(&upper);
printPstrln(&lower);
printf("Result: %s\n\n", result ? "true" : "false");
// Test 3
path.name = "/tmp";
path.len = 4;
result = pstringSplipPath(&path, &upper, &lower);
printf("Test 3:\n");
printPstrln(&path);
printPstrln(&upper);
printPstrln(&lower);
printf("Result: %s\n\n", result ? "true" : "false");
// Test 4
path.name = "/var/log/";
path.len = 9;
result = pstringSplipPath(&path, &upper, &lower);
printf("Test 4:\n");
printPstrln(&path);
printPstrln(&upper);
printPstrln(&lower);
printf("Result: %s\n\n", result ? "true" : "false");
// Test 5
path.name = "/";
path.len = 1;
result = pstringSplipPath(&path, &upper, &lower);
printf("Test 5:\n");
printPstrln(&path);
printPstrln(&upper);
printPstrln(&lower);
printf("Result: %s\n\n", result ? "true" : "false");
// Test 6
const char *tmp = "///home///file/test///";
const char *testS = "test";
path.name = tmp;
path.len = strlen(tmp);
struct pstr test = PSTR_INIT(testS, strlen(testS));
struct pstr empty = PSTR_INIT("", 0);
struct pstr slash = PSTR_INIT("/", 1);
struct pstr dot = PSTR_INIT("..", 2);
printf("Test 6:\n");
printPstr(&path);
assert(pstringSplipPath(&path, &upper, &lower));
printf("\nUpper: ");
printPstr(&upper);
printf("\nLower: ");
printPstr(&lower);
printf("\n");
assert(pstringSplipPath(&lower, &upper, &lower2));
printf("\nUpper: ");
printPstr(&upper);
printf("\nLower: ");
printPstr(&lower2);
printf("\n");
assert(pstringSplipPath(&lower2, &upper, &lower3) == 0);
printf("\nUpper: ");
printPstr(&upper);
printf("\nLower: ");
printPstr(&lower3);
printf("\n");
assert(pstringIsEq(&upper, &test));
assert(pstringSplipPath(&empty, &upper, &lower) == FALSE);
assert(pstringSplipPath(&slash, &upper, &lower) == FALSE);
assert(pstringIsEq(&empty, &test) == FALSE);
assert(pstringIsEq(&dot, &test) == FALSE);
}
void testFsEntry()
{
printf("Test fsEntry: create tree\n");
struct inode node;
struct fsEntry *root, *home, *usr;
struct pstr rootname = PSTR_INIT("root", 4);
struct pstr homename = PSTR_INIT("home", 4);
struct pstr usrname = PSTR_INIT("usr", 3);
assert(fsEntryNewChild(NULL, &rootname, &node, &root) == 0);
assert(fsEntryNewChild(root, &homename, &node, &home) == 0);
assert(fsEntryNewChild(root, &usrname, &node, &usr) == 0);
printf("Test fsEntry: free tree\n");
fsEntryUnref(&usr);
assert(root->ref > 0);
assert(usr == NULL);
fsEntryUnref(&home);
assert(usr == NULL);
}
void run_test(void)
{
testFsPstring();
testFsEntry();
// Example of checking thx to access attributs
//int a[4] = {0};
//int b[3] = {0};