pastebin - collaborative debugging tool
nrubsig.kpaste.net RSS

Difference between
modified post 72f6de by Anonymous on Tue 19th Aug 2025 20:02
original post 395ab by Anonymous on Tue 19th Aug 2025 14:55
Download diff
Show old version | new version | both versions

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

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