mirror of
https://github.com/versity/scoutfs.git
synced 2026-01-05 03:44:05 +00:00
Add kvec key helpers
Add a suite of simple kvec functions to work with kvecs that point to file system keys. The ones worth mentioning format keys into strings. They're used to add formatted strings for the keys to tracepoints. They're still a little rough but this is a functional first step. Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
201
kmod/src/kvec.c
201
kmod/src/kvec.c
@@ -17,6 +17,7 @@
|
||||
#include <linux/magic.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/statfs.h>
|
||||
#include <linux/ctype.h>
|
||||
|
||||
#include "super.h"
|
||||
#include "format.h"
|
||||
@@ -33,6 +34,7 @@
|
||||
|
||||
struct iter {
|
||||
struct kvec *kvec;
|
||||
size_t count;
|
||||
size_t off;
|
||||
size_t i;
|
||||
};
|
||||
@@ -40,6 +42,7 @@ struct iter {
|
||||
static void iter_advance(struct iter *iter, size_t len)
|
||||
{
|
||||
iter->off += len;
|
||||
iter->count -= len;
|
||||
|
||||
while (iter->i < SCOUTFS_KVEC_NR && iter->off >= iter->kvec->iov_len) {
|
||||
iter->off -= iter->kvec->iov_len;
|
||||
@@ -53,6 +56,7 @@ static void iter_init(struct iter *iter, struct kvec *kvec)
|
||||
iter->kvec = kvec;
|
||||
iter->i = 0;
|
||||
iter->off = 0;
|
||||
iter->count = scoutfs_kvec_length(kvec);
|
||||
|
||||
iter_advance(iter, 0);
|
||||
}
|
||||
@@ -65,6 +69,7 @@ static void *iter_ptr(struct iter *iter)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* count of contiguous bytes available at the next vector */
|
||||
static size_t iter_contig(struct iter *iter)
|
||||
{
|
||||
if (iter->i < SCOUTFS_KVEC_NR)
|
||||
@@ -73,6 +78,12 @@ static size_t iter_contig(struct iter *iter)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* count of bytes remaining in the iteration */
|
||||
static size_t iter_count(struct iter *iter)
|
||||
{
|
||||
return iter->count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the result of memcmp between the min of the two total lengths.
|
||||
* If their shorter lengths are equal than the shorter length is considered
|
||||
@@ -101,8 +112,9 @@ int scoutfs_kvec_memcmp(struct kvec *a, struct kvec *b)
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns 0 if [a,b] overlaps with [c,d]. Returns -1 if a < c and
|
||||
* 1 if b > d.
|
||||
* Return -1 if [a,b] doesn't overlap with and is to the left of [c,d],
|
||||
* 1 if it doesn't overlap and is to the right of, and 0 if they
|
||||
* overlap.
|
||||
*/
|
||||
int scoutfs_kvec_cmp_overlap(struct kvec *a, struct kvec *b,
|
||||
struct kvec *c, struct kvec *d)
|
||||
@@ -181,8 +193,10 @@ int scoutfs_kvec_dup_flatten(struct kvec *dst, struct kvec *src)
|
||||
size_t len = scoutfs_kvec_length(src);
|
||||
|
||||
ptr = kmalloc(len, GFP_NOFS);
|
||||
if (!ptr)
|
||||
if (!ptr) {
|
||||
scoutfs_kvec_init_null(dst);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
scoutfs_kvec_init(dst, ptr, len);
|
||||
scoutfs_kvec_memcpy(dst, src);
|
||||
@@ -215,3 +229,184 @@ void scoutfs_kvec_swap(struct kvec *a, struct kvec *b)
|
||||
memcpy(a, b, SCOUTFS_KVEC_BYTES);
|
||||
memcpy(b, tmp, SCOUTFS_KVEC_BYTES);
|
||||
}
|
||||
|
||||
int scoutfs_kvec_alloc_key(struct kvec *kvec)
|
||||
{
|
||||
const size_t len = SCOUTFS_MAX_KEY_SIZE;
|
||||
void *ptr;
|
||||
|
||||
ptr = kzalloc(len, GFP_NOFS);
|
||||
if (!ptr) {
|
||||
scoutfs_kvec_init_null(kvec);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
scoutfs_kvec_init(kvec, ptr, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void scoutfs_kvec_init_key(struct kvec *kvec)
|
||||
{
|
||||
scoutfs_kvec_init(kvec, kvec[0].iov_base, SCOUTFS_MAX_KEY_SIZE);
|
||||
}
|
||||
|
||||
void scoutfs_kvec_set_max_key(struct kvec *kvec)
|
||||
{
|
||||
__u8 *type = kvec[0].iov_base;
|
||||
|
||||
*type = SCOUTFS_MAX_UNUSED_KEY;
|
||||
scoutfs_kvec_init(kvec, type, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clone the source kvec into the dst if the dst is empty or if
|
||||
* the src kvec is less than the dst.
|
||||
*/
|
||||
void scoutfs_kvec_clone_less(struct kvec *dst, struct kvec *src)
|
||||
{
|
||||
if (scoutfs_kvec_length(dst) == 0 ||
|
||||
scoutfs_kvec_memcmp(src, dst) < 0)
|
||||
scoutfs_kvec_clone(dst, src);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy bytes from the kvec iterator into the dest buffer, zeroing the
|
||||
* remainder of the buffer if there aren't enough bytes available in
|
||||
* the iterator. If the tail bool is set then the kvec data is copied
|
||||
* into the tail of the buffer and the head is zeroed.
|
||||
*/
|
||||
static bool iter_memcpy_zero(void *dst, struct iter *src, size_t len, bool tail)
|
||||
{
|
||||
size_t ctg;
|
||||
size_t diff;
|
||||
|
||||
if (len == 0 || iter_count(src) == 0)
|
||||
return false;
|
||||
|
||||
if (iter_count(src) < len) {
|
||||
diff = len - iter_count(src);
|
||||
if (tail) {
|
||||
memset(dst, 0, diff);
|
||||
dst += diff;
|
||||
} else {
|
||||
memset(dst + len - diff, 0, diff);
|
||||
}
|
||||
len = iter_count(src);
|
||||
}
|
||||
|
||||
while ((ctg = min(len, iter_contig(src)))) {
|
||||
memcpy(dst, iter_ptr(src), ctg);
|
||||
iter_advance(src, ctg);
|
||||
dst += ctg;
|
||||
len -= ctg;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int iter_puts_printable(char *dst, struct iter *src)
|
||||
{
|
||||
int len = iter_count(src);
|
||||
size_t ctg;
|
||||
int i;
|
||||
|
||||
while ((ctg = iter_contig(src))) {
|
||||
memcpy(dst, iter_ptr(src), ctg);
|
||||
iter_advance(src, ctg);
|
||||
|
||||
for (i = 0; i < ctg; i++) {
|
||||
if (!isprint(dst[i]))
|
||||
dst[i] = '_';
|
||||
}
|
||||
|
||||
dst += ctg;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
#define EMPTY_STR "''"
|
||||
#define U64_U_BYTES 20
|
||||
#define U64_D_BYTES 21
|
||||
#define U64_X_BYTES 16
|
||||
|
||||
/*
|
||||
* XXX figure out what to do about corrupt keys.
|
||||
*/
|
||||
|
||||
unsigned scoutfs_kvec_key_strlen(struct kvec *key)
|
||||
{
|
||||
struct iter iter;
|
||||
unsigned len = 0;
|
||||
u8 type;
|
||||
|
||||
iter_init(&iter, key);
|
||||
|
||||
if (iter_count(&iter) == 0) {
|
||||
len = sizeof(EMPTY_STR) - 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
iter_memcpy_zero(&type, &iter, sizeof(type), false);
|
||||
|
||||
len = 4; /* "typ." */
|
||||
|
||||
switch(type) {
|
||||
case SCOUTFS_INODE_KEY:
|
||||
len += U64_U_BYTES;
|
||||
break;
|
||||
case SCOUTFS_DIRENT_KEY:
|
||||
len += U64_U_BYTES + (iter_count(&iter) - 8);
|
||||
break;
|
||||
case SCOUTFS_MAX_UNUSED_KEY:
|
||||
break;
|
||||
default:
|
||||
/* hex of everything after the type */
|
||||
len += (scoutfs_kvec_length(key) - 1) * 2;
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
return len + 1; /* null term */
|
||||
}
|
||||
|
||||
void scoutfs_kvec_key_sprintf(char *buf, struct kvec *key)
|
||||
{
|
||||
struct iter iter;
|
||||
__be64 be;
|
||||
u8 type;
|
||||
|
||||
iter_init(&iter, key);
|
||||
|
||||
if (iter_contig(&iter) == 0) {
|
||||
buf += sprintf(buf, EMPTY_STR);
|
||||
goto done;
|
||||
}
|
||||
|
||||
iter_memcpy_zero(&type, &iter, sizeof(type), false);
|
||||
|
||||
switch(type) {
|
||||
case SCOUTFS_INODE_KEY:
|
||||
buf += sprintf(buf, "ino.");
|
||||
iter_memcpy_zero(&be, &iter, sizeof(be), false);
|
||||
buf += sprintf(buf, "%llu", be64_to_cpu(be));
|
||||
break;
|
||||
case SCOUTFS_DIRENT_KEY:
|
||||
buf += sprintf(buf, "den.");
|
||||
iter_memcpy_zero(&be, &iter, sizeof(be), false);
|
||||
buf += sprintf(buf, "%llu.", be64_to_cpu(be));
|
||||
buf += iter_puts_printable(buf, &iter);
|
||||
break;
|
||||
case SCOUTFS_MAX_UNUSED_KEY:
|
||||
buf += sprintf(buf, "max");
|
||||
break;
|
||||
default:
|
||||
buf += sprintf(buf, "unk.");
|
||||
while (iter_memcpy_zero(&be, &iter, sizeof(be), true))
|
||||
buf += sprintf(buf, "%llx", be64_to_cpu(be));
|
||||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
*buf = '\0';
|
||||
}
|
||||
|
||||
@@ -62,5 +62,11 @@ int scoutfs_kvec_dup_flatten(struct kvec *dst, struct kvec *src);
|
||||
void scoutfs_kvec_kfree(struct kvec *kvec);
|
||||
void scoutfs_kvec_init_null(struct kvec *kvec);
|
||||
void scoutfs_kvec_swap(struct kvec *a, struct kvec *b);
|
||||
int scoutfs_kvec_alloc_key(struct kvec *kvec);
|
||||
void scoutfs_kvec_init_key(struct kvec *kvec);
|
||||
void scoutfs_kvec_set_max_key(struct kvec *kvec);
|
||||
void scoutfs_kvec_clone_less(struct kvec *dst, struct kvec *src);
|
||||
unsigned scoutfs_kvec_key_strlen(struct kvec *key);
|
||||
void scoutfs_kvec_key_sprintf(char *buf, struct kvec *key);
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user