Skip to content

Commit f7dd521

Browse files
committed
Merge branch 'net_sched-reflect-tx_queue_len-change-for-pfifo_fast'
Cong Wang says: ==================== net_sched: reflect tx_queue_len change for pfifo_fast This pathcset restores the pfifo_fast qdisc behavior of dropping packets based on latest dev->tx_queue_len. Patch 1 introduces a helper, patch 2 introduces a new Qdisc ops which is called when we modify tx_queue_len, patch 3 implements this ops for pfifo_fast. Please see each patch for details. --- v3: use skb_array_resize_multiple() v2: handle error case for ->change_tx_queue_len() ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 4cd8795 + 7007ba6 commit f7dd521

File tree

6 files changed

+89
-37
lines changed

6 files changed

+89
-37
lines changed

include/linux/netdevice.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3331,6 +3331,7 @@ int dev_get_alias(const struct net_device *, char *, size_t);
33313331
int dev_change_net_namespace(struct net_device *, struct net *, const char *);
33323332
int __dev_set_mtu(struct net_device *, int);
33333333
int dev_set_mtu(struct net_device *, int);
3334+
int dev_change_tx_queue_len(struct net_device *, unsigned long);
33343335
void dev_set_group(struct net_device *, int);
33353336
int dev_set_mac_address(struct net_device *, struct sockaddr *);
33363337
int dev_change_carrier(struct net_device *, bool new_carrier);

include/net/sch_generic.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ struct Qdisc_ops {
200200
struct nlattr *arg,
201201
struct netlink_ext_ack *extack);
202202
void (*attach)(struct Qdisc *sch);
203+
int (*change_tx_queue_len)(struct Qdisc *, unsigned int);
203204

204205
int (*dump)(struct Qdisc *, struct sk_buff *);
205206
int (*dump_stats)(struct Qdisc *, struct gnet_dump *);
@@ -489,6 +490,7 @@ void qdisc_class_hash_remove(struct Qdisc_class_hash *,
489490
void qdisc_class_hash_grow(struct Qdisc *, struct Qdisc_class_hash *);
490491
void qdisc_class_hash_destroy(struct Qdisc_class_hash *);
491492

493+
int dev_qdisc_change_tx_queue_len(struct net_device *dev);
492494
void dev_init_scheduler(struct net_device *dev);
493495
void dev_shutdown(struct net_device *dev);
494496
void dev_activate(struct net_device *dev);

net/core/dev.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7047,6 +7047,35 @@ int dev_set_mtu(struct net_device *dev, int new_mtu)
70477047
}
70487048
EXPORT_SYMBOL(dev_set_mtu);
70497049

7050+
/**
7051+
* dev_change_tx_queue_len - Change TX queue length of a netdevice
7052+
* @dev: device
7053+
* @new_len: new tx queue length
7054+
*/
7055+
int dev_change_tx_queue_len(struct net_device *dev, unsigned long new_len)
7056+
{
7057+
unsigned int orig_len = dev->tx_queue_len;
7058+
int res;
7059+
7060+
if (new_len != (unsigned int)new_len)
7061+
return -ERANGE;
7062+
7063+
if (new_len != orig_len) {
7064+
dev->tx_queue_len = new_len;
7065+
res = call_netdevice_notifiers(NETDEV_CHANGE_TX_QUEUE_LEN, dev);
7066+
res = notifier_to_errno(res);
7067+
if (res) {
7068+
netdev_err(dev,
7069+
"refused to change device tx_queue_len\n");
7070+
dev->tx_queue_len = orig_len;
7071+
return res;
7072+
}
7073+
return dev_qdisc_change_tx_queue_len(dev);
7074+
}
7075+
7076+
return 0;
7077+
}
7078+
70507079
/**
70517080
* dev_set_group - Change group this device belongs to
70527081
* @dev: device

net/core/net-sysfs.c

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -346,37 +346,14 @@ static ssize_t flags_store(struct device *dev, struct device_attribute *attr,
346346
}
347347
NETDEVICE_SHOW_RW(flags, fmt_hex);
348348

349-
static int change_tx_queue_len(struct net_device *dev, unsigned long new_len)
350-
{
351-
unsigned int orig_len = dev->tx_queue_len;
352-
int res;
353-
354-
if (new_len != (unsigned int)new_len)
355-
return -ERANGE;
356-
357-
if (new_len != orig_len) {
358-
dev->tx_queue_len = new_len;
359-
res = call_netdevice_notifiers(NETDEV_CHANGE_TX_QUEUE_LEN, dev);
360-
res = notifier_to_errno(res);
361-
if (res) {
362-
netdev_err(dev,
363-
"refused to change device tx_queue_len\n");
364-
dev->tx_queue_len = orig_len;
365-
return -EFAULT;
366-
}
367-
}
368-
369-
return 0;
370-
}
371-
372349
static ssize_t tx_queue_len_store(struct device *dev,
373350
struct device_attribute *attr,
374351
const char *buf, size_t len)
375352
{
376353
if (!capable(CAP_NET_ADMIN))
377354
return -EPERM;
378355

379-
return netdev_store(dev, attr, buf, len, change_tx_queue_len);
356+
return netdev_store(dev, attr, buf, len, dev_change_tx_queue_len);
380357
}
381358
NETDEVICE_SHOW_RW(tx_queue_len, fmt_dec);
382359

net/core/rtnetlink.c

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2337,19 +2337,11 @@ static int do_setlink(const struct sk_buff *skb,
23372337

23382338
if (tb[IFLA_TXQLEN]) {
23392339
unsigned int value = nla_get_u32(tb[IFLA_TXQLEN]);
2340-
unsigned int orig_len = dev->tx_queue_len;
2341-
2342-
if (dev->tx_queue_len ^ value) {
2343-
dev->tx_queue_len = value;
2344-
err = call_netdevice_notifiers(
2345-
NETDEV_CHANGE_TX_QUEUE_LEN, dev);
2346-
err = notifier_to_errno(err);
2347-
if (err) {
2348-
dev->tx_queue_len = orig_len;
2349-
goto errout;
2350-
}
2351-
status |= DO_SETLINK_MODIFIED;
2352-
}
2340+
2341+
err = dev_change_tx_queue_len(dev, value);
2342+
if (err)
2343+
goto errout;
2344+
status |= DO_SETLINK_MODIFIED;
23532345
}
23542346

23552347
if (tb[IFLA_GSO_MAX_SIZE]) {

net/sched/sch_generic.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -763,6 +763,23 @@ static void pfifo_fast_destroy(struct Qdisc *sch)
763763
}
764764
}
765765

766+
static int pfifo_fast_change_tx_queue_len(struct Qdisc *sch,
767+
unsigned int new_len)
768+
{
769+
struct pfifo_fast_priv *priv = qdisc_priv(sch);
770+
struct skb_array *bands[PFIFO_FAST_BANDS];
771+
int prio;
772+
773+
for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) {
774+
struct skb_array *q = band2list(priv, prio);
775+
776+
bands[prio] = q;
777+
}
778+
779+
return skb_array_resize_multiple(bands, PFIFO_FAST_BANDS, new_len,
780+
GFP_KERNEL);
781+
}
782+
766783
struct Qdisc_ops pfifo_fast_ops __read_mostly = {
767784
.id = "pfifo_fast",
768785
.priv_size = sizeof(struct pfifo_fast_priv),
@@ -773,6 +790,7 @@ struct Qdisc_ops pfifo_fast_ops __read_mostly = {
773790
.destroy = pfifo_fast_destroy,
774791
.reset = pfifo_fast_reset,
775792
.dump = pfifo_fast_dump,
793+
.change_tx_queue_len = pfifo_fast_change_tx_queue_len,
776794
.owner = THIS_MODULE,
777795
.static_flags = TCQ_F_NOLOCK | TCQ_F_CPUSTATS,
778796
};
@@ -1178,6 +1196,39 @@ void dev_deactivate(struct net_device *dev)
11781196
}
11791197
EXPORT_SYMBOL(dev_deactivate);
11801198

1199+
static int qdisc_change_tx_queue_len(struct net_device *dev,
1200+
struct netdev_queue *dev_queue)
1201+
{
1202+
struct Qdisc *qdisc = dev_queue->qdisc_sleeping;
1203+
const struct Qdisc_ops *ops = qdisc->ops;
1204+
1205+
if (ops->change_tx_queue_len)
1206+
return ops->change_tx_queue_len(qdisc, dev->tx_queue_len);
1207+
return 0;
1208+
}
1209+
1210+
int dev_qdisc_change_tx_queue_len(struct net_device *dev)
1211+
{
1212+
bool up = dev->flags & IFF_UP;
1213+
unsigned int i;
1214+
int ret = 0;
1215+
1216+
if (up)
1217+
dev_deactivate(dev);
1218+
1219+
for (i = 0; i < dev->num_tx_queues; i++) {
1220+
ret = qdisc_change_tx_queue_len(dev, &dev->_tx[i]);
1221+
1222+
/* TODO: revert changes on a partial failure */
1223+
if (ret)
1224+
break;
1225+
}
1226+
1227+
if (up)
1228+
dev_activate(dev);
1229+
return ret;
1230+
}
1231+
11811232
static void dev_init_scheduler_queue(struct net_device *dev,
11821233
struct netdev_queue *dev_queue,
11831234
void *_qdisc)

0 commit comments

Comments
 (0)