agreed, sent a new version.

Ethan

On Wed, Aug 12, 2015 at 5:01 PM, Jarno Rajahalme <jrajaha...@nicira.com> wrote:
>
>> On Aug 12, 2015, at 4:13 PM, Ethan J. Jackson <et...@nicira.com> wrote:
>>
>> From: Ethan Jackson <et...@nicira.com>
>>
>> Future patches will need to modify ukey actions in some instances.
>> This patch makes this possible by protecting them with RCU.  It also
>> adds thread safety checks to enforce the new protection mechanism.
>>
>> Signed-off-by: Ethan J. Jackson <et...@nicira.com>
>> ---
>> ofproto/ofproto-dpif-upcall.c | 47 
>> +++++++++++++++++++++++++++++++++++--------
>> 1 file changed, 39 insertions(+), 8 deletions(-)
>>
>> diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
>> index 0f2e186..c57cebd 100644
>> --- a/ofproto/ofproto-dpif-upcall.c
>> +++ b/ofproto/ofproto-dpif-upcall.c
>> @@ -215,7 +215,6 @@ struct udpif_key {
>>     size_t key_len;                /* Length of 'key'. */
>>     const struct nlattr *mask;     /* Datapath flow mask. */
>>     size_t mask_len;               /* Length of 'mask'. */
>> -    struct ofpbuf *actions;        /* Datapath flow actions as nlattrs. */
>>     ovs_u128 ufid;                 /* Unique flow identifier. */
>>     bool ufid_present;             /* True if 'ufid' is in datapath. */
>>     uint32_t hash;                 /* Pre-computed hash for 'key'. */
>> @@ -228,6 +227,10 @@ struct udpif_key {
>>     uint64_t reval_seq OVS_GUARDED;           /* Tracks udpif->reval_seq. */
>>     bool flow_exists OVS_GUARDED;             /* Ensures flows are only 
>> deleted
>>                                                  once. */
>> +    /* Datapath flow actions as nlattrs.  Protected by RCU.  Lockless reads 
>> can
>> +     * be made with ukey_get_actions(), otherwise a lock is required. 
>> Updates
>> +     * should be made with the ukey_set_actions() function. */
>> +    const struct ofpbuf *actions OVS_GUARDED;
>>
>
> IMO it would be prudent to define this as:
>
> OVSRCU_TYPE(const struct ofpbuf *) actions;
>
> and then always use ovsrcu_get() to access it, and ovsrcu_set() to set it. 
> This makes sure the memory barriers are there, i.e., the compiler will not 
> rearrange any initialization of the new actions after the point in which 
> other threads can see it.
>
> With this the OVS_GUARDED would not be needed here.
>
>   Jarno
>
>>     struct xlate_cache *xcache OVS_GUARDED;   /* Cache for xlate entries that
>>                                                * are affected by this ukey.
>> @@ -287,6 +290,8 @@ static struct udpif_key *ukey_create_from_upcall(struct 
>> upcall *,
>> static int ukey_create_from_dpif_flow(const struct udpif *,
>>                                       const struct dpif_flow *,
>>                                       struct udpif_key **);
>> +static void ukey_get_actions(struct udpif_key *, const struct nlattr 
>> **actions,
>> +                             size_t *size);
>> static bool ukey_install_start(struct udpif *, struct udpif_key *ukey);
>> static bool ukey_install_finish(struct udpif_key *ukey, int error);
>> static bool ukey_install(struct udpif *udpif, struct udpif_key *ukey);
>> @@ -1127,7 +1132,7 @@ process_upcall(struct udpif *udpif, struct upcall 
>> *upcall,
>>         if (upcall->sflow) {
>>             union user_action_cookie cookie;
>>             const struct nlattr *actions;
>> -            int actions_len = 0;
>> +            size_t actions_len = 0;
>>             struct dpif_sflow_actions sflow_actions;
>>             memset(&sflow_actions, 0, sizeof sflow_actions);
>>             memset(&cookie, 0, sizeof cookie);
>> @@ -1145,8 +1150,7 @@ process_upcall(struct udpif *udpif, struct upcall 
>> *upcall,
>>                 /* Lookup actions in userspace cache. */
>>                 struct udpif_key *ukey = ukey_lookup(udpif, upcall->ufid);
>>                 if (ukey) {
>> -                    actions = ukey->actions->data;
>> -                    actions_len = ukey->actions->size;
>> +                    ukey_get_actions(ukey, &actions, &actions_len);
>>                     dpif_sflow_read_actions(flow, actions, actions_len,
>>                                             &sflow_actions);
>>                 }
>> @@ -1273,8 +1277,8 @@ handle_upcalls(struct udpif *udpif, struct upcall 
>> *upcalls,
>>             op->dop.u.flow_put.mask_len = ukey->mask_len;
>>             op->dop.u.flow_put.ufid = upcall->ufid;
>>             op->dop.u.flow_put.stats = NULL;
>> -            op->dop.u.flow_put.actions = ukey->actions->data;
>> -            op->dop.u.flow_put.actions_len = ukey->actions->size;
>> +            ukey_get_actions(ukey, &op->dop.u.flow_put.actions,
>> +                             &op->dop.u.flow_put.actions_len);
>>         }
>>
>>         if (upcall->odp_actions.size) {
>> @@ -1340,6 +1344,31 @@ ukey_lookup(struct udpif *udpif, const ovs_u128 *ufid)
>>     return NULL;
>> }
>>
>> +/* Provides safe lockless access of RCU protected 'ukey->actions'.  Callers 
>> may
>> + * alternatively access the field directly if they take 'ukey->mutex'. */
>> +static void
>> +ukey_get_actions(struct udpif_key *ukey, const struct nlattr **actions, 
>> size_t *size)
>> +    OVS_NO_THREAD_SAFETY_ANALYSIS
>> +{
>> +    const struct ofpbuf *buf = ukey->actions;
>> +    *actions = buf->data;
>> +    *size = buf->size;
>> +}
>> +
>> +static void
>> +ukey_set_actions(struct udpif_key *ukey, const struct ofpbuf *actions)
>> +    OVS_REQUIRES(ukey->mutex)
>> +{
>> +    const struct ofpbuf *old_actions = ukey->actions;
>> +
>> +    ukey->actions = ofpbuf_clone(actions);
>> +
>> +    if (old_actions) {
>> +        ovsrcu_postpone(ofpbuf_delete, CONST_CAST(struct ofpbuf *,
>> +                                                  old_actions));
>> +    }
>> +}
>> +
>> static struct udpif_key *
>> ukey_create__(const struct nlattr *key, size_t key_len,
>>               const struct nlattr *mask, size_t mask_len,
>> @@ -1363,7 +1392,9 @@ ukey_create__(const struct nlattr *key, size_t key_len,
>>     ukey->ufid = *ufid;
>>     ukey->pmd_id = pmd_id;
>>     ukey->hash = get_ufid_hash(&ukey->ufid);
>> -    ukey->actions = ofpbuf_clone(actions);
>> +
>> +    ukey->actions = NULL;
>> +    ukey_set_actions(ukey, actions);
>>
>>     ovs_mutex_init(&ukey->mutex);
>>     ukey->dump_seq = dump_seq;
>> @@ -1616,7 +1647,7 @@ ukey_delete__(struct udpif_key *ukey)
>>             recirc_free_id(ukey->recircs[i]);
>>         }
>>         xlate_cache_delete(ukey->xcache);
>> -        ofpbuf_delete(ukey->actions);
>> +        ofpbuf_delete(CONST_CAST(struct ofpbuf *, ukey->actions));
>>         ovs_mutex_destroy(&ukey->mutex);
>>         free(ukey);
>>     }
>> --
>> 2.1.0
>>
>> _______________________________________________
>> dev mailing list
>> dev@openvswitch.org
>> http://openvswitch.org/mailman/listinfo/dev
>
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to