Print this page
5880 Increase IOV_MAX to at least 1024
Portions contributed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/cons.c
+++ new/usr/src/uts/common/io/cons.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 1982, 2010, Oracle and/or its affiliates. All rights reserved.
24 + * Copyright 2015, Joyent, Inc. All rights reserved.
24 25 */
25 26
26 27 /*
27 28 * Indirect console driver for Sun.
28 29 *
29 30 * Redirects all I/O to the device designated as the underlying "hardware"
30 31 * console, as given by the value of rconsvp. The implementation assumes that
31 32 * rconsvp denotes a STREAMS device; the assumption is justified since
32 33 * consoles must be capable of effecting tty semantics.
33 34 *
34 35 * rconsvp is set in autoconf.c:consconfig(), based on information obtained
35 36 * from the EEPROM.
36 37 *
37 38 * XXX: The driver still needs to be converted to use ANSI C consistently
38 39 * throughout.
39 40 */
40 41
41 42 #include <sys/types.h>
42 43 #include <sys/open.h>
43 44 #include <sys/param.h>
44 45 #include <sys/systm.h>
45 46 #include <sys/signal.h>
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
46 47 #include <sys/cred.h>
47 48 #include <sys/user.h>
48 49 #include <sys/proc.h>
49 50 #include <sys/disp.h>
50 51 #include <sys/file.h>
51 52 #include <sys/taskq.h>
52 53 #include <sys/log.h>
53 54 #include <sys/vnode.h>
54 55 #include <sys/uio.h>
55 56 #include <sys/stat.h>
57 +#include <sys/limits.h>
56 58
57 59 #include <sys/console.h>
58 60 #include <sys/consdev.h>
59 61
60 62 #include <sys/stream.h>
61 63 #include <sys/strsubr.h>
62 64 #include <sys/poll.h>
63 65
64 66 #include <sys/debug.h>
65 67
66 68 #include <sys/conf.h>
67 69 #include <sys/ddi.h>
68 70 #include <sys/sunddi.h>
69 71 #include <sys/vt.h>
70 72
71 73 static int cnopen(dev_t *, int, int, struct cred *);
72 74 static int cnclose(dev_t, int, int, struct cred *);
73 75 static int cnread(dev_t, struct uio *, struct cred *);
74 76 static int cnwrite(dev_t, struct uio *, struct cred *);
75 77 static int cnioctl(dev_t, int, intptr_t, int, struct cred *, int *);
76 78 static int cnpoll(dev_t, short, int, short *, struct pollhead **);
77 79 static int cn_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
78 80 static int cn_attach(dev_info_t *, ddi_attach_cmd_t);
79 81 static int cn_detach(dev_info_t *, ddi_detach_cmd_t);
80 82
81 83 static dev_info_t *cn_dip; /* private copy of devinfo pointer */
82 84
83 85 static struct cb_ops cn_cb_ops = {
84 86
85 87 cnopen, /* open */
86 88 cnclose, /* close */
87 89 nodev, /* strategy */
88 90 nodev, /* print */
89 91 nodev, /* dump */
90 92 cnread, /* read */
91 93 cnwrite, /* write */
92 94 cnioctl, /* ioctl */
93 95 nodev, /* devmap */
94 96 nodev, /* mmap */
95 97 nodev, /* segmap */
96 98 cnpoll, /* poll */
97 99 ddi_prop_op, /* cb_prop_op */
98 100 0, /* streamtab */
99 101 D_NEW | D_MP /* Driver compatibility flag */
100 102
101 103 };
102 104
103 105 static struct dev_ops cn_ops = {
104 106
105 107 DEVO_REV, /* devo_rev, */
106 108 0, /* refcnt */
107 109 cn_info, /* info */
108 110 nulldev, /* identify */
109 111 nulldev, /* probe */
110 112 cn_attach, /* attach */
111 113 cn_detach, /* detach */
112 114 nodev, /* reset */
113 115 &cn_cb_ops, /* driver operations */
114 116 (struct bus_ops *)0, /* bus operations */
115 117 NULL, /* power */
116 118 ddi_quiesce_not_needed, /* quiesce */
117 119
118 120 };
119 121
120 122 /*
121 123 * Global variables associated with the console device:
122 124 *
123 125 * XXX: There are too many of these!
124 126 * moved to space.c to become resident in the kernel so that cons
125 127 * can be loadable.
126 128 */
127 129
128 130 extern dev_t rconsdev; /* "hardware" console */
129 131 extern vnode_t *rconsvp; /* pointer to vnode for that device */
130 132
131 133 /*
132 134 * XXX: consulted in prsubr.c, for /proc entry point for obtaining ps info.
133 135 */
134 136 extern dev_t uconsdev; /* What the user thinks is the console device */
135 137
136 138 /*
137 139 * Private driver state:
138 140 */
139 141
140 142 /*
141 143 * The underlying console device potentially can be opened through (at least)
142 144 * two paths: through this driver and through the underlying device's driver.
143 145 * To ensure that reference counts are meaningful and therefore that close
144 146 * routines are called at the right time, it's important to make sure that
145 147 * rconsvp's s_count field (i.e., the count on the underlying device) never
146 148 * has a contribution of more than one through this driver, regardless of how
147 149 * many times this driver's been opened. rconsopen keeps track of the
148 150 * necessary information to ensure this property.
149 151 */
150 152 static uint_t rconsopen;
151 153
152 154
153 155 #include <sys/types.h>
154 156 #include <sys/conf.h>
155 157 #include <sys/param.h>
156 158 #include <sys/systm.h>
157 159 #include <sys/errno.h>
158 160 #include <sys/modctl.h>
159 161
160 162
161 163 extern int nodev(), nulldev();
162 164 extern int dseekneg_flag;
163 165 extern struct mod_ops mod_driverops;
164 166 extern struct dev_ops cn_ops;
165 167
166 168 /*
167 169 * Module linkage information for the kernel.
168 170 */
169 171
170 172 static struct modldrv modldrv = {
171 173 &mod_driverops, /* Type of module. This one is a pseudo driver */
172 174 "Console redirection driver",
173 175 &cn_ops, /* driver ops */
174 176 };
175 177
176 178 static struct modlinkage modlinkage = {
177 179 MODREV_1,
178 180 &modldrv,
179 181 NULL
180 182 };
181 183
182 184 int
183 185 _init(void)
184 186 {
185 187 return (mod_install(&modlinkage));
186 188 }
187 189
188 190 int
189 191 _fini(void)
190 192 {
191 193 return (EBUSY);
192 194 }
193 195
194 196 int
195 197 _info(struct modinfo *modinfop)
196 198 {
197 199 return (mod_info(&modlinkage, modinfop));
198 200 }
199 201
200 202 /*
201 203 * DDI glue routines
202 204 */
203 205 static int
204 206 cn_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
205 207 {
206 208 if (cmd != DDI_ATTACH)
207 209 return (DDI_FAILURE);
208 210
209 211 if (ddi_create_minor_node(devi, "syscon", S_IFCHR,
210 212 0, DDI_PSEUDO, 0) == DDI_FAILURE) {
211 213 return (DDI_FAILURE);
212 214 }
213 215 if (ddi_create_minor_node(devi, "systty", S_IFCHR,
214 216 0, DDI_PSEUDO, 0) == DDI_FAILURE) {
215 217 ddi_remove_minor_node(devi, NULL);
216 218 return (DDI_FAILURE);
217 219 }
218 220 if (ddi_create_minor_node(devi, "console", S_IFCHR,
219 221 0, DDI_PSEUDO, 0) == DDI_FAILURE) {
220 222 ddi_remove_minor_node(devi, NULL);
221 223 return (DDI_FAILURE);
222 224 }
223 225
224 226 cn_dip = devi;
225 227 return (DDI_SUCCESS);
226 228 }
227 229
228 230 static int
229 231 cn_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
230 232 {
231 233 if (cmd != DDI_DETACH)
232 234 return (DDI_FAILURE);
233 235 ddi_remove_minor_node(devi, NULL);
234 236 uconsdev = NODEV;
235 237 return (DDI_SUCCESS);
236 238 }
237 239
238 240 /* ARGSUSED */
239 241 static int
240 242 cn_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
241 243 {
242 244 int error = DDI_FAILURE;
243 245
244 246 switch (infocmd) {
245 247 case DDI_INFO_DEVT2DEVINFO:
246 248 if (getminor((dev_t)arg) == 0 && cn_dip != NULL) {
247 249 *result = (void *) cn_dip;
248 250 error = DDI_SUCCESS;
249 251 }
250 252 break;
251 253
252 254 case DDI_INFO_DEVT2INSTANCE:
253 255 if (getminor((dev_t)arg) == 0) {
254 256 *result = (void *)0;
255 257 error = DDI_SUCCESS;
256 258 }
257 259 break;
258 260
259 261 default:
260 262 break;
261 263 }
262 264
263 265 return (error);
264 266 }
265 267
266 268 /*
267 269 * XXX Caution: before allowing more than 256 minor devices on the
268 270 * console, make sure you understand the 'compatibility' hack
269 271 * in ufs_iget() that translates old dev_t's to new dev_t's.
270 272 * See bugid 1098104 for the sordid details.
271 273 */
272 274
273 275 /* ARGSUSED */
274 276 static int
275 277 cnopen(dev_t *dev, int flag, int state, struct cred *cred)
276 278 {
277 279 int err;
278 280 static int been_here;
279 281 vnode_t *vp = rconsvp;
280 282
281 283 ASSERT(cred != NULL);
282 284
283 285 if (rconsvp == NULL)
284 286 return (0);
285 287
286 288 /*
287 289 * Enable virtual console I/O for console logging if needed.
288 290 */
289 291 if (vsconsvp != NULL && vsconsvp->v_stream == NULL) {
290 292 if (VOP_OPEN(&vsconsvp, FREAD | FWRITE, cred, NULL) != 0) {
291 293 cmn_err(CE_WARN, "cnopen: failed to open vsconsvp "
292 294 "for virtual console logging");
293 295 }
294 296 }
295 297
296 298 /*
297 299 * XXX: Clean up inactive PIDs from previous opens if any.
298 300 * These would have been created as a result of an I_SETSIG
299 301 * issued against console. This is a workaround, and
300 302 * console driver must be correctly redesigned not to need
301 303 * this hook.
302 304 */
303 305 if (vp->v_stream) {
304 306 str_cn_clean(vp);
305 307 }
306 308
307 309 /*
308 310 * XXX: Set hook to tell /proc about underlying console. (There's
309 311 * gotta be a better way...)
310 312 */
311 313 if (state != OTYP_CHR || getminor(*dev) != 0)
312 314 return (ENXIO);
313 315 if (been_here == 0) {
314 316 uconsdev = *dev;
315 317 been_here = 1;
316 318 if (vn_open("/dev/console", UIO_SYSSPACE, FWRITE | FNOCTTY,
317 319 0, &console_vnode, 0, 0) == 0)
318 320 console_taskq = taskq_create("console_taskq",
319 321 1, maxclsyspri - 1, LOG_LOWAT / LOG_MSGSIZE,
320 322 LOG_HIWAT / LOG_MSGSIZE, TASKQ_PREPOPULATE);
321 323 }
322 324
323 325 if ((err = VOP_OPEN(&vp, flag, cred, NULL)) != 0)
324 326 return (err);
325 327
326 328 /*
327 329 * The underlying driver is not allowed to have cloned itself
328 330 * for this open.
329 331 */
330 332 if (vp != rconsvp) {
331 333 /*
332 334 * It might happen that someone set rconsvp to NULL
333 335 * whilst we were in the middle of the open.
334 336 */
335 337 if (rconsvp == NULL) {
336 338 (void) VOP_CLOSE(vp, flag, 1, (offset_t)0, cred, NULL);
337 339 return (0);
338 340 }
339 341 cmn_err(CE_PANIC, "cnopen: cloned open");
340 342 }
341 343
342 344 rconsopen++;
343 345
344 346 return (0);
345 347 }
346 348
347 349 /* ARGSUSED */
348 350 static int
349 351 cnclose(dev_t dev, int flag, int state, struct cred *cred)
350 352 {
351 353 int err = 0;
352 354 vnode_t *vp;
353 355
354 356 /*
355 357 * Since this is the _last_ close, it's our last chance to close the
356 358 * underlying device. (Note that if someone else has the underlying
357 359 * hardware console device open, we won't get here, since spec_close
358 360 * will see s_count > 1.)
359 361 */
360 362 if (state != OTYP_CHR)
361 363 return (ENXIO);
362 364
363 365 if (rconsvp == NULL)
364 366 return (0);
365 367
366 368 while ((rconsopen != 0) && ((vp = rconsvp) != NULL)) {
367 369 err = VOP_CLOSE(vp, flag, 1, (offset_t)0, cred, NULL);
368 370 if (!err) {
369 371 rconsopen--;
370 372 }
371 373 }
372 374 return (err);
373 375 }
374 376
375 377 /* ARGSUSED */
376 378 static int
377 379 cnread(dev_t dev, struct uio *uio, struct cred *cred)
378 380 {
379 381 kcondvar_t sleep_forever;
380 382 kmutex_t sleep_forever_mutex;
381 383
382 384 if (rconsvp == NULL) {
383 385 /*
384 386 * Go to sleep forever. This seems like the least
385 387 * harmful thing to do if there's no console.
386 388 * EOF might be better if we're ending up single-user
387 389 * mode.
388 390 */
389 391 cv_init(&sleep_forever, NULL, CV_DRIVER, NULL);
390 392 mutex_init(&sleep_forever_mutex, NULL, MUTEX_DRIVER, NULL);
391 393 mutex_enter(&sleep_forever_mutex);
392 394 (void) cv_wait_sig(&sleep_forever, &sleep_forever_mutex);
393 395 mutex_exit(&sleep_forever_mutex);
394 396 return (EIO);
395 397 }
396 398
397 399 if (rconsvp->v_stream != NULL)
398 400 return (strread(rconsvp, uio, cred));
399 401 else
400 402 return (cdev_read(rconsdev, uio, cred));
401 403 }
402 404
403 405 /* ARGSUSED */
404 406 static int
405 407 cnwrite(dev_t dev, struct uio *uio, struct cred *cred)
406 408 {
↓ open down ↓ |
341 lines elided |
↑ open up ↑ |
407 409 if (rconsvp == NULL) {
408 410 uio->uio_resid = 0;
409 411 return (0);
410 412 }
411 413
412 414 /*
413 415 * Output to virtual console for logging if enabled.
414 416 */
415 417 if (vsconsvp != NULL && vsconsvp->v_stream != NULL) {
416 418 struiod_t uiod;
419 + struct iovec buf[IOV_MAX_STACK];
420 + int iovlen = 0;
417 421
422 + if (uio->uio_iovcnt > IOV_MAX_STACK) {
423 + iovlen = uio->uio_iovcnt * sizeof (iovec_t);
424 + uiod.d_iov = kmem_alloc(iovlen, KM_SLEEP);
425 + } else {
426 + uiod.d_iov = buf;
427 + }
428 +
418 429 /*
419 430 * strwrite modifies uio so need to make copy.
420 431 */
421 - (void) uiodup(uio, &uiod.d_uio, uiod.d_iov,
422 - sizeof (uiod.d_iov) / sizeof (*uiod.d_iov));
432 + (void) uiodup(uio, &uiod.d_uio, uiod.d_iov, uio->uio_iovcnt);
423 433
424 434 (void) strwrite(vsconsvp, &uiod.d_uio, cred);
435 + if (iovlen != 0)
436 + kmem_free(uiod.d_iov, iovlen);
425 437 }
426 438
427 439 if (rconsvp->v_stream != NULL)
428 440 return (strwrite(rconsvp, uio, cred));
429 441 else
430 442 return (cdev_write(rconsdev, uio, cred));
431 443 }
432 444
433 445 /* ARGSUSED */
434 446 static int
435 447 cnprivateioc(dev_t dev, int cmd, intptr_t arg, int flag, struct cred *cred,
436 448 int *rvalp)
437 449 {
438 450
439 451 /* currently we only support one ioctl */
440 452 if (cmd != CONS_GETTERM)
441 453 return (EINVAL);
442 454
443 455 /* Confirm iwscn is immediate target of cn redirection */
444 456 if (rconsvp != wsconsvp)
445 457 return (ENODEV);
446 458
447 459 /*
448 460 * If the redirection client is not wc, it should return
449 461 * error upon receiving the CONS_GETTERM ioctl.
450 462 *
451 463 * if it is wc, we know that the target supports the CONS_GETTERM
452 464 * ioctl, which very conviently has the exact same data
453 465 * format as this ioctl... so let's just pass it on.
454 466 */
455 467 return (cdev_ioctl(rconsdev, CONS_GETTERM, arg, flag, cred, rvalp));
456 468 }
457 469
458 470 /* ARGSUSED */
459 471 static int
460 472 cnioctl(dev_t dev, int cmd, intptr_t arg, int flag, struct cred *cred,
461 473 int *rvalp)
462 474 {
463 475 if (rconsvp == NULL)
464 476 return (0);
465 477
466 478 /*
467 479 * In wc, VT_SET_CONSUSER which comes from minor node 0
468 480 * has two sources -- either /dev/console or /dev/vt/0 .
469 481 * We need a way to differentiate them, so here we
470 482 * change VT_SET_CONSUSER to a private VT_RESET_CONSUSER
471 483 * ioctl.
472 484 */
473 485 if (cmd == VT_SET_CONSUSER)
474 486 cmd = VT_RESET_CONSUSER;
475 487
476 488 if ((cmd & _CNIOC_MASK) == _CNIOC)
477 489 return (cnprivateioc(dev, cmd, arg, flag, cred, rvalp));
478 490
479 491 if (rconsvp->v_stream != NULL)
480 492 return (strioctl(rconsvp, cmd, arg, flag, U_TO_K,
481 493 cred, rvalp));
482 494
483 495 return (cdev_ioctl(rconsdev, cmd, arg, flag, cred, rvalp));
484 496 }
485 497
486 498 /* ARGSUSED */
487 499 static int
488 500 cnpoll(dev_t dev, short events, int anyyet, short *reventsp,
489 501 struct pollhead **phpp)
490 502 {
491 503 if (rconsvp == NULL)
492 504 return (nochpoll(dev, events, anyyet, reventsp, phpp));
493 505
494 506 if (rconsvp->v_stream != NULL)
495 507 return (strpoll(rconsvp->v_stream, events, anyyet, reventsp,
496 508 phpp));
497 509 else
498 510 return (cdev_poll(rconsdev, events, anyyet, reventsp, phpp));
499 511 }
↓ open down ↓ |
65 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX