// SPDX-License-Identifier: GPL-2.0 /* * What: /sys/kernel/debug/orangefs/debug-help * Date: June 2015 * Contact: Mike Marshall <hubcap@omnibond.com> * Description: * List of client and kernel debug keywords. * * * What: /sys/kernel/debug/orangefs/client-debug * Date: June 2015 * Contact: Mike Marshall <hubcap@omnibond.com> * Description: * Debug setting for "the client", the userspace * helper for the kernel module. * * * What: /sys/kernel/debug/orangefs/kernel-debug * Date: June 2015 * Contact: Mike Marshall <hubcap@omnibond.com> * Description: * Debug setting for the orangefs kernel module. * * Any of the keywords, or comma-separated lists * of keywords, from debug-help can be catted to * client-debug or kernel-debug. * * "none", "all" and "verbose" are special keywords * for client-debug. Setting client-debug to "all" * is kind of like trying to drink water from a * fire hose, "verbose" triggers most of the same * output except for the constant flow of output * from the main wait loop. * * "none" and "all" are similar settings for kernel-debug * no need for a "verbose".
*/ #include <linux/debugfs.h> #include <linux/slab.h>
#define DEBUG_HELP_STRING_SIZE 4096 #define HELP_STRING_UNINITIALIZED \ "Client Debug Keywords are unknown until the first time\n" \ "the client is started after boot.\n" #define ORANGEFS_KMOD_DEBUG_HELP_FILE "debug-help" #define ORANGEFS_KMOD_DEBUG_FILE "kernel-debug" #define ORANGEFS_CLIENT_DEBUG_FILE "client-debug" #define ORANGEFS_VERBOSE "verbose" #define ORANGEFS_ALL "all"
/* * An array of client_debug_mask will be built to hold debug keyword/mask * values fetched from userspace.
*/ struct client_debug_mask { char *keyword;
__u64 mask1;
__u64 mask2;
};
/* * Used to protect data in ORANGEFS_KMOD_DEBUG_FILE and * ORANGEFS_KMOD_DEBUG_FILE.
*/ static DEFINE_MUTEX(orangefs_debug_lock);
/* Used to protect data in ORANGEFS_KMOD_DEBUG_HELP_FILE */ static DEFINE_MUTEX(orangefs_help_file_lock);
/* * initialize kmod debug operations, create orangefs debugfs dir and * ORANGEFS_KMOD_DEBUG_HELP_FILE.
*/ void orangefs_debugfs_init(int debug_mask)
{ /* convert input debug mask to a 64-bit unsigned integer */
orangefs_gossip_debug_mask = (unsignedlonglong)debug_mask;
/* * set the kernel's gossip debug string; invalid mask values will * be ignored.
*/
debug_mask_to_string(&orangefs_gossip_debug_mask, 0);
/* remove any invalid values from the mask */
debug_string_to_mask(kernel_debug_string, &orangefs_gossip_debug_mask,
0);
/* * if the mask has a non-zero value, then indicate that the mask * was set when the kernel module was loaded. The orangefs dev ioctl * command will look at this boolean to determine if the kernel's * debug mask should be overwritten when the client-core is started.
*/ if (orangefs_gossip_debug_mask != 0)
kernel_mask_set_mod_init = true;
pr_info("%s: called with debug mask: :%s: :%llx:\n",
__func__,
kernel_debug_string,
(unsignedlonglong)orangefs_gossip_debug_mask);
/* * I think start always gets called again after stop. Start * needs to return NULL when it is done. The whole "payload" * in this case is a single (long) string, so by the second * time we get to start (pos = 1), we're done.
*/ staticvoid *help_start(struct seq_file *m, loff_t *pos)
{ void *payload = NULL;
/* * Thwart users who try to jamb a ridiculous number * of bytes into the debug file...
*/ if (count > ORANGEFS_MAX_DEBUG_STRING_LEN) {
silly = count;
count = ORANGEFS_MAX_DEBUG_STRING_LEN;
}
buf = kzalloc(ORANGEFS_MAX_DEBUG_STRING_LEN, GFP_KERNEL); if (!buf) goto out;
/* * Map the keyword string from userspace into a valid debug mask. * The mapping process involves mapping the human-inputted string * into a valid mask, and then rebuilding the string from the * verified valid mask. * * A service operation is required to set a new client-side * debug mask.
*/ if (!debugfs_get_aux_num(file)) { // kernel-debug
debug_string_to_mask(buf, &orangefs_gossip_debug_mask, 0);
debug_mask_to_string(&orangefs_gossip_debug_mask, 0);
debug_string = kernel_debug_string;
gossip_debug(GOSSIP_DEBUGFS_DEBUG, "New kernel debug string is %s\n",
kernel_debug_string);
} else { /* Can't reset client debug mask if client is not running. */ if (is_daemon_in_service()) {
pr_info("%s: Client not running :%d:\n",
__func__,
is_daemon_in_service()); goto out;
}
/* * After obtaining a string representation of the client's debug * keywords and their associated masks, this function is called to build an * array of these values.
*/ staticint orangefs_prepare_cdm_array(char *debug_array_string)
{ int i; int rc = -EINVAL; char *cds_head = NULL; char *cds_delimiter = NULL; int keyword_len = 0;
/* * figure out how many elements the cdm_array needs.
*/ for (i = 0; i < strlen(debug_array_string); i++) if (debug_array_string[i] == '\n')
cdm_element_count++;
if (!cdm_element_count) {
pr_info("No elements in client debug array string!\n"); goto out;
}
/* * /sys/kernel/debug/orangefs/debug-help can be catted to * see all the available kernel and client debug keywords. * * When orangefs.ko initializes, we have no idea what keywords the * client supports, nor their associated masks. * * We pass through this function once at module-load and stamp a * boilerplate "we don't know" message for the client in the * debug-help file. We pass through here again when the client * starts and then we can fill out the debug-help file fully. * * The client might be restarted any number of times between * module reloads, we only build the debug-help file the first time.
*/ int orangefs_prepare_debugfs_help_string(int at_boot)
{ char *client_title = "Client Debug Keywords:\n"; char *kernel_title = "Kernel Debug Keywords:\n";
size_t string_size = DEBUG_HELP_STRING_SIZE;
size_t result_size;
size_t i; char *new; int rc = -EINVAL;
if (at_boot)
client_title = HELP_STRING_UNINITIALIZED;
/* build a new debug_help_string. */ new = kzalloc(DEBUG_HELP_STRING_SIZE, GFP_KERNEL); if (!new) {
rc = -ENOMEM; goto out;
}
/* * strlcat(dst, src, size) will append at most * "size - strlen(dst) - 1" bytes of src onto dst, * null terminating the result, and return the total * length of the string it tried to create. * * We'll just plow through here building our new debug * help string and let strlcat take care of assuring that * dst doesn't overflow.
*/
strlcat(new, client_title, string_size);
if (!at_boot) {
/* * fill the client keyword/mask array and remember * how many elements there were.
*/
cdm_element_count =
orangefs_prepare_cdm_array(client_debug_array_string); if (cdm_element_count <= 0) {
kfree(new); goto out;
}
for (i = 0; i < cdm_element_count; i++) {
strlcat(new, "\t", string_size);
strlcat(new, cdm_array[i].keyword, string_size);
strlcat(new, "\n", string_size);
}
}
/* * kernel = type 0 * client = type 1
*/ staticvoid debug_mask_to_string(void *mask, int type)
{ int i; int len = 0; char *debug_string; int element_count = 0;
/* * Some keywords, like "all" or "verbose", are amalgams of * numerous other keywords. Make a special check for those * before grinding through the whole mask only to find out * later...
*/ if (check_amalgam_keyword(mask, type)) goto out;
/* Build the debug string. */ for (i = 0; i < element_count; i++) if (type)
do_c_string(mask, i); else
do_k_string(mask, i);
staticint keyword_is_amalgam(char *keyword)
{ int rc = 0;
if ((!strcmp(keyword, ORANGEFS_ALL)) || (!strcmp(keyword, ORANGEFS_VERBOSE)))
rc = 1;
return rc;
}
/* * kernel = type 0 * client = type 1 * * return 1 if we found an amalgam.
*/ staticint check_amalgam_keyword(void *mask, int type)
{
__u64 *k_mask; struct client_debug_mask *c_mask; int k_all_index = num_kmod_keyword_mask_map - 1; int rc = 0;
if (type) {
c_mask = (struct client_debug_mask *) mask;
original_pointer = strsep_fodder; while ((unchecked_keyword = strsep(&strsep_fodder, ","))) if (strlen(unchecked_keyword)) { for (i = 0; i < element_count; i++) if (type)
do_c_mask(i,
unchecked_keyword,
&c_mask); else
do_k_mask(i,
unchecked_keyword,
&k_mask);
}
kfree(original_pointer);
}
staticvoid do_c_mask(int i, char *unchecked_keyword, struct client_debug_mask **sane_mask)
{
pr_info("%s: client debug mask has been been received " ":%llx: :%llx:\n",
__func__,
(unsignedlonglong)client_debug_mask.mask1,
(unsignedlonglong)client_debug_mask.mask2);
return ret;
}
int orangefs_debugfs_new_client_string(void __user *arg)
{ int ret;
ret = copy_from_user(&client_debug_array_string,
(void __user *)arg,
ORANGEFS_MAX_DEBUG_STRING_LEN);
/* * The real client-core makes an effort to ensure * that actual strings that aren't too long to fit in * this buffer is what we get here. We're going to use * string functions on the stuff we got, so we'll make * this extra effort to try and keep from * flowing out of this buffer when we use the string * functions, even if somehow the stuff we end up * with here is garbage.
*/
client_debug_array_string[ORANGEFS_MAX_DEBUG_STRING_LEN - 1] = '\0';
pr_info("%s: client debug array string has been received.\n",
__func__);
if (!help_string_initialized) {
/* Build a proper debug help string. */
ret = orangefs_prepare_debugfs_help_string(0); if (ret) {
gossip_err("%s: no debug help string \n",
__func__); return ret;
}
}
debug_mask_to_string(&client_debug_mask, 1);
debugfs_remove(client_debug_dentry);
orangefs_client_debug_init();
help_string_initialized++;
return 0;
}
int orangefs_debugfs_new_debug(void __user *arg)
{ struct dev_mask_info_s mask_info = {0}; int ret;
ret = copy_from_user(&mask_info,
(void __user *)arg, sizeof(mask_info));
if (ret != 0) return -EIO;
if (mask_info.mask_type == KERNEL_MASK) { if ((mask_info.mask_value == 0)
&& (kernel_mask_set_mod_init)) { /* * the kernel debug mask was set when the * kernel module was loaded; don't override * it if the client-core was started without * a value for ORANGEFS_KMODMASK.
*/ return 0;
}
debug_mask_to_string(&mask_info.mask_value,
mask_info.mask_type);
orangefs_gossip_debug_mask = mask_info.mask_value;
pr_info("%s: kernel debug mask has been modified to " ":%s: :%llx:\n",
__func__,
kernel_debug_string,
(unsignedlonglong)orangefs_gossip_debug_mask);
} elseif (mask_info.mask_type == CLIENT_MASK) {
debug_mask_to_string(&mask_info.mask_value,
mask_info.mask_type);
pr_info("%s: client debug mask has been modified to" ":%s: :%llx:\n",
__func__,
client_debug_string,
llu(mask_info.mask_value));
} else {
gossip_err("Invalid mask type....\n"); return -EINVAL;
}
return ret;
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.3 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.