Compare commits

..

2 Commits

Author SHA1 Message Date
1742cdc081 Accept pool names and hex inode numbers in vitastor-cli rm-data
rm-data read --pool and --inode with uint64_value(), so a pool name
became 0 and the pool was silently taken from the inode's pool bits,
i.e. "--pool <other pool> --inode <full inode number>" removed data in
a different pool than requested. A hex --inode became 0 and rm-data
"removed" inode 0, reporting success.

Resolve pool names like ls does (ENOENT for an unknown pool), parse
--inode as decimal or 0x hex, and fail with EINVAL on anything else
before removing data.
2026-10-20 10:57:41 +03:00
66434e3220 Fix vitastor-cli rm-data ignoring offsets with size suffixes
rm-data read --min-offset and --max-offset with uint64_value(), which
returns 0 for "8M", "-8M" or "0x1000", and 0 means "from the start" and
"no upper limit". So a range given with a suffix removed the whole
inode instead of a part of it, and the command reported success.

Parse offsets as decimal or 0x hex with an optional K/M/G/T suffix,
reject signs and values that overflow 64 bits, and fail with EINVAL
before removing anything if a value is invalid, the range is empty or
reversed, or --max-offset is explicitly 0 (omit it for no limit).
2026-10-20 10:57:41 +03:00
5 changed files with 272 additions and 51 deletions

View File

@@ -231,8 +231,8 @@ Options:
* `--writers-stopped` allows optimised removal in case of a single 'slim' read-write
child and 'fat' removed parent: the child is merged into parent and parent is renamed
to child in that case. In other cases parent layers are always merged into children.
* `--exact` - remove multiple images with given names.
* `--matching` - remove multiple images with names matching given glob patterns.
* `--exact` - remove multiple images with names matching given glob patterns.
* `--matching` - remove multiple images with given names
* `--down-ok` - continue deletion/merging even if some data will be left on unavailable OSDs.
## flatten
@@ -243,15 +243,16 @@ Flatten a layer, i.e. merge data and detach it from parents.
## rm-data
`vitastor-cli rm-data --pool <pool> --inode <inode> [--wait-list] [--min-offset <offset>]`
`vitastor-cli rm-data --pool <id|name> --inode <inode> [--wait-list] [--min-offset <offset>]`
Remove inode data without changing metadata.
Remove inode data without changing metadata. `<inode>` may be decimal or 0x hex.
```
--wait-list Retrieve full objects listings before starting to remove objects.
Requires more memory, but allows to show correct removal progress.
--min-offset Purge only data starting with specified offset.
--max-offset Purge only data before specified offset.
Offsets are in bytes or with a K/M/G/T unit suffix, decimal or 0x hex.
--client_wait_up_timeout 16 Timeout for waiting until PGs are up in seconds.
```
@@ -287,7 +288,7 @@ Describe unclean object locations in the cluster. Options:
## fix
`vitastor-cli fix [--objects <objects>] --bad-osds <osds> [--part <part>] [--check no]`
`vitastor-cli fix [--objects <objects>] [--bad-osds <osds>] [--part <part>] [--check no]`
Fix inconsistent objects in the cluster by deleting some copies.
@@ -298,7 +299,7 @@ Fix inconsistent objects in the cluster by deleting some copies.
Plain text format: 0x<inode>:0x<stripe> <any delimiter> 0x<inode>:0x<stripe> ...
JSON format: [{"inode":"0x...","stripe":"0x..."},...]
--bad-osds <osds>
Required. Remove inconsistent copies/parts of objects from these OSDs, effectively
Remove inconsistent copies/parts of objects from these OSDs, effectively
marking them bad and allowing Vitastor to recover objects from other copies.
--part <number>
Only remove EC part <number> (from 0 to pg_size-1), required for extreme
@@ -316,17 +317,14 @@ Allocate a new OSD number and reserve it by creating empty `/osd/stats/<n>` key.
## rm-osd
`vitastor-cli rm-osd [-f|--force] [--allow-data-loss] [--allow-up] [--dry-run] <osd_id> [osd_id...]`
`vitastor-cli rm-osd [--force] [--allow-data-loss] [--dry-run] <osd_id> [osd_id...]`
Remove metadata and configuration for specified OSD(s) from etcd.
Refuses to remove OSDs that are up or whose removal makes PGs degraded, offline or incomplete.
Refuses to remove OSDs with data without `--force` and `--allow-data-loss`.
* `-f|--force` - remove OSDs even if they are up or PGs become degraded or offline.
* `--allow-data-loss` - remove OSDs even if PGs or objects become incomplete (DATA LOSS). Implies `--force`.
* `--allow-up` - remove OSDs even if they are up.
* `--dry-run` - only check if deletion is possible without data loss and
redundancy degradation.
With `--dry-run` only checks if deletion is possible without data loss and
redundancy degradation.
## osd-tree

View File

@@ -239,8 +239,8 @@ vitastor-cli dd [iimg=<image> | if=<file>] [oimg=<image> | of=<file>] [bs=1M] \
у удаляемой цепочки есть только один дочерний образ, содержащий небольшой объём данных.
В этом случае дочерний образ вливается в родительский и удаляется, а родительский
переименовывается в дочерний.
* `--exact` - удалить все образы с точно заданными именами.
* `--matching` - удалить все образы с именами, подходящими под переданные glob-шаблоны.
* `--exact` - удалить все образы с именами, подходящими под переданные glob-шаблоны.
* `--matching` - удалить все образы с точно заданными именами.
* `--down-ok` - продолжать удаление/слияние, даже если часть данных останется неудалённой на недоступных OSD.
## flatten
@@ -252,15 +252,16 @@ vitastor-cli dd [iimg=<image> | if=<file>] [oimg=<image> | of=<file>] [bs=1M] \
## rm-data
`vitastor-cli rm-data --pool <pool> --inode <inode> [--wait-list] [--min-offset <offset>]`
`vitastor-cli rm-data --pool <id|name> --inode <inode> [--wait-list] [--min-offset <offset>]`
Удалить данные инода, не меняя метаданные образов.
Удалить данные инода, не меняя метаданные образов. `<inode>` можно задать в десятичном виде или в hex с 0x.
```
--wait-list Сначала запросить полный листинг объектов, а потом начать удалять.
Требует больше памяти, но позволяет правильно печатать прогресс удаления.
--min-offset Удалять только данные, начиная с заданного смещения.
--max-offset Удалять только данные до (исключительно) заданного смещения.
Смещения задаются в байтах или с суффиксом K/M/G/T, в десятичном виде или в hex с 0x.
--client_wait_up_timeout 16 Время ожидания поднятия PG в секундах.
```
@@ -302,7 +303,7 @@ vitastor-cli dd [iimg=<image> | if=<file>] [oimg=<image> | of=<file>] [bs=1M] \
## fix
`vitastor-cli fix [--objects <объекты>] --bad-osds <osds> [--part <номер>] [--check no]`
`vitastor-cli fix [--objects <объекты>] [--bad-osds <osds>] [--part <номер>] [--check no]`
Исправить неконсистентные (неоднозначные) объекты путём удаления части копий.
@@ -313,9 +314,9 @@ vitastor-cli dd [iimg=<image> | if=<file>] [oimg=<image> | of=<file>] [bs=1M] \
Простой формат: 0x<инод>:0x<смещение> <любой разделитель> 0x<инод>:0x<смещение> ...
Формат JSON: [{"inode":"0x<инод>","stripe":"0x<смещение>"},...]
--bad-osds <osds>
Обязательная опция. Удалить неконсистентные копии/части объектов с данных
OSD, таким образом признавая потерю этих копий и позволяя Vitastor-у
восстановить объекты из других копий.
Удалить неконсистентные копии/части объектов с данных OSD, таким образом
признавая потерю этих копий и позволяя Vitastor-у восстановить объекты из
других копий.
--part <номер>
Удалить только части EC с заданным номером (от 0 до pg_size-1). Нужно только
в редких граничных случаях, когда один и тот же OSD содержит несколько частей
@@ -334,19 +335,14 @@ vitastor-cli dd [iimg=<image> | if=<file>] [oimg=<image> | of=<file>] [bs=1M] \
## rm-osd
`vitastor-cli rm-osd [-f|--force] [--allow-data-loss] [--allow-up] [--dry-run] <osd_id> [osd_id...]`
`vitastor-cli rm-osd [--force] [--allow-data-loss] [--dry-run] <osd_id> [osd_id...]`
Удалить метаданные и конфигурацию для заданных OSD из etcd.
Отказывается удалять работающие OSD, а также OSD, после удаления которых PG станут
деградированными, недоступными (offline) или неполными (incomplete).
Отказывается удалять OSD с данными без опций `--force` и `--allow-data-loss`.
* `-f|--force` - удалить OSD, даже если они работают или PG станут деградированными или недоступными.
* `--allow-data-loss` - удалить OSD, даже если PG или объекты станут неполными (ПОТЕРЯ ДАННЫХ).
Включает действие `--force`.
* `--allow-up` - удалить OSD, даже если они работают.
* `--dry-run` - только проверить, возможно ли удаление без потери данных и деградации
избыточности.
С опцией `--dry-run` только проверяет, возможно ли удаление без потери данных и деградации
избыточности.
## osd-tree

View File

@@ -108,20 +108,21 @@ static const char* help_text =
" --writers-stopped allows optimised removal in case of a single 'slim' read-write\n"
" child and 'fat' removed parent: the child is merged into parent and parent is renamed\n"
" to child in that case. In other cases parent layers are always merged into children.\n"
" --exact Remove multiple images with given names.\n"
" --matching Remove multiple images with names matching given glob patterns.\n"
" --exact Remove multiple images with names matching given glob patterns.\n"
" --matching Remove multiple images with given names\n"
" --writers-stopped Allow renaming inodes over their read/write children.\n"
" --down-ok Continue deletion/merging even if some data will be left on unavailable OSDs.\n"
"\n"
"vitastor-cli flatten <layer>\n"
" Flatten a layer, i.e. merge data and detach it from parents.\n"
"\n"
"vitastor-cli rm-data --pool <pool> --inode <inode> [--wait-list] [--min-offset <offset>]\n"
" Remove inode data without changing metadata.\n"
"vitastor-cli rm-data --pool <id|name> --inode <inode> [--wait-list] [--min-offset <offset>]\n"
" Remove inode data without changing metadata. <inode> may be decimal or 0x hex.\n"
" --wait-list Retrieve full objects listings before starting to remove objects.\n"
" Requires more memory, but allows to show correct removal progress.\n"
" --min-offset Purge only data starting with specified offset.\n"
" --max-offset Purge only data before specified offset.\n"
" Offsets are in bytes or with a K/M/G/T unit suffix, decimal or 0x hex.\n"
" --client_wait_up_timeout 16 Timeout for waiting until PGs are up in seconds.\n"
"\n"
"vitastor-cli merge-data <from> <to> [--target <target>]\n"
@@ -145,15 +146,12 @@ static const char* help_text =
" --min-offset, --max-offset\n"
" Restrict listing to specific offsets inside inodes.\n"
"\n"
"vitastor-cli raw-ls --pool_id ID (--pg_num NUM|--offset NUM) [OPTIONS]\n"
"vitastor-cli raw-ls [OPTIONS]\n"
" Find object(s) in the cluster using raw secondary listing operations. Options:\n"
" [--min_inode NUM] [--max_inode NUM] [--offset NUM] [--pg_num NUM] [--pg_count COUNT]\n"
" [--pg_stripe_size NUM] [--osds 1,2,3,...]\n"
" --pool_id (numeric pool ID) is required. --pg_num is required unless --offset is given,\n"
" in which case the PG is calculated from the offset. --pg_count, --pg_stripe_size and\n"
" --osds default to the pool configuration and are required if the pool does not exist.\n"
"\n"
"vitastor-cli fix [--objects <objects>] --bad-osds <osds> [--part <part>] [--check no]\n"
"vitastor-cli fix [--objects <objects>] [--bad-osds <osds>] [--part <part>] [--check no]\n"
" Fix inconsistent objects in the cluster by deleting some copies.\n"
" --objects <objects>\n"
" Objects to fix, either in plain text or JSON format. If not specified,\n"
@@ -161,7 +159,7 @@ static const char* help_text =
" Plain text format: 0x<inode>:0x<stripe> <any delimiter> 0x<inode>:0x<stripe> ...\n"
" JSON format: [{\"inode\":\"0x...\",\"stripe\":\"0x...\"},...]\n"
" --bad-osds <osds>\n"
" Required. Remove inconsistent copies/parts of objects from these OSDs, effectively\n"
" Remove inconsistent copies/parts of objects from these OSDs, effectively\n"
" marking them bad and allowing Vitastor to recover objects from other copies.\n"
" --part <number>\n"
" Only remove EC part <number> (from 0 to pg_size-1), required for extreme\n"
@@ -173,14 +171,11 @@ static const char* help_text =
"vitastor-cli alloc-osd\n"
" Allocate a new OSD number and reserve it by creating empty /osd/stats/<n> key.\n"
"\n"
"vitastor-cli rm-osd [-f|--force] [--allow-data-loss] [--allow-up] [--dry-run] <osd_id> [osd_id...]\n"
"vitastor-cli rm-osd [--force] [--allow-data-loss] [--dry-run] <osd_id> [osd_id...]\n"
" Remove metadata and configuration for specified OSD(s) from etcd.\n"
" Refuses to remove OSDs that are up or whose removal makes PGs degraded, offline or incomplete.\n"
" -f|--force Remove OSDs even if they are up or PGs become degraded or offline.\n"
" --allow-data-loss Remove OSDs even if PGs or objects become incomplete (DATA LOSS). Implies --force.\n"
" --allow-up Remove OSDs even if they are up.\n"
" --dry-run Only check if deletion is possible without data loss and\n"
" redundancy degradation.\n"
" Refuses to remove OSDs with data without --force and --allow-data-loss.\n"
" With --dry-run only checks if deletion is possible without data loss and\n"
" redundancy degradation.\n"
"\n"
"vitastor-cli osd-tree [-l|--long]\n"
" Show current OSD tree, optionally with I/O statistics if -l is specified.\n"

View File

@@ -1,6 +1,7 @@
// Copyright (c) Vitaliy Filippov, 2019+
// License: VNPL-1.1 (see README.md for details)
#include <ctype.h>
#include "cli.h"
#include "cluster_client.h"
@@ -23,6 +24,7 @@ struct rm_inode_t
{
uint64_t inode = 0;
pool_id_t pool_id = 0;
std::string pool_name;
uint64_t min_offset = 0;
uint64_t max_offset = 0;
bool down_ok = false;
@@ -302,6 +304,25 @@ struct rm_inode_t
goto resume_1;
if (state == 100)
return;
if (pool_name != "")
{
pool_id = 0;
for (auto & pp: parent->cli->st_cli->pool_config)
{
if (pp.second.name == pool_name)
{
pool_id = pp.first;
break;
}
}
if (!pool_id)
{
result = (cli_result_t){ .err = ENOENT, .text = "Pool "+pool_name+" does not exist" };
state = 100;
return;
}
inode = INODE_WITH_POOL(pool_id, inode);
}
if (!pool_id)
{
result = (cli_result_t){ .err = EINVAL, .text = "Pool is not specified" };
@@ -317,20 +338,103 @@ struct rm_inode_t
}
};
// Decimal or 0x hex, without sign, octal or overflow
static bool parse_rm_number(std::string s, uint64_t & value)
{
int base = 10;
if (s.size() > 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
{
s = s.substr(2);
base = 16;
}
if (s == "" || s.find_first_not_of(base == 16 ? "0123456789abcdefABCDEF" : "0123456789") != std::string::npos)
return false;
errno = 0;
value = strtoull(s.c_str(), NULL, base);
return !errno;
}
// Command-line values are strings with optional K/M/G/T suffixes, internal callers pass numbers
static bool parse_rm_offset(const json11::Json & value, uint64_t & offset)
{
if (!value.is_string())
{
offset = value.uint64_value();
return true;
}
std::string s = value.string_value();
int shift = 0;
switch (s.size() ? tolower(s.back()) : 0)
{
case 'k': shift = 10; break;
case 'm': shift = 20; break;
case 'g': shift = 30; break;
case 't': shift = 40; break;
}
if (shift)
s.pop_back();
if (!parse_rm_number(s, offset) || offset > (UINT64_MAX >> shift))
return false;
offset <<= shift;
return true;
}
static bool parse_rm_inode(const json11::Json & value, uint64_t & inode)
{
if (!value.is_string())
{
inode = value.uint64_value();
return true;
}
return parse_rm_number(value.string_value(), inode);
}
// A non-numeric string is a pool name, resolved after loading the pool configuration
static bool parse_rm_pool(const json11::Json & value, uint64_t & pool_id, std::string & pool_name)
{
pool_id = value.uint64_value();
if (value.is_string() && !pool_id && value.string_value() != "0")
pool_name = value.string_value();
return pool_id < POOL_ID_MAX && (!value.is_string() || value.string_value() != "");
}
std::function<bool(cli_result_t &)> cli_tool_t::start_rm_data(json11::Json cfg)
{
uint64_t inode = 0, pool_id = 0, min_offset = 0, max_offset = 0;
std::string pool_name, error;
if (!parse_rm_inode(cfg["inode"], inode))
error = "Invalid --inode value: "+cfg["inode"].as_string();
else if (!parse_rm_pool(cfg["pool"], pool_id, pool_name))
error = "Invalid --pool value: "+cfg["pool"].as_string();
else if (!parse_rm_offset(cfg["min_offset"], min_offset))
error = "Invalid --min-offset value: "+cfg["min_offset"].as_string();
else if (!parse_rm_offset(cfg["max_offset"], max_offset))
error = "Invalid --max-offset value: "+cfg["max_offset"].as_string();
else if (!max_offset && cfg["max_offset"].is_string())
error = "--max-offset 0 is invalid, omit it to remove data up to the end";
else if (max_offset && min_offset >= max_offset)
error = "--min-offset must be less than --max-offset";
if (error != "")
{
return [error](cli_result_t & result)
{
result = (cli_result_t){ .err = EINVAL, .text = error };
return true;
};
}
auto remover = new rm_inode_t();
remover->parent = this;
remover->inode = cfg["inode"].uint64_value();
remover->pool_id = cfg["pool"].uint64_value();
remover->inode = inode;
remover->pool_id = pool_id;
remover->pool_name = pool_name;
if (remover->pool_id)
{
remover->inode = (remover->inode & (((uint64_t)1 << (64-POOL_ID_BITS)) - 1)) | (((uint64_t)remover->pool_id) << (64-POOL_ID_BITS));
}
remover->down_ok = cfg["down_ok"].bool_value();
remover->pool_id = INODE_POOL(remover->inode);
remover->min_offset = cfg["min_offset"].uint64_value();
remover->max_offset = cfg["max_offset"].uint64_value();
remover->min_offset = min_offset;
remover->max_offset = max_offset;
return [remover](cli_result_t & result)
{
remover->loop();

View File

@@ -24,4 +24,132 @@ sz=$(stat -c %s ./testdata/bin/testimg.bin)
[[ "$sz" = 67108864 ]] || format_error "File size is $sz bytes after resize to 64 M"
# test rm-data offset parsing and validation
$VITASTOR_CLI create -s 32M rmimg
dd if=/dev/urandom of=./testdata/bin/rmimg.bin bs=1M count=32
$VITASTOR_CLI dd iodepth=4 bs=1M if=./testdata/bin/rmimg.bin oimg=rmimg
check_rmimg()
{
rm -f ./testdata/bin/check.bin
$VITASTOR_CLI dd iodepth=4 bs=1M conv=nosparse iimg=rmimg of=./testdata/bin/check.bin
cmp ./testdata/bin/check.bin ./testdata/bin/rmimg.bin || format_error "$1"
}
zero_rmimg()
{
dd if=/dev/zero of=./testdata/bin/rmimg.bin bs=1M seek=$1 count=$2 conv=notrunc
}
check_rmimg "Image data differs after write"
RM_DATA="$VITASTOR_CLI rm-data --pool 1 --inode $($VITASTOR_CLI ls --json rmimg | jq -r '.[0].inode_num')"
# Bad offsets and empty ranges must fail without removing anything
while IFS='|' read -r -u 3 args err; do
if out=$($RM_DATA $args 2>&1); then
format_error "rm-data $args should fail"
fi
[[ "$out" = "$err" ]] || format_error "rm-data $args failed with an unexpected error: $out"
check_rmimg "rm-data $args removed data"
done 3<<EOF
--min-offset 8M --max-offset 10X|Invalid --max-offset value: 10X
--min-offset 8M --max-offset 1.5G|Invalid --max-offset value: 1.5G
--min-offset 8M --max-offset 0x|Invalid --max-offset value: 0x
--min-offset 8X --max-offset 16M|Invalid --min-offset value: 8X
--min-offset 1.5M|Invalid --min-offset value: 1.5M
--min-offset 8M --max-offset -8M|Invalid --max-offset value: -8M
--min-offset -1|Invalid --min-offset value: -1
--min-offset 16777217T|Invalid --min-offset value: 16777217T
--min-offset 8M --max-offset 16777217T|Invalid --max-offset value: 16777217T
--min-offset 18446744073709551616|Invalid --min-offset value: 18446744073709551616
--min-offset 8M --max-offset 0x10000000000000000|Invalid --max-offset value: 0x10000000000000000
--min-offset 16M --max-offset 8M|--min-offset must be less than --max-offset
--min-offset 8M --max-offset 8M|--min-offset must be less than --max-offset
--min-offset 16M --max-offset 0|--max-offset 0 is invalid, omit it to remove data up to the end
--max-offset 0M|--max-offset 0 is invalid, omit it to remove data up to the end
EOF
$RM_DATA --min-offset 010M --max-offset 012M
zero_rmimg 10 2
check_rmimg "rm-data --min-offset 010M --max-offset 012M removed wrong data"
$RM_DATA --min-offset 8M --max-offset 10M
zero_rmimg 8 2
check_rmimg "rm-data --min-offset 8M --max-offset 10M removed wrong data"
$RM_DATA --min-offset $((20*1024*1024)) --max-offset $((24*1024*1024))
zero_rmimg 20 4
check_rmimg "rm-data with offsets in bytes removed wrong data"
$RM_DATA --min-offset 0x1a00000 --max-offset 0x1c00000
zero_rmimg 26 2
check_rmimg "rm-data with hex offsets removed wrong data"
$RM_DATA --min-offset 30M
zero_rmimg 30 2
check_rmimg "rm-data --min-offset 30M removed wrong data"
# test rm-data pool names and hex inode numbers
$VITASTOR_CLI create-pool testpool2 -s 2 -n 4 --failure_domain osd
wait_pool_up 60 2 2 4
$VITASTOR_CLI create -s 32M -p testpool2 rmimg2
dd if=/dev/urandom of=./testdata/bin/rmimg2.bin bs=1M count=32
$VITASTOR_CLI dd iodepth=4 bs=1M if=./testdata/bin/rmimg2.bin oimg=rmimg2
zero_rmimg2()
{
dd if=/dev/zero of=./testdata/bin/rmimg2.bin bs=1M seek=$1 count=$2 conv=notrunc
}
check_rmimg2()
{
check_rmimg "$1"
rm -f ./testdata/bin/check.bin
$VITASTOR_CLI dd iodepth=4 bs=1M conv=nosparse iimg=rmimg2 of=./testdata/bin/check.bin
cmp ./testdata/bin/check.bin ./testdata/bin/rmimg2.bin || format_error "$1"
}
check_rmimg2 "Image data differs after write"
INODE1=$($VITASTOR_CLI ls --json rmimg | jq -r '.[0].inode_num')
INODE2=$($VITASTOR_CLI ls --json rmimg2 | jq -r '.[0].inode_num')
[[ "$($VITASTOR_CLI ls --json rmimg2 | jq -r '.[0].pool_id')" = 2 ]] || format_error "rmimg2 is not in pool 2"
# Bad inode numbers and unknown pools must fail without removing anything
while IFS='|' read -r -u 3 args err; do
if out=$($VITASTOR_CLI rm-data $args 2>&1); then
format_error "rm-data $args should fail"
fi
[[ "$out" = "$err" ]] || format_error "rm-data $args failed with an unexpected error: $out"
check_rmimg2 "rm-data $args removed data"
done 3<<EOF
--pool 2 --inode ${INODE2}x|Invalid --inode value: ${INODE2}x
--pool 2 --inode 0x|Invalid --inode value: 0x
--pool 2 --inode 0x0x$INODE2|Invalid --inode value: 0x0x$INODE2
--pool 2 --inode -1|Invalid --inode value: -1
--pool 70000 --inode $INODE2|Invalid --pool value: 70000
--pool nosuchpool --inode $(( (1<<48) | INODE1 ))|Pool nosuchpool does not exist
EOF
$VITASTOR_CLI rm-data --pool testpool2 --inode $INODE2 --min-offset 8M --max-offset 12M
zero_rmimg2 8 4
check_rmimg2 "rm-data --pool testpool2 --inode $INODE2 removed wrong data"
$VITASTOR_CLI rm-data --pool 2 --inode $(printf 0x%x $INODE2) --min-offset 16M --max-offset 20M
zero_rmimg2 16 4
check_rmimg2 "rm-data --pool 2 --inode $(printf 0x%x $INODE2) removed wrong data"
$VITASTOR_CLI rm-data --inode $(printf 0x%x $(( (2<<48) | INODE2 ))) --min-offset 20M --max-offset 24M
zero_rmimg2 20 4
check_rmimg2 "rm-data --inode $(printf 0x%x $(( (2<<48) | INODE2 ))) removed wrong data"
# --pool overrides pool bits of --inode
$VITASTOR_CLI rm-data --pool testpool --inode $(( (2<<48) | INODE1 )) --min-offset 0 --max-offset 4M
zero_rmimg 0 4
check_rmimg2 "rm-data --pool testpool --inode $(( (2<<48) | INODE1 )) removed wrong data"
format_green OK