I'll grant you the in-kernel nfs server and ipsec implementations, but those are not tens of millions of lines of code. The only way I can reach that number is by lobbing off a huge part of device drivers into userspace, but that's not really an interesting discussion as it seems purely subjective.
This would facilitate more innovation and ability to quickly resolve reliability issues with filesystems, make the whole “can you boot off of it or do you need a kernel module” distinction obsolete, and would massively reduce the temptation for the kernel to support certain APIs only for certain filesystems (let me inotify on procfs, and use nonblocking IO on any FS I like, dammit!)
Nonblocking I/O only makes sense for IPC. You want async I/O, which Linux doesn't support but Windows does.
I more meant that if filesystem drivers had always been external to the kernel, then it would have been harder for so many syscalls to develop filesystem-specific behavior (e.g. things that work on block FSes but not nfs/tmpfs/9pfs/procfs and so on--inotify, atimes, inode stability, sparsity, stuff like that). Being monolithic made it easier to get lots of FS-specific exceptions, which results in some things requiring you to carefully parse manpages or debug EINVALs based on where files live. The benefit of that approach is that it enabled fast development of new features, but looking back I'm not sure if it was worth it.
> Nonblocking I/O only makes sense for IPC.
I want O_NONBLOCK to not fail for disk files. It could lie and block, or only report ready once things were in the buffer cache, or only report ready once part of the VFS response came out of the hardware interrupt/command queue, or any one of several options. I don't know which if any of those count as "async I/O", but the core problem here is ubiquitous syscalls (read/open/inotify_add_watch) whose failure-or-not is contingent on the type of object you give them (blockdev file vs. non-blockdev file vs. semaphore vs. socket vs. pipe vs. timerfd and so on).
> You want async I/O, which Linux doesn't support but Windows does.
Linux kind of has async block device I/O with io_uring now, but they repeated what is basically the Linux original sin mentioned above and made it contingent on whether a device/driver/filesystem support asynchronous operation or not.
Windows overlapped I/O definitely did it first and better though.