diff options
Diffstat (limited to 'net/sched/sch_api.c')
| -rw-r--r-- | net/sched/sch_api.c | 34 | 
1 files changed, 22 insertions, 12 deletions
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 2adda7fa2d3..58bed7599db 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -135,7 +135,7 @@ static DEFINE_RWLOCK(qdisc_mod_lock);  static struct Qdisc_ops *qdisc_base; -/* Register/uregister queueing discipline */ +/* Register/unregister queueing discipline */  int register_qdisc(struct Qdisc_ops *qops)  { @@ -271,11 +271,16 @@ static struct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle)  	return NULL;  } -static void qdisc_list_add(struct Qdisc *q) +void qdisc_list_add(struct Qdisc *q)  { -	if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) -		list_add_tail(&q->list, &qdisc_dev(q)->qdisc->list); +	if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) { +		struct Qdisc *root = qdisc_dev(q)->qdisc; + +		WARN_ON_ONCE(root == &noop_qdisc); +		list_add_tail(&q->list, &root->list); +	}  } +EXPORT_SYMBOL(qdisc_list_add);  void qdisc_list_del(struct Qdisc *q)  { @@ -558,7 +563,7 @@ out:  }  EXPORT_SYMBOL(__qdisc_calculate_pkt_len); -void qdisc_warn_nonwc(char *txt, struct Qdisc *qdisc) +void qdisc_warn_nonwc(const char *txt, struct Qdisc *qdisc)  {  	if (!(qdisc->flags & TCQ_F_WARN_NONWC)) {  		pr_warn("%s: %s qdisc %X: is non-work-conserving?\n", @@ -737,9 +742,11 @@ void qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n)  	const struct Qdisc_class_ops *cops;  	unsigned long cl;  	u32 parentid; +	int drops;  	if (n == 0)  		return; +	drops = max_t(int, n, 0);  	while ((parentid = sch->parent)) {  		if (TC_H_MAJ(parentid) == TC_H_MAJ(TC_H_INGRESS))  			return; @@ -756,6 +763,7 @@ void qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n)  			cops->put(sch, cl);  		}  		sch->q.qlen -= n; +		sch->qstats.drops += drops;  	}  }  EXPORT_SYMBOL(qdisc_tree_decrease_qlen); @@ -1076,7 +1084,8 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n)  	struct Qdisc *p = NULL;  	int err; -	if ((n->nlmsg_type != RTM_GETQDISC) && !capable(CAP_NET_ADMIN)) +	if ((n->nlmsg_type != RTM_GETQDISC) && +	    !netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN))  		return -EPERM;  	err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL); @@ -1143,7 +1152,7 @@ static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n)  	struct Qdisc *q, *p;  	int err; -	if (!capable(CAP_NET_ADMIN)) +	if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN))  		return -EPERM;  replay: @@ -1296,6 +1305,7 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid,  	struct gnet_dump d;  	struct qdisc_size_table *stab; +	cond_resched();  	nlh = nlmsg_put(skb, portid, seq, event, sizeof(*tcm), flags);  	if (!nlh)  		goto out_nlmsg_trim; @@ -1427,9 +1437,9 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)  	s_idx = cb->args[0];  	s_q_idx = q_idx = cb->args[1]; -	rcu_read_lock();  	idx = 0; -	for_each_netdev_rcu(net, dev) { +	ASSERT_RTNL(); +	for_each_netdev(net, dev) {  		struct netdev_queue *dev_queue;  		if (idx < s_idx) @@ -1452,8 +1462,6 @@ cont:  	}  done: -	rcu_read_unlock(); -  	cb->args[0] = idx;  	cb->args[1] = q_idx; @@ -1483,7 +1491,8 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n)  	u32 qid;  	int err; -	if ((n->nlmsg_type != RTM_GETTCLASS) && !capable(CAP_NET_ADMIN)) +	if ((n->nlmsg_type != RTM_GETTCLASS) && +	    !netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN))  		return -EPERM;  	err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL); @@ -1610,6 +1619,7 @@ static int tc_fill_tclass(struct sk_buff *skb, struct Qdisc *q,  	struct gnet_dump d;  	const struct Qdisc_class_ops *cl_ops = q->ops->cl_ops; +	cond_resched();  	nlh = nlmsg_put(skb, portid, seq, event, sizeof(*tcm), flags);  	if (!nlh)  		goto out_nlmsg_trim;  | 
