|
@@ -352,40 +352,6 @@ static void nf_ct_delete_from_lists(struct nf_conn *ct)
|
|
local_bh_enable();
|
|
local_bh_enable();
|
|
}
|
|
}
|
|
|
|
|
|
-static void death_by_event(unsigned long ul_conntrack)
|
|
|
|
-{
|
|
|
|
- struct nf_conn *ct = (void *)ul_conntrack;
|
|
|
|
- struct net *net = nf_ct_net(ct);
|
|
|
|
- struct nf_conntrack_ecache *ecache = nf_ct_ecache_find(ct);
|
|
|
|
-
|
|
|
|
- BUG_ON(ecache == NULL);
|
|
|
|
-
|
|
|
|
- if (nf_conntrack_event(IPCT_DESTROY, ct) < 0) {
|
|
|
|
- /* bad luck, let's retry again */
|
|
|
|
- ecache->timeout.expires = jiffies +
|
|
|
|
- (prandom_u32() % net->ct.sysctl_events_retry_timeout);
|
|
|
|
- add_timer(&ecache->timeout);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- /* we've got the event delivered, now it's dying */
|
|
|
|
- set_bit(IPS_DYING_BIT, &ct->status);
|
|
|
|
- nf_ct_put(ct);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void nf_ct_dying_timeout(struct nf_conn *ct)
|
|
|
|
-{
|
|
|
|
- struct net *net = nf_ct_net(ct);
|
|
|
|
- struct nf_conntrack_ecache *ecache = nf_ct_ecache_find(ct);
|
|
|
|
-
|
|
|
|
- BUG_ON(ecache == NULL);
|
|
|
|
-
|
|
|
|
- /* set a new timer to retry event delivery */
|
|
|
|
- setup_timer(&ecache->timeout, death_by_event, (unsigned long)ct);
|
|
|
|
- ecache->timeout.expires = jiffies +
|
|
|
|
- (prandom_u32() % net->ct.sysctl_events_retry_timeout);
|
|
|
|
- add_timer(&ecache->timeout);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
bool nf_ct_delete(struct nf_conn *ct, u32 portid, int report)
|
|
bool nf_ct_delete(struct nf_conn *ct, u32 portid, int report)
|
|
{
|
|
{
|
|
struct nf_conn_tstamp *tstamp;
|
|
struct nf_conn_tstamp *tstamp;
|
|
@@ -394,15 +360,20 @@ bool nf_ct_delete(struct nf_conn *ct, u32 portid, int report)
|
|
if (tstamp && tstamp->stop == 0)
|
|
if (tstamp && tstamp->stop == 0)
|
|
tstamp->stop = ktime_to_ns(ktime_get_real());
|
|
tstamp->stop = ktime_to_ns(ktime_get_real());
|
|
|
|
|
|
- if (!nf_ct_is_dying(ct) &&
|
|
|
|
- unlikely(nf_conntrack_event_report(IPCT_DESTROY, ct,
|
|
|
|
- portid, report) < 0)) {
|
|
|
|
|
|
+ if (nf_ct_is_dying(ct))
|
|
|
|
+ goto delete;
|
|
|
|
+
|
|
|
|
+ if (nf_conntrack_event_report(IPCT_DESTROY, ct,
|
|
|
|
+ portid, report) < 0) {
|
|
/* destroy event was not delivered */
|
|
/* destroy event was not delivered */
|
|
nf_ct_delete_from_lists(ct);
|
|
nf_ct_delete_from_lists(ct);
|
|
- nf_ct_dying_timeout(ct);
|
|
|
|
|
|
+ nf_conntrack_ecache_delayed_work(nf_ct_net(ct));
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ nf_conntrack_ecache_work(nf_ct_net(ct));
|
|
set_bit(IPS_DYING_BIT, &ct->status);
|
|
set_bit(IPS_DYING_BIT, &ct->status);
|
|
|
|
+ delete:
|
|
nf_ct_delete_from_lists(ct);
|
|
nf_ct_delete_from_lists(ct);
|
|
nf_ct_put(ct);
|
|
nf_ct_put(ct);
|
|
return true;
|
|
return true;
|
|
@@ -1464,26 +1435,6 @@ void nf_conntrack_flush_report(struct net *net, u32 portid, int report)
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(nf_conntrack_flush_report);
|
|
EXPORT_SYMBOL_GPL(nf_conntrack_flush_report);
|
|
|
|
|
|
-static void nf_ct_release_dying_list(struct net *net)
|
|
|
|
-{
|
|
|
|
- struct nf_conntrack_tuple_hash *h;
|
|
|
|
- struct nf_conn *ct;
|
|
|
|
- struct hlist_nulls_node *n;
|
|
|
|
- int cpu;
|
|
|
|
-
|
|
|
|
- for_each_possible_cpu(cpu) {
|
|
|
|
- struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu);
|
|
|
|
-
|
|
|
|
- spin_lock_bh(&pcpu->lock);
|
|
|
|
- hlist_nulls_for_each_entry(h, n, &pcpu->dying, hnnode) {
|
|
|
|
- ct = nf_ct_tuplehash_to_ctrack(h);
|
|
|
|
- /* never fails to remove them, no listeners at this point */
|
|
|
|
- nf_ct_kill(ct);
|
|
|
|
- }
|
|
|
|
- spin_unlock_bh(&pcpu->lock);
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static int untrack_refs(void)
|
|
static int untrack_refs(void)
|
|
{
|
|
{
|
|
int cnt = 0, cpu;
|
|
int cnt = 0, cpu;
|
|
@@ -1548,7 +1499,6 @@ i_see_dead_people:
|
|
busy = 0;
|
|
busy = 0;
|
|
list_for_each_entry(net, net_exit_list, exit_list) {
|
|
list_for_each_entry(net, net_exit_list, exit_list) {
|
|
nf_ct_iterate_cleanup(net, kill_all, NULL, 0, 0);
|
|
nf_ct_iterate_cleanup(net, kill_all, NULL, 0, 0);
|
|
- nf_ct_release_dying_list(net);
|
|
|
|
if (atomic_read(&net->ct.count) != 0)
|
|
if (atomic_read(&net->ct.count) != 0)
|
|
busy = 1;
|
|
busy = 1;
|
|
}
|
|
}
|