- From e688215b3952be252574eaaf2aacbaefe34abad6 Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Wed, 11 Jun 2025 21:04:36 +0200
- Subject: [PATCH] sys,tests: |FSCTL_DUPLICATE_EXTENTS_TO_FILE| fails with 32bit
- processes on 64bit kernel
- |FSCTL_DUPLICATE_EXTENTS_TO_FILE| fails with 32bit processes on a
- 64bit kernel, typically failing with |STATUS_INVALID_HANDLE|.
- This happens because the layout of |DUPLICATE_EXTENTS_DATA| differs between
- 32bit and 64bit, so a 64bit kernel must test for 32bit processes
- and use |DUPLICATE_EXTENTS_DATA32| instead to use the correct struct
- layout.
- Reported-by: Aurelien Couderc <aurelien.couderc2002@gmail.com>
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- sys/nfs41sys_fsctl.c | 94 ++++++++++++++++-------
- tests/sparsefiles/multisparsefiletest.ksh | 44 ++++++++---
- 2 files changed, 101 insertions(+), 37 deletions(-)
- diff --git a/sys/nfs41sys_fsctl.c b/sys/nfs41sys_fsctl.c
- index e80321b..9df5528 100644
- --- a/sys/nfs41sys_fsctl.c
- +++ b/sys/nfs41sys_fsctl.c
- @@ -614,14 +614,27 @@ NTSTATUS nfs41_DuplicateData(
- NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
- __notnull XXCTL_LOWIO_COMPONENT *FsCtl =
- &RxContext->LowIoContext.ParamsFor.FsCtl;
- - __notnull PDUPLICATE_EXTENTS_DATA duplicatedatabuffer =
- - (PDUPLICATE_EXTENTS_DATA)FsCtl->pInputBuffer;
- __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(RxContext->pFobx);
- - PFILE_OBJECT srcfo = NULL;
- - LONGLONG io_delay;
- +
- + /*
- + * Temporary store |FSCTL_DUPLICATE_EXTENTS_TO_FILE| data here, which
- + * can be either |DUPLICATE_EXTENTS_DATA32| for 32bit processes on a
- + * 64bit kernel, |DUPLICATE_EXTENTS_DATA| for 64bit processes on a
- + * 64bit kernel, or |DUPLICATE_EXTENTS_DATA| for 32bit processes on
- + * a 32bit kernel
- + */
- + struct {
- + HANDLE handle;
- + LONGLONG srcfileoffset;
- + LONGLONG destfileoffset;
- + LONGLONG bytecount;
- + } dd;
- DbgEn();
- + PFILE_OBJECT srcfo = NULL;
- + LONGLONG io_delay;
- +
- RxContext->IoStatusBlock.Information = 0;
- status = check_nfs41_duplicatedata_args(RxContext);
- @@ -633,30 +646,60 @@ NTSTATUS nfs41_DuplicateData(
- goto out;
- }
- - if (FsCtl->InputBufferLength <
- - sizeof(DUPLICATE_EXTENTS_DATA)) {
- - DbgP("nfs41_DuplicateData: "
- - "buffer to small\n");
- - status = STATUS_BUFFER_TOO_SMALL;
- - goto out;
- +#if defined(_WIN64)
- + if (IoIs32bitProcess(RxContext->CurrentIrp)) {
- + if (FsCtl->InputBufferLength <
- + sizeof(DUPLICATE_EXTENTS_DATA32)) {
- + DbgP("nfs41_DuplicateData: "
- + "buffer too small for DUPLICATE_EXTENTS_DATA32\n");
- + status = STATUS_BUFFER_TOO_SMALL;
- + goto out;
- + }
- +
- + PDUPLICATE_EXTENTS_DATA32 ded32bit =
- + (PDUPLICATE_EXTENTS_DATA32)FsCtl->pInputBuffer;
- +
- + dd.handle = (HANDLE)ded32bit->FileHandle;
- + dd.srcfileoffset = ded32bit->SourceFileOffset.QuadPart;
- + dd.destfileoffset = ded32bit->TargetFileOffset.QuadPart;
- + dd.bytecount = ded32bit->ByteCount.QuadPart;
- + }
- + else
- +#endif /* defined(_WIN64) */
- + {
- + if (FsCtl->InputBufferLength <
- + sizeof(DUPLICATE_EXTENTS_DATA)) {
- + DbgP("nfs41_DuplicateData: "
- + "buffer too small for DUPLICATE_EXTENTS_DATA\n");
- + status = STATUS_BUFFER_TOO_SMALL;
- + goto out;
- + }
- +
- + PDUPLICATE_EXTENTS_DATA ded =
- + (PDUPLICATE_EXTENTS_DATA)FsCtl->pInputBuffer;
- +
- + dd.handle = ded->FileHandle;
- + dd.srcfileoffset = ded->SourceFileOffset.QuadPart;
- + dd.destfileoffset = ded->TargetFileOffset.QuadPart;
- + dd.bytecount = ded->ByteCount.QuadPart;
- }
- DbgP("nfs41_DuplicateData: "
- - "duplicatedatabuffer=(FileHandle=0x%p,"
- - "SourceFileOffset=%lld,"
- - "TargetFileOffset=%lld,"
- - "ByteCount=%lld)\n",
- - (void *)duplicatedatabuffer->FileHandle,
- - (long long)duplicatedatabuffer->SourceFileOffset.QuadPart,
- - (long long)duplicatedatabuffer->TargetFileOffset.QuadPart,
- - (long long)duplicatedatabuffer->ByteCount.QuadPart);
- -
- - if (duplicatedatabuffer->ByteCount.QuadPart == 0LL) {
- + "dd=(handle=0x%p,"
- + "srcfileoffset=%lld,"
- + "destfileoffset=%lld,"
- + "bytecount=%lld)\n",
- + (void *)dd.handle,
- + (long long)dd.srcfileoffset,
- + (long long)dd.destfileoffset,
- + (long long)dd.bytecount);
- +
- + if (dd.bytecount == 0LL) {
- status = STATUS_SUCCESS;
- goto out;
- }
- - status = ObReferenceObjectByHandle(duplicatedatabuffer->FileHandle,
- + status = ObReferenceObjectByHandle(dd.handle,
- 0,
- *IoFileObjectType,
- RxContext->CurrentIrp->RequestorMode,
- @@ -724,12 +767,9 @@ NTSTATUS nfs41_DuplicateData(
- goto out;
- entry->u.DuplicateData.src_state = nfs41_src_fobx->nfs41_open_state;
- - entry->u.DuplicateData.srcfileoffset =
- - duplicatedatabuffer->SourceFileOffset.QuadPart;
- - entry->u.DuplicateData.destfileoffset =
- - duplicatedatabuffer->TargetFileOffset.QuadPart;
- - entry->u.DuplicateData.bytecount =
- - duplicatedatabuffer->ByteCount.QuadPart;
- + entry->u.DuplicateData.srcfileoffset = dd.srcfileoffset;
- + entry->u.DuplicateData.destfileoffset = dd.destfileoffset;
- + entry->u.DuplicateData.bytecount = dd.bytecount;
- /* Add extra timeout depending on file size */
- io_delay = pVNetRootContext->timeout +
- diff --git a/tests/sparsefiles/multisparsefiletest.ksh b/tests/sparsefiles/multisparsefiletest.ksh
- index 3994c1f..b62f577 100644
- --- a/tests/sparsefiles/multisparsefiletest.ksh
- +++ b/tests/sparsefiles/multisparsefiletest.ksh
- @@ -221,16 +221,40 @@ function multisparsefiletest1
- typeset tstmod
- - typeset -a tstmodlist=(
- - 'plainfile'
- - 'cp_sparseauto'
- - 'cloned_full'
- - 'cloned_1mbchunks'
- - )
- + case "$(getconf LONG_BIT)" in
- + '64')
- + typeset -a tstmodlist=(
- + 'plainfile'
- + 'cp_sparseauto'
- + 'cloned_full_64bit'
- + 'cloned_1mbchunks_64bit'
- + 'cloned_full_32bit'
- + 'cloned_1mbchunks_32bit'
- + )
- + ;;
- + '32')
- + typeset -a tstmodlist=(
- + 'plainfile'
- + 'cp_sparseauto'
- + 'cloned_full'
- + 'cloned_1mbchunks'
- + )
- + ;;
- + *)
- + print -u2 -f 'ERROR: unknown getconf LONG_BIT result\n'
- + return 8
- + ;;
- + esac
- for tstmod in "${tstmodlist[@]}" ; do
- printf '# Test %d '%s' generated\n' c.i "${c.testlabel}/$tstmod"
- + if [[ "${tstmod}" == *32bit ]] ; then
- + winclonefilecmd='winclonefile.i686.exe'
- + else
- + winclonefilecmd='winclonefile.exe'
- + fi
- +
- case "${tstmod}" in
- 'plainfile')
- c.stdout="$(lssparse -H 'sparsefile2.bin')"
- @@ -239,9 +263,9 @@ function multisparsefiletest1
- /usr/bin/cp --sparse='auto' 'sparsefile2.bin' 'sparsefile2_cpsparse.bin'
- c.stdout="$(lssparse -H 'sparsefile2_cpsparse.bin')"
- ;;
- - 'cloned_full')
- + 'cloned_full' | 'cloned_full_64bit' | 'cloned_full_32bit')
- if $test_cloning ; then
- - winclonefile.exe 'sparsefile2.bin' 'sparsefile2_cloned_full.bin' 1>'/dev/null'
- + ${winclonefilecmd} '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}"
- @@ -249,9 +273,9 @@ function multisparsefiletest1
- continue
- fi
- ;;
- - 'cloned_1mbchunks')
- + 'cloned_1mbchunks' | 'cloned_1mbchunks_64bit' | 'cloned_1mbchunks_32bit')
- if $test_cloning ; then
- - winclonefile.exe \
- + ${winclonefilecmd} \
- --clonechunksize $((1024*1024)) \
- 'sparsefile2.bin' \
- 'sparsefile2_cloned_1mbchunks.bin' 1>'/dev/null'
- --
- 2.45.1
msnfs41client: Patch to fix file cloning for 32bit processes on 64bit kernels, 2025-06-11
Posted by Anonymous on Wed 11th Jun 2025 20:30
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.