Thanks, applied to master.
On 5 June 2014 06:26, Ethan Jackson <et...@nicira.com> wrote: > Acked > > > On Tuesday, June 3, 2014, Joe Stringer <joestrin...@nicira.com> wrote: > >> This patch refactors the code around ukey creation and lookup to >> simplify the code for callers. A new function ukey_acquire() combines >> these functions and attempts to acquire a lock on the ukey. Failure to >> acquire a lock on the ukey is usually a sign that another thread is >> handling the same flow concurrently, which means the flow does not need >> to be handled anyway. >> >> Signed-off-by: Joe Stringer <joestrin...@nicira.com> >> --- >> v2: Make ukey_create() return the ukey locked. >> Rearrange the logic in ukey_acquire(). >> --- >> ofproto/ofproto-dpif-upcall.c | 95 >> +++++++++++++++++++---------------------- >> 1 file changed, 43 insertions(+), 52 deletions(-) >> >> diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c >> index 9d48e98..3a75690 100644 >> --- a/ofproto/ofproto-dpif-upcall.c >> +++ b/ofproto/ofproto-dpif-upcall.c >> @@ -216,6 +216,12 @@ static void upcall_unixctl_set_flow_limit(struct >> unixctl_conn *conn, int argc, >> >> static struct udpif_key *ukey_create(const struct nlattr *key, size_t >> key_len, >> long long int used); >> +static struct udpif_key *ukey_lookup(struct udpif *udpif, >> + const struct nlattr *key, size_t >> key_len, >> + uint32_t hash); >> +static bool ukey_acquire(struct udpif *udpif, const struct nlattr *key, >> + size_t key_len, long long int used, >> + struct udpif_key **result); >> static void ukey_delete(struct revalidator *, struct udpif_key *); >> >> static atomic_bool enable_megaflows = ATOMIC_VAR_INIT(true); >> @@ -983,8 +989,9 @@ handle_upcalls(struct handler *handler, struct upcall >> *upcalls, >> >> /* Must be called with udpif->ukeys[hash % udpif->n_revalidators].mutex. >> */ >> static struct udpif_key * >> -ukey_lookup__(struct udpif *udpif, const struct nlattr *key, size_t >> key_len, >> - uint32_t hash) >> +ukey_lookup(struct udpif *udpif, const struct nlattr *key, size_t >> key_len, >> + uint32_t hash) >> + OVS_REQUIRES(udpif->ukeys->mutex) >> { >> struct udpif_key *ukey; >> struct hmap *hmap = &udpif->ukeys[hash % udpif->n_revalidators].hmap; >> @@ -997,26 +1004,15 @@ ukey_lookup__(struct udpif *udpif, const struct >> nlattr *key, size_t key_len, >> return NULL; >> } >> >> -static struct udpif_key * >> -ukey_lookup(struct udpif *udpif, const struct nlattr *key, size_t >> key_len, >> - uint32_t hash) >> -{ >> - struct udpif_key *ukey; >> - uint32_t idx = hash % udpif->n_revalidators; >> - >> - ovs_mutex_lock(&udpif->ukeys[idx].mutex); >> - ukey = ukey_lookup__(udpif, key, key_len, hash); >> - ovs_mutex_unlock(&udpif->ukeys[idx].mutex); >> - >> - return ukey; >> -} >> - >> +/* Creates a ukey for 'key' and 'key_len', returning it with ukey->mutex >> in >> + * a locked state. */ >> static struct udpif_key * >> ukey_create(const struct nlattr *key, size_t key_len, long long int used) >> + OVS_NO_THREAD_SAFETY_ANALYSIS >> { >> struct udpif_key *ukey = xmalloc(sizeof *ukey); >> - ovs_mutex_init(&ukey->mutex); >> >> + ovs_mutex_init(&ukey->mutex); >> ukey->key = (struct nlattr *) &ukey->key_buf; >> memcpy(&ukey->key_buf, key, key_len); >> ukey->key_len = key_len; >> @@ -1027,33 +1023,44 @@ ukey_create(const struct nlattr *key, size_t >> key_len, long long int used) >> ukey->created = used ? used : time_msec(); >> memset(&ukey->stats, 0, sizeof ukey->stats); >> ukey->xcache = NULL; >> - ovs_mutex_unlock(&ukey->mutex); >> >> return ukey; >> } >> >> -/* Checks for a ukey in 'udpif->ukeys' with the same 'ukey->key' and >> 'hash', >> - * and inserts 'ukey' if it does not exist. >> +/* Searches for a ukey in 'udpif->ukeys' that matches 'key' and >> 'key_len' and >> + * attempts to lock the ukey. If the ukey does not exist, create it. >> * >> - * Returns true if 'ukey' was inserted into 'udpif->ukeys', false >> otherwise. */ >> + * Returns true on success, setting *result to the matching ukey and >> returning >> + * it in a locked state. Otherwise, returns false and clears *result. */ >> static bool >> -udpif_insert_ukey(struct udpif *udpif, struct udpif_key *ukey, uint32_t >> hash) >> +ukey_acquire(struct udpif *udpif, const struct nlattr *key, size_t >> key_len, >> + long long int used, struct udpif_key **result) >> + OVS_TRY_LOCK(true, (*result)->mutex) >> { >> - struct udpif_key *duplicate; >> - uint32_t idx = hash % udpif->n_revalidators; >> - bool ok; >> + struct udpif_key *ukey; >> + uint32_t hash, idx; >> + bool locked = false; >> + >> + hash = hash_bytes(key, key_len, udpif->secret); >> + idx = hash % udpif->n_revalidators; >> >> ovs_mutex_lock(&udpif->ukeys[idx].mutex); >> - duplicate = ukey_lookup__(udpif, ukey->key, ukey->key_len, hash); >> - if (duplicate) { >> - ok = false; >> - } else { >> + ukey = ukey_lookup(udpif, key, key_len, hash); >> + if (!ukey) { >> + ukey = ukey_create(key, key_len, used); >> hmap_insert(&udpif->ukeys[idx].hmap, &ukey->hmap_node, hash); >> - ok = true; >> + locked = true; >> + } else if (!ovs_mutex_trylock(&ukey->mutex)) { >> + locked = true; >> } >> ovs_mutex_unlock(&udpif->ukeys[idx].mutex); >> >> - return ok; >> + if (locked) { >> + *result = ukey; >> + } else { >> + *result = NULL; >> + } >> + return locked; >> } >> >> static void >> @@ -1362,29 +1369,13 @@ revalidate(struct revalidator *revalidator) >> >> for (f = flows; f < &flows[n_dumped]; f++) { >> long long int used = f->stats.used; >> - uint32_t hash = hash_bytes(f->key, f->key_len, >> udpif->secret); >> - struct udpif_key *ukey = ukey_lookup(udpif, f->key, >> f->key_len, >> - hash); >> + struct udpif_key *ukey; >> bool already_dumped, mark; >> >> - if (!ukey) { >> - ukey = ukey_create(f->key, f->key_len, used); >> - if (!udpif_insert_ukey(udpif, ukey, hash)) { >> - /* The same ukey has already been created. This >> means that >> - * another revalidator is processing this flow >> - * concurrently, so don't bother processing it. */ >> - COVERAGE_INC(upcall_duplicate_flow); >> - ukey_delete(NULL, ukey); >> - continue; >> - } >> - } >> - >> - if (ovs_mutex_trylock(&ukey->mutex)) { >> - /* The flow has been dumped, and is being handled by >> another >> - * revalidator concurrently. This can occasionally occur >> if the >> - * datapath is changed in the middle of a flow dump. >> Rather >> - * than perform the same work twice, skip the flow this >> time. >> - */ >> + if (!ukey_acquire(udpif, f->key, f->key_len, used, &ukey)) { >> + /* We couldn't acquire the ukey. This means that >> + * another revalidator is processing this flow >> + * concurrently, so don't bother processing it. */ >> COVERAGE_INC(upcall_duplicate_flow); >> continue; >> } >> -- >> 1.7.10.4 >> >> _______________________________________________ >> dev mailing list >> dev@openvswitch.org >> http://openvswitch.org/mailman/listinfo/dev >> >
_______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev