jump label: Convert dynamic debug to use jump labels
Convert the 'dynamic debug' infrastructure to use jump labels. Signed-off-by: Jason Baron <jbaron@redhat.com> LKML-Reference: <b77627358cea3e27d7be4386f45f66219afb8452.1284733808.git.jbaron@redhat.com> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
This commit is contained in:
parent
8f7b50c514
commit
52159d98be
5 changed files with 26 additions and 132 deletions
|
@ -1,6 +1,8 @@
|
|||
#ifndef _DYNAMIC_DEBUG_H
|
||||
#define _DYNAMIC_DEBUG_H
|
||||
|
||||
#include <linux/jump_label.h>
|
||||
|
||||
/* dynamic_printk_enabled, and dynamic_printk_enabled2 are bitmasks in which
|
||||
* bit n is set to 1 if any modname hashes into the bucket n, 0 otherwise. They
|
||||
* use independent hash functions, to reduce the chance of false positives.
|
||||
|
@ -22,8 +24,6 @@ struct _ddebug {
|
|||
const char *function;
|
||||
const char *filename;
|
||||
const char *format;
|
||||
char primary_hash;
|
||||
char secondary_hash;
|
||||
unsigned int lineno:24;
|
||||
/*
|
||||
* The flags field controls the behaviour at the callsite.
|
||||
|
@ -33,6 +33,7 @@ struct _ddebug {
|
|||
#define _DPRINTK_FLAGS_PRINT (1<<0) /* printk() a message using the format */
|
||||
#define _DPRINTK_FLAGS_DEFAULT 0
|
||||
unsigned int flags:8;
|
||||
char enabled;
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
|
||||
|
@ -42,33 +43,35 @@ int ddebug_add_module(struct _ddebug *tab, unsigned int n,
|
|||
#if defined(CONFIG_DYNAMIC_DEBUG)
|
||||
extern int ddebug_remove_module(const char *mod_name);
|
||||
|
||||
#define __dynamic_dbg_enabled(dd) ({ \
|
||||
int __ret = 0; \
|
||||
if (unlikely((dynamic_debug_enabled & (1LL << DEBUG_HASH)) && \
|
||||
(dynamic_debug_enabled2 & (1LL << DEBUG_HASH2)))) \
|
||||
if (unlikely(dd.flags)) \
|
||||
__ret = 1; \
|
||||
__ret; })
|
||||
|
||||
#define dynamic_pr_debug(fmt, ...) do { \
|
||||
__label__ do_printk; \
|
||||
__label__ out; \
|
||||
static struct _ddebug descriptor \
|
||||
__used \
|
||||
__attribute__((section("__verbose"), aligned(8))) = \
|
||||
{ KBUILD_MODNAME, __func__, __FILE__, fmt, DEBUG_HASH, \
|
||||
DEBUG_HASH2, __LINE__, _DPRINTK_FLAGS_DEFAULT }; \
|
||||
if (__dynamic_dbg_enabled(descriptor)) \
|
||||
{ KBUILD_MODNAME, __func__, __FILE__, fmt, __LINE__, \
|
||||
_DPRINTK_FLAGS_DEFAULT }; \
|
||||
JUMP_LABEL(&descriptor.enabled, do_printk); \
|
||||
goto out; \
|
||||
do_printk: \
|
||||
printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); \
|
||||
out: ; \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define dynamic_dev_dbg(dev, fmt, ...) do { \
|
||||
__label__ do_printk; \
|
||||
__label__ out; \
|
||||
static struct _ddebug descriptor \
|
||||
__used \
|
||||
__attribute__((section("__verbose"), aligned(8))) = \
|
||||
{ KBUILD_MODNAME, __func__, __FILE__, fmt, DEBUG_HASH, \
|
||||
DEBUG_HASH2, __LINE__, _DPRINTK_FLAGS_DEFAULT }; \
|
||||
if (__dynamic_dbg_enabled(descriptor)) \
|
||||
{ KBUILD_MODNAME, __func__, __FILE__, fmt, __LINE__, \
|
||||
_DPRINTK_FLAGS_DEFAULT }; \
|
||||
JUMP_LABEL(&descriptor.enabled, do_printk); \
|
||||
goto out; \
|
||||
do_printk: \
|
||||
dev_printk(KERN_DEBUG, dev, fmt, ##__VA_ARGS__); \
|
||||
out: ; \
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
|
|
|
@ -26,19 +26,11 @@
|
|||
#include <linux/dynamic_debug.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/jump_label.h>
|
||||
|
||||
extern struct _ddebug __start___verbose[];
|
||||
extern struct _ddebug __stop___verbose[];
|
||||
|
||||
/* dynamic_debug_enabled, and dynamic_debug_enabled2 are bitmasks in which
|
||||
* bit n is set to 1 if any modname hashes into the bucket n, 0 otherwise. They
|
||||
* use independent hash functions, to reduce the chance of false positives.
|
||||
*/
|
||||
long long dynamic_debug_enabled;
|
||||
EXPORT_SYMBOL_GPL(dynamic_debug_enabled);
|
||||
long long dynamic_debug_enabled2;
|
||||
EXPORT_SYMBOL_GPL(dynamic_debug_enabled2);
|
||||
|
||||
struct ddebug_table {
|
||||
struct list_head link;
|
||||
char *mod_name;
|
||||
|
@ -87,26 +79,6 @@ static char *ddebug_describe_flags(struct _ddebug *dp, char *buf,
|
|||
return buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* must be called with ddebug_lock held
|
||||
*/
|
||||
|
||||
static int disabled_hash(char hash, bool first_table)
|
||||
{
|
||||
struct ddebug_table *dt;
|
||||
char table_hash_value;
|
||||
|
||||
list_for_each_entry(dt, &ddebug_tables, link) {
|
||||
if (first_table)
|
||||
table_hash_value = dt->ddebugs->primary_hash;
|
||||
else
|
||||
table_hash_value = dt->ddebugs->secondary_hash;
|
||||
if (dt->num_enabled && (hash == table_hash_value))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Search the tables for _ddebug's which match the given
|
||||
* `query' and apply the `flags' and `mask' to them. Tells
|
||||
|
@ -170,17 +142,9 @@ static void ddebug_change(const struct ddebug_query *query,
|
|||
dt->num_enabled++;
|
||||
dp->flags = newflags;
|
||||
if (newflags) {
|
||||
dynamic_debug_enabled |=
|
||||
(1LL << dp->primary_hash);
|
||||
dynamic_debug_enabled2 |=
|
||||
(1LL << dp->secondary_hash);
|
||||
enable_jump_label(&dp->enabled);
|
||||
} else {
|
||||
if (disabled_hash(dp->primary_hash, true))
|
||||
dynamic_debug_enabled &=
|
||||
~(1LL << dp->primary_hash);
|
||||
if (disabled_hash(dp->secondary_hash, false))
|
||||
dynamic_debug_enabled2 &=
|
||||
~(1LL << dp->secondary_hash);
|
||||
disable_jump_label(&dp->enabled);
|
||||
}
|
||||
if (verbose)
|
||||
printk(KERN_INFO
|
||||
|
|
|
@ -101,14 +101,6 @@ basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))"
|
|||
modname_flags = $(if $(filter 1,$(words $(modname))),\
|
||||
-D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))")
|
||||
|
||||
#hash values
|
||||
ifdef CONFIG_DYNAMIC_DEBUG
|
||||
debug_flags = -D"DEBUG_HASH=$(shell ./scripts/basic/hash djb2 $(@D)$(modname))"\
|
||||
-D"DEBUG_HASH2=$(shell ./scripts/basic/hash r5 $(@D)$(modname))"
|
||||
else
|
||||
debug_flags =
|
||||
endif
|
||||
|
||||
orig_c_flags = $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(KBUILD_SUBDIR_CCFLAGS) \
|
||||
$(ccflags-y) $(CFLAGS_$(basetarget).o)
|
||||
_c_flags = $(filter-out $(CFLAGS_REMOVE_$(basetarget).o), $(orig_c_flags))
|
||||
|
@ -152,8 +144,7 @@ endif
|
|||
|
||||
c_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \
|
||||
$(__c_flags) $(modkern_cflags) \
|
||||
-D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags) \
|
||||
$(debug_flags)
|
||||
-D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags)
|
||||
|
||||
a_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \
|
||||
$(__a_flags) $(modkern_aflags)
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
# fixdep: Used to generate dependency information during build process
|
||||
# docproc: Used in Documentation/DocBook
|
||||
|
||||
hostprogs-y := fixdep docproc hash
|
||||
hostprogs-y := fixdep docproc
|
||||
always := $(hostprogs-y)
|
||||
|
||||
# fixdep is needed to compile other host programs
|
||||
|
|
|
@ -1,64 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2008 Red Hat, Inc., Jason Baron <jbaron@redhat.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define DYNAMIC_DEBUG_HASH_BITS 6
|
||||
|
||||
static const char *program;
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf("Usage: %s <djb2|r5> <modname>\n", program);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* djb2 hashing algorithm by Dan Bernstein. From:
|
||||
* http://www.cse.yorku.ca/~oz/hash.html
|
||||
*/
|
||||
|
||||
static unsigned int djb2_hash(char *str)
|
||||
{
|
||||
unsigned long hash = 5381;
|
||||
int c;
|
||||
|
||||
c = *str;
|
||||
while (c) {
|
||||
hash = ((hash << 5) + hash) + c;
|
||||
c = *++str;
|
||||
}
|
||||
return (unsigned int)(hash & ((1 << DYNAMIC_DEBUG_HASH_BITS) - 1));
|
||||
}
|
||||
|
||||
static unsigned int r5_hash(char *str)
|
||||
{
|
||||
unsigned long hash = 0;
|
||||
int c;
|
||||
|
||||
c = *str;
|
||||
while (c) {
|
||||
hash = (hash + (c << 4) + (c >> 4)) * 11;
|
||||
c = *++str;
|
||||
}
|
||||
return (unsigned int)(hash & ((1 << DYNAMIC_DEBUG_HASH_BITS) - 1));
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
program = argv[0];
|
||||
|
||||
if (argc != 3)
|
||||
usage();
|
||||
if (!strcmp(argv[1], "djb2"))
|
||||
printf("%d\n", djb2_hash(argv[2]));
|
||||
else if (!strcmp(argv[1], "r5"))
|
||||
printf("%d\n", r5_hash(argv[2]));
|
||||
else
|
||||
usage();
|
||||
exit(0);
|
||||
}
|
||||
|
Loading…
Reference in a new issue