mirror of
https://github.com/versity/scoutfs.git
synced 2026-01-03 10:55:20 +00:00
Add change-quorum-config command
Add a command to change the quorum config which starts by only supports updating the super block whlie the file system is oflfine. Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
@@ -42,6 +42,40 @@ the super blocks on both devices.
|
||||
.RE
|
||||
.PD
|
||||
|
||||
.TP
|
||||
.BI "change-quorum-config {-Q|--quorum-slot} NR,ADDR,PORT [-F|--offline META-DEVICE DATA-DEVICE]"
|
||||
.sp
|
||||
Change the quorum configuration for an existing file system. The new
|
||||
configuration completely replaces the old configuration. Any slots
|
||||
from the old configuration that should be retained must be described
|
||||
with arguments in the new configuration.
|
||||
.sp
|
||||
Currently the configuration may only be changed offline.
|
||||
.sp
|
||||
.RS 1.0i
|
||||
.PD 0
|
||||
.TP
|
||||
.B "-Q, --quorum-slot NR,ADDR,PORT"
|
||||
The quorum configuration is built by specifying configured slots with
|
||||
multiple arguments as described in the
|
||||
.B mkfs
|
||||
command.
|
||||
.TP
|
||||
.B "-F, --offline META-DEVICE"
|
||||
Perform the change offline by updating the superblock in the metadata
|
||||
device. The command will read the super block and refuse to make the
|
||||
change if it sees any evidence that the metadata device is currently in
|
||||
use. The file system must be successfully unmounted after possibly
|
||||
recovering any previously unresolved mounts for the change to be
|
||||
successful. After the change succeeds the newly configured slots can
|
||||
be used by mounts.
|
||||
.sp
|
||||
The offline change directly reads from and writes to the device and does
|
||||
not protect against concurrent use of the device. It must be carefully
|
||||
run when the file system will not be mounted.
|
||||
.RE
|
||||
.PD
|
||||
|
||||
.TP
|
||||
.BI "df [-h|--human-readable] [-p|--path PATH]"
|
||||
.sp
|
||||
|
||||
171
utils/src/change_quorum_config.c
Normal file
171
utils/src/change_quorum_config.c
Normal file
@@ -0,0 +1,171 @@
|
||||
#define _GNU_SOURCE /* O_DIRECT */
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <uuid/uuid.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <inttypes.h>
|
||||
#include <argp.h>
|
||||
|
||||
#include "sparse.h"
|
||||
#include "cmd.h"
|
||||
#include "util.h"
|
||||
#include "format.h"
|
||||
#include "parse.h"
|
||||
#include "dev.h"
|
||||
#include "quorum.h"
|
||||
|
||||
struct change_quorum_args {
|
||||
char *meta_device;
|
||||
bool offline;
|
||||
int nr_slots;
|
||||
struct scoutfs_quorum_slot slots[SCOUTFS_QUORUM_MAX_SLOTS];
|
||||
};
|
||||
|
||||
static int do_change_quorum(struct change_quorum_args *args)
|
||||
{
|
||||
struct scoutfs_super_block *meta_super = NULL;
|
||||
char uuid_str[37];
|
||||
int meta_fd = -1;
|
||||
int ret;
|
||||
|
||||
meta_fd = open(args->meta_device, O_DIRECT | O_SYNC | O_RDWR | O_EXCL);
|
||||
if (meta_fd < 0) {
|
||||
ret = -errno;
|
||||
fprintf(stderr, "failed to open meta device '%s': %s (%d)\n",
|
||||
args->meta_device, strerror(errno), errno);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = read_block_verify(meta_fd, SCOUTFS_BLOCK_MAGIC_SUPER, 0, SCOUTFS_SUPER_BLKNO,
|
||||
SCOUTFS_BLOCK_SM_SHIFT, (void **)&meta_super);
|
||||
if (ret) {
|
||||
ret = -errno;
|
||||
fprintf(stderr, "failed to read meta super block: %s (%d)\n",
|
||||
strerror(errno), errno);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = meta_super_in_use(meta_fd, meta_super);
|
||||
if (ret < 0) {
|
||||
if (ret == -EBUSY)
|
||||
fprintf(stderr, "The filesystem must be fully recovered and cleanly unmounted to change the quorum config\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
assert(sizeof(meta_super->qconf.slots) == sizeof(args->slots));
|
||||
memcpy(meta_super->qconf.slots, args->slots, sizeof(meta_super->qconf.slots));
|
||||
le64_add_cpu(&meta_super->qconf.version, 1);
|
||||
|
||||
ret = write_block(meta_fd, SCOUTFS_BLOCK_MAGIC_SUPER, meta_super->hdr.fsid, 1,
|
||||
SCOUTFS_SUPER_BLKNO, SCOUTFS_BLOCK_SM_SHIFT, &meta_super->hdr);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
uuid_unparse(meta_super->uuid, uuid_str);
|
||||
|
||||
printf("Successfully changed quorum config for scoutfs filesystem:\n"
|
||||
" meta device path: %s\n"
|
||||
" fsid: %llx\n"
|
||||
" uuid: %s\n"
|
||||
" quorum config version: %llu\n"
|
||||
" quorum slots: ",
|
||||
args->meta_device,
|
||||
le64_to_cpu(meta_super->hdr.fsid),
|
||||
uuid_str,
|
||||
le64_to_cpu(meta_super->qconf.version));
|
||||
|
||||
print_quorum_slots(meta_super->qconf.slots, array_size(meta_super->qconf.slots),
|
||||
" ");
|
||||
|
||||
out:
|
||||
|
||||
if (meta_super)
|
||||
free(meta_super);
|
||||
if (meta_fd != -1)
|
||||
close(meta_fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int parse_opt(int key, char *arg, struct argp_state *state)
|
||||
{
|
||||
struct change_quorum_args *args = state->input;
|
||||
struct scoutfs_quorum_slot slot;
|
||||
int ret;
|
||||
|
||||
switch (key) {
|
||||
case 'F':
|
||||
args->offline = true;
|
||||
break;
|
||||
case 'Q':
|
||||
ret = parse_quorum_slot(&slot, arg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (args->slots[ret].addr.v4.family != cpu_to_le16(SCOUTFS_AF_NONE))
|
||||
argp_error(state, "Quorum slot %u already specified before slot '%s'\n",
|
||||
ret, arg);
|
||||
args->slots[ret] = slot;
|
||||
args->nr_slots++;
|
||||
break;
|
||||
case ARGP_KEY_ARG:
|
||||
if (!args->meta_device)
|
||||
args->meta_device = strdup_or_error(state, arg);
|
||||
else
|
||||
argp_error(state, "more than one metadata device argument given");
|
||||
break;
|
||||
case ARGP_KEY_FINI:
|
||||
if (!args->offline)
|
||||
argp_error(state, "must specify --offline");
|
||||
if (!args->meta_device)
|
||||
argp_error(state, "no metadata device argument given");
|
||||
if (!args->nr_slots)
|
||||
argp_error(state, "must specify at least one quorum slot with --quorum-slot|-Q");
|
||||
if (!valid_quorum_slots(args->slots))
|
||||
argp_error(state, "invalid quorum slot configuration");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct argp_option options[] = {
|
||||
{ "quorum-slot", 'Q', "NR,ADDR,PORT", 0, "Specify quorum slot addresses [Required]"},
|
||||
{ "offline", 'F', NULL, 0, "Write format version in offline device super blocks [Currently Required]"},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static struct argp argp = {
|
||||
options,
|
||||
parse_opt,
|
||||
"",
|
||||
"Change quorum slots and addresses of an existing ScoutFS filesystem"
|
||||
};
|
||||
|
||||
static int change_quorum_cmd(int argc, char *argv[])
|
||||
{
|
||||
struct change_quorum_args change_quorum_args = {
|
||||
.offline = false,
|
||||
};
|
||||
int ret;
|
||||
|
||||
ret = argp_parse(&argp, argc, argv, 0, NULL, &change_quorum_args);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return do_change_quorum(&change_quorum_args);
|
||||
}
|
||||
|
||||
static void __attribute__((constructor)) change_quorum_ctor(void)
|
||||
{
|
||||
cmd_register_argp("change-quorum-config", &argp, GROUP_CORE, change_quorum_cmd);
|
||||
}
|
||||
Reference in New Issue
Block a user