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

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'printk-for-6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux

Pull printk updates from Petr Mladek:

- Add KUnit test for the printk ring buffer

- Fix the check of the maximal record size which is allowed to be
stored into the printk ring buffer. It prevents corruptions of the
ring buffer.

Note that printk() is on the safe side. The messages are limited by
1kB buffer and are always small enough for the minimal log buffer
size 4kB, see CONFIG_LOG_BUF_SHIFT definition.

* tag 'printk-for-6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux:
printk: ringbuffer: Fix data block max size check
printk: kunit: support offstack cpumask
printk: kunit: Fix __counted_by() in struct prbtest_rbdata
printk: ringbuffer: Explain why the KUnit test ignores failed writes
printk: ringbuffer: Add KUnit test

+378 -14
+12
init/Kconfig
··· 1710 1710 very difficult to diagnose system problems, saying N here is 1711 1711 strongly discouraged. 1712 1712 1713 + config PRINTK_RINGBUFFER_KUNIT_TEST 1714 + tristate "KUnit Test for the printk ringbuffer" if !KUNIT_ALL_TESTS 1715 + depends on PRINTK && KUNIT 1716 + default KUNIT_ALL_TESTS 1717 + help 1718 + This builds the printk ringbuffer KUnit test suite. 1719 + 1720 + For more information on KUnit and unit tests in general, please refer 1721 + to the KUnit documentation. 1722 + 1723 + If unsure, say N. 1724 + 1713 1725 config BUG 1714 1726 bool "BUG() support" if EXPERT 1715 1727 default y
+3
kernel/printk/.kunitconfig
··· 1 + CONFIG_KUNIT=y 2 + CONFIG_PRINTK=y 3 + CONFIG_PRINTK_RINGBUFFER_KUNIT_TEST=y
+2
kernel/printk/Makefile
··· 7 7 obj-$(CONFIG_PRINTK) += printk_support.o 8 8 printk_support-y := printk_ringbuffer.o 9 9 printk_support-$(CONFIG_SYSCTL) += sysctl.o 10 + 11 + obj-$(CONFIG_PRINTK_RINGBUFFER_KUNIT_TEST) += printk_ringbuffer_kunit_test.o
+34 -14
kernel/printk/printk_ringbuffer.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 3 + #include <kunit/visibility.h> 3 4 #include <linux/kernel.h> 4 5 #include <linux/irqflags.h> 5 6 #include <linux/string.h> ··· 394 393 * Sanity checker for reserve size. The ringbuffer code assumes that a data 395 394 * block does not exceed the maximum possible size that could fit within the 396 395 * ringbuffer. This function provides that basic size check so that the 397 - * assumption is safe. 396 + * assumption is safe. In particular, it guarantees that data_push_tail() will 397 + * never attempt to push the tail beyond the head. 398 398 */ 399 399 static bool data_check_size(struct prb_data_ring *data_ring, unsigned int size) 400 400 { 401 - struct prb_data_block *db = NULL; 402 - 401 + /* Data-less blocks take no space. */ 403 402 if (size == 0) 404 403 return true; 405 404 406 405 /* 407 - * Ensure the alignment padded size could possibly fit in the data 408 - * array. The largest possible data block must still leave room for 409 - * at least the ID of the next block. 406 + * If data blocks were allowed to be larger than half the data ring 407 + * size, a wrapping data block could require more space than the full 408 + * ringbuffer. 410 409 */ 411 - size = to_blk_size(size); 412 - if (size > DATA_SIZE(data_ring) - sizeof(db->id)) 413 - return false; 414 - 415 - return true; 410 + return to_blk_size(size) <= DATA_SIZE(data_ring) / 2; 416 411 } 417 412 418 413 /* Query the state of a descriptor. */ ··· 1048 1051 do { 1049 1052 next_lpos = get_next_lpos(data_ring, begin_lpos, size); 1050 1053 1051 - if (!data_push_tail(rb, next_lpos - DATA_SIZE(data_ring))) { 1052 - /* Failed to allocate, specify a data-less block. */ 1054 + /* 1055 + * data_check_size() prevents data block allocation that could 1056 + * cause illegal ringbuffer states. But double check that the 1057 + * used space will not be bigger than the ring buffer. Wrapped 1058 + * messages need to reserve more space, see get_next_lpos(). 1059 + * 1060 + * Specify a data-less block when the check or the allocation 1061 + * fails. 1062 + */ 1063 + if (WARN_ON_ONCE(next_lpos - begin_lpos > DATA_SIZE(data_ring)) || 1064 + !data_push_tail(rb, next_lpos - DATA_SIZE(data_ring))) { 1053 1065 blk_lpos->begin = FAILED_LPOS; 1054 1066 blk_lpos->next = FAILED_LPOS; 1055 1067 return NULL; ··· 1146 1140 return &blk->data[0]; 1147 1141 } 1148 1142 1149 - if (!data_push_tail(rb, next_lpos - DATA_SIZE(data_ring))) 1143 + /* 1144 + * data_check_size() prevents data block reallocation that could 1145 + * cause illegal ringbuffer states. But double check that the 1146 + * new used space will not be bigger than the ring buffer. Wrapped 1147 + * messages need to reserve more space, see get_next_lpos(). 1148 + * 1149 + * Specify failure when the check or the allocation fails. 1150 + */ 1151 + if (WARN_ON_ONCE(next_lpos - blk_lpos->begin > DATA_SIZE(data_ring)) || 1152 + !data_push_tail(rb, next_lpos - DATA_SIZE(data_ring))) { 1150 1153 return NULL; 1154 + } 1151 1155 1152 1156 /* The memory barrier involvement is the same as data_alloc:A. */ 1153 1157 if (!atomic_long_try_cmpxchg(&data_ring->head_lpos, &head_lpos, ··· 1701 1685 memset(r, 0, sizeof(*r)); 1702 1686 return false; 1703 1687 } 1688 + EXPORT_SYMBOL_IF_KUNIT(prb_reserve); 1704 1689 1705 1690 /* Commit the data (possibly finalizing it) and restore interrupts. */ 1706 1691 static void _prb_commit(struct prb_reserved_entry *e, unsigned long state_val) ··· 1776 1759 if (head_id != e->id) 1777 1760 desc_make_final(e->rb, e->id); 1778 1761 } 1762 + EXPORT_SYMBOL_IF_KUNIT(prb_commit); 1779 1763 1780 1764 /** 1781 1765 * prb_final_commit() - Commit and finalize (previously reserved) data to ··· 2202 2184 { 2203 2185 return _prb_read_valid(rb, &seq, r, NULL); 2204 2186 } 2187 + EXPORT_SYMBOL_IF_KUNIT(prb_read_valid); 2205 2188 2206 2189 /** 2207 2190 * prb_read_valid_info() - Non-blocking read of meta data for a requested ··· 2352 2333 infos[0].seq = -(u64)_DESCS_COUNT(descbits); 2353 2334 infos[_DESCS_COUNT(descbits) - 1].seq = 0; 2354 2335 } 2336 + EXPORT_SYMBOL_IF_KUNIT(prb_init); 2355 2337 2356 2338 /** 2357 2339 * prb_record_text_space() - Query the full actual used ringbuffer space for
+327
kernel/printk/printk_ringbuffer_kunit_test.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <linux/cpuhplock.h> 4 + #include <linux/cpumask.h> 5 + #include <linux/init.h> 6 + #include <linux/kthread.h> 7 + #include <linux/module.h> 8 + #include <linux/moduleparam.h> 9 + #include <linux/random.h> 10 + #include <linux/slab.h> 11 + #include <linux/timer.h> 12 + #include <linux/wait.h> 13 + 14 + #include <kunit/resource.h> 15 + #include <kunit/test.h> 16 + 17 + #include "printk_ringbuffer.h" 18 + 19 + /* 20 + * This KUnit tests the data integrity of the lockless printk_ringbuffer. 21 + * From multiple CPUs it writes messages of varying length and content while 22 + * a reader validates the correctness of the messages. 23 + * 24 + * IMPORTANT: The more CPUs you can use for this KUnit, the better! 25 + * 26 + * The test works by starting "num_online_cpus() - 1" writer threads, each 27 + * pinned to their own CPU. Each writer thread loops, writing data of varying 28 + * length into a printk_ringbuffer as fast as possible. The data content is 29 + * an embedded data struct followed by string content repeating the byte: 30 + * 31 + * 'A' + CPUID 32 + * 33 + * The reader is running on the remaining online CPU, or if there is only one 34 + * CPU on the same as the writer. 35 + * It ensures that the embedded struct content is consistent with the string 36 + * and that the string * is terminated and is composed of the same repeating 37 + * byte as its first byte. 38 + * 39 + * Because the threads are running in such tight loops, they will call 40 + * cond_resched() from time to time so the system stays functional. 41 + * 42 + * If the reader encounters an error, the test is aborted and some 43 + * information about the error is reported. 44 + * The runtime of the test can be configured with the runtime_ms module parameter. 45 + * 46 + * Note that the test is performed on a separate printk_ringbuffer instance 47 + * and not the instance used by printk(). 48 + */ 49 + 50 + static unsigned long runtime_ms = 10 * MSEC_PER_SEC; 51 + module_param(runtime_ms, ulong, 0400); 52 + 53 + /* test data structure */ 54 + struct prbtest_rbdata { 55 + unsigned int size; 56 + char text[] __counted_by(size); 57 + }; 58 + 59 + #define MAX_RBDATA_TEXT_SIZE 0x80 60 + #define MAX_PRB_RECORD_SIZE (sizeof(struct prbtest_rbdata) + MAX_RBDATA_TEXT_SIZE) 61 + 62 + struct prbtest_data { 63 + struct kunit *test; 64 + struct printk_ringbuffer *ringbuffer; 65 + /* used by writers to signal reader of new records */ 66 + wait_queue_head_t new_record_wait; 67 + }; 68 + 69 + struct prbtest_thread_data { 70 + unsigned long num; 71 + struct prbtest_data *test_data; 72 + }; 73 + 74 + static void prbtest_fail_record(struct kunit *test, const struct prbtest_rbdata *dat, u64 seq) 75 + { 76 + unsigned int len; 77 + 78 + len = dat->size - 1; 79 + 80 + KUNIT_FAIL(test, "BAD RECORD: seq=%llu size=%u text=%.*s\n", 81 + seq, dat->size, 82 + len < MAX_RBDATA_TEXT_SIZE ? len : -1, 83 + len < MAX_RBDATA_TEXT_SIZE ? dat->text : "<invalid>"); 84 + } 85 + 86 + static bool prbtest_check_data(const struct prbtest_rbdata *dat) 87 + { 88 + unsigned int len; 89 + 90 + /* Sane size? At least one character + trailing '\0' */ 91 + if (dat->size < 2 || dat->size > MAX_RBDATA_TEXT_SIZE) 92 + return false; 93 + 94 + len = dat->size - 1; 95 + if (dat->text[len] != '\0') 96 + return false; 97 + 98 + /* String repeats with the same character? */ 99 + while (len--) { 100 + if (dat->text[len] != dat->text[0]) 101 + return false; 102 + } 103 + 104 + return true; 105 + } 106 + 107 + static int prbtest_writer(void *data) 108 + { 109 + struct prbtest_thread_data *tr = data; 110 + char text_id = 'A' + tr->num; 111 + struct prb_reserved_entry e; 112 + struct prbtest_rbdata *dat; 113 + u32 record_size, text_size; 114 + unsigned long count = 0; 115 + struct printk_record r; 116 + 117 + kunit_info(tr->test_data->test, "start thread %03lu (writer)\n", tr->num); 118 + 119 + for (;;) { 120 + /* ensure at least 1 character + trailing '\0' */ 121 + text_size = get_random_u32_inclusive(2, MAX_RBDATA_TEXT_SIZE); 122 + if (WARN_ON_ONCE(text_size < 2)) 123 + text_size = 2; 124 + if (WARN_ON_ONCE(text_size > MAX_RBDATA_TEXT_SIZE)) 125 + text_size = MAX_RBDATA_TEXT_SIZE; 126 + 127 + record_size = sizeof(struct prbtest_rbdata) + text_size; 128 + WARN_ON_ONCE(record_size > MAX_PRB_RECORD_SIZE); 129 + 130 + /* specify the text sizes for reservation */ 131 + prb_rec_init_wr(&r, record_size); 132 + 133 + /* 134 + * Reservation can fail if: 135 + * 136 + * - No free descriptor is available. 137 + * - The buffer is full, and the oldest record is reserved 138 + * but not yet committed. 139 + * 140 + * It actually happens in this test because all CPUs are trying 141 + * to write an unbounded number of messages in a tight loop. 142 + * These failures are intentionally ignored because this test 143 + * focuses on races, ringbuffer consistency, and pushing system 144 + * usability limits. 145 + */ 146 + if (prb_reserve(&e, tr->test_data->ringbuffer, &r)) { 147 + r.info->text_len = record_size; 148 + 149 + dat = (struct prbtest_rbdata *)r.text_buf; 150 + dat->size = text_size; 151 + memset(dat->text, text_id, text_size - 1); 152 + dat->text[text_size - 1] = '\0'; 153 + 154 + prb_commit(&e); 155 + 156 + wake_up_interruptible(&tr->test_data->new_record_wait); 157 + } 158 + 159 + if ((count++ & 0x3fff) == 0) 160 + cond_resched(); 161 + 162 + if (kthread_should_stop()) 163 + break; 164 + } 165 + 166 + kunit_info(tr->test_data->test, "end thread %03lu: wrote=%lu\n", tr->num, count); 167 + 168 + return 0; 169 + } 170 + 171 + struct prbtest_wakeup_timer { 172 + struct timer_list timer; 173 + struct task_struct *task; 174 + }; 175 + 176 + static void prbtest_wakeup_callback(struct timer_list *timer) 177 + { 178 + struct prbtest_wakeup_timer *wakeup = timer_container_of(wakeup, timer, timer); 179 + 180 + set_tsk_thread_flag(wakeup->task, TIF_NOTIFY_SIGNAL); 181 + wake_up_process(wakeup->task); 182 + } 183 + 184 + static int prbtest_reader(struct prbtest_data *test_data, unsigned long timeout_ms) 185 + { 186 + struct prbtest_wakeup_timer wakeup; 187 + char text_buf[MAX_PRB_RECORD_SIZE]; 188 + unsigned long count = 0; 189 + struct printk_info info; 190 + struct printk_record r; 191 + u64 seq = 0; 192 + 193 + wakeup.task = current; 194 + timer_setup_on_stack(&wakeup.timer, prbtest_wakeup_callback, 0); 195 + mod_timer(&wakeup.timer, jiffies + msecs_to_jiffies(timeout_ms)); 196 + 197 + prb_rec_init_rd(&r, &info, text_buf, sizeof(text_buf)); 198 + 199 + kunit_info(test_data->test, "start reader\n"); 200 + 201 + while (!wait_event_interruptible(test_data->new_record_wait, 202 + prb_read_valid(test_data->ringbuffer, seq, &r))) { 203 + /* check/track the sequence */ 204 + if (info.seq < seq) 205 + KUNIT_FAIL(test_data->test, "BAD SEQ READ: request=%llu read=%llu\n", 206 + seq, info.seq); 207 + 208 + if (!prbtest_check_data((struct prbtest_rbdata *)r.text_buf)) 209 + prbtest_fail_record(test_data->test, 210 + (struct prbtest_rbdata *)r.text_buf, info.seq); 211 + 212 + if ((count++ & 0x3fff) == 0) 213 + cond_resched(); 214 + 215 + seq = info.seq + 1; 216 + } 217 + 218 + timer_delete_sync(&wakeup.timer); 219 + timer_destroy_on_stack(&wakeup.timer); 220 + 221 + kunit_info(test_data->test, "end reader: read=%lu seq=%llu\n", count, info.seq); 222 + 223 + return 0; 224 + } 225 + 226 + KUNIT_DEFINE_ACTION_WRAPPER(prbtest_cpumask_cleanup, free_cpumask_var, struct cpumask *); 227 + KUNIT_DEFINE_ACTION_WRAPPER(prbtest_kthread_cleanup, kthread_stop, struct task_struct *); 228 + 229 + static void prbtest_add_cpumask_cleanup(struct kunit *test, cpumask_var_t mask) 230 + { 231 + int err; 232 + 233 + err = kunit_add_action_or_reset(test, prbtest_cpumask_cleanup, mask); 234 + KUNIT_ASSERT_EQ(test, err, 0); 235 + } 236 + 237 + static void prbtest_add_kthread_cleanup(struct kunit *test, struct task_struct *kthread) 238 + { 239 + int err; 240 + 241 + err = kunit_add_action_or_reset(test, prbtest_kthread_cleanup, kthread); 242 + KUNIT_ASSERT_EQ(test, err, 0); 243 + } 244 + 245 + static inline void prbtest_prb_reinit(struct printk_ringbuffer *rb) 246 + { 247 + prb_init(rb, rb->text_data_ring.data, rb->text_data_ring.size_bits, rb->desc_ring.descs, 248 + rb->desc_ring.count_bits, rb->desc_ring.infos); 249 + } 250 + 251 + static void test_readerwriter(struct kunit *test) 252 + { 253 + /* Equivalent to CONFIG_LOG_BUF_SHIFT=13 */ 254 + DEFINE_PRINTKRB(test_rb, 8, 5); 255 + 256 + struct prbtest_thread_data *thread_data; 257 + struct prbtest_data *test_data; 258 + struct task_struct *thread; 259 + cpumask_var_t test_cpus; 260 + int cpu, reader_cpu; 261 + 262 + KUNIT_ASSERT_TRUE(test, alloc_cpumask_var(&test_cpus, GFP_KERNEL)); 263 + prbtest_add_cpumask_cleanup(test, test_cpus); 264 + 265 + cpus_read_lock(); 266 + /* 267 + * Failure of KUNIT_ASSERT() kills the current task 268 + * so it can not be called while the CPU hotplug lock is held. 269 + * Instead use a snapshot of the online CPUs. 270 + * If they change during test execution it is unfortunate but not a grave error. 271 + */ 272 + cpumask_copy(test_cpus, cpu_online_mask); 273 + cpus_read_unlock(); 274 + 275 + /* One CPU is for the reader, all others are writers */ 276 + reader_cpu = cpumask_first(test_cpus); 277 + if (cpumask_weight(test_cpus) == 1) 278 + kunit_warn(test, "more than one CPU is recommended"); 279 + else 280 + cpumask_clear_cpu(reader_cpu, test_cpus); 281 + 282 + /* KUnit test can get restarted more times. */ 283 + prbtest_prb_reinit(&test_rb); 284 + 285 + test_data = kunit_kmalloc(test, sizeof(*test_data), GFP_KERNEL); 286 + KUNIT_ASSERT_NOT_NULL(test, test_data); 287 + test_data->test = test; 288 + test_data->ringbuffer = &test_rb; 289 + init_waitqueue_head(&test_data->new_record_wait); 290 + 291 + kunit_info(test, "running for %lu ms\n", runtime_ms); 292 + 293 + for_each_cpu(cpu, test_cpus) { 294 + thread_data = kunit_kmalloc(test, sizeof(*thread_data), GFP_KERNEL); 295 + KUNIT_ASSERT_NOT_NULL(test, thread_data); 296 + thread_data->test_data = test_data; 297 + thread_data->num = cpu; 298 + 299 + thread = kthread_run_on_cpu(prbtest_writer, thread_data, cpu, 300 + "prbtest writer %u"); 301 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, thread); 302 + prbtest_add_kthread_cleanup(test, thread); 303 + } 304 + 305 + kunit_info(test, "starting test\n"); 306 + 307 + set_cpus_allowed_ptr(current, cpumask_of(reader_cpu)); 308 + prbtest_reader(test_data, runtime_ms); 309 + 310 + kunit_info(test, "completed test\n"); 311 + } 312 + 313 + static struct kunit_case prb_test_cases[] = { 314 + KUNIT_CASE_SLOW(test_readerwriter), 315 + {} 316 + }; 317 + 318 + static struct kunit_suite prb_test_suite = { 319 + .name = "printk-ringbuffer", 320 + .test_cases = prb_test_cases, 321 + }; 322 + kunit_test_suite(prb_test_suite); 323 + 324 + MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); 325 + MODULE_AUTHOR("John Ogness <john.ogness@linutronix.de>"); 326 + MODULE_DESCRIPTION("printk_ringbuffer KUnit test"); 327 + MODULE_LICENSE("GPL");