Add queue locks, fix raw socket close not cleaning up properly
This commit is contained in:
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user