1 /* 2 * Asynchronous teardown 3 * 4 * Copyright IBM, Corp. 2022 5 * 6 * Authors: 7 * Claudio Imbrenda <imbrenda@linux.ibm.com> 8 * 9 * This work is licensed under the terms of the GNU GPL, version 2 or (at your 10 * option) any later version. See the COPYING file in the top-level directory. 11 * 12 */ 13 14 #include "qemu/osdep.h" 15 #include <dirent.h> 16 #include <sys/prctl.h> 17 #include <sched.h> 18 19 #include "qemu/async-teardown.h" 20 21 #ifdef _SC_THREAD_STACK_MIN 22 #define CLONE_STACK_SIZE sysconf(_SC_THREAD_STACK_MIN) 23 #else 24 #define CLONE_STACK_SIZE 16384 25 #endif 26 27 static pid_t the_ppid; 28 29 /* 30 * Close all open file descriptors. 31 */ 32 static void close_all_open_fd(void) 33 { 34 struct dirent *de; 35 int fd, dfd; 36 DIR *dir; 37 38 #ifdef CONFIG_CLOSE_RANGE 39 int r = close_range(0, ~0U, 0); 40 if (!r) { 41 /* Success, no need to try other ways. */ 42 return; 43 } 44 #endif 45 46 dir = opendir("/proc/self/fd"); 47 if (!dir) { 48 /* If /proc is not mounted, there is nothing that can be done. */ 49 return; 50 } 51 /* Avoid closing the directory. */ 52 dfd = dirfd(dir); 53 54 for (de = readdir(dir); de; de = readdir(dir)) { 55 fd = atoi(de->d_name); 56 if (fd != dfd) { 57 close(fd); 58 } 59 } 60 closedir(dir); 61 } 62 63 static void hup_handler(int signal) 64 { 65 /* Check every second if this process has been reparented. */ 66 while (the_ppid == getppid()) { 67 /* sleep() is safe to use in a signal handler. */ 68 sleep(1); 69 } 70 71 /* At this point the parent process has terminated completely. */ 72 _exit(0); 73 } 74 75 static int async_teardown_fn(void *arg) 76 { 77 struct sigaction sa = { .sa_handler = hup_handler }; 78 sigset_t hup_signal; 79 char name[16]; 80 81 /* Set a meaningful name for this process. */ 82 snprintf(name, 16, "cleanup/%d", the_ppid); 83 prctl(PR_SET_NAME, (unsigned long)name); 84 85 /* 86 * Close all file descriptors that might have been inherited from the 87 * main qemu process when doing clone, needed to make libvirt happy. 88 * Not using close_range for increased compatibility with older kernels. 89 */ 90 close_all_open_fd(); 91 92 /* Set up a handler for SIGHUP and unblock SIGHUP. */ 93 sigaction(SIGHUP, &sa, NULL); 94 sigemptyset(&hup_signal); 95 sigaddset(&hup_signal, SIGHUP); 96 sigprocmask(SIG_UNBLOCK, &hup_signal, NULL); 97 98 /* Ask to receive SIGHUP when the parent dies. */ 99 prctl(PR_SET_PDEATHSIG, SIGHUP); 100 101 /* 102 * Sleep forever, unless the parent process has already terminated. The 103 * only interruption can come from the SIGHUP signal, which in normal 104 * operation is received when the parent process dies. 105 */ 106 if (the_ppid == getppid()) { 107 pause(); 108 } 109 110 /* At this point the parent process has terminated completely. */ 111 _exit(0); 112 } 113 114 /* 115 * Allocate a new stack of a reasonable size, and return a pointer to its top. 116 */ 117 static void *new_stack_for_clone(void) 118 { 119 size_t stack_size = CLONE_STACK_SIZE; 120 char *stack_ptr; 121 122 /* Allocate a new stack and get a pointer to its top. */ 123 stack_ptr = qemu_alloc_stack(&stack_size); 124 stack_ptr += stack_size; 125 126 return stack_ptr; 127 } 128 129 /* 130 * Block all signals, start (clone) a new process sharing the address space 131 * with qemu (CLONE_VM), then restore signals. 132 */ 133 void init_async_teardown(void) 134 { 135 sigset_t all_signals, old_signals; 136 137 the_ppid = getpid(); 138 139 sigfillset(&all_signals); 140 sigprocmask(SIG_BLOCK, &all_signals, &old_signals); 141 clone(async_teardown_fn, new_stack_for_clone(), CLONE_VM, NULL); 142 sigprocmask(SIG_SETMASK, &old_signals, NULL); 143 } 144