diff options
author | Felix Fietkau <nbd@nbd.name> | 2023-11-30 14:23:30 +0300 |
---|---|---|
committer | Felix Fietkau <nbd@nbd.name> | 2023-11-30 14:29:40 +0300 |
commit | 40acbe34632b8e4e860fe41bb14ab5d7d5c9cfe9 (patch) | |
tree | 5f89079b27bc2cc73cd97515eb9f2df2c1385459 /udebug.c | |
parent | e84c000c4756ae3d0aa80b2c66ec43cf7fc416c4 (diff) |
udebug: wait for response after buffer add/remove
Fixes a race condition where freeing a buffer and immediately re-allocating and
adding it would fail to pass the file descriptor to udebugd
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Diffstat (limited to 'udebug.c')
-rw-r--r-- | udebug.c | 133 |
1 files changed, 84 insertions, 49 deletions
@@ -290,8 +290,9 @@ recv_retry(int fd, struct iovec *iov, bool wait, int *recv_fd) return total; } -void udebug_send_msg(struct udebug *ctx, struct udebug_client_msg *msg, - struct blob_attr *meta, int fd) +static void +udebug_send_msg(struct udebug *ctx, struct udebug_client_msg *msg, + struct blob_attr *meta, int fd) { struct iovec iov[2] = { { .iov_base = msg, .iov_len = sizeof(*msg) }, @@ -308,6 +309,79 @@ void udebug_send_msg(struct udebug *ctx, struct udebug_client_msg *msg, writev_retry(ctx->fd.fd, iov, ARRAY_SIZE(iov), fd); } +static bool +udebug_recv_msg(struct udebug *ctx, struct udebug_client_msg *msg, int *fd, + bool wait) +{ + struct iovec iov = { + .iov_base = msg, + .iov_len = sizeof(*msg) + }; + int ret; + + ret = recv_retry(ctx->fd.fd, &iov, wait, fd); + if (ret == -2) + __udebug_disconnect(ctx, true); + + return ret == sizeof(*msg); +} + +static struct udebug_client_msg * +__udebug_poll(struct udebug *ctx, int *fd, bool wait) +{ + static struct udebug_client_msg msg = {}; + + while (udebug_recv_msg(ctx, &msg, fd, wait)) { + struct udebug_remote_buf *rb; + void *key; + + if (msg.type != CL_MSG_RING_NOTIFY) + return &msg; + + if (fd && *fd >= 0) + close(*fd); + + if (!ctx->notify_cb) + continue; + + key = (void *)(uintptr_t)msg.id; + rb = avl_find_element(&ctx->remote_rings, key, rb, node); + if (!rb || !rb->poll) + continue; + + if (ctx->poll_handle >= 0) + __atomic_fetch_or(&rb->buf.hdr->notify, + 1UL << ctx->poll_handle, + __ATOMIC_RELAXED); + ctx->notify_cb(ctx, rb); + } + + return NULL; +} + +static struct udebug_client_msg * +udebug_wait_for_response(struct udebug *ctx, struct udebug_client_msg *msg, int *rfd) +{ + int type = msg->type; + int fd = -1; + + do { + if (fd >= 0) + close(fd); + fd = -1; + msg = __udebug_poll(ctx, &fd, true); + } while (msg && msg->type != type); + if (!msg) + return NULL; + + if (rfd) + *rfd = fd; + else if (fd >= 0) + close(fd); + + return msg; +} + static void udebug_buf_msg(struct udebug_buf *buf, enum udebug_client_msg_type type) { @@ -317,6 +391,7 @@ udebug_buf_msg(struct udebug_buf *buf, enum udebug_client_msg_type type) }; udebug_send_msg(buf->ctx, &msg, NULL, -1); + udebug_wait_for_response(buf->ctx, &msg, NULL); } static size_t __udebug_headsize(unsigned int ring_size, unsigned int page_size) @@ -604,6 +679,7 @@ __udebug_buf_add(struct udebug *ctx, struct udebug_buf *buf) blobmsg_close_array(&b, c); udebug_send_msg(ctx, &msg, b.head, buf->fd); + udebug_wait_for_response(ctx, &msg, NULL); } int udebug_buf_add(struct udebug *ctx, struct udebug_buf *buf, @@ -683,58 +759,17 @@ int udebug_connect(struct udebug *ctx, const char *path) return 0; } -static bool -udebug_recv_msg(struct udebug *ctx, struct udebug_client_msg *msg, int *fd, - bool wait) +void udebug_poll(struct udebug *ctx) { - struct iovec iov = { - .iov_base = msg, - .iov_len = sizeof(*msg) - }; - int ret; - - ret = recv_retry(ctx->fd.fd, &iov, wait, fd); - if (ret == -2) - __udebug_disconnect(ctx, true); - - return ret == sizeof(*msg); + while (__udebug_poll(ctx, NULL, false)); } -struct udebug_client_msg *__udebug_poll(struct udebug *ctx, int *fd, bool wait) +struct udebug_client_msg * +udebug_send_and_wait(struct udebug *ctx, struct udebug_client_msg *msg, int *rfd) { - static struct udebug_client_msg msg = {}; - - while (udebug_recv_msg(ctx, &msg, fd, wait)) { - struct udebug_remote_buf *rb; - void *key; - - if (msg.type != CL_MSG_RING_NOTIFY) - return &msg; - - if (fd && *fd >= 0) - close(*fd); - - if (!ctx->notify_cb) - continue; - - key = (void *)(uintptr_t)msg.id; - rb = avl_find_element(&ctx->remote_rings, key, rb, node); - if (!rb || !rb->poll) - continue; + udebug_send_msg(ctx, msg, NULL, -1); - if (ctx->poll_handle >= 0) - __atomic_fetch_or(&rb->buf.hdr->notify, - 1UL << ctx->poll_handle, - __ATOMIC_RELAXED); - ctx->notify_cb(ctx, rb); - } - - return NULL; -} - -void udebug_poll(struct udebug *ctx) -{ - while (__udebug_poll(ctx, NULL, false)); + return udebug_wait_for_response(ctx, msg, rfd); } static void udebug_fd_cb(struct uloop_fd *fd, unsigned int events) |