#The Flopperating System (tfos) - x86 32 bit Hobby OS
1 messages · Page 5 of 1
Imma just name it file_data_space_t
Hey is this good for a page cache
struct page_cache {
struct Page *free_list;
spinlock_t lock;
} page_cache;
void page_cache_init(void) {
page_cache.free_list = NULL;
static spinlock_t initializer = SPINLOCK_INIT;
page_cache.lock = initializer;
spinlock_init(&page_cache.lock);
}
void *page_cache_alloc(void) {
spinlock(&page_cache.lock);
if (page_cache.free_list) {
struct Page *p = page_cache.free_list;
page_cache.free_list = p->next;
p->is_free = 0;
spinlock_unlock(&page_cache.lock, true);
return (void*)p->address;
}
spinlock_unlock(&page_cache.lock, true);
void *page = pmm_alloc_page();
return page;
}
void page_cache_free(void *addr) {
if (!addr) return;
struct Page *p = phys_to_page_index((uintptr_t)addr);
if (!p) return;
p->is_free = 1;
spinlock(&page_cache.lock);
p->next = page_cache.free_list;
page_cache.free_list = p;
spinlock_unlock(&page_cache.lock, true);
}
I make a lock for each page cache
no
I would suggest following the advice you gave and reading up and studying these things before drafting broken prototypes lol
Okay I’ll look into it
education schmeducation
Wait isn’t a page cache useless if I don’t have secondary storage
educational is relative, what are you wanting to teach? parts of my os are educational, but not the kernel
I wanna teach mainly the process
And the issues you encounter
Like I am right now lol
Making my file system not dogshit
it's more the case of "use the os to learn how to mess around with modern hardware at the bare metal level with no restrictions" not "learn how to write a kernel"... I'm not Tannenbaum
my os exposes a userland at ring 0 in a language that's very easy to learn, that's unique and useful in an educational setting as you can instruct how things like drivers work without having to also know C
that's how mine is "educational", so yeah education doesn't always posit perfect kernel code
Yeah nah my kernel is dogshit
you just gotta specify what you expect someone to learn and from what
I guess I want people to learn of the process
And how a normal person might go about this
mine sure isn't perfect it's got 16 years of legacy cruft in parts
Mine is about a year of pain
But yeah I guess I can’t be educational truly
I think I’m just going for
are we really "normal people"? normal people don't write OSes 
Yeah I suppose you’re right
And I wasted my time writing a really bad one
😔
Well I don’t have physical storage @small hound
So a page cache is useless
I don’t use mine at all besides for fucking around on my old pentium laptop
But I haven’t booted it on there in months
just have a user in mind and write for that user, that user being you is just as legit as any else
does it still boot there?
I find if I go more than a few days now without retesting I might break something, but I'm now past dicking with early boot
The only thing that prevented booting a few times was the memory map being dogshit
"useless" as in "there will be no noticeable FS performance gain"? sure
"useless" as in "the os will function the same"? not so much
processes often need to mmap files to access them directly, and the page cache is what they'd use
So the page cache would just live in volatile memory then?
it's not just for reducing IO operations
mmap for files is very much a unix thing isnt it? what's the windows equivalent?
volatile memory? as opposed to what other memory?
I remember it having one
I just mean ram
But yeah
sure yea
CreateFileMapping
Should that be its own address space too
MapViewOfFileEx
NT syscall naming is something else
that's the one
you can read up about this, like you said, to find out how real kernels do this and understand all the intricacies and nuances to this
I prefer the NT syscall naming, the people who wrote unix and POSIX are scared of variables and functions over 6 chars long.
ENOMEM, EFILE, EIO... like wtf. why did nobody have proper descriptive const names
They’re all shit
wasn't it because the C spec didn't allow for longer names or what
For naming at least
Yes exactly
I suppose that was the original reason and the scheme just stuck
That’s why globl is the way it is in some assemblers
and libc is just as bad... stricmp vs strcasecmp etc, make up your minds
@small hound demand paging is for the user space right
only the first 8 chars of a name were relavent like in the 1970s, and nobody thought to modernise it, could have kept the old names but deprecated them in preference of new ones
you probably don't want to demand page an interrupt stack
btw am I the only one when I see union in C code my mind sees onion 🧅
how did you get the discord username "brain"
wowzers
Yeah wtf
lol, I have been known as brain since I was 16, it has a story behind it
goes back to college days
a friend of a friend thought I would take over the world
so he started calling me brain and calling my friend pinky
I owned the name, narf. my friend hated being called pinky and that didn't stick for him
narf brain and pinky name a more iconic trio
yeah I'm 43, so I've been known as brain longer than not
wait discord has a bug for me every gif is flickering rapidly like fit inducing flicker
Longer than Ive been alive probably
Okay I read a bit more
I could create a page cache by pretending part of my memory is a block device
uhhhhhhhhhhhhhhhhh
New pages are added to the page cache
The page cache is the main disk cache used by the Linux kernel. In most cases, the kernel refers to the page cache when reading from or writing to disk. New pages are added to the page cache to satisfy User Mode processes’s read requests. If the page is not already in the cache, a new entry is added to the cache and filled with the data read from the disk. If there is enough free memory, the page is kept in the cache for an indefinite period of time and can then be reused by other processes without accessing the disk.
it doesnt say anything about the "memory being a block device"
Yeah I know but technically you would need a “disk”
But I don’t have that
So it will have to just store the page cache in ram
I was confused, I thought it was stored on the disk
But in reality
That’s not the case lol
there is the block cache, where fast disks are used to cache data from slow disks, but that's another thing
I'm considering adding a similar write through cache to my os, it's in my roadmap
no async writeback 💔
right now most reads hit the disk only thing that doesn't is tree walk to dirs we've seen before
the tree is cached to ram and written through and the file metadata within those dirs
my roadmap:
#1083829658849652838 message
it's mostly straightforward stuff now
Nice nice
This is mine
a lot of things on that list are boring to me to implement, like I'd find an existing radix tree
horses for courses, I guess you do whatever bits interest you
I used someone else's hash map rather than reinvent that wheel
also I have two levels of allocator, the lowest level allocator is primitive O(n) allocate and free, but you aren't supposed to use that for everything, you use that to allocate long lived blocks and then initialise a separate buddy allocator within the block, when you're done with all allocations in that block you can just tear down the underlying one. kinda like how a process gets its own page table in a traditional os, but in my case not paging, as it's a purely interpreted environment
I have an implementation I just have to integrate it into a file system
I have two levels of allocator too
Below page size -> slab
Above page size -> buddy
Actually technically not
My physical allocator uses a buddy
My kernel heap uses a free list for allocations above page size
the inherent problem with "educational OSes" is you either have to say this or just dont make an educational thing at all
all educational OSes are toys
which is the point
shoutout to linux by linus torvalds, gotta be one of my favorite educational kernels fr
Linux kernel is a mess
it's a combination of a thousand independent silos of code with different levels of stability and code hygiene
each written by different teams or people
this is a result of scale, which we don't see at our OSes sizes
kinda like if windows kernel came with a thousand third party drivers
it's stable but probably the worst thing to try and learn from
linux was never meant to be educational
yes it was the opposite
it was rebellion against minix never wanting to grow beyond educational
I think that's what gummi meant
forgot the /s tag
bsd code is so much better at this
but probably because they have a small team of core contributors
I agree it is so consistently clean
meanwhile linux ranges between "wtf" to "pretty good"
linux is extensively documented at least
which is nice
for example RCU documentation is very nice
I guess it depends on the subsystem's author
@small hound can you explain how to do a tlb shootdown for all CPUs
I don’t need code but I remember we talked about it
I thought you already implemented it?
there are many ways to go about this but the simplest and most naive way is to keep a tlb shootdown page in your per core structure and send an IPI to all the other cores and set their per core shootdown page to whatever page you're doing the shootdown on
the smarter way is to batch this and shootdown a list of pages rather than one page at a time
Should I just create a global list for that
And create some thread to do it for me
Like a thread to do the shoot downs for me
why would you want to spawn a whole thread for this and use a global list
if you have DPCs it would be more optimal to use those instead of having a dedicated thread
a global list is pretty unnecessary because you'll often have scenarios where you know some core can't have a given page mapped
so you just skip that core
you'd do core local lists
Okay so create a list of pages for each core
I perform a tlb shootdown every time I map/unmap or otherwise access page tables right?
And I’m sure my vmm_protect will need that too
you don't need to shootdown if you're mapping a brand new page that you can guarantee will not have a mapping anywhere else (you are not overwriting an existing mapping)
for example if you have your vaddress space allocator and it creates a new page that has never been mapped, the shootdown isn't necessary
or if you're in your early kernel boot, and youre mapping the kernel, no one will have the mappings so there is no need to do the shootdown
similarly, if you can guarantee that some page will not be mapped on any other core, such as with a userspace process that has only ran on one core, when you unmap the pages for it, there is no need to do the tlb shootdown
So in map_page I should check if the page being mapped was previously mapped at some point?
yea when you walk the page tables you can check if the page had an existing mapping
Yeah thankfully that’s not super hard to do
In the pt_level function I’ll do that
And set some condition to be true
And only tlb shootdown
If that condition was set
So psuedo code would be
If (page_was_mapped)
tlb_shootdown();
Return;
Else return;
and then you can also check if the page is even mapped on the other cores if you're changing userspace pages and whatnot
since if you have some single threaded process that has only ran on one core you can guarantee that its pages will not have mappings on the other cores
💥
have a blast 😃
I will 😭😭
do take great care when doing this
you may have realized that there is a major potential source of fs corruption
383738 thousand sources
ok name some
If any of the pages used by a file system get accessed by the user
Without an actual syscall
are you marking your kernel pages as user accessible
that's crazy
Definitely not
no that's not an issue
you'd only mark em as user accessible upon the syscall
so if they are accessed before that you just get a page fault
so there's no issue
user process just gets terminated
ok so the source of corruption I am referring to is the block device page cache
you know how you have stuff like /dev/sda
well, what if userspace modifies some arbitrary page in there and that page happens to be filesystem metadata information
then, the rest of the in memory representation of the filesystem would become corrupt
so how do you resolve this predicament
there are many different ways to solve this, or you can just pretend like this won't happen and accept the corruption lmao
Let’s say you modify a page in /dev/sda, can’t you mark the corresponding cached page as dirty so the os knows its corrupted?
And access control
That’s what my guess what be
but what does that even mean? the page would get written back regardless and then the in memory representation doesn't match the on disk representation
so that doesn't really do anything
what does that mean though? there are both data and metadata pages in the block device page cache and it's safe to modify and write back data pages because those don't change the filesystem structure
this doesn't have anything to do with the problem here though
Only allowing root to access /dev/
Wouldn’t that prevent the issue
So the user can’t change the state of the disk to be different from the metadata state
that also doesn't solve the problem? if root accesses it, modifies some metadata page, that gets written back, your filesystem structure still is now corrupt
reread the predicament here
Wait. Can’t you make it so block devices and file system page caches go through the same page cache?
no, because there is no guarantee that file data is page aligned on a block device
remember how sector sizes are typically 512
and also that doesn't solve the issue of metadata corruption lol
Okay I think then the solution is to prevent the user from accessing mounted block devices
ok so that's like using a hammer instead of a scalpel
it just kinda avoids the problem but prevents any modification of the block device page cache which is suboptimal
but sure you can just do that and come back later to actually try and resolve this predicament
😃
But any sane kernel would surely prevent user writes to the block page cache
try it on linux 😃
bsd 😃
spoiler: ||they don't prevent it||
Can I just sanitize syscalls?
I’m still thinking about this issue lol
wdym
just don't worry about it for now
try focusing on actually getting started on the page cache first
just be aware of that problem
i can tell u about a few potential ways of resolving this later
how would this protect against the problem?
syscalls do get sanitized anyways so you don't pass in a buffer at 0x0 or something lol
Prevent situations that could corrupt it in the first place
uhhh no that wouldn't do anything here
you're on kind of the right track
it doesn't really happen at the syscall level but you're kinda on the right track
Sanitize calls to tmpfs_write read etc?
ok just don't worry about this too much for now just go learn about page caches and start working on it, this is just something to keep in mind
Okay
and to answer your question about how linux and the BSD's handle this, they don't, the filesystem just becomes corrupt lol (in memory fs doesn't match what's on disk)
I know it's like this on linux and I believe it's like that on the BSDs
you can double check for the BSDs
that's why stuff like fsck will yell at you if you try to run it on a mounted filesystem
it still lets it happen though
and this was from a very painful discovery after not heeding fsck's warning
ext 2 doesn't have journaling
Also that's not an issue
Also you mean like block cache/buffer cache right?
If the user writes garbage to their disk let them do it
I think I’m more confused now
a block device's "file" would have a page cache though
uhm I guess so? the concern is that this would corrupt data and the in memory representation of the filesystem wouldn't match the on disk version
Ah yea ok I get it
Kinda weird
There's typically a block cache too tho
How?
I think block cache means something else, buffer cache is usually what it's called
I'd store FS metadata in a separate cache (block/buffer)
yea but block cache is a better name so idc
You just write back the changes to disk?
yea but if you write to the block device page cache you need some way to identify if you're writing to metadata or data blocks to determine if you should actually write it to disk or not
for example if you use the block device page cache and modify the dirents of an inode, then the corresponding dirent cache would become invalid and thus corrupt since it doesn't match what's on disk
mildly problematic
Is /dev/sda even cached
yes you can mmap it and it has a page cache lol
give it a shot
I don't think it's such an issue as you make it to be
You can just let the user corrupt it if they want to
I’m so so so confused but I got it
It's a bigger issue than he described
It's not just about users modifying it, it's also an issue with the system modifying it
If you reuse your page cache for your fs metadata caching, and you have a page of metadata that contains a few sectors in common with a page of data, and they get out of sync, you'll have a bad time
Ohhh I see
Maybe I don’t and I’m dumb but I hope i do
Okay I’m kinda almost done with my page cache implementation
@small hound do you have any decent page cache implementation I can look at
https://github.com/torvalds/linux/blob/master/mm/filemap.c linux is alright
I haven't looked at freebsd's
linux and their whimsical naming strikes again
bread 🍞
Okay thank you
Bread 🍞
we promise you rights and liberties, bread 🍞 and peace
amen
I’m having major skill issues rn
Okay I might need to make the rest of the operating system thread safe
@viscid zephyr sorry to ping but i just need help. is it okay to preempt with a timer like the apic?
maybe can you help me too
ultimately that's how it has to work, some timer has to exist that interrupts you so you can switch threads at the end of a time slice
but beware a context switch being tied inherently to an interrupt
no im not doing that, just checking for expired threads and ticking global ticks
the proper way to implement context switching is as glorified setjmp()/longjmp() sort of thing
say thread B is running in userspace. a timer interrupt arrives and you determine that its timeslice is over so you have to switch. here is how the stack might look at the point of switching
someUserlandFunction() -> [interrupt frame] -> handleTimerInterrupt() -> switchThread()
your switchThread() ought to save the state of the preempted thread, such that when control is returned to it by another switchThread(), control returns to:
someUserlandFunction() -> [interrupt frame] -> handleTimerInterrupt()
as in, to the line immediately after the one that called switchThread()
suppose handleTimerInterrupt() is like:
{
/* ... */
if (timesliceExpired)
switchThread();
/* control resumes here */
return;
}
at the point it reaches the end of handleTimerInterrupt(), your interrupt handling routine in asm will restore all the registers and return to userland. that's how you get back into userland after switching back to that thread
That sucks
it follows as well that you can just as well call switchThread() from any context, interrupt or not
what should i do instead
okay thank you for the help
i might have 80 questions soon
how did you write a page cache so quickly btw
im still working on it but yeah im basically done
i made an lru list
how
and stuff
no I mean "how" as in "this sounds like you didn't actually implement a page cache because these things are far more nuanced and complex than anything that you could just 'sit down, get the jist of, and write in one day'"
did you copy an existing impl or something
no. i just read some papers
and made my thing
i dont think its 100% correct yet
im still working on it
im working on Cow
what does that even mean
are you implementing a filesystem with cow
yeah is that bad
what filesystem
That is what I meant yes
what do you mean "you don't know"
on disk?
Yes
I know it’s used in zfs and btrfs
So I’m studying those
And I know sql uses it
you will probably have a better time just porting an existing driver for a filesystem that supports this
also snapshots are very nontrivial and quite complex to implement and if you have only written an incorrect ext2 driver up to this point then I advise not doing this and first writing a functional driver for an on disk filesystem
just a hunch
Yeah I suppose
@small hound I’m just gonna make a proper vfs
And then the tmpfs
Then fat
I’m making a vfs call table now
vfs_call_table_t 🗣️🗣️
what's with all the _t naming for structs
Just makes sense for me
Not all my structs are named that way tho
Like my page info struct is just struct Page
so why not keep everything named this way and reserve _t for type definitions lol
idk your choice
I do reserve _t for type definitions
so why are you also using it for struct definitions
wouldn't this be a struct though
Actually yeah I guess you’re right I’ll just call it vfs_call_table
So I’ll make a vfs_handle struct
Then a vfs mount point struct
I’ll actually try to document this process better
Bc I have been studying on vfs’s a lot
Okay so I’ve made the structs maybe
:o
I made a handle, file system, call table
congrats
why are create/delete on mountpoints
also copy and clone as vfs level operations is kinda silly
Oh yeah you’re right, I was gonna create a entries in the table to destroy and create a file system
huh ?
Is there no circumstance where copy and clone would be used within the vfs
you can make copy/clone with a create() read() and write()
what does this mean
userland utilities that perform such functionality do not rely on underlying system calls to do stuff like copy()
they just use other functions and create copy from it
like this
you wouldn't rely on doing this with a dedicated vfs function and I don't think you will be doing that anyways
you can just construct a clone/copy out of the other ones, it doesn't need to be a function that the underlying filesystem provides
Ah okay I see
so sure you can have a vfs_copy() that just relies on the other ones
But it shouldn’t be in the call table?
no because the underlying filesystem would provide the functions in that table I'm assuming
and the underlying filesystem doesn't need to provide those
Okay
Im almost done creating the structs
i finished the first version of the vfs
i finished
unrelated but i finsihed my vfs
I am starting to have a wee bit of doubt that you actually "finish" these things when you post messages that you do
congrats if you actually did it tho lol
wanna see?
sure
im not gonna commit it just yet
but ill put in paste bin
im not done yet
becausei have to make the init function but
@small hound i https://pastebin.com/SB0zh1xN
Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.
i think its decently solid
what do you think
i finsihed my vfs
im just missing one function
whatever happened to locking
i finished the op table
yeah i just wrote the op table
did the rest of it look okay?
no, you are leaking memory
where
oh i forgot some free statement i know that
typically we call these handles "nodes", and that's the typical way to do it yeah
it also just... isn't thread safe
well yeah i know that much
i will fix that
so each time i reference a node anywhere
i should just increment the ref count?
should it just be like this ?
no it needs to be atomic
with more steps to it
static inline bool refcount_inc_not_zero(refcount_t *rc) {
for (;;) {
unsigned int old = atomic_load(rc);
if (old == 0)
return false;
unsigned int expected = old;
if (atomic_compare_exchange_weak(rc, &expected, old + 1))
return true;
old = expected;
}
}
static inline bool refcount_dec_and_test(refcount_t *rc) {
for (;;) {
unsigned int old = atomic_load(rc);
if (old == 0) {
k_panic("%s(): Possible UAF!\n", __func__);
return false;
}
unsigned int expected = old;
if (atomic_compare_exchange_weak(rc, &expected, old - 1))
return (old - 1) == 0;
old = expected;
}
}```
when would you decrement a ref count
close()
- you can have an explicit destroy function so if some process has a bunch of handles open it goes and yeets all of them at the end of the process's life
this way userspace can't leak memory by not close()ing stuff
ah okay i see... so for each fs i should have a lock right
so my vfs struct should have a lock
a lock for the whole filesystem?
wdym where would you use it
no like lets say i have a tmpfs
and i acknowledge it
should each filesystem have a lock within the vfs
or should it just be a vfs lock
wdym by this
the presence of a lock doesn't mean anything unless the use of the lock is stated
what kinds of vfs operations do you mean
open for example
if you're doing global modification to the vfs then sure, like modifying the mount table
yeah
you do not want to acquire this global lock for opening files because that is really pointless
unless you are somehow doing some large modifications of the global vfs structures on open()
i see
but i should be locking for shared states
like the mount table
so for example
static void vfs_add_mountpoint(struct vfs_mountpoint* mp) {
if (mp_list.tail == NULL) {
mp_list.tail = mp;
} else {
mp_list.tail->next_mountpoint = mp;
}
mp_list.tail = mp;
}
static void vfs_remove_mountpoint(struct vfs_mountpoint* mp) {
struct vfs_mountpoint *m;
if (mp == mp_list.tail) {
mp_list.tail = mp->next_mountpoint;
} else {
for (m = mp_list.tail; m != NULL; m = m->next_mountpoint) {
if (m->next_mountpoint == mp) {
m->next_mountpoint = mp->next_mountpoint;
break;
}
}
}
}
i should probably lock
while modifying the mountpoint table
yes and you should probably not use a singly linked list here and should use a hashtable instead
okay, so both my fs list and mountpoint list should be hashtables?
not singly linked list
why is there a separate fs list
why wouldnt there be
for example
struct vfs_fs *vfs_find_fs(int type) {
struct vfs_fs *fs_to_find;
for (fs_to_find = fs_list.head; fs_to_find != NULL; fs_to_find = fs_to_find->previous) {
if (fs_to_find->filesystem_type == type) {
break;
}
}
return fs_to_find;
}
to find an fs of a certain type
what... why do you need this?
you can also just use your mount table to do this
no need for a separate list
i see
💥
so within this funnction
int vfs_acknowledge_fs(struct vfs_fs *fs) {
if (!fs) {
log("vfs_acknowledge_fs: fs is NULL\n", RED);
return -1;
}
fs->previous = fs_list.head;
fs_list.head = fs;
log_uint("vfs: acknowledged filesystem type ", fs->filesystem_type);
return 0;
}
int vfs_unacknowledge_fs(struct vfs_fs *fs) {
return 0;
}
i should just add the filesystem to the mounpoint table?
instead of a seperate fs list
why does this exist
i thought it would be a good idea t have a global list of file systems known to the vfs
why did you think that
didn't you read papers on this, which ones said to do this
I'm curious now
unmounted filesystems shouldn't be tracked in the VFS (once all references are dropped)
you talked about a while ago having a struct globally with some info and i kinda started doing that everywhere
so i just thought it might come in handy
but youre right
its prob not very useful
nah I just do that since I like the encapsulation it provides and how it can avoid symbol conflicts better by having one struct with members in it rather than a bunch of independent member variables
lol
ah okay
is this looking better for the thread safety
@small hound
static struct vfs_mountpoint* vfs_create_mountpoint(char* device, char* mount_point, int type) {
struct vfs_mountpoint* mp = vfs_mp_struc_alloc();
if (!mp)
return NULL;
spinlock(&mp_list.lock);
if (vfs_assign_mp_fs(mp, type) != 0) {
kfree(mp, sizeof(struct vfs_mountpoint));
spinlock_unlock(&mp_list.lock, true);
return NULL;
}
if (vfs_mp_path_alloc(mp, mount_point) != 0) {
kfree(mp, sizeof(struct vfs_mountpoint));
spinlock_unlock(&mp_list.lock, true);
return NULL;
}
if (vfs_mp_dev_alloc(mp, device) != 0) {
kfree(mp->mount_point, flopstrlen(mp->mount_point) + 1);
kfree(mp, sizeof(struct vfs_mountpoint));
spinlock_unlock(&mp_list.lock, true);
return NULL;
}
spinlock_unlock(&mp_list.lock, true);
return mp;
}
static void vfs_add_mountpoint(struct vfs_mountpoint* mp) {
spinlock(&mp_list.lock);
if (mp_list.tail == NULL) {
mp_list.tail = mp;
} else {
mp_list.tail->next_mountpoint = mp;
}
mp_list.tail = mp;
spinlock_unlock(&mp_list.lock, true);
}
seems a bit odd to just assume that interrupts/preemption would be enabled at the time of the lock and just arbitrarily pass in a true
what does it do
restores interrupts if you disabled them
and by default spinlock() does
sorry yeah
kinda stupid naming
but you don't know if interrupts were enabled before you disabled them
it's whatever as long as you can guarantee that this is only called when interrupts are enabled before acquiring the lock
yeah it checks
otherwise things might be a bit whimsical
seems a bit weird to lock the list before you do anything with it
why does create_mountpoint touch the list lock at all here
those functions literally don't touch the list though
so would do you lock the list in them
oh yeah... i dont access the mplist within any of that
so theres no need
but here i would need to
static void vfs_remove_mountpoint(struct vfs_mountpoint* mp) {
struct vfs_mountpoint *m;
spinlock(&mp_list.lock);
if (mp == mp_list.tail) {
mp_list.tail = mp->next_mountpoint;
} else {
for (m = mp_list.tail; m != NULL; m = m->next_mountpoint) {
if (m->next_mountpoint == mp) {
m->next_mountpoint = mp->next_mountpoint;
break;
}
}
}
if (mp_list.tail == NULL) {
mp_list.head = NULL;
}
spinlock_unlock(&mp_list.lock, true);
}
and within create_mp and remove_mp i should increment the ref count on create and decrement on remove?
indeed
uhhhhhh wdym
refcount on what
yes you'll probably want to refcount it so that any files open on that mountpoint don't have a UAF once it's unmounted
is it fine to do a singly linked list for now, for the mountpoints
uhhhh I just suggested a hashtable but if you really wanna do that then sure lol
no i know, but i just wanna get this working first then do the hashtable
you'd ideally want to use a tree since paths are inherently structured in a way that makes them good with trees
hashtable just simpler
sure a list works
you can use a list
i hope im doing better this time than some other stuff lol
ya it's going pretty good
like i really tried to do hella research and
im also doing one other thing you suggested
yes 👍👍👍👍👍 you're doing great 😃😄😃😃
sory if I come off wrong or mean or anything lol, I'm tryna help so that this project goes smoothly further down the line

no you didnt come off as mean lol
you just questioned stuff you saw which is fair and what i need
oh ok 👍
i ping you alot because you spot stuff i dont
👍 no problem 😁
real but you just wanna make a general purpose refcount here
typedef atomic_uint refcount_t
instead of a custom vfs refcount struct
ahhh i see
should i just make a fule in lib/
called refcount.h
so i can use it everywhere
sure yea
you can just nab the implementations I sent
you technically don't need the CAS loop, I just did it because you can catch a UAF with it better
I'm sure you already know how refcounts work but here's the refresher
- you initialize a refcount, usually with a reference of one to represent the initial reference
- as objects are passed around, refcounts fluctuate (inc/dec), and stuff happens
- once an object's refcount hits zero, you free it
and in the CAS loop I just check if the refcount hits zero before we get to decrement it because that would indicate some double decrement on a refcount
okay sounds good
so i would init like this
indeed
you can also just have a standard refcount_inc that just becomes the atomic fetch add
if you want to you can guard against overflow but a refcount of 4 billion probably won't be reached
-famous last words
static inline bool refcount_inc(refcount_t *rc) {
for (;;) {
unsigned int old = atomic_load(rc);
if (old == UINT_MAX)
return false;
unsigned int expected = old;
if (atomic_compare_exchange_weak(rc, &expected, old + 1))
return true;
}
}``` you can panic on refcount overflow here probably
the reason behind inc_notzero and dec_andtest is because those guard against the uaf of a refcount already being zero and not becoming zero from the caller/the caller not getting the chance to increment it
meaning someone else set it to zero and we didn't get the chance to decrement/increment our refcount so it would uaf
porbably better to prevent against that case then
okay so heres this
i think thats all i need in the init function
oh shit
i set null twice
uhhh intializing a local refcount seems sus
doesn't seem to be doing anything lol
and also you wouldn't refcount "the list as a whole"
yeah youre right lol
so for each new object i would need a refcount_t
for each object that needs it, yea
okay im almost done with that part
sounds great
okay i think im good with the ref counting stuff
ill push the code to github
sounds great 👍
its very rough but it works
lmk what you think
ok I'll probably check later, it late rn
okay have a good night
Okay time to implement FAT
very important
or else you end up with a lot of things to clean
and it take month
linux disagrees 
their codebase is all over the place
💥
I mean considering how huge the codebase is, it’s not the worst
linux probably had more programmers over its lifespan than windows ever did
its a shitfest
50,000 morbillion "fix typo" commits
some parts like locking and rcu are excellent but for other things like drivers? good luck lol
🤪
The drivers are fucked yeah but the actual kernel core itself is very well documented
Okay imma start making the fat implementation
okay i stepped back and im doing tmpfs first
okay
herre we go
We registered the tmpfs with the vfs
And I decided to only expose the tmpfs through the vfs op table
i added ref counting
and i made mount and unmount thread safe
still got more but
and yes i know the way i initialize my spinlocks is weird as fuck
oh no theoretical conversions of file systems into a standardized format for easier access
yes the vfs op table is hella hella HELLA useful
i figured
Nice
Wanna see
Also star my thread 😔😔
yeah sure
im gonna die if i dont have paging my total sucking is beyond major
i do not understand anything currently (i skimmed through it) but cool
It’s mainly just synchronization and node shit
fair
You will probably learn more reading the vfs
Damnnnn commit schedule kinda fire recently
formatting commits can make grepping through them easier
just suggestion 👍
Yeah I prob should have a prefix for my commits
I use conventional commits
What does that mean
A specification for adding human and machine readable meaning to commit messages
Ahhh that makes sense
I should probably do those
@thorn dust would you be able to read through my vfs and tmpfs and lmk what needs fixing and what could be done better
Here they are
(node->vfs_mode & VFS_MODE_APPEND) == VFS_MODE_APPEND seems weird
no need for the comparison operator
also the locks aren't right
How are they not
you only lock for metadata modification not for file data operations unless explicity specified
and that data locking occurs at the page cache level
For now file data is just an array of page pointers
Wait which one are you looking at
Vfs?
yea but you're again not supposed to lock the node when you read/write from and to its data
tmpflopfs.c
Okay
also you'd probably wanna switch to a mutex instead of a spinlock here
I haven’t implemented those yet but I will
But yeah i know a spinlock is not ideal
Spinning on a file operation is cancer
When are you supposed to lock the node then
💥
metadata modification
size, gid, uid, mode, etc.
And that’s it
and any other metadata modification
bro is trolling
Yes I know the relative include paths are cancer but I prefer them
me when my code completely stops compiling after I move source files around
also uhhhh
static int tmpfs_unmount(struct vfs_mountpoint* mp, char* device) {
(void)device;
tmpfs_super_t* sb = (tmpfs_super_t*)mp->data_pointer;
if (!sb) return -1;
bool interrupt_state = spinlock(&sb->lock);
if (refcount_dec_and_test(&sb->refcount)) {
tmpfs_free_tree(sb->root);
kfree(sb, sizeof(*sb));
mp->data_pointer = NULL;
}
spinlock_unlock(&sb->lock, interrupt_state);
return 0;
}```
me when i leak memory 🤪
if dec_and_test is false and it isn't freed you just leak memory because other dec_and_tests dont free the filesystem
ideally here you just drop the last reference and that automatically frees it
you'd want get() and put() helpers to do this
static inline bool thread_get(struct thread *t) {
return refcount_inc_not_zero(&t->refcount);
}
static inline void thread_put(struct thread *t) {
if (refcount_dec_and_test(&t->refcount)) {
if (atomic_load(&t->state) != THREAD_STATE_TERMINATED) {
k_panic("final ref dropped while thread not terminated\n");
}
thread_free(t);
}
}``` example
Ahhh okay I see
There’s also undefined behavior in there because I free sb then unlock it
you can take it one step further here since you have locks and make acquire and release that get and put respectively, as well as acquire/release the lock
static inline bool thread_acquire(struct thread *t) {
if (!refcount_inc_not_zero(&t->refcount))
k_panic("UAF");
return spin_lock(&t->lock);
}
static inline void thread_release(struct thread *t, bool iflag) {
spin_unlock(&t->lock, iflag);
thread_put(t);
}``` example
why get and put
So i should make a tmpfs_lock_acquire or something
I much prefer retain/release
sure yea
I would prob prefer retain and release
I know it doesn’t have everything yeah
why do your operations take in paths?
struct vfs_op_tbl {
struct vfs_node* (*open) (struct vfs_node*, char*); // node, path
int (*close)(struct vfs_node*); // node
rw read; // node, buffer, size
rw write; // node, buffer, size
void* (*mount) (char*, char*, int);
int (*unmount)(struct vfs_mountpoint*, char*); // mp, device name
int (*create) (struct vfs_mountpoint*, char*); // mp, file name
int (*delete) (struct vfs_mountpoint*, char*); // mp, file name
int (*rename) (struct vfs_mountpoint*, char*, char*); // mp, old name, new name
int (*ctrl) (struct vfs_node*, unsigned long, unsigned long); // node, command, arg
int (*seek) (struct vfs_node*, unsigned long, unsigned char); // node, offset, whence
struct vfs_directory_list* (*listdir)(struct vfs_mountpoint*, char*); // mp, path
};```
why is the filesystem responsible for parsing a path?
create/delete/etc should take in a node not a mountpoint here
you should have a lookup function that works on path segments
yus
Okay I see
to be silly with a colon three
I was planning on adding security features within tmp alloc and free but
Never ended up doing that
:3
like what
https://github.com/amar454/floppaos/blob/main/fs/tmpflopfs/tmpflopfs.c#L98 you should have a common DIV_CEIL macro
https://github.com/amar454/floppaos/blob/main/fs/tmpflopfs/tmpflopfs.c#L131 strcmp is not safe
Should I do strncmp instead
yes
Okay note taken
And I should only have “/“ as a path separator then huh
Didn’t get that far 💀💀💀💀
the satire runs deep with this one
Wtf is that lol
I didn’t even see that shit
"What's a signed integer"
Dude he opened an issue but didn’t even star the repo
“What’s an integer” 💀
these interviews are so funny because it's like both sides are competing to see who can be more wrong
the interviewer said call stacks are an OS level concept
crazy
Call stacks are a what level concept
yes you heard that right and he also said they're vastly different from the stack data structure
I do feel like most programmers should be able to answer that question though
I don’t think he knows the concept of a stack at all
We need the plate analogy
The one Wikipedia uses lol
mfw he asks "What are the two parts of a floating point number" and there are three
Can you send the link
coding jesus is his channel
yea no hes just regurgitating textbooks or some shit without understanding them
What a stuck up ass name
yes
Holy shit
What the fuck
I don’t even have to watch the video he just put all the bullshit for me
the answer to most of those is "it depends"
Deadass bro
how big is an array is crazy
What is cache? Idk what the fuck type of cache do you mean
geocache
is the system ILP64 or LP64?
at least 4 bits
How big they are
mfw c spec says integers are at least 2 bytes wide
and then they are 4 bytes literally everywhere and everyone forgets that they are only defined as being at least 2 bytes wide
why are these questions relevant
They aren’t
Shit yeah, C is weird for that
C is archaic as fuck though so
That makes sense
*portability 
C when it can’t be ported to a broken water damaged gameboy 😔
top ten ways to fix imposter syndrome:
number 1. listen to coding jesus speak for more than two seconds
I know bro
Deadass
Listening to this makes me feel smart
I’m running on the treadmill rn listening to it on my tv
Max dopamine
I'm about to go running stay fit queens
Yessir have fun
why would someone even call themselves that
he says it's because he "used to look like jesus"
meanwhile the guy just spreads misinformation online lol
it's kind of impressive to consistently be so confidently incorrect
Egotism
And to have a whole ass comment section that agrees with the schizophrenia
he's always "so close yet so incredibly far" with his "correct answers"
like asking what 64 bit means and saying that it's the register bitwidth without specifying that it's the general purpose register bitwidth
x86 (with avx512) is my favorite 512 bit architecture 🗣️
Wait till bro finds out not all registers are 64 bit
I doubt he would even know the acronym gpr
He wants to have savant syndrome
So bad
lol I just watched for another few seconds and he says that on a multicore system cache coherence is the ONLY thing that allows for all the cores to have the ""same view of memory""
the humble tlb shootdown:
I doubt he knows what smp even is
Even if you said it in plain English
Symmetric multiprocessing
He wouldn’t know
i bet he hasnt even implemented MESI coherency simulation
nerd in a bad way
Dude there was a fucking shooting where I picked up my friend in Spokane
uh what
damn
u good?
what are shorts then
how big is an array
- coding antichrist
Yeah we went in the car and let him take care of his business and then dipped
https://youtu.be/U_6IHLE-xkw is ts u vro
FOLLOW MY INSTA AND TWITTER!!!!
https://instagram.com/oside_penguinzz?igshid=16b01nagr8xjk
My twitter
https://twitter.com/Oside_Penguinz
Yes this is me and my operating system
Whenever I get bitmap images loaded at some point I’m gonna make this video an animated loading for the boot
I’m fine now but it’s actually kinda traumatizing
Like I was tryna get into my friends place before we went out and as he was unlocking the door there was a shot and then I heard the bullet bounce off the wall nearby me
And we saw the guy leave the scene
I feel like I’m actually lucky
To be here
Because I literally heard the shooters breathing a few meters from me
So I’m kinda not in a good state rn lol
yall are gonna love this
I’m gonna be gone for a couple weeks. I’m going into impatient treatment
Last night I had an extremely bad acid trip and freaked out and had a psychotic episode
🙏🙏🙏🙏 get well soon
Okay well I’m working now
I’m osdeving so fucking hard right now
I rewrote so much shit
Yall don’t even know
I’m rewriting so much shit
lets goooo
I rewrote my GDT
unspaghetti
Yes
Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.
Haven’t pushed it yet but
Why
cant work on it yet tho
Show me
unfinished
Oh I see
idk????
Or your kernel binary
Well what is 27mb
What file
Kernel
Or iso
Because the iso will be big
idk
im not home i cant check
i remember checking but i forgot the number
its big as shit tho iirc
takes most of the 27 mb
BRO
uhhhhhhhh 
idk
deadass wtf was i smoking
my old code is fucking SHIT
27 fucking mb stack
damm
insane
maybe thats why paging shits itself
wtf is that stack
anyway are u gonna rewrite idt next?
what do u want to rewrite?
big unspaghetti
It’s because a lot of my operations take mountpoinrs
And walk to paths
Rather than taking in nodes
So
oh
That’s kinda fucked
truly
anything that has "virtual" in it code for it ends up looking like total farts
or is it just my experience with shitty tutorials and 27 mb stacks
If your gdt is more than 100 lines what are you doing
inline asm
im saving this
you're getting mogged right now abbix
u just dont understand
yeah that isnt a 27 mb stack
thats 128kib
Best meme