The branch main has been updated by melifaro:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=0679eb1f39aa798da6c4601bb06bab4c175c4b18

commit 0679eb1f39aa798da6c4601bb06bab4c175c4b18
Author:     Alexander V. Chernikov <melif...@freebsd.org>
AuthorDate: 2023-03-08 11:17:43 +0000
Commit:     Alexander V. Chernikov <melif...@freebsd.org>
CommitDate: 2023-03-08 12:28:55 +0000

    netlink: make snl(3) scratch buffer growable
    
    Differential Revision: https://reviews.freebsd.org/D38946
    MFC after:      2 weeks
---
 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)
 {

Reply via email to