1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2002 - 2008 Jeff Dike (jdike@{addtoit,linux.intel}.com) 4 */ 5 6 #include <unistd.h> 7 #include <errno.h> 8 #include <fcntl.h> 9 #include <poll.h> 10 #include <pty.h> 11 #include <sched.h> 12 #include <signal.h> 13 #include <string.h> 14 #include <kern_util.h> 15 #include <init.h> 16 #include <os.h> 17 #include <sigio.h> 18 #include <um_malloc.h> 19 20 /* 21 * Protected by sigio_lock(), also used by sigio_cleanup, which is an 22 * exitcall. 23 */ 24 static int write_sigio_pid = -1; 25 static unsigned long write_sigio_stack; 26 27 /* 28 * These arrays are initialized before the sigio thread is started, and 29 * the descriptors closed after it is killed. So, it can't see them change. 30 * On the UML side, they are changed under the sigio_lock. 31 */ 32 #define SIGIO_FDS_INIT {-1, -1} 33 34 static int write_sigio_fds[2] = SIGIO_FDS_INIT; 35 static int sigio_private[2] = SIGIO_FDS_INIT; 36 37 struct pollfds { 38 struct pollfd *poll; 39 int size; 40 int used; 41 }; 42 43 /* 44 * Protected by sigio_lock(). Used by the sigio thread, but the UML thread 45 * synchronizes with it. 46 */ 47 static struct pollfds current_poll; 48 static struct pollfds next_poll; 49 static struct pollfds all_sigio_fds; 50 51 static int write_sigio_thread(void *unused) 52 { 53 struct pollfds *fds, tmp; 54 struct pollfd *p; 55 int i, n, respond_fd; 56 char c; 57 58 os_fix_helper_signals(); 59 fds = ¤t_poll; 60 while (1) { 61 n = poll(fds->poll, fds->used, -1); 62 if (n < 0) { 63 if (errno == EINTR) 64 continue; 65 printk(UM_KERN_ERR "write_sigio_thread : poll returned " 66 "%d, errno = %d\n", n, errno); 67 } 68 for (i = 0; i < fds->used; i++) { 69 p = &fds->poll[i]; 70 if (p->revents == 0) 71 continue; 72 if (p->fd == sigio_private[1]) { 73 CATCH_EINTR(n = read(sigio_private[1], &c, 74 sizeof(c))); 75 if (n != sizeof(c)) 76 printk(UM_KERN_ERR 77 "write_sigio_thread : " 78 "read on socket failed, " 79 "err = %d\n", errno); 80 tmp = current_poll; 81 current_poll = next_poll; 82 next_poll = tmp; 83 respond_fd = sigio_private[1]; 84 } 85 else { 86 respond_fd = write_sigio_fds[1]; 87 fds->used--; 88 memmove(&fds->poll[i], &fds->poll[i + 1], 89 (fds->used - i) * sizeof(*fds->poll)); 90 } 91 92 CATCH_EINTR(n = write(respond_fd, &c, sizeof(c))); 93 if (n != sizeof(c)) 94 printk(UM_KERN_ERR "write_sigio_thread : " 95 "write on socket failed, err = %d\n", 96 errno); 97 } 98 } 99 100 return 0; 101 } 102 103 static int need_poll(struct pollfds *polls, int n) 104 { 105 struct pollfd *new; 106 107 if (n <= polls->size) 108 return 0; 109 110 new = uml_kmalloc(n * sizeof(struct pollfd), UM_GFP_ATOMIC); 111 if (new == NULL) { 112 printk(UM_KERN_ERR "need_poll : failed to allocate new " 113 "pollfds\n"); 114 return -ENOMEM; 115 } 116 117 memcpy(new, polls->poll, polls->used * sizeof(struct pollfd)); 118 kfree(polls->poll); 119 120 polls->poll = new; 121 polls->size = n; 122 return 0; 123 } 124 125 /* 126 * Must be called with sigio_lock held, because it's needed by the marked 127 * critical section. 128 */ 129 static void update_thread(void) 130 { 131 unsigned long flags; 132 int n; 133 char c; 134 135 flags = um_set_signals_trace(0); 136 CATCH_EINTR(n = write(sigio_private[0], &c, sizeof(c))); 137 if (n != sizeof(c)) { 138 printk(UM_KERN_ERR "update_thread : write failed, err = %d\n", 139 errno); 140 goto fail; 141 } 142 143 CATCH_EINTR(n = read(sigio_private[0], &c, sizeof(c))); 144 if (n != sizeof(c)) { 145 printk(UM_KERN_ERR "update_thread : read failed, err = %d\n", 146 errno); 147 goto fail; 148 } 149 150 um_set_signals_trace(flags); 151 return; 152 fail: 153 /* Critical section start */ 154 if (write_sigio_pid != -1) { 155 os_kill_process(write_sigio_pid, 1); 156 free_stack(write_sigio_stack, 0); 157 } 158 write_sigio_pid = -1; 159 close(sigio_private[0]); 160 close(sigio_private[1]); 161 close(write_sigio_fds[0]); 162 close(write_sigio_fds[1]); 163 /* Critical section end */ 164 um_set_signals_trace(flags); 165 } 166 167 int __add_sigio_fd(int fd) 168 { 169 struct pollfd *p; 170 int err, i, n; 171 172 for (i = 0; i < all_sigio_fds.used; i++) { 173 if (all_sigio_fds.poll[i].fd == fd) 174 break; 175 } 176 if (i == all_sigio_fds.used) 177 return -ENOSPC; 178 179 p = &all_sigio_fds.poll[i]; 180 181 for (i = 0; i < current_poll.used; i++) { 182 if (current_poll.poll[i].fd == fd) 183 return 0; 184 } 185 186 n = current_poll.used; 187 err = need_poll(&next_poll, n + 1); 188 if (err) 189 return err; 190 191 memcpy(next_poll.poll, current_poll.poll, 192 current_poll.used * sizeof(struct pollfd)); 193 next_poll.poll[n] = *p; 194 next_poll.used = n + 1; 195 update_thread(); 196 197 return 0; 198 } 199 200 201 int add_sigio_fd(int fd) 202 { 203 int err; 204 205 sigio_lock(); 206 err = __add_sigio_fd(fd); 207 sigio_unlock(); 208 209 return err; 210 } 211 212 int __ignore_sigio_fd(int fd) 213 { 214 struct pollfd *p; 215 int err, i, n = 0; 216 217 /* 218 * This is called from exitcalls elsewhere in UML - if 219 * sigio_cleanup has already run, then update_thread will hang 220 * or fail because the thread is no longer running. 221 */ 222 if (write_sigio_pid == -1) 223 return -EIO; 224 225 for (i = 0; i < current_poll.used; i++) { 226 if (current_poll.poll[i].fd == fd) 227 break; 228 } 229 if (i == current_poll.used) 230 return -ENOENT; 231 232 err = need_poll(&next_poll, current_poll.used - 1); 233 if (err) 234 return err; 235 236 for (i = 0; i < current_poll.used; i++) { 237 p = ¤t_poll.poll[i]; 238 if (p->fd != fd) 239 next_poll.poll[n++] = *p; 240 } 241 next_poll.used = current_poll.used - 1; 242 243 update_thread(); 244 245 return 0; 246 } 247 248 int ignore_sigio_fd(int fd) 249 { 250 int err; 251 252 sigio_lock(); 253 err = __ignore_sigio_fd(fd); 254 sigio_unlock(); 255 256 return err; 257 } 258 259 static struct pollfd *setup_initial_poll(int fd) 260 { 261 struct pollfd *p; 262 263 p = uml_kmalloc(sizeof(struct pollfd), UM_GFP_KERNEL); 264 if (p == NULL) { 265 printk(UM_KERN_ERR "setup_initial_poll : failed to allocate " 266 "poll\n"); 267 return NULL; 268 } 269 *p = ((struct pollfd) { .fd = fd, 270 .events = POLLIN, 271 .revents = 0 }); 272 return p; 273 } 274 275 static void write_sigio_workaround(void) 276 { 277 struct pollfd *p; 278 int err; 279 int l_write_sigio_fds[2]; 280 int l_sigio_private[2]; 281 int l_write_sigio_pid; 282 283 /* We call this *tons* of times - and most ones we must just fail. */ 284 sigio_lock(); 285 l_write_sigio_pid = write_sigio_pid; 286 sigio_unlock(); 287 288 if (l_write_sigio_pid != -1) 289 return; 290 291 err = os_pipe(l_write_sigio_fds, 1, 1); 292 if (err < 0) { 293 printk(UM_KERN_ERR "write_sigio_workaround - os_pipe 1 failed, " 294 "err = %d\n", -err); 295 return; 296 } 297 err = os_pipe(l_sigio_private, 1, 1); 298 if (err < 0) { 299 printk(UM_KERN_ERR "write_sigio_workaround - os_pipe 2 failed, " 300 "err = %d\n", -err); 301 goto out_close1; 302 } 303 304 p = setup_initial_poll(l_sigio_private[1]); 305 if (!p) 306 goto out_close2; 307 308 sigio_lock(); 309 310 /* 311 * Did we race? Don't try to optimize this, please, it's not so likely 312 * to happen, and no more than once at the boot. 313 */ 314 if (write_sigio_pid != -1) 315 goto out_free; 316 317 current_poll = ((struct pollfds) { .poll = p, 318 .used = 1, 319 .size = 1 }); 320 321 if (write_sigio_irq(l_write_sigio_fds[0])) 322 goto out_clear_poll; 323 324 memcpy(write_sigio_fds, l_write_sigio_fds, sizeof(l_write_sigio_fds)); 325 memcpy(sigio_private, l_sigio_private, sizeof(l_sigio_private)); 326 327 write_sigio_pid = run_helper_thread(write_sigio_thread, NULL, 328 CLONE_FILES | CLONE_VM, 329 &write_sigio_stack); 330 331 if (write_sigio_pid < 0) 332 goto out_clear; 333 334 sigio_unlock(); 335 return; 336 337 out_clear: 338 write_sigio_pid = -1; 339 write_sigio_fds[0] = -1; 340 write_sigio_fds[1] = -1; 341 sigio_private[0] = -1; 342 sigio_private[1] = -1; 343 out_clear_poll: 344 current_poll = ((struct pollfds) { .poll = NULL, 345 .size = 0, 346 .used = 0 }); 347 out_free: 348 sigio_unlock(); 349 kfree(p); 350 out_close2: 351 close(l_sigio_private[0]); 352 close(l_sigio_private[1]); 353 out_close1: 354 close(l_write_sigio_fds[0]); 355 close(l_write_sigio_fds[1]); 356 } 357 358 void sigio_broken(int fd) 359 { 360 int err; 361 362 write_sigio_workaround(); 363 364 sigio_lock(); 365 err = need_poll(&all_sigio_fds, all_sigio_fds.used + 1); 366 if (err) { 367 printk(UM_KERN_ERR "maybe_sigio_broken - failed to add pollfd " 368 "for descriptor %d\n", fd); 369 goto out; 370 } 371 372 all_sigio_fds.poll[all_sigio_fds.used++] = 373 ((struct pollfd) { .fd = fd, 374 .events = POLLIN, 375 .revents = 0 }); 376 out: 377 sigio_unlock(); 378 } 379 380 /* Changed during early boot */ 381 static int pty_output_sigio; 382 383 void maybe_sigio_broken(int fd) 384 { 385 if (!isatty(fd)) 386 return; 387 388 if (pty_output_sigio) 389 return; 390 391 sigio_broken(fd); 392 } 393 394 static void sigio_cleanup(void) 395 { 396 if (write_sigio_pid == -1) 397 return; 398 399 os_kill_process(write_sigio_pid, 1); 400 free_stack(write_sigio_stack, 0); 401 write_sigio_pid = -1; 402 } 403 404 __uml_exitcall(sigio_cleanup); 405 406 /* Used as a flag during SIGIO testing early in boot */ 407 static int got_sigio; 408 409 static void __init handler(int sig) 410 { 411 got_sigio = 1; 412 } 413 414 struct openpty_arg { 415 int master; 416 int slave; 417 int err; 418 }; 419 420 static void openpty_cb(void *arg) 421 { 422 struct openpty_arg *info = arg; 423 424 info->err = 0; 425 if (openpty(&info->master, &info->slave, NULL, NULL, NULL)) 426 info->err = -errno; 427 } 428 429 static int async_pty(int master, int slave) 430 { 431 int flags; 432 433 flags = fcntl(master, F_GETFL); 434 if (flags < 0) 435 return -errno; 436 437 if ((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) || 438 (fcntl(master, F_SETOWN, os_getpid()) < 0)) 439 return -errno; 440 441 if ((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0)) 442 return -errno; 443 444 return 0; 445 } 446 447 static void __init check_one_sigio(void (*proc)(int, int)) 448 { 449 struct sigaction old, new; 450 struct openpty_arg pty = { .master = -1, .slave = -1 }; 451 int master, slave, err; 452 453 initial_thread_cb(openpty_cb, &pty); 454 if (pty.err) { 455 printk(UM_KERN_ERR "check_one_sigio failed, errno = %d\n", 456 -pty.err); 457 return; 458 } 459 460 master = pty.master; 461 slave = pty.slave; 462 463 if ((master == -1) || (slave == -1)) { 464 printk(UM_KERN_ERR "check_one_sigio failed to allocate a " 465 "pty\n"); 466 return; 467 } 468 469 /* Not now, but complain so we now where we failed. */ 470 err = raw(master); 471 if (err < 0) { 472 printk(UM_KERN_ERR "check_one_sigio : raw failed, errno = %d\n", 473 -err); 474 return; 475 } 476 477 err = async_pty(master, slave); 478 if (err < 0) { 479 printk(UM_KERN_ERR "check_one_sigio : sigio_async failed, " 480 "err = %d\n", -err); 481 return; 482 } 483 484 if (sigaction(SIGIO, NULL, &old) < 0) { 485 printk(UM_KERN_ERR "check_one_sigio : sigaction 1 failed, " 486 "errno = %d\n", errno); 487 return; 488 } 489 490 new = old; 491 new.sa_handler = handler; 492 if (sigaction(SIGIO, &new, NULL) < 0) { 493 printk(UM_KERN_ERR "check_one_sigio : sigaction 2 failed, " 494 "errno = %d\n", errno); 495 return; 496 } 497 498 got_sigio = 0; 499 (*proc)(master, slave); 500 501 close(master); 502 close(slave); 503 504 if (sigaction(SIGIO, &old, NULL) < 0) 505 printk(UM_KERN_ERR "check_one_sigio : sigaction 3 failed, " 506 "errno = %d\n", errno); 507 } 508 509 static void tty_output(int master, int slave) 510 { 511 int n; 512 char buf[512]; 513 514 printk(UM_KERN_INFO "Checking that host ptys support output SIGIO..."); 515 516 memset(buf, 0, sizeof(buf)); 517 518 while (write(master, buf, sizeof(buf)) > 0) ; 519 if (errno != EAGAIN) 520 printk(UM_KERN_ERR "tty_output : write failed, errno = %d\n", 521 errno); 522 while (((n = read(slave, buf, sizeof(buf))) > 0) && 523 !({ barrier(); got_sigio; })) 524 ; 525 526 if (got_sigio) { 527 printk(UM_KERN_CONT "Yes\n"); 528 pty_output_sigio = 1; 529 } else if (n == -EAGAIN) 530 printk(UM_KERN_CONT "No, enabling workaround\n"); 531 else 532 printk(UM_KERN_CONT "tty_output : read failed, err = %d\n", n); 533 } 534 535 static void __init check_sigio(void) 536 { 537 if ((access("/dev/ptmx", R_OK) < 0) && 538 (access("/dev/ptyp0", R_OK) < 0)) { 539 printk(UM_KERN_WARNING "No pseudo-terminals available - " 540 "skipping pty SIGIO check\n"); 541 return; 542 } 543 check_one_sigio(tty_output); 544 } 545 546 /* Here because it only does the SIGIO testing for now */ 547 void __init os_check_bugs(void) 548 { 549 check_sigio(); 550 } 551