pastebin - collaborative debugging tool
nrubsig.kpaste.net RSS


Win32 offload copy prototype, 2025-08-19
Posted by Anonymous on Tue 19th Aug 2025 20:02
raw | new post
view followups (newest first): Win32 offload copy prototype, 2025-08-19 by Anonymous
modification of post by Anonymous (view diff)

  1. diff --git a/daemon/daemon_debug.c b/daemon/daemon_debug.c
  2. index 20fd420..02a0aec 100644
  3. --- a/daemon/daemon_debug.c
  4. +++ b/daemon/daemon_debug.c
  5. @@ -485,6 +485,7 @@ const char* opcode2string(nfs41_opcodes opcode)
  6.          NFSOPCODE_TO_STRLITERAL(NFS41_SYSOP_FSCTL_QUERYALLOCATEDRANGES)
  7.          NFSOPCODE_TO_STRLITERAL(NFS41_SYSOP_FSCTL_SET_ZERO_DATA)
  8.          NFSOPCODE_TO_STRLITERAL(NFS41_SYSOP_FSCTL_DUPLICATE_DATA)
  9. +        NFSOPCODE_TO_STRLITERAL(NFS41_SYSOP_FSCTL_OFFLOAD_DATACOPY)
  10.          NFSOPCODE_TO_STRLITERAL(NFS41_SYSOP_INVALID_OPCODE1)
  11.          default: break;
  12.      }
  13. diff --git a/daemon/fsctl.c b/daemon/fsctl.c
  14. index e1c4f19..a6c5048 100644
  15. --- a/daemon/fsctl.c
  16. +++ b/daemon/fsctl.c
  17. @@ -27,9 +27,6 @@
  18.  #include "daemon_debug.h"
  19.  #include "util.h"
  20.  
  21. -/* Testing only: Use NFS COPY instead of NFS CLONE */
  22. -// #define DUP_DATA_USE_NFSCOPY 1
  23. -
  24.  #define QARLVL 2 /* dprintf level for "query allocated ranges" logging */
  25.  #define SZDLVL 2 /* dprintf level for "set zero data" logging */
  26.  #define DDLVL  2 /* dprintf level for "duplicate data" logging */
  27. @@ -470,7 +467,8 @@ out:
  28.  }
  29.  
  30.  static
  31. -int duplicate_sparsefile(nfs41_open_state *src_state,
  32. +int duplicate_sparsefile(nfs41_opcodes opcode,
  33. +    nfs41_open_state *src_state,
  34.      nfs41_open_state *dst_state,
  35.      uint64_t srcfileoffset,
  36.      uint64_t destfileoffset,
  37. @@ -498,7 +496,8 @@ int duplicate_sparsefile(nfs41_open_state *src_state,
  38.      (void)memset(info, 0, sizeof(*info));
  39.  
  40.      DPRINTF(DDLVL,
  41. -        ("--> duplicate_sparsefile(src_state->path.path='%s')\n",
  42. +        ("--> duplicate_sparsefile(opcode='%s',src_state->path.path='%s')\n",
  43. +        opcode2string(opcode),
  44.          src_state->path.path));
  45.  
  46.      nfs41_open_stateid_arg(src_state, &src_stateid);
  47. @@ -518,9 +517,11 @@ int duplicate_sparsefile(nfs41_open_state *src_state,
  48.      if (status) {
  49.          DPRINTF(0/*DDLVL*/,
  50.              ("duplicate_sparsefile("
  51. +            "opcode='%s',"
  52.              "src_state->path.path='%s' "
  53.              "dst_state->path.path='%s'): "
  54.              "DEALLOCATE failed with '%s'\n",
  55. +            opcode2string(opcode),
  56.              src_state->path.path,
  57.              dst_state->path.path,
  58.              nfs_error_string(status)));
  59. @@ -594,46 +595,45 @@ int duplicate_sparsefile(nfs41_open_state *src_state,
  60.              (int)data_seek_sr_eof,
  61.              (int)hole_seek_sr_eof));
  62.  
  63. -#ifdef DUP_DATA_USE_NFSCOPY
  64. -        nfs41_write_verf verf;
  65. -        status = nfs42_copy(session,
  66. -            src_file,
  67. -            dst_file,
  68. -            &src_stateid,
  69. -            &dst_stateid,
  70. -            data_seek_sr_offset,
  71. -            destfileoffset + (data_seek_sr_offset-srcfileoffset),
  72. -            data_size,
  73. -            &verf,
  74. -            info);
  75. -        /* FIXME: What should we do with |verf| ? Should we COMMIT this ? */
  76. -#else
  77. -        status = nfs42_clone(session,
  78. -            src_file,
  79. -            dst_file,
  80. -            &src_stateid,
  81. -            &dst_stateid,
  82. -            data_seek_sr_offset,
  83. -            destfileoffset + (data_seek_sr_offset-srcfileoffset),
  84. -            data_size,
  85. -            info);
  86. -#endif /* DUP_DATA_USE_NFSCOPY */
  87. -        if (status) {
  88. -            const char dup_op_name[] =
  89. -#ifdef DUP_DATA_USE_NFSCOPY
  90. -                "COPY";
  91. -#else
  92. -                "CLONE";
  93. -#endif /* DUP_DATA_USE_NFSCOPY */
  94. +        if (opcode == NFS41_SYSOP_FSCTL_OFFLOAD_DATACOPY) {
  95. +            nfs41_write_verf verf;
  96. +            status = nfs42_copy(session,
  97. +                src_file,
  98. +                dst_file,
  99. +                &src_stateid,
  100. +                &dst_stateid,
  101. +                data_seek_sr_offset,
  102. +                destfileoffset + (data_seek_sr_offset-srcfileoffset),
  103. +                data_size,
  104. +                &verf,
  105. +                info);
  106. +            /* FIXME: What should we do with |verf| ? Should we COMMIT this ? */
  107. +        }
  108. +        else if (opcode == NFS41_SYSOP_FSCTL_DUPLICATE_DATA) {
  109. +            status = nfs42_clone(session,
  110. +                src_file,
  111. +                dst_file,
  112. +                &src_stateid,
  113. +                &dst_stateid,
  114. +                data_seek_sr_offset,
  115. +                destfileoffset + (data_seek_sr_offset-srcfileoffset),
  116. +                data_size,
  117. +                info);
  118. +        }
  119. +        else {
  120. +            EASSERT(0);
  121. +        }
  122.  
  123. +        if (status) {
  124.              DPRINTF(0/*DDLVL*/,
  125.                  ("duplicate_sparsefile("
  126. +                "opcode='%s',"
  127.                  "src_state->path.path='%s' "
  128.                  "dst_state->path.path='%s'): "
  129. -                "'%s' failed with '%s'\n",
  130. +                "failed with '%s'\n",
  131. +                opcode2string(opcode),
  132.                  src_state->path.path,
  133.                  dst_state->path.path,
  134. -                dup_op_name,
  135.                  nfs_error_string(status)));
  136.              status = nfs_to_windows_error(status, ERROR_BAD_NET_RESP);
  137.              goto out;
  138. @@ -688,25 +688,35 @@ int handle_duplicatedata(void *daemon_context,
  139.              dst_state->path.path,
  140.              src_state->path.path));
  141.  
  142. -    /* NFS SEEK supported ? */
  143. -    if (src_session->client->root->supports_nfs42_seek == false) {
  144. -        status = ERROR_NOT_SUPPORTED;
  145. -        goto out;
  146. +    /*
  147. +     * Check whether we support the required NFS operations...
  148. +     */
  149. +    if (upcall->opcode == NFS41_SYSOP_FSCTL_OFFLOAD_DATACOPY) {
  150. +        if ((src_session->client->root->supports_nfs42_seek == false) ||
  151. +            (src_session->client->root->supports_nfs42_copy == false) ||
  152. +            (src_session->client->root->supports_nfs42_deallocate == false)) {
  153. +            status = ERROR_NOT_SUPPORTED;
  154. +            goto out;
  155. +        }
  156.      }
  157. -    /* NFS CLONE supported ? */
  158. -    if (
  159. -#ifdef DUP_DATA_USE_NFSCOPY
  160. -        src_session->client->root->supports_nfs42_copy == false
  161. -#else
  162. -        src_session->client->root->supports_nfs42_clone == false
  163. -#endif /* DUP_DATA_USE_NFSCOPY */
  164. -        ) {
  165. -        status = ERROR_NOT_SUPPORTED;
  166. -        goto out;
  167. +    else if (upcall->opcode == NFS41_SYSOP_FSCTL_DUPLICATE_DATA) {
  168. +        if ((src_session->client->root->supports_nfs42_seek == false) ||
  169. +            (src_session->client->root->supports_nfs42_clone == false) ||
  170. +            (src_session->client->root->supports_nfs42_deallocate == false)) {
  171. +            status = ERROR_NOT_SUPPORTED;
  172. +            goto out;
  173. +        }
  174.      }
  175. -    /* NFS DEALLOCATE supported ? */
  176. -    if (src_session->client->root->supports_nfs42_deallocate == false) {
  177. -        status = ERROR_NOT_SUPPORTED;
  178. +    else {
  179. +        status = ERROR_INVALID_PARAMETER;
  180. +        eprintf("duplicate_sparsefile("
  181. +            "opcode='%s',"
  182. +            "src_state->path.path='%s' "
  183. +            "dst_state->path.path='%s'): "
  184. +            "Unknown opcode.\n",
  185. +            opcode2string(upcall->opcode),
  186. +            src_state->path.path,
  187. +            dst_state->path.path);
  188.          goto out;
  189.      }
  190.  
  191. @@ -837,7 +847,8 @@ int handle_duplicatedata(void *daemon_context,
  192.  
  193.      (void)memset(&info, 0, sizeof(info));
  194.  
  195. -    status = duplicate_sparsefile(src_state,
  196. +    status = duplicate_sparsefile(upcall->opcode,
  197. +        src_state,
  198.          dst_state,
  199.          args->srcfileoffset,
  200.          args->destfileoffset,
  201. @@ -879,3 +890,10 @@ const nfs41_upcall_op nfs41_op_duplicatedata = {
  202.      .marshall = marshall_duplicatedata,
  203.      .arg_size = sizeof(duplicatedata_upcall_args)
  204.  };
  205. +
  206. +const nfs41_upcall_op nfs41_op_offload_datacopy = {
  207. +    .parse = parse_duplicatedata,
  208. +    .handle = handle_duplicatedata,
  209. +    .marshall = marshall_duplicatedata,
  210. +    .arg_size = sizeof(duplicatedata_upcall_args)
  211. +};
  212. diff --git a/daemon/upcall.c b/daemon/upcall.c
  213. index 45e0729..53433c4 100644
  214. --- a/daemon/upcall.c
  215. +++ b/daemon/upcall.c
  216. @@ -52,6 +52,7 @@ extern const nfs41_upcall_op nfs41_op_setacl;
  217.  extern const nfs41_upcall_op nfs41_op_queryallocatedranges;
  218.  extern const nfs41_upcall_op nfs41_op_setzerodata;
  219.  extern const nfs41_upcall_op nfs41_op_duplicatedata;
  220. +extern const nfs41_upcall_op nfs41_op_offload_datacopy;
  221.  
  222.  /* |_nfs41_opcodes| and |g_upcall_op_table| must be in sync! */
  223.  static const nfs41_upcall_op *g_upcall_op_table[] = {
  224. @@ -78,6 +79,7 @@ static const nfs41_upcall_op *g_upcall_op_table[] = {
  225.      &nfs41_op_queryallocatedranges,
  226.      &nfs41_op_setzerodata,
  227.      &nfs41_op_duplicatedata,
  228. +    &nfs41_op_offload_datacopy,
  229.      NULL,
  230.      NULL
  231.  };
  232. diff --git a/include/nfs41_driver.h b/include/nfs41_driver.h
  233. index bf956f4..7a4ddfc 100644
  234. --- a/include/nfs41_driver.h
  235. +++ b/include/nfs41_driver.h
  236. @@ -88,6 +88,7 @@ typedef enum _nfs41_opcodes {
  237.      NFS41_SYSOP_FSCTL_QUERYALLOCATEDRANGES,
  238.      NFS41_SYSOP_FSCTL_SET_ZERO_DATA,
  239.      NFS41_SYSOP_FSCTL_DUPLICATE_DATA,
  240. +    NFS41_SYSOP_FSCTL_OFFLOAD_DATACOPY,
  241.      NFS41_SYSOP_SHUTDOWN,
  242.      NFS41_SYSOP_INVALID_OPCODE1
  243.  } nfs41_opcodes;
  244. diff --git a/sys/nfs41sys_debug.c b/sys/nfs41sys_debug.c
  245. index ee95c9a..ffebee3 100644
  246. --- a/sys/nfs41sys_debug.c
  247. +++ b/sys/nfs41sys_debug.c
  248. @@ -683,6 +683,8 @@ const char *opcode2string(int opcode)
  249.      case NFS41_SYSOP_FSCTL_QUERYALLOCATEDRANGES: return "NFS41_SYSOP_FSCTL_QUERYALLOCATEDRANGES";
  250.      case NFS41_SYSOP_FSCTL_SET_ZERO_DATA: return "NFS41_SYSOP_FSCTL_SET_ZERO_DATA";
  251.      case NFS41_SYSOP_FSCTL_DUPLICATE_DATA: return "NFS41_SYSOP_FSCTL_DUPLICATE_DATA";
  252. +    case NFS41_SYSOP_FSCTL_OFFLOAD_DATACOPY:
  253. +        return "NFS41_SYSOP_FSCTL_OFFLOAD_DATACOPY";
  254.      default: return "UNKNOWN";
  255.      }
  256.  }
  257. diff --git a/sys/nfs41sys_driver.c b/sys/nfs41sys_driver.c
  258. index b079180..fd72305 100644
  259. --- a/sys/nfs41sys_driver.c
  260. +++ b/sys/nfs41sys_driver.c
  261. @@ -131,6 +131,8 @@ PRDBSS_DEVICE_OBJECT nfs41_dev;
  262.  KEVENT upcallEvent;
  263.  FAST_MUTEX upcallLock, downcallLock, fcblistLock;
  264.  FAST_MUTEX openOwnerLock;
  265. +FAST_MUTEX offloadcontextLock;
  266. +nfs41_offloadcontext_list offloadcontext_list;
  267.  
  268.  LONGLONG xid = 0;
  269.  LONG open_owner_id = 1;
  270. @@ -772,6 +774,7 @@ NTSTATUS nfs41_DeallocateForFobx(
  271.      __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(pFobx);
  272.  
  273.      nfs41_invalidate_fobx_entry(pFobx);
  274. +    nfs41_remove_offloadcontext_for_fobx(pFobx);
  275.  
  276.      if (nfs41_fobx->acl) {
  277.          RxFreePool(nfs41_fobx->acl);
  278. @@ -1396,9 +1399,11 @@ NTSTATUS DriverEntry(
  279.      ExInitializeFastMutex(&downcallLock);
  280.      ExInitializeFastMutex(&openOwnerLock);
  281.      ExInitializeFastMutex(&fcblistLock);
  282. +    ExInitializeFastMutex(&offloadcontextLock);
  283.      InitializeListHead(&upcall.head);
  284.      InitializeListHead(&downcall.head);
  285.      InitializeListHead(&openlist.head);
  286. +    InitializeListHead(&offloadcontext_list.head);
  287.  #ifdef USE_LOOKASIDELISTS_FOR_UPDOWNCALLENTRY_MEM
  288.      /*
  289.       * The |Depth| parameter is unfortunately ignored in Win10,
  290. diff --git a/sys/nfs41sys_driver.h b/sys/nfs41sys_driver.h
  291. index 597d207..3f8cc68 100644
  292. --- a/sys/nfs41sys_driver.h
  293. +++ b/sys/nfs41sys_driver.h
  294. @@ -507,6 +507,12 @@ typedef struct _nfs41_fcb_list {
  295.  } nfs41_fcb_list;
  296.  nfs41_fcb_list openlist;
  297.  
  298. +typedef struct _nfs41_offloadcontext_list {
  299. +    LIST_ENTRY head;
  300. +} nfs41_offloadcontext_list;
  301. +extern nfs41_offloadcontext_list offloadcontext_list;
  302. +extern FAST_MUTEX offloadcontextLock;
  303. +
  304.  typedef enum _NULMRX_STORAGE_TYPE_CODES {
  305.      NTC_NFS41_DEVICE_EXTENSION      =   (NODE_TYPE_CODE)0xFC00,
  306.  } NFS41_STORAGE_TYPE_CODES;
  307. @@ -685,6 +691,8 @@ NTSTATUS marshal_nfs41_duplicatedata(
  308.  NTSTATUS unmarshal_nfs41_duplicatedata(
  309.      nfs41_updowncall_entry *cur,
  310.      unsigned char **buf);
  311. +void nfs41_remove_offloadcontext_for_fobx(
  312. +    IN PMRX_FOBX pFobx);
  313.  
  314.  /* nfs41sys_ioctl.c */
  315.  NTSTATUS nfs41_IoCtl(
  316. diff --git a/sys/nfs41sys_fsctl.c b/sys/nfs41sys_fsctl.c
  317. index c1a3f2b..5e2eb9f 100644
  318. --- a/sys/nfs41sys_fsctl.c
  319. +++ b/sys/nfs41sys_fsctl.c
  320. @@ -56,7 +56,7 @@
  321.  #include <rx.h>
  322.  #include <windef.h>
  323.  #include <winerror.h>
  324. -
  325. +#include <ntddstor.h>
  326.  #include <Ntstrsafe.h>
  327.  
  328.  #include "nfs41sys_buildconfig.h"
  329. @@ -863,6 +863,434 @@ NTSTATUS unmarshal_nfs41_duplicatedata(
  330.      return status;
  331.  }
  332.  
  333. +/*
  334. + * |offloadcontext_entry| - context to store |FSCTL_OFFLOAD_READ| token
  335. + * information
  336. + *
  337. + * * Notes:
  338. + * - These are stored in a global list, as |FSCTL_OFFLOAD_READ|+
  339. + * |FSCTL_OFFLOAD_WRITE| is intended to work for intra-server and
  340. + * inter-server copies, so |FSCTL_OFFLOAD_READ| might be done on one
  341. + * filesystem but |FSCTL_OFFLOAD_WRITE| might be done on a different
  342. + * one
  343. + *
  344. + * * FIXME:
  345. + * - Is it legal if one user passes a token to another user, or
  346. + * should this be prevented ?
  347. + */
  348. +typedef struct _offloadcontext_entry
  349. +{
  350. +    LIST_ENTRY              next;
  351. +    /*
  352. +     * r/w lock - shared access for |FSCTL_OFFLOAD_WRITE|, so one token can
  353. +     * be used for multiple parallel writes, exclusive access for file delete
  354. +     * (i.e. wait until all shared access before deleting the context)
  355. +     */
  356. +    ERESOURCE               resource;
  357. +    STORAGE_OFFLOAD_TOKEN   token;
  358. +    PNFS41_FOBX             src_fobx;
  359. +    ULONGLONG               src_fileoffset;
  360. +    ULONGLONG               src_length;
  361. +} offloadcontext_entry;
  362. +
  363. +
  364. +void nfs41_remove_offloadcontext_for_fobx(
  365. +    IN PMRX_FOBX pFobx)
  366. +{
  367. +    PLIST_ENTRY pEntry;
  368. +    offloadcontext_entry *cur, *found = NULL;
  369. +    __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(pFobx);
  370. +
  371. +    ExAcquireFastMutexUnsafe(&offloadcontextLock);
  372. +
  373. +    pEntry = offloadcontext_list.head.Flink;
  374. +    while (!IsListEmpty(&offloadcontext_list.head)) {
  375. +        cur = (offloadcontext_entry *)CONTAINING_RECORD(pEntry,
  376. +            offloadcontext_entry, next);
  377. +        if (cur->src_fobx == nfs41_fobx) {
  378. +            found = cur;
  379. +            break;
  380. +        }
  381. +        if (pEntry->Flink == &offloadcontext_list.head) {
  382. +            break;
  383. +        }
  384. +        pEntry = pEntry->Flink;
  385. +    }
  386. +
  387. +    if (found) {
  388. +        DbgP("nfs41_remove_offloadcontext(pFobx=0x%p): "
  389. +            "removing found=0x%p\n",
  390. +            pFobx,
  391. +            found);
  392. +
  393. +        /* Wait for any shared access in |nfs41_OffloadWrite()| to finish */
  394. +        (void)ExAcquireResourceExclusiveLite(&found->resource, TRUE);
  395. +        ExReleaseResourceLite(&found->resource);
  396. +
  397. +        RemoveEntryList(&found->next);
  398. +
  399. +        (void)ExDeleteResourceLite(&found->resource);
  400. +        RxFreePool(found);
  401. +    }
  402. +    else {
  403. +        DbgP("nfs41_remove_offloadcontext(pFobx=0x%p): Nothing found.\n",
  404. +            pFobx);
  405. +    }
  406. +
  407. +    ExReleaseFastMutexUnsafe(&offloadcontextLock);
  408. +}
  409. +
  410. +static
  411. +offloadcontext_entry *nfs41_find_offloadcontext_acquireshared(
  412. +    IN offloadcontext_entry *unvalidated_oce)
  413. +{
  414. +    PLIST_ENTRY pEntry;
  415. +    offloadcontext_entry *cur, *found = NULL;
  416. +
  417. +    ExAcquireFastMutexUnsafe(&offloadcontextLock);
  418. +
  419. +    pEntry = offloadcontext_list.head.Flink;
  420. +    while (!IsListEmpty(&offloadcontext_list.head)) {
  421. +        cur = (offloadcontext_entry *)CONTAINING_RECORD(pEntry,
  422. +            offloadcontext_entry, next);
  423. +        if (cur == unvalidated_oce) {
  424. +            found = cur;
  425. +            break;
  426. +        }
  427. +        if (pEntry->Flink == &offloadcontext_list.head) {
  428. +            break;
  429. +        }
  430. +        pEntry = pEntry->Flink;
  431. +    }
  432. +
  433. +    if (found) {
  434. +        DbgP("nfs41_find_offloadcontext_acquireshared(unvalidated_oce=0x%p): "
  435. +            "found=0x%p\n",
  436. +            unvalidated_oce);
  437. +
  438. +        (void)ExAcquireSharedStarveExclusive(&found->resource, TRUE);
  439. +        ExReleaseFastMutexUnsafe(&offloadcontextLock);
  440. +        return found;
  441. +    }
  442. +    else {
  443. +        DbgP("nfs41_find_offloadcontext_acquireshared(unvalidated_oce=0x%p): "
  444. +            "Nothing found.\n",
  445. +            unvalidated_oce);
  446. +        ExReleaseFastMutexUnsafe(&offloadcontextLock);
  447. +        return NULL;
  448. +    }
  449. +}
  450. +
  451. +static
  452. +NTSTATUS nfs41_OffloadRead(
  453. +    IN OUT PRX_CONTEXT RxContext)
  454. +{
  455. +    NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
  456. +    __notnull XXCTL_LOWIO_COMPONENT *FsCtl =
  457. +        &RxContext->LowIoContext.ParamsFor.FsCtl;
  458. +    __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(RxContext->pFobx);
  459. +
  460. +    DbgEn();
  461. +
  462. +    RxContext->IoStatusBlock.Information = 0;
  463. +
  464. +    if (FsCtl->pInputBuffer == NULL) {
  465. +        status = STATUS_INVALID_USER_BUFFER;
  466. +        goto out;
  467. +    }
  468. +
  469. +    if (FsCtl->pOutputBuffer == NULL) {
  470. +        status = STATUS_INVALID_USER_BUFFER;
  471. +        goto out;
  472. +    }
  473. +
  474. +    if (FsCtl->InputBufferLength < sizeof(FSCTL_OFFLOAD_READ_INPUT)) {
  475. +        DbgP("nfs41_OffloadRead: "
  476. +            "buffer too small for FSCTL_OFFLOAD_READ_INPUT\n");
  477. +        status = STATUS_BUFFER_TOO_SMALL;
  478. +        goto out;
  479. +    }
  480. +    if (FsCtl->OutputBufferLength < sizeof(FSCTL_OFFLOAD_READ_OUTPUT)) {
  481. +        DbgP("nfs41_OffloadRead: "
  482. +            "buffer too small for FSCTL_OFFLOAD_READ_OUTPUT\n");
  483. +        status = STATUS_BUFFER_TOO_SMALL;
  484. +        goto out;
  485. +    }
  486. +
  487. +    PFSCTL_OFFLOAD_READ_INPUT ori =
  488. +        (PFSCTL_OFFLOAD_READ_INPUT)FsCtl->pInputBuffer;
  489. +    PFSCTL_OFFLOAD_READ_OUTPUT oro =
  490. +        (PFSCTL_OFFLOAD_READ_OUTPUT)FsCtl->pOutputBuffer;
  491. +
  492. +    DbgP("nfs41_OffloadRead: "
  493. +        "ori->(Size=%lu, Flags=0x%lx, TokenTimeToLive=%lu, Reserved=%lu, "
  494. +        "FileOffset=%llu, CopyLength=%llu)\n",
  495. +        (unsigned long)ori->Size,
  496. +        (unsigned long)ori->Flags,
  497. +        (unsigned long)ori->TokenTimeToLive,
  498. +        (unsigned long)ori->Reserved,
  499. +        (unsigned long long)ori->FileOffset,
  500. +        (unsigned long long)ori->CopyLength);
  501. +
  502. +    offloadcontext_entry *oce = RxAllocatePoolWithTag(NonPagedPoolNx,
  503. +        sizeof(offloadcontext_entry), NFS41_MM_POOLTAG);
  504. +    if (oce == NULL) {
  505. +        status = STATUS_INSUFFICIENT_RESOURCES;
  506. +        goto out;
  507. +    }
  508. +
  509. +    DbgP("nfs41_OffloadRead: oce=0x%p\n", oce);
  510. +
  511. +    (void)ExInitializeResourceLite(&oce->resource);
  512. +
  513. +    (void)memset(&oce->token, 0, sizeof(oce->token));
  514. +    /* Add safeguard to |TokenType| */
  515. +    oce->token.TokenType[0] = 'N';
  516. +    oce->token.TokenType[1] = 'F';
  517. +    oce->token.TokenType[2] = 'S';
  518. +    oce->token.TokenType[3] = '4';
  519. +    /* FIXME: What about the endianness of |TokenIdLength| ? */
  520. +    *((USHORT *)(&oce->token.TokenIdLength[0])) =
  521. +        STORAGE_OFFLOAD_TOKEN_ID_LENGTH;
  522. +    *((void **)(&oce->token.Token[0])) = oce;
  523. +    oce->src_fobx = nfs41_fobx;
  524. +    oce->src_fileoffset = ori->FileOffset;
  525. +    oce->src_length = ori->CopyLength;
  526. +
  527. +    oro->Size = sizeof(FSCTL_OFFLOAD_READ_OUTPUT);
  528. +    oro->Flags = 0;
  529. +    oro->TransferLength = ori->CopyLength;
  530. +    (void)memcpy(&oro->Token[0], &oce->token, sizeof(oce->token));
  531. +
  532. +    nfs41_AddEntry(offloadcontextLock, offloadcontext_list, oce);
  533. +
  534. +    RxContext->CurrentIrp->IoStatus.Status = status = STATUS_SUCCESS;
  535. +    RxContext->InformationToReturn = sizeof(FSCTL_OFFLOAD_READ_OUTPUT);
  536. +
  537. +out:
  538. +    DbgEx();
  539. +    return status;
  540. +}
  541. +
  542. +static
  543. +NTSTATUS check_nfs41_offload_write_args(
  544. +    PRX_CONTEXT RxContext)
  545. +{
  546. +    NTSTATUS status = STATUS_SUCCESS;
  547. +    __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
  548. +    __notnull PNFS41_V_NET_ROOT_EXTENSION VNetRootContext =
  549. +        NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
  550. +
  551. +    /* access checks */
  552. +    if (VNetRootContext->read_only) {
  553. +        status = STATUS_MEDIA_WRITE_PROTECTED;
  554. +        goto out;
  555. +    }
  556. +    if (!(SrvOpen->DesiredAccess &
  557. +        (FILE_WRITE_DATA|FILE_WRITE_ATTRIBUTES))) {
  558. +        status = STATUS_ACCESS_DENIED;
  559. +        goto out;
  560. +    }
  561. +
  562. +out:
  563. +    return status;
  564. +}
  565. +
  566. +static
  567. +NTSTATUS nfs41_OffloadWrite(
  568. +    IN OUT PRX_CONTEXT RxContext)
  569. +{
  570. +    NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
  571. +    nfs41_updowncall_entry *entry = NULL;
  572. +    __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
  573. +    __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
  574. +        NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
  575. +    __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
  576. +        NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
  577. +    __notnull XXCTL_LOWIO_COMPONENT *FsCtl =
  578. +        &RxContext->LowIoContext.ParamsFor.FsCtl;
  579. +    __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(RxContext->pFobx);
  580. +    offloadcontext_entry *src_oce = NULL;
  581. +
  582. +    struct {
  583. +        LONGLONG    srcfileoffset;
  584. +        LONGLONG    destfileoffset;
  585. +        LONGLONG    bytecount;
  586. +    } dd;
  587. +
  588. +    DbgEn();
  589. +
  590. +    LONGLONG io_delay;
  591. +    RxContext->IoStatusBlock.Information = 0;
  592. +
  593. +    status = check_nfs41_offload_write_args(RxContext);
  594. +    if (status)
  595. +        goto out;
  596. +
  597. +    if (FsCtl->pInputBuffer == NULL) {
  598. +        status = STATUS_INVALID_USER_BUFFER;
  599. +        goto out;
  600. +    }
  601. +    if (FsCtl->pOutputBuffer == NULL) {
  602. +        status = STATUS_INVALID_USER_BUFFER;
  603. +        goto out;
  604. +    }
  605. +    if (FsCtl->InputBufferLength < sizeof(FSCTL_OFFLOAD_WRITE_INPUT)) {
  606. +        DbgP("nfs41_OffloadWrite: "
  607. +            "buffer too small for FSCTL_OFFLOAD_WRITE_INPUT\n");
  608. +        status = STATUS_BUFFER_TOO_SMALL;
  609. +        goto out;
  610. +    }
  611. +    if (FsCtl->OutputBufferLength < sizeof(FSCTL_OFFLOAD_WRITE_OUTPUT)) {
  612. +        DbgP("nfs41_OffloadWrite: "
  613. +            "buffer too small for FSCTL_OFFLOAD_WRITE_OUTPUT\n");
  614. +        status = STATUS_BUFFER_TOO_SMALL;
  615. +        goto out;
  616. +    }
  617. +
  618. +    PFSCTL_OFFLOAD_WRITE_INPUT owi =
  619. +        (PFSCTL_OFFLOAD_WRITE_INPUT)FsCtl->pInputBuffer;
  620. +    PFSCTL_OFFLOAD_WRITE_OUTPUT owo =
  621. +        (PFSCTL_OFFLOAD_WRITE_OUTPUT)FsCtl->pOutputBuffer;
  622. +
  623. +    offloadcontext_entry *unvalidated_src_oce;
  624. +
  625. +    /*
  626. +     * Peel |offloadcontext_entry| pointer from token...
  627. +     */
  628. +    unvalidated_src_oce =
  629. +        *((void **)(&(((STORAGE_OFFLOAD_TOKEN *)(&owi->Token[0]))->Token[0])));
  630. +    DbgP("nfs41_OffloadWrite: "
  631. +        "unvalidated_src_oce=0x%p\n", unvalidated_src_oce);
  632. +
  633. +    /*
  634. +     * ... and validate it (and take a shared lock if validation was
  635. +     * successful, so nobody can delete the context while we use it)!
  636. +     */
  637. +    src_oce = nfs41_find_offloadcontext_acquireshared(unvalidated_src_oce);
  638. +    if (src_oce == NULL) {
  639. +        DbgP("nfs41_OffloadWrite: "
  640. +            "nfs41_find_offloadcontext_acquireshared() failed\n");
  641. +        status = STATUS_INVALID_PARAMETER;
  642. +        goto out;
  643. +    }
  644. +
  645. +    DbgP("nfs41_OffloadWrite: src_oce=0x%p\n", src_oce);
  646. +
  647. +    /* Check safeguard... */
  648. +    if ((src_oce->token.TokenType[0] != 'N') ||
  649. +        (src_oce->token.TokenType[1] != 'F') ||
  650. +        (src_oce->token.TokenType[2] != 'S') ||
  651. +        (src_oce->token.TokenType[3] != '4')) {
  652. +        DbgP("nfs41_OffloadWrite: "
  653. +            "token in src_oce=0x%p not a 'NFS4' token\n",
  654. +            src_oce);
  655. +        status = STATUS_INVALID_PARAMETER;
  656. +        goto out;
  657. +    }
  658. +
  659. +    /*
  660. +     * FIXME: We should validate the length passed as
  661. +     * |FSCTL_OFFLOAD_READ_INPUT.CopyLength| here better, because it is
  662. +     * also used as some kind of access control to different parts of a
  663. +     * file
  664. +     */
  665. +    dd.srcfileoffset    = src_oce->src_fileoffset + owi->TransferOffset;
  666. +    dd.destfileoffset   = owi->FileOffset;
  667. +    dd.bytecount        = owi->CopyLength;
  668. +
  669. +    DbgP("nfs41_OffloadWrite: "
  670. +        "dd=(srcfileoffset=%lld,"
  671. +        "destfileoffset=%lld,"
  672. +        "bytecount=%lld)\n",
  673. +        (long long)dd.srcfileoffset,
  674. +        (long long)dd.destfileoffset,
  675. +        (long long)dd.bytecount);
  676. +
  677. +    if (dd.bytecount == 0LL) {
  678. +        status = STATUS_SUCCESS;
  679. +        goto out;
  680. +    }
  681. +
  682. +    PNFS41_FOBX nfs41_src_fobx = src_oce->src_fobx;
  683. +    if (!nfs41_src_fobx) {
  684. +        DbgP("nfs41_OffloadWrite: No nfs41_src_fobx\n");
  685. +        status = STATUS_INVALID_PARAMETER;
  686. +        goto out;
  687. +    }
  688. +
  689. +    /*
  690. +     * Disable caching because NFSv4.2 COPY is basically a
  691. +     * "write" operation. AFAIK we should flush the cache and wait
  692. +     * for the kernel lazy writer (which |RxChangeBufferingState()|
  693. +     * AFAIK does) before doing the COPY, to avoid that we
  694. +     * have outstanding writes in the kernel cache at the same
  695. +     * location where the COPY should do it's work
  696. +     */
  697. +    ULONG flag = DISABLE_CACHING;
  698. +    DbgP("nfs41_OffloadWrite: disableing caching for file '%wZ'\n",
  699. +        SrvOpen->pAlreadyPrefixedName);
  700. +    RxChangeBufferingState((PSRV_OPEN)SrvOpen, ULongToPtr(flag), 1);
  701. +
  702. +    status = nfs41_UpcallCreate(NFS41_SYSOP_FSCTL_OFFLOAD_DATACOPY,
  703. +        &nfs41_fobx->sec_ctx,
  704. +        pVNetRootContext->session,
  705. +        nfs41_fobx->nfs41_open_state,
  706. +        pNetRootContext->nfs41d_version,
  707. +        SrvOpen->pAlreadyPrefixedName,
  708. +        &entry);
  709. +
  710. +    if (status)
  711. +        goto out;
  712. +
  713. +    entry->u.DuplicateData.src_state = nfs41_src_fobx->nfs41_open_state;
  714. +    entry->u.DuplicateData.srcfileoffset = dd.srcfileoffset;
  715. +    entry->u.DuplicateData.destfileoffset = dd.destfileoffset;
  716. +    entry->u.DuplicateData.bytecount = dd.bytecount;
  717. +
  718. +    /* Add extra timeout depending on file size */
  719. +    io_delay = pVNetRootContext->timeout +
  720. +        EXTRA_TIMEOUT_PER_BYTE(entry->u.DuplicateData.bytecount);
  721. +
  722. +    status = nfs41_UpcallWaitForReply(entry, io_delay);
  723. +    if (status) {
  724. +        /* Timeout - |nfs41_downcall()| will free |entry|+contents */
  725. +        entry = NULL;
  726. +        goto out;
  727. +    }
  728. +
  729. +    if (!entry->status) {
  730. +        DbgP("nfs41_OffloadWrite: SUCCESS\n");
  731. +
  732. +        owo->Size = sizeof(FSCTL_OFFLOAD_READ_OUTPUT);
  733. +        owo->Flags = 0;
  734. +        owo->LengthWritten = dd.bytecount;
  735. +
  736. +        RxContext->CurrentIrp->IoStatus.Status = status = STATUS_SUCCESS;
  737. +        RxContext->InformationToReturn = sizeof(FSCTL_OFFLOAD_READ_OUTPUT);
  738. +    }
  739. +    else {
  740. +        DbgP("nfs41_OffloadWrite: "
  741. +            "FAILURE, entry->status=0x%lx\n", entry->status);
  742. +        status = map_setfile_error(entry->status);
  743. +        RxContext->CurrentIrp->IoStatus.Status = status;
  744. +        RxContext->IoStatusBlock.Information = 0;
  745. +    }
  746. +
  747. +out:
  748. +    if (src_oce) {
  749. +        /* Release resource we obtained in shared mode */
  750. +        ExReleaseResourceLite(&src_oce->resource);
  751. +    }
  752. +
  753. +    if (entry) {
  754. +        nfs41_UpcallDestroy(entry);
  755. +    }
  756. +
  757. +    DbgEx();
  758. +    return status;
  759. +}
  760. +
  761.  NTSTATUS nfs41_FsCtl(
  762.      IN OUT PRX_CONTEXT RxContext)
  763.  {
  764. @@ -895,6 +1323,12 @@ NTSTATUS nfs41_FsCtl(
  765.      case FSCTL_DUPLICATE_EXTENTS_TO_FILE:
  766.          status = nfs41_DuplicateData(RxContext);
  767.          break;
  768. +    case FSCTL_OFFLOAD_READ:
  769. +        status = nfs41_OffloadRead(RxContext);
  770. +        break;
  771. +    case FSCTL_OFFLOAD_WRITE:
  772. +        status = nfs41_OffloadWrite(RxContext);
  773. +        break;
  774.      default:
  775.          break;
  776.      }
  777. diff --git a/sys/nfs41sys_updowncall.c b/sys/nfs41sys_updowncall.c
  778. index cf5be35..fc523a4 100644
  779. --- a/sys/nfs41sys_updowncall.c
  780. +++ b/sys/nfs41sys_updowncall.c
  781. @@ -321,6 +321,7 @@ NTSTATUS handle_upcall(
  782.              pbOut, cbOut, len);
  783.          break;
  784.      case NFS41_SYSOP_FSCTL_DUPLICATE_DATA:
  785. +    case NFS41_SYSOP_FSCTL_OFFLOAD_DATACOPY:
  786.          status = marshal_nfs41_duplicatedata(entry,
  787.              pbOut, cbOut, len);
  788.          break;
  789. @@ -785,6 +786,7 @@ NTSTATUS nfs41_downcall(
  790.              unmarshal_nfs41_setzerodata(cur, &buf);
  791.              break;
  792.          case NFS41_SYSOP_FSCTL_DUPLICATE_DATA:
  793. +        case NFS41_SYSOP_FSCTL_OFFLOAD_DATACOPY:
  794.              unmarshal_nfs41_duplicatedata(cur, &buf);
  795.              break;
  796.          }

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