kernel: iovec: implement iterating through an iovec list stored in userspace
This commit is contained in:
@@ -5,6 +5,9 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
struct iovec_iterator {
|
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;
|
const struct iovec *it_vecs;
|
||||||
size_t it_nr_vecs;
|
size_t it_nr_vecs;
|
||||||
size_t it_vec_ptr;
|
size_t it_vec_ptr;
|
||||||
@@ -17,6 +20,11 @@ extern void iovec_iterator_begin(
|
|||||||
struct iovec_iterator *it,
|
struct iovec_iterator *it,
|
||||||
const struct iovec *vecs,
|
const struct iovec *vecs,
|
||||||
size_t nr_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);
|
extern void iovec_iterator_seek(struct iovec_iterator *it, size_t nr_bytes);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,62 @@
|
|||||||
#include <kernel/iovec.h>
|
#include <kernel/iovec.h>
|
||||||
#include <kernel/libc/string.h>
|
#include <kernel/libc/string.h>
|
||||||
#include <kernel/util.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(
|
void iovec_iterator_begin(
|
||||||
struct iovec_iterator *it,
|
struct iovec_iterator *it,
|
||||||
@@ -20,6 +76,8 @@ void iovec_iterator_begin(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (it->it_vec_ptr >= nr_vecs) {
|
if (it->it_vec_ptr >= nr_vecs) {
|
||||||
|
it->it_len = 0;
|
||||||
|
it->it_base = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,10 +97,12 @@ void iovec_iterator_seek(struct iovec_iterator *it, size_t nr_bytes)
|
|||||||
}
|
}
|
||||||
|
|
||||||
nr_bytes -= to_seek;
|
nr_bytes -= to_seek;
|
||||||
|
struct iovec iov;
|
||||||
|
|
||||||
it->it_vec_ptr++;
|
it->it_vec_ptr++;
|
||||||
while (it->it_vec_ptr < it->it_nr_vecs) {
|
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;
|
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) {
|
if (it->it_vec_ptr >= it->it_nr_vecs) {
|
||||||
|
it->it_len = 0;
|
||||||
|
it->it_base = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
it->it_base = it->it_vecs[it->it_vec_ptr].io_base;
|
it->it_base = iov.io_base;
|
||||||
it->it_len = it->it_vecs[it->it_vec_ptr].io_len;
|
it->it_len = iov.io_len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user