netpoll cleanups
Subsystems (3)
cover netpoll cleanups
These patches simplify netpoll by better locking,
reorganizing code etc.
Signature · 1 line
Stephen Hemminger <[email protected]>
PATCH 1/11 netpoll: use skb_queue_purge
Use standard route for flushing queue.
net/core/netpoll.c +1 -5
@@ -816,11 +812,7 @@ void netpoll_cleanup(struct netpoll *np)cancel_rearming_delayed_work (&npinfo->tx_work);/* clean after last, unfinished work */ -if (!skb_queue_empty (&npinfo->txq)) { -struct sk_buff *skb; - skb =__skb_dequeue (&npinfo->txq); -kfree_skb (skb); - } +__skb_queue_purge (&npinfo->txq);kfree (npinfo); np->dev->npinfo =NULL ; }
Signature · 1 line
Stephen Hemminger <[email protected]>
Re: [PATCH 01/11] netpoll: use skb_queue_purge
From: Stephen Hemminger <[email protected]>
Date: Sat, 03 Nov 2007 11:43:15 -0700
Quoted 3 lines
Use standard route for flushing queue.
Signed-off-by Stephen Hemminger <[email protected]>
Applied to net-2.6.25, thanks!
PATCH 2/11 netpoll: netpoll_poll cleanup
In reply to Stephen HemmingerRestructure code slightly to improve readability:
* dereference device once
* change obvious while() loop
* let poll_napi() handle null list itself
net/core/netpoll.c +15 -19
@@ -139,16 +139,15 @@ static int poll_one_napi(struct netpoll_return budget - work; } -static void poll_napi (struct netpoll *np) +static void poll_napi (struct net_device *dev) { -struct netpoll_info *npinfo = np->dev->npinfo; -struct napi_struct *napi;int budget =16 ; +struct napi_struct *napi; -list_for_each_entry (napi, &np->dev->napi_list, dev_list) { +list_for_each_entry (napi, &dev->napi_list, dev_list) {if (napi->poll_owner !=smp_processor_id () &&spin_trylock (&napi->poll_lock)) { - budget =poll_one_napi (npinfo, napi, budget); + budget =poll_one_napi (dev->npinfo, napi, budget);spin_unlock (&napi->poll_lock);if (!budget)
@@ -159,30 +158,27 @@ static void poll_napi(struct netpoll *npstatic void service_arp_queue (struct netpoll_info *npi) { -struct sk_buff *skb; +if (npi) { +struct sk_buff *skb; -if (unlikely (!npi)) -return ; - - skb =skb_dequeue (&npi->arp_tx); - -while (skb !=NULL ) { -arp_reply (skb); - skb =skb_dequeue (&npi->arp_tx); +while ( (skb =skb_dequeue (&npi->arp_tx)) ) +arp_reply (skb); } }void netpoll_poll (struct netpoll *np) { -if (!np->dev || !netif_running (np->dev) || !np->dev->poll_controller) +struct net_device *dev = np->dev; + +if (!dev || !netif_running (dev) || !dev->poll_controller)return ;/* Process pending work on NIC */ - np->dev->poll_controller (np->dev); -if (!list_empty (&np->dev->napi_list)) -poll_napi (np); + dev->poll_controller (dev); + +poll_napi (dev); -service_arp_queue (np->dev->npinfo); +service_arp_queue (dev->npinfo);zap_completion_queue (); }
Signature · 1 line
Stephen Hemminger <[email protected]>
Re: [PATCH 02/11] netpoll: netpoll_poll cleanup
From: Stephen Hemminger <[email protected]>
Date: Sat, 03 Nov 2007 11:43:16 -0700
Quoted 6 lines
Restructure code slightly to improve readability:
* dereference device once
* change obviouswhile()loop
* letpoll_napi()handle null list itselfSigned-off-by Stephen Hemminger <[email protected]>
Applied to net-2.6.25, but I made some coding style fixups, one of which is a huge pet peeve of mine.
When declaring local variables for a function I always list the longest lines down gradually to the shortest lines. It is nicer to the eye and naturally it means that all the complicated structure assignments and dereferences sit at the top and the simpler iterators and counters like 'i' end up at the bottom making local variable lists that much easier to read and search when learning how a function works.
You explicitly changed this one I had set up:
net/core/netpoll.c static int poll_one_napi(struct netpoll_ · line 145
Quoted 5 lines
{
net/core/netpoll.c +1
-2-struct netpoll_info *npinfo = np->dev->npinfo; -struct napi_struct *napi;int budget =16 ; +struct napi_struct *napi;
And I thus reverted it back to the correct order:
struct napi_struct *napi; int budget = 16;
I also got rid of the mid-parens spaces in:
net/core/netpoll.c static void poll_napi(struct netpoll *np · line 164
Quoted 1 line
net/core/netpoll.c +1
-0+while ( (skb =skb_dequeue (&npi->arp_tx)) )
Thanks.
PATCH 3/11 netpoll: no need to store local_mac
In reply to Stephen HemmingerThe local_mac is managed by the network device, no need to keep a spare copy and all the management problems that could cause.
include/linux/netpoll.h +1 -1
@@ -20,7 +20,7 @@ struct netpoll {u32 local_ip, remote_ip;u16 local_port, remote_port; -u8 local_mac[ETH_ALEN ], remote_mac[ETH_ALEN ]; +u8 remote_mac[ETH_ALEN ]; };struct netpoll_info {
net/core/netpoll.c +3 -6
@@ -360,8 +360,8 @@ void netpoll_send_udp(struct netpoll *np eth = (struct ethhdr *)skb_push (skb,ETH_HLEN );skb_reset_mac_header (skb); skb->protocol = eth->h_proto =htons (ETH_P_IP ); -memcpy (eth->h_source, np->local_mac,6 ); -memcpy (eth->h_dest, np->remote_mac,6 ); +memcpy (eth->h_source, np->dev->dev_addr,ETH_ALEN ); +memcpy (eth->h_dest, np->remote_mac,ETH_ALEN ); skb->dev = np->dev;
@@ -431,7 +431,7 @@ static void arp_reply(struct sk_buff *sk/* Fill the device header for the ARP frame */ if (dev_hard_header (send_skb, skb->dev, ptype, - sha, np->local_mac, + sha, np->dev->dev_addr, send_skb->len) <0 ) {kfree_skb (send_skb);return ;
@@ -737,9 +737,6 @@ int netpoll_setup(struct netpoll *np) } } -if (is_zero_ether_addr (np->local_mac) && ndev->dev_addr) -memcpy (np->local_mac, ndev->dev_addr,6 ); -if (!np->local_ip) {rcu_read_lock (); in_dev =__in_dev_get_rcu (ndev);
drivers/net/netconsole.c +4 -6
@@ -306,9 +306,11 @@ static ssize_t show_remote_ip(struct netstatic ssize_t show_local_mac (struct netconsole_target *nt,char *buf) { +struct net_device *dev = nt->np.dev; +DECLARE_MAC_BUF (mac);return snprintf (buf,PAGE_SIZE ,"%s\n" , -print_mac (mac, nt->np.local_mac)); +print_mac (mac, dev->dev_addr)); }static ssize_t show_remote_mac (struct netconsole_target *nt,char *buf)
@@ -667,7 +669,7 @@ static int netconsole_netdev_event(strucstruct netconsole_target *nt;struct net_device *dev = ptr; -if (!(event ==NETDEV_CHANGEADDR || event ==NETDEV_CHANGENAME )) +if (!(event ==NETDEV_CHANGENAME )) goto done;spin_lock_irqsave (&target_list_lock, flags);
@@ -675,10 +677,6 @@ static int netconsole_netdev_event(strucnetconsole_target_get (nt);if (nt->np.dev == dev) {switch (event) { -case NETDEV_CHANGEADDR : -memcpy (nt->np.local_mac, dev->dev_addr,ETH_ALEN ); -break ; -case NETDEV_CHANGENAME :strlcpy (nt->np.dev_name, dev->name,IFNAMSIZ );break ;
Signature · 1 line
Stephen Hemminger <[email protected]>
Re: [PATCH 03/11] netpoll: no need to store local_mac
From: Stephen Hemminger <[email protected]>
Date: Sat, 03 Nov 2007 11:43:17 -0700
Quoted 5 lines
The
local_macis managed by the network device, no need to keep a spare copy and all the management problems that could cause.Signed-off-by Stephen Hemminger <[email protected]>
Applied to net-2.6.25, thanks!
PATCH 4/11 netpoll: alternative implementation of dropping
In reply to Stephen Hemmingernet/core/netpoll.c +4 -4
@@ -40,7 +40,6 @@ static atomic_t trapped;#define USEC_PER_POLL 50#define NETPOLL_RX_ENABLED 1 -#define NETPOLL_RX_DROP 2#define MAX_SKB_SIZE \ (MAX_UDP_CHUNK + sizeof(struct udphdr) + \
@@ -128,13 +127,11 @@ static int poll_one_napi(struct netpoll_if (!test_bit (NAPI_STATE_SCHED , &napi->state))return budget; - npinfo->rx_flags |=NETPOLL_RX_DROP ;atomic_inc (&trapped); work = napi->poll (napi, budget);atomic_dec (&trapped); - npinfo->rx_flags &= ~NETPOLL_RX_DROP ;return budget - work; }
@@ -475,7 +472,7 @@ int __netpoll_rx(struct sk_buff *skb)if (skb->dev->type !=ARPHRD_ETHER ) goto out; -/* check if netpoll clients need ARP */ +/* if receive ARP during middle of NAPI poll, then queue */ if (skb->protocol ==htons (ETH_P_ARP ) &&atomic_read (&trapped)) {skb_queue_tail (&npi->arp_tx, skb);
@@ -537,6 +534,9 @@ int __netpoll_rx(struct sk_buff *skb)return 1 ; out: +/* If packet received while already in poll then just +* silently drop. +*/ if (atomic_read (&trapped)) {kfree_skb (skb);return 1 ;
Signature · 1 line
Stephen Hemminger <[email protected]>
Re: [PATCH 04/11] netpoll: alternative implementation of dropping
From: Stephen Hemminger <[email protected]>
Date: Sat, 03 Nov 2007 11:43:18 -0700
Quoted 1 line
Signed-off-by Stephen Hemminger <[email protected]>
Applied to net-2.6.25, but I gave the changelog a more descriptive headline:
[NETPOLL]: Kill NETPOLL_RX_DROP, set but never tested.
Thanks.
PATCH 5/11 netpoll: dont need rx_flags
In reply to Stephen HemmingerThe rx_flags variable is redundant. Turning rx on/off is done via setting the rx_np pointer.
include/linux/netpoll.h +2 -4
@@ -25,7 +25,6 @@ struct netpoll {struct netpoll_info {atomic_t refcnt; -int rx_flags;spinlock_t rx_lock;struct netpoll *rx_np;/* netpoll that registered an rx_hook */ struct sk_buff_head arp_tx;/* list of arp requests to reply to */
@@ -51,12 +50,11 @@ static inline int netpoll_rx(struct sk_bunsigned long flags;int ret =0 ; -if (!npinfo || (!npinfo->rx_np && !npinfo->rx_flags)) +if (!npinfo || !npinfo->rx_np)return 0 ;spin_lock_irqsave (&npinfo->rx_lock, flags); -/* check rx_flags again with the lock held */ -if (npinfo->rx_flags &&__netpoll_rx (skb)) +if (__netpoll_rx (skb)) ret =1 ;spin_unlock_irqrestore (&npinfo->rx_lock, flags);
net/core/netpoll.c +0 -4
@@ -39,7 +39,6 @@ static struct sk_buff_head skb_pool;static atomic_t trapped;#define USEC_PER_POLL 50 -#define NETPOLL_RX_ENABLED 1#define MAX_SKB_SIZE \ (MAX_UDP_CHUNK + sizeof(struct udphdr) + \
@@ -675,7 +674,6 @@ int netpoll_setup(struct netpoll *np) goto release; } - npinfo->rx_flags =0 ; npinfo->rx_np =NULL ;spin_lock_init (&npinfo->rx_lock);
@@ -757,7 +755,6 @@ int netpoll_setup(struct netpoll *np)if (np->rx_hook) {spin_lock_irqsave (&npinfo->rx_lock, flags); - npinfo->rx_flags |=NETPOLL_RX_ENABLED ; npinfo->rx_np = np;spin_unlock_irqrestore (&npinfo->rx_lock, flags); }
@@ -799,7 +796,6 @@ void netpoll_cleanup(struct netpoll *np)if (npinfo->rx_np == np) {spin_lock_irqsave (&npinfo->rx_lock, flags); npinfo->rx_np =NULL ; - npinfo->rx_flags &= ~NETPOLL_RX_ENABLED ;spin_unlock_irqrestore (&npinfo->rx_lock, flags); }
Signature · 1 line
Stephen Hemminger <[email protected]>
David Miller
maintainerRe: [PATCH 05/11] netpoll: dont need rx_flags
From: Stephen Hemminger <[email protected]>
Date: Sat, 03 Nov 2007 11:43:19 -0700
Quoted 4 lines
The
rx_flagsvariable is redundant. Turning rx on/off is done via setting therx_nppointer.Signed-off-by Stephen Hemminger <[email protected]>
Not all of these transformations are equivalent, and as a result you're adding a bug.
Quoted 4 lines
include/linux/netpoll.h +0
-0@@ -51,12 +50,11 @@ static inline int netpoll_rx(struct sk_bunsigned long flags;int ret =0 ;
include/linux/netpoll.h static inline int netpoll_rx(struct sk_b · line 59
Quoted 10 lines
include/linux/netpoll.h +2
-3-if (!npinfo || (!npinfo->rx_np && !npinfo->rx_flags)) +if (!npinfo || !npinfo->rx_np)return 0 ;spin_lock_irqsave (&npinfo->rx_lock, flags); -/* check rx_flags again with the lock held */ -if (npinfo->rx_flags &&__netpoll_rx (skb)) +if (__netpoll_rx (skb)) ret =1 ;spin_unlock_irqrestore (&npinfo->rx_lock, flags);
If you're using ->rx_np == NULL as your new guard, you have to duplicate that test inside of holding the lock.
->rx_np goes to NULL under the lock, but in the previous code if the rx_flags is set we know that ->rx_np is also NULL, that's why it was OK to only recheck ->rx_flags in the lock and not ->rx_np as well.
Therefore we have to replace the test on ->rx_flags with ->rx_np in all spots to retain correct semantics.
I've made this correction to your patch and applied it to net-2.6.25
Thanks.
PATCH 6/11 netpoll: remove dev_name for npinfo
In reply to Stephen HemmingerThe device name was only in npinfo for netconsole target configuration, so move it to netconsole. Netconsole only needs the value during config, so no need to do all the device name tracking etc..
Make functions for common code for instantiation and start up.
drivers/net/netconsole.c +55 -82
@@ -96,6 +96,7 @@ struct netconsole_target {struct config_item item;#endif int enabled; +char dev_name[IFNAMSIZ ];struct netpoll np; };
@@ -157,39 +158,67 @@ static void netconsole_target_put(struct#endif /* CONFIG_NETCONSOLE_DYNAMIC */ + + +/* +* Allocate and initialize with defaults. +* Note that these targets get their config_item fields zeroed-out. +*/ +static struct netconsole_target *new_target (void ) +{ +struct netconsole_target *nt; + + nt =kzalloc (sizeof (*nt),GFP_KERNEL ); +if (nt) { + nt->np.name ="netconsole" ; +strlcpy (nt->dev_name,"eth0" ,IFNAMSIZ ); + nt->np.local_port =6665 ; + nt->np.remote_port =6666 ; +memset (nt->np.remote_mac,0xff ,ETH_ALEN ); + } + +return nt; +} + +static int start_target (struct netconsole_target *nt) +{ +struct net_device *dev; +int err; + + dev =dev_get_by_name (&init_net, nt->dev_name); +if (!dev) +return -ENODEV ; + + err =netpoll_setup (&nt->np, dev); +if (err) +dev_put (dev); +else + nt->enabled =1 ; +return err; +} + +/* Allocate new target (from boot/module param) and setup netpoll for it */ static struct netconsole_target *alloc_param_target (char *target_config) {int err = -ENOMEM ;struct netconsole_target *nt; -/* -* Allocate and initialize with defaults. -* Note that these targets get their config_item fields zeroed-out. -*/ - nt =kzalloc (sizeof (*nt),GFP_KERNEL ); + nt =new_target ();if (!nt) {printk (KERN_ERR "netconsole: failed to allocate memory\n" ); goto fail; } - nt->np.name ="netconsole" ; -strlcpy (nt->np.dev_name,"eth0" ,IFNAMSIZ ); - nt->np.local_port =6665 ; - nt->np.remote_port =6666 ; -memset (nt->np.remote_mac,0xff ,ETH_ALEN ); -/* Parse parameters and setup netpoll */ - err =netpoll_parse_options (&nt->np, target_config); + err =netpoll_parse_options (&nt->np, target_config, nt->dev_name);if (err) goto fail; - err =netpoll_setup (&nt->np); + + err =start_target (nt);if (err) goto fail; - - nt->enabled =1 ; -return nt; fail:
@@ -279,7 +308,8 @@ static ssize_t show_enabled(struct netcostatic ssize_t show_dev_name (struct netconsole_target *nt,char *buf) { -return snprintf (buf,PAGE_SIZE ,"%s\n" , nt->np.dev_name); +return snprintf (buf,PAGE_SIZE ,"%s\n" , + nt->enabled ? nt->np.dev->name : nt->dev_name); }static ssize_t show_local_port (struct netconsole_target *nt,char *buf)
@@ -339,14 +369,13 @@ static ssize_t store_enabled(struct netcreturn enabled;if (enabled) {/* 1 */ -/* * Skip netpoll_parse_options() -- all the attributes are * already configured via configfs. Just print them out. */ netpoll_print_options (&nt->np); - err =netpoll_setup (&nt->np); + err =start_target (nt);if (err)return err;
@@ -365,7 +394,7 @@ static ssize_t store_dev_name(struct netconst char *buf, size_t count) { - size_t len; + char *cp;if (nt->enabled) { printk(KERN_ERR "netconsole: target (%s) is enabled, "
@@ -374,12 +403,12 @@ static ssize_t store_dev_name(struct netreturn -EINVAL ; } -strlcpy (nt->np.dev_name, buf,IFNAMSIZ ); +strlcpy (nt->dev_name, buf,IFNAMSIZ );/* Get rid of possible trailing newline from echo(1) */ - len =strnlen (nt->np.dev_name,IFNAMSIZ ); -if (nt->np.dev_name[len -1 ] =='\n' ) - nt->np.dev_name[len -1 ] ='\0' ; + cp =strnchr (nt->dev_name,'\n' ,IFNAMSIZ ); +if (cp) + *cp ='\0' ;return strnlen (buf, count); }
@@ -591,21 +620,7 @@ static struct config_item *make_netconsounsigned long flags;struct netconsole_target *nt; -/* -* Allocate and initialize with defaults. -* Target is disabled at creation (enabled == 0). -*/ - nt =kzalloc (sizeof (*nt),GFP_KERNEL ); -if (!nt) { -printk (KERN_ERR "netconsole: failed to allocate memory\n" ); -return NULL ; - } - - nt->np.name ="netconsole" ; -strlcpy (nt->np.dev_name,"eth0" ,IFNAMSIZ ); - nt->np.local_port =6665 ; - nt->np.remote_port =6666 ; -memset (nt->np.remote_mac,0xff ,ETH_ALEN ); + nt =new_target ();/* Initialize the config_item member */ config_item_init_type_name (&nt->item, name, &netconsole_target_type);
@@ -660,40 +675,6 @@ static struct configfs_subsystem netcons#endif /* CONFIG_NETCONSOLE_DYNAMIC */ -/* Handle network interface device notifications */ -static int netconsole_netdev_event (struct notifier_block *this, -unsigned long event, -void *ptr) -{ -unsigned long flags; -struct netconsole_target *nt; -struct net_device *dev = ptr; - -if (!(event ==NETDEV_CHANGENAME )) - goto done; - -spin_lock_irqsave (&target_list_lock, flags); -list_for_each_entry (nt, &target_list, list) { -netconsole_target_get (nt); -if (nt->np.dev == dev) { -switch (event) { -case NETDEV_CHANGENAME : -strlcpy (nt->np.dev_name, dev->name,IFNAMSIZ ); -break ; - } - } -netconsole_target_put (nt); - } -spin_unlock_irqrestore (&target_list_lock, flags); - -done: -return NOTIFY_DONE ; -} - -static struct notifier_block netconsole_netdev_notifier = { - .notifier_call = netconsole_netdev_event, -}; -static void write_msg (struct console *con,const char *msg,unsigned int len) {int frag, left;
@@ -755,22 +736,15 @@ static int __init init_netconsole(void) } } - err =register_netdevice_notifier (&netconsole_netdev_notifier); -if (err) - goto fail; - err =dynamic_netconsole_init ();if (err) - goto undonotifier; + goto fail;register_console (&netconsole);printk (KERN_INFO "netconsole: network logging started\n" );return err; -undonotifier: -unregister_netdevice_notifier (&netconsole_netdev_notifier); - fail:printk (KERN_ERR "netconsole: cleaning up\n" );
@@ -793,7 +767,6 @@ static void __exit cleanup_netconsole(vounregister_console (&netconsole);dynamic_netconsole_exit (); -unregister_netdevice_notifier (&netconsole_netdev_notifier);/* * Targets created via configfs pin references on our module
include/linux/netpoll.h +2 -3
@@ -14,7 +14,6 @@struct netpoll {struct net_device *dev; -char dev_name[IFNAMSIZ ];const char *name;void (*rx_hook)(struct netpoll *,int ,char *,int );
@@ -35,8 +34,8 @@ struct netpoll_info {void netpoll_poll (struct netpoll *np);void netpoll_send_udp (struct netpoll *np,const char *msg,int len);void netpoll_print_options (struct netpoll *np); -int netpoll_parse_options (struct netpoll *np,char *opt); -int netpoll_setup (struct netpoll *np); +int netpoll_parse_options (struct netpoll *np,char *opt,char *name); +int netpoll_setup (struct netpoll *np,struct net_device *dev);int netpoll_trap (void );void netpoll_set_trap (int trap);void netpoll_cleanup (struct netpoll *np);
net/core/netpoll.c +7 -17
@@ -552,7 +552,7 @@ void netpoll_print_options(struct netpolprintk (KERN_INFO "%s: local IP %d.%d.%d.%d\n" , np->name,HIPQUAD (np->local_ip));printk (KERN_INFO "%s: interface %s\n" , - np->name, np->dev_name); + np->name, np->dev->name);printk (KERN_INFO "%s: remote port %d\n" , np->name, np->remote_port); printk(KERN_INFO "%s: remote IP %d.%d.%d.%d\n",
@@ -561,7 +561,7 @@ void netpoll_print_options(struct netpol np->name, print_mac(mac, np->remote_mac)); } -int netpoll_parse_options (struct netpoll *np,char *opt) +int netpoll_parse_options (struct netpoll *np,char *opt,char *dev_name) {char *cur=opt, *delim;
@@ -588,7 +588,7 @@ int netpoll_parse_options(struct netpollif ((delim =strchr (cur,',' )) ==NULL ) goto parse_failed; *delim =0 ; -strlcpy (np->dev_name, cur,sizeof (np->dev_name)); +strlcpy (dev_name, cur,IFNAMSIZ ); cur = delim; } cur++;
@@ -650,22 +650,13 @@ int netpoll_parse_options(struct netpollreturn -1 ; } -int netpoll_setup (struct netpoll *np) +int netpoll_setup (struct netpoll *np,struct net_device *ndev) { -struct net_device *ndev =NULL ;struct in_device *in_dev;struct netpoll_info *npinfo;unsigned long flags;int err; -if (np->dev_name) - ndev =dev_get_by_name (&init_net, np->dev_name); -if (!ndev) { -printk (KERN_ERR "%s: %s doesn't exist, aborting.\n" , - np->name, np->dev_name); -return -ENODEV ; - } - np->dev = ndev;if (!ndev->npinfo) { npinfo =kmalloc (sizeof (*npinfo),GFP_KERNEL );
@@ -689,7 +680,7 @@ int netpoll_setup(struct netpoll *np)if (!ndev->poll_controller) {printk (KERN_ERR "%s: %s doesn't support polling, aborting.\n" , - np->name, np->dev_name); + np->name, ndev->name); err = -ENOTSUPP ; goto release; }
@@ -698,7 +689,7 @@ int netpoll_setup(struct netpoll *np)unsigned long atmost, atleast;printk (KERN_INFO "%s: device %s not up yet, forcing it\n" , - np->name, np->dev_name); + np->name, ndev->name);rtnl_lock (); err =dev_open (ndev);
@@ -742,7 +733,7 @@ int netpoll_setup(struct netpoll *np)if (!in_dev || !in_dev->ifa_list) {rcu_read_unlock ();printk (KERN_ERR "%s: no IP address for %s, aborting\n" , - np->name, np->dev_name); + np->name, ndev->name); err = -EDESTADDRREQ ; goto release; }
@@ -774,7 +765,6 @@ int netpoll_setup(struct netpoll *np)if (!ndev->npinfo)kfree (npinfo); np->dev =NULL ; -dev_put (ndev);return err; }
Signature · 1 line
Stephen Hemminger <[email protected]>
David Miller
maintainerRe: [PATCH 06/11] netpoll: remove dev_name for npinfo
From: Stephen Hemminger <[email protected]>
Date: Sat, 03 Nov 2007 11:43:20 -0700
Quoted 9 lines
The device name was only in npinfo for netconsole target configuration, so move it to netconsole. Netconsole only needs the value during config, so no need to do all the device name tracking etc..
Make functions for common code for instantiation and start up.
Signed-off-by Stephen Hemminger <[email protected]>
Sigh...
return -EUNTESTED;
In netpoll_parse_options() np->dev isn't setup yet, so if you had tested this patch you would have gotten an immediate OOPS.
That's why it needs the npinfo->dev_name in the first place, because it has to be parsed in order to even know what device to attach to. The np->dev usually isn't setup until netpoll_setup() is called.
I appreciate all the work you are doing trying to clean up this beast but you have to start testing this stuff and audit the transformations you are making, instead of always relying on me or someone else to do it for you.
That's why I let these particular patches sit in my inbox for two weeks, I knew half of them would have bugs and most if not all of them were totally untested, so I dreaded reviewing them.
I might have to toss some of the rest of these netconsole things if there are dependencies on this bogus change.
Re: [PATCH 06/11] netpoll: remove dev_name for npinfo
Quoted 11 lines · On Mon, 19 Nov 2007 19:47:50 -0800 (PST) David Miller <[email protected]>…
From: Stephen Hemminger <[email protected]>
Date: Sat, 03 Nov 2007 11:43:20 -0700Quoted 8 lines
The device name was only in npinfo for netconsole target configuration, so move it to netconsole. Netconsole only needs the value during config, so no need to do all the device name tracking etc..
Make functions for common code for instantiation and start up.
Quoted 8 lines
Quoted 1 line
Signed-off-by Stephen Hemminger <[email protected]>Sigh...
return -EUNTESTED;In
netpoll_parse_options()np->devisn't setup yet, so if you had tested this patch you would have gotten an immediate OOPS.
Sorry, I missed the boot up case, I was testing with modprobe and dyanmic reconfig stuff. Places that store the name (and then get confused by renames) are one of the lingering mis-features of the whole network device infrastructure.
Signature · 1 line
Stephen Hemminger <[email protected]>
PATCH 7/11 netpoll: get rid of name parameter
In reply to Stephen HemmingerThe name was being stored and used only for error messages. The same effect can be had by just passing it in where needed during config.
drivers/net/netconsole.c +11 -10
@@ -170,7 +170,6 @@ static struct netconsole_target *new_tar nt =kzalloc (sizeof (*nt),GFP_KERNEL );if (nt) { - nt->np.name ="netconsole" ;strlcpy (nt->dev_name,"eth0" ,IFNAMSIZ ); nt->np.local_port =6665 ; nt->np.remote_port =6666 ;
@@ -186,8 +185,13 @@ static int start_target(struct netconsolint err; dev =dev_get_by_name (&init_net, nt->dev_name); -if (!dev) +if (!dev) { +printk (KERN_ERR "netconsole: device '%s' does not exist.\n" , + nt->dev_name);return -ENODEV ; + } + +netpoll_print_options ("netconsole" , &nt->np); err =netpoll_setup (&nt->np, dev);if (err)
@@ -212,13 +216,16 @@ static struct netconsole_target *alloc_p/* Parse parameters and setup netpoll */ err =netpoll_parse_options (&nt->np, target_config, nt->dev_name); -if (err) +if (err) { +printk (KERN_ERR "netconsole: parse options '%s' failed %d\n" , + target_config, err); goto fail; - + } err =start_target (nt);if (err) goto fail; +return nt; fail:
@@ -369,12 +376,6 @@ static ssize_t store_enabled(struct netcreturn enabled;if (enabled) {/* 1 */ -/* -* Skip netpoll_parse_options() -- all the attributes are -* already configured via configfs. Just print them out. -*/ -netpoll_print_options (&nt->np); - err =start_target (nt);if (err)return err;
include/linux/netpoll.h +1 -2
@@ -14,7 +14,6 @@struct netpoll {struct net_device *dev; -const char *name;void (*rx_hook)(struct netpoll *,int ,char *,int );u32 local_ip, remote_ip;
@@ -33,7 +32,7 @@ struct netpoll_info {void netpoll_poll (struct netpoll *np);void netpoll_send_udp (struct netpoll *np,const char *msg,int len); -void netpoll_print_options (struct netpoll *np); +void netpoll_print_options (const char *prefix,struct netpoll *np);int netpoll_parse_options (struct netpoll *np,char *opt,char *name);int netpoll_setup (struct netpoll *np,struct net_device *dev);int netpoll_trap (void );
net/core/netpoll.c +23 -27
115 lines not on this page · raw message
Signature · 1 line
Stephen Hemminger <[email protected]>
David Miller
maintainerRe: [PATCH 07/11] netpoll: get rid of name parameter
From: Stephen Hemminger <[email protected]>
Date: Sat, 03 Nov 2007 11:43:21 -0700
Quoted 5 lines
The name was being stored and used only for error messages. The same effect can be had by just passing it in where needed during config.
Signed-off-by Stephen Hemminger <[email protected]>
The whole world of netpoll is not netconsole even though it just happens to be that way currently. Otherwise we can just eliminate the modularity completely and merge all of netconsole into net/core/netpoll.c but of course we won't do that.
If another user of netpoll comes by we'll just have to add this thing back again.
I'm dropping this patch.
PATCH 8/11 netpoll: NETPOLL_TRAP configuration change
In reply to Stephen HemmingerNETPOLL_TRAP is actually not used by any in-tree code. Rather than exposing it in kernel configuration, make it a selectable option and make sure API is stubbed properly. I.e: if not configured then netpoll_set_trap is not available.
---
P.s: netpoll stuff should really be EXPORT_SYMBOL_GPL??
include/linux/netdevice.h +7 -6
@@ -837,8 +837,14 @@ extern int call_netdevice_notifiers(unsiextern struct net_device *dev_get_by_index (struct net *net,int ifindex);extern struct net_device *__dev_get_by_index (struct net *net,int ifindex);extern int dev_restart (struct net_device *dev); +#ifdef CONFIG_NETPOLL_TRAP extern int netpoll_trap (void ); +extern void netpoll_set_trap (int trap); +#else +static inline int netpoll_trap (void ) { +return 0 ; +}#endif static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev,
@@ -918,12 +924,11 @@ static inline void netif_start_queue(str*/ static inline void netif_wake_queue (struct net_device *dev) { -#ifdef CONFIG_NETPOLL_TRAP if (netpoll_trap ()) {clear_bit (__LINK_STATE_XOFF, &dev->state);return ; } -#endif +if (test_and_clear_bit (__LINK_STATE_XOFF, &dev->state))__netif_schedule (dev); }
@@ -993,10 +998,8 @@ static inline void netif_start_subqueue(static inline void netif_stop_subqueue (struct net_device *dev,u16 queue_index) {#ifdef CONFIG_NETDEVICES_MULTIQUEUE -#ifdef CONFIG_NETPOLL_TRAP if (netpoll_trap ())return ; -#endif set_bit (__LINK_STATE_XOFF, &dev->egress_subqueue[queue_index].state);#endif }
@@ -1035,10 +1038,8 @@ static inline int netif_subqueue_stoppedstatic inline void netif_wake_subqueue (struct net_device *dev,u16 queue_index) {#ifdef CONFIG_NETDEVICES_MULTIQUEUE -#ifdef CONFIG_NETPOLL_TRAP if (netpoll_trap ())return ; -#endif if (test_and_clear_bit (__LINK_STATE_XOFF, &dev->egress_subqueue[queue_index].state))__netif_schedule (dev);
drivers/net/Kconfig +1 -1
@@ -3118,8 +3118,8 @@ config NETCONSOLE_DYNAMIC config NETPOLL def_bool NETCONSOLE +# If needed use select to enable config NETPOLL_TRAP - bool "Netpoll traffic trapping" default n depends on NETPOLL
net/core/netpoll.c +3 -0
@@ -803,6 +803,7 @@ void netpoll_cleanup(struct netpoll *np) np->dev =NULL ; } +#ifdef CONFIG_NETPOLL_TRAP int netpoll_trap (void ) {return atomic_read (&trapped);
@@ -818,6 +819,8 @@ void netpoll_set_trap(int trap)EXPORT_SYMBOL (netpoll_set_trap);EXPORT_SYMBOL (netpoll_trap); +#endif +EXPORT_SYMBOL (netpoll_print_options);EXPORT_SYMBOL (netpoll_parse_options);EXPORT_SYMBOL (netpoll_setup);
Signature · 1 line
Stephen Hemminger <[email protected]>
David Miller
maintainerRe: [PATCH 08/11] netpoll: NETPOLL_TRAP configuration change
From: Stephen Hemminger <[email protected]>
Date: Sat, 03 Nov 2007 11:43:22 -0700
drivers/net/Kconfig config NETCONSOLE_DYNAMIC · line 3124
Quoted 11 lines
drivers/net/Kconfig +1
-1@@ -3118,8 +3118,8 @@ config NETCONSOLE_DYNAMIC config NETPOLL def_bool NETCONSOLE +# If needed use select to enable config NETPOLL_TRAP - bool "Netpoll traffic trapping" default n depends on NETPOLL
I'm not applying this.
This change means that allmodconfig doesn't pick up this symbol anymore and therefore it's way to difficult to make sure these code segments still get build tested.
PATCH 9/11 netpoll: ethernet devices only
In reply to Stephen HemmingerNetpoll only works on Ethernet devices, so check during setup rather than just failing silently later.
net/core/netpoll.c +6 -0
@@ -653,6 +653,12 @@ int netpoll_setup(struct netpoll *np, stunsigned long flags;int err; +if (ndev->type !=ARPHRD_ETHER ) { +printk (KERN_ERR "netpoll: %s is not an ethernet device\n" , + ndev->name); +return -EINVAL ; + } + np->dev = ndev;if (!ndev->npinfo) { npinfo =kmalloc (sizeof (*npinfo),GFP_KERNEL );
Signature · 1 line
Stephen Hemminger <[email protected]>
David Miller
maintainerRe: [PATCH 09/11] netpoll: ethernet devices only
From: Stephen Hemminger <[email protected]>
Date: Sat, 03 Nov 2007 11:43:23 -0700
Quoted 8 lines
Netpoll only works on Ethernet devices, so check during setup rather than just failing silently later.
Signed-off-by Stephen Hemminger <[email protected]>
net/core/netpoll.c int netpoll_setup(struct netpoll *np, st · line 662
Quoted 10 lines
net/core/netpoll.c +6
-0@@ -653,6 +653,12 @@ int netpoll_setup(struct netpoll *np, stunsigned long flags;int err; +if (ndev->type !=ARPHRD_ETHER ) { +printk (KERN_ERR "netpoll: %s is not an ethernet device\n" , + ndev->name); +return -EINVAL ; + } + np->dev = ndev;
This patch depends upon the broken np->dev_name one, and I also would rather fix the limitations in netpoll.
Re: [PATCH 09/11] netpoll: ethernet devices only
Quoted 14 lines · On Mon, 19 Nov 2007 19:55:15 -0800 (PST) David Miller <[email protected]>…
From: Stephen Hemminger <[email protected]>
Date: Sat, 03 Nov 2007 11:43:23 -0700Quoted 11 lines
Netpoll only works on Ethernet devices, so check during setup rather than just failing silently later.
Signed-off-by Stephen Hemminger <[email protected]>net/core/netpoll.c +0
-0@@ -653,6 +653,12 @@ int netpoll_setup(struct netpoll *np, stunsigned long flags;int err;
Quoted 10 lines
net/core/netpoll.c int netpoll_setup(struct netpoll *np, st · line 662
Quoted 7 lines
net/core/netpoll.c +6
-0+if (ndev->type !=ARPHRD_ETHER ) { +printk (KERN_ERR "netpoll: %s is not an ethernet device\n" , + ndev->name); +return -EINVAL ; + } + np->dev = ndev;This patch depends upon the broken
np->dev_nameone, and I also would rather fix the limitations in netpoll.
Existing netpoll depends on Ethernet and IPV4. Doing the right thing might be hard because it would mean going through more inside irq.
Probably the right thing to do would be to build a header through the normal path and cache it some how.
Signature · 1 line
Stephen Hemminger <[email protected]>
PATCH 10/11 netpoll: rx optimization
In reply to Stephen HemmingerThis patch makes netpoll work for non-NAPI devices that call netif_receive_skb. Devices are allowed to call netif_receive_skb if they are receiving packets in softirq (ie in tasklet). One side effect of this is that received packets will be looked at twice for the non-NAPI case, but this is harmless.
Move the locking out of the inline hook and into the internal function.
include/linux/netpoll.h +11 -22
@@ -30,6 +30,9 @@ struct netpoll_info {struct delayed_work tx_work; }; + +#ifdef CONFIG_NETPOLL +void netpoll_poll (struct netpoll *np);void netpoll_send_udp (struct netpoll *np,const char *msg,int len);void netpoll_print_options (const char *prefix,struct netpoll *np);
@@ -38,32 +41,18 @@ int netpoll_setup(struct netpoll *np, stint netpoll_trap (void );void netpoll_set_trap (int trap);void netpoll_cleanup (struct netpoll *np); -int __netpoll_rx (struct sk_buff *skb); +bool __netpoll_rx (struct sk_buff *skb); -#ifdef CONFIG_NETPOLL -static inline int netpoll_rx (struct sk_buff *skb) +/* Hijack incoming packet for use by netpoll. +* NB: may be called twice for NAPI case +*/ +static inline bool netpoll_rx (struct sk_buff *skb) { -struct netpoll_info *npinfo = skb->dev->npinfo; -unsigned long flags; -int ret =0 ; - -if (!npinfo || !npinfo->rx_np) -return 0 ; - -spin_lock_irqsave (&npinfo->rx_lock, flags); -if (__netpoll_rx (skb)) - ret =1 ; -spin_unlock_irqrestore (&npinfo->rx_lock, flags); +if (unlikely (skb->dev->npinfo)) +return __netpoll_rx (skb); -return ret; -} - -static inline int netpoll_receive_skb (struct sk_buff *skb) -{ -if (!list_empty (&skb->dev->napi_list)) -return netpoll_rx (skb); -return 0 ; +return false; }static inline void *netpoll_poll_lock (struct napi_struct *napi)
net/core/dev.c +1 -2
@@ -2020,8 +2020,7 @@ int netif_receive_skb(struct sk_buff *skint ret =NET_RX_DROP ;__be16 type; -/* if we've gotten here through NAPI, check netpoll */ -if (netpoll_receive_skb (skb)) +if (netpoll_rx (skb))return NET_RX_DROP ;if (!skb->tstamp.tv64)
net/core/netpoll.c +14 -5
@@ -458,16 +458,23 @@ static void arp_reply(struct sk_buff *sknetpoll_send_skb (np, send_skb); } -int __netpoll_rx (struct sk_buff *skb) +bool __netpoll_rx (struct sk_buff *skb) {int proto, len, ulen;struct iphdr *iph;struct udphdr *uh;struct netpoll_info *npi = skb->dev->npinfo; -struct netpoll *np = npi->rx_np; +struct netpoll *np; +unsigned long flags; + +if (!npi) +return false; +spin_lock_irqsave (&npi->rx_lock, flags); + np = npi->rx_np;if (!np) goto out; +if (skb->dev->type !=ARPHRD_ETHER ) goto out;
@@ -528,20 +535,22 @@ int __netpoll_rx(struct sk_buff *skb) np->rx_hook (np,ntohs (uh->source), (char *)(uh+1 ), ulen -sizeof (struct udphdr )); +spin_unlock_irqrestore (&npi->rx_lock, flags);kfree_skb (skb); -return 1 ; +return true; out: +spin_unlock_irqrestore (&npi->rx_lock, flags);/* If packet received while already in poll then just * silently drop. */ if (atomic_read (&trapped)) {kfree_skb (skb); -return 1 ; +return true; } -return 0 ; +return false; }void netpoll_print_options (const char *name,struct netpoll *np)
Signature · 1 line
Stephen Hemminger <[email protected]>
David Miller
maintainerRe: [PATCH 10/11] netpoll: rx optimization
From: Stephen Hemminger <[email protected]>
Date: Sat, 03 Nov 2007 11:43:24 -0700
Quoted 10 lines
This patch makes netpoll work for non-NAPI devices that call
netif_receive_skb. Devices are allowed to callnetif_receive_skbif they are receiving packets in softirq (ie in tasklet). One side effect of this is that received packets will be looked at twice for the non-NAPI case, but this is harmless.Move the locking out of the inline hook and into the internal function.
Signed-off-by Stephen Hemminger <[email protected]>
This one looks OK but it no longer applied, please respin.
Thanks.
PATCH 11/11 netpoll: rx use RCU
In reply to Stephen HemmingerGet rid of rx_lock and use Read-Copy-Update to make sure that netpoll info and rx handle are not used after free.
include/linux/netpoll.h +0 -1
@@ -23,7 +23,6 @@ struct netpoll {struct netpoll_info {atomic_t refcnt; -spinlock_t rx_lock;struct netpoll *rx_np;/* netpoll that registered an rx_hook */ struct sk_buff_head arp_tx;/* list of arp requests to reply to */ struct sk_buff_head txq;
net/core/netpoll.c +15 -19
@@ -463,15 +463,15 @@ bool __netpoll_rx(struct sk_buff *skb)int proto, len, ulen;struct iphdr *iph;struct udphdr *uh; -struct netpoll_info *npi = skb->dev->npinfo; +struct netpoll_info *npi;struct netpoll *np; -unsigned long flags; +rcu_read_lock (); + npi =rcu_dereference (skb->dev->npinfo);if (!npi) -return false; + goto out; -spin_lock_irqsave (&npi->rx_lock, flags); - np = npi->rx_np; + np =rcu_dereference (npi->rx_np);if (!np) goto out;
@@ -535,13 +535,13 @@ bool __netpoll_rx(struct sk_buff *skb) np->rx_hook (np,ntohs (uh->source), (char *)(uh+1 ), ulen -sizeof (struct udphdr )); -spin_unlock_irqrestore (&npi->rx_lock, flags); +rcu_read_unlock ();kfree_skb (skb);return true; out: -spin_unlock_irqrestore (&npi->rx_lock, flags); +rcu_read_unlock ();/* If packet received while already in poll then just * silently drop. */
@@ -678,7 +678,6 @@ int netpoll_setup(struct netpoll *np, st npinfo->rx_np =NULL ; -spin_lock_init (&npinfo->rx_lock);skb_queue_head_init (&npinfo->arp_tx);skb_queue_head_init (&npinfo->txq);INIT_DELAYED_WORK (&npinfo->tx_work, queue_process);
@@ -755,11 +754,8 @@ int netpoll_setup(struct netpoll *np, st HIPQUAD(np->local_ip)); } -if (np->rx_hook) { -spin_lock_irqsave (&npinfo->rx_lock, flags); - npinfo->rx_np = np; -spin_unlock_irqrestore (&npinfo->rx_lock, flags); - } +if (np->rx_hook) +rcu_assign_pointer (npinfo->rx_np, np);/* fill up the skb queue */ refill_skbs ();
@@ -794,21 +790,21 @@ void netpoll_cleanup(struct netpoll *np)if (np->dev) { npinfo = np->dev->npinfo;if (npinfo) { -if (npinfo->rx_np == np) { -spin_lock_irqsave (&npinfo->rx_lock, flags); - npinfo->rx_np =NULL ; -spin_unlock_irqrestore (&npinfo->rx_lock, flags); - } +if (npinfo->rx_np == np) +rcu_assign_pointer (npinfo->rx_np,NULL );if (atomic_dec_and_test (&npinfo->refcnt)) { +skb_queue_purge (&npinfo->arp_tx);skb_queue_purge (&npinfo->txq);cancel_rearming_delayed_work (&npinfo->tx_work);/* clean after last, unfinished work */ __skb_queue_purge (&npinfo->txq); + +rcu_assign_pointer (np->dev->npinfo,NULL ); +synchronize_net ();kfree (npinfo); - np->dev->npinfo =NULL ; } }
Signature · 1 line
Stephen Hemminger <[email protected]>
David Miller
maintainerRe: [PATCH 11/11] netpoll: rx use RCU
From: Stephen Hemminger <[email protected]>
Date: Sat, 03 Nov 2007 11:43:25 -0700
Quoted 4 lines
Get rid of
rx_lockand use Read-Copy-Update to make sure that netpoll info and rx handle are not used after free.Signed-off-by Stephen Hemminger <[email protected]>
Please also respin this one too, thanks.