pastebin - collaborative debugging tool
nrubsig.kpaste.net RSS


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

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