mirror of
https://github.com/versity/scoutfs.git
synced 2026-01-08 13:01:23 +00:00
Implement argp support for mkfs and add --force
Support max-meta-size and max-data-size using KMGTP units with rounding. Detect other fs signatures using blkid library. Detect ScoutFS super using magic value. Move read_block() from print.c into util.c since blkid also needs it. Signed-off-by: Andy Grover <agrover@versity.com>
This commit is contained in:
@@ -47,7 +47,7 @@ endif
|
||||
|
||||
$(BIN): $(OBJ)
|
||||
$(QU) [BIN $@]
|
||||
$(VE)gcc -o $@ $^ -luuid -lm -lcrypto
|
||||
$(VE)gcc -o $@ $^ -luuid -lm -lcrypto -lblkid
|
||||
|
||||
%.o %.d: %.c Makefile sparse.sh
|
||||
$(QU) [CC $<]
|
||||
|
||||
@@ -16,6 +16,7 @@ BuildRequires: git
|
||||
BuildRequires: gzip
|
||||
BuildRequires: libuuid-devel
|
||||
BuildRequires: openssl-devel
|
||||
BuildRequires: libblkid-devel
|
||||
|
||||
#Requires: kmod-scoutfs = %{version}
|
||||
|
||||
|
||||
94
utils/src/blkid.c
Normal file
94
utils/src/blkid.c
Normal file
@@ -0,0 +1,94 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <blkid/blkid.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "format.h"
|
||||
#include "blkid.h"
|
||||
|
||||
static int check_bdev_blkid(int fd, char *devname, char *usage)
|
||||
{
|
||||
blkid_probe pr;
|
||||
int ret = 0;
|
||||
|
||||
pr = blkid_new_probe_from_filename(devname);
|
||||
if (!pr) {
|
||||
fprintf(stderr, "%s: failed to create a new libblkid probe\n", devname);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* enable partitions probing (superblocks are enabled by default) */
|
||||
ret = blkid_probe_enable_partitions(pr, true);
|
||||
if (ret == -1) {
|
||||
fprintf(stderr, "%s: blkid_probe_enable_partitions() failed\n", devname);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = blkid_do_fullprobe(pr);
|
||||
if (ret == -1) {
|
||||
fprintf(stderr, "%s: blkid_do_fullprobe() failed", devname);
|
||||
goto out;
|
||||
} else if (ret == 0) {
|
||||
const char *type;
|
||||
|
||||
if (!blkid_probe_lookup_value(pr, "TYPE", &type, NULL)) {
|
||||
fprintf(stderr, "%s: appears to contain an existing "
|
||||
"%s superblock\n", devname, type);
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!blkid_probe_lookup_value(pr, "PTTYPE", &type, NULL)) {
|
||||
fprintf(stderr, "%s: appears to contain a partition "
|
||||
"table (%s)\n", devname, type);
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
/* return 0 if ok */
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
out:
|
||||
blkid_free_probe(pr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int check_bdev_scoutfs(int fd, char *devname, char *usage)
|
||||
{
|
||||
struct scoutfs_super_block *super = NULL;
|
||||
int ret;
|
||||
|
||||
ret = read_block(fd, SCOUTFS_SUPER_BLKNO, SCOUTFS_BLOCK_SM_SHIFT, (void **)&super);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (le32_to_cpu(super->hdr.magic) == SCOUTFS_SUPER_MAGIC) {
|
||||
fprintf(stderr, "%s: appears to contain an existing "
|
||||
"ScoutFS superblock\n", devname);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
free(super);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Returns -1 on error, 0 otherwise.
|
||||
*/
|
||||
int check_bdev(int fd, char *devname, char *usage)
|
||||
{
|
||||
return check_bdev_blkid(fd, devname, usage) ?:
|
||||
/* Our sig is not in blkid (yet) so check explicitly for us. */
|
||||
check_bdev_scoutfs(fd, devname, usage);
|
||||
}
|
||||
6
utils/src/blkid.h
Normal file
6
utils/src/blkid.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef _BLKID_H_
|
||||
#define _BLKID_H_
|
||||
|
||||
int check_bdev(int fd, char *path, char *usage);
|
||||
|
||||
#endif
|
||||
238
utils/src/mkfs.c
238
utils/src/mkfs.c
@@ -11,12 +11,12 @@
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
#include <argp.h>
|
||||
|
||||
#include "sparse.h"
|
||||
#include "cmd.h"
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "bitops.h"
|
||||
#include "btree.h"
|
||||
#include "leaf_item_hash.h"
|
||||
#include "blkid.h"
|
||||
|
||||
static int write_raw_block(int fd, u64 blkno, int shift, void *blk)
|
||||
{
|
||||
@@ -99,6 +100,16 @@ static int write_alloc_root(struct scoutfs_super_block *super, int fd,
|
||||
return write_raw_block(fd, blkno, SCOUTFS_BLOCK_LG_SHIFT, bt);
|
||||
}
|
||||
|
||||
struct mkfs_args {
|
||||
unsigned long long quorum_count;
|
||||
char *meta_device;
|
||||
char *data_device;
|
||||
unsigned long long max_meta_size;
|
||||
unsigned long long max_data_size;
|
||||
bool force;
|
||||
char __pad[7];
|
||||
};
|
||||
|
||||
/*
|
||||
* Make a new file system by writing:
|
||||
* - super blocks
|
||||
@@ -108,19 +119,18 @@ static int write_alloc_root(struct scoutfs_super_block *super, int fd,
|
||||
* Superblock is written to both metadata and data devices, everything else is
|
||||
* written only to the metadata device.
|
||||
*/
|
||||
static int write_new_fs(char *meta_path, char *data_path,
|
||||
int meta_fd, int data_fd,
|
||||
u8 quorum_count,
|
||||
u64 max_meta_size, u64 max_data_size)
|
||||
static int do_mkfs(struct mkfs_args *args)
|
||||
{
|
||||
struct scoutfs_super_block *super;
|
||||
struct scoutfs_super_block *super = NULL;
|
||||
struct scoutfs_inode inode;
|
||||
struct scoutfs_alloc_list_block *lblk;
|
||||
struct scoutfs_btree_block *bt;
|
||||
struct scoutfs_btree_block *bt = NULL;
|
||||
struct scoutfs_key key;
|
||||
struct timeval tv;
|
||||
int meta_fd = -1;
|
||||
int data_fd = -1;
|
||||
char uuid_str[37];
|
||||
void *zeros;
|
||||
void *zeros = NULL;
|
||||
u64 blkno;
|
||||
u64 meta_size;
|
||||
u64 data_size;
|
||||
@@ -135,6 +145,33 @@ static int write_new_fs(char *meta_path, char *data_path,
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
meta_fd = open(args->meta_device, O_RDWR | O_EXCL);
|
||||
if (meta_fd < 0) {
|
||||
ret = -errno;
|
||||
fprintf(stderr, "failed to open '%s': %s (%d)\n",
|
||||
args->meta_device, strerror(errno), errno);
|
||||
goto out;
|
||||
}
|
||||
if (!args->force) {
|
||||
ret = check_bdev(meta_fd, args->meta_device, "meta");
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
data_fd = open(args->data_device, O_RDWR | O_EXCL);
|
||||
if (data_fd < 0) {
|
||||
ret = -errno;
|
||||
fprintf(stderr, "failed to open '%s': %s (%d)\n",
|
||||
args->data_device, strerror(errno), errno);
|
||||
goto out;
|
||||
}
|
||||
if (!args->force) {
|
||||
ret = check_bdev(data_fd, args->data_device, "data");
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
super = calloc(1, SCOUTFS_BLOCK_SM_SIZE);
|
||||
bt = calloc(1, SCOUTFS_BLOCK_LG_SIZE);
|
||||
zeros = calloc(1, SCOUTFS_BLOCK_SM_SIZE);
|
||||
@@ -145,13 +182,13 @@ static int write_new_fs(char *meta_path, char *data_path,
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = device_size(meta_path, meta_fd, 2ULL * (1024 * 1024 * 1024),
|
||||
max_meta_size, "meta", &meta_size);
|
||||
ret = device_size(args->meta_device, meta_fd, 2ULL * (1024 * 1024 * 1024),
|
||||
args->max_meta_size, "meta", &meta_size);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = device_size(data_path, data_fd, 8ULL * (1024 * 1024 * 1024),
|
||||
max_data_size, "data", &data_size);
|
||||
ret = device_size(args->data_device, data_fd, 8ULL * (1024 * 1024 * 1024),
|
||||
args->max_data_size, "data", &data_size);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
@@ -179,7 +216,7 @@ static int write_new_fs(char *meta_path, char *data_path,
|
||||
super->total_data_blocks = cpu_to_le64(last_data - first_data + 1);
|
||||
super->first_data_blkno = cpu_to_le64(first_data);
|
||||
super->last_data_blkno = cpu_to_le64(last_data);
|
||||
super->quorum_count = quorum_count;
|
||||
super->quorum_count = args->quorum_count;
|
||||
|
||||
/* fs root starts with root inode and its index items */
|
||||
blkno = next_meta++;
|
||||
@@ -293,7 +330,7 @@ static int write_new_fs(char *meta_path, char *data_path,
|
||||
if (fsync(data_fd)) {
|
||||
ret = -errno;
|
||||
fprintf(stderr, "failed to fsync '%s': %s (%d)\n",
|
||||
data_path, strerror(errno), errno);
|
||||
args->data_device, strerror(errno), errno);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -306,7 +343,7 @@ static int write_new_fs(char *meta_path, char *data_path,
|
||||
if (fsync(meta_fd)) {
|
||||
ret = -errno;
|
||||
fprintf(stderr, "failed to fsync '%s': %s (%d)\n",
|
||||
meta_path, strerror(errno), errno);
|
||||
args->meta_device, strerror(errno), errno);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -321,8 +358,8 @@ static int write_new_fs(char *meta_path, char *data_path,
|
||||
" 64KB metadata blocks: "SIZE_FMT"\n"
|
||||
" 4KB data blocks: "SIZE_FMT"\n"
|
||||
" quorum count: %u\n",
|
||||
meta_path,
|
||||
data_path,
|
||||
args->meta_device,
|
||||
args->data_device,
|
||||
le64_to_cpu(super->hdr.fsid),
|
||||
le64_to_cpu(super->format_hash),
|
||||
uuid_str,
|
||||
@@ -340,102 +377,105 @@ out:
|
||||
free(bt);
|
||||
if (zeros)
|
||||
free(zeros);
|
||||
if (meta_fd != -1)
|
||||
close(meta_fd);
|
||||
if (data_fd != -1)
|
||||
close(data_fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct option long_ops[] = {
|
||||
{ "quorum_count", 1, NULL, 'Q' },
|
||||
{ NULL, 0, NULL, 0}
|
||||
static int parse_opt(int key, char *arg, struct argp_state *state)
|
||||
{
|
||||
struct mkfs_args *args = state->input;
|
||||
int ret;
|
||||
|
||||
switch (key) {
|
||||
case 'Q':
|
||||
ret = parse_u64(arg, &args->quorum_count);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
case 'f':
|
||||
args->force = true;
|
||||
break;
|
||||
case 'm': /* max-meta-size */
|
||||
{
|
||||
u64 prev_val;
|
||||
ret = parse_human(arg, &args->max_meta_size);
|
||||
if (ret)
|
||||
return ret;
|
||||
prev_val = args->max_meta_size;
|
||||
args->max_meta_size = round_down(args->max_meta_size, SCOUTFS_BLOCK_LG_SIZE);
|
||||
if (args->max_meta_size != prev_val)
|
||||
fprintf(stderr, "Meta dev size %llu rounded down to %llu bytes\n",
|
||||
prev_val, args->max_meta_size);
|
||||
break;
|
||||
}
|
||||
case 'd': /* max-data-size */
|
||||
{
|
||||
u64 prev_val;
|
||||
ret = parse_human(arg, &args->max_data_size);
|
||||
if (ret)
|
||||
return ret;
|
||||
prev_val = args->max_data_size;
|
||||
args->max_data_size = round_down(args->max_data_size, SCOUTFS_BLOCK_SM_SIZE);
|
||||
if (args->max_data_size != prev_val)
|
||||
fprintf(stderr, "Data dev size %llu rounded down to %llu bytes\n",
|
||||
prev_val, args->max_data_size);
|
||||
break;
|
||||
}
|
||||
case ARGP_KEY_ARG:
|
||||
if (!args->meta_device)
|
||||
args->meta_device = strdup_or_error(state, arg);
|
||||
else if (!args->data_device)
|
||||
args->data_device = strdup_or_error(state, arg);
|
||||
else
|
||||
argp_error(state, "more than two arguments given");
|
||||
break;
|
||||
case ARGP_KEY_FINI:
|
||||
if (!args->quorum_count)
|
||||
argp_error(state, "must provide nonzero quorum count with --quorum-count|-Q option");
|
||||
if (!args->meta_device)
|
||||
argp_error(state, "no metadata device argument given");
|
||||
if (!args->data_device)
|
||||
argp_error(state, "no data device argument given");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct argp_option options[] = {
|
||||
{ "quorum-count", 'Q', "NUM", 0, "Number of voters required to use the filesystem [Required]"},
|
||||
{ "force", 'f', NULL, 0, "Overwrite existing data on block devices"},
|
||||
{ "max-meta-size", 'm', "SIZE", 0, "Use a size less than the base metadata device size (bytes or KMGTP units)"},
|
||||
{ "max-data-size", 'd', "SIZE", 0, "Use a size less than the base data device size (bytes or KMGTP units)"},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static int mkfs_func(int argc, char *argv[])
|
||||
static int mkfs_cmd(int argc, char *argv[])
|
||||
{
|
||||
unsigned long long ull;
|
||||
u8 quorum_count = 0;
|
||||
u64 max_data_size = 0;
|
||||
u64 max_meta_size = 0;
|
||||
char *end = NULL;
|
||||
char *meta_path;
|
||||
char *data_path;
|
||||
int meta_fd;
|
||||
int data_fd;
|
||||
struct argp argp = {
|
||||
options,
|
||||
parse_opt,
|
||||
"META-DEVICE DATA-DEVICE",
|
||||
"Initialize a new ScoutFS filesystem"
|
||||
};
|
||||
struct mkfs_args mkfs_args = {0};
|
||||
int ret;
|
||||
int c;
|
||||
|
||||
while ((c = getopt_long(argc, argv, "Q:D:M:", long_ops, NULL)) != -1) {
|
||||
switch (c) {
|
||||
case 'Q':
|
||||
ull = strtoull(optarg, &end, 0);
|
||||
if (*end != '\0' || ull == 0 ||
|
||||
ull > SCOUTFS_QUORUM_MAX_COUNT) {
|
||||
printf("scoutfs: invalid quorum count '%s'\n",
|
||||
optarg);
|
||||
return -EINVAL;
|
||||
}
|
||||
quorum_count = ull;
|
||||
break;
|
||||
case 'D':
|
||||
ret = parse_human(optarg, &max_data_size);
|
||||
if (ret < 0) {
|
||||
printf("scoutfs: invalid data device size '%s'\n",
|
||||
optarg);
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case 'M':
|
||||
ret = parse_human(optarg, &max_meta_size);
|
||||
if (ret < 0) {
|
||||
printf("scoutfs: invalid meta device size '%s'\n",
|
||||
optarg);
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind + 2 != argc) {
|
||||
printf("scoutfs: mkfs: paths to metadata and data devices are required\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
meta_path = argv[optind];
|
||||
data_path = argv[optind + 1];
|
||||
|
||||
if (!quorum_count) {
|
||||
printf("provide quorum count with --quorum_count|-Q option\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
meta_fd = open(meta_path, O_RDWR | O_EXCL);
|
||||
if (meta_fd < 0) {
|
||||
ret = -errno;
|
||||
fprintf(stderr, "failed to open metadata device '%s': %s (%d)\n",
|
||||
meta_path, strerror(errno), errno);
|
||||
ret = argp_parse(&argp, argc, argv, 0, NULL, &mkfs_args);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
data_fd = open(data_path, O_RDWR | O_EXCL);
|
||||
if (data_fd < 0) {
|
||||
ret = -errno;
|
||||
fprintf(stderr, "failed to open data device '%s': %s (%d)\n",
|
||||
data_path, strerror(errno), errno);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = write_new_fs(meta_path, data_path, meta_fd, data_fd,
|
||||
quorum_count, max_meta_size, max_data_size);
|
||||
close(meta_fd);
|
||||
close(data_fd);
|
||||
|
||||
return ret;
|
||||
return do_mkfs(&mkfs_args);
|
||||
}
|
||||
|
||||
static void __attribute__((constructor)) mkfs_ctor(void)
|
||||
{
|
||||
cmd_register("mkfs", "<path>", "write a new file system", mkfs_func);
|
||||
cmd_register("mkfs", "<meta-device> <data-device>", "write a new file system", mkfs_cmd);
|
||||
|
||||
/* for lack of some other place to put these.. */
|
||||
build_assert(sizeof(uuid_t) == SCOUTFS_UUID_BYTES);
|
||||
|
||||
@@ -26,34 +26,6 @@
|
||||
#include "srch.h"
|
||||
#include "leaf_item_hash.h"
|
||||
|
||||
static int read_block(int fd, u64 blkno, int shift, void **ret_val)
|
||||
{
|
||||
size_t size = 1ULL << shift;
|
||||
void *buf;
|
||||
int ret;
|
||||
|
||||
*ret_val = NULL;
|
||||
|
||||
buf = malloc(size);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = pread(fd, buf, size, blkno << shift);
|
||||
if (ret == -1) {
|
||||
fprintf(stderr, "read blkno %llu returned %d: %s (%d)\n",
|
||||
blkno, ret, strerror(errno), errno);
|
||||
free(buf);
|
||||
return -errno;
|
||||
} else if (ret != size) {
|
||||
fprintf(stderr, "incomplete pread\n");
|
||||
free(buf);
|
||||
return -EINVAL;
|
||||
} else {
|
||||
*ret_val = buf;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void print_block_header(struct scoutfs_block_header *hdr, int size)
|
||||
{
|
||||
u32 crc = crc_block(hdr, size);
|
||||
|
||||
@@ -68,3 +68,31 @@ int get_path(char *path, int flags)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int read_block(int fd, u64 blkno, int shift, void **ret_val)
|
||||
{
|
||||
size_t size = 1ULL << shift;
|
||||
void *buf;
|
||||
int ret;
|
||||
|
||||
*ret_val = NULL;
|
||||
|
||||
buf = malloc(size);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = pread(fd, buf, size, blkno << shift);
|
||||
if (ret == -1) {
|
||||
fprintf(stderr, "read blkno %llu returned %d: %s (%d)\n",
|
||||
blkno, ret, strerror(errno), errno);
|
||||
free(buf);
|
||||
return -errno;
|
||||
} else if (ret != size) {
|
||||
fprintf(stderr, "incomplete pread\n");
|
||||
free(buf);
|
||||
return -EINVAL;
|
||||
} else {
|
||||
*ret_val = buf;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,5 +112,6 @@ static inline int memcmp_lens(const void *a, int a_len,
|
||||
}
|
||||
|
||||
int get_path(char *path, int flags);
|
||||
int read_block(int fd, u64 blkno, int shift, void **ret_val);
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user