Linux Kernel Selftest development
 help / color / mirror / Atom feed
From: Breno Leitao <leitao@debian.org>
To: Shuah Khan <shuah@kernel.org>, Andreas Hindborg <a.hindborg@kernel.org>
Cc: linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org,
	 gustavold@gmail.com, linux-fsdevel@vger.kernel.org,
	 Breno Leitao <leitao@debian.org>,
	kernel-team@meta.com,  vasilisalmpanis@gmail.com
Subject: [PATCH 3/4] selftests/configfs: cover symlink and unlink
Date: Wed, 26 Aug 2026 03:47:04 -0700	[thread overview]
Message-ID: <20260826-config_selftest-v1-3-e364b07e91ac@debian.org> (raw)
In-Reply-To: <20260826-config_selftest-v1-0-e364b07e91ac@debian.org>

samples/configfs had nothing to link from, so symlink(2) went untested
beyond the EPERM a subsystem without ->allow_link() returns.

Cover creating and removing a link, the relative body configfs stores, the
count ->allow_link() and ->drop_link() keep, the busy errors both ends
return, and what get_target() rejects.

Signed-off-by: Breno Leitao <leitao@debian.org>
---
 .../selftests/filesystems/configfs/configfs_test.c | 85 +++++++++++++++++++++-
 1 file changed, 83 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/filesystems/configfs/configfs_test.c b/tools/testing/selftests/filesystems/configfs/configfs_test.c
index 072d0dcf3f96b..9b15e1fd69e5b 100644
--- a/tools/testing/selftests/filesystems/configfs/configfs_test.c
+++ b/tools/testing/selftests/filesystems/configfs/configfs_test.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Exercise the configfs userspace interface through the three subsystems
+ * Exercise the configfs userspace interface through the subsystems
  * registered by samples/configfs.
  *
  * Copyright (c) 2026 Meta Platforms, Inc. and affiliates
@@ -10,6 +10,7 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <limits.h>
 #include <sched.h>
 #include <stdbool.h>
 #include <stdio.h>
@@ -31,16 +32,24 @@
 #define CHILDLESS		"01-childless"
 #define SIMPLE			"02-simple-children"
 #define GROUPS			"03-group-children"
+#define SYMLINKS		"04-symlink-children"
 
 #define ITEM_A			SIMPLE "/kselftest-a"
 #define ITEM_B			SIMPLE "/kselftest-b"
 #define GROUP			GROUPS "/kselftest-group"
 #define GROUP_ITEM		GROUP "/kselftest-a"
+#define LINK_SRC		SYMLINKS "/kselftest-src"
+#define LINK			LINK_SRC "/kselftest-link"
+
+static const char * const test_links[] = {
+	LINK,
+};
 
 /* Deepest first, so one pass empties the tree. */
 static const char * const test_dirs[] = {
 	GROUP_ITEM,
 	GROUP,
+	LINK_SRC,
 	ITEM_A,
 	ITEM_B,
 };
@@ -49,6 +58,10 @@ static void drop_test_dirs(void)
 {
 	size_t i;
 
+	/* Links first: they hold both their source and their target. */
+	for (i = 0; i < ARRAY_SIZE(test_links); i++)
+		unlink(test_links[i]);
+
 	for (i = 0; i < ARRAY_SIZE(test_dirs); i++)
 		rmdir(test_dirs[i]);
 }
@@ -131,7 +144,7 @@ FIXTURE_TEARDOWN(configfs)
 
 TEST_F(configfs, mount_and_subsystems)
 {
-	const char * const subsys[] = { CHILDLESS, SIMPLE, GROUPS };
+	const char * const subsys[] = { CHILDLESS, SIMPLE, GROUPS, SYMLINKS };
 	struct statfs sfs;
 	struct stat st;
 	size_t i;
@@ -324,6 +337,74 @@ TEST_F(configfs, symlink_without_allow_link)
 	EXPECT_EQ(errno, EPERM);
 }
 
+TEST_F(configfs, symlink_and_unlink)
+{
+	char buf[PATH_MAX];
+	struct stat st;
+	ssize_t n;
+
+	ASSERT_EQ(mkdir(ITEM_A, 0755), 0);
+	ASSERT_EQ(mkdir(LINK_SRC, 0755), 0);
+
+	ASSERT_EQ(symlink(ITEM_A, LINK), 0);
+
+	/* configfs stores its own body, a path relative to the link. */
+	n = readlink(LINK, buf, sizeof(buf) - 1);
+	ASSERT_GT(n, 0);
+	buf[n] = '\0';
+	EXPECT_STREQ(buf, "../../" ITEM_A);
+	EXPECT_EQ(stat(LINK "/storeme", &st), 0);
+
+	/* ->allow_link() ran on the source, not on the target. */
+	ASSERT_GT(read_attr(LINK_SRC "/nlinks", buf, sizeof(buf)), 0);
+	EXPECT_STREQ(buf, "1\n");
+
+	ASSERT_EQ(unlink(LINK), 0);
+	ASSERT_GT(read_attr(LINK_SRC "/nlinks", buf, sizeof(buf)), 0);
+	EXPECT_STREQ(buf, "0\n");
+}
+
+TEST_F(configfs, symlink_pins_both_ends)
+{
+	ASSERT_EQ(mkdir(ITEM_A, 0755), 0);
+	ASSERT_EQ(mkdir(LINK_SRC, 0755), 0);
+	ASSERT_EQ(symlink(ITEM_A, LINK), 0);
+
+	/* A linked item cannot go away under the link. */
+	ASSERT_EQ(rmdir(ITEM_A), -1);
+	EXPECT_EQ(errno, EBUSY);
+
+	/* The link counts as a child of its source. */
+	ASSERT_EQ(rmdir(LINK_SRC), -1);
+	EXPECT_EQ(errno, ENOTEMPTY);
+
+	ASSERT_EQ(unlink(LINK), 0);
+	EXPECT_EQ(rmdir(ITEM_A), 0);
+}
+
+TEST_F(configfs, symlink_target_outside_configfs)
+{
+	ASSERT_EQ(mkdir(LINK_SRC, 0755), 0);
+	ASSERT_EQ(symlink("/", LINK), -1);
+	EXPECT_EQ(errno, EPERM);
+}
+
+TEST_F(configfs, symlink_target_missing)
+{
+	ASSERT_EQ(mkdir(LINK_SRC, 0755), 0);
+	ASSERT_EQ(symlink(SIMPLE "/kselftest-gone", LINK), -1);
+	EXPECT_EQ(errno, ENOENT);
+}
+
+TEST_F(configfs, symlink_target_is_an_attribute)
+{
+	ASSERT_EQ(mkdir(LINK_SRC, 0755), 0);
+
+	/* The target is resolved with LOOKUP_DIRECTORY. */
+	ASSERT_EQ(symlink(CHILDLESS "/storeme", LINK), -1);
+	EXPECT_EQ(errno, ENOTDIR);
+}
+
 TEST_F(configfs, module_pinned_by_item)
 {
 	ASSERT_EQ(mkdir(ITEM_A, 0755), 0);

-- 
2.53.0-Meta


  parent reply	other threads:[~2026-08-26 10:47 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-26 10:47 [PATCH 0/4] configfs: add a basic selftest Breno Leitao
2026-08-26 10:47 ` [PATCH 1/4] selftests/configfs: add tests for the userspace interface Breno Leitao
2026-08-26 10:47 ` [PATCH 2/4] samples/configfs: add a subsystem that accepts symlinks Breno Leitao
2026-08-26 10:47 ` Breno Leitao [this message]
2026-08-26 10:47 ` [PATCH 4/4] selftests/configfs: race symlink against rmdir of the target Breno Leitao

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260826-config_selftest-v1-3-e364b07e91ac@debian.org \
    --to=leitao@debian.org \
    --cc=a.hindborg@kernel.org \
    --cc=gustavold@gmail.com \
    --cc=kernel-team@meta.com \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=shuah@kernel.org \
    --cc=vasilisalmpanis@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox