feat: lseek(2), read(2), write(2) implementation
authorMinep <zelong56@gmail.com>
Fri, 29 Jul 2022 16:04:02 +0000 (17:04 +0100)
committerMinep <zelong56@gmail.com>
Fri, 29 Jul 2022 16:09:58 +0000 (17:09 +0100)
feat: unified block device manipulation using vfs.
chore: bug fix & code formatting.

16 files changed:
lunaix-os/hal/ahci/ahci.c
lunaix-os/includes/lunaix/block.h
lunaix-os/includes/lunaix/fctrl.h
lunaix-os/includes/lunaix/foptions.h
lunaix-os/includes/lunaix/fs/twifs.h
lunaix-os/includes/lunaix/proc.h
lunaix-os/includes/lunaix/status.h
lunaix-os/includes/lunaix/syscall.h
lunaix-os/kernel/asm/x86/syscall.S
lunaix-os/kernel/block.c
lunaix-os/kernel/demos/dir_read.c
lunaix-os/kernel/demos/iotest.c [new file with mode: 0644]
lunaix-os/kernel/fs/twifs.c
lunaix-os/kernel/fs/vfs.c
lunaix-os/kernel/proc0.c
lunaix-os/kernel/sched.c

index e892858ffdd1e766336e39ce04142bc206e86ab0..53981a00415b4cdd2860fb4ea314f6bb95d8709a 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <hal/pci.h>
 #include <klibc/string.h>
+#include <lunaix/block.h>
 #include <lunaix/mm/mmio.h>
 #include <lunaix/mm/pmm.h>
 #include <lunaix/mm/valloc.h>
@@ -175,6 +176,8 @@ ahci_init()
         if (!ahci_init_device(port)) {
             kprintf(KERROR "fail to init device");
         }
+
+        block_mount_disk(port->device);
     }
 }
 
index db8ae5cfd5055b72adf10bedfd53b0a379d5b7cb..94e87754c703436758d3f6cfeed92b96ce7cd6b9 100644 (file)
@@ -5,12 +5,14 @@
 
 #define LPT_SIG 0x414e554c
 #define PARTITION_NAME_SIZE 48
+#define DEV_ID_SIZE 32
 
 typedef uint64_t partition_t;
 typedef uint32_t bdev_t;
 
 struct block_dev
 {
+    char bdev_id[DEV_ID_SIZE];
     char name[PARTITION_NAME_SIZE];
     struct hba_device* hd_dev;
     uint64_t base_lba;
@@ -34,4 +36,10 @@ struct lpt_header
     uint32_t table_len;
 } __attribute__((packed));
 
+void
+block_init();
+
+int
+block_mount_disk(struct hba_device* hd_dev);
+
 #endif /* __LUNAIX_BLOCK_H */
index 978553e96383d00806096b8a404c4ff15d879a66..e76ae7b05263c405624cf113ba7aabacc67bacd2 100644 (file)
@@ -12,4 +12,10 @@ __LXSYSCALL1(int, mkdir, const char*, path);
 
 __LXSYSCALL2(int, readdir, int, fd, struct dirent*, dent);
 
+__LXSYSCALL3(int, lseek, int, fd, int, offset, int, options);
+
+__LXSYSCALL3(int, read, int, fd, void*, buf, unsigned int, count);
+
+__LXSYSCALL3(int, write, int, fd, void*, buf, unsigned int, count);
+
 #endif /* __LUNAIX_FCTRL_H */
index 6d6d2d323d4df386cccc94fd0b2a22bf5ab59638..00f3486f82cbb0a2d341feaeef2ae75132ecfef4 100644 (file)
@@ -4,4 +4,8 @@
 #define FO_CREATE 0x1
 #define FO_APPEND 0x2
 
+#define FSEEK_SET 0x1
+#define FSEEK_CUR 0x2
+#define FSEEK_END 0x3
+
 #endif /* __LUNAIX_FOPTIONS_H */
index 8df3ddcf61ef031f09aae295e5aed1b10e68553a..b83b1a4e84a53128fb230f9373c95f8632b100ba 100644 (file)
@@ -7,6 +7,7 @@ struct twifs_node
 {
     struct v_inode* inode;
     struct hstr name;
+    void* data;
     uint32_t itype;
     struct llist_header children;
     struct llist_header siblings;
index eafae4fc43968e6f7958c8432b61c066271b4029..f4de8cf6260a47d4f7a19018be695e919cbdaa1a 100644 (file)
@@ -10,4 +10,6 @@ __LXSYSCALL1(pid_t, wait, int*, status);
 
 __LXSYSCALL3(pid_t, waitpid, pid_t, pid, int*, status, int, options);
 
+__LXSYSCALL(int, geterrno);
+
 #endif /* __LUNAIX_SYS_H */
index dd353feace660a13ec4e8cafc1269963a9170c92..2c3ff963ddc4eff7311a530674b9c13dcc12e4ac 100644 (file)
@@ -17,5 +17,6 @@
 #define EEXIST -12
 #define EBADF -13
 #define ENOTSUP -14
+#define ENXIO -15
 
 #endif /* __LUNAIX_CODE_H */
index 42bc85b8f7b849f447f7fdabce9f0a853b0aa66f..88aa0261840492ad503180c25a03de99b0a439da 100644 (file)
@@ -28,6 +28,8 @@
 #define __SYSCALL_write 22
 #define __SYSCALL_readdir 23
 #define __SYSCALL_mkdir 24
+#define __SYSCALL_lseek 25
+#define __SYSCALL_geterrno 26
 
 #define __SYSCALL_MAX 0x100
 
index 2816bae27c406c14c5b010cc7e93159ad527c2a1..6a8b43277135c5155c29f4c3dea37fe11c7dbbd8 100644 (file)
         .long __lxsys_sigpending
         .long __lxsys_sigsuspend
         .long __lxsys_open
-        .long __lxsys_close
+        .long __lxsys_close         /* 20 */
         .long __lxsys_read
         .long __lxsys_write
         .long __lxsys_readdir
         .long __lxsys_mkdir
+        .long __lxsys_lseek          /* 25 */
+        .long __lxsys_geterrno
         2:
         .rept __SYSCALL_MAX - (2b - 1b)/4
             .long 0
index 0e28f666e2d03548a756e00ecc63e4b05b89bcb7..23b937488a9b1cd197c942e0f1dcb60d8c4404a7 100644 (file)
@@ -1,11 +1,15 @@
 #include <hal/ahci/hba.h>
+#include <klibc/stdio.h>
 #include <klibc/string.h>
 #include <lib/crc.h>
 #include <lunaix/block.h>
+#include <lunaix/fs/twifs.h>
 #include <lunaix/mm/cake.h>
 #include <lunaix/mm/valloc.h>
 #include <lunaix/syslog.h>
 
+#include <lunaix/spike.h>
+
 #define BLOCK_EREAD 1
 #define BLOCK_ESIG 2
 #define BLOCK_ECRC 3
@@ -31,6 +35,106 @@ block_init()
 {
     lbd_pile = cake_new_pile("block_dev", sizeof(struct block_dev), 1, 0);
     dev_registry = vcalloc(sizeof(struct block_dev*), MAX_DEV);
+    free_slot = 0;
+}
+
+int
+__block_read(struct v_file* file, void* buffer, size_t len);
+
+int
+__block_write(struct v_file* file, void* buffer, size_t len);
+
+void
+block_twifs_create()
+{
+    struct twifs_node* dev = twifs_toplevel_node("dev", 3);
+    struct twifs_node* dev_block = twifs_dir_node(dev, "block", 5);
+
+    if (!dev_block) {
+        kprintf(KERROR "fail to create twifs node");
+        return;
+    }
+
+    struct block_dev* bdev;
+    struct twifs_node* bdev_node;
+    for (size_t i = 0; i < MAX_DEV; i++) {
+        if (!(bdev = dev_registry[i])) {
+            continue;
+        }
+
+        bdev_node =
+          twifs_dir_node(dev_block, bdev->bdev_id, strlen(bdev->bdev_id));
+        bdev_node->fops.read = __block_read;
+        bdev_node->fops.write = __block_write;
+        bdev_node->data = i;
+        bdev_node->inode->fsize = bdev->hd_dev->max_lba;
+    }
+}
+
+int
+__block_read(struct v_file* file, void* buffer, size_t len)
+{
+    int index = (int)((struct twifs_node*)file->inode->data)->data;
+    int errno;
+    struct block_dev* bdev;
+    if (index < 0 || index >= MAX_DEV || !(bdev = dev_registry[index])) {
+        return ENXIO;
+    }
+    size_t acc_size = 0, rd_size = 0, bsize = bdev->hd_dev->block_size,
+           rd_block = 0;
+    void* block = valloc(bsize);
+
+    while (acc_size < len) {
+        if (!bdev->hd_dev->ops.read_buffer(
+              bdev->hd_dev, file->f_pos + rd_block, block, bsize)) {
+            errno = ENXIO;
+            goto error;
+        }
+        rd_size = MIN(len - acc_size, bsize);
+        memcpy(buffer + acc_size, block, rd_size);
+        acc_size += rd_size;
+        rd_block++;
+    }
+
+    vfree(block);
+    return rd_block;
+
+error:
+    vfree(block);
+    return errno;
+}
+
+int
+__block_write(struct v_file* file, void* buffer, size_t len)
+{
+    int index = (int)((struct twifs_node*)file->inode->data)->data;
+    int errno;
+    struct block_dev* bdev;
+    if (index < 0 || index >= MAX_DEV || !(bdev = dev_registry[index])) {
+        return ENXIO;
+    }
+    size_t acc_size = 0, wr_size = 0, bsize = bdev->hd_dev->block_size,
+           wr_block = 0;
+    void* block = valloc(bsize);
+
+    while (acc_size < len) {
+        wr_size = MIN(len - acc_size, bsize);
+        memcpy(block, buffer + acc_size, wr_size);
+        if (!bdev->hd_dev->ops.write_buffer(
+              bdev->hd_dev, file->f_pos + wr_block, block, bsize)) {
+            errno = ENXIO;
+            break;
+        }
+        acc_size += wr_size;
+        wr_block++;
+    }
+
+    vfree(block);
+    return wr_block;
+
+error:
+    vfree(block);
+    return errno;
 }
 
 int
@@ -47,17 +151,16 @@ block_mount_disk(struct hba_device* hd_dev)
         goto error;
     }
 
-    if ((errno = __block_mount_partitions(hd_dev))) {
-        goto error;
-    }
+    return errno;
 
 error:
-    kprintf(KERROR "Fail to mount hd: %s[%s] (%x)",
+    kprintf(KERROR "Fail to mount hd: %s[%s] (%x)\n",
             hd_dev->model,
             hd_dev->serial_num,
             -errno);
 }
 
+// FIXME make it more general, manipulate the device through vfs mapping
 int
 __block_mount_partitions(struct hba_device* hd_dev)
 {
@@ -113,7 +216,7 @@ __block_register(struct block_dev* dev)
     if (free_slot >= MAX_DEV) {
         return 0;
     }
-
+    snprintf(dev->bdev_id, DEV_ID_SIZE, "bd%x", free_slot);
     dev_registry[free_slot++] = dev;
     return 1;
 }
\ No newline at end of file
index 8c4a34407fc9a0efc95f4af426e4802d3f8c951f..7a63ba933d7c44469eedaee1de02b3655f66c2c3 100644 (file)
@@ -7,7 +7,7 @@ LOG_MODULE("RDDIR")
 void
 _readdir_main()
 {
-    int fd = open("/bus/../..", 0);
+    int fd = open("/dev/block", 0);
     if (fd == -1) {
         kprintf(KERROR "fail to open\n");
         return;
diff --git a/lunaix-os/kernel/demos/iotest.c b/lunaix-os/kernel/demos/iotest.c
new file mode 100644 (file)
index 0000000..3fc8914
--- /dev/null
@@ -0,0 +1,29 @@
+#include <lunaix/fctrl.h>
+#include <lunaix/foptions.h>
+#include <lunaix/proc.h>
+#include <lunaix/syslog.h>
+
+LOG_MODULE("IOTEST")
+
+void
+_iotest_main()
+{
+    char test_sequence[] = "Once upon a time, in a magical land of Equestria. "
+                           "There were two regal sisters who ruled together "
+                           "and created harmony for all the land.";
+    int fd = open("/dev/block/bd0", 0);
+
+    if (fd < 0) {
+        kprintf(KERROR "fail to open (%d)\n", geterrno());
+        return;
+    }
+
+    lseek(fd, 1, FSEEK_SET);
+    write(fd, test_sequence, sizeof(test_sequence));
+
+    lseek(fd, -1, FSEEK_CUR);
+    char read_out[256];
+    read(fd, read_out, sizeof(read_out));
+
+    kprintf("%s", read_out);
+}
\ No newline at end of file
index a50a657b42867b9f3813c698f2320dc2c91ce81d..ad226ca8d74a2d0069808b7ffadd9a6bd342f11c 100644 (file)
@@ -59,18 +59,11 @@ twifs_init()
 struct twifs_node*
 __twifs_new_node(struct twifs_node* parent, const char* name, int name_len)
 {
-    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;
-    }
-
-    node = cake_grab(twi_pile);
+    struct twifs_node* node = cake_grab(twi_pile);
     memset(node, 0, sizeof(*node));
 
-    node->name = hname;
+    node->name = HSTR(name, name_len);
+    hstr_rehash(&node->name, HSTR_FULL_HASH);
     llist_init_head(&node->children);
 
     if (parent) {
@@ -95,6 +88,13 @@ twifs_file_node(struct twifs_node* parent, const char* name, int name_len)
 struct twifs_node*
 twifs_dir_node(struct twifs_node* parent, const char* name, int name_len)
 {
+    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);
     twi_node->itype = VFS_INODE_TYPE_DIR;
     twi_node->fops.readdir = __twifs_iterate_dir;
index 51ef5c9827f6612313564609f2d47029fa2c4c74..09668f501d09c09bec83b1a8492b6379760ed615 100644 (file)
@@ -204,6 +204,7 @@ vfs_walk(struct v_dnode* start,
 error:
     vfree(dnode->name.value);
     vfs_d_free(dnode);
+    *dentry = NULL;
     return errno;
 }
 
@@ -403,18 +404,21 @@ __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));
         fd_s->file = opened_file;
-        fd_s->pos = file->inode->fsize & -((options & FO_APPEND) == 0);
+        fd_s->pos = file->inode->fsize & -((options & FO_APPEND) != 0);
         __current->fdtable->fds[fd] = fd_s;
     }
 
     return SYSCALL_ESTATUS(errno);
 }
 
+#define GET_FD(fd, fd_s)                                                       \
+    (fd >= 0 && fd < VFS_MAX_FD && (fd_s = __current->fdtable->fds[fd]))
+
 __DEFINE_LXSYSCALL1(int, close, int, fd)
 {
     struct v_fd* fd_s;
     int errno;
-    if (fd < 0 || fd >= VFS_MAX_FD || !(fd_s = __current->fdtable->fds[fd])) {
+    if (!GET_FD(fd, fd_s)) {
         errno = EBADF;
     } else if (!(errno = vfs_close(fd_s->file))) {
         vfree(fd_s);
@@ -442,7 +446,7 @@ __DEFINE_LXSYSCALL2(int, readdir, int, fd, struct dirent*, dent)
 {
     struct v_fd* fd_s;
     int errno;
-    if (fd < 0 || fd >= VFS_MAX_FD || !(fd_s = __current->fdtable->fds[fd])) {
+    if (!GET_FD(fd, fd_s)) {
         errno = EBADF;
     } else if (!(fd_s->file->inode->itype & VFS_INODE_TYPE_DIR)) {
         errno = ENOTDIR;
@@ -490,12 +494,67 @@ done:
     return SYSCALL_ESTATUS(errno);
 }
 
-__DEFINE_LXSYSCALL3(size_t, read, int, fd, void*, buf, size_t, count)
+__DEFINE_LXSYSCALL3(int, read, int, fd, void*, buf, size_t, count)
 {
-    // TODO
+    int errno = 0;
+    struct v_fd* fd_s;
+    if (!GET_FD(fd, fd_s)) {
+        errno = EBADF;
+    } 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;
+        }
+    }
+
+    __current->k_status = errno;
+    return SYSCALL_ESTATUS(errno);
 }
 
-__DEFINE_LXSYSCALL3(size_t, write, int, fd, void*, buf, size_t, count)
+__DEFINE_LXSYSCALL3(int, write, int, fd, void*, buf, size_t, count)
 {
-    // TODO
+    int errno = 0;
+    struct v_fd* fd_s;
+    if (!GET_FD(fd, fd_s)) {
+        errno = EBADF;
+    } 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;
+        }
+    }
+
+    __current->k_status = errno;
+    return SYSCALL_ESTATUS(errno);
+}
+
+__DEFINE_LXSYSCALL3(int, lseek, int, fd, int, offset, int, options)
+{
+    int errno = 0;
+    struct v_fd* fd_s;
+    if (!GET_FD(fd, fd_s)) {
+        errno = EBADF;
+    } else {
+        size_t fpos = fd_s->file->f_pos;
+        switch (options) {
+            case FSEEK_CUR:
+                fpos = (size_t)((int)fd_s->file->f_pos + offset);
+                break;
+            case FSEEK_END:
+                fpos = (size_t)((int)fd_s->file->inode->fsize + offset);
+                break;
+            case FSEEK_SET:
+                fpos = offset;
+                break;
+
+            default:
+                break;
+        }
+        fd_s->pos = fpos;
+    }
+
+    __current->k_status = errno;
+    return SYSCALL_ESTATUS(errno);
 }
\ No newline at end of file
index 4cf0c82abab874365577b2e25d3cad8d8703bc6c..3ad6476679e9e76ff677bfb3a9b561f4900078b8 100644 (file)
@@ -1,4 +1,5 @@
 #include <arch/x86/boot/multiboot.h>
+#include <lunaix/block.h>
 #include <lunaix/common.h>
 #include <lunaix/fs.h>
 #include <lunaix/fs/twifs.h>
@@ -42,7 +43,8 @@ __do_reserved_memory(int unlock);
 
 #define USE_DEMO
 // #define DEMO_SIGNAL
-#define DEMO_READDIR
+// #define DEMO_READDIR
+#define DEMO_IOTEST
 
 extern void
 _pconsole_main();
@@ -56,6 +58,9 @@ _lxinit_main();
 extern void
 _readdir_main();
 
+extern void
+_iotest_main();
+
 void __USER__
 __proc0_usr()
 {
@@ -71,6 +76,8 @@ __proc0_usr()
         _signal_demo_main();
 #elif defined DEMO_READDIR
         _readdir_main();
+#elif defined DEMO_IOTEST
+        _iotest_main();
 #else
         _lxinit_main();
 #endif
@@ -119,39 +126,8 @@ extern uint8_t __kernel_end;              /* link/linker.ld */
 extern uint8_t __init_hhk_end;            /* link/linker.ld */
 extern multiboot_info_t* _k_init_mb_info; /* k_init.c */
 
-char test_sequence[] = "Once upon a time, in a magical land of Equestria. "
-                       "There were two regal sisters who ruled together "
-                       "and created harmony for all the land.";
-
-void
-__test_disk_io()
-{
-    struct hba_port* port = ahci_get_port(0);
-    struct hba_device* dev = port->device;
-    char* buffer = vzalloc_dma(port->device->block_size);
-    strcpy(buffer, test_sequence);
-    kprintf("WRITE: %s\n", buffer);
-    int result;
-
-    // 写入第一扇区 (LBA=0)
-    result = dev->ops.write_buffer(dev, 0, buffer, dev->block_size);
-    if (!result) {
-        kprintf(KWARN "fail to write: %x\n", dev->last_error);
-    }
-
-    memset(buffer, 0, dev->block_size);
-
-    // 读出我们刚刚写的内容!
-    result = dev->ops.read_buffer(dev, 0, buffer, dev->block_size);
-    kprintf(KDEBUG "%x, %x\n", port->regs[HBA_RPxIS], port->regs[HBA_RPxTFD]);
-    if (!result) {
-        kprintf(KWARN "fail to read: %x\n", dev->last_error);
-    } else {
-        kprint_hex(buffer, 256);
-    }
-
-    vfree_dma(buffer);
-}
+extern void
+block_twifs_create();
 
 void
 init_platform()
@@ -168,6 +144,7 @@ init_platform()
     clock_init();
     ps2_kbd_init();
     pci_init();
+    block_init();
     ahci_init();
     // ahci_list_device();
 
@@ -175,6 +152,8 @@ init_platform()
     vfs_init();
     twifs_init();
 
+    block_twifs_create();
+
     vfs_mount("/", "twifs", -1);
 
     //__test_disk_io();
index ee596b17c7d67d4b63f3c607ea4ba15f4b815513..d1ee39d21bc3424ce5399d2c60f71d53cea58dca 100644 (file)
@@ -203,6 +203,11 @@ __DEFINE_LXSYSCALL3(pid_t, waitpid, pid_t, pid, int*, status, int, options)
     return _wait(pid, status, options);
 }
 
+__DEFINE_LXSYSCALL(int, geterrno)
+{
+    return __current->k_status;
+}
+
 pid_t
 _wait(pid_t wpid, int* status, int options)
 {