Commit bb949fbd authored by David S. Miller's avatar David S. Miller

netdev: Create netdev_queue abstraction.

A netdev_queue is an entity managed by a qdisc.

Currently there is one RX and one TX queue, and a netdev_queue merely
contains a backpointer to the net_device.

The Qdisc struct is augmented with a netdev_queue pointer as well.

Eventually the 'dev' Qdisc member will go away and we will have the
resulting hierarchy:

	net_device --> netdev_queue --> Qdisc

Also, qdisc_alloc() and qdisc_create_dflt() now take a netdev_queue
pointer argument.
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e65d22e1
...@@ -448,6 +448,10 @@ static inline void napi_synchronize(const struct napi_struct *n) ...@@ -448,6 +448,10 @@ static inline void napi_synchronize(const struct napi_struct *n)
# define napi_synchronize(n) barrier() # define napi_synchronize(n) barrier()
#endif #endif
struct netdev_queue {
struct net_device *dev;
};
/* /*
* The DEVICE structure. * The DEVICE structure.
* Actually, this whole structure is a big mistake. It mixes I/O * Actually, this whole structure is a big mistake. It mixes I/O
...@@ -624,6 +628,9 @@ struct net_device ...@@ -624,6 +628,9 @@ struct net_device
unsigned char broadcast[MAX_ADDR_LEN]; /* hw bcast add */ unsigned char broadcast[MAX_ADDR_LEN]; /* hw bcast add */
struct netdev_queue rx_queue;
struct netdev_queue tx_queue;
/* ingress path synchronizer */ /* ingress path synchronizer */
spinlock_t ingress_lock; spinlock_t ingress_lock;
struct Qdisc *qdisc_ingress; struct Qdisc *qdisc_ingress;
......
...@@ -37,6 +37,7 @@ struct Qdisc ...@@ -37,6 +37,7 @@ struct Qdisc
u32 parent; u32 parent;
atomic_t refcnt; atomic_t refcnt;
struct sk_buff_head q; struct sk_buff_head q;
struct netdev_queue *dev_queue;
struct net_device *dev; struct net_device *dev;
struct list_head list; struct list_head list;
...@@ -216,8 +217,11 @@ extern void dev_deactivate(struct net_device *dev); ...@@ -216,8 +217,11 @@ extern void dev_deactivate(struct net_device *dev);
extern void qdisc_reset(struct Qdisc *qdisc); extern void qdisc_reset(struct Qdisc *qdisc);
extern void qdisc_destroy(struct Qdisc *qdisc); extern void qdisc_destroy(struct Qdisc *qdisc);
extern void qdisc_tree_decrease_qlen(struct Qdisc *qdisc, unsigned int n); extern void qdisc_tree_decrease_qlen(struct Qdisc *qdisc, unsigned int n);
extern struct Qdisc *qdisc_alloc(struct net_device *dev, struct Qdisc_ops *ops); extern struct Qdisc *qdisc_alloc(struct net_device *dev,
struct netdev_queue *dev_queue,
struct Qdisc_ops *ops);
extern struct Qdisc *qdisc_create_dflt(struct net_device *dev, extern struct Qdisc *qdisc_create_dflt(struct net_device *dev,
struct netdev_queue *dev_queue,
struct Qdisc_ops *ops, u32 parentid); struct Qdisc_ops *ops, u32 parentid);
extern void tcf_destroy(struct tcf_proto *tp); extern void tcf_destroy(struct tcf_proto *tp);
extern void tcf_destroy_chain(struct tcf_proto **fl); extern void tcf_destroy_chain(struct tcf_proto **fl);
......
...@@ -4072,6 +4072,12 @@ static struct net_device_stats *internal_stats(struct net_device *dev) ...@@ -4072,6 +4072,12 @@ static struct net_device_stats *internal_stats(struct net_device *dev)
return &dev->stats; return &dev->stats;
} }
static void netdev_init_queues(struct net_device *dev)
{
dev->rx_queue.dev = dev;
dev->tx_queue.dev = dev;
}
/** /**
* alloc_netdev_mq - allocate network device * alloc_netdev_mq - allocate network device
* @sizeof_priv: size of private data to allocate space for * @sizeof_priv: size of private data to allocate space for
...@@ -4124,6 +4130,8 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, ...@@ -4124,6 +4130,8 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
dev->egress_subqueue_count = queue_count; dev->egress_subqueue_count = queue_count;
dev->gso_max_size = GSO_MAX_SIZE; dev->gso_max_size = GSO_MAX_SIZE;
netdev_init_queues(dev);
dev->get_stats = internal_stats; dev->get_stats = internal_stats;
netpoll_netdev_init(dev); netpoll_netdev_init(dev);
setup(dev); setup(dev);
......
...@@ -359,7 +359,8 @@ static int wme_qdiscop_init(struct Qdisc *qd, struct nlattr *opt) ...@@ -359,7 +359,8 @@ static int wme_qdiscop_init(struct Qdisc *qd, struct nlattr *opt)
/* create child queues */ /* create child queues */
for (i = 0; i < QD_NUM(hw); i++) { for (i = 0; i < QD_NUM(hw); i++) {
skb_queue_head_init(&q->requeued[i]); skb_queue_head_init(&q->requeued[i]);
q->queues[i] = qdisc_create_dflt(qd->dev, &pfifo_qdisc_ops, q->queues[i] = qdisc_create_dflt(qd->dev, qd->dev_queue,
&pfifo_qdisc_ops,
qd->handle); qd->handle);
if (!q->queues[i]) { if (!q->queues[i]) {
q->queues[i] = &noop_qdisc; q->queues[i] = &noop_qdisc;
...@@ -575,7 +576,8 @@ void ieee80211_install_qdisc(struct net_device *dev) ...@@ -575,7 +576,8 @@ void ieee80211_install_qdisc(struct net_device *dev)
{ {
struct Qdisc *qdisc; struct Qdisc *qdisc;
qdisc = qdisc_create_dflt(dev, &wme_qdisc_ops, TC_H_ROOT); qdisc = qdisc_create_dflt(dev, &dev->tx_queue,
&wme_qdisc_ops, TC_H_ROOT);
if (!qdisc) { if (!qdisc) {
printk(KERN_ERR "%s: qdisc installation failed\n", dev->name); printk(KERN_ERR "%s: qdisc installation failed\n", dev->name);
return; return;
......
...@@ -552,8 +552,8 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent, ...@@ -552,8 +552,8 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent,
*/ */
static struct Qdisc * static struct Qdisc *
qdisc_create(struct net_device *dev, u32 parent, u32 handle, qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue,
struct nlattr **tca, int *errp) u32 parent, u32 handle, struct nlattr **tca, int *errp)
{ {
int err; int err;
struct nlattr *kind = tca[TCA_KIND]; struct nlattr *kind = tca[TCA_KIND];
...@@ -593,7 +593,7 @@ qdisc_create(struct net_device *dev, u32 parent, u32 handle, ...@@ -593,7 +593,7 @@ qdisc_create(struct net_device *dev, u32 parent, u32 handle,
if (ops == NULL) if (ops == NULL)
goto err_out; goto err_out;
sch = qdisc_alloc(dev, ops); sch = qdisc_alloc(dev, dev_queue, ops);
if (IS_ERR(sch)) { if (IS_ERR(sch)) {
err = PTR_ERR(sch); err = PTR_ERR(sch);
goto err_out2; goto err_out2;
...@@ -892,10 +892,12 @@ static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) ...@@ -892,10 +892,12 @@ static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
if (!(n->nlmsg_flags&NLM_F_CREATE)) if (!(n->nlmsg_flags&NLM_F_CREATE))
return -ENOENT; return -ENOENT;
if (clid == TC_H_INGRESS) if (clid == TC_H_INGRESS)
q = qdisc_create(dev, tcm->tcm_parent, tcm->tcm_parent, q = qdisc_create(dev, &dev->rx_queue,
tcm->tcm_parent, tcm->tcm_parent,
tca, &err); tca, &err);
else else
q = qdisc_create(dev, tcm->tcm_parent, tcm->tcm_handle, q = qdisc_create(dev, &dev->tx_queue,
tcm->tcm_parent, tcm->tcm_handle,
tca, &err); tca, &err);
if (q == NULL) { if (q == NULL) {
if (err == -EAGAIN) if (err == -EAGAIN)
......
...@@ -296,7 +296,8 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent, ...@@ -296,7 +296,8 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent,
goto err_out; goto err_out;
} }
flow->filter_list = NULL; flow->filter_list = NULL;
flow->q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, classid); flow->q = qdisc_create_dflt(sch->dev, sch->dev_queue,
&pfifo_qdisc_ops, classid);
if (!flow->q) if (!flow->q)
flow->q = &noop_qdisc; flow->q = &noop_qdisc;
pr_debug("atm_tc_change: qdisc %p\n", flow->q); pr_debug("atm_tc_change: qdisc %p\n", flow->q);
...@@ -555,7 +556,8 @@ static int atm_tc_init(struct Qdisc *sch, struct nlattr *opt) ...@@ -555,7 +556,8 @@ static int atm_tc_init(struct Qdisc *sch, struct nlattr *opt)
pr_debug("atm_tc_init(sch %p,[qdisc %p],opt %p)\n", sch, p, opt); pr_debug("atm_tc_init(sch %p,[qdisc %p],opt %p)\n", sch, p, opt);
p->flows = &p->link; p->flows = &p->link;
p->link.q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, sch->handle); p->link.q = qdisc_create_dflt(sch->dev, sch->dev_queue,
&pfifo_qdisc_ops, sch->handle);
if (!p->link.q) if (!p->link.q)
p->link.q = &noop_qdisc; p->link.q = &noop_qdisc;
pr_debug("atm_tc_init: link (%p) qdisc %p\n", &p->link, p->link.q); pr_debug("atm_tc_init: link (%p) qdisc %p\n", &p->link, p->link.q);
......
...@@ -1401,7 +1401,8 @@ static int cbq_init(struct Qdisc *sch, struct nlattr *opt) ...@@ -1401,7 +1401,8 @@ static int cbq_init(struct Qdisc *sch, struct nlattr *opt)
q->link.sibling = &q->link; q->link.sibling = &q->link;
q->link.common.classid = sch->handle; q->link.common.classid = sch->handle;
q->link.qdisc = sch; q->link.qdisc = sch;
if (!(q->link.q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, if (!(q->link.q = qdisc_create_dflt(sch->dev, sch->dev_queue,
&pfifo_qdisc_ops,
sch->handle))) sch->handle)))
q->link.q = &noop_qdisc; q->link.q = &noop_qdisc;
...@@ -1645,7 +1646,8 @@ static int cbq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, ...@@ -1645,7 +1646,8 @@ static int cbq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
if (cl) { if (cl) {
if (new == NULL) { if (new == NULL) {
new = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, new = qdisc_create_dflt(sch->dev, sch->dev_queue,
&pfifo_qdisc_ops,
cl->common.classid); cl->common.classid);
if (new == NULL) if (new == NULL)
return -ENOBUFS; return -ENOBUFS;
...@@ -1877,7 +1879,8 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t ...@@ -1877,7 +1879,8 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
cl->R_tab = rtab; cl->R_tab = rtab;
rtab = NULL; rtab = NULL;
cl->refcnt = 1; cl->refcnt = 1;
if (!(cl->q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, classid))) if (!(cl->q = qdisc_create_dflt(sch->dev, sch->dev_queue,
&pfifo_qdisc_ops, classid)))
cl->q = &noop_qdisc; cl->q = &noop_qdisc;
cl->common.classid = classid; cl->common.classid = classid;
cl->tparent = parent; cl->tparent = parent;
......
...@@ -60,7 +60,8 @@ static int dsmark_graft(struct Qdisc *sch, unsigned long arg, ...@@ -60,7 +60,8 @@ static int dsmark_graft(struct Qdisc *sch, unsigned long arg,
sch, p, new, old); sch, p, new, old);
if (new == NULL) { if (new == NULL) {
new = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, new = qdisc_create_dflt(sch->dev, sch->dev_queue,
&pfifo_qdisc_ops,
sch->handle); sch->handle);
if (new == NULL) if (new == NULL)
new = &noop_qdisc; new = &noop_qdisc;
...@@ -390,7 +391,8 @@ static int dsmark_init(struct Qdisc *sch, struct nlattr *opt) ...@@ -390,7 +391,8 @@ static int dsmark_init(struct Qdisc *sch, struct nlattr *opt)
p->default_index = default_index; p->default_index = default_index;
p->set_tc_index = nla_get_flag(tb[TCA_DSMARK_SET_TC_INDEX]); p->set_tc_index = nla_get_flag(tb[TCA_DSMARK_SET_TC_INDEX]);
p->q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, sch->handle); p->q = qdisc_create_dflt(sch->dev, sch->dev_queue,
&pfifo_qdisc_ops, sch->handle);
if (p->q == NULL) if (p->q == NULL)
p->q = &noop_qdisc; p->q = &noop_qdisc;
......
...@@ -137,7 +137,8 @@ struct Qdisc *fifo_create_dflt(struct Qdisc *sch, struct Qdisc_ops *ops, ...@@ -137,7 +137,8 @@ struct Qdisc *fifo_create_dflt(struct Qdisc *sch, struct Qdisc_ops *ops,
struct Qdisc *q; struct Qdisc *q;
int err = -ENOMEM; int err = -ENOMEM;
q = qdisc_create_dflt(sch->dev, ops, TC_H_MAKE(sch->handle, 1)); q = qdisc_create_dflt(sch->dev, sch->dev_queue,
ops, TC_H_MAKE(sch->handle, 1));
if (q) { if (q) {
err = fifo_set_limit(q, limit); err = fifo_set_limit(q, limit);
if (err < 0) { if (err < 0) {
......
...@@ -440,7 +440,9 @@ static struct Qdisc_ops pfifo_fast_ops __read_mostly = { ...@@ -440,7 +440,9 @@ static struct Qdisc_ops pfifo_fast_ops __read_mostly = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
struct Qdisc *qdisc_alloc(struct net_device *dev, struct Qdisc_ops *ops) struct Qdisc *qdisc_alloc(struct net_device *dev,
struct netdev_queue *dev_queue,
struct Qdisc_ops *ops)
{ {
void *p; void *p;
struct Qdisc *sch; struct Qdisc *sch;
...@@ -462,6 +464,7 @@ struct Qdisc *qdisc_alloc(struct net_device *dev, struct Qdisc_ops *ops) ...@@ -462,6 +464,7 @@ struct Qdisc *qdisc_alloc(struct net_device *dev, struct Qdisc_ops *ops)
sch->ops = ops; sch->ops = ops;
sch->enqueue = ops->enqueue; sch->enqueue = ops->enqueue;
sch->dequeue = ops->dequeue; sch->dequeue = ops->dequeue;
sch->dev_queue = dev_queue;
sch->dev = dev; sch->dev = dev;
dev_hold(dev); dev_hold(dev);
atomic_set(&sch->refcnt, 1); atomic_set(&sch->refcnt, 1);
...@@ -471,12 +474,14 @@ struct Qdisc *qdisc_alloc(struct net_device *dev, struct Qdisc_ops *ops) ...@@ -471,12 +474,14 @@ struct Qdisc *qdisc_alloc(struct net_device *dev, struct Qdisc_ops *ops)
return ERR_PTR(err); return ERR_PTR(err);
} }
struct Qdisc * qdisc_create_dflt(struct net_device *dev, struct Qdisc_ops *ops, struct Qdisc * qdisc_create_dflt(struct net_device *dev,
struct netdev_queue *dev_queue,
struct Qdisc_ops *ops,
unsigned int parentid) unsigned int parentid)
{ {
struct Qdisc *sch; struct Qdisc *sch;
sch = qdisc_alloc(dev, ops); sch = qdisc_alloc(dev, dev_queue, ops);
if (IS_ERR(sch)) if (IS_ERR(sch))
goto errout; goto errout;
sch->stats_lock = &dev->queue_lock; sch->stats_lock = &dev->queue_lock;
...@@ -545,7 +550,8 @@ void dev_activate(struct net_device *dev) ...@@ -545,7 +550,8 @@ void dev_activate(struct net_device *dev)
if (dev->qdisc_sleeping == &noop_qdisc) { if (dev->qdisc_sleeping == &noop_qdisc) {
struct Qdisc *qdisc; struct Qdisc *qdisc;
if (dev->tx_queue_len) { if (dev->tx_queue_len) {
qdisc = qdisc_create_dflt(dev, &pfifo_fast_ops, qdisc = qdisc_create_dflt(dev, &dev->tx_queue,
&pfifo_fast_ops,
TC_H_ROOT); TC_H_ROOT);
if (qdisc == NULL) { if (qdisc == NULL) {
printk(KERN_INFO "%s: activation failed\n", dev->name); printk(KERN_INFO "%s: activation failed\n", dev->name);
......
...@@ -1083,7 +1083,8 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, ...@@ -1083,7 +1083,8 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
cl->refcnt = 1; cl->refcnt = 1;
cl->sched = q; cl->sched = q;
cl->cl_parent = parent; cl->cl_parent = parent;
cl->qdisc = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, classid); cl->qdisc = qdisc_create_dflt(sch->dev, sch->dev_queue,
&pfifo_qdisc_ops, classid);
if (cl->qdisc == NULL) if (cl->qdisc == NULL)
cl->qdisc = &noop_qdisc; cl->qdisc = &noop_qdisc;
INIT_LIST_HEAD(&cl->children); INIT_LIST_HEAD(&cl->children);
...@@ -1201,7 +1202,8 @@ hfsc_graft_class(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, ...@@ -1201,7 +1202,8 @@ hfsc_graft_class(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
if (cl->level > 0) if (cl->level > 0)
return -EINVAL; return -EINVAL;
if (new == NULL) { if (new == NULL) {
new = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, new = qdisc_create_dflt(sch->dev, sch->dev_queue,
&pfifo_qdisc_ops,
cl->cl_common.classid); cl->cl_common.classid);
if (new == NULL) if (new == NULL)
new = &noop_qdisc; new = &noop_qdisc;
...@@ -1443,7 +1445,8 @@ hfsc_init_qdisc(struct Qdisc *sch, struct nlattr *opt) ...@@ -1443,7 +1445,8 @@ hfsc_init_qdisc(struct Qdisc *sch, struct nlattr *opt)
q->root.cl_common.classid = sch->handle; q->root.cl_common.classid = sch->handle;
q->root.refcnt = 1; q->root.refcnt = 1;
q->root.sched = q; q->root.sched = q;
q->root.qdisc = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, q->root.qdisc = qdisc_create_dflt(sch->dev, sch->dev_queue,
&pfifo_qdisc_ops,
sch->handle); sch->handle);
if (q->root.qdisc == NULL) if (q->root.qdisc == NULL)
q->root.qdisc = &noop_qdisc; q->root.qdisc = &noop_qdisc;
......
...@@ -1129,7 +1129,8 @@ static int htb_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, ...@@ -1129,7 +1129,8 @@ static int htb_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
if (cl && !cl->level) { if (cl && !cl->level) {
if (new == NULL && if (new == NULL &&
(new = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, (new = qdisc_create_dflt(sch->dev, sch->dev_queue,
&pfifo_qdisc_ops,
cl->common.classid)) cl->common.classid))
== NULL) == NULL)
return -ENOBUFS; return -ENOBUFS;
...@@ -1256,7 +1257,8 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg) ...@@ -1256,7 +1257,8 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg)
return -EBUSY; return -EBUSY;
if (!cl->level && htb_parent_last_child(cl)) { if (!cl->level && htb_parent_last_child(cl)) {
new_q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, new_q = qdisc_create_dflt(sch->dev, sch->dev_queue,
&pfifo_qdisc_ops,
cl->parent->common.classid); cl->parent->common.classid);
last_child = 1; last_child = 1;
} }
...@@ -1376,7 +1378,8 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, ...@@ -1376,7 +1378,8 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
/* create leaf qdisc early because it uses kmalloc(GFP_KERNEL) /* create leaf qdisc early because it uses kmalloc(GFP_KERNEL)
so that can't be used inside of sch_tree_lock so that can't be used inside of sch_tree_lock
-- thanks to Karlis Peisenieks */ -- thanks to Karlis Peisenieks */
new_q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, classid); new_q = qdisc_create_dflt(sch->dev, sch->dev_queue,
&pfifo_qdisc_ops, classid);
sch_tree_lock(sch); sch_tree_lock(sch);
if (parent && !parent->level) { if (parent && !parent->level) {
unsigned int qlen = parent->un.leaf.q->q.qlen; unsigned int qlen = parent->un.leaf.q->q.qlen;
......
...@@ -536,7 +536,8 @@ static int netem_init(struct Qdisc *sch, struct nlattr *opt) ...@@ -536,7 +536,8 @@ static int netem_init(struct Qdisc *sch, struct nlattr *opt)
qdisc_watchdog_init(&q->watchdog, sch); qdisc_watchdog_init(&q->watchdog, sch);
q->qdisc = qdisc_create_dflt(sch->dev, &tfifo_qdisc_ops, q->qdisc = qdisc_create_dflt(sch->dev, sch->dev_queue,
&tfifo_qdisc_ops,
TC_H_MAKE(sch->handle, 1)); TC_H_MAKE(sch->handle, 1));
if (!q->qdisc) { if (!q->qdisc) {
pr_debug("netem: qdisc create failed\n"); pr_debug("netem: qdisc create failed\n");
......
...@@ -281,7 +281,8 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt) ...@@ -281,7 +281,8 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt)
for (i=0; i<q->bands; i++) { for (i=0; i<q->bands; i++) {
if (q->queues[i] == &noop_qdisc) { if (q->queues[i] == &noop_qdisc) {
struct Qdisc *child; struct Qdisc *child;
child = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, child = qdisc_create_dflt(sch->dev, sch->dev_queue,
&pfifo_qdisc_ops,
TC_H_MAKE(sch->handle, i + 1)); TC_H_MAKE(sch->handle, i + 1));
if (child) { if (child) {
sch_tree_lock(sch); sch_tree_lock(sch);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment