kernel: add VFS spinlock (g_vfs_lock) to fix SMP mount-table races
The VFS mount table (g_mounts[], g_mount_count, fs_root) had zero
locking protection. On SMP (4 CPUs), concurrent access during
pivot_root/mount/umount2 corrupted the mount table, causing:
- Mount points disappearing: vfs_umount shifts array entries while
another CPU's vfs_lookup iterates, skipping/duplicating entries
- Sporadic QEMU reboot: corrupted fs_node_t* pointer from torn
reads causes kernel page fault -> triple fault -> reboot
Fix:
- Add spinlock_t g_vfs_lock in fs.c protecting fs_root, g_mounts[],
and g_mount_count
- Create _nolock variants (vfs_mount_nolock, vfs_umount_nolock) for
compound operations that need atomicity across multiple mutations
- Public vfs_mount/vfs_umount acquire the lock automatically
- vfs_lookup_depth snapshots mount table under lock before traversal
- SYSCALL_PIVOT_ROOT holds g_vfs_lock across the entire compound
mutation (fs_root update + two vfs_mount_nolock calls)
- Export g_vfs_lock and _nolock variants in fs.h
Also:
- fulltest pivot_root test: undo pivot_root in child before exit,
verify /dev/null accessible after undo
- ulibc strrchr: add null-pointer guard (cppcheck ctunullpointer)
- fulltest: struct init {0} instead of {{0}} (cppcheck uninitvar)