(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))))) |#