diff --git a/headers/private/kernel/syscalls.h b/headers/private/kernel/syscalls.h index 627badeae5..f04136e883 100644 --- a/headers/private/kernel/syscalls.h +++ b/headers/private/kernel/syscalls.h @@ -115,7 +115,7 @@ extern status_t _kern_get_image_info(image_id id, image_info *info, size_t size extern status_t _kern_get_next_image_info(team_id team, int32 *cookie, image_info *info, size_t size); // VFS functions -extern status_t _kern_mount(const char *path, const char *device, +extern dev_t _kern_mount(const char *path, const char *device, const char *fs_name, uint32 flags, const char *args); extern status_t _kern_unmount(const char *path, uint32 flags); extern status_t _kern_read_fs_info(dev_t device, struct fs_info *info); diff --git a/headers/private/kernel/vfs.h b/headers/private/kernel/vfs.h index d774449b03..2a0d881004 100644 --- a/headers/private/kernel/vfs.h +++ b/headers/private/kernel/vfs.h @@ -104,7 +104,7 @@ status_t resolve_mount_point_to_volume_root(mount_id mountID, vnode_id nodeID, mount_id *resolvedMountID, vnode_id *resolvedNodeID); /* calls the syscall dispatcher should use for user file I/O */ -status_t _user_mount(const char *path, const char *device, const char *fs_name, +dev_t _user_mount(const char *path, const char *device, const char *fs_name, uint32 flags, const char *args); status_t _user_unmount(const char *path, uint32 flags); status_t _user_read_fs_info(dev_t device, struct fs_info *info); diff --git a/src/system/kernel/fs/Jamfile b/src/system/kernel/fs/Jamfile index f901f0a4a3..ce3075597e 100644 --- a/src/system/kernel/fs/Jamfile +++ b/src/system/kernel/fs/Jamfile @@ -12,6 +12,7 @@ KernelMergeObject kernel_fs.o : pipefs.cpp fd.c vfs.cpp + vfs_boot.cpp vfs_select.cpp message.c node_monitor.cpp diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp index 7db201b3f3..119fceefb0 100644 --- a/src/system/kernel/fs/vfs.cpp +++ b/src/system/kernel/fs/vfs.cpp @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -62,18 +61,6 @@ const static uint32 kMaxUnusedVnodes = 8192; // It may be chosen with respect to the available memory or enhanced // by some timestamp/frequency heurism. -static struct { - const char *path; - const char *target; -} sPredefinedLinks[] = { - {"/system", "/boot/beos/system"}, - {"/bin", "/boot/beos/bin"}, - {"/etc", "/boot/beos/etc"}, - {"/var", "/boot/var"}, - {"/tmp", "/boot/var/tmp"}, - {NULL} -}; - struct vnode { struct vnode *next; vm_cache_ref *cache; @@ -178,10 +165,6 @@ static mount_id sNextMountID = 1; mode_t __gUmask = 022; -// This can be used by other code to see if there is a boot file system already -dev_t gBootDevice = -1; - - /* function declarations */ // file descriptor operation prototypes @@ -3074,123 +3057,6 @@ vfs_setrlimit(int resource, const struct rlimit * rlp) } -status_t -vfs_bootstrap_file_systems(void) -{ - status_t status; - - // bootstrap the root filesystem - status = _kern_mount("/", NULL, "rootfs", 0, NULL); - if (status < B_OK) - panic("error mounting rootfs!\n"); - - _kern_setcwd(-1, "/"); - - // bootstrap the devfs - _kern_create_dir(-1, "/dev", 0755); - status = _kern_mount("/dev", NULL, "devfs", 0, NULL); - if (status < B_OK) - panic("error mounting devfs\n"); - - // bootstrap the pipefs - _kern_create_dir(-1, "/pipe", 0755); - status = _kern_mount("/pipe", NULL, "pipefs", 0, NULL); - if (status < B_OK) - panic("error mounting pipefs\n"); - - // bootstrap the bootfs (if possible) - _kern_create_dir(-1, "/boot", 0755); - status = _kern_mount("/boot", NULL, "bootfs", 0, NULL); - if (status < B_OK) { - // this is no fatal exception at this point, as we may mount - // a real on disk file system later - dprintf("Can't mount bootfs (will try disk file system later)\n"); - } - - // create some standard links on the rootfs - - for (int32 i = 0; sPredefinedLinks[i].path != NULL; i++) { - _kern_create_symlink(-1, sPredefinedLinks[i].path, - sPredefinedLinks[i].target, 0); - // we don't care if it will succeed or not - } - - return B_OK; -} - - -status_t -vfs_mount_boot_file_system(kernel_args *args) -{ - // make the boot partition (and probably others) available - KDiskDeviceManager::CreateDefault(); - KDiskDeviceManager *manager = KDiskDeviceManager::Default(); - - status_t status = manager->InitialDeviceScan(); - if (status == B_OK) { - // ToDo: do this for real... (no hacks allowed :)) - for (;;) { - snooze(500000); - if (manager->CountJobs() == 0) - break; - } - } else - dprintf("KDiskDeviceManager::InitialDeviceScan() failed: %s\n", strerror(status)); - - file_system_module_info *bootfs; - if ((bootfs = get_file_system("bootfs")) == NULL) { - // no bootfs there, yet - - // ToDo: do this for real! It will currently only use the partition offset; - // it does not yet use the disk_identifier information. - - KPartition *bootPartition = NULL; - - struct BootPartitionVisitor : KPartitionVisitor { - BootPartitionVisitor(off_t offset) : fOffset(offset) {} - - virtual bool VisitPre(KPartition *partition) - { - return (partition->ContainsFileSystem() - && partition->Offset() == fOffset); - } - private: - off_t fOffset; - } visitor(args->boot_disk.partition_offset); - - KDiskDevice *device; - int32 cookie = 0; - while ((device = manager->NextDevice(&cookie)) != NULL) { - bootPartition = device->VisitEachDescendant(&visitor); - if (bootPartition) - break; - } - - KPath path; - if (bootPartition == NULL - || bootPartition->GetPath(&path) != B_OK - || _kern_mount("/boot", path.Path(), "bfs", 0, NULL) < B_OK) - panic("could not get boot device!\n"); - } else - put_file_system(bootfs); - - gBootDevice = sNextMountID - 1; - - // create link for the name of the boot device - - fs_info info; - if (_kern_read_fs_info(gBootDevice, &info) == B_OK) { - char path[B_FILE_NAME_LENGTH + 1]; - snprintf(path, sizeof(path), "/%s", info.volume_name); - - _kern_create_symlink(-1, path, "/boot", 0); - } - - file_cache_init_post_boot_device(); - return B_OK; -} - - status_t vfs_init(kernel_args *args) { @@ -4891,7 +4757,7 @@ query_rewind(struct file_descriptor *descriptor) // General File System functions -static status_t +static dev_t fs_mount(char *path, const char *device, const char *fsName, uint32 flags, const char *args, bool kernel) { @@ -5121,7 +4987,7 @@ fs_mount(char *path, const char *device, const char *fsName, uint32 flags, fileDeviceDeleter.id = -1; } - return B_OK; + return mount->id; err7: FS_MOUNT_CALL(mount, unmount)(mount->cookie); @@ -5446,7 +5312,7 @@ err: // Calls from within the kernel -status_t +dev_t _kern_mount(const char *path, const char *device, const char *fsName, uint32 flags, const char *args) { @@ -6076,7 +5942,7 @@ _kern_setcwd(int fd, const char *path) // Calls from userland (with extra address checks) -status_t +dev_t _user_mount(const char *userPath, const char *userDevice, const char *userFileSystem, uint32 flags, const char *userArgs) { diff --git a/src/system/kernel/fs/vfs_boot.cpp b/src/system/kernel/fs/vfs_boot.cpp new file mode 100644 index 0000000000..89bcc49430 --- /dev/null +++ b/src/system/kernel/fs/vfs_boot.cpp @@ -0,0 +1,207 @@ +/* + * Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + * + * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. + * Distributed under the terms of the NewOS License. + */ + + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + + +//#define TRACE_VFS +#ifdef TRACE_VFS +# define PRINT(x) dprintf x +# define FUNCTION(x) dprintf x +#else +# define PRINT(x) ; +# define FUNCTION(x) ; +#endif + + +typedef Stack PartitionStack; + +static struct { + const char *path; + const char *target; +} sPredefinedLinks[] = { + {"/system", "/boot/beos/system"}, + {"/bin", "/boot/beos/bin"}, + {"/etc", "/boot/beos/etc"}, + {"/var", "/boot/var"}, + {"/tmp", "/boot/var/tmp"}, + {NULL} +}; + +// This can be used by other code to see if there is a boot file system already +dev_t gBootDevice = -1; + + +static status_t +get_boot_partitions(kernel_args *args, PartitionStack &partitions) +{ + // make the boot partition (and probably others) available + KDiskDeviceManager::CreateDefault(); + KDiskDeviceManager *manager = KDiskDeviceManager::Default(); + + status_t status = manager->InitialDeviceScan(); + if (status == B_OK) { + // ToDo: do this for real... (no hacks allowed :)) + for (;;) { + snooze(500000); + if (manager->CountJobs() == 0) + break; + } + } else { + dprintf("KDiskDeviceManager::InitialDeviceScan() failed: %s\n", strerror(status)); + return status; + } + + // ToDo: do this for real! It will currently only use the partition offset; + // it does not yet use the disk_identifier information. + + struct BootPartitionVisitor : KPartitionVisitor { + BootPartitionVisitor(kernel_args &args, PartitionStack &stack) + : fArgs(args), fPartitions(stack) {} + + virtual bool VisitPre(KPartition *partition) + { + if (!partition->ContainsFileSystem()) + return false; + + if (!fArgs.boot_disk.booted_from_image) { + // the simple case: we can just boot from the selected boot device + if (partition->Offset() == fArgs.boot_disk.partition_offset) { + fPartitions.Push(partition); + return true; + } + } else { + // for now, we will just collect all BFS volumes + if (fArgs.boot_disk.cd && fArgs.boot_disk.user_selected + && partition->Type() != NULL + && strcmp(partition->Type(), kPartitionTypeDataSession)) + return false; + + if (partition->ContentType() != NULL + && !strcmp(partition->ContentType(), "Be File System")) + fPartitions.Push(partition); + } + return false; + } + private: + kernel_args &fArgs; + PartitionStack &fPartitions; + } visitor(*args, partitions); + + KDiskDevice *device; + int32 cookie = 0; + while ((device = manager->NextDevice(&cookie)) != NULL) { + if (device->VisitEachDescendant(&visitor) != NULL) + break; + } + + // ToDo: sort partition list (ie. when booting from CD, CDs should come first in the list) + return B_OK; +} + + +// #pragma mark - + + +status_t +vfs_bootstrap_file_systems(void) +{ + status_t status; + + // bootstrap the root filesystem + status = _kern_mount("/", NULL, "rootfs", 0, NULL); + if (status < B_OK) + panic("error mounting rootfs!\n"); + + _kern_setcwd(-1, "/"); + + // bootstrap the devfs + _kern_create_dir(-1, "/dev", 0755); + status = _kern_mount("/dev", NULL, "devfs", 0, NULL); + if (status < B_OK) + panic("error mounting devfs\n"); + + // bootstrap the pipefs + _kern_create_dir(-1, "/pipe", 0755); + status = _kern_mount("/pipe", NULL, "pipefs", 0, NULL); + if (status < B_OK) + panic("error mounting pipefs\n"); + + // bootstrap the bootfs (if possible) + _kern_create_dir(-1, "/boot", 0755); + status = _kern_mount("/boot", NULL, "bootfs", 0, NULL); + if (status < B_OK) { + // this is no fatal exception at this point, as we may mount + // a real on disk file system later + dprintf("Can't mount bootfs (will try disk file system later)\n"); + } + + // create some standard links on the rootfs + + for (int32 i = 0; sPredefinedLinks[i].path != NULL; i++) { + _kern_create_symlink(-1, sPredefinedLinks[i].path, + sPredefinedLinks[i].target, 0); + // we don't care if it will succeed or not + } + + return B_OK; +} + + +status_t +vfs_mount_boot_file_system(kernel_args *args) +{ + PartitionStack partitions; + status_t status = get_boot_partitions(args, partitions); + if (status < B_OK) + return status; + + KPartition *bootPartition; + while (partitions.Pop(&bootPartition)) { + KPath path; + if (bootPartition->GetPath(&path) != B_OK) + panic("could not get boot device!\n"); + + gBootDevice = _kern_mount("/boot", path.Path(), NULL, 0, NULL); + if (gBootDevice >= B_OK) + break; + } + + if (gBootDevice < B_OK) + panic("could not mount boot device!\n"); + + // create link for the name of the boot device + + fs_info info; + if (_kern_read_fs_info(gBootDevice, &info) == B_OK) { + char path[B_FILE_NAME_LENGTH + 1]; + snprintf(path, sizeof(path), "/%s", info.volume_name); + + _kern_create_symlink(-1, path, "/boot", 0); + } + + file_cache_init_post_boot_device(); + return B_OK; +} +