3 ms·
Can someone Explain Like I’m Five why someone would design a filesystem to be deeply entangled with a specific struct in memory in a specific kernel design? I’
by eduction 3y ago
Can someone Explain Like I’m Five why someone would design a filesystem to be deeply entangled with a specific struct in memory in a specific kernel design?
I’m referring to where the article says ext4 “still makes heavy use of buffer heads,” implies this has been the case since ext2 and says “the buffer cache was deeply wired into both the block subsystem and the filesystem implementations.”
Naively I would think the job of the filesystem is to handle reads and writes to disk and that a well designed one would leave caching to other parts of the OS.
- rwmj 3y agoThe sibling comment is one reason, but I'd like to add another. ext2 was introduced into Linux in Jan 1993, which is less than 18 months after Linux was first released. ext3 was made by copying the code from ext2 and renaming the identifiers s/ext2/ext3/g, and ext4 the same way from ext3. So these filesystems are old. Even if it was a good idea to structure caching and filesystem block access separately (which as the sibling comment says, it isn't), the Linux developers were just getting started back then and it was much more important to get something working than to think about good abstractions.
- jabl 3y agoI think it's a question of how you design the OS kernel. Consider for example an application that has opened a file, and now wants to read data from the file. So it calls the read() syscall (https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html https://pubs.opengroup.org/onlinepubs/9699919799/functions/r... ) either directly or via fread(), iostream or whatever. How should the kernel handle that? - Since a file is something filesystems do, it seems sensible to quite directly plumb the read() syscall into the filesystem, and the filesystem can then handle reading blocks from the actual disk, or caching previously read blocks. If an OS wants to support multiple filesystem types, it might even provide some common data structures and code for doing this caching of disk blocks. In Linux this being the "struct buffer_head". - The other option being that managing memory is something kernels do, and it makes sense to centralize this management in a common code that can then make sensible decisions what to do with this memory. Such as giving it to applications that ask for memory, using it for caching file contents (page cache), and the crucial part, balancing these different usecases and making good choices what to evict. If you make this design choice, the read() syscall will not immediately be handed down to the filesystem, but rather it first asks the memory management subsystem whether the data happens to be in the page cache, and only if it isn't, it calls down to the filesystem to read that data from the physical disk, copy it to the page cache (potentially evicting something else to make room), and then copy it back to the application asking for it. Now it seems that historically quite a few OS'es, Linux included, started off with the first approach. However later on it turned out that the second way of designing the OS is better, and thus Linux was slowly over time modified to mostly use the page cache. Though the struct buffer_head is still in use here and there.
- asveikau 3y agoThink of the internal kernel interfaces like a library. The older filesystems were coded against the library as it existed at the time of their writing. Some of the APIs got superseded by newer interfaces which are more recommended for newer code. But a lot of code written against the old interface is still out there. For good measure, let's say the new interface isn't a trivial port, sometimes it requires rethinking larger parts of the caller's code.
- thristian 3y agoThe filesystem doesn't just read from one part of the disk and write to another part of the disk, it reads from the disk and stores the result in memory, or it takes data from memory and writes it to the disk. The other part of the kernel that deals with data in memory is the cache. Rather than have two separate representations of "data in memory" and have to translate between them all the time, it makes sense to have one representation of "data in memory" that all the affected systems can use to talk to each other. Even though the kernel now has multiple representations of "data in memory" due to advances in other parts of the kernel, it's still desirable to have just one representation shared between the cache and the filesystem, which is why people are talking about removing the old ones, and porting old code to use the new ones.
- just_a_quack 3y agoI think it's because ext2 and ext4 both use block allocation in favor of paging thru bio and uses buffer tricks to write data in a way that reduces fragmentation
- bcrl 3y agoIt has nothing to do with fragmentation, but with wasted space. When ext2 was originally developed in the 1990s, the typical block size employed was 1KB as storage was orders of magnitude smaller, so wasting half a block per file on a floppy disk or small HDD was a significant concern. Today most filesystems use 4KB blocks to match the page size of the most common CPUs as wasting a couple of kilobytes per file is noise. The journaling layer (jbd) in ext3/ext4 was built on top of buffer_heads as buffer_heads were the way writes got tracked. Rewriting ext4 and jbd2 to use a new data structure to track writes to the journal and disk will be a lot of work. ext4 has a number of issues that make it a less desirable filesystem these days, so it's not clear the work will be worth it any time soon when filesystems like bcachefs, btrfs and xfs do so much better.