From 3a8a88ae03ff1cd44292d4cd79420a2794a8f49e Mon Sep 17 00:00:00 2001 From: acevest Date: Sat, 21 Oct 2023 00:06:53 +0800 Subject: [PATCH] =?utf8?q?=E5=9C=A8=20disk=5Frequest=20=E9=87=8C=E6=B7=BB?= =?utf8?q?=E5=8A=A0=20bbuffer=20=E5=AD=97=E6=AE=B5;=E5=B0=86block=5Fread?= =?utf8?q?=20=E5=8A=A0=E5=88=B0=20bread=20=E9=80=BB=E8=BE=91=E9=87=8C;?= =?utf8?q?=E6=B7=BB=E5=8A=A0=20brelse?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- drivers/ata.c | 38 +++++++++++----- drivers/block.c | 37 ++++++---------- drivers/keyboard.c | 11 ----- fs/buffer.c | 55 ++++++++++++++++++----- gdbscript | 2 + include/buffer.h | 4 ++ include/disk.h | 12 ++--- include/wait.h | 13 +++++- kernel/completion.c | 8 +++- kernel/task_disk.c | 14 +++++- kernel/wait.c | 106 ++++++++++++-------------------------------- 11 files changed, 155 insertions(+), 145 deletions(-) diff --git a/drivers/ata.c b/drivers/ata.c index 6aaef8f..8feb182 100644 --- a/drivers/ata.c +++ b/drivers/ata.c @@ -201,19 +201,47 @@ void ide_ata_init() { } } +void ide_disk_read(dev_t dev, uint32_t sect_nr, uint32_t count, bbuffer_t *b) { + disk_request_t r; + r.dev = dev; + r.command = DISK_REQ_READ; + r.pos = sect_nr; + r.count = count; + r.buf = NULL; + r.bb = b; + send_disk_request(&r); +} + +void tmp_ide_disk_read(dev_t dev, uint32_t sect_nr, uint32_t count, char *buf) { + disk_request_t r; + r.dev = dev; + r.command = DISK_REQ_READ; + r.pos = sect_nr; + r.count = count; + r.buf = buf; + r.bb = NULL; + send_disk_request(&r); +} + // mbr_ext_offset: 在MBR中的扩展分区记录里的偏移地址 // lba_partition_table: 扩展分区的真实偏移地址 void read_partition_table(ide_drive_t *drv, uint32_t mbr_ext_offset, uint32_t lba_partition_table, int depth) { disk_request_t r; char *sect = kmalloc(SECT_SIZE, 0); +#if 1 + // part_no == 0 代表整场硬盘 + tmp_ide_disk_read(MAKE_DISK_DEV(drv->drv_no, 0), lba_partition_table, 1, sect); +#else // part_no == 0 代表整场硬盘 r.dev = MAKE_DISK_DEV(drv->drv_no, 0); r.command = DISK_REQ_READ; r.pos = lba_partition_table; r.count = 1; r.buf = sect; + r.bb = NULL; send_disk_request(&r); +#endif ide_part_t *part = 0; uint32_t part_id = 0; @@ -292,16 +320,6 @@ void ide_read_partions() { } } -void ide_disk_read(dev_t dev, uint32_t sect_nr, uint32_t count, char *buf) { - disk_request_t r; - r.dev = dev; - r.command = DISK_REQ_READ; - r.pos = sect_nr; - r.count = count; - r.buf = buf; - send_disk_request(&r); -} - // ATA_CMD_READ_DMA_EXT void ata_dma_read_ext(int drv, uint64_t pos, uint16_t count, void *dest) { // Intel® diff --git a/drivers/block.c b/drivers/block.c index 674e57e..1b7b8bb 100644 --- a/drivers/block.c +++ b/drivers/block.c @@ -12,23 +12,15 @@ #include #include -bbuffer_t *block_read(dev_t dev, uint32_t block) { - bbuffer_t *bb = 0; - - assert(DEV_MAJOR(dev) == DEV_MAJOR_DISK); - // assert(DEV_MINOR(dev) == 1); - - // 目前不提供hash表组强起来的缓冲功能 - // 直接读 - - // TODO:根据dev得到正确的blocksize - const int blocksize = 1024; - - bb->data = kmalloc(blocksize, 0); // debug - - ide_disk_read(dev, block * blocksize / 512, 1, bb->data); - - return bb; +void ide_disk_read(dev_t dev, uint32_t sect_nr, uint32_t count, bbuffer_t *b); +void block_read(bbuffer_t *b) { + assert(b != NULL); + assert(b->data != NULL); + assert(b->page != NULL); + assert(DEV_MAJOR(b->dev) == DEV_MAJOR_DISK); + assert(b->block_size != 0); + + ide_disk_read(b->dev, (b->block * b->block_size) / 512, b->block_size / 512, b); } #include @@ -38,11 +30,10 @@ void ata_read_ext2_sb() { // 则ext2_superblock应该在第1个block的offset为0的位置 // ext2_superblock默认大小1024 - const int offset = 0; - const int size = offset + 1024; - const int block = 1; - - bbuffer_t *bb = block_read(system.root_dev, block); + const int block = 0; + const int offset = 1024; + const int size = 4096; + bbuffer_t *bb = bread(system.root_dev, block, size); ext2_sb_t *p = (ext2_sb_t *)(bb->data + offset); printk("inodes count %u inodes per group %u free %u\n", p->s_inodes_count, p->s_inodes_per_group, @@ -55,6 +46,4 @@ void ata_read_ext2_sb() { strncpy(volume_name, p->s_volume_name, 16); volume_name[16] = 0; printk("volume %s\n", volume_name); - // printk("last mounted %s\n", p->s_last_mounted); - kfree(bb->data); } diff --git a/drivers/keyboard.c b/drivers/keyboard.c index c3451b1..ff6aa8d 100644 --- a/drivers/keyboard.c +++ b/drivers/keyboard.c @@ -28,8 +28,6 @@ void ide_debug(); void ide_status(); void debug_sched(); -int debug_wait_queue_put(unsigned int v); - void kbd_debug(uint8_t scan_code); char kbd_char_tbl[] = { @@ -93,15 +91,6 @@ void kbd_debug(uint8_t scan_code) { tty_switch(debug_tty); } - if (scan_code == 0x3F) // F5 - debug_wait_queue_put(0); - if (scan_code == 0x40) // F6 - debug_wait_queue_put(1); - if (scan_code == 0x41) // F7 - debug_wait_queue_put(2); - if (scan_code == 0x42) // F8 - debug_wait_queue_put(7); - if (scan_code == 0x43) { // F9 void ata_test(uint64_t nr); ata_test(0); diff --git a/fs/buffer.c b/fs/buffer.c index 5d98a22..fc98755 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -24,6 +24,7 @@ typedef struct bbuffer_store { int blocksize; // list_head_t cache_list; list_head_t free_list; + wait_queue_head_t waitq; } bbuffer_store_t; // 1024, 2048, 4096 @@ -51,26 +52,29 @@ bbuffer_store_t *getstore(uint32_t size) { bbuffer_t *get_from_hash_table(dev_t dev, uint64_t block, uint32_t size) { list_head_t *p = 0; + bbuffer_t *b = 0; + uint32_t hash = hashfn(dev, block); assert(hash < BLOCK_BUFFER_HASH_TABLE_SIZE); list_for_each(p, block_buffer_hash_table + hash) { - bbuffer_t *b = list_entry(p, bbuffer_t, node); - if (b->dev != dev) { + bbuffer_t *t = list_entry(p, bbuffer_t, node); + if (t->dev != dev) { continue; } - if (b->block != block) { + if (t->block != block) { continue; } - assert(b->block_size == size); + assert(t->block_size == size); + + b = t; break; } // 如果找到了就直接返回 - if (0 != p) { - bbuffer_t *b = list_entry(p, bbuffer_t, node); + if (b != NULL) { atomic_inc(&b->ref_count); assert(0 != b); assert(0 != b->data); @@ -119,7 +123,7 @@ again: irq_restore(iflags); retry++; // wait on free list - // ... + wait_on(&s->waitq); goto again; } @@ -138,17 +142,44 @@ again: b->ref_count = 1; b->uptodate = 0; - list_init(&b->node); + return b; +} - irq_restore(iflags); +void brelse(bbuffer_t *b) { + assert(b != NULL); + assert(b->ref_count > 0); - return b; + wait_completion(&b->io_done); + + bbuffer_store_t *s = getstore(b->block_size); + assert(s != NULL); + assert(s - store < 3); + + wake_up(&s->waitq); } bbuffer_t *bread(dev_t dev, uint64_t block, uint32_t size) { bbuffer_t *b = getblk(dev, block, size); - return b; + assert(b != NULL); + + if (b->uptodate == 1) { + return b; + } + + // READ + void block_read(bbuffer_t * b); + block_read(b); + + // 等待I/O结束 + wait_completion(&b->io_done); + if (b->uptodate == 1) { + return b; + } + + brelse(b); + + return NULL; } void init_buffer() { @@ -170,6 +201,7 @@ void init_buffer() { store[i].blocksize = blocksize; // list_init(&store[i].cache_list); list_init(&store[i].free_list); + init_wait_queue_head(&store[i].waitq); int page_left_space = 0; void *data = NULL; @@ -191,6 +223,7 @@ void init_buffer() { b->page = page; b->uptodate = 0; init_completion(&b->io_done); + complete(&b->io_done); list_init(&b->node); assert(NULL != b->data); diff --git a/gdbscript b/gdbscript index 7e970f0..d5fe482 100644 --- a/gdbscript +++ b/gdbscript @@ -8,6 +8,8 @@ set confirm off #break *0x100000 +b block.c:63 +#b task_disk.c:94 #handle SIGINT nostop noprint diff --git a/include/buffer.h b/include/buffer.h index c64a3a8..b415756 100644 --- a/include/buffer.h +++ b/include/buffer.h @@ -26,3 +26,7 @@ typedef struct bbuffer { uint16_t block_size; // block size uint16_t uptodate : 1; } bbuffer_t; + +bbuffer_t *bread(dev_t dev, uint64_t block, uint32_t size); + +void brelse(bbuffer_t *b); diff --git a/include/disk.h b/include/disk.h index 751b5c9..c63d184 100644 --- a/include/disk.h +++ b/include/disk.h @@ -9,10 +9,11 @@ #pragma once +#include #include +#include #include #include -#include typedef enum { DISK_REQ_IDENTIFY, @@ -21,9 +22,10 @@ typedef enum { typedef struct disk_request { dev_t dev; - uint64_t pos; // 扇区号 - uint16_t count; // 扇区数 - void *buf; // 到的缓冲区 + uint64_t pos; // 扇区号 + uint16_t count; // 扇区数 + void *buf; // 到的缓冲区 + bbuffer_t *bb; disk_request_cmd_t command; // 命令 list_head_t list; semaphore_t sem; @@ -38,5 +40,3 @@ typedef struct { } disk_request_queue_t; void send_disk_request(disk_request_t *r); - -void ide_disk_read(dev_t dev, uint32_t sect_nr, uint32_t count, char *buf); diff --git a/include/wait.h b/include/wait.h index f1bf5ea..b591ea3 100644 --- a/include/wait.h +++ b/include/wait.h @@ -45,10 +45,15 @@ void prepare_to_wait(wait_queue_head_t *head, wait_queue_t *wq, unsigned int sta void __end_wait(wait_queue_t *wq); -// void sleep_on(wait_queue_head_t *head); +// 使用这个函数的时候需要注意 +// 设置condition为真的语句和wake_up原子地执行 void wake_up(wait_queue_head_t *head); +void __wake_up(wait_queue_head_t *head, int nr); -void schedule(); +// 只要保证condition设置为真时,它是和wake_up一起原子执行的 +// 那就能保证condition为真是如下__wait_event和wait_event里的if不出问题 +// 也就是不会出现if-break后进程又再次因为其它原因阻塞后,又被wake_up的逻辑 +// 设置为READY状态 #define __wait_event(head, condition) \ do { \ DECLARE_WAIT_QUEUE(__wait, current); \ @@ -57,6 +62,7 @@ void schedule(); if ((condition)) { \ break; \ } \ + void schedule(); \ schedule(); \ } \ __end_wait(&__wait); \ @@ -68,3 +74,6 @@ void schedule(); __wait_event(head, (condition)); \ } \ } while (0) + +// 无条件wait +void wait_on(wait_queue_head_t *head); diff --git a/kernel/completion.c b/kernel/completion.c index 78c191c..8d2ab8b 100644 --- a/kernel/completion.c +++ b/kernel/completion.c @@ -10,13 +10,17 @@ #include #include -void wait_completion(completion_t *x) { wait_event(&x->wait, (x->done == 1)); } +void wait_completion(completion_t *x) { + // + wait_event(&x->wait, (x->done == 1)); +} void complete(completion_t *x) { uint32_t iflags; irq_save(iflags); x->done = 1; - wake_up(&x->wait); + // wake_up(&x->wait); + __wake_up(&x->wait, 0); irq_restore(iflags); } diff --git a/kernel/task_disk.c b/kernel/task_disk.c index a774398..ae22190 100644 --- a/kernel/task_disk.c +++ b/kernel/task_disk.c @@ -102,8 +102,13 @@ void disk_task_entry(void *arg) { break; case DISK_REQ_READ: assert(r->count > 0); - assert(r->buf != NULL); - ata_dma_read_ext(drv_no, pos, r->count, r->buf); + assert(r->buf != NULL || r->bb->data != NULL); + // printk("DISK READ drv_no %u pos %u count %u\n", drv_no, (uint32_t)pos, r->count); + if (r->bb != 0) { + ata_dma_read_ext(drv_no, pos, r->count, r->bb->data); + } else { + ata_dma_read_ext(drv_no, pos, r->count, r->buf); + } break; default: panic("invalid disk request command"); @@ -119,6 +124,11 @@ void disk_task_entry(void *arg) { ata_pio_read_data(drv_no, 1, r->buf); } + if (r->bb != 0) { + r->bb->uptodate = 1; + complete(&r->bb->io_done); + } + // 唤醒等待该请求的进程 up(&(r->sem)); } diff --git a/kernel/wait.c b/kernel/wait.c index 316205e..0ee1d13 100644 --- a/kernel/wait.c +++ b/kernel/wait.c @@ -32,18 +32,6 @@ volatile void __end_wait(wait_queue_t *wq) { irq_restore(flags); } -volatile void wake_up(wait_queue_head_t *head) { - unsigned long flags; - wait_queue_t *p, *tmp; - irq_save(flags); - list_for_each_entry_safe(p, tmp, &head->task_list, task_list) { - list_del(&p->task_list); - // printk("wakeup: %s\n", p->task->name); - p->task->state = TASK_READY; - } - irq_restore(flags); -} - volatile void add_wait_queue(wait_queue_head_t *head, wait_queue_t *wq) { unsigned long flags; irq_save(flags); @@ -58,79 +46,43 @@ volatile void del_wait_queue(wait_queue_head_t *head, wait_queue_t *wq) { irq_restore(flags); } -// volatile void sleep_on(wait_queue_head_t *head) { -// DECLARE_WAIT_QUEUE(wait, current); - -// unsigned long flags; -// irq_save(flags); - -// current->state = TASK_WAIT; -// current->reason = "sleep_on"; - -// list_add_tail(&wait.task_list, &head->task_list); - -// irq_restore(flags); - -// schedule(); - -// // wake_up操作会把wait从heat链表上删除 -// // 所以这里就不用做什么了 -// } - -// volatile void __wake_up(wait_queue_head_t *head, int nr) { -// unsigned long flags; -// wait_queue_t *p, *tmp; -// irq_save(flags); -// list_for_each_entry_safe(p, tmp, &head->task_list, task_list) { -// list_del(&p->task_list); -// // printk("wakeup: %s\n", p->task->name); -// p->task->state = TASK_READY; -// current->reason = "wake_up"; - -// --nr; -// if (nr == 0) { -// break; -// } -// } -// irq_restore(flags); +volatile void __wake_up(wait_queue_head_t *head, int nr) { + unsigned long flags; + wait_queue_t *p, *tmp; + irq_save(flags); + list_for_each_entry_safe(p, tmp, &head->task_list, task_list) { + p->task->state = TASK_READY; + current->reason = "wake_up"; -// // no schedule() here. -// } + --nr; + if (nr == 0) { + break; + } + } + irq_restore(flags); -// volatile void wake_up(wait_queue_head_t *head) { __wake_up(head, 1); } + // no schedule() here. +} -// #include -// DECLARE_WAIT_QUEUE_HEAD(debug_wq); -// unsigned int debug_global_var = 0; -// int debug_wait_queue_get() { -// unsigned int v = 0; -// task_union *task = current; -// DECLARE_WAIT_QUEUE(wait, task); -// add_wait_queue(&debug_wq, &wait); +volatile void wake_up(wait_queue_head_t *head) { + // + __wake_up(head, 1); +} -// while (1) { -// printd("pid %d is going to wait\n", sysc_getpid()); -// task->state = TASK_WAIT; +volatile void wait_on(wait_queue_head_t *head) { + DECLARE_WAIT_QUEUE(wait, current); -// disable_irq(); -// v = debug_global_var; -// if (debug_global_var != 0) debug_global_var--; -// enable_irq(); + unsigned long flags; + irq_save(flags); -// if (v != 0) break; + current->state = TASK_WAIT; + current->reason = "sleep_on"; -// schedule(); -// printd("pid %d is running\n", sysc_getpid()); -// } + list_add_tail(&wait.task_list, &head->task_list); -// printd("pid %d is really running\n", sysc_getpid()); -// task->state = TASK_READY; -// del_wait_queue(&debug_wq, &wait); + irq_restore(flags); -// return v; -// } + schedule(); -int debug_wait_queue_put(unsigned int v) { - // debug_global_var = v; - // wake_up(&debug_wq); + __end_wait(&wait); } -- 2.44.0