- diff --git a/daemon/fsctl.c b/daemon/fsctl.c
 - index e1c4f19..34bae06 100644
 - --- a/daemon/fsctl.c
 - +++ b/daemon/fsctl.c
 - @@ -28,7 +28,7 @@
 - #include "util.h"
 - /* Testing only: Use NFS COPY instead of NFS CLONE */
 - -// #define DUP_DATA_USE_NFSCOPY 1
 - +#define DUP_DATA_USE_NFSCOPY 1
 - #define QARLVL 2 /* dprintf level for "query allocated ranges" logging */
 - #define SZDLVL 2 /* dprintf level for "set zero data" logging */
 - diff --git a/sys/nfs41sys_fsctl.c b/sys/nfs41sys_fsctl.c
 - index c1a3f2b..424c198 100644
 - --- a/sys/nfs41sys_fsctl.c
 - +++ b/sys/nfs41sys_fsctl.c
 - @@ -56,7 +56,7 @@
 - #include <rx.h>
 - #include <windef.h>
 - #include <winerror.h>
 - -
 - +#include <ntddstor.h>
 - #include <Ntstrsafe.h>
 - #include "nfs41sys_buildconfig.h"
 - @@ -863,6 +863,285 @@ NTSTATUS unmarshal_nfs41_duplicatedata(
 - return status;
 - }
 - +typedef struct _offloadcontext_entry
 - +{
 - + LIST_ENTRY next;
 - + /* FIXME: Add r/w mutex to keep this valid until we are done with writes */
 - + STORAGE_OFFLOAD_TOKEN token;
 - + PNFS41_FOBX src_fobx;
 - + ULONGLONG src_fileoffset;
 - + ULONGLONG src_length;
 - +} offloadcontext_entry;
 - +
 - +typedef struct _nfs41_offloadcontext_list {
 - + LIST_ENTRY head;
 - +} nfs41_offloadcontext_list;
 - +nfs41_offloadcontext_list offloadcontext_list;
 - +FAST_MUTEX offloadcontextLock;
 - +
 - +static
 - +NTSTATUS nfs41_OffloadRead(
 - + IN OUT PRX_CONTEXT RxContext)
 - +{
 - + NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
 - +// nfs41_updowncall_entry *entry = NULL;
 - +// __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
 - +// __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
 - +// NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
 - +// __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
 - +// NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
 - + __notnull XXCTL_LOWIO_COMPONENT *FsCtl =
 - + &RxContext->LowIoContext.ParamsFor.FsCtl;
 - + __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(RxContext->pFobx);
 - +
 - + DbgEn();
 - +
 - + RxContext->IoStatusBlock.Information = 0;
 - +
 - +#if 1
 - +static int onceinit = 0;
 - + if (onceinit == 0) {
 - + onceinit = 1;
 - + ExInitializeFastMutex(&offloadcontextLock);
 - + InitializeListHead(&offloadcontext_list.head);
 - + }
 - +#endif
 - + if (FsCtl->pInputBuffer == NULL) {
 - + status = STATUS_INVALID_USER_BUFFER;
 - + goto out;
 - + }
 - +
 - + if (FsCtl->pOutputBuffer == NULL) {
 - + status = STATUS_INVALID_USER_BUFFER;
 - + goto out;
 - + }
 - +
 - + if (FsCtl->InputBufferLength <
 - + sizeof(FSCTL_OFFLOAD_READ_INPUT)) {
 - + DbgP("nfs41_OffloadRead: "
 - + "buffer too small for FSCTL_OFFLOAD_READ_INPUT\n");
 - + status = STATUS_BUFFER_TOO_SMALL;
 - + goto out;
 - + }
 - + if (FsCtl->OutputBufferLength <
 - + sizeof(FSCTL_OFFLOAD_READ_OUTPUT)) {
 - + DbgP("nfs41_OffloadRead: "
 - + "buffer too small for FSCTL_OFFLOAD_READ_OUTPUT\n");
 - + status = STATUS_BUFFER_TOO_SMALL;
 - + goto out;
 - + }
 - +
 - + FSCTL_OFFLOAD_READ_INPUT *ori = (FSCTL_OFFLOAD_READ_INPUT *)FsCtl->pInputBuffer;
 - + FSCTL_OFFLOAD_READ_OUTPUT *oro = (FSCTL_OFFLOAD_READ_OUTPUT *)FsCtl->pOutputBuffer;
 - +
 - + DbgP("nfs41_OffloadRead: "
 - + "ori->(Size=%lu, Flags=0x%lx, TokenTimeToLive=%lu, Reserved=%lu, "
 - + "FileOffset=%llu, CopyLength=%llu)\n",
 - + (unsigned long)ori->Size,
 - + (unsigned long)ori->Flags,
 - + (unsigned long)ori->TokenTimeToLive,
 - + (unsigned long)ori->Reserved,
 - + (unsigned long long)ori->FileOffset,
 - + (unsigned long long)ori->CopyLength);
 - +
 - + offloadcontext_entry *oce = RxAllocatePoolWithTag(NonPagedPoolNx,
 - + sizeof(offloadcontext_entry), NFS41_MM_POOLTAG);
 - + if (oce == NULL) {
 - + status = STATUS_INSUFFICIENT_RESOURCES;
 - + goto out;
 - + }
 - +
 - + DbgP("nfs41_OffloadRead: oce=0x%p\n", oce);
 - +
 - + (void)memset(&oce->token, 0, sizeof(oce->token));
 - + oce->token.TokenType[0] = 'N';
 - + oce->token.TokenType[1] = 'F';
 - + oce->token.TokenType[2] = 'S';
 - + oce->token.TokenType[3] = '4';
 - + *((USHORT *)(&oce->token.TokenIdLength[0])) = STORAGE_OFFLOAD_TOKEN_ID_LENGTH;
 - + *((void **)(&oce->token.Token[0])) = oce;
 - + oce->src_fobx = nfs41_fobx;
 - + oce->src_fileoffset = ori->FileOffset;
 - + oce->src_length = ori->CopyLength;
 - + nfs41_AddEntry(offloadcontextLock, offloadcontext_list, oce);
 - +
 - + oro->Size = sizeof(FSCTL_OFFLOAD_READ_OUTPUT);
 - + oro->Flags = 0;
 - + oro->TransferLength = ori->CopyLength;
 - + (void)memcpy(&oro->Token[0], &oce->token, sizeof(oce->token));
 - +
 - + RxContext->CurrentIrp->IoStatus.Status = status = STATUS_SUCCESS;
 - + RxContext->InformationToReturn = sizeof(FSCTL_OFFLOAD_READ_OUTPUT);
 - +
 - +out:
 - + DbgEx();
 - + return status;
 - +}
 - +
 - +static
 - +NTSTATUS nfs41_OffloadWrite(
 - + IN OUT PRX_CONTEXT RxContext)
 - +{
 - + NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
 - + nfs41_updowncall_entry *entry = NULL;
 - + __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
 - + __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
 - + NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
 - + __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
 - + NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
 - + __notnull XXCTL_LOWIO_COMPONENT *FsCtl =
 - + &RxContext->LowIoContext.ParamsFor.FsCtl;
 - + __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(RxContext->pFobx);
 - +
 - + struct {
 - + LONGLONG srcfileoffset;
 - + LONGLONG destfileoffset;
 - + LONGLONG bytecount;
 - + } dd;
 - +
 - + DbgEn();
 - +
 - + LONGLONG io_delay;
 - + RxContext->IoStatusBlock.Information = 0;
 - +
 - + DbgP("nfs41_OffloadWrite: #mark0\n");
 - +
 - + /* FIXME: should be |check_nfs41_offloadcopydata_args()| */
 - +// status = check_nfs41_duplicatedata_args(RxContext);
 - +// if (status)
 - +// goto out;
 - +
 - + if (FsCtl->pInputBuffer == NULL) {
 - + status = STATUS_INVALID_USER_BUFFER;
 - + goto out;
 - + }
 - + if (FsCtl->pOutputBuffer == NULL) {
 - + status = STATUS_INVALID_USER_BUFFER;
 - + goto out;
 - + }
 - +
 - + PFSCTL_OFFLOAD_WRITE_INPUT owi =
 - + (PFSCTL_OFFLOAD_WRITE_INPUT)FsCtl->pInputBuffer;
 - + PFSCTL_OFFLOAD_WRITE_OUTPUT owo =
 - + (PFSCTL_OFFLOAD_WRITE_OUTPUT)FsCtl->pOutputBuffer;
 - + DbgP("nfs41_OffloadWrite: #mark1\n");
 - +
 - + offloadcontext_entry *src_oce;
 - +
 - + src_oce = *((void **)(&(((STORAGE_OFFLOAD_TOKEN *)(&owi->Token[0]))->Token[0])));
 - + DbgP("nfs41_OffloadWrite: src_oce=0x%p\n", src_oce);
 - +
 - + if ((src_oce->token.TokenType[0] != 'N') ||
 - + (src_oce->token.TokenType[1] != 'F') ||
 - + (src_oce->token.TokenType[2] != 'S') ||
 - + (src_oce->token.TokenType[3] != '4')) {
 - + DbgP("nfs41_OffloadWrite: "
 - + "token in src_oce=0x%p not a 'nfs4' token\n",
 - + src_oce);
 - + status = STATUS_INVALID_PARAMETER;
 - + goto out;
 - + }
 - +
 - + DbgP("nfs41_OffloadWrite: #mark2\n");
 - +
 - + dd.srcfileoffset = src_oce->src_fileoffset + owi->TransferOffset;
 - + dd.destfileoffset = owi->FileOffset;
 - + dd.bytecount = owi->CopyLength;
 - +
 - + DbgP("nfs41_OffloadWrite: "
 - + "dd=(srcfileoffset=%lld,"
 - + "destfileoffset=%lld,"
 - + "bytecount=%lld)\n",
 - + (long long)dd.srcfileoffset,
 - + (long long)dd.destfileoffset,
 - + (long long)dd.bytecount);
 - +
 - + if (dd.bytecount == 0LL) {
 - + status = STATUS_SUCCESS;
 - + goto out;
 - + }
 - +
 - + DbgP("nfs41_OffloadWrite: #mark3\n");
 - +
 - + PNFS41_FOBX nfs41_src_fobx = src_oce->src_fobx;
 - +
 - + if (!nfs41_src_fobx) {
 - + DbgP("nfs41_OffloadWrite: No nfs41_src_fobx\n");
 - + status = STATUS_INVALID_PARAMETER;
 - + goto out;
 - + }
 - +
 - + /*
 - + * Disable caching because NFSv4.2 COPY is basically a
 - + * "write" operation. AFAIK we should flush the cache and wait
 - + * for the kernel lazy writer (which |RxChangeBufferingState()|
 - + * AFAIK does) before doing the COPY, to avoid that we
 - + * have outstanding writes in the kernel cache at the same
 - + * location where the COPY should do it's work
 - + */
 - + ULONG flag = DISABLE_CACHING;
 - + DbgP("nfs41_OffloadWrite: disableing caching for file '%wZ'\n",
 - + SrvOpen->pAlreadyPrefixedName);
 - + RxChangeBufferingState((PSRV_OPEN)SrvOpen, ULongToPtr(flag), 1);
 - +
 - + DbgP("nfs41_OffloadWrite: #mark4\n");
 - +
 - + status = nfs41_UpcallCreate(NFS41_SYSOP_FSCTL_DUPLICATE_DATA,
 - + &nfs41_fobx->sec_ctx,
 - + pVNetRootContext->session,
 - + nfs41_fobx->nfs41_open_state,
 - + pNetRootContext->nfs41d_version,
 - + SrvOpen->pAlreadyPrefixedName,
 - + &entry);
 - +
 - + if (status)
 - + goto out;
 - +
 - + entry->u.DuplicateData.src_state = nfs41_src_fobx->nfs41_open_state;
 - + 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 +
 - + EXTRA_TIMEOUT_PER_BYTE(entry->u.DuplicateData.bytecount);
 - +
 - + DbgP("nfs41_OffloadWrite: #mark5\n");
 - +
 - + status = nfs41_UpcallWaitForReply(entry, io_delay);
 - + if (status) {
 - + /* Timeout - |nfs41_downcall()| will free |entry|+contents */
 - + entry = NULL;
 - + goto out;
 - + }
 - +
 - + if (!entry->status) {
 - + DbgP("nfs41_OffloadWrite: SUCCESS\n");
 - +
 - + owo->Size = sizeof(FSCTL_OFFLOAD_READ_OUTPUT);
 - + owo->Flags = 0;
 - + owo->LengthWritten = dd.bytecount;
 - +
 - + RxContext->CurrentIrp->IoStatus.Status = status = STATUS_SUCCESS;
 - + RxContext->InformationToReturn = sizeof(FSCTL_OFFLOAD_READ_OUTPUT);
 - + }
 - + else {
 - + DbgP("nfs41_OffloadWrite: "
 - + "FAILURE, entry->status=0x%lx\n", entry->status);
 - + status = map_setfile_error(entry->status);
 - + RxContext->CurrentIrp->IoStatus.Status = status;
 - + RxContext->IoStatusBlock.Information = 0;
 - + }
 - +
 - +out:
 - + if (entry) {
 - + nfs41_UpcallDestroy(entry);
 - + }
 - +
 - + DbgEx();
 - + return status;
 - +}
 - +
 - NTSTATUS nfs41_FsCtl(
 - IN OUT PRX_CONTEXT RxContext)
 - {
 - @@ -895,6 +1174,12 @@ NTSTATUS nfs41_FsCtl(
 - case FSCTL_DUPLICATE_EXTENTS_TO_FILE:
 - status = nfs41_DuplicateData(RxContext);
 - break;
 - + case FSCTL_OFFLOAD_READ:
 - + status = nfs41_OffloadRead(RxContext);
 - + break;
 - + case FSCTL_OFFLOAD_WRITE:
 - + status = nfs41_OffloadWrite(RxContext);
 - + break;
 - default:
 - break;
 - }
 
Win32 offload copy prototype, 2025-08-19
Posted by Anonymous on Tue 19th Aug 2025 14:55
raw | new post
view followups (newest first): Win32 offload copy prototype, 2025-08-19 by Anonymous
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.
 nrubsig.kpaste.net RSS