diff mbox series

[fstests] btrfs: test snapshotting a deleted subvolume

Message ID 62415ffc97ff2db4fa65cdd6f9db6ddead8105cd.1703010806.git.osandov@osandov.com (mailing list archive)
State New, archived
Headers show
Series [fstests] btrfs: test snapshotting a deleted subvolume | expand

Commit Message

Omar Sandoval Dec. 19, 2023, 6:34 p.m. UTC
This is a regression test for patch "btrfs: don't abort filesystem when
attempting to snapshot deleted subvolume". Without the fix, the
filesystem goes read-only and prints a warning. With the fix, it should
fail gracefully with ENOENT.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
---
Note that the kernel fix was just sent and isn't yet merged.

Thanks!

 .gitignore                         |   1 +
 src/Makefile                       |   2 +-
 src/t_snapshot_deleted_subvolume.c | 102 +++++++++++++++++++++++++++++
 tests/btrfs/304                    |  26 ++++++++
 tests/btrfs/304.out                |   2 +
 5 files changed, 132 insertions(+), 1 deletion(-)
 create mode 100644 src/t_snapshot_deleted_subvolume.c
 create mode 100755 tests/btrfs/304
 create mode 100644 tests/btrfs/304.out

Comments

Anand Jain Jan. 6, 2024, 12:55 a.m. UTC | #1
On 20/12/2023 00:04, Omar Sandoval wrote:
> This is a regression test for patch "btrfs: don't abort filesystem when
> attempting to snapshot deleted subvolume". Without the fix, the
> filesystem goes read-only and prints a warning. With the fix, it should
> fail gracefully with ENOENT.
> 
> Signed-off-by: Omar Sandoval <osandov@osandov.com>

looks good.
Reviewed-by: Anand Jain <anand.jain@oracle.com>

Added to the staging branch
git@github.com:asj/fstests.git staging

Thx, Anand


> ---
> Note that the kernel fix was just sent and isn't yet merged.
> 
> Thanks!
> 
>   .gitignore                         |   1 +
>   src/Makefile                       |   2 +-
>   src/t_snapshot_deleted_subvolume.c | 102 +++++++++++++++++++++++++++++
>   tests/btrfs/304                    |  26 ++++++++
>   tests/btrfs/304.out                |   2 +
>   5 files changed, 132 insertions(+), 1 deletion(-)
>   create mode 100644 src/t_snapshot_deleted_subvolume.c
>   create mode 100755 tests/btrfs/304
>   create mode 100644 tests/btrfs/304.out
> 
> diff --git a/.gitignore b/.gitignore
> index 4c32ac42..b9bf708b 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -165,6 +165,7 @@ tags
>   /src/t_readdir_2
>   /src/t_readdir_3
>   /src/t_rename_overwrite
> +/src/t_snapshot_deleted_subvolume
>   /src/t_stripealign
>   /src/t_truncate_cmtime
>   /src/t_truncate_self
> diff --git a/src/Makefile b/src/Makefile
> index 8160a0e8..53a32370 100644
> --- a/src/Makefile
> +++ b/src/Makefile
> @@ -33,7 +33,7 @@ LINUX_TARGETS = xfsctl bstat t_mtab getdevicesize preallo_rw_pattern_reader \
>   	attr_replace_test swapon mkswap t_attr_corruption t_open_tmpfiles \
>   	fscrypt-crypt-util bulkstat_null_ocount splice-test chprojid_fail \
>   	detached_mounts_propagation ext4_resize t_readdir_3 splice2pipe \
> -	uuid_ioctl
> +	uuid_ioctl t_snapshot_deleted_subvolume
>   
>   EXTRA_EXECS = dmerror fill2attr fill2fs fill2fs_check scaleread.sh \
>   	      btrfs_crc32c_forged_name.py popdir.pl popattr.py \
> diff --git a/src/t_snapshot_deleted_subvolume.c b/src/t_snapshot_deleted_subvolume.c
> new file mode 100644
> index 00000000..c3adb1c4
> --- /dev/null
> +++ b/src/t_snapshot_deleted_subvolume.c
> @@ -0,0 +1,102 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (c) Meta Platforms, Inc. and affiliates.
> +
> +#include "global.h"
> +
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <sys/ioctl.h>
> +#include <sys/stat.h>
> +#include <unistd.h>
> +
> +#include <linux/types.h>
> +#ifdef HAVE_STRUCT_BTRFS_IOCTL_VOL_ARGS_V2
> +#include <linux/btrfs.h>
> +#else
> +#ifndef BTRFS_IOCTL_MAGIC
> +#define BTRFS_IOCTL_MAGIC 0x94
> +#endif
> +
> +#ifndef BTRFS_IOC_SNAP_DESTROY_V2
> +#define BTRFS_IOC_SNAP_DESTROY_V2 \
> +	_IOW(BTRFS_IOCTL_MAGIC, 63, struct btrfs_ioctl_vol_args_v2)
> +#endif
> +
> +#ifndef BTRFS_IOC_SNAP_CREATE_V2
> +#define BTRFS_IOC_SNAP_CREATE_V2 \
> +	_IOW(BTRFS_IOCTL_MAGIC, 23, struct btrfs_ioctl_vol_args_v2)
> +#endif
> +
> +#ifndef BTRFS_IOC_SUBVOL_CREATE_V2
> +#define BTRFS_IOC_SUBVOL_CREATE_V2 \
> +	_IOW(BTRFS_IOCTL_MAGIC, 24, struct btrfs_ioctl_vol_args_v2)
> +#endif
> +
> +#ifndef BTRFS_SUBVOL_NAME_MAX
> +#define BTRFS_SUBVOL_NAME_MAX 4039
> +#endif
> +
> +struct btrfs_ioctl_vol_args_v2 {
> +	__s64 fd;
> +	__u64 transid;
> +	__u64 flags;
> +	union {
> +		struct {
> +			__u64 size;
> +			struct btrfs_qgroup_inherit *qgroup_inherit;
> +		};
> +		__u64 unused[4];
> +	};
> +	union {
> +		char name[BTRFS_SUBVOL_NAME_MAX + 1];
> +		__u64 devid;
> +		__u64 subvolid;
> +	};
> +};
> +#endif
> +
> +int main(int argc, char **argv)
> +{
> +	if (argc != 2) {
> +		fprintf(stderr, "usage: %s PATH\n", argv[0]);
> +		return EXIT_FAILURE;
> +	}
> +
> +	int dirfd = open(argv[1], O_RDONLY | O_DIRECTORY);
> +	if (dirfd < 0) {
> +		perror(argv[1]);
> +		return EXIT_FAILURE;
> +	}
> +
> +	struct btrfs_ioctl_vol_args_v2 subvol_args = {};
> +	strcpy(subvol_args.name, "subvol");
> +	if (ioctl(dirfd, BTRFS_IOC_SUBVOL_CREATE_V2, &subvol_args) < 0) {
> +		perror("BTRFS_IOC_SUBVOL_CREATE_V2");
> +		return EXIT_FAILURE;
> +	}
> +
> +	int subvolfd = openat(dirfd, "subvol", O_RDONLY | O_DIRECTORY);
> +	if (subvolfd < 0) {
> +		perror("openat");
> +		return EXIT_FAILURE;
> +	}
> +
> +	if (ioctl(dirfd, BTRFS_IOC_SNAP_DESTROY_V2, &subvol_args) < 0) {
> +		perror("BTRFS_IOC_SNAP_DESTROY_V2");
> +		return EXIT_FAILURE;
> +	}
> +
> +	struct btrfs_ioctl_vol_args_v2 snap_args = { .fd = subvolfd };
> +	strcpy(snap_args.name, "snap");
> +	if (ioctl(dirfd, BTRFS_IOC_SNAP_CREATE_V2, &snap_args) < 0) {
> +		if (errno == ENOENT)
> +			return EXIT_SUCCESS;
> +		perror("BTRFS_IOC_SNAP_CREATE_V2");
> +		return EXIT_FAILURE;
> +	}
> +	fprintf(stderr, "BTRFS_IOC_SNAP_CREATE_V2 should've failed\n");
> +	return EXIT_FAILURE;
> +}
> diff --git a/tests/btrfs/304 b/tests/btrfs/304
> new file mode 100755
> index 00000000..65f54b95
> --- /dev/null
> +++ b/tests/btrfs/304
> @@ -0,0 +1,26 @@
> +#! /bin/bash
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (c) Meta Platforms, Inc. and affiliates.
> +#
> +# FS QA Test 304
> +#
> +# Try to snapshot a deleted subvolume.
> +#
> +. ./common/preamble
> +_begin_fstest auto quick snapshot subvol
> +
> +_supported_fs btrfs
> +_require_scratch
> +_require_test_program t_snapshot_deleted_subvolume

> +_fixed_Aby_kernel_commit XXXXXXXXXXXX "btrfs: don't abort filesystem when attempting to snapshot deleted subvolume"


> +
> +_scratch_mkfs >> $seqres.full 2>&1 || _fail "mkfs failed"
> +_scratch_mount
> +
> +"$here/src/t_snapshot_deleted_subvolume" "$SCRATCH_MNT"
> +# Make sure the filesystem didn't go read-only.
> +touch "$SCRATCH_MNT/foo"
> +
> +echo "Silence is golden"
> +status=0
> +exit
> diff --git a/tests/btrfs/304.out b/tests/btrfs/304.out
> new file mode 100644
> index 00000000..c504111c
> --- /dev/null
> +++ b/tests/btrfs/304.out
> @@ -0,0 +1,2 @@
> +QA output created by 304
> +Silence is golden
diff mbox series

Patch

diff --git a/.gitignore b/.gitignore
index 4c32ac42..b9bf708b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -165,6 +165,7 @@  tags
 /src/t_readdir_2
 /src/t_readdir_3
 /src/t_rename_overwrite
+/src/t_snapshot_deleted_subvolume
 /src/t_stripealign
 /src/t_truncate_cmtime
 /src/t_truncate_self
diff --git a/src/Makefile b/src/Makefile
index 8160a0e8..53a32370 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -33,7 +33,7 @@  LINUX_TARGETS = xfsctl bstat t_mtab getdevicesize preallo_rw_pattern_reader \
 	attr_replace_test swapon mkswap t_attr_corruption t_open_tmpfiles \
 	fscrypt-crypt-util bulkstat_null_ocount splice-test chprojid_fail \
 	detached_mounts_propagation ext4_resize t_readdir_3 splice2pipe \
-	uuid_ioctl
+	uuid_ioctl t_snapshot_deleted_subvolume
 
 EXTRA_EXECS = dmerror fill2attr fill2fs fill2fs_check scaleread.sh \
 	      btrfs_crc32c_forged_name.py popdir.pl popattr.py \
diff --git a/src/t_snapshot_deleted_subvolume.c b/src/t_snapshot_deleted_subvolume.c
new file mode 100644
index 00000000..c3adb1c4
--- /dev/null
+++ b/src/t_snapshot_deleted_subvolume.c
@@ -0,0 +1,102 @@ 
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) Meta Platforms, Inc. and affiliates.
+
+#include "global.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <linux/types.h>
+#ifdef HAVE_STRUCT_BTRFS_IOCTL_VOL_ARGS_V2
+#include <linux/btrfs.h>
+#else
+#ifndef BTRFS_IOCTL_MAGIC
+#define BTRFS_IOCTL_MAGIC 0x94
+#endif
+
+#ifndef BTRFS_IOC_SNAP_DESTROY_V2
+#define BTRFS_IOC_SNAP_DESTROY_V2 \
+	_IOW(BTRFS_IOCTL_MAGIC, 63, struct btrfs_ioctl_vol_args_v2)
+#endif
+
+#ifndef BTRFS_IOC_SNAP_CREATE_V2
+#define BTRFS_IOC_SNAP_CREATE_V2 \
+	_IOW(BTRFS_IOCTL_MAGIC, 23, struct btrfs_ioctl_vol_args_v2)
+#endif
+
+#ifndef BTRFS_IOC_SUBVOL_CREATE_V2
+#define BTRFS_IOC_SUBVOL_CREATE_V2 \
+	_IOW(BTRFS_IOCTL_MAGIC, 24, struct btrfs_ioctl_vol_args_v2)
+#endif
+
+#ifndef BTRFS_SUBVOL_NAME_MAX
+#define BTRFS_SUBVOL_NAME_MAX 4039
+#endif
+
+struct btrfs_ioctl_vol_args_v2 {
+	__s64 fd;
+	__u64 transid;
+	__u64 flags;
+	union {
+		struct {
+			__u64 size;
+			struct btrfs_qgroup_inherit *qgroup_inherit;
+		};
+		__u64 unused[4];
+	};
+	union {
+		char name[BTRFS_SUBVOL_NAME_MAX + 1];
+		__u64 devid;
+		__u64 subvolid;
+	};
+};
+#endif
+
+int main(int argc, char **argv)
+{
+	if (argc != 2) {
+		fprintf(stderr, "usage: %s PATH\n", argv[0]);
+		return EXIT_FAILURE;
+	}
+
+	int dirfd = open(argv[1], O_RDONLY | O_DIRECTORY);
+	if (dirfd < 0) {
+		perror(argv[1]);
+		return EXIT_FAILURE;
+	}
+
+	struct btrfs_ioctl_vol_args_v2 subvol_args = {};
+	strcpy(subvol_args.name, "subvol");
+	if (ioctl(dirfd, BTRFS_IOC_SUBVOL_CREATE_V2, &subvol_args) < 0) {
+		perror("BTRFS_IOC_SUBVOL_CREATE_V2");
+		return EXIT_FAILURE;
+	}
+
+	int subvolfd = openat(dirfd, "subvol", O_RDONLY | O_DIRECTORY);
+	if (subvolfd < 0) {
+		perror("openat");
+		return EXIT_FAILURE;
+	}
+
+	if (ioctl(dirfd, BTRFS_IOC_SNAP_DESTROY_V2, &subvol_args) < 0) {
+		perror("BTRFS_IOC_SNAP_DESTROY_V2");
+		return EXIT_FAILURE;
+	}
+
+	struct btrfs_ioctl_vol_args_v2 snap_args = { .fd = subvolfd };
+	strcpy(snap_args.name, "snap");
+	if (ioctl(dirfd, BTRFS_IOC_SNAP_CREATE_V2, &snap_args) < 0) {
+		if (errno == ENOENT)
+			return EXIT_SUCCESS;
+		perror("BTRFS_IOC_SNAP_CREATE_V2");
+		return EXIT_FAILURE;
+	}
+	fprintf(stderr, "BTRFS_IOC_SNAP_CREATE_V2 should've failed\n");
+	return EXIT_FAILURE;
+}
diff --git a/tests/btrfs/304 b/tests/btrfs/304
new file mode 100755
index 00000000..65f54b95
--- /dev/null
+++ b/tests/btrfs/304
@@ -0,0 +1,26 @@ 
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+#
+# FS QA Test 304
+#
+# Try to snapshot a deleted subvolume.
+#
+. ./common/preamble
+_begin_fstest auto quick snapshot subvol
+
+_supported_fs btrfs
+_require_scratch
+_require_test_program t_snapshot_deleted_subvolume
+_fixed_by_kernel_commit XXXXXXXXXXXX "btrfs: don't abort filesystem when attempting to snapshot deleted subvolume"
+
+_scratch_mkfs >> $seqres.full 2>&1 || _fail "mkfs failed"
+_scratch_mount
+
+"$here/src/t_snapshot_deleted_subvolume" "$SCRATCH_MNT"
+# Make sure the filesystem didn't go read-only.
+touch "$SCRATCH_MNT/foo"
+
+echo "Silence is golden"
+status=0
+exit
diff --git a/tests/btrfs/304.out b/tests/btrfs/304.out
new file mode 100644
index 00000000..c504111c
--- /dev/null
+++ b/tests/btrfs/304.out
@@ -0,0 +1,2 @@ 
+QA output created by 304
+Silence is golden