net-sysfs: add support for device-specific rx queue sysfs attributes
Extend existing support for netdevice receive queue sysfs attributes to permit a device-specific attribute group. Initial use case for this support will be to allow the virtio-net device to export per-receive queue mergeable receive buffer size. Signed-off-by: Michael Dalton <mwdalton@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
ab7db91705
commit
a953be53ce
@ -668,15 +668,28 @@ extern struct rps_sock_flow_table __rcu *rps_sock_flow_table;
|
|||||||
bool rps_may_expire_flow(struct net_device *dev, u16 rxq_index, u32 flow_id,
|
bool rps_may_expire_flow(struct net_device *dev, u16 rxq_index, u32 flow_id,
|
||||||
u16 filter_id);
|
u16 filter_id);
|
||||||
#endif
|
#endif
|
||||||
|
#endif /* CONFIG_RPS */
|
||||||
|
|
||||||
/* This structure contains an instance of an RX queue. */
|
/* This structure contains an instance of an RX queue. */
|
||||||
struct netdev_rx_queue {
|
struct netdev_rx_queue {
|
||||||
|
#ifdef CONFIG_RPS
|
||||||
struct rps_map __rcu *rps_map;
|
struct rps_map __rcu *rps_map;
|
||||||
struct rps_dev_flow_table __rcu *rps_flow_table;
|
struct rps_dev_flow_table __rcu *rps_flow_table;
|
||||||
|
#endif
|
||||||
struct kobject kobj;
|
struct kobject kobj;
|
||||||
struct net_device *dev;
|
struct net_device *dev;
|
||||||
} ____cacheline_aligned_in_smp;
|
} ____cacheline_aligned_in_smp;
|
||||||
#endif /* CONFIG_RPS */
|
|
||||||
|
/*
|
||||||
|
* RX queue sysfs structures and functions.
|
||||||
|
*/
|
||||||
|
struct rx_queue_attribute {
|
||||||
|
struct attribute attr;
|
||||||
|
ssize_t (*show)(struct netdev_rx_queue *queue,
|
||||||
|
struct rx_queue_attribute *attr, char *buf);
|
||||||
|
ssize_t (*store)(struct netdev_rx_queue *queue,
|
||||||
|
struct rx_queue_attribute *attr, const char *buf, size_t len);
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_XPS
|
#ifdef CONFIG_XPS
|
||||||
/*
|
/*
|
||||||
@ -1313,7 +1326,7 @@ struct net_device {
|
|||||||
unicast) */
|
unicast) */
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_RPS
|
#ifdef CONFIG_SYSFS
|
||||||
struct netdev_rx_queue *_rx;
|
struct netdev_rx_queue *_rx;
|
||||||
|
|
||||||
/* Number of RX queues allocated at register_netdev() time */
|
/* Number of RX queues allocated at register_netdev() time */
|
||||||
@ -1424,6 +1437,8 @@ struct net_device {
|
|||||||
struct device dev;
|
struct device dev;
|
||||||
/* space for optional device, statistics, and wireless sysfs groups */
|
/* space for optional device, statistics, and wireless sysfs groups */
|
||||||
const struct attribute_group *sysfs_groups[4];
|
const struct attribute_group *sysfs_groups[4];
|
||||||
|
/* space for optional per-rx queue attributes */
|
||||||
|
const struct attribute_group *sysfs_rx_queue_group;
|
||||||
|
|
||||||
/* rtnetlink link ops */
|
/* rtnetlink link ops */
|
||||||
const struct rtnl_link_ops *rtnl_link_ops;
|
const struct rtnl_link_ops *rtnl_link_ops;
|
||||||
@ -2375,7 +2390,7 @@ static inline bool netif_is_multiqueue(const struct net_device *dev)
|
|||||||
|
|
||||||
int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq);
|
int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq);
|
||||||
|
|
||||||
#ifdef CONFIG_RPS
|
#ifdef CONFIG_SYSFS
|
||||||
int netif_set_real_num_rx_queues(struct net_device *dev, unsigned int rxq);
|
int netif_set_real_num_rx_queues(struct net_device *dev, unsigned int rxq);
|
||||||
#else
|
#else
|
||||||
static inline int netif_set_real_num_rx_queues(struct net_device *dev,
|
static inline int netif_set_real_num_rx_queues(struct net_device *dev,
|
||||||
@ -2394,7 +2409,7 @@ static inline int netif_copy_real_num_queues(struct net_device *to_dev,
|
|||||||
from_dev->real_num_tx_queues);
|
from_dev->real_num_tx_queues);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
#ifdef CONFIG_RPS
|
#ifdef CONFIG_SYSFS
|
||||||
return netif_set_real_num_rx_queues(to_dev,
|
return netif_set_real_num_rx_queues(to_dev,
|
||||||
from_dev->real_num_rx_queues);
|
from_dev->real_num_rx_queues);
|
||||||
#else
|
#else
|
||||||
@ -2402,6 +2417,18 @@ static inline int netif_copy_real_num_queues(struct net_device *to_dev,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_SYSFS
|
||||||
|
static inline unsigned int get_netdev_rx_queue_index(
|
||||||
|
struct netdev_rx_queue *queue)
|
||||||
|
{
|
||||||
|
struct net_device *dev = queue->dev;
|
||||||
|
int index = queue - dev->_rx;
|
||||||
|
|
||||||
|
BUG_ON(index >= dev->num_rx_queues);
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#define DEFAULT_MAX_NUM_RSS_QUEUES (8)
|
#define DEFAULT_MAX_NUM_RSS_QUEUES (8)
|
||||||
int netif_get_num_default_rss_queues(void);
|
int netif_get_num_default_rss_queues(void);
|
||||||
|
|
||||||
|
@ -2083,7 +2083,7 @@ int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(netif_set_real_num_tx_queues);
|
EXPORT_SYMBOL(netif_set_real_num_tx_queues);
|
||||||
|
|
||||||
#ifdef CONFIG_RPS
|
#ifdef CONFIG_SYSFS
|
||||||
/**
|
/**
|
||||||
* netif_set_real_num_rx_queues - set actual number of RX queues used
|
* netif_set_real_num_rx_queues - set actual number of RX queues used
|
||||||
* @dev: Network device
|
* @dev: Network device
|
||||||
@ -5764,7 +5764,7 @@ void netif_stacked_transfer_operstate(const struct net_device *rootdev,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(netif_stacked_transfer_operstate);
|
EXPORT_SYMBOL(netif_stacked_transfer_operstate);
|
||||||
|
|
||||||
#ifdef CONFIG_RPS
|
#ifdef CONFIG_SYSFS
|
||||||
static int netif_alloc_rx_queues(struct net_device *dev)
|
static int netif_alloc_rx_queues(struct net_device *dev)
|
||||||
{
|
{
|
||||||
unsigned int i, count = dev->num_rx_queues;
|
unsigned int i, count = dev->num_rx_queues;
|
||||||
@ -6309,7 +6309,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_RPS
|
#ifdef CONFIG_SYSFS
|
||||||
if (rxqs < 1) {
|
if (rxqs < 1) {
|
||||||
pr_err("alloc_netdev: Unable to allocate device with zero RX queues\n");
|
pr_err("alloc_netdev: Unable to allocate device with zero RX queues\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -6365,7 +6365,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
|
|||||||
if (netif_alloc_netdev_queues(dev))
|
if (netif_alloc_netdev_queues(dev))
|
||||||
goto free_all;
|
goto free_all;
|
||||||
|
|
||||||
#ifdef CONFIG_RPS
|
#ifdef CONFIG_SYSFS
|
||||||
dev->num_rx_queues = rxqs;
|
dev->num_rx_queues = rxqs;
|
||||||
dev->real_num_rx_queues = rxqs;
|
dev->real_num_rx_queues = rxqs;
|
||||||
if (netif_alloc_rx_queues(dev))
|
if (netif_alloc_rx_queues(dev))
|
||||||
@ -6385,7 +6385,7 @@ free_all:
|
|||||||
free_pcpu:
|
free_pcpu:
|
||||||
free_percpu(dev->pcpu_refcnt);
|
free_percpu(dev->pcpu_refcnt);
|
||||||
netif_free_tx_queues(dev);
|
netif_free_tx_queues(dev);
|
||||||
#ifdef CONFIG_RPS
|
#ifdef CONFIG_SYSFS
|
||||||
kfree(dev->_rx);
|
kfree(dev->_rx);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -6410,7 +6410,7 @@ void free_netdev(struct net_device *dev)
|
|||||||
release_net(dev_net(dev));
|
release_net(dev_net(dev));
|
||||||
|
|
||||||
netif_free_tx_queues(dev);
|
netif_free_tx_queues(dev);
|
||||||
#ifdef CONFIG_RPS
|
#ifdef CONFIG_SYSFS
|
||||||
kfree(dev->_rx);
|
kfree(dev->_rx);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -498,17 +498,7 @@ static struct attribute_group wireless_group = {
|
|||||||
#define net_class_groups NULL
|
#define net_class_groups NULL
|
||||||
#endif /* CONFIG_SYSFS */
|
#endif /* CONFIG_SYSFS */
|
||||||
|
|
||||||
#ifdef CONFIG_RPS
|
#ifdef CONFIG_SYSFS
|
||||||
/*
|
|
||||||
* RX queue sysfs structures and functions.
|
|
||||||
*/
|
|
||||||
struct rx_queue_attribute {
|
|
||||||
struct attribute attr;
|
|
||||||
ssize_t (*show)(struct netdev_rx_queue *queue,
|
|
||||||
struct rx_queue_attribute *attr, char *buf);
|
|
||||||
ssize_t (*store)(struct netdev_rx_queue *queue,
|
|
||||||
struct rx_queue_attribute *attr, const char *buf, size_t len);
|
|
||||||
};
|
|
||||||
#define to_rx_queue_attr(_attr) container_of(_attr, \
|
#define to_rx_queue_attr(_attr) container_of(_attr, \
|
||||||
struct rx_queue_attribute, attr)
|
struct rx_queue_attribute, attr)
|
||||||
|
|
||||||
@ -543,6 +533,7 @@ static const struct sysfs_ops rx_queue_sysfs_ops = {
|
|||||||
.store = rx_queue_attr_store,
|
.store = rx_queue_attr_store,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_RPS
|
||||||
static ssize_t show_rps_map(struct netdev_rx_queue *queue,
|
static ssize_t show_rps_map(struct netdev_rx_queue *queue,
|
||||||
struct rx_queue_attribute *attribute, char *buf)
|
struct rx_queue_attribute *attribute, char *buf)
|
||||||
{
|
{
|
||||||
@ -718,16 +709,20 @@ static struct rx_queue_attribute rps_cpus_attribute =
|
|||||||
static struct rx_queue_attribute rps_dev_flow_table_cnt_attribute =
|
static struct rx_queue_attribute rps_dev_flow_table_cnt_attribute =
|
||||||
__ATTR(rps_flow_cnt, S_IRUGO | S_IWUSR,
|
__ATTR(rps_flow_cnt, S_IRUGO | S_IWUSR,
|
||||||
show_rps_dev_flow_table_cnt, store_rps_dev_flow_table_cnt);
|
show_rps_dev_flow_table_cnt, store_rps_dev_flow_table_cnt);
|
||||||
|
#endif /* CONFIG_RPS */
|
||||||
|
|
||||||
static struct attribute *rx_queue_default_attrs[] = {
|
static struct attribute *rx_queue_default_attrs[] = {
|
||||||
|
#ifdef CONFIG_RPS
|
||||||
&rps_cpus_attribute.attr,
|
&rps_cpus_attribute.attr,
|
||||||
&rps_dev_flow_table_cnt_attribute.attr,
|
&rps_dev_flow_table_cnt_attribute.attr,
|
||||||
|
#endif
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
static void rx_queue_release(struct kobject *kobj)
|
static void rx_queue_release(struct kobject *kobj)
|
||||||
{
|
{
|
||||||
struct netdev_rx_queue *queue = to_rx_queue(kobj);
|
struct netdev_rx_queue *queue = to_rx_queue(kobj);
|
||||||
|
#ifdef CONFIG_RPS
|
||||||
struct rps_map *map;
|
struct rps_map *map;
|
||||||
struct rps_dev_flow_table *flow_table;
|
struct rps_dev_flow_table *flow_table;
|
||||||
|
|
||||||
@ -743,6 +738,7 @@ static void rx_queue_release(struct kobject *kobj)
|
|||||||
RCU_INIT_POINTER(queue->rps_flow_table, NULL);
|
RCU_INIT_POINTER(queue->rps_flow_table, NULL);
|
||||||
call_rcu(&flow_table->rcu, rps_dev_flow_table_release);
|
call_rcu(&flow_table->rcu, rps_dev_flow_table_release);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
memset(kobj, 0, sizeof(*kobj));
|
memset(kobj, 0, sizeof(*kobj));
|
||||||
dev_put(queue->dev);
|
dev_put(queue->dev);
|
||||||
@ -763,25 +759,36 @@ static int rx_queue_add_kobject(struct net_device *net, int index)
|
|||||||
kobj->kset = net->queues_kset;
|
kobj->kset = net->queues_kset;
|
||||||
error = kobject_init_and_add(kobj, &rx_queue_ktype, NULL,
|
error = kobject_init_and_add(kobj, &rx_queue_ktype, NULL,
|
||||||
"rx-%u", index);
|
"rx-%u", index);
|
||||||
if (error) {
|
if (error)
|
||||||
kobject_put(kobj);
|
goto exit;
|
||||||
return error;
|
|
||||||
|
if (net->sysfs_rx_queue_group) {
|
||||||
|
error = sysfs_create_group(kobj, net->sysfs_rx_queue_group);
|
||||||
|
if (error)
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
kobject_uevent(kobj, KOBJ_ADD);
|
kobject_uevent(kobj, KOBJ_ADD);
|
||||||
dev_hold(queue->dev);
|
dev_hold(queue->dev);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
exit:
|
||||||
|
kobject_put(kobj);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_RPS */
|
#endif /* CONFIG_SYFS */
|
||||||
|
|
||||||
int
|
int
|
||||||
net_rx_queue_update_kobjects(struct net_device *net, int old_num, int new_num)
|
net_rx_queue_update_kobjects(struct net_device *net, int old_num, int new_num)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_RPS
|
#ifdef CONFIG_SYSFS
|
||||||
int i;
|
int i;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
|
||||||
|
#ifndef CONFIG_RPS
|
||||||
|
if (!net->sysfs_rx_queue_group)
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
for (i = old_num; i < new_num; i++) {
|
for (i = old_num; i < new_num; i++) {
|
||||||
error = rx_queue_add_kobject(net, i);
|
error = rx_queue_add_kobject(net, i);
|
||||||
if (error) {
|
if (error) {
|
||||||
@ -790,8 +797,12 @@ net_rx_queue_update_kobjects(struct net_device *net, int old_num, int new_num)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (--i >= new_num)
|
while (--i >= new_num) {
|
||||||
|
if (net->sysfs_rx_queue_group)
|
||||||
|
sysfs_remove_group(&net->_rx[i].kobj,
|
||||||
|
net->sysfs_rx_queue_group);
|
||||||
kobject_put(&net->_rx[i].kobj);
|
kobject_put(&net->_rx[i].kobj);
|
||||||
|
}
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
#else
|
#else
|
||||||
@ -1155,9 +1166,6 @@ static int register_queue_kobjects(struct net_device *net)
|
|||||||
NULL, &net->dev.kobj);
|
NULL, &net->dev.kobj);
|
||||||
if (!net->queues_kset)
|
if (!net->queues_kset)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_RPS
|
|
||||||
real_rx = net->real_num_rx_queues;
|
real_rx = net->real_num_rx_queues;
|
||||||
#endif
|
#endif
|
||||||
real_tx = net->real_num_tx_queues;
|
real_tx = net->real_num_tx_queues;
|
||||||
@ -1184,7 +1192,7 @@ static void remove_queue_kobjects(struct net_device *net)
|
|||||||
{
|
{
|
||||||
int real_rx = 0, real_tx = 0;
|
int real_rx = 0, real_tx = 0;
|
||||||
|
|
||||||
#ifdef CONFIG_RPS
|
#ifdef CONFIG_SYSFS
|
||||||
real_rx = net->real_num_rx_queues;
|
real_rx = net->real_num_rx_queues;
|
||||||
#endif
|
#endif
|
||||||
real_tx = net->real_num_tx_queues;
|
real_tx = net->real_num_tx_queues;
|
||||||
|
Loading…
Reference in New Issue
Block a user