After publishing patches I implemented few suggestions from Robert Watson.
I also implemented better handling of journal overflow. Now one can define at which point journal switch is forced. This can be defined in percents via kern.geom.journal.force_switch. Not ideal, but much better than panicing.
BIO_FLUSH support was added to da(4) disks.
I’m in the process of reimplementing how removed, but still open objects (files, directories) are handled in case of a power failure or system crash.
Currently there is a magic .deleted/ directory where such objects are moved. On boot mount(8) can simply ‘rm -rf .deleted/*’.
The solution I’m implementing currently is to increase a counter in cylinder group (CG) when such situation takes place (objects is removed, but still open). When it is closed, I simply decrease the counter. On boot, a much faster fsck version checks the counter in every CG and if it is greater than 0, it scans all inodes in the CG. If it finds allocated inode, but with linkcnt=0, it cleans the inode, ie. remove all allocated blocks, marks as unallocated, etc.
Because of the complexity of UFS on-disk layout it is not a trivial task. To remove an inode completely I need to:
1. Go through the list of direct blocks pointers and mark the blocks in freeblock bitmaps as free.
2. The same as in 1, but for indirect blocks (single, double and triple).
3. Watch out for fragments. Fragments are only used for small files (which use only direct pointed blocks) and a fragment can be only at the end of the file.
4. Update blocks and fragements counters in three places.
5. Update clusters bitmap.
6. Update pointer of the last used block and fragment if needed.
7. Zero-fill the entire inode.
8. Mark an inode as free in inode’s bitmap.
9. Update inodes related counters in three places.
10. Update pointer of the last used inode.
11. Pray for success.
Most of the things I already implemented, but this is not the code I’d like to show. I’m thinking about extending libufs(3), because now its usefullness is very limited.