162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * What:		/sys/kernel/debug/orangefs/debug-help
462306a36Sopenharmony_ci * Date:		June 2015
562306a36Sopenharmony_ci * Contact:		Mike Marshall <hubcap@omnibond.com>
662306a36Sopenharmony_ci * Description:
762306a36Sopenharmony_ci * 			List of client and kernel debug keywords.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * What:		/sys/kernel/debug/orangefs/client-debug
1162306a36Sopenharmony_ci * Date:		June 2015
1262306a36Sopenharmony_ci * Contact:		Mike Marshall <hubcap@omnibond.com>
1362306a36Sopenharmony_ci * Description:
1462306a36Sopenharmony_ci * 			Debug setting for "the client", the userspace
1562306a36Sopenharmony_ci * 			helper for the kernel module.
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci * What:		/sys/kernel/debug/orangefs/kernel-debug
1962306a36Sopenharmony_ci * Date:		June 2015
2062306a36Sopenharmony_ci * Contact:		Mike Marshall <hubcap@omnibond.com>
2162306a36Sopenharmony_ci * Description:
2262306a36Sopenharmony_ci * 			Debug setting for the orangefs kernel module.
2362306a36Sopenharmony_ci *
2462306a36Sopenharmony_ci * 			Any of the keywords, or comma-separated lists
2562306a36Sopenharmony_ci * 			of keywords, from debug-help can be catted to
2662306a36Sopenharmony_ci * 			client-debug or kernel-debug.
2762306a36Sopenharmony_ci *
2862306a36Sopenharmony_ci * 			"none", "all" and "verbose" are special keywords
2962306a36Sopenharmony_ci * 			for client-debug. Setting client-debug to "all"
3062306a36Sopenharmony_ci * 			is kind of like trying to drink water from a
3162306a36Sopenharmony_ci * 			fire hose, "verbose" triggers most of the same
3262306a36Sopenharmony_ci * 			output except for the constant flow of output
3362306a36Sopenharmony_ci * 			from the main wait loop.
3462306a36Sopenharmony_ci *
3562306a36Sopenharmony_ci * 			"none" and "all" are similar settings for kernel-debug
3662306a36Sopenharmony_ci * 			no need for a "verbose".
3762306a36Sopenharmony_ci */
3862306a36Sopenharmony_ci#include <linux/debugfs.h>
3962306a36Sopenharmony_ci#include <linux/slab.h>
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#include <linux/uaccess.h>
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#include "orangefs-debugfs.h"
4462306a36Sopenharmony_ci#include "protocol.h"
4562306a36Sopenharmony_ci#include "orangefs-kernel.h"
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#define DEBUG_HELP_STRING_SIZE 4096
4862306a36Sopenharmony_ci#define HELP_STRING_UNINITIALIZED \
4962306a36Sopenharmony_ci	"Client Debug Keywords are unknown until the first time\n" \
5062306a36Sopenharmony_ci	"the client is started after boot.\n"
5162306a36Sopenharmony_ci#define ORANGEFS_KMOD_DEBUG_HELP_FILE "debug-help"
5262306a36Sopenharmony_ci#define ORANGEFS_KMOD_DEBUG_FILE "kernel-debug"
5362306a36Sopenharmony_ci#define ORANGEFS_CLIENT_DEBUG_FILE "client-debug"
5462306a36Sopenharmony_ci#define ORANGEFS_VERBOSE "verbose"
5562306a36Sopenharmony_ci#define ORANGEFS_ALL "all"
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci/*
5862306a36Sopenharmony_ci * An array of client_debug_mask will be built to hold debug keyword/mask
5962306a36Sopenharmony_ci * values fetched from userspace.
6062306a36Sopenharmony_ci */
6162306a36Sopenharmony_cistruct client_debug_mask {
6262306a36Sopenharmony_ci	char *keyword;
6362306a36Sopenharmony_ci	__u64 mask1;
6462306a36Sopenharmony_ci	__u64 mask2;
6562306a36Sopenharmony_ci};
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic void orangefs_kernel_debug_init(void);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic int orangefs_debug_help_open(struct inode *, struct file *);
7062306a36Sopenharmony_cistatic void *help_start(struct seq_file *, loff_t *);
7162306a36Sopenharmony_cistatic void *help_next(struct seq_file *, void *, loff_t *);
7262306a36Sopenharmony_cistatic void help_stop(struct seq_file *, void *);
7362306a36Sopenharmony_cistatic int help_show(struct seq_file *, void *);
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic int orangefs_debug_open(struct inode *, struct file *);
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic ssize_t orangefs_debug_read(struct file *,
7862306a36Sopenharmony_ci				 char __user *,
7962306a36Sopenharmony_ci				 size_t,
8062306a36Sopenharmony_ci				 loff_t *);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistatic ssize_t orangefs_debug_write(struct file *,
8362306a36Sopenharmony_ci				  const char __user *,
8462306a36Sopenharmony_ci				  size_t,
8562306a36Sopenharmony_ci				  loff_t *);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistatic int orangefs_prepare_cdm_array(char *);
8862306a36Sopenharmony_cistatic void debug_mask_to_string(void *, int);
8962306a36Sopenharmony_cistatic void do_k_string(void *, int);
9062306a36Sopenharmony_cistatic void do_c_string(void *, int);
9162306a36Sopenharmony_cistatic int keyword_is_amalgam(char *);
9262306a36Sopenharmony_cistatic int check_amalgam_keyword(void *, int);
9362306a36Sopenharmony_cistatic void debug_string_to_mask(char *, void *, int);
9462306a36Sopenharmony_cistatic void do_c_mask(int, char *, struct client_debug_mask **);
9562306a36Sopenharmony_cistatic void do_k_mask(int, char *, __u64 **);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic char kernel_debug_string[ORANGEFS_MAX_DEBUG_STRING_LEN] = "none";
9862306a36Sopenharmony_cistatic char *debug_help_string;
9962306a36Sopenharmony_cistatic char client_debug_string[ORANGEFS_MAX_DEBUG_STRING_LEN];
10062306a36Sopenharmony_cistatic char client_debug_array_string[ORANGEFS_MAX_DEBUG_STRING_LEN];
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic struct dentry *client_debug_dentry;
10362306a36Sopenharmony_cistatic struct dentry *debug_dir;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic unsigned int kernel_mask_set_mod_init;
10662306a36Sopenharmony_cistatic int orangefs_debug_disabled = 1;
10762306a36Sopenharmony_cistatic int help_string_initialized;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_cistatic const struct seq_operations help_debug_ops = {
11062306a36Sopenharmony_ci	.start	= help_start,
11162306a36Sopenharmony_ci	.next	= help_next,
11262306a36Sopenharmony_ci	.stop	= help_stop,
11362306a36Sopenharmony_ci	.show	= help_show,
11462306a36Sopenharmony_ci};
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic const struct file_operations debug_help_fops = {
11762306a36Sopenharmony_ci	.owner		= THIS_MODULE,
11862306a36Sopenharmony_ci	.open           = orangefs_debug_help_open,
11962306a36Sopenharmony_ci	.read           = seq_read,
12062306a36Sopenharmony_ci	.release        = seq_release,
12162306a36Sopenharmony_ci	.llseek         = seq_lseek,
12262306a36Sopenharmony_ci};
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic const struct file_operations kernel_debug_fops = {
12562306a36Sopenharmony_ci	.owner		= THIS_MODULE,
12662306a36Sopenharmony_ci	.open           = orangefs_debug_open,
12762306a36Sopenharmony_ci	.read           = orangefs_debug_read,
12862306a36Sopenharmony_ci	.write		= orangefs_debug_write,
12962306a36Sopenharmony_ci	.llseek         = generic_file_llseek,
13062306a36Sopenharmony_ci};
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistatic int client_all_index;
13362306a36Sopenharmony_cistatic int client_verbose_index;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic struct client_debug_mask *cdm_array;
13662306a36Sopenharmony_cistatic int cdm_element_count;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_cistatic struct client_debug_mask client_debug_mask;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci/*
14162306a36Sopenharmony_ci * Used to protect data in ORANGEFS_KMOD_DEBUG_FILE and
14262306a36Sopenharmony_ci * ORANGEFS_KMOD_DEBUG_FILE.
14362306a36Sopenharmony_ci */
14462306a36Sopenharmony_cistatic DEFINE_MUTEX(orangefs_debug_lock);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci/* Used to protect data in ORANGEFS_KMOD_DEBUG_HELP_FILE */
14762306a36Sopenharmony_cistatic DEFINE_MUTEX(orangefs_help_file_lock);
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci/*
15062306a36Sopenharmony_ci * initialize kmod debug operations, create orangefs debugfs dir and
15162306a36Sopenharmony_ci * ORANGEFS_KMOD_DEBUG_HELP_FILE.
15262306a36Sopenharmony_ci */
15362306a36Sopenharmony_civoid orangefs_debugfs_init(int debug_mask)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	/* convert input debug mask to a 64-bit unsigned integer */
15662306a36Sopenharmony_ci        orangefs_gossip_debug_mask = (unsigned long long)debug_mask;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	/*
15962306a36Sopenharmony_ci	 * set the kernel's gossip debug string; invalid mask values will
16062306a36Sopenharmony_ci	 * be ignored.
16162306a36Sopenharmony_ci	 */
16262306a36Sopenharmony_ci	debug_mask_to_string(&orangefs_gossip_debug_mask, 0);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	/* remove any invalid values from the mask */
16562306a36Sopenharmony_ci	debug_string_to_mask(kernel_debug_string, &orangefs_gossip_debug_mask,
16662306a36Sopenharmony_ci	    0);
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	/*
16962306a36Sopenharmony_ci	 * if the mask has a non-zero value, then indicate that the mask
17062306a36Sopenharmony_ci	 * was set when the kernel module was loaded.  The orangefs dev ioctl
17162306a36Sopenharmony_ci	 * command will look at this boolean to determine if the kernel's
17262306a36Sopenharmony_ci	 * debug mask should be overwritten when the client-core is started.
17362306a36Sopenharmony_ci	 */
17462306a36Sopenharmony_ci	if (orangefs_gossip_debug_mask != 0)
17562306a36Sopenharmony_ci		kernel_mask_set_mod_init = true;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	pr_info("%s: called with debug mask: :%s: :%llx:\n",
17862306a36Sopenharmony_ci		__func__,
17962306a36Sopenharmony_ci		kernel_debug_string,
18062306a36Sopenharmony_ci		(unsigned long long)orangefs_gossip_debug_mask);
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	debug_dir = debugfs_create_dir("orangefs", NULL);
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	debugfs_create_file(ORANGEFS_KMOD_DEBUG_HELP_FILE, 0444, debug_dir,
18562306a36Sopenharmony_ci			    debug_help_string, &debug_help_fops);
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	orangefs_debug_disabled = 0;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	orangefs_kernel_debug_init();
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci/*
19362306a36Sopenharmony_ci * initialize the kernel-debug file.
19462306a36Sopenharmony_ci */
19562306a36Sopenharmony_cistatic void orangefs_kernel_debug_init(void)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	static char k_buffer[ORANGEFS_MAX_DEBUG_STRING_LEN] = { };
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	gossip_debug(GOSSIP_DEBUGFS_DEBUG, "%s: start\n", __func__);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	if (strlen(kernel_debug_string) + 1 < ORANGEFS_MAX_DEBUG_STRING_LEN) {
20262306a36Sopenharmony_ci		strcpy(k_buffer, kernel_debug_string);
20362306a36Sopenharmony_ci		strcat(k_buffer, "\n");
20462306a36Sopenharmony_ci	} else {
20562306a36Sopenharmony_ci		strcpy(k_buffer, "none\n");
20662306a36Sopenharmony_ci		pr_info("%s: overflow 1!\n", __func__);
20762306a36Sopenharmony_ci	}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	debugfs_create_file(ORANGEFS_KMOD_DEBUG_FILE, 0444, debug_dir, k_buffer,
21062306a36Sopenharmony_ci			    &kernel_debug_fops);
21162306a36Sopenharmony_ci}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_civoid orangefs_debugfs_cleanup(void)
21562306a36Sopenharmony_ci{
21662306a36Sopenharmony_ci	debugfs_remove_recursive(debug_dir);
21762306a36Sopenharmony_ci	kfree(debug_help_string);
21862306a36Sopenharmony_ci	debug_help_string = NULL;
21962306a36Sopenharmony_ci}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci/* open ORANGEFS_KMOD_DEBUG_HELP_FILE */
22262306a36Sopenharmony_cistatic int orangefs_debug_help_open(struct inode *inode, struct file *file)
22362306a36Sopenharmony_ci{
22462306a36Sopenharmony_ci	int rc = -ENODEV;
22562306a36Sopenharmony_ci	int ret;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	gossip_debug(GOSSIP_DEBUGFS_DEBUG,
22862306a36Sopenharmony_ci		     "orangefs_debug_help_open: start\n");
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	if (orangefs_debug_disabled)
23162306a36Sopenharmony_ci		goto out;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	ret = seq_open(file, &help_debug_ops);
23462306a36Sopenharmony_ci	if (ret)
23562306a36Sopenharmony_ci		goto out;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	((struct seq_file *)(file->private_data))->private = inode->i_private;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	rc = 0;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ciout:
24262306a36Sopenharmony_ci	gossip_debug(GOSSIP_DEBUGFS_DEBUG,
24362306a36Sopenharmony_ci		     "orangefs_debug_help_open: rc:%d:\n",
24462306a36Sopenharmony_ci		     rc);
24562306a36Sopenharmony_ci	return rc;
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci/*
24962306a36Sopenharmony_ci * I think start always gets called again after stop. Start
25062306a36Sopenharmony_ci * needs to return NULL when it is done. The whole "payload"
25162306a36Sopenharmony_ci * in this case is a single (long) string, so by the second
25262306a36Sopenharmony_ci * time we get to start (pos = 1), we're done.
25362306a36Sopenharmony_ci */
25462306a36Sopenharmony_cistatic void *help_start(struct seq_file *m, loff_t *pos)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	void *payload = NULL;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_start: start\n");
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	mutex_lock(&orangefs_help_file_lock);
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	if (*pos == 0)
26362306a36Sopenharmony_ci		payload = m->private;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	return payload;
26662306a36Sopenharmony_ci}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_cistatic void *help_next(struct seq_file *m, void *v, loff_t *pos)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	(*pos)++;
27162306a36Sopenharmony_ci	gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_next: start\n");
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	return NULL;
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistatic void help_stop(struct seq_file *m, void *p)
27762306a36Sopenharmony_ci{
27862306a36Sopenharmony_ci	gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_stop: start\n");
27962306a36Sopenharmony_ci	mutex_unlock(&orangefs_help_file_lock);
28062306a36Sopenharmony_ci}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_cistatic int help_show(struct seq_file *m, void *v)
28362306a36Sopenharmony_ci{
28462306a36Sopenharmony_ci	gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_show: start\n");
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	seq_puts(m, v);
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	return 0;
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci/*
29262306a36Sopenharmony_ci * initialize the client-debug file.
29362306a36Sopenharmony_ci */
29462306a36Sopenharmony_cistatic void orangefs_client_debug_init(void)
29562306a36Sopenharmony_ci{
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	static char c_buffer[ORANGEFS_MAX_DEBUG_STRING_LEN] = { };
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	gossip_debug(GOSSIP_DEBUGFS_DEBUG, "%s: start\n", __func__);
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	if (strlen(client_debug_string) + 1 < ORANGEFS_MAX_DEBUG_STRING_LEN) {
30262306a36Sopenharmony_ci		strcpy(c_buffer, client_debug_string);
30362306a36Sopenharmony_ci		strcat(c_buffer, "\n");
30462306a36Sopenharmony_ci	} else {
30562306a36Sopenharmony_ci		strcpy(c_buffer, "none\n");
30662306a36Sopenharmony_ci		pr_info("%s: overflow! 2\n", __func__);
30762306a36Sopenharmony_ci	}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	client_debug_dentry = debugfs_create_file(ORANGEFS_CLIENT_DEBUG_FILE,
31062306a36Sopenharmony_ci						  0444,
31162306a36Sopenharmony_ci						  debug_dir,
31262306a36Sopenharmony_ci						  c_buffer,
31362306a36Sopenharmony_ci						  &kernel_debug_fops);
31462306a36Sopenharmony_ci}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci/* open ORANGEFS_KMOD_DEBUG_FILE or ORANGEFS_CLIENT_DEBUG_FILE.*/
31762306a36Sopenharmony_cistatic int orangefs_debug_open(struct inode *inode, struct file *file)
31862306a36Sopenharmony_ci{
31962306a36Sopenharmony_ci	int rc = -ENODEV;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	gossip_debug(GOSSIP_DEBUGFS_DEBUG,
32262306a36Sopenharmony_ci		     "%s: orangefs_debug_disabled: %d\n",
32362306a36Sopenharmony_ci		     __func__,
32462306a36Sopenharmony_ci		     orangefs_debug_disabled);
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	if (orangefs_debug_disabled)
32762306a36Sopenharmony_ci		goto out;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	rc = 0;
33062306a36Sopenharmony_ci	mutex_lock(&orangefs_debug_lock);
33162306a36Sopenharmony_ci	file->private_data = inode->i_private;
33262306a36Sopenharmony_ci	mutex_unlock(&orangefs_debug_lock);
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ciout:
33562306a36Sopenharmony_ci	gossip_debug(GOSSIP_DEBUGFS_DEBUG,
33662306a36Sopenharmony_ci		     "orangefs_debug_open: rc: %d\n",
33762306a36Sopenharmony_ci		     rc);
33862306a36Sopenharmony_ci	return rc;
33962306a36Sopenharmony_ci}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_cistatic ssize_t orangefs_debug_read(struct file *file,
34262306a36Sopenharmony_ci				 char __user *ubuf,
34362306a36Sopenharmony_ci				 size_t count,
34462306a36Sopenharmony_ci				 loff_t *ppos)
34562306a36Sopenharmony_ci{
34662306a36Sopenharmony_ci	char *buf;
34762306a36Sopenharmony_ci	int sprintf_ret;
34862306a36Sopenharmony_ci	ssize_t read_ret = -ENOMEM;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	gossip_debug(GOSSIP_DEBUGFS_DEBUG, "orangefs_debug_read: start\n");
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	buf = kmalloc(ORANGEFS_MAX_DEBUG_STRING_LEN, GFP_KERNEL);
35362306a36Sopenharmony_ci	if (!buf)
35462306a36Sopenharmony_ci		goto out;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	mutex_lock(&orangefs_debug_lock);
35762306a36Sopenharmony_ci	sprintf_ret = sprintf(buf, "%s", (char *)file->private_data);
35862306a36Sopenharmony_ci	mutex_unlock(&orangefs_debug_lock);
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	read_ret = simple_read_from_buffer(ubuf, count, ppos, buf, sprintf_ret);
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	kfree(buf);
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ciout:
36562306a36Sopenharmony_ci	gossip_debug(GOSSIP_DEBUGFS_DEBUG,
36662306a36Sopenharmony_ci		     "orangefs_debug_read: ret: %zu\n",
36762306a36Sopenharmony_ci		     read_ret);
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	return read_ret;
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cistatic ssize_t orangefs_debug_write(struct file *file,
37362306a36Sopenharmony_ci				  const char __user *ubuf,
37462306a36Sopenharmony_ci				  size_t count,
37562306a36Sopenharmony_ci				  loff_t *ppos)
37662306a36Sopenharmony_ci{
37762306a36Sopenharmony_ci	char *buf;
37862306a36Sopenharmony_ci	int rc = -EFAULT;
37962306a36Sopenharmony_ci	size_t silly = 0;
38062306a36Sopenharmony_ci	char *debug_string;
38162306a36Sopenharmony_ci	struct orangefs_kernel_op_s *new_op = NULL;
38262306a36Sopenharmony_ci	struct client_debug_mask c_mask = { NULL, 0, 0 };
38362306a36Sopenharmony_ci	char *s;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	gossip_debug(GOSSIP_DEBUGFS_DEBUG,
38662306a36Sopenharmony_ci		"orangefs_debug_write: %pD\n",
38762306a36Sopenharmony_ci		file);
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	if (count == 0)
39062306a36Sopenharmony_ci		return 0;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	/*
39362306a36Sopenharmony_ci	 * Thwart users who try to jamb a ridiculous number
39462306a36Sopenharmony_ci	 * of bytes into the debug file...
39562306a36Sopenharmony_ci	 */
39662306a36Sopenharmony_ci	if (count > ORANGEFS_MAX_DEBUG_STRING_LEN + 1) {
39762306a36Sopenharmony_ci		silly = count;
39862306a36Sopenharmony_ci		count = ORANGEFS_MAX_DEBUG_STRING_LEN + 1;
39962306a36Sopenharmony_ci	}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	buf = kzalloc(ORANGEFS_MAX_DEBUG_STRING_LEN, GFP_KERNEL);
40262306a36Sopenharmony_ci	if (!buf)
40362306a36Sopenharmony_ci		goto out;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	if (copy_from_user(buf, ubuf, count - 1)) {
40662306a36Sopenharmony_ci		gossip_debug(GOSSIP_DEBUGFS_DEBUG,
40762306a36Sopenharmony_ci			     "%s: copy_from_user failed!\n",
40862306a36Sopenharmony_ci			     __func__);
40962306a36Sopenharmony_ci		goto out;
41062306a36Sopenharmony_ci	}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	/*
41362306a36Sopenharmony_ci	 * Map the keyword string from userspace into a valid debug mask.
41462306a36Sopenharmony_ci	 * The mapping process involves mapping the human-inputted string
41562306a36Sopenharmony_ci	 * into a valid mask, and then rebuilding the string from the
41662306a36Sopenharmony_ci	 * verified valid mask.
41762306a36Sopenharmony_ci	 *
41862306a36Sopenharmony_ci	 * A service operation is required to set a new client-side
41962306a36Sopenharmony_ci	 * debug mask.
42062306a36Sopenharmony_ci	 */
42162306a36Sopenharmony_ci	if (!strcmp(file->f_path.dentry->d_name.name,
42262306a36Sopenharmony_ci		    ORANGEFS_KMOD_DEBUG_FILE)) {
42362306a36Sopenharmony_ci		debug_string_to_mask(buf, &orangefs_gossip_debug_mask, 0);
42462306a36Sopenharmony_ci		debug_mask_to_string(&orangefs_gossip_debug_mask, 0);
42562306a36Sopenharmony_ci		debug_string = kernel_debug_string;
42662306a36Sopenharmony_ci		gossip_debug(GOSSIP_DEBUGFS_DEBUG,
42762306a36Sopenharmony_ci			     "New kernel debug string is %s\n",
42862306a36Sopenharmony_ci			     kernel_debug_string);
42962306a36Sopenharmony_ci	} else {
43062306a36Sopenharmony_ci		/* Can't reset client debug mask if client is not running. */
43162306a36Sopenharmony_ci		if (is_daemon_in_service()) {
43262306a36Sopenharmony_ci			pr_info("%s: Client not running :%d:\n",
43362306a36Sopenharmony_ci				__func__,
43462306a36Sopenharmony_ci				is_daemon_in_service());
43562306a36Sopenharmony_ci			goto out;
43662306a36Sopenharmony_ci		}
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci		debug_string_to_mask(buf, &c_mask, 1);
43962306a36Sopenharmony_ci		debug_mask_to_string(&c_mask, 1);
44062306a36Sopenharmony_ci		debug_string = client_debug_string;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci		new_op = op_alloc(ORANGEFS_VFS_OP_PARAM);
44362306a36Sopenharmony_ci		if (!new_op) {
44462306a36Sopenharmony_ci			pr_info("%s: op_alloc failed!\n", __func__);
44562306a36Sopenharmony_ci			goto out;
44662306a36Sopenharmony_ci		}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci		new_op->upcall.req.param.op =
44962306a36Sopenharmony_ci			ORANGEFS_PARAM_REQUEST_OP_TWO_MASK_VALUES;
45062306a36Sopenharmony_ci		new_op->upcall.req.param.type = ORANGEFS_PARAM_REQUEST_SET;
45162306a36Sopenharmony_ci		memset(new_op->upcall.req.param.s_value,
45262306a36Sopenharmony_ci		       0,
45362306a36Sopenharmony_ci		       ORANGEFS_MAX_DEBUG_STRING_LEN);
45462306a36Sopenharmony_ci		sprintf(new_op->upcall.req.param.s_value,
45562306a36Sopenharmony_ci			"%llx %llx\n",
45662306a36Sopenharmony_ci			c_mask.mask1,
45762306a36Sopenharmony_ci			c_mask.mask2);
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci		/* service_operation returns 0 on success... */
46062306a36Sopenharmony_ci		rc = service_operation(new_op,
46162306a36Sopenharmony_ci				       "orangefs_param",
46262306a36Sopenharmony_ci					ORANGEFS_OP_INTERRUPTIBLE);
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci		if (rc)
46562306a36Sopenharmony_ci			gossip_debug(GOSSIP_DEBUGFS_DEBUG,
46662306a36Sopenharmony_ci				     "%s: service_operation failed! rc:%d:\n",
46762306a36Sopenharmony_ci				     __func__,
46862306a36Sopenharmony_ci				     rc);
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci		op_release(new_op);
47162306a36Sopenharmony_ci	}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	mutex_lock(&orangefs_debug_lock);
47462306a36Sopenharmony_ci	s = file_inode(file)->i_private;
47562306a36Sopenharmony_ci	memset(s, 0, ORANGEFS_MAX_DEBUG_STRING_LEN);
47662306a36Sopenharmony_ci	sprintf(s, "%s\n", debug_string);
47762306a36Sopenharmony_ci	mutex_unlock(&orangefs_debug_lock);
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	*ppos += count;
48062306a36Sopenharmony_ci	if (silly)
48162306a36Sopenharmony_ci		rc = silly;
48262306a36Sopenharmony_ci	else
48362306a36Sopenharmony_ci		rc = count;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ciout:
48662306a36Sopenharmony_ci	gossip_debug(GOSSIP_DEBUGFS_DEBUG,
48762306a36Sopenharmony_ci		     "orangefs_debug_write: rc: %d\n",
48862306a36Sopenharmony_ci		     rc);
48962306a36Sopenharmony_ci	kfree(buf);
49062306a36Sopenharmony_ci	return rc;
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci/*
49462306a36Sopenharmony_ci * After obtaining a string representation of the client's debug
49562306a36Sopenharmony_ci * keywords and their associated masks, this function is called to build an
49662306a36Sopenharmony_ci * array of these values.
49762306a36Sopenharmony_ci */
49862306a36Sopenharmony_cistatic int orangefs_prepare_cdm_array(char *debug_array_string)
49962306a36Sopenharmony_ci{
50062306a36Sopenharmony_ci	int i;
50162306a36Sopenharmony_ci	int rc = -EINVAL;
50262306a36Sopenharmony_ci	char *cds_head = NULL;
50362306a36Sopenharmony_ci	char *cds_delimiter = NULL;
50462306a36Sopenharmony_ci	int keyword_len = 0;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	gossip_debug(GOSSIP_UTILS_DEBUG, "%s: start\n", __func__);
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	/*
50962306a36Sopenharmony_ci	 * figure out how many elements the cdm_array needs.
51062306a36Sopenharmony_ci	 */
51162306a36Sopenharmony_ci	for (i = 0; i < strlen(debug_array_string); i++)
51262306a36Sopenharmony_ci		if (debug_array_string[i] == '\n')
51362306a36Sopenharmony_ci			cdm_element_count++;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	if (!cdm_element_count) {
51662306a36Sopenharmony_ci		pr_info("No elements in client debug array string!\n");
51762306a36Sopenharmony_ci		goto out;
51862306a36Sopenharmony_ci	}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	cdm_array = kcalloc(cdm_element_count, sizeof(*cdm_array), GFP_KERNEL);
52162306a36Sopenharmony_ci	if (!cdm_array) {
52262306a36Sopenharmony_ci		rc = -ENOMEM;
52362306a36Sopenharmony_ci		goto out;
52462306a36Sopenharmony_ci	}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	cds_head = debug_array_string;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	for (i = 0; i < cdm_element_count; i++) {
52962306a36Sopenharmony_ci		cds_delimiter = strchr(cds_head, '\n');
53062306a36Sopenharmony_ci		*cds_delimiter = '\0';
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci		keyword_len = strcspn(cds_head, " ");
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci		cdm_array[i].keyword = kzalloc(keyword_len + 1, GFP_KERNEL);
53562306a36Sopenharmony_ci		if (!cdm_array[i].keyword) {
53662306a36Sopenharmony_ci			rc = -ENOMEM;
53762306a36Sopenharmony_ci			goto out;
53862306a36Sopenharmony_ci		}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci		sscanf(cds_head,
54162306a36Sopenharmony_ci		       "%s %llx %llx",
54262306a36Sopenharmony_ci		       cdm_array[i].keyword,
54362306a36Sopenharmony_ci		       (unsigned long long *)&(cdm_array[i].mask1),
54462306a36Sopenharmony_ci		       (unsigned long long *)&(cdm_array[i].mask2));
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci		if (!strcmp(cdm_array[i].keyword, ORANGEFS_VERBOSE))
54762306a36Sopenharmony_ci			client_verbose_index = i;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci		if (!strcmp(cdm_array[i].keyword, ORANGEFS_ALL))
55062306a36Sopenharmony_ci			client_all_index = i;
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci		cds_head = cds_delimiter + 1;
55362306a36Sopenharmony_ci	}
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	rc = cdm_element_count;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	gossip_debug(GOSSIP_UTILS_DEBUG, "%s: rc:%d:\n", __func__, rc);
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ciout:
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	return rc;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci/*
56662306a36Sopenharmony_ci * /sys/kernel/debug/orangefs/debug-help can be catted to
56762306a36Sopenharmony_ci * see all the available kernel and client debug keywords.
56862306a36Sopenharmony_ci *
56962306a36Sopenharmony_ci * When orangefs.ko initializes, we have no idea what keywords the
57062306a36Sopenharmony_ci * client supports, nor their associated masks.
57162306a36Sopenharmony_ci *
57262306a36Sopenharmony_ci * We pass through this function once at module-load and stamp a
57362306a36Sopenharmony_ci * boilerplate "we don't know" message for the client in the
57462306a36Sopenharmony_ci * debug-help file. We pass through here again when the client
57562306a36Sopenharmony_ci * starts and then we can fill out the debug-help file fully.
57662306a36Sopenharmony_ci *
57762306a36Sopenharmony_ci * The client might be restarted any number of times between
57862306a36Sopenharmony_ci * module reloads, we only build the debug-help file the first time.
57962306a36Sopenharmony_ci */
58062306a36Sopenharmony_ciint orangefs_prepare_debugfs_help_string(int at_boot)
58162306a36Sopenharmony_ci{
58262306a36Sopenharmony_ci	char *client_title = "Client Debug Keywords:\n";
58362306a36Sopenharmony_ci	char *kernel_title = "Kernel Debug Keywords:\n";
58462306a36Sopenharmony_ci	size_t string_size =  DEBUG_HELP_STRING_SIZE;
58562306a36Sopenharmony_ci	size_t result_size;
58662306a36Sopenharmony_ci	size_t i;
58762306a36Sopenharmony_ci	char *new;
58862306a36Sopenharmony_ci	int rc = -EINVAL;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	gossip_debug(GOSSIP_UTILS_DEBUG, "%s: start\n", __func__);
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	if (at_boot)
59362306a36Sopenharmony_ci		client_title = HELP_STRING_UNINITIALIZED;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	/* build a new debug_help_string. */
59662306a36Sopenharmony_ci	new = kzalloc(DEBUG_HELP_STRING_SIZE, GFP_KERNEL);
59762306a36Sopenharmony_ci	if (!new) {
59862306a36Sopenharmony_ci		rc = -ENOMEM;
59962306a36Sopenharmony_ci		goto out;
60062306a36Sopenharmony_ci	}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	/*
60362306a36Sopenharmony_ci	 * strlcat(dst, src, size) will append at most
60462306a36Sopenharmony_ci	 * "size - strlen(dst) - 1" bytes of src onto dst,
60562306a36Sopenharmony_ci	 * null terminating the result, and return the total
60662306a36Sopenharmony_ci	 * length of the string it tried to create.
60762306a36Sopenharmony_ci	 *
60862306a36Sopenharmony_ci	 * We'll just plow through here building our new debug
60962306a36Sopenharmony_ci	 * help string and let strlcat take care of assuring that
61062306a36Sopenharmony_ci	 * dst doesn't overflow.
61162306a36Sopenharmony_ci	 */
61262306a36Sopenharmony_ci	strlcat(new, client_title, string_size);
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	if (!at_boot) {
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci                /*
61762306a36Sopenharmony_ci		 * fill the client keyword/mask array and remember
61862306a36Sopenharmony_ci		 * how many elements there were.
61962306a36Sopenharmony_ci		 */
62062306a36Sopenharmony_ci		cdm_element_count =
62162306a36Sopenharmony_ci			orangefs_prepare_cdm_array(client_debug_array_string);
62262306a36Sopenharmony_ci		if (cdm_element_count <= 0) {
62362306a36Sopenharmony_ci			kfree(new);
62462306a36Sopenharmony_ci			goto out;
62562306a36Sopenharmony_ci		}
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci		for (i = 0; i < cdm_element_count; i++) {
62862306a36Sopenharmony_ci			strlcat(new, "\t", string_size);
62962306a36Sopenharmony_ci			strlcat(new, cdm_array[i].keyword, string_size);
63062306a36Sopenharmony_ci			strlcat(new, "\n", string_size);
63162306a36Sopenharmony_ci		}
63262306a36Sopenharmony_ci	}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	strlcat(new, "\n", string_size);
63562306a36Sopenharmony_ci	strlcat(new, kernel_title, string_size);
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	for (i = 0; i < num_kmod_keyword_mask_map; i++) {
63862306a36Sopenharmony_ci		strlcat(new, "\t", string_size);
63962306a36Sopenharmony_ci		strlcat(new, s_kmod_keyword_mask_map[i].keyword, string_size);
64062306a36Sopenharmony_ci		result_size = strlcat(new, "\n", string_size);
64162306a36Sopenharmony_ci	}
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	/* See if we tried to put too many bytes into "new"... */
64462306a36Sopenharmony_ci	if (result_size >= string_size) {
64562306a36Sopenharmony_ci		kfree(new);
64662306a36Sopenharmony_ci		goto out;
64762306a36Sopenharmony_ci	}
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	if (at_boot) {
65062306a36Sopenharmony_ci		debug_help_string = new;
65162306a36Sopenharmony_ci	} else {
65262306a36Sopenharmony_ci		mutex_lock(&orangefs_help_file_lock);
65362306a36Sopenharmony_ci		memset(debug_help_string, 0, DEBUG_HELP_STRING_SIZE);
65462306a36Sopenharmony_ci		strlcat(debug_help_string, new, string_size);
65562306a36Sopenharmony_ci		mutex_unlock(&orangefs_help_file_lock);
65662306a36Sopenharmony_ci		kfree(new);
65762306a36Sopenharmony_ci	}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	rc = 0;
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ciout:	return rc;
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci/*
66662306a36Sopenharmony_ci * kernel = type 0
66762306a36Sopenharmony_ci * client = type 1
66862306a36Sopenharmony_ci */
66962306a36Sopenharmony_cistatic void debug_mask_to_string(void *mask, int type)
67062306a36Sopenharmony_ci{
67162306a36Sopenharmony_ci	int i;
67262306a36Sopenharmony_ci	int len = 0;
67362306a36Sopenharmony_ci	char *debug_string;
67462306a36Sopenharmony_ci	int element_count = 0;
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	gossip_debug(GOSSIP_UTILS_DEBUG, "%s: start\n", __func__);
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	if (type) {
67962306a36Sopenharmony_ci		debug_string = client_debug_string;
68062306a36Sopenharmony_ci		element_count = cdm_element_count;
68162306a36Sopenharmony_ci	} else {
68262306a36Sopenharmony_ci		debug_string = kernel_debug_string;
68362306a36Sopenharmony_ci		element_count = num_kmod_keyword_mask_map;
68462306a36Sopenharmony_ci	}
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	memset(debug_string, 0, ORANGEFS_MAX_DEBUG_STRING_LEN);
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	/*
68962306a36Sopenharmony_ci	 * Some keywords, like "all" or "verbose", are amalgams of
69062306a36Sopenharmony_ci	 * numerous other keywords. Make a special check for those
69162306a36Sopenharmony_ci	 * before grinding through the whole mask only to find out
69262306a36Sopenharmony_ci	 * later...
69362306a36Sopenharmony_ci	 */
69462306a36Sopenharmony_ci	if (check_amalgam_keyword(mask, type))
69562306a36Sopenharmony_ci		goto out;
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	/* Build the debug string. */
69862306a36Sopenharmony_ci	for (i = 0; i < element_count; i++)
69962306a36Sopenharmony_ci		if (type)
70062306a36Sopenharmony_ci			do_c_string(mask, i);
70162306a36Sopenharmony_ci		else
70262306a36Sopenharmony_ci			do_k_string(mask, i);
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	len = strlen(debug_string);
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	if ((len) && (type))
70762306a36Sopenharmony_ci		client_debug_string[len - 1] = '\0';
70862306a36Sopenharmony_ci	else if (len)
70962306a36Sopenharmony_ci		kernel_debug_string[len - 1] = '\0';
71062306a36Sopenharmony_ci	else if (type)
71162306a36Sopenharmony_ci		strcpy(client_debug_string, "none");
71262306a36Sopenharmony_ci	else
71362306a36Sopenharmony_ci		strcpy(kernel_debug_string, "none");
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ciout:
71662306a36Sopenharmony_cigossip_debug(GOSSIP_UTILS_DEBUG, "%s: string:%s:\n", __func__, debug_string);
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	return;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci}
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_cistatic void do_k_string(void *k_mask, int index)
72362306a36Sopenharmony_ci{
72462306a36Sopenharmony_ci	__u64 *mask = (__u64 *) k_mask;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	if (keyword_is_amalgam((char *) s_kmod_keyword_mask_map[index].keyword))
72762306a36Sopenharmony_ci		goto out;
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	if (*mask & s_kmod_keyword_mask_map[index].mask_val) {
73062306a36Sopenharmony_ci		if ((strlen(kernel_debug_string) +
73162306a36Sopenharmony_ci		     strlen(s_kmod_keyword_mask_map[index].keyword))
73262306a36Sopenharmony_ci			< ORANGEFS_MAX_DEBUG_STRING_LEN - 1) {
73362306a36Sopenharmony_ci				strcat(kernel_debug_string,
73462306a36Sopenharmony_ci				       s_kmod_keyword_mask_map[index].keyword);
73562306a36Sopenharmony_ci				strcat(kernel_debug_string, ",");
73662306a36Sopenharmony_ci			} else {
73762306a36Sopenharmony_ci				gossip_err("%s: overflow!\n", __func__);
73862306a36Sopenharmony_ci				strcpy(kernel_debug_string, ORANGEFS_ALL);
73962306a36Sopenharmony_ci				goto out;
74062306a36Sopenharmony_ci			}
74162306a36Sopenharmony_ci	}
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ciout:
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	return;
74662306a36Sopenharmony_ci}
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_cistatic void do_c_string(void *c_mask, int index)
74962306a36Sopenharmony_ci{
75062306a36Sopenharmony_ci	struct client_debug_mask *mask = (struct client_debug_mask *) c_mask;
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	if (keyword_is_amalgam(cdm_array[index].keyword))
75362306a36Sopenharmony_ci		goto out;
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	if ((mask->mask1 & cdm_array[index].mask1) ||
75662306a36Sopenharmony_ci	    (mask->mask2 & cdm_array[index].mask2)) {
75762306a36Sopenharmony_ci		if ((strlen(client_debug_string) +
75862306a36Sopenharmony_ci		     strlen(cdm_array[index].keyword) + 1)
75962306a36Sopenharmony_ci			< ORANGEFS_MAX_DEBUG_STRING_LEN - 2) {
76062306a36Sopenharmony_ci				strcat(client_debug_string,
76162306a36Sopenharmony_ci				       cdm_array[index].keyword);
76262306a36Sopenharmony_ci				strcat(client_debug_string, ",");
76362306a36Sopenharmony_ci			} else {
76462306a36Sopenharmony_ci				gossip_err("%s: overflow!\n", __func__);
76562306a36Sopenharmony_ci				strcpy(client_debug_string, ORANGEFS_ALL);
76662306a36Sopenharmony_ci				goto out;
76762306a36Sopenharmony_ci			}
76862306a36Sopenharmony_ci	}
76962306a36Sopenharmony_ciout:
77062306a36Sopenharmony_ci	return;
77162306a36Sopenharmony_ci}
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_cistatic int keyword_is_amalgam(char *keyword)
77462306a36Sopenharmony_ci{
77562306a36Sopenharmony_ci	int rc = 0;
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	if ((!strcmp(keyword, ORANGEFS_ALL)) || (!strcmp(keyword, ORANGEFS_VERBOSE)))
77862306a36Sopenharmony_ci		rc = 1;
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	return rc;
78162306a36Sopenharmony_ci}
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci/*
78462306a36Sopenharmony_ci * kernel = type 0
78562306a36Sopenharmony_ci * client = type 1
78662306a36Sopenharmony_ci *
78762306a36Sopenharmony_ci * return 1 if we found an amalgam.
78862306a36Sopenharmony_ci */
78962306a36Sopenharmony_cistatic int check_amalgam_keyword(void *mask, int type)
79062306a36Sopenharmony_ci{
79162306a36Sopenharmony_ci	__u64 *k_mask;
79262306a36Sopenharmony_ci	struct client_debug_mask *c_mask;
79362306a36Sopenharmony_ci	int k_all_index = num_kmod_keyword_mask_map - 1;
79462306a36Sopenharmony_ci	int rc = 0;
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	if (type) {
79762306a36Sopenharmony_ci		c_mask = (struct client_debug_mask *) mask;
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci		if ((c_mask->mask1 == cdm_array[client_all_index].mask1) &&
80062306a36Sopenharmony_ci		    (c_mask->mask2 == cdm_array[client_all_index].mask2)) {
80162306a36Sopenharmony_ci			strcpy(client_debug_string, ORANGEFS_ALL);
80262306a36Sopenharmony_ci			rc = 1;
80362306a36Sopenharmony_ci			goto out;
80462306a36Sopenharmony_ci		}
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci		if ((c_mask->mask1 == cdm_array[client_verbose_index].mask1) &&
80762306a36Sopenharmony_ci		    (c_mask->mask2 == cdm_array[client_verbose_index].mask2)) {
80862306a36Sopenharmony_ci			strcpy(client_debug_string, ORANGEFS_VERBOSE);
80962306a36Sopenharmony_ci			rc = 1;
81062306a36Sopenharmony_ci			goto out;
81162306a36Sopenharmony_ci		}
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	} else {
81462306a36Sopenharmony_ci		k_mask = (__u64 *) mask;
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci		if (*k_mask >= s_kmod_keyword_mask_map[k_all_index].mask_val) {
81762306a36Sopenharmony_ci			strcpy(kernel_debug_string, ORANGEFS_ALL);
81862306a36Sopenharmony_ci			rc = 1;
81962306a36Sopenharmony_ci			goto out;
82062306a36Sopenharmony_ci		}
82162306a36Sopenharmony_ci	}
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ciout:
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	return rc;
82662306a36Sopenharmony_ci}
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci/*
82962306a36Sopenharmony_ci * kernel = type 0
83062306a36Sopenharmony_ci * client = type 1
83162306a36Sopenharmony_ci */
83262306a36Sopenharmony_cistatic void debug_string_to_mask(char *debug_string, void *mask, int type)
83362306a36Sopenharmony_ci{
83462306a36Sopenharmony_ci	char *unchecked_keyword;
83562306a36Sopenharmony_ci	int i;
83662306a36Sopenharmony_ci	char *strsep_fodder = kstrdup(debug_string, GFP_KERNEL);
83762306a36Sopenharmony_ci	char *original_pointer;
83862306a36Sopenharmony_ci	int element_count = 0;
83962306a36Sopenharmony_ci	struct client_debug_mask *c_mask = NULL;
84062306a36Sopenharmony_ci	__u64 *k_mask = NULL;
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	gossip_debug(GOSSIP_UTILS_DEBUG, "%s: start\n", __func__);
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	if (type) {
84562306a36Sopenharmony_ci		c_mask = (struct client_debug_mask *)mask;
84662306a36Sopenharmony_ci		element_count = cdm_element_count;
84762306a36Sopenharmony_ci	} else {
84862306a36Sopenharmony_ci		k_mask = (__u64 *)mask;
84962306a36Sopenharmony_ci		*k_mask = 0;
85062306a36Sopenharmony_ci		element_count = num_kmod_keyword_mask_map;
85162306a36Sopenharmony_ci	}
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	original_pointer = strsep_fodder;
85462306a36Sopenharmony_ci	while ((unchecked_keyword = strsep(&strsep_fodder, ",")))
85562306a36Sopenharmony_ci		if (strlen(unchecked_keyword)) {
85662306a36Sopenharmony_ci			for (i = 0; i < element_count; i++)
85762306a36Sopenharmony_ci				if (type)
85862306a36Sopenharmony_ci					do_c_mask(i,
85962306a36Sopenharmony_ci						  unchecked_keyword,
86062306a36Sopenharmony_ci						  &c_mask);
86162306a36Sopenharmony_ci				else
86262306a36Sopenharmony_ci					do_k_mask(i,
86362306a36Sopenharmony_ci						  unchecked_keyword,
86462306a36Sopenharmony_ci						  &k_mask);
86562306a36Sopenharmony_ci		}
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	kfree(original_pointer);
86862306a36Sopenharmony_ci}
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_cistatic void do_c_mask(int i, char *unchecked_keyword,
87162306a36Sopenharmony_ci    struct client_debug_mask **sane_mask)
87262306a36Sopenharmony_ci{
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	if (!strcmp(cdm_array[i].keyword, unchecked_keyword)) {
87562306a36Sopenharmony_ci		(**sane_mask).mask1 = (**sane_mask).mask1 | cdm_array[i].mask1;
87662306a36Sopenharmony_ci		(**sane_mask).mask2 = (**sane_mask).mask2 | cdm_array[i].mask2;
87762306a36Sopenharmony_ci	}
87862306a36Sopenharmony_ci}
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_cistatic void do_k_mask(int i, char *unchecked_keyword, __u64 **sane_mask)
88162306a36Sopenharmony_ci{
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	if (!strcmp(s_kmod_keyword_mask_map[i].keyword, unchecked_keyword))
88462306a36Sopenharmony_ci		**sane_mask = (**sane_mask) |
88562306a36Sopenharmony_ci				s_kmod_keyword_mask_map[i].mask_val;
88662306a36Sopenharmony_ci}
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ciint orangefs_debugfs_new_client_mask(void __user *arg)
88962306a36Sopenharmony_ci{
89062306a36Sopenharmony_ci	struct dev_mask2_info_s mask2_info = {0};
89162306a36Sopenharmony_ci	int ret;
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	ret = copy_from_user(&mask2_info,
89462306a36Sopenharmony_ci			     (void __user *)arg,
89562306a36Sopenharmony_ci			     sizeof(struct dev_mask2_info_s));
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	if (ret != 0)
89862306a36Sopenharmony_ci		return -EIO;
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	client_debug_mask.mask1 = mask2_info.mask1_value;
90162306a36Sopenharmony_ci	client_debug_mask.mask2 = mask2_info.mask2_value;
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	pr_info("%s: client debug mask has been been received "
90462306a36Sopenharmony_ci		":%llx: :%llx:\n",
90562306a36Sopenharmony_ci		__func__,
90662306a36Sopenharmony_ci		(unsigned long long)client_debug_mask.mask1,
90762306a36Sopenharmony_ci		(unsigned long long)client_debug_mask.mask2);
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	return ret;
91062306a36Sopenharmony_ci}
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ciint orangefs_debugfs_new_client_string(void __user *arg)
91362306a36Sopenharmony_ci{
91462306a36Sopenharmony_ci	int ret;
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	ret = copy_from_user(&client_debug_array_string,
91762306a36Sopenharmony_ci			     (void __user *)arg,
91862306a36Sopenharmony_ci			     ORANGEFS_MAX_DEBUG_STRING_LEN);
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	if (ret != 0) {
92162306a36Sopenharmony_ci		pr_info("%s: CLIENT_STRING: copy_from_user failed\n",
92262306a36Sopenharmony_ci			__func__);
92362306a36Sopenharmony_ci		return -EFAULT;
92462306a36Sopenharmony_ci	}
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	/*
92762306a36Sopenharmony_ci	 * The real client-core makes an effort to ensure
92862306a36Sopenharmony_ci	 * that actual strings that aren't too long to fit in
92962306a36Sopenharmony_ci	 * this buffer is what we get here. We're going to use
93062306a36Sopenharmony_ci	 * string functions on the stuff we got, so we'll make
93162306a36Sopenharmony_ci	 * this extra effort to try and keep from
93262306a36Sopenharmony_ci	 * flowing out of this buffer when we use the string
93362306a36Sopenharmony_ci	 * functions, even if somehow the stuff we end up
93462306a36Sopenharmony_ci	 * with here is garbage.
93562306a36Sopenharmony_ci	 */
93662306a36Sopenharmony_ci	client_debug_array_string[ORANGEFS_MAX_DEBUG_STRING_LEN - 1] =
93762306a36Sopenharmony_ci		'\0';
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	pr_info("%s: client debug array string has been received.\n",
94062306a36Sopenharmony_ci		__func__);
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	if (!help_string_initialized) {
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci		/* Build a proper debug help string. */
94562306a36Sopenharmony_ci		ret = orangefs_prepare_debugfs_help_string(0);
94662306a36Sopenharmony_ci		if (ret) {
94762306a36Sopenharmony_ci			gossip_err("%s: no debug help string \n",
94862306a36Sopenharmony_ci				   __func__);
94962306a36Sopenharmony_ci			return ret;
95062306a36Sopenharmony_ci		}
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	}
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	debug_mask_to_string(&client_debug_mask, 1);
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	debugfs_remove(client_debug_dentry);
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	orangefs_client_debug_init();
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	help_string_initialized++;
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	return 0;
96362306a36Sopenharmony_ci}
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ciint orangefs_debugfs_new_debug(void __user *arg)
96662306a36Sopenharmony_ci{
96762306a36Sopenharmony_ci	struct dev_mask_info_s mask_info = {0};
96862306a36Sopenharmony_ci	int ret;
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	ret = copy_from_user(&mask_info,
97162306a36Sopenharmony_ci			     (void __user *)arg,
97262306a36Sopenharmony_ci			     sizeof(mask_info));
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	if (ret != 0)
97562306a36Sopenharmony_ci		return -EIO;
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	if (mask_info.mask_type == KERNEL_MASK) {
97862306a36Sopenharmony_ci		if ((mask_info.mask_value == 0)
97962306a36Sopenharmony_ci		    && (kernel_mask_set_mod_init)) {
98062306a36Sopenharmony_ci			/*
98162306a36Sopenharmony_ci			 * the kernel debug mask was set when the
98262306a36Sopenharmony_ci			 * kernel module was loaded; don't override
98362306a36Sopenharmony_ci			 * it if the client-core was started without
98462306a36Sopenharmony_ci			 * a value for ORANGEFS_KMODMASK.
98562306a36Sopenharmony_ci			 */
98662306a36Sopenharmony_ci			return 0;
98762306a36Sopenharmony_ci		}
98862306a36Sopenharmony_ci		debug_mask_to_string(&mask_info.mask_value,
98962306a36Sopenharmony_ci				     mask_info.mask_type);
99062306a36Sopenharmony_ci		orangefs_gossip_debug_mask = mask_info.mask_value;
99162306a36Sopenharmony_ci		pr_info("%s: kernel debug mask has been modified to "
99262306a36Sopenharmony_ci			":%s: :%llx:\n",
99362306a36Sopenharmony_ci			__func__,
99462306a36Sopenharmony_ci			kernel_debug_string,
99562306a36Sopenharmony_ci			(unsigned long long)orangefs_gossip_debug_mask);
99662306a36Sopenharmony_ci	} else if (mask_info.mask_type == CLIENT_MASK) {
99762306a36Sopenharmony_ci		debug_mask_to_string(&mask_info.mask_value,
99862306a36Sopenharmony_ci				     mask_info.mask_type);
99962306a36Sopenharmony_ci		pr_info("%s: client debug mask has been modified to"
100062306a36Sopenharmony_ci			":%s: :%llx:\n",
100162306a36Sopenharmony_ci			__func__,
100262306a36Sopenharmony_ci			client_debug_string,
100362306a36Sopenharmony_ci			llu(mask_info.mask_value));
100462306a36Sopenharmony_ci	} else {
100562306a36Sopenharmony_ci		gossip_err("Invalid mask type....\n");
100662306a36Sopenharmony_ci		return -EINVAL;
100762306a36Sopenharmony_ci	}
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	return ret;
101062306a36Sopenharmony_ci}
1011