From fb2fa68752435a8b30b6a17d4c3b8537318ef8a2 Mon Sep 17 00:00:00 2001 From: Matheus Date: Sat, 21 Sep 2024 10:53:49 -0300 Subject: [PATCH] sockets: use new iovec interface --- kernel-src/fs/sockfs.c | 30 ++----------------- kernel-src/include/kernel/iovec.h | 4 +-- kernel-src/include/kernel/net.h | 2 +- kernel-src/include/kernel/sock.h | 49 ++++++++++++++++++++++++++++++- kernel-src/io/iovec.c | 12 ++++---- kernel-src/io/net/localsocket.c | 6 ++-- kernel-src/io/net/tcp.c | 6 ++-- kernel-src/io/net/udp.c | 21 ++++++------- kernel-src/sys/syscalls/recvmsg.c | 22 ++++---------- kernel-src/sys/syscalls/sendmsg.c | 24 ++++----------- 10 files changed, 89 insertions(+), 87 deletions(-) diff --git a/kernel-src/fs/sockfs.c b/kernel-src/fs/sockfs.c index d1577445..212c6f52 100644 --- a/kernel-src/fs/sockfs.c +++ b/kernel-src/fs/sockfs.c @@ -26,38 +26,12 @@ int sockfs_close(vnode_t *node, int flags, cred_t *cred) { int sockfs_read(vnode_t *node, void *buffer, size_t size, uintmax_t offset, int flags, size_t *readc, cred_t *cred) { socket_t *socket = SOCKFS_SOCKET_FROM_NODE(node); - sockdesc_t desc = { - .addr = NULL, - .buffer = buffer, - .count = size, - .flags = flags, - .donecount = 0, - .ctrl = NULL, - .ctrllen = 0 - }; - - int e = socket->ops->recv(socket, &desc); - - *readc = desc.donecount; - return e; + return socket_read(socket, buffer, size, flags, readc); } int sockfs_write(vnode_t *node, void *buffer, size_t size, uintmax_t offset, int flags, size_t *writec, cred_t *cred) { socket_t *socket = SOCKFS_SOCKET_FROM_NODE(node); - sockdesc_t desc = { - .addr = NULL, - .buffer = buffer, - .count = size, - .flags = flags, - .donecount = 0, - .ctrl = NULL, - .ctrllen = 0 - }; - - int e = socket->ops->send(socket, &desc); - - *writec = desc.donecount; - return e; + return socket_write(socket, buffer, size, flags, writec); } int sockfs_poll(vnode_t *node, polldata_t *data, int events) { diff --git a/kernel-src/include/kernel/iovec.h b/kernel-src/include/kernel/iovec.h index 4963d022..a51ffa55 100644 --- a/kernel-src/include/kernel/iovec.h +++ b/kernel-src/include/kernel/iovec.h @@ -47,12 +47,12 @@ int iovec_iterator_copy_from_buffer(iovec_iterator_t *iovec_iterator, void *buff // copies byte_count bytes from the iovec_iterator into the ringbuffer // returns the number of bytes copied // NOTE: the iovec can have userspace addresses. in this case, the copy can possibly fail by returning RINGBUFFER_USER_COPY_FAILED -size_t iovec_iterator_copy_to_ringbuffer(iovec_iterator_t *iovec_iterator, ringbuffer_t *ringbuffer, size_t byte_count); +size_t iovec_iterator_write_to_ringbuffer(iovec_iterator_t *iovec_iterator, ringbuffer_t *ringbuffer, size_t byte_count); // copies byte_count bytes from the ringbuffer into the iovec_iterator // returns the number of bytes copied // NOTE: the iovec can have userspace addresses. in this case, the copy can possibly fail with RINGBUFFER_USER_COPY_FAILED -size_t iovec_iterator_copy_from_ringbuffer(iovec_iterator_t *iovec_iterator, ringbuffer_t *ringbuffer, size_t byte_count); +size_t iovec_iterator_read_from_ringbuffer(iovec_iterator_t *iovec_iterator, ringbuffer_t *ringbuffer, size_t byte_count); // copies byte_count bytes from the ringbuffer into the iovec_iterator, without moving the ringbuffer read pointer // returns the number of bytes copied diff --git a/kernel-src/include/kernel/net.h b/kernel-src/include/kernel/net.h index dfdd3e78..225ee7ac 100644 --- a/kernel-src/include/kernel/net.h +++ b/kernel-src/include/kernel/net.h @@ -78,7 +78,7 @@ void udp_process(netdev_t *netdev, void *buffer, uint32_t ip); void arp_process(netdev_t *netdev, void *buffer); void tcp_process(netdev_t *netdev, void *buffer, ipv4frame_t *ipv4frame); int arp_lookup(netdev_t *netdev, uint32_t ip, mac_t *mac); -int udp_sendpacket(void *buffer, size_t packetsize, uint32_t ip, uint16_t srcport, uint16_t dstport, netdev_t *broadcastdev); +int udp_sendpacket(iovec_iterator_t *iovec_iterator, size_t packetsize, uint32_t ip, uint16_t srcport, uint16_t dstport, netdev_t *broadcastdev); int ipv4_sendpacket(void *buffer, size_t packetsize, uint32_t ip, int proto, netdev_t *broadcastdev); size_t ipv4_getmtu(uint32_t ip); uint32_t ipv4_getnetdevip(uint32_t ip); diff --git a/kernel-src/include/kernel/sock.h b/kernel-src/include/kernel/sock.h index a10e8e2f..093009ef 100644 --- a/kernel-src/include/kernel/sock.h +++ b/kernel-src/include/kernel/sock.h @@ -39,7 +39,7 @@ typedef struct { typedef struct { sockaddr_t *addr; - void *buffer; + iovec_iterator_t iovec_iterator; size_t count; uintmax_t flags; size_t donecount; @@ -79,6 +79,53 @@ typedef struct { #define SOCKET_TYPE_TCP 2 #define SOCKFS_SOCKET_FROM_NODE(nodep) (((socketnode_t *)(nodep))->socket) +static inline int socket_read(socket_t *socket, void *buffer, size_t size, uintmax_t flags, size_t *bytes_read) { + sockdesc_t desc = { + .addr = NULL, + .count = size, + .flags = flags, + .donecount = 0, + .ctrl = NULL, + .ctrllen = 0 + }; + + iovec_t iovec = { + .addr = buffer, + .len = size + }; + + iovec_iterator_init(&desc.iovec_iterator, &iovec, 1); + + int e = socket->ops->recv(socket, &desc); + + *bytes_read = desc.donecount; + + return e; +} + +static inline int socket_write(socket_t *socket, void *buffer, size_t size, uintmax_t flags, size_t *bytes_written) { + sockdesc_t desc = { + .addr = NULL, + .count = size, + .flags = flags, + .donecount = 0, + .ctrl = NULL, + .ctrllen = 0 + }; + + iovec_t iovec = { + .addr = buffer, + .len = size + }; + + iovec_iterator_init(&desc.iovec_iterator, &iovec, 1); + + int e = socket->ops->send(socket, &desc); + + *bytes_written = desc.donecount; + return e; +} + static inline int sock_convertaddress(sockaddr_t *sockaddr, abisockaddr_t *abisockaddr) { switch (abisockaddr->type) { case AF_INET: diff --git a/kernel-src/io/iovec.c b/kernel-src/io/iovec.c index 87b644f6..9e9e5edb 100644 --- a/kernel-src/io/iovec.c +++ b/kernel-src/io/iovec.c @@ -119,7 +119,7 @@ int iovec_iterator_copy_from_buffer(iovec_iterator_t *iovec_iterator, void *buff return error; } -size_t iovec_iterator_copy_to_ringbuffer(iovec_iterator_t *iovec_iterator, ringbuffer_t *ringbuffer, size_t byte_count) { +size_t iovec_iterator_write_to_ringbuffer(iovec_iterator_t *iovec_iterator, ringbuffer_t *ringbuffer, size_t byte_count) { size_t iterator_offset_save = iovec_iterator->total_offset; size_t remaining_total = min(byte_count, iovec_iterator->total_size - iovec_iterator->total_offset); size_t total_done = 0; @@ -140,6 +140,7 @@ size_t iovec_iterator_copy_to_ringbuffer(iovec_iterator_t *iovec_iterator, ringb break; iovec_iterator_skip(iovec_iterator, copy_current); + remaining_total -= current_done; total_done += current_done; if (total_done == byte_count || iovec_iterator_finished(iovec_iterator)) @@ -154,7 +155,7 @@ size_t iovec_iterator_copy_to_ringbuffer(iovec_iterator_t *iovec_iterator, ringb return total_done; } -size_t iovec_iterator_peek_from_ringbuffer(iovec_iterator_t *iovec_iterator, ringbuffer_t *ringbuffer, size_t byte_count, uintmax_t ringbuffer_offset) { +size_t iovec_iterator_peek_from_ringbuffer(iovec_iterator_t *iovec_iterator, ringbuffer_t *ringbuffer, size_t offset, size_t byte_count) { size_t iterator_offset_save = iovec_iterator->total_offset; size_t remaining_total = min(byte_count, iovec_iterator->total_size - iovec_iterator->total_offset); size_t total_done = 0; @@ -164,12 +165,13 @@ size_t iovec_iterator_peek_from_ringbuffer(iovec_iterator_t *iovec_iterator, rin size_t remaining_current = iovec_iterator->current->len - iovec_iterator->current_offset; size_t copy_current = min(remaining_current, remaining_total); - current_done = ringbuffer_peek(ringbuffer, (void *)((uintptr_t)iovec_iterator->current->addr + iovec_iterator->current_offset), total_done, copy_current); + current_done = ringbuffer_peek(ringbuffer, (void *)((uintptr_t)iovec_iterator->current->addr + iovec_iterator->current_offset), offset + total_done, copy_current); if (current_done == 0 || current_done == RINGBUFFER_USER_COPY_FAILED) break; iovec_iterator_skip(iovec_iterator, copy_current); total_done += current_done; + remaining_total -= current_done; if (total_done == byte_count || iovec_iterator_finished(iovec_iterator)) break; @@ -183,8 +185,8 @@ size_t iovec_iterator_peek_from_ringbuffer(iovec_iterator_t *iovec_iterator, rin return total_done; } -size_t iovec_iterator_copy_from_ringbuffer(iovec_iterator_t *iovec_iterator, ringbuffer_t *ringbuffer, size_t byte_count) { - size_t done = iovec_iterator_peek_from_ringbuffer(iovec_iterator, ringbuffer, byte_count, 0); +size_t iovec_iterator_read_from_ringbuffer(iovec_iterator_t *iovec_iterator, ringbuffer_t *ringbuffer, size_t byte_count) { + size_t done = iovec_iterator_peek_from_ringbuffer(iovec_iterator, ringbuffer, 0, byte_count); if (done == RINGBUFFER_USER_COPY_FAILED) return done; diff --git a/kernel-src/io/net/localsocket.c b/kernel-src/io/net/localsocket.c index 522cf450..7157eaea 100644 --- a/kernel-src/io/net/localsocket.c +++ b/kernel-src/io/net/localsocket.c @@ -363,7 +363,7 @@ static int localsock_send(socket_t *socket, sockdesc_t *sockdesc) { goto leave; } - sockdesc->donecount = ringbuffer_write(&peer->ringbuffer, sockdesc->buffer, sockdesc->count); + sockdesc->donecount = iovec_iterator_write_to_ringbuffer(&sockdesc->iovec_iterator, &peer->ringbuffer, sockdesc->count); if (sockdesc->donecount == RINGBUFFER_USER_COPY_FAILED) { error = EFAULT; goto leave; @@ -467,13 +467,13 @@ static int localsock_recv(socket_t *socket, sockdesc_t *sockdesc) { } if (flags & SOCKET_RECV_FLAGS_PEEK) { - sockdesc->donecount = ringbuffer_peek(&localsocket->ringbuffer, sockdesc->buffer, 0, recvcount); + sockdesc->donecount = iovec_iterator_peek_from_ringbuffer(&sockdesc->iovec_iterator, &localsocket->ringbuffer, 0, recvcount); if (sockdesc->donecount == RINGBUFFER_USER_COPY_FAILED) { error = EFAULT; goto leave; } } else { - sockdesc->donecount = ringbuffer_read(&localsocket->ringbuffer, sockdesc->buffer, recvcount); + sockdesc->donecount = iovec_iterator_read_from_ringbuffer(&sockdesc->iovec_iterator, &localsocket->ringbuffer, recvcount); if (sockdesc->donecount == RINGBUFFER_USER_COPY_FAILED) { error = EPIPE; goto leave; diff --git a/kernel-src/io/net/tcp.c b/kernel-src/io/net/tcp.c index 88597c61..72131e6c 100644 --- a/kernel-src/io/net/tcp.c +++ b/kernel-src/io/net/tcp.c @@ -1305,7 +1305,7 @@ static int tcp_send(socket_t *socket, sockdesc_t *sockdesc) { size_t writesize = min(TCB_RINGBUFFER_SIZE - RINGBUFFER_DATACOUNT(&tcb->transmitbuffer), sockdesc->count); __assert(writesize); - sockdesc->donecount = ringbuffer_write(&tcb->transmitbuffer, sockdesc->buffer, writesize); + sockdesc->donecount = iovec_iterator_write_to_ringbuffer(&sockdesc->iovec_iterator, &tcb->transmitbuffer, writesize); if (sockdesc->donecount == RINGBUFFER_USER_COPY_FAILED) { error = EFAULT; goto leave; @@ -1386,13 +1386,13 @@ static int tcp_recv(socket_t *socket, sockdesc_t *sockdesc) { size_t copycount = min(RINGBUFFER_DATACOUNT(&tcb->receivebuffer), sockdesc->count); if (flags & SOCKET_RECV_FLAGS_PEEK) { - sockdesc->donecount = ringbuffer_peek(&tcb->receivebuffer, sockdesc->buffer, 0, copycount); + sockdesc->donecount = iovec_iterator_peek_from_ringbuffer(&sockdesc->iovec_iterator, &tcb->receivebuffer, 0, copycount); if (sockdesc->donecount == RINGBUFFER_USER_COPY_FAILED) { error = EFAULT; goto cleanup; } } else { - sockdesc->donecount = ringbuffer_read(&tcb->receivebuffer, sockdesc->buffer, copycount); + sockdesc->donecount = iovec_iterator_read_from_ringbuffer(&sockdesc->iovec_iterator, &tcb->receivebuffer, copycount); if (sockdesc->donecount == RINGBUFFER_USER_COPY_FAILED) { error = EFAULT; goto cleanup; diff --git a/kernel-src/io/net/udp.c b/kernel-src/io/net/udp.c index 8601e209..f2bab61a 100644 --- a/kernel-src/io/net/udp.c +++ b/kernel-src/io/net/udp.c @@ -32,7 +32,7 @@ typedef struct { static socket_t *ports[65536]; static spinlock_t portlock; -int udp_sendpacket(void *buffer, size_t size, uint32_t ip, uint16_t srcport, uint16_t dstport, netdev_t *broadcastnetdev) { +int udp_sendpacket(iovec_iterator_t *iovec_iterator, size_t size, uint32_t ip, uint16_t srcport, uint16_t dstport, netdev_t *broadcastnetdev) { void *newbuff = alloc(size + sizeof(udpframe_t)); if (newbuff == NULL) return ENOMEM; @@ -45,7 +45,7 @@ int udp_sendpacket(void *buffer, size_t size, uint32_t ip, uint16_t srcport, uin }; memcpy(newbuff, &frame, sizeof(udpframe_t)); - int error = USERCOPY_POSSIBLY_FROM_USER((void *)((uintptr_t)newbuff + sizeof(udpframe_t)), buffer, size); + int error = iovec_iterator_copy_to_buffer(iovec_iterator, (void *)((uintptr_t)newbuff + sizeof(udpframe_t)), size); if (error) goto leave; @@ -203,7 +203,7 @@ static int udp_send(socket_t *socket, sockdesc_t *sockdesc) { socket->state = SOCKET_STATE_BOUND; } - e = udp_sendpacket(sockdesc->buffer, sockdesc->count, sockdesc->addr ? sockdesc->addr->ipv4addr.addr : udpsocket->peeraddress, + e = udp_sendpacket(&sockdesc->iovec_iterator, sockdesc->count, sockdesc->addr ? sockdesc->addr->ipv4addr.addr : udpsocket->peeraddress, udpsocket->port, sockdesc->addr ? sockdesc->addr->ipv4addr.port : udpsocket->peerport, udpsocket->socket.netdev); sockdesc->donecount = sockdesc->count; @@ -261,16 +261,20 @@ static int udp_recv(socket_t *socket, sockdesc_t *sockdesc) { // this abuses an asterisk on the ringbuffer implementation that makes it not need locking when // something is reading and something is writing simultaneously. - // this is done to not need to disable interrupts as the ringbuffer_peek could take a fault + // this is done to not need to disable interrupts as the iovec_peek_from_ringbuffer could take a fault // multiple readers cannot happen because of the socket mutex and the write on the side of the - // NIC is protected by the ringbuffer lock + // NIC is protected by the ringbuffer lock. The ringbuffer lock is taken when reading the desc to ensure that + // the whole packet has reached the ringbuffer size_t copycount; dataheader_t header; + long ipl = spinlock_acquireraiseipl(&udpsocket->ringbufferlock, IPL_DPC); __assert(ringbuffer_peek(&udpsocket->ringbuffer, &header, 0, sizeof(header)) == sizeof(header)); + spinlock_releaseloweripl(&udpsocket->ringbufferlock, ipl); + copycount = min(header.length, sockdesc->count); - sockdesc->donecount = ringbuffer_peek(&udpsocket->ringbuffer, sockdesc->buffer, sizeof(header), copycount); + sockdesc->donecount = iovec_iterator_peek_from_ringbuffer(&sockdesc->iovec_iterator, &udpsocket->ringbuffer, sizeof(header), copycount); if (sockdesc->donecount == RINGBUFFER_USER_COPY_FAILED) { e = EFAULT; goto cleanup; @@ -279,11 +283,8 @@ static int udp_recv(socket_t *socket, sockdesc_t *sockdesc) { __assert(sockdesc->donecount == copycount); // remove the message if not asked to peek - if ((flags & SOCKET_RECV_FLAGS_PEEK) == 0) { - bool status = spinlock_acquireirqclear(&udpsocket->ringbufferlock); + if ((flags & SOCKET_RECV_FLAGS_PEEK) == 0) ringbuffer_truncate(&udpsocket->ringbuffer, sizeof(header) + header.length); - spinlock_releaseirqrestore(&udpsocket->ringbufferlock, status); - } sockdesc->donecount = copycount; sockdesc->addr->ipv4addr.addr = header.peer; diff --git a/kernel-src/sys/syscalls/recvmsg.c b/kernel-src/sys/syscalls/recvmsg.c index c0a73cb0..24848fc4 100644 --- a/kernel-src/sys/syscalls/recvmsg.c +++ b/kernel-src/sys/syscalls/recvmsg.c @@ -28,10 +28,10 @@ syscallret_t syscall_recvmsg(context_t *, int fd, msghdr_t *umsghdr, int flags) return ret; } - void *buffer = vmm_map(NULL, buffersize, VMM_FLAGS_ALLOCATE, ARCH_MMU_FLAGS_READ | ARCH_MMU_FLAGS_WRITE | ARCH_MMU_FLAGS_NOEXEC, NULL); - if (buffer == NULL) { - ret.errno = ENOMEM; - goto cleanup; + if (iovec_user_check(msghdr.iov, msghdr.iovcount) == false) { + ret.errno = EFAULT; + sock_freemsghdr(&msghdr); + return ret; } file = fd_get(fd); @@ -57,7 +57,6 @@ syscallret_t syscall_recvmsg(context_t *, int fd, msghdr_t *umsghdr, int flags) sockdesc_t desc = { .addr = &sockaddr, - .buffer = buffer, .count = buffersize, .flags = fileflagstovnodeflags(file->flags) | recvflags, .donecount = 0, @@ -66,18 +65,12 @@ syscallret_t syscall_recvmsg(context_t *, int fd, msghdr_t *umsghdr, int flags) .ctrldone = 0 }; + iovec_iterator_init(&desc.iovec_iterator, msghdr.iov, msghdr.iovcount); + ret.errno = socket->ops->recv(socket, &desc); if (ret.errno) goto cleanup; - uintmax_t iovoffset = 0; - for (int i = 0; i < msghdr.iovcount; ++i) { - ret.errno = usercopy_touser(msghdr.iov[i].addr, (void *)((uintptr_t)buffer + iovoffset), msghdr.iov[i].len); - if (ret.errno) - goto cleanup; - iovoffset += msghdr.iov[i].len; - } - if (msghdr.addr) { abisockaddr_t abisockaddr; ret.errno = sock_addrtoabiaddr(socket->type, &sockaddr, &abisockaddr); @@ -120,9 +113,6 @@ syscallret_t syscall_recvmsg(context_t *, int fd, msghdr_t *umsghdr, int flags) if (file) fd_release(file); - if (buffer) - vmm_unmap(buffer, buffersize, 0); - sock_freemsghdr(&msghdr); return ret; } diff --git a/kernel-src/sys/syscalls/sendmsg.c b/kernel-src/sys/syscalls/sendmsg.c index 256d1bd9..3279ea67 100644 --- a/kernel-src/sys/syscalls/sendmsg.c +++ b/kernel-src/sys/syscalls/sendmsg.c @@ -23,20 +23,10 @@ syscallret_t syscall_sendmsg(context_t *, int fd, msghdr_t *umsghdr, int flags) return ret; } - void *buffer = vmm_map(NULL, buffersize, VMM_FLAGS_ALLOCATE, ARCH_MMU_FLAGS_READ | ARCH_MMU_FLAGS_WRITE | ARCH_MMU_FLAGS_NOEXEC, NULL); - if (buffer == NULL) { - ret.errno = ENOMEM; - goto cleanup; - } - - uintmax_t iovoffset = 0; - - for (int i = 0; i < msghdr.iovcount; ++i) { - ret.errno = usercopy_fromuser((void *)((uintptr_t)buffer + iovoffset), msghdr.iov[i].addr, msghdr.iov[i].len); - if (ret.errno) - goto cleanup; - - iovoffset += msghdr.iov[i].len; + if (iovec_user_check(msghdr.iov, msghdr.iovcount) == false) { + ret.errno = EFAULT; + sock_freemsghdr(&msghdr); + return ret; } file = fd_get(fd); @@ -61,7 +51,6 @@ syscallret_t syscall_sendmsg(context_t *, int fd, msghdr_t *umsghdr, int flags) sockdesc_t desc = { .addr = msghdr.addr ? &sockaddr : NULL, - .buffer = buffer, .count = buffersize, .flags = fileflagstovnodeflags(file->flags) | ((flags & MSG_NOSIGNAL) ? SOCKET_SEND_FLAGS_NOSIGNAL : 0), .donecount = 0, @@ -70,6 +59,8 @@ syscallret_t syscall_sendmsg(context_t *, int fd, msghdr_t *umsghdr, int flags) .ctrldone = 0 }; + iovec_iterator_init(&desc.iovec_iterator, msghdr.iov, msghdr.iovcount); + ret.errno = socket->ops->send(socket, &desc); ret.ret = ret.errno ? -1 : desc.donecount; @@ -77,9 +68,6 @@ syscallret_t syscall_sendmsg(context_t *, int fd, msghdr_t *umsghdr, int flags) if (file) fd_release(file); - if (buffer) - vmm_unmap(buffer, buffersize, 0); - sock_freemsghdr(&msghdr); return ret; }