A kernel IS a program, just like any other. By default the Linux kernel attempts to access file system, however this behavior can be trivially eliminated by kernel modification (actually just an addition of an "arch_call_rest_init()" function). In order to perform "useful work" then we expect that the developer might include kernel threads (kthreads), perhapos in a custom driver, to perform some desired initialization and application type workload. The Linux kernel contains many kthreads already ,but primarily to perform work ancillary to the kernel or drivers. The APIs available within the kernel context are quite different from those available in Linux user-space. A large fraction of system call functionality would become useless in a no-filesystem scenario.
Yes, Linux expects access to file systems by default.
No, a modified kernel could certainly be made to perform useful work w/o any file system.
The practical use of Linux w/o filesystem is IMO quite limited, but not nil. FWIW, in the past many real-time kernels were built into the same name-space & binary as the RT applications.
--- addendum ---
I've examined the issue in detail against the 6.11.0 sources.
Some thoughts,
I consider a real "filesystem" to be an encoded block device (disk typically) or a network interface (like NSF) that presents a mountable entity of a type that might appear in /proc/filesystems. It is possible to successfully call creat, open, close, read, write, seek and unlink on such a file system. In addition modern Linux includes several pseudo-filesystems such as /proc, /sys. /dev (via devtmpfs) is a semi-real ramdisk fs, but populated by the kernel.. These pseudo-fs (/proc, /sys) are a convenient way to communicate info between user&kernel space, but not conventional filesystems.
(A) It is trivially easy to to cause the kernel to exec a program on a regular filesystem and then never again access any conventional filesystem. Just take a statically linked copy of 'yes' and copy it to /sbin/init . Even a useful binary, such as a firewall or i/o control program may have no i/o to a filesystem. This is a "stops using filesystems" method.
(B) Note that any successful call to exec() necessarily involves access to SOME filesystem. We can take a statically linked binary (like 'yes' or an i/o program) and create a kernel module with the binary blob, and have the module present the blob within one of the of the pseudo filesystems. So like:
uint8 myblob[] = { 0x75, 0x45, .... }
sysfs_create_bin_file(&myblob, __ATTR(myinit, 0755))
This creates an pseudo-fs entry at /sys/myinit which is executable. Then if we set the kernel boot parameter "init=/sys/myinit" the kernel will exec the binary as pid=1. This is an "only uses pseudo-filesystems" method.
We can futher eliminate /dev and other ramdisks and filesystems of any sort with (CONFIG_BLOCK=n; CONFIG_NET=n). This means no disks, no ramdisk, no block devtmpfs nor tmpfs. /proc and /sys still exist, mounted on a bogus '/' root.
A control program dependent on /dev/gpiochip0 [for example] would fail - however it could use the /sys interface such as /sys/devices/pci0000:00/INT3450:00/gpiochip0 and successfully do I/O. So yes there is a method for a "useful app with no filesystem", except the /sys pseudo-fs.
Even in deeply embedded systems, removal of ramdisk for /dev/ and /tmp/ is rare, and various flash or eeprom filesystems (squashfs on a flash/eeprom) are often used. It could however be done and there are viable use-cases.
useful exposure to the outside worldinit(the first user-space process), and that will fail.