From: Miklos Szeredi Date: Mon, 14 Apr 2014 00:34:51 +0000 (+1000) Subject: common: add infrastructure for renameat2 syscall tests X-Git-Tag: v2022.05.01~3180 X-Git-Url: http://git.apps.os.sepia.ceph.com/?p=xfstests-dev.git;a=commitdiff_plain;h=413f501b5325db07389ac40f7f6939abb3eb8b79 common: add infrastructure for renameat2 syscall tests The renameat2() syscall was merged into 3.15-rc (merge commit: 7df934526c0b). This adds the shared infrastructure for the actual test scripts. Signed-off-by: Miklos Szeredi Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner --- diff --git a/.gitignore b/.gitignore index e8c50120..66e6ee8b 100644 --- a/.gitignore +++ b/.gitignore @@ -106,6 +106,7 @@ /src/aio-dio-regress/aio-io-setup-with-nonwritable-context-pointer /src/aio-dio-regress/aiodio_sparse2 /src/cloner +/src/renameat2 # dmapi/ binaries /dmapi/src/common/cmd/read_invis diff --git a/common/renameat2 b/common/renameat2 new file mode 100644 index 00000000..a3351697 --- /dev/null +++ b/common/renameat2 @@ -0,0 +1,129 @@ +###### +# +# renameat2 helpers +# +#----------------------------------------------------------------------- +# Copyright (c) 2014 Miklos Szeredi. All Rights Reserved. +# +# 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. +# +# This program is distributed in the hope that it would 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, write the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +#----------------------------------------------------------------------- +# + +# +# Setup source or dest +# +_setup_one() +{ + local path=$1 + local type=$2 + + case $type in + none) ;; + regu) echo foo > $path;; + symb) ln -s foo $path;; + dire) mkdir $path;; + tree) mkdir $path; echo foo > $path/bar;; + esac +} + +# +# Cleanup source or dest +# +_cleanup_one() +{ + local path=$1 + + if test -d $path; then + rm -f $path/bar + rmdir $path + else + rm -f $path + fi +} + +# +# Check type of source or destination +# +_showtype_one() +{ + local path=$1 + + if test -e $path -o -h $path; then + if test -d $path -a -e $path/bar; then + echo -n "tree" + else + echo -n `stat -c %F $path | cut -b-4` + fi + else + echo -n "none" + fi +} + +# +# This runs renameat2 on all combinations of source and dest +# +_rename_tests_source_dest() +{ + local source=$1 + local dest=$2 + local options=$3 + + for stype in none regu symb dire tree; do + for dtype in none regu symb dire tree; do + echo -n "$options $stype/$dtype -> " + _setup_one $source $stype + _setup_one $dest $dtype + src/renameat2 $source $dest $flags + if test $? == 0; then + _showtype_one $source + echo -n "/" + _showtype_one $dest + echo "." + fi + _cleanup_one $source + _cleanup_one $dest + done + done +} + +# +# This runs _rename_tests_source_dest() for both same-directory and +# cross-directory renames +# +_rename_tests() +{ + local testdir=$1 + local flags=$2 + + #same directory renames + _rename_tests_source_dest $testdir/src $testdir/dst "samedir " + + #cross directory renames + mkdir $testdir/x $testdir/y + _rename_tests_source_dest $testdir/x/src $testdir/y/dst "crossdir" + rmdir $testdir/x $testdir/y +} + +# +# This checks whether the renameat2 syscall is supported +# +_requires_renameat2() +{ + if test ! -x src/renameat2; then + _notrun "renameat2 binary not found" + fi + if ! src/renameat2 -t; then + _notrun "kernel doesn't support renameat2 syscall" + fi +} diff --git a/configure.ac b/configure.ac index 2f95c4c0..43e60291 100644 --- a/configure.ac +++ b/configure.ac @@ -76,6 +76,8 @@ in ;; esac +AC_CHECK_FUNCS([renameat2]) + AC_CONFIG_HEADER(include/config.h) AC_CONFIG_FILES([include/builddefs]) AC_OUTPUT diff --git a/src/Makefile b/src/Makefile index 2dbc696d..d7540484 100644 --- a/src/Makefile +++ b/src/Makefile @@ -18,7 +18,8 @@ LINUX_TARGETS = xfsctl bstat t_mtab getdevicesize preallo_rw_pattern_reader \ locktest unwritten_mmap bulkstat_unlink_test t_stripealign \ bulkstat_unlink_test_modified t_dir_offset t_futimens t_immutable \ stale_handle pwrite_mmap_blocked t_dir_offset2 seek_sanity_test \ - seek_copy_test t_readdir_1 t_readdir_2 fsync-tester nsexec cloner + seek_copy_test t_readdir_1 t_readdir_2 fsync-tester nsexec cloner \ + renameat2 SUBDIRS = diff --git a/src/renameat2.c b/src/renameat2.c new file mode 100644 index 00000000..51459597 --- /dev/null +++ b/src/renameat2.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2014, Miklos Szeredi + * This file is published under GPL2+. + * + * This is a trivial wrapper around the renameat2 syscall. + */ + +#include "global.h" + +#ifndef HAVE_RENAMEAT2 +#include + +#if !defined(SYS_renameat2) && defined(__x86_64__) +#define SYS_renameat2 316 +#endif + +static int renameat2(int dfd1, const char *path1, + int dfd2, const char *path2, + unsigned int flags) +{ +#ifdef SYS_renameat2 + return syscall(SYS_renameat2, dfd1, path1, dfd2, path2, flags); +#else + errno = ENOSYS; + return -1; +#endif +} +#endif + +#ifndef RENAME_NOREPLACE +#define RENAME_NOREPLACE (1 << 0) /* Don't overwrite target */ +#endif +#ifndef RENAME_EXCHANGE +#define RENAME_EXCHANGE (1 << 1) /* Exchange source and dest */ +#endif +#ifndef RENAME_WHITEOUT +#define RENAME_WHITEOUT (1 << 2) /* Whiteout source */ +#endif + +int main(int argc, char *argv[]) +{ + int ret; + int c; + const char *path1 = NULL; + const char *path2 = NULL; + unsigned int flags = 0; + int test = 0; + + for (c = 1; c < argc; c++) { + if (argv[c][0] == '-') { + switch (argv[c][1]) { + case 't': + test = 1; + break; + case 'n': + flags |= RENAME_NOREPLACE; + break; + case 'x': + flags |= RENAME_EXCHANGE; + break; + case 'w': + flags |= RENAME_WHITEOUT; + break; + default: + goto usage; + } + } else if (!path1) { + path1 = argv[c]; + } else if (!path2) { + path2 = argv[c]; + } else { + goto usage; + } + } + + if (!test && (!path1 || !path2)) + goto usage; + + ret = renameat2(AT_FDCWD, path1, AT_FDCWD, path2, flags); + if (ret == -1) { + if (test) { + if (errno == ENOSYS || errno == EINVAL) + return 1; + else + return 0; + } + perror(""); + return 1; + } + + return 0; + +usage: + fprintf(stderr, + "usage: %s [-t] [-n|-x|-w] path1 path2\n" + " -t test\n" + " -n noreplace\n" + " -x exchange\n" + " -w whiteout\n", argv[0]); + + return 1; +}