Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

dm vdo: add basic logging and support utilities

Add various support utilities for the vdo target and deduplication index,
including logging utilities, string and time management, and index-specific
error codes.

Co-developed-by: J. corwin Coburn <corwin@hurlbutnet.net>
Signed-off-by: J. corwin Coburn <corwin@hurlbutnet.net>
Co-developed-by: Michael Sclafani <dm-devel@lists.linux.dev>
Signed-off-by: Michael Sclafani <dm-devel@lists.linux.dev>
Co-developed-by: Thomas Jaskiewicz <tom@jaskiewicz.us>
Signed-off-by: Thomas Jaskiewicz <tom@jaskiewicz.us>
Co-developed-by: Ken Raeburn <raeburn@redhat.com>
Signed-off-by: Ken Raeburn <raeburn@redhat.com>
Signed-off-by: Matthew Sakai <msakai@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@kernel.org>

authored by

Matthew Sakai and committed by
Mike Snitzer
03d1089e 46766d48

+940
+312
drivers/md/dm-vdo/errors.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright 2023 Red Hat 4 + */ 5 + 6 + #include "errors.h" 7 + 8 + #include <linux/compiler.h> 9 + #include <linux/errno.h> 10 + 11 + #include "logger.h" 12 + #include "permassert.h" 13 + #include "string-utils.h" 14 + 15 + static const struct error_info successful = { "UDS_SUCCESS", "Success" }; 16 + 17 + static const char *const message_table[] = { 18 + [EPERM] = "Operation not permitted", 19 + [ENOENT] = "No such file or directory", 20 + [ESRCH] = "No such process", 21 + [EINTR] = "Interrupted system call", 22 + [EIO] = "Input/output error", 23 + [ENXIO] = "No such device or address", 24 + [E2BIG] = "Argument list too long", 25 + [ENOEXEC] = "Exec format error", 26 + [EBADF] = "Bad file descriptor", 27 + [ECHILD] = "No child processes", 28 + [EAGAIN] = "Resource temporarily unavailable", 29 + [ENOMEM] = "Cannot allocate memory", 30 + [EACCES] = "Permission denied", 31 + [EFAULT] = "Bad address", 32 + [ENOTBLK] = "Block device required", 33 + [EBUSY] = "Device or resource busy", 34 + [EEXIST] = "File exists", 35 + [EXDEV] = "Invalid cross-device link", 36 + [ENODEV] = "No such device", 37 + [ENOTDIR] = "Not a directory", 38 + [EISDIR] = "Is a directory", 39 + [EINVAL] = "Invalid argument", 40 + [ENFILE] = "Too many open files in system", 41 + [EMFILE] = "Too many open files", 42 + [ENOTTY] = "Inappropriate ioctl for device", 43 + [ETXTBSY] = "Text file busy", 44 + [EFBIG] = "File too large", 45 + [ENOSPC] = "No space left on device", 46 + [ESPIPE] = "Illegal seek", 47 + [EROFS] = "Read-only file system", 48 + [EMLINK] = "Too many links", 49 + [EPIPE] = "Broken pipe", 50 + [EDOM] = "Numerical argument out of domain", 51 + [ERANGE] = "Numerical result out of range" 52 + }; 53 + 54 + static const struct error_info error_list[] = { 55 + { "UDS_OVERFLOW", "Index overflow" }, 56 + { "UDS_INVALID_ARGUMENT", "Invalid argument passed to internal routine" }, 57 + { "UDS_BAD_STATE", "UDS data structures are in an invalid state" }, 58 + { "UDS_DUPLICATE_NAME", "Attempt to enter the same name into a delta index twice" }, 59 + { "UDS_ASSERTION_FAILED", "Assertion failed" }, 60 + { "UDS_QUEUED", "Request queued" }, 61 + { "UDS_BUFFER_ERROR", "Buffer error" }, 62 + { "UDS_NO_DIRECTORY", "Expected directory is missing" }, 63 + { "UDS_ALREADY_REGISTERED", "Error range already registered" }, 64 + { "UDS_OUT_OF_RANGE", "Cannot access data outside specified limits" }, 65 + { "UDS_EMODULE_LOAD", "Could not load modules" }, 66 + { "UDS_DISABLED", "UDS library context is disabled" }, 67 + { "UDS_UNKNOWN_ERROR", "Unknown error" }, 68 + { "UDS_UNSUPPORTED_VERSION", "Unsupported version" }, 69 + { "UDS_CORRUPT_DATA", "Some index structure is corrupt" }, 70 + { "UDS_NO_INDEX", "No index found" }, 71 + { "UDS_INDEX_NOT_SAVED_CLEANLY", "Index not saved cleanly" }, 72 + }; 73 + 74 + struct error_block { 75 + const char *name; 76 + int base; 77 + int last; 78 + int max; 79 + const struct error_info *infos; 80 + }; 81 + 82 + enum { 83 + MAX_ERROR_BLOCKS = 6, 84 + }; 85 + 86 + static struct { 87 + int allocated; 88 + int count; 89 + struct error_block blocks[MAX_ERROR_BLOCKS]; 90 + } registered_errors = { 91 + .allocated = MAX_ERROR_BLOCKS, 92 + .count = 1, 93 + .blocks = { { 94 + .name = "UDS Error", 95 + .base = UDS_ERROR_CODE_BASE, 96 + .last = UDS_ERROR_CODE_LAST, 97 + .max = UDS_ERROR_CODE_BLOCK_END, 98 + .infos = error_list, 99 + } }, 100 + }; 101 + 102 + /* Get the error info for an error number. Also returns the name of the error block, if known. */ 103 + static const char *get_error_info(int errnum, const struct error_info **info_ptr) 104 + { 105 + struct error_block *block; 106 + 107 + if (errnum == UDS_SUCCESS) { 108 + *info_ptr = &successful; 109 + return NULL; 110 + } 111 + 112 + for (block = registered_errors.blocks; 113 + block < registered_errors.blocks + registered_errors.count; 114 + block++) { 115 + if ((errnum >= block->base) && (errnum < block->last)) { 116 + *info_ptr = block->infos + (errnum - block->base); 117 + return block->name; 118 + } else if ((errnum >= block->last) && (errnum < block->max)) { 119 + *info_ptr = NULL; 120 + return block->name; 121 + } 122 + } 123 + 124 + return NULL; 125 + } 126 + 127 + /* Return a string describing a system error message. */ 128 + static const char *system_string_error(int errnum, char *buf, size_t buflen) 129 + { 130 + size_t len; 131 + const char *error_string = NULL; 132 + 133 + if ((errnum > 0) && (errnum < ARRAY_SIZE(message_table))) 134 + error_string = message_table[errnum]; 135 + 136 + len = ((error_string == NULL) ? 137 + snprintf(buf, buflen, "Unknown error %d", errnum) : 138 + snprintf(buf, buflen, "%s", error_string)); 139 + if (len < buflen) 140 + return buf; 141 + 142 + buf[0] = '\0'; 143 + return "System error"; 144 + } 145 + 146 + /* Convert an error code to a descriptive string. */ 147 + const char *uds_string_error(int errnum, char *buf, size_t buflen) 148 + { 149 + char *buffer = buf; 150 + char *buf_end = buf + buflen; 151 + const struct error_info *info = NULL; 152 + const char *block_name; 153 + 154 + if (buf == NULL) 155 + return NULL; 156 + 157 + if (errnum < 0) 158 + errnum = -errnum; 159 + 160 + block_name = get_error_info(errnum, &info); 161 + if (block_name != NULL) { 162 + if (info != NULL) { 163 + buffer = uds_append_to_buffer(buffer, buf_end, "%s: %s", 164 + block_name, info->message); 165 + } else { 166 + buffer = uds_append_to_buffer(buffer, buf_end, "Unknown %s %d", 167 + block_name, errnum); 168 + } 169 + } else if (info != NULL) { 170 + buffer = uds_append_to_buffer(buffer, buf_end, "%s", info->message); 171 + } else { 172 + const char *tmp = system_string_error(errnum, buffer, buf_end - buffer); 173 + 174 + if (tmp != buffer) 175 + buffer = uds_append_to_buffer(buffer, buf_end, "%s", tmp); 176 + else 177 + buffer += strlen(tmp); 178 + } 179 + 180 + return buf; 181 + } 182 + 183 + /* Convert an error code to its name. */ 184 + const char *uds_string_error_name(int errnum, char *buf, size_t buflen) 185 + { 186 + char *buffer = buf; 187 + char *buf_end = buf + buflen; 188 + const struct error_info *info = NULL; 189 + const char *block_name; 190 + 191 + if (errnum < 0) 192 + errnum = -errnum; 193 + 194 + block_name = get_error_info(errnum, &info); 195 + if (block_name != NULL) { 196 + if (info != NULL) { 197 + buffer = uds_append_to_buffer(buffer, buf_end, "%s", info->name); 198 + } else { 199 + buffer = uds_append_to_buffer(buffer, buf_end, "%s %d", 200 + block_name, errnum); 201 + } 202 + } else if (info != NULL) { 203 + buffer = uds_append_to_buffer(buffer, buf_end, "%s", info->name); 204 + } else { 205 + const char *tmp; 206 + 207 + tmp = system_string_error(errnum, buffer, buf_end - buffer); 208 + if (tmp != buffer) 209 + buffer = uds_append_to_buffer(buffer, buf_end, "%s", tmp); 210 + else 211 + buffer += strlen(tmp); 212 + } 213 + 214 + return buf; 215 + } 216 + 217 + /* 218 + * Translate an error code into a value acceptable to the kernel. The input error code may be a 219 + * system-generated value (such as -EIO), or an internal UDS status code. The result will be a 220 + * negative errno value. 221 + */ 222 + int uds_map_to_system_error(int error) 223 + { 224 + char error_name[UDS_MAX_ERROR_NAME_SIZE]; 225 + char error_message[UDS_MAX_ERROR_MESSAGE_SIZE]; 226 + 227 + /* 0 is success, and negative values are already system error codes. */ 228 + if (likely(error <= 0)) 229 + return error; 230 + 231 + if (error < 1024) { 232 + /* This is probably an errno from userspace. */ 233 + return -error; 234 + } 235 + 236 + /* Internal UDS errors */ 237 + switch (error) { 238 + case UDS_NO_INDEX: 239 + case UDS_CORRUPT_DATA: 240 + /* The index doesn't exist or can't be recovered. */ 241 + return -ENOENT; 242 + 243 + case UDS_INDEX_NOT_SAVED_CLEANLY: 244 + case UDS_UNSUPPORTED_VERSION: 245 + /* 246 + * The index exists, but can't be loaded. Tell the client it exists so they don't 247 + * destroy it inadvertently. 248 + */ 249 + return -EEXIST; 250 + 251 + case UDS_DISABLED: 252 + /* The session is unusable; only returned by requests. */ 253 + return -EIO; 254 + 255 + default: 256 + /* Translate an unexpected error into something generic. */ 257 + uds_log_info("%s: mapping status code %d (%s: %s) to -EIO", 258 + __func__, error, 259 + uds_string_error_name(error, error_name, 260 + sizeof(error_name)), 261 + uds_string_error(error, error_message, 262 + sizeof(error_message))); 263 + return -EIO; 264 + } 265 + } 266 + 267 + /* 268 + * Register a block of error codes. 269 + * 270 + * @block_name: the name of the block of error codes 271 + * @first_error: the first error code in the block 272 + * @next_free_error: one past the highest possible error in the block 273 + * @infos: a pointer to the error info array for the block 274 + * @info_size: the size of the error info array 275 + */ 276 + int uds_register_error_block(const char *block_name, int first_error, 277 + int next_free_error, const struct error_info *infos, 278 + size_t info_size) 279 + { 280 + int result; 281 + struct error_block *block; 282 + struct error_block new_block = { 283 + .name = block_name, 284 + .base = first_error, 285 + .last = first_error + (info_size / sizeof(struct error_info)), 286 + .max = next_free_error, 287 + .infos = infos, 288 + }; 289 + 290 + result = ASSERT(first_error < next_free_error, "well-defined error block range"); 291 + if (result != UDS_SUCCESS) 292 + return result; 293 + 294 + if (registered_errors.count == registered_errors.allocated) { 295 + /* This should never happen. */ 296 + return UDS_OVERFLOW; 297 + } 298 + 299 + for (block = registered_errors.blocks; 300 + block < registered_errors.blocks + registered_errors.count; 301 + block++) { 302 + if (strcmp(block_name, block->name) == 0) 303 + return UDS_DUPLICATE_NAME; 304 + 305 + /* Ensure error ranges do not overlap. */ 306 + if ((first_error < block->max) && (next_free_error > block->base)) 307 + return UDS_ALREADY_REGISTERED; 308 + } 309 + 310 + registered_errors.blocks[registered_errors.count++] = new_block; 311 + return UDS_SUCCESS; 312 + }
+81
drivers/md/dm-vdo/errors.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Copyright 2023 Red Hat 4 + */ 5 + 6 + #ifndef UDS_ERRORS_H 7 + #define UDS_ERRORS_H 8 + 9 + #include <linux/compiler.h> 10 + #include <linux/types.h> 11 + 12 + /* Custom error codes and error-related utilities for UDS */ 13 + 14 + /* Valid status codes for internal UDS functions. */ 15 + enum uds_status_codes { 16 + /* Successful return */ 17 + UDS_SUCCESS = 0, 18 + 19 + /* Used as a base value for reporting internal errors */ 20 + UDS_ERROR_CODE_BASE = 1024, 21 + /* Index overflow */ 22 + UDS_OVERFLOW = UDS_ERROR_CODE_BASE + 0, 23 + /* Invalid argument passed to internal routine */ 24 + UDS_INVALID_ARGUMENT = UDS_ERROR_CODE_BASE + 1, 25 + /* UDS data structures are in an invalid state */ 26 + UDS_BAD_STATE = UDS_ERROR_CODE_BASE + 2, 27 + /* Attempt to enter the same name into an internal structure twice */ 28 + UDS_DUPLICATE_NAME = UDS_ERROR_CODE_BASE + 3, 29 + /* An assertion failed */ 30 + UDS_ASSERTION_FAILED = UDS_ERROR_CODE_BASE + 4, 31 + /* A request has been queued for later processing (not an error) */ 32 + UDS_QUEUED = UDS_ERROR_CODE_BASE + 5, 33 + /* A problem has occurred with a buffer */ 34 + UDS_BUFFER_ERROR = UDS_ERROR_CODE_BASE + 6, 35 + /* No directory was found where one was expected */ 36 + UDS_NO_DIRECTORY = UDS_ERROR_CODE_BASE + 7, 37 + /* This error range has already been registered */ 38 + UDS_ALREADY_REGISTERED = UDS_ERROR_CODE_BASE + 8, 39 + /* Attempt to read or write data outside the valid range */ 40 + UDS_OUT_OF_RANGE = UDS_ERROR_CODE_BASE + 9, 41 + /* Could not load modules */ 42 + UDS_EMODULE_LOAD = UDS_ERROR_CODE_BASE + 10, 43 + /* The index session is disabled */ 44 + UDS_DISABLED = UDS_ERROR_CODE_BASE + 11, 45 + /* Unknown error */ 46 + UDS_UNKNOWN_ERROR = UDS_ERROR_CODE_BASE + 12, 47 + /* The index configuration or volume format is no longer supported */ 48 + UDS_UNSUPPORTED_VERSION = UDS_ERROR_CODE_BASE + 13, 49 + /* Some index structure is corrupt */ 50 + UDS_CORRUPT_DATA = UDS_ERROR_CODE_BASE + 14, 51 + /* No index state found */ 52 + UDS_NO_INDEX = UDS_ERROR_CODE_BASE + 15, 53 + /* Attempt to access incomplete index save data */ 54 + UDS_INDEX_NOT_SAVED_CLEANLY = UDS_ERROR_CODE_BASE + 16, 55 + /* One more than the last UDS_INTERNAL error code */ 56 + UDS_ERROR_CODE_LAST, 57 + /* One more than the last error this block will ever use */ 58 + UDS_ERROR_CODE_BLOCK_END = UDS_ERROR_CODE_BASE + 440, 59 + }; 60 + 61 + enum { 62 + UDS_MAX_ERROR_NAME_SIZE = 80, 63 + UDS_MAX_ERROR_MESSAGE_SIZE = 128, 64 + }; 65 + 66 + struct error_info { 67 + const char *name; 68 + const char *message; 69 + }; 70 + 71 + const char * __must_check uds_string_error(int errnum, char *buf, size_t buflen); 72 + 73 + const char *uds_string_error_name(int errnum, char *buf, size_t buflen); 74 + 75 + int uds_map_to_system_error(int error); 76 + 77 + int uds_register_error_block(const char *block_name, int first_error, 78 + int last_reserved_error, const struct error_info *infos, 79 + size_t info_size); 80 + 81 + #endif /* UDS_ERRORS_H */
+291
drivers/md/dm-vdo/logger.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright 2023 Red Hat 4 + */ 5 + 6 + #include "logger.h" 7 + 8 + #include <linux/delay.h> 9 + #include <linux/hardirq.h> 10 + #include <linux/module.h> 11 + #include <linux/printk.h> 12 + #include <linux/sched.h> 13 + 14 + #include "thread-device.h" 15 + #include "uds-threads.h" 16 + 17 + struct priority_name { 18 + const char *name; 19 + const int priority; 20 + }; 21 + 22 + static const struct priority_name PRIORITIES[] = { 23 + { "ALERT", UDS_LOG_ALERT }, 24 + { "CRITICAL", UDS_LOG_CRIT }, 25 + { "CRIT", UDS_LOG_CRIT }, 26 + { "DEBUG", UDS_LOG_DEBUG }, 27 + { "EMERGENCY", UDS_LOG_EMERG }, 28 + { "EMERG", UDS_LOG_EMERG }, 29 + { "ERROR", UDS_LOG_ERR }, 30 + { "ERR", UDS_LOG_ERR }, 31 + { "INFO", UDS_LOG_INFO }, 32 + { "NOTICE", UDS_LOG_NOTICE }, 33 + { "PANIC", UDS_LOG_EMERG }, 34 + { "WARN", UDS_LOG_WARNING }, 35 + { "WARNING", UDS_LOG_WARNING }, 36 + { NULL, -1 }, 37 + }; 38 + 39 + static const char *const PRIORITY_STRINGS[] = { 40 + "EMERGENCY", 41 + "ALERT", 42 + "CRITICAL", 43 + "ERROR", 44 + "WARN", 45 + "NOTICE", 46 + "INFO", 47 + "DEBUG", 48 + }; 49 + 50 + static int log_level = UDS_LOG_INFO; 51 + 52 + int uds_get_log_level(void) 53 + { 54 + return log_level; 55 + } 56 + 57 + void uds_set_log_level(int new_log_level) 58 + { 59 + log_level = new_log_level; 60 + } 61 + 62 + int uds_log_string_to_priority(const char *string) 63 + { 64 + int i; 65 + 66 + for (i = 0; PRIORITIES[i].name != NULL; i++) { 67 + if (strcasecmp(string, PRIORITIES[i].name) == 0) 68 + return PRIORITIES[i].priority; 69 + } 70 + 71 + return UDS_LOG_INFO; 72 + } 73 + 74 + const char *uds_log_priority_to_string(int priority) 75 + { 76 + if ((priority < 0) || (priority >= (int) ARRAY_SIZE(PRIORITY_STRINGS))) 77 + return "unknown"; 78 + 79 + return PRIORITY_STRINGS[priority]; 80 + } 81 + 82 + static const char *get_current_interrupt_type(void) 83 + { 84 + if (in_nmi()) 85 + return "NMI"; 86 + 87 + if (in_irq()) 88 + return "HI"; 89 + 90 + if (in_softirq()) 91 + return "SI"; 92 + 93 + return "INTR"; 94 + } 95 + 96 + /** 97 + * emit_log_message_to_kernel() - Emit a log message to the kernel at the specified priority. 98 + * 99 + * @priority: The priority at which to log the message 100 + * @fmt: The format string of the message 101 + */ 102 + static void emit_log_message_to_kernel(int priority, const char *fmt, ...) 103 + { 104 + va_list args; 105 + struct va_format vaf; 106 + 107 + if (priority > uds_get_log_level()) 108 + return; 109 + 110 + va_start(args, fmt); 111 + vaf.fmt = fmt; 112 + vaf.va = &args; 113 + 114 + switch (priority) { 115 + case UDS_LOG_EMERG: 116 + case UDS_LOG_ALERT: 117 + case UDS_LOG_CRIT: 118 + printk(KERN_CRIT "%pV", &vaf); 119 + break; 120 + case UDS_LOG_ERR: 121 + printk(KERN_ERR "%pV", &vaf); 122 + break; 123 + case UDS_LOG_WARNING: 124 + printk(KERN_WARNING "%pV", &vaf); 125 + break; 126 + case UDS_LOG_NOTICE: 127 + printk(KERN_NOTICE "%pV", &vaf); 128 + break; 129 + case UDS_LOG_INFO: 130 + printk(KERN_INFO "%pV", &vaf); 131 + break; 132 + case UDS_LOG_DEBUG: 133 + printk(KERN_DEBUG "%pV", &vaf); 134 + break; 135 + default: 136 + printk(KERN_DEFAULT "%pV", &vaf); 137 + break; 138 + } 139 + 140 + va_end(args); 141 + } 142 + 143 + /** 144 + * emit_log_message() - Emit a log message to the kernel log in a format suited to the current 145 + * thread context. 146 + * 147 + * Context info formats: 148 + * 149 + * interrupt: uds[NMI]: blah 150 + * kvdo thread: kvdo12:foobarQ: blah 151 + * thread w/device id: kvdo12:myprog: blah 152 + * other thread: uds: myprog: blah 153 + * 154 + * Fields: module name, interrupt level, process name, device ID. 155 + * 156 + * @priority: the priority at which to log the message 157 + * @module: The name of the module doing the logging 158 + * @prefix: The prefix of the log message 159 + * @vaf1: The first message format descriptor 160 + * @vaf2: The second message format descriptor 161 + */ 162 + static void emit_log_message(int priority, const char *module, const char *prefix, 163 + const struct va_format *vaf1, const struct va_format *vaf2) 164 + { 165 + int device_instance; 166 + 167 + /* 168 + * In interrupt context, identify the interrupt type and module. Ignore the process/thread 169 + * since it could be anything. 170 + */ 171 + if (in_interrupt()) { 172 + const char *type = get_current_interrupt_type(); 173 + 174 + emit_log_message_to_kernel(priority, "%s[%s]: %s%pV%pV\n", module, type, 175 + prefix, vaf1, vaf2); 176 + return; 177 + } 178 + 179 + /* Not at interrupt level; we have a process we can look at, and might have a device ID. */ 180 + device_instance = uds_get_thread_device_id(); 181 + if (device_instance >= 0) { 182 + emit_log_message_to_kernel(priority, "%s%u:%s: %s%pV%pV\n", module, 183 + device_instance, current->comm, prefix, vaf1, 184 + vaf2); 185 + return; 186 + } 187 + 188 + /* 189 + * If it's a kernel thread and the module name is a prefix of its name, assume it is ours 190 + * and only identify the thread. 191 + */ 192 + if (((current->flags & PF_KTHREAD) != 0) && 193 + (strncmp(module, current->comm, strlen(module)) == 0)) { 194 + emit_log_message_to_kernel(priority, "%s: %s%pV%pV\n", current->comm, 195 + prefix, vaf1, vaf2); 196 + return; 197 + } 198 + 199 + /* Identify the module and the process. */ 200 + emit_log_message_to_kernel(priority, "%s: %s: %s%pV%pV\n", module, current->comm, 201 + prefix, vaf1, vaf2); 202 + } 203 + 204 + /* 205 + * uds_log_embedded_message() - Log a message embedded within another message. 206 + * @priority: the priority at which to log the message 207 + * @module: the name of the module doing the logging 208 + * @prefix: optional string prefix to message, may be NULL 209 + * @fmt1: format of message first part (required) 210 + * @args1: arguments for message first part (required) 211 + * @fmt2: format of message second part 212 + */ 213 + void uds_log_embedded_message(int priority, const char *module, const char *prefix, 214 + const char *fmt1, va_list args1, const char *fmt2, ...) 215 + { 216 + va_list args1_copy; 217 + va_list args2; 218 + struct va_format vaf1, vaf2; 219 + 220 + va_start(args2, fmt2); 221 + 222 + if (module == NULL) 223 + module = UDS_LOGGING_MODULE_NAME; 224 + 225 + if (prefix == NULL) 226 + prefix = ""; 227 + 228 + /* 229 + * It is implementation dependent whether va_list is defined as an array type that decays 230 + * to a pointer when passed as an argument. Copy args1 and args2 with va_copy so that vaf1 231 + * and vaf2 get proper va_list pointers irrespective of how va_list is defined. 232 + */ 233 + va_copy(args1_copy, args1); 234 + vaf1.fmt = fmt1; 235 + vaf1.va = &args1_copy; 236 + 237 + vaf2.fmt = fmt2; 238 + vaf2.va = &args2; 239 + 240 + emit_log_message(priority, module, prefix, &vaf1, &vaf2); 241 + 242 + va_end(args1_copy); 243 + va_end(args2); 244 + } 245 + 246 + int uds_vlog_strerror(int priority, int errnum, const char *module, const char *format, 247 + va_list args) 248 + { 249 + char errbuf[UDS_MAX_ERROR_MESSAGE_SIZE]; 250 + const char *message = uds_string_error(errnum, errbuf, sizeof(errbuf)); 251 + 252 + uds_log_embedded_message(priority, module, NULL, format, args, ": %s (%d)", 253 + message, errnum); 254 + return errnum; 255 + } 256 + 257 + int __uds_log_strerror(int priority, int errnum, const char *module, const char *format, ...) 258 + { 259 + va_list args; 260 + 261 + va_start(args, format); 262 + uds_vlog_strerror(priority, errnum, module, format, args); 263 + va_end(args); 264 + return errnum; 265 + } 266 + 267 + void uds_log_backtrace(int priority) 268 + { 269 + if (priority > uds_get_log_level()) 270 + return; 271 + 272 + dump_stack(); 273 + } 274 + 275 + void __uds_log_message(int priority, const char *module, const char *format, ...) 276 + { 277 + va_list args; 278 + 279 + va_start(args, format); 280 + uds_log_embedded_message(priority, module, NULL, format, args, "%s", ""); 281 + va_end(args); 282 + } 283 + 284 + /* 285 + * Sleep or delay a few milliseconds in an attempt to allow the log buffers to be flushed lest they 286 + * be overrun. 287 + */ 288 + void uds_pause_for_logger(void) 289 + { 290 + fsleep(4000); 291 + }
+105
drivers/md/dm-vdo/logger.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Copyright 2023 Red Hat 4 + */ 5 + 6 + #ifndef UDS_LOGGER_H 7 + #define UDS_LOGGER_H 8 + 9 + #include <linux/module.h> 10 + #include <linux/ratelimit.h> 11 + 12 + /* Custom logging utilities for UDS */ 13 + 14 + #define UDS_LOG_EMERG 0 15 + #define UDS_LOG_ALERT 1 16 + #define UDS_LOG_CRIT 2 17 + #define UDS_LOG_ERR 3 18 + #define UDS_LOG_WARNING 4 19 + #define UDS_LOG_NOTICE 5 20 + #define UDS_LOG_INFO 6 21 + #define UDS_LOG_DEBUG 7 22 + 23 + #if defined(MODULE) 24 + #define UDS_LOGGING_MODULE_NAME THIS_MODULE->name 25 + #else /* compiled into the kernel */ 26 + #define UDS_LOGGING_MODULE_NAME "vdo" 27 + #endif 28 + 29 + /* Apply a rate limiter to a log method call. */ 30 + #define uds_log_ratelimit(log_fn, ...) \ 31 + do { \ 32 + static DEFINE_RATELIMIT_STATE(_rs, \ 33 + DEFAULT_RATELIMIT_INTERVAL, \ 34 + DEFAULT_RATELIMIT_BURST); \ 35 + if (__ratelimit(&_rs)) { \ 36 + log_fn(__VA_ARGS__); \ 37 + } \ 38 + } while (0) 39 + 40 + int uds_get_log_level(void); 41 + 42 + void uds_set_log_level(int new_log_level); 43 + 44 + int uds_log_string_to_priority(const char *string); 45 + 46 + const char *uds_log_priority_to_string(int priority); 47 + 48 + void uds_log_embedded_message(int priority, const char *module, const char *prefix, 49 + const char *fmt1, va_list args1, const char *fmt2, ...) 50 + __printf(4, 0) __printf(6, 7); 51 + 52 + void uds_log_backtrace(int priority); 53 + 54 + /* All log functions will preserve the caller's value of errno. */ 55 + 56 + #define uds_log_strerror(priority, errnum, ...) \ 57 + __uds_log_strerror(priority, errnum, UDS_LOGGING_MODULE_NAME, __VA_ARGS__) 58 + 59 + int __uds_log_strerror(int priority, int errnum, const char *module, 60 + const char *format, ...) 61 + __printf(4, 5); 62 + 63 + int uds_vlog_strerror(int priority, int errnum, const char *module, const char *format, 64 + va_list args) 65 + __printf(4, 0); 66 + 67 + /* Log an error prefixed with the string associated with the errnum. */ 68 + #define uds_log_error_strerror(errnum, ...) \ 69 + uds_log_strerror(UDS_LOG_ERR, errnum, __VA_ARGS__) 70 + 71 + #define uds_log_debug_strerror(errnum, ...) \ 72 + uds_log_strerror(UDS_LOG_DEBUG, errnum, __VA_ARGS__) 73 + 74 + #define uds_log_info_strerror(errnum, ...) \ 75 + uds_log_strerror(UDS_LOG_INFO, errnum, __VA_ARGS__) 76 + 77 + #define uds_log_notice_strerror(errnum, ...) \ 78 + uds_log_strerror(UDS_LOG_NOTICE, errnum, __VA_ARGS__) 79 + 80 + #define uds_log_warning_strerror(errnum, ...) \ 81 + uds_log_strerror(UDS_LOG_WARNING, errnum, __VA_ARGS__) 82 + 83 + #define uds_log_fatal_strerror(errnum, ...) \ 84 + uds_log_strerror(UDS_LOG_CRIT, errnum, __VA_ARGS__) 85 + 86 + #define uds_log_message(priority, ...) \ 87 + __uds_log_message(priority, UDS_LOGGING_MODULE_NAME, __VA_ARGS__) 88 + 89 + void __uds_log_message(int priority, const char *module, const char *format, ...) 90 + __printf(3, 4); 91 + 92 + #define uds_log_debug(...) uds_log_message(UDS_LOG_DEBUG, __VA_ARGS__) 93 + 94 + #define uds_log_info(...) uds_log_message(UDS_LOG_INFO, __VA_ARGS__) 95 + 96 + #define uds_log_notice(...) uds_log_message(UDS_LOG_NOTICE, __VA_ARGS__) 97 + 98 + #define uds_log_warning(...) uds_log_message(UDS_LOG_WARNING, __VA_ARGS__) 99 + 100 + #define uds_log_error(...) uds_log_message(UDS_LOG_ERR, __VA_ARGS__) 101 + 102 + #define uds_log_fatal(...) uds_log_message(UDS_LOG_CRIT, __VA_ARGS__) 103 + 104 + void uds_pause_for_logger(void); 105 + #endif /* UDS_LOGGER_H */
+26
drivers/md/dm-vdo/permassert.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright 2023 Red Hat 4 + */ 5 + 6 + #include "permassert.h" 7 + 8 + #include "errors.h" 9 + #include "logger.h" 10 + 11 + int uds_assertion_failed(const char *expression_string, const char *file_name, 12 + int line_number, const char *format, ...) 13 + { 14 + va_list args; 15 + 16 + va_start(args, format); 17 + 18 + uds_log_embedded_message(UDS_LOG_ERR, UDS_LOGGING_MODULE_NAME, "assertion \"", 19 + format, args, "\" (%s) failed at %s:%d", 20 + expression_string, file_name, line_number); 21 + uds_log_backtrace(UDS_LOG_ERR); 22 + 23 + va_end(args); 24 + 25 + return UDS_ASSERTION_FAILED; 26 + }
+46
drivers/md/dm-vdo/permassert.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Copyright 2023 Red Hat 4 + */ 5 + 6 + #ifndef PERMASSERT_H 7 + #define PERMASSERT_H 8 + 9 + #include <linux/compiler.h> 10 + 11 + #include "errors.h" 12 + 13 + /* Utilities for asserting that certain conditions are met */ 14 + 15 + #define STRINGIFY(X) #X 16 + #define STRINGIFY_VALUE(X) STRINGIFY(X) 17 + 18 + /* 19 + * A hack to apply the "warn if unused" attribute to an integral expression. 20 + * 21 + * Since GCC doesn't propagate the warn_unused_result attribute to conditional expressions 22 + * incorporating calls to functions with that attribute, this function can be used to wrap such an 23 + * expression. With optimization enabled, this function contributes no additional instructions, but 24 + * the warn_unused_result attribute still applies to the code calling it. 25 + */ 26 + static inline int __must_check uds_must_use(int value) 27 + { 28 + return value; 29 + } 30 + 31 + /* Assert that an expression is true and return an error if it is not. */ 32 + #define ASSERT(expr, ...) uds_must_use(__UDS_ASSERT(expr, __VA_ARGS__)) 33 + 34 + /* Log a message if the expression is not true. */ 35 + #define ASSERT_LOG_ONLY(expr, ...) __UDS_ASSERT(expr, __VA_ARGS__) 36 + 37 + #define __UDS_ASSERT(expr, ...) \ 38 + (likely(expr) ? UDS_SUCCESS \ 39 + : uds_assertion_failed(STRINGIFY(expr), __FILE__, __LINE__, __VA_ARGS__)) 40 + 41 + /* Log an assertion failure message. */ 42 + int uds_assertion_failed(const char *expression_string, const char *file_name, 43 + int line_number, const char *format, ...) 44 + __printf(4, 5); 45 + 46 + #endif /* PERMASSERT_H */
+28
drivers/md/dm-vdo/string-utils.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright 2023 Red Hat 4 + */ 5 + 6 + #include "string-utils.h" 7 + 8 + #include "errors.h" 9 + #include "logger.h" 10 + #include "memory-alloc.h" 11 + #include "permassert.h" 12 + #include "uds.h" 13 + 14 + char *uds_append_to_buffer(char *buffer, char *buf_end, const char *fmt, ...) 15 + { 16 + va_list args; 17 + size_t n; 18 + 19 + va_start(args, fmt); 20 + n = vsnprintf(buffer, buf_end - buffer, fmt, args); 21 + if (n >= (size_t) (buf_end - buffer)) 22 + buffer = buf_end; 23 + else 24 + buffer += n; 25 + va_end(args); 26 + 27 + return buffer; 28 + }
+23
drivers/md/dm-vdo/string-utils.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Copyright 2023 Red Hat 4 + */ 5 + 6 + #ifndef UDS_STRING_UTILS_H 7 + #define UDS_STRING_UTILS_H 8 + 9 + #include <linux/kernel.h> 10 + #include <linux/string.h> 11 + 12 + /* Utilities related to string manipulation */ 13 + 14 + static inline const char *uds_bool_to_string(bool value) 15 + { 16 + return value ? "true" : "false"; 17 + } 18 + 19 + /* Append a formatted string to the end of a buffer. */ 20 + char *uds_append_to_buffer(char *buffer, char *buf_end, const char *fmt, ...) 21 + __printf(3, 4); 22 + 23 + #endif /* UDS_STRING_UTILS_H */
+28
drivers/md/dm-vdo/time-utils.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Copyright 2023 Red Hat 4 + */ 5 + 6 + #ifndef UDS_TIME_UTILS_H 7 + #define UDS_TIME_UTILS_H 8 + 9 + #include <linux/ktime.h> 10 + #include <linux/time.h> 11 + #include <linux/types.h> 12 + 13 + static inline s64 ktime_to_seconds(ktime_t reltime) 14 + { 15 + return reltime / NSEC_PER_SEC; 16 + } 17 + 18 + static inline ktime_t current_time_ns(clockid_t clock) 19 + { 20 + return clock == CLOCK_MONOTONIC ? ktime_get_ns() : ktime_get_real_ns(); 21 + } 22 + 23 + static inline ktime_t current_time_us(void) 24 + { 25 + return current_time_ns(CLOCK_REALTIME) / NSEC_PER_USEC; 26 + } 27 + 28 + #endif /* UDS_TIME_UTILS_H */