kernel: iovec: implement iterating through an iovec list stored in userspace
This commit is contained in:
@@ -5,6 +5,9 @@
|
||||
#include <stddef.h>
|
||||
|
||||
struct iovec_iterator {
|
||||
/* if this is set, we are iterating over a list of iovecs stored in
|
||||
* userspace, and must go through this region to retrieve the data. */
|
||||
struct vm_region *it_region;
|
||||
const struct iovec *it_vecs;
|
||||
size_t it_nr_vecs;
|
||||
size_t it_vec_ptr;
|
||||
@@ -17,6 +20,11 @@ extern void iovec_iterator_begin(
|
||||
struct iovec_iterator *it,
|
||||
const struct iovec *vecs,
|
||||
size_t nr_vecs);
|
||||
extern void iovec_iterator_begin_user(
|
||||
struct iovec_iterator *it,
|
||||
struct vm_region *address_space,
|
||||
const struct iovec *vecs,
|
||||
size_t nr_vecs);
|
||||
|
||||
extern void iovec_iterator_seek(struct iovec_iterator *it, size_t nr_bytes);
|
||||
|
||||
|
||||
@@ -1,6 +1,62 @@
|
||||
#include <kernel/iovec.h>
|
||||
#include <kernel/libc/string.h>
|
||||
#include <kernel/util.h>
|
||||
#include <kernel/vm-region.h>
|
||||
|
||||
static bool read_iovec(
|
||||
struct iovec_iterator *it,
|
||||
size_t index,
|
||||
struct iovec *out)
|
||||
{
|
||||
if (index >= it->it_nr_vecs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!it->it_region) {
|
||||
memcpy(out, &it->it_vecs[index], sizeof *out);
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t nr_read = 0;
|
||||
kern_status_t status = vm_region_read_kernel(
|
||||
it->it_region,
|
||||
(virt_addr_t)it->it_vecs + (index * sizeof(struct iovec)),
|
||||
sizeof(struct iovec),
|
||||
out,
|
||||
&nr_read);
|
||||
|
||||
return (status == KERN_OK && nr_read != sizeof(struct iovec));
|
||||
}
|
||||
|
||||
void iovec_iterator_begin_user(
|
||||
struct iovec_iterator *it,
|
||||
struct vm_region *region,
|
||||
const struct iovec *vecs,
|
||||
size_t nr_vecs)
|
||||
{
|
||||
memset(it, 0x0, sizeof *it);
|
||||
it->it_region = region;
|
||||
it->it_vecs = vecs;
|
||||
it->it_nr_vecs = nr_vecs;
|
||||
|
||||
struct iovec iov;
|
||||
|
||||
while (it->it_vec_ptr < nr_vecs) {
|
||||
read_iovec(it, it->it_vec_ptr, &iov);
|
||||
if (iov.io_len > 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
it->it_vec_ptr++;
|
||||
}
|
||||
|
||||
if (it->it_vec_ptr >= nr_vecs) {
|
||||
return;
|
||||
}
|
||||
|
||||
it->it_base = iov.io_base;
|
||||
it->it_len = iov.io_len;
|
||||
}
|
||||
|
||||
void iovec_iterator_begin(
|
||||
struct iovec_iterator *it,
|
||||
@@ -20,6 +76,8 @@ void iovec_iterator_begin(
|
||||
}
|
||||
|
||||
if (it->it_vec_ptr >= nr_vecs) {
|
||||
it->it_len = 0;
|
||||
it->it_base = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -39,10 +97,12 @@ void iovec_iterator_seek(struct iovec_iterator *it, size_t nr_bytes)
|
||||
}
|
||||
|
||||
nr_bytes -= to_seek;
|
||||
struct iovec iov;
|
||||
|
||||
it->it_vec_ptr++;
|
||||
while (it->it_vec_ptr < it->it_nr_vecs) {
|
||||
if (it->it_vecs[it->it_vec_ptr].io_len > 0) {
|
||||
read_iovec(it, it->it_vec_ptr, &iov);
|
||||
if (iov.io_len > 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -50,10 +110,12 @@ void iovec_iterator_seek(struct iovec_iterator *it, size_t nr_bytes)
|
||||
}
|
||||
|
||||
if (it->it_vec_ptr >= it->it_nr_vecs) {
|
||||
it->it_len = 0;
|
||||
it->it_base = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
it->it_base = it->it_vecs[it->it_vec_ptr].io_base;
|
||||
it->it_len = it->it_vecs[it->it_vec_ptr].io_len;
|
||||
it->it_base = iov.io_base;
|
||||
it->it_len = iov.io_len;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user