pastebin - collaborative debugging tool
nrubsig.kpaste.net RSS


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

  1. diff --git a/daemon/fsctl.c b/daemon/fsctl.c
  2. index e1c4f19..34bae06 100644
  3. --- a/daemon/fsctl.c
  4. +++ b/daemon/fsctl.c
  5. @@ -28,7 +28,7 @@
  6.  #include "util.h"
  7.  
  8.  /* Testing only: Use NFS COPY instead of NFS CLONE */
  9. -// #define DUP_DATA_USE_NFSCOPY 1
  10. +#define DUP_DATA_USE_NFSCOPY 1
  11.  
  12.  #define QARLVL 2 /* dprintf level for "query allocated ranges" logging */
  13.  #define SZDLVL 2 /* dprintf level for "set zero data" logging */
  14. diff --git a/sys/nfs41sys_fsctl.c b/sys/nfs41sys_fsctl.c
  15. index c1a3f2b..424c198 100644
  16. --- a/sys/nfs41sys_fsctl.c
  17. +++ b/sys/nfs41sys_fsctl.c
  18. @@ -56,7 +56,7 @@
  19.  #include <rx.h>
  20.  #include <windef.h>
  21.  #include <winerror.h>
  22. -
  23. +#include <ntddstor.h>
  24.  #include <Ntstrsafe.h>
  25.  
  26.  #include "nfs41sys_buildconfig.h"
  27. @@ -863,6 +863,285 @@ NTSTATUS unmarshal_nfs41_duplicatedata(
  28.      return status;
  29.  }
  30.  
  31. +typedef struct _offloadcontext_entry
  32. +{
  33. +    LIST_ENTRY              next;
  34. +    /* FIXME: Add r/w mutex to keep this valid until we are done with writes */
  35. +    STORAGE_OFFLOAD_TOKEN   token;
  36. +    PNFS41_FOBX             src_fobx;
  37. +    ULONGLONG               src_fileoffset;
  38. +    ULONGLONG               src_length;
  39. +} offloadcontext_entry;
  40. +
  41. +typedef struct _nfs41_offloadcontext_list {
  42. +    LIST_ENTRY head;
  43. +} nfs41_offloadcontext_list;
  44. +nfs41_offloadcontext_list offloadcontext_list;
  45. +FAST_MUTEX offloadcontextLock;
  46. +
  47. +static
  48. +NTSTATUS nfs41_OffloadRead(
  49. +    IN OUT PRX_CONTEXT RxContext)
  50. +{
  51. +    NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
  52. +//    nfs41_updowncall_entry *entry = NULL;
  53. +//    __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
  54. +//    __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
  55. +//        NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
  56. +//    __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
  57. +//        NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
  58. +    __notnull XXCTL_LOWIO_COMPONENT *FsCtl =
  59. +        &RxContext->LowIoContext.ParamsFor.FsCtl;
  60. +    __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(RxContext->pFobx);
  61. +
  62. +    DbgEn();
  63. +
  64. +    RxContext->IoStatusBlock.Information = 0;
  65. +
  66. +#if 1
  67. +static int onceinit = 0;
  68. +    if (onceinit == 0) {
  69. +        onceinit = 1;
  70. +        ExInitializeFastMutex(&offloadcontextLock);
  71. +        InitializeListHead(&offloadcontext_list.head);
  72. +    }
  73. +#endif
  74. +    if (FsCtl->pInputBuffer == NULL) {
  75. +        status = STATUS_INVALID_USER_BUFFER;
  76. +        goto out;
  77. +    }
  78. +
  79. +    if (FsCtl->pOutputBuffer == NULL) {
  80. +        status = STATUS_INVALID_USER_BUFFER;
  81. +        goto out;
  82. +    }
  83. +
  84. +    if (FsCtl->InputBufferLength <
  85. +        sizeof(FSCTL_OFFLOAD_READ_INPUT)) {
  86. +        DbgP("nfs41_OffloadRead: "
  87. +            "buffer too small for FSCTL_OFFLOAD_READ_INPUT\n");
  88. +        status = STATUS_BUFFER_TOO_SMALL;
  89. +        goto out;
  90. +    }
  91. +    if (FsCtl->OutputBufferLength <
  92. +        sizeof(FSCTL_OFFLOAD_READ_OUTPUT)) {
  93. +        DbgP("nfs41_OffloadRead: "
  94. +            "buffer too small for FSCTL_OFFLOAD_READ_OUTPUT\n");
  95. +        status = STATUS_BUFFER_TOO_SMALL;
  96. +        goto out;
  97. +    }
  98. +
  99. +    FSCTL_OFFLOAD_READ_INPUT *ori = (FSCTL_OFFLOAD_READ_INPUT *)FsCtl->pInputBuffer;
  100. +    FSCTL_OFFLOAD_READ_OUTPUT *oro = (FSCTL_OFFLOAD_READ_OUTPUT *)FsCtl->pOutputBuffer;
  101. +
  102. +    DbgP("nfs41_OffloadRead: "
  103. +        "ori->(Size=%lu, Flags=0x%lx, TokenTimeToLive=%lu, Reserved=%lu, "
  104. +        "FileOffset=%llu, CopyLength=%llu)\n",
  105. +        (unsigned long)ori->Size,
  106. +        (unsigned long)ori->Flags,
  107. +        (unsigned long)ori->TokenTimeToLive,
  108. +        (unsigned long)ori->Reserved,
  109. +        (unsigned long long)ori->FileOffset,
  110. +        (unsigned long long)ori->CopyLength);
  111. +
  112. +    offloadcontext_entry *oce = RxAllocatePoolWithTag(NonPagedPoolNx,
  113. +        sizeof(offloadcontext_entry), NFS41_MM_POOLTAG);
  114. +    if (oce == NULL) {
  115. +        status = STATUS_INSUFFICIENT_RESOURCES;
  116. +        goto out;
  117. +    }
  118. +
  119. +    DbgP("nfs41_OffloadRead: oce=0x%p\n", oce);
  120. +
  121. +    (void)memset(&oce->token, 0, sizeof(oce->token));
  122. +    oce->token.TokenType[0] =               'N';
  123. +    oce->token.TokenType[1] =               'F';
  124. +    oce->token.TokenType[2] =               'S';
  125. +    oce->token.TokenType[3] =               '4';
  126. +    *((USHORT *)(&oce->token.TokenIdLength[0])) = STORAGE_OFFLOAD_TOKEN_ID_LENGTH;
  127. +    *((void **)(&oce->token.Token[0])) = oce;
  128. +    oce->src_fobx = nfs41_fobx;
  129. +    oce->src_fileoffset = ori->FileOffset;
  130. +    oce->src_length = ori->CopyLength;
  131. +    nfs41_AddEntry(offloadcontextLock, offloadcontext_list, oce);
  132. +
  133. +    oro->Size = sizeof(FSCTL_OFFLOAD_READ_OUTPUT);
  134. +    oro->Flags = 0;
  135. +    oro->TransferLength = ori->CopyLength;
  136. +    (void)memcpy(&oro->Token[0], &oce->token, sizeof(oce->token));
  137. +
  138. +    RxContext->CurrentIrp->IoStatus.Status = status = STATUS_SUCCESS;
  139. +    RxContext->InformationToReturn = sizeof(FSCTL_OFFLOAD_READ_OUTPUT);
  140. +
  141. +out:
  142. +    DbgEx();
  143. +    return status;
  144. +}
  145. +
  146. +static
  147. +NTSTATUS nfs41_OffloadWrite(
  148. +    IN OUT PRX_CONTEXT RxContext)
  149. +{
  150. +    NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
  151. +    nfs41_updowncall_entry *entry = NULL;
  152. +    __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
  153. +    __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
  154. +        NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
  155. +    __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
  156. +        NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
  157. +    __notnull XXCTL_LOWIO_COMPONENT *FsCtl =
  158. +        &RxContext->LowIoContext.ParamsFor.FsCtl;
  159. +    __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(RxContext->pFobx);
  160. +
  161. +    struct {
  162. +        LONGLONG    srcfileoffset;
  163. +        LONGLONG    destfileoffset;
  164. +        LONGLONG    bytecount;
  165. +    } dd;
  166. +
  167. +    DbgEn();
  168. +
  169. +    LONGLONG io_delay;
  170. +    RxContext->IoStatusBlock.Information = 0;
  171. +
  172. +    DbgP("nfs41_OffloadWrite: #mark0\n");
  173. +
  174. +    /* FIXME: should be |check_nfs41_offloadcopydata_args()| */
  175. +//    status = check_nfs41_duplicatedata_args(RxContext);
  176. +//    if (status)
  177. +//        goto out;
  178. +
  179. +    if (FsCtl->pInputBuffer == NULL) {
  180. +        status = STATUS_INVALID_USER_BUFFER;
  181. +        goto out;
  182. +    }
  183. +    if (FsCtl->pOutputBuffer == NULL) {
  184. +        status = STATUS_INVALID_USER_BUFFER;
  185. +        goto out;
  186. +    }
  187. +
  188. +    PFSCTL_OFFLOAD_WRITE_INPUT owi =
  189. +        (PFSCTL_OFFLOAD_WRITE_INPUT)FsCtl->pInputBuffer;
  190. +    PFSCTL_OFFLOAD_WRITE_OUTPUT owo =
  191. +        (PFSCTL_OFFLOAD_WRITE_OUTPUT)FsCtl->pOutputBuffer;
  192. +    DbgP("nfs41_OffloadWrite: #mark1\n");
  193. +
  194. +    offloadcontext_entry *src_oce;
  195. +
  196. +    src_oce = *((void **)(&(((STORAGE_OFFLOAD_TOKEN *)(&owi->Token[0]))->Token[0])));
  197. +    DbgP("nfs41_OffloadWrite: src_oce=0x%p\n", src_oce);
  198. +
  199. +    if ((src_oce->token.TokenType[0] != 'N') ||
  200. +        (src_oce->token.TokenType[1] != 'F') ||
  201. +        (src_oce->token.TokenType[2] != 'S') ||
  202. +        (src_oce->token.TokenType[3] != '4')) {
  203. +        DbgP("nfs41_OffloadWrite: "
  204. +            "token in src_oce=0x%p not a 'nfs4' token\n",
  205. +            src_oce);
  206. +        status = STATUS_INVALID_PARAMETER;
  207. +        goto out;
  208. +    }
  209. +
  210. +    DbgP("nfs41_OffloadWrite: #mark2\n");
  211. +
  212. +    dd.srcfileoffset    = src_oce->src_fileoffset + owi->TransferOffset;
  213. +    dd.destfileoffset   = owi->FileOffset;
  214. +    dd.bytecount        = owi->CopyLength;
  215. +
  216. +    DbgP("nfs41_OffloadWrite: "
  217. +        "dd=(srcfileoffset=%lld,"
  218. +        "destfileoffset=%lld,"
  219. +        "bytecount=%lld)\n",
  220. +        (long long)dd.srcfileoffset,
  221. +        (long long)dd.destfileoffset,
  222. +        (long long)dd.bytecount);
  223. +
  224. +    if (dd.bytecount == 0LL) {
  225. +        status = STATUS_SUCCESS;
  226. +        goto out;
  227. +    }
  228. +
  229. +    DbgP("nfs41_OffloadWrite: #mark3\n");
  230. +
  231. +    PNFS41_FOBX nfs41_src_fobx = src_oce->src_fobx;
  232. +
  233. +    if (!nfs41_src_fobx) {
  234. +        DbgP("nfs41_OffloadWrite: No nfs41_src_fobx\n");
  235. +        status = STATUS_INVALID_PARAMETER;
  236. +        goto out;
  237. +    }
  238. +
  239. +    /*
  240. +     * Disable caching because NFSv4.2 COPY is basically a
  241. +     * "write" operation. AFAIK we should flush the cache and wait
  242. +     * for the kernel lazy writer (which |RxChangeBufferingState()|
  243. +     * AFAIK does) before doing the COPY, to avoid that we
  244. +     * have outstanding writes in the kernel cache at the same
  245. +     * location where the COPY should do it's work
  246. +     */
  247. +    ULONG flag = DISABLE_CACHING;
  248. +    DbgP("nfs41_OffloadWrite: disableing caching for file '%wZ'\n",
  249. +        SrvOpen->pAlreadyPrefixedName);
  250. +    RxChangeBufferingState((PSRV_OPEN)SrvOpen, ULongToPtr(flag), 1);
  251. +
  252. +    DbgP("nfs41_OffloadWrite: #mark4\n");
  253. +
  254. +    status = nfs41_UpcallCreate(NFS41_SYSOP_FSCTL_DUPLICATE_DATA,
  255. +        &nfs41_fobx->sec_ctx,
  256. +        pVNetRootContext->session,
  257. +        nfs41_fobx->nfs41_open_state,
  258. +        pNetRootContext->nfs41d_version,
  259. +        SrvOpen->pAlreadyPrefixedName,
  260. +        &entry);
  261. +
  262. +    if (status)
  263. +        goto out;
  264. +
  265. +    entry->u.DuplicateData.src_state = nfs41_src_fobx->nfs41_open_state;
  266. +    entry->u.DuplicateData.srcfileoffset = dd.srcfileoffset;
  267. +    entry->u.DuplicateData.destfileoffset = dd.destfileoffset;
  268. +    entry->u.DuplicateData.bytecount = dd.bytecount;
  269. +
  270. +    /* Add extra timeout depending on file size */
  271. +    io_delay = pVNetRootContext->timeout +
  272. +        EXTRA_TIMEOUT_PER_BYTE(entry->u.DuplicateData.bytecount);
  273. +
  274. +    DbgP("nfs41_OffloadWrite: #mark5\n");
  275. +
  276. +    status = nfs41_UpcallWaitForReply(entry, io_delay);
  277. +    if (status) {
  278. +        /* Timeout - |nfs41_downcall()| will free |entry|+contents */
  279. +        entry = NULL;
  280. +        goto out;
  281. +    }
  282. +
  283. +    if (!entry->status) {
  284. +        DbgP("nfs41_OffloadWrite: SUCCESS\n");
  285. +
  286. +        owo->Size = sizeof(FSCTL_OFFLOAD_READ_OUTPUT);
  287. +        owo->Flags = 0;
  288. +        owo->LengthWritten = dd.bytecount;
  289. +
  290. +        RxContext->CurrentIrp->IoStatus.Status = status = STATUS_SUCCESS;
  291. +        RxContext->InformationToReturn = sizeof(FSCTL_OFFLOAD_READ_OUTPUT);
  292. +    }
  293. +    else {
  294. +        DbgP("nfs41_OffloadWrite: "
  295. +            "FAILURE, entry->status=0x%lx\n", entry->status);
  296. +        status = map_setfile_error(entry->status);
  297. +        RxContext->CurrentIrp->IoStatus.Status = status;
  298. +        RxContext->IoStatusBlock.Information = 0;
  299. +    }
  300. +
  301. +out:
  302. +    if (entry) {
  303. +        nfs41_UpcallDestroy(entry);
  304. +    }
  305. +
  306. +    DbgEx();
  307. +    return status;
  308. +}
  309. +
  310.  NTSTATUS nfs41_FsCtl(
  311.      IN OUT PRX_CONTEXT RxContext)
  312.  {
  313. @@ -895,6 +1174,12 @@ NTSTATUS nfs41_FsCtl(
  314.      case FSCTL_DUPLICATE_EXTENTS_TO_FILE:
  315.          status = nfs41_DuplicateData(RxContext);
  316.          break;
  317. +    case FSCTL_OFFLOAD_READ:
  318. +        status = nfs41_OffloadRead(RxContext);
  319. +        break;
  320. +    case FSCTL_OFFLOAD_WRITE:
  321. +        status = nfs41_OffloadWrite(RxContext);
  322. +        break;
  323.      default:
  324.          break;
  325.      }

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.

Syntax highlighting:

To highlight particular lines, prefix each line with {%HIGHLIGHT}




All content is user-submitted.
The administrators of this site (kpaste.net) are not responsible for their content.
Abuse reports should be emailed to us at