mirror of
https://github.com/torvalds/linux.git
synced 2026-10-23 23:51:02 +02:00
netfilter: flowtable: generalize pending status bit
Rename NF_FLOW_HW_PENDING to NF_FLOW_PENDING and use it to inhibit the flowtable GC worker until pending hw offload work has been completed. Apparently, nf_flow_offload_stats() can schedule work to retrieve stats while the flow is being removed by GC. And this bit can also be used in a follow up patch to disable GC until the flow has been fully added in both directions. Revert the reordering done in commitd644b23afe("netfilter: flowtable: publish HW_DEAD after worker is done") to prevent a race between GC and hw offload handler. Fixes:2c8897953f("netfilter: flowtable: Add pending bit for offload work") Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
parent
16d464013e
commit
7c549fb7ee
|
|
@ -183,10 +183,10 @@ enum nf_flow_flags {
|
|||
NF_FLOW_DNAT,
|
||||
NF_FLOW_CLOSING,
|
||||
NF_FLOW_TEARDOWN,
|
||||
NF_FLOW_PENDING,
|
||||
NF_FLOW_HW,
|
||||
NF_FLOW_HW_DYING,
|
||||
NF_FLOW_HW_DEAD,
|
||||
NF_FLOW_HW_PENDING,
|
||||
NF_FLOW_HW_BIDIRECTIONAL,
|
||||
NF_FLOW_HW_ESTABLISHED,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -575,7 +575,12 @@ static void nf_flow_table_extend_ct_timeout(struct nf_conn *ct)
|
|||
static void nf_flow_offload_gc_step(struct nf_flowtable *flow_table,
|
||||
struct flow_offload *flow, void *data)
|
||||
{
|
||||
bool teardown = test_bit(NF_FLOW_TEARDOWN, &flow->flags);
|
||||
bool teardown;
|
||||
|
||||
if (test_bit(NF_FLOW_PENDING, &flow->flags))
|
||||
return;
|
||||
|
||||
teardown = test_bit(NF_FLOW_TEARDOWN, &flow->flags);
|
||||
|
||||
if (nf_flow_has_expired(flow) ||
|
||||
nf_ct_is_dying(flow->ct) ||
|
||||
|
|
|
|||
|
|
@ -995,6 +995,7 @@ static void flow_offload_work_del(struct flow_offload_work *offload)
|
|||
flow_offload_tuple_del(offload, FLOW_OFFLOAD_DIR_ORIGINAL);
|
||||
if (test_bit(NF_FLOW_HW_BIDIRECTIONAL, &offload->flow->flags))
|
||||
flow_offload_tuple_del(offload, FLOW_OFFLOAD_DIR_REPLY);
|
||||
set_bit(NF_FLOW_HW_DEAD, &offload->flow->flags);
|
||||
}
|
||||
|
||||
static void flow_offload_tuple_stats(struct flow_offload_work *offload,
|
||||
|
|
@ -1056,13 +1057,8 @@ static void flow_offload_work_handler(struct work_struct *work)
|
|||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
}
|
||||
|
||||
clear_bit(NF_FLOW_HW_PENDING, &offload->flow->flags);
|
||||
if (offload->cmd == FLOW_CLS_DESTROY) {
|
||||
/* Publish after the worker's last flow access. */
|
||||
smp_mb__before_atomic();
|
||||
set_bit(NF_FLOW_HW_DEAD, &offload->flow->flags);
|
||||
}
|
||||
smp_mb__before_atomic();
|
||||
clear_bit(NF_FLOW_PENDING, &offload->flow->flags);
|
||||
|
||||
kfree(offload);
|
||||
}
|
||||
|
|
@ -1089,12 +1085,12 @@ nf_flow_offload_work_alloc(struct nf_flowtable *flowtable,
|
|||
{
|
||||
struct flow_offload_work *offload;
|
||||
|
||||
if (test_and_set_bit(NF_FLOW_HW_PENDING, &flow->flags))
|
||||
if (test_and_set_bit(NF_FLOW_PENDING, &flow->flags))
|
||||
return NULL;
|
||||
|
||||
offload = kmalloc_obj(struct flow_offload_work, GFP_ATOMIC);
|
||||
if (!offload) {
|
||||
clear_bit(NF_FLOW_HW_PENDING, &flow->flags);
|
||||
clear_bit(NF_FLOW_PENDING, &flow->flags);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -289,7 +289,7 @@ static bool tcf_ct_flow_is_outdated(const struct flow_offload *flow)
|
|||
{
|
||||
return test_bit(IPS_SEEN_REPLY_BIT, &flow->ct->status) &&
|
||||
test_bit(IPS_HW_OFFLOAD_BIT, &flow->ct->status) &&
|
||||
!test_bit(NF_FLOW_HW_PENDING, &flow->flags) &&
|
||||
!test_bit(NF_FLOW_PENDING, &flow->flags) &&
|
||||
!test_bit(NF_FLOW_HW_ESTABLISHED, &flow->flags);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user