mirror of
https://github.com/versity/scoutfs.git
synced 2026-05-12 23:51:30 +00:00
Merge pull request #308 from versity/auke/totl-delta-repair
totl key repair
This commit is contained in:
@@ -1739,6 +1739,43 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long scoutfs_ioc_inject_totl_delta(struct file *file, unsigned long arg)
|
||||
{
|
||||
struct super_block *sb = file_inode(file)->i_sb;
|
||||
struct scoutfs_ioctl_inject_totl_delta __user *uitd = (void __user *)arg;
|
||||
struct scoutfs_ioctl_inject_totl_delta itd;
|
||||
struct scoutfs_xattr_totl_val tval;
|
||||
struct scoutfs_lock *lock = NULL;
|
||||
struct scoutfs_key key;
|
||||
int ret;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
if (copy_from_user(&itd, uitd, sizeof(itd)))
|
||||
return -EFAULT;
|
||||
|
||||
scoutfs_xattr_init_totl_key(&key, itd.name);
|
||||
tval.total = cpu_to_le64((u64)itd.total);
|
||||
tval.count = cpu_to_le64((u64)itd.count);
|
||||
|
||||
ret = scoutfs_lock_xattr_totl(sb, SCOUTFS_LOCK_WRITE_ONLY, 0, &lock);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = scoutfs_hold_trans(sb, true);
|
||||
if (ret < 0)
|
||||
goto unlock;
|
||||
|
||||
ret = scoutfs_item_delta(sb, &key, &tval, sizeof(tval), lock);
|
||||
|
||||
scoutfs_release_trans(sb);
|
||||
unlock:
|
||||
scoutfs_unlock(sb, lock, SCOUTFS_LOCK_WRITE_ONLY);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
long scoutfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
switch (cmd) {
|
||||
@@ -1790,6 +1827,8 @@ long scoutfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
return scoutfs_ioc_read_xattr_index(file, arg);
|
||||
case SCOUTFS_IOC_PUNCH_OFFLINE:
|
||||
return scoutfs_ioc_punch_offline(file, arg);
|
||||
case SCOUTFS_IOC_INJECT_TOTL_DELTA:
|
||||
return scoutfs_ioc_inject_totl_delta(file, arg);
|
||||
}
|
||||
|
||||
return -ENOTTY;
|
||||
|
||||
@@ -876,4 +876,17 @@ struct scoutfs_ioctl_punch_offline {
|
||||
#define SCOUTFS_IOC_PUNCH_OFFLINE \
|
||||
_IOW(SCOUTFS_IOCTL_MAGIC, 24, struct scoutfs_ioctl_punch_offline)
|
||||
|
||||
/*
|
||||
* Inject a signed (total, count) delta at the totl key @name (a, b, c
|
||||
* match the trailing dotted u64s of a totl xattr name).
|
||||
*/
|
||||
struct scoutfs_ioctl_inject_totl_delta {
|
||||
__u64 name[SCOUTFS_IOCTL_XATTR_TOTAL_NAME_NR];
|
||||
__s64 total;
|
||||
__s64 count;
|
||||
};
|
||||
|
||||
#define SCOUTFS_IOC_INJECT_TOTL_DELTA \
|
||||
_IOW(SCOUTFS_IOCTL_MAGIC, 25, struct scoutfs_ioctl_inject_totl_delta)
|
||||
|
||||
#endif
|
||||
|
||||
1
tests/.gitignore
vendored
1
tests/.gitignore
vendored
@@ -12,3 +12,4 @@ src/o_tmpfile_umask
|
||||
src/o_tmpfile_linkat
|
||||
src/mmap_stress
|
||||
src/mmap_validate
|
||||
src/totl-delta-inject
|
||||
|
||||
@@ -15,7 +15,8 @@ BIN := src/createmany \
|
||||
src/o_tmpfile_umask \
|
||||
src/o_tmpfile_linkat \
|
||||
src/mmap_stress \
|
||||
src/mmap_validate
|
||||
src/mmap_validate \
|
||||
src/totl-delta-inject
|
||||
|
||||
DEPS := $(wildcard src/*.d)
|
||||
|
||||
|
||||
10
tests/golden/totl-delta-inject
Normal file
10
tests/golden/totl-delta-inject
Normal file
@@ -0,0 +1,10 @@
|
||||
== setup three files contributing to totl 8888.0.0
|
||||
== merge baseline into fs_root
|
||||
8888.0.0 = 42, 3
|
||||
== inject (+128, +2) unbalances totl 8888.0.0
|
||||
8888.0.0 = 170, 5
|
||||
== unlink f3 (value 32) produces a -32/-1 delta
|
||||
8888.0.0 = 138, 4
|
||||
== inject (-128, -2) restores accounting for the remaining files
|
||||
8888.0.0 = 10, 2
|
||||
== cleanup
|
||||
@@ -30,6 +30,7 @@ basic-xattr-indx.sh
|
||||
quota.sh
|
||||
totl-merge-read.sh
|
||||
quota-invalidate-race.sh
|
||||
totl-delta-inject.sh
|
||||
lock-refleak.sh
|
||||
lock-shrink-consistency.sh
|
||||
lock-shrink-read-race.sh
|
||||
|
||||
121
tests/src/totl-delta-inject.c
Normal file
121
tests/src/totl-delta-inject.c
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Test helper that calls SCOUTFS_IOC_INJECT_TOTL_DELTA to seed
|
||||
* arbitrary totl deltas.
|
||||
*
|
||||
* Copyright (C) 2026 Versity Software, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
* License v2 as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "ioctl.h"
|
||||
|
||||
static void usage(const char *prog)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: %s <mountpoint> <a>.<b>.<c> <total> <count>\n",
|
||||
prog);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
static int parse_s64(const char *s, int64_t *out)
|
||||
{
|
||||
char *end;
|
||||
int64_t v;
|
||||
|
||||
errno = 0;
|
||||
v = strtoll(s, &end, 0);
|
||||
if (errno || *end != '\0' || end == s)
|
||||
return -1;
|
||||
*out = v;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse "<a>.<b>.<c>" into abc[0..2] (skxt_a, skxt_b, skxt_c). Each
|
||||
* component must be a non-empty unsigned base-0 integer.
|
||||
*/
|
||||
static int parse_dotted_name(const char *s, uint64_t abc[3])
|
||||
{
|
||||
const char *p = s;
|
||||
char *end;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (*p == '\0' || *p == '.')
|
||||
return -1;
|
||||
errno = 0;
|
||||
abc[i] = strtoull(p, &end, 0);
|
||||
if (errno || end == p)
|
||||
return -1;
|
||||
|
||||
if (i < 2) {
|
||||
if (*end != '.')
|
||||
return -1;
|
||||
p = end + 1;
|
||||
} else {
|
||||
if (*end != '\0')
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct scoutfs_ioctl_inject_totl_delta itd = {{0,}};
|
||||
uint64_t abc[3];
|
||||
int64_t total, count;
|
||||
int fd;
|
||||
int ret;
|
||||
|
||||
if (argc != 5)
|
||||
usage(argv[0]);
|
||||
|
||||
if (parse_dotted_name(argv[2], abc) ||
|
||||
parse_s64(argv[3], &total) ||
|
||||
parse_s64(argv[4], &count)) {
|
||||
fprintf(stderr, "could not parse arguments\n");
|
||||
usage(argv[0]);
|
||||
}
|
||||
|
||||
itd.name[0] = abc[0];
|
||||
itd.name[1] = abc[1];
|
||||
itd.name[2] = abc[2];
|
||||
itd.total = total;
|
||||
itd.count = count;
|
||||
|
||||
fd = open(argv[1], O_RDONLY | O_DIRECTORY);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "open(%s): %s\n", argv[1], strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = ioctl(fd, SCOUTFS_IOC_INJECT_TOTL_DELTA, &itd);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr,
|
||||
"INJECT_TOTL_DELTA(%" PRIu64 ".%" PRIu64 ".%" PRIu64
|
||||
", total=%" PRId64 ", count=%" PRId64 "): %s\n",
|
||||
abc[0], abc[1], abc[2], total, count, strerror(errno));
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
43
tests/tests/totl-delta-inject.sh
Normal file
43
tests/tests/totl-delta-inject.sh
Normal file
@@ -0,0 +1,43 @@
|
||||
#
|
||||
# Exercise the SCOUTFS_IOC_INJECT_TOTL_DELTA ioctl that injects totl
|
||||
# deltas directly via totl-delta-inject(1).
|
||||
#
|
||||
|
||||
t_require_commands setfattr scoutfs sync rm touch totl-delta-inject
|
||||
|
||||
# force a log merge then read-xattr-totals filtered to our own keys
|
||||
read_totals()
|
||||
{
|
||||
t_force_log_merge
|
||||
sync
|
||||
echo 1 > $(t_debugfs_path)/drop_weak_item_cache
|
||||
scoutfs read-xattr-totals -p "$T_M0" | \
|
||||
grep -E '^8888\.' || true
|
||||
}
|
||||
|
||||
echo "== setup three files contributing to totl 8888.0.0"
|
||||
touch "$T_D0/f1" "$T_D0/f2" "$T_D0/f3"
|
||||
setfattr -n scoutfs.totl.inj.8888.0.0 -v 2 "$T_D0/f1"
|
||||
setfattr -n scoutfs.totl.inj.8888.0.0 -v 8 "$T_D0/f2"
|
||||
setfattr -n scoutfs.totl.inj.8888.0.0 -v 32 "$T_D0/f3"
|
||||
|
||||
echo "== merge baseline into fs_root"
|
||||
read_totals
|
||||
|
||||
echo "== inject (+128, +2) unbalances totl 8888.0.0"
|
||||
totl-delta-inject "$T_M0" 8888.0.0 128 2
|
||||
read_totals
|
||||
|
||||
echo "== unlink f3 (value 32) produces a -32/-1 delta"
|
||||
rm -f "$T_D0/f3"
|
||||
read_totals
|
||||
|
||||
echo "== inject (-128, -2) restores accounting for the remaining files"
|
||||
totl-delta-inject "$T_M0" 8888.0.0 -128 -2
|
||||
read_totals
|
||||
|
||||
echo "== cleanup"
|
||||
rm -f "$T_D0/f1" "$T_D0/f2"
|
||||
read_totals
|
||||
|
||||
t_pass
|
||||
Reference in New Issue
Block a user