Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Several conflicts here. NFP driver bug fix adding nfp_netdev_is_nfp_repr() check to nfp_fl_output() needed some adjustments because the code block is in an else block now. Parallel additions to net/pkt_cls.h and net/sch_generic.h A bug fix in __tcp_retransmit_skb() conflicted with some of the rbtree changes in net-next. The tc action RCU callback fixes in 'net' had some overlap with some of the recent tcf_block reworking. Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -77,6 +77,8 @@ out:
|
||||
}
|
||||
EXPORT_SYMBOL(register_tcf_proto_ops);
|
||||
|
||||
static struct workqueue_struct *tc_filter_wq;
|
||||
|
||||
int unregister_tcf_proto_ops(struct tcf_proto_ops *ops)
|
||||
{
|
||||
struct tcf_proto_ops *t;
|
||||
@@ -86,6 +88,7 @@ int unregister_tcf_proto_ops(struct tcf_proto_ops *ops)
|
||||
* tcf_proto_ops's destroy() handler.
|
||||
*/
|
||||
rcu_barrier();
|
||||
flush_workqueue(tc_filter_wq);
|
||||
|
||||
write_lock(&cls_mod_lock);
|
||||
list_for_each_entry(t, &tcf_proto_base, head) {
|
||||
@@ -100,6 +103,12 @@ int unregister_tcf_proto_ops(struct tcf_proto_ops *ops)
|
||||
}
|
||||
EXPORT_SYMBOL(unregister_tcf_proto_ops);
|
||||
|
||||
bool tcf_queue_work(struct work_struct *work)
|
||||
{
|
||||
return queue_work(tc_filter_wq, work);
|
||||
}
|
||||
EXPORT_SYMBOL(tcf_queue_work);
|
||||
|
||||
/* Select new prio value from the range, managed by kernel. */
|
||||
|
||||
static inline u32 tcf_auto_prio(struct tcf_proto *tp)
|
||||
@@ -308,27 +317,30 @@ int tcf_block_get(struct tcf_block **p_block,
|
||||
}
|
||||
EXPORT_SYMBOL(tcf_block_get);
|
||||
|
||||
void tcf_block_put_ext(struct tcf_block *block,
|
||||
struct tcf_proto __rcu **p_filter_chain, struct Qdisc *q,
|
||||
struct tcf_block_ext_info *ei)
|
||||
static void tcf_block_put_final(struct work_struct *work)
|
||||
{
|
||||
struct tcf_block *block = container_of(work, struct tcf_block, work);
|
||||
struct tcf_chain *chain, *tmp;
|
||||
|
||||
if (!block)
|
||||
return;
|
||||
/* At this point, all the chains should have refcnt == 1. */
|
||||
rtnl_lock();
|
||||
list_for_each_entry_safe(chain, tmp, &block->chain_list, list)
|
||||
tcf_chain_put(chain);
|
||||
rtnl_unlock();
|
||||
kfree(block);
|
||||
}
|
||||
|
||||
tcf_block_offload_unbind(block, q, ei);
|
||||
|
||||
/* XXX: Standalone actions are not allowed to jump to any chain, and
|
||||
* bound actions should be all removed after flushing. However,
|
||||
* filters are destroyed in RCU callbacks, we have to hold the chains
|
||||
* first, otherwise we would always race with RCU callbacks on this list
|
||||
* without proper locking.
|
||||
*/
|
||||
|
||||
/* Wait for existing RCU callbacks to cool down. */
|
||||
rcu_barrier();
|
||||
/* XXX: Standalone actions are not allowed to jump to any chain, and bound
|
||||
* actions should be all removed after flushing. However, filters are destroyed
|
||||
* in RCU callbacks, we have to hold the chains first, otherwise we would
|
||||
* always race with RCU callbacks on this list without proper locking.
|
||||
*/
|
||||
static void tcf_block_put_deferred(struct work_struct *work)
|
||||
{
|
||||
struct tcf_block *block = container_of(work, struct tcf_block, work);
|
||||
struct tcf_chain *chain;
|
||||
|
||||
rtnl_lock();
|
||||
/* Hold a refcnt for all chains, except 0, in case they are gone. */
|
||||
list_for_each_entry(chain, &block->chain_list, list)
|
||||
if (chain->index)
|
||||
@@ -338,13 +350,31 @@ void tcf_block_put_ext(struct tcf_block *block,
|
||||
list_for_each_entry(chain, &block->chain_list, list)
|
||||
tcf_chain_flush(chain);
|
||||
|
||||
/* Wait for RCU callbacks to release the reference count. */
|
||||
INIT_WORK(&block->work, tcf_block_put_final);
|
||||
/* Wait for RCU callbacks to release the reference count and make
|
||||
* sure their works have been queued before this.
|
||||
*/
|
||||
rcu_barrier();
|
||||
tcf_queue_work(&block->work);
|
||||
rtnl_unlock();
|
||||
}
|
||||
|
||||
/* At this point, all the chains should have refcnt == 1. */
|
||||
list_for_each_entry_safe(chain, tmp, &block->chain_list, list)
|
||||
tcf_chain_put(chain);
|
||||
kfree(block);
|
||||
void tcf_block_put_ext(struct tcf_block *block,
|
||||
struct tcf_proto __rcu **p_filter_chain, struct Qdisc *q,
|
||||
struct tcf_block_ext_info *ei)
|
||||
{
|
||||
if (!block)
|
||||
return;
|
||||
|
||||
tcf_block_offload_unbind(block, q, ei);
|
||||
|
||||
INIT_WORK(&block->work, tcf_block_put_deferred);
|
||||
/* Wait for existing RCU callbacks to cool down, make sure their works
|
||||
* have been queued before this. We can not flush pending works here
|
||||
* because we are holding the RTNL lock.
|
||||
*/
|
||||
rcu_barrier();
|
||||
tcf_queue_work(&block->work);
|
||||
}
|
||||
EXPORT_SYMBOL(tcf_block_put_ext);
|
||||
|
||||
@@ -354,6 +384,7 @@ void tcf_block_put(struct tcf_block *block)
|
||||
|
||||
tcf_block_put_ext(block, NULL, block->q, &ei);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(tcf_block_put);
|
||||
|
||||
struct tcf_block_cb {
|
||||
@@ -1051,6 +1082,7 @@ void tcf_exts_destroy(struct tcf_exts *exts)
|
||||
#ifdef CONFIG_NET_CLS_ACT
|
||||
LIST_HEAD(actions);
|
||||
|
||||
ASSERT_RTNL();
|
||||
tcf_exts_to_list(exts, &actions);
|
||||
tcf_action_destroy(&actions, TCA_ACT_UNBIND);
|
||||
kfree(exts->actions);
|
||||
@@ -1229,6 +1261,10 @@ EXPORT_SYMBOL(tc_setup_cb_call);
|
||||
|
||||
static int __init tc_filter_init(void)
|
||||
{
|
||||
tc_filter_wq = alloc_ordered_workqueue("tc_filter_workqueue", 0);
|
||||
if (!tc_filter_wq)
|
||||
return -ENOMEM;
|
||||
|
||||
rtnl_register(PF_UNSPEC, RTM_NEWTFILTER, tc_ctl_tfilter, NULL, 0);
|
||||
rtnl_register(PF_UNSPEC, RTM_DELTFILTER, tc_ctl_tfilter, NULL, 0);
|
||||
rtnl_register(PF_UNSPEC, RTM_GETTFILTER, tc_ctl_tfilter,
|
||||
|
Reference in New Issue
Block a user