pastebin - collaborative debugging tool
nrubsig.kpaste.net RSS


More debug code to hunt down the Win tar '0' write corruption bug
Posted by Anonymous on Sat 16th Nov 2024 13:01
raw | new post

  1. diff --git a/daemon/readwrite.c b/daemon/readwrite.c
  2. index 14e4bcb..8c0e77e 100644
  3. --- a/daemon/readwrite.c
  4. +++ b/daemon/readwrite.c
  5. @@ -22,6 +22,7 @@
  6.  
  7.  #include <Windows.h>
  8.  #include <stdio.h>
  9. +#include <stdbool.h>
  10.  
  11.  #include "nfs41_ops.h"
  12.  #include "name_cache.h"
  13. @@ -103,6 +104,30 @@ static int read_from_mds(
  14.          }
  15.      }
  16.  out:
  17. +
  18. +#if 1
  19. +#define NUM_TEST_BYTES_FOR_ZERO 512
  20. +    if (len > NUM_TEST_BYTES_FOR_ZERO) {
  21. +        uint32_t zz;
  22. +        const unsigned char *zzc;
  23. +        for (zz = 0, zzc = args->buffer ; zz < NUM_TEST_BYTES_FOR_ZERO ; zz++, zzc++) {
  24. +            if (*zzc != 0)
  25. +                break;
  26. +        }
  27. +
  28. +        if (zz == NUM_TEST_BYTES_FOR_ZERO) {
  29. +            DPRINTF(0,
  30. +                ("read_from_mds(upcall->state_ref->path.path='%s',args->offset=%lld): "
  31. +                "first %d bytes are '\\0', maxreadsize=%d, status=%d\n",
  32. +                upcall->state_ref->path.path,
  33. +                (long long)args->offset,
  34. +                (int)NUM_TEST_BYTES_FOR_ZERO,
  35. +                (int)maxreadsize,
  36. +                (int)status));
  37. +        }
  38. +    }
  39. +#endif
  40. +
  41.      args->out_len = len;
  42.      return status;
  43.  }
  44. @@ -166,6 +191,10 @@ static int handle_read(void *daemon_context, nfs41_upcall *upcall)
  45.  
  46.      args->out_len += pnfs_bytes_read;
  47.  out:
  48. +
  49. +#if 1
  50. +    FlushProcessWriteBuffers();
  51. +#endif
  52.      return status;
  53.  }
  54.  
  55. @@ -181,7 +210,11 @@ static int write_to_mds(
  56.      nfs41_write_verf verf;
  57.      enum stable_how4 stable, committed;
  58.      unsigned char *p;
  59. +#if 1
  60. +    const uint32_t maxwritesize = 131072/2;
  61. +#else
  62.      const uint32_t maxwritesize = max_write_size(session, &file->fh);
  63. +#endif
  64.      uint32_t to_send, reloffset, len;
  65.      int status = 0;
  66.      /* on write verifier mismatch, retry N times before failing */
  67. @@ -189,18 +222,110 @@ static int write_to_mds(
  68.      nfs41_file_info info;
  69.  
  70.      (void)memset(&info, 0, sizeof(info));
  71. +    bool virtlockpages = false;
  72. +
  73. +#if 1
  74. +    WIN32_MEMORY_RANGE_ENTRY mre = {
  75. +        .VirtualAddress=args->buffer,
  76. +        .NumberOfBytes=args->len
  77. +    };
  78. +    
  79. +    if (!PrefetchVirtualMemory(GetCurrentProcess(), 1, &mre, 0)) {
  80. +        DPRINTF(0,
  81. +            ("write_to_mds: "
  82. +            "PrefetchVirtualMemory() failed, GetLastError()=%d\n",
  83. +            (int)GetLastError()));
  84. +    }
  85. +#endif
  86. +
  87. +#if 1
  88. +    void *args_buffer = malloc(args->len);
  89. +    if (!args_buffer)
  90. +        goto out;
  91. +    (void)memmove(args_buffer, args->buffer, args->len);
  92. +#else
  93. +    void *args_buffer = args->buffer;
  94. +#endif
  95. +    
  96. +#if 1
  97. +    if (args->len > NUM_TEST_BYTES_FOR_ZERO) {
  98. +        uint32_t zz;
  99. +        const unsigned char *zzc;
  100. +        for (zz = 0, zzc = args_buffer ; zz < NUM_TEST_BYTES_FOR_ZERO ; zz++, zzc++) {
  101. +            if (*zzc != 0)
  102. +                break;
  103. +        }
  104. +
  105. +        if (zz == NUM_TEST_BYTES_FOR_ZERO) {
  106. +            DPRINTF(0,
  107. +                ("write_to_mds(upcall->state_ref->path.path='%s',args->offset=%lld): "
  108. +                "layer1: first %d bytes are '\\0', maxwritesize=%d\n",
  109. +                upcall->state_ref->path.path,
  110. +                (long long)args->offset,
  111. +                (int)NUM_TEST_BYTES_FOR_ZERO,
  112. +                (int)maxwritesize));
  113. +        }
  114. +    }
  115. +#endif
  116. +
  117. +#if 0
  118. +    if (!VirtualLock(args_buffer, args->len)) {
  119. +        DPRINTF(0,
  120. +            ("write_to_mds(upcall->state_ref->path.path='%s'): "
  121. +            "VirtualLock() failed, GetLastError()=%d\n",
  122. +            upcall->state_ref->path.path, (int)GetLastError()));
  123. +            status = NFS4ERR_IO;
  124. +        goto out;
  125. +    }
  126. +    virtlockpages = true;
  127. +#endif
  128. +
  129. +#if 1
  130. +#if defined(_M_IX86) || defined(_M_X64)
  131. +    {
  132. +        uint32_t zz;
  133. +        const unsigned char *zzc;
  134. +        for (zz = 0, zzc = args_buffer ; zz < args->len ; zz+=64, zzc+=64) {
  135. +            _mm_clflush(zzc);
  136. +        }
  137. +        FlushProcessWriteBuffers();
  138. +    }
  139. +#endif /* defined(_M_IX86) || defined(_M_X64) */
  140. +#endif
  141. +
  142. +#if 1
  143. +    if (args->len > NUM_TEST_BYTES_FOR_ZERO) {
  144. +        uint32_t zz;
  145. +        const unsigned char *zzc;
  146. +        for (zz = 0, zzc = args_buffer ; zz < NUM_TEST_BYTES_FOR_ZERO ; zz++, zzc++) {
  147. +            if (*zzc != 0)
  148. +                break;
  149. +        }
  150. +
  151. +        if (zz == NUM_TEST_BYTES_FOR_ZERO) {
  152. +            DPRINTF(0,
  153. +                ("write_to_mds(upcall->state_ref->path.path='%s',args->offset=%lld): "
  154. +                "layer2: first %d bytes are '\\0', maxwritesize=%d\n",
  155. +                upcall->state_ref->path.path,
  156. +                (long long)args->offset,
  157. +                (int)NUM_TEST_BYTES_FOR_ZERO,
  158. +                (int)maxwritesize));
  159. +        }
  160. +    }
  161. +#endif
  162. +
  163.  
  164.  retry_write:
  165. -    p = args->buffer;
  166. +    p = args_buffer;
  167.      to_send = args->len;
  168.      reloffset = 0;
  169.      len = 0;
  170. -    stable = to_send <= maxwritesize ? FILE_SYNC4 : UNSTABLE4;
  171. +    stable = to_send < maxwritesize ? FILE_SYNC4 : UNSTABLE4;
  172.      committed = FILE_SYNC4;
  173.  
  174. -    if (to_send > maxwritesize) {
  175. -        DPRINTF(1, ("handle_nfs41_write: writing %d in chunks of %d\n",
  176. -            to_send, maxwritesize));
  177. +    if (to_send >= maxwritesize) {
  178. +        DPRINTF(0, ("write_to_mds(upcall->state_ref->path.path='%s'): writing %d in chunks of %d\n",
  179. +            upcall->state_ref->path.path, to_send, maxwritesize));
  180.      }
  181.  
  182.      while(to_send > 0) {
  183. @@ -208,8 +333,12 @@ retry_write:
  184.  
  185.          status = nfs41_write(session, file, stateid, p, chunk,
  186.              args->offset + reloffset, stable, &bytes_written, &verf, &info);
  187. -        if (status && !len)
  188. +        if (status && !len) {
  189. +            DPRINTF(0,
  190. +                ("write_to_mds: fail status=%d, len=%ld\n",
  191. +                (int)status, (long)len));
  192.              goto out;
  193. +        }
  194.          p += bytes_written;
  195.          to_send -= bytes_written;
  196.          len += bytes_written;
  197. @@ -247,6 +376,12 @@ retry_write:
  198.      args->ctime = info.change;
  199.  
  200.  out:
  201. +#if 1
  202. +    free(args_buffer);
  203. +#endif
  204. +    if (virtlockpages) {
  205. +        (void)VirtualUnlock(args_buffer, args->len);
  206. +    }
  207.      args->out_len = len;
  208.      return nfs_to_windows_error(status, ERROR_NET_WRITE_FAULT);
  209.  
  210. diff --git a/sys/nfs41sys_readwrite.c b/sys/nfs41sys_readwrite.c
  211. index c039d23..edf4b76 100644
  212. --- a/sys/nfs41sys_readwrite.c
  213. +++ b/sys/nfs41sys_readwrite.c
  214. @@ -109,6 +109,21 @@ NTSTATUS marshal_nfs41_rw(
  215.      RtlCopyMemory(tmp, &entry->u.ReadWrite.offset,
  216.          sizeof(entry->u.ReadWrite.offset));
  217.      tmp += sizeof(entry->u.ReadWrite.offset);
  218. +
  219. +    if (entry->opcode == NFS41_WRITE) {
  220. +        DbgP("marshal_nfs41_rw: write: len=%lu offset=%llu "
  221. +            "MdlAddress=0x%p MdlFlags=0x%lx\n",
  222. +            entry->buf_len, entry->u.ReadWrite.offset,
  223. +            entry->u.ReadWrite.MdlAddress, (long)entry->u.ReadWrite.MdlAddress->MdlFlags);
  224. +
  225. +
  226. +#if 1
  227. +#if !defined(_ARM64_)
  228. +        (void)(KeInvalidateAllCaches)();
  229. +#endif
  230. +#endif
  231. +    }
  232. +
  233.      __try {
  234.  #pragma warning( push )
  235.  /*
  236. @@ -120,7 +135,7 @@ NTSTATUS marshal_nfs41_rw(
  237.  #pragma warning( pop )
  238.          entry->buf =
  239.              MmMapLockedPagesSpecifyCache(entry->u.ReadWrite.MdlAddress,
  240. -                UserMode, MmCached, NULL, TRUE, NormalPagePriority);
  241. +                UserMode, MmCached, NULL, TRUE, HighPagePriority);
  242.          if (entry->buf == NULL) {
  243.              print_error("marshal_nfs41_rw: "
  244.                  "MmMapLockedPagesSpecifyCache() failed to map pages\n");
  245. @@ -139,6 +154,30 @@ NTSTATUS marshal_nfs41_rw(
  246.      RtlCopyMemory(tmp, &entry->buf, sizeof(HANDLE));
  247.      *len = header_len;
  248.  
  249. +    if (entry->opcode == NFS41_WRITE) {
  250. +        DbgP("marshal_nfs41_rw: write: len=%lu offset=%llu "
  251. +            "MdlAddress=0x%p MdlFlags=0x%lx\n",
  252. +            entry->buf_len, entry->u.ReadWrite.offset,
  253. +            entry->u.ReadWrite.MdlAddress, (long)entry->u.ReadWrite.MdlAddress->MdlFlags);
  254. +    }
  255. +
  256. +#if 1
  257. +#define NUM_TEST_BYTES_FOR_ZERO 512
  258. +    if ((entry->opcode == NFS41_WRITE) && (entry->buf_len > NUM_TEST_BYTES_FOR_ZERO)) {
  259. +        long zz;
  260. +        const unsigned char *zzc;
  261. +        for (zz = 0, zzc = entry->buf ; zz < NUM_TEST_BYTES_FOR_ZERO ; zz++, zzc++) {
  262. +            if (*zzc != 0)
  263. +                break;
  264. +        }
  265. +
  266. +        if (zz == NUM_TEST_BYTES_FOR_ZERO) {
  267. +            DbgP("marshal_nfs41_rw: MYASSERT: "
  268. +                "first %d bytes are '\\0'\n",
  269. +                (int)NUM_TEST_BYTES_FOR_ZERO);
  270. +        }
  271. +    }
  272. +#endif
  273.  #ifdef DEBUG_MARSHAL_DETAIL_RW
  274.      DbgP("marshal_nfs41_rw: len=%lu offset=%llu "
  275.          "MdlAddress=0x%p Userspace=0x%p\n",
  276. diff --git a/tests/wintartests/wintartest_seq001.bash b/tests/wintartests/wintartest_seq001.bash
  277. index 489d169..ee9652b 100644
  278. --- a/tests/wintartests/wintartest_seq001.bash
  279. +++ b/tests/wintartests/wintartest_seq001.bash
  280. @@ -11,19 +11,45 @@
  281.  # Written by Roland Mainz <roland.mainz@nrubsig.org>
  282.  #
  283.  
  284. -export PATH='/bin:/usr/bin'
  285. +function test_wintar_seq
  286. +{
  287. +       set -o xtrace
  288. +       set -o errexit
  289. +       set -o nounset
  290. +
  291. +       # config
  292. +       typeset use_bzip2=$1
  293. +       typeset use_localdiskfortar=$2
  294.  
  295. +       # local vars
  296. +       typeset tarfile_dir
  297. +       typeset tarfilename
  298.         typeset -i i
  299.         typeset out
  300. +       typeset -a testfiles
  301. +       typeset currf
  302.  
  303. -set -o xtrace
  304. -set -o errexit
  305. +       # seq 1040 == 4093 bytes
  306. +       # seq 1042 == 4103 bytes
  307. +       for i in 1 100 1040 5000 10000 12000 ; do
  308. +               rm -f -- "${i}seq.txt"
  309. +               seq "$i" >"${i}seq.txt"
  310. +               testfiles+=( "${i}seq.txt" )
  311. +       done
  312.  
  313. -# Set umask=0000 to avoid permission trouble with SMB filesystems
  314. -umask 0000
  315. +       if "${use_localdiskfortar}" ; then
  316. +               tarfile_dir='/tmp'
  317. +       else
  318. +               tarfile_dir="$PWD"
  319. +       fi
  320.  
  321. -rm -f '10000seq.txt'
  322. -seq 100000 >'10000seq.txt' ; tar -cvf - '10000seq.txt' >'10000seq.tar' #| pbzip2 -1 >'10000seq.tar.bz2'
  323. +       if ${use_bzip2} ; then
  324. +               tarfilename="${tarfile_dir}/test_seq.tar.bz2"
  325. +               tar -cvf - "${testfiles[@]}" | pbzip2 -1 >"${tarfilename}"
  326. +       else
  327. +               tarfilename="${tarfile_dir}/test_seq.tar"
  328. +               tar -cvf - "${testfiles[@]}" >"${tarfilename}"
  329. +       fi
  330.  
  331.         rm -Rf 'tmp'
  332.         mkdir 'tmp'
  333. @@ -32,20 +58,52 @@ cd 'tmp'
  334.         set +o xtrace
  335.  
  336.         for (( i=0 ; i < 2000 ; i++ )) ; do
  337. -       printf '# Cycle %d:\n' "$i"
  338. -       /cygdrive/c/Windows/system32/tar -xvf "$(cygpath -w '../10000seq.tar')"
  339. -       out="$(od -x -v '10000seq.txt' | grep -F ' 0000' | head -n 5)"
  340. +               printf '#### Test cycle %d (usingbzip=%s,tarfileonlocaldisk=%s):\n' "$i" "$use_bzip2" "$use_localdiskfortar"
  341. +               /cygdrive/c/Windows/system32/tar -xvf "$(cygpath -w "${tarfilename}")"
  342. +
  343. +               for currf in "${testfiles[@]}" ; do
  344. +                       if [[ ! -r "$currf" ]] ; then
  345. +                               printf '## ERROR: File %q not found.\n' "$currf"
  346. +                               return 1
  347. +                       fi
  348. +                       if [[ ! -s "$currf" ]] ; then
  349. +                               printf '## ERROR: File %q is empty (ls -l == "%s").\n' "$currf" "$(ls -l "$currf")"
  350. +                               return 1
  351. +                       fi
  352. +
  353. +                       out="$(od -A x -t x1 -v "$currf" | grep -F ' 00' | head -n 5)"
  354.  
  355.                         if [[ "$out" != '' ]] ; then
  356. -               printf '# ERROR: Sequence of zero bytes in plain /usr/bin/seq output found:\n'
  357. +                               printf '## ERROR: Zero byte in plain /usr/bin/seq output %q found:\n' "$currf"
  358.                                 printf -- '---- snip ----\n%s\n---- snip ----\n' "$out"
  359. -               exit 1
  360. +                               return 1
  361.                         fi
  362. +               done
  363.  
  364. -       rm -f '10000seq.txt'
  365. +               rm -f -- "${testfiles[@]}"
  366.         done
  367.  
  368. -printf '# SUCCESS\n'
  369. +       printf '##### SUCCESS\n'
  370. +
  371. +       return 0
  372. +}
  373. +
  374. +
  375. +#
  376. +# main
  377. +#
  378. +
  379. +export PATH='/bin:/usr/bin'
  380. +
  381. +if [[ ! -x '/cygdrive/c/Windows/system32/tar' ]] ; then
  382. +       printf $"%s: %s not found.\n" \
  383. +               "$0" '/cygdrive/c/Windows/system32/tar' 1>&2
  384. +       exit 1
  385. +fi
  386. +
  387. +# Set umask=0000 to avoid permission trouble on SMB filesystems
  388. +umask 0000
  389.  
  390. -exit 0
  391. +test_wintar_seq true true
  392. +exit $?
  393.  # EOF.

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