~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/pstore/ftrace.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * Copyright 2012  Google, Inc.
  4  */
  5 
  6 #include <linux/kernel.h>
  7 #include <linux/compiler.h>
  8 #include <linux/irqflags.h>
  9 #include <linux/percpu.h>
 10 #include <linux/smp.h>
 11 #include <linux/atomic.h>
 12 #include <linux/types.h>
 13 #include <linux/mutex.h>
 14 #include <linux/ftrace.h>
 15 #include <linux/fs.h>
 16 #include <linux/debugfs.h>
 17 #include <linux/err.h>
 18 #include <linux/cache.h>
 19 #include <linux/slab.h>
 20 #include <asm/barrier.h>
 21 #include "internal.h"
 22 
 23 /* This doesn't need to be atomic: speed is chosen over correctness here. */
 24 static u64 pstore_ftrace_stamp;
 25 
 26 static void notrace pstore_ftrace_call(unsigned long ip,
 27                                        unsigned long parent_ip,
 28                                        struct ftrace_ops *op,
 29                                        struct ftrace_regs *fregs)
 30 {
 31         int bit;
 32         unsigned long flags;
 33         struct pstore_ftrace_record rec = {};
 34         struct pstore_record record = {
 35                 .type = PSTORE_TYPE_FTRACE,
 36                 .buf = (char *)&rec,
 37                 .size = sizeof(rec),
 38                 .psi = psinfo,
 39         };
 40 
 41         if (unlikely(oops_in_progress))
 42                 return;
 43 
 44         bit = ftrace_test_recursion_trylock(ip, parent_ip);
 45         if (bit < 0)
 46                 return;
 47 
 48         local_irq_save(flags);
 49 
 50         rec.ip = ip;
 51         rec.parent_ip = parent_ip;
 52         pstore_ftrace_write_timestamp(&rec, pstore_ftrace_stamp++);
 53         pstore_ftrace_encode_cpu(&rec, raw_smp_processor_id());
 54         psinfo->write(&record);
 55 
 56         local_irq_restore(flags);
 57         ftrace_test_recursion_unlock(bit);
 58 }
 59 
 60 static struct ftrace_ops pstore_ftrace_ops __read_mostly = {
 61         .func   = pstore_ftrace_call,
 62 };
 63 
 64 static DEFINE_MUTEX(pstore_ftrace_lock);
 65 static bool pstore_ftrace_enabled;
 66 
 67 static int pstore_set_ftrace_enabled(bool on)
 68 {
 69         ssize_t ret;
 70 
 71         if (on == pstore_ftrace_enabled)
 72                 return 0;
 73 
 74         if (on) {
 75                 ftrace_ops_set_global_filter(&pstore_ftrace_ops);
 76                 ret = register_ftrace_function(&pstore_ftrace_ops);
 77         } else {
 78                 ret = unregister_ftrace_function(&pstore_ftrace_ops);
 79         }
 80 
 81         if (ret) {
 82                 pr_err("%s: unable to %sregister ftrace ops: %zd\n",
 83                        __func__, on ? "" : "un", ret);
 84         } else {
 85                 pstore_ftrace_enabled = on;
 86         }
 87 
 88         return ret;
 89 }
 90 
 91 static ssize_t pstore_ftrace_knob_write(struct file *f, const char __user *buf,
 92                                         size_t count, loff_t *ppos)
 93 {
 94         u8 on;
 95         ssize_t ret;
 96 
 97         ret = kstrtou8_from_user(buf, count, 2, &on);
 98         if (ret)
 99                 return ret;
100 
101         mutex_lock(&pstore_ftrace_lock);
102         ret = pstore_set_ftrace_enabled(on);
103         mutex_unlock(&pstore_ftrace_lock);
104 
105         if (ret == 0)
106                 ret = count;
107 
108         return ret;
109 }
110 
111 static ssize_t pstore_ftrace_knob_read(struct file *f, char __user *buf,
112                                        size_t count, loff_t *ppos)
113 {
114         char val[] = { '' + pstore_ftrace_enabled, '\n' };
115 
116         return simple_read_from_buffer(buf, count, ppos, val, sizeof(val));
117 }
118 
119 static const struct file_operations pstore_knob_fops = {
120         .open   = simple_open,
121         .read   = pstore_ftrace_knob_read,
122         .write  = pstore_ftrace_knob_write,
123 };
124 
125 static struct dentry *pstore_ftrace_dir;
126 
127 static bool record_ftrace;
128 module_param(record_ftrace, bool, 0400);
129 MODULE_PARM_DESC(record_ftrace,
130                  "enable ftrace recording immediately (default: off)");
131 
132 void pstore_register_ftrace(void)
133 {
134         if (!psinfo->write)
135                 return;
136 
137         pstore_ftrace_dir = debugfs_create_dir("pstore", NULL);
138 
139         pstore_set_ftrace_enabled(record_ftrace);
140 
141         debugfs_create_file("record_ftrace", 0600, pstore_ftrace_dir, NULL,
142                             &pstore_knob_fops);
143 }
144 
145 void pstore_unregister_ftrace(void)
146 {
147         mutex_lock(&pstore_ftrace_lock);
148         if (pstore_ftrace_enabled) {
149                 unregister_ftrace_function(&pstore_ftrace_ops);
150                 pstore_ftrace_enabled = false;
151         }
152         mutex_unlock(&pstore_ftrace_lock);
153 
154         debugfs_remove_recursive(pstore_ftrace_dir);
155 }
156 
157 ssize_t pstore_ftrace_combine_log(char **dest_log, size_t *dest_log_size,
158                                   const char *src_log, size_t src_log_size)
159 {
160         size_t dest_size, src_size, total, dest_off, src_off;
161         size_t dest_idx = 0, src_idx = 0, merged_idx = 0;
162         void *merged_buf;
163         struct pstore_ftrace_record *drec, *srec, *mrec;
164         size_t record_size = sizeof(struct pstore_ftrace_record);
165 
166         dest_off = *dest_log_size % record_size;
167         dest_size = *dest_log_size - dest_off;
168 
169         src_off = src_log_size % record_size;
170         src_size = src_log_size - src_off;
171 
172         total = dest_size + src_size;
173         merged_buf = kmalloc(total, GFP_KERNEL);
174         if (!merged_buf)
175                 return -ENOMEM;
176 
177         drec = (struct pstore_ftrace_record *)(*dest_log + dest_off);
178         srec = (struct pstore_ftrace_record *)(src_log + src_off);
179         mrec = (struct pstore_ftrace_record *)(merged_buf);
180 
181         while (dest_size > 0 && src_size > 0) {
182                 if (pstore_ftrace_read_timestamp(&drec[dest_idx]) <
183                     pstore_ftrace_read_timestamp(&srec[src_idx])) {
184                         mrec[merged_idx++] = drec[dest_idx++];
185                         dest_size -= record_size;
186                 } else {
187                         mrec[merged_idx++] = srec[src_idx++];
188                         src_size -= record_size;
189                 }
190         }
191 
192         while (dest_size > 0) {
193                 mrec[merged_idx++] = drec[dest_idx++];
194                 dest_size -= record_size;
195         }
196 
197         while (src_size > 0) {
198                 mrec[merged_idx++] = srec[src_idx++];
199                 src_size -= record_size;
200         }
201 
202         kfree(*dest_log);
203         *dest_log = merged_buf;
204         *dest_log_size = total;
205 
206         return 0;
207 }
208 EXPORT_SYMBOL_GPL(pstore_ftrace_combine_log);
209 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php