Hi,

The current VALUE length limit for the hostctl command for VMware is
fixed 4096 bytes.  I want to pass a longer VALUE.  I made a patch to
change it to variable length.

commane, ok?

Index: share/man/man4/pvbus.4
===================================================================
RCS file: /cvs/src/share/man/man4/pvbus.4,v
retrieving revision 1.14
diff -u -p -r1.14 pvbus.4
--- share/man/man4/pvbus.4      14 Jun 2017 12:42:09 -0000      1.14
+++ share/man/man4/pvbus.4      5 Oct 2022 03:23:00 -0000
@@ -102,13 +102,15 @@ struct pvbus_req {
        char                    *pvr_key;
        size_t                   pvr_valuelen;
        char                    *pvr_value;
+       size_t                  *pvr_len;
 };
 .Ed
 .Pp
 The caller is responsible for attaching character buffers to the
-.Fa pvr_key
-and
+.Fa pvr_key ,
 .Fa pvr_value
+and
+.Fa pvr_len
 fields and to set their length in
 .Fa pvr_keylen
 and
@@ -136,6 +138,14 @@ Write the new value
 to the key
 .Fa pvr_key .
 This command requires write permissions on the device file.
+.It Dv PVBUSIOC_GETVALUELEN
+Get the length of the value of
+.Fa pvr_key
+and return it in
+.Fa pvr_len .
+.It Dv PVBUSIOC_GETTYPELEN
+Get the length of the type and return it in
+.Fa pvr_len .
 .El
 .Sh FILES
 .Bl -tag -width "/dev/pvbusX" -compact
Index: sys/dev/pv/hypervic.c
===================================================================
RCS file: /cvs/src/sys/dev/pv/hypervic.c,v
retrieving revision 1.17
diff -u -p -r1.17 hypervic.c
--- sys/dev/pv/hypervic.c       8 Sep 2022 10:22:06 -0000       1.17
+++ sys/dev/pv/hypervic.c       5 Oct 2022 03:23:01 -0000
@@ -105,7 +105,7 @@ int hv_heartbeat_attach(struct hv_ic_dev
 void   hv_heartbeat(void *);
 int    hv_kvp_attach(struct hv_ic_dev *);
 void   hv_kvp(void *);
-int    hv_kvop(void *, int, char *, char *, size_t);
+int    hv_kvop(void *, int, char *, size_t, char *, size_t, size_t *);
 int    hv_shutdown_attach(struct hv_ic_dev *);
 void   hv_shutdown(void *);
 int    hv_timesync_attach(struct hv_ic_dev *);
@@ -551,11 +551,10 @@ kvp_pool_init(struct kvp_pool *kvpl)
 }
 
 static int
-kvp_pool_insert(struct kvp_pool *kvpl, const char *key, const char *val,
-    uint32_t vallen, uint32_t valtype)
+kvp_pool_insert(struct kvp_pool *kvpl, const char *key, size_t keylen,
+    const char *val, size_t vallen, uint32_t valtype)
 {
        struct kvp_entry *kpe;
-       int keylen = strlen(key);
 
        if (keylen > HV_KVP_MAX_KEY_SIZE / 2)
                return (ERANGE);
@@ -592,11 +591,10 @@ kvp_pool_insert(struct kvp_pool *kvpl, c
 }
 
 static int
-kvp_pool_update(struct kvp_pool *kvpl, const char *key, const char *val,
-    uint32_t vallen, uint32_t valtype)
+kvp_pool_update(struct kvp_pool *kvpl, const char *key, size_t keylen,
+    const char *val, size_t vallen, uint32_t valtype)
 {
        struct kvp_entry *kpe;
-       int keylen = strlen(key);
 
        if (keylen > HV_KVP_MAX_KEY_SIZE / 2)
                return (ERANGE);
@@ -715,12 +713,13 @@ kvp_pool_remove(struct kvp_pool *kvpl, c
 }
 
 static int
-kvp_pool_extract(struct kvp_pool *kvpl, const char *key, char *val,
-    uint32_t vallen)
+kvp_pool_extract(struct kvp_pool *kvpl, int op, const char *key, char *val,
+    size_t vallen, size_t *vlen)
 {
        struct kvp_entry *kpe;
+       char buf[128];
 
-       if (vallen < HV_KVP_MAX_VAL_SIZE / 2)
+       if (vallen > SIZE_T_MAX)
                return (ERANGE);
 
        mtx_enter(&kvpl->kvp_lock);
@@ -734,18 +733,36 @@ kvp_pool_extract(struct kvp_pool *kvpl, 
                return (ENOENT);
        }
 
-       switch (kpe->kpe_valtype) {
-       case HV_KVP_REG_SZ:
-               strlcpy(val, kpe->kpe_val, HV_KVP_MAX_VAL_SIZE / 2);
-               break;
-       case HV_KVP_REG_U32:
-               snprintf(val, HV_KVP_MAX_VAL_SIZE / 2, "%u",
-                   *(uint32_t *)kpe->kpe_val);
-               break;
-       case HV_KVP_REG_U64:
-               snprintf(val, HV_KVP_MAX_VAL_SIZE / 2, "%llu",
-                   *(uint64_t *)kpe->kpe_val);
-               break;
+       if (op == PVBUS_KVGETVALLEN) {
+               switch (kpe->kpe_valtype) {
+               case HV_KVP_REG_SZ:
+                       *vlen = strlen(kpe->kpe_val);
+                       break;
+               case HV_KVP_REG_U32:
+                       snprintf(buf, HV_KVP_MAX_VAL_SIZE / 2, "%u",
+                           *(uint32_t *)kpe->kpe_val);
+                       *vlen = strlen(buf);
+                       break;
+               case HV_KVP_REG_U64:
+                       snprintf(buf, HV_KVP_MAX_VAL_SIZE / 2, "%llu",
+                           *(uint64_t *)kpe->kpe_val);
+                       *vlen = strlen(buf);
+                       break;
+               }
+       } else {
+               switch (kpe->kpe_valtype) {
+               case HV_KVP_REG_SZ:
+                       strlcpy(val, kpe->kpe_val, HV_KVP_MAX_VAL_SIZE / 2);
+                       break;
+               case HV_KVP_REG_U32:
+                       snprintf(val, HV_KVP_MAX_VAL_SIZE / 2, "%u",
+                           *(uint32_t *)kpe->kpe_val);
+                       break;
+               case HV_KVP_REG_U64:
+                       snprintf(val, HV_KVP_MAX_VAL_SIZE / 2, "%llu",
+                           *(uint64_t *)kpe->kpe_val);
+                       break;
+               }
        }
 
        mtx_leave(&kvpl->kvp_lock);
@@ -777,6 +794,29 @@ kvp_pool_keys(struct kvp_pool *kvpl, int
        return (-1);
 }
 
+static int
+kvp_pool_keylen(struct kvp_pool *kvpl, int next, size_t *keylen)
+{
+       struct kvp_entry *kpe;
+       int iter = 0;
+
+       mtx_enter(&kvpl->kvp_lock);
+
+       TAILQ_FOREACH(kpe, &kvpl->kvp_entries, kpe_entry) {
+               if (iter++ < next)
+                       continue;
+               *keylen = strlen(kpe->kpe_key);
+
+               mtx_leave(&kvpl->kvp_lock);
+
+               return (0);
+       }
+
+       mtx_leave(&kvpl->kvp_lock);
+
+       return (-1);
+}
+
 int
 hv_kvp_attach(struct hv_ic_dev *dv)
 {
@@ -812,8 +852,9 @@ hv_kvp_attach(struct hv_ic_dev *dv)
        /* Initialize 'Auto' pool */
        for (i = 0; i < nitems(kvp_pool_auto); i++) {
                if (kvp_pool_insert(&kvp->kvp_pool[HV_KVP_POOL_AUTO],
-                   kvp_pool_auto[i].keyname, kvp_pool_auto[i].value,
-                   strlen(kvp_pool_auto[i].value), HV_KVP_REG_SZ))
+                   kvp_pool_auto[i].keyname, strlen(kvp_pool_auto[i].keyname),
+                   kvp_pool_auto[i].value, strlen(kvp_pool_auto[i].value),
+                   HV_KVP_REG_SZ))
                        DPRINTF("%s: failed to insert into 'Auto' pool\n",
                            sc->sc_dev.dv_xname);
        }
@@ -1135,14 +1176,15 @@ kvp_poolname(char **key)
 }
 
 int
-hv_kvop(void *arg, int op, char *key, char *val, size_t vallen)
+hv_kvop(void *arg, int op, char *key, size_t klen, char *val, size_t vallen,
+    size_t *vlen)
 {
        struct hv_ic_dev *dv = arg;
        struct hv_kvp *kvp = dv->dv_priv;
        struct kvp_pool *kvpl;
        int next, pool, error = 0;
        char *vp = val;
-       size_t keylen;
+       size_t keylen = 0;
 
        pool = kvp_poolname(&key);
        if (pool == -1)
@@ -1150,31 +1192,43 @@ hv_kvop(void *arg, int op, char *key, ch
 
        kvpl = &kvp->kvp_pool[pool];
        if (strlen(key) == 0) {
-               for (next = 0; next < MAXPOOLENTS; next++) {
-                       if ((val + vallen < vp + HV_KVP_MAX_KEY_SIZE / 2) ||
-                           kvp_pool_keys(kvpl, next, vp, &keylen))
-                               goto out;
-                       if (strlcat(val, "\n", vallen) >= vallen)
-                               goto out;
-                       vp += keylen;
+               if (op == PVBUS_KVGETVALLEN) {
+                       *vlen = 0;
+                       for (next = 0; next < MAXPOOLENTS; next++) {
+                               if (kvp_pool_keylen(kvpl, next, &keylen))
+                                       break;
+                               /* `+ 1' means '\n' the end of the line */
+                               *vlen += keylen + 1;
+                       }
+                       /* `+ 1' means '\0' the end of the line */
+                       *vlen += 1;
+               } else {
+                       for (next = 0; next < MAXPOOLENTS; next++) {
+                               if ((val + vallen < vp) ||
+                                   kvp_pool_keys(kvpl, next, vp, &keylen))
+                                       break;
+                               if (strlcat(val, "\n", vallen) >= vallen)
+                                       break;
+                               vp += keylen;
+                       }
+                       if (vp > val)
+                               *(vp - 1) = '\0';
                }
- out:
-               if (vp > val)
-                       *(vp - 1) = '\0';
                return (0);
        }
 
        if (op == PVBUS_KVWRITE) {
+               keylen = strlen(key);
                if (pool == HV_KVP_POOL_AUTO)
-                       error = kvp_pool_update(kvpl, key, val, vallen,
+                       error = kvp_pool_update(kvpl, key, keylen, val, vallen,
                            HV_KVP_REG_SZ);
                else if (pool == HV_KVP_POOL_GUEST)
-                       error = kvp_pool_insert(kvpl, key, val, vallen,
+                       error = kvp_pool_insert(kvpl, key, keylen, val, vallen,
                            HV_KVP_REG_SZ);
                else
                        error = EINVAL;
        } else
-               error = kvp_pool_extract(kvpl, key, val, vallen);
+               error = kvp_pool_extract(kvpl, op, key, val, vallen, vlen);
 
        return (error);
 }
Index: sys/dev/pv/pvbus.c
===================================================================
RCS file: /cvs/src/sys/dev/pv/pvbus.c,v
retrieving revision 1.25
diff -u -p -r1.25 pvbus.c
--- sys/dev/pv/pvbus.c  25 Aug 2022 17:38:16 -0000      1.25
+++ sys/dev/pv/pvbus.c  5 Oct 2022 03:23:01 -0000
@@ -400,12 +400,10 @@ pvbusgetstr(size_t srclen, const char *s
        /*
         * Reject size that is too short or obviously too long:
         * - at least one byte for the nul terminator.
-        * - PAGE_SIZE is an arbitrary value, but known pv backends seem
-        *   to have a hard (PAGE_SIZE - x) limit in their messaging.
         */
        if (srclen < 1)
                return (EINVAL);
-       else if (srclen > PAGE_SIZE)
+       else if (srclen > SIZE_T_MAX)
                return (ENAMETOOLONG);
 
        *dstp = dst = malloc(srclen + 1, M_TEMP|M_ZERO, M_WAITOK);
@@ -437,6 +435,9 @@ pvbusioctl(dev_t dev, u_long cmd, caddr_
        case PVBUSIOC_KVWRITE:
                if ((flags & FWRITE) == 0)
                        return (EPERM);
+               /* FALLTHROUGH */
+       case PVBUSIOC_GETVALUELEN:
+               /* FALLTHROUGH */
        case PVBUSIOC_KVREAD:
                hv = &sc->pvbus_hv[hvid];
                if (hv->hv_base == 0 || hv->hv_kvop == NULL)
@@ -449,6 +450,12 @@ pvbusioctl(dev_t dev, u_long cmd, caddr_
                        return (ENOMEM);
                error = copyout(str, pvr->pvr_key, sz);
                return (error);
+
+       case PVBUSIOC_GETTYPELEN:
+               sz = strlen(pvbus_types[hvid].name);
+               error = copyout(&sz, pvr->pvr_len, sizeof (*pvr->pvr_len));
+               return (error);
+
        default:
                return (ENOTTY);
        }
@@ -457,6 +464,18 @@ pvbusioctl(dev_t dev, u_long cmd, caddr_
        op = PVBUS_KVREAD;
 
        switch (cmd) {
+       case PVBUSIOC_GETVALUELEN:
+               op = PVBUS_KVGETVALLEN;
+               keylen = pvr->pvr_keylen;
+               if ((error = pvbusgetstr(keylen, pvr->pvr_key, &key)) != 0)
+                       break;
+               if ((error = (hv->hv_kvop)(hv->hv_arg, op,
+                   key, keylen, value, valuelen, &sz)) != 0)
+                       break;
+               if ((error = copyout(&sz, pvr->pvr_len,
+                   sizeof (*pvr->pvr_len))) != 0)
+                       break;
+               break;
        case PVBUSIOC_KVWRITE:
                str = pvr->pvr_value;
                op = PVBUS_KVWRITE;
@@ -473,7 +492,7 @@ pvbusioctl(dev_t dev, u_long cmd, caddr_
 
                /* Call driver-specific callback */
                if ((error = (hv->hv_kvop)(hv->hv_arg, op,
-                   key, value, valuelen)) != 0)
+                   key, keylen, value, valuelen, NULL)) != 0)
                        break;
 
                sz = strlen(value) + 1;
Index: sys/dev/pv/pvvar.h
===================================================================
RCS file: /cvs/src/sys/dev/pv/pvvar.h,v
retrieving revision 1.10
diff -u -p -r1.10 pvvar.h
--- sys/dev/pv/pvvar.h  22 Jun 2017 06:21:12 -0000      1.10
+++ sys/dev/pv/pvvar.h  5 Oct 2022 03:23:01 -0000
@@ -24,11 +24,14 @@ struct pvbus_req {
        char                    *pvr_key;
        size_t                   pvr_valuelen;
        char                    *pvr_value;
+       size_t                  *pvr_len;
 };
 
 #define PVBUSIOC_KVREAD                _IOWR('V', 1, struct pvbus_req)
 #define PVBUSIOC_KVWRITE       _IOWR('V', 2, struct pvbus_req)
 #define PVBUSIOC_TYPE          _IOWR('V', 3, struct pvbus_req)
+#define PVBUSIOC_GETVALUELEN   _IOWR('V', 4, struct pvbus_req)
+#define PVBUSIOC_GETTYPELEN    _IOWR('V', 5, struct pvbus_req)
 
 #ifdef _KERNEL
 enum {
@@ -45,7 +48,9 @@ enum {
 enum {
        PVBUS_KVREAD,
        PVBUS_KVWRITE,
-       PVBUS_KVLS
+       PVBUS_KVLS,
+       PVBUS_KVGETVALLEN,
+       PVBUS_KVLSGETVALLEN
 };
 
 struct pvbus_hv {
@@ -55,7 +60,8 @@ struct pvbus_hv {
        uint16_t                 hv_minor;
 
        void                    *hv_arg;
-       int                     (*hv_kvop)(void *, int, char *, char *, size_t);
+       int                     (*hv_kvop)(void *, int, char *, size_t, char *,
+                                   size_t, size_t *);
        void                    (*hv_init_cpu)(struct pvbus_hv *);
 };
 
Index: sys/dev/pv/vmt.c
===================================================================
RCS file: /cvs/src/sys/dev/pv/vmt.c,v
retrieving revision 1.26
diff -u -p -r1.26 vmt.c
--- sys/dev/pv/vmt.c    8 Sep 2022 10:22:06 -0000       1.26
+++ sys/dev/pv/vmt.c    5 Oct 2022 03:23:01 -0000
@@ -241,6 +241,8 @@ struct vmt_softc {
 
        struct vm_rpc           sc_tclo_rpc;
        char                    *sc_rpc_buf;
+       size_t                  sc_rpc_buflen;
+       size_t                  sc_rpc_rxlen;
        int                     sc_rpc_error;
        int                     sc_tclo_ping;
        int                     sc_set_guest_os;
@@ -277,12 +279,13 @@ int        vm_rpc_send(const struct vm_rpc *, 
 int     vm_rpc_send_str(const struct vm_rpc *, const uint8_t *);
 int     vm_rpc_get_length(const struct vm_rpc *, uint32_t *, uint16_t *);
 int     vm_rpc_get_data(const struct vm_rpc *, char *, uint32_t, uint16_t);
-int     vm_rpc_send_rpci_tx_buf(struct vmt_softc *, const uint8_t *, uint32_t);
+int     vm_rpc_send_rpci_tx_buf(struct vmt_softc *, char *, uint32_t);
 int     vm_rpc_send_rpci_tx(struct vmt_softc *, const char *, ...)
            __attribute__((__format__(__kprintf__,2,3)));
-int     vm_rpci_response_successful(struct vmt_softc *);
+int     vm_rpci_response_successful(const char *);
+int     vm_rpc_buf_realloc(struct vmt_softc *, size_t);
 
-int     vmt_kvop(void *, int, char *, char *, size_t);
+int     vmt_kvop(void *, int, char *, size_t, char *, size_t, size_t *);
 
 void    vmt_probe_cmd(struct vm_backdoor *, uint16_t);
 void    vmt_tclo_state_change_success(struct vmt_softc *, int, char);
@@ -440,7 +443,8 @@ vmt_attach(struct device *parent, struct
        struct pvbus_hv         *hv = &pva->pva_hv[PVBUS_VMWARE];
 
        printf("\n");
-       sc->sc_rpc_buf = malloc(VMT_RPC_BUFLEN, M_DEVBUF, M_NOWAIT);
+       sc->sc_rpc_buflen = VMT_RPC_BUFLEN;
+       sc->sc_rpc_buf = malloc(sc->sc_rpc_buflen, M_DEVBUF, M_NOWAIT);
        if (sc->sc_rpc_buf == NULL) {
                printf("%s: unable to allocate buffer for RPC\n",
                    DEVNAME(sc));
@@ -484,32 +488,40 @@ vmt_attach(struct device *parent, struct
        return;
 
 free:
-       free(sc->sc_rpc_buf, M_DEVBUF, VMT_RPC_BUFLEN);
+       free(sc->sc_rpc_buf, M_DEVBUF, sc->sc_rpc_buflen);
 }
 
 int
-vmt_kvop(void *arg, int op, char *key, char *value, size_t valuelen)
+vmt_kvop(void *arg, int op, char *key, size_t keylen, char *value,
+    size_t valuelen, size_t *vlen)
 {
        struct vmt_softc *sc = arg;
-       char *buf = NULL, *ptr;
-       size_t bufsz;
+       char *ptr;
+       size_t bufsz, buflen;
        int error = 0;
+       const char *set_cmd = "info-set %s %s";
+       const char *get_cmd = "info-get %s";
 
-       bufsz = VMT_RPC_BUFLEN;
-       buf = malloc(bufsz, M_TEMP, M_WAITOK | M_ZERO);
+       bufsz = MAX(strlen(set_cmd), strlen(get_cmd)) + keylen + valuelen;
+       if (bufsz > sc->sc_rpc_buflen &&
+           (error = vm_rpc_buf_realloc(sc, bufsz)) != 0)
+               return error;
 
        switch (op) {
        case PVBUS_KVWRITE:
-               if ((size_t)snprintf(buf, bufsz, "info-set %s %s",
-                   key, value) >= bufsz) {
+               buflen = (size_t)snprintf(sc->sc_rpc_buf, bufsz, set_cmd, key,
+                   value);
+               if (buflen >= bufsz) {
                        DPRINTF("%s: write command too long", DEVNAME(sc));
                        error = EINVAL;
                        goto done;
                }
                break;
+       case PVBUS_KVGETVALLEN:
+               /* FALLTHROUGH */
        case PVBUS_KVREAD:
-               if ((size_t)snprintf(buf, bufsz, "info-get %s",
-                   key) >= bufsz) {
+               buflen = (size_t)snprintf(sc->sc_rpc_buf, bufsz, get_cmd, key);
+               if (buflen >= bufsz) {
                        DPRINTF("%s: read command too long", DEVNAME(sc));
                        error = EINVAL;
                        goto done;
@@ -520,15 +532,15 @@ vmt_kvop(void *arg, int op, char *key, c
                goto done;
        }
 
-       if (vm_rpc_send_rpci_tx(sc, "%s", buf) != 0) {
-               DPRINTF("%s: error sending command: %s\n", DEVNAME(sc), buf);
+       if (vm_rpc_send_rpci_tx_buf(sc, sc->sc_rpc_buf, buflen) != 0) {
+               DPRINTF("%s: error sending command: %s\n", DEVNAME(sc), 
sc->sc_rpc_buf);
                sc->sc_rpc_error = 1;
                error = EIO;
                goto done;
        }
 
-       if (vm_rpci_response_successful(sc) == 0) {
-               DPRINTF("%s: host rejected command: %s\n", DEVNAME(sc), buf);
+       if (vm_rpci_response_successful(sc->sc_rpc_buf) == 0) {
+               DPRINTF("%s: host rejected command: %s\n", DEVNAME(sc), 
sc->sc_rpc_buf);
                error = EINVAL;
                goto done;
        }
@@ -536,12 +548,16 @@ vmt_kvop(void *arg, int op, char *key, c
        /* skip response that was tested in vm_rpci_response_successful() */
        ptr = sc->sc_rpc_buf + 2;
 
-       /* might truncate, copy anyway but return error */
-       if (strlcpy(value, ptr, valuelen) >= valuelen)
+       if (op == PVBUS_KVGETVALLEN)
+               /* decrement response that was tested in
+                * vm_rpci_response_successful().
+                */
+               *vlen = strlen(ptr);
+       /* might truncat, copy anyway but return error */
+       else if (strlcpy(value, ptr, valuelen) >= valuelen)
                error = ENOMEM;
 
  done:
-       free(buf, M_TEMP, bufsz);
        return (error);
 }
 
@@ -826,7 +842,7 @@ vmt_tclo_capreg(struct vmt_softc *sc)
                sc->sc_rpc_error = 1;
        }
 
-       if (vm_rpci_response_successful(sc) == 0) {
+       if (vm_rpci_response_successful(sc->sc_rpc_buf) == 0) {
                DPRINTF("%s: host rejected unified loop setting\n",
                    DEVNAME(sc));
        }
@@ -839,7 +855,7 @@ vmt_tclo_capreg(struct vmt_softc *sc)
                sc->sc_rpc_error = 1;
        }
 
-       if (vm_rpci_response_successful(sc) == 0) {
+       if (vm_rpci_response_successful(sc->sc_rpc_buf) == 0) {
                DPRINTF("%s: host rejected statechange capability\n",
                    DEVNAME(sc));
        }
@@ -1644,14 +1660,28 @@ vm_rpc_get_length(const struct vm_rpc *r
 }
 
 int
-vm_rpci_response_successful(struct vmt_softc *sc)
+vm_rpci_response_successful(const char *buf)
 {
-       return (sc->sc_rpc_buf[0] == '1' && sc->sc_rpc_buf[1] == ' ');
+       return (buf[0] == '1' && buf[1] == ' ');
 }
 
 int
-vm_rpc_send_rpci_tx_buf(struct vmt_softc *sc, const uint8_t *buf,
-    uint32_t length)
+vm_rpc_buf_realloc(struct vmt_softc *sc, size_t len)
+{
+       free(sc->sc_rpc_buf, M_DEVBUF, sc->sc_rpc_buflen);
+
+       sc->sc_rpc_buflen = len / VMT_RPC_BUFLEN * VMT_RPC_BUFLEN;
+       sc->sc_rpc_buflen += ((len % VMT_RPC_BUFLEN) <= 0) ? 0 : VMT_RPC_BUFLEN;
+       sc->sc_rpc_buf = malloc(sc->sc_rpc_buflen, M_DEVBUF, M_NOWAIT);
+       if (sc->sc_rpc_buf == NULL) {
+               printf("%s: unable to allocate buffer for RPC\n", DEVNAME(sc));
+               return ENOMEM;
+       }
+       return 0;
+}
+
+int
+vm_rpc_send_rpci_tx_buf(struct vmt_softc *sc, char *buf, uint32_t length)
 {
        struct vm_rpc rpci;
        u_int32_t rlen;
@@ -1677,9 +1707,11 @@ vm_rpc_send_rpci_tx_buf(struct vmt_softc
        }
 
        if (rlen > 0) {
-               if (rlen >= VMT_RPC_BUFLEN) {
-                       rlen = VMT_RPC_BUFLEN - 1;
-               }
+               sc->sc_rpc_rxlen = rlen;
+               /* Add the amount of the NUL terminater */
+               if (rlen >= sc->sc_rpc_buflen &&
+                   (result = vm_rpc_buf_realloc(sc, rlen + 1)) != 0)
+                       goto out;
 
                if (vm_rpc_get_data(&rpci, sc->sc_rpc_buf, rlen, ack) != 0) {
                        DPRINTF("%s: failed to get rpci response data\n",
@@ -1707,7 +1739,7 @@ vm_rpc_send_rpci_tx(struct vmt_softc *sc
        len = vsnprintf(sc->sc_rpc_buf, VMT_RPC_BUFLEN, fmt, args);
        va_end(args);
 
-       if (len >= VMT_RPC_BUFLEN) {
+       if (len >= sc->sc_rpc_buflen) {
                DPRINTF("%s: rpci command didn't fit in buffer\n", DEVNAME(sc));
                return EIO;
        }
Index: sys/dev/pv/xenstore.c
===================================================================
RCS file: /cvs/src/sys/dev/pv/xenstore.c,v
retrieving revision 1.46
diff -u -p -r1.46 xenstore.c
--- sys/dev/pv/xenstore.c       9 Jan 2022 05:42:58 -0000       1.46
+++ sys/dev/pv/xenstore.c       5 Oct 2022 03:23:01 -0000
@@ -1065,7 +1065,8 @@ xs_await_transition(void *xsc, const cha
 }
 
 int
-xs_kvop(void *xsc, int op, char *key, char *value, size_t valuelen)
+xs_kvop(void *xsc, int op, char *key, size_t keylen, char *value,
+    size_t valuelen, size_t *vlen)
 {
        struct xen_softc *sc = xsc;
        struct xs_transaction xst;
@@ -1079,9 +1080,13 @@ xs_kvop(void *xsc, int op, char *key, ch
                iov.iov_len = strlen(value);
                iov_cnt = 1;
                break;
+       case PVBUS_KVGETVALLEN:
+               /* FALLTHROUGH */
        case PVBUS_KVREAD:
                cmd = XS_READ;
                break;
+       case PVBUS_KVLSGETVALLEN:
+               /* FALLTHROUGH */
        case PVBUS_KVLS:
                cmd = XS_LIST;
                break;
@@ -1110,16 +1115,25 @@ xs_kvop(void *xsc, int op, char *key, ch
                         * returns an empty string (single nul byte),
                         * so try to get the directory list in this case.
                         */
-                       return (xs_kvop(xsc, PVBUS_KVLS, key, value, valuelen));
+                       return (xs_kvop(xsc, op == PVBUS_KVREAD ? PVBUS_KVLS :
+                           PVBUS_KVLSGETVALLEN, key, keylen, value,
+                           valuelen, vlen));
                }
                /* FALLTHROUGH */
        case XS_LIST:
-               for (i = 0; i < iov_cnt; i++) {
-                       if (i && strlcat(value, "\n", valuelen) >= valuelen)
-                               break;
-                       if (strlcat(value, iovp[i].iov_base,
-                           valuelen) >= valuelen)
-                               break;
+               if (op == PVBUS_KVGETVALLEN || op == PVBUS_KVLSGETVALLEN) {
+                       *vlen = 0;
+                       for (i = 0; i < iov_cnt; i++)
+                               *vlen += iovp[i].iov_len;
+               } else {
+                       for (i = 0; i < iov_cnt; i++) {
+                               if (i && strlcat(value, "\n", valuelen) >=
+                                   valuelen)
+                                       break;
+                               if (strlcat(value, iovp[i].iov_base,
+                                   valuelen) >= valuelen)
+                                       break;
+                       }
                }
                xs_resfree(&xst, iovp, iov_cnt);
                break;
Index: sys/dev/pv/xenvar.h
===================================================================
RCS file: /cvs/src/sys/dev/pv/xenvar.h,v
retrieving revision 1.51
diff -u -p -r1.51 xenvar.h
--- sys/dev/pv/xenvar.h 21 Jul 2017 20:00:47 -0000      1.51
+++ sys/dev/pv/xenvar.h 5 Oct 2022 03:23:01 -0000
@@ -193,7 +193,7 @@ int xs_getnum(void *, const char *, cons
 int    xs_setnum(void *, const char *, const char *, unsigned long long);
 int    xs_getprop(void *, const char *, const char *, char *, int);
 int    xs_setprop(void *, const char *, const char *, char *, int);
-int    xs_kvop(void *, int, char *, char *, size_t);
+int    xs_kvop(void *, int, char *, size_t, char *, size_t, size_t *);
 
 #define XEN_STATE_UNKNOWN      "0"
 #define XEN_STATE_INITIALIZING "1"
Index: usr.sbin/hostctl/hostctl.c
===================================================================
RCS file: /cvs/src/usr.sbin/hostctl/hostctl.c,v
retrieving revision 1.5
diff -u -p -r1.5 hostctl.c
--- usr.sbin/hostctl/hostctl.c  28 Jun 2019 13:32:47 -0000      1.5
+++ usr.sbin/hostctl/hostctl.c  5 Oct 2022 03:23:01 -0000
@@ -37,8 +37,7 @@ int            qflag = 0;                     /* quiet */
 int             tflag = 0;                     /* show type */
 
 __dead void     usage(void);
-int             kvsetstr(char *, const char *, size_t);
-int             kvsetfile(char *, const char *, size_t);
+int             kvsetfile(char **, const char *, size_t *);
 
 __dead void
 usage(void)
@@ -50,44 +49,40 @@ usage(void)
 }
 
 int
-kvsetstr(char *dst, const char *src, size_t dstlen)
+kvsetfile(char **dst, const char *input, size_t *dstlen)
 {
-       size_t  sz;
-
-       /* Sanitize the string before sending it to the kernel and host */
-       if ((sz = strnvis(dst, src, dstlen, VIS_SAFE | VIS_CSTYLE)) >= dstlen)
-               return (-1);
-
-       /* Remove trailing newline */
-       dst[strcspn(dst, "\n")] = '\0';
-
-       return (0);
-}
-
-int
-kvsetfile(char *dst, const char *input, size_t dstlen)
-{
-       char    *buf = NULL;
+       char     buf[KVBUFSZ];
        int      ret = -1;
-       FILE    *fp;
+       FILE    *fp, *mp;
+       size_t   flen;
 
        if (strcmp("-", input) == 0)
                fp = stdin;
        else if ((fp = fopen(input, "r")) == NULL)
                return (-1);
+       if ((mp = open_memstream(dst, dstlen)) == NULL) {
+               fclose(fp);
+               return (-1);
+       }
 
-       if ((buf = calloc(1, dstlen)) == NULL)
-               goto done;
-       if (fread(buf, 1, dstlen - 1, fp) == 0)
-               goto done;
-       if (kvsetstr(dst, buf, dstlen) == -1)
-               goto done;
+       do {
+               if ((flen = fread(buf, 1, sizeof (buf), fp)) == 0)
+                       goto done;
+               if (fwrite(buf, 1, flen, mp) == 0)
+                       goto done;
+       } while (flen >= sizeof (buf));
 
        ret = 0;
  done:
-       free(buf);
        if (fp != stdin)
                fclose(fp);
+       fclose(mp);
+
+       /* Remove '\n' at the end of line */
+       if ((*dst)[*dstlen - 1] == '\n') {
+               --(*dstlen);
+               (*dst)[*dstlen] = '\0';
+       }
        return (ret);
 }
 
@@ -101,6 +96,7 @@ main(int argc, char *argv[])
        int                     ch;
        unsigned long           cmd = 0;
        char                    *str;
+       size_t                  len;
 
        while ((ch = getopt(argc, argv, "f:i:o:qt")) != -1) {
                switch (ch) {
@@ -137,12 +133,17 @@ main(int argc, char *argv[])
        }
 
        memset(&pvr, 0, sizeof(pvr));
-       pvr.pvr_keylen = pvr.pvr_valuelen = KVBUFSZ;
-       if ((pvr.pvr_key = calloc(1, pvr.pvr_keylen)) == NULL ||
-           (pvr.pvr_value = calloc(1, pvr.pvr_valuelen)) == NULL)
-               err(1, "calloc");
 
        if (tflag) {
+               pvr.pvr_len = &len;
+               if ((ret = ioctl(fd, PVBUSIOC_GETTYPELEN, &pvr, sizeof(pvr)))
+                   == -1)
+                       err(1, "ioctl");
+               /* Add the NUL amount of the terminator */
+               pvr.pvr_keylen = len + 1;
+               if ((pvr.pvr_key = calloc(1, pvr.pvr_keylen)) == NULL)
+                       err(1, "calloc");
+
                if (ioctl(fd, PVBUSIOC_TYPE, &pvr, sizeof(pvr)) == -1)
                        err(1, "ioctl");
 
@@ -159,18 +160,20 @@ main(int argc, char *argv[])
                usage();
        key = argv[0];
 
-       if (kvsetstr(pvr.pvr_key, key, pvr.pvr_keylen) == -1)
-               errx(1, "key too long");
+       if (stravis(&pvr.pvr_key, key, VIS_SAFE | VIS_CSTYLE) == -1)
+               err(1, "stravis");
+       pvr.pvr_keylen = strlen(pvr.pvr_key) + 1;
 
        /* Validate command line options for reading or writing */
        if (argc == 2 && in == NULL) {
                cmd = PVBUSIOC_KVWRITE;
                value = argv[1];
-               if (kvsetstr(pvr.pvr_value, value, pvr.pvr_valuelen) == -1)
-                       errx(1, "value too long");
+               if (stravis(&pvr.pvr_value, value, VIS_SAFE | VIS_CSTYLE) == -1)
+                       err(1, "stravis");
+               pvr.pvr_valuelen = strlen(value) + 1;
        } else if (argc == 1 && in != NULL) {
                cmd = PVBUSIOC_KVWRITE;
-               if (kvsetfile(pvr.pvr_value, in, pvr.pvr_valuelen) == -1)
+               if (kvsetfile(&pvr.pvr_value, in, &pvr.pvr_valuelen) == -1)
                        errx(1, "input file");
        } else if (argc == 1) {
                cmd = cmd == 0 ? PVBUSIOC_KVREAD : cmd;
@@ -184,6 +187,18 @@ main(int argc, char *argv[])
                        err(1, "open: %s", path_pvbus);
        }
 
+       /* Get the length of value of key */
+       if (cmd == PVBUSIOC_KVREAD) {
+               pvr.pvr_len = &len;
+               if ((ret = ioctl(fd, PVBUSIOC_GETVALUELEN, &pvr, sizeof(pvr)))
+                   == -1)
+                       err(1, "ioctl");
+               /* Add the NUL amount of the terminator */
+               pvr.pvr_valuelen = len + 1;
+               if ((pvr.pvr_value = calloc(1, pvr.pvr_valuelen)) == NULL)
+                       err(1, "calloc");
+       }
+
        if ((ret = ioctl(fd, cmd, &pvr, sizeof(pvr))) == -1)
                err(1, "ioctl");
 
@@ -202,7 +217,8 @@ main(int argc, char *argv[])
  done:
        if (outfp != stdout)
                fclose(outfp);
-       free(pvr.pvr_value);
+       if (pvr.pvr_value != NULL)
+           free(pvr.pvr_value);
        free(pvr.pvr_key);
        close(fd);
 
--
ASOU Masato

Reply via email to