185 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Scheme
		
	
	
	
	
	
			
		
		
	
	
			185 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Scheme
		
	
	
	
	
	
(import (chezscheme)
 | 
						|
        (bcache block-manager)
 | 
						|
        (fmt fmt)
 | 
						|
        (loops)
 | 
						|
        (persistent-data btree)
 | 
						|
        (process)
 | 
						|
        (srfi s8 receive)
 | 
						|
        (thin metadata)
 | 
						|
        (utils))
 | 
						|
 | 
						|
;;;;---------------------------------------------------------------------
 | 
						|
;;;; Constraints
 | 
						|
;;;; 1) No thin device has a data block mapped in more than once.
 | 
						|
;;;; 2) Only root nodes may have fewer than max_entries/3
 | 
						|
;;;; 3) tl-leaf values are all in-metadata-bounds?
 | 
						|
;;;; 4) bl-leaf values are all in-data-bounds?
 | 
						|
;;;; 5) internal values are all in-metadata-bounds? (true of every internal
 | 
						|
;;;     node though, can't be used to differentiate).
 | 
						|
(define (thin-check metadata root)
 | 
						|
  (let ((exit-code (system
 | 
						|
                     (fmt #f "../bin/thin_check --override-mapping-root "
 | 
						|
                          root " " metadata " > /dev/null 2>&1"))))
 | 
						|
       (fmt #t "exit-code: " (wrt exit-code) ", ")
 | 
						|
       (zero? exit-code)))
 | 
						|
 | 
						|
;(define metadata "../metadataoriginal")
 | 
						|
;(define nr-metadata-blocks 262144)
 | 
						|
 | 
						|
(define metadata "/home/ejt/work/RedHat/rhel7-vm/dmtest/metadata.bin")
 | 
						|
(define nr-metadata-blocks 32768)
 | 
						|
 | 
						|
;; FIXME: aren't we returning a reference to a cache page and then dropping the lock?
 | 
						|
(define (read-superblock cache)
 | 
						|
  (with-block (b cache 0 (get-flags))
 | 
						|
    (block->superblock b)))
 | 
						|
 | 
						|
 | 
						|
(define (in-metadata-bounds? i)
 | 
						|
  (< i nr-metadata-blocks))
 | 
						|
 | 
						|
(define nr-data-blocks (* 183 32 1024))
 | 
						|
 | 
						|
(define (in-data-bounds? i)
 | 
						|
  (< i nr-data-blocks))
 | 
						|
 | 
						|
(define superblock-salt 160774)
 | 
						|
 | 
						|
(define (checksum-superblock cache)
 | 
						|
  (with-block (b cache 0 (get-flags))
 | 
						|
    (checksum-block b (ftype-sizeof unsigned-32) superblock-salt)))
 | 
						|
 | 
						|
(define (mk-conser v)
 | 
						|
  (lambda (xs)
 | 
						|
    (cons v xs)))
 | 
						|
 | 
						|
(define (add-rmap! rmap parent child)
 | 
						|
  (hashtable-update! rmap child (mk-conser parent) '()))
 | 
						|
 | 
						|
(define (get-nr-entries hdr)
 | 
						|
  (ftype-ref BTreeNodeHeader (nr-entries) hdr))
 | 
						|
 | 
						|
(define (all-values? pred b hdr vt)
 | 
						|
  (let ((vals (block->values b vt)))
 | 
						|
   (all? (lambda (i) (pred (value-at vt vals i)))
 | 
						|
         (iota (get-nr-entries hdr)))))
 | 
						|
 | 
						|
(define (unpack-block bt)
 | 
						|
  (receive (block time) (unpack-block-time bt)
 | 
						|
    block))
 | 
						|
 | 
						|
(define (internal? b hdr)
 | 
						|
  (internal-node? hdr))
 | 
						|
 | 
						|
(define (top-level-leaf? b hdr)
 | 
						|
  (and (leaf-node? hdr)
 | 
						|
       (= (ftype-sizeof unsigned-64) (ftype-ref BTreeNodeHeader (value-size) hdr))
 | 
						|
       (all-values? in-metadata-bounds? b hdr le64-vt)))
 | 
						|
 | 
						|
(define (bottom-level-leaf? b hdr)
 | 
						|
  (and (leaf-node? hdr)
 | 
						|
       (= (ftype-sizeof unsigned-64) (ftype-ref BTreeNodeHeader (value-size) hdr))
 | 
						|
       (let ((vals (block->values b le64-vt)))
 | 
						|
        (all? in-data-bounds?
 | 
						|
              (map (lambda (i)
 | 
						|
                     (unpack-block (value-at le64-vt vals i)))
 | 
						|
                   (iota (get-nr-entries hdr)))))))
 | 
						|
 | 
						|
(define (top-level-root? b hdr)
 | 
						|
  (and (leaf-node? hdr)
 | 
						|
       (< (ftype-ref BTreeNodeHeader (nr-entries) hdr)
 | 
						|
          (/ (ftype-ref BTreeNodeHeader (max-entries) hdr) 3))))
 | 
						|
 | 
						|
(define (details-leaf? b hdr)
 | 
						|
  (and (leaf-node? hdr)
 | 
						|
       (= (ftype-sizeof ThinDeviceDetails)
 | 
						|
          (ftype-ref BTreeNodeHeader (value-size) hdr))))
 | 
						|
 | 
						|
(define (classify-node b hdr)
 | 
						|
  (fold-left append '()
 | 
						|
    (map (lambda (pair)
 | 
						|
           (if ((car pair) b hdr)
 | 
						|
               (cdr pair)
 | 
						|
               '()))
 | 
						|
         `((,internal? internal)
 | 
						|
           (,bottom-level-leaf? bottom-level-leaf)
 | 
						|
           (,top-level-leaf? top-level-leaf)
 | 
						|
           (,details-leaf? details-leaf)))))
 | 
						|
 | 
						|
(define (checksum-btree-node b)
 | 
						|
  (checksum-block b (ftype-sizeof unsigned-32) btree-node-salt))
 | 
						|
 | 
						|
(define (classify-nodes cache)
 | 
						|
  (map (lambda (n)
 | 
						|
         (with-block (b cache n (get-flags))
 | 
						|
           (let ((hdr (block->header b))
 | 
						|
                 (csum (checksum-btree-node b)))
 | 
						|
                (cons n
 | 
						|
                      (if (= csum (ftype-ref BTreeNodeHeader (csum) hdr))
 | 
						|
                          (classify-node b hdr)
 | 
						|
                          '())))))
 | 
						|
       (iota (get-nr-blocks cache))))
 | 
						|
 | 
						|
;;; The rmap depends on which class we're assuming
 | 
						|
 | 
						|
(define-syntax detail-ref
 | 
						|
  (syntax-rules ()
 | 
						|
    ((_ ptr field)
 | 
						|
     (ftype-ref ThinDeviceDetails (field) ptr))))
 | 
						|
 | 
						|
(define (dump-device-details cache)
 | 
						|
  (let ((sb (read-superblock cache)))
 | 
						|
   (fmt #t sb)
 | 
						|
   (device-tree-each cache (ftype-ref ThinSuperblock (device-details-root) sb)
 | 
						|
     (lambda (dev-id dd)
 | 
						|
       (fmt #t "dev-id: " dev-id "\n"
 | 
						|
            "mapped-blocks: " (detail-ref dd mapped-blocks) "\n"
 | 
						|
            "transaction-id: " (detail-ref dd transaction-id) "\n"
 | 
						|
            "creation-time: " (detail-ref dd creation-time) "\n"
 | 
						|
            "snappshotted-time: " (detail-ref dd snapshotted-time) "\n")))))
 | 
						|
 | 
						|
(define (dump-rmap rmap)
 | 
						|
  (receive (keys values) (hashtable-entries rmap)
 | 
						|
    (vector-for-each
 | 
						|
      (lambda (k v)
 | 
						|
        (fmt #t k ": " (dsp v) "\n"))
 | 
						|
      keys
 | 
						|
      values)))
 | 
						|
 | 
						|
;; An interesting node has more than one class.
 | 
						|
(define (filter-interesting-blocks classes)
 | 
						|
  (filter (lambda (xs)
 | 
						|
            (>= (length xs) 1))
 | 
						|
          classes))
 | 
						|
 | 
						|
(define (fmt-list xs)
 | 
						|
  (for-each (lambda (x) (fmt #t x nl)) xs))
 | 
						|
 | 
						|
(with-bcache (cache metadata (* 16 1024))
 | 
						|
  (let ((classes (classify-nodes cache))
 | 
						|
        (rmap (make-eq-hashtable)))
 | 
						|
   (fmt-list (filter-interesting-blocks classes))))
 | 
						|
 | 
						|
#|
 | 
						|
(with-bcache (cache metadata (* 16 1024))
 | 
						|
  (let ((sb (read-superblock cache)))
 | 
						|
   (let ((actual-cs (checksum-superblock cache))
 | 
						|
         (disk-cs (ftype-ref ThinSuperblock (csum) sb)))
 | 
						|
        (fmt #t "actual checksum: " actual-cs ", disk checksum: " disk-cs "\n"))))
 | 
						|
|#
 | 
						|
 | 
						|
#|
 | 
						|
(let loop ((i 0)
 | 
						|
           (successes '()))
 | 
						|
 (if (> i nr-metadata-blocks)
 | 
						|
     (fmt #t "successes: " (wrt successes) "\n")
 | 
						|
     ;; add --ignore-non-fatal-errors flag
 | 
						|
     (if (thin-check "../customer-metadata-full.bin" i)
 | 
						|
         (begin
 | 
						|
           (fmt #t "success: " i "\n")
 | 
						|
           (loop (+ i 1) (cons i successes)))
 | 
						|
         (begin
 | 
						|
           (fmt #t "fail: " i "\n")
 | 
						|
           (loop (+ i 1) successes)))))
 | 
						|
|#
 |