summaryrefslogtreecommitdiff
path: root/sys/dev/pv
diff options
context:
space:
mode:
authorMike Belopuhov <mikeb@cvs.openbsd.org>2016-11-03 18:34:38 +0000
committerMike Belopuhov <mikeb@cvs.openbsd.org>2016-11-03 18:34:38 +0000
commit4b3a0cdd06420cce6386bfd7879bc1c4d66a435a (patch)
tree59849afc9b4edc696c361db325ae3c98b9c67c71 /sys/dev/pv
parente65a8cca5d9ce289be63483259fd0dcbef98db67 (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.c111
-rw-r--r--sys/dev/pv/hypervicreg.h6
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;
};