diff options
Diffstat (limited to 'net/sched')
| -rw-r--r-- | net/sched/act_bpf.c | 2 | ||||
| -rw-r--r-- | net/sched/act_csum.c | 5 | ||||
| -rw-r--r-- | net/sched/act_ipt.c | 9 | ||||
| -rw-r--r-- | net/sched/act_pedit.c | 2 | ||||
| -rw-r--r-- | net/sched/act_police.c | 2 | ||||
| -rw-r--r-- | net/sched/act_sample.c | 3 | ||||
| -rw-r--r-- | net/sched/act_simple.c | 2 | ||||
| -rw-r--r-- | net/sched/act_skbmod.c | 5 | ||||
| -rw-r--r-- | net/sched/act_tunnel_key.c | 10 | ||||
| -rw-r--r-- | net/sched/act_vlan.c | 5 | ||||
| -rw-r--r-- | net/sched/cls_api.c | 33 | ||||
| -rw-r--r-- | net/sched/cls_u32.c | 24 | ||||
| -rw-r--r-- | net/sched/sch_generic.c | 22 | ||||
| -rw-r--r-- | net/sched/sch_netem.c | 2 | ||||
| -rw-r--r-- | net/sched/sch_tbf.c | 3 | 
15 files changed, 81 insertions, 48 deletions
diff --git a/net/sched/act_bpf.c b/net/sched/act_bpf.c index b3f2c15affa7..9d2cabf1dc7e 100644 --- a/net/sched/act_bpf.c +++ b/net/sched/act_bpf.c @@ -352,7 +352,7 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla,  	return res;  out:  	if (res == ACT_P_CREATED) -		tcf_idr_cleanup(*act, est); +		tcf_idr_release(*act, bind);  	return ret;  } diff --git a/net/sched/act_csum.c b/net/sched/act_csum.c index b7ba9b06b147..2a5c8fd860cf 100644 --- a/net/sched/act_csum.c +++ b/net/sched/act_csum.c @@ -350,7 +350,7 @@ static int tcf_csum_sctp(struct sk_buff *skb, unsigned int ihl,  {  	struct sctphdr *sctph; -	if (skb_is_gso(skb) && skb_shinfo(skb)->gso_type & SKB_GSO_SCTP) +	if (skb_is_gso(skb) && skb_is_gso_sctp(skb))  		return 1;  	sctph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*sctph)); @@ -626,7 +626,8 @@ static void tcf_csum_cleanup(struct tc_action *a)  	struct tcf_csum_params *params;  	params = rcu_dereference_protected(p->params, 1); -	kfree_rcu(params, rcu); +	if (params) +		kfree_rcu(params, rcu);  }  static int tcf_csum_walker(struct net *net, struct sk_buff *skb, diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c index 06e380ae0928..7e06b9b62613 100644 --- a/net/sched/act_ipt.c +++ b/net/sched/act_ipt.c @@ -80,9 +80,12 @@ static void ipt_destroy_target(struct xt_entry_target *t)  static void tcf_ipt_release(struct tc_action *a)  {  	struct tcf_ipt *ipt = to_ipt(a); -	ipt_destroy_target(ipt->tcfi_t); + +	if (ipt->tcfi_t) { +		ipt_destroy_target(ipt->tcfi_t); +		kfree(ipt->tcfi_t); +	}  	kfree(ipt->tcfi_tname); -	kfree(ipt->tcfi_t);  }  static const struct nla_policy ipt_policy[TCA_IPT_MAX + 1] = { @@ -187,7 +190,7 @@ err2:  	kfree(tname);  err1:  	if (ret == ACT_P_CREATED) -		tcf_idr_cleanup(*a, est); +		tcf_idr_release(*a, bind);  	return err;  } diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c index 349beaffb29e..fef08835f26d 100644 --- a/net/sched/act_pedit.c +++ b/net/sched/act_pedit.c @@ -176,7 +176,7 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,  		p = to_pedit(*a);  		keys = kmalloc(ksize, GFP_KERNEL);  		if (keys == NULL) { -			tcf_idr_cleanup(*a, est); +			tcf_idr_release(*a, bind);  			kfree(keys_ex);  			return -ENOMEM;  		} diff --git a/net/sched/act_police.c b/net/sched/act_police.c index 95d3c9097b25..faebf82b99f1 100644 --- a/net/sched/act_police.c +++ b/net/sched/act_police.c @@ -194,7 +194,7 @@ failure:  	qdisc_put_rtab(P_tab);  	qdisc_put_rtab(R_tab);  	if (ret == ACT_P_CREATED) -		tcf_idr_cleanup(*a, est); +		tcf_idr_release(*a, bind);  	return err;  } diff --git a/net/sched/act_sample.c b/net/sched/act_sample.c index 1ba0df238756..74c5d7e6a0fa 100644 --- a/net/sched/act_sample.c +++ b/net/sched/act_sample.c @@ -103,7 +103,8 @@ static void tcf_sample_cleanup(struct tc_action *a)  	psample_group = rtnl_dereference(s->psample_group);  	RCU_INIT_POINTER(s->psample_group, NULL); -	psample_group_put(psample_group); +	if (psample_group) +		psample_group_put(psample_group);  }  static bool tcf_sample_dev_ok_push(struct net_device *dev) diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c index 425eac11f6da..b1f38063ada0 100644 --- a/net/sched/act_simple.c +++ b/net/sched/act_simple.c @@ -121,7 +121,7 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla,  		d = to_defact(*a);  		ret = alloc_defdata(d, defdata);  		if (ret < 0) { -			tcf_idr_cleanup(*a, est); +			tcf_idr_release(*a, bind);  			return ret;  		}  		d->tcf_action = parm->action; diff --git a/net/sched/act_skbmod.c b/net/sched/act_skbmod.c index fa975262dbac..7b0700f52b50 100644 --- a/net/sched/act_skbmod.c +++ b/net/sched/act_skbmod.c @@ -152,7 +152,7 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla,  	ASSERT_RTNL();  	p = kzalloc(sizeof(struct tcf_skbmod_params), GFP_KERNEL);  	if (unlikely(!p)) { -		if (ovr) +		if (ret == ACT_P_CREATED)  			tcf_idr_release(*a, bind);  		return -ENOMEM;  	} @@ -190,7 +190,8 @@ static void tcf_skbmod_cleanup(struct tc_action *a)  	struct tcf_skbmod_params  *p;  	p = rcu_dereference_protected(d->skbmod_p, 1); -	kfree_rcu(p, rcu); +	if (p) +		kfree_rcu(p, rcu);  }  static int tcf_skbmod_dump(struct sk_buff *skb, struct tc_action *a, diff --git a/net/sched/act_tunnel_key.c b/net/sched/act_tunnel_key.c index 0e23aac09ad6..1281ca463727 100644 --- a/net/sched/act_tunnel_key.c +++ b/net/sched/act_tunnel_key.c @@ -153,6 +153,7 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla,  		metadata->u.tun_info.mode |= IP_TUNNEL_INFO_TX;  		break;  	default: +		ret = -EINVAL;  		goto err_out;  	} @@ -207,11 +208,12 @@ static void tunnel_key_release(struct tc_action *a)  	struct tcf_tunnel_key_params *params;  	params = rcu_dereference_protected(t->params, 1); +	if (params) { +		if (params->tcft_action == TCA_TUNNEL_KEY_ACT_SET) +			dst_release(¶ms->tcft_enc_metadata->dst); -	if (params->tcft_action == TCA_TUNNEL_KEY_ACT_SET) -		dst_release(¶ms->tcft_enc_metadata->dst); - -	kfree_rcu(params, rcu); +		kfree_rcu(params, rcu); +	}  }  static int tunnel_key_dump_addresses(struct sk_buff *skb, diff --git a/net/sched/act_vlan.c b/net/sched/act_vlan.c index e1a1b3f3983a..c49cb61adedf 100644 --- a/net/sched/act_vlan.c +++ b/net/sched/act_vlan.c @@ -195,7 +195,7 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,  	ASSERT_RTNL();  	p = kzalloc(sizeof(*p), GFP_KERNEL);  	if (!p) { -		if (ovr) +		if (ret == ACT_P_CREATED)  			tcf_idr_release(*a, bind);  		return -ENOMEM;  	} @@ -225,7 +225,8 @@ static void tcf_vlan_cleanup(struct tc_action *a)  	struct tcf_vlan_params *p;  	p = rcu_dereference_protected(v->vlan_p, 1); -	kfree_rcu(p, rcu); +	if (p) +		kfree_rcu(p, rcu);  }  static int tcf_vlan_dump(struct sk_buff *skb, struct tc_action *a, diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 2bc1bc23d42e..247b7cc20c13 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -376,17 +376,12 @@ struct tcf_net {  static unsigned int tcf_net_id;  static int tcf_block_insert(struct tcf_block *block, struct net *net, -			    u32 block_index, struct netlink_ext_ack *extack) +			    struct netlink_ext_ack *extack)  {  	struct tcf_net *tn = net_generic(net, tcf_net_id); -	int err; -	err = idr_alloc_u32(&tn->idr, block, &block_index, block_index, -			    GFP_KERNEL); -	if (err) -		return err; -	block->index = block_index; -	return 0; +	return idr_alloc_u32(&tn->idr, block, &block->index, block->index, +			     GFP_KERNEL);  }  static void tcf_block_remove(struct tcf_block *block, struct net *net) @@ -397,6 +392,7 @@ static void tcf_block_remove(struct tcf_block *block, struct net *net)  }  static struct tcf_block *tcf_block_create(struct net *net, struct Qdisc *q, +					  u32 block_index,  					  struct netlink_ext_ack *extack)  {  	struct tcf_block *block; @@ -419,10 +415,13 @@ static struct tcf_block *tcf_block_create(struct net *net, struct Qdisc *q,  		err = -ENOMEM;  		goto err_chain_create;  	} -	block->net = qdisc_net(q);  	block->refcnt = 1;  	block->net = net; -	block->q = q; +	block->index = block_index; + +	/* Don't store q pointer for blocks which are shared */ +	if (!tcf_block_shared(block)) +		block->q = q;  	return block;  err_chain_create: @@ -518,13 +517,12 @@ int tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q,  	}  	if (!block) { -		block = tcf_block_create(net, q, extack); +		block = tcf_block_create(net, q, ei->block_index, extack);  		if (IS_ERR(block))  			return PTR_ERR(block);  		created = true; -		if (ei->block_index) { -			err = tcf_block_insert(block, net, -					       ei->block_index, extack); +		if (tcf_block_shared(block)) { +			err = tcf_block_insert(block, net, extack);  			if (err)  				goto err_block_insert;  		} @@ -1399,13 +1397,18 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)  		    nla_get_u32(tca[TCA_CHAIN]) != chain->index)  			continue;  		if (!tcf_chain_dump(chain, q, parent, skb, cb, -				    index_start, &index)) +				    index_start, &index)) { +			err = -EMSGSIZE;  			break; +		}  	}  	cb->args[0] = index;  out: +	/* If we did no progress, the error (EMSGSIZE) is real */ +	if (skb->len == 0 && err) +		return err;  	return skb->len;  } diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 6c7601a530e3..ed8b6a24b9e9 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -96,7 +96,7 @@ struct tc_u_hnode {  struct tc_u_common {  	struct tc_u_hnode __rcu	*hlist; -	struct tcf_block	*block; +	void			*ptr;  	int			refcnt;  	struct idr		handle_idr;  	struct hlist_node	hnode; @@ -330,9 +330,25 @@ static struct hlist_head *tc_u_common_hash;  #define U32_HASH_SHIFT 10  #define U32_HASH_SIZE (1 << U32_HASH_SHIFT) +static void *tc_u_common_ptr(const struct tcf_proto *tp) +{ +	struct tcf_block *block = tp->chain->block; + +	/* The block sharing is currently supported only +	 * for classless qdiscs. In that case we use block +	 * for tc_u_common identification. In case the +	 * block is not shared, block->q is a valid pointer +	 * and we can use that. That works for classful qdiscs. +	 */ +	if (tcf_block_shared(block)) +		return block; +	else +		return block->q; +} +  static unsigned int tc_u_hash(const struct tcf_proto *tp)  { -	return hash_ptr(tp->chain->block, U32_HASH_SHIFT); +	return hash_ptr(tc_u_common_ptr(tp), U32_HASH_SHIFT);  }  static struct tc_u_common *tc_u_common_find(const struct tcf_proto *tp) @@ -342,7 +358,7 @@ static struct tc_u_common *tc_u_common_find(const struct tcf_proto *tp)  	h = tc_u_hash(tp);  	hlist_for_each_entry(tc, &tc_u_common_hash[h], hnode) { -		if (tc->block == tp->chain->block) +		if (tc->ptr == tc_u_common_ptr(tp))  			return tc;  	}  	return NULL; @@ -371,7 +387,7 @@ static int u32_init(struct tcf_proto *tp)  			kfree(root_ht);  			return -ENOBUFS;  		} -		tp_c->block = tp->chain->block; +		tp_c->ptr = tc_u_common_ptr(tp);  		INIT_HLIST_NODE(&tp_c->hnode);  		idr_init(&tp_c->handle_idr); diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 190570f21b20..7e3fbe9cc936 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -106,6 +106,14 @@ static inline void qdisc_enqueue_skb_bad_txq(struct Qdisc *q,  	__skb_queue_tail(&q->skb_bad_txq, skb); +	if (qdisc_is_percpu_stats(q)) { +		qdisc_qstats_cpu_backlog_inc(q, skb); +		qdisc_qstats_cpu_qlen_inc(q); +	} else { +		qdisc_qstats_backlog_inc(q, skb); +		q->q.qlen++; +	} +  	if (lock)  		spin_unlock(lock);  } @@ -196,14 +204,6 @@ static void try_bulk_dequeue_skb_slow(struct Qdisc *q,  			break;  		if (unlikely(skb_get_queue_mapping(nskb) != mapping)) {  			qdisc_enqueue_skb_bad_txq(q, nskb); - -			if (qdisc_is_percpu_stats(q)) { -				qdisc_qstats_cpu_backlog_inc(q, nskb); -				qdisc_qstats_cpu_qlen_inc(q); -			} else { -				qdisc_qstats_backlog_inc(q, nskb); -				q->q.qlen++; -			}  			break;  		}  		skb->next = nskb; @@ -628,6 +628,7 @@ static int pfifo_fast_enqueue(struct sk_buff *skb, struct Qdisc *qdisc,  	int band = prio2band[skb->priority & TC_PRIO_MAX];  	struct pfifo_fast_priv *priv = qdisc_priv(qdisc);  	struct skb_array *q = band2list(priv, band); +	unsigned int pkt_len = qdisc_pkt_len(skb);  	int err;  	err = skb_array_produce(q, skb); @@ -636,7 +637,10 @@ static int pfifo_fast_enqueue(struct sk_buff *skb, struct Qdisc *qdisc,  		return qdisc_drop_cpu(skb, qdisc, to_free);  	qdisc_qstats_cpu_qlen_inc(qdisc); -	qdisc_qstats_cpu_backlog_inc(qdisc, skb); +	/* Note: skb can not be used after skb_array_produce(), +	 * so we better not use qdisc_qstats_cpu_backlog_inc() +	 */ +	this_cpu_add(qdisc->cpu_qstats->backlog, pkt_len);  	return NET_XMIT_SUCCESS;  } diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index 7c179addebcd..7d6801fc5340 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -509,7 +509,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch,  	}  	if (unlikely(sch->q.qlen >= sch->limit)) -		return qdisc_drop(skb, sch, to_free); +		return qdisc_drop_all(skb, sch, to_free);  	qdisc_qstats_backlog_inc(sch, skb); diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c index 229172d509cc..03225a8df973 100644 --- a/net/sched/sch_tbf.c +++ b/net/sched/sch_tbf.c @@ -188,7 +188,8 @@ static int tbf_enqueue(struct sk_buff *skb, struct Qdisc *sch,  	int ret;  	if (qdisc_pkt_len(skb) > q->max_size) { -		if (skb_is_gso(skb) && skb_gso_mac_seglen(skb) <= q->max_size) +		if (skb_is_gso(skb) && +		    skb_gso_validate_mac_len(skb, q->max_size))  			return tbf_segment(skb, sch, to_free);  		return qdisc_drop(skb, sch, to_free);  	}  | 

