mirror of
https://github.com/koverstreet/bcachefs-tools.git
synced 2025-02-02 00:00:03 +03:00
add support for maximum journal entry size
also rip out prototype crypto support code - real code is in the dev branch, with the new superblock format
This commit is contained in:
parent
4e158e1553
commit
7f4191a202
11
Makefile
11
Makefile
@ -6,7 +6,7 @@ LDFLAGS+=-static
|
||||
|
||||
PKGCONFIG_LIBS="blkid uuid"
|
||||
CFLAGS+=`pkg-config --cflags ${PKGCONFIG_LIBS}`
|
||||
LDLIBS+=`pkg-config --libs ${PKGCONFIG_LIBS}` -lscrypt -lsodium -lkeyutils -lm
|
||||
LDLIBS+=`pkg-config --libs ${PKGCONFIG_LIBS}` -lm
|
||||
|
||||
ifeq ($(PREFIX),/usr)
|
||||
ROOT_SBINDIR=/sbin
|
||||
@ -24,7 +24,7 @@ libccan.a: $(CCANOBJS)
|
||||
$(AR) r $@ $(CCANOBJS)
|
||||
|
||||
bcache-objs = bcache.o bcache-assemble.o bcache-device.o bcache-format.o\
|
||||
bcache-fs.o bcache-run.o bcache-key.o libbcache.o crypto.o util.o
|
||||
bcache-fs.o bcache-run.o libbcache.o util.o
|
||||
|
||||
-include $(bcache-objs:.o=.d)
|
||||
|
||||
@ -44,4 +44,9 @@ clean:
|
||||
|
||||
.PHONY: deb
|
||||
deb: all
|
||||
debuild -nc -us -uc -i -I
|
||||
debuild --unsigned-source \
|
||||
--unsigned-changes \
|
||||
--no-pre-clean \
|
||||
--build=binary \
|
||||
--diff-ignore \
|
||||
--tar-ignore
|
||||
|
@ -26,7 +26,6 @@
|
||||
|
||||
#include "bcache.h"
|
||||
#include "libbcache.h"
|
||||
#include "crypto.h"
|
||||
|
||||
/* Open a block device, do magic blkid stuff: */
|
||||
static int open_for_format(const char *dev, bool force)
|
||||
@ -80,9 +79,9 @@ static void usage(void)
|
||||
" --metadata_checksum_type=(none|crc32c|crc64)\n"
|
||||
" --data_checksum_type=(none|crc32c|crc64)\n"
|
||||
" --compression_type=(none|lz4|gzip)\n"
|
||||
" --encrypted\n"
|
||||
" --error_action=(continue|readonly|panic)\n"
|
||||
" Action to take on filesystem error\n"
|
||||
" --max_journal_entry_size=size\n"
|
||||
" -l, --label=label\n"
|
||||
" --uuid=uuid\n"
|
||||
" -f, --force\n"
|
||||
@ -108,8 +107,8 @@ static void usage(void)
|
||||
OPT(0, metadata_checksum_type, required_argument) \
|
||||
OPT(0, data_checksum_type, required_argument) \
|
||||
OPT(0, compression_type, required_argument) \
|
||||
OPT(0, encrypted, no_argument) \
|
||||
OPT('e', error_action, required_argument) \
|
||||
OPT(0, max_journal_entry_size, required_argument) \
|
||||
OPT('L', label, required_argument) \
|
||||
OPT('U', uuid, required_argument) \
|
||||
OPT('f', force, no_argument) \
|
||||
@ -144,7 +143,6 @@ int cmd_format(int argc, char *argv[])
|
||||
unsigned meta_csum_type = BCH_CSUM_CRC32C;
|
||||
unsigned data_csum_type = BCH_CSUM_CRC32C;
|
||||
unsigned compression_type = BCH_COMPRESSION_NONE;
|
||||
bool encrypted = false;
|
||||
unsigned on_error_action = BCH_ON_ERROR_RO;
|
||||
char *label = NULL;
|
||||
uuid_le uuid;
|
||||
@ -155,6 +153,7 @@ int cmd_format(int argc, char *argv[])
|
||||
unsigned bucket_size = 0;
|
||||
unsigned tier = 0;
|
||||
bool discard = false;
|
||||
unsigned max_journal_entry_size = 0;
|
||||
char *passphrase = NULL;
|
||||
int opt;
|
||||
|
||||
@ -187,14 +186,15 @@ int cmd_format(int argc, char *argv[])
|
||||
compression_type = read_string_list_or_die(optarg,
|
||||
compression_types, "compression type");
|
||||
break;
|
||||
case Opt_encrypted:
|
||||
encrypted = true;
|
||||
break;
|
||||
case Opt_error_action:
|
||||
case 'e':
|
||||
on_error_action = read_string_list_or_die(optarg,
|
||||
error_actions, "error action");
|
||||
break;
|
||||
case Opt_max_journal_entry_size:
|
||||
max_journal_entry_size = hatoi_validate(optarg,
|
||||
"journal entry size");
|
||||
break;
|
||||
case Opt_label:
|
||||
case 'L':
|
||||
label = strdup(optarg);
|
||||
@ -242,22 +242,6 @@ int cmd_format(int argc, char *argv[])
|
||||
if (uuid_is_null(uuid.b))
|
||||
uuid_generate(uuid.b);
|
||||
|
||||
if (encrypted) {
|
||||
char *pass2;
|
||||
|
||||
passphrase = read_passphrase("Enter passphrase: ");
|
||||
pass2 = read_passphrase("Enter same passphrase again: ");
|
||||
|
||||
if (strcmp(passphrase, pass2)) {
|
||||
memzero_explicit(passphrase, strlen(passphrase));
|
||||
memzero_explicit(pass2, strlen(pass2));
|
||||
die("Passphrases do not match");
|
||||
}
|
||||
|
||||
memzero_explicit(pass2, strlen(pass2));
|
||||
free(pass2);
|
||||
}
|
||||
|
||||
darray_foreach(dev, devices)
|
||||
dev->fd = open_for_format(dev->path, force);
|
||||
|
||||
@ -267,10 +251,10 @@ int cmd_format(int argc, char *argv[])
|
||||
meta_csum_type,
|
||||
data_csum_type,
|
||||
compression_type,
|
||||
passphrase,
|
||||
1,
|
||||
1,
|
||||
on_error_action,
|
||||
max_journal_entry_size,
|
||||
label,
|
||||
uuid);
|
||||
|
||||
|
52
bcache-key.c
52
bcache-key.c
@ -1,52 +0,0 @@
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <keyutils.h>
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
#include "bcache.h"
|
||||
#include "libbcache.h"
|
||||
#include "crypto.h"
|
||||
|
||||
int cmd_unlock(int argc, char *argv[])
|
||||
{
|
||||
struct bcache_disk_key disk_key;
|
||||
struct bcache_key key;
|
||||
struct cache_sb *sb;
|
||||
char *passphrase;
|
||||
char uuid[40];
|
||||
char description[60];
|
||||
|
||||
if (argc != 2)
|
||||
die("please supply a single device");
|
||||
|
||||
sb = bcache_super_read(argv[1]);
|
||||
|
||||
if (!CACHE_SET_ENCRYPTION_KEY(sb))
|
||||
die("filesystem is not encrypted");
|
||||
|
||||
memcpy(&disk_key, sb->encryption_key, sizeof(disk_key));
|
||||
|
||||
if (!memcmp(&disk_key, bch_key_header, sizeof(bch_key_header)))
|
||||
die("filesystem does not have encryption key");
|
||||
|
||||
passphrase = read_passphrase("Enter passphrase: ");
|
||||
|
||||
derive_passphrase(&key, passphrase);
|
||||
disk_key_encrypt(sb, &disk_key, &key);
|
||||
|
||||
if (memcmp(&disk_key, bch_key_header, sizeof(bch_key_header)))
|
||||
die("incorrect passphrase");
|
||||
|
||||
uuid_unparse_lower(sb->user_uuid.b, uuid);
|
||||
sprintf(description, "bcache:%s", uuid);
|
||||
|
||||
if (add_key("logon", description, &key, sizeof(key),
|
||||
KEY_SPEC_USER_KEYRING) < 0)
|
||||
die("add_key error: %s", strerror(errno));
|
||||
|
||||
memzero_explicit(&disk_key, sizeof(disk_key));
|
||||
memzero_explicit(&key, sizeof(key));
|
||||
memzero_explicit(passphrase, strlen(passphrase));
|
||||
free(passphrase);
|
||||
return 0;
|
||||
}
|
@ -813,21 +813,7 @@ LE64_BITMASK(CACHE_SET_ROOT_RESERVE, struct cache_sb, flags2, 0, 6);
|
||||
*/
|
||||
LE64_BITMASK(CACHE_SET_CLEAN, struct cache_sb, flags2, 6, 7);
|
||||
|
||||
/*
|
||||
* If nonzero, encryption is enabled; overrides DATA/META_CSUM_TYPE. Also
|
||||
* indicates encryption algorithm in use, if/when we get more than one:
|
||||
*
|
||||
*/
|
||||
LE64_BITMASK(CACHE_SET_ENCRYPTION_TYPE, struct cache_sb, flags2, 6, 10);
|
||||
|
||||
/*
|
||||
* If nonzero, we have an encryption key in the superblock, which is the key
|
||||
* used to encrypt all other data/metadata. The key will normally be encrypted
|
||||
* with the key userspace provides, but if encryption has been turned off we'll
|
||||
* just store the master key unencrypted in the superblock so we can access the
|
||||
* previously encrypted data.
|
||||
*/
|
||||
LE64_BITMASK(CACHE_SET_ENCRYPTION_KEY, struct cache_sb, flags2, 10, 11);
|
||||
LE64_BITMASK(CACHE_SET_JOURNAL_ENTRY_SIZE, struct cache_sb, flags2, 7, 15);
|
||||
|
||||
/* options: */
|
||||
|
||||
|
4
bcache.c
4
bcache.c
@ -30,7 +30,6 @@ static void usage(void)
|
||||
"\n"
|
||||
"Commands for formatting, startup and shutdown\n"
|
||||
" format Format a new filesystem\n"
|
||||
" unlock Unlock an encrypted filesystem prior to running/mounting\n"
|
||||
" assemble Assemble an existing multi device filesystem\n"
|
||||
" incremental Incrementally assemble an existing multi device filesystem\n"
|
||||
" run Start a partially assembled filesystem\n"
|
||||
@ -84,9 +83,6 @@ int main(int argc, char *argv[])
|
||||
if (!strcmp(cmd, "device_remove"))
|
||||
return cmd_device_remove(argc, argv);
|
||||
|
||||
if (!strcmp(cmd, "unlock"))
|
||||
return cmd_unlock(argc, argv);
|
||||
|
||||
usage();
|
||||
return 0;
|
||||
}
|
||||
|
1
bcache.h
1
bcache.h
@ -11,7 +11,6 @@
|
||||
|
||||
int cmd_format(int argc, char *argv[]);
|
||||
|
||||
int cmd_unlock(int argc, char *argv[]);
|
||||
int cmd_assemble(int argc, char *argv[]);
|
||||
int cmd_incremental(int argc, char *argv[]);
|
||||
int cmd_run(int argc, char *argv[]);
|
||||
|
132
crypto.c
132
crypto.c
@ -1,132 +0,0 @@
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <linux/random.h>
|
||||
#include <libscrypt.h>
|
||||
#include <sodium/crypto_stream_chacha20.h>
|
||||
|
||||
#include "crypto.h"
|
||||
|
||||
char *read_passphrase(const char *prompt)
|
||||
{
|
||||
struct termios old, new;
|
||||
char *buf = NULL;
|
||||
size_t buflen = 0;
|
||||
|
||||
fprintf(stderr, "%s", prompt);
|
||||
fflush(stderr);
|
||||
|
||||
if (tcgetattr(fileno(stdin), &old))
|
||||
die("error getting terminal attrs");
|
||||
|
||||
new = old;
|
||||
new.c_lflag &= ~ECHO;
|
||||
if (tcsetattr(fileno(stdin), TCSAFLUSH, &new))
|
||||
die("error setting terminal attrs");
|
||||
|
||||
if (getline(&buf, &buflen, stdin) <= 0)
|
||||
die("error reading passphrase");
|
||||
|
||||
tcsetattr(fileno(stdin), TCSAFLUSH, &old);
|
||||
fprintf(stderr, "\n");
|
||||
return buf;
|
||||
}
|
||||
|
||||
void derive_passphrase(struct bcache_key *key, const char *passphrase)
|
||||
{
|
||||
const unsigned char salt[] = "bcache";
|
||||
int ret;
|
||||
|
||||
ret = libscrypt_scrypt((void *) passphrase, strlen(passphrase),
|
||||
salt, sizeof(salt),
|
||||
SCRYPT_N, SCRYPT_r, SCRYPT_p,
|
||||
(void *) key, sizeof(*key));
|
||||
if (ret)
|
||||
die("scrypt error: %i", ret);
|
||||
}
|
||||
|
||||
void disk_key_encrypt(struct cache_sb *sb,
|
||||
struct bcache_disk_key *disk_key,
|
||||
struct bcache_key *key)
|
||||
{
|
||||
__le32 nonce[2];
|
||||
int ret;
|
||||
|
||||
memcpy(nonce, &sb->set_magic, sizeof(sb->set_magic));
|
||||
|
||||
ret = crypto_stream_chacha20_xor((void *) disk_key,
|
||||
(void *) disk_key, sizeof(*disk_key),
|
||||
(void *) nonce,
|
||||
(void *) key);
|
||||
if (ret)
|
||||
die("chacha20 error: %i", ret);
|
||||
}
|
||||
|
||||
void disk_key_init(struct bcache_disk_key *disk_key)
|
||||
{
|
||||
ssize_t ret;
|
||||
|
||||
memcpy(&disk_key->header, bch_key_header, sizeof(bch_key_header));
|
||||
#if 0
|
||||
ret = getrandom(disk_key->key, sizeof(disk_key->key), GRND_RANDOM);
|
||||
if (ret != sizeof(disk_key->key))
|
||||
die("error getting random bytes for key");
|
||||
#else
|
||||
int fd = open("/dev/random", O_RDONLY|O_NONBLOCK);
|
||||
if (fd < 0)
|
||||
die("error opening /dev/random");
|
||||
|
||||
size_t n = 0;
|
||||
struct timespec start;
|
||||
bool printed = false;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &start);
|
||||
|
||||
while (n < sizeof(disk_key->key)) {
|
||||
struct timeval timeout = { 1, 0 };
|
||||
fd_set set;
|
||||
|
||||
FD_ZERO(&set);
|
||||
FD_SET(fd, &set);
|
||||
|
||||
if (select(fd + 1, &set, NULL, NULL, &timeout) < 0)
|
||||
die("select error");
|
||||
|
||||
ret = read(fd,
|
||||
(void *) disk_key->key + n,
|
||||
sizeof(disk_key->key) - n);
|
||||
if (ret == -1 && errno != EINTR && errno != EAGAIN)
|
||||
die("error reading from /dev/random");
|
||||
if (ret > 0)
|
||||
n += ret;
|
||||
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
|
||||
now.tv_sec -= start.tv_sec;
|
||||
now.tv_nsec -= start.tv_nsec;
|
||||
|
||||
while (now.tv_nsec < 0) {
|
||||
long nsec_per_sec = 1000 * 1000 * 1000;
|
||||
long sec = now.tv_nsec / nsec_per_sec - 1;
|
||||
now.tv_nsec -= sec * nsec_per_sec;
|
||||
now.tv_sec += sec;
|
||||
}
|
||||
|
||||
if (!printed && now.tv_sec >= 3) {
|
||||
printf("Reading from /dev/random is taking a long time...\n)");
|
||||
printed = true;
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
#endif
|
||||
}
|
24
crypto.h
24
crypto.h
@ -1,24 +0,0 @@
|
||||
#ifndef _CRYPTO_H
|
||||
#define _CRYPTO_H
|
||||
|
||||
#include "util.h"
|
||||
|
||||
struct bcache_key {
|
||||
u64 key[4];
|
||||
};
|
||||
|
||||
struct bcache_disk_key {
|
||||
u64 header;
|
||||
u64 key[4];
|
||||
};
|
||||
|
||||
static const char bch_key_header[8] = BCACHE_MASTER_KEY_HEADER;
|
||||
static const struct nonce bch_master_key_nonce = BCACHE_MASTER_KEY_NONCE;
|
||||
|
||||
char *read_passphrase(const char *);
|
||||
void derive_passphrase(struct bcache_key *, const char *);
|
||||
void disk_key_encrypt(struct cache_sb *sb, struct bcache_disk_key *,
|
||||
struct bcache_key *);
|
||||
void disk_key_init(struct bcache_disk_key *);
|
||||
|
||||
#endif /* _CRYPTO_H */
|
29
libbcache.c
29
libbcache.c
@ -15,7 +15,6 @@
|
||||
|
||||
#include "bcache-ondisk.h"
|
||||
#include "libbcache.h"
|
||||
#include "crypto.h"
|
||||
|
||||
const char * const cache_state[] = {
|
||||
"active",
|
||||
@ -125,10 +124,10 @@ void bcache_format(struct dev_opts *devs, size_t nr_devs,
|
||||
unsigned meta_csum_type,
|
||||
unsigned data_csum_type,
|
||||
unsigned compression_type,
|
||||
const char *passphrase,
|
||||
unsigned meta_replicas,
|
||||
unsigned data_replicas,
|
||||
unsigned on_error_action,
|
||||
unsigned max_journal_entry_size,
|
||||
char *label,
|
||||
uuid_le uuid)
|
||||
{
|
||||
@ -191,6 +190,13 @@ void bcache_format(struct dev_opts *devs, size_t nr_devs,
|
||||
btree_node_size = min(btree_node_size, i->bucket_size);
|
||||
}
|
||||
|
||||
if (!max_journal_entry_size) {
|
||||
/* 2 MB default: */
|
||||
max_journal_entry_size = 4096;
|
||||
}
|
||||
|
||||
max_journal_entry_size = roundup_pow_of_two(max_journal_entry_size);
|
||||
|
||||
sb = calloc(1, sizeof(*sb) + sizeof(struct cache_member) * nr_devs);
|
||||
|
||||
sb->offset = __cpu_to_le64(SB_SECTOR);
|
||||
@ -221,22 +227,7 @@ void bcache_format(struct dev_opts *devs, size_t nr_devs,
|
||||
SET_CACHE_SET_DATA_REPLICAS_HAVE(sb, data_replicas);
|
||||
SET_CACHE_SET_ERROR_ACTION(sb, on_error_action);
|
||||
SET_CACHE_SET_STR_HASH_TYPE(sb, BCH_STR_HASH_SIPHASH);
|
||||
|
||||
if (passphrase) {
|
||||
struct bcache_key key;
|
||||
struct bcache_disk_key disk_key;
|
||||
|
||||
derive_passphrase(&key, passphrase);
|
||||
disk_key_init(&disk_key);
|
||||
disk_key_encrypt(sb, &disk_key, &key);
|
||||
|
||||
memcpy(sb->encryption_key, &disk_key, sizeof(disk_key));
|
||||
SET_CACHE_SET_ENCRYPTION_TYPE(sb, 1);
|
||||
SET_CACHE_SET_ENCRYPTION_KEY(sb, 1);
|
||||
|
||||
memzero_explicit(&disk_key, sizeof(disk_key));
|
||||
memzero_explicit(&key, sizeof(key));
|
||||
}
|
||||
SET_CACHE_SET_JOURNAL_ENTRY_SIZE(sb, ilog2(max_journal_entry_size));
|
||||
|
||||
for (i = devs; i < devs + nr_devs; i++) {
|
||||
struct cache_member *m = sb->members + (i - devs);
|
||||
@ -286,6 +277,7 @@ void bcache_super_print(struct cache_sb *sb, int units)
|
||||
"Version: %llu\n"
|
||||
"Block_size: %s\n"
|
||||
"Btree node size: %s\n"
|
||||
"Max journal entry size: %s\n"
|
||||
"Error action: %s\n"
|
||||
"Clean: %llu\n"
|
||||
|
||||
@ -308,6 +300,7 @@ void bcache_super_print(struct cache_sb *sb, int units)
|
||||
le64_to_cpu(sb->version),
|
||||
pr_units(le16_to_cpu(sb->block_size), units).b,
|
||||
pr_units(CACHE_SET_BTREE_NODE_SIZE(sb), units).b,
|
||||
pr_units(1U << CACHE_SET_JOURNAL_ENTRY_SIZE(sb), units).b,
|
||||
|
||||
CACHE_SET_ERROR_ACTION(sb) < BCH_NR_ERROR_ACTIONS
|
||||
? error_actions[CACHE_SET_ERROR_ACTION(sb)]
|
||||
|
@ -31,10 +31,10 @@ void bcache_format(struct dev_opts *devs, size_t nr_devs,
|
||||
unsigned meta_csum_type,
|
||||
unsigned data_csum_type,
|
||||
unsigned compression_type,
|
||||
const char *passphrase,
|
||||
unsigned meta_replicas,
|
||||
unsigned data_replicas,
|
||||
unsigned on_error_action,
|
||||
unsigned max_journal_entry_size,
|
||||
char *label,
|
||||
uuid_le uuid);
|
||||
|
||||
|
27
util.c
27
util.c
@ -1,4 +1,5 @@
|
||||
#include <alloca.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
@ -21,23 +22,13 @@
|
||||
|
||||
/* Integer stuff: */
|
||||
|
||||
u64 rounddown_pow_of_two(u64 n)
|
||||
{
|
||||
u64 ret;
|
||||
|
||||
do {
|
||||
ret = n;
|
||||
n &= n - 1;
|
||||
} while (n);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned ilog2(u64 n)
|
||||
{
|
||||
unsigned ret = 0;
|
||||
|
||||
while (n) {
|
||||
assert(n > 0);
|
||||
|
||||
while (n > 1) {
|
||||
ret++;
|
||||
n >>= 1;
|
||||
}
|
||||
@ -45,6 +36,16 @@ unsigned ilog2(u64 n)
|
||||
return ret;
|
||||
}
|
||||
|
||||
u64 rounddown_pow_of_two(u64 n)
|
||||
{
|
||||
return 1ULL << ilog2(n);
|
||||
}
|
||||
|
||||
u64 roundup_pow_of_two(u64 n)
|
||||
{
|
||||
return 1ULL << (ilog2(n - 1) + 1);
|
||||
}
|
||||
|
||||
char *skip_spaces(const char *str)
|
||||
{
|
||||
while (isspace(*str))
|
||||
|
8
util.h
8
util.h
@ -58,14 +58,20 @@ static inline void le64_add_cpu(__le64 *var, u64 val)
|
||||
(void) (&_max1 == &_max2); \
|
||||
_max1 > _max2 ? _max1 : _max2; })
|
||||
|
||||
#define max_t(type, x, y) ({ \
|
||||
type __max1 = (x); \
|
||||
type __max2 = (y); \
|
||||
__max1 > __max2 ? __max1: __max2; })
|
||||
|
||||
#define die(arg, ...) \
|
||||
do { \
|
||||
fprintf(stderr, arg "\n", ##__VA_ARGS__); \
|
||||
exit(EXIT_FAILURE); \
|
||||
} while (0)
|
||||
|
||||
u64 rounddown_pow_of_two(u64);
|
||||
unsigned ilog2(u64);
|
||||
u64 rounddown_pow_of_two(u64);
|
||||
u64 roundup_pow_of_two(u64);
|
||||
|
||||
char *skip_spaces(const char *str);
|
||||
char *strim(char *s);
|
||||
|
Loading…
Reference in New Issue
Block a user