diff options
author | Mike Belopuhov <mikeb@cvs.openbsd.org> | 2016-11-03 18:34:38 +0000 |
---|---|---|
committer | Mike Belopuhov <mikeb@cvs.openbsd.org> | 2016-11-03 18:34:38 +0000 |
commit | 4b3a0cdd06420cce6386bfd7879bc1c4d66a435a (patch) | |
tree | 59849afc9b4edc696c361db325ae3c98b9c67c71 /sys/dev/pv | |
parent | e65a8cca5d9ce289be63483259fd0dcbef98db67 (diff) |
Support for key removal and value update operations
This change makes it possible for the Host to update the value
of an existing key via a Set operation as well as to remove the
key completely with a Delete message.
Diffstat (limited to 'sys/dev/pv')
-rw-r--r-- | sys/dev/pv/hypervic.c | 111 | ||||
-rw-r--r-- | sys/dev/pv/hypervicreg.h | 6 |
2 files changed, 87 insertions, 30 deletions
diff --git a/sys/dev/pv/hypervic.c b/sys/dev/pv/hypervic.c index f8027d722ea..c234808842a 100644 --- a/sys/dev/pv/hypervic.c +++ b/sys/dev/pv/hypervic.c @@ -535,6 +535,20 @@ copyin_utf16le(void *dst, const void *src, size_t dlen, size_t slen) return (j); } +static inline int +keycmp_utf16le(const uint8_t *key, const uint8_t *ukey, size_t ukeylen) +{ + int i, j; + + for (i = j = 0; i < ukeylen; i += 2, j++) { + if (key[j] != ukey[i]) + return (key[j] > ukey[i] ? + key[j] - ukey[i] : + ukey[i] - key[j]); + } + return (0); +} + static void kvp_pool_init(struct kvp_pool *kvpl) { @@ -547,7 +561,7 @@ static int kvp_pool_insert(struct kvp_pool *kvpl, const char *key, const char *val, uint32_t vallen, uint32_t valtype) { - struct kvp_entry *kpe, *nkpe; + struct kvp_entry *kpe; int keylen = strlen(key); if (keylen > HV_KVP_MAX_KEY_SIZE / 2) @@ -562,20 +576,20 @@ kvp_pool_insert(struct kvp_pool *kvpl, const char *key, const char *val, } } - nkpe = pool_get(&kvp_entry_pool, PR_ZERO | PR_NOWAIT); - if (nkpe == NULL) + kpe = pool_get(&kvp_entry_pool, PR_ZERO | PR_NOWAIT); + if (kpe == NULL) return (ENOMEM); - strlcpy(nkpe->kpe_key, key, HV_KVP_MAX_KEY_SIZE / 2); + strlcpy(kpe->kpe_key, key, HV_KVP_MAX_KEY_SIZE / 2); - if ((nkpe->kpe_valtype = valtype) == HV_KVP_REG_SZ) - strlcpy(nkpe->kpe_val, val, HV_KVP_MAX_KEY_SIZE / 2); + if ((kpe->kpe_valtype = valtype) == HV_KVP_REG_SZ) + strlcpy(kpe->kpe_val, val, HV_KVP_MAX_KEY_SIZE / 2); else - memcpy(nkpe->kpe_val, val, vallen); + memcpy(kpe->kpe_val, val, vallen); - nkpe->kpe_index = kvpl->kvp_index++ & MAXPOOLENTS; + kpe->kpe_index = kvpl->kvp_index++ & MAXPOOLENTS; - TAILQ_INSERT_TAIL(&kvpl->kvp_entries, nkpe, kpe_entry); + TAILQ_INSERT_TAIL(&kvpl->kvp_entries, kpe, kpe_entry); mtx_leave(&kvpl->kvp_lock); @@ -617,34 +631,34 @@ static int kvp_pool_import(struct kvp_pool *kvpl, const char *key, uint32_t keylen, const char *val, uint32_t vallen, uint32_t valtype) { - struct kvp_entry *kpe, *nkpe; + struct kvp_entry *kpe; if (keylen > HV_KVP_MAX_KEY_SIZE || vallen > HV_KVP_MAX_VAL_SIZE) return (ERANGE); - nkpe = pool_get(&kvp_entry_pool, PR_ZERO | PR_NOWAIT); - if (nkpe == NULL) - return (ENOMEM); - - copyin_utf16le(nkpe->kpe_key, key, HV_KVP_MAX_KEY_SIZE / 2, keylen); - mtx_enter(&kvpl->kvp_lock); TAILQ_FOREACH(kpe, &kvpl->kvp_entries, kpe_entry) { - if (strcmp(kpe->kpe_key, nkpe->kpe_key) == 0) { - mtx_leave(&kvpl->kvp_lock); - pool_put(&kvp_entry_pool, nkpe); - return (EEXIST); - } + if (keycmp_utf16le(kpe->kpe_key, key, keylen) == 0) + break; } + if (kpe == NULL) { + kpe = pool_get(&kvp_entry_pool, PR_ZERO | PR_NOWAIT); + if (kpe == NULL) + return (ENOMEM); + + copyin_utf16le(kpe->kpe_key, key, HV_KVP_MAX_KEY_SIZE / 2, + keylen); - copyin_utf16le(nkpe->kpe_val, val, HV_KVP_MAX_VAL_SIZE / 2, vallen); - nkpe->kpe_valtype = valtype; + kpe->kpe_index = kvpl->kvp_index++ & MAXPOOLENTS; - nkpe->kpe_index = kvpl->kvp_index++ & MAXPOOLENTS; + TAILQ_INSERT_TAIL(&kvpl->kvp_entries, kpe, kpe_entry); + } + + copyin_utf16le(kpe->kpe_val, val, HV_KVP_MAX_VAL_SIZE / 2, vallen); + kpe->kpe_valtype = valtype; - TAILQ_INSERT_TAIL(&kvpl->kvp_entries, nkpe, kpe_entry); mtx_leave(&kvpl->kvp_lock); return (0); @@ -679,6 +693,31 @@ kvp_pool_export(struct kvp_pool *kvpl, uint32_t index, char *key, } static int +kvp_pool_remove(struct kvp_pool *kvpl, const char *key, uint32_t keylen) +{ + struct kvp_entry *kpe; + + mtx_enter(&kvpl->kvp_lock); + + TAILQ_FOREACH(kpe, &kvpl->kvp_entries, kpe_entry) { + if (keycmp_utf16le(kpe->kpe_key, key, keylen) == 0) + break; + } + if (kpe == NULL) { + mtx_leave(&kvpl->kvp_lock); + return (ENOENT); + } + + TAILQ_REMOVE(&kvpl->kvp_entries, kpe, kpe_entry); + + mtx_leave(&kvpl->kvp_lock); + + pool_put(&kvp_entry_pool, kpe); + + return (0); +} + +static int kvp_pool_extract(struct kvp_pool *kvpl, const char *key, char *val, uint32_t vallen) { @@ -766,13 +805,13 @@ hv_kvp_attach(struct hv_ic_dev *dv) for (i = 0; i < NKVPPOOLS; i++) kvp_pool_init(&kvp->kvp_pool[i]); - /* Initialize GuestIntrinsicExchangeItems (pool 3) */ + /* 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)) - printf("%s: failed to insert key '%s'\n", - sc->sc_dev.dv_xname, kvp_pool_auto[i].keyname); + DPRINTF("%s: failed to insert into 'Auto' pool\n", + sc->sc_dev.dv_xname); } sc->sc_pvbus->hv_kvop = hv_kvop; @@ -795,14 +834,16 @@ hv_kvp_process(struct hv_kvp *kvp, struct vmbus_icmsg_kvp *msg) kvm->kvm_val.kvm_key, kvm->kvm_val.kvm_keylen, kvm->kvm_val.kvm_val, kvm->kvm_val.kvm_vallen, kvm->kvm_val.kvm_valtype)) { - DPRINTF("%s: failed to import the value\n", __func__); + DPRINTF("%s: failed to import into 'Guest/Parameters'" + " pool\n", __func__); kvh->kvh_err = HV_KVP_S_CONT; } else if (kvh->kvh_pool == HV_KVP_POOL_EXTERNAL && kvp_pool_import(&kvp->kvp_pool[HV_KVP_POOL_EXTERNAL], kvm->kvm_val.kvm_key, kvm->kvm_val.kvm_keylen, kvm->kvm_val.kvm_val, kvm->kvm_val.kvm_vallen, kvm->kvm_val.kvm_valtype)) { - DPRINTF("%s: failed to import the value\n", __func__); + DPRINTF("%s: failed to import into 'External' pool\n", + __func__); kvh->kvh_err = HV_KVP_S_CONT; } else if (kvh->kvh_pool != HV_KVP_POOL_AUTO_EXTERNAL && kvh->kvh_pool != HV_KVP_POOL_EXTERNAL) { @@ -810,6 +851,16 @@ hv_kvp_process(struct hv_kvp *kvp, struct vmbus_icmsg_kvp *msg) } else kvh->kvh_err = HV_KVP_S_OK; break; + case HV_KVP_OP_DELETE: + if (kvh->kvh_pool != HV_KVP_POOL_EXTERNAL || + kvp_pool_remove(&kvp->kvp_pool[HV_KVP_POOL_EXTERNAL], + kvm->kvm_del.kvm_key, kvm->kvm_del.kvm_keylen)) { + DPRINTF("%s: failed to remove from 'External' pool\n", + __func__); + kvh->kvh_err = HV_KVP_S_CONT; + } else + kvh->kvh_err = HV_KVP_S_OK; + break; case HV_KVP_OP_ENUMERATE: if (kvh->kvh_pool == HV_KVP_POOL_AUTO && kvp_pool_export(&kvp->kvp_pool[HV_KVP_POOL_AUTO], diff --git a/sys/dev/pv/hypervicreg.h b/sys/dev/pv/hypervicreg.h index 5f113d3bf76..e903eb174cb 100644 --- a/sys/dev/pv/hypervicreg.h +++ b/sys/dev/pv/hypervicreg.h @@ -173,6 +173,11 @@ struct hv_kvp_msg_enum { uint8_t kvm_val[HV_KVP_MAX_VAL_SIZE]; } __packed; +struct hv_kvp_msg_del { + uint32_t kvm_keylen; + uint8_t kvm_key[HV_KVP_MAX_KEY_SIZE]; +} __packed; + struct hv_kvp_msg_addr { uint16_t kvm_mac[128]; uint8_t kvm_family; @@ -189,6 +194,7 @@ struct hv_kvp_msg_addr { union hv_kvp_msg { struct hv_kvp_msg_val kvm_val; struct hv_kvp_msg_enum kvm_enum; + struct hv_kvp_msg_del kvm_del; struct hv_kvp_msg_addr kvm_addr; }; |