kmcguire wrote:
I like the extension idea. It can support fragmentation, or not support fragmentation, but would it really be worth it? It would be just as easier to read and write to a fragmented file system as a non-fragmented, right?
Having nonfragmented files gives a lot cleaner and simpler code. Reading from the file is making a read from start+offset, not some complex method that has to take all sorts of limits into account. You can optimize it by buffering, but that's not for embedded systems which is also nice to support. Also, if it's not necessary, why bother?
I propose to add:
One bit at the start of an inode that indicates whether it's fragmented. If it is fragmented, the old driver doesn't read it.
One variable at the superblock indicating the amount of fragmented files. If it's >0 the old driver doesn't write to the filesystem at all.
I propose to change:
The file length and start/end block information. In the case of a fragmented file, there are (length, start) blocks in the data portion indicated here (start/end block). These blocks indicate where the actual data is. In the case of an unfragmented file, these hold their original intent.
In this way, making a driver for a new OS doesn't need to do any chain following, free space management or anything like that. You just read inodes, read linear data and you're done. For writing, you make an extent list of free blocks, find one that fits, fill in the data structures and that's it again. That's what I figured would be a simple FS.
Then you get the second level. It's the same, but there's the possibility of indirect adressing. Making the initial block list is the original algorithm, expanded with reading indirect blocks. Reading files is the same, writing files boils down to the same again. You don't care about the value at the begin of the FS, but you do keep it up to date.
These two can always cooperate.
Then you need a defragmenter, for those cases there's something wrong or somebody wants to defragment it. Defragmenting a non-critical filesystem is pretty simple: 1. round up all fragments of files and make whole files, 2. move files that can fit in an earlier gap there. End of defragmenting. Optional no3 would be abusing little files and complex algorithms to fill in the remaining gaps, although they're probably not very important to fill (they're only to be used when the FS is nearly full, in which case you're screwed anyway).
In the unfragmented system. If I want to write to file, I actually could end up recreating it(easy), or trying to defragment the file system to make room and... all that time I might have to defragment the file multiple times if I dont make enough free room after the file on the first run...
The point behind the two levels is that the first is as simple as can be, while maintaining some required functions, and the second is normal in terms of what people expect (you can't just get an error for nothing), fairly simple and 100% compatible with the first. So, the first type is useful to make and can grow into the second type. You can test with the first one easily since it doesn't need much space or structures in memory to work (some 100 lines of C code should suffice, perhaps 1000 in assembly).
Keep the file system simple by just plain complaining when the disk is "full". Don't bother implementing the warnings - if you're serious about support, make it lvl2-compliant. In that case, the warnings and complexity is moot.
I see the levels as such:
1. Very simple for beginning OSes, very simple and compact applications such as embedded and that's it.
2. For any normal application. Level 1 is a stepping stone to implementing it which you can fully test and use. It just has quite some limits. Those limits mostly involve very-hard-or-slow-stuff, which lvl2 fixes (using fragmentation).
Example for level 1: My OS in a few months (disk driver testing method), my OS' initial boot image, DennisOS, Bubach's OS for fs testing? Bootloader testing?
Level 2: Any real OS, any "grown-up" driver, photo camera's, flash disks etc.