Add queue locks, fix raw socket close not cleaning up properly

This commit is contained in:
Mark
2020-03-21 00:26:11 +02:00
parent 874dd362ba
commit 7be54602f5
3 changed files with 52 additions and 19 deletions
+2
View File
@@ -1,5 +1,6 @@
#pragma once
#include "sys/types.h"
#include "sys/spin.h"
struct netdev;
// Takes up a single page
@@ -17,6 +18,7 @@ struct packet_qh {
};
struct packet_queue {
spin_t lock;
struct packet_qh *head, *tail;
};
+26 -16
View File
@@ -20,7 +20,6 @@
#include "net/if.h"
static struct thread netd_thread = {0};
static spin_t g_rxq_lock = 0;
static struct packet_queue g_rxq;
static struct packet *packet_create(void);
@@ -48,11 +47,8 @@ static void net_daemon(void) {
continue;
}
spin_lock_irqsave(&g_rxq_lock, &irq);
p = packet_queue_pop(&g_rxq);
_assert(p);
spin_release_irqrestore(&g_rxq_lock, &irq);
net_handle_packet(p);
packet_unref(p);
@@ -68,30 +64,37 @@ static inline struct packet_qh *packet_qh_create(struct packet *p) {
void packet_queue_push(struct packet_queue *pq, struct packet *p) {
struct packet_qh *qh = packet_qh_create(p);
qh->next = NULL;
uintptr_t irq;
spin_lock_irqsave(&pq->lock, &irq);
if (pq->tail) {
pq->tail->next = qh;
} else {
pq->head = qh;
}
qh->prev = pq->tail;
qh->next = NULL;
pq->tail = qh;
spin_release_irqrestore(&pq->lock, &irq);
}
struct packet *packet_queue_pop(struct packet_queue *pq) {
uintptr_t irq;
spin_lock_irqsave(&pq->lock, &irq);
struct packet_qh *qh = pq->head;
_assert(qh);
pq->head = qh->next;
if (!pq->head) {
pq->tail = NULL;
}
spin_release_irqrestore(&pq->lock, &irq);
struct packet *p = qh->packet;
kfree(qh);
return p;
}
void packet_queue_init(struct packet_queue *pq) {
pq->lock = 0;
pq->head = NULL;
pq->tail = NULL;
}
@@ -101,6 +104,7 @@ static struct packet *packet_create(void) {
uintptr_t page = amd64_phys_alloc_page();
_assert(page != MM_NADDR);
packet = (struct packet *) MM_VIRTUALIZE(page);
packet->refcount = 0;
return packet;
}
@@ -135,9 +139,7 @@ int net_receive(struct netdev *dev, const void *data, size_t len) {
p->dev = dev;
packet_ref(p);
spin_lock(&g_rxq_lock);
packet_queue_push(&g_rxq, p);
spin_release(&g_rxq_lock);
return 0;
}
@@ -181,16 +183,24 @@ void net_close(struct vfs_ioctx *ioctx, struct ofile *fd) {
_assert(fd);
_assert(fd->flags & OF_SOCKET);
if (fd->socket.domain != AF_INET) {
kwarn("Unknown socket family: %d\n", fd->socket.domain);
return;
}
switch (fd->socket.type) {
case SOCK_DGRAM:
udp_socket_close(ioctx, fd);
switch (fd->socket.domain) {
case AF_INET:
switch (fd->socket.type) {
case SOCK_DGRAM:
udp_socket_close(ioctx, fd);
break;
default:
break;
}
break;
default:
case AF_PACKET:
switch (fd->socket.type) {
case SOCK_RAW:
raw_socket_close(ioctx, fd);
break;
default:
break;
}
break;
}
}
+24 -3
View File
@@ -16,6 +16,7 @@ struct raw_socket {
struct raw_socket *prev, *next;
};
static spin_t g_raw_lock = 0;
static struct raw_socket *g_raw_sockets = NULL;
int raw_socket_open(struct vfs_ioctx *ioctx, struct ofile *fd, int dom, int type, int proto) {
@@ -69,9 +70,23 @@ ssize_t raw_socket_recv(struct vfs_ioctx *ioctx, struct ofile *fd, void *buf, si
}
void raw_socket_close(struct vfs_ioctx *ioctx, struct ofile *fd) {
struct raw_socket *r_sock = kmalloc(sizeof(struct raw_socket));
uintptr_t irq;
struct raw_socket *r_sock = fd->socket.sock;
_assert(r_sock);
spin_lock_irqsave(&g_raw_lock, &irq);
struct raw_socket *prev = r_sock->prev;
struct raw_socket *next = r_sock->next;
if (prev) {
prev->next = next;
} else {
g_raw_sockets = next;
}
if (next) {
next->prev = prev;
}
spin_release_irqrestore(&g_raw_lock, &irq);
// Flush packet queue
while (r_sock->queue.head) {
struct packet *p = packet_queue_pop(&r_sock->queue);
@@ -81,11 +96,17 @@ void raw_socket_close(struct vfs_ioctx *ioctx, struct ofile *fd) {
void raw_packet_handle(struct packet *p) {
// Queue the packet for all the sockets
uintptr_t irq;
// TODO: too much time spent in spinlocked region?
spin_lock_irqsave(&g_raw_lock, &irq);
for (struct raw_socket *r = g_raw_sockets; r; r = r->next) {
packet_ref(p);
packet_queue_push(&r->queue, p);
if (r->wait) {
sched_queue(r->wait);
struct thread *w = r->wait;
if (w) {
r->wait = NULL;
sched_queue(w);
}
}
spin_release_irqrestore(&g_raw_lock, &irq);
}