Advertisement
dchg2000

ocfs2_fallocate_bug_plain_write.py

Sep 27th, 2021
113
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 2.64 KB | None | 0 0
  1. #!/usr/bin/python3
  2.  
  3. # Simulate a specific write pattern that triggers data corruption on OCFS2 volume.
  4. #
  5. # Usage: /path/to/ocfs2_fallocate_bug_plain_write.py [MAX_TIME_SECONDS]
  6. #
  7. # How it works:
  8. # 1. Opens the file for appending
  9. # 2. Write N random bytes, where N is a random integer in range [1..256]
  10. # 3. With 50% probability, wait M centiseconds (=0.01 of a second), where M is in range [1..100]
  11. # 4. If the time elapsed since step 1 is less than MAX_TIME_SECONDS, repeat from step 2
  12. #
  13. # Default MAX_TIME_SECONDS is 20
  14. #
  15. # How to use:
  16. # * Mount the same shared OCFS2 volume on two hosts in the cluster
  17. # * On first host, change current directory to the directory where the OCFS2 volume is mounted
  18. # * Run this script, notice the MD5 hash in its output
  19. # * Calculate MD5 hash of "output.bin" file. It should match the one from the script output
  20. # * Calculate MD5 hash of the same file from the other host
  21. # If data on disk is corrupted, the hashes calculated on two hosts will differ.
  22. # The reason is that the cache on the first host contains correct data, so the hash is correct,
  23. # while the second host has no cached data for this file,
  24. # so it reads the corrupted data directly from the block device.
  25.  
  26. import os, hashlib, random, time, sys
  27.  
  28. FILE = 'output.bin' # file name to write
  29. MAX_CHUNKS = 100000
  30. TIME_LIMIT_SECONDS = 20
  31.  
  32. FALLOC_FL_KEEP_SIZE = 1
  33. FALLOC_FL_PUNCH_HOLE = 2
  34.  
  35. if os.path.exists(FILE):
  36. os.unlink(FILE)
  37.  
  38. hash_sum = hashlib.md5()
  39.  
  40. written = 0
  41. time_start = time.time()
  42. time_end = time_start
  43.  
  44. if len(sys.argv) > 1:
  45. TIME_LIMIT_SECONDS = float(sys.argv[1])
  46.  
  47. last_progress = ''
  48. with open(FILE, 'ab') as fd:
  49. fileno = fd.fileno()
  50.  
  51. for chunk_idx in range(MAX_CHUNKS):
  52. chunk_size = random.randint(1, 256)
  53. with open('/dev/urandom', 'rb') as fd:
  54. chunk = fd.read(chunk_size)
  55. hash_sum.update(chunk)
  56.  
  57. pos = os.lseek(fileno, 0, 1)
  58. os.lseek(fileno, pos, 0)
  59. written += os.write(fileno, chunk)
  60.  
  61. if last_progress:
  62. print('\015' * len(last_progress), end='', file=sys.stderr)
  63.  
  64. last_progress = '{:8d}/{}'.format(chunk_idx + 1, MAX_CHUNKS)
  65. print(last_progress, end='', file=sys.stderr)
  66.  
  67. time_end = time.time()
  68. if time_end - time_start >= TIME_LIMIT_SECONDS:
  69. break
  70.  
  71. delay = random.randint(1, 200)
  72. if delay <= 100:
  73. time.sleep(delay / 100)
  74.  
  75. if last_progress:
  76. print('\015' * len(last_progress), end='', file=sys.stderr)
  77.  
  78. print("Wrote {} bytes, {:.3f} seconds elapsed, MD5 = {}".format(written, time_end - time_start, hash_sum.hexdigest()))
  79.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement