Files
scoutfs/kmod/src/key.h
T
Zach Brown 1485b02554 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 <zab@versity.com>
2017-06-06 14:48:09 -07:00

161 lines
4.5 KiB
C

#ifndef _SCOUTFS_KEY_H_
#define _SCOUTFS_KEY_H_
#include <linux/types.h>
#include "format.h"
struct scoutfs_key_buf {
void *data;
u16 key_len;
u16 buf_len;
};
struct scoutfs_key_buf *scoutfs_key_alloc(struct super_block *sb, u16 len);
struct scoutfs_key_buf *scoutfs_key_dup(struct super_block *sb,
struct scoutfs_key_buf *key);
void scoutfs_key_free(struct super_block *sb, struct scoutfs_key_buf *key);
void scoutfs_key_inc(struct scoutfs_key_buf *key);
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
* callers, for example, search for a small key and get a larger key
* copied in.
*/
static inline void scoutfs_key_init_buf_len(struct scoutfs_key_buf *key,
void *data, u16 key_len,
u16 buf_len)
{
WARN_ON_ONCE(buf_len > SCOUTFS_MAX_KEY_SIZE);
WARN_ON_ONCE(key_len > buf_len);
key->data = data;
key->key_len = key_len;
key->buf_len = buf_len;
}
/*
* Point the key buf, usually statically allocated, at an existing
* contiguous key stored elsewhere.
*/
static inline void scoutfs_key_init(struct scoutfs_key_buf *key,
void *data, u16 len)
{
scoutfs_key_init_buf_len(key, data, len, len);
}
/*
* Compare the fs keys in segment sort order.
*/
static inline int scoutfs_key_compare(struct scoutfs_key_buf *a,
struct scoutfs_key_buf *b)
{
return memcmp(a->data, b->data, min(a->key_len, b->key_len)) ?:
a->key_len < b->key_len ? -1 : a->key_len > b->key_len ? 1 : 0;
}
/*
* Compare ranges of keys where overlapping is equality. Returns:
* -1: a_end < b_start
* 1: a_start > b_end
* else 0: ranges overlap
*/
static inline int scoutfs_key_compare_ranges(struct scoutfs_key_buf *a_start,
struct scoutfs_key_buf *a_end,
struct scoutfs_key_buf *b_start,
struct scoutfs_key_buf *b_end)
{
return scoutfs_key_compare(a_end, b_start) < 0 ? -1 :
scoutfs_key_compare(a_start, b_end) > 0 ? 1 :
0;
}
/*
* Copy as much of the contents of the source buffer that fits into the
* dest buffer.
*/
static inline void scoutfs_key_copy(struct scoutfs_key_buf *dst,
struct scoutfs_key_buf *src)
{
dst->key_len = min(dst->buf_len, src->key_len);
memcpy(dst->data, src->data, dst->key_len);
}
/*
* Initialize the dst buffer to point to the source buffer in all ways,
* including the buf len. The contents of the buffer are shared by the
* fields describing the buffers are not.
*/
static inline void scoutfs_key_clone(struct scoutfs_key_buf *dst,
struct scoutfs_key_buf *src)
{
*dst = *src;
}
/*
* Memset as much of the length as fits in the buffer and set that to
* the new key length.
*/
static inline void scoutfs_key_memset(struct scoutfs_key_buf *key, int c,
u16 len)
{
if (WARN_ON_ONCE(len > SCOUTFS_MAX_KEY_SIZE))
return;
key->key_len = min(key->buf_len, len);
memset(key->data, c, key->key_len);
}
/*
* Set the contents of the buffer to the smallest possible key by sort
* order. It might be truncated if the buffer isn't large enough.
*/
static inline void scoutfs_key_set_min(struct scoutfs_key_buf *key)
{
scoutfs_key_memset(key, 0, sizeof(struct scoutfs_inode_key));
}
/*
* Set the contents of the buffer to the largest possible key by sort
* order. It might be truncated if the buffer isn't large enough.
*/
static inline void scoutfs_key_set_max(struct scoutfs_key_buf *key)
{
scoutfs_key_memset(key, 0xff, sizeof(struct scoutfs_inode_key));
}
#endif