FS shell changes:

* Added basic built-in module support.
* Added rootfs.
* Added "kernel" initialization.
* Exposed the FS syscalls.
* Mounting/unmounting the FS works now.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20873 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2007-04-27 22:37:01 +00:00
parent 4fc054f504
commit 90c0876839
9 changed files with 1744 additions and 20 deletions
+3 -10
View File
@@ -40,23 +40,16 @@ typedef struct fssh_module_dependency {
} fssh_module_dependency;
#if 0
#ifdef __cplusplus
extern "C" {
#endif
extern status_t get_module(const char *path, module_info **_info);
extern status_t put_module(const char *path);
extern status_t get_next_loaded_module_name(uint32 *cookie, char *buffer, size_t *_bufferSize);
extern void *open_module_list(const char *prefix);
extern status_t close_module_list(void *cookie);
extern status_t read_next_module_name(void *cookie, char *buffer, size_t *_bufferSize);
extern fssh_status_t fssh_get_module(const char *path,
fssh_module_info **_info);
extern fssh_status_t fssh_put_module(const char *path);
#ifdef __cplusplus
}
#endif
#endif // 0
#endif /* _FSSH_MODULE_H */
+2
View File
@@ -22,7 +22,9 @@ BuildPlatformStaticLibrary <build2>fs_shell.a :
hash.cpp
list.cpp
lock.cpp
module.cpp
node_monitor.cpp
rootfs.cpp
sem.cpp
stat.cpp
stat_util.cpp
+1
View File
@@ -13,6 +13,7 @@
#include "fssh_kernel_priv.h"
#include "fssh_string.h"
#include "fssh_uio.h"
#include "syscalls.h"
//#define TRACE_FD
+107 -1
View File
@@ -3,9 +3,115 @@
* Distributed under the terms of the MIT License.
*/
#include <BeOSBuildCompatibility.h>
#include <stdio.h>
#include <string.h>
#include "fssh_errors.h"
#include "fssh_module.h"
#include "module.h"
#include "syscalls.h"
#include "vfs.h"
using namespace FSShell;
namespace FSShell {
extern fssh_file_system_module_info gRootFileSystem;
}
extern fssh_module_info *modules[];
static fssh_status_t
init_kernel()
{
fssh_status_t error;
// init module subsystem
error = module_init(NULL);
if (error != FSSH_B_OK) {
fprintf(stderr, "module_init() failed: %s\n", strerror(error));
return error;
} else
printf("module_init() succeeded!\n");
// register built-in modules, i.e. the rootfs and the client FS
register_builtin_module(&gRootFileSystem.info);
for (int i = 0; modules[i]; i++)
register_builtin_module(modules[i]);
// init VFS
error = vfs_init(NULL);
if (error != FSSH_B_OK) {
fprintf(stderr, "initializing VFS failed: %s\n", strerror(error));
return error;
} else
printf("VFS initialized successfully!\n");
// mount root FS
fssh_dev_t rootDev = _kern_mount("/", NULL, "rootfs", 0, NULL, 0);
if (rootDev < 0) {
fprintf(stderr, "mounting rootfs failed: %s\n", strerror(rootDev));
return rootDev;
} else
printf("mounted rootfs successfully!\n");
// create mount point for the client FS
error = _kern_create_dir(-1, "/myfs", 0775);
if (error != FSSH_B_OK) {
fprintf(stderr, "creating mount point failed: %s\n", strerror(error));
return error;
} else
printf("mount point created successfully!\n");
return FSSH_B_OK;
}
int
main()
main(int argc, const char* const* argv)
{
if (argc != 2) {
fprintf(stderr, "Usage: ...\n");
return 1;
}
const char* device = argv[1];
// get FS module
if (!modules[0]) {
fprintf(stderr, "Couldn't find FS module!\n");
return 1;
}
const char* fsName = modules[0]->name;
fssh_status_t error;
// init kernel
error = init_kernel();
if (error != FSSH_B_OK) {
fprintf(stderr, "initializing kernel failed: %s\n", strerror(error));
return error;
} else
printf("kernel initialized successfully!\n");
// mount FS
fssh_dev_t fsDev = _kern_mount("/myfs", device, fsName, 0, NULL, 0);
if (fsDev < 0) {
fprintf(stderr, "mounting FS failed: %s\n", strerror(fsDev));
return 1;
} else
printf("mounted FS successfully!\n");
// unmount FS
error = _kern_unmount("/myfs", 0);
if (error != FSSH_B_OK) {
fprintf(stderr, "unmounting FS failed: %s\n", strerror(error));
return error;
} else
printf("FS unmounted successfully!\n");
return 0;
}
+406
View File
@@ -0,0 +1,406 @@
/*
* Copyright 2002-2007, Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Copyright 2001, Thomas Kurschel. All rights reserved.
* Distributed under the terms of the NewOS License.
*/
/** Manages kernel add-ons and their exported modules. */
#include "module.h"
#include <stdlib.h>
#include "fssh_errors.h"
#include "fssh_kernel_export.h"
#include "fssh_module.h"
#include "fssh_string.h"
#include "hash.h"
#include "lock.h"
//#define TRACE_MODULE
#ifdef TRACE_MODULE
# define TRACE(x) fssh_dprintf x
#else
# define TRACE(x) ;
#endif
#define FATAL(x) fssh_dprintf x
namespace FSShell {
#define MODULE_HASH_SIZE 16
enum module_state {
MODULE_QUERIED = 0,
MODULE_LOADED,
MODULE_INIT,
MODULE_READY,
MODULE_UNINIT,
MODULE_ERROR
};
/* Each known module will have this structure which is put in the
* gModulesHash, and looked up by name.
*/
struct module {
struct module *next;
char *name;
char *file;
int32_t ref_count;
fssh_module_info *info; /* will only be valid if ref_count > 0 */
int32_t offset; /* this is the offset in the headers */
module_state state; /* state of module */
uint32_t flags;
};
#define FSSH_B_BUILT_IN_MODULE 2
/* locking scheme: there is a global lock only; having several locks
* makes trouble if dependent modules get loaded concurrently ->
* they have to wait for each other, i.e. we need one lock per module;
* also we must detect circular references during init and not dead-lock
*/
static recursive_lock sModulesLock;
/* we store the loaded modules by directory path, and all known modules by module name
* in a hash table for quick access
*/
static hash_table *sModulesHash;
/** calculates hash for a module using its name */
static uint32_t
module_hash(void *_module, const void *_key, uint32_t range)
{
module *module = (struct module *)_module;
const char *name = (const char *)_key;
if (module != NULL)
return hash_hash_string(module->name) % range;
if (name != NULL)
return hash_hash_string(name) % range;
return 0;
}
/** compares a module to a given name */
static int
module_compare(void *_module, const void *_key)
{
module *module = (struct module *)_module;
const char *name = (const char *)_key;
if (name == NULL)
return -1;
return fssh_strcmp(module->name, name);
}
static inline void
inc_module_ref_count(struct module *module)
{
module->ref_count++;
}
static inline void
dec_module_ref_count(struct module *module)
{
module->ref_count--;
}
/** Extract the information from the module_info structure pointed at
* by "info" and create the entries required for access to it's details.
*/
static fssh_status_t
create_module(fssh_module_info *info, const char *file, int offset, module **_module)
{
module *module;
TRACE(("create_module(info = %p, file = \"%s\", offset = %d, _module = %p)\n",
info, file, offset, _module));
if (!info->name)
return FSSH_B_BAD_VALUE;
module = (struct module *)hash_lookup(sModulesHash, info->name);
if (module) {
FATAL(("Duplicate module name (%s) detected... ignoring new one\n", info->name));
return FSSH_B_FILE_EXISTS;
}
if ((module = (struct module *)malloc(sizeof(struct module))) == NULL)
return FSSH_B_NO_MEMORY;
TRACE(("create_module: name = \"%s\", file = \"%s\"\n", info->name, file));
module->name = fssh_strdup(info->name);
if (module->name == NULL) {
free(module);
return FSSH_B_NO_MEMORY;
}
module->file = fssh_strdup(file);
if (module->file == NULL) {
free(module->name);
free(module);
return FSSH_B_NO_MEMORY;
}
module->state = MODULE_QUERIED;
module->info = info;
module->offset = offset;
// record where the module_info can be found in the module_info array
module->ref_count = 0;
module->flags = info->flags;
recursive_lock_lock(&sModulesLock);
hash_insert(sModulesHash, module);
recursive_lock_unlock(&sModulesLock);
if (_module)
*_module = module;
return FSSH_B_OK;
}
/** Initializes a loaded module depending on its state */
static inline fssh_status_t
init_module(module *module)
{
switch (module->state) {
case MODULE_QUERIED:
case MODULE_LOADED:
{
fssh_status_t status;
module->state = MODULE_INIT;
// init module
TRACE(("initializing module %s (at %p)... \n", module->name, module->info->std_ops));
status = module->info->std_ops(FSSH_B_MODULE_INIT);
TRACE(("...done (%s)\n", strerror(status)));
if (status >= FSSH_B_OK)
module->state = MODULE_READY;
else {
module->state = MODULE_LOADED;
}
return status;
}
case MODULE_READY:
return FSSH_B_OK;
case MODULE_INIT:
FATAL(("circular reference to %s\n", module->name));
return FSSH_B_ERROR;
case MODULE_UNINIT:
FATAL(("tried to load module %s which is currently unloading\n", module->name));
return FSSH_B_ERROR;
case MODULE_ERROR:
FATAL(("cannot load module %s because its earlier unloading failed\n", module->name));
return FSSH_B_ERROR;
default:
return FSSH_B_ERROR;
}
// never trespasses here
}
/** Uninitializes a module depeding on its state */
static inline int
uninit_module(module *module)
{
TRACE(("uninit_module(%s)\n", module->name));
switch (module->state) {
case MODULE_QUERIED:
case MODULE_LOADED:
return FSSH_B_NO_ERROR;
case MODULE_INIT:
fssh_panic("Trying to unload module %s which is initializing\n", module->name);
return FSSH_B_ERROR;
case MODULE_UNINIT:
fssh_panic("Trying to unload module %s which is un-initializing\n", module->name);
return FSSH_B_ERROR;
case MODULE_READY:
{
fssh_status_t status;
module->state = MODULE_UNINIT;
TRACE(("uninitializing module %s...\n", module->name));
status = module->info->std_ops(FSSH_B_MODULE_UNINIT);
TRACE(("...done (%s)\n", strerror(status)));
if (status == FSSH_B_NO_ERROR) {
module->state = MODULE_LOADED;
return 0;
}
FATAL(("Error unloading module %s (%s)\n", module->name, fssh_strerror(status)));
module->state = MODULE_ERROR;
module->flags |= FSSH_B_KEEP_LOADED;
return status;
}
default:
return FSSH_B_ERROR;
}
// never trespasses here
}
void
register_builtin_module(struct fssh_module_info *info)
{
info->flags |= FSSH_B_BUILT_IN_MODULE;
// this is an internal flag, it doesn't have to be set by modules itself
if (create_module(info, "", -1, NULL) != FSSH_B_OK)
fssh_dprintf("creation of built-in module \"%s\" failed!\n", info->name);
}
static int
dump_modules(int argc, char **argv)
{
hash_iterator iterator;
struct module *module;
hash_rewind(sModulesHash, &iterator);
fssh_dprintf("-- known modules:\n");
while ((module = (struct module *)hash_next(sModulesHash, &iterator)) != NULL) {
fssh_dprintf("%p: \"%s\", \"%s\" (%d), refcount = %d, state = %d\n",
module, module->name, module->file, (int)module->offset, (int)module->ref_count,
module->state);
}
return 0;
}
// #pragma mark -
// Exported Kernel API (private part)
/** Setup the module structures and data for use - must be called
* before any other module call.
*/
fssh_status_t
module_init(kernel_args *args)
{
if (recursive_lock_init(&sModulesLock, "modules rlock") < FSSH_B_OK)
return FSSH_B_ERROR;
sModulesHash = hash_init(MODULE_HASH_SIZE, 0, module_compare, module_hash);
if (sModulesHash == NULL)
return FSSH_B_NO_MEMORY;
fssh_add_debugger_command("modules", &dump_modules, "list all known & loaded modules");
return FSSH_B_OK;
}
} // namespace FSShell
// #pragma mark -
// Exported Kernel API (public part)
using namespace FSShell;
fssh_status_t
fssh_get_module(const char *path, fssh_module_info **_info)
{
module *module;
fssh_status_t status;
TRACE(("get_module(%s)\n", path));
if (path == NULL)
return FSSH_B_BAD_VALUE;
recursive_lock_lock(&sModulesLock);
module = (struct module *)hash_lookup(sModulesHash, path);
if (module == NULL)
goto err;
// The state will be adjusted by the call to init_module
// if we have just loaded the file
if (module->ref_count == 0)
status = init_module(module);
else
status = FSSH_B_OK;
if (status == FSSH_B_OK) {
inc_module_ref_count(module);
*_info = module->info;
}
recursive_lock_unlock(&sModulesLock);
return status;
err:
recursive_lock_unlock(&sModulesLock);
return FSSH_B_ENTRY_NOT_FOUND;
}
fssh_status_t
fssh_put_module(const char *path)
{
module *module;
TRACE(("put_module(path = %s)\n", path));
recursive_lock_lock(&sModulesLock);
module = (struct module *)hash_lookup(sModulesHash, path);
if (module == NULL) {
FATAL(("module: We don't seem to have a reference to module %s\n", path));
recursive_lock_unlock(&sModulesLock);
return FSSH_B_BAD_VALUE;
}
if ((module->flags & FSSH_B_KEEP_LOADED) == 0) {
dec_module_ref_count(module);
if (module->ref_count == 0)
uninit_module(module);
}
recursive_lock_unlock(&sModulesLock);
return FSSH_B_OK;
}
+23
View File
@@ -0,0 +1,23 @@
/*
* Copyright 2007, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef _FSSH_MODULE_PRIVATE_H
#define _FSSH_MODULE_PRIVATE_H
#include "fssh_defs.h"
struct fssh_module_info;
namespace FSShell {
struct kernel_args;
fssh_status_t module_init(kernel_args *args);
void register_builtin_module(struct fssh_module_info *info);
} // namespace FSShell
#endif // _FSSH_MODULE_PRIVATE_H
File diff suppressed because it is too large Load Diff
+89
View File
@@ -0,0 +1,89 @@
/*
* Copyright 2007, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef _FSSH_SYSCALLS_H
#define _FSSH_SYSCALLS_H
#include "fssh_defs.h"
struct fssh_iovec;
// defined in vfs.cpp
fssh_dev_t _kern_mount(const char *path, const char *device,
const char *fsName, uint32_t flags, const char *args,
fssh_size_t argsLength);
fssh_status_t _kern_unmount(const char *path, uint32_t flags);
fssh_status_t _kern_read_fs_info(fssh_dev_t device,
struct fssh_fs_info *info);
fssh_status_t _kern_write_fs_info(fssh_dev_t device,
const struct fssh_fs_info *info, int mask);
fssh_status_t _kern_sync(void);
fssh_dev_t _kern_next_device(int32_t *_cookie);
int _kern_open_entry_ref(fssh_dev_t device, fssh_ino_t inode,
const char *name, int openMode, int perms);
int _kern_open(int fd, const char *path, int openMode, int perms);
int _kern_open_dir_entry_ref(fssh_dev_t device, fssh_ino_t inode,
const char *name);
int _kern_open_dir(int fd, const char *path);
fssh_status_t _kern_fcntl(int fd, int op, uint32_t argument);
fssh_status_t _kern_fsync(int fd);
fssh_status_t _kern_lock_node(int fd);
fssh_status_t _kern_unlock_node(int fd);
fssh_status_t _kern_create_dir_entry_ref(fssh_dev_t device, fssh_ino_t inode,
const char *name, int perms);
fssh_status_t _kern_create_dir(int fd, const char *path, int perms);
fssh_status_t _kern_remove_dir(int fd, const char *path);
fssh_status_t _kern_read_link(int fd, const char *path, char *buffer,
fssh_size_t *_bufferSize);
fssh_status_t _kern_create_symlink(int fd, const char *path,
const char *toPath, int mode);
fssh_status_t _kern_create_link(const char *path, const char *toPath);
fssh_status_t _kern_unlink(int fd, const char *path);
fssh_status_t _kern_rename(int oldFD, const char *oldPath, int newFD,
const char *newPath);
fssh_status_t _kern_access(const char *path, int mode);
fssh_status_t _kern_read_stat(int fd, const char *path, bool traverseLeafLink,
struct fssh_stat *stat, fssh_size_t statSize);
fssh_status_t _kern_write_stat(int fd, const char *path,
bool traverseLeafLink, const struct fssh_stat *stat,
fssh_size_t statSize, int statMask);
int _kern_open_attr_dir(int fd, const char *path);
int _kern_create_attr(int fd, const char *name, uint32_t type,
int openMode);
int _kern_open_attr(int fd, const char *name, int openMode);
fssh_status_t _kern_remove_attr(int fd, const char *name);
fssh_status_t _kern_rename_attr(int fromFile, const char *fromName,
int toFile, const char *toName);
int _kern_open_index_dir(fssh_dev_t device);
fssh_status_t _kern_create_index(fssh_dev_t device, const char *name,
uint32_t type, uint32_t flags);
fssh_status_t _kern_read_index_stat(fssh_dev_t device, const char *name,
struct fssh_stat *stat);
fssh_status_t _kern_remove_index(fssh_dev_t device, const char *name);
fssh_status_t _kern_getcwd(char *buffer, fssh_size_t size);
fssh_status_t _kern_setcwd(int fd, const char *path);
// defined in fd.cpp
fssh_ssize_t _kern_read(int fd, fssh_off_t pos, void *buffer,
fssh_size_t length);
fssh_ssize_t _kern_readv(int fd, fssh_off_t pos, const fssh_iovec *vecs,
fssh_size_t count);
fssh_ssize_t _kern_write(int fd, fssh_off_t pos, const void *buffer,
fssh_size_t length);
fssh_ssize_t _kern_writev(int fd, fssh_off_t pos, const fssh_iovec *vecs,
fssh_size_t count);
fssh_off_t _kern_seek(int fd, fssh_off_t pos, int seekType);
fssh_status_t _kern_ioctl(int fd, uint32_t op, void *buffer,
fssh_size_t length);
fssh_ssize_t _kern_read_dir(int fd, struct fssh_dirent *buffer,
fssh_size_t bufferSize, uint32_t maxCount);
fssh_status_t _kern_rewind_dir(int fd);
fssh_status_t _kern_close(int fd);
int _kern_dup(int fd);
int _kern_dup2(int ofd, int nfd);
#endif // _FSSH_SYSCALLS_H
+10 -9
View File
@@ -20,11 +20,14 @@
#include "fssh_fs_info.h"
#include "fssh_fs_volume.h"
#include "fssh_kernel_export.h"
#include "fssh_module.h"
#include "fssh_stat.h"
#include "fssh_stdio.h"
#include "fssh_string.h"
#include "fssh_unistd.h"
#include "hash.h"
#include "KPath.h"
#include "syscalls.h"
//#define TRACE_VFS
@@ -459,8 +462,7 @@ put_mount(struct fs_mount *mount)
static fssh_status_t
put_file_system(fssh_file_system_module_info *fs)
{
// return put_module(fs->info.name);
return FSSH_B_ERROR;
return fssh_put_module(fs->info.name);
}
@@ -473,22 +475,19 @@ put_file_system(fssh_file_system_module_info *fs)
static fssh_file_system_module_info *
get_file_system(const char *fsName)
{
#if 0
char name[FSSH_B_FILE_NAME_LENGTH];
if (strncmp(fsName, "file_systems/", strlen("file_systems/"))) {
if (fssh_strncmp(fsName, "file_systems/", fssh_strlen("file_systems/"))) {
// construct module name if we didn't get one
// (we currently support only one API)
snprintf(name, sizeof(name), "file_systems/%s/v1", fsName);
fssh_snprintf(name, sizeof(name), "file_systems/%s/v1", fsName);
fsName = NULL;
}
fssh_file_system_module_info *info;
if (get_module(fsName ? fsName : name, (module_info **)&info) != FSSH_B_OK)
if (fssh_get_module(fsName ? fsName : name, (fssh_module_info **)&info) != FSSH_B_OK)
return NULL;
return info;
#endif // 0
return NULL;
}
@@ -4068,7 +4067,9 @@ fs_mount(char *path, const char *device, const char *fsName, uint32_t flags,
if (!(flags & FSSH_B_MOUNT_VIRTUAL_DEVICE) && device) {
// normalize the device path
status = normalizedDevice.SetTo(device, true);
// status = normalizedDevice.SetTo(device, true);
// NOTE: normalizing works only in our namespace.
status = normalizedDevice.SetTo(device, false);
if (status != FSSH_B_OK)
return status;