git: d1c4e56772f8 - stable/13 - netlink: make snl(3) scratch buffer growable
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sat, 08 Apr 2023 19:44:48 UTC
The branch stable/13 has been updated by melifaro:
URL: https://cgit.FreeBSD.org/src/commit/?id=d1c4e56772f804065d7f06c7a6b9d8accccb9d4a
commit d1c4e56772f804065d7f06c7a6b9d8accccb9d4a
Author: Alexander V. Chernikov <melifaro@FreeBSD.org>
AuthorDate: 2023-03-08 11:17:43 +0000
Commit: Alexander V. Chernikov <melifaro@FreeBSD.org>
CommitDate: 2023-04-08 19:05:34 +0000
netlink: make snl(3) scratch buffer growable
Differential Revision: https://reviews.freebsd.org/D38946
MFC after: 2 weeks
(cherry picked from commit 0679eb1f39aa798da6c4601bb06bab4c175c4b18)
---
sys/netlink/netlink_snl.h | 90 ++++++++++++++++++++++++++++++++++++-----------
1 file changed, 69 insertions(+), 21 deletions(-)
diff --git a/sys/netlink/netlink_snl.h b/sys/netlink/netlink_snl.h
index d88808ea6d3b..3c63e3f95419 100644
--- a/sys/netlink/netlink_snl.h
+++ b/sys/netlink/netlink_snl.h
@@ -70,11 +70,31 @@
#define NL_ARRAY_LEN(_a) (sizeof(_a) / sizeof((_a)[0]))
struct linear_buffer {
- char *base; /* Base allocated memory pointer */
- uint32_t offset; /* Currently used offset */
- uint32_t size; /* Total buffer size */
+ char *base; /* Base allocated memory pointer */
+ uint32_t offset; /* Currently used offset */
+ uint32_t size; /* Total buffer size */
+ struct linear_buffer *next; /* Buffer chaining */
};
+static inline struct linear_buffer *
+lb_init(uint32_t size)
+{
+ struct linear_buffer *lb = calloc(1, size);
+
+ if (lb != NULL) {
+ lb->base = (char *)(lb + 1);
+ lb->size = size - sizeof(*lb);
+ }
+
+ return (lb);
+}
+
+static inline void
+lb_free(struct linear_buffer *lb)
+{
+ free(lb);
+}
+
static inline char *
lb_allocz(struct linear_buffer *lb, int len)
{
@@ -101,7 +121,7 @@ struct snl_state {
size_t datalen;
uint32_t seq;
bool init_done;
- struct linear_buffer lb;
+ struct linear_buffer *lb;
};
#define SCRATCH_BUFFER_SIZE 1024
@@ -145,6 +165,45 @@ static const struct snl_hdr_parser _name = { \
}
+static inline void *
+snl_allocz(struct snl_state *ss, int len)
+{
+ void *data = lb_allocz(ss->lb, len);
+
+ if (data == NULL) {
+ uint32_t size = ss->lb->size * 2;
+
+ while (size < len + sizeof(struct linear_buffer))
+ size *= 2;
+
+ struct linear_buffer *lb = lb_init(size);
+
+ if (lb != NULL) {
+ lb->next = ss->lb;
+ ss->lb = lb;
+ data = lb_allocz(ss->lb, len);
+ }
+ }
+
+ return (data);
+}
+
+static inline void
+snl_clear_lb(struct snl_state *ss)
+{
+ struct linear_buffer *lb = ss->lb;
+
+ lb_clear(lb);
+ lb = lb->next;
+ ss->lb->next = NULL;
+ /* Remove all linear bufs except the largest one */
+ while (lb != NULL) {
+ struct linear_buffer *lb_next = lb->next;
+ lb_free(lb);
+ lb = lb_next;
+ }
+}
+
static void
snl_free(struct snl_state *ss)
{
@@ -152,8 +211,10 @@ snl_free(struct snl_state *ss)
close(ss->fd);
if (ss->buf != NULL)
free(ss->buf);
- if (ss->lb.base != NULL)
- free(ss->lb.base);
+ if (ss->lb != NULL) {
+ snl_clear_lb(ss);
+ lb_free(ss->lb);
+ }
}
}
@@ -181,9 +242,8 @@ snl_init(struct snl_state *ss, int netlink_family)
return (false);
}
- ss->lb.size = SCRATCH_BUFFER_SIZE;
- ss->lb.base = calloc(1, ss->lb.size);
- if (ss->lb.base == NULL) {
+ ss->lb = lb_init(SCRATCH_BUFFER_SIZE);
+ if (ss->lb == NULL) {
snl_free(ss);
return (false);
}
@@ -191,18 +251,6 @@ snl_init(struct snl_state *ss, int netlink_family)
return (true);
}
-static inline void *
-snl_allocz(struct snl_state *ss, int len)
-{
- return (lb_allocz(&ss->lb, len));
-}
-
-static inline void
-snl_clear_lb(struct snl_state *ss)
-{
- lb_clear(&ss->lb);
-}
-
static inline bool
snl_send(struct snl_state *ss, void *data, int sz)
{