mirror of
https://github.com/versity/scoutfs.git
synced 2025-12-23 13:35:18 +00:00
Initial commit
This initial commit has enough to make a new file system and print out it's structures. Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
7
utils/.gitignore
vendored
Normal file
7
utils/.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
*.o
|
||||
*.d
|
||||
*.swp
|
||||
src/scoutfs
|
||||
.sparse*
|
||||
.mock.build*
|
||||
cscope.*
|
||||
33
utils/Makefile
Normal file
33
utils/Makefile
Normal file
@@ -0,0 +1,33 @@
|
||||
CFLAGS := -Wall -O2 -Werror -D_FILE_OFFSET_BITS=64 -g -mrdrnd -msse4.2
|
||||
|
||||
BIN := src/scoutfs
|
||||
OBJ := $(patsubst %.c,%.o,$(wildcard src/*.c))
|
||||
DEPS := $(wildcard */*.d)
|
||||
|
||||
all: $(BIN)
|
||||
|
||||
ifneq ($(DEPS),)
|
||||
-include $(DEPS)
|
||||
endif
|
||||
|
||||
ifeq ($(V), )
|
||||
QU = @echo
|
||||
VE = @
|
||||
else
|
||||
QU = @:
|
||||
VE =
|
||||
endif
|
||||
|
||||
$(BIN): $(OBJ)
|
||||
$(QU) [BIN $@]
|
||||
$(VE)gcc -o $@ $^ -luuid
|
||||
|
||||
%.o %.d: %.c Makefile sparse.sh
|
||||
$(QU) [CC $<]
|
||||
$(VE)gcc $(CFLAGS) -MD -MP -MF $*.d -c $< -o $*.o
|
||||
$(QU) [SP $<]
|
||||
$(VE)./sparse.sh -Wbitwise -D__CHECKER__ $(CFLAGS) $<
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@rm -f $(BIN) $(OBJ) $(DEPS) .sparse.*
|
||||
58
utils/sparse.sh
Executable file
58
utils/sparse.sh
Executable file
@@ -0,0 +1,58 @@
|
||||
#!/bin/bash
|
||||
|
||||
# can we find sparse? If not, we're done.
|
||||
which sparse > /dev/null 2>&1 || exit 0
|
||||
|
||||
#
|
||||
# one of the problems with using sparse in userspace is that it picks up
|
||||
# things in system headers that we don't care about. We're willing to
|
||||
# take on the burden of filtering them out so that we can have it tell
|
||||
# us about problems in our code.
|
||||
#
|
||||
# system headers using __transparent_union__
|
||||
RE="^/.*error: ignoring attribute __transparent_union__"
|
||||
|
||||
# we don't care if system headers have gcc attributes sparse doesn't
|
||||
# know about
|
||||
RE="$RE|error: attribute '__leaf__': unknown attribute"
|
||||
|
||||
# yes, sparse, that's the size of memseting a 4 meg buffer all right
|
||||
RE="$RE|warning: memset with byte count of 4194304"
|
||||
|
||||
#
|
||||
# don't filter out 'too many errors' here, it can signify that
|
||||
# sparse doesn't understand something and is throwing a *ton*
|
||||
# of useless errors before giving up and existing. Check
|
||||
# unfiltered sparse output.
|
||||
#
|
||||
|
||||
#
|
||||
# I'm not sure this is needed.
|
||||
#
|
||||
search=$(gcc -print-search-dirs | awk '($1 == "install:"){print "-I" $2}')
|
||||
|
||||
#
|
||||
# We're trying to use sparse against glibc headers which go wild trying to
|
||||
# use internal compiler macros to test features. We copy gcc's and give
|
||||
# them to sparse. But not __SIZE_TYPE__ 'cause sparse defines that one.
|
||||
#
|
||||
defines=".sparse.gcc-defines.h"
|
||||
gcc -dM -E -x c - < /dev/null | grep -v __SIZE_TYPE__ > $defines
|
||||
include="-include $defines"
|
||||
|
||||
#
|
||||
# sparse doesn't seem to notice when it's on a 64bit host. It warns that
|
||||
# 64bit values don't fit in 'unsigned long' without this.
|
||||
#
|
||||
if grep -q "__LP64__ 1" $defines; then
|
||||
m64="-m64"
|
||||
else
|
||||
m64=""
|
||||
fi
|
||||
|
||||
sparse $m64 $include $search/include "$@" 2>&1 | egrep -v "($RE)" | tee .sparse.output
|
||||
if [ -s .sparse.output ]; then
|
||||
exit 1
|
||||
else
|
||||
exit 0
|
||||
fi
|
||||
82
utils/src/cmd.c
Normal file
82
utils/src/cmd.c
Normal file
@@ -0,0 +1,82 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "cmd.h"
|
||||
#include "util.h"
|
||||
|
||||
static struct command {
|
||||
char *name;
|
||||
char *opts;
|
||||
char *summary;
|
||||
int (*func)(int argc, char **argv);
|
||||
} cmds[100], *next_cmd = cmds;
|
||||
|
||||
#define cmd_for_each(com) for (com = cmds; com->func; com++)
|
||||
|
||||
void cmd_register(char *name, char *opts, char *summary,
|
||||
int (*func)(int argc, char **argv))
|
||||
{
|
||||
struct command *com = next_cmd++;
|
||||
|
||||
assert((com - cmds) < array_size(cmds));
|
||||
|
||||
com->name = name;
|
||||
com->opts = opts;
|
||||
com->summary = summary;
|
||||
com->func = func;
|
||||
}
|
||||
|
||||
static struct command *find_command(char *name)
|
||||
{
|
||||
struct command *com;
|
||||
|
||||
cmd_for_each(com) {
|
||||
if (!strcmp(name, com->name))
|
||||
return com;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
struct command *com;
|
||||
|
||||
fprintf(stderr, "usage: scoutfs <command> [<args>]\n"
|
||||
"Commands:\n");
|
||||
|
||||
cmd_for_each(com) {
|
||||
fprintf(stderr, " %8s %12s - %s\n",
|
||||
com->name, com->opts, com->summary);
|
||||
}
|
||||
}
|
||||
|
||||
int cmd_execute(int argc, char **argv)
|
||||
{
|
||||
struct command *com = NULL;
|
||||
int ret;
|
||||
|
||||
if (argc > 1) {
|
||||
com = find_command(argv[1]);
|
||||
if (!com)
|
||||
fprintf(stderr, "scoutfs: unrecognized command: '%s'\n",
|
||||
argv[1]);
|
||||
}
|
||||
if (!com) {
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = com->func(argc - 2, argv + 2);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "scoutfs: %s failed: %s (%d)\n",
|
||||
com->name, strerror(-ret), -ret);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
9
utils/src/cmd.h
Normal file
9
utils/src/cmd.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#ifndef _CMD_H_
|
||||
#define _CMD_H_
|
||||
|
||||
void cmd_register(char *name, char *opts, char *summary,
|
||||
int (*func)(int argc, char **argv));
|
||||
|
||||
int cmd_execute(int argc, char **argv);
|
||||
|
||||
#endif
|
||||
39
utils/src/crc.c
Normal file
39
utils/src/crc.c
Normal file
@@ -0,0 +1,39 @@
|
||||
#include "crc.h"
|
||||
#include "util.h"
|
||||
#include "format.h"
|
||||
|
||||
u32 crc32c(u32 crc, const void *data, unsigned int len)
|
||||
{
|
||||
while (len >= 8) {
|
||||
crc = __builtin_ia32_crc32di(crc, *(u64 *)data);
|
||||
len -= 8;
|
||||
data += 8;
|
||||
}
|
||||
if (len & 4) {
|
||||
crc = __builtin_ia32_crc32si(crc, *(u32 *)data);
|
||||
data += 4;
|
||||
}
|
||||
if (len & 2) {
|
||||
crc = __builtin_ia32_crc32hi(crc, *(u16 *)data);
|
||||
data += 2;
|
||||
}
|
||||
if (len & 1)
|
||||
crc = __builtin_ia32_crc32qi(crc, *(u8 *)data);
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
/* A simple hack to get reasonably solid 64bit hash values */
|
||||
u64 crc32c_64(u32 crc, const void *data, unsigned int len)
|
||||
{
|
||||
unsigned int half = (len + 1) / 2;
|
||||
|
||||
return ((u64)crc32c(crc, data, half) << 32) |
|
||||
crc32c(~crc, data + len - half, half);
|
||||
}
|
||||
|
||||
u32 crc_header(struct scoutfs_header *hdr, size_t size)
|
||||
{
|
||||
return crc32c(~0, (char *)hdr + sizeof(hdr->crc),
|
||||
size - sizeof(hdr->crc));
|
||||
}
|
||||
12
utils/src/crc.h
Normal file
12
utils/src/crc.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef _CRC_H_
|
||||
#define _CRC_H_
|
||||
|
||||
#include "sparse.h"
|
||||
#include "util.h"
|
||||
#include "format.h"
|
||||
|
||||
u32 crc32c(u32 crc, const void *data, unsigned int len);
|
||||
u64 crc32c_64(u32 crc, const void *data, unsigned int len);
|
||||
u32 crc_header(struct scoutfs_header *hdr, size_t size);
|
||||
|
||||
#endif
|
||||
234
utils/src/format.h
Normal file
234
utils/src/format.h
Normal file
@@ -0,0 +1,234 @@
|
||||
#ifndef _SCOUTFS_FORMAT_H_
|
||||
#define _SCOUTFS_FORMAT_H_
|
||||
|
||||
/* statfs(2) f_type */
|
||||
#define SCOUTFS_SUPER_MAGIC 0x554f4353 /* "SCOU" */
|
||||
/* super block id */
|
||||
#define SCOUTFS_SUPER_ID 0x2e736674756f6373ULL /* "scoutfs." */
|
||||
|
||||
/*
|
||||
* Some fs structures are stored in smaller fixed size 4k bricks.
|
||||
*/
|
||||
#define SCOUTFS_BRICK_SHIFT 12
|
||||
#define SCOUTFS_BRICK_SIZE (1 << SCOUTFS_BRICK_SHIFT)
|
||||
|
||||
/*
|
||||
* A large block size reduces the amount of per-block overhead throughout
|
||||
* the system: block IO, manifest communications and storage, etc.
|
||||
*/
|
||||
#define SCOUTFS_BLOCK_SHIFT 22
|
||||
#define SCOUTFS_BLOCK_SIZE (1 << SCOUTFS_BLOCK_SHIFT)
|
||||
|
||||
/* for shifting between brick and block numbers */
|
||||
#define SCOUTFS_BLOCK_BRICK (SCOUTFS_BLOCK_SHIFT - SCOUTFS_BRICK_SHIFT)
|
||||
|
||||
/*
|
||||
* The super bricks leave a bunch of room at the start of the first
|
||||
* block for platform structures like boot loaders.
|
||||
*/
|
||||
#define SCOUTFS_SUPER_BRICK 16
|
||||
|
||||
/*
|
||||
* This header is found at the start of every brick and block
|
||||
* so that we can verify that it's what we were looking for.
|
||||
*/
|
||||
struct scoutfs_header {
|
||||
__le32 crc;
|
||||
__le64 fsid;
|
||||
__le64 seq;
|
||||
__le64 nr;
|
||||
} __packed;
|
||||
|
||||
#define SCOUTFS_UUID_BYTES 16
|
||||
|
||||
/*
|
||||
* The super is stored in a pair of bricks in the first block.
|
||||
*/
|
||||
struct scoutfs_super {
|
||||
struct scoutfs_header hdr;
|
||||
__le64 id;
|
||||
__u8 uuid[SCOUTFS_UUID_BYTES];
|
||||
__le64 total_blocks;
|
||||
__le64 ring_layout_block;
|
||||
__le64 ring_layout_seq;
|
||||
__le64 last_ring_brick;
|
||||
__le64 last_ring_seq;
|
||||
__le64 last_block_seq;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* We should be able to make the offset smaller if neither dirents nor
|
||||
* data items use the full 64 bits.
|
||||
*/
|
||||
struct scoutfs_key {
|
||||
__le64 inode;
|
||||
u8 type;
|
||||
__le64 offset;
|
||||
} __packed;
|
||||
|
||||
#define SCOUTFS_ROOT_INO 1
|
||||
|
||||
#define SCOUTFS_INODE_KEY 128
|
||||
#define SCOUTFS_DIRENT_KEY 192
|
||||
|
||||
struct scoutfs_ring_layout {
|
||||
struct scoutfs_header hdr;
|
||||
__le32 nr_blocks;
|
||||
__le64 blocks[0];
|
||||
} __packed;
|
||||
|
||||
struct scoutfs_ring_entry {
|
||||
u8 type;
|
||||
__le16 len;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Ring blocks are 4k blocks stored inside the large ring blocks
|
||||
* referenced by the ring descriptor block.
|
||||
*
|
||||
* The manifest entries describe the position of a given block in the
|
||||
* manifest. They're keyed by the block number so that we can log
|
||||
* movement of a block in the manifest with one log entry and we can log
|
||||
* deletion with just the block number.
|
||||
*/
|
||||
struct scoutfs_ring_brick {
|
||||
struct scoutfs_header hdr;
|
||||
__le16 nr_entries;
|
||||
} __packed;
|
||||
|
||||
enum {
|
||||
SCOUTFS_RING_REMOVE_MANIFEST = 0,
|
||||
SCOUTFS_RING_ADD_MANIFEST,
|
||||
SCOUTFS_RING_BITMAP,
|
||||
};
|
||||
|
||||
/*
|
||||
* Manifest entries are logged by their block number. This lets us log
|
||||
* a change with one entry and a removal with a tiny block number
|
||||
* without the key.
|
||||
*/
|
||||
struct scoutfs_ring_remove_manifest {
|
||||
__le64 block;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Including both keys might make the manifest too large. It might be
|
||||
* better to only include one key and infer a block's range from the
|
||||
* neighbour's key. The downside of that is that we assume that there
|
||||
* isn't unused key space between blocks in a level. We might search
|
||||
* blocks when we didn't need to.
|
||||
*/
|
||||
struct scoutfs_ring_add_manifest {
|
||||
__le64 block;
|
||||
__le64 seq;
|
||||
__u8 level;
|
||||
struct scoutfs_key first;
|
||||
struct scoutfs_key last;
|
||||
} __packed;
|
||||
|
||||
struct scoutfs_ring_bitmap {
|
||||
__le32 offset;
|
||||
__le64 bits[2];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* This bloom size is chosen to have a roughly 1% false positive rate
|
||||
* for ~90k items which is roughly the worst case for a block full of
|
||||
* dirents with reasonably small names. Pathologically smaller items
|
||||
* could be even more dense.
|
||||
*/
|
||||
#define SCOUTFS_BLOOM_FILTER_BYTES (128 * 1024)
|
||||
#define SCOUTFS_BLOOM_FILTER_BITS (SCOUTFS_BLOOM_FILTER_BYTES * 8)
|
||||
#define SCOUTFS_BLOOM_INDEX_BITS (ilog2(SCOUTFS_BLOOM_FILTER_BITS))
|
||||
#define SCOUTFS_BLOOM_INDEX_MASK ((1 << SCOUTFS_BLOOM_INDEX_BITS) - 1)
|
||||
#define SCOUTFS_BLOOM_INDEX_NR 7
|
||||
|
||||
struct scoutfs_lsm_block {
|
||||
struct scoutfs_header hdr;
|
||||
struct scoutfs_key first;
|
||||
struct scoutfs_key last;
|
||||
__le32 nr_items;
|
||||
/* u8 bloom[SCOUTFS_BLOOM_BYTES]; */
|
||||
/* struct scoutfs_item_header items[0] .. */
|
||||
} __packed;
|
||||
|
||||
struct scoutfs_item_header {
|
||||
struct scoutfs_key key;
|
||||
__le16 len;
|
||||
} __packed;
|
||||
|
||||
struct scoutfs_timespec {
|
||||
__le64 sec;
|
||||
__le32 nsec;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* - otime?
|
||||
* - compat flags?
|
||||
* - version?
|
||||
* - generation?
|
||||
* - be more careful with rdev?
|
||||
*/
|
||||
struct scoutfs_inode {
|
||||
__le64 size;
|
||||
__le64 blocks;
|
||||
__le32 nlink;
|
||||
__le32 uid;
|
||||
__le32 gid;
|
||||
__le32 mode;
|
||||
__le32 rdev;
|
||||
__le32 salt;
|
||||
struct scoutfs_timespec atime;
|
||||
struct scoutfs_timespec ctime;
|
||||
struct scoutfs_timespec mtime;
|
||||
} __packed;
|
||||
|
||||
#define SCOUTFS_ROOT_INO 1
|
||||
|
||||
/*
|
||||
* Dirents are stored in items with an offset of the hash of their name.
|
||||
* Colliding names are packed into the value.
|
||||
*/
|
||||
struct scoutfs_dirent {
|
||||
__le64 ino;
|
||||
#if defined(__LITTLE_ENDIAN_BITFIELD)
|
||||
__u8 type:4,
|
||||
coll_nr:4;
|
||||
#else
|
||||
__u8 coll_nr:4,
|
||||
type:4;
|
||||
#endif
|
||||
__u8 name_len;
|
||||
__u8 name[0];
|
||||
} __packed;
|
||||
|
||||
#define SCOUTFS_NAME_LEN 255
|
||||
|
||||
/*
|
||||
* We only use 31 bits for readdir positions so that we don't confuse
|
||||
* old signed 32bit f_pos applications or those on the other side of
|
||||
* network protocols that have limited readir positions.
|
||||
*/
|
||||
|
||||
#define SCOUTFS_DIRENT_OFF_BITS 27
|
||||
#define SCOUTFS_DIRENT_OFF_MASK ((1 << SCOUTFS_DIRENT_OFF_BITS) - 1)
|
||||
#define SCOUTFS_DIRENT_COLL_BITS 4
|
||||
#define SCOUTFS_DIRENT_COLL_MASK ((1 << SCOUTFS_DIRENT_COLL_BITS) - 1)
|
||||
|
||||
/* getdents returns the *next* pos with each entry. so we can't return ~0 */
|
||||
#define SCOUTFS_DIRENT_MAX_POS \
|
||||
(((1 << (SCOUTFS_DIRENT_OFF_BITS + SCOUTFS_DIRENT_COLL_BITS)) - 1) - 1)
|
||||
|
||||
enum {
|
||||
SCOUTFS_DT_FIFO = 0,
|
||||
SCOUTFS_DT_CHR,
|
||||
SCOUTFS_DT_DIR,
|
||||
SCOUTFS_DT_BLK,
|
||||
SCOUTFS_DT_REG,
|
||||
SCOUTFS_DT_LNK,
|
||||
SCOUTFS_DT_SOCK,
|
||||
SCOUTFS_DT_WHT,
|
||||
};
|
||||
|
||||
#endif
|
||||
38
utils/src/lebitmap.c
Normal file
38
utils/src/lebitmap.c
Normal file
@@ -0,0 +1,38 @@
|
||||
#define _GNU_SOURCE /* ffsll */
|
||||
#include <string.h>
|
||||
|
||||
#include "lebitmap.h"
|
||||
|
||||
void set_le_bit(__le64 *bits, u64 nr)
|
||||
{
|
||||
bits += nr / 64;
|
||||
|
||||
*bits = cpu_to_le64(le64_to_cpu(*bits) | (1ULL << (nr & 63)));
|
||||
}
|
||||
|
||||
void clear_le_bit(__le64 *bits, u64 nr)
|
||||
{
|
||||
bits += nr / 64;
|
||||
|
||||
*bits = cpu_to_le64(le64_to_cpu(*bits) & ~(1ULL << (nr & 63)));
|
||||
}
|
||||
|
||||
int test_le_bit(__le64 *bits, u64 nr)
|
||||
{
|
||||
bits += nr / 64;
|
||||
|
||||
return !!(le64_to_cpu(*bits) & (1ULL << (nr & 63)));
|
||||
}
|
||||
|
||||
/* returns -1 or nr */
|
||||
s64 find_first_le_bit(__le64 *bits, s64 count)
|
||||
{
|
||||
long nr;
|
||||
|
||||
for (nr = 0; count > 0; bits++, nr += 64, count -= 64) {
|
||||
if (*bits)
|
||||
return nr + ffsll(le64_to_cpu(*bits)) - 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
11
utils/src/lebitmap.h
Normal file
11
utils/src/lebitmap.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#ifndef _LEBITMAP_H_
|
||||
#define _LEBITMAP_H_
|
||||
|
||||
#include "sparse.h"
|
||||
|
||||
void set_le_bit(__le64 *bits, u64 nr);
|
||||
void clear_le_bit(__le64 *bits, u64 nr);
|
||||
int test_le_bit(__le64 *bits, u64 nr);
|
||||
s64 find_first_le_bit(__le64 *bits, s64 count);
|
||||
|
||||
#endif
|
||||
24
utils/src/main.c
Normal file
24
utils/src/main.c
Normal file
@@ -0,0 +1,24 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "cmd.h"
|
||||
#include "util.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* XXX parse global options, env, configs, etc.
|
||||
*/
|
||||
|
||||
ret = cmd_execute(argc, argv);
|
||||
if (ret < 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
250
utils/src/mkfs.c
Normal file
250
utils/src/mkfs.c
Normal file
@@ -0,0 +1,250 @@
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/time.h>
|
||||
#include <uuid/uuid.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "sparse.h"
|
||||
#include "cmd.h"
|
||||
#include "util.h"
|
||||
#include "format.h"
|
||||
#include "crc.h"
|
||||
#include "rand.h"
|
||||
|
||||
|
||||
/*
|
||||
* Update the buffer's header and write it out.
|
||||
*/
|
||||
static int write_header(int fd, u64 nr, struct scoutfs_header *hdr, size_t size)
|
||||
{
|
||||
off_t off = nr * size;
|
||||
ssize_t ret;
|
||||
|
||||
hdr->nr = cpu_to_le64(nr);
|
||||
hdr->crc = cpu_to_le32(crc_header(hdr, size));
|
||||
|
||||
ret = pwrite(fd, hdr, size, off);
|
||||
if (ret != size) {
|
||||
fprintf(stderr, "write at nr %llu (offset %llu, size %zu) returned %zd: %s (%d)\n",
|
||||
nr, (long long)off, size, ret, strerror(errno), errno);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_brick(int fd, u64 nr, struct scoutfs_header *hdr)
|
||||
{
|
||||
return write_header(fd, nr, hdr, SCOUTFS_BRICK_SIZE);
|
||||
}
|
||||
|
||||
static int write_block(int fd, u64 nr, struct scoutfs_header *hdr)
|
||||
{
|
||||
return write_header(fd, nr, hdr, SCOUTFS_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
/*
|
||||
* - config blocks that describe ring
|
||||
* - ring entries for lots of free blocks
|
||||
* - manifest that references single block
|
||||
* - block with inode
|
||||
*/
|
||||
/*
|
||||
* So what does mkfs really need to do?
|
||||
*
|
||||
* - super blocks that describe ring log
|
||||
* - ring log with free bitmap entries
|
||||
* - ring log with manifest entries
|
||||
* - single item block with root dir
|
||||
*/
|
||||
static int write_new_fs(char *path, int fd)
|
||||
{
|
||||
struct scoutfs_super *super;
|
||||
struct scoutfs_inode *inode;
|
||||
struct scoutfs_ring_layout *rlo;
|
||||
struct scoutfs_ring_brick *ring;
|
||||
struct scoutfs_ring_entry *ent;
|
||||
struct scoutfs_ring_add_manifest *mani;
|
||||
struct scoutfs_ring_bitmap *bm;
|
||||
struct scoutfs_lsm_block *lblk;
|
||||
struct scoutfs_item_header *ihdr;
|
||||
struct scoutfs_key root_key;
|
||||
struct timeval tv;
|
||||
char uuid_str[37];
|
||||
struct stat st;
|
||||
unsigned int i;
|
||||
u64 total_blocks;
|
||||
void *buf;
|
||||
int ret;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
super = malloc(SCOUTFS_BRICK_SIZE);
|
||||
buf = malloc(SCOUTFS_BLOCK_SIZE);
|
||||
if (!super || !buf) {
|
||||
ret = -errno;
|
||||
fprintf(stderr, "failed to allocate a block: %s (%d)\n",
|
||||
strerror(errno), errno);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (fstat(fd, &st)) {
|
||||
ret = -errno;
|
||||
fprintf(stderr, "failed to stat '%s': %s (%d)\n",
|
||||
path, strerror(errno), errno);
|
||||
goto out;
|
||||
}
|
||||
|
||||
total_blocks = st.st_size >> SCOUTFS_BLOCK_SHIFT;
|
||||
|
||||
root_key.inode = cpu_to_le64(SCOUTFS_ROOT_INO);
|
||||
root_key.type = SCOUTFS_INODE_KEY;
|
||||
root_key.offset = 0;
|
||||
|
||||
/* initialize the super */
|
||||
memset(super, 0, sizeof(struct scoutfs_super));
|
||||
pseudo_random_bytes(&super->hdr.fsid, sizeof(super->hdr.fsid));
|
||||
super->hdr.seq = cpu_to_le64(1);
|
||||
super->id = cpu_to_le64(SCOUTFS_SUPER_ID);
|
||||
uuid_generate(super->uuid);
|
||||
super->total_blocks = cpu_to_le64(total_blocks);
|
||||
super->ring_layout_block = cpu_to_le64(1);
|
||||
super->ring_layout_seq = cpu_to_le64(1);
|
||||
super->last_ring_brick = cpu_to_le64(1);
|
||||
super->last_ring_seq = cpu_to_le64(1);
|
||||
super->last_block_seq = cpu_to_le64(1);
|
||||
|
||||
/* the ring has a single block for now */
|
||||
memset(buf, 0, SCOUTFS_BLOCK_SIZE);
|
||||
rlo = buf;
|
||||
rlo->hdr.fsid = super->hdr.fsid;
|
||||
rlo->hdr.seq = super->ring_layout_seq;
|
||||
rlo->nr_blocks = cpu_to_le32(1);
|
||||
rlo->blocks[0] = cpu_to_le64(2);
|
||||
|
||||
ret = write_block(fd, 1, &rlo->hdr);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* log the root inode block manifest and free bitmap */
|
||||
memset(buf, 0, SCOUTFS_BLOCK_SIZE);
|
||||
ring = buf;
|
||||
ring->hdr.fsid = super->hdr.fsid;
|
||||
ring->hdr.seq = super->last_ring_seq;
|
||||
ring->nr_entries = cpu_to_le16(2);
|
||||
ent = (void *)(ring + 1);
|
||||
ent->type = SCOUTFS_RING_ADD_MANIFEST;
|
||||
ent->len = cpu_to_le16(sizeof(*mani));
|
||||
mani = (void *)(ent + 1);
|
||||
mani->block = cpu_to_le64(3);
|
||||
mani->seq = super->last_block_seq;
|
||||
mani->level = 0;
|
||||
mani->first = root_key;
|
||||
mani->last = root_key;
|
||||
ent = (void *)(mani + 1);
|
||||
ent->type = SCOUTFS_RING_BITMAP;
|
||||
ent->len = cpu_to_le16(sizeof(*bm));
|
||||
bm = (void *)(ent + 1);
|
||||
memset(bm->bits, 0xff, sizeof(bm->bits));
|
||||
/* the first three blocks are allocated */
|
||||
bm->bits[0] = cpu_to_le64(~7ULL);
|
||||
bm->bits[1] = cpu_to_le64(~0ULL);
|
||||
|
||||
ret = write_block(fd, 2, &ring->hdr);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* write a single lsm block with the root inode item */
|
||||
memset(buf, 0, SCOUTFS_BLOCK_SIZE);
|
||||
lblk = buf;
|
||||
lblk->hdr.fsid = super->hdr.fsid;
|
||||
lblk->hdr.seq = super->last_block_seq;
|
||||
lblk->first = root_key;
|
||||
lblk->last = root_key;
|
||||
lblk->nr_items = cpu_to_le32(1);
|
||||
/* XXX set bloom */
|
||||
ihdr = (void *)((char *)(lblk + 1) + SCOUTFS_BLOOM_FILTER_BYTES);
|
||||
ihdr->key = root_key;
|
||||
ihdr->len = cpu_to_le16(sizeof(struct scoutfs_inode));
|
||||
inode = (void *)(ihdr + 1);
|
||||
inode->nlink = cpu_to_le32(2);
|
||||
inode->mode = cpu_to_le32(0755 | 0040000);
|
||||
inode->atime.sec = cpu_to_le64(tv.tv_sec);
|
||||
inode->atime.nsec = cpu_to_le32(tv.tv_usec * 1000);
|
||||
inode->ctime.sec = inode->atime.sec;
|
||||
inode->ctime.nsec = inode->atime.nsec;
|
||||
inode->mtime.sec = inode->atime.sec;
|
||||
inode->mtime.nsec = inode->atime.nsec;
|
||||
|
||||
ret = write_block(fd, 3, &ring->hdr);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* write the two super bricks */
|
||||
for (i = 0; i < 2; i++) {
|
||||
super->hdr.seq = cpu_to_le64(i);
|
||||
ret = write_brick(fd, SCOUTFS_SUPER_BRICK + i, &super->hdr);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (fsync(fd)) {
|
||||
ret = -errno;
|
||||
fprintf(stderr, "failed to fsync '%s': %s (%d)\n",
|
||||
path, strerror(errno), errno);
|
||||
goto out;
|
||||
}
|
||||
|
||||
uuid_unparse(super->uuid, uuid_str);
|
||||
|
||||
printf("Created scoutfs filesystem:\n"
|
||||
" total blocks: %llu\n"
|
||||
" fsid: %llx\n"
|
||||
" uuid: %s\n",
|
||||
total_blocks, le64_to_cpu(super->hdr.fsid), uuid_str);
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
free(super);
|
||||
free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mkfs_func(int argc, char *argv[])
|
||||
{
|
||||
char *path = argv[0];
|
||||
int ret;
|
||||
int fd;
|
||||
|
||||
if (argc != 1) {
|
||||
printf("scoutfs: mkfs: a single path argument is required\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fd = open(path, O_RDWR | O_EXCL);
|
||||
if (fd < 0) {
|
||||
ret = -errno;
|
||||
fprintf(stderr, "failed to open '%s': %s (%d)\n",
|
||||
path, strerror(errno), errno);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = write_new_fs(path, fd);
|
||||
close(fd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __attribute__((constructor)) mkfs_ctor(void)
|
||||
{
|
||||
cmd_register("mkfs", "<path>", "write a new file system", mkfs_func);
|
||||
|
||||
/* for lack of some other place to put these.. */
|
||||
build_assert(sizeof(uuid_t) == SCOUTFS_UUID_BYTES);
|
||||
}
|
||||
402
utils/src/print.c
Normal file
402
utils/src/print.c
Normal file
@@ -0,0 +1,402 @@
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
#include "sparse.h"
|
||||
#include "util.h"
|
||||
#include "format.h"
|
||||
#include "cmd.h"
|
||||
#include "crc.h"
|
||||
#include "lebitmap.h"
|
||||
|
||||
/* XXX maybe these go somewhere */
|
||||
#define SKF "%llu.%u.%llu"
|
||||
#define SKA(k) le64_to_cpu((k)->inode), (k)->type, \
|
||||
le64_to_cpu((k)->offset)
|
||||
|
||||
static void *read_buf(int fd, u64 nr, size_t size)
|
||||
{
|
||||
off_t off = nr * size;
|
||||
ssize_t ret;
|
||||
void *buf;
|
||||
|
||||
buf = malloc(size);
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
ret = pread(fd, buf, size, off);
|
||||
if (ret != size) {
|
||||
fprintf(stderr, "read at blkno %llu (offset %llu) returned %zd: %s (%d)\n",
|
||||
nr, (long long)off, ret, strerror(errno), errno);
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void *read_brick(int fd, u64 nr)
|
||||
{
|
||||
return read_buf(fd, nr, SCOUTFS_BRICK_SIZE);
|
||||
}
|
||||
|
||||
static void *read_block(int fd, u64 nr)
|
||||
{
|
||||
return read_buf(fd, nr, SCOUTFS_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
static void print_header(struct scoutfs_header *hdr, size_t size)
|
||||
{
|
||||
u32 crc = crc_header(hdr, size);
|
||||
char valid_str[40];
|
||||
|
||||
if (crc != le32_to_cpu(hdr->crc))
|
||||
sprintf(valid_str, "# != %08x", crc);
|
||||
else
|
||||
valid_str[0] = '\0';
|
||||
|
||||
printf(" header:\n"
|
||||
" crc: %08x %s\n"
|
||||
" fsid: %llx\n"
|
||||
" seq: %llu\n"
|
||||
" nr: %llu\n",
|
||||
le32_to_cpu(hdr->crc), valid_str, le64_to_cpu(hdr->fsid),
|
||||
le64_to_cpu(hdr->seq), le64_to_cpu(hdr->nr));
|
||||
}
|
||||
|
||||
static void print_brick_header(struct scoutfs_header *hdr)
|
||||
{
|
||||
return print_header(hdr, SCOUTFS_BRICK_SIZE);
|
||||
}
|
||||
|
||||
static void print_block_header(struct scoutfs_header *hdr)
|
||||
{
|
||||
return print_header(hdr, SCOUTFS_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
static void print_inode(struct scoutfs_inode *inode)
|
||||
{
|
||||
printf(" inode:\n"
|
||||
" size: %llu\n"
|
||||
" blocks: %llu\n"
|
||||
" nlink: %u\n"
|
||||
" uid: %u\n"
|
||||
" gid: %u\n"
|
||||
" mode: 0%o\n"
|
||||
" rdev: 0x%x\n"
|
||||
" salt: 0x%x\n"
|
||||
" atime: %llu.%08u\n"
|
||||
" ctime: %llu.%08u\n"
|
||||
" mtime: %llu.%08u\n",
|
||||
le64_to_cpu(inode->size), le64_to_cpu(inode->blocks),
|
||||
le32_to_cpu(inode->nlink), le32_to_cpu(inode->uid),
|
||||
le32_to_cpu(inode->gid), le32_to_cpu(inode->mode),
|
||||
le32_to_cpu(inode->rdev), le32_to_cpu(inode->salt),
|
||||
le64_to_cpu(inode->atime.sec),
|
||||
le32_to_cpu(inode->atime.nsec),
|
||||
le64_to_cpu(inode->ctime.sec),
|
||||
le32_to_cpu(inode->ctime.nsec),
|
||||
le64_to_cpu(inode->mtime.sec),
|
||||
le32_to_cpu(inode->mtime.nsec));
|
||||
}
|
||||
|
||||
static void print_item(struct scoutfs_item_header *ihdr, size_t off)
|
||||
{
|
||||
printf(" item: &%zu\n"
|
||||
" key: "SKF"\n"
|
||||
" len: %u\n",
|
||||
off, SKA(&ihdr->key), le16_to_cpu(ihdr->len));
|
||||
|
||||
switch(ihdr->key.type) {
|
||||
case SCOUTFS_INODE_KEY:
|
||||
print_inode((void *)(ihdr + 1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int print_block(int fd, u64 nr)
|
||||
{
|
||||
struct scoutfs_item_header *ihdr;
|
||||
struct scoutfs_lsm_block *lblk;
|
||||
size_t off;
|
||||
int i;
|
||||
|
||||
lblk = read_block(fd, nr);
|
||||
if (!lblk)
|
||||
return -ENOMEM;
|
||||
|
||||
printf("block: &%llu\n", le64_to_cpu(lblk->hdr.nr));
|
||||
print_block_header(&lblk->hdr);
|
||||
printf(" first: "SKF"\n"
|
||||
" last: "SKF"\n"
|
||||
" nr_items: %u\n",
|
||||
SKA(&lblk->first), SKA(&lblk->last),
|
||||
le32_to_cpu(lblk->nr_items));
|
||||
off = (char *)(lblk + 1) - (char *)lblk + SCOUTFS_BLOOM_FILTER_BYTES;
|
||||
|
||||
for (i = 0; i < le32_to_cpu(lblk->nr_items); i++) {
|
||||
ihdr = (void *)((char *)lblk + off);
|
||||
print_item(ihdr, off);
|
||||
|
||||
off += sizeof(struct scoutfs_item_header) +
|
||||
le16_to_cpu(ihdr->len);
|
||||
}
|
||||
|
||||
free(lblk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int print_blocks(int fd, __le64 *live_blocks, u64 total_blocks)
|
||||
{
|
||||
int ret = 0;
|
||||
int err;
|
||||
s64 nr;
|
||||
|
||||
while ((nr = find_first_le_bit(live_blocks, total_blocks)) >= 0) {
|
||||
clear_le_bit(live_blocks, nr);
|
||||
|
||||
err = print_block(fd, nr);
|
||||
if (!ret && err)
|
||||
ret = err;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *ent_type_str(u8 type)
|
||||
{
|
||||
switch (type) {
|
||||
case SCOUTFS_RING_REMOVE_MANIFEST:
|
||||
return "REMOVE_MANIFEST";
|
||||
case SCOUTFS_RING_ADD_MANIFEST:
|
||||
return "ADD_MANIFEST";
|
||||
case SCOUTFS_RING_BITMAP:
|
||||
return "BITMAP";
|
||||
default:
|
||||
return "(unknown)";
|
||||
}
|
||||
}
|
||||
|
||||
static void print_ring_entry(int fd, struct scoutfs_ring_entry *ent,
|
||||
size_t off)
|
||||
{
|
||||
struct scoutfs_ring_remove_manifest *rem;
|
||||
struct scoutfs_ring_add_manifest *add;
|
||||
struct scoutfs_ring_bitmap *bm;
|
||||
|
||||
printf(" entry: &%zu\n"
|
||||
" type: %u # %s\n"
|
||||
" len: %u\n",
|
||||
off, ent->type, ent_type_str(ent->type), le16_to_cpu(ent->len));
|
||||
|
||||
switch(ent->type) {
|
||||
case SCOUTFS_RING_REMOVE_MANIFEST:
|
||||
rem = (void *)(ent + 1);
|
||||
printf(" block: %llu\n",
|
||||
le64_to_cpu(rem->block));
|
||||
break;
|
||||
case SCOUTFS_RING_ADD_MANIFEST:
|
||||
add = (void *)(ent + 1);
|
||||
printf(" block: %llu\n"
|
||||
" seq: %llu\n"
|
||||
" level: %u\n"
|
||||
" first: "SKF"\n"
|
||||
" last: "SKF"\n",
|
||||
le64_to_cpu(add->block), le64_to_cpu(add->seq),
|
||||
add->level, SKA(&add->first), SKA(&add->last));
|
||||
break;
|
||||
case SCOUTFS_RING_BITMAP:
|
||||
bm = (void *)(ent + 1);
|
||||
printf(" offset: %u\n"
|
||||
" bits: 0x%llx%llx\n",
|
||||
le32_to_cpu(bm->offset),
|
||||
le64_to_cpu(bm->bits[1]), le64_to_cpu(bm->bits[0]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void update_live_blocks(struct scoutfs_ring_entry *ent,
|
||||
__le64 *live_blocks)
|
||||
{
|
||||
struct scoutfs_ring_remove_manifest *rem;
|
||||
struct scoutfs_ring_add_manifest *add;
|
||||
|
||||
switch(ent->type) {
|
||||
case SCOUTFS_RING_REMOVE_MANIFEST:
|
||||
rem = (void *)(ent + 1);
|
||||
clear_le_bit(live_blocks, le64_to_cpu(rem->block));
|
||||
break;
|
||||
case SCOUTFS_RING_ADD_MANIFEST:
|
||||
add = (void *)(ent + 1);
|
||||
set_le_bit(live_blocks, le64_to_cpu(add->block));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int print_ring_block(int fd, u64 block_nr, __le64 *live_blocks)
|
||||
{
|
||||
struct scoutfs_ring_brick *ring;
|
||||
struct scoutfs_ring_entry *ent;
|
||||
size_t off;
|
||||
int ret = 0;
|
||||
u64 nr;
|
||||
int i;
|
||||
|
||||
/* XXX just printing the first brick for now */
|
||||
|
||||
nr = block_nr << SCOUTFS_BLOCK_BRICK;
|
||||
ring = read_brick(fd, nr);
|
||||
if (!ring)
|
||||
return -ENOMEM;
|
||||
|
||||
printf("ring brick: &%llu\n", nr);
|
||||
print_brick_header(&ring->hdr);
|
||||
printf(" nr_entries: %u\n", le16_to_cpu(ring->nr_entries));
|
||||
|
||||
off = sizeof(struct scoutfs_ring_brick);
|
||||
for (i = 0; i < le16_to_cpu(ring->nr_entries); i++) {
|
||||
ent = (void *)((char *)ring + off);
|
||||
|
||||
update_live_blocks(ent, live_blocks);
|
||||
|
||||
print_ring_entry(fd, ent, off);
|
||||
|
||||
off += sizeof(struct scoutfs_ring_entry) +
|
||||
le16_to_cpu(ent->len);
|
||||
}
|
||||
|
||||
free(ring);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int print_ring_layout(int fd, u64 blkno, __le64 *live_blocks)
|
||||
{
|
||||
struct scoutfs_ring_layout *rlo;
|
||||
int ret = 0;
|
||||
int err;
|
||||
int i;
|
||||
|
||||
rlo = read_block(fd, blkno);
|
||||
if (!rlo)
|
||||
return -ENOMEM;
|
||||
|
||||
printf("ring layout: &%llu\n", blkno);
|
||||
print_block_header(&rlo->hdr);
|
||||
printf(" nr_blocks: %u\n", le32_to_cpu(rlo->nr_blocks));
|
||||
|
||||
printf(" blocks: ");
|
||||
for (i = 0; i < le32_to_cpu(rlo->nr_blocks); i++)
|
||||
printf(" %llu\n", le64_to_cpu(rlo->blocks[i]));
|
||||
|
||||
for (i = 0; i < le32_to_cpu(rlo->nr_blocks); i++) {
|
||||
err = print_ring_block(fd, le64_to_cpu(rlo->blocks[i]),
|
||||
live_blocks);
|
||||
if (err && !ret)
|
||||
ret = err;
|
||||
}
|
||||
|
||||
free(rlo);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int print_super_brick(int fd)
|
||||
{
|
||||
struct scoutfs_super *super;
|
||||
char uuid_str[37];
|
||||
__le64 *live_blocks;
|
||||
u64 total_blocks;
|
||||
size_t bytes;
|
||||
int ret = 0;
|
||||
int err;
|
||||
|
||||
/* XXX print both */
|
||||
super = read_brick(fd, SCOUTFS_SUPER_BRICK);
|
||||
if (!super)
|
||||
return -ENOMEM;
|
||||
|
||||
uuid_unparse(super->uuid, uuid_str);
|
||||
|
||||
total_blocks = le64_to_cpu(super->total_blocks);
|
||||
|
||||
printf("super: &%llu\n", le64_to_cpu(super->hdr.nr));
|
||||
print_brick_header(&super->hdr);
|
||||
printf(" id: %llx\n"
|
||||
" uuid: %s\n"
|
||||
" total_blocks: %llu\n"
|
||||
" ring_layout_block: %llu\n"
|
||||
" ring_layout_seq: %llu\n"
|
||||
" last_ring_brick: %llu\n"
|
||||
" last_ring_seq: %llu\n"
|
||||
" last_block_seq: %llu\n",
|
||||
le64_to_cpu(super->id),
|
||||
uuid_str,
|
||||
total_blocks,
|
||||
le64_to_cpu(super->ring_layout_block),
|
||||
le64_to_cpu(super->ring_layout_seq),
|
||||
le64_to_cpu(super->last_ring_brick),
|
||||
le64_to_cpu(super->last_ring_seq),
|
||||
le64_to_cpu(super->last_block_seq));
|
||||
|
||||
/* XXX by hand? */
|
||||
bytes = (total_blocks + 63) / 8;
|
||||
live_blocks = malloc(bytes);
|
||||
if (!live_blocks) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
memset(live_blocks, 0, bytes);
|
||||
|
||||
err = print_ring_layout(fd, le64_to_cpu(super->ring_layout_block),
|
||||
live_blocks);
|
||||
if (err && !ret)
|
||||
ret = err;
|
||||
|
||||
err = print_blocks(fd, live_blocks, total_blocks);
|
||||
if (err && !ret)
|
||||
ret = err;
|
||||
|
||||
out:
|
||||
free(super);
|
||||
free(live_blocks);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int print_cmd(int argc, char **argv)
|
||||
{
|
||||
char *path;
|
||||
int ret;
|
||||
int fd;
|
||||
|
||||
if (argc != 1) {
|
||||
printf("scoutfs print: a single path argument is required\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
path = argv[0];
|
||||
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
ret = -errno;
|
||||
fprintf(stderr, "failed to open '%s': %s (%d)\n",
|
||||
path, strerror(errno), errno);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = print_super_brick(fd);
|
||||
close(fd);
|
||||
return ret;
|
||||
};
|
||||
|
||||
static void __attribute__((constructor)) print_ctor(void)
|
||||
{
|
||||
cmd_register("print", "<device>", "print metadata structures",
|
||||
print_cmd);
|
||||
}
|
||||
30
utils/src/rand.c
Normal file
30
utils/src/rand.c
Normal file
@@ -0,0 +1,30 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "rand.h"
|
||||
#include "sparse.h"
|
||||
#include "util.h"
|
||||
|
||||
void pseudo_random_bytes(void *data, unsigned int len)
|
||||
{
|
||||
unsigned long long tmp;
|
||||
unsigned long long *ll = data;
|
||||
unsigned int sz = sizeof(*ll);
|
||||
unsigned int unaligned;
|
||||
|
||||
/* see if the initial buffer is unaligned */
|
||||
unaligned = min((unsigned long)data & (sz - 1), len);
|
||||
if (unaligned) {
|
||||
__builtin_ia32_rdrand64_step(&tmp);
|
||||
memcpy(data, &tmp, unaligned);
|
||||
data += unaligned;
|
||||
len -= unaligned;
|
||||
}
|
||||
|
||||
for (ll = data; len >= sz; ll++, len -= sz)
|
||||
__builtin_ia32_rdrand64_step(ll);
|
||||
|
||||
if (len) {
|
||||
__builtin_ia32_rdrand64_step(&tmp);
|
||||
memcpy(data, &tmp, len);
|
||||
}
|
||||
}
|
||||
10
utils/src/rand.h
Normal file
10
utils/src/rand.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef _RAND_H_
|
||||
#define _RAND_H_
|
||||
|
||||
/*
|
||||
* We could play around a bit with some macros to get aligned constant
|
||||
* word sized buffers filled by single instructions.
|
||||
*/
|
||||
void pseudo_random_bytes(void *data, unsigned int len);
|
||||
|
||||
#endif
|
||||
105
utils/src/sparse.h
Normal file
105
utils/src/sparse.h
Normal file
@@ -0,0 +1,105 @@
|
||||
#ifndef _SPARSE_H_
|
||||
#define _SPARSE_H_
|
||||
|
||||
#include <endian.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __CHECKER__
|
||||
# undef __force
|
||||
# define __force __attribute__((force))
|
||||
# undef __bitwise
|
||||
# define __bitwise __attribute__((bitwise))
|
||||
/* sparse seems to get confused by some builtins */
|
||||
extern __builtin_ia32_rdrand64_step(unsigned long long *);
|
||||
extern unsigned int __builtin_ia32_crc32di(unsigned int, unsigned long long);
|
||||
extern unsigned int __builtin_ia32_crc32si(unsigned int, unsigned int);
|
||||
extern unsigned int __builtin_ia32_crc32hi(unsigned int, unsigned short);
|
||||
extern unsigned int __builtin_ia32_crc32qi(unsigned int, unsigned char);
|
||||
|
||||
#else
|
||||
# define __force
|
||||
# define __bitwise
|
||||
#endif
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
typedef unsigned long long u64;
|
||||
typedef signed long long s64;
|
||||
|
||||
typedef u8 __u8;
|
||||
typedef u16 __u16;
|
||||
typedef u32 __u32;
|
||||
typedef u64 __u64;
|
||||
|
||||
typedef u16 __bitwise __le16;
|
||||
typedef u16 __bitwise __be16;
|
||||
typedef u32 __bitwise __le32;
|
||||
typedef u32 __bitwise __be32;
|
||||
typedef u64 __bitwise __le64;
|
||||
typedef u64 __bitwise __be64;
|
||||
|
||||
static inline u16 ___swab16(u16 x)
|
||||
{
|
||||
return ((x & (u16)0x00ffU) << 8) |
|
||||
((x & (u16)0xff00U) >> 8);
|
||||
}
|
||||
|
||||
static inline u32 ___swab32(u32 x)
|
||||
{
|
||||
return ((x & (u32)0x000000ffUL) << 24) |
|
||||
((x & (u32)0x0000ff00UL) << 8) |
|
||||
((x & (u32)0x00ff0000UL) >> 8) |
|
||||
((x & (u32)0xff000000UL) >> 24);
|
||||
}
|
||||
|
||||
static inline u64 ___swab64(u64 x)
|
||||
{
|
||||
return (u64)((x & (u64)0x00000000000000ffULL) << 56) |
|
||||
(u64)((x & (u64)0x000000000000ff00ULL) << 40) |
|
||||
(u64)((x & (u64)0x0000000000ff0000ULL) << 24) |
|
||||
(u64)((x & (u64)0x00000000ff000000ULL) << 8) |
|
||||
(u64)((x & (u64)0x000000ff00000000ULL) >> 8) |
|
||||
(u64)((x & (u64)0x0000ff0000000000ULL) >> 24) |
|
||||
(u64)((x & (u64)0x00ff000000000000ULL) >> 40) |
|
||||
(u64)((x & (u64)0xff00000000000000ULL) >> 56);
|
||||
}
|
||||
|
||||
#define __gen_cast_tofrom(end, size) \
|
||||
static inline __##end##size cpu_to_##end##size(u##size x) \
|
||||
{ \
|
||||
return (__force __##end##size)x; \
|
||||
} \
|
||||
static inline u##size end##size##_to_cpu(__##end##size x) \
|
||||
{ \
|
||||
return (__force u##size)x; \
|
||||
}
|
||||
|
||||
#define __gen_swap_tofrom(end, size) \
|
||||
static inline __##end##size cpu_to_##end##size(u##size x) \
|
||||
{ \
|
||||
return (__force __##end##size)___swab##size(x); \
|
||||
} \
|
||||
static inline u##size end##size##_to_cpu(__##end##size x) \
|
||||
{ \
|
||||
return ___swab##size((__force u##size) x); \
|
||||
}
|
||||
|
||||
#define __gen_functions(which, end) \
|
||||
__gen_##which##_tofrom(end, 16) \
|
||||
__gen_##which##_tofrom(end, 32) \
|
||||
__gen_##which##_tofrom(end, 64)
|
||||
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#define __LITTLE_ENDIAN_BITFIELD
|
||||
__gen_functions(swap, be)
|
||||
__gen_functions(cast, le)
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
#define __BIG_ENDIAN_BITFIELD
|
||||
__gen_functions(swap, le)
|
||||
__gen_functions(cast, be)
|
||||
#else
|
||||
#error "machine is neither BIG_ENDIAN nor LITTLE_ENDIAN"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
73
utils/src/util.h
Normal file
73
utils/src/util.h
Normal file
@@ -0,0 +1,73 @@
|
||||
#ifndef _UTIL_H_
|
||||
#define _UTIL_H_
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Generate build warnings if the condition is false but generate no
|
||||
* code at run time if it's true.
|
||||
*/
|
||||
#define build_assert(cond) ((void)sizeof(char[1 - 2*!(cond)]))
|
||||
|
||||
#define min(a, b) \
|
||||
({ \
|
||||
__typeof__(a) _a = (a); \
|
||||
__typeof__(b) _b = (b); \
|
||||
\
|
||||
_a < _b ? _a : _b; \
|
||||
})
|
||||
|
||||
#define max(a, b) \
|
||||
({ \
|
||||
__typeof__(a) _a = (a); \
|
||||
__typeof__(b) _b = (b); \
|
||||
\
|
||||
_a > _b ? _a : _b; \
|
||||
})
|
||||
|
||||
#define swap(a, b) \
|
||||
do { \
|
||||
__typeof__(a) _t = (a); \
|
||||
(a) = (b); \
|
||||
(b) = (_t); \
|
||||
} while (0)
|
||||
|
||||
#define array_size(arr) (sizeof(arr) / sizeof(arr[0]))
|
||||
|
||||
#define __packed __attribute__((packed))
|
||||
|
||||
/*
|
||||
* Round the 'a' value up to the next 'b' power of two boundary. It
|
||||
* casts the mask to the value type before masking to avoid truncation
|
||||
* problems.
|
||||
*/
|
||||
#define round_up(a, b) \
|
||||
({ \
|
||||
__typeof__(a) _b = (b); \
|
||||
\
|
||||
((a) + _b - 1) & ~(_b - 1); \
|
||||
})
|
||||
|
||||
#ifndef offsetof
|
||||
#define offsetof(type, memb) ((unsigned long)&((type *)0)->memb)
|
||||
#endif
|
||||
|
||||
#define container_of(ptr, type, memb) \
|
||||
((type *)((void *)(ptr) - offsetof(type, memb)))
|
||||
|
||||
/*
|
||||
* return -1,0,+1 based on the memcmp comparison of the minimum of their
|
||||
* two lengths. If their min shared bytes are equal but the lengths
|
||||
* are not then the larger length is considered greater.
|
||||
*/
|
||||
static inline int memcmp_lens(const void *a, int a_len,
|
||||
const void *b, int b_len)
|
||||
{
|
||||
unsigned int len = min(a_len, b_len);
|
||||
|
||||
return memcmp(a, b, len) ?: a_len - b_len;
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user