From 1485b0255482bf579698db46071af3a1860f0a9f Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Tue, 6 Jun 2017 14:48:09 -0700 Subject: [PATCH] scoutfs: add SK_ helpers for printing keys Add some percpu string buffers so that we can pass formatted strings as arguments when printing keys. The percpu struct uses a different buffer for each argument. We wrap the whole print call in a wrapper that disables and enables preemption. Signed-off-by: Zach Brown --- kmod/src/key.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++-- kmod/src/key.h | 29 ++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 2 deletions(-) diff --git a/kmod/src/key.c b/kmod/src/key.c index 5b33d637..63963782 100644 --- a/kmod/src/key.c +++ b/kmod/src/key.c @@ -116,9 +116,8 @@ void scoutfs_key_dec(struct scoutfs_key_buf *key) * * XXX nonprintable characters in the trace? */ -int scoutfs_key_str(char *buf, struct scoutfs_key_buf *key) +int scoutfs_key_str_size(char *buf, struct scoutfs_key_buf *key, size_t size) { - size_t size = buf ? INT_MAX : 0; int len; u8 type; @@ -170,3 +169,55 @@ int scoutfs_key_str(char *buf, struct scoutfs_key_buf *key) return snprintf_null(buf, size, "[truncated type %u len %u]", type, key->key_len); } + +/* + * A null buf can be set to find the length of the formatted string. + */ +int scoutfs_key_str(char *buf, struct scoutfs_key_buf *key) +{ + return scoutfs_key_str_size(buf, key, buf ? INT_MAX : 0); +} + +#define MAX_STR_COUNT 10 + +struct key_strings { + bool started; + int next_str; + char strings[MAX_STR_COUNT][SK_STR_BYTES]; +}; + +static DEFINE_PER_CPU(struct key_strings, percpu_key_strings); + +void scoutfs_key_start_percpu(void) +{ + struct key_strings *ks = this_cpu_ptr(&percpu_key_strings); + + BUG_ON(ks->started); + ks->started = true; + get_cpu(); +} + +char *scoutfs_key_percpu_string(void) +{ + struct key_strings *ks = this_cpu_ptr(&percpu_key_strings); + char *str; + + BUG_ON(!ks->started); + + str = ks->strings[ks->next_str++]; + BUG_ON(ks->next_str >= MAX_STR_COUNT); + + return str; +} + +void scoutfs_key_finish_percpu(void) +{ + struct key_strings *ks = this_cpu_ptr(&percpu_key_strings); + + BUG_ON(!ks->started); + + ks->next_str = 0; + ks->started = false; + + put_cpu(); +} diff --git a/kmod/src/key.h b/kmod/src/key.h index 26f4b499..bdeafb57 100644 --- a/kmod/src/key.h +++ b/kmod/src/key.h @@ -19,7 +19,36 @@ void scoutfs_key_inc_cur_len(struct scoutfs_key_buf *key); void scoutfs_key_dec(struct scoutfs_key_buf *key); void scoutfs_key_dec_cur_len(struct scoutfs_key_buf *key); +int scoutfs_key_str_size(char *buf, struct scoutfs_key_buf *key, size_t size); int scoutfs_key_str(char *buf, struct scoutfs_key_buf *key); +void scoutfs_key_start_percpu(void); +char *scoutfs_key_percpu_string(void); +void scoutfs_key_finish_percpu(void); + +#define SK_PCPU(statements) do { \ + scoutfs_key_start_percpu(); \ + { statements; } \ + scoutfs_key_finish_percpu(); \ +} while (0) + +/* + * The biggest keys are typically a little struct then a large name. The + * string representation will tend to be mostly the name, but some of the + * strict fields can blow up from say 8 bytes to 20 bytes. So we give + * a lot of padding for that. + */ +#define SK_STR_BYTES (100 + SCOUTFS_MAX_KEY_SIZE) + +#define SK_FMT "%s" +#define SK_ARG(k) \ +({ \ + char *__str = scoutfs_key_percpu_string(); \ + scoutfs_key_str_size(__str, k, SK_STR_BYTES); \ + __str; \ +}) + +#define SK_TRACE_PRINTK(args...) SK_PCPU(trace_printk(args)) +#define SK_PRINTK(args...) SK_PCPU(printk(args)) /* * Initialize a small key in a larger allocated buffer. This lets