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:
Kent Overstreet 2016-12-11 14:45:48 -09:00
parent 4e158e1553
commit 7f4191a202
12 changed files with 50 additions and 288 deletions

View File

@ -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

View File

@ -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);

View File

@ -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;
}

View File

@ -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: */

View File

@ -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;
}

View File

@ -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
View File

@ -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
}

View File

@ -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 */

View File

@ -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)]

View File

@ -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
View File

@ -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
View File

@ -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);