- From e946c4be6e09dd7697e2c9ca0acb0c9f1cb3160b Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Tue, 6 May 2025 17:41:27 +0200
- Subject: [PATCH 1/2] tests: winclonefile: Add --clonechunksize option to test
- NFS CLONE offsets
- winclonefile: Add --clonechunksize option to test NFSv4.2 CLONE
- offsets.
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- tests/sparsefiles/multisparsefiletest.ksh | 39 ++++-
- tests/winclonefile/winclonefile.c | 199 +++++++++++++++-------
- 2 files changed, 168 insertions(+), 70 deletions(-)
- diff --git a/tests/sparsefiles/multisparsefiletest.ksh b/tests/sparsefiles/multisparsefiletest.ksh
- index b2e7bd5..3994c1f 100644
- --- a/tests/sparsefiles/multisparsefiletest.ksh
- +++ b/tests/sparsefiles/multisparsefiletest.ksh
- @@ -186,7 +186,8 @@ function multisparsefiletest1
- rm -f \
- 'sparsefile2.bin' \
- 'sparsefile2_cpsparse.bin' \
- - 'sparsefile2_cloned.bin'
- + 'sparsefile2_cloned_full.bin' \
- + 'sparsefile2_cloned_1mbchunks.bin'
- c.testlabel=''
- if (( c.i == 0 )) ; then
- @@ -220,7 +221,14 @@ function multisparsefiletest1
- typeset tstmod
- - for tstmod in 'plainfile' 'cp_sparseauto' 'cloned' ; do
- + typeset -a tstmodlist=(
- + 'plainfile'
- + 'cp_sparseauto'
- + 'cloned_full'
- + 'cloned_1mbchunks'
- + )
- +
- + for tstmod in "${tstmodlist[@]}" ; do
- printf '# Test %d '%s' generated\n' c.i "${c.testlabel}/$tstmod"
- case "${tstmod}" in
- @@ -231,10 +239,23 @@ function multisparsefiletest1
- /usr/bin/cp --sparse='auto' 'sparsefile2.bin' 'sparsefile2_cpsparse.bin'
- c.stdout="$(lssparse -H 'sparsefile2_cpsparse.bin')"
- ;;
- - 'cloned')
- + 'cloned_full')
- + if $test_cloning ; then
- + winclonefile.exe 'sparsefile2.bin' 'sparsefile2_cloned_full.bin' 1>'/dev/null'
- + c.stdout="$(lssparse -H 'sparsefile2_cloned_full.bin')"
- + else
- + printf "# Test '%s' SKIPPED\n" "${c.testlabel}/${tstmod}"
- + (( tests_skipped++ ))
- + continue
- + fi
- + ;;
- + 'cloned_1mbchunks')
- if $test_cloning ; then
- - winclonefile.exe 'sparsefile2.bin' 'sparsefile2_cloned.bin' 1>'/dev/null'
- - c.stdout="$(lssparse -H 'sparsefile2_cloned.bin')"
- + winclonefile.exe \
- + --clonechunksize $((1024*1024)) \
- + 'sparsefile2.bin' \
- + 'sparsefile2_cloned_1mbchunks.bin' 1>'/dev/null'
- + c.stdout="$(lssparse -H 'sparsefile2_cloned_1mbchunks.bin')"
- else
- printf "# Test '%s' SKIPPED\n" "${c.testlabel}/${tstmod}"
- (( tests_skipped++ ))
- @@ -242,7 +263,7 @@ function multisparsefiletest1
- fi
- ;;
- *)
- - printf -u2 "Unknown test mod"
- + print -u2 -f 'Unknown test mod\n'
- ;;
- esac
- @@ -269,6 +290,11 @@ function multisparsefiletest1
- return 0
- }
- +
- +#
- +# main
- +#
- +builtin rm
- builtin wc
- #
- @@ -276,6 +302,7 @@ builtin wc
- # - Test whether filesystem supports block cloning and
- # winclonefile.exe is available
- # - variable block size
- +# - verify file sizes (original vs copy/clone)
- # - tests for sparse files >= 2GB, 4GB, 16GB
- #
- typeset test_cloning=false
- diff --git a/tests/winclonefile/winclonefile.c b/tests/winclonefile/winclonefile.c
- index 7d2d490..39b019b 100644
- --- a/tests/winclonefile/winclonefile.c
- +++ b/tests/winclonefile/winclonefile.c
- @@ -39,10 +39,9 @@
- #if 1
- /*
- - * MinGW include do not define |DUPLICATE_EXTENTS_DATA| yet,
- - * see https://github.com/mingw-w64/mingw-w64/issues/90
- - * ("[mingw-w64/mingw-w64] No |DUPLICATE_EXTENTS_DATA|/
- - * |DUPLICATE_EXTENTS_DATA_EX| in MinGW includes")
- + * MinGW include do not define |DUPLICATE_EXTENTS_DATA| yet, see
- + * https://github.com/mingw-w64/mingw-w64/issues/90 ("[mingw-w64/mingw-w64]
- + * No |DUPLICATE_EXTENTS_DATA|/ |DUPLICATE_EXTENTS_DATA_EX| in MinGW includes")
- */
- typedef struct _DUPLICATE_EXTENTS_DATA {
- HANDLE FileHandle;
- @@ -77,6 +76,66 @@ PrintWin32Error(const char *functionName, DWORD lasterrCode)
- LocalFree(lpMsgBuf);
- }
- +static
- +LONGLONG getFsClusterSize(HANDLE h)
- +{
- + BOOL bResult;
- + FILE_STORAGE_INFO fsi = { 0 };
- + bResult = GetFileInformationByHandleEx(h,
- + FileStorageInfo, &fsi, sizeof(fsi));
- + if (!bResult)
- + return -1LL;
- +
- + return fsi.PhysicalBytesPerSectorForAtomicity;
- +}
- +
- +static
- +BOOL fsctlduplicateextentstofile(HANDLE hSrc, HANDLE hDst,
- + LONGLONG srcOffset, LONGLONG dstOffset, ULONG byteCount)
- +{
- + BOOL bResult;
- + DUPLICATE_EXTENTS_DATA ded = {
- + .FileHandle = hSrc,
- + .SourceFileOffset.QuadPart = srcOffset,
- + .TargetFileOffset.QuadPart = dstOffset,
- + .ByteCount.QuadPart = byteCount
- + };
- + DWORD bytesReturnedDummy = 0; /* dummy var */
- +
- + bResult = DeviceIoControl(
- + hDst,
- + FSCTL_DUPLICATE_EXTENTS_TO_FILE,
- + &ded,
- + sizeof(ded),
- + NULL,
- + 0,
- + &bytesReturnedDummy,
- + NULL);
- +
- + return bResult;
- +}
- +
- +static
- +LONGLONG getFileSize(HANDLE h)
- +{
- + BOOL bResult;
- + LARGE_INTEGER fileSize = { .QuadPart = 0LL };
- + bResult = GetFileSizeEx(h, &fileSize);
- + if (!bResult)
- + return -1LL;
- +
- + return fileSize.QuadPart;
- +}
- +
- +
- +static
- +void print_usage(const char *av0)
- +{
- + (void)fprintf(stderr,
- + "Usage: %s [--clonechunksize <numbytes>] <infile> <outfile>\n",
- + av0);
- +}
- +
- int
- main(int ac, char *av[])
- {
- @@ -85,27 +144,42 @@ main(int ac, char *av[])
- HANDLE hSrc = INVALID_HANDLE_VALUE;
- HANDLE hDst = INVALID_HANDLE_VALUE;
- BOOL bResult = FALSE;
- - LARGE_INTEGER fileSize = { .QuadPart = 0LL };
- - DUPLICATE_EXTENTS_DATA ded = {
- - .FileHandle = INVALID_HANDLE_VALUE,
- - .SourceFileOffset.QuadPart = 0LL,
- - .TargetFileOffset.QuadPart = 0LL,
- - .ByteCount.QuadPart = 0LL
- - };
- - DWORD bytesReturnedDummy = 0; /* dummy var */
- + LONGLONG fileSize;
- + LONGLONG maxCloneChunkSize =
- + 1024LL*1024LL*1024LL*1024LL*1024LL; /* 1PB */
- - if (ac != 3) {
- - (void)fprintf(stderr, "Usage: %s <infile> <outfile>\n", av[0]);
- - return (EXIT_USAGE);
- + if (ac == 3) {
- + srcFileName = av[1];
- + dstFileName = av[2];
- }
- + else if (ac == 5) {
- + if (strcmp(av[1], "--clonechunksize") != 0) {
- + print_usage(av[0]);
- + return (EXIT_USAGE);
- + }
- - srcFileName = av[1];
- - dstFileName = av[2];
- + maxCloneChunkSize = atoll(av[2]);
- + srcFileName = av[3];
- + dstFileName = av[4];
- + }
- + else {
- + print_usage(av[0]);
- + return (EXIT_USAGE);
- + }
- - (void)printf("# Attempting to clone existing file '%s' to '%s' "
- - "using FSCTL_DUPLICATE_EXTENTS_TO_FILE...\n",
- - srcFileName,
- - dstFileName);
- + if (ac == 3) {
- + (void)printf("# Attempting to clone existing file '%s' to '%s' using "
- + "FSCTL_DUPLICATE_EXTENTS_TO_FILE...\n",
- + srcFileName,
- + dstFileName);
- + }
- + else if (ac == 5) {
- + (void)printf("# Attempting to clone existing file '%s' to '%s' in "
- + "%lld byte chunks using FSCTL_DUPLICATE_EXTENTS_TO_FILE...\n",
- + srcFileName,
- + dstFileName,
- + maxCloneChunkSize);
- + }
- hSrc = CreateFileA(
- srcFileName,
- @@ -124,36 +198,31 @@ main(int ac, char *av[])
- (void)printf("# Successfully opened existing source file '%s'.\n",
- srcFileName);
- - bResult = GetFileSizeEx(hSrc, &fileSize);
- - if (!bResult) {
- + fileSize = getFileSize(hSrc);
- + if (fileSize < 0LL) {
- PrintWin32Error("GetFileSizeEx",
- GetLastError());
- goto cleanup;
- }
- - if (fileSize.QuadPart == 0LL) {
- - (void)fprintf(stderr,
- - "# [NOTE] Source file '%s' is empty, "
- - "cloning will result in an empty file.\n",
- + if (fileSize == 0LL) {
- + (void)printf("# [NOTE] Source file '%s' is empty, cloning "
- + "will result in an empty file.\n",
- srcFileName);
- }
- (void)printf("Source file size: %lld bytes.\n",
- - fileSize.QuadPart);
- + fileSize);
- /* Get cluster size */
- - FILE_STORAGE_INFO fsi = { 0 };
- - bResult = GetFileInformationByHandleEx(hSrc,
- - FileStorageInfo, &fsi, sizeof(fsi));
- - if (!bResult) {
- + long long srcClusterSize =
- + getFsClusterSize(hSrc);
- + if (srcClusterSize < 0) {
- PrintWin32Error("FileStorageInfo",
- GetLastError());
- goto cleanup;
- }
- -
- - unsigned long long srcClusterSize =
- - fsi.PhysicalBytesPerSectorForAtomicity;
- - (void)printf("src file cluster size=%llu\n", srcClusterSize);
- + (void)printf("src file cluster size=%lld\n", srcClusterSize);
- hDst = CreateFileA(
- dstFileName,
- @@ -170,14 +239,18 @@ main(int ac, char *av[])
- goto cleanup;
- }
- - if (fileSize.QuadPart > 0LL) {
- - if (!SetFilePointerEx(hDst, fileSize, NULL, FILE_BEGIN)) {
- + if (fileSize > 0LL) {
- + LARGE_INTEGER fs = { .QuadPart = fileSize };
- + if (!SetFilePointerEx(hDst, fs, NULL, FILE_BEGIN)) {
- PrintWin32Error("SetFilePointerEx (pre-allocate)",
- GetLastError());
- goto cleanup;
- }
- - /* Sets the file size to the current position of the file pointer */
- + /*
- + * Sets the file size to the current position of the file
- + * pointer
- + */
- bResult = SetEndOfFile(hDst);
- if (!bResult) {
- PrintWin32Error("SetEndOfFile (pre-allocate)",
- @@ -187,45 +260,43 @@ main(int ac, char *av[])
- /* Reset file pointer to pos 0 */
- LARGE_INTEGER currentPos = { .QuadPart = 0LL };
- - SetFilePointerEx(hDst, currentPos, NULL, FILE_BEGIN);
- + (void)SetFilePointerEx(hDst, currentPos, NULL, FILE_BEGIN);
- }
- - ded.FileHandle = hSrc;
- - ded.SourceFileOffset.QuadPart = 0LL;
- - ded.TargetFileOffset.QuadPart = 0LL;
- - ded.ByteCount = fileSize;
- -
- /*
- - * |FSCTL_DUPLICATE_EXTENTS_TO_FILE| spec requires that the src size
- - * is rounded to the filesytem's cluster size
- + * |FSCTL_DUPLICATE_EXTENTS_TO_FILE| spec requires that the
- + * src size is rounded to the filesytem's cluster size
- *
- * FIXME: What about the size of the destination file ?
- */
- - ded.ByteCount.QuadPart =
- - (ded.ByteCount.QuadPart+srcClusterSize) & ~(srcClusterSize-1);
- + LONGLONG byteCount =
- + (fileSize+srcClusterSize) & ~(srcClusterSize-1);
- - (void)printf("# DeviceIoControl(FSCTL_DUPLICATE_EXTENTS_TO_FILE)\n");
- + LONGLONG cloneOffset = 0LL;
- - bResult = DeviceIoControl(
- - hDst,
- - FSCTL_DUPLICATE_EXTENTS_TO_FILE,
- - &ded,
- - sizeof(ded),
- - NULL,
- - 0,
- - &bytesReturnedDummy,
- - NULL);
- + while(byteCount > 0) {
- + (void)printf("# FSCTL_DUPLICATE_EXTENTS_TO_FILE: cloneOffset=%lld)\n",
- + cloneOffset);
- - if (!bResult) {
- - PrintWin32Error("DeviceIoControl(FSCTL_DUPLICATE_EXTENTS_TO_FILE)",
- - GetLastError());
- - goto cleanup;
- + bResult = fsctlduplicateextentstofile(hSrc,
- + hDst,
- + cloneOffset,
- + cloneOffset,
- + __min(byteCount, maxCloneChunkSize));
- +
- + if (!bResult) {
- + PrintWin32Error("DeviceIoControl(FSCTL_DUPLICATE_EXTENTS_TO_FILE)",
- + GetLastError());
- + goto cleanup;
- + }
- +
- + byteCount -= maxCloneChunkSize;
- + cloneOffset += maxCloneChunkSize;
- }
- (void)printf("# Successfully cloned '%s' to '%s'!\n",
- srcFileName, dstFileName);
- -
- cleanup:
- if ((!bResult) && (hDst != INVALID_HANDLE_VALUE)) {
- (void)printf("# Failure, deleting destination file...\n");
- --
- 2.45.1
- From 8acaa301aafb52cd0d53631af0b875d1fc42cd56 Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Tue, 6 May 2025 18:11:58 +0200
- Subject: [PATCH 2/2] cygwin: README.bintarball.txt: Recommend Cygwin version
- 3.6.1
- README.bintarball.txt: Recommend Cygwin version 3.6.1
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- cygwin/README.bintarball.txt | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
- diff --git a/cygwin/README.bintarball.txt b/cygwin/README.bintarball.txt
- index 7b5fb9b..160df6f 100644
- --- a/cygwin/README.bintarball.txt
- +++ b/cygwin/README.bintarball.txt
- @@ -154,7 +154,7 @@ NFSv4.2/NFSv4.1 filesystem driver for Windows 10/11&Windows Server 2019+2022
- - Windows 10 (32bit or 64bit), Windows 11 or Windows Server 2019+2022
- - Cygwin:
- - Cygwin versions:
- - - 64bit: >= 3.5.7 (or 3.6.x-devel)
- + - 64bit: >= 3.5.7, recommended >= 3.6.1
- - 32bit: >= 3.3.6
- - Packages (required):
- cygwin
- --
- 2.45.1
msnfs41client: Patches for clone tests+docs, 2025-05-06
Posted by Anonymous on Tue 6th May 2025 17:32
raw | new post
Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.