refactor: inode creation, inode cache lookup and it's hashing are now separated.
refactor: reduce the v_inode and v_file size due to ops invariants.
chores: minor refactoring and fixings.
#define VFS_WALK_MKPARENT 0x1
#define VFS_WALK_FSRELATIVE 0x2
#define VFS_WALK_PARENT 0x4
-#define VFS_WALK_NOFOLLOW 0x4
+#define VFS_WALK_NOFOLLOW 0x8
#define VFS_HASHTABLE_BITS 10
#define VFS_HASHTABLE_SIZE (1 << VFS_HASHTABLE_BITS)
#define FSTYPE_ROFS 0x1
+#define DO_STATUS(errno) SYSCALL_ESTATUS(__current->k_status = errno)
+#define DO_STATUS_OR_RETURN(errno) ({ errno < 0 ? DO_STATUS(errno) : errno; })
+
+#define TEST_FD(fd) (fd >= 0 && fd < VFS_MAX_FD)
+
#define VFS_VALID_CHAR(chr) \
(('A' <= (chr) && (chr) <= 'Z') || ('a' <= (chr) && (chr) <= 'z') || \
('0' <= (chr) && (chr) <= '9') || (chr) == '.' || (chr) == '_' || \
(chr) == '-')
-extern struct hstr vfs_ddot;
-extern struct hstr vfs_dot;
-
typedef uint32_t inode_t;
struct v_dnode;
struct v_inode;
struct v_superblock;
struct v_file;
+struct v_file_ops;
+struct v_inode_ops;
struct v_fd;
struct pcache;
+extern struct v_file_ops default_file_ops;
+extern struct v_inode_ops default_inode_ops;
+
+extern struct hstr vfs_ddot;
+extern struct hstr vfs_dot;
+extern struct v_dnode* vfs_sysroot;
+
struct filesystem
{
struct hlist_node fs_list;
struct hstr fs_name;
uint32_t types;
- int fs_id; // can be used to detect fs type on partition
+ int fs_id;
int (*mount)(struct v_superblock* vsb, struct v_dnode* mount_point);
int (*unmount)(struct v_superblock* vsb);
};
{
uint32_t (*read_capacity)(struct v_superblock* vsb);
uint32_t (*read_usage)(struct v_superblock* vsb);
+ void (*init_inode)(struct v_superblock* vsb, struct v_inode* inode);
} ops;
};
{
int (*write)(struct v_inode* inode, void* buffer, size_t len, size_t fpos);
int (*read)(struct v_inode* inode, void* buffer, size_t len, size_t fpos);
- int (*readdir)(struct v_inode* inode, struct dir_context* dctx);
+ int (*readdir)(struct v_file* file, struct dir_context* dctx);
int (*seek)(struct v_inode* inode, size_t offset);
int (*close)(struct v_file* file);
- int (*sync)(struct v_inode* inode);
+ int (*sync)(struct v_file* file);
+};
+
+struct v_inode_ops
+{
+ int (*create)(struct v_inode* this, struct v_dnode* dnode);
+ int (*open)(struct v_inode* this, struct v_file* file);
+ int (*sync)(struct v_inode* this);
+ int (*mkdir)(struct v_inode* this, struct v_dnode* dnode);
+ int (*rmdir)(struct v_inode* this, struct v_dnode* dir);
+ int (*unlink)(struct v_inode* this);
+ int (*link)(struct v_inode* this, struct v_dnode* new_name);
+ int (*read_symlink)(struct v_inode* this, const char** path_out);
+ int (*set_symlink)(struct v_inode* this, const char* target);
+ int (*dir_lookup)(struct v_inode* this, struct v_dnode* dnode);
+ int (*rename)(struct v_inode* from_inode,
+ struct v_dnode* from_dnode,
+ struct v_dnode* to_dnode);
};
struct v_file
struct llist_header* f_list;
uint32_t f_pos;
atomic_ulong ref_count;
- struct v_file_ops ops;
+ struct v_file_ops* ops; // for caching
};
struct v_fd
uint32_t link_count;
uint32_t lb_usage;
uint32_t fsize;
+ struct v_superblock* sb;
struct hlist_node hash_list;
struct lru_node lru;
struct pcache* pg_cache;
void* data; // 允许底层FS绑定他的一些专有数据
- struct
- {
- int (*create)(struct v_inode* this, struct v_dnode* dnode);
- int (*open)(struct v_inode* this, struct v_file* file);
- int (*sync)(struct v_inode* this);
- int (*mkdir)(struct v_inode* this, struct v_dnode* dnode);
- int (*rmdir)(struct v_inode* this, struct v_dnode* dir);
- int (*unlink)(struct v_inode* this);
- int (*link)(struct v_inode* this, struct v_dnode* new_name);
- int (*read_symlink)(struct v_inode* this, const char** path_out);
- int (*set_symlink)(struct v_inode* this, const char* target);
- int (*dir_lookup)(struct v_inode* this, struct v_dnode* dnode);
- int (*rename)(struct v_inode* from_inode,
- struct v_dnode* from_dnode,
- struct v_dnode* to_dnode);
- } ops;
- struct v_file_ops default_fops;
+ struct v_inode_ops* ops;
+ struct v_file_ops* default_fops;
};
struct v_mount
void
fsm_init();
+void
+fsm_register_all();
+
+struct filesystem*
+fsm_new_fs(char* name, size_t name_len);
+
void
fsm_register(struct filesystem* fs);
vfs_d_free(struct v_dnode* dnode);
struct v_inode*
-vfs_i_alloc(struct v_superblock* sb,
- uint32_t inode_id,
- void (*init)(struct v_inode* inode, void* data),
- void* data);
+vfs_i_find(struct v_superblock* sb, uint32_t i_id);
+
+void
+vfs_i_addhash(struct v_inode* inode);
+
+struct v_inode*
+vfs_i_alloc(struct v_superblock* sb);
void
vfs_i_free(struct v_inode* inode);
void
mnt_chillax(struct v_mount* mnt);
+int
+vfs_mount_root(const char* fs_name, struct device* device);
+
struct v_mount*
vfs_create_mount(struct v_mount* parent, struct v_dnode* mnt_point);
+
+int
+default_file_read(struct v_inode* inode, void* buffer, size_t len, size_t fpos);
+
+int
+default_file_write(struct v_inode* inode,
+ void* buffer,
+ size_t len,
+ size_t fpos);
+
+int
+default_file_readdir(struct v_file* file, struct dir_context* dctx);
+
+int
+default_inode_dirlookup(struct v_inode* this, struct v_dnode* dnode);
+
+int
+default_inode_rename(struct v_inode* from_inode,
+ struct v_dnode* from_dnode,
+ struct v_dnode* to_dnode);
+
+int
+default_file_close(struct v_file* file);
+
+int
+default_file_seek(struct v_inode* inode, size_t offset);
+
+int
+default_inode_open(struct v_inode* this, struct v_file* file);
+
+int
+default_inode_rmdir(struct v_inode* this, struct v_dnode* dir);
+
+int
+default_inode_mkdir(struct v_inode* this, struct v_dnode* dir);
+
#endif /* __LUNAIX_VFS_H */
--- /dev/null
+#ifndef __LUNAIX_RAMFS_H
+#define __LUNAIX_RAMFS_H
+
+void
+ramfs_init();
+
+#endif /* __LUNAIX_RAMFS_H */
void
panick(const char* msg);
+void
+panickf(const char* fmt, ...);
+
#define wait_until(cond) \
while (!(cond)) \
;
struct dirent ent = { .d_offset = 0 };
- while (!readdir(fd, &ent)) {
+ while (readdir(fd, &ent) == 1) {
kprintf(KINFO "%s\n", ent.d_name);
}
--- /dev/null
+#include <lunaix/fs.h>
+
+int
+default_file_close(struct v_file* file)
+{
+ return 0;
+}
+
+int
+default_file_seek(struct v_inode* inode, size_t offset)
+{
+ return 0;
+}
+
+int
+default_inode_open(struct v_inode* this, struct v_file* file)
+{
+ return 0;
+}
+
+int
+default_file_read(struct v_inode* inode, void* buffer, size_t len, size_t fpos)
+{
+ return ENOTSUP;
+}
+
+int
+default_file_write(struct v_inode* inode, void* buffer, size_t len, size_t fpos)
+{
+ return ENOTSUP;
+}
+
+int
+default_file_readdir(struct v_file* file, struct dir_context* dctx)
+{
+ int i = 0;
+ struct v_dnode *pos, *n;
+ llist_for_each(pos, n, &file->dnode->children, siblings)
+ {
+ if (i < dctx->index) {
+ i++;
+ continue;
+ }
+ dctx->read_complete_callback(dctx, pos->name.value, pos->name.len, 0);
+ break;
+ }
+}
+
+int
+default_inode_dirlookup(struct v_inode* this, struct v_dnode* dnode)
+{
+ return ENOENT;
+}
+
+int
+default_inode_rename(struct v_inode* from_inode,
+ struct v_dnode* from_dnode,
+ struct v_dnode* to_dnode)
+{
+ return 0;
+}
+
+int
+default_inode_sync(struct v_inode* this)
+{
+ return 0;
+}
+
+int
+default_inode_rmdir(struct v_inode* this, struct v_dnode* dir)
+{
+ return ENOTSUP;
+}
+
+int
+default_inode_mkdir(struct v_inode* this, struct v_dnode* dir)
+{
+ return ENOTSUP;
+}
+
+struct v_file_ops default_file_ops = { .close = default_file_close,
+ .read = default_file_read,
+ .seek = default_file_seek,
+ .readdir = default_file_readdir };
+
+struct v_inode_ops default_inode_ops = { .dir_lookup = default_inode_dirlookup,
+ .sync = default_inode_sync,
+ .open = default_inode_open,
+ .rename = default_inode_rename,
+ .rmdir = default_inode_rmdir };
\ No newline at end of file
--- /dev/null
+#include <lunaix/fs.h>
+#include <lunaix/fs/ramfs.h>
+#include <lunaix/fs/twifs.h>
+
+void
+fsm_register_all()
+{
+ ramfs_init();
+ twifs_init();
+ // Add more fs implementation
+}
\ No newline at end of file
#include <klibc/string.h>
#include <lunaix/ds/hashtable.h>
#include <lunaix/fs.h>
+#include <lunaix/mm/valloc.h>
#define HASH_BUCKET_BITS 4
#define HASH_BUCKET_NUM (1 << HASH_BUCKET_BITS)
fsm_init()
{
hashtable_init(fs_registry);
+
+ fsm_register_all();
}
void
}
return NULL;
+}
+
+struct filesystem*
+fsm_new_fs(char* name, size_t name_len)
+{
+ struct filesystem* fs = vzalloc(sizeof(*fs));
+ fs->fs_name = HHSTR(name, name_len, 0);
+ return fs;
}
\ No newline at end of file
}
}
+int
+vfs_mount_root(const char* fs_name, struct device* device)
+{
+ int errno = 0;
+ if (vfs_sysroot->mnt && (errno = vfs_unmount_at(vfs_sysroot))) {
+ return errno;
+ }
+ return vfs_mount_at(fs_name, device, vfs_sysroot);
+}
+
int
vfs_mount(const char* target, const char* fs_name, struct device* device)
{
int errno;
struct v_dnode* mnt;
- if (!(errno = vfs_walk(__current->cwd, target, &mnt, NULL, 0))) {
+ if (!(errno =
+ vfs_walk(__current->cwd, target, &mnt, NULL, VFS_WALK_MKPARENT))) {
errno = vfs_mount_at(fs_name, device, mnt);
}
int errno = 0;
if (!(errno = fs->mount(sb, mnt_point))) {
+ mnt_point->super_block = sb;
sb->fs = fs;
sb->root = mnt_point;
- mnt_point->super_block = sb;
if (!(mnt_point->mnt = vfs_create_mount(parent_mnt, mnt_point))) {
errno = ENOMEM;
- vfs_sb_free(sb);
+ goto cleanup;
}
+ } else {
+ goto cleanup;
}
return errno;
+
+cleanup:
+ vfs_sb_free(sb);
+ return errno;
}
int
return errno;
}
+
+__DEFINE_LXSYSCALL3(int,
+ mount,
+ const char*,
+ source,
+ const char*,
+ target,
+ const char*,
+ fstype)
+{
+ struct v_dnode *dev, *mnt;
+ int errno = 0;
+
+ if ((errno = vfs_walk(__current->cwd, source, &dev, NULL, 0))) {
+ goto done;
+ }
+
+ if ((errno = vfs_walk(__current->cwd, target, &mnt, NULL, 0))) {
+ goto done;
+ }
+
+ if (mnt->ref_count > 1) {
+ errno = EBUSY;
+ goto done;
+ }
+
+ // By our convention.
+ // XXX could we do better?
+ struct device* device = (struct device*)dev->data;
+
+ if (!(dev->inode->itype & VFS_IFVOLDEV) || !device) {
+ errno = ENOTDEV;
+ goto done;
+ }
+
+ errno = vfs_mount_at(fstype, device, mnt);
+
+done:
+ return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL1(int, unmount, const char*, target)
+{
+ return vfs_unmount(target);
+}
\ No newline at end of file
}
// Filling up the page
- errno = inode->default_fops.read(inode, pg->pg, PG_SIZE, pg->fpos);
+ errno = inode->default_fops->read(inode, pg->pg, PG_SIZE, pg->fpos);
if (errno >= 0 && errno < PG_SIZE) {
// EOF
len = buf_off + errno;
return;
}
- int errno = inode->default_fops.write(inode, page->pg, PG_SIZE, page->fpos);
+ int errno =
+ inode->default_fops->write(inode, page->pg, PG_SIZE, page->fpos);
if (!errno) {
page->flags &= ~PCACHE_DIRTY;
--- /dev/null
+/**
+ * @file ramfs.c
+ * @author Lunaixsky
+ * @brief RamFS - a file system sit in RAM
+ * @version 0.1
+ * @date 2022-08-18
+ *
+ * @copyright Copyright (c) 2022
+ *
+ */
+#include <lunaix/fs.h>
+#include <lunaix/fs/ramfs.h>
+#include <lunaix/mm/valloc.h>
+
+/*
+ A RAM FS will play a role of being a root.
+
+ This is an temporary meaure as we don't have any concrete fs
+ yet. In the near future, we will have an ISO-9660 as our first
+ fs and mount our boot medium as root. And similar thing could
+ be done when we have installed our OS into hard disk, in that
+ case, our rootfs will be something like ext2.
+
+ RamFS vs. TwiFS: Indeed, they are both fs that lives in RAM so
+ there is no foundmentally differences. However, TwiFS is designed
+ to be a 'virtual FIlesystem for KERnel space' (FIKER), so other
+ kernel sub-modules can just create node and attach their own
+ implementation of read/write, without brothering to create a
+ full featured concrete filesystem. This particularly useful for
+ kernel state exposure. In Lunaix, TwiFS is summation of procfs,
+ sysfs and kernfs in Linux world.
+
+ However, there is a smell of bad-design in the concept of TwiFS.
+ Since it tries to integrate too much responsibility. The TwiFS may
+ be replaced by more specific fs in the future.
+
+ On the other hand, RamFS is designed to be act like a dummy fs
+ that just ensure 'something there at least' and thus provide basic
+ 'mountibility' for other fs.
+*/
+
+volatile static inode_t ino = 0;
+
+extern const struct v_inode_ops ramfs_inode_ops;
+
+int
+ramfs_readdir(struct v_file* file, struct dir_context* dctx)
+{
+ int i = 0;
+ struct v_dnode *pos, *n;
+ llist_for_each(pos, n, &file->dnode->children, siblings)
+ {
+ if (i++ >= dctx->index) {
+ dctx->read_complete_callback(
+ dctx, pos->name.value, pos->name.len, 0);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int
+ramfs_mkdir(struct v_inode* this, struct v_dnode* dnode)
+{
+ struct v_inode* inode = vfs_i_alloc(dnode->super_block);
+ inode->itype = VFS_IFDIR;
+
+ vfs_i_addhash(inode);
+ vfs_assign_inode(dnode, inode);
+
+ return 0;
+}
+
+int
+ramfs_create(struct v_inode* this, struct v_dnode* dnode)
+{
+ struct v_inode* inode = vfs_i_alloc(dnode->super_block);
+ inode->itype = VFS_IFFILE;
+
+ vfs_i_addhash(inode);
+ vfs_assign_inode(dnode, inode);
+
+ return 0;
+}
+
+void
+ramfs_inode_init(struct v_superblock* vsb, struct v_inode* inode)
+{
+ inode->id = ino++;
+ inode->ops = &ramfs_inode_ops;
+ inode->default_fops = &default_file_ops;
+}
+
+int
+ramfs_mount(struct v_superblock* vsb, struct v_dnode* mount_point)
+{
+ vsb->ops.init_inode = ramfs_inode_init;
+
+ struct v_inode* inode = vfs_i_alloc(vsb);
+ inode->itype = VFS_IFDIR;
+
+ vfs_i_addhash(inode);
+ vfs_assign_inode(mount_point, inode);
+
+ return 0;
+}
+
+int
+ramfs_unmount(struct v_superblock* vsb)
+{
+ return 0;
+}
+
+void
+ramfs_init()
+{
+ struct filesystem* ramfs = fsm_new_fs("ramfs", 5);
+ ramfs->mount = ramfs_mount;
+ ramfs->unmount = ramfs_unmount;
+
+ fsm_register(ramfs);
+}
+
+const struct v_inode_ops ramfs_inode_ops = { .mkdir = ramfs_mkdir,
+ .rmdir = default_inode_rmdir,
+ .dir_lookup =
+ default_inode_dirlookup,
+ .create = ramfs_create,
+ .open = default_inode_open,
+ .rename = default_inode_rename };
\ No newline at end of file
static struct cake_pile* twi_pile;
-static volatile int32_t inode_id = 0;
+static volatile uint32_t inode_id = 0;
-int
-__twifs_dirlookup(struct v_inode* inode, struct v_dnode* dnode);
-
-int
-__twifs_openfile(struct v_inode* inode, struct v_file* file);
-
-struct twifs_node*
-__twifs_get_node(struct twifs_node* parent, struct hstr* name);
-
-struct v_inode*
-__twifs_get_inode(struct twifs_node* twi_node);
-
-int
-__twifs_iterate_dir(struct v_inode* inode, struct dir_context* dctx);
-
-int
-__twifs_mount(struct v_superblock* vsb, struct v_dnode* mount_point);
-
-int
-__twifs_mkdir(struct v_inode* inode, struct v_dnode* dnode);
-
-int
-__twifs_rmstuff(struct v_inode* inode, struct v_dnode* dir);
-
-int
-__twifs_fwrite(struct v_inode* inode, void* buffer, size_t len, size_t fpos);
-
-int
-__twifs_fread(struct v_inode* inode, void* buffer, size_t len, size_t fpos);
-
-void
-twifs_init()
-{
- twi_pile = cake_new_pile("twifs_node", sizeof(struct twifs_node), 1, 0);
-
- struct filesystem* twifs = vzalloc(sizeof(struct filesystem));
- twifs->fs_name = HSTR("twifs", 5);
- twifs->mount = __twifs_mount;
- twifs->types = FSTYPE_ROFS;
- twifs->fs_id = 0;
-
- fsm_register(twifs);
-
- fs_root = twifs_dir_node(NULL, NULL, 0, 0);
-}
+extern const struct v_file_ops twifs_file_ops;
+extern const struct v_inode_ops twifs_inode_ops;
struct twifs_node*
__twifs_new_node(struct twifs_node* parent,
return node;
}
-int
-twifs_rm_node(struct twifs_node* node)
-{
- if ((node->itype & VFS_IFDIR) && !llist_empty(&node->children)) {
- return ENOTEMPTY;
- }
- llist_delete(&node->siblings);
- cake_release(twi_pile, node);
- return 0;
-}
-
-struct twifs_node*
-twifs_file_node(struct twifs_node* parent,
- const char* name,
- int name_len,
- uint32_t itype)
-{
- struct twifs_node* twi_node =
- __twifs_new_node(parent, name, name_len, VFS_IFFILE | itype);
-
- return twi_node;
-}
-
-struct twifs_node*
-twifs_dir_node(struct twifs_node* parent,
- const char* name,
- int name_len,
- uint32_t itype)
-{
- struct hstr hname = HSTR(name, name_len);
- hstr_rehash(&hname, HSTR_FULL_HASH);
- struct twifs_node* node = __twifs_get_node(parent, &hname);
- if (node) {
- return node;
- }
-
- struct twifs_node* twi_node =
- __twifs_new_node(parent, name, name_len, VFS_IFDIR | itype);
-
- return twi_node;
-}
-
-struct twifs_node*
-twifs_toplevel_node(const char* name, int name_len, uint32_t itype)
-{
- return twifs_dir_node(fs_root, name, name_len, itype);
-}
-
-int
-__twifs_mkdir(struct v_inode* inode, struct v_dnode* dnode)
-{
- return ENOTSUP;
-}
-
void
-__twifs_init_inode(struct v_inode* inode, void* data)
+__twifs_init_inode(struct v_superblock* vsb, struct v_inode* inode)
{
- struct twifs_node* twi_node = (struct twifs_node*)data;
-
- inode->itype = twi_node->itype;
- inode->data = twi_node;
-
- inode->ctime = clock_unixtime();
- inode->atime = inode->ctime;
- inode->mtime = inode->ctime;
-
- inode->ops.dir_lookup = __twifs_dirlookup;
- inode->ops.mkdir = __twifs_mkdir;
- inode->ops.rmdir = __twifs_rmstuff;
- inode->ops.open = __twifs_openfile;
-
- inode->default_fops = (struct v_file_ops){ .read = __twifs_fread,
- .write = __twifs_fwrite,
- .readdir = __twifs_iterate_dir };
-
- return inode;
+ inode->ops = &twifs_inode_ops;
+ inode->default_fops = &twifs_file_ops;
}
int
__twifs_mount(struct v_superblock* vsb, struct v_dnode* mount_point)
{
vsb->dev = 1;
- struct v_inode* inode =
- vfs_i_alloc(vsb, fs_root->ino_id, __twifs_init_inode, fs_root);
+ vsb->ops.init_inode = __twifs_init_inode;
+
+ struct v_inode* inode = vfs_i_alloc(vsb);
if (!inode) {
return ENOMEM;
}
+
+ inode->id = fs_root->ino_id;
+ inode->itype = fs_root->itype;
+ inode->data = fs_root;
+
+ vfs_i_addhash(inode);
vfs_assign_inode(mount_point, inode);
return 0;
}
return NULL;
}
-int
-__twifs_rmstuff(struct v_inode* inode, struct v_dnode* dir)
-{
- return ENOTSUP;
-}
-
int
__twifs_dirlookup(struct v_inode* inode, struct v_dnode* dnode)
{
struct twifs_node* child_node = __twifs_get_node(twi_node, &dnode->name);
if (child_node) {
- struct v_inode* inode = vfs_i_alloc(dnode->super_block,
- child_node->ino_id,
- __twifs_init_inode,
- child_node);
- if (!inode) {
+ struct v_inode* inode = vfs_i_find(inode->sb, child_node->ino_id);
+ if (inode) {
+ goto done;
+ }
+
+ if (!(inode = vfs_i_alloc(inode->sb))) {
return ENOENT;
}
- dnode->data = twi_node->data;
+ inode->id = child_node->ino_id;
+ inode->itype = child_node->itype;
+ inode->data = child_node;
+
+ vfs_i_addhash(inode);
+
+ done:
+ dnode->data = child_node->data;
vfs_assign_inode(dnode, inode);
return 0;
}
}
int
-__twifs_iterate_dir(struct v_inode* inode, struct dir_context* dctx)
+__twifs_iterate_dir(struct v_file* file, struct dir_context* dctx)
{
- struct twifs_node* twi_node = (struct twifs_node*)(inode->data);
+ struct twifs_node* twi_node = (struct twifs_node*)(file->inode->data);
int counter = 0;
struct twifs_node *pos, *n;
dctx->index = counter;
dctx->read_complete_callback(
dctx, pos->name.value, pos->name.len, pos->itype);
- return 0;
+ return 1;
}
}
- return 1;
+ return 0;
}
int
}
return ENOTSUP;
}
+
+int
+twifs_rm_node(struct twifs_node* node)
+{
+ if ((node->itype & VFS_IFDIR) && !llist_empty(&node->children)) {
+ return ENOTEMPTY;
+ }
+ llist_delete(&node->siblings);
+ cake_release(twi_pile, node);
+ return 0;
+}
+
+struct twifs_node*
+twifs_file_node(struct twifs_node* parent,
+ const char* name,
+ int name_len,
+ uint32_t itype)
+{
+ struct twifs_node* twi_node =
+ __twifs_new_node(parent, name, name_len, VFS_IFFILE | itype);
+
+ return twi_node;
+}
+
+struct twifs_node*
+twifs_dir_node(struct twifs_node* parent,
+ const char* name,
+ int name_len,
+ uint32_t itype)
+{
+ struct hstr hname = HSTR(name, name_len);
+ hstr_rehash(&hname, HSTR_FULL_HASH);
+ struct twifs_node* node = __twifs_get_node(parent, &hname);
+ if (node) {
+ return node;
+ }
+
+ struct twifs_node* twi_node =
+ __twifs_new_node(parent, name, name_len, VFS_IFDIR | itype);
+
+ return twi_node;
+}
+
+struct twifs_node*
+twifs_toplevel_node(const char* name, int name_len, uint32_t itype)
+{
+ return twifs_dir_node(fs_root, name, name_len, itype);
+}
+
+void
+twifs_init()
+{
+ twi_pile = cake_new_pile("twifs_node", sizeof(struct twifs_node), 1, 0);
+
+ struct filesystem* twifs = vzalloc(sizeof(struct filesystem));
+ twifs->fs_name = HSTR("twifs", 5);
+ twifs->mount = __twifs_mount;
+ twifs->types = FSTYPE_ROFS;
+ twifs->fs_id = 0;
+
+ fsm_register(twifs);
+
+ fs_root = twifs_dir_node(NULL, NULL, 0, 0);
+}
+
+const struct v_file_ops twifs_file_ops = { .close = default_file_close,
+ .read = __twifs_fread,
+ .write = __twifs_fwrite,
+ .readdir = __twifs_iterate_dir };
+
+const struct v_inode_ops twifs_inode_ops = { .dir_lookup = __twifs_dirlookup,
+ .mkdir = default_inode_mkdir,
+ .rmdir = default_inode_rmdir,
+ .open = __twifs_openfile };
\ No newline at end of file
static struct cake_pile* superblock_pile;
static struct cake_pile* fd_pile;
-static struct v_dnode* sysroot;
+struct v_dnode* vfs_sysroot;
static struct hbucket* dnode_cache;
static struct lru_zone *dnode_lru, *inode_lru;
hstr_rehash(&vfs_dot, HSTR_FULL_HASH);
// 创建一个根dnode。
- sysroot = vfs_d_alloc(NULL, &vfs_empty);
- atomic_fetch_add(&sysroot->ref_count, 1);
+ vfs_sysroot = vfs_d_alloc(NULL, &vfs_empty);
+ atomic_fetch_add(&vfs_sysroot->ref_count, 1);
}
inline struct hbucket*
if ((walk_options & VFS_WALK_FSRELATIVE) && start) {
start = start->super_block->root;
} else {
- start = sysroot;
+ start = vfs_sysroot;
+ if (!vfs_sysroot->mnt) {
+ panick("vfs: no root");
+ }
}
i++;
}
goto error;
}
- lock_inode(current_level->inode);
+ struct v_inode* current_inode = current_level->inode;
- errno =
- current_level->inode->ops.dir_lookup(current_level->inode, dnode);
+ lock_inode(current_inode);
+
+ errno = current_inode->ops->dir_lookup(current_inode, dnode);
if (errno == ENOENT && (walk_options & VFS_WALK_MKPARENT)) {
- if (!current_level->inode->ops.mkdir) {
+ if (!current_inode->ops->mkdir) {
errno = ENOTSUP;
} else {
- errno = current_level->inode->ops.mkdir(
- current_level->inode, dnode);
+ errno = current_inode->ops->mkdir(current_inode, dnode);
}
}
vfs_dcache_add(current_level, dnode);
- unlock_inode(current_level->inode);
+ unlock_inode(current_inode);
if (errno) {
unlock_dnode(current_level);
int errno = __vfs_walk(start, path, &interim, component, options);
int counter = 0;
+ // FIXME This is NOT a correct way to resolve symlink!
while (!errno && interim->inode && (options & VFS_WALK_NOFOLLOW)) {
if (counter >= VFS_MAX_SYMLINK) {
errno = ELOOP;
continue;
}
if ((interim->inode->itype & VFS_IFSYMLINK) &&
- interim->inode->ops.read_symlink) {
+ interim->inode->ops->read_symlink) {
lock_inode(interim->inode);
- errno = interim->inode->ops.read_symlink(interim->inode, &pathname);
+ errno =
+ interim->inode->ops->read_symlink(interim->inode, &pathname);
unlock_inode(interim->inode);
if (errno) {
int
vfs_open(struct v_dnode* dnode, struct v_file** file)
{
- if (!dnode->inode || !dnode->inode->ops.open) {
+ if (!dnode->inode || !dnode->inode->ops->open) {
return ENOTSUP;
}
inode->pg_cache = pcache;
}
- int errno = inode->ops.open(inode, vfile);
+ int errno = inode->ops->open(inode, vfile);
if (errno) {
cake_release(file_pile, vfile);
} else {
lock_inode(to_link->inode);
if (to_link->super_block->root != name->super_block->root) {
errno = EXDEV;
- } else if (!to_link->inode->ops.link) {
+ } else if (!to_link->inode->ops->link) {
errno = ENOTSUP;
- } else if (!(errno = to_link->inode->ops.link(to_link->inode, name))) {
+ } else if (!(errno = to_link->inode->ops->link(to_link->inode, name))) {
vfs_assign_inode(name, to_link->inode);
}
unlock_inode(to_link->inode);
vfs_close(struct v_file* file)
{
int errno = 0;
- if (!file->ops.close || !(errno = file->ops.close(file))) {
+ if (!(errno = file->ops->close(file))) {
atomic_fetch_sub(&file->dnode->ref_count, 1);
file->inode->open_count--;
mnt_chillax(file->dnode->mnt);
int errno = ENOTSUP;
pcache_commit_all(file->inode);
- if (file->ops.sync) {
- errno = file->ops.sync(file->inode);
+
+ if (file->ops->sync) {
+ errno = file->ops->sync(file);
}
unlock_inode(file->inode);
}
struct v_inode*
-vfs_i_alloc(struct v_superblock* sb,
- uint32_t inode_id,
- void (*init)(struct v_inode* inode, void* data),
- void* data)
+vfs_i_find(struct v_superblock* sb, uint32_t i_id)
{
- // 每个超级块儿维护一个inode缓存哈希表。
- // 他们的hash value自然就是inode id了。
- struct hbucket* slot = &sb->i_cache[inode_id & VFS_HASH_MASK];
+ struct hbucket* slot = &sb->i_cache[i_id & VFS_HASH_MASK];
struct v_inode *pos, *n;
hashtable_bucket_foreach(slot, pos, n, hash_list)
{
- if (pos->id == inode_id) {
- goto done;
+ if (pos->id == i_id) {
+ lru_use_one(inode_lru, &pos->lru);
+ return pos;
}
}
- if (!(pos = cake_grab(inode_pile))) {
+ return NULL;
+}
+
+void
+vfs_i_addhash(struct v_inode* inode)
+{
+ struct hbucket* slot = &inode->sb->i_cache[inode->id & VFS_HASH_MASK];
+
+ hlist_delete(&inode->hash_list);
+ hlist_add(&slot->head, &inode->hash_list);
+}
+
+struct v_inode*
+vfs_i_alloc(struct v_superblock* sb)
+{
+ assert(sb->ops.init_inode);
+
+ struct v_inode* inode;
+ if (!(inode = cake_grab(inode_pile))) {
lru_evict_half(inode_lru);
- if (!(pos = cake_grab(inode_pile))) {
+ if (!(inode = cake_grab(inode_pile))) {
return NULL;
}
}
- memset(pos, 0, sizeof(*pos));
-
- pos->id = inode_id;
+ memset(inode, 0, sizeof(*inode));
+ mutex_init(&inode->lock);
- mutex_init(&pos->lock);
+ sb->ops.init_inode(sb, inode);
- init(pos, data);
-
- hlist_add(&slot->head, &pos->hash_list);
+ inode->sb = sb;
+ inode->ctime = clock_unixtime();
+ inode->atime = inode->ctime;
+ inode->mtime = inode->ctime;
done:
- lru_use_one(inode_lru, &pos->lru);
- return pos;
+ lru_use_one(inode_lru, &inode->lru);
+ return inode;
}
void
pcache_release(inode->pg_cache);
vfree(inode->pg_cache);
}
- inode->ops.sync(inode);
+ inode->ops->sync(inode);
hlist_delete(&inode->hash_list);
cake_release(inode_pile, inode);
}
#define FLOCATE_CREATE_EMPTY 1
-#define DO_STATUS(errno) SYSCALL_ESTATUS(__current->k_status = errno)
-#define DO_STATUS_OR_RETURN(errno) ({ errno < 0 ? DO_STATUS(errno) : errno; })
-
-#define TEST_FD(fd) (fd >= 0 && fd < VFS_MAX_FD)
-
int
__vfs_getfd(int fd, struct v_fd** fd_s)
{
lock_dnode(parent);
- if (!(errno = parent->inode->ops.create(parent->inode, file_new))) {
+ if (!(errno = parent->inode->ops->create(parent->inode, file_new))) {
vfs_dcache_add(parent, file_new);
*file = file_new;
} else {
}
struct v_inode* o_inode = ofile->inode;
- if (!(o_inode->itype & VFS_IFSEQDEV) && !(options & FO_DIRECT)) {
- // XXX Change here accordingly when signature of pcache_r/w changed.
- ofile->ops.read = pcache_read;
- ofile->ops.write = pcache_write;
- }
if (!errno && !(errno = vfs_alloc_fdslot(&fd))) {
struct v_fd* fd_s = vzalloc(sizeof(*fd_s));
lock_inode(inode);
- if (!(fd_s->file->inode->itype & VFS_IFDIR)) {
+ if (!(inode->itype & VFS_IFDIR)) {
errno = ENOTDIR;
} else {
struct dir_context dctx =
.index = dent->d_offset,
.read_complete_callback =
__vfs_readdir_callback };
+ errno = 1;
if (dent->d_offset == 0) {
__vfs_readdir_callback(&dctx, vfs_dot.value, vfs_dot.len, 0);
} else if (dent->d_offset == 1) {
__vfs_readdir_callback(&dctx, vfs_ddot.value, vfs_ddot.len, 0);
} else {
dctx.index -= 2;
- if ((errno = fd_s->file->ops.readdir(inode, &dctx))) {
+ if ((errno = fd_s->file->ops->readdir(fd_s->file, &dctx)) != 1) {
unlock_inode(inode);
goto done;
}
}
- errno = 0;
dent->d_offset++;
}
unlock_inode(inode);
done:
- return DO_STATUS(errno);
+ return DO_STATUS_OR_RETURN(errno);
}
__DEFINE_LXSYSCALL3(int, read, int, fd, void*, buf, size_t, count)
file->inode->atime = clock_unixtime();
- __SYSCALL_INTERRUPTIBLE(
- { errno = file->ops.read(file->inode, buf, count, file->f_pos); })
+ __SYSCALL_INTERRUPTIBLE({
+ if ((file->inode->itype & VFS_IFSEQDEV) || (fd_s->flags & FO_DIRECT)) {
+ errno = file->ops->read(file->inode, buf, count, file->f_pos);
+ } else {
+ errno = pcache_read(file->inode, buf, count, file->f_pos);
+ }
+ })
if (errno > 0) {
file->f_pos += errno;
file->inode->mtime = clock_unixtime();
- __SYSCALL_INTERRUPTIBLE(
- { errno = file->ops.write(file->inode, buf, count, file->f_pos); })
+ __SYSCALL_INTERRUPTIBLE({
+ if ((file->inode->itype & VFS_IFSEQDEV) || (fd_s->flags & FO_DIRECT)) {
+ errno = file->ops->write(file->inode, buf, count, file->f_pos);
+ } else {
+ errno = pcache_write(file->inode, buf, count, file->f_pos);
+ }
+ })
if (errno > 0) {
file->f_pos += errno;
fpos = offset;
break;
}
- if (!file->ops.seek || !(errno = file->ops.seek(file->inode, fpos))) {
+ if (!(errno = file->ops->seek(file->inode, fpos))) {
file->f_pos = fpos;
}
{
const char* link;
struct v_inode* inode = dnode->inode;
- if (inode->ops.read_symlink) {
+ if (inode->ops->read_symlink) {
lock_inode(inode);
- int errno = inode->ops.read_symlink(inode, &link);
+ int errno = inode->ops->read_symlink(inode, &link);
strncpy(buf, link, size);
unlock_inode(inode);
lock_inode(parent->inode);
if ((dnode->inode->itype & VFS_IFDIR)) {
- errno = parent->inode->ops.rmdir(parent->inode, dnode);
+ errno = parent->inode->ops->rmdir(parent->inode, dnode);
if (!errno) {
vfs_dcache_remove(dnode);
}
if ((parent->super_block->fs->types & FSTYPE_ROFS)) {
errno = ENOTSUP;
- } else if (!parent->inode->ops.mkdir) {
+ } else if (!parent->inode->ops->mkdir) {
errno = ENOTSUP;
} else if (!(parent->inode->itype & VFS_IFDIR)) {
errno = ENOTDIR;
- } else if (!(errno = parent->inode->ops.mkdir(parent->inode, dir))) {
+ } else if (!(errno = parent->inode->ops->mkdir(parent->inode, dir))) {
vfs_dcache_add(parent, dir);
goto cleanup;
}
} else if (!(inode->itype & VFS_IFDIR)) {
// The underlying unlink implementation should handle
// symlink case
- errno = inode->ops.unlink(inode);
+ errno = inode->ops->unlink(inode);
if (!errno) {
vfs_d_free(dnode);
}
errno = EROFS;
goto done;
}
- if (!dnode->inode->ops.set_symlink) {
+ if (!dnode->inode->ops->set_symlink) {
errno = ENOTSUP;
goto done;
}
lock_inode(dnode->inode);
- errno = dnode->inode->ops.set_symlink(dnode->inode, link_target);
+ errno = dnode->inode->ops->set_symlink(dnode->inode, link_target);
unlock_inode(dnode->inode);
goto cleanup;
}
- if ((errno = current->inode->ops.rename(current->inode, current, target))) {
+ if ((errno =
+ current->inode->ops->rename(current->inode, current, target))) {
unlock_dnode(target);
goto cleanup;
}
done:
vfree(name.value);
return DO_STATUS(errno);
-}
-
-__DEFINE_LXSYSCALL3(int,
- mount,
- const char*,
- source,
- const char*,
- target,
- const char*,
- fstype)
-{
- struct v_dnode *dev, *mnt;
- int errno = 0;
-
- if ((errno = vfs_walk(__current->cwd, source, &dev, NULL, 0))) {
- goto done;
- }
-
- if ((errno = vfs_walk(__current->cwd, target, &mnt, NULL, 0))) {
- goto done;
- }
-
- if (mnt->ref_count > 1) {
- errno = EBUSY;
- goto done;
- }
-
- // By our convention.
- // XXX could we do better?
- struct device* device = (struct device*)dev->data;
-
- if (!(dev->inode->itype & VFS_IFVOLDEV) || !device) {
- errno = ENOTDEV;
- goto done;
- }
-
- errno = vfs_mount_at(fstype, device, mnt);
-
-done:
- return DO_STATUS(errno);
-}
-
-__DEFINE_LXSYSCALL1(int, unmount, const char*, target)
-{
- return vfs_unmount(target);
}
\ No newline at end of file
void
_kernel_init()
{
-
+ int errno = 0;
cake_init();
valloc_init();
- fsm_init();
vfs_init();
- twifs_init();
+ fsm_init();
device_init();
- // 挂载 TwiFS 为根目录
- vfs_mount("/", "twifs", NULL);
+ if ((errno = vfs_mount_root("ramfs", NULL))) {
+ panickf("Fail to mount root. (errno=%d)", errno);
+ }
+
+ // FIXME replace with more specific fs for device.
+ vfs_mount("/dev", "twifs", NULL);
lxconsole_init();
#define USE_DEMO
// #define DEMO_SIGNAL
-// #define DEMO_READDIR
-#define DEMO_IOTEST
+#define DEMO_READDIR
+//#define DEMO_IOTEST
extern void
_pconsole_main();
asm("int %0" ::"i"(LUNAIX_SYS_PANIC), "D"(msg));
spin();
}
+
+void
+panickf(const char* fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ __sprintf_internal(buffer, fmt, 1024, args);
+ va_end(args);
+
+ asm("int %0" ::"i"(LUNAIX_SYS_PANIC), "D"(buffer));
+ spin();
+}