pastebin - collaborative debugging tool
rovema.kpaste.net RSS


msnfs41client: winoffloadcopyfile, volumeserialnumber from NFS fs_id, misc, 2025-08-21
Posted by Anonymous on Thu 21st Aug 2025 13:44
raw | new post

  1. From b4a3d623216c511b8a9d089c7030d2741e96d158 Mon Sep 17 00:00:00 2001
  2. From: Roland Mainz <roland.mainz@nrubsig.org>
  3. Date: Thu, 21 Aug 2025 10:36:04 +0200
  4. Subject: [PATCH 1/2] cygwin,tests: Add "winoffloadcopyfile" tool to test
  5.  offload data copy
  6.  
  7. Add "winoffloadcopyfile" tool to test offload data copy
  8. (|FSCTL_OFFLOAD_READ|+|FSCTL_OFFLOAD_WRITE|).
  9.  
  10. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  11. ---
  12. cygwin/Makefile                               |   4 +
  13.  cygwin/Makefile.install                       |   7 +
  14.  tests/sparsefiles/multisparsefiletest.ksh     |  36 ++-
  15.  tests/winoffloadcopyfile/Makefile             |  23 ++
  16.  tests/winoffloadcopyfile/winoffloadcopyfile.c | 237 ++++++++++++++++++
  17.  5 files changed, 306 insertions(+), 1 deletion(-)
  18.  create mode 100644 tests/winoffloadcopyfile/Makefile
  19.  create mode 100644 tests/winoffloadcopyfile/winoffloadcopyfile.c
  20.  
  21. diff --git a/cygwin/Makefile b/cygwin/Makefile
  22. index 4cff33b..6fbb7f0 100644
  23. --- a/cygwin/Makefile
  24. +++ b/cygwin/Makefile
  25. @@ -24,6 +24,7 @@ $(PROJECT_BASEDIR_DIR)/tests/ea/nfs_ea.exe \
  26.         $(PROJECT_BASEDIR_DIR)/tests/winfsinfo1/winfsinfo.exe \
  27.         $(PROJECT_BASEDIR_DIR)/tests/filemmaptests/qsortonmmapedfile1.exe \
  28.         $(PROJECT_BASEDIR_DIR)/tests/winclonefile/winclonefile.exe \
  29. +       $(PROJECT_BASEDIR_DIR)/tests/winoffloadcopyfile/winoffloadcopyfile.exe \
  30.         $(PROJECT_BASEDIR_DIR)/tests/winsg/winsg.exe: build_testutils
  31.  
  32.  #
  33. @@ -70,6 +71,7 @@ build_testutils:
  34.         (cd "$(PROJECT_BASEDIR_DIR)/tests/winfsinfo1" && make all)
  35.         (cd "$(PROJECT_BASEDIR_DIR)/tests/filemmaptests" && make all)
  36.         (cd "$(PROJECT_BASEDIR_DIR)/tests/winclonefile" && make all)
  37. +       (cd "$(PROJECT_BASEDIR_DIR)/tests/winoffloadcopyfile" && make all)
  38.         (cd "$(PROJECT_BASEDIR_DIR)/tests/winsg" && make all)
  39.  
  40.  build: build_32bit_release build_32bit_debug build_64bit_release build_64bit_debug build_arm_64bit_debug build_testutils
  41. @@ -106,6 +108,7 @@ clean:
  42.         (cd "$(PROJECT_BASEDIR_DIR)/tests/winfsinfo1" && make clean)
  43.         (cd "$(PROJECT_BASEDIR_DIR)/tests/filemmaptests" && make clean)
  44.         (cd "$(PROJECT_BASEDIR_DIR)/tests/winclonefile" && make clean)
  45. +       (cd "$(PROJECT_BASEDIR_DIR)/tests/winoffloadcopyfile" && make clean)
  46.         (cd "$(PROJECT_BASEDIR_DIR)/tests/winsg" && make clean)
  47.  
  48.  installdest_util: \
  49. @@ -117,6 +120,7 @@ installdest_util: \
  50.         $(PROJECT_BASEDIR_DIR)/tests/winfsinfo1/winfsinfo.exe \
  51.         $(PROJECT_BASEDIR_DIR)/tests/filemmaptests/qsortonmmapedfile1.exe \
  52.         $(PROJECT_BASEDIR_DIR)/tests/winclonefile/winclonefile.exe \
  53. +       $(PROJECT_BASEDIR_DIR)/tests/winoffloadcopyfile/winoffloadcopyfile.exe \
  54.         $(PROJECT_BASEDIR_DIR)/tests/winsg/winsg.exe \
  55.         $(CYGWIN_MAKEFILE_DIR)/devel/msnfs41client.bash
  56.  
  57. diff --git a/cygwin/Makefile.install b/cygwin/Makefile.install
  58. index c361190..2ad96b0 100644
  59. --- a/cygwin/Makefile.install
  60. +++ b/cygwin/Makefile.install
  61. @@ -119,6 +119,13 @@ installdest:
  62.         else \
  63.                 (cd $(DESTDIR)/$(CYGWIN_BASEPATH)/bin/ && $(LINKEXE) winclonefile.i686.exe winclonefile.exe) \
  64.         fi
  65. +       cp "$(PROJECT_BASEDIR_DIR)/tests/winoffloadcopyfile/winoffloadcopyfile.x86_64.exe" $(DESTDIR)/$(CYGWIN_BASEPATH)/bin/winoffloadcopyfile.x86_64.exe
  66. +       cp "$(PROJECT_BASEDIR_DIR)/tests/winoffloadcopyfile/winoffloadcopyfile.i686.exe" $(DESTDIR)/$(CYGWIN_BASEPATH)/bin/winoffloadcopyfile.i686.exe
  67. +       if [[ "$(CYGWIN_BASEPATH)" == *64* ]] ; then \
  68. +               (cd $(DESTDIR)/$(CYGWIN_BASEPATH)/bin/ && $(LINKEXE) winoffloadcopyfile.x86_64.exe winoffloadcopyfile.exe) \
  69. +       else \
  70. +               (cd $(DESTDIR)/$(CYGWIN_BASEPATH)/bin/ && $(LINKEXE) winoffloadcopyfile.i686.exe winoffloadcopyfile.exe) \
  71. +       fi
  72.         cp "$(PROJECT_BASEDIR_DIR)/tests/lssparse/lssparse.x86_64.exe" $(DESTDIR)/$(CYGWIN_BASEPATH)/bin/lssparse.x86_64.exe
  73.         if [[ "$(CYGWIN_BASEPATH)" == *64* ]] ; then \
  74.                 (cd $(DESTDIR)/$(CYGWIN_BASEPATH)/bin/ && $(LINKEXE) lssparse.x86_64.exe lssparse.exe) \
  75. diff --git a/tests/sparsefiles/multisparsefiletest.ksh b/tests/sparsefiles/multisparsefiletest.ksh
  76. index b62f577..0d43585 100644
  77. --- a/tests/sparsefiles/multisparsefiletest.ksh
  78. +++ b/tests/sparsefiles/multisparsefiletest.ksh
  79. @@ -187,7 +187,9 @@ function multisparsefiletest1
  80.              'sparsefile2.bin' \
  81.              'sparsefile2_cpsparse.bin' \
  82.              'sparsefile2_cloned_full.bin' \
  83. -            'sparsefile2_cloned_1mbchunks.bin'
  84. +            'sparsefile2_cloned_1mbchunks.bin' \
  85. +            'sparsefile2_offloadcopy_full.bin' \
  86. +            'sparsefile2_offloadcopy_1mbchunks.bin'
  87.          c.testlabel=''
  88.  
  89.          if (( c.i == 0 )) ; then
  90. @@ -230,6 +232,10 @@ function multisparsefiletest1
  91.                      'cloned_1mbchunks_64bit'
  92.                      'cloned_full_32bit'
  93.                      'cloned_1mbchunks_32bit'
  94. +                    'offloadcopy_full_64bit'
  95. +                    'offloadcopy_1mbchunks_64bit'
  96. +                    'offloadcopy_full_32bit'
  97. +                    'offloadcopy_1mbchunks_32bit'
  98.                  )
  99.                  ;;
  100.              '32')
  101. @@ -238,6 +244,8 @@ function multisparsefiletest1
  102.                      'cp_sparseauto'
  103.                      'cloned_full'
  104.                      'cloned_1mbchunks'
  105. +                    'offloadcopy_full'
  106. +                    'offloadcopy_1mbchunks'
  107.                  )
  108.                  ;;
  109.              *)
  110. @@ -251,8 +259,10 @@ function multisparsefiletest1
  111.  
  112.              if [[ "${tstmod}" == *32bit ]] ; then
  113.                  winclonefilecmd='winclonefile.i686.exe'
  114. +                winoffloadcopyfilecmd='winoffloadcopyfile.i686.exe'
  115.              else
  116.                  winclonefilecmd='winclonefile.exe'
  117. +                winoffloadcopyfilecmd='winoffloadcopyfile.exe'
  118.              fi
  119.  
  120.              case "${tstmod}" in
  121. @@ -286,6 +296,29 @@ function multisparsefiletest1
  122.                          continue
  123.                      fi
  124.                      ;;
  125. +                'offloadcopy_full' | 'offloadcopy_full_64bit' | 'offloadcopy_full_32bit')
  126. +                    if $test_cloning ; then
  127. +                        ${winoffloadcopyfilecmd} 'sparsefile2.bin' 'sparsefile2_offloadcopy_full.bin' 1>'/dev/null'
  128. +                        c.stdout="$(lssparse -H 'sparsefile2_offloadcopy_full.bin')"
  129. +                    else
  130. +                        printf "# Test '%s' SKIPPED\n" "${c.testlabel}/${tstmod}"
  131. +                        (( tests_skipped++ ))
  132. +                        continue
  133. +                    fi
  134. +                    ;;
  135. +                'offloadcopy_1mbchunks' | 'offloadcopy_1mbchunks_64bit' | 'offloadcopy_1mbchunks_32bit')
  136. +                    if $test_cloning ; then
  137. +                        ${winoffloadcopyfilecmd} \
  138. +                            --clonechunksize $((1024*1024)) \
  139. +                            'sparsefile2.bin' \
  140. +                            'sparsefile2_offloadcopy_1mbchunks.bin' 1>'/dev/null'
  141. +                        c.stdout="$(lssparse -H 'sparsefile2_offloadcopy_1mbchunks.bin')"
  142. +                    else
  143. +                        printf "# Test '%s' SKIPPED\n" "${c.testlabel}/${tstmod}"
  144. +                        (( tests_skipped++ ))
  145. +                        continue
  146. +                    fi
  147. +                    ;;
  148.                  *)
  149.                      print -u2 -f 'Unknown test mod\n'
  150.                      ;;
  151. @@ -330,6 +363,7 @@ builtin wc
  152.  # - tests for sparse files >= 2GB, 4GB, 16GB
  153.  #
  154.  typeset test_cloning=false
  155. +typeset test_offloadcopy=true
  156.  
  157.  multisparsefiletest1
  158.  
  159. diff --git a/tests/winoffloadcopyfile/Makefile b/tests/winoffloadcopyfile/Makefile
  160. new file mode 100644
  161. index 0000000..a429b44
  162. --- /dev/null
  163. +++ b/tests/winoffloadcopyfile/Makefile
  164. @@ -0,0 +1,23 @@
  165. +#
  166. +# Makefile for winoffloadcopyfile
  167. +#
  168. +
  169. +# POSIX Makefile
  170. +
  171. +all: winoffloadcopyfile.i686.exe winoffloadcopyfile.x86_64.exe winoffloadcopyfile.exe
  172. +
  173. +winoffloadcopyfile.i686.exe: winoffloadcopyfile.c
  174. +       clang -target i686-pc-windows-gnu -std=gnu17 -Wall -Wextra -DUNICODE=1 -D_UNICODE=1 -I../../include -g winoffloadcopyfile.c -lntdll -o winoffloadcopyfile.i686.exe
  175. +
  176. +winoffloadcopyfile.x86_64.exe: winoffloadcopyfile.c
  177. +       clang -target x86_64-pc-windows-gnu -std=gnu17 -Wall -Wextra -DUNICODE=1 -D_UNICODE=1 -I../../include -g winoffloadcopyfile.c -lntdll -o winoffloadcopyfile.x86_64.exe
  178. +
  179. +winoffloadcopyfile.exe: winoffloadcopyfile.x86_64.exe
  180. +       ln -s winoffloadcopyfile.x86_64.exe winoffloadcopyfile.exe
  181. +
  182. +clean:
  183. +       rm -fv \
  184. +               winoffloadcopyfile.i686.exe \
  185. +               winoffloadcopyfile.x86_64.exe \
  186. +               winoffloadcopyfile.exe
  187. +# EOF.
  188. diff --git a/tests/winoffloadcopyfile/winoffloadcopyfile.c b/tests/winoffloadcopyfile/winoffloadcopyfile.c
  189. new file mode 100644
  190. index 0000000..021037b
  191. --- /dev/null
  192. +++ b/tests/winoffloadcopyfile/winoffloadcopyfile.c
  193. @@ -0,0 +1,237 @@
  194. +/*
  195. + * MIT License
  196. + *
  197. + * Copyright (c) 2025 Roland Mainz <roland.mainz@nrubsig.org>
  198. + *
  199. + * Permission is hereby granted, free of charge, to any person obtaining a copy
  200. + * of this software and associated documentation files (the "Software"), to deal
  201. + * in the Software without restriction, including without limitation the rights
  202. + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  203. + * copies of the Software, and to permit persons to whom the Software is
  204. + * furnished to do so, subject to the following conditions:
  205. + *
  206. + * The above copyright notice and this permission notice shall be included in
  207. + * all copies or substantial portions of the Software.
  208. + *
  209. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  210. + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  211. + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  212. + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  213. + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  214. + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  215. + * SOFTWARE.
  216. + */
  217. +
  218. +/*
  219. + * winoffloadcopyfile.c - clone a file
  220. + *
  221. + * Written by Roland Mainz <roland.mainz@nrubsig.org>
  222. + */
  223. +
  224. +#define WIN32_LEAN_AND_MEAN 1
  225. +
  226. +#include <windows.h>
  227. +#include <winioctl.h>
  228. +#include <stdio.h>
  229. +
  230. +#define EXIT_USAGE (2)
  231. +
  232. +#ifndef OFFLOAD_READ_FLAG_ALL_ZERO_BEYOND_CURRENT_RANGE
  233. +typedef struct _FSCTL_OFFLOAD_READ_INPUT {
  234. +    DWORD Size;
  235. +    DWORD Flags;
  236. +    DWORD TokenTimeToLive;
  237. +    DWORD Reserved;
  238. +    DWORDLONG FileOffset;
  239. +    DWORDLONG CopyLength;
  240. +} FSCTL_OFFLOAD_READ_INPUT, *PFSCTL_OFFLOAD_READ_INPUT;
  241. +
  242. +typedef struct _FSCTL_OFFLOAD_READ_OUTPUT {
  243. +    DWORD Size;
  244. +    DWORD Flags;
  245. +    DWORDLONG TransferLength;
  246. +    BYTE  Token[512];
  247. +} FSCTL_OFFLOAD_READ_OUTPUT, *PFSCTL_OFFLOAD_READ_OUTPUT;
  248. +
  249. +#define OFFLOAD_READ_FLAG_ALL_ZERO_BEYOND_CURRENT_RANGE (1)
  250. +
  251. +typedef struct _FSCTL_OFFLOAD_WRITE_INPUT {
  252. +    DWORD Size;
  253. +    DWORD Flags;
  254. +    DWORDLONG FileOffset;
  255. +    DWORDLONG CopyLength;
  256. +    DWORDLONG TransferOffset;
  257. +    BYTE  Token[512];
  258. +} FSCTL_OFFLOAD_WRITE_INPUT, *PFSCTL_OFFLOAD_WRITE_INPUT;
  259. +
  260. +typedef struct _FSCTL_OFFLOAD_WRITE_OUTPUT {
  261. +    DWORD Size;
  262. +    DWORD Flags;
  263. +    DWORDLONG LengthWritten;
  264. +} FSCTL_OFFLOAD_WRITE_OUTPUT, *PFSCTL_OFFLOAD_WRITE_OUTPUT;
  265. +#endif /* OFFLOAD_READ_FLAG_ALL_ZERO_BEYOND_CURRENT_RANGE */
  266. +
  267. +#ifndef STORAGE_OFFLOAD_MAX_TOKEN_LENGTH
  268. +#define STORAGE_OFFLOAD_MAX_TOKEN_LENGTH        (512)
  269. +#define STORAGE_OFFLOAD_TOKEN_ID_LENGTH         (0x1F8)
  270. +#define STORAGE_OFFLOAD_TOKEN_TYPE_ZERO_DATA    (0xFFFF0001)
  271. +
  272. +typedef struct _STORAGE_OFFLOAD_TOKEN {
  273. +
  274. +    BYTE  TokenType[4];
  275. +    BYTE  Reserved[2];
  276. +    BYTE  TokenIdLength[2];
  277. +    union {
  278. +        struct {
  279. +            BYTE    Reserved2[STORAGE_OFFLOAD_TOKEN_ID_LENGTH];
  280. +        } StorageOffloadZeroDataToken;
  281. +        BYTE        Token[STORAGE_OFFLOAD_TOKEN_ID_LENGTH];
  282. +    } DUMMYUNIONNAME;
  283. +} STORAGE_OFFLOAD_TOKEN, *PSTORAGE_OFFLOAD_TOKEN;
  284. +#endif /* STORAGE_OFFLOAD_MAX_TOKEN_LENGTH */
  285. +
  286. +int main(int argc, char* argv[])
  287. +{
  288. +    int retval = EXIT_FAILURE;
  289. +
  290. +    if (argc != 3) {
  291. +        (void)fprintf(stderr,
  292. +            "Usage: %s <source_file> <destination_file>\n",
  293. +            argv[0]);
  294. +        return EXIT_USAGE;
  295. +    }
  296. +
  297. +    const char *srcFilename = argv[1];
  298. +    const char *destFilename = argv[2];
  299. +    HANDLE hSrc = INVALID_HANDLE_VALUE;
  300. +    HANDLE hDest = INVALID_HANDLE_VALUE;
  301. +    BOOL bSuccess = FALSE;
  302. +    DWORD ioctlBytesReturned = 0;
  303. +
  304. +    BYTE tokenBuffer[STORAGE_OFFLOAD_MAX_TOKEN_LENGTH] = { 0 };
  305. +    PSTORAGE_OFFLOAD_TOKEN pToken = (PSTORAGE_OFFLOAD_TOKEN)tokenBuffer;
  306. +
  307. +    (void)printf("Attempting offloaded copy from '%s' to '%s'\n",
  308. +        srcFilename,
  309. +        destFilename);
  310. +
  311. +    hSrc = CreateFileA(srcFilename,
  312. +        GENERIC_READ,
  313. +        FILE_SHARE_READ,
  314. +        NULL,
  315. +        OPEN_EXISTING,
  316. +        FILE_ATTRIBUTE_NORMAL,
  317. +        NULL);
  318. +    if (hSrc == INVALID_HANDLE_VALUE) {
  319. +        (void)fprintf(stderr,
  320. +            "Cannot open src file, lasterr=%d\n",
  321. +            (int)GetLastError());
  322. +        goto cleanup;
  323. +    }
  324. +
  325. +    hDest = CreateFileA(destFilename,
  326. +        GENERIC_ALL,
  327. +        FILE_SHARE_DELETE|FILE_SHARE_WRITE,
  328. +        NULL,
  329. +        CREATE_ALWAYS,
  330. +        FILE_ATTRIBUTE_NORMAL,
  331. +        NULL);
  332. +    if (hDest == INVALID_HANDLE_VALUE) {
  333. +        (void)fprintf(stderr,
  334. +            "Cannot open dst file, lasterr=%d\n",
  335. +            (int)GetLastError());
  336. +        goto cleanup;
  337. +    }
  338. +
  339. +    LARGE_INTEGER fileSize;
  340. +    if (!GetFileSizeEx(hSrc, &fileSize)) {
  341. +        (void)fprintf(stderr,
  342. +            "Cannot src file size, lasterr=%d\n",
  343. +            (int)GetLastError());
  344. +        goto cleanup;
  345. +    }
  346. +
  347. +    FSCTL_OFFLOAD_READ_INPUT readInput = { 0 };
  348. +    readInput.Size = sizeof(FSCTL_OFFLOAD_READ_INPUT);
  349. +    readInput.FileOffset = 0;
  350. +    readInput.CopyLength = fileSize.QuadPart;
  351. +
  352. +    FSCTL_OFFLOAD_READ_OUTPUT readOutput = { 0 };
  353. +    readOutput.Size = sizeof(FSCTL_OFFLOAD_READ_OUTPUT);
  354. +
  355. +    bSuccess = DeviceIoControl(
  356. +        hSrc,
  357. +        FSCTL_OFFLOAD_READ,
  358. +        &readInput,
  359. +        sizeof(readInput),
  360. +        &readOutput,
  361. +        sizeof(readOutput),
  362. +        &ioctlBytesReturned,
  363. +        NULL);
  364. +
  365. +    if (!bSuccess) {
  366. +        (void)fprintf(stderr,
  367. +            "FSCTL_OFFLOAD_READ failed, lasterr=%d\n",
  368. +            (int)GetLastError());
  369. +        goto cleanup;
  370. +    }
  371. +
  372. +    if (!SetFilePointerEx(hDest, fileSize, NULL, FILE_BEGIN)) {
  373. +        (void)fprintf(stderr,
  374. +            "Cannot set dest file pointer, lasterr=%d\n",
  375. +            (int)GetLastError());
  376. +        goto cleanup;
  377. +    }
  378. +
  379. +    if (!SetEndOfFile(hDest)) {
  380. +        (void)fprintf(stderr,
  381. +            "Cannot set dest file size, lasterr=%d\n",
  382. +            (int)GetLastError());
  383. +        goto cleanup;
  384. +    }
  385. +
  386. +    (void)memcpy(pToken, readOutput.Token, sizeof(tokenBuffer));
  387. +
  388. +    FSCTL_OFFLOAD_WRITE_INPUT writeInput = { 0 };
  389. +    writeInput.Size = sizeof(FSCTL_OFFLOAD_WRITE_INPUT);
  390. +    writeInput.FileOffset = 0;
  391. +    writeInput.CopyLength = fileSize.QuadPart;
  392. +    writeInput.TransferOffset = 0;
  393. +    (void)memcpy(writeInput.Token, pToken, sizeof(tokenBuffer));
  394. +
  395. +    FSCTL_OFFLOAD_WRITE_OUTPUT writeOutput = { 0 };
  396. +    writeOutput.Size = sizeof(FSCTL_OFFLOAD_WRITE_OUTPUT);
  397. +
  398. +    (void)printf("Performing copy with FSCTL_OFFLOAD_WRITE...\n");
  399. +    bSuccess = DeviceIoControl(
  400. +        hDest,
  401. +        FSCTL_OFFLOAD_WRITE,
  402. +        &writeInput,
  403. +        sizeof(writeInput),
  404. +        &writeOutput,
  405. +        sizeof(writeOutput),
  406. +        &ioctlBytesReturned,
  407. +        NULL);
  408. +
  409. +    if (!bSuccess) {
  410. +        (void)fprintf(stderr,
  411. +            "FSCTL_OFFLOAD_WRITE failed, lasterr=%d\n",
  412. +            (int)GetLastError());
  413. +        goto cleanup;
  414. +    }
  415. +
  416. +    (void)printf("Offload write successful. Bytes written: %lld\n",
  417. +        (long long)writeOutput.LengthWritten);
  418. +    (void)printf("Offloaded copy completed successfully!\n");
  419. +    retval = EXIT_SUCCESS;
  420. +
  421. +cleanup:
  422. +    if (hSrc != INVALID_HANDLE_VALUE) {
  423. +        (void)CloseHandle(hSrc);
  424. +    }
  425. +    if (hDest != INVALID_HANDLE_VALUE) {
  426. +        (void)CloseHandle(hDest);
  427. +    }
  428. +
  429. +    return retval;
  430. +}
  431. --
  432. 2.45.1
  433.  
  434. From a2b05101926134bdf1d237e1a95e1e4d63246d17 Mon Sep 17 00:00:00 2001
  435. From: Roland Mainz <roland.mainz@nrubsig.org>
  436. Date: Thu, 21 Aug 2025 13:06:29 +0200
  437. Subject: [PATCH 2/2] daemon:
  438.  |FILE_ID_INFORMATION.VolumeSerialNumber|+|FILE_FS_VOLUME_INFORMATION.VolumeSerialNumber|
  439.  should be calculated from |nfs41_fsid|
  440.  
  441. |FILE_ID_INFORMATION.VolumeSerialNumber| and
  442. |FILE_FS_VOLUME_INFORMATION.VolumeSerialNumber| should be calculated from
  443. |nfs41_fsid|.
  444.  
  445. Reported-by: Jeremy Drake <cygwin@jdrake.com>
  446. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  447. ---
  448. daemon/getattr.c |  8 +++++++-
  449.  daemon/util.h    | 25 +++++++++++++++++++++++++
  450.  daemon/volume.c  |  8 +++++++-
  451.  3 files changed, 39 insertions(+), 2 deletions(-)
  452.  
  453. diff --git a/daemon/getattr.c b/daemon/getattr.c
  454. index aa64ad7..f057eab 100644
  455. --- a/daemon/getattr.c
  456. +++ b/daemon/getattr.c
  457. @@ -175,8 +175,14 @@ static int handle_getattr(void *daemon_context, nfs41_upcall *upcall)
  458.              &args->remote_protocol_info);
  459.          break;
  460.      case FileIdInformation:
  461. +        nfs41_superblock *superblock = state->file.fh.superblock;
  462.          nfs41_file_info_to_FILE_ID_128(&info, &args->id_info.FileId);
  463. -        args->id_info.VolumeSerialNumber = 0xBABAFACE; /* 64bit! */
  464. +        /*
  465. +         * |FILE_ID_INFORMATION.VolumeSerialNumber| is a 64bit |ULONGLONG|
  466. +         */
  467. +        args->id_info.VolumeSerialNumber =
  468. +            nfs41_fsid2VolumeSerialNumber64(&superblock->fsid);
  469. +        EASSERT(args->id_info.VolumeSerialNumber != 0ULL);
  470.          break;
  471.  #ifdef NFS41_DRIVER_WSL_SUPPORT
  472.      case FileStatInformation:
  473. diff --git a/daemon/util.h b/daemon/util.h
  474. index 8dba1a9..87c2315 100644
  475. --- a/daemon/util.h
  476. +++ b/daemon/util.h
  477. @@ -211,6 +211,31 @@ static __inline int nfs41_fsid_cmp(
  478.          return 0;
  479.  }
  480.  
  481. +/*
  482. + * |nfs41_fsid2VolumeSerialNumber32()| - used for
  483. + * |FILE_FS_VOLUME_INFORMATION.VolumeSerialNumber|, which is a 32bit |ULONG|
  484. + */
  485. +static __inline ULONG nfs41_fsid2VolumeSerialNumber32(
  486. +    IN const nfs41_fsid *restrict fsid)
  487. +{
  488. +    ULONG vsn;
  489. +#define XOR_UINT64_WORDS(value) (((value) >> 32UL) ^ ((value) & 0x00000000FFFFFFFF))
  490. +    vsn = (ULONG)(XOR_UINT64_WORDS(fsid->major) ^ XOR_UINT64_WORDS(fsid->minor));
  491. +    return vsn;
  492. +}
  493. +
  494. +/*
  495. + * |nfs41_fsid2VolumeSerialNumber64()| - used for
  496. + * |FILE_ID_INFORMATION.VolumeSerialNumber|, which is a 64bit |ULONGLONG|
  497. + */
  498. +static __inline ULONGLONG nfs41_fsid2VolumeSerialNumber64(
  499. +    IN const nfs41_fsid *restrict fsid)
  500. +{
  501. +    ULONGLONG vsn;
  502. +    vsn = fsid->major ^ fsid->minor;
  503. +    return vsn;
  504. +}
  505. +
  506.  static __inline void open_delegation4_cpy(
  507.      OUT open_delegation4 *restrict dst,
  508.      IN  const open_delegation4 *restrict src)
  509. diff --git a/daemon/volume.c b/daemon/volume.c
  510. index dbb2431..3501c6e 100644
  511. --- a/daemon/volume.c
  512. +++ b/daemon/volume.c
  513. @@ -123,9 +123,15 @@ static int handle_volume(void *daemon_context, nfs41_upcall *upcall)
  514.      switch (args->query) {
  515.      case FileFsVolumeInformation:
  516.          PFILE_FS_VOLUME_INFORMATION vi = &args->info.volume_info;
  517. +        nfs41_superblock *superblock = upcall->state_ref->file.fh.superblock;
  518.  
  519.          vi->VolumeCreationTime.QuadPart = 0LL;
  520. -        vi->VolumeSerialNumber = 0xBABAFACE;
  521. +        /*
  522. +         * |FILE_FS_VOLUME_INFORMATION.VolumeSerialNumber| is a 32bit |ULONG|
  523. +         */
  524. +        vi->VolumeSerialNumber =
  525. +            nfs41_fsid2VolumeSerialNumber32(&superblock->fsid);
  526. +        EASSERT(vi->VolumeSerialNumber != 0UL);
  527.          vi->SupportsObjects = FALSE;
  528.  
  529.          /*
  530. --
  531. 2.45.1

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