[v2] fstests: transport two ext4 tests from LTP
diff mbox series

Message ID CAAPJbvqksutxzznPO1T5Z_pQA-=SuKHLuzp_TOyJu7s3W2tL=Q@mail.gmail.com
State New
Headers show
Series
  • [v2] fstests: transport two ext4 tests from LTP
Related show

Commit Message

Sun Yong Nov. 4, 2019, 7:30 a.m. UTC
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>
---
v2: Correct copyright information
---

Comments

Eryu Guan Nov. 10, 2019, 1:17 p.m. UTC | #1
On Mon, Nov 04, 2019 at 03:30:55PM +0800, Sun Yong wrote:
> 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>
> ---
> v2: Correct copyright information
> ---
> diff --git a/src/Makefile b/src/Makefile
> index ce6d8610..387293d1 100644
> --- a/src/Makefile
> +++ b/src/Makefile
> @@ -16,7 +16,8 @@ TARGETS = dirstress fill fill2 getpagesize holes lstat64 \
>      holetest t_truncate_self t_mmap_dio af_unix t_mmap_stale_pmd \
>      t_mmap_cow_race t_mmap_fallocate fsync-err t_mmap_write_ro \
>      t_ext4_dax_journal_corruption t_ext4_dax_inline_corruption \
> -    t_ofd_locks t_locks_execve t_mmap_collision mmap-write-concurrent
> +    t_ofd_locks t_locks_execve t_mmap_collision mmap-write-concurrent \
> +    t_ext4_file_time t_create_short_dirs t_create_long_dirs
> 
>  LINUX_TARGETS = xfsctl bstat t_mtab getdevicesize preallo_rw_pattern_reader \
>      preallo_rw_pattern_writer ftrunc trunc fs_perms testx looptest \
> diff --git a/src/t_create_long_dirs.c b/src/t_create_long_dirs.c
> new file mode 100644
> index 00000000..76a886aa
> --- /dev/null
> +++ b/src/t_create_long_dirs.c
> @@ -0,0 +1,155 @@
> +/******************************************************************************/
> +/*
>         */
> +/* Copyright (c) 2009 FUJITSU LIMITED
>         */
> +/*
>         */

Seems your patch got white-space damaged somehow, would you please check
and re-send?

Thanks,
Eryu

> +/* 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, write to the Free Software
>         */
> +/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> 02110-1301 USA    */
> +/*
>         */
> +/* 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"
> +
> +#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
> index 00000000..c5733b9d
> --- /dev/null
> +++ b/src/t_create_short_dirs.c
> @@ -0,0 +1,158 @@
> +/******************************************************************************/
> +/*
>         */
> +/* Copyright (c) 2009 FUJITSU LIMITED
>         */
> +/*
>         */
> +/* 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, write to the Free Software
>         */
> +/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> 02110-1301 USA    */
> +/*
>         */
> +/* 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"
> +
> +/* valid characters for a directory name */
> +char chars[] =
> "0123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM";
> +
> +/* to store the generated directory name */
> +char name[10];
> +int names;
> +int parent_fd;
> +
> +/* 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)
> +
> +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");
> +        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_ext4_file_time.c b/src/t_ext4_file_time.c
> new file mode 100644
> index 00000000..a10adb3d
> --- /dev/null
> +++ b/src/t_ext4_file_time.c
> @@ -0,0 +1,69 @@
> +/******************************************************************************/
> +/*
>         */
> +/* Copyright (c) 2009 FUJITSU LIMITED
>         */
> +/*
>         */
> +/* 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, write to the Free Software
>         */
> +/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> 02110-1301 USA    */
> +/*
>         */
> +/* 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: 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
> index 00000000..b6e5df9f
> --- /dev/null
> +++ b/tests/ext4/043
> @@ -0,0 +1,64 @@
> +#! /bin/bash
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (c) 2019 SUSE Linux Products GmbH.  All Rights Reserved.
> +#
> +# FS QA Test No. 043
> +#
> +# Transfer from ltp/testcases/kernel/fs/ext4-new-features/ext4_nsec_timestamps
> +# Test file timestamps is second with 128 inode size
> +#
> +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.*
> +    _scratch_cleanup_files
> +}
> +
> +# 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_ext4_file_time"
> +_require_command "$TUNE2FS_PROG" tune2fs
> +
> +echo "Silence is golden"
> +
> +echo "Start test timestamps with 128 inode size one device
> $SCRATCH_DEV" >$seqres.full
> +_scratch_mkfs_ext4 -I 128 >> $seqres.full 2>&1
> +tune2fs -O extents $SCRATCH_DEV >>$seqres.full 2>&1
> +_scratch_mount
> +
> +touch "${SCRATCH_MNT}/tmp_file"
> +
> +atime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file atime nsec`
> +mtime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file mtime nsec`
> +ctime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file ctime nsec`
> +
> +if [ $atime -ne 0 -o $mtime -ne 0 -o $ctime -ne 0 ]; then
> +        echo "Timestamp is not second(atime: $atime, mtime: $mtime,
> ctime: $ctime)" >> $seqres.full
> +        _scratch_unmount >> $seqres.full 2>&1
> +        exit
> +fi
> +echo "Ext4 nanosecond timestamps test with 128 inode size pass" >> $seqres.full
> +_scratch_unmount >> $seqres.full 2>&1
> +
> +# no BUG_ON, all done
> +status=0
> +exit
> diff --git a/tests/ext4/043.out b/tests/ext4/043.out
> new file mode 100644
> index 00000000..f90f0a57
> --- /dev/null
> +++ b/tests/ext4/043.out
> @@ -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
> index 00000000..3e899f5a
> --- /dev/null
> +++ b/tests/ext4/044
> @@ -0,0 +1,112 @@
> +#! /bin/bash
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (c) 2019 SUSE Linux Products GmbH.  All Rights Reserved.
> +#
> +# FS QA Test No. 044
> +#
> +# Transfer from ltp/testcases/kernel/fs/ext4-new-features/ext4_nsec_timestamps
> +# Test file timestamps is nanosecond with 256 inode size
> +#
> +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.*
> +    _scratch_cleanup_files
> +}
> +
> +# 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_ext4_file_time"
> +
> +echo "Silence is golden"
> +
> +echo "Test timestamps with 256 inode size one device $SCRATCH_DEV"
> >$seqres.full
> +_scratch_mkfs_ext4 -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 {'print $1'}`
> +nsec=`echo $cur_time | awk {'print $2'}`
> +
> +sec_atime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file atime sec`
> +sec_mtime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file mtime sec`
> +sec_ctime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file ctime sec`
> +nsec_atime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file atime nsec`
> +nsec_mtime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file mtime nsec`
> +nsec_ctime=`$here/src/t_ext4_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)" >>
> $seqres.full
> +        _scratch_unmount >> $seqres.full 2>&1
> +        exit
> +fi
> +
> +diff1=$(( $sec_atime - $sec ))
> +diff2=$(( $sec_mtime - $sec ))
> +diff3=$(( $sec_ctime - $sec ))
> +
> +# Test difference between file time and current time
> +if [ $diff1 -gt 1 -o $diff2 -gt 1 -o $diff2 -gt 1 ]; then
> +        echo "The timestamp is wrong, it must be earlier than the
> current time we got. \
> +             (sec_atime: $sec_atime, sec_mtime: $sec_mtime,
> sec_ctime: $sec_ctime, \
> +             cur_time[s]: $sec)" >> $seqres.full
> +        _scratch_unmount >> $seqres.full 2>&1
> +        exit
> +fi
> +_scratch_unmount >> $seqres.full 2>&1
> +
> +# Test mount to ext3 and then mount back to ext4
> +mount -t ext3 $SCRATCH_DEV $SCRATCH_MNT
> +if [ $? -ne 0 ]; then
> +        echo "$SCRATCH_DEV fail in mounting to ext3" >> $seqres.full
> +        _scratch_unmount >> $seqres.full 2>&1
> +        exit
> +fi
> +_scratch_unmount >> $seqres.full 2>&1
> +_scratch_mount
> +
> +nsec_atime2=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file atime nsec`
> +nsec_mtime2=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file mtime nsec`
> +nsec_ctime2=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file ctime nsec`
> +
> +if [ $nsec_atime -ne $nsec_atime2 -o $nsec_ctime -ne $nsec_ctime2 -o \
> +     $nsec_mtime -ne $nsec_mtime2 ]; then
> +        echo "File nanosecond timestamp has changed \
> +                        unexpected. Before[atime mtime ctime]: $nsec_atime \
> +                        nsec_mtime $nsec_ctime, After[atime mtime ctime]: \
> +                        $nsec_atime2 $nsec_mtime2 $nsec_ctime2)" >>
> $seqres.full
> +        _scratch_unmount >> $seqres.full 2>&1
> +        exit
> +fi
> +_scratch_unmount >> $seqres.full 2>&1
> +
> +# no BUG_ON, all done
> +status=0
> +exit
> diff --git a/tests/ext4/044.out b/tests/ext4/044.out
> new file mode 100644
> index 00000000..12a61dc4
> --- /dev/null
> +++ b/tests/ext4/044.out
> @@ -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
> index 00000000..c70baa97
> --- /dev/null
> +++ b/tests/ext4/045
> @@ -0,0 +1,148 @@
> +#! /bin/bash
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (c) 2019 SUSE Linux Products GmbH.  All Rights Reserved.
> +#
> +# FS QA Test No. 045
> +#
> +# Transfer from
> ltp/testcases/kernel/fs/ext4-new-features/ext4_subdir_limit_test
> +#
> +# Test subdirectory limit of ext4.
> +# We create more than 32000 subdirectorys 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
> +FAIL=1
> +PASS=0
> +prev_block_size=0
> +prev_result=$FAIL
> +
> +_cleanup()
> +{
> +    cd /
> +    rm -f $tmp.*
> +    _scratch_cleanup_files
> +}
> +
> +# 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_command "$TUNE2FS_PROG" tune2fs
> +_require_command "$E2FSCK_PROG" e2fsck
> +_require_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
> +# $4: filesystem block size
> +_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, Block size: $4" >> $seqres.full 2>&1
> +
> +    # Only mkfs if block size has been changed, or previous case failed
> +    if [ $prev_result -ne $PASS -o $4 -ne $prev_block_size ]; then
> +        $MKFS_EXT4_PROG -F -b $4 -I 256 $SCRATCH_DEV >> $seqres.full 2>&1
> +        prev_block_size=$4
> +        tune2fs -O extents $SCRATCH_DEV >> $seqres.full 2>&1
> +    fi
> +    prev_result=$FAIL
> +
> +    _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 $SCRATCH_DEV 2> /dev/null | 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
> +
> +    # run fsck to make sure the filesystem has no errors
> +    $E2FSCK_PROG -fy $SCRATCH_DEV >> $seqres.full 2>&1
> +    if [ $? -ne 0 ]; then
> +        echo "fsck: the filesystem has errors, please check
> $seqres.full for detail"
> +        return
> +    fi
> +
> +    prev_result=$PASS
> +}
> +
> +# main
> +DIR_LEN=( $SHORT_DIR $LONG_DIR )
> +PARENT_DIR=( "$SCRATCH_MNT" "$SCRATCH_MNT/sub" )
> +BLOCK_SIZE=( 1024 2048 4096 )
> +
> +for ((i = 0; i < 3; i++)); do
> +    for ((j = 0; j < 2; j++)); do
> +        for ((k = 0; k < 2; k++)); do
> +            if [ ${DIR_LEN[$k]} -eq $LONG_DIR -a \
> +                    ${BLOCK_SIZE[$i]} -eq 1024 ]; then
> +                continue
> +            fi
> +            _workout 65537 ${DIR_LEN[$k]} ${PARENT_DIR[$j]} ${BLOCK_SIZE[$i]}
> +        done
> +    done
> +done
> +
> +_scratch_unmount >> $seqres.full 2>&1
> +
> +# no BUG_ON, all done
> +status=0
> +exit
> diff --git a/tests/ext4/045.out b/tests/ext4/045.out
> new file mode 100644
> index 00000000..66276cfa
> --- /dev/null
> +++ b/tests/ext4/045.out
> @@ -0,0 +1,2 @@
> +QA output created by 045
> +Silence is golden
> diff --git a/tests/ext4/group b/tests/ext4/group
> index 9dfc0d35..8419cdea 100644
> --- a/tests/ext4/group
> +++ b/tests/ext4/group
> @@ -45,6 +45,9 @@
>  040 dangerous_fuzzers
>  041 dangerous_fuzzers
>  042 auto quick
> +043 auto quick
> +044 auto quick
> +045 auto
>  271 auto rw quick
>  301 aio auto ioctl rw stress defrag
>  302 aio auto ioctl rw stress defrag
Darrick J. Wong Nov. 26, 2019, 4:06 p.m. UTC | #2
On Mon, Nov 04, 2019 at 03:30:55PM +0800, Sun Yong wrote:
> 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.

Might be a good idea to split these into separate patches...

> [1] https://marc.info/?l=linux-fsdevel&m=157190623919681&w=2
> 
> Signed-off-by: Sun Yong <yosun@suse.com>
> ---
> v2: Correct copyright information
> ---
> diff --git a/src/Makefile b/src/Makefile
> index ce6d8610..387293d1 100644
> --- a/src/Makefile
> +++ b/src/Makefile
> @@ -16,7 +16,8 @@ TARGETS = dirstress fill fill2 getpagesize holes lstat64 \
>      holetest t_truncate_self t_mmap_dio af_unix t_mmap_stale_pmd \
>      t_mmap_cow_race t_mmap_fallocate fsync-err t_mmap_write_ro \
>      t_ext4_dax_journal_corruption t_ext4_dax_inline_corruption \
> -    t_ofd_locks t_locks_execve t_mmap_collision mmap-write-concurrent
> +    t_ofd_locks t_locks_execve t_mmap_collision mmap-write-concurrent \
> +    t_ext4_file_time t_create_short_dirs t_create_long_dirs
> 
>  LINUX_TARGETS = xfsctl bstat t_mtab getdevicesize preallo_rw_pattern_reader \
>      preallo_rw_pattern_writer ftrunc trunc fs_perms testx looptest \
> diff --git a/src/t_create_long_dirs.c b/src/t_create_long_dirs.c
> new file mode 100644
> index 00000000..76a886aa
> --- /dev/null
> +++ b/src/t_create_long_dirs.c
> @@ -0,0 +1,155 @@
> +/******************************************************************************/
> +/*
>         */

Don't wrap, like Eryu asked.

> +/* Copyright (c) 2009 FUJITSU LIMITED
>         */
> +/*
>         */
> +/* 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.

SPDX headers instead of GPL boilerplate, please.

>         */
> +/*
>         */
> +/* 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, write to the Free Software
>         */
> +/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> 02110-1301 USA    */
> +/*
>         */
> +/* 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"
> +
> +#define NAME_LEN    255
> +#define NCHARS        62
> +#define MAX_LEN1    62
> +#define MAX_LEN2    (62 * 62)
> +#define MAX_LEN3    (62 * 62 * 62)

62?

Oh, 26 + 26 + 10.

> +
> +/* 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;
> +            }
> +        }
> +    }
> +}

I would've thought you could just do:

for (i = 0; i < n; i++) {
	snprintf(name, sizeof(name) - 1, "%0*d", depth, n);
	mkdirat(dir, name, ...);
}

instead of this nested loopy thing, since the goal is to end up with a
subdirectory containing somewhere between 1 and 238328 names in it,
right?

Unless there's some speedup that nested looping gets us?

> +
> +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
> index 00000000..c5733b9d
> --- /dev/null
> +++ b/src/t_create_short_dirs.c
> @@ -0,0 +1,158 @@
> +/******************************************************************************/
> +/*
>         */
> +/* Copyright (c) 2009 FUJITSU LIMITED
>         */
> +/*
>         */
> +/* 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, write to the Free Software
>         */
> +/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> 02110-1301 USA    */
> +/*
>         */
> +/* 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"
> +
> +/* valid characters for a directory name */
> +char chars[] =
> "0123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM";
> +
> +/* to store the generated directory name */
> +char name[10];
> +int names;
> +int parent_fd;
> +
> +/* 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)
> +
> +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[])

How does this program differ from the other one?

> +{
> +    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");
> +        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_ext4_file_time.c b/src/t_ext4_file_time.c
> new file mode 100644
> index 00000000..a10adb3d
> --- /dev/null
> +++ b/src/t_ext4_file_time.c
> @@ -0,0 +1,69 @@
> +/******************************************************************************/
> +/*
>         */
> +/* Copyright (c) 2009 FUJITSU LIMITED
>         */
> +/*
>         */
> +/* 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, write to the Free Software
>         */
> +/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> 02110-1301 USA    */
> +/*
>         */
> +/* 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: file_time <filename> <atime|mtime|ctime> <sec|nsec>
> + */
> +int main(int argc, char *argv[])
> +{
> +    time_t t;

Is this program going to fail on 32-bit systems?

> +    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
> index 00000000..b6e5df9f
> --- /dev/null
> +++ b/tests/ext4/043
> @@ -0,0 +1,64 @@
> +#! /bin/bash
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (c) 2019 SUSE Linux Products GmbH.  All Rights Reserved.
> +#
> +# FS QA Test No. 043
> +#
> +# Transfer from ltp/testcases/kernel/fs/ext4-new-features/ext4_nsec_timestamps
> +# Test file timestamps is second with 128 inode size

(Huh?)

OH, "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.*
> +    _scratch_cleanup_files
> +}
> +
> +# 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_ext4_file_time"
> +_require_command "$TUNE2FS_PROG" tune2fs
> +
> +echo "Silence is golden"
> +
> +echo "Start test timestamps with 128 inode size one device
> $SCRATCH_DEV" >$seqres.full
> +_scratch_mkfs_ext4 -I 128 >> $seqres.full 2>&1
> +tune2fs -O extents $SCRATCH_DEV >>$seqres.full 2>&1

$TUNE2FS_PROG

Also, why turn on extents?

> +_scratch_mount
> +
> +touch "${SCRATCH_MNT}/tmp_file"
> +
> +atime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file atime nsec`
> +mtime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file mtime nsec`
> +ctime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file ctime nsec`
> +
> +if [ $atime -ne 0 -o $mtime -ne 0 -o $ctime -ne 0 ]; then
> +        echo "Timestamp is not second(atime: $atime, mtime: $mtime,
> ctime: $ctime)" >> $seqres.full

OH, this test checks for nonzero value in the nsec fields when ext4
doesn't support the extended timestamp fields.

> +        _scratch_unmount >> $seqres.full 2>&1

No need to unmount at the end of the test; fstests will do that for you.
For that matter all you need here is:

if [ $atime -ne 0 .... ]; then
	echo "nsec should be zero when extended timestamps are disabled"
	echo "atime: $atime..."
fi

Without any of the "_scratch_unmount" or "exit".  If we fail the if test
and emit the message, the change in golden output will be sufficient for
fstests to mark the test failed.

> +        exit
> +fi
> +echo "Ext4 nanosecond timestamps test with 128 inode size pass" >> $seqres.full
> +_scratch_unmount >> $seqres.full 2>&1
> +
> +# no BUG_ON, all done

BUG_ON?  What are you talking about?  Is there a fix commit that goes
with this?

Also, if this will crash recent kernels then this should be in the
dangerous group, not auto.

> +status=0
> +exit
> diff --git a/tests/ext4/043.out b/tests/ext4/043.out
> new file mode 100644
> index 00000000..f90f0a57
> --- /dev/null
> +++ b/tests/ext4/043.out
> @@ -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
> index 00000000..3e899f5a
> --- /dev/null
> +++ b/tests/ext4/044
> @@ -0,0 +1,112 @@
> +#! /bin/bash
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (c) 2019 SUSE Linux Products GmbH.  All Rights Reserved.
> +#
> +# FS QA Test No. 044
> +#
> +# Transfer from ltp/testcases/kernel/fs/ext4-new-features/ext4_nsec_timestamps
> +# Test file timestamps is nanosecond with 256 inode size

"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.*
> +    _scratch_cleanup_files

Don't bother erasing the scratch fs files, the next _scratch_mkfs will
do that for you.

> +}
> +
> +# get standard environment, filters and checks
> +. ./common/rc
> +. ./common/filter

I don't think we need filter here...?

> +
> +# 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_ext4_file_time"
> +
> +echo "Silence is golden"
> +
> +echo "Test timestamps with 256 inode size one device $SCRATCH_DEV"
> >$seqres.full
> +_scratch_mkfs_ext4 -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 {'print $1'}`
> +nsec=`echo $cur_time | awk {'print $2'}`
> +
> +sec_atime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file atime sec`
> +sec_mtime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file mtime sec`
> +sec_ctime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file ctime sec`
> +nsec_atime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file atime nsec`
> +nsec_mtime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file mtime nsec`
> +nsec_ctime=`$here/src/t_ext4_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)" >>
> $seqres.full
> +        _scratch_unmount >> $seqres.full 2>&1
> +        exit
> +fi
> +
> +diff1=$(( $sec_atime - $sec ))
> +diff2=$(( $sec_mtime - $sec ))
> +diff3=$(( $sec_ctime - $sec ))
> +
> +# Test difference between file time and current time
> +if [ $diff1 -gt 1 -o $diff2 -gt 1 -o $diff2 -gt 1 ]; then
> +        echo "The timestamp is wrong, it must be earlier than the
> current time we got. \
> +             (sec_atime: $sec_atime, sec_mtime: $sec_mtime,
> sec_ctime: $sec_ctime, \
> +             cur_time[s]: $sec)" >> $seqres.full
> +        _scratch_unmount >> $seqres.full 2>&1
> +        exit
> +fi
> +_scratch_unmount >> $seqres.full 2>&1
> +
> +# Test mount to ext3 and then mount back to ext4
> +mount -t ext3 $SCRATCH_DEV $SCRATCH_MNT

Hm... what /is/ the rule about changing filesystem types?  Do we just
open-code _try_scratch_mount to force ext3 here?

_mount -t ext3 `_scratch_mount_options $*` || _fail "ext3 mount failed"

> +if [ $? -ne 0 ]; then
> +        echo "$SCRATCH_DEV fail in mounting to ext3" >> $seqres.full
> +        _scratch_unmount >> $seqres.full 2>&1
> +        exit
> +fi
> +_scratch_unmount >> $seqres.full 2>&1
> +_scratch_mount
> +
> +nsec_atime2=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file atime nsec`
> +nsec_mtime2=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file mtime nsec`
> +nsec_ctime2=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file ctime nsec`
> +
> +if [ $nsec_atime -ne $nsec_atime2 -o $nsec_ctime -ne $nsec_ctime2 -o \
> +     $nsec_mtime -ne $nsec_mtime2 ]; then
> +        echo "File nanosecond timestamp has changed \
> +                        unexpected. Before[atime mtime ctime]: $nsec_atime \
> +                        nsec_mtime $nsec_ctime, After[atime mtime ctime]: \
> +                        $nsec_atime2 $nsec_mtime2 $nsec_ctime2)" >>
> $seqres.full
> +        _scratch_unmount >> $seqres.full 2>&1
> +        exit

If you really want to bail out early, do it with _fail, i.e.

_fail "File nanosecond timestamp has changed..."

Please consider doing all these checks individually, not in one huge if
statement.

> +fi
> +_scratch_unmount >> $seqres.full 2>&1
> +
> +# no BUG_ON, all done
> +status=0
> +exit
> diff --git a/tests/ext4/044.out b/tests/ext4/044.out
> new file mode 100644
> index 00000000..12a61dc4
> --- /dev/null
> +++ b/tests/ext4/044.out
> @@ -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
> index 00000000..c70baa97
> --- /dev/null
> +++ b/tests/ext4/045
> @@ -0,0 +1,148 @@
> +#! /bin/bash
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (c) 2019 SUSE Linux Products GmbH.  All Rights Reserved.
> +#
> +# FS QA Test No. 045
> +#
> +# Transfer from
> ltp/testcases/kernel/fs/ext4-new-features/ext4_subdir_limit_test
> +#
> +# Test subdirectory limit of ext4.
> +# We create more than 32000 subdirectorys on the ext4 filesystem.

"subdirectories"

> +#
> +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
> +FAIL=1
> +PASS=0
> +prev_block_size=0
> +prev_result=$FAIL
> +
> +_cleanup()
> +{
> +    cd /
> +    rm -f $tmp.*
> +    _scratch_cleanup_files
> +}
> +
> +# 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_command "$TUNE2FS_PROG" tune2fs
> +_require_command "$E2FSCK_PROG" e2fsck
> +_require_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
> +# $4: filesystem block size
> +_workout()

Local functions should not be prefixed with "_"; those are reserved for
common/ library functions.

> +{
> +    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, Block size: $4" >> $seqres.full 2>&1
> +
> +    # Only mkfs if block size has been changed, or previous case failed
> +    if [ $prev_result -ne $PASS -o $4 -ne $prev_block_size ]; then
> +        $MKFS_EXT4_PROG -F -b $4 -I 256 $SCRATCH_DEV >> $seqres.full 2>&1

_scratch_mkfs -b $4 -I 256 ?

> +        prev_block_size=$4
> +        tune2fs -O extents $SCRATCH_DEV >> $seqres.full 2>&1

$TUNE2FS_PROG, do not call tune2fs directly.

Also, why don't you just format the fs with extents turned on in the
first place?

> +    fi
> +    prev_result=$FAIL
> +
> +    _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 $SCRATCH_DEV 2> /dev/null | grep '^Filesystem features'

$DUMPE2FS_PROG

> | grep -q dir_nlink
> +    if [ $? -ne 0 ]; then
> +        echo "Feature dir_nlink is not set, please check $seqres.full
> for detail"
> +        return
> +    fi
> +
> +    # run fsck to make sure the filesystem has no errors
> +    $E2FSCK_PROG -fy $SCRATCH_DEV >> $seqres.full 2>&1
> +    if [ $? -ne 0 ]; then
> +        echo "fsck: the filesystem has errors, please check
> $seqres.full for detail"

_check_scratch_fs?

> +        return
> +    fi
> +
> +    prev_result=$PASS
> +}
> +
> +# main
> +DIR_LEN=( $SHORT_DIR $LONG_DIR )
> +PARENT_DIR=( "$SCRATCH_MNT" "$SCRATCH_MNT/sub" )
> +BLOCK_SIZE=( 1024 2048 4096 )
> +
> +for ((i = 0; i < 3; i++)); do
> +    for ((j = 0; j < 2; j++)); do
> +        for ((k = 0; k < 2; k++)); do
> +            if [ ${DIR_LEN[$k]} -eq $LONG_DIR -a \
> +                    ${BLOCK_SIZE[$i]} -eq 1024 ]; then
> +                continue
> +            fi
> +            _workout 65537 ${DIR_LEN[$k]} ${PARENT_DIR[$j]} ${BLOCK_SIZE[$i]}
> +        done
> +    done
> +done
> +
> +_scratch_unmount >> $seqres.full 2>&1
> +
> +# no BUG_ON, all done
> +status=0
> +exit
> diff --git a/tests/ext4/045.out b/tests/ext4/045.out
> new file mode 100644
> index 00000000..66276cfa
> --- /dev/null
> +++ b/tests/ext4/045.out
> @@ -0,0 +1,2 @@
> +QA output created by 045
> +Silence is golden
> diff --git a/tests/ext4/group b/tests/ext4/group
> index 9dfc0d35..8419cdea 100644
> --- a/tests/ext4/group
> +++ b/tests/ext4/group
> @@ -45,6 +45,9 @@
>  040 dangerous_fuzzers
>  041 dangerous_fuzzers
>  042 auto quick
> +043 auto quick
> +044 auto quick
> +045 auto

"dir" group too?

--D

>  271 auto rw quick
>  301 aio auto ioctl rw stress defrag
>  302 aio auto ioctl rw stress defrag
Sun Yong Nov. 27, 2019, 8:03 a.m. UTC | #3
Hi Darrick, Eryu,

Thank you so much for both of your review and helpful suggestions.
Some days before I had sent a
v4(https://patchwork.kernel.org/patch/11241473/) which solved wrap
issue, but no need to review that version in case there has some issue
to fix. I'll take all suggestions by Darrick in next version, or split
it into separate patches, and let you know when I finished.

Thanks,
Yong

Darrick J. Wong <darrick.wong@oracle.com> 于2019年11月27日周三 上午12:06写道:
>
> On Mon, Nov 04, 2019 at 03:30:55PM +0800, Sun Yong wrote:
> > 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.
>
> Might be a good idea to split these into separate patches...
>
> > [1] https://marc.info/?l=linux-fsdevel&m=157190623919681&w=2
> >
> > Signed-off-by: Sun Yong <yosun@suse.com>
> > ---
> > v2: Correct copyright information
> > ---
> > diff --git a/src/Makefile b/src/Makefile
> > index ce6d8610..387293d1 100644
> > --- a/src/Makefile
> > +++ b/src/Makefile
> > @@ -16,7 +16,8 @@ TARGETS = dirstress fill fill2 getpagesize holes lstat64 \
> >      holetest t_truncate_self t_mmap_dio af_unix t_mmap_stale_pmd \
> >      t_mmap_cow_race t_mmap_fallocate fsync-err t_mmap_write_ro \
> >      t_ext4_dax_journal_corruption t_ext4_dax_inline_corruption \
> > -    t_ofd_locks t_locks_execve t_mmap_collision mmap-write-concurrent
> > +    t_ofd_locks t_locks_execve t_mmap_collision mmap-write-concurrent \
> > +    t_ext4_file_time t_create_short_dirs t_create_long_dirs
> >
> >  LINUX_TARGETS = xfsctl bstat t_mtab getdevicesize preallo_rw_pattern_reader \
> >      preallo_rw_pattern_writer ftrunc trunc fs_perms testx looptest \
> > diff --git a/src/t_create_long_dirs.c b/src/t_create_long_dirs.c
> > new file mode 100644
> > index 00000000..76a886aa
> > --- /dev/null
> > +++ b/src/t_create_long_dirs.c
> > @@ -0,0 +1,155 @@
> > +/******************************************************************************/
> > +/*
> >         */
>
> Don't wrap, like Eryu asked.
>
> > +/* Copyright (c) 2009 FUJITSU LIMITED
> >         */
> > +/*
> >         */
> > +/* 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.
>
> SPDX headers instead of GPL boilerplate, please.
>
> >         */
> > +/*
> >         */
> > +/* 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, write to the Free Software
> >         */
> > +/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> > 02110-1301 USA    */
> > +/*
> >         */
> > +/* 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"
> > +
> > +#define NAME_LEN    255
> > +#define NCHARS        62
> > +#define MAX_LEN1    62
> > +#define MAX_LEN2    (62 * 62)
> > +#define MAX_LEN3    (62 * 62 * 62)
>
> 62?
>
> Oh, 26 + 26 + 10.
>
> > +
> > +/* 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;
> > +            }
> > +        }
> > +    }
> > +}
>
> I would've thought you could just do:
>
> for (i = 0; i < n; i++) {
>         snprintf(name, sizeof(name) - 1, "%0*d", depth, n);
>         mkdirat(dir, name, ...);
> }
>
> instead of this nested loopy thing, since the goal is to end up with a
> subdirectory containing somewhere between 1 and 238328 names in it,
> right?
>
> Unless there's some speedup that nested looping gets us?
>
> > +
> > +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
> > index 00000000..c5733b9d
> > --- /dev/null
> > +++ b/src/t_create_short_dirs.c
> > @@ -0,0 +1,158 @@
> > +/******************************************************************************/
> > +/*
> >         */
> > +/* Copyright (c) 2009 FUJITSU LIMITED
> >         */
> > +/*
> >         */
> > +/* 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, write to the Free Software
> >         */
> > +/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> > 02110-1301 USA    */
> > +/*
> >         */
> > +/* 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"
> > +
> > +/* valid characters for a directory name */
> > +char chars[] =
> > "0123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM";
> > +
> > +/* to store the generated directory name */
> > +char name[10];
> > +int names;
> > +int parent_fd;
> > +
> > +/* 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)
> > +
> > +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[])
>
> How does this program differ from the other one?
>
> > +{
> > +    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");
> > +        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_ext4_file_time.c b/src/t_ext4_file_time.c
> > new file mode 100644
> > index 00000000..a10adb3d
> > --- /dev/null
> > +++ b/src/t_ext4_file_time.c
> > @@ -0,0 +1,69 @@
> > +/******************************************************************************/
> > +/*
> >         */
> > +/* Copyright (c) 2009 FUJITSU LIMITED
> >         */
> > +/*
> >         */
> > +/* 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, write to the Free Software
> >         */
> > +/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> > 02110-1301 USA    */
> > +/*
> >         */
> > +/* 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: file_time <filename> <atime|mtime|ctime> <sec|nsec>
> > + */
> > +int main(int argc, char *argv[])
> > +{
> > +    time_t t;
>
> Is this program going to fail on 32-bit systems?
>
> > +    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
> > index 00000000..b6e5df9f
> > --- /dev/null
> > +++ b/tests/ext4/043
> > @@ -0,0 +1,64 @@
> > +#! /bin/bash
> > +# SPDX-License-Identifier: GPL-2.0
> > +# Copyright (c) 2019 SUSE Linux Products GmbH.  All Rights Reserved.
> > +#
> > +# FS QA Test No. 043
> > +#
> > +# Transfer from ltp/testcases/kernel/fs/ext4-new-features/ext4_nsec_timestamps
> > +# Test file timestamps is second with 128 inode size
>
> (Huh?)
>
> OH, "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.*
> > +    _scratch_cleanup_files
> > +}
> > +
> > +# 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_ext4_file_time"
> > +_require_command "$TUNE2FS_PROG" tune2fs
> > +
> > +echo "Silence is golden"
> > +
> > +echo "Start test timestamps with 128 inode size one device
> > $SCRATCH_DEV" >$seqres.full
> > +_scratch_mkfs_ext4 -I 128 >> $seqres.full 2>&1
> > +tune2fs -O extents $SCRATCH_DEV >>$seqres.full 2>&1
>
> $TUNE2FS_PROG
>
> Also, why turn on extents?
>
> > +_scratch_mount
> > +
> > +touch "${SCRATCH_MNT}/tmp_file"
> > +
> > +atime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file atime nsec`
> > +mtime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file mtime nsec`
> > +ctime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file ctime nsec`
> > +
> > +if [ $atime -ne 0 -o $mtime -ne 0 -o $ctime -ne 0 ]; then
> > +        echo "Timestamp is not second(atime: $atime, mtime: $mtime,
> > ctime: $ctime)" >> $seqres.full
>
> OH, this test checks for nonzero value in the nsec fields when ext4
> doesn't support the extended timestamp fields.
>
> > +        _scratch_unmount >> $seqres.full 2>&1
>
> No need to unmount at the end of the test; fstests will do that for you.
> For that matter all you need here is:
>
> if [ $atime -ne 0 .... ]; then
>         echo "nsec should be zero when extended timestamps are disabled"
>         echo "atime: $atime..."
> fi
>
> Without any of the "_scratch_unmount" or "exit".  If we fail the if test
> and emit the message, the change in golden output will be sufficient for
> fstests to mark the test failed.
>
> > +        exit
> > +fi
> > +echo "Ext4 nanosecond timestamps test with 128 inode size pass" >> $seqres.full
> > +_scratch_unmount >> $seqres.full 2>&1
> > +
> > +# no BUG_ON, all done
>
> BUG_ON?  What are you talking about?  Is there a fix commit that goes
> with this?
>
> Also, if this will crash recent kernels then this should be in the
> dangerous group, not auto.
>
> > +status=0
> > +exit
> > diff --git a/tests/ext4/043.out b/tests/ext4/043.out
> > new file mode 100644
> > index 00000000..f90f0a57
> > --- /dev/null
> > +++ b/tests/ext4/043.out
> > @@ -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
> > index 00000000..3e899f5a
> > --- /dev/null
> > +++ b/tests/ext4/044
> > @@ -0,0 +1,112 @@
> > +#! /bin/bash
> > +# SPDX-License-Identifier: GPL-2.0
> > +# Copyright (c) 2019 SUSE Linux Products GmbH.  All Rights Reserved.
> > +#
> > +# FS QA Test No. 044
> > +#
> > +# Transfer from ltp/testcases/kernel/fs/ext4-new-features/ext4_nsec_timestamps
> > +# Test file timestamps is nanosecond with 256 inode size
>
> "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.*
> > +    _scratch_cleanup_files
>
> Don't bother erasing the scratch fs files, the next _scratch_mkfs will
> do that for you.
>
> > +}
> > +
> > +# get standard environment, filters and checks
> > +. ./common/rc
> > +. ./common/filter
>
> I don't think we need filter here...?
>
> > +
> > +# 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_ext4_file_time"
> > +
> > +echo "Silence is golden"
> > +
> > +echo "Test timestamps with 256 inode size one device $SCRATCH_DEV"
> > >$seqres.full
> > +_scratch_mkfs_ext4 -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 {'print $1'}`
> > +nsec=`echo $cur_time | awk {'print $2'}`
> > +
> > +sec_atime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file atime sec`
> > +sec_mtime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file mtime sec`
> > +sec_ctime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file ctime sec`
> > +nsec_atime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file atime nsec`
> > +nsec_mtime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file mtime nsec`
> > +nsec_ctime=`$here/src/t_ext4_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)" >>
> > $seqres.full
> > +        _scratch_unmount >> $seqres.full 2>&1
> > +        exit
> > +fi
> > +
> > +diff1=$(( $sec_atime - $sec ))
> > +diff2=$(( $sec_mtime - $sec ))
> > +diff3=$(( $sec_ctime - $sec ))
> > +
> > +# Test difference between file time and current time
> > +if [ $diff1 -gt 1 -o $diff2 -gt 1 -o $diff2 -gt 1 ]; then
> > +        echo "The timestamp is wrong, it must be earlier than the
> > current time we got. \
> > +             (sec_atime: $sec_atime, sec_mtime: $sec_mtime,
> > sec_ctime: $sec_ctime, \
> > +             cur_time[s]: $sec)" >> $seqres.full
> > +        _scratch_unmount >> $seqres.full 2>&1
> > +        exit
> > +fi
> > +_scratch_unmount >> $seqres.full 2>&1
> > +
> > +# Test mount to ext3 and then mount back to ext4
> > +mount -t ext3 $SCRATCH_DEV $SCRATCH_MNT
>
> Hm... what /is/ the rule about changing filesystem types?  Do we just
> open-code _try_scratch_mount to force ext3 here?
>
> _mount -t ext3 `_scratch_mount_options $*` || _fail "ext3 mount failed"
>
> > +if [ $? -ne 0 ]; then
> > +        echo "$SCRATCH_DEV fail in mounting to ext3" >> $seqres.full
> > +        _scratch_unmount >> $seqres.full 2>&1
> > +        exit
> > +fi
> > +_scratch_unmount >> $seqres.full 2>&1
> > +_scratch_mount
> > +
> > +nsec_atime2=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file atime nsec`
> > +nsec_mtime2=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file mtime nsec`
> > +nsec_ctime2=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file ctime nsec`
> > +
> > +if [ $nsec_atime -ne $nsec_atime2 -o $nsec_ctime -ne $nsec_ctime2 -o \
> > +     $nsec_mtime -ne $nsec_mtime2 ]; then
> > +        echo "File nanosecond timestamp has changed \
> > +                        unexpected. Before[atime mtime ctime]: $nsec_atime \
> > +                        nsec_mtime $nsec_ctime, After[atime mtime ctime]: \
> > +                        $nsec_atime2 $nsec_mtime2 $nsec_ctime2)" >>
> > $seqres.full
> > +        _scratch_unmount >> $seqres.full 2>&1
> > +        exit
>
> If you really want to bail out early, do it with _fail, i.e.
>
> _fail "File nanosecond timestamp has changed..."
>
> Please consider doing all these checks individually, not in one huge if
> statement.
>
> > +fi
> > +_scratch_unmount >> $seqres.full 2>&1
> > +
> > +# no BUG_ON, all done
> > +status=0
> > +exit
> > diff --git a/tests/ext4/044.out b/tests/ext4/044.out
> > new file mode 100644
> > index 00000000..12a61dc4
> > --- /dev/null
> > +++ b/tests/ext4/044.out
> > @@ -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
> > index 00000000..c70baa97
> > --- /dev/null
> > +++ b/tests/ext4/045
> > @@ -0,0 +1,148 @@
> > +#! /bin/bash
> > +# SPDX-License-Identifier: GPL-2.0
> > +# Copyright (c) 2019 SUSE Linux Products GmbH.  All Rights Reserved.
> > +#
> > +# FS QA Test No. 045
> > +#
> > +# Transfer from
> > ltp/testcases/kernel/fs/ext4-new-features/ext4_subdir_limit_test
> > +#
> > +# Test subdirectory limit of ext4.
> > +# We create more than 32000 subdirectorys on the ext4 filesystem.
>
> "subdirectories"
>
> > +#
> > +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
> > +FAIL=1
> > +PASS=0
> > +prev_block_size=0
> > +prev_result=$FAIL
> > +
> > +_cleanup()
> > +{
> > +    cd /
> > +    rm -f $tmp.*
> > +    _scratch_cleanup_files
> > +}
> > +
> > +# 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_command "$TUNE2FS_PROG" tune2fs
> > +_require_command "$E2FSCK_PROG" e2fsck
> > +_require_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
> > +# $4: filesystem block size
> > +_workout()
>
> Local functions should not be prefixed with "_"; those are reserved for
> common/ library functions.
>
> > +{
> > +    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, Block size: $4" >> $seqres.full 2>&1
> > +
> > +    # Only mkfs if block size has been changed, or previous case failed
> > +    if [ $prev_result -ne $PASS -o $4 -ne $prev_block_size ]; then
> > +        $MKFS_EXT4_PROG -F -b $4 -I 256 $SCRATCH_DEV >> $seqres.full 2>&1
>
> _scratch_mkfs -b $4 -I 256 ?
>
> > +        prev_block_size=$4
> > +        tune2fs -O extents $SCRATCH_DEV >> $seqres.full 2>&1
>
> $TUNE2FS_PROG, do not call tune2fs directly.
>
> Also, why don't you just format the fs with extents turned on in the
> first place?
>
> > +    fi
> > +    prev_result=$FAIL
> > +
> > +    _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 $SCRATCH_DEV 2> /dev/null | grep '^Filesystem features'
>
> $DUMPE2FS_PROG
>
> > | grep -q dir_nlink
> > +    if [ $? -ne 0 ]; then
> > +        echo "Feature dir_nlink is not set, please check $seqres.full
> > for detail"
> > +        return
> > +    fi
> > +
> > +    # run fsck to make sure the filesystem has no errors
> > +    $E2FSCK_PROG -fy $SCRATCH_DEV >> $seqres.full 2>&1
> > +    if [ $? -ne 0 ]; then
> > +        echo "fsck: the filesystem has errors, please check
> > $seqres.full for detail"
>
> _check_scratch_fs?
>
> > +        return
> > +    fi
> > +
> > +    prev_result=$PASS
> > +}
> > +
> > +# main
> > +DIR_LEN=( $SHORT_DIR $LONG_DIR )
> > +PARENT_DIR=( "$SCRATCH_MNT" "$SCRATCH_MNT/sub" )
> > +BLOCK_SIZE=( 1024 2048 4096 )
> > +
> > +for ((i = 0; i < 3; i++)); do
> > +    for ((j = 0; j < 2; j++)); do
> > +        for ((k = 0; k < 2; k++)); do
> > +            if [ ${DIR_LEN[$k]} -eq $LONG_DIR -a \
> > +                    ${BLOCK_SIZE[$i]} -eq 1024 ]; then
> > +                continue
> > +            fi
> > +            _workout 65537 ${DIR_LEN[$k]} ${PARENT_DIR[$j]} ${BLOCK_SIZE[$i]}
> > +        done
> > +    done
> > +done
> > +
> > +_scratch_unmount >> $seqres.full 2>&1
> > +
> > +# no BUG_ON, all done
> > +status=0
> > +exit
> > diff --git a/tests/ext4/045.out b/tests/ext4/045.out
> > new file mode 100644
> > index 00000000..66276cfa
> > --- /dev/null
> > +++ b/tests/ext4/045.out
> > @@ -0,0 +1,2 @@
> > +QA output created by 045
> > +Silence is golden
> > diff --git a/tests/ext4/group b/tests/ext4/group
> > index 9dfc0d35..8419cdea 100644
> > --- a/tests/ext4/group
> > +++ b/tests/ext4/group
> > @@ -45,6 +45,9 @@
> >  040 dangerous_fuzzers
> >  041 dangerous_fuzzers
> >  042 auto quick
> > +043 auto quick
> > +044 auto quick
> > +045 auto
>
> "dir" group too?
>
> --D
>
> >  271 auto rw quick
> >  301 aio auto ioctl rw stress defrag
> >  302 aio auto ioctl rw stress defrag
Darrick J. Wong Nov. 27, 2019, 4:11 p.m. UTC | #4
On Wed, Nov 27, 2019 at 04:03:45PM +0800, Sun Yong wrote:
> Hi Darrick, Eryu,
> 
> Thank you so much for both of your review and helpful suggestions.
> Some days before I had sent a
> v4(https://patchwork.kernel.org/patch/11241473/) which solved wrap
> issue, but no need to review that version in case there has some issue
> to fix. I'll take all suggestions by Darrick in next version, or split
> it into separate patches, and let you know when I finished.

Oh, silly me, I didn't see the v3 and v4 attached to the v1 submission
thread; I saw (in mutt threaded mode fwiw) that the v2 patch was the
newest thread.

When you send v5, could you please start it as a new thread?

--D

> Thanks,
> Yong
> 
> Darrick J. Wong <darrick.wong@oracle.com> 于2019年11月27日周三 上午12:06写道:
> >
> > On Mon, Nov 04, 2019 at 03:30:55PM +0800, Sun Yong wrote:
> > > 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.
> >
> > Might be a good idea to split these into separate patches...
> >
> > > [1] https://marc.info/?l=linux-fsdevel&m=157190623919681&w=2
> > >
> > > Signed-off-by: Sun Yong <yosun@suse.com>
> > > ---
> > > v2: Correct copyright information
> > > ---
> > > diff --git a/src/Makefile b/src/Makefile
> > > index ce6d8610..387293d1 100644
> > > --- a/src/Makefile
> > > +++ b/src/Makefile
> > > @@ -16,7 +16,8 @@ TARGETS = dirstress fill fill2 getpagesize holes lstat64 \
> > >      holetest t_truncate_self t_mmap_dio af_unix t_mmap_stale_pmd \
> > >      t_mmap_cow_race t_mmap_fallocate fsync-err t_mmap_write_ro \
> > >      t_ext4_dax_journal_corruption t_ext4_dax_inline_corruption \
> > > -    t_ofd_locks t_locks_execve t_mmap_collision mmap-write-concurrent
> > > +    t_ofd_locks t_locks_execve t_mmap_collision mmap-write-concurrent \
> > > +    t_ext4_file_time t_create_short_dirs t_create_long_dirs
> > >
> > >  LINUX_TARGETS = xfsctl bstat t_mtab getdevicesize preallo_rw_pattern_reader \
> > >      preallo_rw_pattern_writer ftrunc trunc fs_perms testx looptest \
> > > diff --git a/src/t_create_long_dirs.c b/src/t_create_long_dirs.c
> > > new file mode 100644
> > > index 00000000..76a886aa
> > > --- /dev/null
> > > +++ b/src/t_create_long_dirs.c
> > > @@ -0,0 +1,155 @@
> > > +/******************************************************************************/
> > > +/*
> > >         */
> >
> > Don't wrap, like Eryu asked.
> >
> > > +/* Copyright (c) 2009 FUJITSU LIMITED
> > >         */
> > > +/*
> > >         */
> > > +/* 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.
> >
> > SPDX headers instead of GPL boilerplate, please.
> >
> > >         */
> > > +/*
> > >         */
> > > +/* 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, write to the Free Software
> > >         */
> > > +/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> > > 02110-1301 USA    */
> > > +/*
> > >         */
> > > +/* 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"
> > > +
> > > +#define NAME_LEN    255
> > > +#define NCHARS        62
> > > +#define MAX_LEN1    62
> > > +#define MAX_LEN2    (62 * 62)
> > > +#define MAX_LEN3    (62 * 62 * 62)
> >
> > 62?
> >
> > Oh, 26 + 26 + 10.
> >
> > > +
> > > +/* 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;
> > > +            }
> > > +        }
> > > +    }
> > > +}
> >
> > I would've thought you could just do:
> >
> > for (i = 0; i < n; i++) {
> >         snprintf(name, sizeof(name) - 1, "%0*d", depth, n);
> >         mkdirat(dir, name, ...);
> > }
> >
> > instead of this nested loopy thing, since the goal is to end up with a
> > subdirectory containing somewhere between 1 and 238328 names in it,
> > right?
> >
> > Unless there's some speedup that nested looping gets us?
> >
> > > +
> > > +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
> > > index 00000000..c5733b9d
> > > --- /dev/null
> > > +++ b/src/t_create_short_dirs.c
> > > @@ -0,0 +1,158 @@
> > > +/******************************************************************************/
> > > +/*
> > >         */
> > > +/* Copyright (c) 2009 FUJITSU LIMITED
> > >         */
> > > +/*
> > >         */
> > > +/* 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, write to the Free Software
> > >         */
> > > +/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> > > 02110-1301 USA    */
> > > +/*
> > >         */
> > > +/* 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"
> > > +
> > > +/* valid characters for a directory name */
> > > +char chars[] =
> > > "0123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM";
> > > +
> > > +/* to store the generated directory name */
> > > +char name[10];
> > > +int names;
> > > +int parent_fd;
> > > +
> > > +/* 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)
> > > +
> > > +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[])
> >
> > How does this program differ from the other one?
> >
> > > +{
> > > +    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");
> > > +        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_ext4_file_time.c b/src/t_ext4_file_time.c
> > > new file mode 100644
> > > index 00000000..a10adb3d
> > > --- /dev/null
> > > +++ b/src/t_ext4_file_time.c
> > > @@ -0,0 +1,69 @@
> > > +/******************************************************************************/
> > > +/*
> > >         */
> > > +/* Copyright (c) 2009 FUJITSU LIMITED
> > >         */
> > > +/*
> > >         */
> > > +/* 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, write to the Free Software
> > >         */
> > > +/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> > > 02110-1301 USA    */
> > > +/*
> > >         */
> > > +/* 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: file_time <filename> <atime|mtime|ctime> <sec|nsec>
> > > + */
> > > +int main(int argc, char *argv[])
> > > +{
> > > +    time_t t;
> >
> > Is this program going to fail on 32-bit systems?
> >
> > > +    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
> > > index 00000000..b6e5df9f
> > > --- /dev/null
> > > +++ b/tests/ext4/043
> > > @@ -0,0 +1,64 @@
> > > +#! /bin/bash
> > > +# SPDX-License-Identifier: GPL-2.0
> > > +# Copyright (c) 2019 SUSE Linux Products GmbH.  All Rights Reserved.
> > > +#
> > > +# FS QA Test No. 043
> > > +#
> > > +# Transfer from ltp/testcases/kernel/fs/ext4-new-features/ext4_nsec_timestamps
> > > +# Test file timestamps is second with 128 inode size
> >
> > (Huh?)
> >
> > OH, "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.*
> > > +    _scratch_cleanup_files
> > > +}
> > > +
> > > +# 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_ext4_file_time"
> > > +_require_command "$TUNE2FS_PROG" tune2fs
> > > +
> > > +echo "Silence is golden"
> > > +
> > > +echo "Start test timestamps with 128 inode size one device
> > > $SCRATCH_DEV" >$seqres.full
> > > +_scratch_mkfs_ext4 -I 128 >> $seqres.full 2>&1
> > > +tune2fs -O extents $SCRATCH_DEV >>$seqres.full 2>&1
> >
> > $TUNE2FS_PROG
> >
> > Also, why turn on extents?
> >
> > > +_scratch_mount
> > > +
> > > +touch "${SCRATCH_MNT}/tmp_file"
> > > +
> > > +atime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file atime nsec`
> > > +mtime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file mtime nsec`
> > > +ctime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file ctime nsec`
> > > +
> > > +if [ $atime -ne 0 -o $mtime -ne 0 -o $ctime -ne 0 ]; then
> > > +        echo "Timestamp is not second(atime: $atime, mtime: $mtime,
> > > ctime: $ctime)" >> $seqres.full
> >
> > OH, this test checks for nonzero value in the nsec fields when ext4
> > doesn't support the extended timestamp fields.
> >
> > > +        _scratch_unmount >> $seqres.full 2>&1
> >
> > No need to unmount at the end of the test; fstests will do that for you.
> > For that matter all you need here is:
> >
> > if [ $atime -ne 0 .... ]; then
> >         echo "nsec should be zero when extended timestamps are disabled"
> >         echo "atime: $atime..."
> > fi
> >
> > Without any of the "_scratch_unmount" or "exit".  If we fail the if test
> > and emit the message, the change in golden output will be sufficient for
> > fstests to mark the test failed.
> >
> > > +        exit
> > > +fi
> > > +echo "Ext4 nanosecond timestamps test with 128 inode size pass" >> $seqres.full
> > > +_scratch_unmount >> $seqres.full 2>&1
> > > +
> > > +# no BUG_ON, all done
> >
> > BUG_ON?  What are you talking about?  Is there a fix commit that goes
> > with this?
> >
> > Also, if this will crash recent kernels then this should be in the
> > dangerous group, not auto.
> >
> > > +status=0
> > > +exit
> > > diff --git a/tests/ext4/043.out b/tests/ext4/043.out
> > > new file mode 100644
> > > index 00000000..f90f0a57
> > > --- /dev/null
> > > +++ b/tests/ext4/043.out
> > > @@ -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
> > > index 00000000..3e899f5a
> > > --- /dev/null
> > > +++ b/tests/ext4/044
> > > @@ -0,0 +1,112 @@
> > > +#! /bin/bash
> > > +# SPDX-License-Identifier: GPL-2.0
> > > +# Copyright (c) 2019 SUSE Linux Products GmbH.  All Rights Reserved.
> > > +#
> > > +# FS QA Test No. 044
> > > +#
> > > +# Transfer from ltp/testcases/kernel/fs/ext4-new-features/ext4_nsec_timestamps
> > > +# Test file timestamps is nanosecond with 256 inode size
> >
> > "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.*
> > > +    _scratch_cleanup_files
> >
> > Don't bother erasing the scratch fs files, the next _scratch_mkfs will
> > do that for you.
> >
> > > +}
> > > +
> > > +# get standard environment, filters and checks
> > > +. ./common/rc
> > > +. ./common/filter
> >
> > I don't think we need filter here...?
> >
> > > +
> > > +# 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_ext4_file_time"
> > > +
> > > +echo "Silence is golden"
> > > +
> > > +echo "Test timestamps with 256 inode size one device $SCRATCH_DEV"
> > > >$seqres.full
> > > +_scratch_mkfs_ext4 -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 {'print $1'}`
> > > +nsec=`echo $cur_time | awk {'print $2'}`
> > > +
> > > +sec_atime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file atime sec`
> > > +sec_mtime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file mtime sec`
> > > +sec_ctime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file ctime sec`
> > > +nsec_atime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file atime nsec`
> > > +nsec_mtime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file mtime nsec`
> > > +nsec_ctime=`$here/src/t_ext4_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)" >>
> > > $seqres.full
> > > +        _scratch_unmount >> $seqres.full 2>&1
> > > +        exit
> > > +fi
> > > +
> > > +diff1=$(( $sec_atime - $sec ))
> > > +diff2=$(( $sec_mtime - $sec ))
> > > +diff3=$(( $sec_ctime - $sec ))
> > > +
> > > +# Test difference between file time and current time
> > > +if [ $diff1 -gt 1 -o $diff2 -gt 1 -o $diff2 -gt 1 ]; then
> > > +        echo "The timestamp is wrong, it must be earlier than the
> > > current time we got. \
> > > +             (sec_atime: $sec_atime, sec_mtime: $sec_mtime,
> > > sec_ctime: $sec_ctime, \
> > > +             cur_time[s]: $sec)" >> $seqres.full
> > > +        _scratch_unmount >> $seqres.full 2>&1
> > > +        exit
> > > +fi
> > > +_scratch_unmount >> $seqres.full 2>&1
> > > +
> > > +# Test mount to ext3 and then mount back to ext4
> > > +mount -t ext3 $SCRATCH_DEV $SCRATCH_MNT
> >
> > Hm... what /is/ the rule about changing filesystem types?  Do we just
> > open-code _try_scratch_mount to force ext3 here?
> >
> > _mount -t ext3 `_scratch_mount_options $*` || _fail "ext3 mount failed"
> >
> > > +if [ $? -ne 0 ]; then
> > > +        echo "$SCRATCH_DEV fail in mounting to ext3" >> $seqres.full
> > > +        _scratch_unmount >> $seqres.full 2>&1
> > > +        exit
> > > +fi
> > > +_scratch_unmount >> $seqres.full 2>&1
> > > +_scratch_mount
> > > +
> > > +nsec_atime2=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file atime nsec`
> > > +nsec_mtime2=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file mtime nsec`
> > > +nsec_ctime2=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file ctime nsec`
> > > +
> > > +if [ $nsec_atime -ne $nsec_atime2 -o $nsec_ctime -ne $nsec_ctime2 -o \
> > > +     $nsec_mtime -ne $nsec_mtime2 ]; then
> > > +        echo "File nanosecond timestamp has changed \
> > > +                        unexpected. Before[atime mtime ctime]: $nsec_atime \
> > > +                        nsec_mtime $nsec_ctime, After[atime mtime ctime]: \
> > > +                        $nsec_atime2 $nsec_mtime2 $nsec_ctime2)" >>
> > > $seqres.full
> > > +        _scratch_unmount >> $seqres.full 2>&1
> > > +        exit
> >
> > If you really want to bail out early, do it with _fail, i.e.
> >
> > _fail "File nanosecond timestamp has changed..."
> >
> > Please consider doing all these checks individually, not in one huge if
> > statement.
> >
> > > +fi
> > > +_scratch_unmount >> $seqres.full 2>&1
> > > +
> > > +# no BUG_ON, all done
> > > +status=0
> > > +exit
> > > diff --git a/tests/ext4/044.out b/tests/ext4/044.out
> > > new file mode 100644
> > > index 00000000..12a61dc4
> > > --- /dev/null
> > > +++ b/tests/ext4/044.out
> > > @@ -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
> > > index 00000000..c70baa97
> > > --- /dev/null
> > > +++ b/tests/ext4/045
> > > @@ -0,0 +1,148 @@
> > > +#! /bin/bash
> > > +# SPDX-License-Identifier: GPL-2.0
> > > +# Copyright (c) 2019 SUSE Linux Products GmbH.  All Rights Reserved.
> > > +#
> > > +# FS QA Test No. 045
> > > +#
> > > +# Transfer from
> > > ltp/testcases/kernel/fs/ext4-new-features/ext4_subdir_limit_test
> > > +#
> > > +# Test subdirectory limit of ext4.
> > > +# We create more than 32000 subdirectorys on the ext4 filesystem.
> >
> > "subdirectories"
> >
> > > +#
> > > +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
> > > +FAIL=1
> > > +PASS=0
> > > +prev_block_size=0
> > > +prev_result=$FAIL
> > > +
> > > +_cleanup()
> > > +{
> > > +    cd /
> > > +    rm -f $tmp.*
> > > +    _scratch_cleanup_files
> > > +}
> > > +
> > > +# 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_command "$TUNE2FS_PROG" tune2fs
> > > +_require_command "$E2FSCK_PROG" e2fsck
> > > +_require_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
> > > +# $4: filesystem block size
> > > +_workout()
> >
> > Local functions should not be prefixed with "_"; those are reserved for
> > common/ library functions.
> >
> > > +{
> > > +    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, Block size: $4" >> $seqres.full 2>&1
> > > +
> > > +    # Only mkfs if block size has been changed, or previous case failed
> > > +    if [ $prev_result -ne $PASS -o $4 -ne $prev_block_size ]; then
> > > +        $MKFS_EXT4_PROG -F -b $4 -I 256 $SCRATCH_DEV >> $seqres.full 2>&1
> >
> > _scratch_mkfs -b $4 -I 256 ?
> >
> > > +        prev_block_size=$4
> > > +        tune2fs -O extents $SCRATCH_DEV >> $seqres.full 2>&1
> >
> > $TUNE2FS_PROG, do not call tune2fs directly.
> >
> > Also, why don't you just format the fs with extents turned on in the
> > first place?
> >
> > > +    fi
> > > +    prev_result=$FAIL
> > > +
> > > +    _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 $SCRATCH_DEV 2> /dev/null | grep '^Filesystem features'
> >
> > $DUMPE2FS_PROG
> >
> > > | grep -q dir_nlink
> > > +    if [ $? -ne 0 ]; then
> > > +        echo "Feature dir_nlink is not set, please check $seqres.full
> > > for detail"
> > > +        return
> > > +    fi
> > > +
> > > +    # run fsck to make sure the filesystem has no errors
> > > +    $E2FSCK_PROG -fy $SCRATCH_DEV >> $seqres.full 2>&1
> > > +    if [ $? -ne 0 ]; then
> > > +        echo "fsck: the filesystem has errors, please check
> > > $seqres.full for detail"
> >
> > _check_scratch_fs?
> >
> > > +        return
> > > +    fi
> > > +
> > > +    prev_result=$PASS
> > > +}
> > > +
> > > +# main
> > > +DIR_LEN=( $SHORT_DIR $LONG_DIR )
> > > +PARENT_DIR=( "$SCRATCH_MNT" "$SCRATCH_MNT/sub" )
> > > +BLOCK_SIZE=( 1024 2048 4096 )
> > > +
> > > +for ((i = 0; i < 3; i++)); do
> > > +    for ((j = 0; j < 2; j++)); do
> > > +        for ((k = 0; k < 2; k++)); do
> > > +            if [ ${DIR_LEN[$k]} -eq $LONG_DIR -a \
> > > +                    ${BLOCK_SIZE[$i]} -eq 1024 ]; then
> > > +                continue
> > > +            fi
> > > +            _workout 65537 ${DIR_LEN[$k]} ${PARENT_DIR[$j]} ${BLOCK_SIZE[$i]}
> > > +        done
> > > +    done
> > > +done
> > > +
> > > +_scratch_unmount >> $seqres.full 2>&1
> > > +
> > > +# no BUG_ON, all done
> > > +status=0
> > > +exit
> > > diff --git a/tests/ext4/045.out b/tests/ext4/045.out
> > > new file mode 100644
> > > index 00000000..66276cfa
> > > --- /dev/null
> > > +++ b/tests/ext4/045.out
> > > @@ -0,0 +1,2 @@
> > > +QA output created by 045
> > > +Silence is golden
> > > diff --git a/tests/ext4/group b/tests/ext4/group
> > > index 9dfc0d35..8419cdea 100644
> > > --- a/tests/ext4/group
> > > +++ b/tests/ext4/group
> > > @@ -45,6 +45,9 @@
> > >  040 dangerous_fuzzers
> > >  041 dangerous_fuzzers
> > >  042 auto quick
> > > +043 auto quick
> > > +044 auto quick
> > > +045 auto
> >
> > "dir" group too?
> >
> > --D
> >
> > >  271 auto rw quick
> > >  301 aio auto ioctl rw stress defrag
> > >  302 aio auto ioctl rw stress defrag

Patch
diff mbox series

diff --git a/src/Makefile b/src/Makefile
index ce6d8610..387293d1 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -16,7 +16,8 @@  TARGETS = dirstress fill fill2 getpagesize holes lstat64 \
     holetest t_truncate_self t_mmap_dio af_unix t_mmap_stale_pmd \
     t_mmap_cow_race t_mmap_fallocate fsync-err t_mmap_write_ro \
     t_ext4_dax_journal_corruption t_ext4_dax_inline_corruption \
-    t_ofd_locks t_locks_execve t_mmap_collision mmap-write-concurrent
+    t_ofd_locks t_locks_execve t_mmap_collision mmap-write-concurrent \
+    t_ext4_file_time t_create_short_dirs t_create_long_dirs

 LINUX_TARGETS = xfsctl bstat t_mtab getdevicesize preallo_rw_pattern_reader \
     preallo_rw_pattern_writer ftrunc trunc fs_perms testx looptest \
diff --git a/src/t_create_long_dirs.c b/src/t_create_long_dirs.c
new file mode 100644
index 00000000..76a886aa
--- /dev/null
+++ b/src/t_create_long_dirs.c
@@ -0,0 +1,155 @@ 
+/******************************************************************************/
+/*
        */
+/* Copyright (c) 2009 FUJITSU LIMITED
        */
+/*
        */
+/* 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, write to the Free Software
        */
+/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA    */
+/*
        */
+/* 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"
+
+#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
index 00000000..c5733b9d
--- /dev/null
+++ b/src/t_create_short_dirs.c
@@ -0,0 +1,158 @@ 
+/******************************************************************************/
+/*
        */
+/* Copyright (c) 2009 FUJITSU LIMITED
        */
+/*
        */
+/* 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, write to the Free Software
        */
+/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA    */
+/*
        */
+/* 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"
+
+/* valid characters for a directory name */
+char chars[] =
"0123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM";
+
+/* to store the generated directory name */
+char name[10];
+int names;
+int parent_fd;
+
+/* 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)
+
+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");
+        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_ext4_file_time.c b/src/t_ext4_file_time.c
new file mode 100644
index 00000000..a10adb3d
--- /dev/null
+++ b/src/t_ext4_file_time.c
@@ -0,0 +1,69 @@ 
+/******************************************************************************/
+/*
        */
+/* Copyright (c) 2009 FUJITSU LIMITED
        */
+/*
        */
+/* 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, write to the Free Software
        */
+/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA    */
+/*
        */
+/* 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: 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
index 00000000..b6e5df9f
--- /dev/null
+++ b/tests/ext4/043
@@ -0,0 +1,64 @@ 
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2019 SUSE Linux Products GmbH.  All Rights Reserved.
+#
+# FS QA Test No. 043
+#
+# Transfer from ltp/testcases/kernel/fs/ext4-new-features/ext4_nsec_timestamps
+# Test file timestamps is second with 128 inode size
+#
+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.*
+    _scratch_cleanup_files
+}
+
+# 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_ext4_file_time"
+_require_command "$TUNE2FS_PROG" tune2fs
+
+echo "Silence is golden"
+
+echo "Start test timestamps with 128 inode size one device
$SCRATCH_DEV" >$seqres.full
+_scratch_mkfs_ext4 -I 128 >> $seqres.full 2>&1
+tune2fs -O extents $SCRATCH_DEV >>$seqres.full 2>&1
+_scratch_mount
+
+touch "${SCRATCH_MNT}/tmp_file"
+
+atime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file atime nsec`
+mtime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file mtime nsec`
+ctime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file ctime nsec`
+
+if [ $atime -ne 0 -o $mtime -ne 0 -o $ctime -ne 0 ]; then
+        echo "Timestamp is not second(atime: $atime, mtime: $mtime,
ctime: $ctime)" >> $seqres.full
+        _scratch_unmount >> $seqres.full 2>&1
+        exit
+fi
+echo "Ext4 nanosecond timestamps test with 128 inode size pass" >> $seqres.full
+_scratch_unmount >> $seqres.full 2>&1
+
+# no BUG_ON, all done
+status=0
+exit
diff --git a/tests/ext4/043.out b/tests/ext4/043.out
new file mode 100644
index 00000000..f90f0a57
--- /dev/null
+++ b/tests/ext4/043.out
@@ -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
index 00000000..3e899f5a
--- /dev/null
+++ b/tests/ext4/044
@@ -0,0 +1,112 @@ 
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2019 SUSE Linux Products GmbH.  All Rights Reserved.
+#
+# FS QA Test No. 044
+#
+# Transfer from ltp/testcases/kernel/fs/ext4-new-features/ext4_nsec_timestamps
+# Test file timestamps is nanosecond with 256 inode size
+#
+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.*
+    _scratch_cleanup_files
+}
+
+# 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_ext4_file_time"
+
+echo "Silence is golden"
+
+echo "Test timestamps with 256 inode size one device $SCRATCH_DEV"
>$seqres.full
+_scratch_mkfs_ext4 -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 {'print $1'}`
+nsec=`echo $cur_time | awk {'print $2'}`
+
+sec_atime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file atime sec`
+sec_mtime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file mtime sec`
+sec_ctime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file ctime sec`
+nsec_atime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file atime nsec`
+nsec_mtime=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file mtime nsec`
+nsec_ctime=`$here/src/t_ext4_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)" >>
$seqres.full
+        _scratch_unmount >> $seqres.full 2>&1
+        exit
+fi
+
+diff1=$(( $sec_atime - $sec ))
+diff2=$(( $sec_mtime - $sec ))
+diff3=$(( $sec_ctime - $sec ))
+
+# Test difference between file time and current time
+if [ $diff1 -gt 1 -o $diff2 -gt 1 -o $diff2 -gt 1 ]; then
+        echo "The timestamp is wrong, it must be earlier than the
current time we got. \
+             (sec_atime: $sec_atime, sec_mtime: $sec_mtime,
sec_ctime: $sec_ctime, \
+             cur_time[s]: $sec)" >> $seqres.full
+        _scratch_unmount >> $seqres.full 2>&1
+        exit
+fi
+_scratch_unmount >> $seqres.full 2>&1
+
+# Test mount to ext3 and then mount back to ext4
+mount -t ext3 $SCRATCH_DEV $SCRATCH_MNT
+if [ $? -ne 0 ]; then
+        echo "$SCRATCH_DEV fail in mounting to ext3" >> $seqres.full
+        _scratch_unmount >> $seqres.full 2>&1
+        exit
+fi
+_scratch_unmount >> $seqres.full 2>&1
+_scratch_mount
+
+nsec_atime2=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file atime nsec`
+nsec_mtime2=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file mtime nsec`
+nsec_ctime2=`$here/src/t_ext4_file_time $SCRATCH_MNT/tmp_file ctime nsec`
+
+if [ $nsec_atime -ne $nsec_atime2 -o $nsec_ctime -ne $nsec_ctime2 -o \
+     $nsec_mtime -ne $nsec_mtime2 ]; then
+        echo "File nanosecond timestamp has changed \
+                        unexpected. Before[atime mtime ctime]: $nsec_atime \
+                        nsec_mtime $nsec_ctime, After[atime mtime ctime]: \
+                        $nsec_atime2 $nsec_mtime2 $nsec_ctime2)" >>
$seqres.full
+        _scratch_unmount >> $seqres.full 2>&1
+        exit
+fi
+_scratch_unmount >> $seqres.full 2>&1
+
+# no BUG_ON, all done
+status=0
+exit
diff --git a/tests/ext4/044.out b/tests/ext4/044.out
new file mode 100644
index 00000000..12a61dc4
--- /dev/null
+++ b/tests/ext4/044.out
@@ -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
index 00000000..c70baa97
--- /dev/null
+++ b/tests/ext4/045
@@ -0,0 +1,148 @@ 
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2019 SUSE Linux Products GmbH.  All Rights Reserved.
+#
+# FS QA Test No. 045
+#
+# Transfer from
ltp/testcases/kernel/fs/ext4-new-features/ext4_subdir_limit_test
+#
+# Test subdirectory limit of ext4.
+# We create more than 32000 subdirectorys 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
+FAIL=1
+PASS=0
+prev_block_size=0
+prev_result=$FAIL
+
+_cleanup()
+{
+    cd /
+    rm -f $tmp.*
+    _scratch_cleanup_files
+}
+
+# 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_command "$TUNE2FS_PROG" tune2fs
+_require_command "$E2FSCK_PROG" e2fsck
+_require_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
+# $4: filesystem block size
+_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, Block size: $4" >> $seqres.full 2>&1
+
+    # Only mkfs if block size has been changed, or previous case failed
+    if [ $prev_result -ne $PASS -o $4 -ne $prev_block_size ]; then
+        $MKFS_EXT4_PROG -F -b $4 -I 256 $SCRATCH_DEV >> $seqres.full 2>&1
+        prev_block_size=$4
+        tune2fs -O extents $SCRATCH_DEV >> $seqres.full 2>&1
+    fi
+    prev_result=$FAIL
+
+    _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 $SCRATCH_DEV 2> /dev/null | 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
+
+    # run fsck to make sure the filesystem has no errors
+    $E2FSCK_PROG -fy $SCRATCH_DEV >> $seqres.full 2>&1
+    if [ $? -ne 0 ]; then
+        echo "fsck: the filesystem has errors, please check
$seqres.full for detail"
+        return
+    fi
+
+    prev_result=$PASS
+}
+
+# main
+DIR_LEN=( $SHORT_DIR $LONG_DIR )
+PARENT_DIR=( "$SCRATCH_MNT" "$SCRATCH_MNT/sub" )
+BLOCK_SIZE=( 1024 2048 4096 )
+
+for ((i = 0; i < 3; i++)); do
+    for ((j = 0; j < 2; j++)); do
+        for ((k = 0; k < 2; k++)); do
+            if [ ${DIR_LEN[$k]} -eq $LONG_DIR -a \
+                    ${BLOCK_SIZE[$i]} -eq 1024 ]; then
+                continue
+            fi
+            _workout 65537 ${DIR_LEN[$k]} ${PARENT_DIR[$j]} ${BLOCK_SIZE[$i]}
+        done
+    done
+done
+
+_scratch_unmount >> $seqres.full 2>&1
+
+# no BUG_ON, all done
+status=0
+exit
diff --git a/tests/ext4/045.out b/tests/ext4/045.out
new file mode 100644
index 00000000..66276cfa
--- /dev/null
+++ b/tests/ext4/045.out
@@ -0,0 +1,2 @@ 
+QA output created by 045
+Silence is golden
diff --git a/tests/ext4/group b/tests/ext4/group
index 9dfc0d35..8419cdea 100644
--- a/tests/ext4/group
+++ b/tests/ext4/group
@@ -45,6 +45,9 @@ 
 040 dangerous_fuzzers
 041 dangerous_fuzzers
 042 auto quick
+043 auto quick
+044 auto quick
+045 auto
 271 auto rw quick
 301 aio auto ioctl rw stress defrag
 302 aio auto ioctl rw stress defrag