device_init();
struct device*
-device_add(struct device* parent, void* underlay, char* name_fmt, ...);
+device_addseq(struct device* parent, void* underlay, char* name_fmt, ...);
+
+struct device*
+device_addvol(struct device* parent, void* underlay, char* name_fmt, ...);
void
device_remove(struct device* dev);
#include <hal/ahci/hba.h>
#include <lunaix/block.h>
+#include <lunaix/clock.h>
#include <lunaix/ds/btrie.h>
#include <lunaix/ds/hashtable.h>
#include <lunaix/ds/hstr.h>
#define VFS_NAME_MAXLEN 128
#define VFS_MAX_FD 32
-#define VFS_INODE_TYPE_DIR 0x1
-#define VFS_INODE_TYPE_FILE 0x2
-#define VFS_INODE_TYPE_DEVICE 0x4
-#define VFS_INODE_TYPE_SYMLINK 0x8
+#define VFS_IFDIR 0x1
+#define VFS_IFFILE 0x2
+#define VFS_IFSEQDEV 0x4
+#define VFS_IFVOLDEV 0x8
+#define VFS_IFSYMLINK 0x16
#define VFS_WALK_MKPARENT 0x1
#define VFS_WALK_FSRELATIVE 0x2
struct v_inode
{
uint32_t itype;
- uint32_t ctime;
- uint32_t mtime;
- uint64_t lb_addr;
+ time_t ctime;
+ time_t mtime;
+ time_t atime;
+ lba_t lb_addr;
uint32_t open_count;
uint32_t link_count;
uint32_t lb_usage;
int (*symlink)(struct v_inode* this, const char* target);
int (*dir_lookup)(struct v_inode* this, struct v_dnode* dnode);
} ops;
+ struct v_file_ops default_fops;
};
struct v_dnode
struct pcache_pg** page);
int
-pcache_write(struct v_file* file, void* data, uint32_t len);
+pcache_write(struct v_file* file, void* data, uint32_t len, uint32_t fpos);
int
-pcache_read(struct v_file* file, void* data, uint32_t len);
+pcache_read(struct v_file* file, void* data, uint32_t len, uint32_t fpos);
void
pcache_release(struct pcache* pcache);
uint32_t itype;
struct llist_header children;
struct llist_header siblings;
- struct v_file_ops fops;
+ struct
+ {
+ int (*write)(struct v_file* file,
+ void* buffer,
+ size_t len,
+ size_t fpos);
+ int (*read)(struct v_file* file, void* buffer, size_t len, size_t fpos);
+ } ops;
};
void
twifs_init();
struct twifs_node*
-twifs_file_node(struct twifs_node* parent, const char* name, int name_len);
+twifs_file_node(struct twifs_node* parent,
+ const char* name,
+ int name_len,
+ uint32_t itype);
struct twifs_node*
-twifs_dir_node(struct twifs_node* parent, const char* name, int name_len);
+twifs_dir_node(struct twifs_node* parent,
+ const char* name,
+ int name_len,
+ uint32_t itype);
struct twifs_node*
-twifs_toplevel_node(const char* name, int name_len);
+twifs_toplevel_node(const char* name, int name_len, uint32_t itype);
int
twifs_rm_node(struct twifs_node* node);
#ifndef __LUNAIX_CONSOLE_H
#define __LUNAIX_CONSOLE_H
-#include <lunaix/ds/fifobuf.h>
+#include <lunaix/ds/fifo.h>
#include <lunaix/timer.h>
struct console
// TODO: WTERMSIG
typedef int32_t pid_t;
+typedef int64_t lba_t;
#endif /* __LUNAIX_TYPES_H */
return 0;
}
- struct device* dev = device_add(NULL, bdev, "sd%c", 'a' + free_slot);
+ struct device* dev = device_addvol(NULL, bdev, "sd%c", 'a' + free_slot);
dev->write = __block_write;
dev->read = __block_read;
"There were two regal sisters who ruled together "
"and created harmony for all the land.";
- int fd = open("/dev/sda", 0); // sda 设备 - 硬盘
+ // sda 设备 - 硬盘
+ // sda设备属于容积设备(Volumetric Device),
+ // Lunaix会尽可能缓存任何对此设备的上层读写,并使用延迟写入策略。(FO_DIRECT可用于屏蔽该功能)
+ int fd = open("/dev/sda", 0);
- // tty 设备 - 控制台,使用O_DIRECT打开,即所有IO绕过Lunaix内核的缓存机制
- int tty = open("/dev/tty", FO_DIRECT);
+ // tty 设备 - 控制台。
+ // tty设备属于序列设备(Sequential Device),该类型设备的上层读写
+ // 无须经过Lunaix的缓存层,而是直接下发到底层驱动。(不受FO_DIRECT的影响)
+ int tty = open("/dev/tty", 0);
if (fd < 0 || tty < 0) {
kprintf(KERROR "fail to open (%d)\n", geterrno());
// 移动指针至512字节,在大多数情况下,这是第二个逻辑扇区的起始处
lseek(fd, 512, FSEEK_SET);
- write(fd, test_sequence, sizeof(test_sequence));
+
+ // 总共写入 64 * 136 字节,会产生3个页作为缓存
+ for (size_t i = 0; i < 64; i++) {
+ write(fd, test_sequence, sizeof(test_sequence));
+ }
+
lseek(fd, 521, FSEEK_SET);
write(fd, test_sequence, sizeof(test_sequence));
write(tty, read_out, sizeof(read_out));
write(tty, "\n", 1);
+ // 关闭文件,这同时会将页缓存中的数据下发到底层驱动
close(fd);
close(tty);
void
device_init()
{
- dev_root = twifs_toplevel_node("dev", 3);
+ dev_root = twifs_toplevel_node("dev", 3, 0);
llist_init_head(&dev_list);
}
struct device*
-device_add(struct device* parent, void* underlay, char* name_fmt, ...)
+__device_add(struct device* parent,
+ void* underlay,
+ char* name_fmt,
+ uint32_t type,
+ va_list args)
{
struct device* dev = vzalloc(sizeof(struct device));
- va_list args;
- va_start(args, name_fmt);
-
size_t strlen =
__sprintf_internal(dev->name_val, name_fmt, DEVICE_NAME_SIZE, args);
llist_append(&dev_list, &dev->dev_list);
struct twifs_node* dev_node =
- twifs_file_node(dev_root, dev->name_val, strlen);
+ twifs_file_node(dev_root, dev->name_val, strlen, type);
dev_node->data = dev;
- dev_node->fops.read = __dev_read;
- dev_node->fops.write = __dev_write;
+ dev_node->ops.read = __dev_read;
+ dev_node->ops.write = __dev_write;
dev->fs_node = dev_node;
+ return dev;
+}
+
+struct device*
+device_addseq(struct device* parent, void* underlay, char* name_fmt, ...)
+{
+ va_list args;
+ va_start(args, name_fmt);
+
+ struct device* dev =
+ __device_add(parent, underlay, name_fmt, VFS_IFSEQDEV, args);
+
+ va_end(args);
+ return dev;
+}
+
+struct device*
+device_addvol(struct device* parent, void* underlay, char* name_fmt, ...)
+{
+ va_list args;
+ va_start(args, name_fmt);
+
+ struct device* dev =
+ __device_add(parent, underlay, name_fmt, VFS_IFVOLDEV, args);
+
va_end(args);
return dev;
}
struct btrie_node* tree = root->btrie_root;
// Time complexity: O(log_2(log_2(N))) where N is the index to lookup
- while (lz && tree) {
+ while (bitmask && tree) {
i = (index & bitmask) >> lz;
struct btrie_node *subtree = 0, *pos, *n;
{
btrie->btrie_root = vzalloc(sizeof(struct btrie_node));
llist_init_head(&btrie->btrie_root->nodes);
+ llist_init_head(&btrie->btrie_root->children);
btrie->truncated = trunc_bits;
}
{
void* pg = pmm_alloc_page(KERNEL_PID, 0);
void* pg_v = vmm_vmap(pg, PG_SIZE, PG_PREM_URW);
- struct pcache_pg* ppg = valloc(sizeof(struct pcache_pg));
+ struct pcache_pg* ppg = vzalloc(sizeof(struct pcache_pg));
ppg->pg = pg_v;
llist_append(&pcache->pages, &ppg->pg_list);
}
int
-pcache_write(struct v_file* file, void* data, uint32_t len)
+pcache_write(struct v_file* file, void* data, uint32_t len, uint32_t fpos)
{
- uint32_t pg_off, buf_off = 0, fpos = file->f_pos;
+ uint32_t pg_off, buf_off = 0;
struct pcache* pcache = file->inode->pg_cache;
struct pcache_pg* pg;
}
int
-pcache_read(struct v_file* file, void* data, uint32_t len)
+pcache_read(struct v_file* file, void* data, uint32_t len, uint32_t fpos)
{
- uint32_t pg_off, buf_off = 0, new_pg = 0, fpos = file->f_pos;
+ uint32_t pg_off, buf_off = 0, new_pg = 0;
int errno = 0;
struct pcache* pcache = file->inode->pg_cache;
struct pcache_pg* pg;
+ struct v_inode* inode = file->inode;
while (buf_off < len) {
if (pcache_get_page(pcache, fpos, &pg_off, &pg)) {
// Filling up the page
- errno = file->ops.read(file, pg->pg, PG_SIZE, pg->fpos);
- if (errno > 0 && errno < PG_SIZE) {
+ errno = inode->default_fops.read(file, pg->pg, PG_SIZE, pg->fpos);
+ if (errno >= 0 && errno < PG_SIZE) {
// EOF
len = buf_off + errno;
} else if (errno < 0) {
return;
}
- int errno = file->ops.write(file, page->pg, PG_SIZE, page->fpos);
+ struct v_inode* inode = file->inode;
+ int errno = inode->default_fops.write(file, page->pg, PG_SIZE, page->fpos);
if (!errno) {
page->flags &= ~PCACHE_DIRTY;
int
__twifs_rmstuff(struct v_inode* inode);
+int
+__twifs_fwrite(struct v_file* file, void* buffer, size_t len, size_t fpos);
+
+int
+__twifs_fread(struct v_file* file, void* buffer, size_t len, size_t fpos);
+
void
twifs_init()
{
fsm_register(twifs);
- fs_root = twifs_dir_node(NULL, NULL, 0);
+ fs_root = twifs_dir_node(NULL, NULL, 0, 0);
}
struct twifs_node*
-__twifs_new_node(struct twifs_node* parent, const char* name, int name_len)
+__twifs_new_node(struct twifs_node* parent,
+ const char* name,
+ int name_len,
+ uint32_t itype)
{
struct twifs_node* node = cake_grab(twi_pile);
memset(node, 0, sizeof(*node));
node->name = HSTR(name, name_len);
+ node->itype = itype;
hstr_rehash(&node->name, HSTR_FULL_HASH);
llist_init_head(&node->children);
int
twifs_rm_node(struct twifs_node* node)
{
- if ((node->itype & VFS_INODE_TYPE_DIR) && !llist_empty(&node->children)) {
+ if ((node->itype & VFS_IFDIR) && !llist_empty(&node->children)) {
return ENOTEMPTY;
}
llist_delete(&node->siblings);
}
struct twifs_node*
-twifs_file_node(struct twifs_node* parent, const char* name, int name_len)
+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);
- twi_node->itype = VFS_INODE_TYPE_FILE;
+ struct twifs_node* twi_node =
+ __twifs_new_node(parent, name, name_len, VFS_IFFILE | itype);
struct v_inode* twi_inode = __twifs_create_inode(twi_node);
twi_node->inode = twi_inode;
}
struct twifs_node*
-twifs_dir_node(struct twifs_node* parent, const char* name, int name_len)
+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);
return node;
}
- struct twifs_node* twi_node = __twifs_new_node(parent, name, name_len);
- twi_node->itype = VFS_INODE_TYPE_DIR;
+ struct twifs_node* twi_node =
+ __twifs_new_node(parent, name, name_len, VFS_IFDIR | itype);
struct v_inode* twi_inode = __twifs_create_inode(twi_node);
- twi_node->fops.readdir = __twifs_iterate_dir;
twi_node->inode = twi_inode;
return twi_node;
}
struct twifs_node*
-twifs_toplevel_node(const char* name, int name_len)
+twifs_toplevel_node(const char* name, int name_len, uint32_t itype)
{
- return twifs_dir_node(fs_root, name, name_len);
+ return twifs_dir_node(fs_root, name, name_len, itype);
}
int
__twifs_mkdir(struct v_inode* inode, struct v_dnode* dnode)
{
struct twifs_node* parent_node = (struct twifs_node*)inode->data;
- if (!(parent_node->itype & VFS_INODE_TYPE_DIR)) {
+ if (!(parent_node->itype & VFS_IFDIR)) {
return ENOTDIR;
}
struct twifs_node* new_node =
- twifs_dir_node(parent_node, dnode->name.value, dnode->name.len);
+ twifs_dir_node(parent_node, dnode->name.value, dnode->name.len, 0);
dnode->inode = new_node->inode;
return 0;
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;
}
+int
+__twifs_fwrite(struct v_file* file, void* buffer, size_t len, size_t fpos)
+{
+ struct twifs_node* twi_node = (struct twifs_node*)file->inode->data;
+ if (!twi_node || !twi_node->ops.write) {
+ return ENOTSUP;
+ }
+ return twi_node->ops.write(file, buffer, len, fpos);
+}
+
+int
+__twifs_fread(struct v_file* file, void* buffer, size_t len, size_t fpos)
+{
+ struct twifs_node* twi_node = (struct twifs_node*)file->inode->data;
+ if (!twi_node || !twi_node->ops.read) {
+ return ENOTSUP;
+ }
+ return twi_node->ops.read(file, buffer, len, fpos);
+}
+
struct twifs_node*
__twifs_get_node(struct twifs_node* parent, struct hstr* name)
{
{
struct twifs_node* twi_node = (struct twifs_node*)inode->data;
- if (!(twi_node->itype & VFS_INODE_TYPE_DIR)) {
+ if (!(twi_node->itype & VFS_IFDIR)) {
return ENOTDIR;
}
{
struct twifs_node* twi_node = (struct twifs_node*)inode->data;
if (twi_node) {
- file->inode = twi_node->inode;
- file->ops = twi_node->fops;
return 0;
}
return ENOTSUP;
// 创建一个根superblock,用来蕴含我们的根目录。
root_sb = vfs_sb_alloc();
root_sb->root = vfs_d_alloc();
+ root_sb->root->inode = vfs_i_alloc();
}
inline struct hbucket*
errno = ELOOP;
continue;
}
- if ((interim->inode->itype & VFS_INODE_TYPE_SYMLINK) &&
+ if ((interim->inode->itype & VFS_IFSYMLINK) &&
!(options & VFS_WALK_NOFOLLOW) &&
interim->inode->ops.read_symlink) {
errno = interim->inode->ops.read_symlink(interim->inode, &pathname);
return ENOTSUP;
}
+ struct v_inode* inode = dnode->inode;
struct v_file* vfile = cake_grab(file_pile);
memset(vfile, 0, sizeof(*vfile));
vfile->dnode = dnode;
- vfile->inode = dnode->inode;
+ vfile->inode = inode;
vfile->ref_count = 1;
- dnode->inode->open_count++;
+ vfile->ops = inode->default_fops;
+ inode->open_count++;
- if ((dnode->inode->itype & VFS_INODE_TYPE_FILE) &&
- !dnode->inode->pg_cache) {
+ if ((inode->itype & VFS_IFFILE) && !inode->pg_cache) {
struct pcache* pcache = vzalloc(sizeof(struct pcache));
pcache_init(pcache);
- dnode->inode->pg_cache = pcache;
+ inode->pg_cache = pcache;
}
- int errno = dnode->inode->ops.open(dnode->inode, vfile);
+ int errno = inode->ops.open(inode, vfile);
if (errno) {
cake_release(file_pile, vfile);
} else {
vfs_fsync(struct v_file* file)
{
int errno = ENOTSUP;
+ pcache_commit_all(file);
if (file->ops.sync) {
errno = file->ops.sync(file);
}
#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; })
int
__vfs_try_locate_file(const char* path,
}
int
-__vfs_do_open(struct v_file** file_out, const char* path, int options)
+__file_cached_read(struct v_file* file, void* buf, size_t len, size_t fpos)
{
- int errno;
+ return pcache_read(file, buf, len, fpos);
+}
+
+int
+vfs_do_open(const char* path, int options)
+{
+ int errno, fd;
struct v_dnode *dentry, *file;
- struct v_file* opened_file = 0;
+ struct v_file* ofile = 0;
errno = __vfs_try_locate_file(path, &dentry, &file, 0);
errno = dentry->inode->ops.create(dentry->inode);
}
- if (!errno) {
- errno = vfs_open(file, &opened_file);
+ if (!errno && (errno = vfs_open(file, &ofile))) {
+ return errno;
}
- *file_out = opened_file;
- return errno;
-}
-
-__DEFINE_LXSYSCALL2(int, open, const char*, path, int, options)
-{
- struct v_file* opened_file;
- int errno = __vfs_do_open(&opened_file, path, options), fd;
+ 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));
- opened_file->f_pos =
- opened_file->inode->fsize & -((options & FO_APPEND) != 0);
- fd_s->file = opened_file;
+ ofile->f_pos = ofile->inode->fsize & -((options & FO_APPEND) != 0);
+ fd_s->file = ofile;
fd_s->flags = options;
__current->fdtable->fds[fd] = fd_s;
return fd;
}
- return DO_STATUS(errno);
+ return errno;
+}
+
+__DEFINE_LXSYSCALL2(int, open, const char*, path, int, options)
+{
+ int errno = vfs_do_open(path, options);
+ return DO_STATUS_OR_RETURN(errno);
}
+
#define TEST_FD(fd) (fd >= 0 && fd < VFS_MAX_FD)
#define GET_FD(fd, fd_s) (TEST_FD(fd) && (fd_s = __current->fdtable->fds[fd]))
int errno;
if (!GET_FD(fd, fd_s)) {
errno = EBADF;
- } else if (!(fd_s->file->inode->itype & VFS_INODE_TYPE_DIR)) {
+ } else if (!(fd_s->file->inode->itype & VFS_IFDIR)) {
errno = ENOTDIR;
} else {
struct dir_context dctx =
errno = ENOTSUP;
} else if (!parent->inode->ops.mkdir) {
errno = ENOTSUP;
- } else if (!(parent->inode->itype & VFS_INODE_TYPE_DIR)) {
+ } else if (!(parent->inode->itype & VFS_IFDIR)) {
errno = ENOTDIR;
} else {
dir = vfs_d_alloc();
}
struct v_file* file = fd_s->file;
- if ((file->inode->itype & VFS_INODE_TYPE_DIR)) {
+ if ((file->inode->itype & VFS_IFDIR)) {
errno = EISDIR;
goto done;
}
- if ((fd_s->flags & FO_DIRECT)) {
- errno = file->ops.read(file, buf, count, file->f_pos);
- } else {
- errno = pcache_read(file, buf, count);
- }
+ errno = file->ops.read(file, buf, count, file->f_pos);
if (errno > 0) {
file->f_pos += errno;
}
struct v_file* file = fd_s->file;
- if ((file->inode->itype & VFS_INODE_TYPE_DIR)) {
+ if ((file->inode->itype & VFS_IFDIR)) {
errno = EISDIR;
goto done;
}
- if ((fd_s->flags & FO_DIRECT)) {
- errno = file->ops.write(file, buf, count, file->f_pos);
- } else {
- errno = pcache_write(file, buf, count);
- }
+ errno = file->ops.write(file, buf, count, file->f_pos);
if (errno > 0) {
file->f_pos += errno;
goto done;
}
- if ((dnode->inode->itype & VFS_INODE_TYPE_DIR)) {
+ if ((dnode->inode->itype & VFS_IFDIR)) {
errno = dnode->inode->ops.rmdir(dnode->inode);
} else {
errno = ENOTDIR;
int errno;
if (inode->open_count) {
errno = EBUSY;
- } else if (!(inode->itype & VFS_INODE_TYPE_DIR)) {
+ } else if (!(inode->itype & VFS_IFDIR)) {
// TODO handle symbolic link and type other than regular file
errno = inode->ops.unlink(inode);
if (!errno) {
lx_console.flush_timer = NULL;
- struct device* tty_dev = device_add(NULL, &lx_console, "tty");
+ struct device* tty_dev = device_addseq(NULL, &lx_console, "tty");
tty_dev->write = __tty_write;
}
char c;
int lines = 0;
+ int j = 0;
for (size_t i = 0; i < size; i++) {
c = data[i];
- buffer[(ptr + i) % console->buffer.size] = c;
+ if (!c) {
+ continue;
+ }
+ buffer[(ptr + j) % console->buffer.size] = c;
lines += (c == '\n');
+ j++;
}
+ size = j;
+
uintptr_t new_ptr = (ptr + size) % console->buffer.size;
console->buffer.wr_pos = new_ptr;
for (size_t i = 0; i < VFS_MAX_FD; i++) {
struct v_fd* fd = proc->fdtable->fds[i];
if (fd)
- vfs_close(fd);
+ vfs_close(fd->file);
}
vfree(proc->fdtable);