diff options
author | Jeff Dike <jdike@addtoit.com> | 2007-02-10 04:43:53 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-11 13:51:21 -0500 |
commit | f28169d2000177e8b72ccc6d72887be779dceca8 (patch) | |
tree | 0ef842014c67d8a136cc26c99113b69e2ede87ea /arch/um/drivers/net_kern.c | |
parent | d79a580936396bbcd2f4fae2c6215f9cf81e3c0d (diff) |
[PATCH] uml: return hotplug errors to host
I noticed that errors happening while hotplugging devices from the host were
never returned back to the mconsole client. In some cases, success was
returned instead of even an information-free error.
This patch cleans that up by having the low-level configuration code pass back
an error string along with an error code. At the top level, which knows
whether it is early boot time or responding to an mconsole request, the string
is printk'd or returned to the mconsole client.
There are also whitespace and trivial code cleanups in the surrounding code.
Signed-off-by: Jeff Dike <jdike@addtoit.com>
Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/um/drivers/net_kern.c')
-rw-r--r-- | arch/um/drivers/net_kern.c | 97 |
1 files changed, 46 insertions, 51 deletions
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index afe3d427ddfa..07e839e387db 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and | 2 | * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and |
3 | * James Leu (jleu@mindspring.net). | 3 | * James Leu (jleu@mindspring.net). |
4 | * Copyright (C) 2001 by various other people who didn't put their name here. | 4 | * Copyright (C) 2001 by various other people who didn't put their name here. |
5 | * Licensed under the GPL. | 5 | * Licensed under the GPL. |
@@ -91,8 +91,8 @@ irqreturn_t uml_net_interrupt(int irq, void *dev_id) | |||
91 | spin_lock(&lp->lock); | 91 | spin_lock(&lp->lock); |
92 | while((err = uml_net_rx(dev)) > 0) ; | 92 | while((err = uml_net_rx(dev)) > 0) ; |
93 | if(err < 0) { | 93 | if(err < 0) { |
94 | printk(KERN_ERR | 94 | printk(KERN_ERR |
95 | "Device '%s' read returned %d, shutting it down\n", | 95 | "Device '%s' read returned %d, shutting it down\n", |
96 | dev->name, err); | 96 | dev->name, err); |
97 | /* dev_close can't be called in interrupt context, and takes | 97 | /* dev_close can't be called in interrupt context, and takes |
98 | * again lp->lock. | 98 | * again lp->lock. |
@@ -159,7 +159,7 @@ out: | |||
159 | static int uml_net_close(struct net_device *dev) | 159 | static int uml_net_close(struct net_device *dev) |
160 | { | 160 | { |
161 | struct uml_net_private *lp = dev->priv; | 161 | struct uml_net_private *lp = dev->priv; |
162 | 162 | ||
163 | netif_stop_queue(dev); | 163 | netif_stop_queue(dev); |
164 | 164 | ||
165 | free_irq(dev->irq, dev); | 165 | free_irq(dev->irq, dev); |
@@ -194,7 +194,7 @@ static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
194 | 194 | ||
195 | /* this is normally done in the interrupt when tx finishes */ | 195 | /* this is normally done in the interrupt when tx finishes */ |
196 | netif_wake_queue(dev); | 196 | netif_wake_queue(dev); |
197 | } | 197 | } |
198 | else if(len == 0){ | 198 | else if(len == 0){ |
199 | netif_start_queue(dev); | 199 | netif_start_queue(dev); |
200 | lp->stats.tx_dropped++; | 200 | lp->stats.tx_dropped++; |
@@ -333,7 +333,7 @@ static int eth_configure(int n, void *init, char *mac, | |||
333 | struct uml_net_private *lp; | 333 | struct uml_net_private *lp; |
334 | int save, err, size; | 334 | int save, err, size; |
335 | 335 | ||
336 | size = transport->private_size + sizeof(struct uml_net_private) + | 336 | size = transport->private_size + sizeof(struct uml_net_private) + |
337 | sizeof(((struct uml_net_private *) 0)->user); | 337 | sizeof(((struct uml_net_private *) 0)->user); |
338 | 338 | ||
339 | device = kzalloc(sizeof(*device), GFP_KERNEL); | 339 | device = kzalloc(sizeof(*device), GFP_KERNEL); |
@@ -438,7 +438,7 @@ static int eth_configure(int n, void *init, char *mac, | |||
438 | lp->tl.function = uml_net_user_timer_expire; | 438 | lp->tl.function = uml_net_user_timer_expire; |
439 | memcpy(lp->mac, device->mac, sizeof(lp->mac)); | 439 | memcpy(lp->mac, device->mac, sizeof(lp->mac)); |
440 | 440 | ||
441 | if (transport->user->init) | 441 | if (transport->user->init) |
442 | (*transport->user->init)(&lp->user, dev); | 442 | (*transport->user->init)(&lp->user, dev); |
443 | 443 | ||
444 | set_ether_mac(dev, device->mac); | 444 | set_ether_mac(dev, device->mac); |
@@ -463,35 +463,33 @@ static struct uml_net *find_device(int n) | |||
463 | return(device); | 463 | return(device); |
464 | } | 464 | } |
465 | 465 | ||
466 | static int eth_parse(char *str, int *index_out, char **str_out) | 466 | static int eth_parse(char *str, int *index_out, char **str_out, |
467 | char **error_out) | ||
467 | { | 468 | { |
468 | char *end; | 469 | char *end; |
469 | int n; | 470 | int n, err = -EINVAL;; |
470 | 471 | ||
471 | n = simple_strtoul(str, &end, 0); | 472 | n = simple_strtoul(str, &end, 0); |
472 | if(end == str){ | 473 | if(end == str){ |
473 | printk(KERN_ERR "eth_setup: Failed to parse '%s'\n", str); | 474 | *error_out = "Bad device number"; |
474 | return(1); | 475 | return err; |
475 | } | ||
476 | if(n < 0){ | ||
477 | printk(KERN_ERR "eth_setup: device %d is negative\n", n); | ||
478 | return(1); | ||
479 | } | 476 | } |
477 | |||
480 | str = end; | 478 | str = end; |
481 | if(*str != '='){ | 479 | if(*str != '='){ |
482 | printk(KERN_ERR | 480 | *error_out = "Expected '=' after device number"; |
483 | "eth_setup: expected '=' after device number\n"); | 481 | return err; |
484 | return(1); | ||
485 | } | 482 | } |
483 | |||
486 | str++; | 484 | str++; |
487 | if(find_device(n)){ | 485 | if(find_device(n)){ |
488 | printk(KERN_ERR "eth_setup: Device %d already configured\n", | 486 | *error_out = "Device already configured"; |
489 | n); | 487 | return err; |
490 | return(1); | ||
491 | } | 488 | } |
492 | if(index_out) *index_out = n; | 489 | |
490 | *index_out = n; | ||
493 | *str_out = str; | 491 | *str_out = str; |
494 | return(0); | 492 | return 0; |
495 | } | 493 | } |
496 | 494 | ||
497 | struct eth_init { | 495 | struct eth_init { |
@@ -581,11 +579,15 @@ static int eth_setup_common(char *str, int index) | |||
581 | static int eth_setup(char *str) | 579 | static int eth_setup(char *str) |
582 | { | 580 | { |
583 | struct eth_init *new; | 581 | struct eth_init *new; |
582 | char *error; | ||
584 | int n, err; | 583 | int n, err; |
585 | 584 | ||
586 | err = eth_parse(str, &n, &str); | 585 | err = eth_parse(str, &n, &str, &error); |
587 | if(err) | 586 | if(err){ |
587 | printk(KERN_ERR "eth_setup - Couldn't parse '%s' : %s\n", | ||
588 | str, error); | ||
588 | return 1; | 589 | return 1; |
590 | } | ||
589 | 591 | ||
590 | new = alloc_bootmem(sizeof(*new)); | 592 | new = alloc_bootmem(sizeof(*new)); |
591 | if (new == NULL){ | 593 | if (new == NULL){ |
@@ -619,26 +621,30 @@ static int eth_init(void) | |||
619 | if(eth_setup_common(eth->init, eth->index)) | 621 | if(eth_setup_common(eth->init, eth->index)) |
620 | list_del(ð->list); | 622 | list_del(ð->list); |
621 | } | 623 | } |
622 | 624 | ||
623 | return(1); | 625 | return(1); |
624 | } | 626 | } |
625 | __initcall(eth_init); | 627 | __initcall(eth_init); |
626 | #endif | 628 | #endif |
627 | 629 | ||
628 | static int net_config(char *str) | 630 | static int net_config(char *str, char **error_out) |
629 | { | 631 | { |
630 | int n, err; | 632 | int n, err; |
631 | 633 | ||
632 | err = eth_parse(str, &n, &str); | 634 | err = eth_parse(str, &n, &str, error_out); |
633 | if(err) return(err); | 635 | if(err) |
636 | return err; | ||
634 | 637 | ||
638 | /* This string is broken up and the pieces used by the underlying | ||
639 | * driver. So, it is freed only if eth_setup_common fails. | ||
640 | */ | ||
635 | str = kstrdup(str, GFP_KERNEL); | 641 | str = kstrdup(str, GFP_KERNEL); |
636 | if(str == NULL){ | 642 | if(str == NULL){ |
637 | printk(KERN_ERR "net_config failed to strdup string\n"); | 643 | *error_out = "net_config failed to strdup string"; |
638 | return(-1); | 644 | return -ENOMEM; |
639 | } | 645 | } |
640 | err = !eth_setup_common(str, n); | 646 | err = !eth_setup_common(str, n); |
641 | if(err) | 647 | if(err) |
642 | kfree(str); | 648 | kfree(str); |
643 | return(err); | 649 | return(err); |
644 | } | 650 | } |
@@ -658,7 +664,7 @@ static int net_id(char **str, int *start_out, int *end_out) | |||
658 | return n; | 664 | return n; |
659 | } | 665 | } |
660 | 666 | ||
661 | static int net_remove(int n) | 667 | static int net_remove(int n, char **error_out) |
662 | { | 668 | { |
663 | struct uml_net *device; | 669 | struct uml_net *device; |
664 | struct net_device *dev; | 670 | struct net_device *dev; |
@@ -727,7 +733,7 @@ struct notifier_block uml_inetaddr_notifier = { | |||
727 | static int uml_net_init(void) | 733 | static int uml_net_init(void) |
728 | { | 734 | { |
729 | struct list_head *ele; | 735 | struct list_head *ele; |
730 | struct uml_net_private *lp; | 736 | struct uml_net_private *lp; |
731 | struct in_device *ip; | 737 | struct in_device *ip; |
732 | struct in_ifaddr *in; | 738 | struct in_ifaddr *in; |
733 | 739 | ||
@@ -747,7 +753,7 @@ static int uml_net_init(void) | |||
747 | uml_inetaddr_event(NULL, NETDEV_UP, in); | 753 | uml_inetaddr_event(NULL, NETDEV_UP, in); |
748 | in = in->ifa_next; | 754 | in = in->ifa_next; |
749 | } | 755 | } |
750 | } | 756 | } |
751 | 757 | ||
752 | return(0); | 758 | return(0); |
753 | } | 759 | } |
@@ -783,8 +789,8 @@ struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra) | |||
783 | return(skb); | 789 | return(skb); |
784 | } | 790 | } |
785 | 791 | ||
786 | void iter_addresses(void *d, void (*cb)(unsigned char *, unsigned char *, | 792 | void iter_addresses(void *d, void (*cb)(unsigned char *, unsigned char *, |
787 | void *), | 793 | void *), |
788 | void *arg) | 794 | void *arg) |
789 | { | 795 | { |
790 | struct net_device *dev = d; | 796 | struct net_device *dev = d; |
@@ -809,11 +815,11 @@ int dev_netmask(void *d, void *m) | |||
809 | struct in_ifaddr *in; | 815 | struct in_ifaddr *in; |
810 | __be32 *mask_out = m; | 816 | __be32 *mask_out = m; |
811 | 817 | ||
812 | if(ip == NULL) | 818 | if(ip == NULL) |
813 | return(1); | 819 | return(1); |
814 | 820 | ||
815 | in = ip->ifa_list; | 821 | in = ip->ifa_list; |
816 | if(in == NULL) | 822 | if(in == NULL) |
817 | return(1); | 823 | return(1); |
818 | 824 | ||
819 | *mask_out = in->ifa_mask; | 825 | *mask_out = in->ifa_mask; |
@@ -835,7 +841,7 @@ void free_output_buffer(void *buffer) | |||
835 | free_pages((unsigned long) buffer, 0); | 841 | free_pages((unsigned long) buffer, 0); |
836 | } | 842 | } |
837 | 843 | ||
838 | int tap_setup_common(char *str, char *type, char **dev_name, char **mac_out, | 844 | int tap_setup_common(char *str, char *type, char **dev_name, char **mac_out, |
839 | char **gate_addr) | 845 | char **gate_addr) |
840 | { | 846 | { |
841 | char *remain; | 847 | char *remain; |
@@ -854,14 +860,3 @@ unsigned short eth_protocol(struct sk_buff *skb) | |||
854 | { | 860 | { |
855 | return(eth_type_trans(skb, skb->dev)); | 861 | return(eth_type_trans(skb, skb->dev)); |
856 | } | 862 | } |
857 | |||
858 | /* | ||
859 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
860 | * Emacs will notice this stuff at the end of the file and automatically | ||
861 | * adjust the settings for this buffer only. This must remain at the end | ||
862 | * of the file. | ||
863 | * --------------------------------------------------------------------------- | ||
864 | * Local variables: | ||
865 | * c-file-style: "linux" | ||
866 | * End: | ||
867 | */ | ||