cregit-Linux how code gets into the kernel

Release 4.14 arch/um/drivers/chan_user.c

Directory: arch/um/drivers
/*
 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com)
 * Licensed under the GPL
 */

#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sched.h>
#include <signal.h>
#include <termios.h>
#include <sys/ioctl.h>
#include "chan_user.h"
#include <os.h>
#include <um_malloc.h>


void generic_close(int fd, void *unused) { close(fd); }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Dike17100.00%2100.00%
Total17100.00%2100.00%


int generic_read(int fd, char *c_out, void *unused) { int n; n = read(fd, c_out, sizeof(*c_out)); if (n > 0) return n; else if (errno == EAGAIN) return 0; else if (n == 0) return -EIO; return -errno; }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Dike68100.00%2100.00%
Total68100.00%2100.00%

/* XXX Trivial wrapper around write */
int generic_write(int fd, const char *buf, int n, void *unused) { int err; err = write(fd, buf, n); if (err > 0) return err; else if (errno == EAGAIN) return 0; else if (err == 0) return -EIO; return -errno; }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Dike68100.00%3100.00%
Total68100.00%3100.00%


int generic_window_size(int fd, void *unused, unsigned short *rows_out, unsigned short *cols_out) { struct winsize size; int ret; if (ioctl(fd, TIOCGWINSZ, &size) < 0) return -errno; ret = ((*rows_out != size.ws_row) || (*cols_out != size.ws_col)); *rows_out = size.ws_row; *cols_out = size.ws_col; return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Dike86100.00%2100.00%
Total86100.00%2100.00%


void generic_free(void *data) { kfree(data); }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Dike14100.00%1100.00%
Total14100.00%1100.00%


int generic_console_write(int fd, const char *buf, int n) { sigset_t old, no_sigio; struct termios save, new; int err; if (isatty(fd)) { sigemptyset(&no_sigio); sigaddset(&no_sigio, SIGIO); if (sigprocmask(SIG_BLOCK, &no_sigio, &old)) goto error; CATCH_EINTR(err = tcgetattr(fd, &save)); if (err) goto error; new = save; /* * The terminal becomes a bit less raw, to handle \n also as * "Carriage Return", not only as "New Line". Otherwise, the new * line won't start at the first column. */ new.c_oflag |= OPOST; CATCH_EINTR(err = tcsetattr(fd, TCSAFLUSH, &new)); if (err) goto error; } err = generic_write(fd, buf, n, NULL); /* * Restore raw mode, in any case; we *must* ignore any error apart * EINTR, except for debug. */ if (isatty(fd)) { CATCH_EINTR(tcsetattr(fd, TCSAFLUSH, &save)); sigprocmask(SIG_SETMASK, &old, NULL); } return err; error: return -errno; }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Dike14481.36%375.00%
Paolo 'Blaisorblade' Giarrusso3318.64%125.00%
Total177100.00%4100.00%

/* * UML SIGWINCH handling * * The point of this is to handle SIGWINCH on consoles which have host * ttys and relay them inside UML to whatever might be running on the * console and cares about the window size (since SIGWINCH notifies * about terminal size changes). * * So, we have a separate thread for each host tty attached to a UML * device (side-issue - I'm annoyed that one thread can't have * multiple controlling ttys for the purpose of handling SIGWINCH, but * I imagine there are other reasons that doesn't make any sense). * * SIGWINCH can't be received synchronously, so you have to set up to * receive it as a signal. That being the case, if you are going to * wait for it, it is convenient to sit in sigsuspend() and wait for * the signal to bounce you out of it (see below for how we make sure * to exit only on SIGWINCH). */
static void winch_handler(int sig) { }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Dike8100.00%1100.00%
Total8100.00%1100.00%

struct winch_data { int pty_fd; int pipe_fd; };
static int winch_thread(void *arg) { struct winch_data *data = arg; sigset_t sigs; int pty_fd, pipe_fd; int count; char c = 1; pty_fd = data->pty_fd; pipe_fd = data->pipe_fd; count = write(pipe_fd, &c, sizeof(c)); if (count != sizeof(c)) printk(UM_KERN_ERR "winch_thread : failed to write " "synchronization byte, err = %d\n", -count); /* * We are not using SIG_IGN on purpose, so don't fix it as I thought to * do! If using SIG_IGN, the sigsuspend() call below would not stop on * SIGWINCH. */ signal(SIGWINCH, winch_handler); sigfillset(&sigs); /* Block all signals possible. */ if (sigprocmask(SIG_SETMASK, &sigs, NULL) < 0) { printk(UM_KERN_ERR "winch_thread : sigprocmask failed, " "errno = %d\n", errno); exit(1); } /* In sigsuspend(), block anything else than SIGWINCH. */ sigdelset(&sigs, SIGWINCH); if (setsid() < 0) { printk(UM_KERN_ERR "winch_thread : setsid failed, errno = %d\n", errno); exit(1); } if (ioctl(pty_fd, TIOCSCTTY, 0) < 0) { printk(UM_KERN_ERR "winch_thread : TIOCSCTTY failed on " "fd %d err = %d\n", pty_fd, errno); exit(1); } if (tcsetpgrp(pty_fd, os_getpid()) < 0) { printk(UM_KERN_ERR "winch_thread : tcsetpgrp failed on " "fd %d err = %d\n", pty_fd, errno); exit(1); } /* * These are synchronization calls between various UML threads on the * host - since they are not different kernel threads, we cannot use * kernel semaphores. We don't use SysV semaphores because they are * persistent. */ count = read(pipe_fd, &c, sizeof(c)); if (count != sizeof(c)) printk(UM_KERN_ERR "winch_thread : failed to read " "synchronization byte, err = %d\n", errno); while(1) { /* * This will be interrupted by SIGWINCH only, since * other signals are blocked. */ sigsuspend(&sigs); count = write(pipe_fd, &c, sizeof(c)); if (count != sizeof(c)) printk(UM_KERN_ERR "winch_thread : write failed, " "err = %d\n", errno); } }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Dike25887.16%466.67%
Paolo 'Blaisorblade' Giarrusso237.77%116.67%
Bodo Stroesser155.07%116.67%
Total296100.00%6100.00%


static int winch_tramp(int fd, struct tty_port *port, int *fd_out, unsigned long *stack_out) { struct winch_data data; int fds[2], n, err; char c; err = os_pipe(fds, 1, 1); if (err < 0) { printk(UM_KERN_ERR "winch_tramp : os_pipe failed, err = %d\n", -err); goto out; } data = ((struct winch_data) { .pty_fd = fd, .pipe_fd = fds[1] } ); /* * CLONE_FILES so this thread doesn't hold open files which are open * now, but later closed in a different thread. This is a * problem with /dev/net/tun, which if held open by this * thread, prevents the TUN/TAP device from being reused. */ err = run_helper_thread(winch_thread, &data, CLONE_FILES, stack_out); if (err < 0) { printk(UM_KERN_ERR "fork of winch_thread failed - errno = %d\n", -err); goto out_close; } *fd_out = fds[0]; n = read(fds[0], &c, sizeof(c)); if (n != sizeof(c)) { printk(UM_KERN_ERR "winch_tramp : failed to read " "synchronization byte\n"); printk(UM_KERN_ERR "read failed, err = %d\n", errno); printk(UM_KERN_ERR "fd %d will not support SIGWINCH\n", fd); err = -EINVAL; goto out_close; } if (os_set_fd_block(*fd_out, 0)) { printk(UM_KERN_ERR "winch_tramp: failed to set thread_fd " "non-blocking.\n"); goto out_close; } return err; out_close: close(fds[1]); close(fds[0]); out: return err; }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Dike21888.98%861.54%
Eduard-Gabriel Munteanu197.76%17.69%
Paolo 'Blaisorblade' Giarrusso41.63%17.69%
Richard Weinberger20.82%17.69%
Andrew Morton10.41%17.69%
Gerd Knorr10.41%17.69%
Total245100.00%13100.00%


void register_winch(int fd, struct tty_port *port) { unsigned long stack; int pid, thread, count, thread_fd = -1; char c = 1; if (!isatty(fd)) return; pid = tcgetpgrp(fd); if (is_skas_winch(pid, fd, port)) { register_winch_irq(-1, fd, -1, port, 0); return; } if (pid == -1) { thread = winch_tramp(fd, port, &thread_fd, &stack); if (thread < 0) return; register_winch_irq(thread_fd, fd, thread, port, stack); count = write(thread_fd, &c, sizeof(c)); if (count != sizeof(c)) printk(UM_KERN_ERR "register_winch : failed to write " "synchronization byte, err = %d\n", errno); } }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Dike12076.92%866.67%
Al Viro2012.82%18.33%
Paolo 'Blaisorblade' Giarrusso95.77%18.33%
Richard Weinberger63.85%18.33%
Gerd Knorr10.64%18.33%
Total156100.00%12100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Jeff Dike104388.46%1664.00%
Paolo 'Blaisorblade' Giarrusso695.85%28.00%
Al Viro221.87%28.00%
Eduard-Gabriel Munteanu191.61%14.00%
Bodo Stroesser151.27%14.00%
Richard Weinberger80.68%14.00%
Gerd Knorr20.17%14.00%
Andrew Morton10.08%14.00%
Total1179100.00%25100.00%
Directory: arch/um/drivers
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.