From: Jeff Layton <jlayton@kernel.org>
To: fstests@vger.kernel.org
Cc: linux-fsdevel@vger.kernel.org, Zorro Lang <zlang@redhat.com>,
Christian Brauner <brauner@kernel.org>,
Jeff Layton <jlayton@kernel.org>
Subject: [PATCH fstests v3 3/3] generic: add tests for file delegations
Date: Wed, 03 Dec 2025 10:43:09 -0500 [thread overview]
Message-ID: <20251203-dir-deleg-v3-3-be55fbf2ad53@kernel.org> (raw)
In-Reply-To: <20251203-dir-deleg-v3-0-be55fbf2ad53@kernel.org>
Mostly the same ones as leases, but some additional tests to validate
that they are broken on metadata changes.
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
common/locktest | 5 ++
src/locktest.c | 202 +++++++++++++++++++++++++++++++++++++++++++++++++-
tests/generic/784 | 20 +++++
tests/generic/784.out | 2 +
4 files changed, 227 insertions(+), 2 deletions(-)
diff --git a/common/locktest b/common/locktest
index 12b5c27e0c03ad4c60985e3882026fce04e7330e..9344c43d8ee97679b49357b4e75de89ad56221ff 100644
--- a/common/locktest
+++ b/common/locktest
@@ -101,3 +101,8 @@ _run_dirdelegtest() {
TESTFILE=$DELEGDIR
_run_generic "-D"
}
+
+_run_filedelegtest() {
+ TESTFILE=$DELEGDIR
+ _run_generic "-F"
+}
diff --git a/src/locktest.c b/src/locktest.c
index eb40dce3f1b28ef34752518808ec2f3999cd4257..54ee1f07539ef08e768d2c809c40327f315d43e7 100644
--- a/src/locktest.c
+++ b/src/locktest.c
@@ -126,6 +126,8 @@ static char *child[] = { "child0", "child1" };
#define CMD_CHMOD 19
#define CMD_MKDIR 20
#define CMD_RMDIR 21
+#define CMD_UNLINK_S 22
+#define CMD_RENAME_S 23
#define PASS 0
#define FAIL 1
@@ -169,6 +171,8 @@ static char *get_cmd_str(int cmd)
case CMD_CHMOD: return "Chmod"; break;
case CMD_MKDIR: return "Mkdir"; break;
case CMD_RMDIR: return "Rmdir"; break;
+ case CMD_UNLINK_S: return "Remove Self"; break;
+ case CMD_RENAME_S: return "Rename Self"; break;
}
return "unknown";
}
@@ -716,6 +720,150 @@ static int64_t lease_tests[][6] =
{0,0,0,0,0,CLIENT}
};
+char *filedeleg_descriptions[] = {
+ /* 1 */"Take Read Deleg",
+ /* 2 */"Take Write Deleg",
+ /* 3 */"Fail Write Deleg if file is open somewhere else",
+ /* 4 */"Fail Read Deleg if opened with write permissions",
+ /* 5 */"Read deleg gets SIGIO on write open",
+ /* 6 */"Write deleg gets SIGIO on read open",
+ /* 7 */"Read deleg does _not_ get SIGIO on read open",
+ /* 8 */"Read deleg gets SIGIO on write open",
+ /* 9 */"Write deleg gets SIGIO on truncate",
+ /* 10 */"Read deleg gets SIGIO on truncate",
+ /* 11 */"Read deleg gets SIGIO on chmod",
+ /* 12 */"Read deleg gets SIGIO on unlink",
+ /* 13 */"Read deleg gets SIGIO on rename",
+};
+
+static int64_t filedeleg_tests[][6] =
+ /* test # Action [offset|flags|arg] length expected server/client */
+ /* [sigio_wait_time] */
+ {
+ /* Various tests to exercise delegs */
+
+ /* SECTION 1: Simple verification of being able to take delegs */
+ /* Take Read Deleg */
+ {1, CMD_CLOSE, 0, 0, PASS, CLIENT },
+ {1, CMD_OPEN, O_RDONLY, 0, PASS, CLIENT },
+ {1, CMD_CLOSE, 0, 0, PASS, SERVER },
+ {1, CMD_OPEN, O_RDONLY, 0, PASS, SERVER },
+ {1, CMD_SETDELEG, F_RDLCK, 0, PASS, SERVER },
+ {1, CMD_GETDELEG, F_RDLCK, 0, PASS, SERVER },
+ {1, CMD_SETDELEG, F_UNLCK, 0, PASS, SERVER },
+ {1, CMD_CLOSE, 0, 0, PASS, SERVER },
+ {1, CMD_CLOSE, 0, 0, PASS, CLIENT },
+
+ /* Take Write Deleg */
+ {2, CMD_OPEN, O_RDWR, 0, PASS, SERVER },
+ {2, CMD_SETDELEG, F_WRLCK, 0, PASS, SERVER },
+ {2, CMD_GETDELEG, F_WRLCK, 0, PASS, SERVER },
+ {2, CMD_SETDELEG, F_UNLCK, 0, PASS, SERVER },
+ {2, CMD_CLOSE, 0, 0, PASS, SERVER },
+ /* Fail Write Deleg with other users */
+ {3, CMD_OPEN, O_RDONLY, 0, PASS, CLIENT },
+ {3, CMD_OPEN, O_RDWR, 0, PASS, SERVER },
+ {3, CMD_SETDELEG, F_WRLCK, 0, FAIL, SERVER },
+ {3, CMD_GETDELEG, F_WRLCK, 0, FAIL, SERVER },
+ {3, CMD_CLOSE, 0, 0, PASS, SERVER },
+ {3, CMD_CLOSE, 0, 0, PASS, CLIENT },
+ /* Fail Read Deleg if opened for write */
+ {4, CMD_OPEN, O_RDWR, 0, PASS, SERVER },
+ {4, CMD_SETDELEG, F_RDLCK, 0, FAIL, SERVER },
+ {4, CMD_GETDELEG, F_RDLCK, 0, FAIL, SERVER },
+ {4, CMD_CLOSE, 0, 0, PASS, SERVER },
+
+ /* SECTION 2: Proper SIGIO notifications */
+ /* Get SIGIO when read deleg is broken by write */
+ {5, CMD_OPEN, O_RDONLY, 0, PASS, CLIENT },
+ {5, CMD_SETDELEG, F_RDLCK, 0, PASS, CLIENT },
+ {5, CMD_GETDELEG, F_RDLCK, 0, PASS, CLIENT },
+ {5, CMD_SIGIO, 0, 0, PASS, CLIENT },
+ {5, CMD_OPEN, O_RDWR, 0, PASS, SERVER },
+ {5, CMD_WAIT_SIGIO, 5, 0, PASS, CLIENT },
+ {5, CMD_CLOSE, 0, 0, PASS, SERVER },
+ {5, CMD_CLOSE, 0, 0, PASS, CLIENT },
+
+ /* Get SIGIO when write deleg is broken by read */
+ {6, CMD_OPEN, O_RDWR, 0, PASS, CLIENT },
+ {6, CMD_SETDELEG, F_WRLCK, 0, PASS, CLIENT },
+ {6, CMD_GETDELEG, F_WRLCK, 0, PASS, CLIENT },
+ {6, CMD_SIGIO, 0, 0, PASS, CLIENT },
+ {6, CMD_OPEN, O_RDONLY, 0, PASS, SERVER },
+ {6, CMD_WAIT_SIGIO, 5, 0, PASS, CLIENT },
+ {6, CMD_CLOSE, 0, 0, PASS, SERVER },
+ {6, CMD_CLOSE, 0, 0, PASS, CLIENT },
+
+ /* Don't get SIGIO when read deleg is taken by read */
+ {7, CMD_OPEN, O_RDONLY, 0, PASS, CLIENT },
+ {7, CMD_SETDELEG, F_RDLCK, 0, PASS, CLIENT },
+ {7, CMD_GETDELEG, F_RDLCK, 0, PASS, CLIENT },
+ {7, CMD_SIGIO, 0, 0, PASS, CLIENT },
+ {7, CMD_OPEN, O_RDONLY, 0, PASS, SERVER },
+ {7, CMD_WAIT_SIGIO, 5, 0, FAIL, CLIENT },
+ {7, CMD_CLOSE, 0, 0, PASS, SERVER },
+ {7, CMD_CLOSE, 0, 0, PASS, CLIENT },
+
+ /* Get SIGIO when Read deleg is broken by Write */
+ {8, CMD_OPEN, O_RDONLY, 0, PASS, CLIENT },
+ {8, CMD_SETDELEG, F_RDLCK, 0, PASS, CLIENT },
+ {8, CMD_GETDELEG, F_RDLCK, 0, PASS, CLIENT },
+ {8, CMD_SIGIO, 0, 0, PASS, CLIENT },
+ {8, CMD_OPEN, O_RDWR, 0, PASS, SERVER },
+ {8, CMD_WAIT_SIGIO, 5, 0, PASS, CLIENT },
+ {8, CMD_CLOSE, 0, 0, PASS, SERVER },
+ {8, CMD_CLOSE, 0, 0, PASS, CLIENT },
+
+ /* Get SIGIO when Write deleg is broken by Truncate */
+ {9, CMD_OPEN, O_RDWR, 0, PASS, CLIENT },
+ {9, CMD_SETDELEG, F_WRLCK, 0, PASS, CLIENT },
+ {9, CMD_GETDELEG, F_WRLCK, 0, PASS, CLIENT },
+ {9, CMD_SIGIO, 0, 0, PASS, CLIENT },
+ {9, CMD_TRUNCATE, FILE_SIZE/2, 0, PASS, CLIENT },
+ {9, CMD_WAIT_SIGIO, 5, 0, PASS, CLIENT },
+ {9, CMD_CLOSE, 0, 0, PASS, CLIENT },
+
+ /* Get SIGIO when Read deleg is broken by Truncate */
+ {10, CMD_OPEN, O_RDONLY, 0, PASS, CLIENT },
+ {10, CMD_SETDELEG, F_RDLCK, 0, PASS, CLIENT },
+ {10, CMD_GETDELEG, F_RDLCK, 0, PASS, CLIENT },
+ {10, CMD_SIGIO, 0, 0, PASS, CLIENT },
+ {10, CMD_TRUNCATE, FILE_SIZE/2, 0, PASS, SERVER },
+ {10, CMD_WAIT_SIGIO, 5, 0, PASS, CLIENT },
+ {10, CMD_CLOSE, 0, 0, PASS, CLIENT },
+
+ /* Get SIGIO when Read deleg is broken by Chmod */
+ {11, CMD_OPEN, O_RDONLY, 0, PASS, SERVER },
+ {11, CMD_SETDELEG, F_RDLCK, 0, PASS, SERVER },
+ {11, CMD_GETDELEG, F_RDLCK, 0, PASS, SERVER },
+ {11, CMD_SIGIO, 0, 0, PASS, SERVER },
+ {11, CMD_CHMOD, 0644, 0, PASS, CLIENT },
+ {11, CMD_WAIT_SIGIO, 5, 0, PASS, SERVER },
+ {11, CMD_CLOSE, 0, 0, PASS, SERVER },
+
+ /* Get SIGIO when file is unlinked */
+ {12, CMD_OPEN, O_RDONLY, 0, PASS, SERVER },
+ {12, CMD_SETDELEG, F_RDLCK, 0, PASS, SERVER },
+ {12, CMD_GETDELEG, F_RDLCK, 0, PASS, SERVER },
+ {12, CMD_SIGIO, 0, 0, PASS, SERVER },
+ {12, CMD_UNLINK_S, 0, 0, PASS, CLIENT },
+ {12, CMD_WAIT_SIGIO, 5, 0, PASS, SERVER },
+ {12, CMD_CLOSE, 0, 0, PASS, SERVER },
+
+ /* Get SIGIO when file is renamed */
+ {13, CMD_OPEN, O_RDONLY, 0, PASS, SERVER },
+ {13, CMD_SETDELEG, F_RDLCK, 0, PASS, SERVER },
+ {13, CMD_GETDELEG, F_RDLCK, 0, PASS, SERVER },
+ {13, CMD_SIGIO, 0, 0, PASS, SERVER },
+ {13, CMD_RENAME_S, 0, 0, PASS, CLIENT },
+ {13, CMD_WAIT_SIGIO, 5, 0, PASS, SERVER },
+ {13, CMD_CLOSE, 0, 0, PASS, SERVER },
+
+ /* indicate end of array */
+ {0,0,0,0,0,SERVER},
+ {0,0,0,0,0,CLIENT}
+};
+
char *dirdeleg_descriptions[] = {
/* 1 */"Take Read Lease",
/* 2 */"Write Lease Should Fail",
@@ -1124,6 +1272,37 @@ int do_chmod(int mode)
return PASS;
}
+int do_unlink_self(void)
+{
+ int ret;
+
+ ret = unlink(filename);
+ if (ret < 0) {
+ perror("unlink");
+ return FAIL;
+ }
+ return PASS;
+}
+
+int do_rename_self(void)
+{
+ int ret;
+ char target[PATH_MAX];
+
+ ret = snprintf(target, sizeof(target), "%s2", filename);
+ if (ret >= sizeof(target)) {
+ perror("snprintf");
+ return FAIL;
+ }
+
+ ret = rename(filename, target);
+ if (ret < 0) {
+ perror("unlink");
+ return FAIL;
+ }
+ return PASS;
+}
+
static int do_lock(int cmd, int type, int start, int length)
{
int ret;
@@ -1347,6 +1526,7 @@ main(int argc, char *argv[])
int fail_count = 0;
int run_leases = 0;
int run_dirdelegs = 0;
+ int run_filedelegs = 0;
int test_setlease = 0;
atexit(cleanup);
@@ -1360,7 +1540,7 @@ main(int argc, char *argv[])
prog = p+1;
}
- while ((c = getopt(argc, argv, "dDLn:h:p:t?")) != EOF) {
+ while ((c = getopt(argc, argv, "dDFLn:h:p:t?")) != EOF) {
switch (c) {
case 'd': /* debug flag */
@@ -1371,6 +1551,10 @@ main(int argc, char *argv[])
run_dirdelegs = 1;
break;
+ case 'F':
+ run_filedelegs = 1;
+ break;
+
case 'L': /* Lease testing */
run_leases = 1;
break;
@@ -1430,7 +1614,7 @@ main(int argc, char *argv[])
if (test_setlease == 1) {
struct delegation deleg = { .d_type = F_UNLCK };
- if (run_dirdelegs)
+ if (run_dirdelegs || run_filedelegs)
fcntl(f_fd, F_SETDELEG, &deleg);
else
fcntl(f_fd, F_SETLEASE, F_UNLCK);
@@ -1568,6 +1752,8 @@ main(int argc, char *argv[])
*/
if (run_dirdelegs)
fail_count = run(dirdeleg_tests, dirdeleg_descriptions);
+ else if (run_filedelegs)
+ fail_count = run(filedeleg_tests, filedeleg_descriptions);
else if (run_leases)
fail_count = run(lease_tests, lease_descriptions);
else
@@ -1673,6 +1859,12 @@ int run(int64_t tests[][6], char *descriptions[])
case CMD_RMDIR:
result = do_rmdir(tests[index][ARG]);
break;
+ case CMD_UNLINK_S:
+ result = do_unlink_self();
+ break;
+ case CMD_RENAME_S:
+ result = do_rename_self();
+ break;
}
if( result != tests[index][RESULT]) {
fail_flag++;
@@ -1817,6 +2009,12 @@ int run(int64_t tests[][6], char *descriptions[])
case CMD_RMDIR:
result = do_rmdir(ctl.offset);
break;
+ case CMD_UNLINK_S:
+ result = do_unlink_self();
+ break;
+ case CMD_RENAME_S:
+ result = do_rename_self();
+ break;
}
if( result != ctl.result ) {
fprintf(stderr,"Failure in %d:%s\n",
diff --git a/tests/generic/784 b/tests/generic/784
new file mode 100755
index 0000000000000000000000000000000000000000..6c20bac9b7fb719af05afd507849213359f9ca0f
--- /dev/null
+++ b/tests/generic/784
@@ -0,0 +1,20 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2025 Jeff Layton <jlayton@kernel.org>. All Rights Reserved.
+#
+# FS QA Test 784
+#
+# Test file delegation support
+#
+. ./common/preamble
+_begin_fstest auto quick locks
+
+# Import common functions.
+. ./common/filter
+. ./common/locktest
+
+_require_test
+_require_test_fcntl_setdeleg
+
+_run_filedelegtest
+_exit 0
diff --git a/tests/generic/784.out b/tests/generic/784.out
new file mode 100644
index 0000000000000000000000000000000000000000..7b499e08fed85d0430ecad03c824f745cb42ec44
--- /dev/null
+++ b/tests/generic/784.out
@@ -0,0 +1,2 @@
+QA output created by 784
+success!
--
2.52.0
next prev parent reply other threads:[~2025-12-03 15:43 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-12-03 15:43 [PATCH fstests v3 0/3] generic: new testcases for delegation support Jeff Layton
2025-12-03 15:43 ` [PATCH fstests v3 1/3] common/rc: clean up after the _require_test_fcntl_setlease() test Jeff Layton
2025-12-05 17:14 ` Zorro Lang
2025-12-03 15:43 ` [PATCH fstests v3 2/3] generic: add tests for directory delegations Jeff Layton
2025-12-05 17:15 ` Zorro Lang
2025-12-03 15:43 ` Jeff Layton [this message]
2025-12-05 17:25 ` [PATCH fstests v3 3/3] generic: add tests for file delegations Zorro Lang
2025-12-06 18:35 ` Jeff Layton
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=20251203-dir-deleg-v3-3-be55fbf2ad53@kernel.org \
--to=jlayton@kernel.org \
--cc=brauner@kernel.org \
--cc=fstests@vger.kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=zlang@redhat.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;
as well as URLs for NNTP newsgroup(s).