]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs_copy: actually do directio writes to block devices
authorDarrick J. Wong <djwong@kernel.org>
Wed, 20 Dec 2023 16:53:43 +0000 (08:53 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Fri, 22 Dec 2023 02:29:14 +0000 (18:29 -0800)
Not sure why block device targets don't get O_DIRECT in !buffered mode,
but it's misleading when the copy completes instantly only to stall
forever due to fsync-on-close.  Adjust the "write last sector" code to
allocate a properly aligned buffer.

In removing the onstack buffer for EOD writes, this also corrects the
buffer being larger than necessary -- the old code declared an array of
32768 pointers, whereas all we really need is an aligned 32768-byte
buffer.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
copy/xfs_copy.c

index 2cfb7519e27e46a7669839de57f33d84ca30bee0..0420649de9dc59f608e30f98ea5b3cf61fd3ca00 100644 (file)
@@ -827,13 +827,9 @@ main(int argc, char **argv)
                        do_out(_("Creating file %s\n"), target[i].name);
 
                        open_flags |= O_CREAT;
-                       if (!buffered_output)
-                               open_flags |= O_DIRECT;
                        write_last_block = 1;
                } else if (S_ISREG(statbuf.st_mode))  {
                        open_flags |= O_TRUNC;
-                       if (!buffered_output)
-                               open_flags |= O_DIRECT;
                        write_last_block = 1;
                } else  {
                        /*
@@ -850,6 +846,8 @@ main(int argc, char **argv)
                                exit(1);
                        }
                }
+               if (!buffered_output)
+                       open_flags |= O_DIRECT;
 
                target[i].fd = open(target[i].name, open_flags, 0644);
                if (target[i].fd < 0)  {
@@ -882,14 +880,15 @@ main(int argc, char **argv)
                                }
                        }
                } else  {
-                       char    *lb[XFS_MAX_SECTORSIZE] = { NULL };
+                       char    *lb = memalign(wbuf_align, XFS_MAX_SECTORSIZE);
                        off64_t off;
                        ssize_t len;
 
                        /* ensure device files are sufficiently large */
+                       memset(lb, 0, XFS_MAX_SECTORSIZE);
 
                        off = mp->m_sb.sb_dblocks * source_blocksize;
-                       off -= sizeof(lb);
+                       off -= XFS_MAX_SECTORSIZE;
                        len = pwrite(target[i].fd, lb, XFS_MAX_SECTORSIZE, off);
                        if (len < 0) {
                                do_log(_("%s:  failed to write last block\n"),
@@ -906,6 +905,7 @@ main(int argc, char **argv)
                                        target[i].name);
                                exit(1);
                        }
+                       free(lb);
                }
        }