diff mbox series

[1/2] open_by_handle: add support for testing connectable file handles

Message ID 20250409115220.1911467-2-amir73il@gmail.com (mailing list archive)
State New
Headers show
Series Tests for AT_HANDLE_CONNECTABLE | expand

Commit Message

Amir Goldstein April 9, 2025, 11:52 a.m. UTC
Test for kernel and filesystem support for conenctable file handles.

With -N flag, encode connectable file handles and fail the test if the
kernel or filesystem do not support conenctable file handles.

Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
 common/rc            | 16 +++++++++++++---
 src/open_by_handle.c | 44 +++++++++++++++++++++++++++++++++++---------
 2 files changed, 48 insertions(+), 12 deletions(-)
diff mbox series

Patch

diff --git a/common/rc b/common/rc
index 6592c835..6407b744 100644
--- a/common/rc
+++ b/common/rc
@@ -3829,8 +3829,14 @@  _require_freeze()
 }
 
 # Does NFS export work on this fs?
-_require_exportfs()
+_require_open_by_handle()
 {
+	local what="NFS export"
+	local opts="$1"
+	if [ "$1" == "-N" ]; then
+		what="connectable file handles"
+	fi
+
 	_require_test_program "open_by_handle"
 
 	# virtiofs doesn't support open_by_handle_at(2) yet, though the syscall
@@ -3841,10 +3847,14 @@  _require_exportfs()
 		_notrun "$FSTYP doesn't support open_by_handle_at(2)"
 
 	mkdir -p "$TEST_DIR"/exportfs_test
-	$here/src/open_by_handle -c "$TEST_DIR"/exportfs_test 2>&1 \
-		|| _notrun "$FSTYP does not support NFS export"
+	$here/src/open_by_handle $opts -c "$TEST_DIR"/exportfs_test 2>&1 \
+		|| _notrun "$FSTYP does not support $what"
 }
 
+_require_exportfs()
+{
+	_require_open_by_handle
+}
 
 # Does shutdown work on this fs?
 _require_scratch_shutdown()
diff --git a/src/open_by_handle.c b/src/open_by_handle.c
index a99cce4b..d281343a 100644
--- a/src/open_by_handle.c
+++ b/src/open_by_handle.c
@@ -96,6 +96,9 @@  Examples:
 #ifndef AT_HANDLE_MNT_ID_UNIQUE
 #	define AT_HANDLE_MNT_ID_UNIQUE 0x001
 #endif
+#ifndef AT_HANDLE_CONNECTABLE
+#	define AT_HANDLE_CONNECTABLE   0x002
+#endif
 
 #define MAXFILES 1024
 
@@ -121,6 +124,7 @@  void usage(void)
 	fprintf(stderr, "open_by_handle -d <test_dir> [N] - unlink test files and hardlinks, drop caches and try to open by handle\n");
 	fprintf(stderr, "open_by_handle -m <test_dir> [N] - rename test files, drop caches and try to open by handle\n");
 	fprintf(stderr, "open_by_handle -M <test_dir> [N] - do not silently skip the mount ID verifications\n");
+	fprintf(stderr, "open_by_handle -N <test_dir> [N] - encode connectable file handles\n");
 	fprintf(stderr, "open_by_handle -p <test_dir>     - create/delete and try to open by handle also test_dir itself\n");
 	fprintf(stderr, "open_by_handle -i <handles_file> <test_dir> [N] - read test files handles from file and try to open by handle\n");
 	fprintf(stderr, "open_by_handle -o <handles_file> <test_dir> [N] - get file handles of test files and write handles to file\n");
@@ -130,14 +134,16 @@  void usage(void)
 	fprintf(stderr, "open_by_handle -C <feature>      - check if <feature> is supported by the kernel.\n");
 	fprintf(stderr, "  <feature> can be any of the following values:\n");
 	fprintf(stderr, "  - AT_HANDLE_MNT_ID_UNIQUE\n");
+	fprintf(stderr, "  - AT_HANDLE_CONNECTABLE\n");
 	exit(EXIT_FAILURE);
 }
 
-static int do_name_to_handle_at(const char *fname, struct file_handle *fh,
-				int bufsz, bool force_check_mountid)
+static int do_name_to_handle_at(const char *fname, struct file_handle *fh, int bufsz,
+				bool force_check_mountid, bool connectable)
 {
 	int ret;
 	int mntid_short;
+	int at_flags;
 
 	static bool skip_mntid, skip_mntid_unique;
 
@@ -181,18 +187,24 @@  static int do_name_to_handle_at(const char *fname, struct file_handle *fh,
 		}
 	}
 
+	at_flags = connectable ? AT_HANDLE_CONNECTABLE : 0;
 	fh->handle_bytes = bufsz;
-	ret = name_to_handle_at(AT_FDCWD, fname, fh, &mntid_short, 0);
+	ret = name_to_handle_at(AT_FDCWD, fname, fh, &mntid_short, at_flags);
 	if (bufsz < fh->handle_bytes) {
 		/* Query the filesystem required bufsz and the file handle */
 		if (ret != -1 || errno != EOVERFLOW) {
 			fprintf(stderr, "%s: unexpected result from name_to_handle_at: %d (%m)\n", fname, ret);
 			return EXIT_FAILURE;
 		}
-		ret = name_to_handle_at(AT_FDCWD, fname, fh, &mntid_short, 0);
+		ret = name_to_handle_at(AT_FDCWD, fname, fh, &mntid_short, at_flags);
 	}
 	if (ret < 0) {
-		fprintf(stderr, "%s: name_to_handle: %m\n", fname);
+		/* No filesystem support for encoding connectable file handles (e.g. overlayfs)? */
+		if (connectable)
+			fprintf(stderr, "%s: name_to_handle_at(AT_HANDLE_CONNECTABLE) not supported by %s\n",
+					fname, errno == EINVAL ? "kernel" : "filesystem");
+		else
+			fprintf(stderr, "%s: name_to_handle: %m\n", fname);
 		return EXIT_FAILURE;
 	}
 
@@ -245,8 +257,17 @@  static int check_feature(const char *feature)
 			return EXIT_FAILURE;
 		}
 		return 0;
+	} else if (!strcmp(feature, "AT_HANDLE_CONNECTABLE")) {
+		int ret = name_to_handle_at(AT_FDCWD, ".", NULL, NULL, AT_HANDLE_CONNECTABLE);
+		/* If AT_HANDLE_CONNECTABLE is supported, we get EFAULT. */
+		if (ret < 0 && errno == EINVAL) {
+			fprintf(stderr, "name_to_handle_at(AT_HANDLE_CONNECTABLE) not supported by running kernel\n");
+			return EXIT_FAILURE;
+		}
+		return 0;
 	}
 
+
 	fprintf(stderr, "unknown feature name '%s'\n", feature);
 	return EXIT_FAILURE;
 }
@@ -270,13 +291,13 @@  int main(int argc, char **argv)
 	int	create = 0, delete = 0, nlink = 1, move = 0;
 	int	rd = 0, wr = 0, wrafter = 0, parent = 0;
 	int	keepopen = 0, drop_caches = 1, sleep_loop = 0;
-	int	force_check_mountid = 0;
+	bool	force_check_mountid = 0, connectable = 0;
 	int	bufsz = MAX_HANDLE_SZ;
 
 	if (argc < 2)
 		usage();
 
-	while ((c = getopt(argc, argv, "cC:ludmMrwapknhi:o:sz")) != -1) {
+	while ((c = getopt(argc, argv, "cC:ludmMNrwapknhi:o:sz")) != -1) {
 		switch (c) {
 		case 'c':
 			create = 1;
@@ -313,6 +334,9 @@  int main(int argc, char **argv)
 		case 'M':
 			force_check_mountid = 1;
 			break;
+		case 'N':
+			connectable = 1;
+			break;
 		case 'p':
 			parent = 1;
 			break;
@@ -445,7 +469,8 @@  int main(int argc, char **argv)
 				return EXIT_FAILURE;
 			}
 		} else {
-			ret = do_name_to_handle_at(fname, &handle[i].fh, bufsz, force_check_mountid);
+			ret = do_name_to_handle_at(fname, &handle[i].fh, bufsz,
+						   force_check_mountid, connectable);
 			if (ret)
 				return EXIT_FAILURE;
 		}
@@ -475,7 +500,8 @@  int main(int argc, char **argv)
 				return EXIT_FAILURE;
 			}
 		} else {
-			ret = do_name_to_handle_at(test_dir, &dir_handle.fh, bufsz, force_check_mountid);
+			ret = do_name_to_handle_at(test_dir, &dir_handle.fh, bufsz,
+						   force_check_mountid, connectable);
 			if (ret)
 				return EXIT_FAILURE;
 		}