feat: page caching layer for vfs
authorMinep <zelong56@gmail.com>
Sat, 6 Aug 2022 17:35:00 +0000 (18:35 +0100)
committerMinep <zelong56@gmail.com>
Sat, 6 Aug 2022 17:35:00 +0000 (18:35 +0100)
refactor: replace all mem allocation with valloc
fix: read/write to block device now using byte offset value instead of sector offset

17 files changed:
lunaix-os/hal/acpi/acpi.c
lunaix-os/hal/acpi/parser/madt_parser.c
lunaix-os/hal/acpi/parser/mcfg_parser.c
lunaix-os/hal/pci.c
lunaix-os/includes/lunaix/ds/btrie.h [new file with mode: 0644]
lunaix-os/includes/lunaix/foptions.h
lunaix-os/includes/lunaix/fs.h
lunaix-os/includes/lunaix/status.h
lunaix-os/kernel/block.c
lunaix-os/kernel/demos/iotest.c
lunaix-os/kernel/device.c
lunaix-os/kernel/ds/btrie.c [new file with mode: 0644]
lunaix-os/kernel/fs/pcache.c [new file with mode: 0644]
lunaix-os/kernel/fs/twifs/twifs.c [moved from lunaix-os/kernel/fs/twifs.c with 100% similarity]
lunaix-os/kernel/fs/vfs.c
lunaix-os/kernel/mm/region.c
lunaix-os/kernel/proc0.c

index 5c1eb17d408d95af26137acc3c24e7e4524741de..55c27aea4994876ef99d7232e16f94bb45e8a709 100644 (file)
@@ -1,6 +1,6 @@
 #include <hal/acpi/acpi.h>
 
-#include <lunaix/mm/kalloc.h>
+#include <lunaix/mm/valloc.h>
 #include <lunaix/spike.h>
 #include <lunaix/syslog.h>
 
@@ -28,7 +28,7 @@ acpi_init(multiboot_info_t* mb_info)
 
     acpi_rsdt_t* rsdt = rsdp->rsdt;
 
-    ctx = lxcalloc(1, sizeof(acpi_context));
+    ctx = vzalloc(sizeof(acpi_context));
     assert_msg(ctx, "Fail to create ACPI context");
 
     strncpy(ctx->oem_id, rsdt->header.oem_id, 6);
index 971a4a0c37213079212b1b800422ca9fd763fbc3..8456b57ce9ee2efa54341f31a08aa0f9f3b72fdd 100644 (file)
@@ -1,5 +1,5 @@
 #include "parser.h"
-#include <lunaix/mm/kalloc.h>
+#include <lunaix/mm/valloc.h>
 
 void
 madt_parse(acpi_madt_t* madt, acpi_context* toc)
@@ -12,8 +12,7 @@ madt_parse(acpi_madt_t* madt, acpi_context* toc)
 
     // Cosidering only one IOAPIC present (max 24 pins)
     // FIXME: use hash table instead
-    toc->madt.irq_exception =
-      (acpi_intso_t*)lxcalloc(24, sizeof(acpi_intso_t*));
+    toc->madt.irq_exception = (acpi_intso_t*)vcalloc(24, sizeof(acpi_intso_t*));
 
     size_t so_idx = 0;
     while (ics_start < ics_end) {
index 0efe0d590ceefc954db9ad0fff1e6d508d279be3..49d04a79cb044f1aa1ba0eda7dbc1d4ab9e2b09b 100644 (file)
@@ -1,6 +1,6 @@
 #include "lunaix/syslog.h"
 #include "parser.h"
-#include <lunaix/mm/kalloc.h>
+#include <lunaix/mm/valloc.h>
 
 LOG_MODULE("MCFG")
 
@@ -13,8 +13,7 @@ mcfg_parse(acpi_sdthdr_t* mcfg, acpi_context* toc)
       (struct acpi_mcfg_alloc*)((uintptr_t)mcfg + (sizeof(acpi_sdthdr_t) + 8));
 
     toc->mcfg.alloc_num = alloc_num;
-    toc->mcfg.allocations =
-      lxmalloc(sizeof(struct mcfg_alloc_info) * alloc_num);
+    toc->mcfg.allocations = valloc(sizeof(struct mcfg_alloc_info) * alloc_num);
 
     for (size_t i = 0; i < alloc_num; i++) {
         toc->mcfg.allocations[i] = (struct mcfg_alloc_info){
index b03c128fb792335638ea425d35a664b37e239e2a..50fe80d6c109fa7ffa8e04121b7b7d65f0393cf0 100644 (file)
@@ -11,7 +11,7 @@
 #include <hal/acpi/acpi.h>
 #include <hal/apic.h>
 #include <hal/pci.h>
-#include <lunaix/mm/kalloc.h>
+#include <lunaix/mm/valloc.h>
 #include <lunaix/spike.h>
 #include <lunaix/syslog.h>
 
@@ -55,7 +55,7 @@ pci_probe_device(int bus, int dev, int funct)
     pci_reg_t intr = pci_read_cspace(base, 0x3c);
     pci_reg_t class = pci_read_cspace(base, 0x8);
 
-    struct pci_device* device = lxmalloc(sizeof(struct pci_device));
+    struct pci_device* device = valloc(sizeof(struct pci_device));
     *device = (struct pci_device){ .cspace_base = base,
                                    .class_info = class,
                                    .device_info = reg1,
diff --git a/lunaix-os/includes/lunaix/ds/btrie.h b/lunaix-os/includes/lunaix/ds/btrie.h
new file mode 100644 (file)
index 0000000..ad3d04c
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef __LUNAIX_SPARSE_H
+#define __LUNAIX_SPARSE_H
+
+#include <lunaix/ds/llist.h>
+#include <lunaix/types.h>
+
+#define BTRIE_BITS 4
+
+struct btrie
+{
+    struct btrie_node* btrie_root;
+    int truncated;
+};
+
+struct btrie_node
+{
+    struct llist_header children;
+    struct llist_header siblings;
+    struct llist_header nodes;
+    struct btrie_node* parent;
+    uint32_t index;
+    void* data;
+};
+
+void
+btrie_init(struct btrie* btrie, uint32_t trunc_bits);
+
+void*
+btrie_get(struct btrie* root, uint32_t index);
+
+void
+btrie_set(struct btrie* root, uint32_t index, void* data);
+
+void*
+btrie_remove(struct btrie* root, uint32_t index);
+
+void
+btrie_release(struct btrie* tree);
+
+#endif /* __LUNAIX_SPARSE_H */
index 00f3486f82cbb0a2d341feaeef2ae75132ecfef4..f43fb10fb884e500245fb88c72f847813895946e 100644 (file)
@@ -3,6 +3,7 @@
 
 #define FO_CREATE 0x1
 #define FO_APPEND 0x2
+#define FO_DIRECT 0x4
 
 #define FSEEK_SET 0x1
 #define FSEEK_CUR 0x2
index bc22fd537e371c13f1c7c32e39f9256726a3c26b..2d405eec00eeba31bd0e1e1af63641c77d5892e1 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <hal/ahci/hba.h>
 #include <lunaix/block.h>
+#include <lunaix/ds/btrie.h>
 #include <lunaix/ds/hashtable.h>
 #include <lunaix/ds/hstr.h>
 #include <lunaix/ds/llist.h>
 #define VFS_INODE_TYPE_DEVICE 0x4
 #define VFS_INODE_TYPE_SYMLINK 0x8
 
-#define VFS_ENOFS -2
-#define VFS_EBADMNT -3
-
-#define VFS_EENDOFDIR -5
-
-#define VFS_EINVLD -8
-#define VFS_EEOF -9
-
 #define VFS_WALK_MKPARENT 0x1
 #define VFS_WALK_FSRELATIVE 0x2
 #define VFS_WALK_PARENT 0x4
 #define VFS_WALK_NOFOLLOW 0x4
 
-#define VFS_IOBUF_FDIRTY 0x1
-
 #define FSTYPE_ROFS 0x1
 
 #define VFS_VALID_CHAR(chr)                                                    \
@@ -42,6 +33,7 @@ extern struct hstr vfs_ddot;
 extern struct hstr vfs_dot;
 
 struct v_dnode;
+struct pcache;
 
 struct filesystem
 {
@@ -79,8 +71,8 @@ struct dir_context
 
 struct v_file_ops
 {
-    int (*write)(struct v_file* file, void* buffer, size_t len);
-    int (*read)(struct v_file* file, void* buffer, size_t len);
+    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);
     int (*readdir)(struct v_file* file, struct dir_context* dctx);
     int (*seek)(struct v_file* file, size_t offset);
     int (*rename)(struct v_file* file, char* new_name);
@@ -94,6 +86,7 @@ struct v_file
     struct v_dnode* dnode;
     struct llist_header* f_list;
     uint32_t f_pos;
+    uint32_t ref_count;
     void* data; // 允许底层FS绑定他的一些专有数据
     struct v_file_ops ops;
 };
@@ -101,7 +94,6 @@ struct v_file
 struct v_fd
 {
     struct v_file* file;
-    int pos;
     int flags;
 };
 
@@ -115,10 +107,11 @@ struct v_inode
     uint32_t link_count;
     uint32_t lb_usage;
     uint32_t fsize;
+    struct pcache* pg_cache;
     void* data; // 允许底层FS绑定他的一些专有数据
     struct
     {
-        int (*create)(struct v_inode* this, struct v_file* file);
+        int (*create)(struct v_inode* this);
         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);
@@ -151,6 +144,24 @@ struct v_fdtable
     struct v_fd* fds[VFS_MAX_FD];
 };
 
+struct pcache_pg
+{
+    struct llist_header pg_list;
+    struct llist_header dirty_list;
+    void* pg;
+    uint32_t flags;
+    uint32_t fpos;
+};
+
+struct pcache
+{
+    struct btrie tree;
+    struct llist_header pages;
+    struct llist_header dirty;
+    uint32_t n_dirty;
+    uint32_t n_pages;
+};
+
 /* --- file system manager --- */
 void
 fsm_init();
@@ -218,4 +229,40 @@ vfs_i_alloc();
 
 void
 vfs_i_free(struct v_inode* inode);
+
+void
+pcache_init(struct pcache* pcache);
+
+void
+pcache_release_page(struct pcache* pcache, struct pcache_pg* page);
+
+struct pcache_pg*
+pcache_new_page(struct pcache* pcache, uint32_t index);
+
+void
+pcache_set_dirty(struct pcache* pcache, struct pcache_pg* pg);
+
+struct pcache_pg*
+pcache_get_page(struct pcache* pcache,
+                uint32_t index,
+                uint32_t* offset,
+                struct pcache_pg** page);
+
+int
+pcache_write(struct v_file* file, void* data, uint32_t len);
+
+int
+pcache_read(struct v_file* file, void* data, uint32_t len);
+
+void
+pcache_release(struct pcache* pcache);
+
+int
+pcache_commit(struct v_file* file, struct pcache_pg* page);
+
+void
+pcache_invalidate(struct v_file* file, struct pcache_pg* page);
+
+void
+pcache_commit_all(struct v_file* file);
 #endif /* __LUNAIX_VFS_H */
index fe9224c8e89c6e3a30d4b62265c5be481437d136..4007c315a36ca54e335be97cb057af48b19ca0da 100644 (file)
@@ -25,5 +25,6 @@
 #define EBUSY -20
 #define EXDEV -21
 #define ELOOP -22
+#define ENODEV -23
 
 #endif /* __LUNAIX_CODE_H */
index a4c1942b7756e2632900efb83e69c5a2295590b4..d88017da73198d73a9be3a49035c73c4521dad59 100644 (file)
@@ -47,18 +47,19 @@ __block_read(struct device* dev,
     int errno;
     struct block_dev* bdev = (struct block_dev*)dev->underlay;
     size_t acc_size = 0, rd_size = 0, bsize = bdev->hd_dev->block_size,
-           rd_block = 0;
-    void* block = valloc(bsize);
+           rd_block = offset / bsize, r = offset % bsize;
+    void* block = vzalloc(bsize);
 
     while (acc_size < len) {
         if (!bdev->hd_dev->ops.read_buffer(
-              bdev->hd_dev, offset + rd_block, block, bsize)) {
+              bdev->hd_dev, rd_block, block, bsize)) {
             errno = ENXIO;
             goto error;
         }
-        rd_size = MIN(len - acc_size, bsize);
-        memcpy(buf + acc_size, block, rd_size);
+        rd_size = MIN(len - acc_size, bsize - r);
+        memcpy(buf + acc_size, block + r, rd_size);
         acc_size += rd_size;
+        r = 0;
         rd_block++;
     }
 
@@ -79,18 +80,19 @@ __block_write(struct device* dev,
     int errno;
     struct block_dev* bdev = (struct block_dev*)dev->underlay;
     size_t acc_size = 0, wr_size = 0, bsize = bdev->hd_dev->block_size,
-           wr_block = 0;
-    void* block = valloc(bsize);
+           wr_block = offset / bsize, r = offset % bsize;
+    void* block = vzalloc(bsize);
 
     while (acc_size < len) {
-        wr_size = MIN(len - acc_size, bsize);
-        memcpy(block, buf + acc_size, wr_size);
+        wr_size = MIN(len - acc_size, bsize - r);
+        memcpy(block + r, buf + acc_size, wr_size);
         if (!bdev->hd_dev->ops.write_buffer(
-              bdev->hd_dev, offset + wr_block, block, bsize)) {
+              bdev->hd_dev, wr_block, block, bsize)) {
             errno = ENXIO;
             break;
         }
         acc_size += wr_size;
+        r = 0;
         wr_block++;
     }
 
index f51abcc230e5c552b275ecb8441c64ba560e8f28..0cf7cba2e92a80dc37c221b7bdec6437eaf43369 100644 (file)
@@ -13,24 +13,30 @@ _iotest_main()
                            "There were two regal sisters who ruled together "
                            "and created harmony for all the land.";
 
-    int fd = open("/dev/sda", 0);  // bd0 设备 - 硬盘
-    int tty = open("/dev/tty", 0); // tty 设备 - 控制台
+    int fd = open("/dev/sda", 0); // sda 设备 - 硬盘
+
+    // tty 设备 - 控制台,使用O_DIRECT打开,即所有IO绕过Lunaix内核的缓存机制
+    int tty = open("/dev/tty", FO_DIRECT);
 
     if (fd < 0 || tty < 0) {
         kprintf(KERROR "fail to open (%d)\n", geterrno());
         return;
     }
 
-    // 移动指针至第二个逻辑扇区(LBA=1),并写入
-    lseek(fd, 1, FSEEK_SET);
+    // 移动指针至512字节,在大多数情况下,这是第二个逻辑扇区的起始处
+    lseek(fd, 512, FSEEK_SET);
+    write(fd, test_sequence, sizeof(test_sequence));
+    lseek(fd, 521, FSEEK_SET);
     write(fd, test_sequence, sizeof(test_sequence));
 
     // 读出我们写的内容
     char read_out[256];
-    lseek(fd, -1, FSEEK_CUR);
+    lseek(fd, 512, FSEEK_SET);
     read(fd, read_out, sizeof(read_out));
 
+    // 将读出的内容直接写入tty设备
     write(tty, read_out, sizeof(read_out));
+    write(tty, "\n", 1);
 
     close(fd);
     close(tty);
index 9cb2fa1d0d2d515b01168e55c0987644d57bce16..f114431169142f1ed54f092ef7b146544409c4ea 100644 (file)
@@ -8,10 +8,10 @@ struct llist_header dev_list;
 static struct twifs_node* dev_root;
 
 int
-__dev_read(struct v_file* file, void* buffer, size_t len);
+__dev_read(struct v_file* file, void* buffer, size_t len, size_t fpos);
 
 int
-__dev_write(struct v_file* file, void* buffer, size_t len);
+__dev_write(struct v_file* file, void* buffer, size_t len, size_t fpos);
 
 void
 device_init()
@@ -52,7 +52,7 @@ device_add(struct device* parent, void* underlay, char* name_fmt, ...)
 }
 
 int
-__dev_read(struct v_file* file, void* buffer, size_t len)
+__dev_read(struct v_file* file, void* buffer, size_t len, size_t fpos)
 {
     struct twifs_node* dev_node = (struct twifs_node*)file->inode->data;
     struct device* dev = (struct device*)dev_node->data;
@@ -60,11 +60,11 @@ __dev_read(struct v_file* file, void* buffer, size_t len)
     if (!dev->read) {
         return ENOTSUP;
     }
-    return dev->read(dev, buffer, file->f_pos, len);
+    return dev->read(dev, buffer, fpos, len);
 }
 
 int
-__dev_write(struct v_file* file, void* buffer, size_t len)
+__dev_write(struct v_file* file, void* buffer, size_t len, size_t fpos)
 {
     struct twifs_node* dev_node = (struct twifs_node*)file->inode->data;
     struct device* dev = (struct device*)dev_node->data;
@@ -72,7 +72,7 @@ __dev_write(struct v_file* file, void* buffer, size_t len)
     if (!dev->write) {
         return ENOTSUP;
     }
-    return dev->write(dev, buffer, file->f_pos, len);
+    return dev->write(dev, buffer, fpos, len);
 }
 
 void
diff --git a/lunaix-os/kernel/ds/btrie.c b/lunaix-os/kernel/ds/btrie.c
new file mode 100644 (file)
index 0000000..92f034b
--- /dev/null
@@ -0,0 +1,120 @@
+/**
+ * @file btrie.c
+ * @author Lunaixsky
+ * @brief Bitwise trie tree implementation for sparse array.
+ * @version 0.1
+ * @date 2022-08-01
+ *
+ * @copyright Copyright (c) 2022
+ *
+ */
+
+#include <lunaix/ds/btrie.h>
+#include <lunaix/mm/valloc.h>
+#include <lunaix/spike.h>
+
+#define BTRIE_INSERT 1
+
+struct btrie_node*
+__btrie_traversal(struct btrie* root, uint32_t index, int options)
+{
+    index = index >> root->truncated;
+    uint32_t lz = index ? ROUNDDOWN(31 - __builtin_clz(index), BTRIE_BITS) : 0;
+    uint32_t bitmask = ((1 << BTRIE_BITS) - 1) << lz;
+    uint32_t i = 0;
+    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) {
+        i = (index & bitmask) >> lz;
+        struct btrie_node *subtree = 0, *pos, *n;
+
+        llist_for_each(pos, n, &tree->children, siblings)
+        {
+            if (pos->index == i) {
+                subtree = pos;
+                break;
+            }
+        }
+
+        if (!subtree && (options & BTRIE_INSERT)) {
+            struct btrie_node* new_tree = vzalloc(sizeof(struct btrie_node));
+            new_tree->index = i;
+            new_tree->parent = tree;
+            llist_init_head(&new_tree->children);
+
+            llist_append(&tree->children, &new_tree->siblings);
+            llist_append(&root->btrie_root->nodes, &new_tree->nodes);
+            tree = new_tree;
+        } else {
+            tree = subtree;
+        }
+        bitmask = bitmask >> BTRIE_BITS;
+        lz -= BTRIE_BITS;
+    }
+
+    return tree;
+}
+
+void
+btrie_init(struct btrie* btrie, uint32_t trunc_bits)
+{
+    btrie->btrie_root = vzalloc(sizeof(struct btrie_node));
+    llist_init_head(&btrie->btrie_root->nodes);
+    btrie->truncated = trunc_bits;
+}
+
+void*
+btrie_get(struct btrie* root, uint32_t index)
+{
+    struct btrie_node* node = __btrie_traversal(root, index, 0);
+    if (!node) {
+        return NULL;
+    }
+    return node->data;
+}
+
+void
+btrie_set(struct btrie* root, uint32_t index, void* data)
+{
+    struct btrie_node* node = __btrie_traversal(root, index, BTRIE_INSERT);
+    node->data = data;
+}
+
+void
+__btrie_remove(struct btrie_node* node)
+{
+    struct btrie_node* parent = node->parent;
+    if (parent) {
+        llist_delete(&node->siblings);
+        llist_delete(&node->nodes);
+        vfree(node);
+        if (llist_empty(&parent->children)) {
+            __btrie_remove(parent);
+        }
+    }
+}
+
+void*
+btrie_remove(struct btrie* root, uint32_t index)
+{
+    struct btrie_node* node = __btrie_traversal(root, index, 0);
+    if (!node) {
+        return 0;
+    }
+    void* data = node->data;
+    __btrie_remove(node);
+    return data;
+}
+
+void
+btrie_release(struct btrie* tree)
+{
+    struct btrie_node *pos, *n;
+    llist_for_each(pos, n, &tree->btrie_root->nodes, nodes)
+    {
+        vfree(pos);
+    }
+
+    vfree(tree->btrie_root);
+}
\ No newline at end of file
diff --git a/lunaix-os/kernel/fs/pcache.c b/lunaix-os/kernel/fs/pcache.c
new file mode 100644 (file)
index 0000000..a1632a1
--- /dev/null
@@ -0,0 +1,172 @@
+#include <klibc/string.h>
+#include <lunaix/ds/btrie.h>
+#include <lunaix/fs.h>
+#include <lunaix/mm/page.h>
+#include <lunaix/mm/pmm.h>
+#include <lunaix/mm/valloc.h>
+#include <lunaix/mm/vmm.h>
+#include <lunaix/spike.h>
+
+#define PCACHE_DIRTY 0x1
+
+void
+pcache_init(struct pcache* pcache)
+{
+    btrie_init(&pcache->tree, PG_SIZE_BITS);
+    llist_init_head(&pcache->dirty);
+    llist_init_head(&pcache->pages);
+}
+
+void
+pcache_release_page(struct pcache* pcache, struct pcache_pg* page)
+{
+    pmm_free_page(KERNEL_PID, page->pg);
+    vmm_del_mapping(PD_REFERENCED, page->pg);
+
+    llist_delete(&page->pg_list);
+
+    vfree(page);
+
+    pcache->n_pages--;
+}
+
+struct pcache_pg*
+pcache_new_page(struct pcache* pcache, uint32_t index)
+{
+    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));
+    ppg->pg = pg_v;
+
+    llist_append(&pcache->pages, &ppg->pg_list);
+    btrie_set(&pcache->tree, index, ppg);
+
+    return ppg;
+}
+
+void
+pcache_set_dirty(struct pcache* pcache, struct pcache_pg* pg)
+{
+    if (!(pg->flags & PCACHE_DIRTY)) {
+        pg->flags |= PCACHE_DIRTY;
+        pcache->n_dirty++;
+        llist_append(&pcache->dirty, &pg->dirty_list);
+    }
+}
+
+struct pcache_pg*
+pcache_get_page(struct pcache* pcache,
+                uint32_t index,
+                uint32_t* offset,
+                struct pcache_pg** page)
+{
+    struct pcache_pg* pg = btrie_get(&pcache->tree, index);
+    int is_new = 0;
+    *offset = index & ((1 << pcache->tree.truncated) - 1);
+    if (!pg) {
+        pg = pcache_new_page(pcache, index);
+        pg->fpos = index - *offset;
+        pcache->n_pages++;
+        is_new = 1;
+    }
+    *page = pg;
+    return is_new;
+}
+
+int
+pcache_write(struct v_file* file, void* data, uint32_t len)
+{
+    uint32_t pg_off, buf_off = 0, fpos = file->f_pos;
+    struct pcache* pcache = file->inode->pg_cache;
+    struct pcache_pg* pg;
+
+    while (buf_off < len) {
+        pcache_get_page(pcache, fpos, &pg_off, &pg);
+        uint32_t wr_bytes = MIN(PG_SIZE - pg_off, len - buf_off);
+        memcpy(pg->pg + pg_off, (data + buf_off), wr_bytes);
+
+        pcache_set_dirty(pcache, pg);
+
+        buf_off += wr_bytes;
+        fpos += wr_bytes;
+    }
+
+    return buf_off;
+}
+
+int
+pcache_read(struct v_file* file, void* data, uint32_t len)
+{
+    uint32_t pg_off, buf_off = 0, new_pg = 0, fpos = file->f_pos;
+    int errno = 0;
+    struct pcache* pcache = file->inode->pg_cache;
+    struct pcache_pg* pg;
+
+    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) {
+                // EOF
+                len = buf_off + errno;
+            } else if (errno < 0) {
+                break;
+            }
+        }
+        uint32_t rd_bytes = MIN(PG_SIZE - pg_off, len - buf_off);
+        memcpy((data + buf_off), pg->pg + pg_off, rd_bytes);
+
+        buf_off += rd_bytes;
+        fpos += rd_bytes;
+    }
+
+    return errno < 0 ? errno : buf_off;
+}
+
+void
+pcache_release(struct pcache* pcache)
+{
+    struct pcache_pg *pos, *n;
+    llist_for_each(pos, n, &pcache->pages, pg_list)
+    {
+        vfree(pos);
+    }
+
+    btrie_release(&pcache->tree);
+}
+
+int
+pcache_commit(struct v_file* file, struct pcache_pg* page)
+{
+    if (!(page->flags & PCACHE_DIRTY)) {
+        return;
+    }
+
+    int errno = file->ops.write(file, page->pg, PG_SIZE, page->fpos);
+
+    if (!errno) {
+        page->flags &= ~PCACHE_DIRTY;
+        llist_delete(&page->dirty_list);
+        file->inode->pg_cache->n_dirty--;
+    }
+
+    return errno;
+}
+
+void
+pcache_commit_all(struct v_file* file)
+{
+    struct pcache* cache = file->inode->pg_cache;
+    struct pcache_pg *pos, *n;
+    llist_for_each(pos, n, &cache->dirty, dirty_list)
+    {
+        pcache_commit(file, pos);
+    }
+}
+
+void
+pcache_invalidate(struct v_file* file, struct pcache_pg* page)
+{
+    pcache_commit(file, page);
+    pcache_release_page(&file->inode->pg_cache, page);
+}
\ No newline at end of file
index fcceb7073243dbb66102d5d3eb5952fdf2b05dcf..f09a701ef1cebee15bdf4a880a88fd8477107072 100644 (file)
@@ -146,7 +146,7 @@ __vfs_walk(struct v_dnode* start,
                 return ENAMETOOLONG;
             }
             if (!VFS_VALID_CHAR(current)) {
-                return VFS_EINVLD;
+                return EINVAL;
             }
             name_content[j++] = current;
             if (lookahead) {
@@ -247,8 +247,7 @@ vfs_walk(struct v_dnode* start,
         } else {
             break;
         }
-        errno =
-          __vfs_walk_internal(start, pathname, &interim, component, options);
+        errno = __vfs_walk(start, pathname, &interim, component, options);
         counter++;
     }
 
@@ -288,7 +287,7 @@ vfs_mount_at(const char* fs_name, bdev_t device, struct v_dnode* mnt_point)
 {
     struct filesystem* fs = fsm_get(fs_name);
     if (!fs)
-        return VFS_ENOFS;
+        return ENODEV;
     struct v_superblock* sb = vfs_sb_alloc();
     sb->dev = device;
     sb->fs_id = fs_id++;
@@ -310,7 +309,7 @@ vfs_unmount_at(struct v_dnode* mnt_point)
     int errno = 0;
     struct v_superblock* sb = mnt_point->super_block;
     if (!sb) {
-        return VFS_EBADMNT;
+        return EINVAL;
     }
     if (!(errno = sb->fs->unmount(sb))) {
         struct v_dnode* fs_root = sb->root;
@@ -333,8 +332,16 @@ vfs_open(struct v_dnode* dnode, struct v_file** file)
 
     vfile->dnode = dnode;
     vfile->inode = dnode->inode;
+    vfile->ref_count = 1;
     dnode->inode->open_count++;
 
+    if ((dnode->inode->itype & VFS_INODE_TYPE_FILE) &&
+        !dnode->inode->pg_cache) {
+        struct pcache* pcache = vzalloc(sizeof(struct pcache));
+        pcache_init(pcache);
+        dnode->inode->pg_cache = pcache;
+    }
+
     int errno = dnode->inode->ops.open(dnode->inode, vfile);
     if (errno) {
         cake_release(file_pile, vfile);
@@ -363,15 +370,12 @@ vfs_link(struct v_dnode* to_link, struct v_dnode* name)
 int
 vfs_close(struct v_file* file)
 {
-    if (!file->ops.close) {
-        return ENOTSUP;
-    }
-
-    int errno = file->ops.close(file);
-    if (!errno) {
+    int errno = 0;
+    if (!file->ops.close || !(errno = file->ops.close(file))) {
         if (file->inode->open_count) {
             file->inode->open_count--;
         }
+        pcache_commit_all(file);
         cake_release(file_pile, file);
     }
     return errno;
@@ -441,7 +445,6 @@ vfs_i_alloc()
 {
     struct v_inode* inode = cake_grab(inode_pile);
     memset(inode, 0, sizeof(*inode));
-
     return inode;
 }
 
@@ -466,18 +469,23 @@ __vfs_try_locate_file(const char* path,
     char name_str[VFS_NAME_MAXLEN];
     struct hstr name = HSTR(name_str, 0);
     int errno;
-    if (!(errno = vfs_walk(NULL, path, fdir, &name, VFS_WALK_PARENT))) {
-        errno = vfs_walk(*fdir, name.value, file, NULL, 0);
-        if (errno == ENOENT && (options & FLOCATE_CREATE_EMPTY)) {
-            struct v_dnode* file_new;
-            file_new = vfs_d_alloc();
-            file_new->name =
-              HHSTR(valloc(VFS_NAME_MAXLEN), name.len, name.hash);
-            strcpy(file_new->name.value, name_str);
-            *file = file_new;
-
-            llist_append(&(*fdir)->children, &file_new->siblings);
-        }
+    if ((errno = vfs_walk(NULL, path, fdir, &name, VFS_WALK_PARENT))) {
+        return errno;
+    }
+
+    errno = vfs_walk(*fdir, name.value, file, NULL, 0);
+    if (errno != ENOENT || !(options & FLOCATE_CREATE_EMPTY)) {
+        return errno;
+    }
+
+    if (!(errno = (*fdir)->inode->ops.create((*fdir)->inode))) {
+        struct v_dnode* file_new;
+        file_new = vfs_d_alloc();
+        file_new->name = HHSTR(valloc(VFS_NAME_MAXLEN), name.len, name.hash);
+        strcpy(file_new->name.value, name_str);
+        *file = file_new;
+
+        llist_append(&(*fdir)->children, &file_new->siblings);
     }
 
     return errno;
@@ -493,8 +501,10 @@ __vfs_do_open(struct v_file** file_out, const char* path, int options)
     errno = __vfs_try_locate_file(path, &dentry, &file, 0);
 
     if (errno != ENOENT && (options & FO_CREATE)) {
-        errno = dentry->inode->ops.create(dentry->inode, opened_file);
-    } else if (!errno) {
+        errno = dentry->inode->ops.create(dentry->inode);
+    }
+
+    if (!errno) {
         errno = vfs_open(file, &opened_file);
     }
 
@@ -509,8 +519,10 @@ __DEFINE_LXSYSCALL2(int, open, const char*, path, int, options)
 
     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;
-        fd_s->pos = opened_file->inode->fsize & -((options & FO_APPEND) != 0);
+        fd_s->flags = options;
         __current->fdtable->fds[fd] = fd_s;
         return fd;
     }
@@ -523,14 +535,22 @@ __DEFINE_LXSYSCALL2(int, open, const char*, path, int, options)
 __DEFINE_LXSYSCALL1(int, close, int, fd)
 {
     struct v_fd* fd_s;
-    int errno;
+    int errno = 0;
     if (!GET_FD(fd, fd_s)) {
         errno = EBADF;
-    } else if (!(errno = vfs_close(fd_s->file))) {
-        vfree(fd_s);
-        __current->fdtable->fds[fd] = 0;
+        goto done_err;
     }
 
+    if (fd_s->file->ref_count > 1) {
+        fd_s->file->ref_count--;
+    } else if ((errno = vfs_close(fd_s->file))) {
+        goto done_err;
+    }
+
+    vfree(fd_s);
+    __current->fdtable->fds[fd] = 0;
+
+done_err:
     return DO_STATUS(errno);
 }
 
@@ -614,14 +634,27 @@ __DEFINE_LXSYSCALL3(int, read, int, fd, void*, buf, size_t, count)
     struct v_fd* fd_s;
     if (!GET_FD(fd, fd_s)) {
         errno = EBADF;
+        goto done;
+    }
+
+    struct v_file* file = fd_s->file;
+    if ((file->inode->itype & VFS_INODE_TYPE_DIR)) {
+        errno = EISDIR;
+        goto done;
+    }
+
+    if ((fd_s->flags & FO_DIRECT)) {
+        errno = file->ops.read(file, buf, count, file->f_pos);
     } else {
-        struct v_file* file = fd_s->file;
-        file->f_pos = fd_s->pos;
-        if ((errno = file->ops.read(file, buf, count)) >= 0) {
-            fd_s->pos += errno;
-        }
+        errno = pcache_read(file, buf, count);
+    }
+
+    if (errno > 0) {
+        file->f_pos += errno;
+        return errno;
     }
 
+done:
     return DO_STATUS(errno);
 }
 
@@ -631,14 +664,27 @@ __DEFINE_LXSYSCALL3(int, write, int, fd, void*, buf, size_t, count)
     struct v_fd* fd_s;
     if (!GET_FD(fd, fd_s)) {
         errno = EBADF;
+        goto done;
+    }
+
+    struct v_file* file = fd_s->file;
+    if ((file->inode->itype & VFS_INODE_TYPE_DIR)) {
+        errno = EISDIR;
+        goto done;
+    }
+
+    if ((fd_s->flags & FO_DIRECT)) {
+        errno = file->ops.write(file, buf, count, file->f_pos);
     } else {
-        struct v_file* file = fd_s->file;
-        file->f_pos = fd_s->pos;
-        if ((errno = file->ops.write(file, buf, count)) >= 0) {
-            fd_s->pos += errno;
-        }
+        errno = pcache_write(file, buf, count);
+    }
+
+    if (errno > 0) {
+        file->f_pos += errno;
+        return errno;
     }
 
+done:
     return DO_STATUS(errno);
 }
 
@@ -649,22 +695,22 @@ __DEFINE_LXSYSCALL3(int, lseek, int, fd, int, offset, int, options)
     if (!GET_FD(fd, fd_s)) {
         errno = EBADF;
     } else {
-        size_t fpos = fd_s->file->f_pos;
+        struct v_file* file = fd_s->file;
+        size_t fpos = file->f_pos;
         switch (options) {
             case FSEEK_CUR:
-                fpos = (size_t)((int)fd_s->file->f_pos + offset);
+                fpos = (size_t)((int)file->f_pos + offset);
                 break;
             case FSEEK_END:
-                fpos = (size_t)((int)fd_s->file->inode->fsize + offset);
+                fpos = (size_t)((int)file->inode->fsize + offset);
                 break;
             case FSEEK_SET:
                 fpos = offset;
                 break;
-
-            default:
-                break;
         }
-        fd_s->pos = fpos;
+        if (!file->ops.seek || !(errno = file->ops.seek(file, fpos))) {
+            file->f_pos = fpos;
+        }
     }
 
     return DO_STATUS(errno);
@@ -892,13 +938,10 @@ int
 __vfs_dup_fd(struct v_fd* old, struct v_fd** new)
 {
     int errno = 0;
-    struct v_file* newopened;
-    if (!(errno = vfs_open(old->file->dnode, &newopened))) {
-        *new = cake_grab(fd_pile);
-        **new = (struct v_fd){ .file = newopened,
-                               .pos = old->pos,
-                               .flags = old->flags };
-    }
+    struct v_fd* copied = cake_grab(fd_pile);
+
+    memcpy(copied, old, sizeof(struct v_fd));
+    old->file->ref_count++;
 
     return errno;
 }
index 1f706dc362140c5203a36b9371b04571b8f492b1..920c35bbb86a3ea26cf04c247bce0b317128c5e1 100644 (file)
@@ -1,5 +1,5 @@
-#include <lunaix/mm/kalloc.h>
 #include <lunaix/mm/region.h>
+#include <lunaix/mm/valloc.h>
 
 void
 region_add(struct mm_region* regions,
@@ -7,7 +7,7 @@ region_add(struct mm_region* regions,
            unsigned long end,
            unsigned int attr)
 {
-    struct mm_region* region = lxmalloc(sizeof(struct mm_region));
+    struct mm_region* region = valloc(sizeof(struct mm_region));
 
     *region = (struct mm_region){ .attr = attr, .end = end, .start = start };
 
index 3aa402ed42d16befb2ccb9dec032d7832244fdc4..ec997425b9c0161ab817d19f91591c9c4c5585d2 100644 (file)
@@ -43,8 +43,8 @@ __do_reserved_memory(int unlock);
 
 #define USE_DEMO
 // #define DEMO_SIGNAL
-#define DEMO_READDIR
-//#define DEMO_IOTEST
+// #define DEMO_READDIR
+#define DEMO_IOTEST
 
 extern void
 _pconsole_main();