LCOV - code coverage report
Current view: top level - arch/um/os-Linux - sigio.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 55 237 23.2 %
Date: 2023-08-24 13:40:31 Functions: 9 19 47.4 %

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

Generated by: LCOV version 1.14