xref: /openbmc/linux/fs/orangefs/orangefs-debugfs.c (revision 19ff7fcc76e6911a955742b40f85ba1030ccba5e)
1575e9461SMike Marshall /*
2575e9461SMike Marshall  * What:		/sys/kernel/debug/orangefs/debug-help
3575e9461SMike Marshall  * Date:		June 2015
4575e9461SMike Marshall  * Contact:		Mike Marshall <hubcap@omnibond.com>
5575e9461SMike Marshall  * Description:
6575e9461SMike Marshall  * 			List of client and kernel debug keywords.
7575e9461SMike Marshall  *
8575e9461SMike Marshall  *
9575e9461SMike Marshall  * What:		/sys/kernel/debug/orangefs/client-debug
10575e9461SMike Marshall  * Date:		June 2015
11575e9461SMike Marshall  * Contact:		Mike Marshall <hubcap@omnibond.com>
12575e9461SMike Marshall  * Description:
13575e9461SMike Marshall  * 			Debug setting for "the client", the userspace
14575e9461SMike Marshall  * 			helper for the kernel module.
15575e9461SMike Marshall  *
16575e9461SMike Marshall  *
17575e9461SMike Marshall  * What:		/sys/kernel/debug/orangefs/kernel-debug
18575e9461SMike Marshall  * Date:		June 2015
19575e9461SMike Marshall  * Contact:		Mike Marshall <hubcap@omnibond.com>
20575e9461SMike Marshall  * Description:
21575e9461SMike Marshall  * 			Debug setting for the orangefs kernel module.
22575e9461SMike Marshall  *
23575e9461SMike Marshall  * 			Any of the keywords, or comma-separated lists
24575e9461SMike Marshall  * 			of keywords, from debug-help can be catted to
25575e9461SMike Marshall  * 			client-debug or kernel-debug.
26575e9461SMike Marshall  *
27575e9461SMike Marshall  * 			"none", "all" and "verbose" are special keywords
28575e9461SMike Marshall  * 			for client-debug. Setting client-debug to "all"
29575e9461SMike Marshall  * 			is kind of like trying to drink water from a
30575e9461SMike Marshall  * 			fire hose, "verbose" triggers most of the same
31575e9461SMike Marshall  * 			output except for the constant flow of output
32575e9461SMike Marshall  * 			from the main wait loop.
33575e9461SMike Marshall  *
34575e9461SMike Marshall  * 			"none" and "all" are similar settings for kernel-debug
35575e9461SMike Marshall  * 			no need for a "verbose".
36575e9461SMike Marshall  */
37575e9461SMike Marshall #include <linux/debugfs.h>
38575e9461SMike Marshall #include <linux/slab.h>
39575e9461SMike Marshall 
40575e9461SMike Marshall #include <linux/uaccess.h>
41575e9461SMike Marshall 
42575e9461SMike Marshall #include "orangefs-debugfs.h"
43575e9461SMike Marshall #include "protocol.h"
44575e9461SMike Marshall #include "orangefs-kernel.h"
45575e9461SMike Marshall 
4644f46410SMartin Brandenburg #define DEBUG_HELP_STRING_SIZE 4096
4744f46410SMartin Brandenburg #define HELP_STRING_UNINITIALIZED \
4844f46410SMartin Brandenburg 	"Client Debug Keywords are unknown until the first time\n" \
4944f46410SMartin Brandenburg 	"the client is started after boot.\n"
5044f46410SMartin Brandenburg #define ORANGEFS_KMOD_DEBUG_HELP_FILE "debug-help"
5144f46410SMartin Brandenburg #define ORANGEFS_KMOD_DEBUG_FILE "kernel-debug"
5244f46410SMartin Brandenburg #define ORANGEFS_CLIENT_DEBUG_FILE "client-debug"
5344f46410SMartin Brandenburg #define ORANGEFS_VERBOSE "verbose"
5444f46410SMartin Brandenburg #define ORANGEFS_ALL "all"
55575e9461SMike Marshall 
5644f46410SMartin Brandenburg /*
5744f46410SMartin Brandenburg  * An array of client_debug_mask will be built to hold debug keyword/mask
5844f46410SMartin Brandenburg  * values fetched from userspace.
5944f46410SMartin Brandenburg  */
6044f46410SMartin Brandenburg struct client_debug_mask {
6144f46410SMartin Brandenburg 	char *keyword;
6244f46410SMartin Brandenburg 	__u64 mask1;
6344f46410SMartin Brandenburg 	__u64 mask2;
64575e9461SMike Marshall };
65575e9461SMike Marshall 
6644f46410SMartin Brandenburg static int orangefs_kernel_debug_init(void);
6744f46410SMartin Brandenburg 
6844f46410SMartin Brandenburg static int orangefs_debug_help_open(struct inode *, struct file *);
69575e9461SMike Marshall static void *help_start(struct seq_file *, loff_t *);
70575e9461SMike Marshall static void *help_next(struct seq_file *, void *, loff_t *);
71575e9461SMike Marshall static void help_stop(struct seq_file *, void *);
72575e9461SMike Marshall static int help_show(struct seq_file *, void *);
73575e9461SMike Marshall 
7444f46410SMartin Brandenburg static int orangefs_debug_open(struct inode *, struct file *);
75575e9461SMike Marshall 
76575e9461SMike Marshall static ssize_t orangefs_debug_read(struct file *,
77575e9461SMike Marshall 				 char __user *,
78575e9461SMike Marshall 				 size_t,
79575e9461SMike Marshall 				 loff_t *);
80575e9461SMike Marshall 
81575e9461SMike Marshall static ssize_t orangefs_debug_write(struct file *,
82575e9461SMike Marshall 				  const char __user *,
83575e9461SMike Marshall 				  size_t,
84575e9461SMike Marshall 				  loff_t *);
85575e9461SMike Marshall 
8644f46410SMartin Brandenburg static int orangefs_prepare_cdm_array(char *);
8744f46410SMartin Brandenburg static void debug_mask_to_string(void *, int);
8844f46410SMartin Brandenburg static void do_k_string(void *, int);
8944f46410SMartin Brandenburg static void do_c_string(void *, int);
9044f46410SMartin Brandenburg static int keyword_is_amalgam(char *);
9144f46410SMartin Brandenburg static int check_amalgam_keyword(void *, int);
9244f46410SMartin Brandenburg static void debug_string_to_mask(char *, void *, int);
9344f46410SMartin Brandenburg static void do_c_mask(int, char *, struct client_debug_mask **);
9444f46410SMartin Brandenburg static void do_k_mask(int, char *, __u64 **);
9544f46410SMartin Brandenburg 
9644f46410SMartin Brandenburg static char kernel_debug_string[ORANGEFS_MAX_DEBUG_STRING_LEN] = "none";
9744f46410SMartin Brandenburg static char *debug_help_string;
9844f46410SMartin Brandenburg static char client_debug_string[ORANGEFS_MAX_DEBUG_STRING_LEN];
9944f46410SMartin Brandenburg static char client_debug_array_string[ORANGEFS_MAX_DEBUG_STRING_LEN];
10044f46410SMartin Brandenburg 
10144f46410SMartin Brandenburg static struct dentry *help_file_dentry;
10244f46410SMartin Brandenburg static struct dentry *client_debug_dentry;
10344f46410SMartin Brandenburg static struct dentry *debug_dir;
10444f46410SMartin Brandenburg 
10544f46410SMartin Brandenburg static unsigned int kernel_mask_set_mod_init;
10644f46410SMartin Brandenburg static int orangefs_debug_disabled = 1;
10744f46410SMartin Brandenburg static int help_string_initialized;
10844f46410SMartin Brandenburg 
10944f46410SMartin Brandenburg static const struct seq_operations help_debug_ops = {
11044f46410SMartin Brandenburg 	.start	= help_start,
11144f46410SMartin Brandenburg 	.next	= help_next,
11244f46410SMartin Brandenburg 	.stop	= help_stop,
11344f46410SMartin Brandenburg 	.show	= help_show,
11444f46410SMartin Brandenburg };
11544f46410SMartin Brandenburg 
11644f46410SMartin Brandenburg const struct file_operations debug_help_fops = {
117*19ff7fccSMike Marshall 	.owner		= THIS_MODULE,
11844f46410SMartin Brandenburg 	.open           = orangefs_debug_help_open,
11944f46410SMartin Brandenburg 	.read           = seq_read,
12044f46410SMartin Brandenburg 	.release        = seq_release,
12144f46410SMartin Brandenburg 	.llseek         = seq_lseek,
12244f46410SMartin Brandenburg };
12344f46410SMartin Brandenburg 
124575e9461SMike Marshall static const struct file_operations kernel_debug_fops = {
125*19ff7fccSMike Marshall 	.owner		= THIS_MODULE,
126575e9461SMike Marshall 	.open           = orangefs_debug_open,
127575e9461SMike Marshall 	.read           = orangefs_debug_read,
128575e9461SMike Marshall 	.write		= orangefs_debug_write,
129575e9461SMike Marshall 	.llseek         = generic_file_llseek,
130575e9461SMike Marshall };
131575e9461SMike Marshall 
13244f46410SMartin Brandenburg static int client_all_index;
13344f46410SMartin Brandenburg static int client_verbose_index;
13444f46410SMartin Brandenburg 
13544f46410SMartin Brandenburg static struct client_debug_mask *cdm_array;
13644f46410SMartin Brandenburg static int cdm_element_count;
13744f46410SMartin Brandenburg 
13844f46410SMartin Brandenburg static struct client_debug_mask client_debug_mask;
13944f46410SMartin Brandenburg 
14044f46410SMartin Brandenburg /*
14144f46410SMartin Brandenburg  * Used to protect data in ORANGEFS_KMOD_DEBUG_FILE and
14244f46410SMartin Brandenburg  * ORANGEFS_KMOD_DEBUG_FILE.
14344f46410SMartin Brandenburg  */
14444f46410SMartin Brandenburg static DEFINE_MUTEX(orangefs_debug_lock);
14544f46410SMartin Brandenburg 
146dc033621SMike Marshall /* Used to protect data in ORANGEFS_KMOD_DEBUG_HELP_FILE */
147dc033621SMike Marshall static DEFINE_MUTEX(orangefs_help_file_lock);
148dc033621SMike Marshall 
149575e9461SMike Marshall /*
150575e9461SMike Marshall  * initialize kmod debug operations, create orangefs debugfs dir and
151575e9461SMike Marshall  * ORANGEFS_KMOD_DEBUG_HELP_FILE.
152575e9461SMike Marshall  */
15344f46410SMartin Brandenburg int orangefs_debugfs_init(int debug_mask)
154575e9461SMike Marshall {
155575e9461SMike Marshall 	int rc = -ENOMEM;
156575e9461SMike Marshall 
15744f46410SMartin Brandenburg 	/* convert input debug mask to a 64-bit unsigned integer */
15844f46410SMartin Brandenburg         orangefs_gossip_debug_mask = (unsigned long long)debug_mask;
15944f46410SMartin Brandenburg 
16044f46410SMartin Brandenburg 	/*
16144f46410SMartin Brandenburg 	 * set the kernel's gossip debug string; invalid mask values will
16244f46410SMartin Brandenburg 	 * be ignored.
16344f46410SMartin Brandenburg 	 */
16444f46410SMartin Brandenburg 	debug_mask_to_string(&orangefs_gossip_debug_mask, 0);
16544f46410SMartin Brandenburg 
16644f46410SMartin Brandenburg 	/* remove any invalid values from the mask */
16744f46410SMartin Brandenburg 	debug_string_to_mask(kernel_debug_string, &orangefs_gossip_debug_mask,
16844f46410SMartin Brandenburg 	    0);
16944f46410SMartin Brandenburg 
17044f46410SMartin Brandenburg 	/*
17144f46410SMartin Brandenburg 	 * if the mask has a non-zero value, then indicate that the mask
17244f46410SMartin Brandenburg 	 * was set when the kernel module was loaded.  The orangefs dev ioctl
17344f46410SMartin Brandenburg 	 * command will look at this boolean to determine if the kernel's
17444f46410SMartin Brandenburg 	 * debug mask should be overwritten when the client-core is started.
17544f46410SMartin Brandenburg 	 */
17644f46410SMartin Brandenburg 	if (orangefs_gossip_debug_mask != 0)
17744f46410SMartin Brandenburg 		kernel_mask_set_mod_init = true;
17844f46410SMartin Brandenburg 
17944f46410SMartin Brandenburg 	pr_info("%s: called with debug mask: :%s: :%llx:\n",
18044f46410SMartin Brandenburg 		__func__,
18144f46410SMartin Brandenburg 		kernel_debug_string,
18244f46410SMartin Brandenburg 		(unsigned long long)orangefs_gossip_debug_mask);
18344f46410SMartin Brandenburg 
184575e9461SMike Marshall 	debug_dir = debugfs_create_dir("orangefs", NULL);
1852180c52cSMike Marshall 	if (!debug_dir) {
1862180c52cSMike Marshall 		pr_info("%s: debugfs_create_dir failed.\n", __func__);
187575e9461SMike Marshall 		goto out;
1882180c52cSMike Marshall 	}
189575e9461SMike Marshall 
190575e9461SMike Marshall 	help_file_dentry = debugfs_create_file(ORANGEFS_KMOD_DEBUG_HELP_FILE,
191575e9461SMike Marshall 				  0444,
192575e9461SMike Marshall 				  debug_dir,
193575e9461SMike Marshall 				  debug_help_string,
194575e9461SMike Marshall 				  &debug_help_fops);
1952180c52cSMike Marshall 	if (!help_file_dentry) {
1962180c52cSMike Marshall 		pr_info("%s: debugfs_create_file failed.\n", __func__);
197575e9461SMike Marshall 		goto out;
1982180c52cSMike Marshall 	}
199575e9461SMike Marshall 
200575e9461SMike Marshall 	orangefs_debug_disabled = 0;
20144f46410SMartin Brandenburg 
20244f46410SMartin Brandenburg 	rc = orangefs_kernel_debug_init();
203575e9461SMike Marshall 
204575e9461SMike Marshall out:
205575e9461SMike Marshall 
206575e9461SMike Marshall 	return rc;
207575e9461SMike Marshall }
208575e9461SMike Marshall 
20944f46410SMartin Brandenburg /*
21044f46410SMartin Brandenburg  * initialize the kernel-debug file.
21144f46410SMartin Brandenburg  */
21244f46410SMartin Brandenburg static int orangefs_kernel_debug_init(void)
21344f46410SMartin Brandenburg {
21444f46410SMartin Brandenburg 	int rc = -ENOMEM;
21544f46410SMartin Brandenburg 	struct dentry *ret;
21644f46410SMartin Brandenburg 	char *k_buffer = NULL;
21744f46410SMartin Brandenburg 
21844f46410SMartin Brandenburg 	gossip_debug(GOSSIP_DEBUGFS_DEBUG, "%s: start\n", __func__);
21944f46410SMartin Brandenburg 
22044f46410SMartin Brandenburg 	k_buffer = kzalloc(ORANGEFS_MAX_DEBUG_STRING_LEN, GFP_KERNEL);
22144f46410SMartin Brandenburg 	if (!k_buffer)
22244f46410SMartin Brandenburg 		goto out;
22344f46410SMartin Brandenburg 
22444f46410SMartin Brandenburg 	if (strlen(kernel_debug_string) + 1 < ORANGEFS_MAX_DEBUG_STRING_LEN) {
22544f46410SMartin Brandenburg 		strcpy(k_buffer, kernel_debug_string);
22644f46410SMartin Brandenburg 		strcat(k_buffer, "\n");
22744f46410SMartin Brandenburg 	} else {
22844f46410SMartin Brandenburg 		strcpy(k_buffer, "none\n");
22944f46410SMartin Brandenburg 		pr_info("%s: overflow 1!\n", __func__);
23044f46410SMartin Brandenburg 	}
23144f46410SMartin Brandenburg 
23244f46410SMartin Brandenburg 	ret = debugfs_create_file(ORANGEFS_KMOD_DEBUG_FILE,
23344f46410SMartin Brandenburg 				  0444,
23444f46410SMartin Brandenburg 				  debug_dir,
23544f46410SMartin Brandenburg 				  k_buffer,
23644f46410SMartin Brandenburg 				  &kernel_debug_fops);
23744f46410SMartin Brandenburg 	if (!ret) {
23844f46410SMartin Brandenburg 		pr_info("%s: failed to create %s.\n",
23944f46410SMartin Brandenburg 			__func__,
24044f46410SMartin Brandenburg 			ORANGEFS_KMOD_DEBUG_FILE);
24144f46410SMartin Brandenburg 		goto out;
24244f46410SMartin Brandenburg 	}
24344f46410SMartin Brandenburg 
24444f46410SMartin Brandenburg 	rc = 0;
24544f46410SMartin Brandenburg 
24644f46410SMartin Brandenburg out:
24744f46410SMartin Brandenburg 
24844f46410SMartin Brandenburg 	gossip_debug(GOSSIP_DEBUGFS_DEBUG, "%s: rc:%d:\n", __func__, rc);
24944f46410SMartin Brandenburg 	return rc;
25044f46410SMartin Brandenburg }
25144f46410SMartin Brandenburg 
25244f46410SMartin Brandenburg 
253575e9461SMike Marshall void orangefs_debugfs_cleanup(void)
254575e9461SMike Marshall {
255575e9461SMike Marshall 	debugfs_remove_recursive(debug_dir);
256575e9461SMike Marshall }
257575e9461SMike Marshall 
258575e9461SMike Marshall /* open ORANGEFS_KMOD_DEBUG_HELP_FILE */
259575e9461SMike Marshall static int orangefs_debug_help_open(struct inode *inode, struct file *file)
260575e9461SMike Marshall {
261575e9461SMike Marshall 	int rc = -ENODEV;
262575e9461SMike Marshall 	int ret;
263575e9461SMike Marshall 
264575e9461SMike Marshall 	gossip_debug(GOSSIP_DEBUGFS_DEBUG,
265575e9461SMike Marshall 		     "orangefs_debug_help_open: start\n");
266575e9461SMike Marshall 
267575e9461SMike Marshall 	if (orangefs_debug_disabled)
268575e9461SMike Marshall 		goto out;
269575e9461SMike Marshall 
270575e9461SMike Marshall 	ret = seq_open(file, &help_debug_ops);
271575e9461SMike Marshall 	if (ret)
272575e9461SMike Marshall 		goto out;
273575e9461SMike Marshall 
274575e9461SMike Marshall 	((struct seq_file *)(file->private_data))->private = inode->i_private;
275575e9461SMike Marshall 
276575e9461SMike Marshall 	rc = 0;
277575e9461SMike Marshall 
278575e9461SMike Marshall out:
279575e9461SMike Marshall 	gossip_debug(GOSSIP_DEBUGFS_DEBUG,
280575e9461SMike Marshall 		     "orangefs_debug_help_open: rc:%d:\n",
281575e9461SMike Marshall 		     rc);
282575e9461SMike Marshall 	return rc;
283575e9461SMike Marshall }
284575e9461SMike Marshall 
285575e9461SMike Marshall /*
286575e9461SMike Marshall  * I think start always gets called again after stop. Start
287575e9461SMike Marshall  * needs to return NULL when it is done. The whole "payload"
288575e9461SMike Marshall  * in this case is a single (long) string, so by the second
289575e9461SMike Marshall  * time we get to start (pos = 1), we're done.
290575e9461SMike Marshall  */
291575e9461SMike Marshall static void *help_start(struct seq_file *m, loff_t *pos)
292575e9461SMike Marshall {
293575e9461SMike Marshall 	void *payload = NULL;
294575e9461SMike Marshall 
295575e9461SMike Marshall 	gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_start: start\n");
296575e9461SMike Marshall 
297dc033621SMike Marshall 	mutex_lock(&orangefs_help_file_lock);
298dc033621SMike Marshall 
299575e9461SMike Marshall 	if (*pos == 0)
300575e9461SMike Marshall 		payload = m->private;
301575e9461SMike Marshall 
302575e9461SMike Marshall 	return payload;
303575e9461SMike Marshall }
304575e9461SMike Marshall 
305575e9461SMike Marshall static void *help_next(struct seq_file *m, void *v, loff_t *pos)
306575e9461SMike Marshall {
307575e9461SMike Marshall 	gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_next: start\n");
308575e9461SMike Marshall 
309575e9461SMike Marshall 	return NULL;
310575e9461SMike Marshall }
311575e9461SMike Marshall 
312575e9461SMike Marshall static void help_stop(struct seq_file *m, void *p)
313575e9461SMike Marshall {
314575e9461SMike Marshall 	gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_stop: start\n");
315dc033621SMike Marshall 	mutex_unlock(&orangefs_help_file_lock);
316575e9461SMike Marshall }
317575e9461SMike Marshall 
318575e9461SMike Marshall static int help_show(struct seq_file *m, void *v)
319575e9461SMike Marshall {
320575e9461SMike Marshall 	gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_show: start\n");
321575e9461SMike Marshall 
322575e9461SMike Marshall 	seq_puts(m, v);
323575e9461SMike Marshall 
324575e9461SMike Marshall 	return 0;
325575e9461SMike Marshall }
326575e9461SMike Marshall 
327575e9461SMike Marshall /*
328575e9461SMike Marshall  * initialize the client-debug file.
329575e9461SMike Marshall  */
330575e9461SMike Marshall int orangefs_client_debug_init(void)
331575e9461SMike Marshall {
332575e9461SMike Marshall 
333575e9461SMike Marshall 	int rc = -ENOMEM;
334575e9461SMike Marshall 	char *c_buffer = NULL;
335575e9461SMike Marshall 
336575e9461SMike Marshall 	gossip_debug(GOSSIP_DEBUGFS_DEBUG, "%s: start\n", __func__);
337575e9461SMike Marshall 
338575e9461SMike Marshall 	c_buffer = kzalloc(ORANGEFS_MAX_DEBUG_STRING_LEN, GFP_KERNEL);
339575e9461SMike Marshall 	if (!c_buffer)
340575e9461SMike Marshall 		goto out;
341575e9461SMike Marshall 
342575e9461SMike Marshall 	if (strlen(client_debug_string) + 1 < ORANGEFS_MAX_DEBUG_STRING_LEN) {
343575e9461SMike Marshall 		strcpy(c_buffer, client_debug_string);
344575e9461SMike Marshall 		strcat(c_buffer, "\n");
345575e9461SMike Marshall 	} else {
346575e9461SMike Marshall 		strcpy(c_buffer, "none\n");
347575e9461SMike Marshall 		pr_info("%s: overflow! 2\n", __func__);
348575e9461SMike Marshall 	}
349575e9461SMike Marshall 
350575e9461SMike Marshall 	client_debug_dentry = debugfs_create_file(ORANGEFS_CLIENT_DEBUG_FILE,
351575e9461SMike Marshall 						  0444,
352575e9461SMike Marshall 						  debug_dir,
353575e9461SMike Marshall 						  c_buffer,
354575e9461SMike Marshall 						  &kernel_debug_fops);
355575e9461SMike Marshall 	if (!client_debug_dentry) {
3562180c52cSMike Marshall 		pr_info("%s: failed to create updated %s.\n",
357575e9461SMike Marshall 			__func__,
358575e9461SMike Marshall 			ORANGEFS_CLIENT_DEBUG_FILE);
359575e9461SMike Marshall 		goto out;
360575e9461SMike Marshall 	}
361575e9461SMike Marshall 
362575e9461SMike Marshall 	rc = 0;
363575e9461SMike Marshall 
364575e9461SMike Marshall out:
365575e9461SMike Marshall 
366575e9461SMike Marshall 	gossip_debug(GOSSIP_DEBUGFS_DEBUG, "%s: rc:%d:\n", __func__, rc);
367575e9461SMike Marshall 	return rc;
368575e9461SMike Marshall }
369575e9461SMike Marshall 
370575e9461SMike Marshall /* open ORANGEFS_KMOD_DEBUG_FILE or ORANGEFS_CLIENT_DEBUG_FILE.*/
37144f46410SMartin Brandenburg static int orangefs_debug_open(struct inode *inode, struct file *file)
372575e9461SMike Marshall {
373575e9461SMike Marshall 	int rc = -ENODEV;
374575e9461SMike Marshall 
375575e9461SMike Marshall 	gossip_debug(GOSSIP_DEBUGFS_DEBUG,
376575e9461SMike Marshall 		     "%s: orangefs_debug_disabled: %d\n",
377575e9461SMike Marshall 		     __func__,
378575e9461SMike Marshall 		     orangefs_debug_disabled);
379575e9461SMike Marshall 
380575e9461SMike Marshall 	if (orangefs_debug_disabled)
381575e9461SMike Marshall 		goto out;
382575e9461SMike Marshall 
383575e9461SMike Marshall 	rc = 0;
384575e9461SMike Marshall 	mutex_lock(&orangefs_debug_lock);
385575e9461SMike Marshall 	file->private_data = inode->i_private;
386575e9461SMike Marshall 	mutex_unlock(&orangefs_debug_lock);
387575e9461SMike Marshall 
388575e9461SMike Marshall out:
389575e9461SMike Marshall 	gossip_debug(GOSSIP_DEBUGFS_DEBUG,
390575e9461SMike Marshall 		     "orangefs_debug_open: rc: %d\n",
391575e9461SMike Marshall 		     rc);
392575e9461SMike Marshall 	return rc;
393575e9461SMike Marshall }
394575e9461SMike Marshall 
395575e9461SMike Marshall static ssize_t orangefs_debug_read(struct file *file,
396575e9461SMike Marshall 				 char __user *ubuf,
397575e9461SMike Marshall 				 size_t count,
398575e9461SMike Marshall 				 loff_t *ppos)
399575e9461SMike Marshall {
400575e9461SMike Marshall 	char *buf;
401575e9461SMike Marshall 	int sprintf_ret;
402575e9461SMike Marshall 	ssize_t read_ret = -ENOMEM;
403575e9461SMike Marshall 
404575e9461SMike Marshall 	gossip_debug(GOSSIP_DEBUGFS_DEBUG, "orangefs_debug_read: start\n");
405575e9461SMike Marshall 
406575e9461SMike Marshall 	buf = kmalloc(ORANGEFS_MAX_DEBUG_STRING_LEN, GFP_KERNEL);
407575e9461SMike Marshall 	if (!buf)
408575e9461SMike Marshall 		goto out;
409575e9461SMike Marshall 
410575e9461SMike Marshall 	mutex_lock(&orangefs_debug_lock);
411575e9461SMike Marshall 	sprintf_ret = sprintf(buf, "%s", (char *)file->private_data);
412575e9461SMike Marshall 	mutex_unlock(&orangefs_debug_lock);
413575e9461SMike Marshall 
414575e9461SMike Marshall 	read_ret = simple_read_from_buffer(ubuf, count, ppos, buf, sprintf_ret);
415575e9461SMike Marshall 
416575e9461SMike Marshall 	kfree(buf);
417575e9461SMike Marshall 
418575e9461SMike Marshall out:
419575e9461SMike Marshall 	gossip_debug(GOSSIP_DEBUGFS_DEBUG,
420575e9461SMike Marshall 		     "orangefs_debug_read: ret: %zu\n",
421575e9461SMike Marshall 		     read_ret);
422575e9461SMike Marshall 
423575e9461SMike Marshall 	return read_ret;
424575e9461SMike Marshall }
425575e9461SMike Marshall 
426575e9461SMike Marshall static ssize_t orangefs_debug_write(struct file *file,
427575e9461SMike Marshall 				  const char __user *ubuf,
428575e9461SMike Marshall 				  size_t count,
429575e9461SMike Marshall 				  loff_t *ppos)
430575e9461SMike Marshall {
431575e9461SMike Marshall 	char *buf;
432575e9461SMike Marshall 	int rc = -EFAULT;
433575e9461SMike Marshall 	size_t silly = 0;
434575e9461SMike Marshall 	char *debug_string;
435575e9461SMike Marshall 	struct orangefs_kernel_op_s *new_op = NULL;
436575e9461SMike Marshall 	struct client_debug_mask c_mask = { NULL, 0, 0 };
437575e9461SMike Marshall 
438575e9461SMike Marshall 	gossip_debug(GOSSIP_DEBUGFS_DEBUG,
439f66debf1SAl Viro 		"orangefs_debug_write: %pD\n",
440f66debf1SAl Viro 		file);
441575e9461SMike Marshall 
442575e9461SMike Marshall 	/*
443575e9461SMike Marshall 	 * Thwart users who try to jamb a ridiculous number
444575e9461SMike Marshall 	 * of bytes into the debug file...
445575e9461SMike Marshall 	 */
446575e9461SMike Marshall 	if (count > ORANGEFS_MAX_DEBUG_STRING_LEN + 1) {
447575e9461SMike Marshall 		silly = count;
448575e9461SMike Marshall 		count = ORANGEFS_MAX_DEBUG_STRING_LEN + 1;
449575e9461SMike Marshall 	}
450575e9461SMike Marshall 
451dde58ca4SNicholas Mc Guire 	buf = kzalloc(ORANGEFS_MAX_DEBUG_STRING_LEN, GFP_KERNEL);
452575e9461SMike Marshall 	if (!buf)
453575e9461SMike Marshall 		goto out;
454575e9461SMike Marshall 
455575e9461SMike Marshall 	if (copy_from_user(buf, ubuf, count - 1)) {
456575e9461SMike Marshall 		gossip_debug(GOSSIP_DEBUGFS_DEBUG,
457575e9461SMike Marshall 			     "%s: copy_from_user failed!\n",
458575e9461SMike Marshall 			     __func__);
459575e9461SMike Marshall 		goto out;
460575e9461SMike Marshall 	}
461575e9461SMike Marshall 
462575e9461SMike Marshall 	/*
463575e9461SMike Marshall 	 * Map the keyword string from userspace into a valid debug mask.
464575e9461SMike Marshall 	 * The mapping process involves mapping the human-inputted string
465575e9461SMike Marshall 	 * into a valid mask, and then rebuilding the string from the
466575e9461SMike Marshall 	 * verified valid mask.
467575e9461SMike Marshall 	 *
468575e9461SMike Marshall 	 * A service operation is required to set a new client-side
469575e9461SMike Marshall 	 * debug mask.
470575e9461SMike Marshall 	 */
471575e9461SMike Marshall 	if (!strcmp(file->f_path.dentry->d_name.name,
472575e9461SMike Marshall 		    ORANGEFS_KMOD_DEBUG_FILE)) {
47344f46410SMartin Brandenburg 		debug_string_to_mask(buf, &orangefs_gossip_debug_mask, 0);
47444f46410SMartin Brandenburg 		debug_mask_to_string(&orangefs_gossip_debug_mask, 0);
475575e9461SMike Marshall 		debug_string = kernel_debug_string;
476575e9461SMike Marshall 		gossip_debug(GOSSIP_DEBUGFS_DEBUG,
477575e9461SMike Marshall 			     "New kernel debug string is %s\n",
478575e9461SMike Marshall 			     kernel_debug_string);
479575e9461SMike Marshall 	} else {
480575e9461SMike Marshall 		/* Can't reset client debug mask if client is not running. */
481575e9461SMike Marshall 		if (is_daemon_in_service()) {
482575e9461SMike Marshall 			pr_info("%s: Client not running :%d:\n",
483575e9461SMike Marshall 				__func__,
484575e9461SMike Marshall 				is_daemon_in_service());
485575e9461SMike Marshall 			goto out;
486575e9461SMike Marshall 		}
487575e9461SMike Marshall 
488575e9461SMike Marshall 		debug_string_to_mask(buf, &c_mask, 1);
489575e9461SMike Marshall 		debug_mask_to_string(&c_mask, 1);
490575e9461SMike Marshall 		debug_string = client_debug_string;
491575e9461SMike Marshall 
492575e9461SMike Marshall 		new_op = op_alloc(ORANGEFS_VFS_OP_PARAM);
493575e9461SMike Marshall 		if (!new_op) {
494575e9461SMike Marshall 			pr_info("%s: op_alloc failed!\n", __func__);
495575e9461SMike Marshall 			goto out;
496575e9461SMike Marshall 		}
497575e9461SMike Marshall 
498575e9461SMike Marshall 		new_op->upcall.req.param.op =
499575e9461SMike Marshall 			ORANGEFS_PARAM_REQUEST_OP_TWO_MASK_VALUES;
500575e9461SMike Marshall 		new_op->upcall.req.param.type = ORANGEFS_PARAM_REQUEST_SET;
501575e9461SMike Marshall 		memset(new_op->upcall.req.param.s_value,
502575e9461SMike Marshall 		       0,
503575e9461SMike Marshall 		       ORANGEFS_MAX_DEBUG_STRING_LEN);
504575e9461SMike Marshall 		sprintf(new_op->upcall.req.param.s_value,
505575e9461SMike Marshall 			"%llx %llx\n",
506575e9461SMike Marshall 			c_mask.mask1,
507575e9461SMike Marshall 			c_mask.mask2);
508575e9461SMike Marshall 
509575e9461SMike Marshall 		/* service_operation returns 0 on success... */
510575e9461SMike Marshall 		rc = service_operation(new_op,
511575e9461SMike Marshall 				       "orangefs_param",
512575e9461SMike Marshall 					ORANGEFS_OP_INTERRUPTIBLE);
513575e9461SMike Marshall 
514575e9461SMike Marshall 		if (rc)
515575e9461SMike Marshall 			gossip_debug(GOSSIP_DEBUGFS_DEBUG,
516575e9461SMike Marshall 				     "%s: service_operation failed! rc:%d:\n",
517575e9461SMike Marshall 				     __func__,
518575e9461SMike Marshall 				     rc);
519575e9461SMike Marshall 
520575e9461SMike Marshall 		op_release(new_op);
521575e9461SMike Marshall 	}
522575e9461SMike Marshall 
523575e9461SMike Marshall 	mutex_lock(&orangefs_debug_lock);
524575e9461SMike Marshall 	memset(file->f_inode->i_private, 0, ORANGEFS_MAX_DEBUG_STRING_LEN);
525575e9461SMike Marshall 	sprintf((char *)file->f_inode->i_private, "%s\n", debug_string);
526575e9461SMike Marshall 	mutex_unlock(&orangefs_debug_lock);
527575e9461SMike Marshall 
528575e9461SMike Marshall 	*ppos += count;
529575e9461SMike Marshall 	if (silly)
530575e9461SMike Marshall 		rc = silly;
531575e9461SMike Marshall 	else
532575e9461SMike Marshall 		rc = count;
533575e9461SMike Marshall 
534575e9461SMike Marshall out:
535575e9461SMike Marshall 	gossip_debug(GOSSIP_DEBUGFS_DEBUG,
536575e9461SMike Marshall 		     "orangefs_debug_write: rc: %d\n",
537575e9461SMike Marshall 		     rc);
538575e9461SMike Marshall 	kfree(buf);
539575e9461SMike Marshall 	return rc;
540575e9461SMike Marshall }
54144f46410SMartin Brandenburg 
54244f46410SMartin Brandenburg /*
54344f46410SMartin Brandenburg  * After obtaining a string representation of the client's debug
54444f46410SMartin Brandenburg  * keywords and their associated masks, this function is called to build an
54544f46410SMartin Brandenburg  * array of these values.
54644f46410SMartin Brandenburg  */
54744f46410SMartin Brandenburg static int orangefs_prepare_cdm_array(char *debug_array_string)
54844f46410SMartin Brandenburg {
54944f46410SMartin Brandenburg 	int i;
55044f46410SMartin Brandenburg 	int rc = -EINVAL;
55144f46410SMartin Brandenburg 	char *cds_head = NULL;
55244f46410SMartin Brandenburg 	char *cds_delimiter = NULL;
55344f46410SMartin Brandenburg 	int keyword_len = 0;
55444f46410SMartin Brandenburg 
55544f46410SMartin Brandenburg 	gossip_debug(GOSSIP_UTILS_DEBUG, "%s: start\n", __func__);
55644f46410SMartin Brandenburg 
55744f46410SMartin Brandenburg 	/*
55844f46410SMartin Brandenburg 	 * figure out how many elements the cdm_array needs.
55944f46410SMartin Brandenburg 	 */
56044f46410SMartin Brandenburg 	for (i = 0; i < strlen(debug_array_string); i++)
56144f46410SMartin Brandenburg 		if (debug_array_string[i] == '\n')
56244f46410SMartin Brandenburg 			cdm_element_count++;
56344f46410SMartin Brandenburg 
56444f46410SMartin Brandenburg 	if (!cdm_element_count) {
56544f46410SMartin Brandenburg 		pr_info("No elements in client debug array string!\n");
56644f46410SMartin Brandenburg 		goto out;
56744f46410SMartin Brandenburg 	}
56844f46410SMartin Brandenburg 
56944f46410SMartin Brandenburg 	cdm_array =
57044f46410SMartin Brandenburg 		kzalloc(cdm_element_count * sizeof(struct client_debug_mask),
57144f46410SMartin Brandenburg 			GFP_KERNEL);
57244f46410SMartin Brandenburg 	if (!cdm_array) {
57344f46410SMartin Brandenburg 		pr_info("malloc failed for cdm_array!\n");
57444f46410SMartin Brandenburg 		rc = -ENOMEM;
57544f46410SMartin Brandenburg 		goto out;
57644f46410SMartin Brandenburg 	}
57744f46410SMartin Brandenburg 
57844f46410SMartin Brandenburg 	cds_head = debug_array_string;
57944f46410SMartin Brandenburg 
58044f46410SMartin Brandenburg 	for (i = 0; i < cdm_element_count; i++) {
58144f46410SMartin Brandenburg 		cds_delimiter = strchr(cds_head, '\n');
58244f46410SMartin Brandenburg 		*cds_delimiter = '\0';
58344f46410SMartin Brandenburg 
58444f46410SMartin Brandenburg 		keyword_len = strcspn(cds_head, " ");
58544f46410SMartin Brandenburg 
58644f46410SMartin Brandenburg 		cdm_array[i].keyword = kzalloc(keyword_len + 1, GFP_KERNEL);
58744f46410SMartin Brandenburg 		if (!cdm_array[i].keyword) {
58844f46410SMartin Brandenburg 			rc = -ENOMEM;
58944f46410SMartin Brandenburg 			goto out;
59044f46410SMartin Brandenburg 		}
59144f46410SMartin Brandenburg 
59244f46410SMartin Brandenburg 		sscanf(cds_head,
59344f46410SMartin Brandenburg 		       "%s %llx %llx",
59444f46410SMartin Brandenburg 		       cdm_array[i].keyword,
59544f46410SMartin Brandenburg 		       (unsigned long long *)&(cdm_array[i].mask1),
59644f46410SMartin Brandenburg 		       (unsigned long long *)&(cdm_array[i].mask2));
59744f46410SMartin Brandenburg 
59844f46410SMartin Brandenburg 		if (!strcmp(cdm_array[i].keyword, ORANGEFS_VERBOSE))
59944f46410SMartin Brandenburg 			client_verbose_index = i;
60044f46410SMartin Brandenburg 
60144f46410SMartin Brandenburg 		if (!strcmp(cdm_array[i].keyword, ORANGEFS_ALL))
60244f46410SMartin Brandenburg 			client_all_index = i;
60344f46410SMartin Brandenburg 
60444f46410SMartin Brandenburg 		cds_head = cds_delimiter + 1;
60544f46410SMartin Brandenburg 	}
60644f46410SMartin Brandenburg 
60744f46410SMartin Brandenburg 	rc = cdm_element_count;
60844f46410SMartin Brandenburg 
60944f46410SMartin Brandenburg 	gossip_debug(GOSSIP_UTILS_DEBUG, "%s: rc:%d:\n", __func__, rc);
61044f46410SMartin Brandenburg 
61144f46410SMartin Brandenburg out:
61244f46410SMartin Brandenburg 
61344f46410SMartin Brandenburg 	return rc;
61444f46410SMartin Brandenburg 
61544f46410SMartin Brandenburg }
61644f46410SMartin Brandenburg 
61744f46410SMartin Brandenburg /*
61844f46410SMartin Brandenburg  * /sys/kernel/debug/orangefs/debug-help can be catted to
61944f46410SMartin Brandenburg  * see all the available kernel and client debug keywords.
62044f46410SMartin Brandenburg  *
621dc033621SMike Marshall  * When orangefs.ko initializes, we have no idea what keywords the
62244f46410SMartin Brandenburg  * client supports, nor their associated masks.
62344f46410SMartin Brandenburg  *
624dc033621SMike Marshall  * We pass through this function once at module-load and stamp a
62544f46410SMartin Brandenburg  * boilerplate "we don't know" message for the client in the
62644f46410SMartin Brandenburg  * debug-help file. We pass through here again when the client
62744f46410SMartin Brandenburg  * starts and then we can fill out the debug-help file fully.
62844f46410SMartin Brandenburg  *
62944f46410SMartin Brandenburg  * The client might be restarted any number of times between
630dc033621SMike Marshall  * module reloads, we only build the debug-help file the first time.
63144f46410SMartin Brandenburg  */
63244f46410SMartin Brandenburg int orangefs_prepare_debugfs_help_string(int at_boot)
63344f46410SMartin Brandenburg {
63444f46410SMartin Brandenburg 	char *client_title = "Client Debug Keywords:\n";
63544f46410SMartin Brandenburg 	char *kernel_title = "Kernel Debug Keywords:\n";
636dc033621SMike Marshall 	size_t string_size =  DEBUG_HELP_STRING_SIZE;
637dc033621SMike Marshall 	size_t result_size;
638dc033621SMike Marshall 	size_t i;
639dc033621SMike Marshall 	char *new;
640dc033621SMike Marshall 	int rc = -EINVAL;
64144f46410SMartin Brandenburg 
64244f46410SMartin Brandenburg 	gossip_debug(GOSSIP_UTILS_DEBUG, "%s: start\n", __func__);
64344f46410SMartin Brandenburg 
644dc033621SMike Marshall 	if (at_boot)
64544f46410SMartin Brandenburg 		client_title = HELP_STRING_UNINITIALIZED;
646dc033621SMike Marshall 
647dc033621SMike Marshall 	/* build a new debug_help_string. */
648dc033621SMike Marshall 	new = kzalloc(DEBUG_HELP_STRING_SIZE, GFP_KERNEL);
649dc033621SMike Marshall 	if (!new) {
650dc033621SMike Marshall 		rc = -ENOMEM;
651dc033621SMike Marshall 		goto out;
652dc033621SMike Marshall 	}
653dc033621SMike Marshall 
654dc033621SMike Marshall 	/*
655dc033621SMike Marshall 	 * strlcat(dst, src, size) will append at most
656dc033621SMike Marshall 	 * "size - strlen(dst) - 1" bytes of src onto dst,
657dc033621SMike Marshall 	 * null terminating the result, and return the total
658dc033621SMike Marshall 	 * length of the string it tried to create.
659dc033621SMike Marshall 	 *
660dc033621SMike Marshall 	 * We'll just plow through here building our new debug
661dc033621SMike Marshall 	 * help string and let strlcat take care of assuring that
662dc033621SMike Marshall 	 * dst doesn't overflow.
663dc033621SMike Marshall 	 */
664dc033621SMike Marshall 	strlcat(new, client_title, string_size);
665dc033621SMike Marshall 
666dc033621SMike Marshall 	if (!at_boot) {
667dc033621SMike Marshall 
66844f46410SMartin Brandenburg                 /*
66944f46410SMartin Brandenburg 		 * fill the client keyword/mask array and remember
67044f46410SMartin Brandenburg 		 * how many elements there were.
67144f46410SMartin Brandenburg 		 */
67244f46410SMartin Brandenburg 		cdm_element_count =
67344f46410SMartin Brandenburg 			orangefs_prepare_cdm_array(client_debug_array_string);
67444f46410SMartin Brandenburg 		if (cdm_element_count <= 0)
67544f46410SMartin Brandenburg 			goto out;
67644f46410SMartin Brandenburg 
67744f46410SMartin Brandenburg 		for (i = 0; i < cdm_element_count; i++) {
678dc033621SMike Marshall 			strlcat(new, "\t", string_size);
679dc033621SMike Marshall 			strlcat(new, cdm_array[i].keyword, string_size);
680dc033621SMike Marshall 			strlcat(new, "\n", string_size);
68144f46410SMartin Brandenburg 		}
68244f46410SMartin Brandenburg 	}
68344f46410SMartin Brandenburg 
684dc033621SMike Marshall 	strlcat(new, "\n", string_size);
685dc033621SMike Marshall 	strlcat(new, kernel_title, string_size);
68644f46410SMartin Brandenburg 
68744f46410SMartin Brandenburg 	for (i = 0; i < num_kmod_keyword_mask_map; i++) {
688dc033621SMike Marshall 		strlcat(new, "\t", string_size);
689dc033621SMike Marshall 		strlcat(new, s_kmod_keyword_mask_map[i].keyword, string_size);
690dc033621SMike Marshall 		result_size = strlcat(new, "\n", string_size);
691dc033621SMike Marshall 	}
692dc033621SMike Marshall 
693dc033621SMike Marshall 	/* See if we tried to put too many bytes into "new"... */
694dc033621SMike Marshall 	if (result_size >= string_size) {
695dc033621SMike Marshall 		kfree(new);
696dc033621SMike Marshall 		goto out;
697dc033621SMike Marshall 	}
698dc033621SMike Marshall 
699dc033621SMike Marshall 	if (at_boot) {
700dc033621SMike Marshall 		debug_help_string = new;
701dc033621SMike Marshall 	} else {
702dc033621SMike Marshall 		mutex_lock(&orangefs_help_file_lock);
703dc033621SMike Marshall 		memset(debug_help_string, 0, DEBUG_HELP_STRING_SIZE);
704dc033621SMike Marshall 		strlcat(debug_help_string, new, string_size);
705dc033621SMike Marshall 		mutex_unlock(&orangefs_help_file_lock);
70644f46410SMartin Brandenburg 	}
70744f46410SMartin Brandenburg 
70844f46410SMartin Brandenburg 	rc = 0;
70944f46410SMartin Brandenburg 
710dc033621SMike Marshall out:	return rc;
71144f46410SMartin Brandenburg 
71244f46410SMartin Brandenburg }
71344f46410SMartin Brandenburg 
71444f46410SMartin Brandenburg /*
71544f46410SMartin Brandenburg  * kernel = type 0
71644f46410SMartin Brandenburg  * client = type 1
71744f46410SMartin Brandenburg  */
71844f46410SMartin Brandenburg static void debug_mask_to_string(void *mask, int type)
71944f46410SMartin Brandenburg {
72044f46410SMartin Brandenburg 	int i;
72144f46410SMartin Brandenburg 	int len = 0;
72244f46410SMartin Brandenburg 	char *debug_string;
72344f46410SMartin Brandenburg 	int element_count = 0;
72444f46410SMartin Brandenburg 
72544f46410SMartin Brandenburg 	gossip_debug(GOSSIP_UTILS_DEBUG, "%s: start\n", __func__);
72644f46410SMartin Brandenburg 
72744f46410SMartin Brandenburg 	if (type) {
72844f46410SMartin Brandenburg 		debug_string = client_debug_string;
72944f46410SMartin Brandenburg 		element_count = cdm_element_count;
73044f46410SMartin Brandenburg 	} else {
73144f46410SMartin Brandenburg 		debug_string = kernel_debug_string;
73244f46410SMartin Brandenburg 		element_count = num_kmod_keyword_mask_map;
73344f46410SMartin Brandenburg 	}
73444f46410SMartin Brandenburg 
73544f46410SMartin Brandenburg 	memset(debug_string, 0, ORANGEFS_MAX_DEBUG_STRING_LEN);
73644f46410SMartin Brandenburg 
73744f46410SMartin Brandenburg 	/*
73844f46410SMartin Brandenburg 	 * Some keywords, like "all" or "verbose", are amalgams of
73944f46410SMartin Brandenburg 	 * numerous other keywords. Make a special check for those
74044f46410SMartin Brandenburg 	 * before grinding through the whole mask only to find out
74144f46410SMartin Brandenburg 	 * later...
74244f46410SMartin Brandenburg 	 */
74344f46410SMartin Brandenburg 	if (check_amalgam_keyword(mask, type))
74444f46410SMartin Brandenburg 		goto out;
74544f46410SMartin Brandenburg 
74644f46410SMartin Brandenburg 	/* Build the debug string. */
74744f46410SMartin Brandenburg 	for (i = 0; i < element_count; i++)
74844f46410SMartin Brandenburg 		if (type)
74944f46410SMartin Brandenburg 			do_c_string(mask, i);
75044f46410SMartin Brandenburg 		else
75144f46410SMartin Brandenburg 			do_k_string(mask, i);
75244f46410SMartin Brandenburg 
75344f46410SMartin Brandenburg 	len = strlen(debug_string);
75444f46410SMartin Brandenburg 
75544f46410SMartin Brandenburg 	if ((len) && (type))
75644f46410SMartin Brandenburg 		client_debug_string[len - 1] = '\0';
75744f46410SMartin Brandenburg 	else if (len)
75844f46410SMartin Brandenburg 		kernel_debug_string[len - 1] = '\0';
75944f46410SMartin Brandenburg 	else if (type)
76044f46410SMartin Brandenburg 		strcpy(client_debug_string, "none");
76144f46410SMartin Brandenburg 	else
76244f46410SMartin Brandenburg 		strcpy(kernel_debug_string, "none");
76344f46410SMartin Brandenburg 
76444f46410SMartin Brandenburg out:
76544f46410SMartin Brandenburg gossip_debug(GOSSIP_UTILS_DEBUG, "%s: string:%s:\n", __func__, debug_string);
76644f46410SMartin Brandenburg 
76744f46410SMartin Brandenburg 	return;
76844f46410SMartin Brandenburg 
76944f46410SMartin Brandenburg }
77044f46410SMartin Brandenburg 
77144f46410SMartin Brandenburg static void do_k_string(void *k_mask, int index)
77244f46410SMartin Brandenburg {
77344f46410SMartin Brandenburg 	__u64 *mask = (__u64 *) k_mask;
77444f46410SMartin Brandenburg 
77544f46410SMartin Brandenburg 	if (keyword_is_amalgam((char *) s_kmod_keyword_mask_map[index].keyword))
77644f46410SMartin Brandenburg 		goto out;
77744f46410SMartin Brandenburg 
77844f46410SMartin Brandenburg 	if (*mask & s_kmod_keyword_mask_map[index].mask_val) {
77944f46410SMartin Brandenburg 		if ((strlen(kernel_debug_string) +
78044f46410SMartin Brandenburg 		     strlen(s_kmod_keyword_mask_map[index].keyword))
78144f46410SMartin Brandenburg 			< ORANGEFS_MAX_DEBUG_STRING_LEN - 1) {
78244f46410SMartin Brandenburg 				strcat(kernel_debug_string,
78344f46410SMartin Brandenburg 				       s_kmod_keyword_mask_map[index].keyword);
78444f46410SMartin Brandenburg 				strcat(kernel_debug_string, ",");
78544f46410SMartin Brandenburg 			} else {
78644f46410SMartin Brandenburg 				gossip_err("%s: overflow!\n", __func__);
78744f46410SMartin Brandenburg 				strcpy(kernel_debug_string, ORANGEFS_ALL);
78844f46410SMartin Brandenburg 				goto out;
78944f46410SMartin Brandenburg 			}
79044f46410SMartin Brandenburg 	}
79144f46410SMartin Brandenburg 
79244f46410SMartin Brandenburg out:
79344f46410SMartin Brandenburg 
79444f46410SMartin Brandenburg 	return;
79544f46410SMartin Brandenburg }
79644f46410SMartin Brandenburg 
79744f46410SMartin Brandenburg static void do_c_string(void *c_mask, int index)
79844f46410SMartin Brandenburg {
79944f46410SMartin Brandenburg 	struct client_debug_mask *mask = (struct client_debug_mask *) c_mask;
80044f46410SMartin Brandenburg 
80144f46410SMartin Brandenburg 	if (keyword_is_amalgam(cdm_array[index].keyword))
80244f46410SMartin Brandenburg 		goto out;
80344f46410SMartin Brandenburg 
80444f46410SMartin Brandenburg 	if ((mask->mask1 & cdm_array[index].mask1) ||
80544f46410SMartin Brandenburg 	    (mask->mask2 & cdm_array[index].mask2)) {
80644f46410SMartin Brandenburg 		if ((strlen(client_debug_string) +
80744f46410SMartin Brandenburg 		     strlen(cdm_array[index].keyword) + 1)
80844f46410SMartin Brandenburg 			< ORANGEFS_MAX_DEBUG_STRING_LEN - 2) {
80944f46410SMartin Brandenburg 				strcat(client_debug_string,
81044f46410SMartin Brandenburg 				       cdm_array[index].keyword);
81144f46410SMartin Brandenburg 				strcat(client_debug_string, ",");
81244f46410SMartin Brandenburg 			} else {
81344f46410SMartin Brandenburg 				gossip_err("%s: overflow!\n", __func__);
81444f46410SMartin Brandenburg 				strcpy(client_debug_string, ORANGEFS_ALL);
81544f46410SMartin Brandenburg 				goto out;
81644f46410SMartin Brandenburg 			}
81744f46410SMartin Brandenburg 	}
81844f46410SMartin Brandenburg out:
81944f46410SMartin Brandenburg 	return;
82044f46410SMartin Brandenburg }
82144f46410SMartin Brandenburg 
82244f46410SMartin Brandenburg static int keyword_is_amalgam(char *keyword)
82344f46410SMartin Brandenburg {
82444f46410SMartin Brandenburg 	int rc = 0;
82544f46410SMartin Brandenburg 
82644f46410SMartin Brandenburg 	if ((!strcmp(keyword, ORANGEFS_ALL)) || (!strcmp(keyword, ORANGEFS_VERBOSE)))
82744f46410SMartin Brandenburg 		rc = 1;
82844f46410SMartin Brandenburg 
82944f46410SMartin Brandenburg 	return rc;
83044f46410SMartin Brandenburg }
83144f46410SMartin Brandenburg 
83244f46410SMartin Brandenburg /*
83344f46410SMartin Brandenburg  * kernel = type 0
83444f46410SMartin Brandenburg  * client = type 1
83544f46410SMartin Brandenburg  *
83644f46410SMartin Brandenburg  * return 1 if we found an amalgam.
83744f46410SMartin Brandenburg  */
83844f46410SMartin Brandenburg static int check_amalgam_keyword(void *mask, int type)
83944f46410SMartin Brandenburg {
84044f46410SMartin Brandenburg 	__u64 *k_mask;
84144f46410SMartin Brandenburg 	struct client_debug_mask *c_mask;
84244f46410SMartin Brandenburg 	int k_all_index = num_kmod_keyword_mask_map - 1;
84344f46410SMartin Brandenburg 	int rc = 0;
84444f46410SMartin Brandenburg 
84544f46410SMartin Brandenburg 	if (type) {
84644f46410SMartin Brandenburg 		c_mask = (struct client_debug_mask *) mask;
84744f46410SMartin Brandenburg 
84844f46410SMartin Brandenburg 		if ((c_mask->mask1 == cdm_array[client_all_index].mask1) &&
84944f46410SMartin Brandenburg 		    (c_mask->mask2 == cdm_array[client_all_index].mask2)) {
85044f46410SMartin Brandenburg 			strcpy(client_debug_string, ORANGEFS_ALL);
85144f46410SMartin Brandenburg 			rc = 1;
85244f46410SMartin Brandenburg 			goto out;
85344f46410SMartin Brandenburg 		}
85444f46410SMartin Brandenburg 
85544f46410SMartin Brandenburg 		if ((c_mask->mask1 == cdm_array[client_verbose_index].mask1) &&
85644f46410SMartin Brandenburg 		    (c_mask->mask2 == cdm_array[client_verbose_index].mask2)) {
85744f46410SMartin Brandenburg 			strcpy(client_debug_string, ORANGEFS_VERBOSE);
85844f46410SMartin Brandenburg 			rc = 1;
85944f46410SMartin Brandenburg 			goto out;
86044f46410SMartin Brandenburg 		}
86144f46410SMartin Brandenburg 
86244f46410SMartin Brandenburg 	} else {
86344f46410SMartin Brandenburg 		k_mask = (__u64 *) mask;
86444f46410SMartin Brandenburg 
86544f46410SMartin Brandenburg 		if (*k_mask >= s_kmod_keyword_mask_map[k_all_index].mask_val) {
86644f46410SMartin Brandenburg 			strcpy(kernel_debug_string, ORANGEFS_ALL);
86744f46410SMartin Brandenburg 			rc = 1;
86844f46410SMartin Brandenburg 			goto out;
86944f46410SMartin Brandenburg 		}
87044f46410SMartin Brandenburg 	}
87144f46410SMartin Brandenburg 
87244f46410SMartin Brandenburg out:
87344f46410SMartin Brandenburg 
87444f46410SMartin Brandenburg 	return rc;
87544f46410SMartin Brandenburg }
87644f46410SMartin Brandenburg 
87744f46410SMartin Brandenburg /*
87844f46410SMartin Brandenburg  * kernel = type 0
87944f46410SMartin Brandenburg  * client = type 1
88044f46410SMartin Brandenburg  */
88144f46410SMartin Brandenburg static void debug_string_to_mask(char *debug_string, void *mask, int type)
88244f46410SMartin Brandenburg {
88344f46410SMartin Brandenburg 	char *unchecked_keyword;
88444f46410SMartin Brandenburg 	int i;
88544f46410SMartin Brandenburg 	char *strsep_fodder = kstrdup(debug_string, GFP_KERNEL);
88644f46410SMartin Brandenburg 	char *original_pointer;
88744f46410SMartin Brandenburg 	int element_count = 0;
88844f46410SMartin Brandenburg 	struct client_debug_mask *c_mask = NULL;
88944f46410SMartin Brandenburg 	__u64 *k_mask = NULL;
89044f46410SMartin Brandenburg 
89144f46410SMartin Brandenburg 	gossip_debug(GOSSIP_UTILS_DEBUG, "%s: start\n", __func__);
89244f46410SMartin Brandenburg 
89344f46410SMartin Brandenburg 	if (type) {
89444f46410SMartin Brandenburg 		c_mask = (struct client_debug_mask *)mask;
89544f46410SMartin Brandenburg 		element_count = cdm_element_count;
89644f46410SMartin Brandenburg 	} else {
89744f46410SMartin Brandenburg 		k_mask = (__u64 *)mask;
89844f46410SMartin Brandenburg 		*k_mask = 0;
89944f46410SMartin Brandenburg 		element_count = num_kmod_keyword_mask_map;
90044f46410SMartin Brandenburg 	}
90144f46410SMartin Brandenburg 
90244f46410SMartin Brandenburg 	original_pointer = strsep_fodder;
90344f46410SMartin Brandenburg 	while ((unchecked_keyword = strsep(&strsep_fodder, ",")))
90444f46410SMartin Brandenburg 		if (strlen(unchecked_keyword)) {
90544f46410SMartin Brandenburg 			for (i = 0; i < element_count; i++)
90644f46410SMartin Brandenburg 				if (type)
90744f46410SMartin Brandenburg 					do_c_mask(i,
90844f46410SMartin Brandenburg 						  unchecked_keyword,
90944f46410SMartin Brandenburg 						  &c_mask);
91044f46410SMartin Brandenburg 				else
91144f46410SMartin Brandenburg 					do_k_mask(i,
91244f46410SMartin Brandenburg 						  unchecked_keyword,
91344f46410SMartin Brandenburg 						  &k_mask);
91444f46410SMartin Brandenburg 		}
91544f46410SMartin Brandenburg 
91644f46410SMartin Brandenburg 	kfree(original_pointer);
91744f46410SMartin Brandenburg }
91844f46410SMartin Brandenburg 
91944f46410SMartin Brandenburg static void do_c_mask(int i, char *unchecked_keyword,
92044f46410SMartin Brandenburg     struct client_debug_mask **sane_mask)
92144f46410SMartin Brandenburg {
92244f46410SMartin Brandenburg 
92344f46410SMartin Brandenburg 	if (!strcmp(cdm_array[i].keyword, unchecked_keyword)) {
92444f46410SMartin Brandenburg 		(**sane_mask).mask1 = (**sane_mask).mask1 | cdm_array[i].mask1;
92544f46410SMartin Brandenburg 		(**sane_mask).mask2 = (**sane_mask).mask2 | cdm_array[i].mask2;
92644f46410SMartin Brandenburg 	}
92744f46410SMartin Brandenburg }
92844f46410SMartin Brandenburg 
92944f46410SMartin Brandenburg static void do_k_mask(int i, char *unchecked_keyword, __u64 **sane_mask)
93044f46410SMartin Brandenburg {
93144f46410SMartin Brandenburg 
93244f46410SMartin Brandenburg 	if (!strcmp(s_kmod_keyword_mask_map[i].keyword, unchecked_keyword))
93344f46410SMartin Brandenburg 		**sane_mask = (**sane_mask) |
93444f46410SMartin Brandenburg 				s_kmod_keyword_mask_map[i].mask_val;
93544f46410SMartin Brandenburg }
93644f46410SMartin Brandenburg 
93744f46410SMartin Brandenburg int orangefs_debugfs_new_client_mask(void __user *arg)
93844f46410SMartin Brandenburg {
93944f46410SMartin Brandenburg 	struct dev_mask2_info_s mask2_info = {0};
94044f46410SMartin Brandenburg 	int ret;
94144f46410SMartin Brandenburg 
94244f46410SMartin Brandenburg 	ret = copy_from_user(&mask2_info,
94344f46410SMartin Brandenburg 			     (void __user *)arg,
94444f46410SMartin Brandenburg 			     sizeof(struct dev_mask2_info_s));
94544f46410SMartin Brandenburg 
94644f46410SMartin Brandenburg 	if (ret != 0)
94744f46410SMartin Brandenburg 		return -EIO;
94844f46410SMartin Brandenburg 
94944f46410SMartin Brandenburg 	client_debug_mask.mask1 = mask2_info.mask1_value;
95044f46410SMartin Brandenburg 	client_debug_mask.mask2 = mask2_info.mask2_value;
95144f46410SMartin Brandenburg 
95244f46410SMartin Brandenburg 	pr_info("%s: client debug mask has been been received "
95344f46410SMartin Brandenburg 		":%llx: :%llx:\n",
95444f46410SMartin Brandenburg 		__func__,
95544f46410SMartin Brandenburg 		(unsigned long long)client_debug_mask.mask1,
95644f46410SMartin Brandenburg 		(unsigned long long)client_debug_mask.mask2);
95744f46410SMartin Brandenburg 
95844f46410SMartin Brandenburg 	return ret;
95944f46410SMartin Brandenburg }
96044f46410SMartin Brandenburg 
96144f46410SMartin Brandenburg int orangefs_debugfs_new_client_string(void __user *arg)
96244f46410SMartin Brandenburg {
96344f46410SMartin Brandenburg 	int ret;
96444f46410SMartin Brandenburg 
96544f46410SMartin Brandenburg 	ret = copy_from_user(&client_debug_array_string,
96644f46410SMartin Brandenburg                                      (void __user *)arg,
96744f46410SMartin Brandenburg                                      ORANGEFS_MAX_DEBUG_STRING_LEN);
968dc033621SMike Marshall 
969dc033621SMike Marshall 	if (ret != 0) {
970dc033621SMike Marshall 		pr_info("%s: CLIENT_STRING: copy_from_user failed\n",
971dc033621SMike Marshall 			__func__);
97244f46410SMartin Brandenburg 		return -EIO;
973dc033621SMike Marshall 	}
97444f46410SMartin Brandenburg 
97544f46410SMartin Brandenburg 	/*
97644f46410SMartin Brandenburg 	 * The real client-core makes an effort to ensure
97744f46410SMartin Brandenburg 	 * that actual strings that aren't too long to fit in
97844f46410SMartin Brandenburg 	 * this buffer is what we get here. We're going to use
97944f46410SMartin Brandenburg 	 * string functions on the stuff we got, so we'll make
98044f46410SMartin Brandenburg 	 * this extra effort to try and keep from
98144f46410SMartin Brandenburg 	 * flowing out of this buffer when we use the string
98244f46410SMartin Brandenburg 	 * functions, even if somehow the stuff we end up
98344f46410SMartin Brandenburg 	 * with here is garbage.
98444f46410SMartin Brandenburg 	 */
98544f46410SMartin Brandenburg 	client_debug_array_string[ORANGEFS_MAX_DEBUG_STRING_LEN - 1] =
98644f46410SMartin Brandenburg 		'\0';
98744f46410SMartin Brandenburg 
98844f46410SMartin Brandenburg 	pr_info("%s: client debug array string has been received.\n",
98944f46410SMartin Brandenburg 		__func__);
99044f46410SMartin Brandenburg 
99144f46410SMartin Brandenburg 	if (!help_string_initialized) {
99244f46410SMartin Brandenburg 
993dc033621SMike Marshall 		/* Build a proper debug help string. */
99444f46410SMartin Brandenburg 		if (orangefs_prepare_debugfs_help_string(0)) {
99544f46410SMartin Brandenburg 			gossip_err("%s: no debug help string \n",
99644f46410SMartin Brandenburg 				   __func__);
99744f46410SMartin Brandenburg 			return -EIO;
99844f46410SMartin Brandenburg 		}
99944f46410SMartin Brandenburg 
100044f46410SMartin Brandenburg 	}
100144f46410SMartin Brandenburg 
100244f46410SMartin Brandenburg 	debug_mask_to_string(&client_debug_mask, 1);
100344f46410SMartin Brandenburg 
100444f46410SMartin Brandenburg 	debugfs_remove(client_debug_dentry);
100544f46410SMartin Brandenburg 
100644f46410SMartin Brandenburg 	orangefs_client_debug_init();
100744f46410SMartin Brandenburg 
100844f46410SMartin Brandenburg 	help_string_initialized++;
100944f46410SMartin Brandenburg 
101044f46410SMartin Brandenburg 	return ret;
101144f46410SMartin Brandenburg }
101244f46410SMartin Brandenburg 
101344f46410SMartin Brandenburg int orangefs_debugfs_new_debug(void __user *arg)
101444f46410SMartin Brandenburg {
101544f46410SMartin Brandenburg 	struct dev_mask_info_s mask_info = {0};
101644f46410SMartin Brandenburg 	int ret;
101744f46410SMartin Brandenburg 
101844f46410SMartin Brandenburg 	ret = copy_from_user(&mask_info,
101944f46410SMartin Brandenburg 			     (void __user *)arg,
102044f46410SMartin Brandenburg 			     sizeof(mask_info));
102144f46410SMartin Brandenburg 
102244f46410SMartin Brandenburg 	if (ret != 0)
102344f46410SMartin Brandenburg 		return -EIO;
102444f46410SMartin Brandenburg 
102544f46410SMartin Brandenburg 	if (mask_info.mask_type == KERNEL_MASK) {
102644f46410SMartin Brandenburg 		if ((mask_info.mask_value == 0)
102744f46410SMartin Brandenburg 		    && (kernel_mask_set_mod_init)) {
102844f46410SMartin Brandenburg 			/*
102944f46410SMartin Brandenburg 			 * the kernel debug mask was set when the
103044f46410SMartin Brandenburg 			 * kernel module was loaded; don't override
103144f46410SMartin Brandenburg 			 * it if the client-core was started without
103244f46410SMartin Brandenburg 			 * a value for ORANGEFS_KMODMASK.
103344f46410SMartin Brandenburg 			 */
103444f46410SMartin Brandenburg 			return 0;
103544f46410SMartin Brandenburg 		}
103644f46410SMartin Brandenburg 		debug_mask_to_string(&mask_info.mask_value,
103744f46410SMartin Brandenburg 				     mask_info.mask_type);
103844f46410SMartin Brandenburg 		orangefs_gossip_debug_mask = mask_info.mask_value;
103944f46410SMartin Brandenburg 		pr_info("%s: kernel debug mask has been modified to "
104044f46410SMartin Brandenburg 			":%s: :%llx:\n",
104144f46410SMartin Brandenburg 			__func__,
104244f46410SMartin Brandenburg 			kernel_debug_string,
104344f46410SMartin Brandenburg 			(unsigned long long)orangefs_gossip_debug_mask);
104444f46410SMartin Brandenburg 	} else if (mask_info.mask_type == CLIENT_MASK) {
104544f46410SMartin Brandenburg 		debug_mask_to_string(&mask_info.mask_value,
104644f46410SMartin Brandenburg 				     mask_info.mask_type);
104744f46410SMartin Brandenburg 		pr_info("%s: client debug mask has been modified to"
104844f46410SMartin Brandenburg 			":%s: :%llx:\n",
104944f46410SMartin Brandenburg 			__func__,
105044f46410SMartin Brandenburg 			client_debug_string,
105144f46410SMartin Brandenburg 			llu(mask_info.mask_value));
105244f46410SMartin Brandenburg 	} else {
105344f46410SMartin Brandenburg 		gossip_lerr("Invalid mask type....\n");
105444f46410SMartin Brandenburg 		return -EINVAL;
105544f46410SMartin Brandenburg 	}
105644f46410SMartin Brandenburg 
105744f46410SMartin Brandenburg 	return ret;
105844f46410SMartin Brandenburg }
1059