mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-27 12:48:22 +00:00
devfs: use iovec_iterator internally
This commit is contained in:
+37
-14
@@ -8,8 +8,8 @@
|
||||
#include <kernel/vmm.h>
|
||||
#include <kernel/usercopy.h>
|
||||
|
||||
#define DISK_READ(desc, buf, lba, size) (desc)->read(desc->private, buf, lba, size)
|
||||
#define DISK_WRITE(desc, buf, lba, size) (desc)->write(desc->private, buf, lba, size)
|
||||
#define DISK_READ(desc, it, lba, size) (desc)->read(desc->private, it, lba, size)
|
||||
#define DISK_WRITE(desc, it, lba, size) (desc)->write(desc->private, it, lba, size)
|
||||
|
||||
typedef struct {
|
||||
char signature[8];
|
||||
@@ -72,10 +72,34 @@ static void bytestolba(blockdesc_t *desc, uintmax_t offset, size_t size, uintmax
|
||||
*lbacount = toplba - *lbaoffset;
|
||||
}
|
||||
|
||||
static inline int disk_read_direct(blockdesc_t *desc, void *buffer, size_t lba_offset, size_t block_count) {
|
||||
iovec_t iovec = {
|
||||
.addr = buffer,
|
||||
.len = block_count * desc->blocksize
|
||||
};
|
||||
|
||||
iovec_iterator_t iovec_iterator;
|
||||
iovec_iterator_init(&iovec_iterator, &iovec, 1);
|
||||
|
||||
return DISK_READ(desc, &iovec_iterator, lba_offset, block_count);
|
||||
}
|
||||
|
||||
static inline int disk_write_direct(blockdesc_t *desc, void *buffer, size_t lba_offset, size_t block_count) {
|
||||
iovec_t iovec = {
|
||||
.addr = buffer,
|
||||
.len = block_count * desc->blocksize
|
||||
};
|
||||
|
||||
iovec_iterator_t iovec_iterator;
|
||||
iovec_iterator_init(&iovec_iterator, &iovec, 1);
|
||||
|
||||
return DISK_WRITE(desc, &iovec_iterator, lba_offset, block_count);
|
||||
}
|
||||
|
||||
#define MAP_FLAGS (ARCH_MMU_FLAGS_READ | ARCH_MMU_FLAGS_WRITE | ARCH_MMU_FLAGS_NOEXEC)
|
||||
|
||||
// this is only really called by the page cache VOP_GETPAGE and VOP_PUTPAGE functions, so we can make a few assumptions
|
||||
static int rwblock(int minor, void *buffer, size_t size, uintmax_t offset, int flags, bool write, size_t *done) {
|
||||
static int rwblock(int minor, iovec_iterator_t *iovec_iterator, size_t size, uintmax_t offset, int flags, bool write, size_t *done) {
|
||||
blockdesc_t *desc = getdesc(minor);
|
||||
if (desc == NULL)
|
||||
return ENODEV;
|
||||
@@ -104,28 +128,27 @@ static int rwblock(int minor, void *buffer, size_t size, uintmax_t offset, int f
|
||||
|
||||
int error = 0;
|
||||
if (write) {
|
||||
error = DISK_WRITE(desc, buffer, lbaoffset + desc->lbaoffset, lbacount);
|
||||
error = DISK_WRITE(desc, iovec_iterator, lbaoffset + desc->lbaoffset, lbacount);
|
||||
if (error)
|
||||
goto cleanup;
|
||||
} else {
|
||||
error = DISK_READ(desc, buffer, lbaoffset + desc->lbaoffset, lbacount);
|
||||
error = DISK_READ(desc, iovec_iterator, lbaoffset + desc->lbaoffset, lbacount);
|
||||
if (error)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
||||
*done = size;
|
||||
|
||||
cleanup:
|
||||
return error;
|
||||
}
|
||||
|
||||
static int read(int minor, void *buffer, size_t size, uintmax_t offset, int flags, size_t *readc) {
|
||||
return rwblock(minor, buffer, size, offset, flags, false, readc);
|
||||
static int read(int minor, iovec_iterator_t *iovec_iterator, size_t size, uintmax_t offset, int flags, size_t *readc) {
|
||||
return rwblock(minor, iovec_iterator, size, offset, flags, false, readc);
|
||||
}
|
||||
|
||||
static int write(int minor, void *buffer, size_t size, uintmax_t offset, int flags, size_t *writec) {
|
||||
return rwblock(minor, buffer, size, offset, flags, true, writec);
|
||||
static int write(int minor, iovec_iterator_t *iovec_iterator, size_t size, uintmax_t offset, int flags, size_t *writec) {
|
||||
return rwblock(minor, iovec_iterator, size, offset, flags, true, writec);
|
||||
}
|
||||
|
||||
static int ioctl(int minor, unsigned long request, void *arg, int *result, cred_t *cred) {
|
||||
@@ -177,7 +200,7 @@ static int detectpart(blockdesc_t *desc) {
|
||||
// read first two sectors
|
||||
void *sects = vmm_map(NULL, desc->blocksize * 2, VMM_FLAGS_ALLOCATE, MAP_FLAGS, NULL);
|
||||
__assert(sects);
|
||||
__assert(DISK_READ(desc, sects, 0, 2) == 0);
|
||||
__assert(disk_read_direct(desc, sects, 0, 2) == 0);
|
||||
|
||||
void *lba0 = sects;
|
||||
void *lba1 = (void *)((uintptr_t)lba0 + desc->blocksize);
|
||||
@@ -199,7 +222,7 @@ static void dogpt(blockdesc_t *desc, char *name) {
|
||||
// get header
|
||||
void *lba1 = vmm_map(NULL, desc->blocksize, VMM_FLAGS_ALLOCATE, MAP_FLAGS, NULL);
|
||||
__assert(lba1);
|
||||
__assert(DISK_READ(desc, lba1, 1, 1) == 0);
|
||||
__assert(disk_read_direct(desc, lba1, 1, 1) == 0);
|
||||
gptheader_t *header = lba1;
|
||||
|
||||
// get partition table
|
||||
@@ -207,7 +230,7 @@ static void dogpt(blockdesc_t *desc, char *name) {
|
||||
size_t tablelbasize = ROUND_UP(tablebytesize, desc->blocksize) / desc->blocksize;
|
||||
void *tablebuffer = vmm_map(NULL, tablelbasize * desc->blocksize, VMM_FLAGS_ALLOCATE, MAP_FLAGS, NULL);
|
||||
__assert(tablebuffer);
|
||||
__assert(DISK_READ(desc, tablebuffer, header->entryarraylbastart, tablelbasize) == 0);
|
||||
__assert(disk_read_direct(desc, tablebuffer, header->entryarraylbastart, tablelbasize) == 0);
|
||||
|
||||
// name + 'p' + 3 digits (max gpt partition count is 128) + '\0'
|
||||
size_t namebuflen = strlen(name) + 5;
|
||||
@@ -241,7 +264,7 @@ static void dombr(blockdesc_t *desc, char *name) {
|
||||
// get entries
|
||||
void *lba0 = vmm_map(NULL, desc->blocksize, VMM_FLAGS_ALLOCATE, MAP_FLAGS, NULL);
|
||||
__assert(lba0);
|
||||
__assert(DISK_READ(desc, lba0, 0, 1) == 0);
|
||||
__assert(disk_read_direct(desc, lba0, 0, 1) == 0);
|
||||
mbrentry_t *mbrents = (mbrentry_t *)((uintptr_t)lba0 + MBR_ENTRIES_OFFSET);
|
||||
|
||||
// name + 'p' + single digit (max mbr partition count is 4) + '\0'
|
||||
|
||||
+23
-10
@@ -503,22 +503,35 @@ static int iowrite(nvmenamespace_t *namespace, uint64_t prp[2], uint64_t lba, ui
|
||||
|
||||
#define PAGES_FLAGS (ARCH_MMU_FLAGS_READ | ARCH_MMU_FLAGS_WRITE | ARCH_MMU_FLAGS_NOEXEC)
|
||||
|
||||
static int rwblocks(nvmenamespace_t *namespace, void *buffer, uintmax_t lba, size_t count, bool write) {
|
||||
static int rwblocks(nvmenamespace_t *namespace, iovec_iterator_t *iovec_iterator, uintmax_t lba, size_t count, bool write) {
|
||||
__assert(namespace->blocksize <= PAGE_SIZE);
|
||||
|
||||
int err = 0;
|
||||
|
||||
uint64_t prp[2] = {0, 0};
|
||||
__assert(((uintptr_t)buffer % namespace->blocksize) == 0);
|
||||
uintmax_t pageoffset = (uintptr_t)buffer - ROUND_DOWN((uintptr_t)buffer, PAGE_SIZE);
|
||||
|
||||
int done = 0;
|
||||
while (done < count) {
|
||||
size_t docount = (done == 0) ? (PAGE_SIZE - pageoffset) / namespace->blocksize : PAGE_SIZE / namespace->blocksize;
|
||||
void *page;
|
||||
size_t page_offset, page_remaining;
|
||||
// XXX this takes an entire page from the iovec, though it may not be used fully.
|
||||
// ATM this does not really matter but it could at one point in the future
|
||||
err = iovec_iterator_next_page(iovec_iterator, &page_offset, &page_remaining, &page);
|
||||
|
||||
if (err)
|
||||
break;
|
||||
|
||||
// check that there is enough space to complete the write of this page
|
||||
__assert(page);
|
||||
__assert(page_remaining >= min((count - done) * namespace->blocksize, PAGE_SIZE));
|
||||
|
||||
// and that the space is aligned to the block size
|
||||
__assert((page_remaining % namespace->blocksize) == 0);
|
||||
|
||||
size_t docount = page_remaining / namespace->blocksize;
|
||||
docount = min(docount, count - done);
|
||||
|
||||
prp[0] = (uint64_t)vmm_getphysical((void *)((uintptr_t)buffer + done * namespace->blocksize), true);
|
||||
__assert(prp[0]);
|
||||
prp[0] = (uint64_t)page + page_offset;
|
||||
|
||||
err = write ? iowrite(namespace, prp, lba + done, docount) : ioread(namespace, prp, lba + done, docount);
|
||||
|
||||
@@ -533,12 +546,12 @@ static int rwblocks(nvmenamespace_t *namespace, void *buffer, uintmax_t lba, siz
|
||||
return err;
|
||||
}
|
||||
|
||||
static int read(void *private, void *buffer, uintmax_t lba, size_t count) {
|
||||
return rwblocks(private, buffer, lba, count, false);
|
||||
static int read(void *private, iovec_iterator_t *iovec_iterator, uintmax_t lba, size_t count) {
|
||||
return rwblocks(private, iovec_iterator, lba, count, false);
|
||||
}
|
||||
|
||||
static int write(void *private, void *buffer, uintmax_t lba, size_t count) {
|
||||
return rwblocks(private, buffer, lba, count, true);
|
||||
static int write(void *private, iovec_iterator_t *iovec_iterator, uintmax_t lba, size_t count) {
|
||||
return rwblocks(private, iovec_iterator, lba, count, true);
|
||||
}
|
||||
|
||||
static void initnamespace(nvmecontroller_t *controller, int id) {
|
||||
|
||||
@@ -99,7 +99,7 @@ static void vioblk_enqueue(vioblkdev_t *blkdev, requestheader_t *headerphys, voi
|
||||
interrupt_set(intstatus);
|
||||
}
|
||||
|
||||
static int vioblk_rw(vioblkdev_t *blkdev, void *buffer, uintmax_t lba, size_t count, bool write) {
|
||||
static int vioblk_rw(vioblkdev_t *blkdev, iovec_iterator_t *iovec_iterator, uintmax_t lba, size_t count, bool write) {
|
||||
void *physpage = pmm_allocpage(PMM_SECTION_DEFAULT);
|
||||
if (physpage == NULL)
|
||||
return ENOMEM;
|
||||
@@ -112,21 +112,28 @@ static int vioblk_rw(vioblkdev_t *blkdev, void *buffer, uintmax_t lba, size_t co
|
||||
|
||||
headerhhdm->type = write ? HEADER_TYPE_WRITE : HEADER_TYPE_READ;
|
||||
|
||||
__assert(((uintptr_t)buffer % 512) == 0);
|
||||
uintmax_t pageoffset = (uintptr_t)buffer - ROUND_DOWN((uintptr_t)buffer, PAGE_SIZE);
|
||||
|
||||
int done = 0;
|
||||
while (done < count) {
|
||||
void *page;
|
||||
size_t page_offset, page_remaining;
|
||||
err = iovec_iterator_next_page(iovec_iterator, &page_offset, &page_remaining, &page);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
// check that there is enough space to complete the write of this page
|
||||
__assert(page);
|
||||
__assert(page_remaining >= min((count - done) * 512, PAGE_SIZE));
|
||||
|
||||
// and that the space is aligned to the block size
|
||||
__assert((page_remaining % 512) == 0);
|
||||
|
||||
headerhhdm->sector = lba + done;
|
||||
size_t docount = (done == 0) ? (PAGE_SIZE - pageoffset) / 512 : PAGE_SIZE / 512;
|
||||
size_t docount = page_remaining / 512;
|
||||
docount = min(docount, count - done);
|
||||
|
||||
void *bufferphys = vmm_getphysical((void *)((uintptr_t)buffer + done * 512), true);
|
||||
__assert(bufferphys);
|
||||
vioblk_enqueue(blkdev, header, (void *)((uintptr_t)page + page_offset), PAGE_SIZE, status, write);
|
||||
|
||||
vioblk_enqueue(blkdev, header, bufferphys, docount * 512, status, write);
|
||||
|
||||
pmm_release(bufferphys);
|
||||
pmm_release(page);
|
||||
|
||||
if (*statushhdm) {
|
||||
err = EIO;
|
||||
@@ -140,12 +147,12 @@ static int vioblk_rw(vioblkdev_t *blkdev, void *buffer, uintmax_t lba, size_t co
|
||||
return err;
|
||||
}
|
||||
|
||||
static int vioblk_write(void *private, void *buffer, uintmax_t lba, size_t count) {
|
||||
return vioblk_rw(private, buffer, lba, count, true);
|
||||
static int vioblk_write(void *private, iovec_iterator_t *iovec_iterator, uintmax_t lba, size_t count) {
|
||||
return vioblk_rw(private, iovec_iterator, lba, count, true);
|
||||
}
|
||||
|
||||
static int vioblk_read(void *private, void *buffer, uintmax_t lba, size_t count) {
|
||||
return vioblk_rw(private, buffer, lba, count, false);
|
||||
static int vioblk_read(void *private, iovec_iterator_t *iovec_iterator, uintmax_t lba, size_t count) {
|
||||
return vioblk_rw(private, iovec_iterator, lba, count, false);
|
||||
}
|
||||
|
||||
int vioblk_newdevice(viodevice_t *viodevice) {
|
||||
|
||||
Reference in New Issue
Block a user