diff mbox series

[v2,1/2] Rewrite fsx-linux test

Message ID 20231030110107.4528-2-andrea.cervesato@suse.de
State Accepted
Headers show
Series Rewrite fsx-linux | expand

Commit Message

Andrea Cervesato Oct. 30, 2023, 11:01 a.m. UTC
From: Andrea Cervesato <andrea.cervesato@suse.com>

This is a complete rewrite of the old test. Some options have been
removed, since they were not used by LTP runtests. Also, the new
test is not skipping any operation and running a new one if the
previous failed, until the total amount of operations have been
executed. The test passes once all operations succeded.

Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
Updated ltp-aiodio.part3 testfile which had a few errors

 runtest/ltp-aiodio.part3                  |   99 +-
 testcases/kernel/fs/fsx-linux/Makefile    |    4 +-
 testcases/kernel/fs/fsx-linux/fsx-linux.c | 1509 ++++-----------------
 testcases/network/nfs/fsx-linux/fsx.sh    |    3 +-
 4 files changed, 324 insertions(+), 1291 deletions(-)

Comments

Petr Vorel Nov. 1, 2023, 10:34 a.m. UTC | #1
Hi Andrea,

...
> +++ b/testcases/kernel/fs/fsx-linux/fsx-linux.c
> @@ -1,1353 +1,392 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
>  /*
>   * Copyright (C) 1991, NeXT Computer, Inc.  All Rights Reserverd.
> - * Copyright (c) 1998-2001 Apple Computer, Inc. All rights reserved.
> - *
> - * @APPLE_LICENSE_HEADER_START@
> - *
> - * The contents of this file constitute Original Code as defined in and
> - * are subject to the Apple Public Source License Version 1.1 (the
> - * "License").  You may not use this file except in compliance with the
> - * License.  Please obtain a copy of the License at
> - * http://www.apple.com/publicsource and read it before using this file.

I wonder if we can switch from APSL-1.1 to GPL-2.0-or-later
https://spdx.org/licenses/APSL-1.1.html

"This is a complete rewrite of the old test." may justify that.

> - *
> - * This Original Code and all software distributed under the License are
> - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
> - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
> - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
> - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
> - * License for the specific language governing rights and limitations
> - * under the License.
> - *
> - * @APPLE_LICENSE_HEADER_END@
...

> -#include <sys/types.h>
> -#include <sys/stat.h>
> -#if defined(_UWIN) || defined(__linux__)

I would also consider moving (and rename) the file to testcases/kernel/fs/fsx/fsx.c.
We don't care about _UWIN any more.

Kind regards,
Petr
Cyril Hrubis Nov. 1, 2023, 10:53 a.m. UTC | #2
Hi!
> > +++ b/testcases/kernel/fs/fsx-linux/fsx-linux.c
> > @@ -1,1353 +1,392 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> >  /*
> >   * Copyright (C) 1991, NeXT Computer, Inc.  All Rights Reserverd.
> > - * Copyright (c) 1998-2001 Apple Computer, Inc. All rights reserved.
> > - *
> > - * @APPLE_LICENSE_HEADER_START@
> > - *
> > - * The contents of this file constitute Original Code as defined in and
> > - * are subject to the Apple Public Source License Version 1.1 (the
> > - * "License").  You may not use this file except in compliance with the
> > - * License.  Please obtain a copy of the License at
> > - * http://www.apple.com/publicsource and read it before using this file.
> 
> I wonder if we can switch from APSL-1.1 to GPL-2.0-or-later
> https://spdx.org/licenses/APSL-1.1.html
> 
> "This is a complete rewrite of the old test." may justify that.

The test was written from scratch based loosely on what the original
stress test did, so I would say that the new license is okay.

But I suggested adding "Based on fxs.c test by Next Computer, Inc."
instead of the copyright lines, since I suppose that once we add these
copyrights we have to keep the original license.

> > - * This Original Code and all software distributed under the License are
> > - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
> > - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
> > - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
> > - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
> > - * License for the specific language governing rights and limitations
> > - * under the License.
> > - *
> > - * @APPLE_LICENSE_HEADER_END@
> ...
> 
> > -#include <sys/types.h>
> > -#include <sys/stat.h>
> > -#if defined(_UWIN) || defined(__linux__)
> 
> I would also consider moving (and rename) the file to testcases/kernel/fs/fsx/fsx.c.
> We don't care about _UWIN any more.

I would keep the linux in the name, at least is clear that we do not
intend to be portable to BSDs etc. like the orignal code was.
Petr Vorel Nov. 1, 2023, 11:11 a.m. UTC | #3
> Hi!
> > > +++ b/testcases/kernel/fs/fsx-linux/fsx-linux.c
> > > @@ -1,1353 +1,392 @@
> > > +// SPDX-License-Identifier: GPL-2.0-or-later
> > >  /*
> > >   * Copyright (C) 1991, NeXT Computer, Inc.  All Rights Reserverd.
> > > - * Copyright (c) 1998-2001 Apple Computer, Inc. All rights reserved.
> > > - *
> > > - * @APPLE_LICENSE_HEADER_START@
> > > - *
> > > - * The contents of this file constitute Original Code as defined in and
> > > - * are subject to the Apple Public Source License Version 1.1 (the
> > > - * "License").  You may not use this file except in compliance with the
> > > - * License.  Please obtain a copy of the License at
> > > - * http://www.apple.com/publicsource and read it before using this file.

> > I wonder if we can switch from APSL-1.1 to GPL-2.0-or-later
> > https://spdx.org/licenses/APSL-1.1.html

> > "This is a complete rewrite of the old test." may justify that.

> The test was written from scratch based loosely on what the original
> stress test did, so I would say that the new license is okay.

> But I suggested adding "Based on fxs.c test by Next Computer, Inc."
> instead of the copyright lines, since I suppose that once we add these
> copyrights we have to keep the original license.

Sounds good, thanks!
Not yet marking as changes requested (the real review should be done).

> > > - * This Original Code and all software distributed under the License are
> > > - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
> > > - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
> > > - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
> > > - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
> > > - * License for the specific language governing rights and limitations
> > > - * under the License.
> > > - *
> > > - * @APPLE_LICENSE_HEADER_END@
> > ...

> > > -#include <sys/types.h>
> > > -#include <sys/stat.h>
> > > -#if defined(_UWIN) || defined(__linux__)

> > I would also consider moving (and rename) the file to testcases/kernel/fs/fsx/fsx.c.
> > We don't care about _UWIN any more.

> I would keep the linux in the name, at least is clear that we do not
> intend to be portable to BSDs etc. like the orignal code was.

OK.

Kind regards,
Petr
Petr Vorel Nov. 13, 2023, 4:05 p.m. UTC | #4
Hi Andrea,

...
> +++ b/testcases/kernel/fs/fsx-linux/Makefile
> @@ -22,13 +22,11 @@

>  top_srcdir			?= ../../../..

> -include $(top_srcdir)/include/mk/env_pre.mk
> +include $(top_srcdir)/include/mk/testcases.mk

>  CPPFLAGS			+= -DNO_XFS -I$(abs_srcdir) \
>  				   -D_LARGEFILE64_SOURCE -D_GNU_SOURCE

>  WCFLAGS				+= -w

> -INSTALL_TARGETS			:= fsxtest*
> -
>  include $(top_srcdir)/include/mk/generic_leaf_target.mk

This could be a separate change, right? The point of separating changes is to
make each patchset smaller, which I agree does not help much here.

Kind regards,
Petr
Andrea Cervesato Nov. 14, 2023, 10:31 a.m. UTC | #5
Hi Petr,

On 11/13/23 17:05, Petr Vorel wrote:
> Hi Andrea,
>
> ...
>> +++ b/testcases/kernel/fs/fsx-linux/Makefile
>> @@ -22,13 +22,11 @@
>>   top_srcdir			?= ../../../..
>> -include $(top_srcdir)/include/mk/env_pre.mk
>> +include $(top_srcdir)/include/mk/testcases.mk
>>   CPPFLAGS			+= -DNO_XFS -I$(abs_srcdir) \
>>   				   -D_LARGEFILE64_SOURCE -D_GNU_SOURCE
>>   WCFLAGS				+= -w
>> -INSTALL_TARGETS			:= fsxtest*
>> -
>>   include $(top_srcdir)/include/mk/generic_leaf_target.mk
> This could be a separate change, right? The point of separating changes is to
> make each patchset smaller, which I agree does not help much here.
Sure, I can do it after review.
> Kind regards,
> Petr

Best regards,
Andrea Cervesato
Andrea Cervesato Nov. 20, 2023, 3:55 p.m. UTC | #6
Hi!

On 11/1/23 11:53, Cyril Hrubis wrote:
> Hi!
>>> +++ b/testcases/kernel/fs/fsx-linux/fsx-linux.c
>>> @@ -1,1353 +1,392 @@
>>> +// SPDX-License-Identifier: GPL-2.0-or-later
>>>   /*
>>>    * Copyright (C) 1991, NeXT Computer, Inc.  All Rights Reserverd.
>>> - * Copyright (c) 1998-2001 Apple Computer, Inc. All rights reserved.
>>> - *
>>> - * @APPLE_LICENSE_HEADER_START@
>>> - *
>>> - * The contents of this file constitute Original Code as defined in and
>>> - * are subject to the Apple Public Source License Version 1.1 (the
>>> - * "License").  You may not use this file except in compliance with the
>>> - * License.  Please obtain a copy of the License at
>>> - * http://www.apple.com/publicsource and read it before using this file.
>> I wonder if we can switch from APSL-1.1 to GPL-2.0-or-later
>> https://spdx.org/licenses/APSL-1.1.html
>>
>> "This is a complete rewrite of the old test." may justify that.
> The test was written from scratch based loosely on what the original
> stress test did, so I would say that the new license is okay.
>
> But I suggested adding "Based on fxs.c test by Next Computer, Inc."
> instead of the copyright lines, since I suppose that once we add these
> copyrights we have to keep the original license.
This is explained in the description.
>>> - * This Original Code and all software distributed under the License are
>>> - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
>>> - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
>>> - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
>>> - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
>>> - * License for the specific language governing rights and limitations
>>> - * under the License.
>>> - *
>>> - * @APPLE_LICENSE_HEADER_END@
>> ...
>>
>>> -#include <sys/types.h>
>>> -#include <sys/stat.h>
>>> -#if defined(_UWIN) || defined(__linux__)
>> I would also consider moving (and rename) the file to testcases/kernel/fs/fsx/fsx.c.
>> We don't care about _UWIN any more.
> I would keep the linux in the name, at least is clear that we do not
> intend to be portable to BSDs etc. like the orignal code was.
>
Andrea Cervesato
Petr Vorel Nov. 20, 2023, 4:50 p.m. UTC | #7
Hi Andrea,

> Hi!

> On 11/1/23 11:53, Cyril Hrubis wrote:
> > Hi!
> > > > +++ b/testcases/kernel/fs/fsx-linux/fsx-linux.c
> > > > @@ -1,1353 +1,392 @@
> > > > +// SPDX-License-Identifier: GPL-2.0-or-later
> > > >   /*
> > > >    * Copyright (C) 1991, NeXT Computer, Inc.  All Rights Reserverd.
> > > > - * Copyright (c) 1998-2001 Apple Computer, Inc. All rights reserved.
> > > > - *
> > > > - * @APPLE_LICENSE_HEADER_START@
> > > > - *
> > > > - * The contents of this file constitute Original Code as defined in and
> > > > - * are subject to the Apple Public Source License Version 1.1 (the
> > > > - * "License").  You may not use this file except in compliance with the
> > > > - * License.  Please obtain a copy of the License at
> > > > - * http://www.apple.com/publicsource and read it before using this file.
> > > I wonder if we can switch from APSL-1.1 to GPL-2.0-or-later
> > > https://spdx.org/licenses/APSL-1.1.html

> > > "This is a complete rewrite of the old test." may justify that.
> > The test was written from scratch based loosely on what the original
> > stress test did, so I would say that the new license is okay.

> > But I suggested adding "Based on fxs.c test by Next Computer, Inc."
> > instead of the copyright lines, since I suppose that once we add these
> > copyrights we have to keep the original license.
> This is explained in the description.

If you mean the commit message description, that's IMHO not enough.
Statements like this are added into the source code header so that people who
download tarballs see it as well.

Kind regards,
Petr
Andrea Cervesato Nov. 20, 2023, 6:24 p.m. UTC | #8
Hi Petr,

> On 20 Nov 2023, at 17:50, Petr Vorel <pvorel@suse.cz> wrote:
> 
> Hi Andrea,
> 
>> Hi!
> 
>>> On 11/1/23 11:53, Cyril Hrubis wrote:
>>> Hi!
>>>>> +++ b/testcases/kernel/fs/fsx-linux/fsx-linux.c
>>>>> @@ -1,1353 +1,392 @@
>>>>> +// SPDX-License-Identifier: GPL-2.0-or-later
>>>>>  /*
>>>>>   * Copyright (C) 1991, NeXT Computer, Inc.  All Rights Reserverd.
>>>>> - * Copyright (c) 1998-2001 Apple Computer, Inc. All rights reserved.
>>>>> - *
>>>>> - * @APPLE_LICENSE_HEADER_START@
>>>>> - *
>>>>> - * The contents of this file constitute Original Code as defined in and
>>>>> - * are subject to the Apple Public Source License Version 1.1 (the
>>>>> - * "License").  You may not use this file except in compliance with the
>>>>> - * License.  Please obtain a copy of the License at
>>>>> - * http://www.apple.com/publicsource and read it before using this file.
>>>> I wonder if we can switch from APSL-1.1 to GPL-2.0-or-later
>>>> https://spdx.org/licenses/APSL-1.1.html
> 
>>>> "This is a complete rewrite of the old test." may justify that.
>>> The test was written from scratch based loosely on what the original
>>> stress test did, so I would say that the new license is okay.
> 
>>> But I suggested adding "Based on fxs.c test by Next Computer, Inc."
>>> instead of the copyright lines, since I suppose that once we add these
>>> copyrights we have to keep the original license.
>> This is explained in the description.
> 
> If you mean the commit message description, that's IMHO not enough.
> Statements like this are added into the source code header so that people who
> download tarballs see it as well.
> 

I meant the test Description section.

> Kind regards,
> Petr
diff mbox series

Patch

diff --git a/runtest/ltp-aiodio.part3 b/runtest/ltp-aiodio.part3
index d53e836b9..65931ddf4 100644
--- a/runtest/ltp-aiodio.part3
+++ b/runtest/ltp-aiodio.part3
@@ -1,51 +1,48 @@ 
-#           fname:  this filename is Required (no default)
-#
-#
-FSX032 fsx-linux -l 500000 -r 4096 -t 4096 -w 4096 -N 10000 $TMPDIR/aiodio.$$/junkfile
-FSX033 fsx-linux -l 500000 -r 4096 -t 2048 -w 2048 -N 10000 $TMPDIR/aiodio.$$/junkfile
-FSX034 fsx-linux -l 500000 -r 4096 -N 10000 $TMPDIR/aiodio.$$/junkfile
-FSX035 fsx-linux -N 10000 $TMPDIR/aiodio.$$/junkfile
-FSX036 fsx-linux -N 10000 $TMPDIR/aiodio.$$/junkfile
-FSX037 fsx-linux -N 10000 $TMPDIR/aiodio.$$/junkfile
-FSX038 fsx-linux -N 10000 $TMPDIR/aiodio.$$/junkfile
-FSX039 fsx-linux -N 10000 $TMPDIR/aiodio.$$/junkfile
-FSX040 fsx-linux -N 10000 -o 1024 $TMPDIR/aiodio.$$/junkfile
-FSX041 fsx-linux -N 10000 -o 2048 $TMPDIR/aiodio.$$/junkfile
-FSX042 fsx-linux -N 10000 -o 4096 $TMPDIR/aiodio.$$/junkfile
-FSX043 fsx-linux -N 10000 -o 8192 $TMPDIR/aiodio.$$/junkfile
-FSX044 fsx-linux -N 10000 -o 16384 $TMPDIR/aiodio.$$/junkfile
-FSX045 fsx-linux -N 10000 -o 32768 $TMPDIR/aiodio.$$/junkfile
-FSX046 fsx-linux -N 10000 -o 128000 $TMPDIR/aiodio.$$/junkfile
-FSX047 fsx-linux -N 10000 -o 1024 $TMPDIR/aiodio.$$/junkfile
-FSX048 fsx-linux -N 10000 -o 2048 $TMPDIR/aiodio.$$/junkfile
-FSX049 fsx-linux -N 10000 -o 4096 $TMPDIR/aiodio.$$/junkfile
-FSX050 fsx-linux -N 10000 -o 8192 $TMPDIR/aiodio.$$/junkfile
-FSX051 fsx-linux -N 10000 -o 16384 $TMPDIR/aiodio.$$/junkfile
-FSX052 fsx-linux -N 10000 -o 32768 $TMPDIR/aiodio.$$/junkfile
-FSX053 fsx-linux -N 10000 -o 128000 $TMPDIR/aiodio.$$/junkfile
-FSX054 fsx-linux -N 10000  -o 1024 -l 500000 -r 4096 -t 4096 -w 4096 $TMPDIR/aiodio.$$/junkfile
-FSX055 fsx-linux -N 10000  -o 2048 -l 500000 -r 4096 -t 2048 -w 2048 $TMPDIR/aiodio.$$/junkfile
-FSX056 fsx-linux -N 10000  -o 4096 -l 500000 -r 4096 -t 4096 -w 4096 $TMPDIR/aiodio.$$/junkfile
-FSX057 fsx-linux -N 10000  -o 8192 -l 500000 -r 4096 -t 2048 -w 2048 $TMPDIR/aiodio.$$/junkfile
-FSX058 fsx-linux -N 10000  -o 16384 -l 500000 -r 4096 -t 4096 -w 4096 $TMPDIR/aiodio.$$/junkfile
-FSX059 fsx-linux -N 10000  -o 32768 -l 500000 -r 4096 -t 2048 -w 2048 $TMPDIR/aiodio.$$/junkfile
-FSX060 fsx-linux -N 10000  -o 128000 -l 500000 -r 4096 -t 4096 -w 4096 $TMPDIR/aiodio.$$/junkfile
-FSX061 fsx-linux -N 10000 -o 32768 $TMPDIR/aiodio.$$/junkfile
-FSX062 fsx-linux -N 10000 -o 128000 $TMPDIR/aiodio.$$/junkfile
-FSX063 fsx-linux -N 10000  -o 1024  -l 500000 -r 4096 -t 4096 -w 4096 $TMPDIR/aiodio.$$/junkfile
-FSX064 fsx-linux -N 10000  -o 2048 -l 500000 -r 4096 -t 2048 -w 2048 $TMPDIR/aiodio.$$/junkfile
-FSX065 fsx-linux -N 10000  -o 4096 -l 500000 -r 4096 -t 4096 -w 4096 $TMPDIR/aiodio.$$/junkfile
-FSX066 fsx-linux -N 10000  -o 8192  -l 500000 -r 4096 -t 2048 -w 2048 $TMPDIR/aiodio.$$/junkfile
-FSX067 fsx-linux -N 10000  -o 16384 -l 500000 -r 4096 -t 4096 -w 4096 $TMPDIR/aiodio.$$/junkfile
-FSX068 fsx-linux -N 10000  -o 32768 -l 500000 -r 4096 -t 2048 -w 2048 $TMPDIR/aiodio.$$/junkfile
-FSX069 fsx-linux -N 10000  -o 128000 -l 500000 -r 4096 -t 4096 -w 4096 $TMPDIR/aiodio.$$/junkfile
-FSX070 fsx-linux -N 10000  -o 128000 -l 500000 -r 4096 -t 4096 -w 4096 $TMPDIR/aiodio.$$/junkfile
-FSX071 fsx-linux -N 10000  -o 16384 -l 500000 -r 4096 -t 4096 -w 4096   $TMPDIR/aiodio.$$/junkfile1
-FSX072 fsx-linux -N 10000  -o 32768 -l 500000 -r 4096 -t 2048 -w 2048   $TMPDIR/aiodio.$$/junkfile2
-FSX073 fsx-linux -N 10000  -o 128000 -l 500000 -r 4096 -t 4096 -w 4096 $TMPDIR/aiodio.$$/junkfile3
-FSX074 fsx-linux -N 10000  -o 16384 -l 500000 -r 4096 -t 4096 -w 4096   $TMPDIR/aiodio.$$/junkfile4
-FSX075 fsx-linux -N 10000  -o 32768 -l 500000 -r 4096 -t 2048 -w 2048   $TMPDIR/aiodio.$$/junkfile5
-FSX076 fsx-linux -N 10000  -o 128000 -l 500000 -r 4096 -t 4096 -w 4096 $TMPDIR/aiodio.$$/junkfile6
-FSX077 fsx-linux -N 10000   $TMPDIR/aiodio.$$/junkfile7
-FSX078 fsx-linux -N 100000  $TMPDIR/aiodio.$$/junkfile8
-FSX079 fsx-linux -N 100000  $TMPDIR/aiodio.$$/junkfile9
+FSX032 fsx-linux -l 500000 -r 4096 -t 4096 -w 4096 -N 10000
+FSX033 fsx-linux -l 500000 -r 4096 -t 2048 -w 2048 -N 10000
+FSX034 fsx-linux -l 500000 -r 4096 -N 10000
+FSX035 fsx-linux -N 10000
+FSX036 fsx-linux -N 10000
+FSX037 fsx-linux -N 10000
+FSX038 fsx-linux -N 10000
+FSX039 fsx-linux -N 10000
+FSX040 fsx-linux -N 10000 -o 1024
+FSX041 fsx-linux -N 10000 -o 2048
+FSX042 fsx-linux -N 10000 -o 4096
+FSX043 fsx-linux -N 10000 -o 8192
+FSX044 fsx-linux -N 10000 -o 16384
+FSX045 fsx-linux -N 10000 -o 32768
+FSX046 fsx-linux -N 10000 -o 128000
+FSX047 fsx-linux -N 10000 -o 1024
+FSX048 fsx-linux -N 10000 -o 2048
+FSX049 fsx-linux -N 10000 -o 4096
+FSX050 fsx-linux -N 10000 -o 8192
+FSX051 fsx-linux -N 10000 -o 16384
+FSX052 fsx-linux -N 10000 -o 32768
+FSX053 fsx-linux -N 10000 -o 128000
+FSX054 fsx-linux -N 10000  -o 1024 -l 500000 -r 4096 -t 4096 -w 4096
+FSX055 fsx-linux -N 10000  -o 2048 -l 500000 -r 4096 -t 2048 -w 2048
+FSX056 fsx-linux -N 10000  -o 4096 -l 500000 -r 4096 -t 4096 -w 4096
+FSX057 fsx-linux -N 10000  -o 8192 -l 500000 -r 4096 -t 2048 -w 2048
+FSX058 fsx-linux -N 10000  -o 16384 -l 500000 -r 4096 -t 4096 -w 4096
+FSX059 fsx-linux -N 10000  -o 32768 -l 500000 -r 4096 -t 2048 -w 2048
+FSX060 fsx-linux -N 10000  -o 128000 -l 500000 -r 4096 -t 4096 -w 4096
+FSX061 fsx-linux -N 10000 -o 32768
+FSX062 fsx-linux -N 10000 -o 128000
+FSX063 fsx-linux -N 10000  -o 1024  -l 500000 -r 4096 -t 4096 -w 4096
+FSX064 fsx-linux -N 10000  -o 2048 -l 500000 -r 4096 -t 2048 -w 2048
+FSX065 fsx-linux -N 10000  -o 4096 -l 500000 -r 4096 -t 4096 -w 4096
+FSX066 fsx-linux -N 10000  -o 8192  -l 500000 -r 4096 -t 2048 -w 2048
+FSX067 fsx-linux -N 10000  -o 16384 -l 500000 -r 4096 -t 4096 -w 4096
+FSX068 fsx-linux -N 10000  -o 32768 -l 500000 -r 4096 -t 2048 -w 2048
+FSX069 fsx-linux -N 10000  -o 128000 -l 500000 -r 4096 -t 4096 -w 4096
+FSX070 fsx-linux -N 10000  -o 128000 -l 500000 -r 4096 -t 4096 -w 4096
+FSX071 fsx-linux -N 10000  -o 16384 -l 500000 -r 4096 -t 4096 -w 4096
+FSX072 fsx-linux -N 10000  -o 32768 -l 500000 -r 4096 -t 2048 -w 2048
+FSX073 fsx-linux -N 10000  -o 128000 -l 500000 -r 4096 -t 4096 -w 40963
+FSX074 fsx-linux -N 10000  -o 16384 -l 500000 -r 4096 -t 4096 -w 4096
+FSX075 fsx-linux -N 10000  -o 32768 -l 500000 -r 4096 -t 2048 -w 2048
+FSX076 fsx-linux -N 10000  -o 128000 -l 500000 -r 4096 -t 4096 -w 40966
+FSX077 fsx-linux -N 10000
+FSX078 fsx-linux -N 100000
+FSX079 fsx-linux -N 100000
diff --git a/testcases/kernel/fs/fsx-linux/Makefile b/testcases/kernel/fs/fsx-linux/Makefile
index 956486b8a..5d04d81bc 100644
--- a/testcases/kernel/fs/fsx-linux/Makefile
+++ b/testcases/kernel/fs/fsx-linux/Makefile
@@ -22,13 +22,11 @@ 
 
 top_srcdir			?= ../../../..
 
-include $(top_srcdir)/include/mk/env_pre.mk
+include $(top_srcdir)/include/mk/testcases.mk
 
 CPPFLAGS			+= -DNO_XFS -I$(abs_srcdir) \
 				   -D_LARGEFILE64_SOURCE -D_GNU_SOURCE
 
 WCFLAGS				+= -w
 
-INSTALL_TARGETS			:= fsxtest*
-
 include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/fs/fsx-linux/fsx-linux.c b/testcases/kernel/fs/fsx-linux/fsx-linux.c
index 64c27a0f5..112c21f85 100644
--- a/testcases/kernel/fs/fsx-linux/fsx-linux.c
+++ b/testcases/kernel/fs/fsx-linux/fsx-linux.c
@@ -1,1353 +1,392 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * Copyright (C) 1991, NeXT Computer, Inc.  All Rights Reserverd.
- * Copyright (c) 1998-2001 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License").  You may not use this file except in compliance with the
- * License.  Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
- *
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
- * License for the specific language governing rights and limitations
- * under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- *
- *	File:	fsx.c
  *	Author:	Avadis Tevanian, Jr.
  *
- *	File system exerciser.
- *
- *	Rewrite and enhancements 1998-2001 Conrad Minshall -- conrad@mac.com
- *
- *	Various features from Joe Sokol, Pat Dirks, and Clark Warner.
- *
- *	Small changes to work under Linux -- davej@suse.de
- *
- *	Sundry porting patches from Guy Harris 12/2001
- * $FreeBSD: src/tools/regression/fsx/fsx.c,v 1.1 2001/12/20 04:15:57 jkh Exp $
+ * Copyright (c) 1998-2001 Apple Computer, Inc. All rights reserved.
+ *	Conrad Minshall <conrad@mac.com>
+ *	Dave Jones <davej@suse.de>
+ *	Zach Brown <zab@clusterfs.com>
+ *	Joe Sokol, Pat Dirks, Clark Warner, Guy Harris
  *
- *	Add multi-file testing feature -- Zach Brown <zab@clusterfs.com>
+ * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
  */
 
-#include <sys/types.h>
-#include <sys/stat.h>
-#if defined(_UWIN) || defined(__linux__)
-#include <sys/param.h>
-#include <limits.h>
-#include <time.h>
-#include <string.h>
-#include <sys/time.h>
-#endif
-#include <fcntl.h>
-#include <sys/mman.h>
-#ifndef MAP_FILE
-#define MAP_FILE 0
-#endif
-#include <limits.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdarg.h>
-#include <errno.h>
-
-/*
- *	A log entry is an operation and a bunch of arguments.
+/*\
+ * [Description]
+ *
+ * This is a complete rewrite of the old fsx-linux tool, created by
+ * NeXT Computer, Inc. and Apple Computer, Inc. between 1991 and 2001,
+ * then adapted for LTP. Test is actually a file system exerciser: we bring a
+ * file and randomly write operations like read/write/map read/map write and
+ * truncate, according with input parameters. Then we check if all of them
+ * have been completed.
  */
 
-struct log_entry {
-	int operation;
-	struct timeval tv;
-	int args[3];
+#include <stdlib.h>
+#include "tst_test.h"
+
+#define FNAME "ltp-file.bin"
+
+enum {
+	OP_READ = 0,
+	OP_WRITE,
+	OP_TRUNCATE,
+	OP_MAPREAD,
+	OP_MAPWRITE,
+	/* keep counter here */
+	OP_TOTAL,
 };
 
-#define	LOGSIZE	1000
+static char *str_file_max_size;
+static char *str_op_max_size;
+static char *str_op_nums;
+static char *str_op_write_align;
+static char *str_op_read_align;
+static char *str_op_trunc_align;
+
+static int file_desc;
+static long long file_max_size = 256 * 1024;
+static long long op_max_size = 64 * 1024;
+static long long file_size;
+static int op_write_align = 1;
+static int op_read_align = 1;
+static int op_trunc_align = 1;
+static int op_nums = 1000;
+static int page_size;
+
+static char *file_buff;
+static char *temp_buff;
+
+struct file_pos_t {
+	long long offset;
+	long long size;
+};
 
-struct log_entry oplog[LOGSIZE];	/* the log */
-int logptr = 0;			/* current position in log */
-int logcount = 0;		/* total ops */
+static void op_align_pages(struct file_pos_t *pos)
+{
+	long long pg_offset;
 
-/*
- *	Define operations
- */
+	pg_offset = pos->offset % page_size;
 
-#define	OP_READ		1
-#define OP_WRITE	2
-#define OP_TRUNCATE	3
-#define OP_CLOSEOPEN	4
-#define OP_MAPREAD	5
-#define OP_MAPWRITE	6
-#define OP_SKIPPED	7
-
-int page_size;
-int page_mask;
-
-char *original_buf;		/* a pointer to the original data */
-char *good_buf;			/* a pointer to the correct data */
-char *temp_buf;			/* a pointer to the current data */
-char *fname;			/* name of our test file */
-char logfile[1024];		/* name of our log file */
-char goodfile[1024];		/* name of our test file */
-
-off_t file_size = 0;
-off_t biggest = 0;
-char state[256];
-unsigned long testcalls = 0;	/* calls to function "test" */
-
-unsigned long simulatedopcount = 0;	/* -b flag */
-int closeprob = 0;		/* -c flag */
-int debug = 0;			/* -d flag */
-unsigned long debugstart = 0;	/* -D flag */
-unsigned long maxfilelen = 256 * 1024;	/* -l flag */
-int sizechecks = 1;		/* -n flag disables them */
-int maxoplen = 64 * 1024;	/* -o flag */
-int quiet = 0;			/* -q flag */
-unsigned long progressinterval = 0;	/* -p flag */
-int readbdy = 1;		/* -r flag */
-int style = 0;			/* -s flag */
-int truncbdy = 1;		/* -t flag */
-int writebdy = 1;		/* -w flag */
-long monitorstart = -1;		/* -m flag */
-long monitorend = -1;		/* -m flag */
-int lite = 0;			/* -L flag */
-long numops = -1;		/* -N flag */
-int randomoplen = 1;		/* -O flag disables it */
-int seed = 1;			/* -S flag */
-int mapped_writes = 1;		/* -W flag disables */
-int mapped_reads = 1;		/* -R flag disables it */
-int fsxgoodfd = 0;
-FILE *fsxlogf = NULL;
-int badoff = -1;
-
-void vwarnc(int code,const char *fmt, va_list ap)
-{
-	fprintf(stderr, "fsx: ");
-	if (fmt != NULL) {
-		vfprintf(stderr, fmt, ap);
-		fprintf(stderr, ": ");
-	}
-	fprintf(stderr, "%s\n", strerror(code));
+	pos->offset -= pg_offset;
+	pos->size += pg_offset;
 }
 
-void warn(const char *fmt, ...)
+static void op_file_position(
+	const long long fsize,
+	const int align,
+	struct file_pos_t *pos)
 {
-	va_list ap;
-	va_start(ap, fmt);
-	vwarnc(errno, fmt, ap);
-	va_end(ap);
-}
+	long long diff;
 
-void
-    __attribute__ ((format(printf, 1, 2)))
-    prt(char *fmt, ...)
-{
-	va_list args;
+	pos->offset = random() % fsize;
+	pos->size = random() % (fsize - pos->offset);
 
-	va_start(args, fmt);
-	vfprintf(stdout, fmt, args);
-	va_end(args);
+	diff = pos->offset % align;
 
-	if (fsxlogf) {
-		va_start(args, fmt);
-		vfprintf(fsxlogf, fmt, args);
-		va_end(args);
+	if (diff) {
+		pos->offset -= diff;
+		pos->size += diff;
 	}
-}
-
-void prterr(char *prefix)
-{
-	prt("%s%s%s\n", prefix, prefix ? ": " : "", strerror(errno));
-}
 
-void log4(int operation, int arg0, int arg1, int arg2, struct timeval *tv)
-{
-	struct log_entry *le;
-
-	le = &oplog[logptr];
-	le->tv = *tv;
-	le->operation = operation;
-	le->args[0] = arg0;
-	le->args[1] = arg1;
-	le->args[2] = arg2;
-	logptr++;
-	logcount++;
-	if (logptr >= LOGSIZE)
-		logptr = 0;
+	if (!pos->size)
+		pos->size = 1;
 }
 
-void logdump(void)
+static void update_file_size(struct file_pos_t const *pos)
 {
-	int i, count, down;
-	struct log_entry *lp;
-
-	prt("LOG DUMP (%d total operations):\n", logcount);
-	if (logcount < LOGSIZE) {
-		i = 0;
-		count = logcount;
-	} else {
-		i = logptr;
-		count = LOGSIZE;
-	}
-	for (; count > 0; count--) {
-		int opnum;
+	if (pos->offset + pos->size > file_size) {
+		file_size = pos->offset + pos->size;
 
-		opnum = i + 1 + (logcount / LOGSIZE) * LOGSIZE;
-		lp = &oplog[i];
-		prt("%d: %lu.%06lu ", opnum, lp->tv.tv_sec, lp->tv.tv_usec);
-
-		switch (lp->operation) {
-		case OP_MAPREAD:
-			prt("MAPREAD  0x%x thru 0x%x (0x%x bytes)",
-			    lp->args[0], lp->args[0] + lp->args[1] - 1,
-			    lp->args[1]);
-			if (badoff >= lp->args[0] && badoff <
-			    lp->args[0] + lp->args[1])
-				prt("\t***RRRR***");
-			break;
-		case OP_MAPWRITE:
-			prt("MAPWRITE 0x%x thru 0x%x (0x%x bytes)",
-			    lp->args[0], lp->args[0] + lp->args[1] - 1,
-			    lp->args[1]);
-			if (badoff >= lp->args[0] && badoff <
-			    lp->args[0] + lp->args[1])
-				prt("\t******WWWW");
-			break;
-		case OP_READ:
-			prt("READ     0x%x thru 0x%x (0x%x bytes)",
-			    lp->args[0], lp->args[0] + lp->args[1] - 1,
-			    lp->args[1]);
-			if (badoff >= lp->args[0] &&
-			    badoff < lp->args[0] + lp->args[1])
-				prt("\t***RRRR***");
-			break;
-		case OP_WRITE:
-			prt("WRITE    0x%x thru 0x%x (0x%x bytes)",
-			    lp->args[0], lp->args[0] + lp->args[1] - 1,
-			    lp->args[1]);
-			if (lp->args[0] > lp->args[2])
-				prt(" HOLE");
-			else if (lp->args[0] + lp->args[1] > lp->args[2])
-				prt(" EXTEND");
-			if ((badoff >= lp->args[0] || badoff >= lp->args[2]) &&
-			    badoff < lp->args[0] + lp->args[1])
-				prt("\t***WWWW");
-			break;
-		case OP_TRUNCATE:
-			down = lp->args[0] < lp->args[1];
-			prt("TRUNCATE %s\tfrom 0x%x to 0x%x",
-			    down ? "DOWN" : "UP", lp->args[1], lp->args[0]);
-			if (badoff >= lp->args[!down] &&
-			    badoff < lp->args[! !down])
-				prt("\t******WWWW");
-			break;
-		case OP_CLOSEOPEN:
-			prt("CLOSE/OPEN");
-			break;
-		case OP_SKIPPED:
-			prt("SKIPPED (no operation)");
-			break;
-		default:
-			prt("BOGUS LOG ENTRY (operation code = %d)!",
-			    lp->operation);
-		}
-		prt("\n");
-		i++;
-		if (i == LOGSIZE)
-			i = 0;
+		tst_res(TINFO, "File size changed: %llu", file_size);
 	}
 }
 
-void save_buffer(char *buffer, off_t bufferlength, int fd)
+static int memory_compare(
+	const char *a,
+	const char *b,
+	const long long offset,
+	const long long size)
 {
-	off_t ret;
-	ssize_t byteswritten;
-
-	if (fd <= 0 || bufferlength == 0)
-		return;
+	int diff;
 
-	if (bufferlength > INT_MAX) {
-		prt("fsx flaw: overflow in save_buffer\n");
-		exit(67);
-	}
-	if (lite) {
-		off_t size_by_seek = lseek(fd, (off_t) 0, SEEK_END);
-		if (size_by_seek == (off_t) - 1)
-			prterr("save_buffer: lseek eof");
-		else if (bufferlength > size_by_seek) {
-			warn("save_buffer: .fsxgood file too short... will "
-			     "save 0x%llx bytes instead of 0x%llx\n",
-			     (unsigned long long)size_by_seek,
-			     (unsigned long long)bufferlength);
-			bufferlength = size_by_seek;
+	for (long long i = 0; i < size; i++) {
+		diff = a[i] - b[i];
+		if (diff) {
+			tst_res(TINFO,
+				"File memory differs at offset=%llu ('%c' != '%c')",
+				offset + i, a[i], b[i]);
+			break;
 		}
 	}
 
-	ret = lseek(fd, (off_t) 0, SEEK_SET);
-	if (ret == (off_t) - 1)
-		prterr("save_buffer: lseek 0");
-
-	byteswritten = write(fd, buffer, (size_t) bufferlength);
-	if (byteswritten != bufferlength) {
-		if (byteswritten == -1)
-			prterr("save_buffer write");
-		else
-			warn("save_buffer: short write, 0x%x bytes instead "
-			     "of 0x%llx\n",
-			     (unsigned)byteswritten,
-			     (unsigned long long)bufferlength);
-	}
+	return diff;
 }
 
-void report_failure(int status)
+static int op_read(void)
 {
-	logdump();
-
-	if (fsxgoodfd) {
-		if (good_buf) {
-			save_buffer(good_buf, file_size, fsxgoodfd);
-			prt("Correct content saved for comparison\n");
-			prt("(maybe hexdump \"%s\" vs \"%s\")\n",
-			    fname, goodfile);
-		}
-		close(fsxgoodfd);
+	if (!file_size) {
+		tst_res(TINFO, "Skipping zero size read");
+		return 0;
 	}
-	exit(status);
-}
 
-#define short_at(cp) ((unsigned short)((*((unsigned char *)(cp)) << 8) | \
-				        *(((unsigned char *)(cp)) + 1)))
+	struct file_pos_t pos;
 
-void check_buffers(unsigned offset, unsigned size)
-{
-	unsigned char c, t;
-	unsigned i = 0;
-	unsigned n = 0;
-	unsigned op = 0;
-	unsigned bad = 0;
-
-	if (memcmp(good_buf + offset, temp_buf, size) != 0) {
-		prt("READ BAD DATA: offset = 0x%x, size = 0x%x\n",
-		    offset, size);
-		prt("OFFSET\tGOOD\tBAD\tRANGE\n");
-		while (size > 0) {
-			c = good_buf[offset];
-			t = temp_buf[i];
-			if (c != t) {
-				if (n == 0) {
-					bad = short_at(&temp_buf[i]);
-					prt("%#07x\t%#06x\t%#06x", offset,
-					    short_at(&good_buf[offset]), bad);
-					op = temp_buf[offset & 1 ? i + 1 : i];
-				}
-				n++;
-				badoff = offset;
-			}
-			offset++;
-			i++;
-			size--;
-		}
-		if (n) {
-			prt("\t%#7x\n", n);
-			if (bad)
-				prt("operation# (mod 256) for the bad data "
-				    "may be %u\n", ((unsigned)op & 0xff));
-			else
-				prt("operation# (mod 256) for the bad data "
-				    "unknown, check HOLE and EXTEND ops\n");
-		} else
-			prt("????????????????\n");
-		report_failure(110);
-	}
-}
+	op_file_position(file_size, op_read_align, &pos);
 
-struct test_file {
-	char *path;
-	int fd;
-} *test_files = NULL;
+	tst_res(TINFO,
+		"Reading at offset=%llu, size=%llu",
+		pos.offset,
+		pos.size);
 
-int num_test_files = 0;
-enum fd_iteration_policy {
-	FD_SINGLE,
-	FD_ROTATE,
-	FD_RANDOM,
-};
-int fd_policy = FD_RANDOM;
-int fd_last = 0;
+	memset(temp_buff, 0, file_max_size);
 
-struct test_file *get_tf(void)
-{
-	unsigned index = 0;
-
-	switch (fd_policy) {
-	case FD_ROTATE:
-		index = fd_last++;
-		break;
-	case FD_RANDOM:
-		index = random();
-		break;
-	case FD_SINGLE:
-		index = 0;
-		break;
-	default:
-		prt("unknown policy");
-		exit(1);
-		break;
-	}
-	return &test_files[index % num_test_files];
-}
+	SAFE_LSEEK(file_desc, (off_t)pos.offset, SEEK_SET);
+	SAFE_READ(0, file_desc, temp_buff, pos.size);
 
-void assign_fd_policy(char *policy)
-{
-	if (!strcmp(policy, "random"))
-		fd_policy = FD_RANDOM;
-	else if (!strcmp(policy, "rotate"))
-		fd_policy = FD_ROTATE;
-	else {
-		prt("unknown -I policy: '%s'\n", policy);
-		exit(1);
-	}
-}
+	int ret = memory_compare(
+		file_buff + pos.offset,
+		temp_buff,
+		pos.offset,
+		pos.size);
 
-int get_fd(void)
-{
-	struct test_file *tf = get_tf();
-	return tf->fd;
+	if (ret)
+		return -1;
+
+	return 1;
 }
 
-void open_test_files(char **argv, int argc)
+static int op_write(void)
 {
-	struct test_file *tf;
-	int i;
+	if (file_size >= file_max_size) {
+		tst_res(TINFO, "Skipping max size write");
+		return 0;
+	}
 
-	num_test_files = argc;
-	if (num_test_files == 1)
-		fd_policy = FD_SINGLE;
+	struct file_pos_t pos;
+	char data;
 
-	test_files = calloc(num_test_files, sizeof(*test_files));
-	if (test_files == NULL) {
-		prterr("reallocating space for test files");
-		exit(1);
-	}
+	op_file_position(file_max_size, op_write_align, &pos);
 
-	for (i = 0, tf = test_files; i < num_test_files; i++, tf++) {
+	for (long long i = 0; i < pos.size; i++) {
+		data = random() % 10 + 'a';
 
-		tf->path = argv[i];
-		tf->fd = open(tf->path, O_RDWR | (lite ? 0 : O_CREAT | O_TRUNC),
-			      0666);
-		if (tf->fd < 0) {
-			prterr(tf->path);
-			exit(91);
-		}
+		file_buff[pos.offset + i] = data;
+		temp_buff[i] = data;
 	}
 
-	if (quiet || fd_policy == FD_SINGLE)
-		return;
+	tst_res(TINFO,
+		"Writing at offset=%llu, size=%llu",
+		pos.offset,
+		pos.size);
 
-	for (i = 0, tf = test_files; i < num_test_files; i++, tf++)
-		prt("fd %d: %s\n", i, tf->path);
-}
+	SAFE_LSEEK(file_desc, (off_t)pos.offset, SEEK_SET);
+	SAFE_WRITE(SAFE_WRITE_ALL, file_desc, temp_buff, pos.size);
 
-void close_test_files(void)
-{
-	int i;
-	struct test_file *tf;
+	update_file_size(&pos);
 
-	for (i = 0, tf = test_files; i < num_test_files; i++, tf++) {
-		if (close(tf->fd)) {
-			prterr("close");
-			report_failure(99);
-		}
-	}
+	return 1;
 }
 
-void check_size(void)
+static int op_truncate(void)
 {
-	struct stat statbuf;
-	off_t size_by_seek;
-	int fd = get_fd();
+	struct file_pos_t pos;
 
-	if (fstat(fd, &statbuf)) {
-		prterr("check_size: fstat");
-		statbuf.st_size = -1;
-	}
-	size_by_seek = lseek(fd, (off_t) 0, SEEK_END);
-	if (file_size != statbuf.st_size || file_size != size_by_seek) {
-		prt("Size error: expected 0x%llx stat 0x%llx seek 0x%llx\n",
-		    (unsigned long long)file_size,
-		    (unsigned long long)statbuf.st_size,
-		    (unsigned long long)size_by_seek);
-		report_failure(120);
-	}
-}
+	op_file_position(file_max_size, op_trunc_align, &pos);
 
-void check_trunc_hack(void)
-{
-	struct stat statbuf;
-	int fd = get_fd();
-
-	ftruncate(fd, (off_t) 0);
-	ftruncate(fd, (off_t) 100000);
-	if (fstat(fd, &statbuf)) {
-		prterr("trunc_hack: fstat");
-		statbuf.st_size = -1;
-	}
-	if (statbuf.st_size != (off_t) 100000) {
-		prt("no extend on truncate! not posix!\n");
-		exit(130);
-	}
-	ftruncate(fd, 0);
-}
+	file_size = pos.offset + pos.size;
 
-static char *tf_buf = NULL;
-static int max_tf_len = 0;
+	tst_res(TINFO, "Truncating to %llu", file_size);
 
-void alloc_tf_buf(void)
-{
-	char dummy = '\0';
-	int highest = num_test_files - 1;
-	int len;
-
-	len = snprintf(&dummy, 0, "%u ", highest);
-	if (len < 1) {
-		prterr("finding max tf_buf");
-		exit(1);
-	}
-	len++;
-	tf_buf = malloc(len);
-	if (tf_buf == NULL) {
-		prterr("allocating tf_buf");
-		exit(1);
-	}
-	max_tf_len = snprintf(tf_buf, len, "%u ", highest);
-	if (max_tf_len < 1) {
-		prterr("fiding max_tv_len\n");
-		exit(1);
-	}
-	if (max_tf_len != len - 1) {
-		warn("snprintf() gave %d instead of %d?\n",
-		     max_tf_len, len - 1);
-		exit(1);
-	}
-}
+	SAFE_FTRUNCATE(file_desc, file_size);
+	memset(file_buff + file_size, 0, file_max_size - file_size);
 
-char *fill_tf_buf(struct test_file *tf)
-{
-	if (tf_buf == NULL)
-		alloc_tf_buf();
-
-	sprintf(tf_buf, "%lu ", (unsigned long)(tf - test_files));
-	return tf_buf;
-}
-
-void
-output_line(struct test_file *tf, int op, unsigned offset,
-	    unsigned size, struct timeval *tv)
-{
-	char *tf_num = "";
-
-	char *ops[] = {
-		[OP_READ] = "read",
-		[OP_WRITE] = "write",
-		[OP_TRUNCATE] = "trunc from",
-		[OP_MAPREAD] = "mapread",
-		[OP_MAPWRITE] = "mapwrite",
-	};
-
-	/* W. */
-	if (!(!quiet && ((progressinterval &&
-			  testcalls % progressinterval == 0) ||
-			 (debug &&
-			  (monitorstart == -1 ||
-			   (offset + size > monitorstart &&
-			    (monitorend == -1 || offset <= monitorend)))))))
-		return;
-
-	if (fd_policy != FD_SINGLE)
-		tf_num = fill_tf_buf(tf);
-
-	prt("%06lu %lu.%06lu %.*s%-10s %#08x %s %#08x\t(0x%x bytes)\n",
-	    testcalls, tv->tv_sec, tv->tv_usec, max_tf_len,
-	    tf_num, ops[op],
-	    offset, op == OP_TRUNCATE ? " to " : "thru",
-	    offset + size - 1, size);
+	return 1;
 }
 
-void doread(unsigned offset, unsigned size)
+static int op_map_read(void)
 {
-	struct timeval t;
-	off_t ret;
-	unsigned iret;
-	struct test_file *tf = get_tf();
-	int fd = tf->fd;
-
-	offset -= offset % readbdy;
-	gettimeofday(&t, NULL);
-	if (size == 0) {
-		if (!quiet && testcalls > simulatedopcount)
-			prt("skipping zero size read\n");
-		log4(OP_SKIPPED, OP_READ, offset, size, &t);
-		return;
-	}
-	if (size + offset > file_size) {
-		if (!quiet && testcalls > simulatedopcount)
-			prt("skipping seek/read past end of file\n");
-		log4(OP_SKIPPED, OP_READ, offset, size, &t);
-		return;
+	if (!file_size) {
+		tst_res(TINFO, "Skipping zero size read");
+		return 0;
 	}
 
-	log4(OP_READ, offset, size, 0, &t);
+	struct file_pos_t pos;
+	char *addr;
 
-	if (testcalls <= simulatedopcount)
-		return;
+	op_file_position(file_size, op_read_align, &pos);
+	op_align_pages(&pos);
 
-	output_line(tf, OP_READ, offset, size, &t);
+	tst_res(TINFO,
+		"Map reading at offset=%llu, size=%llu",
+		pos.offset,
+		pos.size);
 
-	ret = lseek(fd, (off_t) offset, SEEK_SET);
-	if (ret == (off_t) - 1) {
-		prterr("doread: lseek");
-		report_failure(140);
-	}
-	iret = read(fd, temp_buf, size);
-	if (!quiet && (debug > 1 &&
-		       (monitorstart == -1 ||
-			(offset + size > monitorstart &&
-			 (monitorend == -1 || offset <= monitorend))))) {
-		gettimeofday(&t, NULL);
-		prt("       %lu.%06lu read done\n", t.tv_sec, t.tv_usec);
-	}
-	if (iret != size) {
-		if (iret == -1)
-			prterr("doread: read");
-		else
-			prt("short read: 0x%x bytes instead of 0x%x\n",
-			    iret, size);
-		report_failure(141);
-	}
-	check_buffers(offset, size);
-}
-
-void domapread(unsigned offset, unsigned size)
-{
-	struct timeval t;
-	unsigned pg_offset;
-	unsigned map_size;
-	char *p;
-	struct test_file *tf = get_tf();
-	int fd = tf->fd;
-
-	offset -= offset % readbdy;
-	gettimeofday(&t, NULL);
-	if (size == 0) {
-		if (!quiet && testcalls > simulatedopcount)
-			prt("skipping zero size read\n");
-		log4(OP_SKIPPED, OP_MAPREAD, offset, size, &t);
-		return;
-	}
-	if (size + offset > file_size) {
-		if (!quiet && testcalls > simulatedopcount)
-			prt("skipping seek/read past end of file\n");
-		log4(OP_SKIPPED, OP_MAPREAD, offset, size, &t);
-		return;
-	}
-
-	log4(OP_MAPREAD, offset, size, 0, &t);
+	addr = SAFE_MMAP(
+		0, pos.size,
+		PROT_READ,
+		MAP_FILE | MAP_SHARED,
+		file_desc,
+		(off_t)pos.offset);
 
-	if (testcalls <= simulatedopcount)
-		return;
+	memcpy(file_buff + pos.offset, addr, pos.size);
 
-	output_line(tf, OP_MAPREAD, offset, size, &t);
+	int ret = memory_compare(
+		addr,
+		file_buff + pos.offset,
+		pos.offset,
+		pos.size);
 
-	pg_offset = offset & page_mask;
-	map_size = pg_offset + size;
+	SAFE_MUNMAP(addr, pos.size);
+	if (ret)
+		return -1;
 
-	if ((p = mmap(0, map_size, PROT_READ, MAP_FILE | MAP_SHARED, fd,
-		      (off_t) (offset - pg_offset))) == MAP_FAILED) {
-		prterr("domapread: mmap");
-		report_failure(190);
-	}
-	if (!quiet && (debug > 1 &&
-		       (monitorstart == -1 ||
-			(offset + size > monitorstart &&
-			 (monitorend == -1 || offset <= monitorend))))) {
-		gettimeofday(&t, NULL);
-		prt("       %lu.%06lu mmap done\n", t.tv_sec, t.tv_usec);
-	}
-	memcpy(temp_buf, p + pg_offset, size);
-	if (!quiet && (debug > 1 &&
-		       (monitorstart == -1 ||
-			(offset + size > monitorstart &&
-			 (monitorend == -1 || offset <= monitorend))))) {
-		gettimeofday(&t, NULL);
-		prt("       %lu.%06lu memcpy done\n", t.tv_sec, t.tv_usec);
-	}
-	if (munmap(p, map_size) != 0) {
-		prterr("domapread: munmap");
-		report_failure(191);
-	}
-	if (!quiet && (debug > 1 &&
-		       (monitorstart == -1 ||
-			(offset + size > monitorstart &&
-			 (monitorend == -1 || offset <= monitorend))))) {
-		gettimeofday(&t, NULL);
-		prt("       %lu.%06lu munmap done\n", t.tv_sec, t.tv_usec);
-	}
-
-	check_buffers(offset, size);
+	return 1;
 }
 
-void gendata(char *original_buf, char *good_buf, unsigned offset, unsigned size)
+static int op_map_write(void)
 {
-	while (size--) {
-		good_buf[offset] = testcalls % 256;
-		if (offset % 2)
-			good_buf[offset] += original_buf[offset];
-		offset++;
+	if (file_size >= file_max_size) {
+		tst_res(TINFO, "Skipping max size write");
+		return 0;
 	}
-}
 
-void dowrite(unsigned offset, unsigned size)
-{
-	struct timeval t;
-	off_t ret;
-	unsigned iret;
-	struct test_file *tf = get_tf();
-	int fd = tf->fd;
-
-	offset -= offset % writebdy;
-	gettimeofday(&t, NULL);
-	if (size == 0) {
-		if (!quiet && testcalls > simulatedopcount)
-			prt("skipping zero size write\n");
-		log4(OP_SKIPPED, OP_WRITE, offset, size, &t);
-		return;
-	}
+	struct file_pos_t pos;
+	char *addr;
 
-	log4(OP_WRITE, offset, size, file_size, &t);
+	op_file_position(file_max_size, op_write_align, &pos);
+	op_align_pages(&pos);
 
-	gendata(original_buf, good_buf, offset, size);
-	if (file_size < offset + size) {
-		if (file_size < offset)
-			memset(good_buf + file_size, '\0', offset - file_size);
-		file_size = offset + size;
-		if (lite) {
-			warn("Lite file size bug in fsx!");
-			report_failure(149);
-		}
-	}
+	if (file_size < pos.offset + pos.size)
+		SAFE_FTRUNCATE(file_desc, pos.offset + pos.size);
 
-	if (testcalls <= simulatedopcount)
-		return;
+	tst_res(TINFO,
+		"Map writing at offset=%llu, size=%llu",
+		pos.offset,
+		pos.size);
 
-	output_line(tf, OP_WRITE, offset, size, &t);
+	for (long long i = 0; i < pos.size; i++)
+		file_buff[pos.offset + i] = random() % 10 + 'l';
 
-	ret = lseek(fd, (off_t) offset, SEEK_SET);
-	if (ret == (off_t) - 1) {
-		prterr("dowrite: lseek");
-		report_failure(150);
-	}
-	iret = write(fd, good_buf + offset, size);
-	if (!quiet && (debug > 1 &&
-		       (monitorstart == -1 ||
-			(offset + size > monitorstart &&
-			 (monitorend == -1 || offset <= monitorend))))) {
-		gettimeofday(&t, NULL);
-		prt("       %lu.%06lu write done\n", t.tv_sec, t.tv_usec);
-	}
-	if (iret != size) {
-		if (iret == -1)
-			prterr("dowrite: write");
-		else
-			prt("short write: 0x%x bytes instead of 0x%x\n",
-			    iret, size);
-		report_failure(151);
-	}
-}
+	addr = SAFE_MMAP(
+		0, pos.size,
+		PROT_READ | PROT_WRITE,
+		MAP_FILE | MAP_SHARED,
+		file_desc,
+		(off_t)pos.offset);
 
-void domapwrite(unsigned offset, unsigned size)
-{
-	struct timeval t;
-	unsigned pg_offset;
-	unsigned map_size;
-	off_t cur_filesize;
-	char *p;
-	struct test_file *tf = get_tf();
-	int fd = tf->fd;
-
-	offset -= offset % writebdy;
-	gettimeofday(&t, NULL);
-	if (size == 0) {
-		if (!quiet && testcalls > simulatedopcount)
-			prt("skipping zero size write\n");
-		log4(OP_SKIPPED, OP_MAPWRITE, offset, size, &t);
-		return;
-	}
-	cur_filesize = file_size;
-
-	log4(OP_MAPWRITE, offset, size, 0, &t);
-
-	gendata(original_buf, good_buf, offset, size);
-	if (file_size < offset + size) {
-		if (file_size < offset)
-			memset(good_buf + file_size, '\0', offset - file_size);
-		file_size = offset + size;
-		if (lite) {
-			warn("Lite file size bug in fsx!");
-			report_failure(200);
-		}
-	}
+	memcpy(addr, file_buff + pos.offset, pos.size);
+	msync(addr, pos.size, MS_SYNC);
 
-	if (testcalls <= simulatedopcount)
-		return;
+	SAFE_MUNMAP(addr, pos.size);
 
-	output_line(tf, OP_MAPWRITE, offset, size, &t);
+	update_file_size(&pos);
 
-	if (file_size > cur_filesize) {
-		if (ftruncate(fd, file_size) == -1) {
-			prterr("domapwrite: ftruncate");
-			exit(201);
-		}
-		if (!quiet && (debug > 1 &&
-			       (monitorstart == -1 ||
-				(offset + size > monitorstart &&
-				 (monitorend == -1
-				  || offset <= monitorend))))) {
-			gettimeofday(&t, NULL);
-			prt("       %lu.%06lu truncate done\n", t.tv_sec,
-			    t.tv_usec);
-		}
-	}
-	pg_offset = offset & page_mask;
-	map_size = pg_offset + size;
-
-	if ((p =
-	     mmap(0, map_size, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED,
-		  fd, (off_t) (offset - pg_offset))) == MAP_FAILED) {
-		prterr("domapwrite: mmap");
-		report_failure(202);
-	}
-	if (!quiet && (debug > 1 &&
-		       (monitorstart == -1 ||
-			(offset + size > monitorstart &&
-			 (monitorend == -1 || offset <= monitorend))))) {
-		gettimeofday(&t, NULL);
-		prt("       %lu.%06lu mmap done\n", t.tv_sec, t.tv_usec);
-	}
-	memcpy(p + pg_offset, good_buf + offset, size);
-	if (!quiet && (debug > 1 &&
-		       (monitorstart == -1 ||
-			(offset + size > monitorstart &&
-			 (monitorend == -1 || offset <= monitorend))))) {
-		gettimeofday(&t, NULL);
-		prt("       %lu.%06lu memcpy done\n", t.tv_sec, t.tv_usec);
-	}
-	if (msync(p, map_size, 0) != 0) {
-		prterr("domapwrite: msync");
-		report_failure(203);
-	}
-	if (!quiet && (debug > 1 &&
-		       (monitorstart == -1 ||
-			(offset + size > monitorstart &&
-			 (monitorend == -1 || offset <= monitorend))))) {
-		gettimeofday(&t, NULL);
-		prt("       %lu.%06lu msync done\n", t.tv_sec, t.tv_usec);
-	}
-	if (munmap(p, map_size) != 0) {
-		prterr("domapwrite: munmap");
-		report_failure(204);
-	}
-	if (!quiet && (debug > 1 &&
-		       (monitorstart == -1 ||
-			(offset + size > monitorstart &&
-			 (monitorend == -1 || offset <= monitorend))))) {
-		gettimeofday(&t, NULL);
-		prt("       %lu.%06lu munmap done\n", t.tv_sec, t.tv_usec);
-	}
+	return 1;
 }
 
-void dotruncate(unsigned size)
+static void run(void)
 {
-	struct timeval t;
-	int oldsize = file_size;
-	struct test_file *tf = get_tf();
-	int fd = tf->fd;
-
-	size -= size % truncbdy;
-	gettimeofday(&t, NULL);
-	if (size > biggest) {
-		biggest = size;
-		if (!quiet && testcalls > simulatedopcount)
-			prt("truncating to largest ever: 0x%x\n", size);
-	}
+	int op;
+	int ret;
+	int counter = 0;
 
-	log4(OP_TRUNCATE, size, (unsigned)file_size, 0, &t);
+	file_size = 0;
 
-	if (size > file_size)
-		memset(good_buf + file_size, '\0', size - file_size);
-	file_size = size;
+	memset(file_buff, 0, file_max_size);
+	memset(temp_buff, 0, file_max_size);
 
-	if (testcalls <= simulatedopcount)
-		return;
+	SAFE_FTRUNCATE(file_desc, 0);
 
-	output_line(tf, OP_TRUNCATE, oldsize, size, &t);
+	while (counter < op_nums) {
+		op = random() % OP_TOTAL;
 
-	if (ftruncate(fd, (off_t) size) == -1) {
-		prt("ftruncate1: %x\n", size);
-		prterr("dotruncate: ftruncate");
-		report_failure(160);
-	}
-	if (!quiet && debug > 1) {
-		gettimeofday(&t, NULL);
-		prt("       %lu.%06lu trunc done\n", t.tv_sec, t.tv_usec);
-	}
-}
+		switch (op) {
+		case OP_WRITE:
+			ret = op_write();
+			break;
+		case OP_MAPREAD:
+			ret = op_map_read();
+			break;
+		case OP_MAPWRITE:
+			ret = op_map_write();
+			break;
+		case OP_TRUNCATE:
+			ret = op_truncate();
+			break;
+		case OP_READ:
+		default:
+			ret = op_read();
+			break;
+		};
 
-void writefileimage(void)
-{
-	ssize_t iret;
-	int fd = get_fd();
+		if (ret == -1)
+			break;
 
-	if (lseek(fd, (off_t) 0, SEEK_SET) == (off_t) - 1) {
-		prterr("writefileimage: lseek");
-		report_failure(171);
+		counter += ret;
 	}
-	iret = write(fd, good_buf, file_size);
-	if ((off_t) iret != file_size) {
-		if (iret == -1)
-			prterr("writefileimage: write");
-		else
-			prt("short write: 0x%lx bytes instead of 0x%llx\n",
-			    (unsigned long)iret, (unsigned long long)file_size);
-		report_failure(172);
-	}
-	if (lite ? 0 : ftruncate(fd, file_size) == -1) {
-		prt("ftruncate2: %llx\n", (unsigned long long)file_size);
-		prterr("writefileimage: ftruncate");
-		report_failure(173);
-	}
-}
 
-void docloseopen(void)
-{
-	struct timeval t;
-	struct test_file *tf = get_tf();
-
-	if (testcalls <= simulatedopcount)
-		return;
-
-	gettimeofday(&t, NULL);
-	log4(OP_CLOSEOPEN, file_size, (unsigned)file_size, 0, &t);
-
-	if (debug)
-		prt("%06lu %lu.%06lu close/open\n", testcalls, t.tv_sec,
-		    t.tv_usec);
-	if (close(tf->fd)) {
-		prterr("docloseopen: close");
-		report_failure(180);
-	}
-	if (!quiet && debug > 1) {
-		gettimeofday(&t, NULL);
-		prt("       %lu.%06lu close done\n", t.tv_sec, t.tv_usec);
-	}
-	tf->fd = open(tf->path, O_RDWR, 0);
-	if (tf->fd < 0) {
-		prterr("docloseopen: open");
-		report_failure(181);
-	}
-	if (!quiet && debug > 1) {
-		gettimeofday(&t, NULL);
-		prt("       %lu.%06lu open done\n", t.tv_sec, t.tv_usec);
-	}
+	if (counter != op_nums)
+		tst_brk(TFAIL, "Some file operations failed");
+	else
+		tst_res(TPASS, "All file operations succeed");
 }
 
-void test(void)
+static void setup(void)
 {
-	unsigned long offset;
-	unsigned long size = maxoplen;
-	unsigned long rv = random();
-	unsigned long op = rv % (3 + !lite + mapped_writes);
-
-	/* turn off the map read if necessary */
-
-	if (op == 2 && !mapped_reads)
-		op = 0;
-
-	if (simulatedopcount > 0 && testcalls == simulatedopcount)
-		writefileimage();
-
-	testcalls++;
-
-	if (debugstart > 0 && testcalls >= debugstart)
-		debug = 1;
-
-	if (!quiet && testcalls < simulatedopcount && testcalls % 100000 == 0)
-		prt("%lu...\n", testcalls);
-
-	/*
-	 * READ:        op = 0
-	 * WRITE:       op = 1
-	 * MAPREAD:     op = 2
-	 * TRUNCATE:    op = 3
-	 * MAPWRITE:    op = 3 or 4
-	 */
-	if (lite ? 0 : op == 3 && (style & 1) == 0)	/* vanilla truncate? */
-		dotruncate(random() % maxfilelen);
-	else {
-		if (randomoplen)
-			size = random() % (maxoplen + 1);
-		if (lite ? 0 : op == 3)
-			dotruncate(size);
-		else {
-			offset = random();
-			if (op == 1 || op == (lite ? 3 : 4)) {
-				offset %= maxfilelen;
-				if (offset + size > maxfilelen)
-					size = maxfilelen - offset;
-				if (op != 1)
-					domapwrite(offset, size);
-				else
-					dowrite(offset, size);
-			} else {
-				if (file_size)
-					offset %= file_size;
-				else
-					offset = 0;
-				if (offset + size > file_size)
-					size = file_size - offset;
-				if (op != 0)
-					domapread(offset, size);
-				else
-					doread(offset, size);
-			}
-		}
-	}
-	if (sizechecks && testcalls > simulatedopcount)
-		check_size();
-	if (closeprob && (rv >> 3) < (1 << 28) / closeprob)
-		docloseopen();
-}
+	if (tst_parse_filesize(str_file_max_size, &file_max_size, 1, LLONG_MAX))
+		tst_brk(TBROK, "Invalid file size '%s'", str_file_max_size);
 
-void cleanup(int sig)
-{
-	if (sig)
-		prt("signal %d\n", sig);
-	prt("testcalls = %lu\n", testcalls);
-	exit(sig);
-}
+	if (tst_parse_filesize(str_op_max_size, &op_max_size, 1, LLONG_MAX))
+		tst_brk(TBROK, "Invalid maximum size for single operation '%s'", str_op_max_size);
 
-void usage(void)
-{
-	fprintf(stdout, "usage: %s",
-		"fsx [-dnqLOW] [-b opnum] [-c Prob] [-l flen] [-m "
-		"start:end] [-o oplen] [-p progressinterval] [-r readbdy] [-s style] [-t "
-		"truncbdy] [-w writebdy] [-D startingop] [-N numops] [-P dirpath] [-S seed] "
-		"[ -I random|rotate ] fname [additional paths to fname..]\n"
-		"	-b opnum: beginning operation number (default 1)\n"
-		"	-c P: 1 in P chance of file close+open at each op (default infinity)\n"
-		"	-d: debug output for all operations [-d -d = more debugging]\n"
-		"	-l flen: the upper bound on file size (default 262144)\n"
-		"	-m start:end: monitor (print debug) specified byte range (default 0:infinity)\n"
-		"	-n: no verifications of file size\n"
-		"	-o oplen: the upper bound on operation size (default 65536)\n"
-		"	-p progressinterval: debug output at specified operation interval\n"
-		"	-q: quieter operation\n"
-		"	-r readbdy: 4096 would make reads page aligned (default 1)\n"
-		"	-s style: 1 gives smaller truncates (default 0)\n"
-		"	-t truncbdy: 4096 would make truncates page aligned (default 1)\n"
-		"	-w writebdy: 4096 would make writes page aligned (default 1)\n"
-		"	-D startingop: debug output starting at specified operation\n"
-		"	-L: fsxLite - no file creations & no file size changes\n"
-		"	-N numops: total # operations to do (default infinity)\n"
-		"	-O: use oplen (see -o flag) for every op (default random)\n"
-		"	-P: save .fsxlog and .fsxgood files in dirpath (default ./)\n"
-		"	-S seed: for random # generator (default 1) 0 gets timestamp\n"
-		"	-W: mapped write operations DISabled\n"
-		"	-R: read() system calls only (mapped reads disabled)\n"
-		"	-I: When multiple paths to the file are given each operation uses\n"
-		"	    a different path.  Iterate through them in order with 'rotate'\n"
-		"	    or chose then at 'random'.  (defaults to random)\n"
-		"	fname: this filename is REQUIRED (no default)\n");
-	exit(90);
-}
+	if (tst_parse_int(str_op_nums, &op_nums, 1, INT_MAX))
+		tst_brk(TBROK, "Invalid number of operations '%s'", str_op_nums);
 
-int getnum(char *s, char **e)
-{
-	int ret = -1;
-
-	*e = NULL;
-	ret = strtol(s, e, 0);
-	if (*e)
-		switch (**e) {
-		case 'b':
-		case 'B':
-			ret *= 512;
-			*e = *e + 1;
-			break;
-		case 'k':
-		case 'K':
-			ret *= 1024;
-			*e = *e + 1;
-			break;
-		case 'm':
-		case 'M':
-			ret *= 1024 * 1024;
-			*e = *e + 1;
-			break;
-		case 'w':
-		case 'W':
-			ret *= 4;
-			*e = *e + 1;
-			break;
-		}
-	return (ret);
-}
+	if (tst_parse_int(str_op_write_align, &op_write_align, 1, INT_MAX))
+		tst_brk(TBROK, "Invalid memory write alignment factor '%s'", str_op_write_align);
 
-int main(int argc, char **argv)
-{
-	int i, style, ch;
-	char *endp;
-	int dirpath = 0;
-
-	goodfile[0] = 0;
-	logfile[0] = 0;
-
-	page_size = getpagesize();
-	page_mask = page_size - 1;
-
-	setvbuf(stdout, NULL, _IOLBF, 0);	/* line buffered stdout */
-
-	while ((ch = getopt(argc, argv,
-			    "b:c:dl:m:no:p:qr:s:t:w:D:I:LN:OP:RS:W"))
-	       != EOF)
-		switch (ch) {
-		case 'b':
-			simulatedopcount = getnum(optarg, &endp);
-			if (!quiet)
-				fprintf(stdout, "Will begin at operation"
-					"%ld\n", simulatedopcount);
-			if (simulatedopcount == 0)
-				usage();
-			simulatedopcount -= 1;
-			break;
-		case 'c':
-			closeprob = getnum(optarg, &endp);
-			if (!quiet)
-				fprintf(stdout,
-					"Chance of close/open is 1 in %d\n",
-					closeprob);
-			if (closeprob <= 0)
-				usage();
-			break;
-		case 'd':
-			debug++;
-			break;
-		case 'l':
-			maxfilelen = getnum(optarg, &endp);
-			if (maxfilelen <= 0)
-				usage();
-			break;
-		case 'm':
-			monitorstart = getnum(optarg, &endp);
-			if (monitorstart < 0)
-				usage();
-			if (!endp || *endp++ != ':')
-				usage();
-			monitorend = getnum(endp, &endp);
-			if (monitorend < 0)
-				usage();
-			if (monitorend == 0)
-				monitorend = -1;	/* aka infinity */
-			debug = 1;
-		case 'n':
-			sizechecks = 0;
-			break;
-		case 'o':
-			maxoplen = getnum(optarg, &endp);
-			if (maxoplen <= 0)
-				usage();
-			break;
-		case 'p':
-			progressinterval = getnum(optarg, &endp);
-			if (progressinterval < 0)
-				usage();
-			break;
-		case 'q':
-			quiet = 1;
-			break;
-		case 'r':
-			readbdy = getnum(optarg, &endp);
-			if (readbdy <= 0)
-				usage();
-			break;
-		case 's':
-			style = getnum(optarg, &endp);
-			if (style < 0 || style > 1)
-				usage();
-			break;
-		case 't':
-			truncbdy = getnum(optarg, &endp);
-			if (truncbdy <= 0)
-				usage();
-			break;
-		case 'w':
-			writebdy = getnum(optarg, &endp);
-			if (writebdy <= 0)
-				usage();
-			break;
-		case 'D':
-			debugstart = getnum(optarg, &endp);
-			if (debugstart < 1)
-				usage();
-			break;
-		case 'I':
-			assign_fd_policy(optarg);
-			break;
-		case 'L':
-			lite = 1;
-			break;
-		case 'N':
-			numops = getnum(optarg, &endp);
-			if (numops < 0)
-				usage();
-			break;
-		case 'O':
-			randomoplen = 0;
-			break;
-		case 'P':
-			strncpy(goodfile, optarg, sizeof(goodfile));
-			strcat(goodfile, "/");
-			strncpy(logfile, optarg, sizeof(logfile));
-			strcat(logfile, "/");
-			dirpath = 1;
-			break;
-		case 'R':
-			mapped_reads = 0;
-			break;
-		case 'S':
-			seed = getnum(optarg, &endp);
-			if (seed == 0)
-				seed = time(0) % 10000;
-			if (!quiet)
-				fprintf(stdout, "Seed set to %d\n", seed);
-			if (seed < 0)
-				usage();
-			break;
-		case 'W':
-			mapped_writes = 0;
-			if (!quiet)
-				fprintf(stdout, "mapped writes DISABLED\n");
-			break;
+	if (tst_parse_int(str_op_read_align, &op_read_align, 1, INT_MAX))
+		tst_brk(TBROK, "Invalid memory read alignment factor '%s'", str_op_read_align);
 
-		default:
-			usage();
+	if (tst_parse_int(str_op_trunc_align, &op_trunc_align, 1, INT_MAX))
+		tst_brk(TBROK, "Invalid memory truncate alignment factor '%s'", str_op_trunc_align);
 
-		}
-	argc -= optind;
-	argv += optind;
-	if (argc < 1)
-		usage();
-	fname = argv[0];
-
-	signal(SIGHUP, cleanup);
-	signal(SIGINT, cleanup);
-	signal(SIGPIPE, cleanup);
-	signal(SIGALRM, cleanup);
-	signal(SIGTERM, cleanup);
-	signal(SIGXCPU, cleanup);
-	signal(SIGXFSZ, cleanup);
-	signal(SIGVTALRM, cleanup);
-	signal(SIGUSR1, cleanup);
-	signal(SIGUSR2, cleanup);
-
-	initstate(seed, state, 256);
-	setstate(state);
-
-	open_test_files(argv, argc);
-
-	strncat(goodfile, dirpath ? basename(fname) : fname, 256);
-	strcat(goodfile, ".fsxgood");
-	fsxgoodfd = open(goodfile, O_RDWR | O_CREAT | O_TRUNC, 0666);
-	if (fsxgoodfd < 0) {
-		prterr(goodfile);
-		exit(92);
-	}
-	strncat(logfile, dirpath ? basename(fname) : fname, 256);
-	strcat(logfile, ".fsxlog");
-	fsxlogf = fopen(logfile, "w");
-	if (fsxlogf == NULL) {
-		prterr(logfile);
-		exit(93);
-	}
-	if (lite) {
-		off_t ret;
-		int fd = get_fd();
-		file_size = maxfilelen = lseek(fd, (off_t) 0, SEEK_END);
-		if (file_size == (off_t) - 1) {
-			prterr(fname);
-			warn("main: lseek eof");
-			exit(94);
-		}
-		ret = lseek(fd, (off_t) 0, SEEK_SET);
-		if (ret == (off_t) - 1) {
-			prterr(fname);
-			warn("main: lseek 0");
-			exit(95);
-		}
-	}
-	original_buf = malloc(maxfilelen);
-	if (original_buf == NULL)
-		exit(96);
-	for (i = 0; i < maxfilelen; i++)
-		original_buf[i] = random() % 256;
-
-	good_buf = malloc(maxfilelen);
-	if (good_buf == NULL)
-		exit(97);
-	memset(good_buf, '\0', maxfilelen);
-
-	temp_buf = malloc(maxoplen);
-	if (temp_buf == NULL)
-		exit(99);
-	memset(temp_buf, '\0', maxoplen);
-
-	if (lite) {		/* zero entire existing file */
-		ssize_t written;
-		int fd = get_fd();
-
-		written = write(fd, good_buf, (size_t) maxfilelen);
-		if (written != maxfilelen) {
-			if (written == -1) {
-				prterr(fname);
-				warn("main: error on write");
-			} else
-				warn("main: short write, 0x%x bytes instead "
-				     "of 0x%x\n",
-				     (unsigned)written, maxfilelen);
-			exit(98);
-		}
-	} else
-		check_trunc_hack();
+	page_size = (int)sysconf(_SC_PAGESIZE);
+
+	srandom(time(NULL));
 
-	while (numops == -1 || numops--)
-		test();
+	file_desc = SAFE_OPEN(FNAME, O_RDWR | O_CREAT, 0666);
 
-	close_test_files();
-	prt("All operations completed A-OK!\n");
+	file_buff = SAFE_MALLOC(file_max_size);
+	temp_buff = SAFE_MALLOC(file_max_size);
+}
 
-	if (tf_buf)
-		free(tf_buf);
+static void cleanup(void)
+{
+	if (file_buff)
+		free(file_buff);
 
-	free(original_buf);
-	free(good_buf);
-	free(temp_buf);
+	if (temp_buff)
+		free(temp_buff);
 
-	return 0;
+	if (file_desc)
+		SAFE_CLOSE(file_desc);
 }
+
+static struct tst_test test = {
+	.needs_tmpdir = 1,
+	.setup = setup,
+	.cleanup = cleanup,
+	.test_all = run,
+	.options = (struct tst_option[]) {
+		{ "l:", &str_file_max_size, "Maximum size in MB of the test file(s) (default 262144)" },
+		{ "o:", &str_op_max_size, "Maximum size for single operation (default 65536)" },
+		{ "N:", &str_op_nums, "Total # operations to do (default 1000)" },
+		{ "w:", &str_op_write_align, "Write memory page alignment (default 1)" },
+		{ "r:", &str_op_read_align, "Read memory page alignment (default 1)" },
+		{ "t:", &str_op_trunc_align, "Truncate memory page alignment (default 1)" },
+		{},
+	},
+};
diff --git a/testcases/network/nfs/fsx-linux/fsx.sh b/testcases/network/nfs/fsx-linux/fsx.sh
index 9bb46ad6e..dbecbfaf9 100755
--- a/testcases/network/nfs/fsx-linux/fsx.sh
+++ b/testcases/network/nfs/fsx-linux/fsx.sh
@@ -14,10 +14,9 @@  do_test()
 {
 	ITERATIONS=${ITERATIONS:=50000}
 	tst_res TINFO "starting fsx-linux -N $ITERATIONS..."
-	fsx-linux -N $ITERATIONS testfile > fsx-out.log 2>&1
+	fsx-linux -N $ITERATIONS
 	if [ "$?" -ne 0 ]; then
 		tst_res TFAIL "Errors have resulted from this test"
-		cat fsx-out.log
 	else
 		tst_res TPASS "fsx-linux test passed"
 	fi