forked from mirrors/linux
		
	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
					
				
					 3 changed files with 66 additions and 31 deletions
				
			
		|  | @ -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 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, | ||||||
| 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 a new issue
	
	 Michael Dalton
						Michael Dalton