-static void tbl_mask_array_delete_mask(struct mask_array *ma,
- const struct sw_flow_mask *mask)
-{
- int i = 0;
-
- /* Delete a mask pointer from the valid section.
- *
- * Also move the last entry in its place, so there is no
- * whole in the valid section.
- *
- * Notice the last entry still points to the original mask.
- *
- * <Note>: there is a small race window that may cause a mask
- * to be missed in a search. Imaging a core is
- * walking through the array, passing the index of deleting mask.
- * But before reaching the last entry, it is overwritten,
- * by another core that is adding a new mask, now the last entry
- * will point to the new mask. In this case, the moved up last
- * entry can be missed by the core walking the mask array.
- *
- * In case this missed mask would have led to successful
- * lookup, Hitting the race window could cause a packet to miss
- * kernel flow cache, and be sent to the user space.
- * </Note>
- */
- for (i = 0; i < ma->count; i++)
- if (mask == ovsl_dereference(ma->masks[i])) {
- struct sw_flow_mask *last;
-
- last = ovsl_dereference(ma->masks[ma->count - 1]);
- rcu_assign_pointer(ma->masks[i], last);
- ma->count--;
- break;
- }
-
- /* Remove the deleted mask pointers from the invalid section. */
- for (i = ma->count; i < ma->max; i++)
- if (mask == ovsl_dereference(ma->masks[i]))
- RCU_INIT_POINTER(ma->masks[i], NULL);
-}
-