- 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.