mirror of
https://github.com/versity/scoutfs.git
synced 2026-02-07 19:20:44 +00:00
Add all the missing key types to scoutfs_key_str() so that we can get traces and printks of all key types. Signed-off-by: Zach Brown <zab@versity.com>
303 lines
7.3 KiB
C
303 lines
7.3 KiB
C
/*
|
|
* Copyright (C) 2017 Versity Software, Inc. All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public
|
|
* License v2 as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*/
|
|
#include <linux/kernel.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/slab.h>
|
|
|
|
#include "key.h"
|
|
|
|
struct scoutfs_key_buf *scoutfs_key_alloc(struct super_block *sb, u16 len)
|
|
{
|
|
struct scoutfs_key_buf *key;
|
|
|
|
if (WARN_ON_ONCE(len > SCOUTFS_MAX_KEY_SIZE))
|
|
return NULL;
|
|
|
|
key = kmalloc(sizeof(struct scoutfs_key_buf) + len, GFP_NOFS);
|
|
if (key) {
|
|
key->data = key + 1;
|
|
key->key_len = len;
|
|
key->buf_len = len;
|
|
}
|
|
|
|
return key;
|
|
}
|
|
|
|
struct scoutfs_key_buf *scoutfs_key_dup(struct super_block *sb,
|
|
struct scoutfs_key_buf *key)
|
|
{
|
|
struct scoutfs_key_buf *dup;
|
|
|
|
dup = scoutfs_key_alloc(sb, key->key_len);
|
|
if (dup)
|
|
memcpy(dup->data, key->data, dup->key_len);
|
|
return dup;
|
|
}
|
|
|
|
void scoutfs_key_free(struct super_block *sb, struct scoutfs_key_buf *key)
|
|
{
|
|
kfree(key);
|
|
}
|
|
|
|
/*
|
|
* Keys are large multi-byte big-endian values. To correctly increase
|
|
* or decrease keys we need to start by extending the key to the full
|
|
* precision using the max key size, setting the least significant bytes
|
|
* to 0.
|
|
*/
|
|
static void extend_zeros(struct scoutfs_key_buf *key)
|
|
{
|
|
if (key->key_len < SCOUTFS_MAX_KEY_SIZE &&
|
|
!WARN_ON_ONCE(key->buf_len != SCOUTFS_MAX_KEY_SIZE)) {
|
|
memset(key->data + key->key_len, 0,
|
|
key->buf_len - key->key_len);
|
|
key->key_len = key->buf_len;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* There are callers that work with a range of keys of a uniform length
|
|
* who know that it's safe to increment their keys that aren't full
|
|
* precision. These are exceptional so a specific function variant
|
|
* marks them.
|
|
*/
|
|
void scoutfs_key_inc_cur_len(struct scoutfs_key_buf *key)
|
|
{
|
|
u8 *bytes = key->data;
|
|
int i;
|
|
|
|
for (i = key->key_len - 1; i >= 0; i--) {
|
|
if (++bytes[i] != 0)
|
|
break;
|
|
}
|
|
}
|
|
|
|
void scoutfs_key_inc(struct scoutfs_key_buf *key)
|
|
{
|
|
extend_zeros(key);
|
|
scoutfs_key_inc_cur_len(key);
|
|
}
|
|
|
|
void scoutfs_key_dec_cur_len(struct scoutfs_key_buf *key)
|
|
{
|
|
u8 *bytes = key->data;
|
|
int i;
|
|
|
|
for (i = key->key_len - 1; i >= 0; i--) {
|
|
if (--bytes[i] != 255)
|
|
break;
|
|
}
|
|
}
|
|
|
|
void scoutfs_key_dec(struct scoutfs_key_buf *key)
|
|
{
|
|
extend_zeros(key);
|
|
scoutfs_key_dec_cur_len(key);
|
|
}
|
|
|
|
/* return the bytes of the string including the null term */
|
|
#define snprintf_null(buf, size, fmt, args...) \
|
|
(snprintf((buf), (size), fmt, ##args) + 1)
|
|
|
|
/*
|
|
* Write the null-terminated string that describes the key to the
|
|
* buffer. The bytes copied (including the null) is returned. A null
|
|
* buffer can be used to find the string size without writing anything.
|
|
*
|
|
* XXX nonprintable characters in the trace?
|
|
*/
|
|
int scoutfs_key_str_size(char *buf, struct scoutfs_key_buf *key, size_t size)
|
|
{
|
|
int len;
|
|
u8 type;
|
|
|
|
if (key == NULL || key->data == NULL)
|
|
return snprintf_null(buf, size, "[NULL]");
|
|
|
|
if (key->key_len == 0)
|
|
return snprintf_null(buf, size, "[0 len]");
|
|
|
|
type = *(u8 *)key->data;
|
|
|
|
switch(type) {
|
|
|
|
case SCOUTFS_INODE_KEY: {
|
|
struct scoutfs_inode_key *ikey = key->data;
|
|
|
|
if (key->key_len < sizeof(struct scoutfs_inode_key))
|
|
break;
|
|
|
|
return snprintf_null(buf, size, "ino.%llu",
|
|
be64_to_cpu(ikey->ino));
|
|
}
|
|
|
|
case SCOUTFS_XATTR_KEY: {
|
|
struct scoutfs_xattr_key *xkey = key->data;
|
|
|
|
len = (int)key->key_len - offsetof(struct scoutfs_xattr_key,
|
|
name[1]);
|
|
if (len <= 0)
|
|
break;
|
|
|
|
return snprintf_null(buf, size, "xat.%llu.%.*s",
|
|
be64_to_cpu(xkey->ino), len, xkey->name);
|
|
}
|
|
|
|
case SCOUTFS_DIRENT_KEY: {
|
|
struct scoutfs_dirent_key *dkey = key->data;
|
|
|
|
len = (int)key->key_len - sizeof(struct scoutfs_dirent_key);
|
|
if (len <= 0)
|
|
break;
|
|
|
|
return snprintf_null(buf, size, "dnt.%llu.%.*s",
|
|
be64_to_cpu(dkey->ino), len, dkey->name);
|
|
}
|
|
|
|
case SCOUTFS_READDIR_KEY: {
|
|
struct scoutfs_readdir_key *rkey = key->data;
|
|
|
|
return snprintf_null(buf, size, "rdr.%llu.%llu",
|
|
be64_to_cpu(rkey->ino),
|
|
be64_to_cpu(rkey->pos));
|
|
}
|
|
|
|
case SCOUTFS_LINK_BACKREF_KEY: {
|
|
struct scoutfs_link_backref_key *lkey = key->data;
|
|
|
|
len = (int)key->key_len - sizeof(*lkey);
|
|
if (len <= 0)
|
|
break;
|
|
|
|
return snprintf_null(buf, size, "lbr.%llu.%llu.%.*s",
|
|
be64_to_cpu(lkey->ino),
|
|
be64_to_cpu(lkey->dir_ino), len,
|
|
lkey->name);
|
|
}
|
|
|
|
case SCOUTFS_SYMLINK_KEY: {
|
|
struct scoutfs_symlink_key *skey = key->data;
|
|
|
|
return snprintf_null(buf, size, "sym.%llu",
|
|
be64_to_cpu(skey->ino));
|
|
}
|
|
|
|
case SCOUTFS_FILE_EXTENT_KEY: {
|
|
struct scoutfs_file_extent_key *ekey = key->data;
|
|
|
|
return snprintf_null(buf, size, "ext.%llu.%llu.%llu.%llu.%x",
|
|
be64_to_cpu(ekey->ino),
|
|
be64_to_cpu(ekey->last_blk_off),
|
|
be64_to_cpu(ekey->last_blkno),
|
|
be64_to_cpu(ekey->blocks),
|
|
ekey->flags);
|
|
}
|
|
|
|
case SCOUTFS_ORPHAN_KEY: {
|
|
struct scoutfs_orphan_key *okey = key->data;
|
|
|
|
return snprintf_null(buf, size, "orp.%llu",
|
|
be64_to_cpu(okey->ino));
|
|
}
|
|
|
|
case SCOUTFS_FREE_EXTENT_BLKNO_KEY:
|
|
case SCOUTFS_FREE_EXTENT_BLOCKS_KEY: {
|
|
struct scoutfs_free_extent_blkno_key *fkey = key->data;
|
|
|
|
return snprintf_null(buf, size, "%s.%llu.%llu.%llu",
|
|
fkey->type == SCOUTFS_FREE_EXTENT_BLKNO_KEY ? "fel" :
|
|
"fes",
|
|
be64_to_cpu(fkey->node_id),
|
|
be64_to_cpu(fkey->last_blkno),
|
|
be64_to_cpu(fkey->blocks));
|
|
}
|
|
|
|
case SCOUTFS_INODE_INDEX_CTIME_KEY:
|
|
case SCOUTFS_INODE_INDEX_MTIME_KEY:
|
|
case SCOUTFS_INODE_INDEX_SIZE_KEY:
|
|
case SCOUTFS_INODE_INDEX_META_SEQ_KEY:
|
|
case SCOUTFS_INODE_INDEX_DATA_SEQ_KEY: {
|
|
struct scoutfs_inode_index_key *ikey = key->data;
|
|
|
|
return snprintf_null(buf, size, "%s.%llu.%u.%llu",
|
|
ikey->type == SCOUTFS_INODE_INDEX_CTIME_KEY ? "ctm" :
|
|
ikey->type == SCOUTFS_INODE_INDEX_MTIME_KEY ? "mtm" :
|
|
ikey->type == SCOUTFS_INODE_INDEX_SIZE_KEY ? "siz" :
|
|
ikey->type == SCOUTFS_INODE_INDEX_META_SEQ_KEY ? "msq" :
|
|
ikey->type == SCOUTFS_INODE_INDEX_DATA_SEQ_KEY ? "dsq" :
|
|
"uii", be64_to_cpu(ikey->major),
|
|
be32_to_cpu(ikey->minor),
|
|
be64_to_cpu(ikey->ino));
|
|
}
|
|
|
|
default:
|
|
return snprintf_null(buf, size, "[unknown type %u len %u]",
|
|
type, key->key_len);
|
|
}
|
|
|
|
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();
|
|
}
|