On Wed, Jan 8, 2014 at 3:57 PM, Ben Pfaff <b...@nicira.com> wrote:
> On Wed, Jan 08, 2014 at 03:32:25PM -0800, Pravin Shelar wrote:
>> On Fri, Dec 27, 2013 at 8:03 PM, Ben Pfaff <b...@nicira.com> wrote:
>> > This will allow for parallelism in multithreaded forwarding in an upcoming
>> > commit.
>> >
>> > Signed-off-by: Ben Pfaff <b...@nicira.com>
>
> ...
>
>> > +static struct dp_netdev_flow *
>> > +dp_netdev_flow_ref(const struct dp_netdev_flow *flow_)
>> > +{
>> > +    struct dp_netdev_flow *flow = CONST_CAST(struct dp_netdev_flow *, 
>> > flow_);
>> > +    if (flow) {
>> > +        ovs_refcount_ref(&flow->ref_cnt);
>> > +    }
>> > +    return flow;
>> > +}
>> > +
>> Can we have lock annotations for taking ref on action?
>
> I think that we could, but I don't think it would be very useful
> because these references aren't lexically balanced in one of the three
> callers.  That is, dpif_netdev_flow_dump_next() returns holding a
> reference, intentionally, which only next the next call to that
> function or to dpif_netdev_flow_dump_done() will release.
>
>> > +static void
>> > +dp_netdev_flow_unref(struct dp_netdev_flow *flow)
>> > +{
>> > +    if (flow && ovs_refcount_unref(&flow->ref_cnt) == 1) {
>> > +        cls_rule_destroy(CONST_CAST(struct cls_rule *, &flow->cr));
>> > +        ovs_mutex_lock(&flow->mutex);
>> > +        dp_netdev_actions_unref(flow->actions);
>> > +        ovs_mutex_unlock(&flow->mutex);
>>
>> do we really need to take lock here ?
>
> No.  Clang complains if we don't, because of the lock annotations:
>
>     ../lib/dpif-netdev.c:851:39: error: reading variable 'actions' requires 
> locking any mutex [-Werror,-Wthread-safety-analysis]
>             dp_netdev_actions_unref(flow->actions);
>
> At some point we probably will want to introduce some "fake locking"
> functions that are no-ops but satisfy Clang, but we haven't done that
> yet and our current practice is to just take the locks anyway.
>
>> > @@ -931,20 +1101,31 @@ dpif_netdev_flow_get(const struct dpif *dpif,
>> >          return error;
>> >      }
>> >
>> > -    ovs_mutex_lock(&dp_netdev_mutex);
>> > +    ovs_rwlock_rdlock(&dp->cls.rwlock);
>> >      netdev_flow = dp_netdev_find_flow(dp, &key);
>> > +    ovs_rwlock_unlock(&dp->cls.rwlock);
>> > +
>>
>> This needs dp->flow_mutex, since it does lookup flow_table. or
>> hmap_insert locking needs fix.
>
> Thanks.
>
> The comments show that I intended for dp->cls.rwlock to protect both
> dp->cls and dp->flow_table, so in dp_netdev_flow_add() I moved the
> hmap_insert() inside the existing block that holds dp->cls.rwlock.
>
>> It will be less confusing if classifier and flow table lookup
>> functions are named explicitly.
>
> Do you have a suggestion?  I have spent too much time looking at this
> code, myself.
>
>> > +    ovs_mutex_init(&netdev_flow->mutex);
>> > +    ovs_mutex_lock(&netdev_flow->mutex);
>> > +
>> >      netdev_flow->actions = dp_netdev_actions_create(actions, actions_len);
>> >
>> >      match_init(&match, flow, wc);
>> > -    cls_rule_init(&netdev_flow->cr, &match, NETDEV_RULE_PRIORITY);
>> > +    cls_rule_init(CONST_CAST(struct cls_rule *, &netdev_flow->cr),
>> > +                  &match, NETDEV_RULE_PRIORITY);
>> >      ovs_rwlock_wrlock(&dp->cls.rwlock);
>> > -    classifier_insert(&dp->cls, &netdev_flow->cr);
>> > +    classifier_insert(&dp->cls,
>> > +                      CONST_CAST(struct cls_rule *, &netdev_flow->cr));
>> >      ovs_rwlock_unlock(&dp->cls.rwlock);
>> >
>> > -    hmap_insert(&dp->flow_table, &netdev_flow->node, flow_hash(flow, 0));
>> > +    ovs_mutex_unlock(&netdev_flow->mutex);
>> > +
>> flow->mutex lock can be released once actions pointer is set, right?
>> or does it protect something more?
>> At this point no one can have access to this flow, so this locking
>> must be for sanity checker.
>
> Yes, all it us protects us against, at this point, is Clang warnings.
> Again, I guess we should work on that, and I'm sure we will at some
> point.
>
>> > +
>> > +exit:
>> > +    ovs_rwlock_unlock(&dp->port_rwlock);
>> > +    dp_netdev_unref(dp);
>> >  }
>> >
>> >  static void
>>
>> How much does separate flow_mutex lock helps over just cls.rwlock?
>
> I have not measured the advantage, but the idea is that cls.rwlock
> should be held for writing as briefly as possible, because it delays
> packet forwarding.  However, we need some way to ensure that writers
> (and there might be several threads trying to write) can prevent the
> flow table from changing as they check for some property and then act
> based on it (e.g. add a flow only if one doesn't already exist), so
> flow_mutex allows for that without delaying forwarding threads.

Thanks for explanation. make sense.
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to