109 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright 2023 Red Hat4 */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 18static struct hlist_head thread_list;19static struct mutex thread_mutex;20 21struct 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 29void vdo_initialize_threads_mutex(void)30{31 mutex_init(&thread_mutex);32}33 34static 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 50int 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 module72 * threads to have names like "uds:callbackW" and the main test runner thread to be named73 * "zub:runtest".74 *75 * Otherwise if the current thread has a name containing a colon character, prefix the name76 * 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 associated78 * 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 99void 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