1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright 2023 Red Hat 4 */ 5 6 #include "thread-utils.h" 7 8 #include <asm/current.h> 9 #include <linux/delay.h> 10 #include <linux/kthread.h> 11 #include <linux/mutex.h> 12 #include <linux/types.h> 13 14 #include "errors.h" 15 #include "logger.h" 16 #include "memory-alloc.h" 17 18 static struct hlist_head thread_list; 19 static struct mutex thread_mutex; 20 21 struct thread { 22 void (*thread_function)(void *thread_data); 23 void *thread_data; 24 struct hlist_node thread_links; 25 struct task_struct *thread_task; 26 struct completion thread_done; 27 }; 28 29 void vdo_initialize_threads_mutex(void) 30 { 31 mutex_init(&thread_mutex); 32 } 33 34 static int thread_starter(void *arg) 35 { 36 struct registered_thread allocating_thread; 37 struct thread *thread = arg; 38 39 thread->thread_task = current; 40 mutex_lock(&thread_mutex); 41 hlist_add_head(&thread->thread_links, &thread_list); 42 mutex_unlock(&thread_mutex); 43 vdo_register_allocating_thread(&allocating_thread, NULL); 44 thread->thread_function(thread->thread_data); 45 vdo_unregister_allocating_thread(); 46 complete(&thread->thread_done); 47 return 0; 48 } 49 50 int vdo_create_thread(void (*thread_function)(void *), void *thread_data, 51 const char *name, struct thread **new_thread) 52 { 53 char *name_colon = strchr(name, ':'); 54 char *my_name_colon = strchr(current->comm, ':'); 55 struct task_struct *task; 56 struct thread *thread; 57 int result; 58 59 result = vdo_allocate(1, struct thread, __func__, &thread); 60 if (result != VDO_SUCCESS) { 61 vdo_log_warning("Error allocating memory for %s", name); 62 return result; 63 } 64 65 thread->thread_function = thread_function; 66 thread->thread_data = thread_data; 67 init_completion(&thread->thread_done); 68 /* 69 * Start the thread, with an appropriate thread name. 70 * 71 * If the name supplied contains a colon character, use that name. This causes uds module 72 * threads to have names like "uds:callbackW" and the main test runner thread to be named 73 * "zub:runtest". 74 * 75 * Otherwise if the current thread has a name containing a colon character, prefix the name 76 * supplied with the name of the current thread up to (and including) the colon character. 77 * Thus when the "kvdo0:dedupeQ" thread opens an index session, all the threads associated 78 * with that index will have names like "kvdo0:foo". 79 * 80 * Otherwise just use the name supplied. This should be a rare occurrence. 81 */ 82 if ((name_colon == NULL) && (my_name_colon != NULL)) { 83 task = kthread_run(thread_starter, thread, "%.*s:%s", 84 (int) (my_name_colon - current->comm), current->comm, 85 name); 86 } else { 87 task = kthread_run(thread_starter, thread, "%s", name); 88 } 89 90 if (IS_ERR(task)) { 91 vdo_free(thread); 92 return PTR_ERR(task); 93 } 94 95 *new_thread = thread; 96 return VDO_SUCCESS; 97 } 98 99 void vdo_join_threads(struct thread *thread) 100 { 101 while (wait_for_completion_interruptible(&thread->thread_done)) 102 fsleep(1000); 103 104 mutex_lock(&thread_mutex); 105 hlist_del(&thread->thread_links); 106 mutex_unlock(&thread_mutex); 107 vdo_free(thread); 108 } 109