- From 498cbb60fc0702bd4c7744f56588bcbacea350ae Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Sat, 23 Aug 2025 12:34:09 +0200
- Subject: [PATCH 1/3] tests: Add --copychunksize option to winoffloadcopyfile
- Add --copychunksize option to winoffloadcopyfile.
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- tests/sparsefiles/multisparsefiletest.ksh | 2 +-
- tests/winoffloadcopyfile/winoffloadcopyfile.c | 219 ++++++++++++------
- 2 files changed, 151 insertions(+), 70 deletions(-)
- diff --git a/tests/sparsefiles/multisparsefiletest.ksh b/tests/sparsefiles/multisparsefiletest.ksh
- index 0d43585..0d39082 100644
- --- a/tests/sparsefiles/multisparsefiletest.ksh
- +++ b/tests/sparsefiles/multisparsefiletest.ksh
- @@ -309,7 +309,7 @@ function multisparsefiletest1
- 'offloadcopy_1mbchunks' | 'offloadcopy_1mbchunks_64bit' | 'offloadcopy_1mbchunks_32bit')
- if $test_cloning ; then
- ${winoffloadcopyfilecmd} \
- - --clonechunksize $((1024*1024)) \
- + --copychunksize $((1024*1024)) \
- 'sparsefile2.bin' \
- 'sparsefile2_offloadcopy_1mbchunks.bin' 1>'/dev/null'
- c.stdout="$(lssparse -H 'sparsefile2_offloadcopy_1mbchunks.bin')"
- diff --git a/tests/winoffloadcopyfile/winoffloadcopyfile.c b/tests/winoffloadcopyfile/winoffloadcopyfile.c
- index 021037b..db1a209 100644
- --- a/tests/winoffloadcopyfile/winoffloadcopyfile.c
- +++ b/tests/winoffloadcopyfile/winoffloadcopyfile.c
- @@ -23,7 +23,8 @@
- */
- /*
- - * winoffloadcopyfile.c - clone a file
- + * winoffloadcopyfile.c - copy a file with Win32
- + * |FSCTL_OFFLOAD_READ|+|FSCTL_OFFLOAD_WRITE|
- *
- * Written by Roland Mainz <roland.mainz@nrubsig.org>
- */
- @@ -36,6 +37,7 @@
- #define EXIT_USAGE (2)
- +/* MinGW headers are currently missing these defines and types */
- #ifndef OFFLOAD_READ_FLAG_ALL_ZERO_BEYOND_CURRENT_RANGE
- typedef struct _FSCTL_OFFLOAD_READ_INPUT {
- DWORD Size;
- @@ -90,30 +92,137 @@ typedef struct _STORAGE_OFFLOAD_TOKEN {
- } STORAGE_OFFLOAD_TOKEN, *PSTORAGE_OFFLOAD_TOKEN;
- #endif /* STORAGE_OFFLOAD_MAX_TOKEN_LENGTH */
- -int main(int argc, char* argv[])
- +static
- +void print_usage(const char *av0)
- {
- - int retval = EXIT_FAILURE;
- + (void)fprintf(stderr,
- + "Usage: %s [--copychunksize <numbytes>] <infile> <outfile>\n",
- + av0);
- +}
- +
- +static
- +BOOL offloadcopy(
- + HANDLE hSrc,
- + HANDLE hDest,
- + LONGLONG src_offset,
- + LONGLONG dst_offset,
- + LONGLONG copy_length,
- + LONGLONG *pBytesCopied)
- +{
- + BOOL bSuccess;
- + DWORD ioctlBytesReturned = 0;
- +
- + BYTE tokenBuffer[STORAGE_OFFLOAD_MAX_TOKEN_LENGTH] = { 0 };
- + PSTORAGE_OFFLOAD_TOKEN pToken = (PSTORAGE_OFFLOAD_TOKEN)tokenBuffer;
- - if (argc != 3) {
- + FSCTL_OFFLOAD_READ_INPUT readInput = { 0 };
- + readInput.Size = sizeof(FSCTL_OFFLOAD_READ_INPUT);
- + readInput.FileOffset = src_offset;
- + readInput.CopyLength = copy_length;
- +
- + FSCTL_OFFLOAD_READ_OUTPUT readOutput = { 0 };
- + readOutput.Size = sizeof(FSCTL_OFFLOAD_READ_OUTPUT);
- +
- + bSuccess = DeviceIoControl(
- + hSrc,
- + FSCTL_OFFLOAD_READ,
- + &readInput,
- + sizeof(readInput),
- + &readOutput,
- + sizeof(readOutput),
- + &ioctlBytesReturned,
- + NULL);
- +
- + if (!bSuccess) {
- (void)fprintf(stderr,
- - "Usage: %s <source_file> <destination_file>\n",
- - argv[0]);
- - return EXIT_USAGE;
- + "FSCTL_OFFLOAD_READ failed, lasterr=%d\n",
- + (int)GetLastError());
- + return FALSE;
- + }
- +
- + (void)memcpy(pToken, readOutput.Token, sizeof(tokenBuffer));
- +
- + FSCTL_OFFLOAD_WRITE_INPUT writeInput = { 0 };
- + writeInput.Size = sizeof(FSCTL_OFFLOAD_WRITE_INPUT);
- + writeInput.FileOffset = dst_offset;
- + writeInput.CopyLength = copy_length;
- + writeInput.TransferOffset = 0LL;
- + (void)memcpy(writeInput.Token, pToken, sizeof(tokenBuffer));
- +
- + FSCTL_OFFLOAD_WRITE_OUTPUT writeOutput = { 0 };
- + writeOutput.Size = sizeof(FSCTL_OFFLOAD_WRITE_OUTPUT);
- +
- + (void)printf("Performing copy with FSCTL_OFFLOAD_WRITE...\n");
- + bSuccess = DeviceIoControl(
- + hDest,
- + FSCTL_OFFLOAD_WRITE,
- + &writeInput,
- + sizeof(writeInput),
- + &writeOutput,
- + sizeof(writeOutput),
- + &ioctlBytesReturned,
- + NULL);
- +
- + if (!bSuccess) {
- + (void)fprintf(stderr,
- + "FSCTL_OFFLOAD_WRITE failed, lasterr=%d\n",
- + (int)GetLastError());
- + return FALSE;
- + }
- +
- + *pBytesCopied = writeOutput.LengthWritten;
- +
- + (void)printf("Offload write successful. Bytes written: %lld\n",
- + (long long)*pBytesCopied);
- + (void)printf("Offloaded copy completed successfully!\n");
- +
- + return TRUE;
- +}
- +
- +int main(int ac, char *av[])
- +{
- + int retval = EXIT_FAILURE;
- + LONGLONG maxCopyChunkSize =
- + 1024LL*1024LL*1024LL*1024LL*1024LL; /* 1PB */
- + const char *srcFilename;
- + const char *destFilename;
- +
- + if (ac == 3) {
- + srcFilename = av[1];
- + destFilename = av[2];
- + }
- + else if (ac == 5) {
- + if (strcmp(av[1], "--copychunksize") != 0) {
- + print_usage(av[0]);
- + return (EXIT_USAGE);
- + }
- +
- + maxCopyChunkSize = atoll(av[2]);
- + srcFilename = av[3];
- + destFilename = av[4];
- + }
- + else {
- + print_usage(av[0]);
- + return (EXIT_USAGE);
- }
- - const char *srcFilename = argv[1];
- - const char *destFilename = argv[2];
- HANDLE hSrc = INVALID_HANDLE_VALUE;
- HANDLE hDest = INVALID_HANDLE_VALUE;
- - BOOL bSuccess = FALSE;
- - DWORD ioctlBytesReturned = 0;
- -
- - BYTE tokenBuffer[STORAGE_OFFLOAD_MAX_TOKEN_LENGTH] = { 0 };
- - PSTORAGE_OFFLOAD_TOKEN pToken = (PSTORAGE_OFFLOAD_TOKEN)tokenBuffer;
- - (void)printf("Attempting offloaded copy from '%s' to '%s'\n",
- - srcFilename,
- - destFilename);
- + if (ac == 3) {
- + (void)printf("# Attempting offloded copy from '%s' to '%s' using "
- + "FSCTL_OFFLOAD_READ+FSCTL_OFFLOAD_WRITE...\n",
- + srcFilename,
- + destFilename);
- + }
- + else if (ac == 5) {
- + (void)printf("# Attempting offloded copy from '%s' to '%s' in "
- + "%lld byte chunks using "
- + "FSCTL_OFFLOAD_READ+FSCTL_OFFLOAD_WRITE...\n",
- + srcFilename,
- + destFilename,
- + maxCopyChunkSize);
- + }
- hSrc = CreateFileA(srcFilename,
- GENERIC_READ,
- @@ -151,31 +260,9 @@ int main(int argc, char* argv[])
- goto cleanup;
- }
- - FSCTL_OFFLOAD_READ_INPUT readInput = { 0 };
- - readInput.Size = sizeof(FSCTL_OFFLOAD_READ_INPUT);
- - readInput.FileOffset = 0;
- - readInput.CopyLength = fileSize.QuadPart;
- -
- - FSCTL_OFFLOAD_READ_OUTPUT readOutput = { 0 };
- - readOutput.Size = sizeof(FSCTL_OFFLOAD_READ_OUTPUT);
- -
- - bSuccess = DeviceIoControl(
- - hSrc,
- - FSCTL_OFFLOAD_READ,
- - &readInput,
- - sizeof(readInput),
- - &readOutput,
- - sizeof(readOutput),
- - &ioctlBytesReturned,
- - NULL);
- -
- - if (!bSuccess) {
- - (void)fprintf(stderr,
- - "FSCTL_OFFLOAD_READ failed, lasterr=%d\n",
- - (int)GetLastError());
- - goto cleanup;
- - }
- -
- + /*
- + * Extend destination file
- + */
- if (!SetFilePointerEx(hDest, fileSize, NULL, FILE_BEGIN)) {
- (void)fprintf(stderr,
- "Cannot set dest file pointer, lasterr=%d\n",
- @@ -190,39 +277,33 @@ int main(int argc, char* argv[])
- goto cleanup;
- }
- - (void)memcpy(pToken, readOutput.Token, sizeof(tokenBuffer));
- + LONGLONG bytesCopied = 0LL;
- + LONGLONG byteCount = fileSize.QuadPart;
- + LONGLONG copyOffset = 0LL;
- + BOOL bResult;
- - FSCTL_OFFLOAD_WRITE_INPUT writeInput = { 0 };
- - writeInput.Size = sizeof(FSCTL_OFFLOAD_WRITE_INPUT);
- - writeInput.FileOffset = 0;
- - writeInput.CopyLength = fileSize.QuadPart;
- - writeInput.TransferOffset = 0;
- - (void)memcpy(writeInput.Token, pToken, sizeof(tokenBuffer));
- + while (byteCount > 0) {
- + (void)printf("# offloadcopy: copyOffset=%lld)\n",
- + copyOffset);
- - FSCTL_OFFLOAD_WRITE_OUTPUT writeOutput = { 0 };
- - writeOutput.Size = sizeof(FSCTL_OFFLOAD_WRITE_OUTPUT);
- + bResult = offloadcopy(hSrc,
- + hDest,
- + copyOffset,
- + copyOffset,
- + __min(byteCount, maxCopyChunkSize),
- + &bytesCopied);
- - (void)printf("Performing copy with FSCTL_OFFLOAD_WRITE...\n");
- - bSuccess = DeviceIoControl(
- - hDest,
- - FSCTL_OFFLOAD_WRITE,
- - &writeInput,
- - sizeof(writeInput),
- - &writeOutput,
- - sizeof(writeOutput),
- - &ioctlBytesReturned,
- - NULL);
- + if (!bResult) {
- + goto cleanup;
- + }
- - if (!bSuccess) {
- - (void)fprintf(stderr,
- - "FSCTL_OFFLOAD_WRITE failed, lasterr=%d\n",
- - (int)GetLastError());
- - goto cleanup;
- + byteCount -= bytesCopied;
- + copyOffset += bytesCopied;
- }
- - (void)printf("Offload write successful. Bytes written: %lld\n",
- - (long long)writeOutput.LengthWritten);
- - (void)printf("Offloaded copy completed successfully!\n");
- + (void)printf("# Successfully used offload read+write to copy '%s' to '%s'!\n",
- + srcFilename,
- + destFilename);
- retval = EXIT_SUCCESS;
- cleanup:
- --
- 2.45.1
- From c9f9bee6aaa2380b167608802e401bb77b129f05 Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Sat, 23 Aug 2025 12:35:09 +0200
- Subject: [PATCH 2/3] tests: multisparsefiletest: offloadcopy tests should be
- enabled with test_offloadcopy=true
- multisparsefiletest: offloadcopy tests should be enabled with
- test_offloadcopy=true
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- tests/sparsefiles/multisparsefiletest.ksh | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
- diff --git a/tests/sparsefiles/multisparsefiletest.ksh b/tests/sparsefiles/multisparsefiletest.ksh
- index 0d39082..b8106e4 100644
- --- a/tests/sparsefiles/multisparsefiletest.ksh
- +++ b/tests/sparsefiles/multisparsefiletest.ksh
- @@ -297,7 +297,7 @@ function multisparsefiletest1
- fi
- ;;
- 'offloadcopy_full' | 'offloadcopy_full_64bit' | 'offloadcopy_full_32bit')
- - if $test_cloning ; then
- + if $test_offloadcopy ; then
- ${winoffloadcopyfilecmd} 'sparsefile2.bin' 'sparsefile2_offloadcopy_full.bin' 1>'/dev/null'
- c.stdout="$(lssparse -H 'sparsefile2_offloadcopy_full.bin')"
- else
- @@ -307,7 +307,7 @@ function multisparsefiletest1
- fi
- ;;
- 'offloadcopy_1mbchunks' | 'offloadcopy_1mbchunks_64bit' | 'offloadcopy_1mbchunks_32bit')
- - if $test_cloning ; then
- + if $test_offloadcopy ; then
- ${winoffloadcopyfilecmd} \
- --copychunksize $((1024*1024)) \
- 'sparsefile2.bin' \
- --
- 2.45.1
- From d72d3f30b9fa50f1b144e9e676f446df06551f06 Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Sat, 23 Aug 2025 17:22:59 +0200
- Subject: [PATCH 3/3] daemon: Implement custom NFS port support for NFSv4
- referrals
- Implement custom (non-2049) NFS port support for NFSv4 referrals.
- Reported-by: Martin Wege <martin.l.wege@gmail.com>
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- daemon/namespace.c | 12 ++++--
- daemon/util.c | 100 +++++++++++++++++++++++++++++++++++++++++++++
- daemon/util.h | 22 ++++++++++
- 3 files changed, 131 insertions(+), 3 deletions(-)
- diff --git a/daemon/namespace.c b/daemon/namespace.c
- index 75bc67f..4a2b157 100644
- --- a/daemon/namespace.c
- +++ b/daemon/namespace.c
- @@ -535,13 +535,19 @@ static int referral_mount_location(
- /* create a client and session for the first available server */
- for (i = 0; i < loc->server_count; i++) {
- - DPRINTF(1,
- + char addr[NFS41_HOSTNAME_LEN+1];
- + unsigned short port;
- +
- + DPRINTF(0,
- ("referral_mount_location: "
- "trying loc->servers[%d].address='%s'\n",
- (int)i, loc->servers[i].address));
- - /* XXX: only deals with 'address' as a hostname with default port */
- - status = nfs41_server_resolve(loc->servers[i].address, 2049, &addrs);
- + status = parse_fs_location_server_address(loc->servers[i].address,
- + addr, &port);
- + if (status) continue;
- +
- + status = nfs41_server_resolve(addr, port, &addrs);
- if (status) continue;
- status = nfs41_root_mount_addrs(root, &addrs, 0, 0, client_out);
- diff --git a/daemon/util.c b/daemon/util.c
- index e497109..4788d85 100644
- --- a/daemon/util.c
- +++ b/daemon/util.c
- @@ -668,3 +668,103 @@ int nfs41_cached_getchangeattr(nfs41_open_state *state, nfs41_file_info *restric
- &state->file, &change_bitmap, info);
- return status;
- }
- +
- +static
- +bool parse_last_two_numbers(
- + IN const char *restrict str,
- + OUT const char **begin_dot, OUT int *num1, OUT int *num2)
- +{
- + const char *last_dot = NULL;
- + const char *second_last_dot = NULL;
- + char *endptr = NULL;
- +
- + last_dot = memrchr(str, '.', strlen(str));
- + if (last_dot == NULL) {
- + return false;
- + }
- +
- + second_last_dot = memrchr(str, '.', last_dot - str);
- + if (second_last_dot == NULL) {
- + return false;
- + }
- +
- + *begin_dot = second_last_dot;
- +
- + errno = 0;
- + *num1 = (int)strtol(second_last_dot + 1, &endptr, 10);
- +
- + if ((errno == ERANGE) ||
- + (endptr != last_dot) ||
- + (endptr == second_last_dot + 1)) {
- + return false;
- + }
- +
- + errno = 0;
- + *num2 = (int)strtol(last_dot + 1, &endptr, 10);
- +
- + if ((errno == ERANGE) ||
- + (*endptr != '\0') ||
- + (endptr == last_dot + 1)) {
- + return false;
- + }
- +
- + return true;
- +}
- +
- +static
- +int count_chars(IN const char *restrict s, IN int ch)
- +{
- + int num = 0;
- + unsigned char c;
- +
- + while((c = *s++) != '\0') {
- + if (c == (unsigned char)ch)
- + num++;
- + }
- + return num;
- +}
- +
- +int parse_fs_location_server_address(IN const char *restrict inaddr,
- + OUT char *restrict addr,
- + OUT unsigned short *restrict port)
- +{
- + /*
- + * See https://datatracker.ietf.org/doc/html/rfc5665#section-5.2.3.3
- + * for IPv4 and
- + * https://datatracker.ietf.org/doc/html/rfc5665#section-5.2.3.4 for
- + * IPv6.
- + */
- + int dot_count = count_chars(inaddr, '.');
- + int colon_count = count_chars(inaddr, ':');
- +
- + if (((dot_count == 5) && (colon_count == 0)) ||
- + (colon_count == 7) && (dot_count == 2)) {
- + int num1, num2;
- + const char *begin_dot = NULL;
- + if (parse_last_two_numbers(inaddr, &begin_dot, &num1, &num2)) {
- + size_t len = begin_dot - inaddr;
- + (void)memcpy(addr, inaddr, len);
- + addr[len] = '\0';
- + *port = (unsigned short)((num1 << 8) + num2);
- + DPRINTF(0,
- + ("parse_fs_location_server_address: "
- + "addr='%s' port=%d\n",
- + addr, (unsigned short)*port));
- +
- + return NO_ERROR;
- + }
- + else {
- + return ERROR_BAD_NET_NAME;
- + }
- + }
- + else if (((dot_count == 3) && (colon_count == 0)) ||
- + (colon_count == 5) && (dot_count == 0)) {
- + (void)strcpy(addr, inaddr);
- + *port = 2049;
- + return NO_ERROR;
- + }
- +
- + eprintf("parse_fs_location_server_address: Unknown format addr='%s'\n",
- + inaddr);
- + return ERROR_BAD_NET_NAME;
- +}
- diff --git a/daemon/util.h b/daemon/util.h
- index 87c2315..b936ac4 100644
- --- a/daemon/util.h
- +++ b/daemon/util.h
- @@ -69,6 +69,24 @@ void *mempcpy(void *restrict dest, const void *restrict src, size_t n)
- return (void *)((char *)dest + n);
- }
- +static __inline
- +void *memrchr(const void * restrict s, int c, size_t n)
- +{
- + const unsigned char *cp;
- +
- + if (n == 0UL)
- + return NULL;
- +
- + cp = (const unsigned char *)s + n;
- + do {
- + if (*(--cp) == (unsigned char)c) {
- + return((void *)cp);
- + }
- + } while (--n != 0UL);
- +
- + return NULL;
- +}
- +
- int safe_read(unsigned char **pos, uint32_t *remaining, void *dest, uint32_t dest_len);
- int safe_write(unsigned char **pos, uint32_t *remaining, void *dest, uint32_t dest_len);
- int get_safe_write_bufferpos(unsigned char **pos, uint32_t *remaining,
- @@ -406,4 +424,8 @@ bool getwinntversionnnumbers(DWORD *MajorVersionPtr, DWORD *MinorVersionPtr, DWO
- int nfs41_cached_getchangeattr(nfs41_open_state *state, nfs41_file_info *restrict info);
- +int parse_fs_location_server_address(IN const char *restrict inaddr,
- + OUT char *restrict addr,
- + OUT unsigned short *restrict port);
- +
- #endif /* !__NFS41_DAEMON_UTIL_H__ */
- --
- 2.45.1
msnfs41client: Patches for offload copy tests, custom (non-2049) port numbers for NFSv4 referrals+misc, 2025-08-23
Posted by Anonymous on Sat 23rd Aug 2025 16:32
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.