Blame view
arch/um/drivers/port_kern.c
6.53 KB
67608e0c8 [PATCH] uml: port... |
1 |
/* |
e99525f97 uml: console subs... |
2 |
* Copyright (C) 2001 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com) |
1da177e4c Linux-2.6.12-rc2 |
3 4 |
* Licensed under the GPL */ |
e99525f97 uml: console subs... |
5 |
#include "linux/completion.h" |
1da177e4c Linux-2.6.12-rc2 |
6 |
#include "linux/interrupt.h" |
e99525f97 uml: console subs... |
7 |
#include "linux/list.h" |
2aa9c5db8 uml: port mutex c... |
8 |
#include "linux/mutex.h" |
5a0e3ad6a include cleanup: ... |
9 |
#include "linux/slab.h" |
d43c36dc6 headers: remove s... |
10 |
#include "linux/workqueue.h" |
1da177e4c Linux-2.6.12-rc2 |
11 |
#include "asm/atomic.h" |
1da177e4c Linux-2.6.12-rc2 |
12 |
#include "init.h" |
e99525f97 uml: console subs... |
13 |
#include "irq_kern.h" |
1da177e4c Linux-2.6.12-rc2 |
14 |
#include "os.h" |
e99525f97 uml: console subs... |
15 |
#include "port.h" |
1da177e4c Linux-2.6.12-rc2 |
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
struct port_list { struct list_head list; atomic_t wait_count; int has_connection; struct completion done; int port; int fd; spinlock_t lock; struct list_head pending; struct list_head connections; }; struct port_dev { struct port_list *port; int helper_pid; int telnetd_pid; }; struct connection { struct list_head list; int fd; int helper_pid; int socket[2]; int telnetd_pid; struct port_list *port; }; |
7bea96fd2 [PATCH] uml pt_re... |
43 |
static irqreturn_t pipe_interrupt(int irq, void *data) |
1da177e4c Linux-2.6.12-rc2 |
44 45 46 47 48 |
{ struct connection *conn = data; int fd; fd = os_rcv_fd(conn->socket[0], &conn->helper_pid); |
e99525f97 uml: console subs... |
49 50 |
if (fd < 0) { if (fd == -EAGAIN) |
67608e0c8 [PATCH] uml: port... |
51 |
return IRQ_NONE; |
1da177e4c Linux-2.6.12-rc2 |
52 |
|
67608e0c8 [PATCH] uml: port... |
53 54 |
printk(KERN_ERR "pipe_interrupt : os_rcv_fd returned %d ", |
1da177e4c Linux-2.6.12-rc2 |
55 56 57 58 59 60 61 62 63 64 |
-fd); os_close_file(conn->fd); } list_del(&conn->list); conn->fd = fd; list_add(&conn->list, &conn->port->connections); complete(&conn->port->done); |
67608e0c8 [PATCH] uml: port... |
65 |
return IRQ_HANDLED; |
1da177e4c Linux-2.6.12-rc2 |
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
} #define NO_WAITER_MSG \ "**** " \ "There are currently no UML consoles waiting for port connections. " \ "Either disconnect from one to make it available or activate some more " \ "by enabling more consoles in the UML /etc/inittab. " \ "**** " static int port_accept(struct port_list *port) { struct connection *conn; |
e99525f97 uml: console subs... |
83 |
int fd, socket[2], pid; |
1da177e4c Linux-2.6.12-rc2 |
84 85 |
fd = port_connection(port->fd, socket, &pid); |
e99525f97 uml: console subs... |
86 87 |
if (fd < 0) { if (fd != -EAGAIN) |
1da177e4c Linux-2.6.12-rc2 |
88 89 90 91 92 93 94 |
printk(KERN_ERR "port_accept : port_connection " "returned %d ", -fd); goto out; } conn = kmalloc(sizeof(*conn), GFP_ATOMIC); |
e99525f97 uml: console subs... |
95 |
if (conn == NULL) { |
1da177e4c Linux-2.6.12-rc2 |
96 97 98 99 100 |
printk(KERN_ERR "port_accept : failed to allocate " "connection "); goto out_close; } |
67608e0c8 [PATCH] uml: port... |
101 |
*conn = ((struct connection) |
1da177e4c Linux-2.6.12-rc2 |
102 103 104 105 106 |
{ .list = LIST_HEAD_INIT(conn->list), .fd = fd, .socket = { socket[0], socket[1] }, .telnetd_pid = pid, .port = port }); |
e99525f97 uml: console subs... |
107 |
if (um_request_irq(TELNETD_IRQ, socket[0], IRQ_READ, pipe_interrupt, |
bd6aa6502 [PATCH] irq-flags... |
108 |
IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM, |
e99525f97 uml: console subs... |
109 |
"telnetd", conn)) { |
1da177e4c Linux-2.6.12-rc2 |
110 111 112 113 114 |
printk(KERN_ERR "port_accept : failed to get IRQ for " "telnetd "); goto out_free; } |
e99525f97 uml: console subs... |
115 |
if (atomic_read(&port->wait_count) == 0) { |
a6ea4ccee uml: rename os_{r... |
116 |
os_write_file(fd, NO_WAITER_MSG, sizeof(NO_WAITER_MSG)); |
e99525f97 uml: console subs... |
117 118 |
printk(KERN_ERR "No one waiting for port "); |
1da177e4c Linux-2.6.12-rc2 |
119 120 |
} list_add(&conn->list, &port->pending); |
67608e0c8 [PATCH] uml: port... |
121 |
return 1; |
1da177e4c Linux-2.6.12-rc2 |
122 123 124 125 126 |
out_free: kfree(conn); out_close: os_close_file(fd); |
e99525f97 uml: console subs... |
127 |
os_kill_process(pid, 1); |
1da177e4c Linux-2.6.12-rc2 |
128 |
out: |
e99525f97 uml: console subs... |
129 |
return 0; |
67608e0c8 [PATCH] uml: port... |
130 |
} |
1da177e4c Linux-2.6.12-rc2 |
131 |
|
2aa9c5db8 uml: port mutex c... |
132 |
static DEFINE_MUTEX(ports_mutex); |
c59bce626 [PATCH] uml: use ... |
133 |
static LIST_HEAD(ports); |
1da177e4c Linux-2.6.12-rc2 |
134 |
|
e99525f97 uml: console subs... |
135 |
static void port_work_proc(struct work_struct *unused) |
1da177e4c Linux-2.6.12-rc2 |
136 137 138 139 140 141 |
{ struct port_list *port; struct list_head *ele; unsigned long flags; local_irq_save(flags); |
e99525f97 uml: console subs... |
142 |
list_for_each(ele, &ports) { |
1da177e4c Linux-2.6.12-rc2 |
143 |
port = list_entry(ele, struct port_list, list); |
e99525f97 uml: console subs... |
144 |
if (!port->has_connection) |
1da177e4c Linux-2.6.12-rc2 |
145 |
continue; |
e99525f97 uml: console subs... |
146 |
|
1da177e4c Linux-2.6.12-rc2 |
147 |
reactivate_fd(port->fd, ACCEPT_IRQ); |
e99525f97 uml: console subs... |
148 149 |
while (port_accept(port)) ; |
1da177e4c Linux-2.6.12-rc2 |
150 151 152 153 |
port->has_connection = 0; } local_irq_restore(flags); } |
6d5aefb8e WorkQueue: Fix up... |
154 |
DECLARE_WORK(port_work, port_work_proc); |
1da177e4c Linux-2.6.12-rc2 |
155 |
|
7bea96fd2 [PATCH] uml pt_re... |
156 |
static irqreturn_t port_interrupt(int irq, void *data) |
1da177e4c Linux-2.6.12-rc2 |
157 158 159 160 161 |
{ struct port_list *port = data; port->has_connection = 1; schedule_work(&port_work); |
67608e0c8 [PATCH] uml: port... |
162 163 |
return IRQ_HANDLED; } |
1da177e4c Linux-2.6.12-rc2 |
164 165 166 167 168 169 170 |
void *port_data(int port_num) { struct list_head *ele; struct port_list *port; struct port_dev *dev = NULL; int fd; |
2aa9c5db8 uml: port mutex c... |
171 |
mutex_lock(&ports_mutex); |
e99525f97 uml: console subs... |
172 |
list_for_each(ele, &ports) { |
1da177e4c Linux-2.6.12-rc2 |
173 |
port = list_entry(ele, struct port_list, list); |
e99525f97 uml: console subs... |
174 175 |
if (port->port == port_num) goto found; |
1da177e4c Linux-2.6.12-rc2 |
176 177 |
} port = kmalloc(sizeof(struct port_list), GFP_KERNEL); |
e99525f97 uml: console subs... |
178 |
if (port == NULL) { |
1da177e4c Linux-2.6.12-rc2 |
179 180 181 182 183 184 |
printk(KERN_ERR "Allocation of port list failed "); goto out; } fd = port_listen_fd(port_num); |
e99525f97 uml: console subs... |
185 |
if (fd < 0) { |
1da177e4c Linux-2.6.12-rc2 |
186 187 188 189 190 |
printk(KERN_ERR "binding to port %d failed, errno = %d ", port_num, -fd); goto out_free; } |
e99525f97 uml: console subs... |
191 192 |
if (um_request_irq(ACCEPT_IRQ, fd, IRQ_READ, port_interrupt, |
67608e0c8 [PATCH] uml: port... |
193 |
IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM, |
e99525f97 uml: console subs... |
194 |
"port", port)) { |
1da177e4c Linux-2.6.12-rc2 |
195 196 197 198 |
printk(KERN_ERR "Failed to get IRQ for port %d ", port_num); goto out_close; } |
67608e0c8 [PATCH] uml: port... |
199 |
*port = ((struct port_list) |
1da177e4c Linux-2.6.12-rc2 |
200 201 202 203 204 205 206 207 208 209 210 211 212 |
{ .list = LIST_HEAD_INIT(port->list), .wait_count = ATOMIC_INIT(0), .has_connection = 0, .port = port_num, .fd = fd, .pending = LIST_HEAD_INIT(port->pending), .connections = LIST_HEAD_INIT(port->connections) }); spin_lock_init(&port->lock); init_completion(&port->done); list_add(&port->list, &ports); found: dev = kmalloc(sizeof(struct port_dev), GFP_KERNEL); |
e99525f97 uml: console subs... |
213 |
if (dev == NULL) { |
1da177e4c Linux-2.6.12-rc2 |
214 215 216 217 218 219 220 221 222 |
printk(KERN_ERR "Allocation of port device entry failed "); goto out; } *dev = ((struct port_dev) { .port = port, .helper_pid = -1, .telnetd_pid = -1 }); goto out; |
1da177e4c Linux-2.6.12-rc2 |
223 224 |
out_close: os_close_file(fd); |
79f662334 uml: fix error cl... |
225 226 |
out_free: kfree(port); |
1da177e4c Linux-2.6.12-rc2 |
227 |
out: |
2aa9c5db8 uml: port mutex c... |
228 |
mutex_unlock(&ports_mutex); |
67608e0c8 [PATCH] uml: port... |
229 |
return dev; |
1da177e4c Linux-2.6.12-rc2 |
230 231 232 233 234 235 236 237 |
} int port_wait(void *data) { struct port_dev *dev = data; struct connection *conn; struct port_list *port = dev->port; int fd; |
67608e0c8 [PATCH] uml: port... |
238 |
atomic_inc(&port->wait_count); |
e99525f97 uml: console subs... |
239 |
while (1) { |
1da177e4c Linux-2.6.12-rc2 |
240 |
fd = -ERESTARTSYS; |
e99525f97 uml: console subs... |
241 |
if (wait_for_completion_interruptible(&port->done)) |
67608e0c8 [PATCH] uml: port... |
242 |
goto out; |
1da177e4c Linux-2.6.12-rc2 |
243 244 |
spin_lock(&port->lock); |
67608e0c8 [PATCH] uml: port... |
245 |
conn = list_entry(port->connections.next, struct connection, |
1da177e4c Linux-2.6.12-rc2 |
246 247 248 249 250 251 252 |
list); list_del(&conn->list); spin_unlock(&port->lock); os_shutdown_socket(conn->socket[0], 1, 1); os_close_file(conn->socket[0]); os_shutdown_socket(conn->socket[1], 1, 1); |
67608e0c8 [PATCH] uml: port... |
253 |
os_close_file(conn->socket[1]); |
1da177e4c Linux-2.6.12-rc2 |
254 255 256 257 |
/* This is done here because freeing an IRQ can't be done * within the IRQ handler. So, pipe_interrupt always ups * the semaphore regardless of whether it got a successful |
67608e0c8 [PATCH] uml: port... |
258 |
* connection. Then we loop here throwing out failed |
1da177e4c Linux-2.6.12-rc2 |
259 260 |
* connections until a good one is found. */ |
1da177e4c Linux-2.6.12-rc2 |
261 |
free_irq(TELNETD_IRQ, conn); |
e99525f97 uml: console subs... |
262 263 |
if (conn->fd >= 0) break; |
1da177e4c Linux-2.6.12-rc2 |
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 |
os_close_file(conn->fd); kfree(conn); } fd = conn->fd; dev->helper_pid = conn->helper_pid; dev->telnetd_pid = conn->telnetd_pid; kfree(conn); out: atomic_dec(&port->wait_count); return fd; } void port_remove_dev(void *d) { struct port_dev *dev = d; |
e99525f97 uml: console subs... |
280 |
if (dev->helper_pid != -1) |
1da177e4c Linux-2.6.12-rc2 |
281 |
os_kill_process(dev->helper_pid, 0); |
e99525f97 uml: console subs... |
282 |
if (dev->telnetd_pid != -1) |
1da177e4c Linux-2.6.12-rc2 |
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 |
os_kill_process(dev->telnetd_pid, 1); dev->helper_pid = -1; dev->telnetd_pid = -1; } void port_kern_free(void *d) { struct port_dev *dev = d; port_remove_dev(dev); kfree(dev); } static void free_port(void) { struct list_head *ele; struct port_list *port; |
e99525f97 uml: console subs... |
300 |
list_for_each(ele, &ports) { |
1da177e4c Linux-2.6.12-rc2 |
301 302 303 304 305 306 307 |
port = list_entry(ele, struct port_list, list); free_irq_by_fd(port->fd); os_close_file(port->fd); } } __uml_exitcall(free_port); |