- From f69e5071a0e1a2e3d8b33fa4ac3d14e1ca017a13 Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Wed, 20 Aug 2025 10:10:21 +0200
- Subject: [PATCH 1/6] daemon: Handle NFSv4.2 COPY requests which copied less
- bytes than requested
- Handle NFSv4.2 COPY requests which copied less bytes than requested.
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- daemon/fsctl.c | 40 ++++++++++++++++++++++++++++------------
- daemon/nfs41_ops.h | 1 +
- daemon/nfs42_ops.c | 9 ++-------
- 3 files changed, 31 insertions(+), 19 deletions(-)
- diff --git a/daemon/fsctl.c b/daemon/fsctl.c
- index e1c4f19..f90950b 100644
- --- a/daemon/fsctl.c
- +++ b/daemon/fsctl.c
- @@ -595,18 +595,34 @@ int duplicate_sparsefile(nfs41_open_state *src_state,
- (int)hole_seek_sr_eof));
- #ifdef DUP_DATA_USE_NFSCOPY
- - nfs41_write_verf verf;
- - status = nfs42_copy(session,
- - src_file,
- - dst_file,
- - &src_stateid,
- - &dst_stateid,
- - data_seek_sr_offset,
- - destfileoffset + (data_seek_sr_offset-srcfileoffset),
- - data_size,
- - &verf,
- - info);
- - /* FIXME: What should we do with |verf| ? Should we COMMIT this ? */
- + uint64_t bytes_written;
- + uint64_t bytestowrite = data_size;
- + uint64_t writeoffset = 0ULL;
- +
- + do
- + {
- + nfs41_write_verf verf;
- + bytes_written = 0ULL;
- +
- + status = nfs42_copy(session,
- + src_file,
- + dst_file,
- + &src_stateid,
- + &dst_stateid,
- + (data_seek_sr_offset + writeoffset),
- + (destfileoffset + (data_seek_sr_offset-srcfileoffset) +
- + writeoffset),
- + bytestowrite,
- + &bytes_written,
- + &verf,
- + info);
- + if (status)
- + break;
- +
- + bytestowrite -= bytes_written;
- + writeoffset += bytes_written;
- + /* FIXME: What should we do with |verf| ? Should we COMMIT this ? */
- + } while (bytestowrite > 0ULL);
- #else
- status = nfs42_clone(session,
- src_file,
- diff --git a/daemon/nfs41_ops.h b/daemon/nfs41_ops.h
- index dd9dcb4..bd93fbf 100644
- --- a/daemon/nfs41_ops.h
- +++ b/daemon/nfs41_ops.h
- @@ -1299,6 +1299,7 @@ int nfs42_copy(
- IN uint64_t src_offset,
- IN uint64_t dst_offset,
- IN uint64_t length,
- + OUT uint64_t *bytes_written,
- OUT nfs41_write_verf *writeverf,
- OUT nfs41_file_info *cinfo);
- diff --git a/daemon/nfs42_ops.c b/daemon/nfs42_ops.c
- index 582a968..3494a3b 100644
- --- a/daemon/nfs42_ops.c
- +++ b/daemon/nfs42_ops.c
- @@ -122,6 +122,7 @@ int nfs42_copy(
- IN uint64_t src_offset,
- IN uint64_t dst_offset,
- IN uint64_t length,
- + OUT uint64_t *bytes_written,
- OUT nfs41_write_verf *writeverf,
- OUT nfs41_file_info *cinfo)
- {
- @@ -205,13 +206,7 @@ int nfs42_copy(
- nfs41_superblock_space_changed(dst_file->fh.superblock);
- - if (copy_res.u.resok4.response.count != length) {
- - DPRINTF(0,
- - ("nfs42_copy: "
- - "copy_res.u.resok4.response.count(=%lld) < length(=%lld)\n",
- - (long long)copy_res.u.resok4.response.count, (long long)length));
- - status = ERROR_NET_WRITE_FAULT;
- - }
- + *bytes_written = copy_res.u.resok4.response.count;
- out:
- return status;
- --
- 2.45.1
- From 5570d231f70931307e16ee386b0d9d5f704682ff Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Wed, 20 Aug 2025 12:21:53 +0200
- Subject: [PATCH 2/6] README.md,daemon,docs,include,sys: Implement data copy
- offload via |FSCTL_OFFLOAD_READ|+|FSCTL_OFFLOAD_WRITE|
- Implement data copy (server-side data copying) offload via
- |FSCTL_OFFLOAD_READ|+|FSCTL_OFFLOAD_WRITE| and NFSv4.2 COPY.
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- README.md | 17 ++
- daemon/daemon_debug.c | 1 +
- daemon/fsctl.c | 151 +++++++------
- daemon/upcall.c | 2 +
- docs/README.xml | 21 ++
- include/nfs41_driver.h | 1 +
- sys/nfs41sys_debug.c | 2 +
- sys/nfs41sys_driver.c | 5 +
- sys/nfs41sys_driver.h | 8 +
- sys/nfs41sys_fsctl.c | 439 +++++++++++++++++++++++++++++++++++++-
- sys/nfs41sys_updowncall.c | 2 +
- 11 files changed, 581 insertions(+), 68 deletions(-)
- diff --git a/README.md b/README.md
- index 1c737a1..efe279c 100644
- --- a/README.md
- +++ b/README.md
- @@ -139,6 +139,23 @@ NFSv4.2/NFSv4.1 filesystem driver for Windows 10/11 & Windows Server
- sparse files. Requires on Win11 \>= 22H2 because it relies on
- `|CopyFile2()|` flag `|COPY_FILE_ENABLE_SPARSE_COPY|`.
- +- Data copy offload (server-side copy)
- +
- + - Implemented via Win32 `|FSCTL_OFFLOAD_READ|`+`|FSCTL_OFFLOAD_WRITE|`
- + to copy data blocks directly on the server.
- +
- + - Requires NFSv4.2 server which supports the NFSv4.2 operations
- + "COPY", "DEALLOCATE", "SEEK"
- +
- + - Sparse files are correctly copied including all hole and data ranges
- +
- + - Windows 10 `|CopyFile2()|` API uses
- + `|FSCTL_OFFLOAD_READ|`+`|FSCTL_OFFLOAD_WRITE|` by default
- +
- + - Windows 10 tools like xcopy.exe (on Windows 11 requires `/NOCLONE`,
- + otherwise block cloning is the default), robocopy etc. all use
- + `|CopyFile2()|`, and therefore server-side copies by default
- +
- - Block cloning support
- - Implemented via Win32 `|FSCTL_DUPLICATE_EXTENTS_TO_FILE|` to clone
- diff --git a/daemon/daemon_debug.c b/daemon/daemon_debug.c
- index 20fd420..02a0aec 100644
- --- a/daemon/daemon_debug.c
- +++ b/daemon/daemon_debug.c
- @@ -485,6 +485,7 @@ const char* opcode2string(nfs41_opcodes opcode)
- NFSOPCODE_TO_STRLITERAL(NFS41_SYSOP_FSCTL_QUERYALLOCATEDRANGES)
- NFSOPCODE_TO_STRLITERAL(NFS41_SYSOP_FSCTL_SET_ZERO_DATA)
- NFSOPCODE_TO_STRLITERAL(NFS41_SYSOP_FSCTL_DUPLICATE_DATA)
- + NFSOPCODE_TO_STRLITERAL(NFS41_SYSOP_FSCTL_OFFLOAD_DATACOPY)
- NFSOPCODE_TO_STRLITERAL(NFS41_SYSOP_INVALID_OPCODE1)
- default: break;
- }
- diff --git a/daemon/fsctl.c b/daemon/fsctl.c
- index f90950b..fbbd8aa 100644
- --- a/daemon/fsctl.c
- +++ b/daemon/fsctl.c
- @@ -27,9 +27,6 @@
- #include "daemon_debug.h"
- #include "util.h"
- -/* Testing only: Use NFS COPY instead of NFS CLONE */
- -// #define DUP_DATA_USE_NFSCOPY 1
- -
- #define QARLVL 2 /* dprintf level for "query allocated ranges" logging */
- #define SZDLVL 2 /* dprintf level for "set zero data" logging */
- #define DDLVL 2 /* dprintf level for "duplicate data" logging */
- @@ -470,7 +467,8 @@ out:
- }
- static
- -int duplicate_sparsefile(nfs41_open_state *src_state,
- +int duplicate_sparsefile(nfs41_opcodes opcode,
- + nfs41_open_state *src_state,
- nfs41_open_state *dst_state,
- uint64_t srcfileoffset,
- uint64_t destfileoffset,
- @@ -498,7 +496,8 @@ int duplicate_sparsefile(nfs41_open_state *src_state,
- (void)memset(info, 0, sizeof(*info));
- DPRINTF(DDLVL,
- - ("--> duplicate_sparsefile(src_state->path.path='%s')\n",
- + ("--> duplicate_sparsefile(opcode='%s',src_state->path.path='%s')\n",
- + opcode2string(opcode),
- src_state->path.path));
- nfs41_open_stateid_arg(src_state, &src_stateid);
- @@ -518,9 +517,11 @@ int duplicate_sparsefile(nfs41_open_state *src_state,
- if (status) {
- DPRINTF(0/*DDLVL*/,
- ("duplicate_sparsefile("
- + "opcode='%s',"
- "src_state->path.path='%s' "
- "dst_state->path.path='%s'): "
- "DEALLOCATE failed with '%s'\n",
- + opcode2string(opcode),
- src_state->path.path,
- dst_state->path.path,
- nfs_error_string(status)));
- @@ -594,62 +595,60 @@ int duplicate_sparsefile(nfs41_open_state *src_state,
- (int)data_seek_sr_eof,
- (int)hole_seek_sr_eof));
- -#ifdef DUP_DATA_USE_NFSCOPY
- - uint64_t bytes_written;
- - uint64_t bytestowrite = data_size;
- - uint64_t writeoffset = 0ULL;
- -
- - do
- - {
- - nfs41_write_verf verf;
- - bytes_written = 0ULL;
- -
- - status = nfs42_copy(session,
- + if (opcode == NFS41_SYSOP_FSCTL_OFFLOAD_DATACOPY) {
- + uint64_t bytes_written;
- + uint64_t bytestowrite = data_size;
- + uint64_t writeoffset = 0ULL;
- +
- + do
- + {
- + nfs41_write_verf verf;
- + bytes_written = 0ULL;
- +
- + status = nfs42_copy(session,
- + src_file,
- + dst_file,
- + &src_stateid,
- + &dst_stateid,
- + (data_seek_sr_offset + writeoffset),
- + (destfileoffset + (data_seek_sr_offset-srcfileoffset) + writeoffset),
- + bytestowrite,
- + &bytes_written,
- + &verf,
- + info);
- + if (status)
- + break;
- +
- + bytestowrite -= bytes_written;
- + writeoffset += bytes_written;
- + /* FIXME: What should we do with |verf| ? Should we COMMIT this ? */
- + } while (bytestowrite > 0ULL);
- + }
- + else if (opcode == NFS41_SYSOP_FSCTL_DUPLICATE_DATA) {
- + status = nfs42_clone(session,
- src_file,
- dst_file,
- &src_stateid,
- &dst_stateid,
- - (data_seek_sr_offset + writeoffset),
- - (destfileoffset + (data_seek_sr_offset-srcfileoffset) +
- - writeoffset),
- - bytestowrite,
- - &bytes_written,
- - &verf,
- + data_seek_sr_offset,
- + destfileoffset + (data_seek_sr_offset-srcfileoffset),
- + data_size,
- info);
- - if (status)
- - break;
- -
- - bytestowrite -= bytes_written;
- - writeoffset += bytes_written;
- - /* FIXME: What should we do with |verf| ? Should we COMMIT this ? */
- - } while (bytestowrite > 0ULL);
- -#else
- - status = nfs42_clone(session,
- - src_file,
- - dst_file,
- - &src_stateid,
- - &dst_stateid,
- - data_seek_sr_offset,
- - destfileoffset + (data_seek_sr_offset-srcfileoffset),
- - data_size,
- - info);
- -#endif /* DUP_DATA_USE_NFSCOPY */
- - if (status) {
- - const char dup_op_name[] =
- -#ifdef DUP_DATA_USE_NFSCOPY
- - "COPY";
- -#else
- - "CLONE";
- -#endif /* DUP_DATA_USE_NFSCOPY */
- + }
- + else {
- + EASSERT(0);
- + }
- + if (status) {
- DPRINTF(0/*DDLVL*/,
- ("duplicate_sparsefile("
- + "opcode='%s',"
- "src_state->path.path='%s' "
- "dst_state->path.path='%s'): "
- - "'%s' failed with '%s'\n",
- + "failed with '%s'\n",
- + opcode2string(opcode),
- src_state->path.path,
- dst_state->path.path,
- - dup_op_name,
- nfs_error_string(status)));
- status = nfs_to_windows_error(status, ERROR_BAD_NET_RESP);
- goto out;
- @@ -704,25 +703,35 @@ int handle_duplicatedata(void *daemon_context,
- dst_state->path.path,
- src_state->path.path));
- - /* NFS SEEK supported ? */
- - if (src_session->client->root->supports_nfs42_seek == false) {
- - status = ERROR_NOT_SUPPORTED;
- - goto out;
- + /*
- + * Check whether we support the required NFS operations...
- + */
- + if (upcall->opcode == NFS41_SYSOP_FSCTL_OFFLOAD_DATACOPY) {
- + if ((src_session->client->root->supports_nfs42_seek == false) ||
- + (src_session->client->root->supports_nfs42_copy == false) ||
- + (src_session->client->root->supports_nfs42_deallocate == false)) {
- + status = ERROR_NOT_SUPPORTED;
- + goto out;
- + }
- }
- - /* NFS CLONE supported ? */
- - if (
- -#ifdef DUP_DATA_USE_NFSCOPY
- - src_session->client->root->supports_nfs42_copy == false
- -#else
- - src_session->client->root->supports_nfs42_clone == false
- -#endif /* DUP_DATA_USE_NFSCOPY */
- - ) {
- - status = ERROR_NOT_SUPPORTED;
- - goto out;
- + else if (upcall->opcode == NFS41_SYSOP_FSCTL_DUPLICATE_DATA) {
- + if ((src_session->client->root->supports_nfs42_seek == false) ||
- + (src_session->client->root->supports_nfs42_clone == false) ||
- + (src_session->client->root->supports_nfs42_deallocate == false)) {
- + status = ERROR_NOT_SUPPORTED;
- + goto out;
- + }
- }
- - /* NFS DEALLOCATE supported ? */
- - if (src_session->client->root->supports_nfs42_deallocate == false) {
- - status = ERROR_NOT_SUPPORTED;
- + else {
- + status = ERROR_INVALID_PARAMETER;
- + eprintf("duplicate_sparsefile("
- + "opcode='%s',"
- + "src_state->path.path='%s' "
- + "dst_state->path.path='%s'): "
- + "Unknown opcode.\n",
- + opcode2string(upcall->opcode),
- + src_state->path.path,
- + dst_state->path.path);
- goto out;
- }
- @@ -853,7 +862,8 @@ int handle_duplicatedata(void *daemon_context,
- (void)memset(&info, 0, sizeof(info));
- - status = duplicate_sparsefile(src_state,
- + status = duplicate_sparsefile(upcall->opcode,
- + src_state,
- dst_state,
- args->srcfileoffset,
- args->destfileoffset,
- @@ -895,3 +905,10 @@ const nfs41_upcall_op nfs41_op_duplicatedata = {
- .marshall = marshall_duplicatedata,
- .arg_size = sizeof(duplicatedata_upcall_args)
- };
- +
- +const nfs41_upcall_op nfs41_op_offload_datacopy = {
- + .parse = parse_duplicatedata,
- + .handle = handle_duplicatedata,
- + .marshall = marshall_duplicatedata,
- + .arg_size = sizeof(duplicatedata_upcall_args)
- +};
- diff --git a/daemon/upcall.c b/daemon/upcall.c
- index 45e0729..53433c4 100644
- --- a/daemon/upcall.c
- +++ b/daemon/upcall.c
- @@ -52,6 +52,7 @@ extern const nfs41_upcall_op nfs41_op_setacl;
- extern const nfs41_upcall_op nfs41_op_queryallocatedranges;
- extern const nfs41_upcall_op nfs41_op_setzerodata;
- extern const nfs41_upcall_op nfs41_op_duplicatedata;
- +extern const nfs41_upcall_op nfs41_op_offload_datacopy;
- /* |_nfs41_opcodes| and |g_upcall_op_table| must be in sync! */
- static const nfs41_upcall_op *g_upcall_op_table[] = {
- @@ -78,6 +79,7 @@ static const nfs41_upcall_op *g_upcall_op_table[] = {
- &nfs41_op_queryallocatedranges,
- &nfs41_op_setzerodata,
- &nfs41_op_duplicatedata,
- + &nfs41_op_offload_datacopy,
- NULL,
- NULL
- };
- diff --git a/docs/README.xml b/docs/README.xml
- index 1252843..a69372a 100644
- --- a/docs/README.xml
- +++ b/docs/README.xml
- @@ -141,6 +141,27 @@
- </itemizedlist>
- </para>
- </listitem>
- + <listitem>
- + <para>Data copy offload (server-side copy)
- + <itemizedlist>
- + <listitem>
- + <para>Implemented via Win32 <literal>|FSCTL_OFFLOAD_READ|</literal>+<literal>|FSCTL_OFFLOAD_WRITE|</literal> to copy data blocks directly on the server.</para>
- + </listitem>
- + <listitem>
- + <para>Requires NFSv4.2 server which supports the NFSv4.2 operations "COPY", "DEALLOCATE", "SEEK"</para>
- + </listitem>
- + <listitem>
- + <para>Sparse files are correctly copied including all hole and data ranges</para>
- + </listitem>
- + <listitem>
- + <para>Windows 10 <literal>|CopyFile2()|</literal> API uses <literal>|FSCTL_OFFLOAD_READ|</literal>+<literal>|FSCTL_OFFLOAD_WRITE|</literal> by default</para>
- + </listitem>
- + <listitem>
- + <para>Windows 10 tools like xcopy.exe (on Windows 11 requires <literal>/NOCLONE</literal>, otherwise block cloning is the default), robocopy etc. all use <literal>|CopyFile2()|</literal>, and therefore server-side copies by default</para>
- + </listitem>
- + </itemizedlist>
- + </para>
- + </listitem>
- <listitem>
- <para>Block cloning support
- <itemizedlist>
- diff --git a/include/nfs41_driver.h b/include/nfs41_driver.h
- index bf956f4..7a4ddfc 100644
- --- a/include/nfs41_driver.h
- +++ b/include/nfs41_driver.h
- @@ -88,6 +88,7 @@ typedef enum _nfs41_opcodes {
- NFS41_SYSOP_FSCTL_QUERYALLOCATEDRANGES,
- NFS41_SYSOP_FSCTL_SET_ZERO_DATA,
- NFS41_SYSOP_FSCTL_DUPLICATE_DATA,
- + NFS41_SYSOP_FSCTL_OFFLOAD_DATACOPY,
- NFS41_SYSOP_SHUTDOWN,
- NFS41_SYSOP_INVALID_OPCODE1
- } nfs41_opcodes;
- diff --git a/sys/nfs41sys_debug.c b/sys/nfs41sys_debug.c
- index ee95c9a..ffebee3 100644
- --- a/sys/nfs41sys_debug.c
- +++ b/sys/nfs41sys_debug.c
- @@ -683,6 +683,8 @@ const char *opcode2string(int opcode)
- case NFS41_SYSOP_FSCTL_QUERYALLOCATEDRANGES: return "NFS41_SYSOP_FSCTL_QUERYALLOCATEDRANGES";
- case NFS41_SYSOP_FSCTL_SET_ZERO_DATA: return "NFS41_SYSOP_FSCTL_SET_ZERO_DATA";
- case NFS41_SYSOP_FSCTL_DUPLICATE_DATA: return "NFS41_SYSOP_FSCTL_DUPLICATE_DATA";
- + case NFS41_SYSOP_FSCTL_OFFLOAD_DATACOPY:
- + return "NFS41_SYSOP_FSCTL_OFFLOAD_DATACOPY";
- default: return "UNKNOWN";
- }
- }
- diff --git a/sys/nfs41sys_driver.c b/sys/nfs41sys_driver.c
- index b079180..fd72305 100644
- --- a/sys/nfs41sys_driver.c
- +++ b/sys/nfs41sys_driver.c
- @@ -131,6 +131,8 @@ PRDBSS_DEVICE_OBJECT nfs41_dev;
- KEVENT upcallEvent;
- FAST_MUTEX upcallLock, downcallLock, fcblistLock;
- FAST_MUTEX openOwnerLock;
- +FAST_MUTEX offloadcontextLock;
- +nfs41_offloadcontext_list offloadcontext_list;
- LONGLONG xid = 0;
- LONG open_owner_id = 1;
- @@ -772,6 +774,7 @@ NTSTATUS nfs41_DeallocateForFobx(
- __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(pFobx);
- nfs41_invalidate_fobx_entry(pFobx);
- + nfs41_remove_offloadcontext_for_fobx(pFobx);
- if (nfs41_fobx->acl) {
- RxFreePool(nfs41_fobx->acl);
- @@ -1396,9 +1399,11 @@ NTSTATUS DriverEntry(
- ExInitializeFastMutex(&downcallLock);
- ExInitializeFastMutex(&openOwnerLock);
- ExInitializeFastMutex(&fcblistLock);
- + ExInitializeFastMutex(&offloadcontextLock);
- InitializeListHead(&upcall.head);
- InitializeListHead(&downcall.head);
- InitializeListHead(&openlist.head);
- + InitializeListHead(&offloadcontext_list.head);
- #ifdef USE_LOOKASIDELISTS_FOR_UPDOWNCALLENTRY_MEM
- /*
- * The |Depth| parameter is unfortunately ignored in Win10,
- diff --git a/sys/nfs41sys_driver.h b/sys/nfs41sys_driver.h
- index 597d207..3f8cc68 100644
- --- a/sys/nfs41sys_driver.h
- +++ b/sys/nfs41sys_driver.h
- @@ -507,6 +507,12 @@ typedef struct _nfs41_fcb_list {
- } nfs41_fcb_list;
- nfs41_fcb_list openlist;
- +typedef struct _nfs41_offloadcontext_list {
- + LIST_ENTRY head;
- +} nfs41_offloadcontext_list;
- +extern nfs41_offloadcontext_list offloadcontext_list;
- +extern FAST_MUTEX offloadcontextLock;
- +
- typedef enum _NULMRX_STORAGE_TYPE_CODES {
- NTC_NFS41_DEVICE_EXTENSION = (NODE_TYPE_CODE)0xFC00,
- } NFS41_STORAGE_TYPE_CODES;
- @@ -685,6 +691,8 @@ NTSTATUS marshal_nfs41_duplicatedata(
- NTSTATUS unmarshal_nfs41_duplicatedata(
- nfs41_updowncall_entry *cur,
- unsigned char **buf);
- +void nfs41_remove_offloadcontext_for_fobx(
- + IN PMRX_FOBX pFobx);
- /* nfs41sys_ioctl.c */
- NTSTATUS nfs41_IoCtl(
- diff --git a/sys/nfs41sys_fsctl.c b/sys/nfs41sys_fsctl.c
- index c1a3f2b..546a95b 100644
- --- a/sys/nfs41sys_fsctl.c
- +++ b/sys/nfs41sys_fsctl.c
- @@ -56,7 +56,7 @@
- #include <rx.h>
- #include <windef.h>
- #include <winerror.h>
- -
- +#include <ntddstor.h>
- #include <Ntstrsafe.h>
- #include "nfs41sys_buildconfig.h"
- @@ -863,6 +863,437 @@ NTSTATUS unmarshal_nfs41_duplicatedata(
- return status;
- }
- +/*
- + * |offloadcontext_entry| - context to store |FSCTL_OFFLOAD_READ| token
- + * information
- + *
- + * * Notes:
- + * - These are stored in a global list, as |FSCTL_OFFLOAD_READ|+
- + * |FSCTL_OFFLOAD_WRITE| is intended to work for intra-server and
- + * inter-server copies, so |FSCTL_OFFLOAD_READ| might be done on one
- + * filesystem but |FSCTL_OFFLOAD_WRITE| might be done on a different
- + * one
- + *
- + * * FIXME:
- + * - Is it legal if one user passes a token to another user, or
- + * should this be prevented ?
- + * - |offloadcontext_entry| lifetime is unkown. Right now we create
- + * it via |FSCTL_OFFLOAD_READ| and remove it when the matching file gets
- + * closed, but we ignore |FSCTL_OFFLOAD_READ_INPUT.TokenTimeToLive|
- + */
- +typedef struct _offloadcontext_entry
- +{
- + LIST_ENTRY next;
- + /*
- + * r/w lock - shared access for |FSCTL_OFFLOAD_WRITE|, so one token can
- + * be used for multiple parallel writes, exclusive access for file delete
- + * (i.e. wait until all shared access before deleting the context)
- + */
- + ERESOURCE resource;
- + STORAGE_OFFLOAD_TOKEN token;
- + PNFS41_FOBX src_fobx;
- + ULONGLONG src_fileoffset;
- + ULONGLONG src_length;
- +} offloadcontext_entry;
- +
- +
- +void nfs41_remove_offloadcontext_for_fobx(
- + IN PMRX_FOBX pFobx)
- +{
- + PLIST_ENTRY pEntry;
- + offloadcontext_entry *cur, *found = NULL;
- + __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(pFobx);
- +
- + ExAcquireFastMutexUnsafe(&offloadcontextLock);
- +
- + pEntry = offloadcontext_list.head.Flink;
- + while (!IsListEmpty(&offloadcontext_list.head)) {
- + cur = (offloadcontext_entry *)CONTAINING_RECORD(pEntry,
- + offloadcontext_entry, next);
- + if (cur->src_fobx == nfs41_fobx) {
- + found = cur;
- + break;
- + }
- + if (pEntry->Flink == &offloadcontext_list.head) {
- + break;
- + }
- + pEntry = pEntry->Flink;
- + }
- +
- + if (found) {
- + DbgP("nfs41_remove_offloadcontext(pFobx=0x%p): "
- + "removing found=0x%p\n",
- + pFobx,
- + found);
- +
- + /* Wait for any shared access in |nfs41_OffloadWrite()| to finish */
- + (void)ExAcquireResourceExclusiveLite(&found->resource, TRUE);
- + ExReleaseResourceLite(&found->resource);
- +
- + RemoveEntryList(&found->next);
- +
- + (void)ExDeleteResourceLite(&found->resource);
- + RxFreePool(found);
- + }
- + else {
- + DbgP("nfs41_remove_offloadcontext(pFobx=0x%p): Nothing found.\n",
- + pFobx);
- + }
- +
- + ExReleaseFastMutexUnsafe(&offloadcontextLock);
- +}
- +
- +static
- +offloadcontext_entry *nfs41_find_offloadcontext_acquireshared(
- + IN offloadcontext_entry *unvalidated_oce)
- +{
- + PLIST_ENTRY pEntry;
- + offloadcontext_entry *cur, *found = NULL;
- +
- + ExAcquireFastMutexUnsafe(&offloadcontextLock);
- +
- + pEntry = offloadcontext_list.head.Flink;
- + while (!IsListEmpty(&offloadcontext_list.head)) {
- + cur = (offloadcontext_entry *)CONTAINING_RECORD(pEntry,
- + offloadcontext_entry, next);
- + if (cur == unvalidated_oce) {
- + found = cur;
- + break;
- + }
- + if (pEntry->Flink == &offloadcontext_list.head) {
- + break;
- + }
- + pEntry = pEntry->Flink;
- + }
- +
- + if (found) {
- + DbgP("nfs41_find_offloadcontext_acquireshared(unvalidated_oce=0x%p): "
- + "found=0x%p\n",
- + unvalidated_oce);
- +
- + (void)ExAcquireSharedStarveExclusive(&found->resource, TRUE);
- + ExReleaseFastMutexUnsafe(&offloadcontextLock);
- + return found;
- + }
- + else {
- + DbgP("nfs41_find_offloadcontext_acquireshared(unvalidated_oce=0x%p): "
- + "Nothing found.\n",
- + unvalidated_oce);
- + ExReleaseFastMutexUnsafe(&offloadcontextLock);
- + return NULL;
- + }
- +}
- +
- +static
- +NTSTATUS nfs41_OffloadRead(
- + IN OUT PRX_CONTEXT RxContext)
- +{
- + NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
- + __notnull XXCTL_LOWIO_COMPONENT *FsCtl =
- + &RxContext->LowIoContext.ParamsFor.FsCtl;
- + __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(RxContext->pFobx);
- +
- + DbgEn();
- +
- + RxContext->IoStatusBlock.Information = 0;
- +
- + if (FsCtl->pInputBuffer == NULL) {
- + status = STATUS_INVALID_USER_BUFFER;
- + goto out;
- + }
- +
- + if (FsCtl->pOutputBuffer == NULL) {
- + status = STATUS_INVALID_USER_BUFFER;
- + goto out;
- + }
- +
- + if (FsCtl->InputBufferLength < sizeof(FSCTL_OFFLOAD_READ_INPUT)) {
- + DbgP("nfs41_OffloadRead: "
- + "buffer too small for FSCTL_OFFLOAD_READ_INPUT\n");
- + status = STATUS_BUFFER_TOO_SMALL;
- + goto out;
- + }
- + if (FsCtl->OutputBufferLength < sizeof(FSCTL_OFFLOAD_READ_OUTPUT)) {
- + DbgP("nfs41_OffloadRead: "
- + "buffer too small for FSCTL_OFFLOAD_READ_OUTPUT\n");
- + status = STATUS_BUFFER_TOO_SMALL;
- + goto out;
- + }
- +
- + PFSCTL_OFFLOAD_READ_INPUT ori =
- + (PFSCTL_OFFLOAD_READ_INPUT)FsCtl->pInputBuffer;
- + PFSCTL_OFFLOAD_READ_OUTPUT oro =
- + (PFSCTL_OFFLOAD_READ_OUTPUT)FsCtl->pOutputBuffer;
- +
- + DbgP("nfs41_OffloadRead: "
- + "ori->(Size=%lu, Flags=0x%lx, TokenTimeToLive=%lu, Reserved=%lu, "
- + "FileOffset=%llu, CopyLength=%llu)\n",
- + (unsigned long)ori->Size,
- + (unsigned long)ori->Flags,
- + (unsigned long)ori->TokenTimeToLive,
- + (unsigned long)ori->Reserved,
- + (unsigned long long)ori->FileOffset,
- + (unsigned long long)ori->CopyLength);
- +
- + offloadcontext_entry *oce = RxAllocatePoolWithTag(NonPagedPoolNx,
- + sizeof(offloadcontext_entry), NFS41_MM_POOLTAG);
- + if (oce == NULL) {
- + status = STATUS_INSUFFICIENT_RESOURCES;
- + goto out;
- + }
- +
- + DbgP("nfs41_OffloadRead: oce=0x%p\n", oce);
- +
- + (void)ExInitializeResourceLite(&oce->resource);
- +
- + (void)memset(&oce->token, 0, sizeof(oce->token));
- + /* Add safeguard to |TokenType| */
- + oce->token.TokenType[0] = 'N';
- + oce->token.TokenType[1] = 'F';
- + oce->token.TokenType[2] = 'S';
- + oce->token.TokenType[3] = '4';
- + /* FIXME: What about the endianness of |TokenIdLength| ? */
- + *((USHORT *)(&oce->token.TokenIdLength[0])) =
- + STORAGE_OFFLOAD_TOKEN_ID_LENGTH;
- + *((void **)(&oce->token.Token[0])) = oce;
- + oce->src_fobx = nfs41_fobx;
- + oce->src_fileoffset = ori->FileOffset;
- + oce->src_length = ori->CopyLength;
- +
- + oro->Size = sizeof(FSCTL_OFFLOAD_READ_OUTPUT);
- + oro->Flags = 0;
- + oro->TransferLength = ori->CopyLength;
- + (void)memcpy(&oro->Token[0], &oce->token, sizeof(oce->token));
- +
- + nfs41_AddEntry(offloadcontextLock, offloadcontext_list, oce);
- +
- + RxContext->CurrentIrp->IoStatus.Status = status = STATUS_SUCCESS;
- + RxContext->InformationToReturn = sizeof(FSCTL_OFFLOAD_READ_OUTPUT);
- +
- +out:
- + DbgEx();
- + return status;
- +}
- +
- +static
- +NTSTATUS check_nfs41_offload_write_args(
- + PRX_CONTEXT RxContext)
- +{
- + NTSTATUS status = STATUS_SUCCESS;
- + __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
- + __notnull PNFS41_V_NET_ROOT_EXTENSION VNetRootContext =
- + NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
- +
- + /* access checks */
- + if (VNetRootContext->read_only) {
- + status = STATUS_MEDIA_WRITE_PROTECTED;
- + goto out;
- + }
- + if (!(SrvOpen->DesiredAccess &
- + (FILE_WRITE_DATA|FILE_WRITE_ATTRIBUTES))) {
- + status = STATUS_ACCESS_DENIED;
- + goto out;
- + }
- +
- +out:
- + return status;
- +}
- +
- +static
- +NTSTATUS nfs41_OffloadWrite(
- + IN OUT PRX_CONTEXT RxContext)
- +{
- + NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
- + nfs41_updowncall_entry *entry = NULL;
- + __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
- + __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
- + NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
- + __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
- + NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
- + __notnull XXCTL_LOWIO_COMPONENT *FsCtl =
- + &RxContext->LowIoContext.ParamsFor.FsCtl;
- + __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(RxContext->pFobx);
- + offloadcontext_entry *src_oce = NULL;
- +
- + struct {
- + LONGLONG srcfileoffset;
- + LONGLONG destfileoffset;
- + LONGLONG bytecount;
- + } dd;
- +
- + DbgEn();
- +
- + LONGLONG io_delay;
- + RxContext->IoStatusBlock.Information = 0;
- +
- + status = check_nfs41_offload_write_args(RxContext);
- + if (status)
- + goto out;
- +
- + if (FsCtl->pInputBuffer == NULL) {
- + status = STATUS_INVALID_USER_BUFFER;
- + goto out;
- + }
- + if (FsCtl->pOutputBuffer == NULL) {
- + status = STATUS_INVALID_USER_BUFFER;
- + goto out;
- + }
- + if (FsCtl->InputBufferLength < sizeof(FSCTL_OFFLOAD_WRITE_INPUT)) {
- + DbgP("nfs41_OffloadWrite: "
- + "buffer too small for FSCTL_OFFLOAD_WRITE_INPUT\n");
- + status = STATUS_BUFFER_TOO_SMALL;
- + goto out;
- + }
- + if (FsCtl->OutputBufferLength < sizeof(FSCTL_OFFLOAD_WRITE_OUTPUT)) {
- + DbgP("nfs41_OffloadWrite: "
- + "buffer too small for FSCTL_OFFLOAD_WRITE_OUTPUT\n");
- + status = STATUS_BUFFER_TOO_SMALL;
- + goto out;
- + }
- +
- + PFSCTL_OFFLOAD_WRITE_INPUT owi =
- + (PFSCTL_OFFLOAD_WRITE_INPUT)FsCtl->pInputBuffer;
- + PFSCTL_OFFLOAD_WRITE_OUTPUT owo =
- + (PFSCTL_OFFLOAD_WRITE_OUTPUT)FsCtl->pOutputBuffer;
- +
- + offloadcontext_entry *unvalidated_src_oce;
- +
- + /*
- + * Peel |offloadcontext_entry| pointer from token...
- + */
- + unvalidated_src_oce =
- + *((void **)(&(((STORAGE_OFFLOAD_TOKEN *)(&owi->Token[0]))->Token[0])));
- + DbgP("nfs41_OffloadWrite: "
- + "unvalidated_src_oce=0x%p\n", unvalidated_src_oce);
- +
- + /*
- + * ... and validate it (and take a shared lock if validation was
- + * successful, so nobody can delete the context while we use it)!
- + */
- + src_oce = nfs41_find_offloadcontext_acquireshared(unvalidated_src_oce);
- + if (src_oce == NULL) {
- + DbgP("nfs41_OffloadWrite: "
- + "nfs41_find_offloadcontext_acquireshared() failed\n");
- + status = STATUS_INVALID_PARAMETER;
- + goto out;
- + }
- +
- + DbgP("nfs41_OffloadWrite: src_oce=0x%p\n", src_oce);
- +
- + /* Check safeguard... */
- + if ((src_oce->token.TokenType[0] != 'N') ||
- + (src_oce->token.TokenType[1] != 'F') ||
- + (src_oce->token.TokenType[2] != 'S') ||
- + (src_oce->token.TokenType[3] != '4')) {
- + DbgP("nfs41_OffloadWrite: "
- + "token in src_oce=0x%p not a 'NFS4' token\n",
- + src_oce);
- + status = STATUS_INVALID_PARAMETER;
- + goto out;
- + }
- +
- + /*
- + * FIXME: We should validate the length passed as
- + * |FSCTL_OFFLOAD_READ_INPUT.CopyLength| here better, because it is
- + * also used as some kind of access control to different parts of a
- + * file
- + */
- + dd.srcfileoffset = src_oce->src_fileoffset + owi->TransferOffset;
- + dd.destfileoffset = owi->FileOffset;
- + dd.bytecount = owi->CopyLength;
- +
- + DbgP("nfs41_OffloadWrite: "
- + "dd=(srcfileoffset=%lld,"
- + "destfileoffset=%lld,"
- + "bytecount=%lld)\n",
- + (long long)dd.srcfileoffset,
- + (long long)dd.destfileoffset,
- + (long long)dd.bytecount);
- +
- + if (dd.bytecount == 0LL) {
- + status = STATUS_SUCCESS;
- + goto out;
- + }
- +
- + PNFS41_FOBX nfs41_src_fobx = src_oce->src_fobx;
- + if (!nfs41_src_fobx) {
- + DbgP("nfs41_OffloadWrite: No nfs41_src_fobx\n");
- + status = STATUS_INVALID_PARAMETER;
- + goto out;
- + }
- +
- + /*
- + * Disable caching because NFSv4.2 COPY is basically a
- + * "write" operation. AFAIK we should flush the cache and wait
- + * for the kernel lazy writer (which |RxChangeBufferingState()|
- + * AFAIK does) before doing the COPY, to avoid that we
- + * have outstanding writes in the kernel cache at the same
- + * location where the COPY should do it's work
- + */
- + ULONG flag = DISABLE_CACHING;
- + DbgP("nfs41_OffloadWrite: disableing caching for file '%wZ'\n",
- + SrvOpen->pAlreadyPrefixedName);
- + RxChangeBufferingState((PSRV_OPEN)SrvOpen, ULongToPtr(flag), 1);
- +
- + status = nfs41_UpcallCreate(NFS41_SYSOP_FSCTL_OFFLOAD_DATACOPY,
- + &nfs41_fobx->sec_ctx,
- + pVNetRootContext->session,
- + nfs41_fobx->nfs41_open_state,
- + pNetRootContext->nfs41d_version,
- + SrvOpen->pAlreadyPrefixedName,
- + &entry);
- +
- + if (status)
- + goto out;
- +
- + entry->u.DuplicateData.src_state = nfs41_src_fobx->nfs41_open_state;
- + entry->u.DuplicateData.srcfileoffset = dd.srcfileoffset;
- + entry->u.DuplicateData.destfileoffset = dd.destfileoffset;
- + entry->u.DuplicateData.bytecount = dd.bytecount;
- +
- + /* Add extra timeout depending on file size */
- + io_delay = pVNetRootContext->timeout +
- + EXTRA_TIMEOUT_PER_BYTE(entry->u.DuplicateData.bytecount);
- +
- + status = nfs41_UpcallWaitForReply(entry, io_delay);
- + if (status) {
- + /* Timeout - |nfs41_downcall()| will free |entry|+contents */
- + entry = NULL;
- + goto out;
- + }
- +
- + if (!entry->status) {
- + DbgP("nfs41_OffloadWrite: SUCCESS\n");
- +
- + owo->Size = sizeof(FSCTL_OFFLOAD_READ_OUTPUT);
- + owo->Flags = 0;
- + owo->LengthWritten = dd.bytecount;
- +
- + RxContext->CurrentIrp->IoStatus.Status = status = STATUS_SUCCESS;
- + RxContext->InformationToReturn = sizeof(FSCTL_OFFLOAD_READ_OUTPUT);
- + }
- + else {
- + DbgP("nfs41_OffloadWrite: "
- + "FAILURE, entry->status=0x%lx\n", entry->status);
- + status = map_setfile_error(entry->status);
- + RxContext->CurrentIrp->IoStatus.Status = status;
- + RxContext->IoStatusBlock.Information = 0;
- + }
- +
- +out:
- + if (src_oce) {
- + /* Release resource we obtained in shared mode */
- + ExReleaseResourceLite(&src_oce->resource);
- + }
- +
- + if (entry) {
- + nfs41_UpcallDestroy(entry);
- + }
- +
- + DbgEx();
- + return status;
- +}
- +
- NTSTATUS nfs41_FsCtl(
- IN OUT PRX_CONTEXT RxContext)
- {
- @@ -895,6 +1326,12 @@ NTSTATUS nfs41_FsCtl(
- case FSCTL_DUPLICATE_EXTENTS_TO_FILE:
- status = nfs41_DuplicateData(RxContext);
- break;
- + case FSCTL_OFFLOAD_READ:
- + status = nfs41_OffloadRead(RxContext);
- + break;
- + case FSCTL_OFFLOAD_WRITE:
- + status = nfs41_OffloadWrite(RxContext);
- + break;
- default:
- break;
- }
- diff --git a/sys/nfs41sys_updowncall.c b/sys/nfs41sys_updowncall.c
- index cf5be35..fc523a4 100644
- --- a/sys/nfs41sys_updowncall.c
- +++ b/sys/nfs41sys_updowncall.c
- @@ -321,6 +321,7 @@ NTSTATUS handle_upcall(
- pbOut, cbOut, len);
- break;
- case NFS41_SYSOP_FSCTL_DUPLICATE_DATA:
- + case NFS41_SYSOP_FSCTL_OFFLOAD_DATACOPY:
- status = marshal_nfs41_duplicatedata(entry,
- pbOut, cbOut, len);
- break;
- @@ -785,6 +786,7 @@ NTSTATUS nfs41_downcall(
- unmarshal_nfs41_setzerodata(cur, &buf);
- break;
- case NFS41_SYSOP_FSCTL_DUPLICATE_DATA:
- + case NFS41_SYSOP_FSCTL_OFFLOAD_DATACOPY:
- unmarshal_nfs41_duplicatedata(cur, &buf);
- break;
- }
- --
- 2.45.1
- From 53d029884cf831c74cf9cb5b3e6808583d94f215 Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Wed, 20 Aug 2025 14:04:41 +0200
- Subject: [PATCH 3/6] sys: Move |FAST_MUTEX| into the list structs they protect
- Move |FAST_MUTEX| into the list structs they protect.
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- sys/nfs41sys_driver.c | 44 +++++++++++++++++++--------------------
- sys/nfs41sys_driver.h | 21 +++++++++----------
- sys/nfs41sys_fsctl.c | 25 +++++++++++-----------
- sys/nfs41sys_mount.c | 26 +++++++++++------------
- sys/nfs41sys_openclose.c | 2 +-
- sys/nfs41sys_updowncall.c | 20 +++++++++---------
- 6 files changed, 69 insertions(+), 69 deletions(-)
- diff --git a/sys/nfs41sys_driver.c b/sys/nfs41sys_driver.c
- index fd72305..a0328e9 100644
- --- a/sys/nfs41sys_driver.c
- +++ b/sys/nfs41sys_driver.c
- @@ -129,10 +129,11 @@ PRDBSS_DEVICE_OBJECT nfs41_dev;
- KEVENT upcallEvent;
- -FAST_MUTEX upcallLock, downcallLock, fcblistLock;
- -FAST_MUTEX openOwnerLock;
- -FAST_MUTEX offloadcontextLock;
- -nfs41_offloadcontext_list offloadcontext_list;
- +nfs41_updowncall_list upcalllist;
- +nfs41_updowncall_list downcalllist;
- +nfs41_fcb_list openlist;
- +
- +nfs41_offloadcontext_list offloadcontextlist;
- LONGLONG xid = 0;
- LONG open_owner_id = 1;
- @@ -692,7 +693,7 @@ VOID nfs41_remove_fcb_entry(
- {
- PLIST_ENTRY pEntry;
- nfs41_fcb_list_entry *cur;
- - ExAcquireFastMutexUnsafe(&fcblistLock);
- + ExAcquireFastMutexUnsafe(&openlist.lock);
- pEntry = openlist.head.Flink;
- while (!IsListEmpty(&openlist.head)) {
- @@ -715,7 +716,7 @@ VOID nfs41_remove_fcb_entry(
- }
- pEntry = pEntry->Flink;
- }
- - ExReleaseFastMutexUnsafe(&fcblistLock);
- + ExReleaseFastMutexUnsafe(&openlist.lock);
- }
- static
- @@ -726,7 +727,7 @@ VOID nfs41_invalidate_fobx_entry(
- nfs41_fcb_list_entry *cur;
- __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(pFobx);
- - ExAcquireFastMutexUnsafe(&fcblistLock);
- + ExAcquireFastMutexUnsafe(&openlist.lock);
- pEntry = openlist.head.Flink;
- while (!IsListEmpty(&openlist.head)) {
- @@ -749,7 +750,7 @@ VOID nfs41_invalidate_fobx_entry(
- }
- pEntry = pEntry->Flink;
- }
- - ExReleaseFastMutexUnsafe(&fcblistLock);
- + ExReleaseFastMutexUnsafe(&openlist.lock);
- }
- NTSTATUS nfs41_Flush(
- @@ -795,7 +796,7 @@ VOID nfs41_update_fcb_list(
- {
- PLIST_ENTRY pEntry;
- nfs41_fcb_list_entry *cur;
- - ExAcquireFastMutexUnsafe(&fcblistLock);
- + ExAcquireFastMutexUnsafe(&openlist.lock);
- pEntry = openlist.head.Flink;
- while (!IsListEmpty(&openlist.head)) {
- cur = (nfs41_fcb_list_entry *)CONTAINING_RECORD(pEntry,
- @@ -822,7 +823,7 @@ VOID nfs41_update_fcb_list(
- }
- pEntry = pEntry->Flink;
- }
- - ExReleaseFastMutexUnsafe(&fcblistLock);
- + ExReleaseFastMutexUnsafe(&openlist.lock);
- }
- NTSTATUS nfs41_IsValidDirectory (
- @@ -910,7 +911,7 @@ void enable_caching(
- RxChangeBufferingState((PSRV_OPEN)SrvOpen, ULongToPtr(flag), 1);
- - ExAcquireFastMutexUnsafe(&fcblistLock);
- + ExAcquireFastMutexUnsafe(&openlist.lock);
- pEntry = openlist.head.Flink;
- while (!IsListEmpty(&openlist.head)) {
- cur = (nfs41_fcb_list_entry *)CONTAINING_RECORD(pEntry,
- @@ -950,7 +951,7 @@ void enable_caching(
- nfs41_fobx->deleg_type = 0;
- }
- out_release_fcblistlock:
- - ExReleaseFastMutexUnsafe(&fcblistLock);
- + ExReleaseFastMutexUnsafe(&openlist.lock);
- }
- NTSTATUS nfs41_CompleteBufferingStateChangeRequest(
- @@ -1238,7 +1239,7 @@ VOID fcbopen_main(PVOID ctx)
- PLIST_ENTRY pEntry;
- nfs41_fcb_list_entry *cur;
- status = KeDelayExecutionThread(KernelMode, TRUE, &timeout);
- - ExAcquireFastMutexUnsafe(&fcblistLock);
- + ExAcquireFastMutexUnsafe(&openlist.lock);
- pEntry = openlist.head.Flink;
- while (!IsListEmpty(&openlist.head)) {
- PNFS41_NETROOT_EXTENSION pNetRootContext;
- @@ -1335,7 +1336,7 @@ out:
- }
- pEntry = pEntry->Flink;
- }
- - ExReleaseFastMutexUnsafe(&fcblistLock);
- + ExReleaseFastMutexUnsafe(&openlist.lock);
- }
- // DbgEx();
- }
- @@ -1395,15 +1396,14 @@ NTSTATUS DriverEntry(
- }
- KeInitializeEvent(&upcallEvent, SynchronizationEvent, FALSE );
- - ExInitializeFastMutex(&upcallLock);
- - ExInitializeFastMutex(&downcallLock);
- - ExInitializeFastMutex(&openOwnerLock);
- - ExInitializeFastMutex(&fcblistLock);
- - ExInitializeFastMutex(&offloadcontextLock);
- - InitializeListHead(&upcall.head);
- - InitializeListHead(&downcall.head);
- + ExInitializeFastMutex(&upcalllist.lock);
- + ExInitializeFastMutex(&downcalllist.lock);
- + ExInitializeFastMutex(&openlist.lock);
- + ExInitializeFastMutex(&offloadcontextlist.lock);
- + InitializeListHead(&upcalllist.head);
- + InitializeListHead(&downcalllist.head);
- InitializeListHead(&openlist.head);
- - InitializeListHead(&offloadcontext_list.head);
- + InitializeListHead(&offloadcontextlist.head);
- #ifdef USE_LOOKASIDELISTS_FOR_UPDOWNCALLENTRY_MEM
- /*
- * The |Depth| parameter is unfortunately ignored in Win10,
- diff --git a/sys/nfs41sys_driver.h b/sys/nfs41sys_driver.h
- index 3f8cc68..c96244c 100644
- --- a/sys/nfs41sys_driver.h
- +++ b/sys/nfs41sys_driver.h
- @@ -302,9 +302,11 @@ typedef struct _updowncall_entry {
- } nfs41_updowncall_entry;
- typedef struct _updowncall_list {
- + FAST_MUTEX lock;
- LIST_ENTRY head;
- } nfs41_updowncall_list;
- -nfs41_updowncall_list upcall, downcall;
- +extern nfs41_updowncall_list upcalllist;
- +extern nfs41_updowncall_list downcalllist;
- #define SERVER_NAME_BUFFER_SIZE 1024
- @@ -351,7 +353,8 @@ typedef struct _nfs41_mount_entry {
- } nfs41_mount_entry;
- typedef struct _nfs41_mount_list {
- - LIST_ENTRY head;
- + FAST_MUTEX lock;
- + LIST_ENTRY head;
- } nfs41_mount_list;
- #define nfs41_AddEntry(lock,list,pEntry) \
- @@ -409,7 +412,6 @@ typedef struct _NFS41_NETROOT_EXTENSION {
- NODE_BYTE_SIZE NodeByteSize;
- DWORD nfs41d_version;
- BOOLEAN mounts_init;
- - FAST_MUTEX mountLock;
- nfs41_mount_list mounts;
- } NFS41_NETROOT_EXTENSION, *PNFS41_NETROOT_EXTENSION;
- #define NFS41GetNetRootExtension(pNetRoot) \
- @@ -503,15 +505,16 @@ typedef struct _nfs41_fcb_list_entry {
- } nfs41_fcb_list_entry;
- typedef struct _nfs41_fcb_list {
- - LIST_ENTRY head;
- + FAST_MUTEX lock;
- + LIST_ENTRY head;
- } nfs41_fcb_list;
- -nfs41_fcb_list openlist;
- +extern nfs41_fcb_list openlist;
- typedef struct _nfs41_offloadcontext_list {
- + FAST_MUTEX lock;
- LIST_ENTRY head;
- } nfs41_offloadcontext_list;
- -extern nfs41_offloadcontext_list offloadcontext_list;
- -extern FAST_MUTEX offloadcontextLock;
- +extern nfs41_offloadcontext_list offloadcontextlist;
- typedef enum _NULMRX_STORAGE_TYPE_CODES {
- NTC_NFS41_DEVICE_EXTENSION = (NODE_TYPE_CODE)0xFC00,
- @@ -542,10 +545,6 @@ typedef enum _NULMRX_STORAGE_TYPE_CODES {
- /* Globals */
- extern KEVENT upcallEvent;
- -extern FAST_MUTEX upcallLock;
- -extern FAST_MUTEX downcallLock;
- -extern FAST_MUTEX fcblistLock;
- -extern FAST_MUTEX openOwnerLock;
- extern LONGLONG xid;
- extern LONG open_owner_id;
- diff --git a/sys/nfs41sys_fsctl.c b/sys/nfs41sys_fsctl.c
- index 546a95b..0d7da28 100644
- --- a/sys/nfs41sys_fsctl.c
- +++ b/sys/nfs41sys_fsctl.c
- @@ -904,17 +904,17 @@ void nfs41_remove_offloadcontext_for_fobx(
- offloadcontext_entry *cur, *found = NULL;
- __notnull PNFS41_FOBX nfs41_fobx = NFS41GetFobxExtension(pFobx);
- - ExAcquireFastMutexUnsafe(&offloadcontextLock);
- + ExAcquireFastMutexUnsafe(&offloadcontextlist.lock);
- - pEntry = offloadcontext_list.head.Flink;
- - while (!IsListEmpty(&offloadcontext_list.head)) {
- + pEntry = offloadcontextlist.head.Flink;
- + while (!IsListEmpty(&offloadcontextlist.head)) {
- cur = (offloadcontext_entry *)CONTAINING_RECORD(pEntry,
- offloadcontext_entry, next);
- if (cur->src_fobx == nfs41_fobx) {
- found = cur;
- break;
- }
- - if (pEntry->Flink == &offloadcontext_list.head) {
- + if (pEntry->Flink == &offloadcontextlist.head) {
- break;
- }
- pEntry = pEntry->Flink;
- @@ -940,7 +940,7 @@ void nfs41_remove_offloadcontext_for_fobx(
- pFobx);
- }
- - ExReleaseFastMutexUnsafe(&offloadcontextLock);
- + ExReleaseFastMutexUnsafe(&offloadcontextlist.lock);
- }
- static
- @@ -950,17 +950,17 @@ offloadcontext_entry *nfs41_find_offloadcontext_acquireshared(
- PLIST_ENTRY pEntry;
- offloadcontext_entry *cur, *found = NULL;
- - ExAcquireFastMutexUnsafe(&offloadcontextLock);
- + ExAcquireFastMutexUnsafe(&offloadcontextlist.lock);
- - pEntry = offloadcontext_list.head.Flink;
- - while (!IsListEmpty(&offloadcontext_list.head)) {
- + pEntry = offloadcontextlist.head.Flink;
- + while (!IsListEmpty(&offloadcontextlist.head)) {
- cur = (offloadcontext_entry *)CONTAINING_RECORD(pEntry,
- offloadcontext_entry, next);
- if (cur == unvalidated_oce) {
- found = cur;
- break;
- }
- - if (pEntry->Flink == &offloadcontext_list.head) {
- + if (pEntry->Flink == &offloadcontextlist.head) {
- break;
- }
- pEntry = pEntry->Flink;
- @@ -972,14 +972,14 @@ offloadcontext_entry *nfs41_find_offloadcontext_acquireshared(
- unvalidated_oce);
- (void)ExAcquireSharedStarveExclusive(&found->resource, TRUE);
- - ExReleaseFastMutexUnsafe(&offloadcontextLock);
- + ExReleaseFastMutexUnsafe(&offloadcontextlist.lock);
- return found;
- }
- else {
- DbgP("nfs41_find_offloadcontext_acquireshared(unvalidated_oce=0x%p): "
- "Nothing found.\n",
- unvalidated_oce);
- - ExReleaseFastMutexUnsafe(&offloadcontextLock);
- + ExReleaseFastMutexUnsafe(&offloadcontextlist.lock);
- return NULL;
- }
- }
- @@ -1065,7 +1065,8 @@ NTSTATUS nfs41_OffloadRead(
- oro->TransferLength = ori->CopyLength;
- (void)memcpy(&oro->Token[0], &oce->token, sizeof(oce->token));
- - nfs41_AddEntry(offloadcontextLock, offloadcontext_list, oce);
- + nfs41_AddEntry(offloadcontextlist.lock,
- + offloadcontextlist, oce);
- RxContext->CurrentIrp->IoStatus.Status = status = STATUS_SUCCESS;
- RxContext->InformationToReturn = sizeof(FSCTL_OFFLOAD_READ_OUTPUT);
- diff --git a/sys/nfs41sys_mount.c b/sys/nfs41sys_mount.c
- index 069c682..6d652b6 100644
- --- a/sys/nfs41sys_mount.c
- +++ b/sys/nfs41sys_mount.c
- @@ -986,7 +986,7 @@ NTSTATUS nfs41_CreateVNetRoot(
- status = STATUS_NFS_SHARE_NOT_MOUNTED;
- - ExAcquireFastMutexUnsafe(&pNetRootContext->mountLock);
- + ExAcquireFastMutexUnsafe(&pNetRootContext->mounts.lock);
- pEntry = &pNetRootContext->mounts.head;
- pEntry = pEntry->Flink;
- while (pEntry != NULL) {
- @@ -1039,7 +1039,7 @@ NTSTATUS nfs41_CreateVNetRoot(
- status = STATUS_SUCCESS;
- }
- #endif /* NFS41_DRIVER_SYSTEM_LUID_MOUNTS_ARE_GLOBAL */
- - ExReleaseFastMutexUnsafe(&pNetRootContext->mountLock);
- + ExReleaseFastMutexUnsafe(&pNetRootContext->mounts.lock);
- if (status != STATUS_SUCCESS) {
- DbgP("No existing mount found, "
- @@ -1111,13 +1111,13 @@ NTSTATUS nfs41_CreateVNetRoot(
- #ifdef DEBUG_MOUNT
- DbgP("Initializing mount array\n");
- #endif
- - ExInitializeFastMutex(&pNetRootContext->mountLock);
- + ExInitializeFastMutex(&pNetRootContext->mounts.lock);
- InitializeListHead(&pNetRootContext->mounts.head);
- pNetRootContext->mounts_init = TRUE;
- } else {
- PLIST_ENTRY pEntry;
- - ExAcquireFastMutexUnsafe(&pNetRootContext->mountLock);
- + ExAcquireFastMutexUnsafe(&pNetRootContext->mounts.lock);
- pEntry = &pNetRootContext->mounts.head;
- pEntry = pEntry->Flink;
- while (pEntry != NULL) {
- @@ -1167,7 +1167,7 @@ NTSTATUS nfs41_CreateVNetRoot(
- break;
- pEntry = pEntry->Flink;
- }
- - ExReleaseFastMutexUnsafe(&pNetRootContext->mountLock);
- + ExReleaseFastMutexUnsafe(&pNetRootContext->mounts.lock);
- #ifdef DEBUG_MOUNT
- if (!found_matching_flavor)
- DbgP("Didn't find matching security flavor\n");
- @@ -1180,7 +1180,7 @@ NTSTATUS nfs41_CreateVNetRoot(
- &pVNetRootContext->FsAttrs);
- if (status != STATUS_SUCCESS) {
- BOOLEAN MountsEmpty;
- - nfs41_IsListEmpty(pNetRootContext->mountLock,
- + nfs41_IsListEmpty(pNetRootContext->mounts.lock,
- pNetRootContext->mounts, MountsEmpty);
- if (!found_existing_mount && MountsEmpty)
- pNetRootContext->mounts_init = FALSE;
- @@ -1219,7 +1219,7 @@ NTSTATUS nfs41_CreateVNetRoot(
- * \\server@port\@(pubnfs4|nfs4)\path mounts later
- */
- copy_nfs41_mount_config(&entry->Config, Config);
- - nfs41_AddEntry(pNetRootContext->mountLock,
- + nfs41_AddEntry(pNetRootContext->mounts.lock,
- pNetRootContext->mounts, entry);
- } else if (!found_matching_flavor) {
- ASSERT(existing_mount != NULL);
- @@ -1390,7 +1390,7 @@ NTSTATUS nfs41_FinalizeNetRoot(
- }
- do {
- - nfs41_GetFirstMountEntry(pNetRootContext->mountLock,
- + nfs41_GetFirstMountEntry(pNetRootContext->mounts.lock,
- pNetRootContext->mounts, mount_tmp);
- if (mount_tmp == NULL)
- break;
- @@ -1432,7 +1432,7 @@ NTSTATUS nfs41_FinalizeNetRoot(
- print_error("nfs41_unmount RPCSEC_GSS_KRB5P failed with %d\n",
- status);
- }
- - nfs41_RemoveEntry(pNetRootContext->mountLock, mount_tmp);
- + nfs41_RemoveEntry(pNetRootContext->mounts.lock, mount_tmp);
- RxFreePool(mount_tmp);
- mount_tmp = NULL;
- } while (1);
- @@ -1441,10 +1441,10 @@ NTSTATUS nfs41_FinalizeNetRoot(
- // check if there is anything waiting in the upcall or downcall queue
- do {
- - nfs41_GetFirstEntry(upcallLock, upcall, tmp);
- + nfs41_GetFirstEntry(upcalllist.lock, upcalllist, tmp);
- if (tmp != NULL) {
- DbgP("Removing entry from upcall list\n");
- - nfs41_RemoveEntry(upcallLock, tmp);
- + nfs41_RemoveEntry(upcalllist.lock, tmp);
- tmp->status = STATUS_INSUFFICIENT_RESOURCES;
- (void)KeSetEvent(&tmp->cond, IO_NFS41FS_INCREMENT, FALSE);
- } else
- @@ -1452,10 +1452,10 @@ NTSTATUS nfs41_FinalizeNetRoot(
- } while (1);
- do {
- - nfs41_GetFirstEntry(downcallLock, downcall, tmp);
- + nfs41_GetFirstEntry(downcalllist.lock, downcalllist, tmp);
- if (tmp != NULL) {
- DbgP("Removing entry from downcall list\n");
- - nfs41_RemoveEntry(downcallLock, tmp);
- + nfs41_RemoveEntry(downcalllist.lock, tmp);
- tmp->status = STATUS_INSUFFICIENT_RESOURCES;
- (void)KeSetEvent(&tmp->cond, IO_NFS41FS_INCREMENT, FALSE);
- } else
- diff --git a/sys/nfs41sys_openclose.c b/sys/nfs41sys_openclose.c
- index f7bd38d..2833d1f 100644
- --- a/sys/nfs41sys_openclose.c
- +++ b/sys/nfs41sys_openclose.c
- @@ -1051,7 +1051,7 @@ retry_on_link:
- oentry->session = pVNetRootContext->session;
- oentry->ChangeTime = entry->ChangeTime;
- oentry->skip = FALSE;
- - nfs41_AddEntry(fcblistLock, openlist, oentry);
- + nfs41_AddEntry(openlist.lock, openlist, oentry);
- }
- }
- diff --git a/sys/nfs41sys_updowncall.c b/sys/nfs41sys_updowncall.c
- index fc523a4..cf9e4cf 100644
- --- a/sys/nfs41sys_updowncall.c
- +++ b/sys/nfs41sys_updowncall.c
- @@ -518,7 +518,7 @@ NTSTATUS nfs41_UpcallWaitForReply(
- FsRtlEnterFileSystem();
- - nfs41_AddEntry(upcallLock, upcall, entry);
- + nfs41_AddEntry(upcalllist.lock, upcalllist, entry);
- (void)KeSetEvent(&upcallEvent, IO_NFS41FS_INCREMENT, FALSE);
- if (entry->async_op)
- @@ -567,7 +567,7 @@ retry_wait:
- ExReleaseFastMutexUnsafe(&entry->lock);
- goto out;
- }
- - nfs41_RemoveEntry(downcallLock, entry);
- + nfs41_RemoveEntry(downcalllist.lock, entry);
- out:
- FsRtlExitFileSystem();
- @@ -585,14 +585,14 @@ NTSTATUS nfs41_upcall(
- FsRtlEnterFileSystem();
- process_upcall:
- - nfs41_RemoveFirst(upcallLock, upcall, pEntry);
- + nfs41_RemoveFirst(upcalllist.lock, upcalllist, pEntry);
- if (pEntry) {
- nfs41_updowncall_entry *entry;
- entry = (nfs41_updowncall_entry *)CONTAINING_RECORD(pEntry,
- nfs41_updowncall_entry, next);
- ExAcquireFastMutexUnsafe(&entry->lock);
- - nfs41_AddEntry(downcallLock, downcall, entry);
- + nfs41_AddEntry(downcalllist.lock, downcalllist, entry);
- status = handle_upcall(RxContext, entry, &len);
- if (status == STATUS_SUCCESS &&
- entry->state == NFS41_WAITING_FOR_UPCALL)
- @@ -665,8 +665,8 @@ NTSTATUS nfs41_downcall(
- unmarshal_nfs41_header(tmp, &buf);
- - ExAcquireFastMutexUnsafe(&downcallLock);
- - pEntry = &downcall.head;
- + ExAcquireFastMutexUnsafe(&downcalllist.lock);
- + pEntry = &downcalllist.head;
- pEntry = pEntry->Flink;
- while (pEntry != NULL) {
- cur = (nfs41_updowncall_entry *)CONTAINING_RECORD(pEntry,
- @@ -675,11 +675,11 @@ NTSTATUS nfs41_downcall(
- found = 1;
- break;
- }
- - if (pEntry->Flink == &downcall.head)
- + if (pEntry->Flink == &downcalllist.head)
- break;
- pEntry = pEntry->Flink;
- }
- - ExReleaseFastMutexUnsafe(&downcallLock);
- + ExReleaseFastMutexUnsafe(&downcalllist.lock);
- SeStopImpersonatingClient();
- if (!found) {
- print_error("Didn't find xid=%lld entry\n", tmp->xid);
- @@ -728,7 +728,7 @@ NTSTATUS nfs41_downcall(
- break;
- }
- ExReleaseFastMutexUnsafe(&cur->lock);
- - nfs41_RemoveEntry(downcallLock, cur);
- + nfs41_RemoveEntry(downcalllist.lock, cur);
- nfs41_UpcallDestroy(cur);
- status = STATUS_UNSUCCESSFUL;
- goto out_free;
- @@ -806,7 +806,7 @@ NTSTATUS nfs41_downcall(
- map_readwrite_errors(cur->status);
- cur->u.ReadWrite.rxcontext->InformationToReturn = 0;
- }
- - nfs41_RemoveEntry(downcallLock, cur);
- + nfs41_RemoveEntry(downcalllist.lock, cur);
- RxLowIoCompletion(cur->u.ReadWrite.rxcontext);
- nfs41_UpcallDestroy(cur);
- break;
- --
- 2.45.1
- From 3b1789d27c56e109fd49dce920a953770019de23 Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Wed, 20 Aug 2025 16:21:21 +0200
- Subject: [PATCH 4/6] sys,tests: Reenable |FORCE_POSIX_SEMANTICS_DELETE| so rm
- -Rf on read-only dir can report an error
- Reenable |FORCE_POSIX_SEMANTICS_DELETE| so rm -Rf on read-only dir
- can report an error.
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- sys/nfs41sys_buildconfig.h | 16 +++++++++++++++-
- sys/nfs41sys_fileinfo.c | 14 ++++++++++++++
- tests/manual_testing.txt | 11 ++++++++++-
- 3 files changed, 39 insertions(+), 2 deletions(-)
- diff --git a/sys/nfs41sys_buildconfig.h b/sys/nfs41sys_buildconfig.h
- index a8c10ad..21eb201 100644
- --- a/sys/nfs41sys_buildconfig.h
- +++ b/sys/nfs41sys_buildconfig.h
- @@ -26,8 +26,22 @@
- /*
- * |FORCE_POSIX_SEMANTICS_DELETE| is for bug-by-bug compatibility with the
- * original Windows NFSv3 filesystem driver
- + *
- + * If we ever disable this e must make sure that this works and still returns
- + * errors to the caller, e.g. rm -Rf on a readonly dir must return an
- + * error.
- + *
- + * Example:
- + * ---- snip ----
- + * $ ksh93 -c 'mkdir d1 && touch d1/f1 && chmod -R a-w d1 &&
- + * if rm -Rf d1 ; then echo "# Test failed" ; else
- + * echo "# Test OK" ; fi'
- + * rm: cannot remove 'd1': Permission denied
- + * # Test OK
- + * ---- snip ----
- */
- -// #define FORCE_POSIX_SEMANTICS_DELETE 1
- +#define FORCE_POSIX_SEMANTICS_DELETE 1
- +
- #define USE_STACK_FOR_DOWNCALL_UPDOWNCALLENTRY_MEM 1
- #if (NTDDI_VERSION >= NTDDI_WIN10_VB)
- diff --git a/sys/nfs41sys_fileinfo.c b/sys/nfs41sys_fileinfo.c
- index 82b8054..cea57ad 100644
- --- a/sys/nfs41sys_fileinfo.c
- +++ b/sys/nfs41sys_fileinfo.c
- @@ -696,6 +696,20 @@ NTSTATUS nfs41_SetFileInformation(
- }
- #else
- /* Do Win32 delete-on-close */
- + /*
- + * We must make sure that this works and still returns errors
- + * to the caller, e.g. rm -Rf on a readonly dir must return
- + * an error.
- + *
- + * Example:
- + * ---- snip ----
- + * $ ksh93 -c 'mkdir d1 && touch d1/f1 && chmod -R a-w d1 &&
- + * if rm -Rf d1 ; then echo "# Test failed" ; else
- + * echo "# Test OK" ; fi'
- + * rm: cannot remove 'd1': Permission denied
- + * # Test OK
- + s * ---- snip ----
- + */
- nfs41_fcb->DeletePending = TRUE;
- nfs41_fcb->StandardInfo.DeletePending = TRUE;
- #endif /* FORCE_POSIX_SEMANTICS_DELETE */
- diff --git a/tests/manual_testing.txt b/tests/manual_testing.txt
- index c9a5fd6..38bd49b 100644
- --- a/tests/manual_testing.txt
- +++ b/tests/manual_testing.txt
- @@ -1,5 +1,5 @@
- #
- -# ms-nfs41-client manual testing sequence, 2025-08-16
- +# ms-nfs41-client manual testing sequence, 2025-08-20
- #
- # Draft version, needs to be turned into automated tests
- # if possible
- @@ -771,6 +771,15 @@ bash /usr/share/msnfs41client/tests/misc/wintartest_comparewinvsgnu001.bash myta
- bash -c 'set -o errexit ; rm -Rf sillytestdir ; mkdir sillytestdir ; cd sillytestdir ; touch sillytest ; ( command exec {n}<"sillytest" ; printf "fd=%d\n" $n ; sleep 10) & sleep 1 ; ls -la ; cmd /C "del sillytest" ; ls -la ; if [[ "$(ls -1 .nfs*)" != "" ]] ; then echo "# test OK" ; else echo "# test FAILED" ; fi ; wait'
- bash -c 'set -o errexit ; rm -Rf sillytestdir ; mkdir sillytestdir ; cd sillytestdir ; touch sillytest ; ( command exec {n}<"sillytest" ; printf "fd=%d\n" $n ; sleep 10) & sleep 1 ; ls -la ; rm -f sillytest ; ls -la ; if [[ "$(ls -1 .nfs*)" != "" ]] ; then echo "# test OK" ; else echo "# test FAILED" ; fi ; wait'
- +#
- +# Test rm on read-only dir
- +#
- +---- snip ----
- +$ ksh93 -c 'mkdir d1 && touch d1/f1 && chmod -R a-w d1 && if rm -Rf d1 ; then echo "# Test failed, rm on readonly dir should return error" ; else echo "# Test OK" ; fi'
- +rm: cannot remove 'd1': Permission denied
- +# Test OK
- +---- snip ----
- +
- #
- # WSL install for testing
- #
- --
- 2.45.1
- From 180c8865f1f810b9dd5e4f7398b8142843f87542 Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Wed, 20 Aug 2025 17:43:10 +0200
- Subject: [PATCH 5/6] daemon: Align upcall/downcall buffers to cache line size
- Align upcall/downcall buffers to cache line size for slightly
- better performance.
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- daemon/nfs41_daemon.c | 5 ++++-
- 1 file changed, 4 insertions(+), 1 deletion(-)
- diff --git a/daemon/nfs41_daemon.c b/daemon/nfs41_daemon.c
- index c798c28..fb919c5 100644
- --- a/daemon/nfs41_daemon.c
- +++ b/daemon/nfs41_daemon.c
- @@ -137,7 +137,10 @@ static unsigned int nfsd_worker_thread_main(void *args)
- HANDLE pipe;
- // buffer used to process upcall, assumed to be fixed size.
- // if we ever need to handle non-cached IO, need to make it dynamic
- - unsigned char outbuf[UPCALL_BUF_SIZE], inbuf[UPCALL_BUF_SIZE];
- + // we use 128byte alignment to make sure we start at the beginning
- + // of a cache line
- + _declspec(align(128)) unsigned char outbuf[UPCALL_BUF_SIZE];
- + _declspec(align(128)) unsigned char inbuf[UPCALL_BUF_SIZE];
- DWORD inbuf_len, outbuf_len;
- nfs41_upcall upcall;
- --
- 2.45.1
- From c5e498c2f270b931dc51c4467fa1078631ef2b5a Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Wed, 20 Aug 2025 17:53:30 +0200
- Subject: [PATCH 6/6] daemon: Fix |DPRINTF()| debug level constant in
- |duplicate_sparsefile()|
- Fix |DPRINTF()| debug level constant in |duplicate_sparsefile()|.
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- daemon/fsctl.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
- diff --git a/daemon/fsctl.c b/daemon/fsctl.c
- index fbbd8aa..c730ab2 100644
- --- a/daemon/fsctl.c
- +++ b/daemon/fsctl.c
- @@ -543,7 +543,7 @@ int duplicate_sparsefile(nfs41_opcodes opcode,
- #ifdef LINUX_NFSD_SEEK_NXIO_BUG_WORKAROUND
- if (data_seek_status == NFS4ERR_NXIO) {
- - DPRINTF(QARLVL, ("SEEK_DATA failed with NFS4ERR_NXIO\n"));
- + DPRINTF(DDLVL, ("SEEK_DATA failed with NFS4ERR_NXIO\n"));
- goto out;
- }
- #endif /* LINUX_NFSD_SEEK_NXIO_BUG_WORKAROUND */
- --
- 2.45.1
msnfs41client: Patches for Win32 data copy offload, fix rm in read-only dirs, cleanup+misc, 2025-08-20
Posted by Anonymous on Wed 20th Aug 2025 17:19
raw | new post
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.