Motr  M0
finject_debugfs.c
Go to the documentation of this file.
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 2012-2020 Seagate Technology LLC and/or its Affiliates
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * For any questions about this software or licensing,
18  * please email opensource@seagate.com or cortx-questions@seagate.com.
19  *
20  */
21 
22 
23 #include <linux/kernel.h> /* pr_info */
24 
25 #if 0
26 
27 //#ifdef ENABLE_FAULT_INJECTION
28 
29 #include <linux/debugfs.h> /* debugfs_create_dir */
30 #include <linux/kernel.h> /* kstrtoul */
31 #include <linux/module.h> /* THIS_MODULE */
32 #include <linux/seq_file.h> /* seq_read */
33 #include <linux/uaccess.h> /* strncpy_from_user */
34 #include <linux/string.h> /* strncmp */
35 #include <linux/ctype.h> /* isprint */
36 #include <linux/slab.h> /* kfree */
37 
38 #include "lib/thread.h" /* M0_THREAD_INIT */
39 #include "lib/mutex.h" /* m0_mutex */
40 #include "lib/time.h" /* m0_time_now */
41 #include "lib/misc.h" /* M0_SET_ARR0 */
42 #include "lib/string.h" /* m0_strdup */
43 #include "lib/finject.h"
44 #include "lib/finject_internal.h"
47 
48 
101 static struct dentry *fi_dir;
102 static const char fi_dir_name[] = "finject";
103 static bool fi_ctl_is_opened = false;
104 
105 
106 static void *fi_stat_start(struct seq_file *seq, loff_t *pos)
107 {
108  if (*pos == 0)
109  return SEQ_START_TOKEN;
110  else if (*pos >= m0_fi_states_get_free_idx())
111  /* indicate beyond end of file position */
112  return NULL;
113 
114 
115  return (void*)(m0_fi_states_get() + *pos);
116 }
117 
118 static void *fi_stat_next(struct seq_file *seq, void *v, loff_t *pos)
119 {
120  loff_t cur_pos = (*pos)++;
121 
122  if (cur_pos >= m0_fi_states_get_free_idx())
123  /* indicate end of sequence */
124  return NULL;
125 
126  return (void*)(m0_fi_states_get() + cur_pos);
127 }
128 
129 static void fi_stat_stop(struct seq_file *seq, void *v)
130 {
131 }
132 
133 static int fi_stat_show(struct seq_file *seq, void *v)
134 {
135  const struct m0_fi_fpoint_state *state = v;
137 
138  /* print header */
139  if (SEQ_START_TOKEN == v) {
140  seq_puts(seq, m0_fi_states_headline[0]);
141  seq_puts(seq, m0_fi_states_headline[1]);
142  return 0;
143  }
144 
145  /* skip disabled states */
146  /* TODO: add an option to control this in runtime through debugfs */
147  /*if (!fi_state_enabled(state))
148  return SEQ_SKIP;*/
149 
151 
152  seq_printf(seq, m0_fi_states_print_format,
153  si.si_idx, si.si_enb, si.si_total_hit_cnt,
154  si.si_total_trigger_cnt, si.si_hit_cnt,
155  si.si_trigger_cnt, si.si_type, si.si_data,
156  si.si_module, si.si_file, si.si_line_num,
157  si.si_func, si.si_tag);
158 
159  return 0;
160 }
161 
162 static const struct seq_operations fi_stat_sops = {
163  .start = fi_stat_start,
164  .stop = fi_stat_stop,
165  .next = fi_stat_next,
166  .show = fi_stat_show,
167 };
168 
169 static int fi_stat_open(struct inode *i, struct file *f)
170 {
171  int rc = 0;
172 
173  rc = seq_open(f, &fi_stat_sops);
174 
175  if (rc == 0) {
176  struct seq_file *sf = f->private_data;
177  sf->private = i->i_private;
178  }
179 
180  return rc;
181 }
182 
183 static const struct file_operations fi_stat_fops = {
184  .owner = THIS_MODULE,
185  .open = fi_stat_open,
186  .read = seq_read,
187  .llseek = seq_lseek,
188  .release = seq_release,
189 };
190 
191 static int fi_ctl_open(struct inode *i, struct file *f)
192 {
193  if (fi_ctl_is_opened)
194  return -EBUSY;
195 
196  fi_ctl_is_opened = true;
197 
198  return 0;
199 }
200 
201 static int fi_ctl_release(struct inode *i, struct file *f)
202 {
203  fi_ctl_is_opened = false;
204  return 0;
205 }
206 
207 static int fi_ctl_process_cmd(int argc, char *argv[])
208 {
209  /* there should be at least "action", "func" and "tag" */
210  if (argc < 3) {
211  pr_err(KBUILD_MODNAME ": finject_ctl too few arguments\n");
212  return -EINVAL;
213  }
214 
215  if (strcmp(argv[0], "enable") == 0) {
216  int rc;
217  char *func;
218  char *tag;
219 
220  /* "enable" also requires an "fp_type" */
221  if (argc < 4) {
222  pr_err(KBUILD_MODNAME ": finject_ctl too few arguments"
223  " for command '%s'\n", argv[0]);
224  return -EINVAL;
225  }
226 
227  func = m0_strdup(argv[1]);
228  if (func == NULL)
229  return -ENOMEM;
230 
231  rc = m0_fi_add_dyn_id(func);
232  if (rc != 0) {
233  kfree(func);
234  return rc;
235  }
236 
237  tag = m0_strdup(argv[2]);
238  if (tag == NULL)
239  return -ENOMEM;
240 
242  if (rc != 0) {
243  kfree(tag);
244  return rc;
245  }
246 
247  if (strcmp(argv[3], "always") == 0) {
248  if (argc > 4) {
249  pr_err(KBUILD_MODNAME ": finject_ctl too many"
250  " arguments for command '%s'\n", argv[0]);
251  return -EINVAL;
252  }
253  m0_fi_enable(func, tag);
254  } else if (strcmp(argv[3], "oneshot") == 0) {
255  if (argc > 4) {
256  pr_err(KBUILD_MODNAME ": finject_ctl too many"
257  " arguments for command '%s'\n", argv[0]);
258  return -EINVAL;
259  }
260  m0_fi_enable_once(func, tag);
261  } else if (strcmp(argv[3], "random") == 0) {
262  unsigned long p;
263  if (argc != 5) {
264  pr_err(KBUILD_MODNAME ": finject_ctl incorrect"
265  " number of arguments for FP type '%s'\n",
266  argv[3]);
267  return -EINVAL;
268  }
269  rc = kstrtoul(argv[4], 0, &p);
270  if (rc < 0)
271  return rc;
272  m0_fi_enable_random(func, tag, p);
273  } else if (strcmp(argv[3], "off_n_on_m") == 0) {
274  unsigned long n;
275  unsigned long m;
276  if (argc != 6) {
277  pr_err(KBUILD_MODNAME ": finject_ctl incorrect"
278  " number of arguments for FP type '%s'\n",
279  argv[3]);
280  return -EINVAL;
281  }
282  rc = kstrtoul(argv[4], 0, &n);
283  if (rc < 0)
284  return rc;
285  rc = kstrtoul(argv[5], 0, &m);
286  if (rc < 0)
287  return rc;
288  m0_fi_enable_off_n_on_m(func, tag, n, m);
289  } else {
290  pr_err(KBUILD_MODNAME ": finject_ctl: invalid or not"
291  " allowed FP type '%s'\n", argv[3]);
292  return -EINVAL;
293  }
294  } else if (strcmp(argv[0], "disable") == 0) {
295  m0_fi_disable(argv[1], argv[2]);
296  } else {
297  pr_err(KBUILD_MODNAME ": finject_ctl: invalid action '%s'\n",
298  argv[0]);
299  return -EINVAL;
300  }
301 
302  return 0;
303 }
304 
305 static ssize_t fi_ctl_write(struct file *file, const char __user *user_buf,
306  size_t size, loff_t *ppos)
307 {
308  int rc;
309  int i;
310  ssize_t ret_size = size;
311  char buf[256];
312  int argc;
313  char **argv;
314 
316  if (size > sizeof buf - 1)
317  return -EINVAL;
318 
319  if (strncpy_from_user(buf, user_buf, size) < 0)
320  return -EFAULT;
321  buf[size] = 0;
322 
323  /*
324  * usually debugfs files are written with `echo` command which appends a
325  * newline character at the end of string, so we need to remove it if it
326  * present
327  */
328  if (buf[size - 1] == '\n') {
329  buf[size - 1] = 0;
330  size--;
331  }
332 
333  /*
334  * check that buffer contains only printable text data to prevent
335  * user-space from injecting some malicious binary code into kernel in
336  * place of FP identifiers
337  */
338  for (i = 0; i < size; ++i)
339  if (!isprint(buf[i]))
340  return -EINVAL;
341 
342  pr_info(KBUILD_MODNAME ": finject_ctl command '%s'\n", buf);
343 
344  argv = argv_split(GFP_KERNEL, buf, &argc);
345  if (argv == NULL)
346  return -ENOMEM;
347 
348  rc = fi_ctl_process_cmd(argc, argv);
349  argv_free(argv);
350 
351  if (rc < 0)
352  return rc;
353 
354  /* ignore the rest of the buffer, only one command at a time */
355  *ppos += ret_size;
356  return ret_size;
357 }
358 
359 static const struct file_operations fi_ctl_fops = {
360  .owner = THIS_MODULE,
361  .open = fi_ctl_open,
362  .release = fi_ctl_release,
363  .write = fi_ctl_write,
364 };
365 
366 int fi_dfs_init(void)
367 {
368  struct dentry *stat_file;
369  static const char stat_name[] = "stat";
370  struct dentry *ctl_file;
371  static const char ctl_name[] = "ctl";
372  int rc = 0;
373 
374  fi_dir = debugfs_create_dir(fi_dir_name, dfs_root_dir);
375  if (fi_dir == NULL) {
376  pr_err(KBUILD_MODNAME ": can't create debugfs dir '%s/%s'\n",
377  dfs_root_name, fi_dir_name);
378  rc = -EPERM;
379  goto out;
380  }
381 
382  stat_file = debugfs_create_file(stat_name, S_IRUSR, fi_dir, NULL,
383  &fi_stat_fops);
384  if (stat_file == NULL) {
385  pr_err(KBUILD_MODNAME ": failed to create debugfs file"
386  " '%s/%s/%s'\n", dfs_root_name, fi_dir_name, stat_name);
387  rc = -EPERM;
388  goto err;
389  }
390 
391  ctl_file = debugfs_create_file(ctl_name, S_IWUSR, fi_dir, NULL,
392  &fi_ctl_fops);
393  if (ctl_file == NULL) {
394  pr_err(KBUILD_MODNAME ": failed to create debugfs file"
395  " '%s/%s/%s'\n", dfs_root_name, fi_dir_name, ctl_name);
396  rc = -EPERM;
397  goto err;
398  }
399 out:
400  return rc;
401 err:
402  debugfs_remove_recursive(fi_dir);
403  fi_dir = NULL;
404  return rc;
405 }
406 
407 void fi_dfs_cleanup(void)
408 {
409  debugfs_remove_recursive(fi_dir);
410 }
411 
414 #else
415 
416 int fi_dfs_init(void)
417 {
418  pr_warning(KBUILD_MODNAME ": fault injection is not available, because it"
419  " was disabled during build\n");
420  return 0;
421 }
422 
423 void fi_dfs_cleanup(void)
424 {
425 }
426 
427 #endif /* ENABLE_FAULT_INJECTION */
428 
429 /*
430  * Local variables:
431  * c-indentation-style: "K&R"
432  * c-basic-offset: 8
433  * tab-width: 8
434  * fill-column: 80
435  * scroll-step: 1
436  * End:
437  */
static struct m0_addb2_philter p
Definition: consumer.c:40
#define m0_strdup(s)
Definition: string.h:43
#define NULL
Definition: misc.h:38
static struct m0_addb2_mach * m
Definition: consumer.c:38
static FILE * f
Definition: adieu.c:79
static uint64_t tag(uint8_t code, uint64_t id)
Definition: addb2.c:1047
struct m0_file file
Definition: di.c:36
static char * user_buf[NR]
Definition: ad.c:62
M0_INTERNAL const struct m0_fi_fpoint_state * m0_fi_states_get(void)
Definition: finject.c:88
struct dentry * dfs_root_dir
static void m0_fi_enable_random(const char *func, const char *tag, uint32_t p)
Definition: finject.h:321
Definition: sock.c:887
struct inode * inode
Definition: dir.c:624
void fi_dfs_cleanup(void)
int i
Definition: dir.c:1033
M0_INTERNAL void m0_fi_disable(const char *fp_func, const char *fp_tag)
Definition: finject.c:485
static void m0_fi_enable(const char *func, const char *tag)
Definition: finject.h:276
static int struct dentry * dentry
Definition: dir.c:589
M0_THREAD_ENTER
Definition: dir.c:336
int fi_dfs_init(void)
M0_INTERNAL int m0_fi_add_dyn_id(char *str)
Definition: finject.c:171
const char m0_fi_states_print_format[]
Definition: finject.c:83
const char dfs_root_name[]
static void m0_fi_enable_off_n_on_m(const char *func, const char *tag, uint32_t n, uint32_t m)
Definition: finject.h:346
uint64_t n
Definition: fops.h:107
M0_INTERNAL uint32_t m0_fi_states_get_free_idx(void)
Definition: finject.c:94
m0_bcount_t size
Definition: di.c:39
static void m0_fi_enable_once(const char *func, const char *tag)
Definition: finject.h:301
M0_INTERNAL void m0_fi_states_get_state_info(const struct m0_fi_fpoint_state *s, struct m0_fi_fpoint_state_info *si)
Definition: finject.c:123
const char * m0_fi_states_headline[]
Definition: finject.c:77
#define out(...)
Definition: gen.c:41
int32_t rc
Definition: trigger_fop.h:47
static struct sync_interactions si
Definition: sync.c:121
uint64_t seq
Definition: common.c:97