Compare commits

..

1 Commits

Author SHA1 Message Date
Zach Brown
8624132ad2 Add debug command to wipe log_trees data_freed
Signed-off-by: Zach Brown <zab@versity.com>
2024-02-19 09:54:56 -08:00
4 changed files with 243 additions and 32 deletions

View File

@@ -1,15 +1,6 @@
Versity ScoutFS Release Notes
=============================
---
v1.20
\
*Apr 22, 2024*
Minor changes to packaging to better support "weak" module linking of
the kernel module, and to including git hashes in the built package. No
changes in runtime behaviour.
---
v1.19
\

View File

@@ -12,22 +12,17 @@ else
SP = @:
endif
SCOUTFS_GIT_DESCRIBE ?= \
SCOUTFS_GIT_DESCRIBE := \
$(shell git describe --all --abbrev=6 --long 2>/dev/null || \
echo no-git)
ESCAPED_GIT_DESCRIBE := \
$(shell echo $(SCOUTFS_GIT_DESCRIBE) |sed -e 's/\//\\\//g')
RPM_GITHASH ?= $(shell git rev-parse --short HEAD)
SCOUTFS_ARGS := SCOUTFS_GIT_DESCRIBE=$(SCOUTFS_GIT_DESCRIBE) \
RPM_GITHASH=$(RPM_GITHASH) \
CONFIG_SCOUTFS_FS=m -C $(SK_KSRC) M=$(CURDIR)/src \
EXTRA_CFLAGS="-Werror"
# - We use the git describe from tags to set up the RPM versioning
RPM_VERSION := $(shell git describe --long --tags | awk -F '-' '{gsub(/^v/,""); print $$1}')
RPM_GITHASH := $(shell git rev-parse --short HEAD)
TARFILE = scoutfs-kmod-$(RPM_VERSION).tar
@@ -46,8 +41,7 @@ modules_install:
%.spec: %.spec.in .FORCE
sed -e 's/@@VERSION@@/$(RPM_VERSION)/g' \
-e 's/@@GITHASH@@/$(RPM_GITHASH)/g' \
-e 's/@@GITDESCRIBE@@/$(ESCAPED_GIT_DESCRIBE)/g' < $< > $@+
-e 's/@@GITHASH@@/$(RPM_GITHASH)/g' < $< > $@+
mv $@+ $@

View File

@@ -1,7 +1,6 @@
%define kmod_name scoutfs
%define kmod_version @@VERSION@@
%define kmod_git_hash @@GITHASH@@
%define kmod_git_describe @@GITDESCRIBE@@
%define pkg_date %(date +%%Y%%m%%d)
# Disable the building of the debug package(s).
@@ -76,7 +75,7 @@ echo "Building for kernel: %{kernel_version} flavors: '%{flavors_to_build}'"
for flavor in %flavors_to_build; do
rm -rf obj/$flavor
cp -r source obj/$flavor
make RPM_GITHASH=%{kmod_git_hash} SCOUTFS_GIT_DESCRIBE=%{kmod_git_describe} SK_KSRC=%{kernel_source $flavor} -C obj/$flavor module
make SK_KSRC=%{kernel_source $flavor} -C obj/$flavor module
done
%install
@@ -98,21 +97,10 @@ find %{buildroot} -type f -name \*.ko -exec %{__chmod} u+x \{\} \;
/lib/modules
%post
echo /lib/modules/%{kversion}/%{install_mod_dir}/scoutfs.ko | weak-modules --add-modules --no-initramfs
weak-modules --add-kernel --no-initramfs
depmod -a
%endif
%clean
rm -rf %{buildroot}
%preun
# stash our modules for postun cleanup
SCOUTFS_RPM_NAME=$(rpm -q %{name} | grep "%{version}-%{release}")
rpm -ql $SCOUTFS_RPM_NAME | grep '\.ko$' > /var/run/%{name}-modules-%{version}-%{release} || true
%postun
if [ -x /sbin/weak-modules ]; then
cat /var/run/%{name}-modules-%{version}-%{release} | /sbin/weak-modules --remove-modules --no-initramfs
fi
rm /var/run/%{name}-modules-%{version}-%{release} || true

View File

@@ -0,0 +1,238 @@
#define _GNU_SOURCE /* O_DIRECT */
#include <unistd.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <assert.h>
#include <ctype.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 "btree.h"
#include "avl.h"
struct wipe_ltdf_args {
char *meta_device;
u64 fsid;
u64 rid;
};
static int do_wipe_ltdf(struct wipe_ltdf_args *args)
{
struct scoutfs_super_block *super = NULL;
struct scoutfs_btree_block *bt = NULL;
struct scoutfs_btree_item *item;
struct scoutfs_avl_node *node;
struct scoutfs_log_trees *lt;
bool found = false;
int meta_fd = -1;
unsigned val_len;
u64 blkno;
int ret;
meta_fd = open(args->meta_device, O_DIRECT | 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;
}
ret = read_block_verify(meta_fd, SCOUTFS_BLOCK_MAGIC_SUPER, args->fsid, SCOUTFS_SUPER_BLKNO,
SCOUTFS_BLOCK_SM_SHIFT, (void **)&super);
if (ret) {
ret = -errno;
fprintf(stderr, "failed to read meta super block: %s (%d)\n",
strerror(errno), errno);
goto out;
}
if (!(le64_to_cpu(super->flags) & SCOUTFS_FLAG_IS_META_BDEV)) {
fprintf(stderr, "The super block in device %s doesn't have the META_BDEV flag set, is it a data device?\n",
args->meta_device);
ret = -EIO;
goto out;
}
blkno = le64_to_cpu(super->logs_root.ref.blkno);
if (blkno == 0) {
fprintf(stderr, "The logs_root btree ref is empty, no pending log_trees items\n");
ret = 0;
goto out;
}
if (super->logs_root.height != 1) {
fprintf(stderr, "The logs_root btree is not a single leaf, can't find items\n");
ret = -EINVAL;
goto out;
}
ret = read_block_verify(meta_fd, SCOUTFS_BLOCK_MAGIC_BTREE, args->fsid, blkno,
SCOUTFS_BLOCK_LG_SHIFT, (void **)&bt);
if (ret) {
ret = -errno;
fprintf(stderr, "failed to read meta super block: %s (%d)\n",
strerror(errno), errno);
goto out;
}
if (bt->level != 0) {
fprintf(stderr, "read non-leaf logs_root btree block at blkno %llu with level %u\n",
blkno, bt->level);
ret = -EIO;
goto out;
}
node = avl_first(&bt->item_root);
while (node) {
item = container_of(node, struct scoutfs_btree_item, node);
val_len = le16_to_cpu(item->val_len);
if (val_len != sizeof(struct scoutfs_log_trees)) {
fprintf(stderr, "invalid item length: %u, expected %zu\n",
val_len, sizeof(struct scoutfs_log_trees));
ret = -EIO;
goto out;
}
lt = (void *)bt + le16_to_cpu(item->val_off);
if (le64_to_cpu(lt->rid) == args->rid) {
printf("found rid %016llx\n", args->rid);
found = true;
break;
} else {
printf("skipping mount rid %016llx\n", le64_to_cpu(lt->rid));
}
node = avl_next(&bt->item_root, node);
}
if (!found) {
fprintf(stderr, "couldn't find log_trees item with rid %016llx\n", args->rid);
ret = -ENOENT;
goto out;
}
printf("wiping meta_avail: blkno %llu total_nr %llu\n",
le64_to_cpu(lt->meta_avail.ref.blkno), le64_to_cpu(lt->meta_avail.total_nr));
printf("wiping meta_freed: blkno %llu total_nr %llu\n",
le64_to_cpu(lt->meta_freed.ref.blkno), le64_to_cpu(lt->meta_freed.total_nr));
printf("wiping data_avail: blkno %llu total_len %llu\n",
le64_to_cpu(lt->data_avail.root.ref.blkno), le64_to_cpu(lt->data_avail.total_len));
printf("wiping data_freed: blkno %llu total_len %llu\n",
le64_to_cpu(lt->data_freed.root.ref.blkno), le64_to_cpu(lt->data_freed.total_len));
memset(&lt->meta_avail, 0, sizeof(lt->meta_avail));
memset(&lt->meta_freed, 0, sizeof(lt->meta_freed));
memset(&lt->data_avail, 0, sizeof(lt->data_avail));
memset(&lt->data_freed, 0, sizeof(lt->data_freed));
ret = write_block(meta_fd, SCOUTFS_BLOCK_MAGIC_BTREE, super->hdr.fsid,
le64_to_cpu(bt->hdr.seq), blkno, SCOUTFS_BLOCK_LG_SHIFT,
&bt->hdr);
if (ret)
fprintf(stderr, "Failed to write updated log_trees block.\n");
else
printf("Writing updated log_trees block succeeded.\n");
out:
if (meta_fd >= 0)
close(meta_fd);
if (super)
free(super);
if (bt)
free(bt);
return ret;
}
static int parse_opt(int key, char *arg, struct argp_state *state)
{
struct wipe_ltdf_args *args = state->input;
int ret;
switch (key) {
case 'f': /* fsid */
{
ret = parse_u64(arg, &args->fsid);
if (ret)
return ret;
if (args->fsid == 0)
argp_error(state, "must provide non-zero fsid");
break;
}
case 'r': /* rid */
{
ret = parse_u64(arg, &args->rid);
if (ret)
return ret;
if (args->rid == 0)
argp_error(state, "must provide non-zero rid");
break;
}
case ARGP_KEY_ARG:
if (!args->meta_device)
args->meta_device = strdup_or_error(state, arg);
else
argp_error(state, "more than two metadata device given");
break;
case ARGP_KEY_FINI:
if (!args->fsid)
argp_error(state, "must specify fsid with --fsid|-f");
if (!args->rid)
argp_error(state, "must specify rid with --rid|-r");
if (!args->meta_device)
argp_error(state, "no metadata device argument given");
break;
default:
break;
}
return 0;
}
static struct argp_option options[] = {
{ "fsid", 'f', "FSID", 0, "fsid of volume in which to wipe root item, for validation"},
{ "rid", 'r', "RID", 0, "rid of log_trees item in which to wipe data_freed btree ref"},
{ NULL }
};
static struct argp argp = {
options,
parse_opt,
"META-DEVICE",
"(debug) wipe a data_freed btree root ref for a given mount rid, do not do this"
};
static int wipe_ltdf_cmd(int argc, char *argv[])
{
struct wipe_ltdf_args wipe_ltdf_args = {NULL,};
int ret;
ret = argp_parse(&argp, argc, argv, 0, NULL, &wipe_ltdf_args);
if (ret)
return ret;
return do_wipe_ltdf(&wipe_ltdf_args);
}
static void __attribute__((constructor)) wipe_ltdf_ctor(void)
{
cmd_register_argp("wipe-log-trees-data-freed", &argp, GROUP_DEBUG, wipe_ltdf_cmd);
}