From 570d51dcf1aba138760b5d266bc8bafa7179b44b Mon Sep 17 00:00:00 2001 From: Matheus Date: Wed, 18 Sep 2024 21:59:16 -0300 Subject: [PATCH] udp: prepare for copyless read/write --- kernel-src/io/net/udp.c | 52 +++++++++++++++++++------------------ kernel-src/lib/ringbuffer.c | 2 +- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/kernel-src/io/net/udp.c b/kernel-src/io/net/udp.c index f4d50948..8601e209 100644 --- a/kernel-src/io/net/udp.c +++ b/kernel-src/io/net/udp.c @@ -45,11 +45,15 @@ int udp_sendpacket(void *buffer, size_t size, uint32_t ip, uint16_t srcport, uin }; memcpy(newbuff, &frame, sizeof(udpframe_t)); - memcpy((void *)((uintptr_t)newbuff + sizeof(udpframe_t)), buffer, size); + int error = USERCOPY_POSSIBLY_FROM_USER((void *)((uintptr_t)newbuff + sizeof(udpframe_t)), buffer, size); + if (error) + goto leave; - int e = ipv4_sendpacket(newbuff, size + sizeof(udpframe_t), ip, IPV4_PROTO_UDP, broadcastnetdev); + error = ipv4_sendpacket(newbuff, size + sizeof(udpframe_t), ip, IPV4_PROTO_UDP, broadcastnetdev); + + leave: free(newbuff); - return e; + return error; } void udp_init() { @@ -163,12 +167,8 @@ static int internalpoll(socket_t *socket, polldata_t *data, int events) { int revents = 0; if (events & POLLIN) { - bool intstate = interrupt_set(false); - spinlock_acquire(&udpsocket->ringbufferlock); if (RINGBUFFER_DATACOUNT(&udpsocket->ringbuffer) > 0) revents |= POLLIN; - spinlock_release(&udpsocket->ringbufferlock); - interrupt_set(intstate); } if (events & POLLOUT) @@ -259,29 +259,31 @@ static int udp_recv(socket_t *socket, sockdesc_t *sockdesc) { MUTEX_ACQUIRE(&socket->mutex, false); } - bool intstate = interrupt_set(false); - spinlock_acquire(&udpsocket->ringbufferlock); - - // TODO rewrite this to handle a possible sleep in the ringbuffer + // 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 + // multiple readers cannot happen because of the socket mutex and the write on the side of the + // NIC is protected by the ringbuffer lock size_t copycount; dataheader_t header; - if (flags & SOCKET_RECV_FLAGS_PEEK) { - __assert(ringbuffer_peek(&udpsocket->ringbuffer, &header, 0, sizeof(header)) == sizeof(header)); - copycount = min(header.length, sockdesc->count); - __assert(ringbuffer_peek(&udpsocket->ringbuffer, sockdesc->buffer, sizeof(header), copycount) == copycount); - } else { - __assert(ringbuffer_read(&udpsocket->ringbuffer, &header, sizeof(header)) == sizeof(header)); + __assert(ringbuffer_peek(&udpsocket->ringbuffer, &header, 0, sizeof(header)) == sizeof(header)); + copycount = min(header.length, sockdesc->count); - copycount = min(header.length, sockdesc->count); - __assert(ringbuffer_read(&udpsocket->ringbuffer, sockdesc->buffer, copycount) == copycount); - - // truncate the rest if the buffer wasn't big enough to handle everything - if (header.length > sockdesc->count) - ringbuffer_truncate(&udpsocket->ringbuffer, header.length - copycount); + sockdesc->donecount = ringbuffer_peek(&udpsocket->ringbuffer, sockdesc->buffer, sizeof(header), copycount); + if (sockdesc->donecount == RINGBUFFER_USER_COPY_FAILED) { + e = EFAULT; + goto cleanup; + } + + __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); + ringbuffer_truncate(&udpsocket->ringbuffer, sizeof(header) + header.length); + spinlock_releaseirqrestore(&udpsocket->ringbufferlock, status); } - spinlock_release(&udpsocket->ringbufferlock); - interrupt_set(intstate); sockdesc->donecount = copycount; sockdesc->addr->ipv4addr.addr = header.peer; diff --git a/kernel-src/lib/ringbuffer.c b/kernel-src/lib/ringbuffer.c index 2d5721b2..08c5f013 100644 --- a/kernel-src/lib/ringbuffer.c +++ b/kernel-src/lib/ringbuffer.c @@ -68,7 +68,7 @@ size_t ringbuffer_peek(ringbuffer_t *ringbuffer, void *buffer, uintmax_t offset, return count; if (USERCOPY_POSSIBLY_TO_USER((void *)((uintptr_t)buffer + firstpasscount), ringbuffer->data, count - firstpasscount)) - return -RINGBUFFER_USER_COPY_FAILED; + return RINGBUFFER_USER_COPY_FAILED; return count; }