mirror of
https://github.com/versity/scoutfs.git
synced 2026-07-20 15:02:21 +00:00
We can't cross-mount ipv4/ipv6.
I thought this would just work between ipv4 and ipv6 based quorum members, but it turns out it will only work one way by default. While we could make this work (multiple sockets, special sockopts) it is highly unlikely and very undesirable. Much stronger feels to just disallow it explicitly and reject mixed v4/v6 configurations outright (mkfs/change-quorum, and mount) to avoid this. I can't imagine this doing any good for users' fencing setups. The test cases added validate the 2 easy userspace checks. The mount check isn't easily testable because we disallow userspace from creating such a failure path. One additional test section tests the migration path from v4->v6->v4 so there's at least some test that checks that this actually works. Signed-off-by: Auke Kok <auke.kok@versity.com>
This commit is contained in:
@@ -1244,6 +1244,7 @@ static int verify_quorum_slots(struct super_block *sb, struct quorum_info *qinf,
|
||||
struct sockaddr_in *other4;
|
||||
struct sockaddr_in6 *sin6;
|
||||
struct sockaddr_in6 *other6;
|
||||
__le16 family = cpu_to_le16(SCOUTFS_AF_NONE);
|
||||
int found = 0;
|
||||
int ret;
|
||||
int i;
|
||||
@@ -1255,6 +1256,14 @@ static int verify_quorum_slots(struct super_block *sb, struct quorum_info *qinf,
|
||||
continue;
|
||||
|
||||
if (quorum_slot_ipv4(qconf, i)) {
|
||||
if (family == cpu_to_le16(SCOUTFS_AF_NONE)) {
|
||||
family = cpu_to_le16(SCOUTFS_AF_IPV4);
|
||||
} else if (family != cpu_to_le16(SCOUTFS_AF_IPV4)) {
|
||||
scoutfs_err(sb, "quorum slot #%d is IPv4 but earlier slots are IPv6; mixed IPv4/IPv6 quorum is not supported",
|
||||
i);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
scoutfs_quorum_slot_sin(qconf, i, &sin);
|
||||
sin4 = (struct sockaddr_in *)&sin;
|
||||
|
||||
@@ -1287,6 +1296,14 @@ static int verify_quorum_slots(struct super_block *sb, struct quorum_info *qinf,
|
||||
|
||||
found++;
|
||||
} else if (quorum_slot_ipv6(qconf, i)) {
|
||||
if (family == cpu_to_le16(SCOUTFS_AF_NONE)) {
|
||||
family = cpu_to_le16(SCOUTFS_AF_IPV6);
|
||||
} else if (family != cpu_to_le16(SCOUTFS_AF_IPV6)) {
|
||||
scoutfs_err(sb, "quorum slot #%d is IPv6 but earlier slots are IPv4; mixed IPv4/IPv6 quorum is not supported",
|
||||
i);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
quorum_slot_sin(qconf, i, &sin);
|
||||
sin6 = (struct sockaddr_in6 *)&sin;
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
== mkfs rejects mixed v4/v6 quorum
|
||||
rc: 64
|
||||
== mkfs all-v4, mount three members, cross-mount signature visible
|
||||
== change-quorum-config rejects mixed v4/v6 quorum
|
||||
rc: 64
|
||||
== switch v4 -> v6, signature survives, cross-mount write again
|
||||
== switch v6 -> v4, signatures survive
|
||||
@@ -1,6 +1,7 @@
|
||||
export-get-name-parent.sh
|
||||
basic-block-counts.sh
|
||||
basic-bad-mounts.sh
|
||||
basic-inetaddr.sh
|
||||
basic-posix-acl.sh
|
||||
basic-acl-consistency.sh
|
||||
inode-items-updated.sh
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
#
|
||||
# Test that mixed ipv4/6 fails through mkfs/quorum change and that
|
||||
# users can migrate from ipv4 to v6 and back.
|
||||
#
|
||||
|
||||
t_require_commands dmsetup blockdev cmp
|
||||
|
||||
P0=$T_SCRATCH_PORT
|
||||
P1=$((T_SCRATCH_PORT + 1))
|
||||
P2=$((T_SCRATCH_PORT + 2))
|
||||
SIG=$T_TMP.sig
|
||||
seq 1 4096 > "$SIG"
|
||||
|
||||
trap '
|
||||
umount $T_TMPDIR/m0 $T_TMPDIR/m1 $T_TMPDIR/m2 2>/dev/null
|
||||
dmsetup remove _bia_m0 _bia_m1 _bia_m2 _bia_d0 _bia_d1 _bia_d2 2>/dev/null
|
||||
' EXIT
|
||||
|
||||
mkdir -p "$T_TMPDIR/m0" "$T_TMPDIR/m1" "$T_TMPDIR/m2"
|
||||
for nv in "m0 $T_EX_META_DEV" "m1 $T_EX_META_DEV" "m2 $T_EX_META_DEV" \
|
||||
"d0 $T_EX_DATA_DEV" "d1 $T_EX_DATA_DEV" "d2 $T_EX_DATA_DEV"; do
|
||||
set -- $nv
|
||||
t_quiet dmsetup create _bia_$1 --table "0 $(blockdev --getsz $2) linear $2 0"
|
||||
done
|
||||
|
||||
mnt() {
|
||||
mount -t scoutfs \
|
||||
-o metadev_path=/dev/mapper/_bia_m$1,quorum_slot_nr=$1 \
|
||||
/dev/mapper/_bia_d$1 "$T_TMPDIR/m$1"
|
||||
}
|
||||
mount_all() {
|
||||
mnt 0 &
|
||||
mnt 1 &
|
||||
mnt 2 &
|
||||
wait
|
||||
}
|
||||
umount_all() {
|
||||
umount $T_TMPDIR/m0 &
|
||||
umount $T_TMPDIR/m1 &
|
||||
umount $T_TMPDIR/m2 &
|
||||
wait
|
||||
}
|
||||
verify() {
|
||||
cmp -s "$SIG" "$T_TMPDIR/m0/sig" &&
|
||||
cmp -s "$SIG" "$T_TMPDIR/m1/sig" &&
|
||||
cmp -s "$SIG" "$T_TMPDIR/m2/sig" || t_fail "$1"
|
||||
}
|
||||
|
||||
echo "== mkfs rejects mixed v4/v6 quorum"
|
||||
t_rc scoutfs mkfs -f -Q 0,127.0.0.1,$P0 -Q 1,::1,$P1 -Q 2,127.0.0.1,$P2 /dev/mapper/_bia_m0 /dev/mapper/_bia_d0
|
||||
|
||||
echo "== mkfs all-v4, mount three members, cross-mount signature visible"
|
||||
t_quiet scoutfs mkfs -f -Q 0,127.0.0.1,$P0 -Q 1,127.0.0.1,$P1 -Q 2,127.0.0.1,$P2 /dev/mapper/_bia_m0 /dev/mapper/_bia_d0
|
||||
mount_all
|
||||
cp "$SIG" "$T_TMPDIR/m0/sig"
|
||||
verify "v4 initial"
|
||||
umount_all
|
||||
|
||||
echo "== change-quorum-config rejects mixed v4/v6 quorum"
|
||||
t_rc scoutfs change-quorum-config --offline -Q 0,127.0.0.1,$P0 -Q 1,::1,$P1 -Q 2,127.0.0.1,$P2 /dev/mapper/_bia_m0
|
||||
|
||||
echo "== switch v4 -> v6, signature survives, cross-mount write again"
|
||||
t_quiet scoutfs change-quorum-config --offline -Q 0,::1,$P0 -Q 1,::1,$P1 -Q 2,::1,$P2 /dev/mapper/_bia_m0
|
||||
mount_all
|
||||
verify "after v4->v6"
|
||||
cp "$SIG" "$T_TMPDIR/m1/sig-v6"
|
||||
cmp -s "$SIG" "$T_TMPDIR/m0/sig-v6" || t_fail "v6 cross-mount write not visible on m0"
|
||||
cmp -s "$SIG" "$T_TMPDIR/m2/sig-v6" || t_fail "v6 cross-mount write not visible on m2"
|
||||
umount_all
|
||||
|
||||
echo "== switch v6 -> v4, signatures survive"
|
||||
t_quiet scoutfs change-quorum-config --offline -Q 0,127.0.0.1,$P0 -Q 1,127.0.0.1,$P1 -Q 2,127.0.0.1,$P2 /dev/mapper/_bia_m0
|
||||
mount_all
|
||||
verify "after v6->v4"
|
||||
cmp -s "$SIG" "$T_TMPDIR/m0/sig-v6" || t_fail "after v6->v4 sig-v6 lost"
|
||||
umount_all
|
||||
|
||||
t_pass
|
||||
@@ -20,11 +20,20 @@ bool valid_quorum_slots(struct scoutfs_quorum_slot *slots)
|
||||
bool valid = true;
|
||||
char *addr;
|
||||
char ip6addr[INET6_ADDRSTRLEN];
|
||||
__le16 family = cpu_to_le16(SCOUTFS_AF_NONE);
|
||||
int i;
|
||||
int j;
|
||||
|
||||
for (i = 0; i < SCOUTFS_QUORUM_MAX_SLOTS; i++) {
|
||||
if (slots[i].addr.v4.family == cpu_to_le16(SCOUTFS_AF_IPV4)) {
|
||||
if (family == cpu_to_le16(SCOUTFS_AF_NONE)) {
|
||||
family = cpu_to_le16(SCOUTFS_AF_IPV4);
|
||||
} else if (family != cpu_to_le16(SCOUTFS_AF_IPV4)) {
|
||||
fprintf(stderr, "quorum slot nr %u is IPv4 but earlier slots are IPv6; mixed IPv4/IPv6 quorum is not supported\n",
|
||||
i);
|
||||
valid = false;
|
||||
}
|
||||
|
||||
for (j = i + 1; j < SCOUTFS_QUORUM_MAX_SLOTS; j++) {
|
||||
if (slots[i].addr.v4.addr == slots[j].addr.v4.addr &&
|
||||
slots[i].addr.v4.port == slots[j].addr.v4.port) {
|
||||
@@ -38,6 +47,14 @@ bool valid_quorum_slots(struct scoutfs_quorum_slot *slots)
|
||||
}
|
||||
}
|
||||
} else if (slots[i].addr.v6.family == cpu_to_le16(SCOUTFS_AF_IPV6)) {
|
||||
if (family == cpu_to_le16(SCOUTFS_AF_NONE)) {
|
||||
family = cpu_to_le16(SCOUTFS_AF_IPV6);
|
||||
} else if (family != cpu_to_le16(SCOUTFS_AF_IPV6)) {
|
||||
fprintf(stderr, "quorum slot nr %u is IPv6 but earlier slots are IPv4; mixed IPv4/IPv6 quorum is not supported\n",
|
||||
i);
|
||||
valid = false;
|
||||
}
|
||||
|
||||
for (j = i + 1; j < SCOUTFS_QUORUM_MAX_SLOTS; j++) {
|
||||
if ((IN6_ARE_ADDR_EQUAL(slots[i].addr.v6.addr, slots[j].addr.v6.addr)) &&
|
||||
(slots[i].addr.v6.port == slots[j].addr.v6.port)) {
|
||||
|
||||
Reference in New Issue
Block a user