fstests: transport two ext4 tests from LTP
authorYong Sun <sunyong0511@gmail.com>
Thu, 27 Feb 2020 10:35:07 +0000 (18:35 +0800)
committerEryu Guan <guaneryu@gmail.com>
Fri, 6 Mar 2020 07:55:39 +0000 (15:55 +0800)
Recently LTP upstream removed some ext4 tests[1].  And two of them
is still valid to keep. So I transport those two tests here.

ext4-nsec-timestamps, which is used to test nanosec timestamps of
ext4, rewrite into ext4/043 and 044.  ext4-subdir-limit, which is
used to test subdirectory limit of ext4, rewrite into ext4/045.

[1] https://marc.info/?l=linux-fsdevel&m=157190623919681&w=2

Signed-off-by: Sun Yong <yosun@suse.com>
Reviewed-by: Eryu Guan <guaneryu@gmail.com>
Signed-off-by: Eryu Guan <guaneryu@gmail.com>
.gitignore
src/t_create_long_dirs.c [new file with mode: 0644]
src/t_create_short_dirs.c [new file with mode: 0644]
src/t_get_file_time.c [new file with mode: 0644]
tests/ext4/043 [new file with mode: 0755]
tests/ext4/043.out [new file with mode: 0644]
tests/ext4/044 [new file with mode: 0755]
tests/ext4/044.out [new file with mode: 0644]
tests/ext4/045 [new file with mode: 0755]
tests/ext4/045.out [new file with mode: 0644]
tests/ext4/group

index a26a004..5f5c4a0 100644 (file)
 /src/swapon
 /src/t_access_root
 /src/t_attr_corruption
+/src/t_create_long_dirs
+/src/t_create_short_dirs
 /src/t_dir_offset
 /src/t_dir_offset2
 /src/t_dir_type
 /src/t_ext4_dax_inline_corruption
 /src/t_ext4_dax_journal_corruption
 /src/t_futimens
+/src/t_get_file_time
 /src/t_getcwd
 /src/t_holes
 /src/t_immutable
diff --git a/src/t_create_long_dirs.c b/src/t_create_long_dirs.c
new file mode 100644 (file)
index 0000000..0a7ee0f
--- /dev/null
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2009 FUJITSU LIMITED
+ * Author: Li Zefan <lizf@cn.fujitsu.com>
+ */
+
+#define _POSIX_C_SOURCE 200809L
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "config.h"
+
+/* NCHARS = 10 + 26 + 26 = 62 */
+#define NAME_LEN       255
+#define NCHARS         62
+#define MAX_LEN1       62
+#define MAX_LEN2       (62 * 62)
+#define MAX_LEN3       (62 * 62 * 62)
+
+/* valid characters for the directory name */
+char chars[NCHARS + 1] = "0123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM";
+
+/* to store the generated directory name */
+char name[NAME_LEN + 1];
+int names;
+int parent_fd;
+
+/*
+ * init_name - initialize the directory name
+ *
+ * Generate a randomized directory name, and then we generate more
+ * directory names based on it.
+ */
+void init_name(void)
+{
+       int i;
+
+       srand(time(NULL));
+
+       for (i = 0; i < NAME_LEN; i++)
+               name[i] = chars[rand() % 62];
+}
+
+void create_dir(void)
+{
+       if (mkdirat(parent_fd, name, S_IRWXU)) {
+               perror("mkdir");
+               exit(1);
+       }
+}
+
+/*
+ * create_dirs - create @names directory names
+ * @n: how many names to be created
+ *
+ * if n <= 62,       we need to modify 1 char of the name
+ * if n <= 62*62,    we need to modify 2 chars
+ * if n <= 62*62*62, we need to modify 3 chars
+ */
+void create_dirs(int n)
+{
+       int i, j, k;
+       int depth;
+
+       if (n <= MAX_LEN1)
+               depth = 1;
+       else if (n <= MAX_LEN2)
+               depth = 2;
+       else
+               depth = 3;
+
+       for (i = 0; i < NCHARS; i++) {
+               name[0] = chars[i];
+               if (depth == 1) {
+                       create_dir();
+                       if (--n == 0)
+                               return;
+                       continue;
+               }
+
+               for (j = 0; j < NCHARS; j++) {
+                       name[1] = chars[j];
+                       if (depth == 2) {
+                               create_dir();
+                               if (--n == 0)
+                                       return;
+                               continue;
+                       }
+
+                       for (k = 0; k < NCHARS; k++) {
+                               name[2] = chars[k];
+                               create_dir();
+                               if (--n == 0)
+                                       return;
+                       }
+               }
+       }
+}
+
+void usage()
+{
+       fprintf(stderr, "Usage: create_long_dirs nr_dirs parent_dir\n");
+}
+
+/*
+ * Create long-name directories
+ * @argv[1]: directory number
+ * @argv[2]: parent directory
+ */
+int main(int argc, char *argv[])
+{
+       if (argc != 3) {
+               usage();
+               return 1;
+       }
+
+       names = atoi(argv[1]);
+       if (names > MAX_LEN3 || names <= 0) {
+               usage();
+               return 1;
+       }
+
+       parent_fd = open(argv[2], O_RDONLY);
+       if (parent_fd == -1) {
+               perror("open parent dir failed");
+               return 1;
+       }
+
+       init_name();
+
+       create_dirs(names);
+
+       return 0;
+}
diff --git a/src/t_create_short_dirs.c b/src/t_create_short_dirs.c
new file mode 100644 (file)
index 0000000..b41582a
--- /dev/null
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2009 FUJITSU LIMITED
+ * Author: Li Zefan <lizf@cn.fujitsu.com>
+ */
+
+#define _POSIX_C_SOURCE 200809L
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include "config.h"
+
+/* NCHARS = 10 + 26 + 26 = 62 */
+#define NCHARS      62
+#define MAX_LEN1    62
+#define MAX_LEN2    (62 * 62)
+#define MAX_LEN3    (62 * 62 * 62)
+#define MAX_NAMES   (MAX_LEN1 + MAX_LEN2 + MAX_LEN3)
+
+/* valid characters for a directory name */
+char chars[] = "0123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM";
+
+/* to store the generated directory name */
+char name[10];
+int names;
+int parent_fd;
+
+void create_dir(void)
+{
+       if (mkdirat(parent_fd, name, S_IRWXU)) {
+               perror("mkdir");
+               exit(1);
+       }
+}
+
+/*
+ * create_1 - create length-1 directory names
+ * @n: how name names to be created
+ */
+void create_1(int n)
+{
+       int i;
+
+       name[1] = '\0';
+       for (i = 0; i < NCHARS; i++) {
+               name[0] = chars[i];
+               create_dir();
+               if (--n == 0)
+                       return;
+       }
+}
+
+/*
+ * create_2 - generate length-2 directory names
+ * @n: how many names to be created
+ */
+void create_2(int n)
+{
+       int i, j;
+
+       name[2] = '\0';
+       for (i = 0; i < NCHARS; i++) {
+               name[0] = chars[i];
+               for (j = 0; j < NCHARS; j++) {
+                       name[1] = chars[j];
+                       create_dir();
+                       if (--n == 0)
+                               return;
+               }
+       }
+}
+
+/*
+ * create_3 - generate length-3 directory names
+ * @n: how many names to be created
+ */
+void create_3(int n)
+{
+       int i, j, k;
+
+       name[3] = '\0';
+       for (i = 0; i < NCHARS; i++) {
+               name[0] = chars[i];
+               for (j = 0; j < NCHARS; j++) {
+                       name[1] = chars[j];
+                       for (k = 0; k < NCHARS; k++) {
+                               name[2] = chars[k];
+                               create_dir();
+                               if (--n == 0)
+                                       return;
+                       }
+               }
+       }
+}
+
+void usage()
+{
+       fprintf(stderr, "Usage: create_short_dirs nr_dirs parent_dir\n");
+}
+
+/*
+ * Create short-name directoriess
+ * @argv[1]: director number
+ * @argv[2]: the parent directory
+ */
+int main(int argc, char *argv[])
+{
+       if (argc != 3) {
+               usage();
+               return 1;
+       }
+
+       names = atoi(argv[1]);
+       if (names > MAX_NAMES || names <= 0) {
+               usage();
+               return 1;
+       }
+
+       parent_fd = open(argv[2], O_RDONLY);
+       if (parent_fd == -1) {
+               perror("open parent dir failed");
+               return 1;
+       }
+
+       create_1(names);
+       if (names <= MAX_LEN1)
+               return 0;
+
+       names -= MAX_LEN1;
+       create_2(names);
+       if (names <= MAX_LEN2)
+               return 0;
+
+       names -= MAX_LEN2;
+       create_3(names);
+
+       return 0;
+}
diff --git a/src/t_get_file_time.c b/src/t_get_file_time.c
new file mode 100644 (file)
index 0000000..90286a7
--- /dev/null
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2009 FUJITSU LIMITED
+ * Author: Li Zefan <lizf@cn.fujitsu.com>
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+
+/*
+ * Usage: t_get_file_time <filename> <atime|mtime|ctime> <sec|nsec>
+ */
+int main(int argc, char *argv[])
+{
+       time_t t;
+       struct stat st;
+
+       if (argc != 4) {
+               fprintf(stderr, "Wrong argument num!\n");
+               return 1;
+       }
+
+       if (stat(argv[1], &st) != 0) {
+               perror("stat failed");
+               return 1;
+       }
+
+       if (strcmp(argv[3], "sec") == 0) {
+               if (strcmp(argv[2], "atime") == 0)
+                       t = st.st_atime;
+               else if (strcmp(argv[2], "mtime") == 0)
+                       t = st.st_mtime;
+               else
+                       t = st.st_ctime;
+       } else if (strcmp(argv[3], "nsec") == 0) {
+               if (strcmp(argv[2], "atime") == 0)
+                       t = st.st_atim.tv_nsec;
+               else if (strcmp(argv[2], "mtime") == 0)
+                       t = st.st_mtim.tv_nsec;
+               else
+                       t = st.st_ctim.tv_nsec;
+       } else {
+               fprintf(stderr, "Wrong argument: %s\n", argv[3]);
+               return 1;
+       }
+
+       printf("%lu\n", t);
+
+       return 0;
+}
diff --git a/tests/ext4/043 b/tests/ext4/043
new file mode 100755 (executable)
index 0000000..5f8bfaf
--- /dev/null
@@ -0,0 +1,56 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2020 SUSE Linux Products GmbH.  All Rights Reserved.
+#
+# FS QA Test No. 043
+#
+# Test file timestamps are only precise to seconds with 128-byte inodes."
+#
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1       # failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+       cd /
+       rm -f $tmp.*
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+
+# remove previous $seqres.full before test
+rm -f $seqres.full
+
+# real QA test starts here
+_supported_fs ext3 ext4
+_supported_os Linux
+
+_require_scratch
+_require_test_program "t_get_file_time"
+
+echo "Silence is golden"
+
+echo "Start test timestamps with 128 inode size one device $SCRATCH_DEV" >$seqres.full
+_scratch_mkfs -I 128 >> $seqres.full 2>&1
+_scratch_mount
+
+touch "${SCRATCH_MNT}/tmp_file"
+
+atime=`$here/src/t_get_file_time $SCRATCH_MNT/tmp_file atime nsec`
+mtime=`$here/src/t_get_file_time $SCRATCH_MNT/tmp_file mtime nsec`
+ctime=`$here/src/t_get_file_time $SCRATCH_MNT/tmp_file ctime nsec`
+
+if [ $atime -ne 0 -o $mtime -ne 0 -o $ctime -ne 0 ]; then
+       echo "nsec should be zero when extended timestamps are disabled"
+       echo "atime: $atime, mtime: $mtime, ctime: $ctime"
+fi
+
+status=0
+exit
diff --git a/tests/ext4/043.out b/tests/ext4/043.out
new file mode 100644 (file)
index 0000000..f90f0a5
--- /dev/null
@@ -0,0 +1,2 @@
+QA output created by 043
+Silence is golden
diff --git a/tests/ext4/044 b/tests/ext4/044
new file mode 100755 (executable)
index 0000000..61b4f56
--- /dev/null
@@ -0,0 +1,88 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2020 SUSE Linux Products GmbH.  All Rights Reserved.
+#
+# FS QA Test No. 044
+#
+# Test file timestamps are precise to nanoseconds with 256-byte inodes
+#
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1       # failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+       cd /
+       rm -f $tmp.*
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+
+# remove previous $seqres.full before test
+rm -f $seqres.full
+
+# real QA test starts here
+_supported_fs ext4
+_supported_os Linux
+_require_scratch
+_require_test_program "t_get_file_time"
+
+echo "Silence is golden"
+
+echo "Test timestamps with 256 inode size one device $SCRATCH_DEV" >$seqres.full
+_scratch_mkfs -t ext3 -I 256 >> $seqres.full 2>&1
+_scratch_mount
+
+# Create file
+touch "${SCRATCH_MNT}/tmp_file"
+sleep 1
+
+# Change atime, ctime and mtime of the file
+touch "${SCRATCH_MNT}/tmp_file"
+
+cur_time=`date '+%s %N'`
+sec=`echo $cur_time | $AWK_PROG {'print $1'}`
+nsec=`echo $cur_time | $AWK_PROG {'print $2'}`
+
+sec_atime=`$here/src/t_get_file_time $SCRATCH_MNT/tmp_file atime sec`
+sec_mtime=`$here/src/t_get_file_time $SCRATCH_MNT/tmp_file mtime sec`
+sec_ctime=`$here/src/t_get_file_time $SCRATCH_MNT/tmp_file ctime sec`
+nsec_atime=`$here/src/t_get_file_time $SCRATCH_MNT/tmp_file atime nsec`
+nsec_mtime=`$here/src/t_get_file_time $SCRATCH_MNT/tmp_file mtime nsec`
+nsec_ctime=`$here/src/t_get_file_time $SCRATCH_MNT/tmp_file ctime nsec`
+
+# Test nanosecond
+if [ $nsec_atime -eq 0 -a $nsec_mtime -eq 0 -a $nsec_ctime -eq 0 ]; then
+       echo "The timestamp is not nanosecond(nsec_atime: $nsec_atime, \
+nsec_mtime: $nsec_mtime, nsec_ctime: $nsec_ctime, cur_time[ns]: $nsec)"
+fi
+
+# Check difference between file time and current time
+_within_tolerance "sec_atime" $sec_atime $sec 1
+_within_tolerance "sec_mtime" $sec_mtime $sec 1
+_within_tolerance "sec_ctime" $sec_ctime $sec 1
+
+_scratch_unmount >> $seqres.full 2>&1
+
+# Test mount to ext3 then mount back to ext4 and check timestamp again
+_mount -t ext3 `_scratch_mount_options $*` || _fail "ext3 mount failed"
+_scratch_unmount >> $seqres.full 2>&1
+_scratch_mount
+
+nsec_atime2=`$here/src/t_get_file_time $SCRATCH_MNT/tmp_file atime nsec`
+nsec_mtime2=`$here/src/t_get_file_time $SCRATCH_MNT/tmp_file mtime nsec`
+nsec_ctime2=`$here/src/t_get_file_time $SCRATCH_MNT/tmp_file ctime nsec`
+
+[ $nsec_atime -ne $nsec_atime2 ] && echo "File nanosecond timestamp atime has changed unexpected from $nsec_atime to $nsec_atime2"
+[ $nsec_mtime -ne $nsec_mtime2 ] && echo "File nanosecond timestamp mtime has changed unexpected from $nsec_mtime to $nsec_mtime2"
+[ $nsec_ctime -ne $nsec_ctime2 ] && echo "File nanosecond timestamp ctime has changed unexpected from $nsec_ctime to $nsec_ctime2"
+
+status=0
+exit
diff --git a/tests/ext4/044.out b/tests/ext4/044.out
new file mode 100644 (file)
index 0000000..12a61dc
--- /dev/null
@@ -0,0 +1,2 @@
+QA output created by 044
+Silence is golden
diff --git a/tests/ext4/045 b/tests/ext4/045
new file mode 100755 (executable)
index 0000000..068f82d
--- /dev/null
@@ -0,0 +1,111 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2020 SUSE Linux Products GmbH.  All Rights Reserved.
+#
+# FS QA Test No. 045
+#
+# Test subdirectory limit of ext4.
+# We create more than 65000 subdirectories on the ext4 filesystem.
+#
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1       # failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+SHORT_DIR=1
+LONG_DIR=2
+
+_cleanup()
+{
+       cd /
+       rm -f $tmp.*
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+
+# remove previous $seqres.full before test
+rm -f $seqres.full
+
+# real QA test starts here
+_supported_fs ext4
+_supported_os Linux
+
+_require_scratch
+_require_test_program "t_create_short_dirs"
+_require_test_program "t_create_long_dirs"
+_require_dumpe2fs "$DUMPE2FS_PROG" dumpe2fs
+
+echo "Silence is golden"
+
+# Run a test case
+# $1: Number of directories to create
+# $2: create short dir or long dir
+# $3: parent directory
+workout()
+{
+       local dir_name_len=""
+       if [ $2 -eq $SHORT_DIR ]; then
+               dir_name_len="short name"
+       else
+               dir_name_len="long name"
+       fi
+
+       echo "Num of dirs to create: $1, Dir name len: $dir_name_len, " \
+               "Parent dir: $3" >> $seqres.full
+
+       _scratch_mkfs "-O extent,dir_nlink,dir_index -I 256" >> $seqres.full 2>&1
+       _scratch_mount
+
+       # create directories
+       mkdir -p $3 2> /dev/null
+
+       if [ $2 -eq $SHORT_DIR ]; then
+               $here/src/t_create_short_dirs $1 $3
+       else
+               $here/src/t_create_long_dirs $1 $3
+       fi
+
+       if [ $? -ne 0 ]; then
+               nr_dirs=`ls $3 | wc -l`
+               echo "Failed to create directories - $nr_dirs"
+               _scratch_unmount
+               return
+       fi
+
+       # delete directories
+       cd $3
+       ls | xargs rmdir
+       if [ $? -ne 0 ]; then
+               echo "Failed to remove directories in $3"
+               cd - > /dev/null
+               _scratch_unmount
+               return
+       fi
+       cd - > /dev/null
+       _scratch_unmount
+
+       # check dir_nlink is set
+       $DUMPE2FS_PROG -h $SCRATCH_DEV 2>> $seqres.full | grep '^Filesystem features' | grep -q dir_nlink
+       if [ $? -ne 0 ]; then
+               echo "Feature dir_nlink is not set, please check $seqres.full for detail"
+               return
+       fi
+}
+
+# main
+DIR_NUM=65537
+DIR_LEN=( $SHORT_DIR $LONG_DIR )
+PARENT_DIR="$SCRATCH_MNT/subdir"
+
+for ((i = 0; i < 2; i++)); do
+       workout $DIR_NUM ${DIR_LEN[$i]} $PARENT_DIR
+done
+
+status=0
+exit
diff --git a/tests/ext4/045.out b/tests/ext4/045.out
new file mode 100644 (file)
index 0000000..66276cf
--- /dev/null
@@ -0,0 +1,2 @@
+QA output created by 045
+Silence is golden
index 62483c3..a1adc55 100644 (file)
@@ -44,6 +44,9 @@
 040 dangerous_fuzzers
 041 dangerous_fuzzers
 042 auto quick
+043 auto quick
+044 auto quick
+045 auto dir
 271 auto rw quick
 301 aio auto ioctl rw stress defrag
 302 aio auto ioctl rw stress defrag