summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/linux/dynamic_fault.h3
-rw-r--r--lib/dynamic_fault.c118
2 files changed, 88 insertions, 33 deletions
diff --git a/include/linux/dynamic_fault.h b/include/linux/dynamic_fault.h
index c090547b39e5..850ebe1053ee 100644
--- a/include/linux/dynamic_fault.h
+++ b/include/linux/dynamic_fault.h
@@ -14,7 +14,8 @@ struct _dfault {
const char *modname;
const char *function;
const char *filename;
- unsigned int lineno:24;
+ unsigned int lineno:16;
+ unsigned int index:16;
/*
* The flags field controls the behaviour at the callsite.
* The bits here are changed dynamically when the user
diff --git a/lib/dynamic_fault.c b/lib/dynamic_fault.c
index b8668a5d33d0..d55cec90bf8f 100644
--- a/lib/dynamic_fault.c
+++ b/lib/dynamic_fault.c
@@ -1,7 +1,7 @@
/*
* lib/dynamic_fault.c
*
- * make fault() calls runtime configurable based upon their
+ * make dynamic_fault() calls runtime configurable based upon their
* source module.
*
* Copyright (C) 2011 Adam Berkan <aberkan@google.com>
@@ -55,6 +55,7 @@ struct dfault_query {
const char *module;
const char *function;
unsigned int first_lineno, last_lineno;
+ unsigned int first_index, last_index;
};
struct dfault_iter {
@@ -101,8 +102,8 @@ static char *dfault_describe_flags(struct _dfault *df, char *buf,
* the user which dfault's were changed, or whether none
* were matched.
*/
-static void dfault_change(const struct dfault_query *query,
- unsigned int flags, unsigned int mask)
+static int dfault_change(const struct dfault_query *query,
+ unsigned int flags, unsigned int mask)
{
int i;
struct dfault_table *dt;
@@ -141,6 +142,14 @@ static void dfault_change(const struct dfault_query *query,
df->lineno > query->last_lineno)
continue;
+ /* match against the fault index */
+ if (query->first_index &&
+ df->index < query->first_index)
+ continue;
+ if (query->last_index &&
+ df->index > query->last_index)
+ continue;
+
nfound++;
newflags = (df->flags & mask) | flags;
@@ -158,17 +167,21 @@ static void dfault_change(const struct dfault_query *query,
if (verbose)
printk(KERN_INFO
- "dfault: changed %s:%d [%s]%s %s\n",
- df->filename, df->lineno,
- dt->mod_name, df->function,
- dfault_describe_flags(df, flagbuf,
- sizeof(flagbuf)));
+ "dfault: changed %s:%d [%s]%s #%d %s\n",
+ df->filename, df->lineno,
+ dt->mod_name, df->function, df->index,
+ dfault_describe_flags(df, flagbuf,
+ sizeof(flagbuf)));
}
}
mutex_unlock(&dfault_lock);
- if (!nfound && verbose)
+ if (!nfound && verbose) {
printk(KERN_INFO "dfault: no matches for query\n");
+ return -ENOENT;
+ }
+
+ return 0;
}
/*
@@ -226,11 +239,11 @@ static int dfault_tokenize(char *buf, char *words[], int maxwords)
}
/*
- * Parse a single line number. Note that the empty string ""
- * is treated as a special case and converted to zero, which
+ * Parse a single number. Note that the empty string "" is
+ * treated as a special case and converted to zero, which
* is later treated as a "don't care" value.
*/
-static inline int parse_lineno(const char *str, unsigned int *val)
+static inline int parse_number(const char *str, unsigned int *val)
{
char *end = NULL;
BUG_ON(str == NULL);
@@ -243,6 +256,31 @@ static inline int parse_lineno(const char *str, unsigned int *val)
}
/*
+ * Parse a range.
+ */
+static inline int parse_range(char *str,
+ unsigned int *first,
+ unsigned int *last)
+{
+ char *first_str = str;
+ char *last_str = strchr(first_str, '-');
+
+ if (last_str)
+ *last_str++ = '\0';
+ if (parse_number(first_str, first) < 0)
+ return -EINVAL;
+ if (last_str != NULL) {
+ /* range <first>-<last> */
+ if (parse_number(last_str, last) < 0)
+ return -EINVAL;
+ } else {
+ *last = *first;
+ }
+
+ return 0;
+}
+
+/*
* Parse words[] as a dfault query specification, which is a series
* of (keyword, value) pairs chosen from these possibilities:
*
@@ -252,6 +290,8 @@ static inline int parse_lineno(const char *str, unsigned int *val)
* module <module-name>
* line <lineno>
* line <first-lineno>-<last-lineno> // where either may be empty
+ * index <m>-<n> // dynamic faults numbered from <m>
+ * // to <n> inside each matching function
*/
static int dfault_parse_query(char *words[], int nwords,
struct dfault_query *query)
@@ -271,19 +311,13 @@ static int dfault_parse_query(char *words[], int nwords,
else if (!strcmp(words[i], "module"))
query->module = words[i+1];
else if (!strcmp(words[i], "line")) {
- char *first = words[i+1];
- char *last = strchr(first, '-');
- if (last)
- *last++ = '\0';
- if (parse_lineno(first, &query->first_lineno) < 0)
- return -EINVAL;
- if (last != NULL) {
- /* range <first>-<last> */
- if (parse_lineno(last, &query->last_lineno) < 0)
- return -EINVAL;
- } else {
- query->last_lineno = query->first_lineno;
- }
+ parse_range(words[i+1],
+ &query->first_lineno,
+ &query->last_lineno);
+ } else if (!strcmp(words[i], "index")) {
+ parse_range(words[i+1],
+ &query->first_index,
+ &query->last_index);
} else {
if (verbose)
printk(KERN_ERR "%s: unknown keyword \"%s\"\n",
@@ -294,10 +328,11 @@ static int dfault_parse_query(char *words[], int nwords,
if (verbose)
printk(KERN_INFO "%s: q->function=\"%s\" q->filename=\"%s\" "
- "q->module=\"%s\" q->lineno=%u-%u\n",
+ "q->module=\"%s\" q->lineno=%u-%u\n q->index=%u-%u",
__func__, query->function, query->filename,
- query->module, query->first_lineno,
- query->last_lineno);
+ query->module,
+ query->first_lineno, query->last_lineno,
+ query->first_index, query->last_index);
return 0;
}
@@ -378,6 +413,7 @@ static ssize_t dfault_proc_write(struct file *file, const char __user *ubuf,
int nwords;
char *words[MAXWORDS];
char tmpbuf[256];
+ int ret;
if (len == 0)
return 0;
@@ -400,7 +436,9 @@ static ssize_t dfault_proc_write(struct file *file, const char __user *ubuf,
return -EINVAL;
/* actually go and implement the change */
- dfault_change(&query, flags, mask);
+ ret = dfault_change(&query, flags, mask);
+ if (ret < 0)
+ return ret;
*offp += len;
return len;
@@ -514,13 +552,14 @@ static int dfault_proc_show(struct seq_file *m, void *p)
if (p == SEQ_START_TOKEN) {
seq_puts(m,
- "# filename:lineno [module]function flags format\n");
+ "# filename:lineno [module]function index "
+ "flags format\n");
return 0;
}
- seq_printf(m, "%s:%u [%s]%s %s \"",
+ seq_printf(m, "%s:%u [%s]%s %d %s \"",
df->filename, df->lineno,
- iter->table->mod_name, df->function,
+ iter->table->mod_name, df->function, df->index,
dfault_describe_flags(df, flagsbuf, sizeof(flagsbuf)));
seq_puts(m, "\"\n");
@@ -591,6 +630,9 @@ int dfault_add_module(struct _dfault *tab, unsigned int n,
{
struct dfault_table *dt;
char *new_name;
+ const char *func;
+ unsigned index;
+ int i;
dt = kzalloc(sizeof(*dt), GFP_KERNEL);
if (dt == NULL)
@@ -609,6 +651,18 @@ int dfault_add_module(struct _dfault *tab, unsigned int n,
list_add_tail(&dt->link, &dfault_tables);
mutex_unlock(&dfault_lock);
+ index = 1;
+ func = NULL;
+
+ /* __attribute__(("section")) emits things in reverse order */
+ for (i = n - 1; i >= 0; i--) {
+ if (!func || strcmp(tab[i].function, func)) {
+ index = 1;
+ func = tab[i].function;
+ }
+ tab[i].index = index++;
+ }
+
if (verbose)
printk(KERN_INFO "%u debug prints in module %s\n",
n, dt->mod_name);