diff mbox series

[1/9] seek_sanity_test: fix allocation unit detection on XFS realtime

Message ID 165644768327.1045534.10420155448662856970.stgit@magnolia (mailing list archive)
State New, archived
Headers show
Series fstests: random fixes | expand

Commit Message

Darrick J. Wong June 28, 2022, 8:21 p.m. UTC
From: Darrick J. Wong <djwong@kernel.org>

The seek sanity test tries to figure out a file space allocation unit by
calling stat and then using an iterative SEEK_DATA method to try to
detect a smaller blocksize based on SEEK_DATA's consultation of the
filesystem's internal block mapping.  This was put in (AFAICT) because
XFS' stat implementation returns max(filesystem blocksize, PAGESIZE) for
most regular files.

Unfortunately, for a realtime file with an extent size larger than a
single filesystem block this doesn't work at all because block mappings
still work at filesystem block granularity, but allocation units do not.
To fix this, detect the specific case where st_blksize != PAGE_SIZE and
trust the fstat results.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 src/seek_sanity_test.c |   12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

Comments

Christoph Hellwig June 29, 2022, 7:41 a.m. UTC | #1
Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>
liuyd.fnst@fujitsu.com July 28, 2022, 1:37 a.m. UTC | #2
Hi, guys.

Recently I hit a regression during test xfstest. Reverting this commit 
could fix that error.

Reproduce steps (only nfs4.2 has this error):
```
# cat local.config

export TEST_DEV=127.0.0.1:/home/nfs/share0

export TEST_DIR=/mnt/test

export SCRATCH_DEV=127.0.0.1:/home/nfs/share1

export SCRATCH_MNT=/mnt/scratch

export FSX_AVOID="-E"

export NFS_MOUNT_OPTIONS="-o rw,relatime,vers=4.2"


# ./check -nfs generic/285

FSTYP         -- nfs

PLATFORM      -- Linux/aarch64 hpe-apollo80-01-n00 
5.14.0-131.el9.aarch64 #1 SMP PREEMPT_DYNAMIC Mon Jul 18 16:13:44 EDT 2022

MKFS_OPTIONS  -- 127.0.0.1:/home/nfs/share1

MOUNT_OPTIONS -- -o rw,relatime,vers=4.2 -o 
context=system_u:object_r:root_t:s0 127.0.0.1:/home/nfs/share1 /mnt/scratch



generic/285 2s ... [failed, exit status 1]- output mismatch (see 
/root/xfstests/results//generic/285.out.bad)

     --- tests/generic/285.out	2022-07-27 21:07:43.160268552 -0400

     +++ /root/xfstests/results//generic/285.out.bad	2022-07-27 
21:31:27.887090532 -0400

     @@ -1 +1,3 @@

      QA output created by 285

     +seek sanity check failed!

     +(see /root/xfstests/results//generic/285.full for details)

     ...

     (Run 'diff -u /root/xfstests/tests/generic/285.out 
/root/xfstests/results//generic/285.out.bad'  to see the entire diff)

Ran: generic/285

Failures: generic/285

Failed 1 of 1 tests


```

Reverting this commit then test pass.
```
# git revert e861a30255c9780425ee5193325d30882fbe7410
# make -j && make install -j
---snip---
# ./check -nfs generic/285

FSTYP         -- nfs

PLATFORM      -- Linux/aarch64 hpe-apollo80-01-n00 
5.14.0-131.el9.aarch64 #1 SMP PREEMPT_DYNAMIC Mon Jul 18 16:13:44 EDT 2022

MKFS_OPTIONS  -- 127.0.0.1:/home/nfs/share1

MOUNT_OPTIONS -- -o rw,relatime,vers=4.2 -o 
context=system_u:object_r:root_t:s0 127.0.0.1:/home/nfs/share1 /mnt/scratch



generic/285 1s ...  1s

Ran: generic/285

Passed all 1 tests

```

On 6/29/22 04:21, Darrick J. Wong wrote:
> From: Darrick J. Wong <djwong@kernel.org>
> 
> The seek sanity test tries to figure out a file space allocation unit by
> calling stat and then using an iterative SEEK_DATA method to try to
> detect a smaller blocksize based on SEEK_DATA's consultation of the
> filesystem's internal block mapping.  This was put in (AFAICT) because
> XFS' stat implementation returns max(filesystem blocksize, PAGESIZE) for
> most regular files.
> 
> Unfortunately, for a realtime file with an extent size larger than a
> single filesystem block this doesn't work at all because block mappings
> still work at filesystem block granularity, but allocation units do not.
> To fix this, detect the specific case where st_blksize != PAGE_SIZE and
> trust the fstat results.
> 
> Signed-off-by: Darrick J. Wong <djwong@kernel.org>
> ---
>   src/seek_sanity_test.c |   12 +++++++++++-
>   1 file changed, 11 insertions(+), 1 deletion(-)
> 
> 
> diff --git a/src/seek_sanity_test.c b/src/seek_sanity_test.c
> index 76587b7f..1030d0c5 100644
> --- a/src/seek_sanity_test.c
> +++ b/src/seek_sanity_test.c
> @@ -45,6 +45,7 @@ static int get_io_sizes(int fd)
>   	off_t pos = 0, offset = 1;
>   	struct stat buf;
>   	int shift, ret;
> +	int pagesz = sysconf(_SC_PAGE_SIZE);
>   
>   	ret = fstat(fd, &buf);
>   	if (ret) {
> @@ -53,8 +54,16 @@ static int get_io_sizes(int fd)
>   		return ret;
>   	}
>   
> -	/* st_blksize is typically also the allocation size */
> +	/*
> +	 * st_blksize is typically also the allocation size.  However, XFS
> +	 * rounds this up to the page size, so if the stat blocksize is exactly
> +	 * one page, use this iterative algorithm to see if SEEK_DATA will hint
> +	 * at a more precise answer based on the filesystem's (pre)allocation
> +	 * decisions.
> +	 */
>   	alloc_size = buf.st_blksize;
> +	if (alloc_size != pagesz)
> +		goto done;
>   
>   	/* try to discover the actual alloc size */
>   	while (pos == 0 && offset < alloc_size) {
> @@ -80,6 +89,7 @@ static int get_io_sizes(int fd)
>   	if (!shift)
>   		offset += pos ? 0 : 1;
>   	alloc_size = offset;
> +done:
>   	fprintf(stdout, "Allocation size: %ld\n", alloc_size);
>   	return 0;
>   
>
Darrick J. Wong July 28, 2022, 2:31 a.m. UTC | #3
On Thu, Jul 28, 2022 at 01:37:08AM +0000, liuyd.fnst@fujitsu.com wrote:
> Hi, guys.
> 
> Recently I hit a regression during test xfstest. Reverting this commit 
> could fix that error.
> 
> Reproduce steps (only nfs4.2 has this error):
> ```
> # cat local.config
> 
> export TEST_DEV=127.0.0.1:/home/nfs/share0
> 
> export TEST_DIR=/mnt/test
> 
> export SCRATCH_DEV=127.0.0.1:/home/nfs/share1

ahahaaaa, NFS.  I forgot that it sets st_blksize == 1048576, which will
trip this up.

Let me work on a fix to seek_sanity_test.c to make this work for xfs
realtime without breaking NFS.  I /think/ the solution is to replace the
"if (...) goto done;" bit with something that queries FS_IOC_GETXATTR
and XFS_IOC_FSGEOMETRY to figure out if the file being tested is a
realtime file on an XFS filesystem, and set alloc_size to the rt extent
size.

/* Compute the file allocation unit size for an XFS file. */
static int detect_xfs_alloc_unit(int fd)
{
	struct fsxattr fsx;
	struct xfs_fsop_geom fsgeom;
	int ret;

	ret = ioctl(fd, XFS_IOC_FSGEOMETRY, &fsgeom);
	if (ret)
		return -1;

	ret = ioctl(fd, FS_IOC_FSGETXATTR, &fsx);
	if (ret)
		return -1;

	alloc_size = fsgeom.blocksize;
	if (fsx.fsx_xflags & FS_XFLAG_REALTIME)
		alloc_size *= fsgeom.rtextsize;

	return 0;
}

should suffice to fix these testcase on xfs realtime without messing up
nfs.

--D

> export SCRATCH_MNT=/mnt/scratch
> 
> export FSX_AVOID="-E"
> 
> export NFS_MOUNT_OPTIONS="-o rw,relatime,vers=4.2"
> 
> 
> # ./check -nfs generic/285
> 
> FSTYP         -- nfs
> 
> PLATFORM      -- Linux/aarch64 hpe-apollo80-01-n00 
> 5.14.0-131.el9.aarch64 #1 SMP PREEMPT_DYNAMIC Mon Jul 18 16:13:44 EDT 2022
> 
> MKFS_OPTIONS  -- 127.0.0.1:/home/nfs/share1
> 
> MOUNT_OPTIONS -- -o rw,relatime,vers=4.2 -o 
> context=system_u:object_r:root_t:s0 127.0.0.1:/home/nfs/share1 /mnt/scratch
> 
> 
> 
> generic/285 2s ... [failed, exit status 1]- output mismatch (see 
> /root/xfstests/results//generic/285.out.bad)
> 
>      --- tests/generic/285.out	2022-07-27 21:07:43.160268552 -0400
> 
>      +++ /root/xfstests/results//generic/285.out.bad	2022-07-27 
> 21:31:27.887090532 -0400
> 
>      @@ -1 +1,3 @@
> 
>       QA output created by 285
> 
>      +seek sanity check failed!
> 
>      +(see /root/xfstests/results//generic/285.full for details)
> 
>      ...
> 
>      (Run 'diff -u /root/xfstests/tests/generic/285.out 
> /root/xfstests/results//generic/285.out.bad'  to see the entire diff)
> 
> Ran: generic/285
> 
> Failures: generic/285
> 
> Failed 1 of 1 tests
> 
> 
> ```
> 
> Reverting this commit then test pass.
> ```
> # git revert e861a30255c9780425ee5193325d30882fbe7410
> # make -j && make install -j
> ---snip---
> # ./check -nfs generic/285
> 
> FSTYP         -- nfs
> 
> PLATFORM      -- Linux/aarch64 hpe-apollo80-01-n00 
> 5.14.0-131.el9.aarch64 #1 SMP PREEMPT_DYNAMIC Mon Jul 18 16:13:44 EDT 2022
> 
> MKFS_OPTIONS  -- 127.0.0.1:/home/nfs/share1
> 
> MOUNT_OPTIONS -- -o rw,relatime,vers=4.2 -o 
> context=system_u:object_r:root_t:s0 127.0.0.1:/home/nfs/share1 /mnt/scratch
> 
> 
> 
> generic/285 1s ...  1s
> 
> Ran: generic/285
> 
> Passed all 1 tests
> 
> ```
> 
> On 6/29/22 04:21, Darrick J. Wong wrote:
> > From: Darrick J. Wong <djwong@kernel.org>
> > 
> > The seek sanity test tries to figure out a file space allocation unit by
> > calling stat and then using an iterative SEEK_DATA method to try to
> > detect a smaller blocksize based on SEEK_DATA's consultation of the
> > filesystem's internal block mapping.  This was put in (AFAICT) because
> > XFS' stat implementation returns max(filesystem blocksize, PAGESIZE) for
> > most regular files.
> > 
> > Unfortunately, for a realtime file with an extent size larger than a
> > single filesystem block this doesn't work at all because block mappings
> > still work at filesystem block granularity, but allocation units do not.
> > To fix this, detect the specific case where st_blksize != PAGE_SIZE and
> > trust the fstat results.
> > 
> > Signed-off-by: Darrick J. Wong <djwong@kernel.org>
> > ---
> >   src/seek_sanity_test.c |   12 +++++++++++-
> >   1 file changed, 11 insertions(+), 1 deletion(-)
> > 
> > 
> > diff --git a/src/seek_sanity_test.c b/src/seek_sanity_test.c
> > index 76587b7f..1030d0c5 100644
> > --- a/src/seek_sanity_test.c
> > +++ b/src/seek_sanity_test.c
> > @@ -45,6 +45,7 @@ static int get_io_sizes(int fd)
> >   	off_t pos = 0, offset = 1;
> >   	struct stat buf;
> >   	int shift, ret;
> > +	int pagesz = sysconf(_SC_PAGE_SIZE);
> >   
> >   	ret = fstat(fd, &buf);
> >   	if (ret) {
> > @@ -53,8 +54,16 @@ static int get_io_sizes(int fd)
> >   		return ret;
> >   	}
> >   
> > -	/* st_blksize is typically also the allocation size */
> > +	/*
> > +	 * st_blksize is typically also the allocation size.  However, XFS
> > +	 * rounds this up to the page size, so if the stat blocksize is exactly
> > +	 * one page, use this iterative algorithm to see if SEEK_DATA will hint
> > +	 * at a more precise answer based on the filesystem's (pre)allocation
> > +	 * decisions.
> > +	 */
> >   	alloc_size = buf.st_blksize;
> > +	if (alloc_size != pagesz)
> > +		goto done;
> >   
> >   	/* try to discover the actual alloc size */
> >   	while (pos == 0 && offset < alloc_size) {
> > @@ -80,6 +89,7 @@ static int get_io_sizes(int fd)
> >   	if (!shift)
> >   		offset += pos ? 0 : 1;
> >   	alloc_size = offset;
> > +done:
> >   	fprintf(stdout, "Allocation size: %ld\n", alloc_size);
> >   	return 0;
> >   
> >
Darrick J. Wong July 28, 2022, 2:37 a.m. UTC | #4
Does this patch fix NFS for you?

--D
---
From: Darrick J. Wong <djwong@kernel.org>

seek_sanity_test: use XFS ioctls to determine file allocation unit size

liuyd.fnst@fujitsu.com reported that my recent change to the seek sanity
test broke NFS.  I foolishly thought that st_blksize was sufficient to
find the file allocation unit size so that applications could figure out
the SEEK_HOLE granularity.  Replace that with an explicit callout to XFS
ioctls so that xfs realtime will work again.

Fixes: e861a302 ("seek_sanity_test: fix allocation unit detection on XFS realtime")
Reported-by: liuyd.fnst@fujitsu.com
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 src/Makefile           |    4 ++++
 src/seek_sanity_test.c |   40 +++++++++++++++++++++++++++++++---------
 2 files changed, 35 insertions(+), 9 deletions(-)

diff --git a/src/Makefile b/src/Makefile
index 38628a22..b89a7a5e 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -82,6 +82,10 @@ ifeq ($(HAVE_LIBCAP), true)
 LLDLIBS += -lcap
 endif
 
+ifeq ($(HAVE_FSXATTR_XFLAG_HASATTR), yes)
+LCFLAGS += -DHAVE_FSXATTR_XFLAG_HASATTR
+endif
+
 ifeq ($(HAVE_SEEK_DATA), yes)
  ifeq ($(HAVE_FSXATTR_XFLAG_HASATTR), yes)
   ifeq ($(HAVE_NFTW), yes)
diff --git a/src/seek_sanity_test.c b/src/seek_sanity_test.c
index 1030d0c5..b53f4862 100644
--- a/src/seek_sanity_test.c
+++ b/src/seek_sanity_test.c
@@ -40,6 +40,32 @@ static void get_file_system(int fd)
 	}
 }
 
+#ifdef HAVE_FSXATTR_XFLAG_HASATTR
+/* Compute the file allocation unit size for an XFS file. */
+static int detect_xfs_alloc_unit(int fd)
+{
+	struct fsxattr fsx;
+	struct xfs_fsop_geom fsgeom;
+	int ret;
+
+	ret = ioctl(fd, XFS_IOC_FSGEOMETRY, &fsgeom);
+	if (ret)
+		return -1;
+
+	ret = ioctl(fd, FS_IOC_FSGETXATTR, &fsx);
+	if (ret)
+		return -1;
+
+	alloc_size = fsgeom.blocksize;
+	if (fsx.fsx_xflags & FS_XFLAG_REALTIME)
+		alloc_size *= fsgeom.rtextsize;
+
+	return 0;
+}
+#else
+# define detect_xfs_alloc_unit(fd) (-1)
+#endif
+
 static int get_io_sizes(int fd)
 {
 	off_t pos = 0, offset = 1;
@@ -47,6 +73,10 @@ static int get_io_sizes(int fd)
 	int shift, ret;
 	int pagesz = sysconf(_SC_PAGE_SIZE);
 
+	ret = detect_xfs_alloc_unit(fd);
+	if (!ret)
+		goto done;
+
 	ret = fstat(fd, &buf);
 	if (ret) {
 		fprintf(stderr, "  ERROR %d: Failed to find io blocksize\n",
@@ -54,16 +84,8 @@ static int get_io_sizes(int fd)
 		return ret;
 	}
 
-	/*
-	 * st_blksize is typically also the allocation size.  However, XFS
-	 * rounds this up to the page size, so if the stat blocksize is exactly
-	 * one page, use this iterative algorithm to see if SEEK_DATA will hint
-	 * at a more precise answer based on the filesystem's (pre)allocation
-	 * decisions.
-	 */
+	/* st_blksize is typically also the allocation size */
 	alloc_size = buf.st_blksize;
-	if (alloc_size != pagesz)
-		goto done;
 
 	/* try to discover the actual alloc size */
 	while (pos == 0 && offset < alloc_size) {
liuyd.fnst@fujitsu.com July 28, 2022, 3:38 a.m. UTC | #5
Hi, Darrick.


On 7/28/22 10:37, Darrick J. Wong wrote:
> Does this patch fix NFS for you?

It works for me. Thanks.
BTW. It has conflict during "git am". Looks like your branch are ahead 
of master.

> 
> --D
> ---
> From: Darrick J. Wong <djwong@kernel.org>
> 
> seek_sanity_test: use XFS ioctls to determine file allocation unit size
> 
> liuyd.fnst@fujitsu.com reported that my recent change to the seek sanity
> test broke NFS.  I foolishly thought that st_blksize was sufficient to
> find the file allocation unit size so that applications could figure out
> the SEEK_HOLE granularity.  Replace that with an explicit callout to XFS
> ioctls so that xfs realtime will work again.
> 
> Fixes: e861a302 ("seek_sanity_test: fix allocation unit detection on XFS realtime")
> Reported-by: liuyd.fnst@fujitsu.com
> Signed-off-by: Darrick J. Wong <djwong@kernel.org>
> ---
>   src/Makefile           |    4 ++++
>   src/seek_sanity_test.c |   40 +++++++++++++++++++++++++++++++---------
>   2 files changed, 35 insertions(+), 9 deletions(-)
> 
> diff --git a/src/Makefile b/src/Makefile
> index 38628a22..b89a7a5e 100644
> --- a/src/Makefile
> +++ b/src/Makefile
> @@ -82,6 +82,10 @@ ifeq ($(HAVE_LIBCAP), true)
>   LLDLIBS += -lcap
>   endif
>   
> +ifeq ($(HAVE_FSXATTR_XFLAG_HASATTR), yes)
> +LCFLAGS += -DHAVE_FSXATTR_XFLAG_HASATTR
> +endif
> +
>   ifeq ($(HAVE_SEEK_DATA), yes)
>    ifeq ($(HAVE_FSXATTR_XFLAG_HASATTR), yes)
>     ifeq ($(HAVE_NFTW), yes)
> diff --git a/src/seek_sanity_test.c b/src/seek_sanity_test.c
> index 1030d0c5..b53f4862 100644
> --- a/src/seek_sanity_test.c
> +++ b/src/seek_sanity_test.c
> @@ -40,6 +40,32 @@ static void get_file_system(int fd)
>   	}
>   }
>   
> +#ifdef HAVE_FSXATTR_XFLAG_HASATTR
> +/* Compute the file allocation unit size for an XFS file. */
> +static int detect_xfs_alloc_unit(int fd)
> +{
> +	struct fsxattr fsx;
> +	struct xfs_fsop_geom fsgeom;
> +	int ret;
> +
> +	ret = ioctl(fd, XFS_IOC_FSGEOMETRY, &fsgeom);
> +	if (ret)
> +		return -1;
> +
> +	ret = ioctl(fd, FS_IOC_FSGETXATTR, &fsx);
> +	if (ret)
> +		return -1;
> +
> +	alloc_size = fsgeom.blocksize;
> +	if (fsx.fsx_xflags & FS_XFLAG_REALTIME)
> +		alloc_size *= fsgeom.rtextsize;
> +
> +	return 0;
> +}
> +#else
> +# define detect_xfs_alloc_unit(fd) (-1)
> +#endif
> +
>   static int get_io_sizes(int fd)
>   {
>   	off_t pos = 0, offset = 1;
> @@ -47,6 +73,10 @@ static int get_io_sizes(int fd)
>   	int shift, ret;
>   	int pagesz = sysconf(_SC_PAGE_SIZE);
>   
> +	ret = detect_xfs_alloc_unit(fd);
> +	if (!ret)
> +		goto done;
> +
>   	ret = fstat(fd, &buf);
>   	if (ret) {
>   		fprintf(stderr, "  ERROR %d: Failed to find io blocksize\n",
> @@ -54,16 +84,8 @@ static int get_io_sizes(int fd)
>   		return ret;
>   	}
>   
> -	/*
> -	 * st_blksize is typically also the allocation size.  However, XFS
> -	 * rounds this up to the page size, so if the stat blocksize is exactly
> -	 * one page, use this iterative algorithm to see if SEEK_DATA will hint
> -	 * at a more precise answer based on the filesystem's (pre)allocation
> -	 * decisions.
> -	 */
> +	/* st_blksize is typically also the allocation size */
>   	alloc_size = buf.st_blksize;
> -	if (alloc_size != pagesz)
> -		goto done;
>   
>   	/* try to discover the actual alloc size */
>   	while (pos == 0 && offset < alloc_size) {
Darrick J. Wong July 28, 2022, 3:54 a.m. UTC | #6
On Thu, Jul 28, 2022 at 03:38:38AM +0000, liuyd.fnst@fujitsu.com wrote:
> Hi, Darrick.
> 
> 
> On 7/28/22 10:37, Darrick J. Wong wrote:
> > Does this patch fix NFS for you?
> 
> It works for me. Thanks.
> BTW. It has conflict during "git am". Looks like your branch are ahead 
> of master.

Yes, I base my development branch off of for-next nowadays.  Thanks for
the report, I'll add a tested-by if that's ok and send it out as a bug
fix.

--D

> > 
> > --D
> > ---
> > From: Darrick J. Wong <djwong@kernel.org>
> > 
> > seek_sanity_test: use XFS ioctls to determine file allocation unit size
> > 
> > liuyd.fnst@fujitsu.com reported that my recent change to the seek sanity
> > test broke NFS.  I foolishly thought that st_blksize was sufficient to
> > find the file allocation unit size so that applications could figure out
> > the SEEK_HOLE granularity.  Replace that with an explicit callout to XFS
> > ioctls so that xfs realtime will work again.
> > 
> > Fixes: e861a302 ("seek_sanity_test: fix allocation unit detection on XFS realtime")
> > Reported-by: liuyd.fnst@fujitsu.com
> > Signed-off-by: Darrick J. Wong <djwong@kernel.org>
> > ---
> >   src/Makefile           |    4 ++++
> >   src/seek_sanity_test.c |   40 +++++++++++++++++++++++++++++++---------
> >   2 files changed, 35 insertions(+), 9 deletions(-)
> > 
> > diff --git a/src/Makefile b/src/Makefile
> > index 38628a22..b89a7a5e 100644
> > --- a/src/Makefile
> > +++ b/src/Makefile
> > @@ -82,6 +82,10 @@ ifeq ($(HAVE_LIBCAP), true)
> >   LLDLIBS += -lcap
> >   endif
> >   
> > +ifeq ($(HAVE_FSXATTR_XFLAG_HASATTR), yes)
> > +LCFLAGS += -DHAVE_FSXATTR_XFLAG_HASATTR
> > +endif
> > +
> >   ifeq ($(HAVE_SEEK_DATA), yes)
> >    ifeq ($(HAVE_FSXATTR_XFLAG_HASATTR), yes)
> >     ifeq ($(HAVE_NFTW), yes)
> > diff --git a/src/seek_sanity_test.c b/src/seek_sanity_test.c
> > index 1030d0c5..b53f4862 100644
> > --- a/src/seek_sanity_test.c
> > +++ b/src/seek_sanity_test.c
> > @@ -40,6 +40,32 @@ static void get_file_system(int fd)
> >   	}
> >   }
> >   
> > +#ifdef HAVE_FSXATTR_XFLAG_HASATTR
> > +/* Compute the file allocation unit size for an XFS file. */
> > +static int detect_xfs_alloc_unit(int fd)
> > +{
> > +	struct fsxattr fsx;
> > +	struct xfs_fsop_geom fsgeom;
> > +	int ret;
> > +
> > +	ret = ioctl(fd, XFS_IOC_FSGEOMETRY, &fsgeom);
> > +	if (ret)
> > +		return -1;
> > +
> > +	ret = ioctl(fd, FS_IOC_FSGETXATTR, &fsx);
> > +	if (ret)
> > +		return -1;
> > +
> > +	alloc_size = fsgeom.blocksize;
> > +	if (fsx.fsx_xflags & FS_XFLAG_REALTIME)
> > +		alloc_size *= fsgeom.rtextsize;
> > +
> > +	return 0;
> > +}
> > +#else
> > +# define detect_xfs_alloc_unit(fd) (-1)
> > +#endif
> > +
> >   static int get_io_sizes(int fd)
> >   {
> >   	off_t pos = 0, offset = 1;
> > @@ -47,6 +73,10 @@ static int get_io_sizes(int fd)
> >   	int shift, ret;
> >   	int pagesz = sysconf(_SC_PAGE_SIZE);
> >   
> > +	ret = detect_xfs_alloc_unit(fd);
> > +	if (!ret)
> > +		goto done;
> > +
> >   	ret = fstat(fd, &buf);
> >   	if (ret) {
> >   		fprintf(stderr, "  ERROR %d: Failed to find io blocksize\n",
> > @@ -54,16 +84,8 @@ static int get_io_sizes(int fd)
> >   		return ret;
> >   	}
> >   
> > -	/*
> > -	 * st_blksize is typically also the allocation size.  However, XFS
> > -	 * rounds this up to the page size, so if the stat blocksize is exactly
> > -	 * one page, use this iterative algorithm to see if SEEK_DATA will hint
> > -	 * at a more precise answer based on the filesystem's (pre)allocation
> > -	 * decisions.
> > -	 */
> > +	/* st_blksize is typically also the allocation size */
> >   	alloc_size = buf.st_blksize;
> > -	if (alloc_size != pagesz)
> > -		goto done;
> >   
> >   	/* try to discover the actual alloc size */
> >   	while (pos == 0 && offset < alloc_size) {
diff mbox series

Patch

diff --git a/src/seek_sanity_test.c b/src/seek_sanity_test.c
index 76587b7f..1030d0c5 100644
--- a/src/seek_sanity_test.c
+++ b/src/seek_sanity_test.c
@@ -45,6 +45,7 @@  static int get_io_sizes(int fd)
 	off_t pos = 0, offset = 1;
 	struct stat buf;
 	int shift, ret;
+	int pagesz = sysconf(_SC_PAGE_SIZE);
 
 	ret = fstat(fd, &buf);
 	if (ret) {
@@ -53,8 +54,16 @@  static int get_io_sizes(int fd)
 		return ret;
 	}
 
-	/* st_blksize is typically also the allocation size */
+	/*
+	 * st_blksize is typically also the allocation size.  However, XFS
+	 * rounds this up to the page size, so if the stat blocksize is exactly
+	 * one page, use this iterative algorithm to see if SEEK_DATA will hint
+	 * at a more precise answer based on the filesystem's (pre)allocation
+	 * decisions.
+	 */
 	alloc_size = buf.st_blksize;
+	if (alloc_size != pagesz)
+		goto done;
 
 	/* try to discover the actual alloc size */
 	while (pos == 0 && offset < alloc_size) {
@@ -80,6 +89,7 @@  static int get_io_sizes(int fd)
 	if (!shift)
 		offset += pos ? 0 : 1;
 	alloc_size = offset;
+done:
 	fprintf(stdout, "Allocation size: %ld\n", alloc_size);
 	return 0;