1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * What: /sys/kernel/debug/orangefs/debug-help |
4 | * Date: June 2015 |
5 | * Contact: Mike Marshall <hubcap@omnibond.com> |
6 | * Description: |
7 | * List of client and kernel debug keywords. |
8 | * |
9 | * |
10 | * What: /sys/kernel/debug/orangefs/client-debug |
11 | * Date: June 2015 |
12 | * Contact: Mike Marshall <hubcap@omnibond.com> |
13 | * Description: |
14 | * Debug setting for "the client", the userspace |
15 | * helper for the kernel module. |
16 | * |
17 | * |
18 | * What: /sys/kernel/debug/orangefs/kernel-debug |
19 | * Date: June 2015 |
20 | * Contact: Mike Marshall <hubcap@omnibond.com> |
21 | * Description: |
22 | * Debug setting for the orangefs kernel module. |
23 | * |
24 | * Any of the keywords, or comma-separated lists |
25 | * of keywords, from debug-help can be catted to |
26 | * client-debug or kernel-debug. |
27 | * |
28 | * "none", "all" and "verbose" are special keywords |
29 | * for client-debug. Setting client-debug to "all" |
30 | * is kind of like trying to drink water from a |
31 | * fire hose, "verbose" triggers most of the same |
32 | * output except for the constant flow of output |
33 | * from the main wait loop. |
34 | * |
35 | * "none" and "all" are similar settings for kernel-debug |
36 | * no need for a "verbose". |
37 | */ |
38 | #include <linux/debugfs.h> |
39 | #include <linux/slab.h> |
40 | |
41 | #include <linux/uaccess.h> |
42 | |
43 | #include "orangefs-debugfs.h" |
44 | #include "protocol.h" |
45 | #include "orangefs-kernel.h" |
46 | |
47 | #define DEBUG_HELP_STRING_SIZE 4096 |
48 | #define HELP_STRING_UNINITIALIZED \ |
49 | "Client Debug Keywords are unknown until the first time\n" \ |
50 | "the client is started after boot.\n" |
51 | #define ORANGEFS_KMOD_DEBUG_HELP_FILE "debug-help" |
52 | #define ORANGEFS_KMOD_DEBUG_FILE "kernel-debug" |
53 | #define ORANGEFS_CLIENT_DEBUG_FILE "client-debug" |
54 | #define ORANGEFS_VERBOSE "verbose" |
55 | #define ORANGEFS_ALL "all" |
56 | |
57 | /* |
58 | * An array of client_debug_mask will be built to hold debug keyword/mask |
59 | * values fetched from userspace. |
60 | */ |
61 | struct client_debug_mask { |
62 | char *keyword; |
63 | __u64 mask1; |
64 | __u64 mask2; |
65 | }; |
66 | |
67 | static void orangefs_kernel_debug_init(void); |
68 | |
69 | static int orangefs_debug_help_open(struct inode *, struct file *); |
70 | static void *help_start(struct seq_file *, loff_t *); |
71 | static void *help_next(struct seq_file *, void *, loff_t *); |
72 | static void help_stop(struct seq_file *, void *); |
73 | static int help_show(struct seq_file *, void *); |
74 | |
75 | static int orangefs_debug_open(struct inode *, struct file *); |
76 | |
77 | static ssize_t orangefs_debug_read(struct file *, |
78 | char __user *, |
79 | size_t, |
80 | loff_t *); |
81 | |
82 | static ssize_t orangefs_debug_write(struct file *, |
83 | const char __user *, |
84 | size_t, |
85 | loff_t *); |
86 | |
87 | static int orangefs_prepare_cdm_array(char *); |
88 | static void debug_mask_to_string(void *, int); |
89 | static void do_k_string(void *, int); |
90 | static void do_c_string(void *, int); |
91 | static int keyword_is_amalgam(char *); |
92 | static int check_amalgam_keyword(void *, int); |
93 | static void debug_string_to_mask(char *, void *, int); |
94 | static void do_c_mask(int, char *, struct client_debug_mask **); |
95 | static void do_k_mask(int, char *, __u64 **); |
96 | |
97 | static char kernel_debug_string[ORANGEFS_MAX_DEBUG_STRING_LEN] = "none" ; |
98 | static char *debug_help_string; |
99 | static char client_debug_string[ORANGEFS_MAX_DEBUG_STRING_LEN]; |
100 | static char client_debug_array_string[ORANGEFS_MAX_DEBUG_STRING_LEN]; |
101 | |
102 | static struct dentry *client_debug_dentry; |
103 | static struct dentry *debug_dir; |
104 | |
105 | static unsigned int kernel_mask_set_mod_init; |
106 | static int orangefs_debug_disabled = 1; |
107 | static int help_string_initialized; |
108 | |
109 | static const struct seq_operations help_debug_ops = { |
110 | .start = help_start, |
111 | .next = help_next, |
112 | .stop = help_stop, |
113 | .show = help_show, |
114 | }; |
115 | |
116 | static const struct file_operations debug_help_fops = { |
117 | .owner = THIS_MODULE, |
118 | .open = orangefs_debug_help_open, |
119 | .read = seq_read, |
120 | .release = seq_release, |
121 | .llseek = seq_lseek, |
122 | }; |
123 | |
124 | static const struct file_operations kernel_debug_fops = { |
125 | .owner = THIS_MODULE, |
126 | .open = orangefs_debug_open, |
127 | .read = orangefs_debug_read, |
128 | .write = orangefs_debug_write, |
129 | .llseek = generic_file_llseek, |
130 | }; |
131 | |
132 | static int client_all_index; |
133 | static int client_verbose_index; |
134 | |
135 | static struct client_debug_mask *cdm_array; |
136 | static int cdm_element_count; |
137 | |
138 | static struct client_debug_mask client_debug_mask; |
139 | |
140 | /* |
141 | * Used to protect data in ORANGEFS_KMOD_DEBUG_FILE and |
142 | * ORANGEFS_KMOD_DEBUG_FILE. |
143 | */ |
144 | static DEFINE_MUTEX(orangefs_debug_lock); |
145 | |
146 | /* Used to protect data in ORANGEFS_KMOD_DEBUG_HELP_FILE */ |
147 | static DEFINE_MUTEX(orangefs_help_file_lock); |
148 | |
149 | /* |
150 | * initialize kmod debug operations, create orangefs debugfs dir and |
151 | * ORANGEFS_KMOD_DEBUG_HELP_FILE. |
152 | */ |
153 | void orangefs_debugfs_init(int debug_mask) |
154 | { |
155 | /* convert input debug mask to a 64-bit unsigned integer */ |
156 | orangefs_gossip_debug_mask = (unsigned long long)debug_mask; |
157 | |
158 | /* |
159 | * set the kernel's gossip debug string; invalid mask values will |
160 | * be ignored. |
161 | */ |
162 | debug_mask_to_string(&orangefs_gossip_debug_mask, 0); |
163 | |
164 | /* remove any invalid values from the mask */ |
165 | debug_string_to_mask(kernel_debug_string, &orangefs_gossip_debug_mask, |
166 | 0); |
167 | |
168 | /* |
169 | * if the mask has a non-zero value, then indicate that the mask |
170 | * was set when the kernel module was loaded. The orangefs dev ioctl |
171 | * command will look at this boolean to determine if the kernel's |
172 | * debug mask should be overwritten when the client-core is started. |
173 | */ |
174 | if (orangefs_gossip_debug_mask != 0) |
175 | kernel_mask_set_mod_init = true; |
176 | |
177 | pr_info("%s: called with debug mask: :%s: :%llx:\n" , |
178 | __func__, |
179 | kernel_debug_string, |
180 | (unsigned long long)orangefs_gossip_debug_mask); |
181 | |
182 | debug_dir = debugfs_create_dir(name: "orangefs" , NULL); |
183 | |
184 | debugfs_create_file(ORANGEFS_KMOD_DEBUG_HELP_FILE, mode: 0444, parent: debug_dir, |
185 | data: debug_help_string, fops: &debug_help_fops); |
186 | |
187 | orangefs_debug_disabled = 0; |
188 | |
189 | orangefs_kernel_debug_init(); |
190 | } |
191 | |
192 | /* |
193 | * initialize the kernel-debug file. |
194 | */ |
195 | static void orangefs_kernel_debug_init(void) |
196 | { |
197 | static char k_buffer[ORANGEFS_MAX_DEBUG_STRING_LEN] = { }; |
198 | |
199 | gossip_debug(GOSSIP_DEBUGFS_DEBUG, "%s: start\n" , __func__); |
200 | |
201 | if (strlen(kernel_debug_string) + 1 < ORANGEFS_MAX_DEBUG_STRING_LEN) { |
202 | strcpy(p: k_buffer, q: kernel_debug_string); |
203 | strcat(p: k_buffer, q: "\n" ); |
204 | } else { |
205 | strcpy(p: k_buffer, q: "none\n" ); |
206 | pr_info("%s: overflow 1!\n" , __func__); |
207 | } |
208 | |
209 | debugfs_create_file(ORANGEFS_KMOD_DEBUG_FILE, mode: 0444, parent: debug_dir, data: k_buffer, |
210 | fops: &kernel_debug_fops); |
211 | } |
212 | |
213 | |
214 | void orangefs_debugfs_cleanup(void) |
215 | { |
216 | debugfs_remove_recursive(dentry: debug_dir); |
217 | kfree(objp: debug_help_string); |
218 | debug_help_string = NULL; |
219 | } |
220 | |
221 | /* open ORANGEFS_KMOD_DEBUG_HELP_FILE */ |
222 | static int orangefs_debug_help_open(struct inode *inode, struct file *file) |
223 | { |
224 | int rc = -ENODEV; |
225 | int ret; |
226 | |
227 | gossip_debug(GOSSIP_DEBUGFS_DEBUG, |
228 | "orangefs_debug_help_open: start\n" ); |
229 | |
230 | if (orangefs_debug_disabled) |
231 | goto out; |
232 | |
233 | ret = seq_open(file, &help_debug_ops); |
234 | if (ret) |
235 | goto out; |
236 | |
237 | ((struct seq_file *)(file->private_data))->private = inode->i_private; |
238 | |
239 | rc = 0; |
240 | |
241 | out: |
242 | gossip_debug(GOSSIP_DEBUGFS_DEBUG, |
243 | "orangefs_debug_help_open: rc:%d:\n" , |
244 | rc); |
245 | return rc; |
246 | } |
247 | |
248 | /* |
249 | * I think start always gets called again after stop. Start |
250 | * needs to return NULL when it is done. The whole "payload" |
251 | * in this case is a single (long) string, so by the second |
252 | * time we get to start (pos = 1), we're done. |
253 | */ |
254 | static void *help_start(struct seq_file *m, loff_t *pos) |
255 | { |
256 | void *payload = NULL; |
257 | |
258 | gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_start: start\n" ); |
259 | |
260 | mutex_lock(&orangefs_help_file_lock); |
261 | |
262 | if (*pos == 0) |
263 | payload = m->private; |
264 | |
265 | return payload; |
266 | } |
267 | |
268 | static void *help_next(struct seq_file *m, void *v, loff_t *pos) |
269 | { |
270 | (*pos)++; |
271 | gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_next: start\n" ); |
272 | |
273 | return NULL; |
274 | } |
275 | |
276 | static void help_stop(struct seq_file *m, void *p) |
277 | { |
278 | gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_stop: start\n" ); |
279 | mutex_unlock(lock: &orangefs_help_file_lock); |
280 | } |
281 | |
282 | static int help_show(struct seq_file *m, void *v) |
283 | { |
284 | gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_show: start\n" ); |
285 | |
286 | seq_puts(m, s: v); |
287 | |
288 | return 0; |
289 | } |
290 | |
291 | /* |
292 | * initialize the client-debug file. |
293 | */ |
294 | static void orangefs_client_debug_init(void) |
295 | { |
296 | |
297 | static char c_buffer[ORANGEFS_MAX_DEBUG_STRING_LEN] = { }; |
298 | |
299 | gossip_debug(GOSSIP_DEBUGFS_DEBUG, "%s: start\n" , __func__); |
300 | |
301 | if (strlen(client_debug_string) + 1 < ORANGEFS_MAX_DEBUG_STRING_LEN) { |
302 | strcpy(p: c_buffer, q: client_debug_string); |
303 | strcat(p: c_buffer, q: "\n" ); |
304 | } else { |
305 | strcpy(p: c_buffer, q: "none\n" ); |
306 | pr_info("%s: overflow! 2\n" , __func__); |
307 | } |
308 | |
309 | client_debug_dentry = debugfs_create_file(ORANGEFS_CLIENT_DEBUG_FILE, |
310 | mode: 0444, |
311 | parent: debug_dir, |
312 | data: c_buffer, |
313 | fops: &kernel_debug_fops); |
314 | } |
315 | |
316 | /* open ORANGEFS_KMOD_DEBUG_FILE or ORANGEFS_CLIENT_DEBUG_FILE.*/ |
317 | static int orangefs_debug_open(struct inode *inode, struct file *file) |
318 | { |
319 | int rc = -ENODEV; |
320 | |
321 | gossip_debug(GOSSIP_DEBUGFS_DEBUG, |
322 | "%s: orangefs_debug_disabled: %d\n" , |
323 | __func__, |
324 | orangefs_debug_disabled); |
325 | |
326 | if (orangefs_debug_disabled) |
327 | goto out; |
328 | |
329 | rc = 0; |
330 | mutex_lock(&orangefs_debug_lock); |
331 | file->private_data = inode->i_private; |
332 | mutex_unlock(lock: &orangefs_debug_lock); |
333 | |
334 | out: |
335 | gossip_debug(GOSSIP_DEBUGFS_DEBUG, |
336 | "orangefs_debug_open: rc: %d\n" , |
337 | rc); |
338 | return rc; |
339 | } |
340 | |
341 | static ssize_t orangefs_debug_read(struct file *file, |
342 | char __user *ubuf, |
343 | size_t count, |
344 | loff_t *ppos) |
345 | { |
346 | char *buf; |
347 | int sprintf_ret; |
348 | ssize_t read_ret = -ENOMEM; |
349 | |
350 | gossip_debug(GOSSIP_DEBUGFS_DEBUG, "orangefs_debug_read: start\n" ); |
351 | |
352 | buf = kmalloc(ORANGEFS_MAX_DEBUG_STRING_LEN, GFP_KERNEL); |
353 | if (!buf) |
354 | goto out; |
355 | |
356 | mutex_lock(&orangefs_debug_lock); |
357 | sprintf_ret = sprintf(buf, fmt: "%s" , (char *)file->private_data); |
358 | mutex_unlock(lock: &orangefs_debug_lock); |
359 | |
360 | read_ret = simple_read_from_buffer(to: ubuf, count, ppos, from: buf, available: sprintf_ret); |
361 | |
362 | kfree(objp: buf); |
363 | |
364 | out: |
365 | gossip_debug(GOSSIP_DEBUGFS_DEBUG, |
366 | "orangefs_debug_read: ret: %zu\n" , |
367 | read_ret); |
368 | |
369 | return read_ret; |
370 | } |
371 | |
372 | static ssize_t orangefs_debug_write(struct file *file, |
373 | const char __user *ubuf, |
374 | size_t count, |
375 | loff_t *ppos) |
376 | { |
377 | char *buf; |
378 | int rc = -EFAULT; |
379 | size_t silly = 0; |
380 | char *debug_string; |
381 | struct orangefs_kernel_op_s *new_op = NULL; |
382 | struct client_debug_mask c_mask = { NULL, 0, 0 }; |
383 | char *s; |
384 | |
385 | gossip_debug(GOSSIP_DEBUGFS_DEBUG, |
386 | "orangefs_debug_write: %pD\n" , |
387 | file); |
388 | |
389 | if (count == 0) |
390 | return 0; |
391 | |
392 | /* |
393 | * Thwart users who try to jamb a ridiculous number |
394 | * of bytes into the debug file... |
395 | */ |
396 | if (count > ORANGEFS_MAX_DEBUG_STRING_LEN + 1) { |
397 | silly = count; |
398 | count = ORANGEFS_MAX_DEBUG_STRING_LEN + 1; |
399 | } |
400 | |
401 | buf = kzalloc(ORANGEFS_MAX_DEBUG_STRING_LEN, GFP_KERNEL); |
402 | if (!buf) |
403 | goto out; |
404 | |
405 | if (copy_from_user(to: buf, from: ubuf, n: count - 1)) { |
406 | gossip_debug(GOSSIP_DEBUGFS_DEBUG, |
407 | "%s: copy_from_user failed!\n" , |
408 | __func__); |
409 | goto out; |
410 | } |
411 | |
412 | /* |
413 | * Map the keyword string from userspace into a valid debug mask. |
414 | * The mapping process involves mapping the human-inputted string |
415 | * into a valid mask, and then rebuilding the string from the |
416 | * verified valid mask. |
417 | * |
418 | * A service operation is required to set a new client-side |
419 | * debug mask. |
420 | */ |
421 | if (!strcmp(file->f_path.dentry->d_name.name, |
422 | ORANGEFS_KMOD_DEBUG_FILE)) { |
423 | debug_string_to_mask(buf, &orangefs_gossip_debug_mask, 0); |
424 | debug_mask_to_string(&orangefs_gossip_debug_mask, 0); |
425 | debug_string = kernel_debug_string; |
426 | gossip_debug(GOSSIP_DEBUGFS_DEBUG, |
427 | "New kernel debug string is %s\n" , |
428 | kernel_debug_string); |
429 | } else { |
430 | /* Can't reset client debug mask if client is not running. */ |
431 | if (is_daemon_in_service()) { |
432 | pr_info("%s: Client not running :%d:\n" , |
433 | __func__, |
434 | is_daemon_in_service()); |
435 | goto out; |
436 | } |
437 | |
438 | debug_string_to_mask(buf, &c_mask, 1); |
439 | debug_mask_to_string(&c_mask, 1); |
440 | debug_string = client_debug_string; |
441 | |
442 | new_op = op_alloc(ORANGEFS_VFS_OP_PARAM); |
443 | if (!new_op) { |
444 | pr_info("%s: op_alloc failed!\n" , __func__); |
445 | goto out; |
446 | } |
447 | |
448 | new_op->upcall.req.param.op = |
449 | ORANGEFS_PARAM_REQUEST_OP_TWO_MASK_VALUES; |
450 | new_op->upcall.req.param.type = ORANGEFS_PARAM_REQUEST_SET; |
451 | memset(new_op->upcall.req.param.s_value, |
452 | 0, |
453 | ORANGEFS_MAX_DEBUG_STRING_LEN); |
454 | sprintf(buf: new_op->upcall.req.param.s_value, |
455 | fmt: "%llx %llx\n" , |
456 | c_mask.mask1, |
457 | c_mask.mask2); |
458 | |
459 | /* service_operation returns 0 on success... */ |
460 | rc = service_operation(op: new_op, |
461 | op_name: "orangefs_param" , |
462 | ORANGEFS_OP_INTERRUPTIBLE); |
463 | |
464 | if (rc) |
465 | gossip_debug(GOSSIP_DEBUGFS_DEBUG, |
466 | "%s: service_operation failed! rc:%d:\n" , |
467 | __func__, |
468 | rc); |
469 | |
470 | op_release(op: new_op); |
471 | } |
472 | |
473 | mutex_lock(&orangefs_debug_lock); |
474 | s = file_inode(f: file)->i_private; |
475 | memset(s, 0, ORANGEFS_MAX_DEBUG_STRING_LEN); |
476 | sprintf(buf: s, fmt: "%s\n" , debug_string); |
477 | mutex_unlock(lock: &orangefs_debug_lock); |
478 | |
479 | *ppos += count; |
480 | if (silly) |
481 | rc = silly; |
482 | else |
483 | rc = count; |
484 | |
485 | out: |
486 | gossip_debug(GOSSIP_DEBUGFS_DEBUG, |
487 | "orangefs_debug_write: rc: %d\n" , |
488 | rc); |
489 | kfree(objp: buf); |
490 | return rc; |
491 | } |
492 | |
493 | /* |
494 | * After obtaining a string representation of the client's debug |
495 | * keywords and their associated masks, this function is called to build an |
496 | * array of these values. |
497 | */ |
498 | static int orangefs_prepare_cdm_array(char *debug_array_string) |
499 | { |
500 | int i; |
501 | int rc = -EINVAL; |
502 | char *cds_head = NULL; |
503 | char *cds_delimiter = NULL; |
504 | int keyword_len = 0; |
505 | |
506 | gossip_debug(GOSSIP_UTILS_DEBUG, "%s: start\n" , __func__); |
507 | |
508 | /* |
509 | * figure out how many elements the cdm_array needs. |
510 | */ |
511 | for (i = 0; i < strlen(debug_array_string); i++) |
512 | if (debug_array_string[i] == '\n') |
513 | cdm_element_count++; |
514 | |
515 | if (!cdm_element_count) { |
516 | pr_info("No elements in client debug array string!\n" ); |
517 | goto out; |
518 | } |
519 | |
520 | cdm_array = kcalloc(n: cdm_element_count, size: sizeof(*cdm_array), GFP_KERNEL); |
521 | if (!cdm_array) { |
522 | rc = -ENOMEM; |
523 | goto out; |
524 | } |
525 | |
526 | cds_head = debug_array_string; |
527 | |
528 | for (i = 0; i < cdm_element_count; i++) { |
529 | cds_delimiter = strchr(cds_head, '\n'); |
530 | *cds_delimiter = '\0'; |
531 | |
532 | keyword_len = strcspn(cds_head, " " ); |
533 | |
534 | cdm_array[i].keyword = kzalloc(size: keyword_len + 1, GFP_KERNEL); |
535 | if (!cdm_array[i].keyword) { |
536 | rc = -ENOMEM; |
537 | goto out; |
538 | } |
539 | |
540 | sscanf(cds_head, |
541 | "%s %llx %llx" , |
542 | cdm_array[i].keyword, |
543 | (unsigned long long *)&(cdm_array[i].mask1), |
544 | (unsigned long long *)&(cdm_array[i].mask2)); |
545 | |
546 | if (!strcmp(cdm_array[i].keyword, ORANGEFS_VERBOSE)) |
547 | client_verbose_index = i; |
548 | |
549 | if (!strcmp(cdm_array[i].keyword, ORANGEFS_ALL)) |
550 | client_all_index = i; |
551 | |
552 | cds_head = cds_delimiter + 1; |
553 | } |
554 | |
555 | rc = cdm_element_count; |
556 | |
557 | gossip_debug(GOSSIP_UTILS_DEBUG, "%s: rc:%d:\n" , __func__, rc); |
558 | |
559 | out: |
560 | |
561 | return rc; |
562 | |
563 | } |
564 | |
565 | /* |
566 | * /sys/kernel/debug/orangefs/debug-help can be catted to |
567 | * see all the available kernel and client debug keywords. |
568 | * |
569 | * When orangefs.ko initializes, we have no idea what keywords the |
570 | * client supports, nor their associated masks. |
571 | * |
572 | * We pass through this function once at module-load and stamp a |
573 | * boilerplate "we don't know" message for the client in the |
574 | * debug-help file. We pass through here again when the client |
575 | * starts and then we can fill out the debug-help file fully. |
576 | * |
577 | * The client might be restarted any number of times between |
578 | * module reloads, we only build the debug-help file the first time. |
579 | */ |
580 | int orangefs_prepare_debugfs_help_string(int at_boot) |
581 | { |
582 | char *client_title = "Client Debug Keywords:\n" ; |
583 | char *kernel_title = "Kernel Debug Keywords:\n" ; |
584 | size_t string_size = DEBUG_HELP_STRING_SIZE; |
585 | size_t result_size; |
586 | size_t i; |
587 | char *new; |
588 | int rc = -EINVAL; |
589 | |
590 | gossip_debug(GOSSIP_UTILS_DEBUG, "%s: start\n" , __func__); |
591 | |
592 | if (at_boot) |
593 | client_title = HELP_STRING_UNINITIALIZED; |
594 | |
595 | /* build a new debug_help_string. */ |
596 | new = kzalloc(DEBUG_HELP_STRING_SIZE, GFP_KERNEL); |
597 | if (!new) { |
598 | rc = -ENOMEM; |
599 | goto out; |
600 | } |
601 | |
602 | /* |
603 | * strlcat(dst, src, size) will append at most |
604 | * "size - strlen(dst) - 1" bytes of src onto dst, |
605 | * null terminating the result, and return the total |
606 | * length of the string it tried to create. |
607 | * |
608 | * We'll just plow through here building our new debug |
609 | * help string and let strlcat take care of assuring that |
610 | * dst doesn't overflow. |
611 | */ |
612 | strlcat(p: new, q: client_title, avail: string_size); |
613 | |
614 | if (!at_boot) { |
615 | |
616 | /* |
617 | * fill the client keyword/mask array and remember |
618 | * how many elements there were. |
619 | */ |
620 | cdm_element_count = |
621 | orangefs_prepare_cdm_array(debug_array_string: client_debug_array_string); |
622 | if (cdm_element_count <= 0) { |
623 | kfree(objp: new); |
624 | goto out; |
625 | } |
626 | |
627 | for (i = 0; i < cdm_element_count; i++) { |
628 | strlcat(p: new, q: "\t" , avail: string_size); |
629 | strlcat(p: new, q: cdm_array[i].keyword, avail: string_size); |
630 | strlcat(p: new, q: "\n" , avail: string_size); |
631 | } |
632 | } |
633 | |
634 | strlcat(p: new, q: "\n" , avail: string_size); |
635 | strlcat(p: new, q: kernel_title, avail: string_size); |
636 | |
637 | for (i = 0; i < num_kmod_keyword_mask_map; i++) { |
638 | strlcat(p: new, q: "\t" , avail: string_size); |
639 | strlcat(p: new, q: s_kmod_keyword_mask_map[i].keyword, avail: string_size); |
640 | result_size = strlcat(p: new, q: "\n" , avail: string_size); |
641 | } |
642 | |
643 | /* See if we tried to put too many bytes into "new"... */ |
644 | if (result_size >= string_size) { |
645 | kfree(objp: new); |
646 | goto out; |
647 | } |
648 | |
649 | if (at_boot) { |
650 | debug_help_string = new; |
651 | } else { |
652 | mutex_lock(&orangefs_help_file_lock); |
653 | memset(debug_help_string, 0, DEBUG_HELP_STRING_SIZE); |
654 | strlcat(p: debug_help_string, q: new, avail: string_size); |
655 | mutex_unlock(lock: &orangefs_help_file_lock); |
656 | kfree(objp: new); |
657 | } |
658 | |
659 | rc = 0; |
660 | |
661 | out: return rc; |
662 | |
663 | } |
664 | |
665 | /* |
666 | * kernel = type 0 |
667 | * client = type 1 |
668 | */ |
669 | static void debug_mask_to_string(void *mask, int type) |
670 | { |
671 | int i; |
672 | int len = 0; |
673 | char *debug_string; |
674 | int element_count = 0; |
675 | |
676 | gossip_debug(GOSSIP_UTILS_DEBUG, "%s: start\n" , __func__); |
677 | |
678 | if (type) { |
679 | debug_string = client_debug_string; |
680 | element_count = cdm_element_count; |
681 | } else { |
682 | debug_string = kernel_debug_string; |
683 | element_count = num_kmod_keyword_mask_map; |
684 | } |
685 | |
686 | memset(debug_string, 0, ORANGEFS_MAX_DEBUG_STRING_LEN); |
687 | |
688 | /* |
689 | * Some keywords, like "all" or "verbose", are amalgams of |
690 | * numerous other keywords. Make a special check for those |
691 | * before grinding through the whole mask only to find out |
692 | * later... |
693 | */ |
694 | if (check_amalgam_keyword(mask, type)) |
695 | goto out; |
696 | |
697 | /* Build the debug string. */ |
698 | for (i = 0; i < element_count; i++) |
699 | if (type) |
700 | do_c_string(mask, i); |
701 | else |
702 | do_k_string(mask, i); |
703 | |
704 | len = strlen(debug_string); |
705 | |
706 | if ((len) && (type)) |
707 | client_debug_string[len - 1] = '\0'; |
708 | else if (len) |
709 | kernel_debug_string[len - 1] = '\0'; |
710 | else if (type) |
711 | strcpy(p: client_debug_string, q: "none" ); |
712 | else |
713 | strcpy(p: kernel_debug_string, q: "none" ); |
714 | |
715 | out: |
716 | gossip_debug(GOSSIP_UTILS_DEBUG, "%s: string:%s:\n" , __func__, debug_string); |
717 | |
718 | return; |
719 | |
720 | } |
721 | |
722 | static void do_k_string(void *k_mask, int index) |
723 | { |
724 | __u64 *mask = (__u64 *) k_mask; |
725 | |
726 | if (keyword_is_amalgam((char *) s_kmod_keyword_mask_map[index].keyword)) |
727 | goto out; |
728 | |
729 | if (*mask & s_kmod_keyword_mask_map[index].mask_val) { |
730 | if ((strlen(kernel_debug_string) + |
731 | strlen(s_kmod_keyword_mask_map[index].keyword)) |
732 | < ORANGEFS_MAX_DEBUG_STRING_LEN - 1) { |
733 | strcat(p: kernel_debug_string, |
734 | q: s_kmod_keyword_mask_map[index].keyword); |
735 | strcat(p: kernel_debug_string, q: "," ); |
736 | } else { |
737 | gossip_err("%s: overflow!\n" , __func__); |
738 | strcpy(p: kernel_debug_string, ORANGEFS_ALL); |
739 | goto out; |
740 | } |
741 | } |
742 | |
743 | out: |
744 | |
745 | return; |
746 | } |
747 | |
748 | static void do_c_string(void *c_mask, int index) |
749 | { |
750 | struct client_debug_mask *mask = (struct client_debug_mask *) c_mask; |
751 | |
752 | if (keyword_is_amalgam(cdm_array[index].keyword)) |
753 | goto out; |
754 | |
755 | if ((mask->mask1 & cdm_array[index].mask1) || |
756 | (mask->mask2 & cdm_array[index].mask2)) { |
757 | if ((strlen(client_debug_string) + |
758 | strlen(cdm_array[index].keyword) + 1) |
759 | < ORANGEFS_MAX_DEBUG_STRING_LEN - 2) { |
760 | strcat(p: client_debug_string, |
761 | q: cdm_array[index].keyword); |
762 | strcat(p: client_debug_string, q: "," ); |
763 | } else { |
764 | gossip_err("%s: overflow!\n" , __func__); |
765 | strcpy(p: client_debug_string, ORANGEFS_ALL); |
766 | goto out; |
767 | } |
768 | } |
769 | out: |
770 | return; |
771 | } |
772 | |
773 | static int keyword_is_amalgam(char *keyword) |
774 | { |
775 | int rc = 0; |
776 | |
777 | if ((!strcmp(keyword, ORANGEFS_ALL)) || (!strcmp(keyword, ORANGEFS_VERBOSE))) |
778 | rc = 1; |
779 | |
780 | return rc; |
781 | } |
782 | |
783 | /* |
784 | * kernel = type 0 |
785 | * client = type 1 |
786 | * |
787 | * return 1 if we found an amalgam. |
788 | */ |
789 | static int check_amalgam_keyword(void *mask, int type) |
790 | { |
791 | __u64 *k_mask; |
792 | struct client_debug_mask *c_mask; |
793 | int k_all_index = num_kmod_keyword_mask_map - 1; |
794 | int rc = 0; |
795 | |
796 | if (type) { |
797 | c_mask = (struct client_debug_mask *) mask; |
798 | |
799 | if ((c_mask->mask1 == cdm_array[client_all_index].mask1) && |
800 | (c_mask->mask2 == cdm_array[client_all_index].mask2)) { |
801 | strcpy(p: client_debug_string, ORANGEFS_ALL); |
802 | rc = 1; |
803 | goto out; |
804 | } |
805 | |
806 | if ((c_mask->mask1 == cdm_array[client_verbose_index].mask1) && |
807 | (c_mask->mask2 == cdm_array[client_verbose_index].mask2)) { |
808 | strcpy(p: client_debug_string, ORANGEFS_VERBOSE); |
809 | rc = 1; |
810 | goto out; |
811 | } |
812 | |
813 | } else { |
814 | k_mask = (__u64 *) mask; |
815 | |
816 | if (*k_mask >= s_kmod_keyword_mask_map[k_all_index].mask_val) { |
817 | strcpy(p: kernel_debug_string, ORANGEFS_ALL); |
818 | rc = 1; |
819 | goto out; |
820 | } |
821 | } |
822 | |
823 | out: |
824 | |
825 | return rc; |
826 | } |
827 | |
828 | /* |
829 | * kernel = type 0 |
830 | * client = type 1 |
831 | */ |
832 | static void debug_string_to_mask(char *debug_string, void *mask, int type) |
833 | { |
834 | char *unchecked_keyword; |
835 | int i; |
836 | char *strsep_fodder = kstrdup(s: debug_string, GFP_KERNEL); |
837 | char *original_pointer; |
838 | int element_count = 0; |
839 | struct client_debug_mask *c_mask = NULL; |
840 | __u64 *k_mask = NULL; |
841 | |
842 | gossip_debug(GOSSIP_UTILS_DEBUG, "%s: start\n" , __func__); |
843 | |
844 | if (type) { |
845 | c_mask = (struct client_debug_mask *)mask; |
846 | element_count = cdm_element_count; |
847 | } else { |
848 | k_mask = (__u64 *)mask; |
849 | *k_mask = 0; |
850 | element_count = num_kmod_keyword_mask_map; |
851 | } |
852 | |
853 | original_pointer = strsep_fodder; |
854 | while ((unchecked_keyword = strsep(&strsep_fodder, "," ))) |
855 | if (strlen(unchecked_keyword)) { |
856 | for (i = 0; i < element_count; i++) |
857 | if (type) |
858 | do_c_mask(i, |
859 | unchecked_keyword, |
860 | &c_mask); |
861 | else |
862 | do_k_mask(i, |
863 | unchecked_keyword, |
864 | &k_mask); |
865 | } |
866 | |
867 | kfree(objp: original_pointer); |
868 | } |
869 | |
870 | static void do_c_mask(int i, char *unchecked_keyword, |
871 | struct client_debug_mask **sane_mask) |
872 | { |
873 | |
874 | if (!strcmp(cdm_array[i].keyword, unchecked_keyword)) { |
875 | (**sane_mask).mask1 = (**sane_mask).mask1 | cdm_array[i].mask1; |
876 | (**sane_mask).mask2 = (**sane_mask).mask2 | cdm_array[i].mask2; |
877 | } |
878 | } |
879 | |
880 | static void do_k_mask(int i, char *unchecked_keyword, __u64 **sane_mask) |
881 | { |
882 | |
883 | if (!strcmp(s_kmod_keyword_mask_map[i].keyword, unchecked_keyword)) |
884 | **sane_mask = (**sane_mask) | |
885 | s_kmod_keyword_mask_map[i].mask_val; |
886 | } |
887 | |
888 | int orangefs_debugfs_new_client_mask(void __user *arg) |
889 | { |
890 | struct dev_mask2_info_s mask2_info = {0}; |
891 | int ret; |
892 | |
893 | ret = copy_from_user(to: &mask2_info, |
894 | from: (void __user *)arg, |
895 | n: sizeof(struct dev_mask2_info_s)); |
896 | |
897 | if (ret != 0) |
898 | return -EIO; |
899 | |
900 | client_debug_mask.mask1 = mask2_info.mask1_value; |
901 | client_debug_mask.mask2 = mask2_info.mask2_value; |
902 | |
903 | pr_info("%s: client debug mask has been been received " |
904 | ":%llx: :%llx:\n" , |
905 | __func__, |
906 | (unsigned long long)client_debug_mask.mask1, |
907 | (unsigned long long)client_debug_mask.mask2); |
908 | |
909 | return ret; |
910 | } |
911 | |
912 | int orangefs_debugfs_new_client_string(void __user *arg) |
913 | { |
914 | int ret; |
915 | |
916 | ret = copy_from_user(to: &client_debug_array_string, |
917 | from: (void __user *)arg, |
918 | ORANGEFS_MAX_DEBUG_STRING_LEN); |
919 | |
920 | if (ret != 0) { |
921 | pr_info("%s: CLIENT_STRING: copy_from_user failed\n" , |
922 | __func__); |
923 | return -EFAULT; |
924 | } |
925 | |
926 | /* |
927 | * The real client-core makes an effort to ensure |
928 | * that actual strings that aren't too long to fit in |
929 | * this buffer is what we get here. We're going to use |
930 | * string functions on the stuff we got, so we'll make |
931 | * this extra effort to try and keep from |
932 | * flowing out of this buffer when we use the string |
933 | * functions, even if somehow the stuff we end up |
934 | * with here is garbage. |
935 | */ |
936 | client_debug_array_string[ORANGEFS_MAX_DEBUG_STRING_LEN - 1] = |
937 | '\0'; |
938 | |
939 | pr_info("%s: client debug array string has been received.\n" , |
940 | __func__); |
941 | |
942 | if (!help_string_initialized) { |
943 | |
944 | /* Build a proper debug help string. */ |
945 | ret = orangefs_prepare_debugfs_help_string(at_boot: 0); |
946 | if (ret) { |
947 | gossip_err("%s: no debug help string \n" , |
948 | __func__); |
949 | return ret; |
950 | } |
951 | |
952 | } |
953 | |
954 | debug_mask_to_string(mask: &client_debug_mask, type: 1); |
955 | |
956 | debugfs_remove(dentry: client_debug_dentry); |
957 | |
958 | orangefs_client_debug_init(); |
959 | |
960 | help_string_initialized++; |
961 | |
962 | return 0; |
963 | } |
964 | |
965 | int orangefs_debugfs_new_debug(void __user *arg) |
966 | { |
967 | struct dev_mask_info_s mask_info = {0}; |
968 | int ret; |
969 | |
970 | ret = copy_from_user(to: &mask_info, |
971 | from: (void __user *)arg, |
972 | n: sizeof(mask_info)); |
973 | |
974 | if (ret != 0) |
975 | return -EIO; |
976 | |
977 | if (mask_info.mask_type == KERNEL_MASK) { |
978 | if ((mask_info.mask_value == 0) |
979 | && (kernel_mask_set_mod_init)) { |
980 | /* |
981 | * the kernel debug mask was set when the |
982 | * kernel module was loaded; don't override |
983 | * it if the client-core was started without |
984 | * a value for ORANGEFS_KMODMASK. |
985 | */ |
986 | return 0; |
987 | } |
988 | debug_mask_to_string(mask: &mask_info.mask_value, |
989 | type: mask_info.mask_type); |
990 | orangefs_gossip_debug_mask = mask_info.mask_value; |
991 | pr_info("%s: kernel debug mask has been modified to " |
992 | ":%s: :%llx:\n" , |
993 | __func__, |
994 | kernel_debug_string, |
995 | (unsigned long long)orangefs_gossip_debug_mask); |
996 | } else if (mask_info.mask_type == CLIENT_MASK) { |
997 | debug_mask_to_string(mask: &mask_info.mask_value, |
998 | type: mask_info.mask_type); |
999 | pr_info("%s: client debug mask has been modified to" |
1000 | ":%s: :%llx:\n" , |
1001 | __func__, |
1002 | client_debug_string, |
1003 | llu(mask_info.mask_value)); |
1004 | } else { |
1005 | gossip_err("Invalid mask type....\n" ); |
1006 | return -EINVAL; |
1007 | } |
1008 | |
1009 | return ret; |
1010 | } |
1011 | |