diff options
Diffstat (limited to 'arch/um')
57 files changed, 1055 insertions, 1046 deletions
diff --git a/arch/um/Kconfig b/arch/um/Kconfig index d32a80e6668c..b3a21ba77cd2 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig | |||
@@ -16,6 +16,9 @@ config MMU | |||
16 | bool | 16 | bool |
17 | default y | 17 | default y |
18 | 18 | ||
19 | config NO_IOMEM | ||
20 | def_bool y | ||
21 | |||
19 | mainmenu "Linux/Usermode Kernel Configuration" | 22 | mainmenu "Linux/Usermode Kernel Configuration" |
20 | 23 | ||
21 | config ISA | 24 | config ISA |
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c index 7d4190e55654..7b8baf146acc 100644 --- a/arch/um/drivers/chan_kern.c +++ b/arch/um/drivers/chan_kern.c | |||
@@ -19,44 +19,11 @@ | |||
19 | #include "line.h" | 19 | #include "line.h" |
20 | #include "os.h" | 20 | #include "os.h" |
21 | 21 | ||
22 | /* XXX: could well be moved to somewhere else, if needed. */ | ||
23 | static int my_printf(const char * fmt, ...) | ||
24 | __attribute__ ((format (printf, 1, 2))); | ||
25 | |||
26 | static int my_printf(const char * fmt, ...) | ||
27 | { | ||
28 | /* Yes, can be called on atomic context.*/ | ||
29 | char *buf = kmalloc(4096, GFP_ATOMIC); | ||
30 | va_list args; | ||
31 | int r; | ||
32 | |||
33 | if (!buf) { | ||
34 | /* We print directly fmt. | ||
35 | * Yes, yes, yes, feel free to complain. */ | ||
36 | r = strlen(fmt); | ||
37 | } else { | ||
38 | va_start(args, fmt); | ||
39 | r = vsprintf(buf, fmt, args); | ||
40 | va_end(args); | ||
41 | fmt = buf; | ||
42 | } | ||
43 | |||
44 | if (r) | ||
45 | r = os_write_file(1, fmt, r); | ||
46 | return r; | ||
47 | |||
48 | } | ||
49 | |||
50 | #ifdef CONFIG_NOCONFIG_CHAN | 22 | #ifdef CONFIG_NOCONFIG_CHAN |
51 | /* Despite its name, there's no added trailing newline. */ | 23 | static void *not_configged_init(char *str, int device, |
52 | static int my_puts(const char * buf) | 24 | const struct chan_opts *opts) |
53 | { | ||
54 | return os_write_file(1, buf, strlen(buf)); | ||
55 | } | ||
56 | |||
57 | static void *not_configged_init(char *str, int device, struct chan_opts *opts) | ||
58 | { | 25 | { |
59 | my_puts("Using a channel type which is configured out of " | 26 | printk("Using a channel type which is configured out of " |
60 | "UML\n"); | 27 | "UML\n"); |
61 | return NULL; | 28 | return NULL; |
62 | } | 29 | } |
@@ -64,34 +31,34 @@ static void *not_configged_init(char *str, int device, struct chan_opts *opts) | |||
64 | static int not_configged_open(int input, int output, int primary, void *data, | 31 | static int not_configged_open(int input, int output, int primary, void *data, |
65 | char **dev_out) | 32 | char **dev_out) |
66 | { | 33 | { |
67 | my_puts("Using a channel type which is configured out of " | 34 | printk("Using a channel type which is configured out of " |
68 | "UML\n"); | 35 | "UML\n"); |
69 | return -ENODEV; | 36 | return -ENODEV; |
70 | } | 37 | } |
71 | 38 | ||
72 | static void not_configged_close(int fd, void *data) | 39 | static void not_configged_close(int fd, void *data) |
73 | { | 40 | { |
74 | my_puts("Using a channel type which is configured out of " | 41 | printk("Using a channel type which is configured out of " |
75 | "UML\n"); | 42 | "UML\n"); |
76 | } | 43 | } |
77 | 44 | ||
78 | static int not_configged_read(int fd, char *c_out, void *data) | 45 | static int not_configged_read(int fd, char *c_out, void *data) |
79 | { | 46 | { |
80 | my_puts("Using a channel type which is configured out of " | 47 | printk("Using a channel type which is configured out of " |
81 | "UML\n"); | 48 | "UML\n"); |
82 | return -EIO; | 49 | return -EIO; |
83 | } | 50 | } |
84 | 51 | ||
85 | static int not_configged_write(int fd, const char *buf, int len, void *data) | 52 | static int not_configged_write(int fd, const char *buf, int len, void *data) |
86 | { | 53 | { |
87 | my_puts("Using a channel type which is configured out of " | 54 | printk("Using a channel type which is configured out of " |
88 | "UML\n"); | 55 | "UML\n"); |
89 | return -EIO; | 56 | return -EIO; |
90 | } | 57 | } |
91 | 58 | ||
92 | static int not_configged_console_write(int fd, const char *buf, int len) | 59 | static int not_configged_console_write(int fd, const char *buf, int len) |
93 | { | 60 | { |
94 | my_puts("Using a channel type which is configured out of " | 61 | printk("Using a channel type which is configured out of " |
95 | "UML\n"); | 62 | "UML\n"); |
96 | return -EIO; | 63 | return -EIO; |
97 | } | 64 | } |
@@ -99,14 +66,14 @@ static int not_configged_console_write(int fd, const char *buf, int len) | |||
99 | static int not_configged_window_size(int fd, void *data, unsigned short *rows, | 66 | static int not_configged_window_size(int fd, void *data, unsigned short *rows, |
100 | unsigned short *cols) | 67 | unsigned short *cols) |
101 | { | 68 | { |
102 | my_puts("Using a channel type which is configured out of " | 69 | printk("Using a channel type which is configured out of " |
103 | "UML\n"); | 70 | "UML\n"); |
104 | return -ENODEV; | 71 | return -ENODEV; |
105 | } | 72 | } |
106 | 73 | ||
107 | static void not_configged_free(void *data) | 74 | static void not_configged_free(void *data) |
108 | { | 75 | { |
109 | my_puts("Using a channel type which is configured out of " | 76 | printk("Using a channel type which is configured out of " |
110 | "UML\n"); | 77 | "UML\n"); |
111 | } | 78 | } |
112 | 79 | ||
@@ -255,15 +222,28 @@ void enable_chan(struct line *line) | |||
255 | } | 222 | } |
256 | } | 223 | } |
257 | 224 | ||
225 | /* Items are added in IRQ context, when free_irq can't be called, and | ||
226 | * removed in process context, when it can. | ||
227 | * This handles interrupt sources which disappear, and which need to | ||
228 | * be permanently disabled. This is discovered in IRQ context, but | ||
229 | * the freeing of the IRQ must be done later. | ||
230 | */ | ||
231 | static DEFINE_SPINLOCK(irqs_to_free_lock); | ||
258 | static LIST_HEAD(irqs_to_free); | 232 | static LIST_HEAD(irqs_to_free); |
259 | 233 | ||
260 | void free_irqs(void) | 234 | void free_irqs(void) |
261 | { | 235 | { |
262 | struct chan *chan; | 236 | struct chan *chan; |
237 | LIST_HEAD(list); | ||
238 | struct list_head *ele; | ||
263 | 239 | ||
264 | while(!list_empty(&irqs_to_free)){ | 240 | spin_lock_irq(&irqs_to_free_lock); |
265 | chan = list_entry(irqs_to_free.next, struct chan, free_list); | 241 | list_splice_init(&irqs_to_free, &list); |
266 | list_del(&chan->free_list); | 242 | INIT_LIST_HEAD(&irqs_to_free); |
243 | spin_unlock_irq(&irqs_to_free_lock); | ||
244 | |||
245 | list_for_each(ele, &list){ | ||
246 | chan = list_entry(ele, struct chan, free_list); | ||
267 | 247 | ||
268 | if(chan->input) | 248 | if(chan->input) |
269 | free_irq(chan->line->driver->read_irq, chan); | 249 | free_irq(chan->line->driver->read_irq, chan); |
@@ -279,7 +259,9 @@ static void close_one_chan(struct chan *chan, int delay_free_irq) | |||
279 | return; | 259 | return; |
280 | 260 | ||
281 | if(delay_free_irq){ | 261 | if(delay_free_irq){ |
262 | spin_lock_irq(&irqs_to_free_lock); | ||
282 | list_add(&chan->free_list, &irqs_to_free); | 263 | list_add(&chan->free_list, &irqs_to_free); |
264 | spin_unlock_irq(&irqs_to_free_lock); | ||
283 | } | 265 | } |
284 | else { | 266 | else { |
285 | if(chan->input) | 267 | if(chan->input) |
@@ -372,8 +354,7 @@ int console_write_chan(struct list_head *chans, const char *buf, int len) | |||
372 | return ret; | 354 | return ret; |
373 | } | 355 | } |
374 | 356 | ||
375 | int console_open_chan(struct line *line, struct console *co, | 357 | int console_open_chan(struct line *line, struct console *co) |
376 | const struct chan_opts *opts) | ||
377 | { | 358 | { |
378 | int err; | 359 | int err; |
379 | 360 | ||
@@ -381,7 +362,7 @@ int console_open_chan(struct line *line, struct console *co, | |||
381 | if(err) | 362 | if(err) |
382 | return err; | 363 | return err; |
383 | 364 | ||
384 | printk("Console initialized on /dev/%s%d\n",co->name,co->index); | 365 | printk("Console initialized on /dev/%s%d\n", co->name, co->index); |
385 | return 0; | 366 | return 0; |
386 | } | 367 | } |
387 | 368 | ||
@@ -534,7 +515,7 @@ static const struct chan_type chan_table[] = { | |||
534 | }; | 515 | }; |
535 | 516 | ||
536 | static struct chan *parse_chan(struct line *line, char *str, int device, | 517 | static struct chan *parse_chan(struct line *line, char *str, int device, |
537 | const struct chan_opts *opts) | 518 | const struct chan_opts *opts, char **error_out) |
538 | { | 519 | { |
539 | const struct chan_type *entry; | 520 | const struct chan_type *entry; |
540 | const struct chan_ops *ops; | 521 | const struct chan_ops *ops; |
@@ -553,19 +534,21 @@ static struct chan *parse_chan(struct line *line, char *str, int device, | |||
553 | } | 534 | } |
554 | } | 535 | } |
555 | if(ops == NULL){ | 536 | if(ops == NULL){ |
556 | my_printf("parse_chan couldn't parse \"%s\"\n", | 537 | *error_out = "No match for configured backends"; |
557 | str); | ||
558 | return NULL; | 538 | return NULL; |
559 | } | 539 | } |
560 | if(ops->init == NULL) | 540 | |
561 | return NULL; | ||
562 | data = (*ops->init)(str, device, opts); | 541 | data = (*ops->init)(str, device, opts); |
563 | if(data == NULL) | 542 | if(data == NULL){ |
543 | *error_out = "Configuration failed"; | ||
564 | return NULL; | 544 | return NULL; |
545 | } | ||
565 | 546 | ||
566 | chan = kmalloc(sizeof(*chan), GFP_ATOMIC); | 547 | chan = kmalloc(sizeof(*chan), GFP_ATOMIC); |
567 | if(chan == NULL) | 548 | if(chan == NULL){ |
549 | *error_out = "Memory allocation failed"; | ||
568 | return NULL; | 550 | return NULL; |
551 | } | ||
569 | *chan = ((struct chan) { .list = LIST_HEAD_INIT(chan->list), | 552 | *chan = ((struct chan) { .list = LIST_HEAD_INIT(chan->list), |
570 | .free_list = | 553 | .free_list = |
571 | LIST_HEAD_INIT(chan->free_list), | 554 | LIST_HEAD_INIT(chan->free_list), |
@@ -582,7 +565,7 @@ static struct chan *parse_chan(struct line *line, char *str, int device, | |||
582 | } | 565 | } |
583 | 566 | ||
584 | int parse_chan_pair(char *str, struct line *line, int device, | 567 | int parse_chan_pair(char *str, struct line *line, int device, |
585 | const struct chan_opts *opts) | 568 | const struct chan_opts *opts, char **error_out) |
586 | { | 569 | { |
587 | struct list_head *chans = &line->chan_list; | 570 | struct list_head *chans = &line->chan_list; |
588 | struct chan *new, *chan; | 571 | struct chan *new, *chan; |
@@ -599,14 +582,14 @@ int parse_chan_pair(char *str, struct line *line, int device, | |||
599 | in = str; | 582 | in = str; |
600 | *out = '\0'; | 583 | *out = '\0'; |
601 | out++; | 584 | out++; |
602 | new = parse_chan(line, in, device, opts); | 585 | new = parse_chan(line, in, device, opts, error_out); |
603 | if(new == NULL) | 586 | if(new == NULL) |
604 | return -1; | 587 | return -1; |
605 | 588 | ||
606 | new->input = 1; | 589 | new->input = 1; |
607 | list_add(&new->list, chans); | 590 | list_add(&new->list, chans); |
608 | 591 | ||
609 | new = parse_chan(line, out, device, opts); | 592 | new = parse_chan(line, out, device, opts, error_out); |
610 | if(new == NULL) | 593 | if(new == NULL) |
611 | return -1; | 594 | return -1; |
612 | 595 | ||
@@ -614,7 +597,7 @@ int parse_chan_pair(char *str, struct line *line, int device, | |||
614 | new->output = 1; | 597 | new->output = 1; |
615 | } | 598 | } |
616 | else { | 599 | else { |
617 | new = parse_chan(line, str, device, opts); | 600 | new = parse_chan(line, str, device, opts, error_out); |
618 | if(new == NULL) | 601 | if(new == NULL) |
619 | return -1; | 602 | return -1; |
620 | 603 | ||
diff --git a/arch/um/drivers/harddog_kern.c b/arch/um/drivers/harddog_kern.c index 64ff22aa077b..55601687b3bc 100644 --- a/arch/um/drivers/harddog_kern.c +++ b/arch/um/drivers/harddog_kern.c | |||
@@ -9,10 +9,10 @@ | |||
9 | * modify it under the terms of the GNU General Public License | 9 | * modify it under the terms of the GNU General Public License |
10 | * as published by the Free Software Foundation; either version | 10 | * as published by the Free Software Foundation; either version |
11 | * 2 of the License, or (at your option) any later version. | 11 | * 2 of the License, or (at your option) any later version. |
12 | * | 12 | * |
13 | * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide | 13 | * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide |
14 | * warranty for any of this software. This material is provided | 14 | * warranty for any of this software. This material is provided |
15 | * "AS-IS" and at no charge. | 15 | * "AS-IS" and at no charge. |
16 | * | 16 | * |
17 | * (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk> | 17 | * (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk> |
18 | * | 18 | * |
@@ -29,11 +29,11 @@ | |||
29 | * Made SMP safe for 2.3.x | 29 | * Made SMP safe for 2.3.x |
30 | * | 30 | * |
31 | * 20011127 Joel Becker (jlbec@evilplan.org> | 31 | * 20011127 Joel Becker (jlbec@evilplan.org> |
32 | * Added soft_noboot; Allows testing the softdog trigger without | 32 | * Added soft_noboot; Allows testing the softdog trigger without |
33 | * requiring a recompile. | 33 | * requiring a recompile. |
34 | * Added WDIOC_GETTIMEOUT and WDIOC_SETTIMOUT. | 34 | * Added WDIOC_GETTIMEOUT and WDIOC_SETTIMOUT. |
35 | */ | 35 | */ |
36 | 36 | ||
37 | #include <linux/module.h> | 37 | #include <linux/module.h> |
38 | #include <linux/types.h> | 38 | #include <linux/types.h> |
39 | #include <linux/kernel.h> | 39 | #include <linux/kernel.h> |
@@ -44,12 +44,13 @@ | |||
44 | #include <linux/reboot.h> | 44 | #include <linux/reboot.h> |
45 | #include <linux/smp_lock.h> | 45 | #include <linux/smp_lock.h> |
46 | #include <linux/init.h> | 46 | #include <linux/init.h> |
47 | #include <linux/spinlock.h> | ||
47 | #include <asm/uaccess.h> | 48 | #include <asm/uaccess.h> |
48 | #include "mconsole.h" | 49 | #include "mconsole.h" |
49 | 50 | ||
50 | MODULE_LICENSE("GPL"); | 51 | MODULE_LICENSE("GPL"); |
51 | 52 | ||
52 | /* Locked by the BKL in harddog_open and harddog_release */ | 53 | static DEFINE_SPINLOCK(lock); |
53 | static int timer_alive; | 54 | static int timer_alive; |
54 | static int harddog_in_fd = -1; | 55 | static int harddog_in_fd = -1; |
55 | static int harddog_out_fd = -1; | 56 | static int harddog_out_fd = -1; |
@@ -57,18 +58,18 @@ static int harddog_out_fd = -1; | |||
57 | /* | 58 | /* |
58 | * Allow only one person to hold it open | 59 | * Allow only one person to hold it open |
59 | */ | 60 | */ |
60 | 61 | ||
61 | extern int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock); | 62 | extern int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock); |
62 | 63 | ||
63 | static int harddog_open(struct inode *inode, struct file *file) | 64 | static int harddog_open(struct inode *inode, struct file *file) |
64 | { | 65 | { |
65 | int err; | 66 | int err = -EBUSY; |
66 | char *sock = NULL; | 67 | char *sock = NULL; |
67 | 68 | ||
68 | lock_kernel(); | 69 | spin_lock(&lock); |
69 | if(timer_alive) | 70 | if(timer_alive) |
70 | return -EBUSY; | 71 | goto err; |
71 | #ifdef CONFIG_HARDDOG_NOWAYOUT | 72 | #ifdef CONFIG_HARDDOG_NOWAYOUT |
72 | __module_get(THIS_MODULE); | 73 | __module_get(THIS_MODULE); |
73 | #endif | 74 | #endif |
74 | 75 | ||
@@ -76,11 +77,15 @@ static int harddog_open(struct inode *inode, struct file *file) | |||
76 | sock = mconsole_notify_socket(); | 77 | sock = mconsole_notify_socket(); |
77 | #endif | 78 | #endif |
78 | err = start_watchdog(&harddog_in_fd, &harddog_out_fd, sock); | 79 | err = start_watchdog(&harddog_in_fd, &harddog_out_fd, sock); |
79 | if(err) return(err); | 80 | if(err) |
81 | goto err; | ||
80 | 82 | ||
81 | timer_alive = 1; | 83 | timer_alive = 1; |
82 | unlock_kernel(); | 84 | spin_unlock(&lock); |
83 | return nonseekable_open(inode, file); | 85 | return nonseekable_open(inode, file); |
86 | err: | ||
87 | spin_unlock(&lock); | ||
88 | return err; | ||
84 | } | 89 | } |
85 | 90 | ||
86 | extern void stop_watchdog(int in_fd, int out_fd); | 91 | extern void stop_watchdog(int in_fd, int out_fd); |
@@ -90,14 +95,16 @@ static int harddog_release(struct inode *inode, struct file *file) | |||
90 | /* | 95 | /* |
91 | * Shut off the timer. | 96 | * Shut off the timer. |
92 | */ | 97 | */ |
93 | lock_kernel(); | 98 | |
99 | spin_lock(&lock); | ||
94 | 100 | ||
95 | stop_watchdog(harddog_in_fd, harddog_out_fd); | 101 | stop_watchdog(harddog_in_fd, harddog_out_fd); |
96 | harddog_in_fd = -1; | 102 | harddog_in_fd = -1; |
97 | harddog_out_fd = -1; | 103 | harddog_out_fd = -1; |
98 | 104 | ||
99 | timer_alive=0; | 105 | timer_alive=0; |
100 | unlock_kernel(); | 106 | spin_unlock(&lock); |
107 | |||
101 | return 0; | 108 | return 0; |
102 | } | 109 | } |
103 | 110 | ||
@@ -110,7 +117,7 @@ static ssize_t harddog_write(struct file *file, const char __user *data, size_t | |||
110 | * Refresh the timer. | 117 | * Refresh the timer. |
111 | */ | 118 | */ |
112 | if(len) | 119 | if(len) |
113 | return(ping_watchdog(harddog_out_fd)); | 120 | return ping_watchdog(harddog_out_fd); |
114 | return 0; | 121 | return 0; |
115 | } | 122 | } |
116 | 123 | ||
@@ -134,11 +141,11 @@ static int harddog_ioctl(struct inode *inode, struct file *file, | |||
134 | case WDIOC_GETBOOTSTATUS: | 141 | case WDIOC_GETBOOTSTATUS: |
135 | return put_user(0,(int __user *)argp); | 142 | return put_user(0,(int __user *)argp); |
136 | case WDIOC_KEEPALIVE: | 143 | case WDIOC_KEEPALIVE: |
137 | return(ping_watchdog(harddog_out_fd)); | 144 | return ping_watchdog(harddog_out_fd); |
138 | } | 145 | } |
139 | } | 146 | } |
140 | 147 | ||
141 | static struct file_operations harddog_fops = { | 148 | static const struct file_operations harddog_fops = { |
142 | .owner = THIS_MODULE, | 149 | .owner = THIS_MODULE, |
143 | .write = harddog_write, | 150 | .write = harddog_write, |
144 | .ioctl = harddog_ioctl, | 151 | .ioctl = harddog_ioctl, |
@@ -165,7 +172,7 @@ static int __init harddog_init(void) | |||
165 | 172 | ||
166 | printk(banner); | 173 | printk(banner); |
167 | 174 | ||
168 | return(0); | 175 | return 0; |
169 | } | 176 | } |
170 | 177 | ||
171 | static void __exit harddog_exit(void) | 178 | static void __exit harddog_exit(void) |
@@ -175,14 +182,3 @@ static void __exit harddog_exit(void) | |||
175 | 182 | ||
176 | module_init(harddog_init); | 183 | module_init(harddog_init); |
177 | module_exit(harddog_exit); | 184 | module_exit(harddog_exit); |
178 | |||
179 | /* | ||
180 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
181 | * Emacs will notice this stuff at the end of the file and automatically | ||
182 | * adjust the settings for this buffer only. This must remain at the end | ||
183 | * of the file. | ||
184 | * --------------------------------------------------------------------------- | ||
185 | * Local variables: | ||
186 | * c-file-style: "linux" | ||
187 | * End: | ||
188 | */ | ||
diff --git a/arch/um/drivers/harddog_user.c b/arch/um/drivers/harddog_user.c index def013b5a3c7..c495ecf263b1 100644 --- a/arch/um/drivers/harddog_user.c +++ b/arch/um/drivers/harddog_user.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | 2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) |
3 | * Licensed under the GPL | 3 | * Licensed under the GPL |
4 | */ | 4 | */ |
@@ -38,7 +38,7 @@ int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock) | |||
38 | int in_fds[2], out_fds[2], pid, n, err; | 38 | int in_fds[2], out_fds[2], pid, n, err; |
39 | char pid_buf[sizeof("nnnnn\0")], c; | 39 | char pid_buf[sizeof("nnnnn\0")], c; |
40 | char *pid_args[] = { "/usr/bin/uml_watchdog", "-pid", pid_buf, NULL }; | 40 | char *pid_args[] = { "/usr/bin/uml_watchdog", "-pid", pid_buf, NULL }; |
41 | char *mconsole_args[] = { "/usr/bin/uml_watchdog", "-mconsole", NULL, | 41 | char *mconsole_args[] = { "/usr/bin/uml_watchdog", "-mconsole", NULL, |
42 | NULL }; | 42 | NULL }; |
43 | char **args = NULL; | 43 | char **args = NULL; |
44 | 44 | ||
@@ -96,7 +96,7 @@ int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock) | |||
96 | } | 96 | } |
97 | *in_fd_ret = in_fds[0]; | 97 | *in_fd_ret = in_fds[0]; |
98 | *out_fd_ret = out_fds[1]; | 98 | *out_fd_ret = out_fds[1]; |
99 | return(0); | 99 | return 0; |
100 | 100 | ||
101 | out_close_in: | 101 | out_close_in: |
102 | os_close_file(in_fds[0]); | 102 | os_close_file(in_fds[0]); |
@@ -105,7 +105,7 @@ int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock) | |||
105 | os_close_file(out_fds[0]); | 105 | os_close_file(out_fds[0]); |
106 | os_close_file(out_fds[1]); | 106 | os_close_file(out_fds[1]); |
107 | out: | 107 | out: |
108 | return(err); | 108 | return err; |
109 | } | 109 | } |
110 | 110 | ||
111 | void stop_watchdog(int in_fd, int out_fd) | 111 | void stop_watchdog(int in_fd, int out_fd) |
@@ -123,20 +123,9 @@ int ping_watchdog(int fd) | |||
123 | if(n != sizeof(c)){ | 123 | if(n != sizeof(c)){ |
124 | printk("ping_watchdog - write failed, err = %d\n", -n); | 124 | printk("ping_watchdog - write failed, err = %d\n", -n); |
125 | if(n < 0) | 125 | if(n < 0) |
126 | return(n); | 126 | return n; |
127 | return(-EIO); | 127 | return -EIO; |
128 | } | 128 | } |
129 | return 1; | 129 | return 1; |
130 | 130 | ||
131 | } | 131 | } |
132 | |||
133 | /* | ||
134 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
135 | * Emacs will notice this stuff at the end of the file and automatically | ||
136 | * adjust the settings for this buffer only. This must remain at the end | ||
137 | * of the file. | ||
138 | * --------------------------------------------------------------------------- | ||
139 | * Local variables: | ||
140 | * c-file-style: "linux" | ||
141 | * End: | ||
142 | */ | ||
diff --git a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c index a0d148ea63d6..10e08a8c17c3 100644 --- a/arch/um/drivers/hostaudio_kern.c +++ b/arch/um/drivers/hostaudio_kern.c | |||
@@ -15,19 +15,22 @@ | |||
15 | #include "os.h" | 15 | #include "os.h" |
16 | 16 | ||
17 | struct hostaudio_state { | 17 | struct hostaudio_state { |
18 | int fd; | 18 | int fd; |
19 | }; | 19 | }; |
20 | 20 | ||
21 | struct hostmixer_state { | 21 | struct hostmixer_state { |
22 | int fd; | 22 | int fd; |
23 | }; | 23 | }; |
24 | 24 | ||
25 | #define HOSTAUDIO_DEV_DSP "/dev/sound/dsp" | 25 | #define HOSTAUDIO_DEV_DSP "/dev/sound/dsp" |
26 | #define HOSTAUDIO_DEV_MIXER "/dev/sound/mixer" | 26 | #define HOSTAUDIO_DEV_MIXER "/dev/sound/mixer" |
27 | 27 | ||
28 | /* Only changed from linux_main at boot time */ | 28 | /* Changed either at boot time or module load time. At boot, this is |
29 | char *dsp = HOSTAUDIO_DEV_DSP; | 29 | * single-threaded; at module load, multiple modules would each have |
30 | char *mixer = HOSTAUDIO_DEV_MIXER; | 30 | * their own copy of these variables. |
31 | */ | ||
32 | static char *dsp = HOSTAUDIO_DEV_DSP; | ||
33 | static char *mixer = HOSTAUDIO_DEV_MIXER; | ||
31 | 34 | ||
32 | #define DSP_HELP \ | 35 | #define DSP_HELP \ |
33 | " This is used to specify the host dsp device to the hostaudio driver.\n" \ | 36 | " This is used to specify the host dsp device to the hostaudio driver.\n" \ |
@@ -69,12 +72,12 @@ MODULE_PARM_DESC(mixer, MIXER_HELP); | |||
69 | static ssize_t hostaudio_read(struct file *file, char __user *buffer, | 72 | static ssize_t hostaudio_read(struct file *file, char __user *buffer, |
70 | size_t count, loff_t *ppos) | 73 | size_t count, loff_t *ppos) |
71 | { | 74 | { |
72 | struct hostaudio_state *state = file->private_data; | 75 | struct hostaudio_state *state = file->private_data; |
73 | void *kbuf; | 76 | void *kbuf; |
74 | int err; | 77 | int err; |
75 | 78 | ||
76 | #ifdef DEBUG | 79 | #ifdef DEBUG |
77 | printk("hostaudio: read called, count = %d\n", count); | 80 | printk("hostaudio: read called, count = %d\n", count); |
78 | #endif | 81 | #endif |
79 | 82 | ||
80 | kbuf = kmalloc(count, GFP_KERNEL); | 83 | kbuf = kmalloc(count, GFP_KERNEL); |
@@ -88,7 +91,7 @@ static ssize_t hostaudio_read(struct file *file, char __user *buffer, | |||
88 | if(copy_to_user(buffer, kbuf, err)) | 91 | if(copy_to_user(buffer, kbuf, err)) |
89 | err = -EFAULT; | 92 | err = -EFAULT; |
90 | 93 | ||
91 | out: | 94 | out: |
92 | kfree(kbuf); | 95 | kfree(kbuf); |
93 | return(err); | 96 | return(err); |
94 | } | 97 | } |
@@ -96,12 +99,12 @@ static ssize_t hostaudio_read(struct file *file, char __user *buffer, | |||
96 | static ssize_t hostaudio_write(struct file *file, const char __user *buffer, | 99 | static ssize_t hostaudio_write(struct file *file, const char __user *buffer, |
97 | size_t count, loff_t *ppos) | 100 | size_t count, loff_t *ppos) |
98 | { | 101 | { |
99 | struct hostaudio_state *state = file->private_data; | 102 | struct hostaudio_state *state = file->private_data; |
100 | void *kbuf; | 103 | void *kbuf; |
101 | int err; | 104 | int err; |
102 | 105 | ||
103 | #ifdef DEBUG | 106 | #ifdef DEBUG |
104 | printk("hostaudio: write called, count = %d\n", count); | 107 | printk("hostaudio: write called, count = %d\n", count); |
105 | #endif | 108 | #endif |
106 | 109 | ||
107 | kbuf = kmalloc(count, GFP_KERNEL); | 110 | kbuf = kmalloc(count, GFP_KERNEL); |
@@ -125,24 +128,24 @@ static ssize_t hostaudio_write(struct file *file, const char __user *buffer, | |||
125 | static unsigned int hostaudio_poll(struct file *file, | 128 | static unsigned int hostaudio_poll(struct file *file, |
126 | struct poll_table_struct *wait) | 129 | struct poll_table_struct *wait) |
127 | { | 130 | { |
128 | unsigned int mask = 0; | 131 | unsigned int mask = 0; |
129 | 132 | ||
130 | #ifdef DEBUG | 133 | #ifdef DEBUG |
131 | printk("hostaudio: poll called (unimplemented)\n"); | 134 | printk("hostaudio: poll called (unimplemented)\n"); |
132 | #endif | 135 | #endif |
133 | 136 | ||
134 | return(mask); | 137 | return(mask); |
135 | } | 138 | } |
136 | 139 | ||
137 | static int hostaudio_ioctl(struct inode *inode, struct file *file, | 140 | static int hostaudio_ioctl(struct inode *inode, struct file *file, |
138 | unsigned int cmd, unsigned long arg) | 141 | unsigned int cmd, unsigned long arg) |
139 | { | 142 | { |
140 | struct hostaudio_state *state = file->private_data; | 143 | struct hostaudio_state *state = file->private_data; |
141 | unsigned long data = 0; | 144 | unsigned long data = 0; |
142 | int err; | 145 | int err; |
143 | 146 | ||
144 | #ifdef DEBUG | 147 | #ifdef DEBUG |
145 | printk("hostaudio: ioctl called, cmd = %u\n", cmd); | 148 | printk("hostaudio: ioctl called, cmd = %u\n", cmd); |
146 | #endif | 149 | #endif |
147 | switch(cmd){ | 150 | switch(cmd){ |
148 | case SNDCTL_DSP_SPEED: | 151 | case SNDCTL_DSP_SPEED: |
@@ -179,42 +182,40 @@ static int hostaudio_ioctl(struct inode *inode, struct file *file, | |||
179 | 182 | ||
180 | static int hostaudio_open(struct inode *inode, struct file *file) | 183 | static int hostaudio_open(struct inode *inode, struct file *file) |
181 | { | 184 | { |
182 | struct hostaudio_state *state; | 185 | struct hostaudio_state *state; |
183 | int r = 0, w = 0; | 186 | int r = 0, w = 0; |
184 | int ret; | 187 | int ret; |
185 | 188 | ||
186 | #ifdef DEBUG | 189 | #ifdef DEBUG |
187 | printk("hostaudio: open called (host: %s)\n", dsp); | 190 | printk("hostaudio: open called (host: %s)\n", dsp); |
188 | #endif | 191 | #endif |
189 | 192 | ||
190 | state = kmalloc(sizeof(struct hostaudio_state), GFP_KERNEL); | 193 | state = kmalloc(sizeof(struct hostaudio_state), GFP_KERNEL); |
191 | if(state == NULL) | 194 | if(state == NULL) |
192 | return(-ENOMEM); | 195 | return(-ENOMEM); |
193 | 196 | ||
194 | if(file->f_mode & FMODE_READ) r = 1; | 197 | if(file->f_mode & FMODE_READ) r = 1; |
195 | if(file->f_mode & FMODE_WRITE) w = 1; | 198 | if(file->f_mode & FMODE_WRITE) w = 1; |
196 | 199 | ||
197 | ret = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0); | 200 | ret = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0); |
198 | if(ret < 0){ | 201 | if(ret < 0){ |
199 | kfree(state); | 202 | kfree(state); |
200 | return(ret); | 203 | return(ret); |
201 | } | 204 | } |
202 | |||
203 | state->fd = ret; | 205 | state->fd = ret; |
204 | file->private_data = state; | 206 | file->private_data = state; |
205 | return(0); | 207 | return(0); |
206 | } | 208 | } |
207 | 209 | ||
208 | static int hostaudio_release(struct inode *inode, struct file *file) | 210 | static int hostaudio_release(struct inode *inode, struct file *file) |
209 | { | 211 | { |
210 | struct hostaudio_state *state = file->private_data; | 212 | struct hostaudio_state *state = file->private_data; |
211 | 213 | ||
212 | #ifdef DEBUG | 214 | #ifdef DEBUG |
213 | printk("hostaudio: release called\n"); | 215 | printk("hostaudio: release called\n"); |
214 | #endif | 216 | #endif |
215 | 217 | os_close_file(state->fd); | |
216 | os_close_file(state->fd); | 218 | kfree(state); |
217 | kfree(state); | ||
218 | 219 | ||
219 | return(0); | 220 | return(0); |
220 | } | 221 | } |
@@ -224,10 +225,10 @@ static int hostaudio_release(struct inode *inode, struct file *file) | |||
224 | static int hostmixer_ioctl_mixdev(struct inode *inode, struct file *file, | 225 | static int hostmixer_ioctl_mixdev(struct inode *inode, struct file *file, |
225 | unsigned int cmd, unsigned long arg) | 226 | unsigned int cmd, unsigned long arg) |
226 | { | 227 | { |
227 | struct hostmixer_state *state = file->private_data; | 228 | struct hostmixer_state *state = file->private_data; |
228 | 229 | ||
229 | #ifdef DEBUG | 230 | #ifdef DEBUG |
230 | printk("hostmixer: ioctl called\n"); | 231 | printk("hostmixer: ioctl called\n"); |
231 | #endif | 232 | #endif |
232 | 233 | ||
233 | return(os_ioctl_generic(state->fd, cmd, arg)); | 234 | return(os_ioctl_generic(state->fd, cmd, arg)); |
@@ -235,68 +236,67 @@ static int hostmixer_ioctl_mixdev(struct inode *inode, struct file *file, | |||
235 | 236 | ||
236 | static int hostmixer_open_mixdev(struct inode *inode, struct file *file) | 237 | static int hostmixer_open_mixdev(struct inode *inode, struct file *file) |
237 | { | 238 | { |
238 | struct hostmixer_state *state; | 239 | struct hostmixer_state *state; |
239 | int r = 0, w = 0; | 240 | int r = 0, w = 0; |
240 | int ret; | 241 | int ret; |
241 | 242 | ||
242 | #ifdef DEBUG | 243 | #ifdef DEBUG |
243 | printk("hostmixer: open called (host: %s)\n", mixer); | 244 | printk("hostmixer: open called (host: %s)\n", mixer); |
244 | #endif | 245 | #endif |
245 | 246 | ||
246 | state = kmalloc(sizeof(struct hostmixer_state), GFP_KERNEL); | 247 | state = kmalloc(sizeof(struct hostmixer_state), GFP_KERNEL); |
247 | if(state == NULL) return(-ENOMEM); | 248 | if(state == NULL) return(-ENOMEM); |
248 | 249 | ||
249 | if(file->f_mode & FMODE_READ) r = 1; | 250 | if(file->f_mode & FMODE_READ) r = 1; |
250 | if(file->f_mode & FMODE_WRITE) w = 1; | 251 | if(file->f_mode & FMODE_WRITE) w = 1; |
251 | 252 | ||
252 | ret = os_open_file(mixer, of_set_rw(OPENFLAGS(), r, w), 0); | 253 | ret = os_open_file(mixer, of_set_rw(OPENFLAGS(), r, w), 0); |
253 | 254 | ||
254 | if(ret < 0){ | 255 | if(ret < 0){ |
255 | printk("hostaudio_open_mixdev failed to open '%s', err = %d\n", | 256 | printk("hostaudio_open_mixdev failed to open '%s', err = %d\n", |
256 | dsp, -ret); | 257 | dsp, -ret); |
257 | kfree(state); | 258 | kfree(state); |
258 | return(ret); | 259 | return(ret); |
259 | } | 260 | } |
260 | 261 | ||
261 | file->private_data = state; | 262 | file->private_data = state; |
262 | return(0); | 263 | return(0); |
263 | } | 264 | } |
264 | 265 | ||
265 | static int hostmixer_release(struct inode *inode, struct file *file) | 266 | static int hostmixer_release(struct inode *inode, struct file *file) |
266 | { | 267 | { |
267 | struct hostmixer_state *state = file->private_data; | 268 | struct hostmixer_state *state = file->private_data; |
268 | 269 | ||
269 | #ifdef DEBUG | 270 | #ifdef DEBUG |
270 | printk("hostmixer: release called\n"); | 271 | printk("hostmixer: release called\n"); |
271 | #endif | 272 | #endif |
272 | 273 | ||
273 | os_close_file(state->fd); | 274 | os_close_file(state->fd); |
274 | kfree(state); | 275 | kfree(state); |
275 | 276 | ||
276 | return(0); | 277 | return(0); |
277 | } | 278 | } |
278 | 279 | ||
279 | |||
280 | /* kernel module operations */ | 280 | /* kernel module operations */ |
281 | 281 | ||
282 | static const struct file_operations hostaudio_fops = { | 282 | static const struct file_operations hostaudio_fops = { |
283 | .owner = THIS_MODULE, | 283 | .owner = THIS_MODULE, |
284 | .llseek = no_llseek, | 284 | .llseek = no_llseek, |
285 | .read = hostaudio_read, | 285 | .read = hostaudio_read, |
286 | .write = hostaudio_write, | 286 | .write = hostaudio_write, |
287 | .poll = hostaudio_poll, | 287 | .poll = hostaudio_poll, |
288 | .ioctl = hostaudio_ioctl, | 288 | .ioctl = hostaudio_ioctl, |
289 | .mmap = NULL, | 289 | .mmap = NULL, |
290 | .open = hostaudio_open, | 290 | .open = hostaudio_open, |
291 | .release = hostaudio_release, | 291 | .release = hostaudio_release, |
292 | }; | 292 | }; |
293 | 293 | ||
294 | static const struct file_operations hostmixer_fops = { | 294 | static const struct file_operations hostmixer_fops = { |
295 | .owner = THIS_MODULE, | 295 | .owner = THIS_MODULE, |
296 | .llseek = no_llseek, | 296 | .llseek = no_llseek, |
297 | .ioctl = hostmixer_ioctl_mixdev, | 297 | .ioctl = hostmixer_ioctl_mixdev, |
298 | .open = hostmixer_open_mixdev, | 298 | .open = hostmixer_open_mixdev, |
299 | .release = hostmixer_release, | 299 | .release = hostmixer_release, |
300 | }; | 300 | }; |
301 | 301 | ||
302 | struct { | 302 | struct { |
@@ -310,42 +310,31 @@ MODULE_LICENSE("GPL"); | |||
310 | 310 | ||
311 | static int __init hostaudio_init_module(void) | 311 | static int __init hostaudio_init_module(void) |
312 | { | 312 | { |
313 | printk(KERN_INFO "UML Audio Relay (host dsp = %s, host mixer = %s)\n", | 313 | printk(KERN_INFO "UML Audio Relay (host dsp = %s, host mixer = %s)\n", |
314 | dsp, mixer); | 314 | dsp, mixer); |
315 | 315 | ||
316 | module_data.dev_audio = register_sound_dsp(&hostaudio_fops, -1); | 316 | module_data.dev_audio = register_sound_dsp(&hostaudio_fops, -1); |
317 | if(module_data.dev_audio < 0){ | 317 | if(module_data.dev_audio < 0){ |
318 | printk(KERN_ERR "hostaudio: couldn't register DSP device!\n"); | 318 | printk(KERN_ERR "hostaudio: couldn't register DSP device!\n"); |
319 | return -ENODEV; | 319 | return -ENODEV; |
320 | } | 320 | } |
321 | 321 | ||
322 | module_data.dev_mixer = register_sound_mixer(&hostmixer_fops, -1); | 322 | module_data.dev_mixer = register_sound_mixer(&hostmixer_fops, -1); |
323 | if(module_data.dev_mixer < 0){ | 323 | if(module_data.dev_mixer < 0){ |
324 | printk(KERN_ERR "hostmixer: couldn't register mixer " | 324 | printk(KERN_ERR "hostmixer: couldn't register mixer " |
325 | "device!\n"); | 325 | "device!\n"); |
326 | unregister_sound_dsp(module_data.dev_audio); | 326 | unregister_sound_dsp(module_data.dev_audio); |
327 | return -ENODEV; | 327 | return -ENODEV; |
328 | } | 328 | } |
329 | 329 | ||
330 | return 0; | 330 | return 0; |
331 | } | 331 | } |
332 | 332 | ||
333 | static void __exit hostaudio_cleanup_module (void) | 333 | static void __exit hostaudio_cleanup_module (void) |
334 | { | 334 | { |
335 | unregister_sound_mixer(module_data.dev_mixer); | 335 | unregister_sound_mixer(module_data.dev_mixer); |
336 | unregister_sound_dsp(module_data.dev_audio); | 336 | unregister_sound_dsp(module_data.dev_audio); |
337 | } | 337 | } |
338 | 338 | ||
339 | module_init(hostaudio_init_module); | 339 | module_init(hostaudio_init_module); |
340 | module_exit(hostaudio_cleanup_module); | 340 | module_exit(hostaudio_cleanup_module); |
341 | |||
342 | /* | ||
343 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
344 | * Emacs will notice this stuff at the end of the file and automatically | ||
345 | * adjust the settings for this buffer only. This must remain at the end | ||
346 | * of the file. | ||
347 | * --------------------------------------------------------------------------- | ||
348 | * Local variables: | ||
349 | * c-file-style: "linux" | ||
350 | * End: | ||
351 | */ | ||
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 83301e1ef67c..01d4ab6b0ef1 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c | |||
@@ -191,7 +191,6 @@ void line_flush_buffer(struct tty_struct *tty) | |||
191 | /*XXX: copied from line_write, verify if it is correct!*/ | 191 | /*XXX: copied from line_write, verify if it is correct!*/ |
192 | if(tty->stopped) | 192 | if(tty->stopped) |
193 | return; | 193 | return; |
194 | //return 0; | ||
195 | 194 | ||
196 | spin_lock_irqsave(&line->lock, flags); | 195 | spin_lock_irqsave(&line->lock, flags); |
197 | err = flush_buffer(line); | 196 | err = flush_buffer(line); |
@@ -421,42 +420,55 @@ int line_setup_irq(int fd, int input, int output, struct line *line, void *data) | |||
421 | return err; | 420 | return err; |
422 | } | 421 | } |
423 | 422 | ||
423 | /* Normally, a driver like this can rely mostly on the tty layer | ||
424 | * locking, particularly when it comes to the driver structure. | ||
425 | * However, in this case, mconsole requests can come in "from the | ||
426 | * side", and race with opens and closes. | ||
427 | * | ||
428 | * mconsole config requests will want to be sure the device isn't in | ||
429 | * use, and get_config, open, and close will want a stable | ||
430 | * configuration. The checking and modification of the configuration | ||
431 | * is done under a spinlock. Checking whether the device is in use is | ||
432 | * line->tty->count > 1, also under the spinlock. | ||
433 | * | ||
434 | * tty->count serves to decide whether the device should be enabled or | ||
435 | * disabled on the host. If it's equal to 1, then we are doing the | ||
436 | * first open or last close. Otherwise, open and close just return. | ||
437 | */ | ||
438 | |||
424 | int line_open(struct line *lines, struct tty_struct *tty) | 439 | int line_open(struct line *lines, struct tty_struct *tty) |
425 | { | 440 | { |
426 | struct line *line; | 441 | struct line *line = &lines[tty->index]; |
427 | int err = -ENODEV; | 442 | int err = -ENODEV; |
428 | 443 | ||
429 | line = &lines[tty->index]; | 444 | spin_lock(&line->count_lock); |
430 | tty->driver_data = line; | 445 | if(!line->valid) |
446 | goto out_unlock; | ||
431 | 447 | ||
432 | /* The IRQ which takes this lock is not yet enabled and won't be run | 448 | err = 0; |
433 | * before the end, so we don't need to use spin_lock_irq.*/ | 449 | if(tty->count > 1) |
434 | spin_lock(&line->lock); | 450 | goto out_unlock; |
451 | |||
452 | spin_unlock(&line->count_lock); | ||
435 | 453 | ||
436 | tty->driver_data = line; | 454 | tty->driver_data = line; |
437 | line->tty = tty; | 455 | line->tty = tty; |
438 | if(!line->valid) | ||
439 | goto out; | ||
440 | 456 | ||
441 | if(tty->count == 1){ | 457 | enable_chan(line); |
442 | /* Here the device is opened, if necessary, and interrupt | 458 | INIT_DELAYED_WORK(&line->task, line_timer_cb); |
443 | * is registered. | ||
444 | */ | ||
445 | enable_chan(line); | ||
446 | INIT_DELAYED_WORK(&line->task, line_timer_cb); | ||
447 | 459 | ||
448 | if(!line->sigio){ | 460 | if(!line->sigio){ |
449 | chan_enable_winch(&line->chan_list, tty); | 461 | chan_enable_winch(&line->chan_list, tty); |
450 | line->sigio = 1; | 462 | line->sigio = 1; |
451 | } | ||
452 | |||
453 | chan_window_size(&line->chan_list, &tty->winsize.ws_row, | ||
454 | &tty->winsize.ws_col); | ||
455 | } | 463 | } |
456 | 464 | ||
457 | err = 0; | 465 | chan_window_size(&line->chan_list, &tty->winsize.ws_row, |
458 | out: | 466 | &tty->winsize.ws_col); |
459 | spin_unlock(&line->lock); | 467 | |
468 | return err; | ||
469 | |||
470 | out_unlock: | ||
471 | spin_unlock(&line->count_lock); | ||
460 | return err; | 472 | return err; |
461 | } | 473 | } |
462 | 474 | ||
@@ -466,25 +478,36 @@ void line_close(struct tty_struct *tty, struct file * filp) | |||
466 | { | 478 | { |
467 | struct line *line = tty->driver_data; | 479 | struct line *line = tty->driver_data; |
468 | 480 | ||
469 | /* XXX: I assume this should be called in process context, not with | 481 | /* If line_open fails (and tty->driver_data is never set), |
470 | * interrupts disabled! | 482 | * tty_open will call line_close. So just return in this case. |
471 | */ | 483 | */ |
472 | spin_lock_irq(&line->lock); | 484 | if(line == NULL) |
485 | return; | ||
473 | 486 | ||
474 | /* We ignore the error anyway! */ | 487 | /* We ignore the error anyway! */ |
475 | flush_buffer(line); | 488 | flush_buffer(line); |
476 | 489 | ||
477 | if(tty->count == 1){ | 490 | spin_lock(&line->count_lock); |
478 | line->tty = NULL; | 491 | if(!line->valid) |
479 | tty->driver_data = NULL; | 492 | goto out_unlock; |
480 | 493 | ||
481 | if(line->sigio){ | 494 | if(tty->count > 1) |
482 | unregister_winch(tty); | 495 | goto out_unlock; |
483 | line->sigio = 0; | 496 | |
484 | } | 497 | spin_unlock(&line->count_lock); |
498 | |||
499 | line->tty = NULL; | ||
500 | tty->driver_data = NULL; | ||
501 | |||
502 | if(line->sigio){ | ||
503 | unregister_winch(tty); | ||
504 | line->sigio = 0; | ||
485 | } | 505 | } |
486 | 506 | ||
487 | spin_unlock_irq(&line->lock); | 507 | return; |
508 | |||
509 | out_unlock: | ||
510 | spin_unlock(&line->count_lock); | ||
488 | } | 511 | } |
489 | 512 | ||
490 | void close_lines(struct line *lines, int nlines) | 513 | void close_lines(struct line *lines, int nlines) |
@@ -495,14 +518,44 @@ void close_lines(struct line *lines, int nlines) | |||
495 | close_chan(&lines[i].chan_list, 0); | 518 | close_chan(&lines[i].chan_list, 0); |
496 | } | 519 | } |
497 | 520 | ||
521 | static int setup_one_line(struct line *lines, int n, char *init, int init_prio, | ||
522 | char **error_out) | ||
523 | { | ||
524 | struct line *line = &lines[n]; | ||
525 | int err = -EINVAL; | ||
526 | |||
527 | spin_lock(&line->count_lock); | ||
528 | |||
529 | if(line->tty != NULL){ | ||
530 | *error_out = "Device is already open"; | ||
531 | goto out; | ||
532 | } | ||
533 | |||
534 | if (line->init_pri <= init_prio){ | ||
535 | line->init_pri = init_prio; | ||
536 | if (!strcmp(init, "none")) | ||
537 | line->valid = 0; | ||
538 | else { | ||
539 | line->init_str = init; | ||
540 | line->valid = 1; | ||
541 | } | ||
542 | } | ||
543 | err = 0; | ||
544 | out: | ||
545 | spin_unlock(&line->count_lock); | ||
546 | return err; | ||
547 | } | ||
548 | |||
498 | /* Common setup code for both startup command line and mconsole initialization. | 549 | /* Common setup code for both startup command line and mconsole initialization. |
499 | * @lines contains the array (of size @num) to modify; | 550 | * @lines contains the array (of size @num) to modify; |
500 | * @init is the setup string; | 551 | * @init is the setup string; |
552 | * @error_out is an error string in the case of failure; | ||
501 | */ | 553 | */ |
502 | 554 | ||
503 | int line_setup(struct line *lines, unsigned int num, char *init) | 555 | int line_setup(struct line *lines, unsigned int num, char *init, |
556 | char **error_out) | ||
504 | { | 557 | { |
505 | int i, n; | 558 | int i, n, err; |
506 | char *end; | 559 | char *end; |
507 | 560 | ||
508 | if(*init == '=') { | 561 | if(*init == '=') { |
@@ -513,73 +566,56 @@ int line_setup(struct line *lines, unsigned int num, char *init) | |||
513 | else { | 566 | else { |
514 | n = simple_strtoul(init, &end, 0); | 567 | n = simple_strtoul(init, &end, 0); |
515 | if(*end != '='){ | 568 | if(*end != '='){ |
516 | printk(KERN_ERR "line_setup failed to parse \"%s\"\n", | 569 | *error_out = "Couldn't parse device number"; |
517 | init); | 570 | return -EINVAL; |
518 | return 0; | ||
519 | } | 571 | } |
520 | init = end; | 572 | init = end; |
521 | } | 573 | } |
522 | init++; | 574 | init++; |
523 | 575 | ||
524 | if (n >= (signed int) num) { | 576 | if (n >= (signed int) num) { |
525 | printk("line_setup - %d out of range ((0 ... %d) allowed)\n", | 577 | *error_out = "Device number out of range"; |
526 | n, num - 1); | 578 | return -EINVAL; |
527 | return 0; | ||
528 | } | 579 | } |
529 | else if (n >= 0){ | 580 | else if (n >= 0){ |
530 | if (lines[n].tty != NULL) { | 581 | err = setup_one_line(lines, n, init, INIT_ONE, error_out); |
531 | printk("line_setup - device %d is open\n", n); | 582 | if(err) |
532 | return 0; | 583 | return err; |
533 | } | ||
534 | if (lines[n].init_pri <= INIT_ONE){ | ||
535 | lines[n].init_pri = INIT_ONE; | ||
536 | if (!strcmp(init, "none")) | ||
537 | lines[n].valid = 0; | ||
538 | else { | ||
539 | lines[n].init_str = init; | ||
540 | lines[n].valid = 1; | ||
541 | } | ||
542 | } | ||
543 | } | 584 | } |
544 | else { | 585 | else { |
545 | for(i = 0; i < num; i++){ | 586 | for(i = 0; i < num; i++){ |
546 | if(lines[i].init_pri <= INIT_ALL){ | 587 | err = setup_one_line(lines, i, init, INIT_ALL, |
547 | lines[i].init_pri = INIT_ALL; | 588 | error_out); |
548 | if(!strcmp(init, "none")) lines[i].valid = 0; | 589 | if(err) |
549 | else { | 590 | return err; |
550 | lines[i].init_str = init; | ||
551 | lines[i].valid = 1; | ||
552 | } | ||
553 | } | ||
554 | } | 591 | } |
555 | } | 592 | } |
556 | return n == -1 ? num : n; | 593 | return n == -1 ? num : n; |
557 | } | 594 | } |
558 | 595 | ||
559 | int line_config(struct line *lines, unsigned int num, char *str, | 596 | int line_config(struct line *lines, unsigned int num, char *str, |
560 | const struct chan_opts *opts) | 597 | const struct chan_opts *opts, char **error_out) |
561 | { | 598 | { |
562 | struct line *line; | 599 | struct line *line; |
563 | char *new; | 600 | char *new; |
564 | int n; | 601 | int n; |
565 | 602 | ||
566 | if(*str == '='){ | 603 | if(*str == '='){ |
567 | printk("line_config - can't configure all devices from " | 604 | *error_out = "Can't configure all devices from mconsole"; |
568 | "mconsole\n"); | 605 | return -EINVAL; |
569 | return 1; | ||
570 | } | 606 | } |
571 | 607 | ||
572 | new = kstrdup(str, GFP_KERNEL); | 608 | new = kstrdup(str, GFP_KERNEL); |
573 | if(new == NULL){ | 609 | if(new == NULL){ |
574 | printk("line_config - kstrdup failed\n"); | 610 | *error_out = "Failed to allocate memory"; |
575 | return 1; | 611 | return -ENOMEM; |
576 | } | 612 | } |
577 | n = line_setup(lines, num, new); | 613 | n = line_setup(lines, num, new, error_out); |
578 | if(n < 0) | 614 | if(n < 0) |
579 | return 1; | 615 | return n; |
580 | 616 | ||
581 | line = &lines[n]; | 617 | line = &lines[n]; |
582 | return parse_chan_pair(line->init_str, line, n, opts); | 618 | return parse_chan_pair(line->init_str, line, n, opts, error_out); |
583 | } | 619 | } |
584 | 620 | ||
585 | int line_get_config(char *name, struct line *lines, unsigned int num, char *str, | 621 | int line_get_config(char *name, struct line *lines, unsigned int num, char *str, |
@@ -602,13 +638,13 @@ int line_get_config(char *name, struct line *lines, unsigned int num, char *str, | |||
602 | 638 | ||
603 | line = &lines[dev]; | 639 | line = &lines[dev]; |
604 | 640 | ||
605 | spin_lock(&line->lock); | 641 | spin_lock(&line->count_lock); |
606 | if(!line->valid) | 642 | if(!line->valid) |
607 | CONFIG_CHUNK(str, size, n, "none", 1); | 643 | CONFIG_CHUNK(str, size, n, "none", 1); |
608 | else if(line->tty == NULL) | 644 | else if(line->tty == NULL) |
609 | CONFIG_CHUNK(str, size, n, line->init_str, 1); | 645 | CONFIG_CHUNK(str, size, n, line->init_str, 1); |
610 | else n = chan_config_string(&line->chan_list, str, size, error_out); | 646 | else n = chan_config_string(&line->chan_list, str, size, error_out); |
611 | spin_unlock(&line->lock); | 647 | spin_unlock(&line->count_lock); |
612 | 648 | ||
613 | return n; | 649 | return n; |
614 | } | 650 | } |
@@ -628,22 +664,21 @@ int line_id(char **str, int *start_out, int *end_out) | |||
628 | return n; | 664 | return n; |
629 | } | 665 | } |
630 | 666 | ||
631 | int line_remove(struct line *lines, unsigned int num, int n) | 667 | int line_remove(struct line *lines, unsigned int num, int n, char **error_out) |
632 | { | 668 | { |
633 | int err; | 669 | int err; |
634 | char config[sizeof("conxxxx=none\0")]; | 670 | char config[sizeof("conxxxx=none\0")]; |
635 | 671 | ||
636 | sprintf(config, "%d=none", n); | 672 | sprintf(config, "%d=none", n); |
637 | err = line_setup(lines, num, config); | 673 | err = line_setup(lines, num, config, error_out); |
638 | if(err >= 0) | 674 | if(err >= 0) |
639 | err = 0; | 675 | err = 0; |
640 | return err; | 676 | return err; |
641 | } | 677 | } |
642 | 678 | ||
643 | struct tty_driver *line_register_devfs(struct lines *set, | 679 | struct tty_driver *register_lines(struct line_driver *line_driver, |
644 | struct line_driver *line_driver, | 680 | const struct tty_operations *ops, |
645 | const struct tty_operations *ops, | 681 | struct line *lines, int nlines) |
646 | struct line *lines, int nlines) | ||
647 | { | 682 | { |
648 | int i; | 683 | int i; |
649 | struct tty_driver *driver = alloc_tty_driver(nlines); | 684 | struct tty_driver *driver = alloc_tty_driver(nlines); |
@@ -683,6 +718,7 @@ static LIST_HEAD(winch_handlers); | |||
683 | void lines_init(struct line *lines, int nlines, struct chan_opts *opts) | 718 | void lines_init(struct line *lines, int nlines, struct chan_opts *opts) |
684 | { | 719 | { |
685 | struct line *line; | 720 | struct line *line; |
721 | char *error; | ||
686 | int i; | 722 | int i; |
687 | 723 | ||
688 | for(i = 0; i < nlines; i++){ | 724 | for(i = 0; i < nlines; i++){ |
@@ -696,8 +732,9 @@ void lines_init(struct line *lines, int nlines, struct chan_opts *opts) | |||
696 | if(line->init_str == NULL) | 732 | if(line->init_str == NULL) |
697 | printk("lines_init - kstrdup returned NULL\n"); | 733 | printk("lines_init - kstrdup returned NULL\n"); |
698 | 734 | ||
699 | if(parse_chan_pair(line->init_str, line, i, opts)){ | 735 | if(parse_chan_pair(line->init_str, line, i, opts, &error)){ |
700 | printk("parse_chan_pair failed for device %d\n", i); | 736 | printk("parse_chan_pair failed for device %d : %s\n", |
737 | i, error); | ||
701 | line->valid = 0; | 738 | line->valid = 0; |
702 | } | 739 | } |
703 | } | 740 | } |
@@ -737,7 +774,7 @@ static irqreturn_t winch_interrupt(int irq, void *data) | |||
737 | line = tty->driver_data; | 774 | line = tty->driver_data; |
738 | chan_window_size(&line->chan_list, &tty->winsize.ws_row, | 775 | chan_window_size(&line->chan_list, &tty->winsize.ws_row, |
739 | &tty->winsize.ws_col); | 776 | &tty->winsize.ws_col); |
740 | kill_pg(tty->pgrp, SIGWINCH, 1); | 777 | kill_pgrp(tty->pgrp, SIGWINCH, 1); |
741 | } | 778 | } |
742 | out: | 779 | out: |
743 | if(winch->fd != -1) | 780 | if(winch->fd != -1) |
diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index 96f0189327af..178b2eff4a8c 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c | |||
@@ -33,7 +33,6 @@ | |||
33 | #include "irq_user.h" | 33 | #include "irq_user.h" |
34 | #include "init.h" | 34 | #include "init.h" |
35 | #include "os.h" | 35 | #include "os.h" |
36 | #include "umid.h" | ||
37 | #include "irq_kern.h" | 36 | #include "irq_kern.h" |
38 | #include "choose-mode.h" | 37 | #include "choose-mode.h" |
39 | 38 | ||
@@ -337,13 +336,15 @@ void mconsole_stop(struct mc_request *req) | |||
337 | mconsole_reply(req, "", 0, 0); | 336 | mconsole_reply(req, "", 0, 0); |
338 | } | 337 | } |
339 | 338 | ||
340 | /* This list is populated by __initcall routines. */ | 339 | static DEFINE_SPINLOCK(mc_devices_lock); |
341 | |||
342 | static LIST_HEAD(mconsole_devices); | 340 | static LIST_HEAD(mconsole_devices); |
343 | 341 | ||
344 | void mconsole_register_dev(struct mc_device *new) | 342 | void mconsole_register_dev(struct mc_device *new) |
345 | { | 343 | { |
344 | spin_lock(&mc_devices_lock); | ||
345 | BUG_ON(!list_empty(&new->list)); | ||
346 | list_add(&new->list, &mconsole_devices); | 346 | list_add(&new->list, &mconsole_devices); |
347 | spin_unlock(&mc_devices_lock); | ||
347 | } | 348 | } |
348 | 349 | ||
349 | static struct mc_device *mconsole_find_dev(char *name) | 350 | static struct mc_device *mconsole_find_dev(char *name) |
@@ -367,18 +368,21 @@ struct unplugged_pages { | |||
367 | void *pages[UNPLUGGED_PER_PAGE]; | 368 | void *pages[UNPLUGGED_PER_PAGE]; |
368 | }; | 369 | }; |
369 | 370 | ||
371 | static DECLARE_MUTEX(plug_mem_mutex); | ||
370 | static unsigned long long unplugged_pages_count = 0; | 372 | static unsigned long long unplugged_pages_count = 0; |
371 | static struct list_head unplugged_pages = LIST_HEAD_INIT(unplugged_pages); | 373 | static LIST_HEAD(unplugged_pages); |
372 | static int unplug_index = UNPLUGGED_PER_PAGE; | 374 | static int unplug_index = UNPLUGGED_PER_PAGE; |
373 | 375 | ||
374 | static int mem_config(char *str) | 376 | static int mem_config(char *str, char **error_out) |
375 | { | 377 | { |
376 | unsigned long long diff; | 378 | unsigned long long diff; |
377 | int err = -EINVAL, i, add; | 379 | int err = -EINVAL, i, add; |
378 | char *ret; | 380 | char *ret; |
379 | 381 | ||
380 | if(str[0] != '=') | 382 | if(str[0] != '='){ |
383 | *error_out = "Expected '=' after 'mem'"; | ||
381 | goto out; | 384 | goto out; |
385 | } | ||
382 | 386 | ||
383 | str++; | 387 | str++; |
384 | if(str[0] == '-') | 388 | if(str[0] == '-') |
@@ -386,15 +390,21 @@ static int mem_config(char *str) | |||
386 | else if(str[0] == '+'){ | 390 | else if(str[0] == '+'){ |
387 | add = 1; | 391 | add = 1; |
388 | } | 392 | } |
389 | else goto out; | 393 | else { |
394 | *error_out = "Expected increment to start with '-' or '+'"; | ||
395 | goto out; | ||
396 | } | ||
390 | 397 | ||
391 | str++; | 398 | str++; |
392 | diff = memparse(str, &ret); | 399 | diff = memparse(str, &ret); |
393 | if(*ret != '\0') | 400 | if(*ret != '\0'){ |
401 | *error_out = "Failed to parse memory increment"; | ||
394 | goto out; | 402 | goto out; |
403 | } | ||
395 | 404 | ||
396 | diff /= PAGE_SIZE; | 405 | diff /= PAGE_SIZE; |
397 | 406 | ||
407 | down(&plug_mem_mutex); | ||
398 | for(i = 0; i < diff; i++){ | 408 | for(i = 0; i < diff; i++){ |
399 | struct unplugged_pages *unplugged; | 409 | struct unplugged_pages *unplugged; |
400 | void *addr; | 410 | void *addr; |
@@ -435,11 +445,14 @@ static int mem_config(char *str) | |||
435 | unplugged = list_entry(entry, | 445 | unplugged = list_entry(entry, |
436 | struct unplugged_pages, | 446 | struct unplugged_pages, |
437 | list); | 447 | list); |
438 | unplugged->pages[unplug_index++] = addr; | ||
439 | err = os_drop_memory(addr, PAGE_SIZE); | 448 | err = os_drop_memory(addr, PAGE_SIZE); |
440 | if(err) | 449 | if(err){ |
441 | printk("Failed to release memory - " | 450 | printk("Failed to release memory - " |
442 | "errno = %d\n", err); | 451 | "errno = %d\n", err); |
452 | *error_out = "Failed to release memory"; | ||
453 | goto out_unlock; | ||
454 | } | ||
455 | unplugged->pages[unplug_index++] = addr; | ||
443 | } | 456 | } |
444 | 457 | ||
445 | unplugged_pages_count++; | 458 | unplugged_pages_count++; |
@@ -447,6 +460,8 @@ static int mem_config(char *str) | |||
447 | } | 460 | } |
448 | 461 | ||
449 | err = 0; | 462 | err = 0; |
463 | out_unlock: | ||
464 | up(&plug_mem_mutex); | ||
450 | out: | 465 | out: |
451 | return err; | 466 | return err; |
452 | } | 467 | } |
@@ -470,12 +485,14 @@ static int mem_id(char **str, int *start_out, int *end_out) | |||
470 | return 0; | 485 | return 0; |
471 | } | 486 | } |
472 | 487 | ||
473 | static int mem_remove(int n) | 488 | static int mem_remove(int n, char **error_out) |
474 | { | 489 | { |
490 | *error_out = "Memory doesn't support the remove operation"; | ||
475 | return -EBUSY; | 491 | return -EBUSY; |
476 | } | 492 | } |
477 | 493 | ||
478 | static struct mc_device mem_mc = { | 494 | static struct mc_device mem_mc = { |
495 | .list = LIST_HEAD_INIT(mem_mc.list), | ||
479 | .name = "mem", | 496 | .name = "mem", |
480 | .config = mem_config, | 497 | .config = mem_config, |
481 | .get_config = mem_get_config, | 498 | .get_config = mem_get_config, |
@@ -542,7 +559,7 @@ static void mconsole_get_config(int (*get_config)(char *, char *, int, | |||
542 | void mconsole_config(struct mc_request *req) | 559 | void mconsole_config(struct mc_request *req) |
543 | { | 560 | { |
544 | struct mc_device *dev; | 561 | struct mc_device *dev; |
545 | char *ptr = req->request.data, *name; | 562 | char *ptr = req->request.data, *name, *error_string = ""; |
546 | int err; | 563 | int err; |
547 | 564 | ||
548 | ptr += strlen("config"); | 565 | ptr += strlen("config"); |
@@ -559,8 +576,8 @@ void mconsole_config(struct mc_request *req) | |||
559 | ptr++; | 576 | ptr++; |
560 | 577 | ||
561 | if(*ptr == '='){ | 578 | if(*ptr == '='){ |
562 | err = (*dev->config)(name); | 579 | err = (*dev->config)(name, &error_string); |
563 | mconsole_reply(req, "", err, 0); | 580 | mconsole_reply(req, error_string, err, 0); |
564 | } | 581 | } |
565 | else mconsole_get_config(dev->get_config, req, name); | 582 | else mconsole_get_config(dev->get_config, req, name); |
566 | } | 583 | } |
@@ -595,13 +612,16 @@ void mconsole_remove(struct mc_request *req) | |||
595 | goto out; | 612 | goto out; |
596 | } | 613 | } |
597 | 614 | ||
598 | err = (*dev->remove)(n); | 615 | err_msg = NULL; |
616 | err = (*dev->remove)(n, &err_msg); | ||
599 | switch(err){ | 617 | switch(err){ |
600 | case -ENODEV: | 618 | case -ENODEV: |
601 | err_msg = "Device doesn't exist"; | 619 | if(err_msg == NULL) |
620 | err_msg = "Device doesn't exist"; | ||
602 | break; | 621 | break; |
603 | case -EBUSY: | 622 | case -EBUSY: |
604 | err_msg = "Device is currently open"; | 623 | if(err_msg == NULL) |
624 | err_msg = "Device is currently open"; | ||
605 | break; | 625 | break; |
606 | default: | 626 | default: |
607 | break; | 627 | break; |
@@ -615,7 +635,7 @@ struct mconsole_output { | |||
615 | struct mc_request *req; | 635 | struct mc_request *req; |
616 | }; | 636 | }; |
617 | 637 | ||
618 | static DEFINE_SPINLOCK(console_lock); | 638 | static DEFINE_SPINLOCK(client_lock); |
619 | static LIST_HEAD(clients); | 639 | static LIST_HEAD(clients); |
620 | static char console_buf[MCONSOLE_MAX_DATA]; | 640 | static char console_buf[MCONSOLE_MAX_DATA]; |
621 | static int console_index = 0; | 641 | static int console_index = 0; |
@@ -670,16 +690,18 @@ static void with_console(struct mc_request *req, void (*proc)(void *), | |||
670 | unsigned long flags; | 690 | unsigned long flags; |
671 | 691 | ||
672 | entry.req = req; | 692 | entry.req = req; |
693 | spin_lock_irqsave(&client_lock, flags); | ||
673 | list_add(&entry.list, &clients); | 694 | list_add(&entry.list, &clients); |
674 | spin_lock_irqsave(&console_lock, flags); | 695 | spin_unlock_irqrestore(&client_lock, flags); |
675 | 696 | ||
676 | (*proc)(arg); | 697 | (*proc)(arg); |
677 | 698 | ||
678 | mconsole_reply_len(req, console_buf, console_index, 0, 0); | 699 | mconsole_reply_len(req, console_buf, console_index, 0, 0); |
679 | console_index = 0; | 700 | console_index = 0; |
680 | 701 | ||
681 | spin_unlock_irqrestore(&console_lock, flags); | 702 | spin_lock_irqsave(&client_lock, flags); |
682 | list_del(&entry.list); | 703 | list_del(&entry.list); |
704 | spin_unlock_irqrestore(&client_lock, flags); | ||
683 | } | 705 | } |
684 | 706 | ||
685 | #ifdef CONFIG_MAGIC_SYSRQ | 707 | #ifdef CONFIG_MAGIC_SYSRQ |
diff --git a/arch/um/drivers/mconsole_user.c b/arch/um/drivers/mconsole_user.c index 75aef6f7ef6e..f02634fbf32a 100644 --- a/arch/um/drivers/mconsole_user.c +++ b/arch/um/drivers/mconsole_user.c | |||
@@ -16,7 +16,7 @@ | |||
16 | #include "user.h" | 16 | #include "user.h" |
17 | #include "sysdep/ptrace.h" | 17 | #include "sysdep/ptrace.h" |
18 | #include "mconsole.h" | 18 | #include "mconsole.h" |
19 | #include "umid.h" | 19 | #include "os.h" |
20 | #include "user_util.h" | 20 | #include "user_util.h" |
21 | 21 | ||
22 | static struct mconsole_command commands[] = { | 22 | static struct mconsole_command commands[] = { |
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index afe3d427ddfa..04e31f86c10a 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. |
@@ -108,7 +108,7 @@ irqreturn_t uml_net_interrupt(int irq, void *dev_id) | |||
108 | 108 | ||
109 | out: | 109 | out: |
110 | spin_unlock(&lp->lock); | 110 | spin_unlock(&lp->lock); |
111 | return(IRQ_HANDLED); | 111 | return IRQ_HANDLED; |
112 | } | 112 | } |
113 | 113 | ||
114 | static int uml_net_open(struct net_device *dev) | 114 | static int uml_net_open(struct net_device *dev) |
@@ -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++; |
@@ -239,7 +239,7 @@ static int uml_net_set_mac(struct net_device *dev, void *addr) | |||
239 | set_ether_mac(dev, hwaddr->sa_data); | 239 | set_ether_mac(dev, hwaddr->sa_data); |
240 | spin_unlock_irq(&lp->lock); | 240 | spin_unlock_irq(&lp->lock); |
241 | 241 | ||
242 | return(0); | 242 | return 0; |
243 | } | 243 | } |
244 | 244 | ||
245 | static int uml_net_change_mtu(struct net_device *dev, int new_mtu) | 245 | static int uml_net_change_mtu(struct net_device *dev, int new_mtu) |
@@ -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); |
@@ -460,38 +460,36 @@ static struct uml_net *find_device(int n) | |||
460 | device = NULL; | 460 | device = NULL; |
461 | out: | 461 | out: |
462 | spin_unlock(&devices_lock); | 462 | spin_unlock(&devices_lock); |
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 { |
@@ -500,13 +498,11 @@ struct eth_init { | |||
500 | int index; | 498 | int index; |
501 | }; | 499 | }; |
502 | 500 | ||
503 | /* Filled in at boot time. Will need locking if the transports become | 501 | static DEFINE_SPINLOCK(transports_lock); |
504 | * modular. | 502 | static LIST_HEAD(transports); |
505 | */ | ||
506 | struct list_head transports = LIST_HEAD_INIT(transports); | ||
507 | 503 | ||
508 | /* Filled in during early boot */ | 504 | /* Filled in during early boot */ |
509 | struct list_head eth_cmd_line = LIST_HEAD_INIT(eth_cmd_line); | 505 | static LIST_HEAD(eth_cmd_line); |
510 | 506 | ||
511 | static int check_transport(struct transport *transport, char *eth, int n, | 507 | static int check_transport(struct transport *transport, char *eth, int n, |
512 | void **init_out, char **mac_out) | 508 | void **init_out, char **mac_out) |
@@ -515,23 +511,23 @@ static int check_transport(struct transport *transport, char *eth, int n, | |||
515 | 511 | ||
516 | len = strlen(transport->name); | 512 | len = strlen(transport->name); |
517 | if(strncmp(eth, transport->name, len)) | 513 | if(strncmp(eth, transport->name, len)) |
518 | return(0); | 514 | return 0; |
519 | 515 | ||
520 | eth += len; | 516 | eth += len; |
521 | if(*eth == ',') | 517 | if(*eth == ',') |
522 | eth++; | 518 | eth++; |
523 | else if(*eth != '\0') | 519 | else if(*eth != '\0') |
524 | return(0); | 520 | return 0; |
525 | 521 | ||
526 | *init_out = kmalloc(transport->setup_size, GFP_KERNEL); | 522 | *init_out = kmalloc(transport->setup_size, GFP_KERNEL); |
527 | if(*init_out == NULL) | 523 | if(*init_out == NULL) |
528 | return(1); | 524 | return 1; |
529 | 525 | ||
530 | if(!transport->setup(eth, mac_out, *init_out)){ | 526 | if(!transport->setup(eth, mac_out, *init_out)){ |
531 | kfree(*init_out); | 527 | kfree(*init_out); |
532 | *init_out = NULL; | 528 | *init_out = NULL; |
533 | } | 529 | } |
534 | return(1); | 530 | return 1; |
535 | } | 531 | } |
536 | 532 | ||
537 | void register_transport(struct transport *new) | 533 | void register_transport(struct transport *new) |
@@ -542,7 +538,10 @@ void register_transport(struct transport *new) | |||
542 | char *mac = NULL; | 538 | char *mac = NULL; |
543 | int match; | 539 | int match; |
544 | 540 | ||
541 | spin_lock(&transports_lock); | ||
542 | BUG_ON(!list_empty(&new->list)); | ||
545 | list_add(&new->list, &transports); | 543 | list_add(&new->list, &transports); |
544 | spin_unlock(&transports_lock); | ||
546 | 545 | ||
547 | list_for_each_safe(ele, next, ð_cmd_line){ | 546 | list_for_each_safe(ele, next, ð_cmd_line){ |
548 | eth = list_entry(ele, struct eth_init, list); | 547 | eth = list_entry(ele, struct eth_init, list); |
@@ -564,7 +563,9 @@ static int eth_setup_common(char *str, int index) | |||
564 | struct transport *transport; | 563 | struct transport *transport; |
565 | void *init; | 564 | void *init; |
566 | char *mac = NULL; | 565 | char *mac = NULL; |
566 | int found = 0; | ||
567 | 567 | ||
568 | spin_lock(&transports_lock); | ||
568 | list_for_each(ele, &transports){ | 569 | list_for_each(ele, &transports){ |
569 | transport = list_entry(ele, struct transport, list); | 570 | transport = list_entry(ele, struct transport, list); |
570 | if(!check_transport(transport, str, index, &init, &mac)) | 571 | if(!check_transport(transport, str, index, &init, &mac)) |
@@ -573,19 +574,26 @@ static int eth_setup_common(char *str, int index) | |||
573 | eth_configure(index, init, mac, transport); | 574 | eth_configure(index, init, mac, transport); |
574 | kfree(init); | 575 | kfree(init); |
575 | } | 576 | } |
576 | return(1); | 577 | found = 1; |
578 | break; | ||
577 | } | 579 | } |
578 | return(0); | 580 | |
581 | spin_unlock(&transports_lock); | ||
582 | return found; | ||
579 | } | 583 | } |
580 | 584 | ||
581 | static int eth_setup(char *str) | 585 | static int eth_setup(char *str) |
582 | { | 586 | { |
583 | struct eth_init *new; | 587 | struct eth_init *new; |
588 | char *error; | ||
584 | int n, err; | 589 | int n, err; |
585 | 590 | ||
586 | err = eth_parse(str, &n, &str); | 591 | err = eth_parse(str, &n, &str, &error); |
587 | if(err) | 592 | if(err){ |
593 | printk(KERN_ERR "eth_setup - Couldn't parse '%s' : %s\n", | ||
594 | str, error); | ||
588 | return 1; | 595 | return 1; |
596 | } | ||
589 | 597 | ||
590 | new = alloc_bootmem(sizeof(*new)); | 598 | new = alloc_bootmem(sizeof(*new)); |
591 | if (new == NULL){ | 599 | if (new == NULL){ |
@@ -607,38 +615,24 @@ __uml_help(eth_setup, | |||
607 | " Configure a network device.\n\n" | 615 | " Configure a network device.\n\n" |
608 | ); | 616 | ); |
609 | 617 | ||
610 | #if 0 | 618 | static int net_config(char *str, char **error_out) |
611 | static int eth_init(void) | ||
612 | { | ||
613 | struct list_head *ele, *next; | ||
614 | struct eth_init *eth; | ||
615 | |||
616 | list_for_each_safe(ele, next, ð_cmd_line){ | ||
617 | eth = list_entry(ele, struct eth_init, list); | ||
618 | |||
619 | if(eth_setup_common(eth->init, eth->index)) | ||
620 | list_del(ð->list); | ||
621 | } | ||
622 | |||
623 | return(1); | ||
624 | } | ||
625 | __initcall(eth_init); | ||
626 | #endif | ||
627 | |||
628 | static int net_config(char *str) | ||
629 | { | 619 | { |
630 | int n, err; | 620 | int n, err; |
631 | 621 | ||
632 | err = eth_parse(str, &n, &str); | 622 | err = eth_parse(str, &n, &str, error_out); |
633 | if(err) return(err); | 623 | if(err) |
624 | return err; | ||
634 | 625 | ||
626 | /* This string is broken up and the pieces used by the underlying | ||
627 | * driver. So, it is freed only if eth_setup_common fails. | ||
628 | */ | ||
635 | str = kstrdup(str, GFP_KERNEL); | 629 | str = kstrdup(str, GFP_KERNEL); |
636 | if(str == NULL){ | 630 | if(str == NULL){ |
637 | printk(KERN_ERR "net_config failed to strdup string\n"); | 631 | *error_out = "net_config failed to strdup string"; |
638 | return(-1); | 632 | return -ENOMEM; |
639 | } | 633 | } |
640 | err = !eth_setup_common(str, n); | 634 | err = !eth_setup_common(str, n); |
641 | if(err) | 635 | if(err) |
642 | kfree(str); | 636 | kfree(str); |
643 | return(err); | 637 | return(err); |
644 | } | 638 | } |
@@ -658,7 +652,7 @@ static int net_id(char **str, int *start_out, int *end_out) | |||
658 | return n; | 652 | return n; |
659 | } | 653 | } |
660 | 654 | ||
661 | static int net_remove(int n) | 655 | static int net_remove(int n, char **error_out) |
662 | { | 656 | { |
663 | struct uml_net *device; | 657 | struct uml_net *device; |
664 | struct net_device *dev; | 658 | struct net_device *dev; |
@@ -671,7 +665,7 @@ static int net_remove(int n) | |||
671 | dev = device->dev; | 665 | dev = device->dev; |
672 | lp = dev->priv; | 666 | lp = dev->priv; |
673 | if(lp->fd > 0) | 667 | if(lp->fd > 0) |
674 | return -EBUSY; | 668 | return -EBUSY; |
675 | if(lp->remove != NULL) (*lp->remove)(&lp->user); | 669 | if(lp->remove != NULL) (*lp->remove)(&lp->user); |
676 | unregister_netdev(dev); | 670 | unregister_netdev(dev); |
677 | platform_device_unregister(&device->pdev); | 671 | platform_device_unregister(&device->pdev); |
@@ -683,10 +677,11 @@ static int net_remove(int n) | |||
683 | } | 677 | } |
684 | 678 | ||
685 | static struct mc_device net_mc = { | 679 | static struct mc_device net_mc = { |
680 | .list = LIST_HEAD_INIT(net_mc.list), | ||
686 | .name = "eth", | 681 | .name = "eth", |
687 | .config = net_config, | 682 | .config = net_config, |
688 | .get_config = NULL, | 683 | .get_config = NULL, |
689 | .id = net_id, | 684 | .id = net_id, |
690 | .remove = net_remove, | 685 | .remove = net_remove, |
691 | }; | 686 | }; |
692 | 687 | ||
@@ -699,7 +694,8 @@ static int uml_inetaddr_event(struct notifier_block *this, unsigned long event, | |||
699 | void (*proc)(unsigned char *, unsigned char *, void *); | 694 | void (*proc)(unsigned char *, unsigned char *, void *); |
700 | unsigned char addr_buf[4], netmask_buf[4]; | 695 | unsigned char addr_buf[4], netmask_buf[4]; |
701 | 696 | ||
702 | if(dev->open != uml_net_open) return(NOTIFY_DONE); | 697 | if(dev->open != uml_net_open) |
698 | return NOTIFY_DONE; | ||
703 | 699 | ||
704 | lp = dev->priv; | 700 | lp = dev->priv; |
705 | 701 | ||
@@ -717,9 +713,10 @@ static int uml_inetaddr_event(struct notifier_block *this, unsigned long event, | |||
717 | memcpy(netmask_buf, &ifa->ifa_mask, sizeof(netmask_buf)); | 713 | memcpy(netmask_buf, &ifa->ifa_mask, sizeof(netmask_buf)); |
718 | (*proc)(addr_buf, netmask_buf, &lp->user); | 714 | (*proc)(addr_buf, netmask_buf, &lp->user); |
719 | } | 715 | } |
720 | return(NOTIFY_DONE); | 716 | return NOTIFY_DONE; |
721 | } | 717 | } |
722 | 718 | ||
719 | /* uml_net_init shouldn't be called twice on two CPUs at the same time */ | ||
723 | struct notifier_block uml_inetaddr_notifier = { | 720 | struct notifier_block uml_inetaddr_notifier = { |
724 | .notifier_call = uml_inetaddr_event, | 721 | .notifier_call = uml_inetaddr_event, |
725 | }; | 722 | }; |
@@ -727,7 +724,7 @@ struct notifier_block uml_inetaddr_notifier = { | |||
727 | static int uml_net_init(void) | 724 | static int uml_net_init(void) |
728 | { | 725 | { |
729 | struct list_head *ele; | 726 | struct list_head *ele; |
730 | struct uml_net_private *lp; | 727 | struct uml_net_private *lp; |
731 | struct in_device *ip; | 728 | struct in_device *ip; |
732 | struct in_ifaddr *in; | 729 | struct in_ifaddr *in; |
733 | 730 | ||
@@ -738,18 +735,21 @@ static int uml_net_init(void) | |||
738 | * didn't get a chance to run for them. This fakes it so that | 735 | * didn't get a chance to run for them. This fakes it so that |
739 | * addresses which have already been set up get handled properly. | 736 | * addresses which have already been set up get handled properly. |
740 | */ | 737 | */ |
738 | spin_lock(&opened_lock); | ||
741 | list_for_each(ele, &opened){ | 739 | list_for_each(ele, &opened){ |
742 | lp = list_entry(ele, struct uml_net_private, list); | 740 | lp = list_entry(ele, struct uml_net_private, list); |
743 | ip = lp->dev->ip_ptr; | 741 | ip = lp->dev->ip_ptr; |
744 | if(ip == NULL) continue; | 742 | if(ip == NULL) |
743 | continue; | ||
745 | in = ip->ifa_list; | 744 | in = ip->ifa_list; |
746 | while(in != NULL){ | 745 | while(in != NULL){ |
747 | uml_inetaddr_event(NULL, NETDEV_UP, in); | 746 | uml_inetaddr_event(NULL, NETDEV_UP, in); |
748 | in = in->ifa_next; | 747 | in = in->ifa_next; |
749 | } | 748 | } |
750 | } | 749 | } |
750 | spin_unlock(&opened_lock); | ||
751 | 751 | ||
752 | return(0); | 752 | return 0; |
753 | } | 753 | } |
754 | 754 | ||
755 | __initcall(uml_net_init); | 755 | __initcall(uml_net_init); |
@@ -759,13 +759,16 @@ static void close_devices(void) | |||
759 | struct list_head *ele; | 759 | struct list_head *ele; |
760 | struct uml_net_private *lp; | 760 | struct uml_net_private *lp; |
761 | 761 | ||
762 | spin_lock(&opened_lock); | ||
762 | list_for_each(ele, &opened){ | 763 | list_for_each(ele, &opened){ |
763 | lp = list_entry(ele, struct uml_net_private, list); | 764 | lp = list_entry(ele, struct uml_net_private, list); |
764 | free_irq(lp->dev->irq, lp->dev); | 765 | free_irq(lp->dev->irq, lp->dev); |
765 | if((lp->close != NULL) && (lp->fd >= 0)) | 766 | if((lp->close != NULL) && (lp->fd >= 0)) |
766 | (*lp->close)(lp->fd, &lp->user); | 767 | (*lp->close)(lp->fd, &lp->user); |
767 | if(lp->remove != NULL) (*lp->remove)(&lp->user); | 768 | if(lp->remove != NULL) |
769 | (*lp->remove)(&lp->user); | ||
768 | } | 770 | } |
771 | spin_unlock(&opened_lock); | ||
769 | } | 772 | } |
770 | 773 | ||
771 | __uml_exitcall(close_devices); | 774 | __uml_exitcall(close_devices); |
@@ -783,8 +786,8 @@ struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra) | |||
783 | return(skb); | 786 | return(skb); |
784 | } | 787 | } |
785 | 788 | ||
786 | void iter_addresses(void *d, void (*cb)(unsigned char *, unsigned char *, | 789 | void iter_addresses(void *d, void (*cb)(unsigned char *, unsigned char *, |
787 | void *), | 790 | void *), |
788 | void *arg) | 791 | void *arg) |
789 | { | 792 | { |
790 | struct net_device *dev = d; | 793 | struct net_device *dev = d; |
@@ -809,11 +812,11 @@ int dev_netmask(void *d, void *m) | |||
809 | struct in_ifaddr *in; | 812 | struct in_ifaddr *in; |
810 | __be32 *mask_out = m; | 813 | __be32 *mask_out = m; |
811 | 814 | ||
812 | if(ip == NULL) | 815 | if(ip == NULL) |
813 | return(1); | 816 | return(1); |
814 | 817 | ||
815 | in = ip->ifa_list; | 818 | in = ip->ifa_list; |
816 | if(in == NULL) | 819 | if(in == NULL) |
817 | return(1); | 820 | return(1); |
818 | 821 | ||
819 | *mask_out = in->ifa_mask; | 822 | *mask_out = in->ifa_mask; |
@@ -827,7 +830,7 @@ void *get_output_buffer(int *len_out) | |||
827 | ret = (void *) __get_free_pages(GFP_KERNEL, 0); | 830 | ret = (void *) __get_free_pages(GFP_KERNEL, 0); |
828 | if(ret) *len_out = PAGE_SIZE; | 831 | if(ret) *len_out = PAGE_SIZE; |
829 | else *len_out = 0; | 832 | else *len_out = 0; |
830 | return(ret); | 833 | return ret; |
831 | } | 834 | } |
832 | 835 | ||
833 | void free_output_buffer(void *buffer) | 836 | void free_output_buffer(void *buffer) |
@@ -835,7 +838,7 @@ void free_output_buffer(void *buffer) | |||
835 | free_pages((unsigned long) buffer, 0); | 838 | free_pages((unsigned long) buffer, 0); |
836 | } | 839 | } |
837 | 840 | ||
838 | int tap_setup_common(char *str, char *type, char **dev_name, char **mac_out, | 841 | int tap_setup_common(char *str, char *type, char **dev_name, char **mac_out, |
839 | char **gate_addr) | 842 | char **gate_addr) |
840 | { | 843 | { |
841 | char *remain; | 844 | char *remain; |
@@ -854,14 +857,3 @@ unsigned short eth_protocol(struct sk_buff *skb) | |||
854 | { | 857 | { |
855 | return(eth_type_trans(skb, skb->dev)); | 858 | return(eth_type_trans(skb, skb->dev)); |
856 | } | 859 | } |
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 | */ | ||
diff --git a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c index 6dfe632f1c14..1c8efd95c421 100644 --- a/arch/um/drivers/port_kern.c +++ b/arch/um/drivers/port_kern.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) | 2 | * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) |
3 | * Licensed under the GPL | 3 | * Licensed under the GPL |
4 | */ | 4 | */ |
@@ -55,9 +55,9 @@ static irqreturn_t pipe_interrupt(int irq, void *data) | |||
55 | fd = os_rcv_fd(conn->socket[0], &conn->helper_pid); | 55 | fd = os_rcv_fd(conn->socket[0], &conn->helper_pid); |
56 | if(fd < 0){ | 56 | if(fd < 0){ |
57 | if(fd == -EAGAIN) | 57 | if(fd == -EAGAIN) |
58 | return(IRQ_NONE); | 58 | return IRQ_NONE; |
59 | 59 | ||
60 | printk(KERN_ERR "pipe_interrupt : os_rcv_fd returned %d\n", | 60 | printk(KERN_ERR "pipe_interrupt : os_rcv_fd returned %d\n", |
61 | -fd); | 61 | -fd); |
62 | os_close_file(conn->fd); | 62 | os_close_file(conn->fd); |
63 | } | 63 | } |
@@ -68,7 +68,7 @@ static irqreturn_t pipe_interrupt(int irq, void *data) | |||
68 | list_add(&conn->list, &conn->port->connections); | 68 | list_add(&conn->list, &conn->port->connections); |
69 | 69 | ||
70 | complete(&conn->port->done); | 70 | complete(&conn->port->done); |
71 | return(IRQ_HANDLED); | 71 | return IRQ_HANDLED; |
72 | } | 72 | } |
73 | 73 | ||
74 | #define NO_WAITER_MSG \ | 74 | #define NO_WAITER_MSG \ |
@@ -97,14 +97,14 @@ static int port_accept(struct port_list *port) | |||
97 | "connection\n"); | 97 | "connection\n"); |
98 | goto out_close; | 98 | goto out_close; |
99 | } | 99 | } |
100 | *conn = ((struct connection) | 100 | *conn = ((struct connection) |
101 | { .list = LIST_HEAD_INIT(conn->list), | 101 | { .list = LIST_HEAD_INIT(conn->list), |
102 | .fd = fd, | 102 | .fd = fd, |
103 | .socket = { socket[0], socket[1] }, | 103 | .socket = { socket[0], socket[1] }, |
104 | .telnetd_pid = pid, | 104 | .telnetd_pid = pid, |
105 | .port = port }); | 105 | .port = port }); |
106 | 106 | ||
107 | if(um_request_irq(TELNETD_IRQ, socket[0], IRQ_READ, pipe_interrupt, | 107 | if(um_request_irq(TELNETD_IRQ, socket[0], IRQ_READ, pipe_interrupt, |
108 | IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM, | 108 | IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM, |
109 | "telnetd", conn)){ | 109 | "telnetd", conn)){ |
110 | printk(KERN_ERR "port_accept : failed to get IRQ for " | 110 | printk(KERN_ERR "port_accept : failed to get IRQ for " |
@@ -117,20 +117,20 @@ static int port_accept(struct port_list *port) | |||
117 | printk("No one waiting for port\n"); | 117 | printk("No one waiting for port\n"); |
118 | } | 118 | } |
119 | list_add(&conn->list, &port->pending); | 119 | list_add(&conn->list, &port->pending); |
120 | return(1); | 120 | return 1; |
121 | 121 | ||
122 | out_free: | 122 | out_free: |
123 | kfree(conn); | 123 | kfree(conn); |
124 | out_close: | 124 | out_close: |
125 | os_close_file(fd); | 125 | os_close_file(fd); |
126 | if(pid != -1) | 126 | if(pid != -1) |
127 | os_kill_process(pid, 1); | 127 | os_kill_process(pid, 1); |
128 | out: | 128 | out: |
129 | return(ret); | 129 | return ret; |
130 | } | 130 | } |
131 | 131 | ||
132 | DECLARE_MUTEX(ports_sem); | 132 | static DECLARE_MUTEX(ports_sem); |
133 | struct list_head ports = LIST_HEAD_INIT(ports); | 133 | static LIST_HEAD(ports); |
134 | 134 | ||
135 | void port_work_proc(struct work_struct *unused) | 135 | void port_work_proc(struct work_struct *unused) |
136 | { | 136 | { |
@@ -158,8 +158,8 @@ static irqreturn_t port_interrupt(int irq, void *data) | |||
158 | 158 | ||
159 | port->has_connection = 1; | 159 | port->has_connection = 1; |
160 | schedule_work(&port_work); | 160 | schedule_work(&port_work); |
161 | return(IRQ_HANDLED); | 161 | return IRQ_HANDLED; |
162 | } | 162 | } |
163 | 163 | ||
164 | void *port_data(int port_num) | 164 | void *port_data(int port_num) |
165 | { | 165 | { |
@@ -185,14 +185,14 @@ void *port_data(int port_num) | |||
185 | port_num, -fd); | 185 | port_num, -fd); |
186 | goto out_free; | 186 | goto out_free; |
187 | } | 187 | } |
188 | if(um_request_irq(ACCEPT_IRQ, fd, IRQ_READ, port_interrupt, | 188 | if(um_request_irq(ACCEPT_IRQ, fd, IRQ_READ, port_interrupt, |
189 | IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM, "port", | 189 | IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM, |
190 | port)){ | 190 | "port", port)){ |
191 | printk(KERN_ERR "Failed to get IRQ for port %d\n", port_num); | 191 | printk(KERN_ERR "Failed to get IRQ for port %d\n", port_num); |
192 | goto out_close; | 192 | goto out_close; |
193 | } | 193 | } |
194 | 194 | ||
195 | *port = ((struct port_list) | 195 | *port = ((struct port_list) |
196 | { .list = LIST_HEAD_INIT(port->list), | 196 | { .list = LIST_HEAD_INIT(port->list), |
197 | .wait_count = ATOMIC_INIT(0), | 197 | .wait_count = ATOMIC_INIT(0), |
198 | .has_connection = 0, | 198 | .has_connection = 0, |
@@ -222,7 +222,7 @@ void *port_data(int port_num) | |||
222 | os_close_file(fd); | 222 | os_close_file(fd); |
223 | out: | 223 | out: |
224 | up(&ports_sem); | 224 | up(&ports_sem); |
225 | return(dev); | 225 | return dev; |
226 | } | 226 | } |
227 | 227 | ||
228 | int port_wait(void *data) | 228 | int port_wait(void *data) |
@@ -232,15 +232,15 @@ int port_wait(void *data) | |||
232 | struct port_list *port = dev->port; | 232 | struct port_list *port = dev->port; |
233 | int fd; | 233 | int fd; |
234 | 234 | ||
235 | atomic_inc(&port->wait_count); | 235 | atomic_inc(&port->wait_count); |
236 | while(1){ | 236 | while(1){ |
237 | fd = -ERESTARTSYS; | 237 | fd = -ERESTARTSYS; |
238 | if(wait_for_completion_interruptible(&port->done)) | 238 | if(wait_for_completion_interruptible(&port->done)) |
239 | goto out; | 239 | goto out; |
240 | 240 | ||
241 | spin_lock(&port->lock); | 241 | spin_lock(&port->lock); |
242 | 242 | ||
243 | conn = list_entry(port->connections.next, struct connection, | 243 | conn = list_entry(port->connections.next, struct connection, |
244 | list); | 244 | list); |
245 | list_del(&conn->list); | 245 | list_del(&conn->list); |
246 | spin_unlock(&port->lock); | 246 | spin_unlock(&port->lock); |
@@ -248,12 +248,12 @@ int port_wait(void *data) | |||
248 | os_shutdown_socket(conn->socket[0], 1, 1); | 248 | os_shutdown_socket(conn->socket[0], 1, 1); |
249 | os_close_file(conn->socket[0]); | 249 | os_close_file(conn->socket[0]); |
250 | os_shutdown_socket(conn->socket[1], 1, 1); | 250 | os_shutdown_socket(conn->socket[1], 1, 1); |
251 | os_close_file(conn->socket[1]); | 251 | os_close_file(conn->socket[1]); |
252 | 252 | ||
253 | /* This is done here because freeing an IRQ can't be done | 253 | /* This is done here because freeing an IRQ can't be done |
254 | * within the IRQ handler. So, pipe_interrupt always ups | 254 | * within the IRQ handler. So, pipe_interrupt always ups |
255 | * the semaphore regardless of whether it got a successful | 255 | * the semaphore regardless of whether it got a successful |
256 | * connection. Then we loop here throwing out failed | 256 | * connection. Then we loop here throwing out failed |
257 | * connections until a good one is found. | 257 | * connections until a good one is found. |
258 | */ | 258 | */ |
259 | free_irq(TELNETD_IRQ, conn); | 259 | free_irq(TELNETD_IRQ, conn); |
diff --git a/arch/um/drivers/port_user.c b/arch/um/drivers/port_user.c index bc6afaf74c1a..80508023054f 100644 --- a/arch/um/drivers/port_user.c +++ b/arch/um/drivers/port_user.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) | 2 | * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) |
3 | * Licensed under the GPL | 3 | * Licensed under the GPL |
4 | */ | 4 | */ |
@@ -38,18 +38,18 @@ static void *port_init(char *str, int device, const struct chan_opts *opts) | |||
38 | if(*str != ':'){ | 38 | if(*str != ':'){ |
39 | printk("port_init : channel type 'port' must specify a " | 39 | printk("port_init : channel type 'port' must specify a " |
40 | "port number\n"); | 40 | "port number\n"); |
41 | return(NULL); | 41 | return NULL; |
42 | } | 42 | } |
43 | str++; | 43 | str++; |
44 | port = strtoul(str, &end, 0); | 44 | port = strtoul(str, &end, 0); |
45 | if((*end != '\0') || (end == str)){ | 45 | if((*end != '\0') || (end == str)){ |
46 | printk("port_init : couldn't parse port '%s'\n", str); | 46 | printk("port_init : couldn't parse port '%s'\n", str); |
47 | return(NULL); | 47 | return NULL; |
48 | } | 48 | } |
49 | 49 | ||
50 | kern_data = port_data(port); | 50 | kern_data = port_data(port); |
51 | if(kern_data == NULL) | 51 | if(kern_data == NULL) |
52 | return(NULL); | 52 | return NULL; |
53 | 53 | ||
54 | data = um_kmalloc(sizeof(*data)); | 54 | data = um_kmalloc(sizeof(*data)); |
55 | if(data == NULL) | 55 | if(data == NULL) |
@@ -59,10 +59,10 @@ static void *port_init(char *str, int device, const struct chan_opts *opts) | |||
59 | .kernel_data = kern_data }); | 59 | .kernel_data = kern_data }); |
60 | sprintf(data->dev, "%d", port); | 60 | sprintf(data->dev, "%d", port); |
61 | 61 | ||
62 | return(data); | 62 | return data; |
63 | err: | 63 | err: |
64 | port_kern_free(kern_data); | 64 | port_kern_free(kern_data); |
65 | return(NULL); | 65 | return NULL; |
66 | } | 66 | } |
67 | 67 | ||
68 | static void port_free(void *d) | 68 | static void port_free(void *d) |
@@ -83,14 +83,14 @@ static int port_open(int input, int output, int primary, void *d, | |||
83 | if((fd >= 0) && data->raw){ | 83 | if((fd >= 0) && data->raw){ |
84 | CATCH_EINTR(err = tcgetattr(fd, &data->tt)); | 84 | CATCH_EINTR(err = tcgetattr(fd, &data->tt)); |
85 | if(err) | 85 | if(err) |
86 | return(err); | 86 | return err; |
87 | 87 | ||
88 | err = raw(fd); | 88 | err = raw(fd); |
89 | if(err) | 89 | if(err) |
90 | return(err); | 90 | return err; |
91 | } | 91 | } |
92 | *dev_out = data->dev; | 92 | *dev_out = data->dev; |
93 | return(fd); | 93 | return fd; |
94 | } | 94 | } |
95 | 95 | ||
96 | static void port_close(int fd, void *d) | 96 | static void port_close(int fd, void *d) |
@@ -120,8 +120,8 @@ int port_listen_fd(int port) | |||
120 | int fd, err, arg; | 120 | int fd, err, arg; |
121 | 121 | ||
122 | fd = socket(PF_INET, SOCK_STREAM, 0); | 122 | fd = socket(PF_INET, SOCK_STREAM, 0); |
123 | if(fd == -1) | 123 | if(fd == -1) |
124 | return(-errno); | 124 | return -errno; |
125 | 125 | ||
126 | arg = 1; | 126 | arg = 1; |
127 | if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &arg, sizeof(arg)) < 0){ | 127 | if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &arg, sizeof(arg)) < 0){ |
@@ -136,7 +136,7 @@ int port_listen_fd(int port) | |||
136 | err = -errno; | 136 | err = -errno; |
137 | goto out; | 137 | goto out; |
138 | } | 138 | } |
139 | 139 | ||
140 | if(listen(fd, 1) < 0){ | 140 | if(listen(fd, 1) < 0){ |
141 | err = -errno; | 141 | err = -errno; |
142 | goto out; | 142 | goto out; |
@@ -146,10 +146,10 @@ int port_listen_fd(int port) | |||
146 | if(err < 0) | 146 | if(err < 0) |
147 | goto out; | 147 | goto out; |
148 | 148 | ||
149 | return(fd); | 149 | return fd; |
150 | out: | 150 | out: |
151 | os_close_file(fd); | 151 | os_close_file(fd); |
152 | return(err); | 152 | return err; |
153 | } | 153 | } |
154 | 154 | ||
155 | struct port_pre_exec_data { | 155 | struct port_pre_exec_data { |
@@ -173,13 +173,13 @@ void port_pre_exec(void *arg) | |||
173 | int port_connection(int fd, int *socket, int *pid_out) | 173 | int port_connection(int fd, int *socket, int *pid_out) |
174 | { | 174 | { |
175 | int new, err; | 175 | int new, err; |
176 | char *argv[] = { "/usr/sbin/in.telnetd", "-L", | 176 | char *argv[] = { "/usr/sbin/in.telnetd", "-L", |
177 | "/usr/lib/uml/port-helper", NULL }; | 177 | "/usr/lib/uml/port-helper", NULL }; |
178 | struct port_pre_exec_data data; | 178 | struct port_pre_exec_data data; |
179 | 179 | ||
180 | new = os_accept_connection(fd); | 180 | new = os_accept_connection(fd); |
181 | if(new < 0) | 181 | if(new < 0) |
182 | return(new); | 182 | return new; |
183 | 183 | ||
184 | err = os_pipe(socket, 0, 0); | 184 | err = os_pipe(socket, 0, 0); |
185 | if(err < 0) | 185 | if(err < 0) |
@@ -190,29 +190,18 @@ int port_connection(int fd, int *socket, int *pid_out) | |||
190 | .pipe_fd = socket[1] }); | 190 | .pipe_fd = socket[1] }); |
191 | 191 | ||
192 | err = run_helper(port_pre_exec, &data, argv, NULL); | 192 | err = run_helper(port_pre_exec, &data, argv, NULL); |
193 | if(err < 0) | 193 | if(err < 0) |
194 | goto out_shutdown; | 194 | goto out_shutdown; |
195 | 195 | ||
196 | *pid_out = err; | 196 | *pid_out = err; |
197 | return(new); | 197 | return new; |
198 | 198 | ||
199 | out_shutdown: | 199 | out_shutdown: |
200 | os_shutdown_socket(socket[0], 1, 1); | 200 | os_shutdown_socket(socket[0], 1, 1); |
201 | os_close_file(socket[0]); | 201 | os_close_file(socket[0]); |
202 | os_shutdown_socket(socket[1], 1, 1); | 202 | os_shutdown_socket(socket[1], 1, 1); |
203 | os_close_file(socket[1]); | 203 | os_close_file(socket[1]); |
204 | out_close: | 204 | out_close: |
205 | os_close_file(new); | 205 | os_close_file(new); |
206 | return(err); | 206 | return err; |
207 | } | 207 | } |
208 | |||
209 | /* | ||
210 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
211 | * Emacs will notice this stuff at the end of the file and automatically | ||
212 | * adjust the settings for this buffer only. This must remain at the end | ||
213 | * of the file. | ||
214 | * --------------------------------------------------------------------------- | ||
215 | * Local variables: | ||
216 | * c-file-style: "linux" | ||
217 | * End: | ||
218 | */ | ||
diff --git a/arch/um/drivers/random.c b/arch/um/drivers/random.c index 73b2bdd6d2d3..e942e836f995 100644 --- a/arch/um/drivers/random.c +++ b/arch/um/drivers/random.c | |||
@@ -78,6 +78,7 @@ static const struct file_operations rng_chrdev_ops = { | |||
78 | .read = rng_dev_read, | 78 | .read = rng_dev_read, |
79 | }; | 79 | }; |
80 | 80 | ||
81 | /* rng_init shouldn't be called more than once at boot time */ | ||
81 | static struct miscdevice rng_miscdev = { | 82 | static struct miscdevice rng_miscdev = { |
82 | RNG_MISCDEV_MINOR, | 83 | RNG_MISCDEV_MINOR, |
83 | RNG_MODULE_NAME, | 84 | RNG_MODULE_NAME, |
diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c index ed9c59082d0d..fc22b9bd9153 100644 --- a/arch/um/drivers/ssl.c +++ b/arch/um/drivers/ssl.c | |||
@@ -38,6 +38,7 @@ static void ssl_announce(char *dev_name, int dev) | |||
38 | dev_name); | 38 | dev_name); |
39 | } | 39 | } |
40 | 40 | ||
41 | /* Almost const, except that xterm_title may be changed in an initcall */ | ||
41 | static struct chan_opts opts = { | 42 | static struct chan_opts opts = { |
42 | .announce = ssl_announce, | 43 | .announce = ssl_announce, |
43 | .xterm_title = "Serial Line #%d", | 44 | .xterm_title = "Serial Line #%d", |
@@ -46,10 +47,12 @@ static struct chan_opts opts = { | |||
46 | .in_kernel = 1, | 47 | .in_kernel = 1, |
47 | }; | 48 | }; |
48 | 49 | ||
49 | static int ssl_config(char *str); | 50 | static int ssl_config(char *str, char **error_out); |
50 | static int ssl_get_config(char *dev, char *str, int size, char **error_out); | 51 | static int ssl_get_config(char *dev, char *str, int size, char **error_out); |
51 | static int ssl_remove(int n); | 52 | static int ssl_remove(int n, char **error_out); |
52 | 53 | ||
54 | |||
55 | /* Const, except for .mc.list */ | ||
53 | static struct line_driver driver = { | 56 | static struct line_driver driver = { |
54 | .name = "UML serial line", | 57 | .name = "UML serial line", |
55 | .device_name = "ttyS", | 58 | .device_name = "ttyS", |
@@ -61,9 +64,8 @@ static struct line_driver driver = { | |||
61 | .read_irq_name = "ssl", | 64 | .read_irq_name = "ssl", |
62 | .write_irq = SSL_WRITE_IRQ, | 65 | .write_irq = SSL_WRITE_IRQ, |
63 | .write_irq_name = "ssl-write", | 66 | .write_irq_name = "ssl-write", |
64 | .symlink_from = "serial", | ||
65 | .symlink_to = "tts", | ||
66 | .mc = { | 67 | .mc = { |
68 | .list = LIST_HEAD_INIT(driver.mc.list), | ||
67 | .name = "ssl", | 69 | .name = "ssl", |
68 | .config = ssl_config, | 70 | .config = ssl_config, |
69 | .get_config = ssl_get_config, | 71 | .get_config = ssl_get_config, |
@@ -72,17 +74,16 @@ static struct line_driver driver = { | |||
72 | }, | 74 | }, |
73 | }; | 75 | }; |
74 | 76 | ||
75 | /* The array is initialized by line_init, which is an initcall. The | 77 | /* The array is initialized by line_init, at initcall time. The |
76 | * individual elements are protected by individual semaphores. | 78 | * elements are locked individually as needed. |
77 | */ | 79 | */ |
78 | static struct line serial_lines[NR_PORTS] = | 80 | static struct line serial_lines[NR_PORTS] = |
79 | { [0 ... NR_PORTS - 1] = LINE_INIT(CONFIG_SSL_CHAN, &driver) }; | 81 | { [0 ... NR_PORTS - 1] = LINE_INIT(CONFIG_SSL_CHAN, &driver) }; |
80 | 82 | ||
81 | static struct lines lines = LINES_INIT(NR_PORTS); | 83 | static int ssl_config(char *str, char **error_out) |
82 | |||
83 | static int ssl_config(char *str) | ||
84 | { | 84 | { |
85 | return line_config(serial_lines, ARRAY_SIZE(serial_lines), str, &opts); | 85 | return line_config(serial_lines, ARRAY_SIZE(serial_lines), str, &opts, |
86 | error_out); | ||
86 | } | 87 | } |
87 | 88 | ||
88 | static int ssl_get_config(char *dev, char *str, int size, char **error_out) | 89 | static int ssl_get_config(char *dev, char *str, int size, char **error_out) |
@@ -91,9 +92,10 @@ static int ssl_get_config(char *dev, char *str, int size, char **error_out) | |||
91 | size, error_out); | 92 | size, error_out); |
92 | } | 93 | } |
93 | 94 | ||
94 | static int ssl_remove(int n) | 95 | static int ssl_remove(int n, char **error_out) |
95 | { | 96 | { |
96 | return line_remove(serial_lines, ARRAY_SIZE(serial_lines), n); | 97 | return line_remove(serial_lines, ARRAY_SIZE(serial_lines), n, |
98 | error_out); | ||
97 | } | 99 | } |
98 | 100 | ||
99 | static int ssl_open(struct tty_struct *tty, struct file *filp) | 101 | static int ssl_open(struct tty_struct *tty, struct file *filp) |
@@ -168,9 +170,10 @@ static int ssl_console_setup(struct console *co, char *options) | |||
168 | { | 170 | { |
169 | struct line *line = &serial_lines[co->index]; | 171 | struct line *line = &serial_lines[co->index]; |
170 | 172 | ||
171 | return console_open_chan(line, co, &opts); | 173 | return console_open_chan(line, co); |
172 | } | 174 | } |
173 | 175 | ||
176 | /* No locking for register_console call - relies on single-threaded initcalls */ | ||
174 | static struct console ssl_cons = { | 177 | static struct console ssl_cons = { |
175 | .name = "ttyS", | 178 | .name = "ttyS", |
176 | .write = ssl_console_write, | 179 | .write = ssl_console_write, |
@@ -186,9 +189,8 @@ static int ssl_init(void) | |||
186 | 189 | ||
187 | printk(KERN_INFO "Initializing software serial port version %d\n", | 190 | printk(KERN_INFO "Initializing software serial port version %d\n", |
188 | ssl_version); | 191 | ssl_version); |
189 | ssl_driver = line_register_devfs(&lines, &driver, &ssl_ops, | 192 | ssl_driver = register_lines(&driver, &ssl_ops, serial_lines, |
190 | serial_lines, | 193 | ARRAY_SIZE(serial_lines)); |
191 | ARRAY_SIZE(serial_lines)); | ||
192 | 194 | ||
193 | lines_init(serial_lines, ARRAY_SIZE(serial_lines), &opts); | 195 | lines_init(serial_lines, ARRAY_SIZE(serial_lines), &opts); |
194 | 196 | ||
@@ -212,7 +214,15 @@ __uml_exitcall(ssl_exit); | |||
212 | 214 | ||
213 | static int ssl_chan_setup(char *str) | 215 | static int ssl_chan_setup(char *str) |
214 | { | 216 | { |
215 | return line_setup(serial_lines, ARRAY_SIZE(serial_lines), str); | 217 | char *error; |
218 | int ret; | ||
219 | |||
220 | ret = line_setup(serial_lines, ARRAY_SIZE(serial_lines), str, &error); | ||
221 | if(ret < 0) | ||
222 | printk(KERN_ERR "Failed to set up serial line with " | ||
223 | "configuration string \"%s\" : %s\n", str, error); | ||
224 | |||
225 | return 1; | ||
216 | } | 226 | } |
217 | 227 | ||
218 | __setup("ssl", ssl_chan_setup); | 228 | __setup("ssl", ssl_chan_setup); |
diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c index 7a4897e27f42..7ff0b0fc37e7 100644 --- a/arch/um/drivers/stdio_console.c +++ b/arch/um/drivers/stdio_console.c | |||
@@ -30,8 +30,6 @@ | |||
30 | 30 | ||
31 | #define MAX_TTYS (16) | 31 | #define MAX_TTYS (16) |
32 | 32 | ||
33 | /* ----------------------------------------------------------------------------- */ | ||
34 | |||
35 | /* Referenced only by tty_driver below - presumably it's locked correctly | 33 | /* Referenced only by tty_driver below - presumably it's locked correctly |
36 | * by the tty driver. | 34 | * by the tty driver. |
37 | */ | 35 | */ |
@@ -44,6 +42,7 @@ void stdio_announce(char *dev_name, int dev) | |||
44 | dev_name); | 42 | dev_name); |
45 | } | 43 | } |
46 | 44 | ||
45 | /* Almost const, except that xterm_title may be changed in an initcall */ | ||
47 | static struct chan_opts opts = { | 46 | static struct chan_opts opts = { |
48 | .announce = stdio_announce, | 47 | .announce = stdio_announce, |
49 | .xterm_title = "Virtual Console #%d", | 48 | .xterm_title = "Virtual Console #%d", |
@@ -52,10 +51,12 @@ static struct chan_opts opts = { | |||
52 | .in_kernel = 1, | 51 | .in_kernel = 1, |
53 | }; | 52 | }; |
54 | 53 | ||
55 | static int con_config(char *str); | 54 | static int con_config(char *str, char **error_out); |
56 | static int con_get_config(char *dev, char *str, int size, char **error_out); | 55 | static int con_get_config(char *dev, char *str, int size, char **error_out); |
57 | static int con_remove(int n); | 56 | static int con_remove(int n, char **con_remove); |
57 | |||
58 | 58 | ||
59 | /* Const, except for .mc.list */ | ||
59 | static struct line_driver driver = { | 60 | static struct line_driver driver = { |
60 | .name = "UML console", | 61 | .name = "UML console", |
61 | .device_name = "tty", | 62 | .device_name = "tty", |
@@ -67,9 +68,8 @@ static struct line_driver driver = { | |||
67 | .read_irq_name = "console", | 68 | .read_irq_name = "console", |
68 | .write_irq = CONSOLE_WRITE_IRQ, | 69 | .write_irq = CONSOLE_WRITE_IRQ, |
69 | .write_irq_name = "console-write", | 70 | .write_irq_name = "console-write", |
70 | .symlink_from = "ttys", | ||
71 | .symlink_to = "vc", | ||
72 | .mc = { | 71 | .mc = { |
72 | .list = LIST_HEAD_INIT(driver.mc.list), | ||
73 | .name = "con", | 73 | .name = "con", |
74 | .config = con_config, | 74 | .config = con_config, |
75 | .get_config = con_get_config, | 75 | .get_config = con_get_config, |
@@ -78,18 +78,16 @@ static struct line_driver driver = { | |||
78 | }, | 78 | }, |
79 | }; | 79 | }; |
80 | 80 | ||
81 | static struct lines console_lines = LINES_INIT(MAX_TTYS); | 81 | /* The array is initialized by line_init, at initcall time. The |
82 | 82 | * elements are locked individually as needed. | |
83 | /* The array is initialized by line_init, which is an initcall. The | ||
84 | * individual elements are protected by individual semaphores. | ||
85 | */ | 83 | */ |
86 | struct line vts[MAX_TTYS] = { LINE_INIT(CONFIG_CON_ZERO_CHAN, &driver), | 84 | static struct line vts[MAX_TTYS] = { LINE_INIT(CONFIG_CON_ZERO_CHAN, &driver), |
87 | [ 1 ... MAX_TTYS - 1 ] = | 85 | [ 1 ... MAX_TTYS - 1 ] = |
88 | LINE_INIT(CONFIG_CON_CHAN, &driver) }; | 86 | LINE_INIT(CONFIG_CON_CHAN, &driver) }; |
89 | 87 | ||
90 | static int con_config(char *str) | 88 | static int con_config(char *str, char **error_out) |
91 | { | 89 | { |
92 | return line_config(vts, ARRAY_SIZE(vts), str, &opts); | 90 | return line_config(vts, ARRAY_SIZE(vts), str, &opts, error_out); |
93 | } | 91 | } |
94 | 92 | ||
95 | static int con_get_config(char *dev, char *str, int size, char **error_out) | 93 | static int con_get_config(char *dev, char *str, int size, char **error_out) |
@@ -97,9 +95,9 @@ static int con_get_config(char *dev, char *str, int size, char **error_out) | |||
97 | return line_get_config(dev, vts, ARRAY_SIZE(vts), str, size, error_out); | 95 | return line_get_config(dev, vts, ARRAY_SIZE(vts), str, size, error_out); |
98 | } | 96 | } |
99 | 97 | ||
100 | static int con_remove(int n) | 98 | static int con_remove(int n, char **error_out) |
101 | { | 99 | { |
102 | return line_remove(vts, ARRAY_SIZE(vts), n); | 100 | return line_remove(vts, ARRAY_SIZE(vts), n, error_out); |
103 | } | 101 | } |
104 | 102 | ||
105 | static int con_open(struct tty_struct *tty, struct file *filp) | 103 | static int con_open(struct tty_struct *tty, struct file *filp) |
@@ -146,9 +144,10 @@ static int uml_console_setup(struct console *co, char *options) | |||
146 | { | 144 | { |
147 | struct line *line = &vts[co->index]; | 145 | struct line *line = &vts[co->index]; |
148 | 146 | ||
149 | return console_open_chan(line, co, &opts); | 147 | return console_open_chan(line, co); |
150 | } | 148 | } |
151 | 149 | ||
150 | /* No locking for register_console call - relies on single-threaded initcalls */ | ||
152 | static struct console stdiocons = { | 151 | static struct console stdiocons = { |
153 | .name = "tty", | 152 | .name = "tty", |
154 | .write = uml_console_write, | 153 | .write = uml_console_write, |
@@ -156,16 +155,14 @@ static struct console stdiocons = { | |||
156 | .setup = uml_console_setup, | 155 | .setup = uml_console_setup, |
157 | .flags = CON_PRINTBUFFER, | 156 | .flags = CON_PRINTBUFFER, |
158 | .index = -1, | 157 | .index = -1, |
159 | .data = &vts, | ||
160 | }; | 158 | }; |
161 | 159 | ||
162 | int stdio_init(void) | 160 | int stdio_init(void) |
163 | { | 161 | { |
164 | char *new_title; | 162 | char *new_title; |
165 | 163 | ||
166 | console_driver = line_register_devfs(&console_lines, &driver, | 164 | console_driver = register_lines(&driver, &console_ops, vts, |
167 | &console_ops, vts, | 165 | ARRAY_SIZE(vts)); |
168 | ARRAY_SIZE(vts)); | ||
169 | if (console_driver == NULL) | 166 | if (console_driver == NULL) |
170 | return -1; | 167 | return -1; |
171 | printk(KERN_INFO "Initialized stdio console driver\n"); | 168 | printk(KERN_INFO "Initialized stdio console driver\n"); |
@@ -192,7 +189,15 @@ __uml_exitcall(console_exit); | |||
192 | 189 | ||
193 | static int console_chan_setup(char *str) | 190 | static int console_chan_setup(char *str) |
194 | { | 191 | { |
195 | return line_setup(vts, ARRAY_SIZE(vts), str); | 192 | char *error; |
193 | int ret; | ||
194 | |||
195 | ret = line_setup(vts, ARRAY_SIZE(vts), str, &error); | ||
196 | if(ret < 0) | ||
197 | printk(KERN_ERR "Failed to set up console with " | ||
198 | "configuration string \"%s\" : %s\n", str, error); | ||
199 | |||
200 | return 1; | ||
196 | } | 201 | } |
197 | __setup("con", console_chan_setup); | 202 | __setup("con", console_chan_setup); |
198 | __channel_help(console_chan_setup, "con"); | 203 | __channel_help(console_chan_setup, "con"); |
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 49c047b75cc5..f98d26e51381 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c | |||
@@ -56,6 +56,7 @@ | |||
56 | enum ubd_req { UBD_READ, UBD_WRITE }; | 56 | enum ubd_req { UBD_READ, UBD_WRITE }; |
57 | 57 | ||
58 | struct io_thread_req { | 58 | struct io_thread_req { |
59 | struct request *req; | ||
59 | enum ubd_req op; | 60 | enum ubd_req op; |
60 | int fds[2]; | 61 | int fds[2]; |
61 | unsigned long offsets[2]; | 62 | unsigned long offsets[2]; |
@@ -106,10 +107,6 @@ static inline void ubd_set_bit(__u64 bit, unsigned char *data) | |||
106 | 107 | ||
107 | #define DRIVER_NAME "uml-blkdev" | 108 | #define DRIVER_NAME "uml-blkdev" |
108 | 109 | ||
109 | /* Can be taken in interrupt context, and is passed to the block layer to lock | ||
110 | * the request queue. Kernel side code knows that. */ | ||
111 | static DEFINE_SPINLOCK(ubd_io_lock); | ||
112 | |||
113 | static DEFINE_MUTEX(ubd_lock); | 110 | static DEFINE_MUTEX(ubd_lock); |
114 | 111 | ||
115 | /* XXX - this made sense in 2.4 days, now it's only used as a boolean, and | 112 | /* XXX - this made sense in 2.4 days, now it's only used as a boolean, and |
@@ -132,12 +129,8 @@ static struct block_device_operations ubd_blops = { | |||
132 | .getgeo = ubd_getgeo, | 129 | .getgeo = ubd_getgeo, |
133 | }; | 130 | }; |
134 | 131 | ||
135 | /* Protected by the queue_lock */ | ||
136 | static request_queue_t *ubd_queue; | ||
137 | |||
138 | /* Protected by ubd_lock */ | 132 | /* Protected by ubd_lock */ |
139 | static int fake_major = MAJOR_NR; | 133 | static int fake_major = MAJOR_NR; |
140 | |||
141 | static struct gendisk *ubd_gendisk[MAX_DEV]; | 134 | static struct gendisk *ubd_gendisk[MAX_DEV]; |
142 | static struct gendisk *fake_gendisk[MAX_DEV]; | 135 | static struct gendisk *fake_gendisk[MAX_DEV]; |
143 | 136 | ||
@@ -148,10 +141,6 @@ static struct gendisk *fake_gendisk[MAX_DEV]; | |||
148 | #define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 0, .c = 0, \ | 141 | #define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 0, .c = 0, \ |
149 | .cl = 1 }) | 142 | .cl = 1 }) |
150 | #endif | 143 | #endif |
151 | |||
152 | /* Not protected - changed only in ubd_setup_common and then only to | ||
153 | * to enable O_SYNC. | ||
154 | */ | ||
155 | static struct openflags global_openflags = OPEN_FLAGS; | 144 | static struct openflags global_openflags = OPEN_FLAGS; |
156 | 145 | ||
157 | struct cow { | 146 | struct cow { |
@@ -178,6 +167,8 @@ struct ubd { | |||
178 | unsigned no_cow:1; | 167 | unsigned no_cow:1; |
179 | struct cow cow; | 168 | struct cow cow; |
180 | struct platform_device pdev; | 169 | struct platform_device pdev; |
170 | struct request_queue *queue; | ||
171 | spinlock_t lock; | ||
181 | }; | 172 | }; |
182 | 173 | ||
183 | #define DEFAULT_COW { \ | 174 | #define DEFAULT_COW { \ |
@@ -198,8 +189,10 @@ struct ubd { | |||
198 | .no_cow = 0, \ | 189 | .no_cow = 0, \ |
199 | .shared = 0, \ | 190 | .shared = 0, \ |
200 | .cow = DEFAULT_COW, \ | 191 | .cow = DEFAULT_COW, \ |
192 | .lock = SPIN_LOCK_UNLOCKED, \ | ||
201 | } | 193 | } |
202 | 194 | ||
195 | /* Protected by ubd_lock */ | ||
203 | struct ubd ubd_devs[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD }; | 196 | struct ubd ubd_devs[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD }; |
204 | 197 | ||
205 | /* Only changed by fake_ide_setup which is a setup */ | 198 | /* Only changed by fake_ide_setup which is a setup */ |
@@ -242,7 +235,6 @@ static void make_ide_entries(char *dev_name) | |||
242 | 235 | ||
243 | ent = create_proc_entry("media", S_IFREG|S_IRUGO, dir); | 236 | ent = create_proc_entry("media", S_IFREG|S_IRUGO, dir); |
244 | if(!ent) return; | 237 | if(!ent) return; |
245 | ent->nlink = 1; | ||
246 | ent->data = NULL; | 238 | ent->data = NULL; |
247 | ent->read_proc = proc_ide_read_media; | 239 | ent->read_proc = proc_ide_read_media; |
248 | ent->write_proc = NULL; | 240 | ent->write_proc = NULL; |
@@ -286,12 +278,12 @@ static int parse_unit(char **ptr) | |||
286 | * otherwise, the str pointer is used (and owned) inside ubd_devs array, so it | 278 | * otherwise, the str pointer is used (and owned) inside ubd_devs array, so it |
287 | * should not be freed on exit. | 279 | * should not be freed on exit. |
288 | */ | 280 | */ |
289 | static int ubd_setup_common(char *str, int *index_out) | 281 | static int ubd_setup_common(char *str, int *index_out, char **error_out) |
290 | { | 282 | { |
291 | struct ubd *ubd_dev; | 283 | struct ubd *ubd_dev; |
292 | struct openflags flags = global_openflags; | 284 | struct openflags flags = global_openflags; |
293 | char *backing_file; | 285 | char *backing_file; |
294 | int n, err, i; | 286 | int n, err = 0, i; |
295 | 287 | ||
296 | if(index_out) *index_out = -1; | 288 | if(index_out) *index_out = -1; |
297 | n = *str; | 289 | n = *str; |
@@ -302,56 +294,55 @@ static int ubd_setup_common(char *str, int *index_out) | |||
302 | str++; | 294 | str++; |
303 | if(!strcmp(str, "sync")){ | 295 | if(!strcmp(str, "sync")){ |
304 | global_openflags = of_sync(global_openflags); | 296 | global_openflags = of_sync(global_openflags); |
305 | return(0); | 297 | goto out1; |
306 | } | 298 | } |
299 | |||
300 | err = -EINVAL; | ||
307 | major = simple_strtoul(str, &end, 0); | 301 | major = simple_strtoul(str, &end, 0); |
308 | if((*end != '\0') || (end == str)){ | 302 | if((*end != '\0') || (end == str)){ |
309 | printk(KERN_ERR | 303 | *error_out = "Didn't parse major number"; |
310 | "ubd_setup : didn't parse major number\n"); | 304 | goto out1; |
311 | return(1); | ||
312 | } | 305 | } |
313 | 306 | ||
314 | err = 1; | 307 | mutex_lock(&ubd_lock); |
315 | mutex_lock(&ubd_lock); | 308 | if(fake_major != MAJOR_NR){ |
316 | if(fake_major != MAJOR_NR){ | 309 | *error_out = "Can't assign a fake major twice"; |
317 | printk(KERN_ERR "Can't assign a fake major twice\n"); | 310 | goto out1; |
318 | goto out1; | 311 | } |
319 | } | ||
320 | 312 | ||
321 | fake_major = major; | 313 | fake_major = major; |
322 | 314 | ||
323 | printk(KERN_INFO "Setting extra ubd major number to %d\n", | 315 | printk(KERN_INFO "Setting extra ubd major number to %d\n", |
324 | major); | 316 | major); |
325 | err = 0; | 317 | err = 0; |
326 | out1: | 318 | out1: |
327 | mutex_unlock(&ubd_lock); | 319 | mutex_unlock(&ubd_lock); |
328 | return(err); | 320 | return err; |
329 | } | 321 | } |
330 | 322 | ||
331 | n = parse_unit(&str); | 323 | n = parse_unit(&str); |
332 | if(n < 0){ | 324 | if(n < 0){ |
333 | printk(KERN_ERR "ubd_setup : couldn't parse unit number " | 325 | *error_out = "Couldn't parse device number"; |
334 | "'%s'\n", str); | 326 | return -EINVAL; |
335 | return(1); | ||
336 | } | 327 | } |
337 | if(n >= MAX_DEV){ | 328 | if(n >= MAX_DEV){ |
338 | printk(KERN_ERR "ubd_setup : index %d out of range " | 329 | *error_out = "Device number out of range"; |
339 | "(%d devices, from 0 to %d)\n", n, MAX_DEV, MAX_DEV - 1); | 330 | return 1; |
340 | return(1); | ||
341 | } | 331 | } |
342 | 332 | ||
343 | err = 1; | 333 | err = -EBUSY; |
344 | mutex_lock(&ubd_lock); | 334 | mutex_lock(&ubd_lock); |
345 | 335 | ||
346 | ubd_dev = &ubd_devs[n]; | 336 | ubd_dev = &ubd_devs[n]; |
347 | if(ubd_dev->file != NULL){ | 337 | if(ubd_dev->file != NULL){ |
348 | printk(KERN_ERR "ubd_setup : device already configured\n"); | 338 | *error_out = "Device is already configured"; |
349 | goto out; | 339 | goto out; |
350 | } | 340 | } |
351 | 341 | ||
352 | if (index_out) | 342 | if (index_out) |
353 | *index_out = n; | 343 | *index_out = n; |
354 | 344 | ||
345 | err = -EINVAL; | ||
355 | for (i = 0; i < sizeof("rscd="); i++) { | 346 | for (i = 0; i < sizeof("rscd="); i++) { |
356 | switch (*str) { | 347 | switch (*str) { |
357 | case 'r': | 348 | case 'r': |
@@ -370,47 +361,54 @@ static int ubd_setup_common(char *str, int *index_out) | |||
370 | str++; | 361 | str++; |
371 | goto break_loop; | 362 | goto break_loop; |
372 | default: | 363 | default: |
373 | printk(KERN_ERR "ubd_setup : Expected '=' or flag letter (r, s, c, or d)\n"); | 364 | *error_out = "Expected '=' or flag letter " |
365 | "(r, s, c, or d)"; | ||
374 | goto out; | 366 | goto out; |
375 | } | 367 | } |
376 | str++; | 368 | str++; |
377 | } | 369 | } |
378 | 370 | ||
379 | if (*str == '=') | 371 | if (*str == '=') |
380 | printk(KERN_ERR "ubd_setup : Too many flags specified\n"); | 372 | *error_out = "Too many flags specified"; |
381 | else | 373 | else |
382 | printk(KERN_ERR "ubd_setup : Expected '='\n"); | 374 | *error_out = "Missing '='"; |
383 | goto out; | 375 | goto out; |
384 | 376 | ||
385 | break_loop: | 377 | break_loop: |
386 | err = 0; | ||
387 | backing_file = strchr(str, ','); | 378 | backing_file = strchr(str, ','); |
388 | 379 | ||
389 | if (!backing_file) { | 380 | if (backing_file == NULL) |
390 | backing_file = strchr(str, ':'); | 381 | backing_file = strchr(str, ':'); |
391 | } | ||
392 | 382 | ||
393 | if(backing_file){ | 383 | if(backing_file != NULL){ |
394 | if(ubd_dev->no_cow) | 384 | if(ubd_dev->no_cow){ |
395 | printk(KERN_ERR "Can't specify both 'd' and a " | 385 | *error_out = "Can't specify both 'd' and a cow file"; |
396 | "cow file\n"); | 386 | goto out; |
387 | } | ||
397 | else { | 388 | else { |
398 | *backing_file = '\0'; | 389 | *backing_file = '\0'; |
399 | backing_file++; | 390 | backing_file++; |
400 | } | 391 | } |
401 | } | 392 | } |
393 | err = 0; | ||
402 | ubd_dev->file = str; | 394 | ubd_dev->file = str; |
403 | ubd_dev->cow.file = backing_file; | 395 | ubd_dev->cow.file = backing_file; |
404 | ubd_dev->boot_openflags = flags; | 396 | ubd_dev->boot_openflags = flags; |
405 | out: | 397 | out: |
406 | mutex_unlock(&ubd_lock); | 398 | mutex_unlock(&ubd_lock); |
407 | return(err); | 399 | return err; |
408 | } | 400 | } |
409 | 401 | ||
410 | static int ubd_setup(char *str) | 402 | static int ubd_setup(char *str) |
411 | { | 403 | { |
412 | ubd_setup_common(str, NULL); | 404 | char *error; |
413 | return(1); | 405 | int err; |
406 | |||
407 | err = ubd_setup_common(str, NULL, &error); | ||
408 | if(err) | ||
409 | printk(KERN_ERR "Failed to initialize device with \"%s\" : " | ||
410 | "%s\n", str, error); | ||
411 | return 1; | ||
414 | } | 412 | } |
415 | 413 | ||
416 | __setup("ubd", ubd_setup); | 414 | __setup("ubd", ubd_setup); |
@@ -422,7 +420,7 @@ __uml_help(ubd_setup, | |||
422 | " use either a ':' or a ',': the first one allows writing things like;\n" | 420 | " use either a ':' or a ',': the first one allows writing things like;\n" |
423 | " ubd0=~/Uml/root_cow:~/Uml/root_backing_file\n" | 421 | " ubd0=~/Uml/root_cow:~/Uml/root_backing_file\n" |
424 | " while with a ',' the shell would not expand the 2nd '~'.\n" | 422 | " while with a ',' the shell would not expand the 2nd '~'.\n" |
425 | " When using only one filename, UML will detect whether to thread it like\n" | 423 | " When using only one filename, UML will detect whether to treat it like\n" |
426 | " a COW file or a backing file. To override this detection, add the 'd'\n" | 424 | " a COW file or a backing file. To override this detection, add the 'd'\n" |
427 | " flag:\n" | 425 | " flag:\n" |
428 | " ubd0d=BackingFile\n" | 426 | " ubd0d=BackingFile\n" |
@@ -471,12 +469,6 @@ static void do_ubd_request(request_queue_t * q); | |||
471 | /* Only changed by ubd_init, which is an initcall. */ | 469 | /* Only changed by ubd_init, which is an initcall. */ |
472 | int thread_fd = -1; | 470 | int thread_fd = -1; |
473 | 471 | ||
474 | /* Changed by ubd_handler, which is serialized because interrupts only | ||
475 | * happen on CPU 0. | ||
476 | * XXX: currently unused. | ||
477 | */ | ||
478 | static int intr_count = 0; | ||
479 | |||
480 | /* call ubd_finish if you need to serialize */ | 472 | /* call ubd_finish if you need to serialize */ |
481 | static void __ubd_finish(struct request *req, int error) | 473 | static void __ubd_finish(struct request *req, int error) |
482 | { | 474 | { |
@@ -499,36 +491,38 @@ static void __ubd_finish(struct request *req, int error) | |||
499 | * spin_lock_irq()/spin_lock_irqsave() */ | 491 | * spin_lock_irq()/spin_lock_irqsave() */ |
500 | static inline void ubd_finish(struct request *req, int error) | 492 | static inline void ubd_finish(struct request *req, int error) |
501 | { | 493 | { |
502 | spin_lock(&ubd_io_lock); | 494 | struct ubd *dev = req->rq_disk->private_data; |
495 | |||
496 | spin_lock(&dev->lock); | ||
503 | __ubd_finish(req, error); | 497 | __ubd_finish(req, error); |
504 | spin_unlock(&ubd_io_lock); | 498 | spin_unlock(&dev->lock); |
505 | } | 499 | } |
506 | 500 | ||
507 | /* XXX - move this inside ubd_intr. */ | 501 | /* XXX - move this inside ubd_intr. */ |
508 | /* Called without ubd_io_lock held, and only in interrupt context. */ | 502 | /* Called without dev->lock held, and only in interrupt context. */ |
509 | static void ubd_handler(void) | 503 | static void ubd_handler(void) |
510 | { | 504 | { |
511 | struct io_thread_req req; | 505 | struct io_thread_req req; |
512 | struct request *rq = elv_next_request(ubd_queue); | 506 | struct request *rq; |
507 | struct ubd *dev; | ||
513 | int n; | 508 | int n; |
514 | 509 | ||
515 | do_ubd = 0; | 510 | do_ubd = 0; |
516 | intr_count++; | ||
517 | n = os_read_file(thread_fd, &req, sizeof(req)); | 511 | n = os_read_file(thread_fd, &req, sizeof(req)); |
518 | if(n != sizeof(req)){ | 512 | if(n != sizeof(req)){ |
519 | printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, " | 513 | printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, " |
520 | "err = %d\n", os_getpid(), -n); | 514 | "err = %d\n", os_getpid(), -n); |
521 | spin_lock(&ubd_io_lock); | ||
522 | end_request(rq, 0); | ||
523 | spin_unlock(&ubd_io_lock); | ||
524 | return; | 515 | return; |
525 | } | 516 | } |
526 | 517 | ||
518 | rq = req.req; | ||
519 | dev = rq->rq_disk->private_data; | ||
520 | |||
527 | ubd_finish(rq, req.error); | 521 | ubd_finish(rq, req.error); |
528 | reactivate_fd(thread_fd, UBD_IRQ); | 522 | reactivate_fd(thread_fd, UBD_IRQ); |
529 | spin_lock(&ubd_io_lock); | 523 | spin_lock(&dev->lock); |
530 | do_ubd_request(ubd_queue); | 524 | do_ubd_request(dev->queue); |
531 | spin_unlock(&ubd_io_lock); | 525 | spin_unlock(&dev->lock); |
532 | } | 526 | } |
533 | 527 | ||
534 | static irqreturn_t ubd_intr(int irq, void *dev) | 528 | static irqreturn_t ubd_intr(int irq, void *dev) |
@@ -632,8 +626,7 @@ static int ubd_open_dev(struct ubd *ubd_dev) | |||
632 | } | 626 | } |
633 | 627 | ||
634 | static int ubd_disk_register(int major, u64 size, int unit, | 628 | static int ubd_disk_register(int major, u64 size, int unit, |
635 | struct gendisk **disk_out) | 629 | struct gendisk **disk_out) |
636 | |||
637 | { | 630 | { |
638 | struct gendisk *disk; | 631 | struct gendisk *disk; |
639 | 632 | ||
@@ -659,7 +652,7 @@ static int ubd_disk_register(int major, u64 size, int unit, | |||
659 | } | 652 | } |
660 | 653 | ||
661 | disk->private_data = &ubd_devs[unit]; | 654 | disk->private_data = &ubd_devs[unit]; |
662 | disk->queue = ubd_queue; | 655 | disk->queue = ubd_devs[unit].queue; |
663 | add_disk(disk); | 656 | add_disk(disk); |
664 | 657 | ||
665 | *disk_out = disk; | 658 | *disk_out = disk; |
@@ -668,28 +661,39 @@ static int ubd_disk_register(int major, u64 size, int unit, | |||
668 | 661 | ||
669 | #define ROUND_BLOCK(n) ((n + ((1 << 9) - 1)) & (-1 << 9)) | 662 | #define ROUND_BLOCK(n) ((n + ((1 << 9) - 1)) & (-1 << 9)) |
670 | 663 | ||
671 | static int ubd_add(int n) | 664 | static int ubd_add(int n, char **error_out) |
672 | { | 665 | { |
673 | struct ubd *ubd_dev = &ubd_devs[n]; | 666 | struct ubd *ubd_dev = &ubd_devs[n]; |
674 | int err; | 667 | int err = 0; |
675 | 668 | ||
676 | err = -ENODEV; | ||
677 | if(ubd_dev->file == NULL) | 669 | if(ubd_dev->file == NULL) |
678 | goto out; | 670 | goto out; |
679 | 671 | ||
680 | err = ubd_file_size(ubd_dev, &ubd_dev->size); | 672 | err = ubd_file_size(ubd_dev, &ubd_dev->size); |
681 | if(err < 0) | 673 | if(err < 0){ |
674 | *error_out = "Couldn't determine size of device's file"; | ||
682 | goto out; | 675 | goto out; |
676 | } | ||
683 | 677 | ||
684 | ubd_dev->size = ROUND_BLOCK(ubd_dev->size); | 678 | ubd_dev->size = ROUND_BLOCK(ubd_dev->size); |
685 | 679 | ||
686 | err = ubd_disk_register(MAJOR_NR, ubd_dev->size, n, &ubd_gendisk[n]); | 680 | err = -ENOMEM; |
687 | if(err) | 681 | ubd_dev->queue = blk_init_queue(do_ubd_request, &ubd_dev->lock); |
682 | if (ubd_dev->queue == NULL) { | ||
683 | *error_out = "Failed to initialize device queue"; | ||
688 | goto out; | 684 | goto out; |
685 | } | ||
686 | ubd_dev->queue->queuedata = ubd_dev; | ||
687 | |||
688 | err = ubd_disk_register(MAJOR_NR, ubd_dev->size, n, &ubd_gendisk[n]); | ||
689 | if(err){ | ||
690 | *error_out = "Failed to register device"; | ||
691 | goto out_cleanup; | ||
692 | } | ||
689 | 693 | ||
690 | if(fake_major != MAJOR_NR) | 694 | if(fake_major != MAJOR_NR) |
691 | ubd_disk_register(fake_major, ubd_dev->size, n, | 695 | ubd_disk_register(fake_major, ubd_dev->size, n, |
692 | &fake_gendisk[n]); | 696 | &fake_gendisk[n]); |
693 | 697 | ||
694 | /* perhaps this should also be under the "if (fake_major)" above */ | 698 | /* perhaps this should also be under the "if (fake_major)" above */ |
695 | /* using the fake_disk->disk_name and also the fakehd_set name */ | 699 | /* using the fake_disk->disk_name and also the fakehd_set name */ |
@@ -699,30 +703,37 @@ static int ubd_add(int n) | |||
699 | err = 0; | 703 | err = 0; |
700 | out: | 704 | out: |
701 | return err; | 705 | return err; |
706 | |||
707 | out_cleanup: | ||
708 | blk_cleanup_queue(ubd_dev->queue); | ||
709 | goto out; | ||
702 | } | 710 | } |
703 | 711 | ||
704 | static int ubd_config(char *str) | 712 | static int ubd_config(char *str, char **error_out) |
705 | { | 713 | { |
706 | int n, ret; | 714 | int n, ret; |
707 | 715 | ||
716 | /* This string is possibly broken up and stored, so it's only | ||
717 | * freed if ubd_setup_common fails, or if only general options | ||
718 | * were set. | ||
719 | */ | ||
708 | str = kstrdup(str, GFP_KERNEL); | 720 | str = kstrdup(str, GFP_KERNEL); |
709 | if (str == NULL) { | 721 | if (str == NULL) { |
710 | printk(KERN_ERR "ubd_config failed to strdup string\n"); | 722 | *error_out = "Failed to allocate memory"; |
711 | ret = 1; | 723 | return -ENOMEM; |
712 | goto out; | ||
713 | } | 724 | } |
714 | ret = ubd_setup_common(str, &n); | 725 | |
715 | if (ret) { | 726 | ret = ubd_setup_common(str, &n, error_out); |
716 | ret = -1; | 727 | if (ret) |
717 | goto err_free; | 728 | goto err_free; |
718 | } | 729 | |
719 | if (n == -1) { | 730 | if (n == -1) { |
720 | ret = 0; | 731 | ret = 0; |
721 | goto err_free; | 732 | goto err_free; |
722 | } | 733 | } |
723 | 734 | ||
724 | mutex_lock(&ubd_lock); | 735 | mutex_lock(&ubd_lock); |
725 | ret = ubd_add(n); | 736 | ret = ubd_add(n, error_out); |
726 | if (ret) | 737 | if (ret) |
727 | ubd_devs[n].file = NULL; | 738 | ubd_devs[n].file = NULL; |
728 | mutex_unlock(&ubd_lock); | 739 | mutex_unlock(&ubd_lock); |
@@ -777,7 +788,7 @@ static int ubd_id(char **str, int *start_out, int *end_out) | |||
777 | return n; | 788 | return n; |
778 | } | 789 | } |
779 | 790 | ||
780 | static int ubd_remove(int n) | 791 | static int ubd_remove(int n, char **error_out) |
781 | { | 792 | { |
782 | struct ubd *ubd_dev; | 793 | struct ubd *ubd_dev; |
783 | int err = -ENODEV; | 794 | int err = -ENODEV; |
@@ -807,6 +818,7 @@ static int ubd_remove(int n) | |||
807 | fake_gendisk[n] = NULL; | 818 | fake_gendisk[n] = NULL; |
808 | } | 819 | } |
809 | 820 | ||
821 | blk_cleanup_queue(ubd_dev->queue); | ||
810 | platform_device_unregister(&ubd_dev->pdev); | 822 | platform_device_unregister(&ubd_dev->pdev); |
811 | *ubd_dev = ((struct ubd) DEFAULT_UBD); | 823 | *ubd_dev = ((struct ubd) DEFAULT_UBD); |
812 | err = 0; | 824 | err = 0; |
@@ -815,8 +827,11 @@ out: | |||
815 | return err; | 827 | return err; |
816 | } | 828 | } |
817 | 829 | ||
818 | /* All these are called by mconsole in process context and without ubd-specific locks. */ | 830 | /* All these are called by mconsole in process context and without |
831 | * ubd-specific locks. The structure itself is const except for .list. | ||
832 | */ | ||
819 | static struct mc_device ubd_mc = { | 833 | static struct mc_device ubd_mc = { |
834 | .list = LIST_HEAD_INIT(ubd_mc.list), | ||
820 | .name = "ubd", | 835 | .name = "ubd", |
821 | .config = ubd_config, | 836 | .config = ubd_config, |
822 | .get_config = ubd_get_config, | 837 | .get_config = ubd_get_config, |
@@ -836,13 +851,17 @@ static int __init ubd0_init(void) | |||
836 | { | 851 | { |
837 | struct ubd *ubd_dev = &ubd_devs[0]; | 852 | struct ubd *ubd_dev = &ubd_devs[0]; |
838 | 853 | ||
854 | mutex_lock(&ubd_lock); | ||
839 | if(ubd_dev->file == NULL) | 855 | if(ubd_dev->file == NULL) |
840 | ubd_dev->file = "root_fs"; | 856 | ubd_dev->file = "root_fs"; |
857 | mutex_unlock(&ubd_lock); | ||
858 | |||
841 | return(0); | 859 | return(0); |
842 | } | 860 | } |
843 | 861 | ||
844 | __initcall(ubd0_init); | 862 | __initcall(ubd0_init); |
845 | 863 | ||
864 | /* Used in ubd_init, which is an initcall */ | ||
846 | static struct platform_driver ubd_driver = { | 865 | static struct platform_driver ubd_driver = { |
847 | .driver = { | 866 | .driver = { |
848 | .name = DRIVER_NAME, | 867 | .name = DRIVER_NAME, |
@@ -851,17 +870,12 @@ static struct platform_driver ubd_driver = { | |||
851 | 870 | ||
852 | static int __init ubd_init(void) | 871 | static int __init ubd_init(void) |
853 | { | 872 | { |
854 | int i; | 873 | char *error; |
874 | int i, err; | ||
855 | 875 | ||
856 | if (register_blkdev(MAJOR_NR, "ubd")) | 876 | if (register_blkdev(MAJOR_NR, "ubd")) |
857 | return -1; | 877 | return -1; |
858 | 878 | ||
859 | ubd_queue = blk_init_queue(do_ubd_request, &ubd_io_lock); | ||
860 | if (!ubd_queue) { | ||
861 | unregister_blkdev(MAJOR_NR, "ubd"); | ||
862 | return -1; | ||
863 | } | ||
864 | |||
865 | if (fake_major != MAJOR_NR) { | 879 | if (fake_major != MAJOR_NR) { |
866 | char name[sizeof("ubd_nnn\0")]; | 880 | char name[sizeof("ubd_nnn\0")]; |
867 | 881 | ||
@@ -870,8 +884,14 @@ static int __init ubd_init(void) | |||
870 | return -1; | 884 | return -1; |
871 | } | 885 | } |
872 | platform_driver_register(&ubd_driver); | 886 | platform_driver_register(&ubd_driver); |
873 | for (i = 0; i < MAX_DEV; i++) | 887 | mutex_lock(&ubd_lock); |
874 | ubd_add(i); | 888 | for (i = 0; i < MAX_DEV; i++){ |
889 | err = ubd_add(i, &error); | ||
890 | if(err) | ||
891 | printk(KERN_ERR "Failed to initialize ubd device %d :" | ||
892 | "%s\n", i, error); | ||
893 | } | ||
894 | mutex_unlock(&ubd_lock); | ||
875 | return 0; | 895 | return 0; |
876 | } | 896 | } |
877 | 897 | ||
@@ -1003,7 +1023,7 @@ static void cowify_req(struct io_thread_req *req, unsigned long *bitmap, | |||
1003 | req->bitmap_words, bitmap_len); | 1023 | req->bitmap_words, bitmap_len); |
1004 | } | 1024 | } |
1005 | 1025 | ||
1006 | /* Called with ubd_io_lock held */ | 1026 | /* Called with dev->lock held */ |
1007 | static int prepare_request(struct request *req, struct io_thread_req *io_req) | 1027 | static int prepare_request(struct request *req, struct io_thread_req *io_req) |
1008 | { | 1028 | { |
1009 | struct gendisk *disk = req->rq_disk; | 1029 | struct gendisk *disk = req->rq_disk; |
@@ -1022,6 +1042,7 @@ static int prepare_request(struct request *req, struct io_thread_req *io_req) | |||
1022 | offset = ((__u64) req->sector) << 9; | 1042 | offset = ((__u64) req->sector) << 9; |
1023 | len = req->current_nr_sectors << 9; | 1043 | len = req->current_nr_sectors << 9; |
1024 | 1044 | ||
1045 | io_req->req = req; | ||
1025 | io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd : ubd_dev->fd; | 1046 | io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd : ubd_dev->fd; |
1026 | io_req->fds[1] = ubd_dev->fd; | 1047 | io_req->fds[1] = ubd_dev->fd; |
1027 | io_req->cow_offset = -1; | 1048 | io_req->cow_offset = -1; |
@@ -1043,7 +1064,7 @@ static int prepare_request(struct request *req, struct io_thread_req *io_req) | |||
1043 | return(0); | 1064 | return(0); |
1044 | } | 1065 | } |
1045 | 1066 | ||
1046 | /* Called with ubd_io_lock held */ | 1067 | /* Called with dev->lock held */ |
1047 | static void do_ubd_request(request_queue_t *q) | 1068 | static void do_ubd_request(request_queue_t *q) |
1048 | { | 1069 | { |
1049 | struct io_thread_req io_req; | 1070 | struct io_thread_req io_req; |
@@ -1102,7 +1123,7 @@ static int ubd_ioctl(struct inode * inode, struct file * file, | |||
1102 | sizeof(ubd_id))) | 1123 | sizeof(ubd_id))) |
1103 | return(-EFAULT); | 1124 | return(-EFAULT); |
1104 | return(0); | 1125 | return(0); |
1105 | 1126 | ||
1106 | case CDROMVOLREAD: | 1127 | case CDROMVOLREAD: |
1107 | if(copy_from_user(&volume, (char __user *) arg, sizeof(volume))) | 1128 | if(copy_from_user(&volume, (char __user *) arg, sizeof(volume))) |
1108 | return(-EFAULT); | 1129 | return(-EFAULT); |
diff --git a/arch/um/include/chan_kern.h b/arch/um/include/chan_kern.h index 9003a343e148..c4b41bb1035f 100644 --- a/arch/um/include/chan_kern.h +++ b/arch/um/include/chan_kern.h | |||
@@ -30,14 +30,13 @@ struct chan { | |||
30 | extern void chan_interrupt(struct list_head *chans, struct delayed_work *task, | 30 | extern void chan_interrupt(struct list_head *chans, struct delayed_work *task, |
31 | struct tty_struct *tty, int irq); | 31 | struct tty_struct *tty, int irq); |
32 | extern int parse_chan_pair(char *str, struct line *line, int device, | 32 | extern int parse_chan_pair(char *str, struct line *line, int device, |
33 | const struct chan_opts *opts); | 33 | const struct chan_opts *opts, char **error_out); |
34 | extern int open_chan(struct list_head *chans); | 34 | extern int open_chan(struct list_head *chans); |
35 | extern int write_chan(struct list_head *chans, const char *buf, int len, | 35 | extern int write_chan(struct list_head *chans, const char *buf, int len, |
36 | int write_irq); | 36 | int write_irq); |
37 | extern int console_write_chan(struct list_head *chans, const char *buf, | 37 | extern int console_write_chan(struct list_head *chans, const char *buf, |
38 | int len); | 38 | int len); |
39 | extern int console_open_chan(struct line *line, struct console *co, | 39 | extern int console_open_chan(struct line *line, struct console *co); |
40 | const struct chan_opts *opts); | ||
41 | extern void deactivate_chan(struct list_head *chans, int irq); | 40 | extern void deactivate_chan(struct list_head *chans, int irq); |
42 | extern void reactivate_chan(struct list_head *chans, int irq); | 41 | extern void reactivate_chan(struct list_head *chans, int irq); |
43 | extern void chan_enable_winch(struct list_head *chans, struct tty_struct *tty); | 42 | extern void chan_enable_winch(struct list_head *chans, struct tty_struct *tty); |
diff --git a/arch/um/include/chan_user.h b/arch/um/include/chan_user.h index a795547a1dbd..38f16d812e7c 100644 --- a/arch/um/include/chan_user.h +++ b/arch/um/include/chan_user.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) | 2 | * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) |
3 | * Licensed under the GPL | 3 | * Licensed under the GPL |
4 | */ | 4 | */ |
@@ -9,11 +9,11 @@ | |||
9 | #include "init.h" | 9 | #include "init.h" |
10 | 10 | ||
11 | struct chan_opts { | 11 | struct chan_opts { |
12 | void (*announce)(char *dev_name, int dev); | 12 | void (*const announce)(char *dev_name, int dev); |
13 | char *xterm_title; | 13 | char *xterm_title; |
14 | int raw; | 14 | const int raw; |
15 | unsigned long tramp_stack; | 15 | const unsigned long tramp_stack; |
16 | int in_kernel; | 16 | const int in_kernel; |
17 | }; | 17 | }; |
18 | 18 | ||
19 | enum chan_init_pri { INIT_STATIC, INIT_ALL, INIT_ONE }; | 19 | enum chan_init_pri { INIT_STATIC, INIT_ALL, INIT_ONE }; |
@@ -54,14 +54,3 @@ __uml_help(fn, prefix "[0-9]*=<channel description>\n" \ | |||
54 | ); | 54 | ); |
55 | 55 | ||
56 | #endif | 56 | #endif |
57 | |||
58 | /* | ||
59 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
60 | * Emacs will notice this stuff at the end of the file and automatically | ||
61 | * adjust the settings for this buffer only. This must remain at the end | ||
62 | * of the file. | ||
63 | * --------------------------------------------------------------------------- | ||
64 | * Local variables: | ||
65 | * c-file-style: "linux" | ||
66 | * End: | ||
67 | */ | ||
diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h index cec9fcc57bf5..173af029d12b 100644 --- a/arch/um/include/kern_util.h +++ b/arch/um/include/kern_util.h | |||
@@ -61,7 +61,6 @@ extern int set_signals(int enable); | |||
61 | extern void force_sigbus(void); | 61 | extern void force_sigbus(void); |
62 | extern int pid_to_processor_id(int pid); | 62 | extern int pid_to_processor_id(int pid); |
63 | extern void deliver_signals(void *t); | 63 | extern void deliver_signals(void *t); |
64 | extern int next_syscall_index(int max); | ||
65 | extern int next_trap_index(int max); | 64 | extern int next_trap_index(int max); |
66 | extern void default_idle(void); | 65 | extern void default_idle(void); |
67 | extern void finish_fork(void); | 66 | extern void finish_fork(void); |
@@ -88,7 +87,6 @@ extern void timer_irq(union uml_pt_regs *regs); | |||
88 | extern void unprotect_stack(unsigned long stack); | 87 | extern void unprotect_stack(unsigned long stack); |
89 | extern void do_uml_exitcalls(void); | 88 | extern void do_uml_exitcalls(void); |
90 | extern int attach_debugger(int idle_pid, int pid, int stop); | 89 | extern int attach_debugger(int idle_pid, int pid, int stop); |
91 | extern void bad_segv(struct faultinfo fi, unsigned long ip); | ||
92 | extern int config_gdb(char *str); | 90 | extern int config_gdb(char *str); |
93 | extern int remove_gdb(void); | 91 | extern int remove_gdb(void); |
94 | extern char *uml_strdup(char *string); | 92 | extern char *uml_strdup(char *string); |
@@ -104,8 +102,6 @@ extern int clear_user_proc(void *buf, int size); | |||
104 | extern int copy_to_user_proc(void *to, void *from, int size); | 102 | extern int copy_to_user_proc(void *to, void *from, int size); |
105 | extern int copy_from_user_proc(void *to, void *from, int size); | 103 | extern int copy_from_user_proc(void *to, void *from, int size); |
106 | extern int strlen_user_proc(char *str); | 104 | extern int strlen_user_proc(char *str); |
107 | extern void bus_handler(int sig, union uml_pt_regs *regs); | ||
108 | extern void winch(int sig, union uml_pt_regs *regs); | ||
109 | extern long execute_syscall(void *r); | 105 | extern long execute_syscall(void *r); |
110 | extern int smp_sigio_handler(void); | 106 | extern int smp_sigio_handler(void); |
111 | extern void *get_current(void); | 107 | extern void *get_current(void); |
@@ -120,7 +116,6 @@ extern void time_init_kern(void); | |||
120 | 116 | ||
121 | /* Are we disallowed to sleep? Used to choose between GFP_KERNEL and GFP_ATOMIC. */ | 117 | /* Are we disallowed to sleep? Used to choose between GFP_KERNEL and GFP_ATOMIC. */ |
122 | extern int __cant_sleep(void); | 118 | extern int __cant_sleep(void); |
123 | extern void segv_handler(int sig, union uml_pt_regs *regs); | ||
124 | extern void sigio_handler(int sig, union uml_pt_regs *regs); | 119 | extern void sigio_handler(int sig, union uml_pt_regs *regs); |
125 | 120 | ||
126 | #endif | 121 | #endif |
diff --git a/arch/um/include/line.h b/arch/um/include/line.h index 5f232ae89fbb..1223f2c844b4 100644 --- a/arch/um/include/line.h +++ b/arch/um/include/line.h | |||
@@ -11,36 +11,37 @@ | |||
11 | #include "linux/tty.h" | 11 | #include "linux/tty.h" |
12 | #include "linux/interrupt.h" | 12 | #include "linux/interrupt.h" |
13 | #include "linux/spinlock.h" | 13 | #include "linux/spinlock.h" |
14 | #include "linux/mutex.h" | ||
14 | #include "chan_user.h" | 15 | #include "chan_user.h" |
15 | #include "mconsole_kern.h" | 16 | #include "mconsole_kern.h" |
16 | 17 | ||
18 | /* There's only one modifiable field in this - .mc.list */ | ||
17 | struct line_driver { | 19 | struct line_driver { |
18 | char *name; | 20 | const char *name; |
19 | char *device_name; | 21 | const char *device_name; |
20 | short major; | 22 | const short major; |
21 | short minor_start; | 23 | const short minor_start; |
22 | short type; | 24 | const short type; |
23 | short subtype; | 25 | const short subtype; |
24 | int read_irq; | 26 | const int read_irq; |
25 | char *read_irq_name; | 27 | const char *read_irq_name; |
26 | int write_irq; | 28 | const int write_irq; |
27 | char *write_irq_name; | 29 | const char *write_irq_name; |
28 | char *symlink_from; | ||
29 | char *symlink_to; | ||
30 | struct mc_device mc; | 30 | struct mc_device mc; |
31 | }; | 31 | }; |
32 | 32 | ||
33 | struct line { | 33 | struct line { |
34 | struct tty_struct *tty; | 34 | struct tty_struct *tty; |
35 | spinlock_t count_lock; | ||
36 | int valid; | ||
37 | |||
35 | char *init_str; | 38 | char *init_str; |
36 | int init_pri; | 39 | int init_pri; |
37 | struct list_head chan_list; | 40 | struct list_head chan_list; |
38 | int valid; | 41 | |
39 | int count; | ||
40 | int throttled; | ||
41 | /*This lock is actually, mostly, local to*/ | 42 | /*This lock is actually, mostly, local to*/ |
42 | spinlock_t lock; | 43 | spinlock_t lock; |
43 | 44 | int throttled; | |
44 | /* Yes, this is a real circular buffer. | 45 | /* Yes, this is a real circular buffer. |
45 | * XXX: And this should become a struct kfifo! | 46 | * XXX: And this should become a struct kfifo! |
46 | * | 47 | * |
@@ -57,22 +58,17 @@ struct line { | |||
57 | }; | 58 | }; |
58 | 59 | ||
59 | #define LINE_INIT(str, d) \ | 60 | #define LINE_INIT(str, d) \ |
60 | { .init_str = str, \ | 61 | { .count_lock = SPIN_LOCK_UNLOCKED, \ |
62 | .init_str = str, \ | ||
61 | .init_pri = INIT_STATIC, \ | 63 | .init_pri = INIT_STATIC, \ |
62 | .valid = 1, \ | 64 | .valid = 1, \ |
63 | .lock = SPIN_LOCK_UNLOCKED, \ | 65 | .lock = SPIN_LOCK_UNLOCKED, \ |
64 | .driver = d } | 66 | .driver = d } |
65 | 67 | ||
66 | struct lines { | ||
67 | int num; | ||
68 | }; | ||
69 | |||
70 | #define LINES_INIT(n) { .num = n } | ||
71 | |||
72 | extern void line_close(struct tty_struct *tty, struct file * filp); | 68 | extern void line_close(struct tty_struct *tty, struct file * filp); |
73 | extern int line_open(struct line *lines, struct tty_struct *tty); | 69 | extern int line_open(struct line *lines, struct tty_struct *tty); |
74 | extern int line_setup(struct line *lines, unsigned int sizeof_lines, | 70 | extern int line_setup(struct line *lines, unsigned int sizeof_lines, |
75 | char *init); | 71 | char *init, char **error_out); |
76 | extern int line_write(struct tty_struct *tty, const unsigned char *buf, | 72 | extern int line_write(struct tty_struct *tty, const unsigned char *buf, |
77 | int len); | 73 | int len); |
78 | extern void line_put_char(struct tty_struct *tty, unsigned char ch); | 74 | extern void line_put_char(struct tty_struct *tty, unsigned char ch); |
@@ -90,17 +86,18 @@ extern char *add_xterm_umid(char *base); | |||
90 | extern int line_setup_irq(int fd, int input, int output, struct line *line, | 86 | extern int line_setup_irq(int fd, int input, int output, struct line *line, |
91 | void *data); | 87 | void *data); |
92 | extern void line_close_chan(struct line *line); | 88 | extern void line_close_chan(struct line *line); |
93 | extern struct tty_driver * line_register_devfs(struct lines *set, | 89 | extern struct tty_driver *register_lines(struct line_driver *line_driver, |
94 | struct line_driver *line_driver, | 90 | const struct tty_operations *driver, |
95 | const struct tty_operations *driver, | 91 | struct line *lines, int nlines); |
96 | struct line *lines, int nlines); | ||
97 | extern void lines_init(struct line *lines, int nlines, struct chan_opts *opts); | 92 | extern void lines_init(struct line *lines, int nlines, struct chan_opts *opts); |
98 | extern void close_lines(struct line *lines, int nlines); | 93 | extern void close_lines(struct line *lines, int nlines); |
99 | 94 | ||
100 | extern int line_config(struct line *lines, unsigned int sizeof_lines, | 95 | extern int line_config(struct line *lines, unsigned int sizeof_lines, |
101 | char *str, const struct chan_opts *opts); | 96 | char *str, const struct chan_opts *opts, |
97 | char **error_out); | ||
102 | extern int line_id(char **str, int *start_out, int *end_out); | 98 | extern int line_id(char **str, int *start_out, int *end_out); |
103 | extern int line_remove(struct line *lines, unsigned int sizeof_lines, int n); | 99 | extern int line_remove(struct line *lines, unsigned int sizeof_lines, int n, |
100 | char **error_out); | ||
104 | extern int line_get_config(char *dev, struct line *lines, | 101 | extern int line_get_config(char *dev, struct line *lines, |
105 | unsigned int sizeof_lines, char *str, | 102 | unsigned int sizeof_lines, char *str, |
106 | int size, char **error_out); | 103 | int size, char **error_out); |
diff --git a/arch/um/include/mconsole_kern.h b/arch/um/include/mconsole_kern.h index 1ea6d928e1cd..d2fe07e78958 100644 --- a/arch/um/include/mconsole_kern.h +++ b/arch/um/include/mconsole_kern.h | |||
@@ -18,10 +18,10 @@ struct mconsole_entry { | |||
18 | struct mc_device { | 18 | struct mc_device { |
19 | struct list_head list; | 19 | struct list_head list; |
20 | char *name; | 20 | char *name; |
21 | int (*config)(char *); | 21 | int (*config)(char *, char **); |
22 | int (*get_config)(char *, char *, int, char **); | 22 | int (*get_config)(char *, char *, int, char **); |
23 | int (*id)(char **, int *, int *); | 23 | int (*id)(char **, int *, int *); |
24 | int (*remove)(int); | 24 | int (*remove)(int, char **); |
25 | }; | 25 | }; |
26 | 26 | ||
27 | #define CONFIG_CHUNK(str, size, current, chunk, end) \ | 27 | #define CONFIG_CHUNK(str, size, current, chunk, end) \ |
@@ -50,14 +50,3 @@ static inline void mconsole_register_dev(struct mc_device *new) | |||
50 | #endif | 50 | #endif |
51 | 51 | ||
52 | #endif | 52 | #endif |
53 | |||
54 | /* | ||
55 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
56 | * Emacs will notice this stuff at the end of the file and automatically | ||
57 | * adjust the settings for this buffer only. This must remain at the end | ||
58 | * of the file. | ||
59 | * --------------------------------------------------------------------------- | ||
60 | * Local variables: | ||
61 | * c-file-style: "linux" | ||
62 | * End: | ||
63 | */ | ||
diff --git a/arch/um/include/net_kern.h b/arch/um/include/net_kern.h index 218f8b47fdcd..125ab42df18a 100644 --- a/arch/um/include/net_kern.h +++ b/arch/um/include/net_kern.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) | 2 | * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) |
3 | * Licensed under the GPL | 3 | * Licensed under the GPL |
4 | */ | 4 | */ |
@@ -36,7 +36,7 @@ struct uml_net_private { | |||
36 | void (*remove)(void *); | 36 | void (*remove)(void *); |
37 | int (*read)(int, struct sk_buff **skb, struct uml_net_private *); | 37 | int (*read)(int, struct sk_buff **skb, struct uml_net_private *); |
38 | int (*write)(int, struct sk_buff **skb, struct uml_net_private *); | 38 | int (*write)(int, struct sk_buff **skb, struct uml_net_private *); |
39 | 39 | ||
40 | void (*add_address)(unsigned char *, unsigned char *, void *); | 40 | void (*add_address)(unsigned char *, unsigned char *, void *); |
41 | void (*delete_address)(unsigned char *, unsigned char *, void *); | 41 | void (*delete_address)(unsigned char *, unsigned char *, void *); |
42 | int (*set_mtu)(int mtu, void *); | 42 | int (*set_mtu)(int mtu, void *); |
@@ -52,18 +52,18 @@ struct net_kern_info { | |||
52 | 52 | ||
53 | struct transport { | 53 | struct transport { |
54 | struct list_head list; | 54 | struct list_head list; |
55 | char *name; | 55 | const char *name; |
56 | int (*setup)(char *, char **, void *); | 56 | int (* const setup)(char *, char **, void *); |
57 | const struct net_user_info *user; | 57 | const struct net_user_info *user; |
58 | const struct net_kern_info *kern; | 58 | const struct net_kern_info *kern; |
59 | int private_size; | 59 | const int private_size; |
60 | int setup_size; | 60 | const int setup_size; |
61 | }; | 61 | }; |
62 | 62 | ||
63 | extern struct net_device *ether_init(int); | 63 | extern struct net_device *ether_init(int); |
64 | extern unsigned short ether_protocol(struct sk_buff *); | 64 | extern unsigned short ether_protocol(struct sk_buff *); |
65 | extern struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra); | 65 | extern struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra); |
66 | extern int tap_setup_common(char *str, char *type, char **dev_name, | 66 | extern int tap_setup_common(char *str, char *type, char **dev_name, |
67 | char **mac_out, char **gate_addr); | 67 | char **mac_out, char **gate_addr); |
68 | extern void register_transport(struct transport *new); | 68 | extern void register_transport(struct transport *new); |
69 | extern unsigned short eth_protocol(struct sk_buff *skb); | 69 | extern unsigned short eth_protocol(struct sk_buff *skb); |
diff --git a/arch/um/include/os.h b/arch/um/include/os.h index 13a86bd383d3..8629bd191492 100644 --- a/arch/um/include/os.h +++ b/arch/um/include/os.h | |||
@@ -137,7 +137,6 @@ extern int os_new_tty_pgrp(int fd, int pid); | |||
137 | extern int os_get_ifname(int fd, char *namebuf); | 137 | extern int os_get_ifname(int fd, char *namebuf); |
138 | extern int os_set_slip(int fd); | 138 | extern int os_set_slip(int fd); |
139 | extern int os_set_owner(int fd, int pid); | 139 | extern int os_set_owner(int fd, int pid); |
140 | extern int os_sigio_async(int master, int slave); | ||
141 | extern int os_mode_fd(int fd, int mode); | 140 | extern int os_mode_fd(int fd, int mode); |
142 | 141 | ||
143 | extern int os_seek_file(int fd, __u64 offset); | 142 | extern int os_seek_file(int fd, __u64 offset); |
@@ -341,4 +340,6 @@ extern void maybe_sigio_broken(int fd, int read); | |||
341 | extern void sig_handler_common_skas(int sig, void *sc_ptr); | 340 | extern void sig_handler_common_skas(int sig, void *sc_ptr); |
342 | extern void user_signal(int sig, union uml_pt_regs *regs, int pid); | 341 | extern void user_signal(int sig, union uml_pt_regs *regs, int pid); |
343 | 342 | ||
343 | extern int os_arch_prctl(int pid, int code, unsigned long *addr); | ||
344 | |||
344 | #endif | 345 | #endif |
diff --git a/arch/um/include/sigio.h b/arch/um/include/sigio.h index fe99ea163c2e..434f1a9ae4b3 100644 --- a/arch/um/include/sigio.h +++ b/arch/um/include/sigio.h | |||
@@ -12,14 +12,3 @@ extern void sigio_lock(void); | |||
12 | extern void sigio_unlock(void); | 12 | extern void sigio_unlock(void); |
13 | 13 | ||
14 | #endif | 14 | #endif |
15 | |||
16 | /* | ||
17 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
18 | * Emacs will notice this stuff at the end of the file and automatically | ||
19 | * adjust the settings for this buffer only. This must remain at the end | ||
20 | * of the file. | ||
21 | * --------------------------------------------------------------------------- | ||
22 | * Local variables: | ||
23 | * c-file-style: "linux" | ||
24 | * End: | ||
25 | */ | ||
diff --git a/arch/um/include/tempfile.h b/arch/um/include/tempfile.h index e36d9e0f5105..d441eac936b9 100644 --- a/arch/um/include/tempfile.h +++ b/arch/um/include/tempfile.h | |||
@@ -9,13 +9,3 @@ | |||
9 | extern int make_tempfile(const char *template, char **tempname, int do_unlink); | 9 | extern int make_tempfile(const char *template, char **tempname, int do_unlink); |
10 | 10 | ||
11 | #endif | 11 | #endif |
12 | /* | ||
13 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
14 | * Emacs will notice this stuff at the end of the file and automatically | ||
15 | * adjust the settings for this buffer only. This must remain at the end | ||
16 | * of the file. | ||
17 | * --------------------------------------------------------------------------- | ||
18 | * Local variables: | ||
19 | * c-file-style: "linux" | ||
20 | * End: | ||
21 | */ | ||
diff --git a/arch/um/include/umid.h b/arch/um/include/umid.h deleted file mode 100644 index 11373c851f15..000000000000 --- a/arch/um/include/umid.h +++ /dev/null | |||
@@ -1,22 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #ifndef __UMID_H__ | ||
7 | #define __UMID_H__ | ||
8 | |||
9 | extern int umid_file_name(char *name, char *buf, int len); | ||
10 | |||
11 | #endif | ||
12 | |||
13 | /* | ||
14 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
15 | * Emacs will notice this stuff at the end of the file and automatically | ||
16 | * adjust the settings for this buffer only. This must remain at the end | ||
17 | * of the file. | ||
18 | * --------------------------------------------------------------------------- | ||
19 | * Local variables: | ||
20 | * c-file-style: "linux" | ||
21 | * End: | ||
22 | */ | ||
diff --git a/arch/um/include/user_util.h b/arch/um/include/user_util.h index 06625fefef33..023575f67343 100644 --- a/arch/um/include/user_util.h +++ b/arch/um/include/user_util.h | |||
@@ -38,8 +38,6 @@ extern unsigned long long highmem; | |||
38 | 38 | ||
39 | extern char host_info[]; | 39 | extern char host_info[]; |
40 | 40 | ||
41 | extern char saved_command_line[]; | ||
42 | |||
43 | extern unsigned long _stext, _etext, _sdata, _edata, __bss_start, _end; | 41 | extern unsigned long _stext, _etext, _sdata, _edata, __bss_start, _end; |
44 | extern unsigned long _unprotected_end; | 42 | extern unsigned long _unprotected_end; |
45 | extern unsigned long brk_start; | 43 | extern unsigned long brk_start; |
diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index 6fa63a2a89e3..c5cf4a0827b0 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile | |||
@@ -7,7 +7,7 @@ extra-y := vmlinux.lds | |||
7 | clean-files := | 7 | clean-files := |
8 | 8 | ||
9 | obj-y = config.o exec.o exitcode.o init_task.o irq.o ksyms.o mem.o \ | 9 | obj-y = config.o exec.o exitcode.o init_task.o irq.o ksyms.o mem.o \ |
10 | physmem.o process.o ptrace.o reboot.o resource.o sigio.o \ | 10 | physmem.o process.o ptrace.o reboot.o sigio.o \ |
11 | signal.o smp.o syscall.o sysrq.o time.o tlb.o trap.o uaccess.o \ | 11 | signal.o smp.o syscall.o sysrq.o time.o tlb.o trap.o uaccess.o \ |
12 | um_arch.o umid.o | 12 | um_arch.o umid.o |
13 | 13 | ||
diff --git a/arch/um/kernel/exec.c b/arch/um/kernel/exec.c index 8d56ec6cca79..121166400e25 100644 --- a/arch/um/kernel/exec.c +++ b/arch/um/kernel/exec.c | |||
@@ -39,9 +39,9 @@ static long execve1(char *file, char __user * __user *argv, | |||
39 | char __user *__user *env) | 39 | char __user *__user *env) |
40 | { | 40 | { |
41 | long error; | 41 | long error; |
42 | #ifdef CONFIG_TTY_LOG | ||
42 | struct tty_struct *tty; | 43 | struct tty_struct *tty; |
43 | 44 | ||
44 | #ifdef CONFIG_TTY_LOG | ||
45 | mutex_lock(&tty_mutex); | 45 | mutex_lock(&tty_mutex); |
46 | tty = get_current_tty(); | 46 | tty = get_current_tty(); |
47 | if (tty) | 47 | if (tty) |
diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c index 5c1e611f628d..50a288bb875a 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c | |||
@@ -79,7 +79,7 @@ skip: | |||
79 | return 0; | 79 | return 0; |
80 | } | 80 | } |
81 | 81 | ||
82 | struct irq_fd *active_fds = NULL; | 82 | static struct irq_fd *active_fds = NULL; |
83 | static struct irq_fd **last_irq_ptr = &active_fds; | 83 | static struct irq_fd **last_irq_ptr = &active_fds; |
84 | 84 | ||
85 | extern void free_irqs(void); | 85 | extern void free_irqs(void); |
@@ -124,8 +124,8 @@ int activate_fd(int irq, int fd, int type, void *dev_id) | |||
124 | if (err < 0) | 124 | if (err < 0) |
125 | goto out; | 125 | goto out; |
126 | 126 | ||
127 | new_fd = um_kmalloc(sizeof(*new_fd)); | ||
128 | err = -ENOMEM; | 127 | err = -ENOMEM; |
128 | new_fd = kmalloc(sizeof(struct irq_fd), GFP_KERNEL); | ||
129 | if (new_fd == NULL) | 129 | if (new_fd == NULL) |
130 | goto out; | 130 | goto out; |
131 | 131 | ||
@@ -176,9 +176,8 @@ int activate_fd(int irq, int fd, int type, void *dev_id) | |||
176 | */ | 176 | */ |
177 | spin_unlock_irqrestore(&irq_lock, flags); | 177 | spin_unlock_irqrestore(&irq_lock, flags); |
178 | kfree(tmp_pfd); | 178 | kfree(tmp_pfd); |
179 | tmp_pfd = NULL; | ||
180 | 179 | ||
181 | tmp_pfd = um_kmalloc(n); | 180 | tmp_pfd = kmalloc(n, GFP_KERNEL); |
182 | if (tmp_pfd == NULL) | 181 | if (tmp_pfd == NULL) |
183 | goto out_kfree; | 182 | goto out_kfree; |
184 | 183 | ||
diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c index c95855ba6ab5..e85d65deea0d 100644 --- a/arch/um/kernel/mem.c +++ b/arch/um/kernel/mem.c | |||
@@ -24,8 +24,9 @@ | |||
24 | #include "init.h" | 24 | #include "init.h" |
25 | #include "kern_constants.h" | 25 | #include "kern_constants.h" |
26 | 26 | ||
27 | /* Changed during early boot */ | 27 | /* allocated in paging_init, zeroed in mem_init, and unchanged thereafter */ |
28 | unsigned long *empty_zero_page = NULL; | 28 | unsigned long *empty_zero_page = NULL; |
29 | /* allocated in paging_init and unchanged thereafter */ | ||
29 | unsigned long *empty_bad_page = NULL; | 30 | unsigned long *empty_bad_page = NULL; |
30 | pgd_t swapper_pg_dir[PTRS_PER_PGD]; | 31 | pgd_t swapper_pg_dir[PTRS_PER_PGD]; |
31 | unsigned long long highmem; | 32 | unsigned long long highmem; |
@@ -65,8 +66,8 @@ void mem_init(void) | |||
65 | { | 66 | { |
66 | max_low_pfn = (high_physmem - uml_physmem) >> PAGE_SHIFT; | 67 | max_low_pfn = (high_physmem - uml_physmem) >> PAGE_SHIFT; |
67 | 68 | ||
68 | /* clear the zero-page */ | 69 | /* clear the zero-page */ |
69 | memset((void *) empty_zero_page, 0, PAGE_SIZE); | 70 | memset((void *) empty_zero_page, 0, PAGE_SIZE); |
70 | 71 | ||
71 | /* Map in the area just after the brk now that kmalloc is about | 72 | /* Map in the area just after the brk now that kmalloc is about |
72 | * to be turned on. | 73 | * to be turned on. |
@@ -253,8 +254,10 @@ struct page *arch_validate(struct page *page, gfp_t mask, int order) | |||
253 | int i; | 254 | int i; |
254 | 255 | ||
255 | again: | 256 | again: |
256 | if(page == NULL) return(page); | 257 | if(page == NULL) |
257 | if(PageHighMem(page)) return(page); | 258 | return page; |
259 | if(PageHighMem(page)) | ||
260 | return page; | ||
258 | 261 | ||
259 | addr = (unsigned long) page_address(page); | 262 | addr = (unsigned long) page_address(page); |
260 | for(i = 0; i < (1 << order); i++){ | 263 | for(i = 0; i < (1 << order); i++){ |
@@ -263,13 +266,15 @@ struct page *arch_validate(struct page *page, gfp_t mask, int order) | |||
263 | sizeof(zero), | 266 | sizeof(zero), |
264 | ¤t->thread.fault_addr, | 267 | ¤t->thread.fault_addr, |
265 | ¤t->thread.fault_catcher)){ | 268 | ¤t->thread.fault_catcher)){ |
266 | if(!(mask & __GFP_WAIT)) return(NULL); | 269 | if(!(mask & __GFP_WAIT)) |
270 | return NULL; | ||
267 | else break; | 271 | else break; |
268 | } | 272 | } |
269 | addr += PAGE_SIZE; | 273 | addr += PAGE_SIZE; |
270 | } | 274 | } |
271 | 275 | ||
272 | if(i == (1 << order)) return(page); | 276 | if(i == (1 << order)) |
277 | return page; | ||
273 | page = alloc_pages(mask, order); | 278 | page = alloc_pages(mask, order); |
274 | goto again; | 279 | goto again; |
275 | } | 280 | } |
@@ -283,7 +288,6 @@ void free_initmem(void) | |||
283 | } | 288 | } |
284 | 289 | ||
285 | #ifdef CONFIG_BLK_DEV_INITRD | 290 | #ifdef CONFIG_BLK_DEV_INITRD |
286 | |||
287 | void free_initrd_mem(unsigned long start, unsigned long end) | 291 | void free_initrd_mem(unsigned long start, unsigned long end) |
288 | { | 292 | { |
289 | if (start < end) | 293 | if (start < end) |
@@ -296,37 +300,36 @@ void free_initrd_mem(unsigned long start, unsigned long end) | |||
296 | totalram_pages++; | 300 | totalram_pages++; |
297 | } | 301 | } |
298 | } | 302 | } |
299 | |||
300 | #endif | 303 | #endif |
301 | 304 | ||
302 | void show_mem(void) | 305 | void show_mem(void) |
303 | { | 306 | { |
304 | int pfn, total = 0, reserved = 0; | 307 | int pfn, total = 0, reserved = 0; |
305 | int shared = 0, cached = 0; | 308 | int shared = 0, cached = 0; |
306 | int highmem = 0; | 309 | int highmem = 0; |
307 | struct page *page; | 310 | struct page *page; |
308 | 311 | ||
309 | printk("Mem-info:\n"); | 312 | printk("Mem-info:\n"); |
310 | show_free_areas(); | 313 | show_free_areas(); |
311 | printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); | 314 | printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); |
312 | pfn = max_mapnr; | 315 | pfn = max_mapnr; |
313 | while(pfn-- > 0) { | 316 | while(pfn-- > 0) { |
314 | page = pfn_to_page(pfn); | 317 | page = pfn_to_page(pfn); |
315 | total++; | 318 | total++; |
316 | if(PageHighMem(page)) | 319 | if(PageHighMem(page)) |
317 | highmem++; | 320 | highmem++; |
318 | if(PageReserved(page)) | 321 | if(PageReserved(page)) |
319 | reserved++; | 322 | reserved++; |
320 | else if(PageSwapCache(page)) | 323 | else if(PageSwapCache(page)) |
321 | cached++; | 324 | cached++; |
322 | else if(page_count(page)) | 325 | else if(page_count(page)) |
323 | shared += page_count(page) - 1; | 326 | shared += page_count(page) - 1; |
324 | } | 327 | } |
325 | printk("%d pages of RAM\n", total); | 328 | printk("%d pages of RAM\n", total); |
326 | printk("%d pages of HIGHMEM\n", highmem); | 329 | printk("%d pages of HIGHMEM\n", highmem); |
327 | printk("%d reserved pages\n", reserved); | 330 | printk("%d reserved pages\n", reserved); |
328 | printk("%d pages shared\n", shared); | 331 | printk("%d pages shared\n", shared); |
329 | printk("%d pages swap cached\n", cached); | 332 | printk("%d pages swap cached\n", cached); |
330 | } | 333 | } |
331 | 334 | ||
332 | /* | 335 | /* |
@@ -362,28 +365,7 @@ pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) | |||
362 | struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) | 365 | struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) |
363 | { | 366 | { |
364 | struct page *pte; | 367 | struct page *pte; |
365 | 368 | ||
366 | pte = alloc_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO); | 369 | pte = alloc_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO); |
367 | return pte; | 370 | return pte; |
368 | } | 371 | } |
369 | |||
370 | struct iomem_region *iomem_regions = NULL; | ||
371 | int iomem_size = 0; | ||
372 | |||
373 | extern int parse_iomem(char *str, int *add) __init; | ||
374 | |||
375 | __uml_setup("iomem=", parse_iomem, | ||
376 | "iomem=<name>,<file>\n" | ||
377 | " Configure <file> as an IO memory region named <name>.\n\n" | ||
378 | ); | ||
379 | |||
380 | /* | ||
381 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
382 | * Emacs will notice this stuff at the end of the file and automatically | ||
383 | * adjust the settings for this buffer only. This must remain at the end | ||
384 | * of the file. | ||
385 | * --------------------------------------------------------------------------- | ||
386 | * Local variables: | ||
387 | * c-file-style: "linux" | ||
388 | * End: | ||
389 | */ | ||
diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c index abafa64b8727..638f3b5f6094 100644 --- a/arch/um/kernel/physmem.c +++ b/arch/um/kernel/physmem.c | |||
@@ -40,7 +40,7 @@ static struct rb_node **find_rb(void *virt) | |||
40 | while(*n != NULL){ | 40 | while(*n != NULL){ |
41 | d = rb_entry(*n, struct phys_desc, rb); | 41 | d = rb_entry(*n, struct phys_desc, rb); |
42 | if(d->virt == virt) | 42 | if(d->virt == virt) |
43 | return(n); | 43 | return n; |
44 | 44 | ||
45 | if(d->virt > virt) | 45 | if(d->virt > virt) |
46 | n = &(*n)->rb_left; | 46 | n = &(*n)->rb_left; |
@@ -48,7 +48,7 @@ static struct rb_node **find_rb(void *virt) | |||
48 | n = &(*n)->rb_right; | 48 | n = &(*n)->rb_right; |
49 | } | 49 | } |
50 | 50 | ||
51 | return(n); | 51 | return n; |
52 | } | 52 | } |
53 | 53 | ||
54 | static struct phys_desc *find_phys_mapping(void *virt) | 54 | static struct phys_desc *find_phys_mapping(void *virt) |
@@ -56,9 +56,9 @@ static struct phys_desc *find_phys_mapping(void *virt) | |||
56 | struct rb_node **n = find_rb(virt); | 56 | struct rb_node **n = find_rb(virt); |
57 | 57 | ||
58 | if(*n == NULL) | 58 | if(*n == NULL) |
59 | return(NULL); | 59 | return NULL; |
60 | 60 | ||
61 | return(rb_entry(*n, struct phys_desc, rb)); | 61 | return rb_entry(*n, struct phys_desc, rb); |
62 | } | 62 | } |
63 | 63 | ||
64 | static void insert_phys_mapping(struct phys_desc *desc) | 64 | static void insert_phys_mapping(struct phys_desc *desc) |
@@ -89,10 +89,10 @@ static struct desc_mapping *find_mapping(int fd) | |||
89 | list_for_each(ele, &descriptor_mappings){ | 89 | list_for_each(ele, &descriptor_mappings){ |
90 | desc = list_entry(ele, struct desc_mapping, list); | 90 | desc = list_entry(ele, struct desc_mapping, list); |
91 | if(desc->fd == fd) | 91 | if(desc->fd == fd) |
92 | return(desc); | 92 | return desc; |
93 | } | 93 | } |
94 | 94 | ||
95 | return(NULL); | 95 | return NULL; |
96 | } | 96 | } |
97 | 97 | ||
98 | static struct desc_mapping *descriptor_mapping(int fd) | 98 | static struct desc_mapping *descriptor_mapping(int fd) |
@@ -101,11 +101,11 @@ static struct desc_mapping *descriptor_mapping(int fd) | |||
101 | 101 | ||
102 | desc = find_mapping(fd); | 102 | desc = find_mapping(fd); |
103 | if(desc != NULL) | 103 | if(desc != NULL) |
104 | return(desc); | 104 | return desc; |
105 | 105 | ||
106 | desc = kmalloc(sizeof(*desc), GFP_ATOMIC); | 106 | desc = kmalloc(sizeof(*desc), GFP_ATOMIC); |
107 | if(desc == NULL) | 107 | if(desc == NULL) |
108 | return(NULL); | 108 | return NULL; |
109 | 109 | ||
110 | *desc = ((struct desc_mapping) | 110 | *desc = ((struct desc_mapping) |
111 | { .fd = fd, | 111 | { .fd = fd, |
@@ -113,7 +113,7 @@ static struct desc_mapping *descriptor_mapping(int fd) | |||
113 | .pages = LIST_HEAD_INIT(desc->pages) }); | 113 | .pages = LIST_HEAD_INIT(desc->pages) }); |
114 | list_add(&desc->list, &descriptor_mappings); | 114 | list_add(&desc->list, &descriptor_mappings); |
115 | 115 | ||
116 | return(desc); | 116 | return desc; |
117 | } | 117 | } |
118 | 118 | ||
119 | int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w) | 119 | int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w) |
@@ -125,11 +125,11 @@ int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w) | |||
125 | 125 | ||
126 | fd_maps = descriptor_mapping(fd); | 126 | fd_maps = descriptor_mapping(fd); |
127 | if(fd_maps == NULL) | 127 | if(fd_maps == NULL) |
128 | return(-ENOMEM); | 128 | return -ENOMEM; |
129 | 129 | ||
130 | phys = __pa(virt); | 130 | phys = __pa(virt); |
131 | desc = find_phys_mapping(virt); | 131 | desc = find_phys_mapping(virt); |
132 | if(desc != NULL) | 132 | if(desc != NULL) |
133 | panic("Address 0x%p is already substituted\n", virt); | 133 | panic("Address 0x%p is already substituted\n", virt); |
134 | 134 | ||
135 | err = -ENOMEM; | 135 | err = -ENOMEM; |
@@ -155,7 +155,7 @@ int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w) | |||
155 | rb_erase(&desc->rb, &phys_mappings); | 155 | rb_erase(&desc->rb, &phys_mappings); |
156 | kfree(desc); | 156 | kfree(desc); |
157 | out: | 157 | out: |
158 | return(err); | 158 | return err; |
159 | } | 159 | } |
160 | 160 | ||
161 | static int physmem_fd = -1; | 161 | static int physmem_fd = -1; |
@@ -182,10 +182,10 @@ int physmem_remove_mapping(void *virt) | |||
182 | virt = (void *) ((unsigned long) virt & PAGE_MASK); | 182 | virt = (void *) ((unsigned long) virt & PAGE_MASK); |
183 | desc = find_phys_mapping(virt); | 183 | desc = find_phys_mapping(virt); |
184 | if(desc == NULL) | 184 | if(desc == NULL) |
185 | return(0); | 185 | return 0; |
186 | 186 | ||
187 | remove_mapping(desc); | 187 | remove_mapping(desc); |
188 | return(1); | 188 | return 1; |
189 | } | 189 | } |
190 | 190 | ||
191 | void physmem_forget_descriptor(int fd) | 191 | void physmem_forget_descriptor(int fd) |
@@ -239,9 +239,9 @@ void arch_free_page(struct page *page, int order) | |||
239 | 239 | ||
240 | int is_remapped(void *virt) | 240 | int is_remapped(void *virt) |
241 | { | 241 | { |
242 | struct phys_desc *desc = find_phys_mapping(virt); | 242 | struct phys_desc *desc = find_phys_mapping(virt); |
243 | 243 | ||
244 | return(desc != NULL); | 244 | return desc != NULL; |
245 | } | 245 | } |
246 | 246 | ||
247 | /* Changed during early boot */ | 247 | /* Changed during early boot */ |
@@ -276,7 +276,7 @@ int init_maps(unsigned long physmem, unsigned long iomem, unsigned long highmem) | |||
276 | else map = alloc_bootmem_low_pages(total_len); | 276 | else map = alloc_bootmem_low_pages(total_len); |
277 | 277 | ||
278 | if(map == NULL) | 278 | if(map == NULL) |
279 | return(-ENOMEM); | 279 | return -ENOMEM; |
280 | 280 | ||
281 | for(i = 0; i < total_pages; i++){ | 281 | for(i = 0; i < total_pages; i++){ |
282 | p = &map[i]; | 282 | p = &map[i]; |
@@ -286,7 +286,7 @@ int init_maps(unsigned long physmem, unsigned long iomem, unsigned long highmem) | |||
286 | } | 286 | } |
287 | 287 | ||
288 | max_mapnr = total_pages; | 288 | max_mapnr = total_pages; |
289 | return(0); | 289 | return 0; |
290 | } | 290 | } |
291 | 291 | ||
292 | /* Changed during early boot */ | 292 | /* Changed during early boot */ |
@@ -296,7 +296,7 @@ unsigned long get_kmem_end(void) | |||
296 | { | 296 | { |
297 | if(kmem_top == 0) | 297 | if(kmem_top == 0) |
298 | kmem_top = CHOOSE_MODE(kmem_end_tt, kmem_end_skas); | 298 | kmem_top = CHOOSE_MODE(kmem_end_tt, kmem_end_skas); |
299 | return(kmem_top); | 299 | return kmem_top; |
300 | } | 300 | } |
301 | 301 | ||
302 | void map_memory(unsigned long virt, unsigned long phys, unsigned long len, | 302 | void map_memory(unsigned long virt, unsigned long phys, unsigned long len, |
@@ -379,7 +379,7 @@ int phys_mapping(unsigned long phys, __u64 *offset_out) | |||
379 | *offset_out = phys - iomem_size; | 379 | *offset_out = phys - iomem_size; |
380 | } | 380 | } |
381 | 381 | ||
382 | return(fd); | 382 | return fd; |
383 | } | 383 | } |
384 | 384 | ||
385 | static int __init uml_mem_setup(char *line, int *add) | 385 | static int __init uml_mem_setup(char *line, int *add) |
@@ -398,6 +398,23 @@ __uml_setup("mem=", uml_mem_setup, | |||
398 | " Example: mem=64M\n\n" | 398 | " Example: mem=64M\n\n" |
399 | ); | 399 | ); |
400 | 400 | ||
401 | extern int __init parse_iomem(char *str, int *add); | ||
402 | |||
403 | __uml_setup("iomem=", parse_iomem, | ||
404 | "iomem=<name>,<file>\n" | ||
405 | " Configure <file> as an IO memory region named <name>.\n\n" | ||
406 | ); | ||
407 | |||
408 | /* | ||
409 | * This list is constructed in parse_iomem and addresses filled in in | ||
410 | * setup_iomem, both of which run during early boot. Afterwards, it's | ||
411 | * unchanged. | ||
412 | */ | ||
413 | struct iomem_region *iomem_regions = NULL; | ||
414 | |||
415 | /* Initialized in parse_iomem */ | ||
416 | int iomem_size = 0; | ||
417 | |||
401 | unsigned long find_iomem(char *driver, unsigned long *len_out) | 418 | unsigned long find_iomem(char *driver, unsigned long *len_out) |
402 | { | 419 | { |
403 | struct iomem_region *region = iomem_regions; | 420 | struct iomem_region *region = iomem_regions; |
@@ -405,13 +422,13 @@ unsigned long find_iomem(char *driver, unsigned long *len_out) | |||
405 | while(region != NULL){ | 422 | while(region != NULL){ |
406 | if(!strcmp(region->driver, driver)){ | 423 | if(!strcmp(region->driver, driver)){ |
407 | *len_out = region->size; | 424 | *len_out = region->size; |
408 | return(region->virt); | 425 | return region->virt; |
409 | } | 426 | } |
410 | 427 | ||
411 | region = region->next; | 428 | region = region->next; |
412 | } | 429 | } |
413 | 430 | ||
414 | return(0); | 431 | return 0; |
415 | } | 432 | } |
416 | 433 | ||
417 | int setup_iomem(void) | 434 | int setup_iomem(void) |
@@ -435,18 +452,7 @@ int setup_iomem(void) | |||
435 | region = region->next; | 452 | region = region->next; |
436 | } | 453 | } |
437 | 454 | ||
438 | return(0); | 455 | return 0; |
439 | } | 456 | } |
440 | 457 | ||
441 | __initcall(setup_iomem); | 458 | __initcall(setup_iomem); |
442 | |||
443 | /* | ||
444 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
445 | * Emacs will notice this stuff at the end of the file and automatically | ||
446 | * adjust the settings for this buffer only. This must remain at the end | ||
447 | * of the file. | ||
448 | * --------------------------------------------------------------------------- | ||
449 | * Local variables: | ||
450 | * c-file-style: "linux" | ||
451 | * End: | ||
452 | */ | ||
diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index 9a77fb3c269d..627742d89434 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include "kern_util.h" | 18 | #include "kern_util.h" |
19 | #include "skas_ptrace.h" | 19 | #include "skas_ptrace.h" |
20 | #include "sysdep/ptrace.h" | 20 | #include "sysdep/ptrace.h" |
21 | #include "os.h" | ||
21 | 22 | ||
22 | static inline void set_singlestepping(struct task_struct *child, int on) | 23 | static inline void set_singlestepping(struct task_struct *child, int on) |
23 | { | 24 | { |
@@ -241,6 +242,12 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
241 | break; | 242 | break; |
242 | } | 243 | } |
243 | #endif | 244 | #endif |
245 | #ifdef PTRACE_ARCH_PRCTL | ||
246 | case PTRACE_ARCH_PRCTL: | ||
247 | /* XXX Calls ptrace on the host - needs some SMP thinking */ | ||
248 | ret = arch_prctl_skas(child, data, (void *) addr); | ||
249 | break; | ||
250 | #endif | ||
244 | default: | 251 | default: |
245 | ret = ptrace_request(child, request, addr, data); | 252 | ret = ptrace_request(child, request, addr, data); |
246 | break; | 253 | break; |
diff --git a/arch/um/kernel/resource.c b/arch/um/kernel/resource.c deleted file mode 100644 index 32188e12e8af..000000000000 --- a/arch/um/kernel/resource.c +++ /dev/null | |||
@@ -1,23 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #include "linux/pci.h" | ||
7 | |||
8 | unsigned long resource_fixup(struct pci_dev * dev, struct resource * res, | ||
9 | unsigned long start, unsigned long size) | ||
10 | { | ||
11 | return start; | ||
12 | } | ||
13 | |||
14 | /* | ||
15 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
16 | * Emacs will notice this stuff at the end of the file and automatically | ||
17 | * adjust the settings for this buffer only. This must remain at the end | ||
18 | * of the file. | ||
19 | * --------------------------------------------------------------------------- | ||
20 | * Local variables: | ||
21 | * c-file-style: "linux" | ||
22 | * End: | ||
23 | */ | ||
diff --git a/arch/um/kernel/sigio.c b/arch/um/kernel/sigio.c index 2b0ab438301c..89f9866a1354 100644 --- a/arch/um/kernel/sigio.c +++ b/arch/um/kernel/sigio.c | |||
@@ -23,7 +23,7 @@ static irqreturn_t sigio_interrupt(int irq, void *data) | |||
23 | 23 | ||
24 | os_read_file(sigio_irq_fd, &c, sizeof(c)); | 24 | os_read_file(sigio_irq_fd, &c, sizeof(c)); |
25 | reactivate_fd(sigio_irq_fd, SIGIO_WRITE_IRQ); | 25 | reactivate_fd(sigio_irq_fd, SIGIO_WRITE_IRQ); |
26 | return(IRQ_HANDLED); | 26 | return IRQ_HANDLED; |
27 | } | 27 | } |
28 | 28 | ||
29 | int write_sigio_irq(int fd) | 29 | int write_sigio_irq(int fd) |
@@ -36,12 +36,13 @@ int write_sigio_irq(int fd) | |||
36 | if(err){ | 36 | if(err){ |
37 | printk("write_sigio_irq : um_request_irq failed, err = %d\n", | 37 | printk("write_sigio_irq : um_request_irq failed, err = %d\n", |
38 | err); | 38 | err); |
39 | return(-1); | 39 | return -1; |
40 | } | 40 | } |
41 | sigio_irq_fd = fd; | 41 | sigio_irq_fd = fd; |
42 | return(0); | 42 | return 0; |
43 | } | 43 | } |
44 | 44 | ||
45 | /* These are called from os-Linux/sigio.c to protect its pollfds arrays. */ | ||
45 | static DEFINE_SPINLOCK(sigio_spinlock); | 46 | static DEFINE_SPINLOCK(sigio_spinlock); |
46 | 47 | ||
47 | void sigio_lock(void) | 48 | void sigio_lock(void) |
diff --git a/arch/um/kernel/skas/mem.c b/arch/um/kernel/skas/mem.c index 0d2cce621134..7c18dfcd7d8e 100644 --- a/arch/um/kernel/skas/mem.c +++ b/arch/um/kernel/skas/mem.c | |||
@@ -14,13 +14,9 @@ unsigned long set_task_sizes_skas(unsigned long *task_size_out) | |||
14 | unsigned long host_task_size = ROUND_4M((unsigned long) | 14 | unsigned long host_task_size = ROUND_4M((unsigned long) |
15 | &host_task_size); | 15 | &host_task_size); |
16 | 16 | ||
17 | #ifdef CONFIG_HOST_TASK_SIZE | ||
18 | *host_size_out = ROUND_4M(CONFIG_HOST_TASK_SIZE); | ||
19 | *task_size_out = CONFIG_HOST_TASK_SIZE; | ||
20 | #else | ||
21 | if (!skas_needs_stub) | 17 | if (!skas_needs_stub) |
22 | *task_size_out = host_task_size; | 18 | *task_size_out = host_task_size; |
23 | else *task_size_out = CONFIG_STUB_START & PGDIR_MASK; | 19 | else *task_size_out = CONFIG_STUB_START & PGDIR_MASK; |
24 | #endif | 20 | |
25 | return host_task_size; | 21 | return host_task_size; |
26 | } | 22 | } |
diff --git a/arch/um/kernel/syscall.c b/arch/um/kernel/syscall.c index f5ed8624648b..2828c5283227 100644 --- a/arch/um/kernel/syscall.c +++ b/arch/um/kernel/syscall.c | |||
@@ -149,22 +149,6 @@ long sys_olduname(struct oldold_utsname __user * name) | |||
149 | return error; | 149 | return error; |
150 | } | 150 | } |
151 | 151 | ||
152 | DEFINE_SPINLOCK(syscall_lock); | ||
153 | |||
154 | static int syscall_index = 0; | ||
155 | |||
156 | int next_syscall_index(int limit) | ||
157 | { | ||
158 | int ret; | ||
159 | |||
160 | spin_lock(&syscall_lock); | ||
161 | ret = syscall_index; | ||
162 | if(++syscall_index == limit) | ||
163 | syscall_index = 0; | ||
164 | spin_unlock(&syscall_lock); | ||
165 | return(ret); | ||
166 | } | ||
167 | |||
168 | int kernel_execve(const char *filename, char *const argv[], char *const envp[]) | 152 | int kernel_execve(const char *filename, char *const argv[], char *const envp[]) |
169 | { | 153 | { |
170 | mm_segment_t fs; | 154 | mm_segment_t fs; |
diff --git a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c index 239c98054dec..f9e02b31a97a 100644 --- a/arch/um/kernel/sysrq.c +++ b/arch/um/kernel/sysrq.c | |||
@@ -50,7 +50,7 @@ void dump_stack(void) | |||
50 | EXPORT_SYMBOL(dump_stack); | 50 | EXPORT_SYMBOL(dump_stack); |
51 | 51 | ||
52 | /*Stolen from arch/i386/kernel/traps.c */ | 52 | /*Stolen from arch/i386/kernel/traps.c */ |
53 | static int kstack_depth_to_print = 24; | 53 | static const int kstack_depth_to_print = 24; |
54 | 54 | ||
55 | /* This recently started being used in arch-independent code too, as in | 55 | /* This recently started being used in arch-independent code too, as in |
56 | * kernel/sched.c.*/ | 56 | * kernel/sched.c.*/ |
diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c index 2e354b3ca060..b1f8b0752419 100644 --- a/arch/um/kernel/time.c +++ b/arch/um/kernel/time.c | |||
@@ -35,31 +35,31 @@ unsigned long long sched_clock(void) | |||
35 | return (unsigned long long)jiffies_64 * (1000000000 / HZ); | 35 | return (unsigned long long)jiffies_64 * (1000000000 / HZ); |
36 | } | 36 | } |
37 | 37 | ||
38 | static unsigned long long prev_nsecs; | 38 | static unsigned long long prev_nsecs[NR_CPUS]; |
39 | #ifdef CONFIG_UML_REAL_TIME_CLOCK | 39 | #ifdef CONFIG_UML_REAL_TIME_CLOCK |
40 | static long long delta; /* Deviation per interval */ | 40 | static long long delta[NR_CPUS]; /* Deviation per interval */ |
41 | #endif | 41 | #endif |
42 | 42 | ||
43 | void timer_irq(union uml_pt_regs *regs) | 43 | void timer_irq(union uml_pt_regs *regs) |
44 | { | 44 | { |
45 | unsigned long long ticks = 0; | 45 | unsigned long long ticks = 0; |
46 | |||
47 | #ifdef CONFIG_UML_REAL_TIME_CLOCK | 46 | #ifdef CONFIG_UML_REAL_TIME_CLOCK |
48 | if(prev_nsecs){ | 47 | int c = cpu(); |
48 | if(prev_nsecs[c]){ | ||
49 | /* We've had 1 tick */ | 49 | /* We've had 1 tick */ |
50 | unsigned long long nsecs = os_nsecs(); | 50 | unsigned long long nsecs = os_nsecs(); |
51 | 51 | ||
52 | delta += nsecs - prev_nsecs; | 52 | delta[c] += nsecs - prev_nsecs[c]; |
53 | prev_nsecs = nsecs; | 53 | prev_nsecs[c] = nsecs; |
54 | 54 | ||
55 | /* Protect against the host clock being set backwards */ | 55 | /* Protect against the host clock being set backwards */ |
56 | if(delta < 0) | 56 | if(delta[c] < 0) |
57 | delta = 0; | 57 | delta[c] = 0; |
58 | 58 | ||
59 | ticks += (delta * HZ) / BILLION; | 59 | ticks += (delta[c] * HZ) / BILLION; |
60 | delta -= (ticks * BILLION) / HZ; | 60 | delta[c] -= (ticks * BILLION) / HZ; |
61 | } | 61 | } |
62 | else prev_nsecs = os_nsecs(); | 62 | else prev_nsecs[c] = os_nsecs(); |
63 | #else | 63 | #else |
64 | ticks = 1; | 64 | ticks = 1; |
65 | #endif | 65 | #endif |
@@ -69,8 +69,8 @@ void timer_irq(union uml_pt_regs *regs) | |||
69 | } | 69 | } |
70 | } | 70 | } |
71 | 71 | ||
72 | /* Protects local_offset */ | ||
72 | static DEFINE_SPINLOCK(timer_spinlock); | 73 | static DEFINE_SPINLOCK(timer_spinlock); |
73 | |||
74 | static unsigned long long local_offset = 0; | 74 | static unsigned long long local_offset = 0; |
75 | 75 | ||
76 | static inline unsigned long long get_time(void) | 76 | static inline unsigned long long get_time(void) |
diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c index b5f124a2f6ae..26f15c458574 100644 --- a/arch/um/kernel/trap.c +++ b/arch/um/kernel/trap.c | |||
@@ -128,7 +128,18 @@ out_of_memory: | |||
128 | goto out; | 128 | goto out; |
129 | } | 129 | } |
130 | 130 | ||
131 | void segv_handler(int sig, union uml_pt_regs *regs) | 131 | static void bad_segv(struct faultinfo fi, unsigned long ip) |
132 | { | ||
133 | struct siginfo si; | ||
134 | |||
135 | si.si_signo = SIGSEGV; | ||
136 | si.si_code = SEGV_ACCERR; | ||
137 | si.si_addr = (void __user *) FAULT_ADDRESS(fi); | ||
138 | current->thread.arch.faultinfo = fi; | ||
139 | force_sig_info(SIGSEGV, &si, current); | ||
140 | } | ||
141 | |||
142 | static void segv_handler(int sig, union uml_pt_regs *regs) | ||
132 | { | 143 | { |
133 | struct faultinfo * fi = UPT_FAULTINFO(regs); | 144 | struct faultinfo * fi = UPT_FAULTINFO(regs); |
134 | 145 | ||
@@ -205,17 +216,6 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc) | |||
205 | return(0); | 216 | return(0); |
206 | } | 217 | } |
207 | 218 | ||
208 | void bad_segv(struct faultinfo fi, unsigned long ip) | ||
209 | { | ||
210 | struct siginfo si; | ||
211 | |||
212 | si.si_signo = SIGSEGV; | ||
213 | si.si_code = SEGV_ACCERR; | ||
214 | si.si_addr = (void __user *) FAULT_ADDRESS(fi); | ||
215 | current->thread.arch.faultinfo = fi; | ||
216 | force_sig_info(SIGSEGV, &si, current); | ||
217 | } | ||
218 | |||
219 | void relay_signal(int sig, union uml_pt_regs *regs) | 219 | void relay_signal(int sig, union uml_pt_regs *regs) |
220 | { | 220 | { |
221 | if(arch_handle_signal(sig, regs)) | 221 | if(arch_handle_signal(sig, regs)) |
@@ -232,14 +232,14 @@ void relay_signal(int sig, union uml_pt_regs *regs) | |||
232 | force_sig(sig, current); | 232 | force_sig(sig, current); |
233 | } | 233 | } |
234 | 234 | ||
235 | void bus_handler(int sig, union uml_pt_regs *regs) | 235 | static void bus_handler(int sig, union uml_pt_regs *regs) |
236 | { | 236 | { |
237 | if(current->thread.fault_catcher != NULL) | 237 | if(current->thread.fault_catcher != NULL) |
238 | do_longjmp(current->thread.fault_catcher, 1); | 238 | do_longjmp(current->thread.fault_catcher, 1); |
239 | else relay_signal(sig, regs); | 239 | else relay_signal(sig, regs); |
240 | } | 240 | } |
241 | 241 | ||
242 | void winch(int sig, union uml_pt_regs *regs) | 242 | static void winch(int sig, union uml_pt_regs *regs) |
243 | { | 243 | { |
244 | do_IRQ(WINCH_IRQ, regs); | 244 | do_IRQ(WINCH_IRQ, regs); |
245 | } | 245 | } |
diff --git a/arch/um/kernel/tt/gdb.c b/arch/um/kernel/tt/gdb.c index 786e4edd86c5..8eba8f7dca68 100644 --- a/arch/um/kernel/tt/gdb.c +++ b/arch/um/kernel/tt/gdb.c | |||
@@ -139,7 +139,7 @@ static void config_gdb_cb(void *arg) | |||
139 | init_proxy(debugger_pid, 0, 0); | 139 | init_proxy(debugger_pid, 0, 0); |
140 | } | 140 | } |
141 | 141 | ||
142 | int gdb_config(char *str) | 142 | int gdb_config(char *str, char **error_out) |
143 | { | 143 | { |
144 | struct gdb_data data; | 144 | struct gdb_data data; |
145 | 145 | ||
@@ -154,7 +154,7 @@ void remove_gdb_cb(void *unused) | |||
154 | exit_debugger_cb(NULL); | 154 | exit_debugger_cb(NULL); |
155 | } | 155 | } |
156 | 156 | ||
157 | int gdb_remove(int unused) | 157 | int gdb_remove(int unused, char **error_out) |
158 | { | 158 | { |
159 | initial_thread_cb(remove_gdb_cb, NULL); | 159 | initial_thread_cb(remove_gdb_cb, NULL); |
160 | return 0; | 160 | return 0; |
diff --git a/arch/um/kernel/tt/gdb_kern.c b/arch/um/kernel/tt/gdb_kern.c index 68e1bf63cd0a..03b06bc00771 100644 --- a/arch/um/kernel/tt/gdb_kern.c +++ b/arch/um/kernel/tt/gdb_kern.c | |||
@@ -8,10 +8,11 @@ | |||
8 | 8 | ||
9 | #ifdef CONFIG_MCONSOLE | 9 | #ifdef CONFIG_MCONSOLE |
10 | 10 | ||
11 | extern int gdb_config(char *str); | 11 | extern int gdb_config(char *str, char **error_out); |
12 | extern int gdb_remove(int n); | 12 | extern int gdb_remove(int n, char **error_out); |
13 | 13 | ||
14 | static struct mc_device gdb_mc = { | 14 | static struct mc_device gdb_mc = { |
15 | .list = INIT_LIST_HEAD(gdb_mc.list), | ||
15 | .name = "gdb", | 16 | .name = "gdb", |
16 | .config = gdb_config, | 17 | .config = gdb_config, |
17 | .remove = gdb_remove, | 18 | .remove = gdb_remove, |
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index 66f43c906821..89c6dba731f8 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c | |||
@@ -30,7 +30,6 @@ | |||
30 | #include "kern.h" | 30 | #include "kern.h" |
31 | #include "mem_user.h" | 31 | #include "mem_user.h" |
32 | #include "mem.h" | 32 | #include "mem.h" |
33 | #include "umid.h" | ||
34 | #include "initrd.h" | 33 | #include "initrd.h" |
35 | #include "init.h" | 34 | #include "init.h" |
36 | #include "os.h" | 35 | #include "os.h" |
@@ -44,9 +43,9 @@ | |||
44 | #define DEFAULT_COMMAND_LINE "root=98:0" | 43 | #define DEFAULT_COMMAND_LINE "root=98:0" |
45 | 44 | ||
46 | /* Changed in linux_main and setup_arch, which run before SMP is started */ | 45 | /* Changed in linux_main and setup_arch, which run before SMP is started */ |
47 | static char command_line[COMMAND_LINE_SIZE] = { 0 }; | 46 | static char __initdata command_line[COMMAND_LINE_SIZE] = { 0 }; |
48 | 47 | ||
49 | static void add_arg(char *arg) | 48 | static void __init add_arg(char *arg) |
50 | { | 49 | { |
51 | if (strlen(command_line) + strlen(arg) + 1 > COMMAND_LINE_SIZE) { | 50 | if (strlen(command_line) + strlen(arg) + 1 > COMMAND_LINE_SIZE) { |
52 | printf("add_arg: Too many command line arguments!\n"); | 51 | printf("add_arg: Too many command line arguments!\n"); |
@@ -331,7 +330,7 @@ EXPORT_SYMBOL(end_iomem); | |||
331 | 330 | ||
332 | extern char __binary_start; | 331 | extern char __binary_start; |
333 | 332 | ||
334 | int linux_main(int argc, char **argv) | 333 | int __init linux_main(int argc, char **argv) |
335 | { | 334 | { |
336 | unsigned long avail, diff; | 335 | unsigned long avail, diff; |
337 | unsigned long virtmem_size, max_physmem; | 336 | unsigned long virtmem_size, max_physmem; |
@@ -482,7 +481,7 @@ void __init setup_arch(char **cmdline_p) | |||
482 | atomic_notifier_chain_register(&panic_notifier_list, | 481 | atomic_notifier_chain_register(&panic_notifier_list, |
483 | &panic_exit_notifier); | 482 | &panic_exit_notifier); |
484 | paging_init(); | 483 | paging_init(); |
485 | strlcpy(saved_command_line, command_line, COMMAND_LINE_SIZE); | 484 | strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE); |
486 | *cmdline_p = command_line; | 485 | *cmdline_p = command_line; |
487 | setup_hostinfo(); | 486 | setup_hostinfo(); |
488 | } | 487 | } |
diff --git a/arch/um/kernel/umid.c b/arch/um/kernel/umid.c index 4eaee823bfd2..039e16efcd55 100644 --- a/arch/um/kernel/umid.c +++ b/arch/um/kernel/umid.c | |||
@@ -16,8 +16,10 @@ static int __init set_umid_arg(char *name, int *add) | |||
16 | { | 16 | { |
17 | int err; | 17 | int err; |
18 | 18 | ||
19 | if(umid_inited) | 19 | if(umid_inited){ |
20 | printf("umid already set\n"); | ||
20 | return 0; | 21 | return 0; |
22 | } | ||
21 | 23 | ||
22 | *add = 0; | 24 | *add = 0; |
23 | err = set_umid(name); | 25 | err = set_umid(name); |
diff --git a/arch/um/os-Linux/aio.c b/arch/um/os-Linux/aio.c index f897140cc4ae..6ff12743a0bd 100644 --- a/arch/um/os-Linux/aio.c +++ b/arch/um/os-Linux/aio.c | |||
@@ -24,9 +24,6 @@ struct aio_thread_req { | |||
24 | struct aio_context *aio; | 24 | struct aio_context *aio; |
25 | }; | 25 | }; |
26 | 26 | ||
27 | static int aio_req_fd_r = -1; | ||
28 | static int aio_req_fd_w = -1; | ||
29 | |||
30 | #if defined(HAVE_AIO_ABI) | 27 | #if defined(HAVE_AIO_ABI) |
31 | #include <linux/aio_abi.h> | 28 | #include <linux/aio_abi.h> |
32 | 29 | ||
@@ -111,6 +108,7 @@ static int do_aio(aio_context_t ctx, enum aio_type type, int fd, char *buf, | |||
111 | return err; | 108 | return err; |
112 | } | 109 | } |
113 | 110 | ||
111 | /* Initialized in an initcall and unchanged thereafter */ | ||
114 | static aio_context_t ctx = 0; | 112 | static aio_context_t ctx = 0; |
115 | 113 | ||
116 | static int aio_thread(void *arg) | 114 | static int aio_thread(void *arg) |
@@ -137,7 +135,7 @@ static int aio_thread(void *arg) | |||
137 | err = os_write_file(reply_fd, &reply, sizeof(reply)); | 135 | err = os_write_file(reply_fd, &reply, sizeof(reply)); |
138 | if(err != sizeof(reply)) | 136 | if(err != sizeof(reply)) |
139 | printk("aio_thread - write failed, fd = %d, " | 137 | printk("aio_thread - write failed, fd = %d, " |
140 | "err = %d\n", aio_req_fd_r, -err); | 138 | "err = %d\n", reply_fd, -err); |
141 | } | 139 | } |
142 | } | 140 | } |
143 | return 0; | 141 | return 0; |
@@ -182,6 +180,11 @@ out: | |||
182 | return err; | 180 | return err; |
183 | } | 181 | } |
184 | 182 | ||
183 | /* These are initialized in initcalls and not changed */ | ||
184 | static int aio_req_fd_r = -1; | ||
185 | static int aio_req_fd_w = -1; | ||
186 | static int aio_pid = -1; | ||
187 | |||
185 | static int not_aio_thread(void *arg) | 188 | static int not_aio_thread(void *arg) |
186 | { | 189 | { |
187 | struct aio_thread_req req; | 190 | struct aio_thread_req req; |
@@ -208,14 +211,12 @@ static int not_aio_thread(void *arg) | |||
208 | err = os_write_file(req.aio->reply_fd, &reply, sizeof(reply)); | 211 | err = os_write_file(req.aio->reply_fd, &reply, sizeof(reply)); |
209 | if(err != sizeof(reply)) | 212 | if(err != sizeof(reply)) |
210 | printk("not_aio_thread - write failed, fd = %d, " | 213 | printk("not_aio_thread - write failed, fd = %d, " |
211 | "err = %d\n", aio_req_fd_r, -err); | 214 | "err = %d\n", req.aio->reply_fd, -err); |
212 | } | 215 | } |
213 | 216 | ||
214 | return 0; | 217 | return 0; |
215 | } | 218 | } |
216 | 219 | ||
217 | static int aio_pid = -1; | ||
218 | |||
219 | static int init_aio_24(void) | 220 | static int init_aio_24(void) |
220 | { | 221 | { |
221 | unsigned long stack; | 222 | unsigned long stack; |
@@ -308,6 +309,7 @@ static int submit_aio_26(enum aio_type type, int io_fd, char *buf, int len, | |||
308 | } | 309 | } |
309 | #endif | 310 | #endif |
310 | 311 | ||
312 | /* Initialized in an initcall and unchanged thereafter */ | ||
311 | static int aio_24 = DEFAULT_24_AIO; | 313 | static int aio_24 = DEFAULT_24_AIO; |
312 | 314 | ||
313 | static int __init set_aio_24(char *name, int *add) | 315 | static int __init set_aio_24(char *name, int *add) |
diff --git a/arch/um/os-Linux/elf_aux.c b/arch/um/os-Linux/elf_aux.c index 5a99dd3fbed0..3a8d7e3aae0a 100644 --- a/arch/um/os-Linux/elf_aux.c +++ b/arch/um/os-Linux/elf_aux.c | |||
@@ -21,12 +21,11 @@ typedef Elf32_auxv_t elf_auxv_t; | |||
21 | typedef Elf64_auxv_t elf_auxv_t; | 21 | typedef Elf64_auxv_t elf_auxv_t; |
22 | #endif | 22 | #endif |
23 | 23 | ||
24 | /* These are initialized very early in boot and never changed */ | ||
24 | char * elf_aux_platform; | 25 | char * elf_aux_platform; |
25 | long elf_aux_hwcap; | 26 | long elf_aux_hwcap; |
26 | |||
27 | unsigned long vsyscall_ehdr; | 27 | unsigned long vsyscall_ehdr; |
28 | unsigned long vsyscall_end; | 28 | unsigned long vsyscall_end; |
29 | |||
30 | unsigned long __kernel_vsyscall; | 29 | unsigned long __kernel_vsyscall; |
31 | 30 | ||
32 | __init void scan_elf_aux( char **envp) | 31 | __init void scan_elf_aux( char **envp) |
diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c index 189fa677085a..371b4335f46d 100644 --- a/arch/um/os-Linux/file.c +++ b/arch/um/os-Linux/file.c | |||
@@ -162,25 +162,6 @@ int os_set_owner(int fd, int pid) | |||
162 | return 0; | 162 | return 0; |
163 | } | 163 | } |
164 | 164 | ||
165 | /* FIXME? moved wholesale from sigio_user.c to get fcntls out of that file */ | ||
166 | int os_sigio_async(int master, int slave) | ||
167 | { | ||
168 | int flags; | ||
169 | |||
170 | flags = fcntl(master, F_GETFL); | ||
171 | if(flags < 0) | ||
172 | return -errno; | ||
173 | |||
174 | if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) || | ||
175 | (fcntl(master, F_SETOWN, os_getpid()) < 0)) | ||
176 | return -errno; | ||
177 | |||
178 | if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0)) | ||
179 | return -errno; | ||
180 | |||
181 | return(0); | ||
182 | } | ||
183 | |||
184 | int os_mode_fd(int fd, int mode) | 165 | int os_mode_fd(int fd, int mode) |
185 | { | 166 | { |
186 | int err; | 167 | int err; |
diff --git a/arch/um/os-Linux/irq.c b/arch/um/os-Linux/irq.c index d46b818c1311..d1b61d474e0a 100644 --- a/arch/um/os-Linux/irq.c +++ b/arch/um/os-Linux/irq.c | |||
@@ -20,6 +20,10 @@ | |||
20 | #include "os.h" | 20 | #include "os.h" |
21 | #include "um_malloc.h" | 21 | #include "um_malloc.h" |
22 | 22 | ||
23 | /* | ||
24 | * Locked by irq_lock in arch/um/kernel/irq.c. Changed by os_create_pollfd | ||
25 | * and os_free_irq_by_cb, which are called under irq_lock. | ||
26 | */ | ||
23 | static struct pollfd *pollfds = NULL; | 27 | static struct pollfd *pollfds = NULL; |
24 | static int pollfds_num = 0; | 28 | static int pollfds_num = 0; |
25 | static int pollfds_size = 0; | 29 | static int pollfds_size = 0; |
@@ -58,7 +62,7 @@ int os_create_pollfd(int fd, int events, void *tmp_pfd, int size_tmpfds) | |||
58 | if (pollfds_num == pollfds_size) { | 62 | if (pollfds_num == pollfds_size) { |
59 | if (size_tmpfds <= pollfds_size * sizeof(pollfds[0])) { | 63 | if (size_tmpfds <= pollfds_size * sizeof(pollfds[0])) { |
60 | /* return min size needed for new pollfds area */ | 64 | /* return min size needed for new pollfds area */ |
61 | return((pollfds_size + 1) * sizeof(pollfds[0])); | 65 | return (pollfds_size + 1) * sizeof(pollfds[0]); |
62 | } | 66 | } |
63 | 67 | ||
64 | if (pollfds != NULL) { | 68 | if (pollfds != NULL) { |
diff --git a/arch/um/os-Linux/mem.c b/arch/um/os-Linux/mem.c index 4203681e508d..f1ea169db85e 100644 --- a/arch/um/os-Linux/mem.c +++ b/arch/um/os-Linux/mem.c | |||
@@ -20,7 +20,13 @@ | |||
20 | 20 | ||
21 | #include <sys/param.h> | 21 | #include <sys/param.h> |
22 | 22 | ||
23 | /* Modified by which_tmpdir, which is called during early boot */ | ||
23 | static char *default_tmpdir = "/tmp"; | 24 | static char *default_tmpdir = "/tmp"; |
25 | |||
26 | /* | ||
27 | * Modified when creating the physical memory file and when checking | ||
28 | * the tmp filesystem for usability, both happening during early boot. | ||
29 | */ | ||
24 | static char *tempdir = NULL; | 30 | static char *tempdir = NULL; |
25 | 31 | ||
26 | static void __init find_tempdir(void) | 32 | static void __init find_tempdir(void) |
@@ -29,7 +35,8 @@ static void __init find_tempdir(void) | |||
29 | int i; | 35 | int i; |
30 | char *dir = NULL; | 36 | char *dir = NULL; |
31 | 37 | ||
32 | if(tempdir != NULL) return; /* We've already been called */ | 38 | if(tempdir != NULL) /* We've already been called */ |
39 | return; | ||
33 | for(i = 0; dirs[i]; i++){ | 40 | for(i = 0; dirs[i]; i++){ |
34 | dir = getenv(dirs[i]); | 41 | dir = getenv(dirs[i]); |
35 | if((dir != NULL) && (*dir != '\0')) | 42 | if((dir != NULL) && (*dir != '\0')) |
@@ -83,6 +90,7 @@ static int next(int fd, char *buf, int size, char c) | |||
83 | return 1; | 90 | return 1; |
84 | } | 91 | } |
85 | 92 | ||
93 | /* which_tmpdir is called only during early boot */ | ||
86 | static int checked_tmpdir = 0; | 94 | static int checked_tmpdir = 0; |
87 | 95 | ||
88 | /* Look for a tmpfs mounted at /dev/shm. I couldn't find a cleaner | 96 | /* Look for a tmpfs mounted at /dev/shm. I couldn't find a cleaner |
@@ -186,7 +194,7 @@ int make_tempfile(const char *template, char **out_tempname, int do_unlink) | |||
186 | } else { | 194 | } else { |
187 | free(tempname); | 195 | free(tempname); |
188 | } | 196 | } |
189 | return(fd); | 197 | return fd; |
190 | out: | 198 | out: |
191 | free(tempname); | 199 | free(tempname); |
192 | return -1; | 200 | return -1; |
@@ -231,7 +239,7 @@ int create_tmp_file(unsigned long long len) | |||
231 | exit(1); | 239 | exit(1); |
232 | } | 240 | } |
233 | 241 | ||
234 | return(fd); | 242 | return fd; |
235 | } | 243 | } |
236 | 244 | ||
237 | int create_mem_file(unsigned long long len) | 245 | int create_mem_file(unsigned long long len) |
@@ -245,7 +253,7 @@ int create_mem_file(unsigned long long len) | |||
245 | errno = -err; | 253 | errno = -err; |
246 | perror("exec_close"); | 254 | perror("exec_close"); |
247 | } | 255 | } |
248 | return(fd); | 256 | return fd; |
249 | } | 257 | } |
250 | 258 | ||
251 | 259 | ||
diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c index 7fe92680c7dd..5178eba9afa5 100644 --- a/arch/um/os-Linux/start_up.c +++ b/arch/um/os-Linux/start_up.c | |||
@@ -54,7 +54,7 @@ static int ptrace_child(void *arg) | |||
54 | perror("ptrace"); | 54 | perror("ptrace"); |
55 | os_kill_process(pid, 0); | 55 | os_kill_process(pid, 0); |
56 | } | 56 | } |
57 | os_stop_process(pid); | 57 | kill(pid, SIGSTOP); |
58 | 58 | ||
59 | /*This syscall will be intercepted by the parent. Don't call more than | 59 | /*This syscall will be intercepted by the parent. Don't call more than |
60 | * once, please.*/ | 60 | * once, please.*/ |
@@ -73,6 +73,34 @@ static int ptrace_child(void *arg) | |||
73 | _exit(ret); | 73 | _exit(ret); |
74 | } | 74 | } |
75 | 75 | ||
76 | static void fatal_perror(char *str) | ||
77 | { | ||
78 | perror(str); | ||
79 | exit(1); | ||
80 | } | ||
81 | |||
82 | static void fatal(char *fmt, ...) | ||
83 | { | ||
84 | va_list list; | ||
85 | |||
86 | va_start(list, fmt); | ||
87 | vprintf(fmt, list); | ||
88 | va_end(list); | ||
89 | fflush(stdout); | ||
90 | |||
91 | exit(1); | ||
92 | } | ||
93 | |||
94 | static void non_fatal(char *fmt, ...) | ||
95 | { | ||
96 | va_list list; | ||
97 | |||
98 | va_start(list, fmt); | ||
99 | vprintf(fmt, list); | ||
100 | va_end(list); | ||
101 | fflush(stdout); | ||
102 | } | ||
103 | |||
76 | static int start_ptraced_child(void **stack_out) | 104 | static int start_ptraced_child(void **stack_out) |
77 | { | 105 | { |
78 | void *stack; | 106 | void *stack; |
@@ -82,20 +110,20 @@ static int start_ptraced_child(void **stack_out) | |||
82 | stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, | 110 | stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, |
83 | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | 111 | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); |
84 | if(stack == MAP_FAILED) | 112 | if(stack == MAP_FAILED) |
85 | panic("check_ptrace : mmap failed, errno = %d", errno); | 113 | fatal_perror("check_ptrace : mmap failed"); |
86 | sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *); | 114 | sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *); |
87 | pid = clone(ptrace_child, (void *) sp, SIGCHLD, NULL); | 115 | pid = clone(ptrace_child, (void *) sp, SIGCHLD, NULL); |
88 | if(pid < 0) | 116 | if(pid < 0) |
89 | panic("start_ptraced_child : clone failed, errno = %d", errno); | 117 | fatal_perror("start_ptraced_child : clone failed"); |
90 | CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); | 118 | CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); |
91 | if(n < 0) | 119 | if(n < 0) |
92 | panic("check_ptrace : clone failed, errno = %d", errno); | 120 | fatal_perror("check_ptrace : clone failed"); |
93 | if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) | 121 | if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) |
94 | panic("check_ptrace : expected SIGSTOP, got status = %d", | 122 | fatal("check_ptrace : expected SIGSTOP, got status = %d", |
95 | status); | 123 | status); |
96 | 124 | ||
97 | *stack_out = stack; | 125 | *stack_out = stack; |
98 | return(pid); | 126 | return pid; |
99 | } | 127 | } |
100 | 128 | ||
101 | /* When testing for SYSEMU support, if it is one of the broken versions, we | 129 | /* When testing for SYSEMU support, if it is one of the broken versions, we |
@@ -105,34 +133,34 @@ static int start_ptraced_child(void **stack_out) | |||
105 | * must work anyway! | 133 | * must work anyway! |
106 | */ | 134 | */ |
107 | static int stop_ptraced_child(int pid, void *stack, int exitcode, | 135 | static int stop_ptraced_child(int pid, void *stack, int exitcode, |
108 | int mustpanic) | 136 | int mustexit) |
109 | { | 137 | { |
110 | int status, n, ret = 0; | 138 | int status, n, ret = 0; |
111 | 139 | ||
112 | if(ptrace(PTRACE_CONT, pid, 0, 0) < 0) | 140 | if(ptrace(PTRACE_CONT, pid, 0, 0) < 0) |
113 | panic("check_ptrace : ptrace failed, errno = %d", errno); | 141 | fatal_perror("stop_ptraced_child : ptrace failed"); |
114 | CATCH_EINTR(n = waitpid(pid, &status, 0)); | 142 | CATCH_EINTR(n = waitpid(pid, &status, 0)); |
115 | if(!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) { | 143 | if(!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) { |
116 | int exit_with = WEXITSTATUS(status); | 144 | int exit_with = WEXITSTATUS(status); |
117 | if (exit_with == 2) | 145 | if (exit_with == 2) |
118 | printf("check_ptrace : child exited with status 2. " | 146 | non_fatal("check_ptrace : child exited with status 2. " |
119 | "Serious trouble happening! Try updating your " | 147 | "Serious trouble happening! Try updating " |
120 | "host skas patch!\nDisabling SYSEMU support."); | 148 | "your host skas patch!\nDisabling SYSEMU " |
121 | printf("check_ptrace : child exited with exitcode %d, while " | 149 | "support."); |
122 | "expecting %d; status 0x%x", exit_with, | 150 | non_fatal("check_ptrace : child exited with exitcode %d, while " |
123 | exitcode, status); | 151 | "expecting %d; status 0x%x\n", exit_with, |
124 | if (mustpanic) | 152 | exitcode, status); |
125 | panic("\n"); | 153 | if (mustexit) |
126 | else | 154 | exit(1); |
127 | printf("\n"); | ||
128 | ret = -1; | 155 | ret = -1; |
129 | } | 156 | } |
130 | 157 | ||
131 | if(munmap(stack, PAGE_SIZE) < 0) | 158 | if(munmap(stack, PAGE_SIZE) < 0) |
132 | panic("check_ptrace : munmap failed, errno = %d", errno); | 159 | fatal_perror("check_ptrace : munmap failed"); |
133 | return ret; | 160 | return ret; |
134 | } | 161 | } |
135 | 162 | ||
163 | /* Changed only during early boot */ | ||
136 | int ptrace_faultinfo = 1; | 164 | int ptrace_faultinfo = 1; |
137 | int ptrace_ldt = 1; | 165 | int ptrace_ldt = 1; |
138 | int proc_mm = 1; | 166 | int proc_mm = 1; |
@@ -160,6 +188,7 @@ __uml_setup("mode=skas0", mode_skas0_cmd_param, | |||
160 | " specify mode=tt. Note that this was recently added - on \n" | 188 | " specify mode=tt. Note that this was recently added - on \n" |
161 | " older kernels you must use simply \"skas0\".\n\n"); | 189 | " older kernels you must use simply \"skas0\".\n\n"); |
162 | 190 | ||
191 | /* Changed only during early boot */ | ||
163 | static int force_sysemu_disabled = 0; | 192 | static int force_sysemu_disabled = 0; |
164 | 193 | ||
165 | static int __init nosysemu_cmd_param(char *str, int* add) | 194 | static int __init nosysemu_cmd_param(char *str, int* add) |
@@ -180,9 +209,9 @@ __uml_setup("nosysemu", nosysemu_cmd_param, | |||
180 | static void __init check_sysemu(void) | 209 | static void __init check_sysemu(void) |
181 | { | 210 | { |
182 | void *stack; | 211 | void *stack; |
183 | int pid, n, status, count=0; | 212 | int pid, n, status, count=0; |
184 | 213 | ||
185 | printf("Checking syscall emulation patch for ptrace..."); | 214 | non_fatal("Checking syscall emulation patch for ptrace..."); |
186 | sysemu_supported = 0; | 215 | sysemu_supported = 0; |
187 | pid = start_ptraced_child(&stack); | 216 | pid = start_ptraced_child(&stack); |
188 | 217 | ||
@@ -191,31 +220,30 @@ static void __init check_sysemu(void) | |||
191 | 220 | ||
192 | CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); | 221 | CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); |
193 | if (n < 0) | 222 | if (n < 0) |
194 | panic("check_sysemu : wait failed, errno = %d", errno); | 223 | fatal_perror("check_sysemu : wait failed"); |
195 | if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) | 224 | if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) |
196 | panic("check_sysemu : expected SIGTRAP, " | 225 | fatal("check_sysemu : expected SIGTRAP, got status = %d", |
197 | "got status = %d", status); | 226 | status); |
198 | 227 | ||
199 | n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, | 228 | n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, |
200 | os_getpid()); | 229 | os_getpid()); |
201 | if(n < 0) | 230 | if(n < 0) |
202 | panic("check_sysemu : failed to modify system " | 231 | fatal_perror("check_sysemu : failed to modify system call " |
203 | "call return, errno = %d", errno); | 232 | "return"); |
204 | 233 | ||
205 | if (stop_ptraced_child(pid, stack, 0, 0) < 0) | 234 | if (stop_ptraced_child(pid, stack, 0, 0) < 0) |
206 | goto fail_stopped; | 235 | goto fail_stopped; |
207 | 236 | ||
208 | sysemu_supported = 1; | 237 | sysemu_supported = 1; |
209 | printf("OK\n"); | 238 | non_fatal("OK\n"); |
210 | set_using_sysemu(!force_sysemu_disabled); | 239 | set_using_sysemu(!force_sysemu_disabled); |
211 | 240 | ||
212 | printf("Checking advanced syscall emulation patch for ptrace..."); | 241 | non_fatal("Checking advanced syscall emulation patch for ptrace..."); |
213 | pid = start_ptraced_child(&stack); | 242 | pid = start_ptraced_child(&stack); |
214 | 243 | ||
215 | if(ptrace(PTRACE_OLDSETOPTIONS, pid, 0, | 244 | if((ptrace(PTRACE_OLDSETOPTIONS, pid, 0, |
216 | (void *) PTRACE_O_TRACESYSGOOD) < 0) | 245 | (void *) PTRACE_O_TRACESYSGOOD) < 0)) |
217 | panic("check_ptrace: PTRACE_OLDSETOPTIONS failed, errno = %d", | 246 | fatal_perror("check_ptrace: PTRACE_OLDSETOPTIONS failed"); |
218 | errno); | ||
219 | 247 | ||
220 | while(1){ | 248 | while(1){ |
221 | count++; | 249 | count++; |
@@ -223,29 +251,30 @@ static void __init check_sysemu(void) | |||
223 | goto fail; | 251 | goto fail; |
224 | CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); | 252 | CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); |
225 | if(n < 0) | 253 | if(n < 0) |
226 | panic("check_ptrace : wait failed, errno = %d", errno); | 254 | fatal_perror("check_ptrace : wait failed"); |
255 | |||
227 | if(WIFSTOPPED(status) && (WSTOPSIG(status) == (SIGTRAP|0x80))){ | 256 | if(WIFSTOPPED(status) && (WSTOPSIG(status) == (SIGTRAP|0x80))){ |
228 | if (!count) | 257 | if (!count) |
229 | panic("check_ptrace : SYSEMU_SINGLESTEP " | 258 | fatal("check_ptrace : SYSEMU_SINGLESTEP " |
230 | "doesn't singlestep"); | 259 | "doesn't singlestep"); |
231 | n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, | 260 | n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, |
232 | os_getpid()); | 261 | os_getpid()); |
233 | if(n < 0) | 262 | if(n < 0) |
234 | panic("check_sysemu : failed to modify system " | 263 | fatal_perror("check_sysemu : failed to modify " |
235 | "call return, errno = %d", errno); | 264 | "system call return"); |
236 | break; | 265 | break; |
237 | } | 266 | } |
238 | else if(WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP)) | 267 | else if(WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP)) |
239 | count++; | 268 | count++; |
240 | else | 269 | else |
241 | panic("check_ptrace : expected SIGTRAP or " | 270 | fatal("check_ptrace : expected SIGTRAP or " |
242 | "(SIGTRAP|0x80), got status = %d", status); | 271 | "(SIGTRAP | 0x80), got status = %d", status); |
243 | } | 272 | } |
244 | if (stop_ptraced_child(pid, stack, 0, 0) < 0) | 273 | if (stop_ptraced_child(pid, stack, 0, 0) < 0) |
245 | goto fail_stopped; | 274 | goto fail_stopped; |
246 | 275 | ||
247 | sysemu_supported = 2; | 276 | sysemu_supported = 2; |
248 | printf("OK\n"); | 277 | non_fatal("OK\n"); |
249 | 278 | ||
250 | if ( !force_sysemu_disabled ) | 279 | if ( !force_sysemu_disabled ) |
251 | set_using_sysemu(sysemu_supported); | 280 | set_using_sysemu(sysemu_supported); |
@@ -254,7 +283,7 @@ static void __init check_sysemu(void) | |||
254 | fail: | 283 | fail: |
255 | stop_ptraced_child(pid, stack, 1, 0); | 284 | stop_ptraced_child(pid, stack, 1, 0); |
256 | fail_stopped: | 285 | fail_stopped: |
257 | printf("missing\n"); | 286 | non_fatal("missing\n"); |
258 | } | 287 | } |
259 | 288 | ||
260 | static void __init check_ptrace(void) | 289 | static void __init check_ptrace(void) |
@@ -262,22 +291,25 @@ static void __init check_ptrace(void) | |||
262 | void *stack; | 291 | void *stack; |
263 | int pid, syscall, n, status; | 292 | int pid, syscall, n, status; |
264 | 293 | ||
265 | printf("Checking that ptrace can change system call numbers..."); | 294 | non_fatal("Checking that ptrace can change system call numbers..."); |
266 | pid = start_ptraced_child(&stack); | 295 | pid = start_ptraced_child(&stack); |
267 | 296 | ||
268 | if(ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0) | 297 | if((ptrace(PTRACE_OLDSETOPTIONS, pid, 0, |
269 | panic("check_ptrace: PTRACE_OLDSETOPTIONS failed, errno = %d", errno); | 298 | (void *) PTRACE_O_TRACESYSGOOD) < 0)) |
299 | fatal_perror("check_ptrace: PTRACE_OLDSETOPTIONS failed"); | ||
270 | 300 | ||
271 | while(1){ | 301 | while(1){ |
272 | if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) | 302 | if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) |
273 | panic("check_ptrace : ptrace failed, errno = %d", | 303 | fatal_perror("check_ptrace : ptrace failed"); |
274 | errno); | 304 | |
275 | CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); | 305 | CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); |
276 | if(n < 0) | 306 | if(n < 0) |
277 | panic("check_ptrace : wait failed, errno = %d", errno); | 307 | fatal_perror("check_ptrace : wait failed"); |
278 | if(!WIFSTOPPED(status) || (WSTOPSIG(status) != (SIGTRAP|0x80))) | 308 | |
279 | panic("check_ptrace : expected (SIGTRAP|0x80), " | 309 | if(!WIFSTOPPED(status) || |
280 | "got status = %d", status); | 310 | (WSTOPSIG(status) != (SIGTRAP | 0x80))) |
311 | fatal("check_ptrace : expected (SIGTRAP|0x80), " | ||
312 | "got status = %d", status); | ||
281 | 313 | ||
282 | syscall = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_NR_OFFSET, | 314 | syscall = ptrace(PTRACE_PEEKUSR, pid, PT_SYSCALL_NR_OFFSET, |
283 | 0); | 315 | 0); |
@@ -285,13 +317,13 @@ static void __init check_ptrace(void) | |||
285 | n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, | 317 | n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_NR_OFFSET, |
286 | __NR_getppid); | 318 | __NR_getppid); |
287 | if(n < 0) | 319 | if(n < 0) |
288 | panic("check_ptrace : failed to modify system " | 320 | fatal_perror("check_ptrace : failed to modify " |
289 | "call, errno = %d", errno); | 321 | "system call"); |
290 | break; | 322 | break; |
291 | } | 323 | } |
292 | } | 324 | } |
293 | stop_ptraced_child(pid, stack, 0, 1); | 325 | stop_ptraced_child(pid, stack, 0, 1); |
294 | printf("OK\n"); | 326 | non_fatal("OK\n"); |
295 | check_sysemu(); | 327 | check_sysemu(); |
296 | } | 328 | } |
297 | 329 | ||
@@ -350,22 +382,22 @@ static inline void check_skas3_ptrace_faultinfo(void) | |||
350 | void *stack; | 382 | void *stack; |
351 | int pid, n; | 383 | int pid, n; |
352 | 384 | ||
353 | printf(" - PTRACE_FAULTINFO..."); | 385 | non_fatal(" - PTRACE_FAULTINFO..."); |
354 | pid = start_ptraced_child(&stack); | 386 | pid = start_ptraced_child(&stack); |
355 | 387 | ||
356 | n = ptrace(PTRACE_FAULTINFO, pid, 0, &fi); | 388 | n = ptrace(PTRACE_FAULTINFO, pid, 0, &fi); |
357 | if (n < 0) { | 389 | if (n < 0) { |
358 | ptrace_faultinfo = 0; | 390 | ptrace_faultinfo = 0; |
359 | if(errno == EIO) | 391 | if(errno == EIO) |
360 | printf("not found\n"); | 392 | non_fatal("not found\n"); |
361 | else | 393 | else |
362 | perror("not found"); | 394 | perror("not found"); |
363 | } | 395 | } |
364 | else { | 396 | else { |
365 | if (!ptrace_faultinfo) | 397 | if (!ptrace_faultinfo) |
366 | printf("found but disabled on command line\n"); | 398 | non_fatal("found but disabled on command line\n"); |
367 | else | 399 | else |
368 | printf("found\n"); | 400 | non_fatal("found\n"); |
369 | } | 401 | } |
370 | 402 | ||
371 | init_registers(pid); | 403 | init_registers(pid); |
@@ -383,13 +415,13 @@ static inline void check_skas3_ptrace_ldt(void) | |||
383 | .ptr = ldtbuf, | 415 | .ptr = ldtbuf, |
384 | .bytecount = sizeof(ldtbuf)}; | 416 | .bytecount = sizeof(ldtbuf)}; |
385 | 417 | ||
386 | printf(" - PTRACE_LDT..."); | 418 | non_fatal(" - PTRACE_LDT..."); |
387 | pid = start_ptraced_child(&stack); | 419 | pid = start_ptraced_child(&stack); |
388 | 420 | ||
389 | n = ptrace(PTRACE_LDT, pid, 0, (unsigned long) &ldt_op); | 421 | n = ptrace(PTRACE_LDT, pid, 0, (unsigned long) &ldt_op); |
390 | if (n < 0) { | 422 | if (n < 0) { |
391 | if(errno == EIO) | 423 | if(errno == EIO) |
392 | printf("not found\n"); | 424 | non_fatal("not found\n"); |
393 | else { | 425 | else { |
394 | perror("not found"); | 426 | perror("not found"); |
395 | } | 427 | } |
@@ -397,9 +429,9 @@ static inline void check_skas3_ptrace_ldt(void) | |||
397 | } | 429 | } |
398 | else { | 430 | else { |
399 | if(ptrace_ldt) | 431 | if(ptrace_ldt) |
400 | printf("found\n"); | 432 | non_fatal("found\n"); |
401 | else | 433 | else |
402 | printf("found, but use is disabled\n"); | 434 | non_fatal("found, but use is disabled\n"); |
403 | } | 435 | } |
404 | 436 | ||
405 | stop_ptraced_child(pid, stack, 1, 1); | 437 | stop_ptraced_child(pid, stack, 1, 1); |
@@ -414,22 +446,22 @@ static inline void check_skas3_ptrace_ldt(void) | |||
414 | 446 | ||
415 | static inline void check_skas3_proc_mm(void) | 447 | static inline void check_skas3_proc_mm(void) |
416 | { | 448 | { |
417 | printf(" - /proc/mm..."); | 449 | non_fatal(" - /proc/mm..."); |
418 | if (os_access("/proc/mm", OS_ACC_W_OK) < 0) { | 450 | if (access("/proc/mm", W_OK) < 0) { |
419 | proc_mm = 0; | 451 | proc_mm = 0; |
420 | printf("not found\n"); | 452 | perror("not found"); |
421 | } | 453 | } |
422 | else { | 454 | else { |
423 | if (!proc_mm) | 455 | if (!proc_mm) |
424 | printf("found but disabled on command line\n"); | 456 | non_fatal("found but disabled on command line\n"); |
425 | else | 457 | else |
426 | printf("found\n"); | 458 | non_fatal("found\n"); |
427 | } | 459 | } |
428 | } | 460 | } |
429 | 461 | ||
430 | int can_do_skas(void) | 462 | int can_do_skas(void) |
431 | { | 463 | { |
432 | printf("Checking for the skas3 patch in the host:\n"); | 464 | non_fatal("Checking for the skas3 patch in the host:\n"); |
433 | 465 | ||
434 | check_skas3_proc_mm(); | 466 | check_skas3_proc_mm(); |
435 | check_skas3_ptrace_faultinfo(); | 467 | check_skas3_ptrace_faultinfo(); |
@@ -443,16 +475,16 @@ int can_do_skas(void) | |||
443 | #else | 475 | #else |
444 | int can_do_skas(void) | 476 | int can_do_skas(void) |
445 | { | 477 | { |
446 | return(0); | 478 | return 0; |
447 | } | 479 | } |
448 | #endif | 480 | #endif |
449 | 481 | ||
450 | int __init parse_iomem(char *str, int *add) | 482 | int __init parse_iomem(char *str, int *add) |
451 | { | 483 | { |
452 | struct iomem_region *new; | 484 | struct iomem_region *new; |
453 | struct uml_stat buf; | 485 | struct stat64 buf; |
454 | char *file, *driver; | 486 | char *file, *driver; |
455 | int fd, err, size; | 487 | int fd, size; |
456 | 488 | ||
457 | driver = str; | 489 | driver = str; |
458 | file = strchr(str,','); | 490 | file = strchr(str,','); |
@@ -462,15 +494,14 @@ int __init parse_iomem(char *str, int *add) | |||
462 | } | 494 | } |
463 | *file = '\0'; | 495 | *file = '\0'; |
464 | file++; | 496 | file++; |
465 | fd = os_open_file(file, of_rdwr(OPENFLAGS()), 0); | 497 | fd = open(file, O_RDWR, 0); |
466 | if(fd < 0){ | 498 | if(fd < 0){ |
467 | os_print_error(fd, "parse_iomem - Couldn't open io file"); | 499 | os_print_error(fd, "parse_iomem - Couldn't open io file"); |
468 | goto out; | 500 | goto out; |
469 | } | 501 | } |
470 | 502 | ||
471 | err = os_stat_fd(fd, &buf); | 503 | if(fstat64(fd, &buf) < 0){ |
472 | if(err < 0){ | 504 | perror("parse_iomem - cannot stat_fd file"); |
473 | os_print_error(err, "parse_iomem - cannot stat_fd file"); | ||
474 | goto out_close; | 505 | goto out_close; |
475 | } | 506 | } |
476 | 507 | ||
@@ -480,7 +511,7 @@ int __init parse_iomem(char *str, int *add) | |||
480 | goto out_close; | 511 | goto out_close; |
481 | } | 512 | } |
482 | 513 | ||
483 | size = (buf.ust_size + UM_KERN_PAGE_SIZE) & ~(UM_KERN_PAGE_SIZE - 1); | 514 | size = (buf.st_size + UM_KERN_PAGE_SIZE) & ~(UM_KERN_PAGE_SIZE - 1); |
484 | 515 | ||
485 | *new = ((struct iomem_region) { .next = iomem_regions, | 516 | *new = ((struct iomem_region) { .next = iomem_regions, |
486 | .driver = driver, | 517 | .driver = driver, |
@@ -491,11 +522,11 @@ int __init parse_iomem(char *str, int *add) | |||
491 | iomem_regions = new; | 522 | iomem_regions = new; |
492 | iomem_size += new->size + UM_KERN_PAGE_SIZE; | 523 | iomem_size += new->size + UM_KERN_PAGE_SIZE; |
493 | 524 | ||
494 | return(0); | 525 | return 0; |
495 | out_close: | 526 | out_close: |
496 | os_close_file(fd); | 527 | close(fd); |
497 | out: | 528 | out: |
498 | return(1); | 529 | return 1; |
499 | } | 530 | } |
500 | 531 | ||
501 | 532 | ||
@@ -526,6 +557,24 @@ static void openpty_cb(void *arg) | |||
526 | info->err = -errno; | 557 | info->err = -errno; |
527 | } | 558 | } |
528 | 559 | ||
560 | static int async_pty(int master, int slave) | ||
561 | { | ||
562 | int flags; | ||
563 | |||
564 | flags = fcntl(master, F_GETFL); | ||
565 | if(flags < 0) | ||
566 | return -errno; | ||
567 | |||
568 | if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) || | ||
569 | (fcntl(master, F_SETOWN, os_getpid()) < 0)) | ||
570 | return -errno; | ||
571 | |||
572 | if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0)) | ||
573 | return -errno; | ||
574 | |||
575 | return(0); | ||
576 | } | ||
577 | |||
529 | static void __init check_one_sigio(void (*proc)(int, int)) | 578 | static void __init check_one_sigio(void (*proc)(int, int)) |
530 | { | 579 | { |
531 | struct sigaction old, new; | 580 | struct sigaction old, new; |
@@ -551,7 +600,7 @@ static void __init check_one_sigio(void (*proc)(int, int)) | |||
551 | if (err < 0) | 600 | if (err < 0) |
552 | panic("check_sigio : __raw failed, errno = %d\n", -err); | 601 | panic("check_sigio : __raw failed, errno = %d\n", -err); |
553 | 602 | ||
554 | err = os_sigio_async(master, slave); | 603 | err = async_pty(master, slave); |
555 | if(err < 0) | 604 | if(err < 0) |
556 | panic("tty_fds : sigio_async failed, err = %d\n", -err); | 605 | panic("tty_fds : sigio_async failed, err = %d\n", -err); |
557 | 606 | ||
diff --git a/arch/um/os-Linux/sys-i386/registers.c b/arch/um/os-Linux/sys-i386/registers.c index 7cd0369e02b3..79cd93c8c5ed 100644 --- a/arch/um/os-Linux/sys-i386/registers.c +++ b/arch/um/os-Linux/sys-i386/registers.c | |||
@@ -34,27 +34,27 @@ void init_thread_registers(union uml_pt_regs *to) | |||
34 | int save_fp_registers(int pid, unsigned long *fp_regs) | 34 | int save_fp_registers(int pid, unsigned long *fp_regs) |
35 | { | 35 | { |
36 | if(ptrace(PTRACE_GETFPREGS, pid, 0, fp_regs) < 0) | 36 | if(ptrace(PTRACE_GETFPREGS, pid, 0, fp_regs) < 0) |
37 | return(-errno); | 37 | return -errno; |
38 | return(0); | 38 | return 0; |
39 | } | 39 | } |
40 | 40 | ||
41 | int restore_fp_registers(int pid, unsigned long *fp_regs) | 41 | int restore_fp_registers(int pid, unsigned long *fp_regs) |
42 | { | 42 | { |
43 | if(ptrace(PTRACE_SETFPREGS, pid, 0, fp_regs) < 0) | 43 | if(ptrace(PTRACE_SETFPREGS, pid, 0, fp_regs) < 0) |
44 | return(-errno); | 44 | return -errno; |
45 | return(0); | 45 | return 0; |
46 | } | 46 | } |
47 | 47 | ||
48 | static int move_registers(int pid, int int_op, union uml_pt_regs *regs, | 48 | static int move_registers(int pid, int int_op, union uml_pt_regs *regs, |
49 | int fp_op, unsigned long *fp_regs) | 49 | int fp_op, unsigned long *fp_regs) |
50 | { | 50 | { |
51 | if(ptrace(int_op, pid, 0, regs->skas.regs) < 0) | 51 | if(ptrace(int_op, pid, 0, regs->skas.regs) < 0) |
52 | return(-errno); | 52 | return -errno; |
53 | 53 | ||
54 | if(ptrace(fp_op, pid, 0, fp_regs) < 0) | 54 | if(ptrace(fp_op, pid, 0, fp_regs) < 0) |
55 | return(-errno); | 55 | return -errno; |
56 | 56 | ||
57 | return(0); | 57 | return 0; |
58 | } | 58 | } |
59 | 59 | ||
60 | void save_registers(int pid, union uml_pt_regs *regs) | 60 | void save_registers(int pid, union uml_pt_regs *regs) |
diff --git a/arch/um/os-Linux/sys-x86_64/Makefile b/arch/um/os-Linux/sys-x86_64/Makefile index f67842a7735b..7955e061a678 100644 --- a/arch/um/os-Linux/sys-x86_64/Makefile +++ b/arch/um/os-Linux/sys-x86_64/Makefile | |||
@@ -3,7 +3,7 @@ | |||
3 | # Licensed under the GPL | 3 | # Licensed under the GPL |
4 | # | 4 | # |
5 | 5 | ||
6 | obj-$(CONFIG_MODE_SKAS) = registers.o signal.o | 6 | obj-$(CONFIG_MODE_SKAS) = registers.o prctl.o signal.o |
7 | 7 | ||
8 | USER_OBJS := $(obj-y) | 8 | USER_OBJS := $(obj-y) |
9 | 9 | ||
diff --git a/arch/um/os-Linux/sys-x86_64/prctl.c b/arch/um/os-Linux/sys-x86_64/prctl.c new file mode 100644 index 000000000000..9d34eddb517f --- /dev/null +++ b/arch/um/os-Linux/sys-x86_64/prctl.c | |||
@@ -0,0 +1,12 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007 Jeff Dike (jdike@{addtoit.com,linux.intel.com}) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #include <sys/ptrace.h> | ||
7 | #include <linux/ptrace.h> | ||
8 | |||
9 | int os_arch_prctl(int pid, int code, unsigned long *addr) | ||
10 | { | ||
11 | return ptrace(PTRACE_ARCH_PRCTL, pid, (unsigned long) addr, code); | ||
12 | } | ||
diff --git a/arch/um/os-Linux/sys-x86_64/registers.c b/arch/um/os-Linux/sys-x86_64/registers.c index cb8e8a263280..a2d7e0c603f7 100644 --- a/arch/um/os-Linux/sys-x86_64/registers.c +++ b/arch/um/os-Linux/sys-x86_64/registers.c | |||
@@ -27,12 +27,12 @@ static int move_registers(int pid, int int_op, int fp_op, | |||
27 | union uml_pt_regs *regs) | 27 | union uml_pt_regs *regs) |
28 | { | 28 | { |
29 | if(ptrace(int_op, pid, 0, regs->skas.regs) < 0) | 29 | if(ptrace(int_op, pid, 0, regs->skas.regs) < 0) |
30 | return(-errno); | 30 | return -errno; |
31 | 31 | ||
32 | if(ptrace(fp_op, pid, 0, regs->skas.fp) < 0) | 32 | if(ptrace(fp_op, pid, 0, regs->skas.fp) < 0) |
33 | return(-errno); | 33 | return -errno; |
34 | 34 | ||
35 | return(0); | 35 | return 0; |
36 | } | 36 | } |
37 | 37 | ||
38 | void save_registers(int pid, union uml_pt_regs *regs) | 38 | void save_registers(int pid, union uml_pt_regs *regs) |
diff --git a/arch/um/os-Linux/umid.c b/arch/um/os-Linux/umid.c index 48092b95c8ab..b462863f7172 100644 --- a/arch/um/os-Linux/umid.c +++ b/arch/um/os-Linux/umid.c | |||
@@ -18,7 +18,7 @@ | |||
18 | #define UMID_LEN 64 | 18 | #define UMID_LEN 64 |
19 | 19 | ||
20 | /* Changed by set_umid, which is run early in boot */ | 20 | /* Changed by set_umid, which is run early in boot */ |
21 | char umid[UMID_LEN] = { 0 }; | 21 | static char umid[UMID_LEN] = { 0 }; |
22 | 22 | ||
23 | /* Changed by set_uml_dir and make_uml_dir, which are run early in boot */ | 23 | /* Changed by set_uml_dir and make_uml_dir, which are run early in boot */ |
24 | static char *uml_dir = UML_DIR; | 24 | static char *uml_dir = UML_DIR; |
@@ -235,6 +235,7 @@ int __init set_umid(char *name) | |||
235 | return 0; | 235 | return 0; |
236 | } | 236 | } |
237 | 237 | ||
238 | /* Changed in make_umid, which is called during early boot */ | ||
238 | static int umid_setup = 0; | 239 | static int umid_setup = 0; |
239 | 240 | ||
240 | int __init make_umid(void) | 241 | int __init make_umid(void) |
diff --git a/arch/um/sys-x86_64/ptrace.c b/arch/um/sys-x86_64/ptrace.c index 147bbf05cbc2..55b66e09a98c 100644 --- a/arch/um/sys-x86_64/ptrace.c +++ b/arch/um/sys-x86_64/ptrace.c | |||
@@ -71,8 +71,6 @@ int poke_user(struct task_struct *child, long addr, long data) | |||
71 | 71 | ||
72 | if (addr < MAX_REG_OFFSET) | 72 | if (addr < MAX_REG_OFFSET) |
73 | return putreg(child, addr, data); | 73 | return putreg(child, addr, data); |
74 | |||
75 | #if 0 /* Need x86_64 debugregs handling */ | ||
76 | else if((addr >= offsetof(struct user, u_debugreg[0])) && | 74 | else if((addr >= offsetof(struct user, u_debugreg[0])) && |
77 | (addr <= offsetof(struct user, u_debugreg[7]))){ | 75 | (addr <= offsetof(struct user, u_debugreg[7]))){ |
78 | addr -= offsetof(struct user, u_debugreg[0]); | 76 | addr -= offsetof(struct user, u_debugreg[0]); |
@@ -81,7 +79,6 @@ int poke_user(struct task_struct *child, long addr, long data) | |||
81 | child->thread.arch.debugregs[addr] = data; | 79 | child->thread.arch.debugregs[addr] = data; |
82 | return 0; | 80 | return 0; |
83 | } | 81 | } |
84 | #endif | ||
85 | return -EIO; | 82 | return -EIO; |
86 | } | 83 | } |
87 | 84 | ||
@@ -119,14 +116,12 @@ int peek_user(struct task_struct *child, long addr, long data) | |||
119 | if(addr < MAX_REG_OFFSET){ | 116 | if(addr < MAX_REG_OFFSET){ |
120 | tmp = getreg(child, addr); | 117 | tmp = getreg(child, addr); |
121 | } | 118 | } |
122 | #if 0 /* Need x86_64 debugregs handling */ | ||
123 | else if((addr >= offsetof(struct user, u_debugreg[0])) && | 119 | else if((addr >= offsetof(struct user, u_debugreg[0])) && |
124 | (addr <= offsetof(struct user, u_debugreg[7]))){ | 120 | (addr <= offsetof(struct user, u_debugreg[7]))){ |
125 | addr -= offsetof(struct user, u_debugreg[0]); | 121 | addr -= offsetof(struct user, u_debugreg[0]); |
126 | addr = addr >> 2; | 122 | addr = addr >> 2; |
127 | tmp = child->thread.arch.debugregs[addr]; | 123 | tmp = child->thread.arch.debugregs[addr]; |
128 | } | 124 | } |
129 | #endif | ||
130 | return put_user(tmp, (unsigned long *) data); | 125 | return put_user(tmp, (unsigned long *) data); |
131 | } | 126 | } |
132 | 127 | ||
diff --git a/arch/um/sys-x86_64/syscalls.c b/arch/um/sys-x86_64/syscalls.c index 73ce4463f70c..01b91f9fa789 100644 --- a/arch/um/sys-x86_64/syscalls.c +++ b/arch/um/sys-x86_64/syscalls.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include "asm/prctl.h" /* XXX This should get the constants from libc */ | 16 | #include "asm/prctl.h" /* XXX This should get the constants from libc */ |
17 | #include "choose-mode.h" | 17 | #include "choose-mode.h" |
18 | #include "kern.h" | 18 | #include "kern.h" |
19 | #include "os.h" | ||
19 | 20 | ||
20 | asmlinkage long sys_uname64(struct new_utsname __user * name) | 21 | asmlinkage long sys_uname64(struct new_utsname __user * name) |
21 | { | 22 | { |
@@ -58,40 +59,69 @@ static long arch_prctl_tt(int code, unsigned long addr) | |||
58 | 59 | ||
59 | #ifdef CONFIG_MODE_SKAS | 60 | #ifdef CONFIG_MODE_SKAS |
60 | 61 | ||
61 | /* XXX: Must also call arch_prctl in the host, beside saving the segment bases! */ | 62 | long arch_prctl_skas(struct task_struct *task, int code, |
62 | static long arch_prctl_skas(int code, unsigned long addr) | 63 | unsigned long __user *addr) |
63 | { | 64 | { |
64 | long ret = 0; | 65 | unsigned long *ptr = addr, tmp; |
66 | long ret; | ||
67 | int pid = task->mm->context.skas.id.u.pid; | ||
65 | 68 | ||
69 | /* | ||
70 | * With ARCH_SET_FS (and ARCH_SET_GS is treated similarly to | ||
71 | * be safe), we need to call arch_prctl on the host because | ||
72 | * setting %fs may result in something else happening (like a | ||
73 | * GDT or thread.fs being set instead). So, we let the host | ||
74 | * fiddle the registers and thread struct and restore the | ||
75 | * registers afterwards. | ||
76 | * | ||
77 | * So, the saved registers are stored to the process (this | ||
78 | * needed because a stub may have been the last thing to run), | ||
79 | * arch_prctl is run on the host, then the registers are read | ||
80 | * back. | ||
81 | */ | ||
66 | switch(code){ | 82 | switch(code){ |
67 | case ARCH_SET_FS: | 83 | case ARCH_SET_FS: |
68 | current->thread.regs.regs.skas.regs[FS_BASE / sizeof(unsigned long)] = addr; | ||
69 | break; | ||
70 | case ARCH_SET_GS: | 84 | case ARCH_SET_GS: |
71 | current->thread.regs.regs.skas.regs[GS_BASE / sizeof(unsigned long)] = addr; | 85 | restore_registers(pid, ¤t->thread.regs.regs); |
86 | break; | ||
87 | case ARCH_GET_FS: | ||
88 | case ARCH_GET_GS: | ||
89 | /* | ||
90 | * With these two, we read to a local pointer and | ||
91 | * put_user it to the userspace pointer that we were | ||
92 | * given. If addr isn't valid (because it hasn't been | ||
93 | * faulted in or is just bogus), we want put_user to | ||
94 | * fault it in (or return -EFAULT) instead of having | ||
95 | * the host return -EFAULT. | ||
96 | */ | ||
97 | ptr = &tmp; | ||
98 | } | ||
99 | |||
100 | ret = os_arch_prctl(pid, code, ptr); | ||
101 | if(ret) | ||
102 | return ret; | ||
103 | |||
104 | switch(code){ | ||
105 | case ARCH_SET_FS: | ||
106 | case ARCH_SET_GS: | ||
107 | save_registers(pid, ¤t->thread.regs.regs); | ||
72 | break; | 108 | break; |
73 | case ARCH_GET_FS: | 109 | case ARCH_GET_FS: |
74 | ret = put_user(current->thread.regs.regs.skas. | 110 | ret = put_user(tmp, addr); |
75 | regs[FS_BASE / sizeof(unsigned long)], | ||
76 | (unsigned long __user *)addr); | ||
77 | break; | 111 | break; |
78 | case ARCH_GET_GS: | 112 | case ARCH_GET_GS: |
79 | ret = put_user(current->thread.regs.regs.skas. | 113 | ret = put_user(tmp, addr); |
80 | regs[GS_BASE / sizeof(unsigned long)], | ||
81 | (unsigned long __user *)addr); | ||
82 | break; | 114 | break; |
83 | default: | ||
84 | ret = -EINVAL; | ||
85 | break; | ||
86 | } | 115 | } |
87 | 116 | ||
88 | return(ret); | 117 | return ret; |
89 | } | 118 | } |
90 | #endif | 119 | #endif |
91 | 120 | ||
92 | long sys_arch_prctl(int code, unsigned long addr) | 121 | long sys_arch_prctl(int code, unsigned long addr) |
93 | { | 122 | { |
94 | return(CHOOSE_MODE_PROC(arch_prctl_tt, arch_prctl_skas, code, addr)); | 123 | return CHOOSE_MODE_PROC(arch_prctl_tt, arch_prctl_skas, current, code, |
124 | (unsigned long __user *) addr); | ||
95 | } | 125 | } |
96 | 126 | ||
97 | long sys_clone(unsigned long clone_flags, unsigned long newsp, | 127 | long sys_clone(unsigned long clone_flags, unsigned long newsp, |
@@ -105,5 +135,14 @@ long sys_clone(unsigned long clone_flags, unsigned long newsp, | |||
105 | ret = do_fork(clone_flags, newsp, ¤t->thread.regs, 0, parent_tid, | 135 | ret = do_fork(clone_flags, newsp, ¤t->thread.regs, 0, parent_tid, |
106 | child_tid); | 136 | child_tid); |
107 | current->thread.forking = 0; | 137 | current->thread.forking = 0; |
108 | return(ret); | 138 | return ret; |
139 | } | ||
140 | |||
141 | void arch_switch_to_skas(struct task_struct *from, struct task_struct *to) | ||
142 | { | ||
143 | if(to->thread.arch.fs == 0) | ||
144 | return; | ||
145 | |||
146 | arch_prctl_skas(to, ARCH_SET_FS, (void __user *) to->thread.arch.fs); | ||
109 | } | 147 | } |
148 | |||
diff --git a/arch/um/sys-x86_64/tls.c b/arch/um/sys-x86_64/tls.c index ce1bf1b81c43..febbc94be25f 100644 --- a/arch/um/sys-x86_64/tls.c +++ b/arch/um/sys-x86_64/tls.c | |||
@@ -1,14 +1,17 @@ | |||
1 | #include "linux/sched.h" | 1 | #include "linux/sched.h" |
2 | 2 | ||
3 | void debug_arch_force_load_TLS(void) | ||
4 | { | ||
5 | } | ||
6 | |||
7 | void clear_flushed_tls(struct task_struct *task) | 3 | void clear_flushed_tls(struct task_struct *task) |
8 | { | 4 | { |
9 | } | 5 | } |
10 | 6 | ||
11 | int arch_copy_tls(struct task_struct *t) | 7 | int arch_copy_tls(struct task_struct *t) |
12 | { | 8 | { |
9 | /* | ||
10 | * If CLONE_SETTLS is set, we need to save the thread id | ||
11 | * (which is argument 5, child_tid, of clone) so it can be set | ||
12 | * during context switches. | ||
13 | */ | ||
14 | t->thread.arch.fs = t->thread.regs.regs.skas.regs[R8 / sizeof(long)]; | ||
15 | |||
13 | return 0; | 16 | return 0; |
14 | } | 17 | } |