test that we actually lock dirs on projection

This commit is contained in:
Ashe Connor 2019-02-19 17:07:25 +11:00
Родитель 98498eec62
Коммит ffff2f2f46
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 997E657B1C52B6C5
7 изменённых файлов: 114 добавлений и 12 удалений

Просмотреть файл

@ -58,7 +58,8 @@ TESTS = t000-mirror-read.t \
t201-event-err.t \
t202-event-deny.t \
t203-event-null.t \
t204-event-allow.t
t204-event-allow.t \
t205-event-locking.t
if ENABLE_VFSAPI
TESTS += t500-vfs-mirror-basic.t \

Просмотреть файл

@ -15,7 +15,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see http://www.gnu.org/licenses/ .
test_description='projfs file operation permission denial tests
test_description='projfs file operation permission null-denial tests
Check that projfs file operation permission requests respond to
denial responses caused by event handlers returning null.

44
t/t205-event-locking.t Executable file
Просмотреть файл

@ -0,0 +1,44 @@
#!/bin/sh
#
# Copyright (C) 2018-2019 GitHub, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see http://www.gnu.org/licenses/ .
test_description='projfs file operation locking tests
Check that projfs file operation notification events are issued serially for a
given path.
'
. ./test-lib.sh
. "$TEST_DIRECTORY"/test-lib-event.sh
rm lock >/dev/null 2>/dev/null
projfs_start test_projfs_handlers source target --timeout 1 --lock-file lock || exit 1
# wait_mount will trigger a projection, so we need to reset it to empty
setfattr -n user.projection.empty -v 0x01 source
test_expect_success 'test concurrent access does not trigger failure' '
projfs_run_twice ls target
'
projfs_stop || exit 1
test_expect_success 'check no event error messages' '
test_must_be_empty test_projfs_handlers.err
'
test_done

19
t/test-lib-functions.sh поставляемый
Просмотреть файл

@ -754,6 +754,25 @@ projfs_start () {
trap projfs_stop EXIT
}
# Run the given command twice in parallel, wait for both to complete, and
# return with 1 if at least one of the executions fails.
projfs_run_twice () {
"$@" &
pidA="$!"
"$@" &
pidB="$!"
ret=0
if ! wait $pidA; then
ret=1
fi
if ! wait $pidB; then
ret=1
fi
return $ret
}
# Stop the projected filesystem command that was started by projfs_start()
# and wait for its umount operation to be completed.
projfs_stop () {

Просмотреть файл

@ -103,7 +103,8 @@ static const struct option all_long_opts[] = {
{ "help", no_argument, NULL, TEST_OPT_NUM_HELP },
{ "retval", required_argument, NULL, TEST_OPT_NUM_RETVAL },
{ "retval-file", required_argument, NULL, TEST_OPT_NUM_RETFILE },
{ "timeout", required_argument, NULL, TEST_OPT_NUM_TIMEOUT}
{ "timeout", required_argument, NULL, TEST_OPT_NUM_TIMEOUT },
{ "lock-file", required_argument, NULL, TEST_OPT_NUM_LOCKFILE },
};
struct opt_usage {
@ -115,13 +116,15 @@ static const struct opt_usage all_opts_usage[] = {
{ NULL, 1 },
{ "allow|deny|null|<error>", 1 },
{ "<retval-file>", 1 },
{ "<max-seconds>", 1 }
{ "<max-seconds>", 1 },
{ "<lock-file>", 1 },
};
/* option values */
static int optval_retval;
static const char *optval_retfile;
static long int optval_timeout;
static const char *optval_lockfile;
static unsigned int opt_set_flags = TEST_OPT_NONE;
@ -351,6 +354,11 @@ void test_parse_opts(int argc, char *const argv[], unsigned int opt_flags,
opt_set_flags |= TEST_OPT_TIMEOUT;
break;
case TEST_OPT_NUM_LOCKFILE:
optval_lockfile = optarg;
opt_set_flags |= TEST_OPT_LOCKFILE;
break;
case '?':
if (optopt > 0)
test_exit_error(argv[0],
@ -442,6 +450,12 @@ unsigned int test_get_opts(unsigned int opt_flags, ...)
*l = optval_timeout;
break;
case TEST_OPT_LOCKFILE:
s = va_arg(ap, const char**);
if (ret_flag != TEST_OPT_NONE)
*s = optval_lockfile;
break;
default:
errx(EXIT_FAILURE,
"unknown option flag: %u", opt_flag);

Просмотреть файл

@ -30,11 +30,13 @@
#define TEST_OPT_NUM_RETVAL 1
#define TEST_OPT_NUM_RETFILE 2
#define TEST_OPT_NUM_TIMEOUT 3
#define TEST_OPT_NUM_LOCKFILE 4
#define TEST_OPT_HELP (0x0001 << TEST_OPT_NUM_HELP)
#define TEST_OPT_RETVAL (0x0001 << TEST_OPT_NUM_RETVAL)
#define TEST_OPT_RETFILE (0x0001 << TEST_OPT_NUM_RETFILE)
#define TEST_OPT_TIMEOUT (0x0001 << TEST_OPT_NUM_TIMEOUT)
#define TEST_OPT_LOCKFILE (0x0001 << TEST_OPT_NUM_LOCKFILE)
#define TEST_OPT_NONE 0x0000
#define TEST_OPT_VFSAPI 0x8000 // not a command-line option

Просмотреть файл

@ -23,6 +23,7 @@
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "test_common.h"
@ -30,11 +31,13 @@ static int test_handle_event(struct projfs_event *event, const char *desc,
int proj, int perm)
{
unsigned int opt_flags, ret_flags;
const char *retfile;
int ret;
const char *retfile, *lockfile = NULL;
int ret, timeout = 0, fd = 0, res;
opt_flags = test_get_opts((TEST_OPT_RETVAL | TEST_OPT_RETFILE),
&ret, &ret_flags, &retfile);
opt_flags = test_get_opts((TEST_OPT_RETVAL | TEST_OPT_RETFILE |
TEST_OPT_TIMEOUT | TEST_OPT_LOCKFILE),
&ret, &ret_flags, &retfile, &timeout,
&lockfile);
if ((opt_flags & TEST_OPT_RETFILE) == TEST_OPT_NONE ||
(ret_flags & TEST_FILE_EXIST) != TEST_FILE_NONE) {
@ -57,6 +60,24 @@ static int test_handle_event(struct projfs_event *event, const char *desc,
// TODO: hydrate file/dir based on projection list
}
if (lockfile) {
fd = open(lockfile, (O_CREAT | O_EXCL | O_RDWR), 0600);
if (fd == -1 && errno == EEXIST)
return -EEXIST;
else if (fd == -1)
return -EINVAL;
}
if (timeout)
sleep(timeout);
if (lockfile) {
close(fd);
res = unlink(lockfile);
if (res == -1)
return -EINVAL;
}
if ((ret_flags & TEST_VAL_SET) == TEST_VAL_UNSET)
ret = perm ? PROJFS_ALLOW : 0;
else if (!perm && ret > 0)
@ -87,7 +108,8 @@ int main(int argc, char *const argv[])
struct projfs_handlers handlers = { 0 };
test_parse_mount_opts(argc, argv,
(TEST_OPT_RETVAL | TEST_OPT_RETFILE),
(TEST_OPT_RETVAL | TEST_OPT_RETFILE |
TEST_OPT_TIMEOUT | TEST_OPT_LOCKFILE),
&lower_path, &mount_path);
handlers.handle_proj_event = &test_proj_event;