[functional-tests] some thin/delete tests
This commit is contained in:
		| @@ -1,4 +1,5 @@ | ||||
| #include <linux/dm-ioctl.h> | ||||
| #include <linux/kdev_t.h> | ||||
| #include <stdbool.h> | ||||
| #include <stdint.h> | ||||
| #include <stdlib.h> | ||||
| @@ -239,7 +240,7 @@ static bool list_devices(struct dm_interface *dmi, struct dm_ioctl *ctl, | ||||
|  | ||||
| 	if (nl->dev) { | ||||
| 		for (;;) { | ||||
| 			dlb_append(&dlb, major(nl->dev), minor(nl->dev), nl->name); | ||||
| 			dlb_append(&dlb, MAJOR(nl->dev), MINOR(nl->dev), nl->name); | ||||
|  | ||||
| 			if (!nl->next) | ||||
| 				break; | ||||
| @@ -273,7 +274,9 @@ int dm_list_devices(struct dm_interface *dmi, struct dev_list **devs) | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| int dm_create_device(struct dm_interface *dmi, const char *name, const char *uuid) | ||||
| // Obviously major and minor are only valid if successful. | ||||
| int dm_create_device(struct dm_interface *dmi, const char *name, const char *uuid, | ||||
| 		     uint32_t *major_result, uint32_t *minor_result) | ||||
| { | ||||
| 	int r; | ||||
| 	struct dm_ioctl *ctl = alloc_ctl(0); | ||||
| @@ -294,8 +297,11 @@ int dm_create_device(struct dm_interface *dmi, const char *name, const char *uui | ||||
| 	} | ||||
|  | ||||
| 	r = ioctl(dmi->fd, DM_DEV_CREATE, ctl); | ||||
| 	if (!r) { | ||||
| 		*major_result = MAJOR(ctl->dev); | ||||
| 		*minor_result = MINOR(ctl->dev); | ||||
| 	} | ||||
| 	free_ctl(ctl); | ||||
|  | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -9,6 +9,7 @@ | ||||
|           (fmt fmt) | ||||
|           (list-utils) | ||||
|           (loops) | ||||
|           (prefix (parser-combinators) p:) | ||||
|           (process) | ||||
|           (srfi s27 random-bits) | ||||
|           (temp-file) | ||||
| @@ -19,6 +20,7 @@ | ||||
|   (define (register-dm-tests) #t) | ||||
|  | ||||
|   ;; FIXME: use memoisation to avoid running blockdev so much | ||||
|   ;; FIXME: return a disk-size, and take a dm-device | ||||
|   (define (get-dev-size dev) | ||||
|     (run-ok-rcv (stdout stderr) (fmt #f "blockdev --getsz " dev) | ||||
|                 (string->number (chomp stdout)))) | ||||
| @@ -113,14 +115,21 @@ | ||||
|                  80 ;; low water mark | ||||
|                  (length opts-str) opts-str))))) | ||||
|  | ||||
|   ;; FIXME: move somewhere else, and do IO in bigger blocks | ||||
|   (define (zero-dev dev size) | ||||
|     (define (dd . args) | ||||
|       (build-command-line (cons "dd" args))) | ||||
|   (define (dd-cmd . args) | ||||
|     (build-command-line (cons "dd" args))) | ||||
|  | ||||
|     (run-ok (dd "if=/dev/zero" | ||||
|                 (string-append "of=" (dm-device-path dev)) | ||||
|                 "bs=512" (fmt #f "count=" (to-sectors size))))) | ||||
|   ;; FIXME: move somewhere else, and do IO in bigger blocks | ||||
|   (define zero-dev | ||||
|     (case-lambda | ||||
|       ((dev) | ||||
|        (zero-dev dev | ||||
|                  (sectors | ||||
|                    (get-dev-size | ||||
|                      (dm-device-path dev))))) | ||||
|       ((dev size) | ||||
|        (run-ok (dd-cmd "if=/dev/zero" | ||||
|                        (string-append "of=" (dm-device-path dev)) | ||||
|                        "bs=512" (fmt #f "count=" (to-sectors size))))))) | ||||
|  | ||||
|   ;; The contents should be | ||||
|   (define (with-ini-file-fn section contents fn) | ||||
| @@ -173,6 +182,14 @@ | ||||
|                      block-size | ||||
|                      (lambda (pool) b1 b2 ...))))) | ||||
|  | ||||
|   (define-syntax with-default-pool | ||||
|     (syntax-rules () | ||||
|       ((_ (pool) b1 b2 ...) | ||||
|        (with-pool (pool (default-md-table) | ||||
|                         (default-data-table (gig 10)) | ||||
|                         (kilo 64)) | ||||
|                   b1 b2 ...)))) | ||||
|  | ||||
|   (define (default-md-table) | ||||
|     (list ((mk-fast-allocator) (meg 32)))) | ||||
|  | ||||
| @@ -198,6 +215,9 @@ | ||||
|   (define (create-snap pool new-id origin-id) | ||||
|     (message pool 0 (fmt #f "create_snap " new-id " " origin-id))) | ||||
|  | ||||
|   (define (delete-thin pool id) | ||||
|     (message pool 0 (fmt #f "delete " id))) | ||||
|  | ||||
|   (define (with-thin-fn pool id size fn) | ||||
|     (with-device-fn (generate-dev-name) "" (thin-table pool id size) fn)) | ||||
|  | ||||
| @@ -216,6 +236,135 @@ | ||||
|        (with-new-thin-fn pool id size (lambda (thin) | ||||
|                                         b1 b2 ...))))) | ||||
|  | ||||
|   ;;;----------------------------------------------------------- | ||||
|   ;;; Pool status | ||||
|   ;;;----------------------------------------------------------- | ||||
|   (define-record-type pool-status | ||||
|     (fields (mutable transaction-id) | ||||
|             (mutable used-metadata) | ||||
|             (mutable total-metadata) | ||||
|             (mutable used-data) | ||||
|             (mutable total-data) | ||||
|             (mutable held-root)          ; (bool . root?) | ||||
|             (mutable needs-check)        ; bool | ||||
|             (mutable discard)            ; bool | ||||
|             (mutable discard-passdown)   ; bool | ||||
|             (mutable block-zeroing)      ; bool | ||||
|             (mutable io-mode)            ; 'out-of-data-space, 'ro, 'rw | ||||
|             (mutable no-space-behaviour) ; 'error, 'queue | ||||
|             (mutable fail)               ; bool | ||||
|             )) | ||||
|  | ||||
|   (define (default-pool-status) | ||||
|     (make-pool-status 0  ; trans id | ||||
|                       0  ; used md | ||||
|                       0  ; total md | ||||
|                       0  ; used data | ||||
|                       0  ; total data | ||||
|                       (cons #f 0)  ; held root | ||||
|                       #f  ; need check | ||||
|                       #t  ; discard | ||||
|                       #t  ; discard passdown | ||||
|                       #t  ; block zeroing | ||||
|                       'rw  ; io-mode | ||||
|                       'queue  ; no space behaviour | ||||
|                       #f  ; fail | ||||
|                       )) | ||||
|  | ||||
|   (define digit (p:charset "0123456789")) | ||||
|  | ||||
|   (define number | ||||
|     (p:lift (lambda (cs) | ||||
|               (string->number | ||||
|                 (apply string cs))) | ||||
|             (p:many+ digit))) | ||||
|  | ||||
|   (define held-root | ||||
|     (p:alt | ||||
|       (p:>> (p:lit "-") | ||||
|             (p:pure (cons #f 0))) | ||||
|       (p:parse-m (p:<- root number) | ||||
|                  (p:pure (cons #t root))))) | ||||
|  | ||||
|   (define space | ||||
|     (p:many+ (p:charset " \t"))) | ||||
|  | ||||
|   (define slash | ||||
|     (p:lit "/")) | ||||
|  | ||||
|   ;; The options parser returns a function that mutates the status. | ||||
|   (define-syntax opt-mut | ||||
|     (syntax-rules () | ||||
|       ((_ (status txt) b1 b2 ...) | ||||
|        (p:>> (p:lit txt) | ||||
|              (p:pure (lambda (status) b1 b2 ...)))))) | ||||
|  | ||||
|   (define pool-option | ||||
|     (p:one-of | ||||
|       (opt-mut (status "skip_block_zeroing") | ||||
|         (pool-status-block-zeroing-set! status #f)) | ||||
|  | ||||
|       (opt-mut (status "ignore_discard") | ||||
|         (pool-status-discard-set! status #f)) | ||||
|  | ||||
|       (opt-mut (status "no_discard_passdown") | ||||
|         (pool-status-discard-passdown-set! status #f)) | ||||
|  | ||||
|       (opt-mut (status "discard_passdown") | ||||
|         (pool-status-discard-passdown-set! status #t)) | ||||
|  | ||||
|       (opt-mut (status "out_of_data_space") | ||||
|         (pool-status-io-mode-set! status 'out-of-data-space)) | ||||
|  | ||||
|       (opt-mut (status "ro") | ||||
|         (pool-status-io-mode-set! status 'ro)) | ||||
|  | ||||
|       (opt-mut (status "rw") | ||||
|         (pool-status-io-mode-set! status 'rw)) | ||||
|  | ||||
|       (opt-mut (status "error_if_no_space") | ||||
|         (pool-status-no-space-behaviour-set! status 'error)) | ||||
|  | ||||
|       (opt-mut (status "queue_if_no_space") | ||||
|         (pool-status-no-space-behaviour-set! status 'queue)))) | ||||
|  | ||||
|   (define needs-check | ||||
|     (p:one-of | ||||
|       (p:>> (p:lit "needs_check") | ||||
|             (p:pure #t)) | ||||
|       (p:pure #f))) | ||||
|  | ||||
|   (define (parse-pool-status txt) | ||||
|     (p:parse-m (p:<- transaction-id number) | ||||
|                space | ||||
|                (p:<- used-metadata number) | ||||
|                slash | ||||
|                (p:<- total-metadata number) | ||||
|                space | ||||
|                (p:<- used-data number) | ||||
|                slash | ||||
|                (p:<- total-data number) | ||||
|                space | ||||
|                (p:<- metadata-snap held-root) | ||||
|                space | ||||
|                (p:<- options (p:many* (p:<* pool-option space))) | ||||
|                (p:<- check needs-check) | ||||
|  | ||||
|                (let ((status (default-pool-status))) | ||||
|                 (pool-status-transaction-id-set! status transaction-id) | ||||
|                 (pool-status-used-metadata-set! status used-metadata) | ||||
|                 (pool-status-total-metadata-set! status total-metadata) | ||||
|                 (pool-status-used-data-set! status used-data) | ||||
|                 (pool-status-total-data-set! status total-data) | ||||
|                 (pool-status-held-root-set! status metadata-snap) | ||||
|                 (pool-status-needs-check-set! status check) | ||||
|                 (for-each (lambda (mut) (mut status)) options) | ||||
|                 (p:pure status)))) | ||||
|  | ||||
|   (define (get-pool-status pool) | ||||
|     (p:parse-value parse-pool-status | ||||
|       (get-status pool))) | ||||
|  | ||||
|   ;;;----------------------------------------------------------- | ||||
|   ;;; Fundamental dm scenarios | ||||
|   ;;;----------------------------------------------------------- | ||||
| @@ -279,7 +428,7 @@ | ||||
|     (let ((pv (mk-fast-allocator))) | ||||
|      (with-devices ((dev1 "foo" "uuid" (linear-table pv 4)) | ||||
|                     (dev2 "bar" "uuid2" (linear-table pv 4))) | ||||
|                    (let ((names (map device-details-name (list-devices)))) | ||||
|                    (let ((names (map dm-device-name (list-devices)))) | ||||
|                     (assert-member? "foo" names) | ||||
|                     (assert-member? "bar" names))))) | ||||
|  | ||||
| @@ -385,17 +534,13 @@ | ||||
|  | ||||
|   (define-dm-scenario (thin create too-large-thin-dev-fails) | ||||
|     "The thin-id must be less 2^24" | ||||
|     (with-pool (pool (default-md-table) | ||||
|                      (default-data-table (gig 10)) | ||||
|                      (kilo 64)) | ||||
|     (with-default-pool (pool) | ||||
|       (assert-raises | ||||
|         (create-thin pool (expt 2 24))))) | ||||
|  | ||||
|   (define-dm-scenario (thin create largest-thin-dev-succeeds) | ||||
|     "The thin-id must be less 2^24" | ||||
|     (with-pool (pool (default-md-table) | ||||
|                      (default-data-table (gig 10)) | ||||
|                      (kilo 64)) | ||||
|     (with-default-pool (pool) | ||||
|       (create-thin pool (- (expt 2 24) 1)))) | ||||
|  | ||||
|   (define-dm-scenario (thin create too-small-metadata-fails) | ||||
| @@ -405,5 +550,56 @@ | ||||
|                        (default-data-table (gig 10)) | ||||
|                        (kilo 64)) | ||||
|                  #t))) | ||||
|  | ||||
|   ;;;----------------------------------------------------------- | ||||
|   ;;; Thin deletion scenarios | ||||
|   ;;;----------------------------------------------------------- | ||||
|   (define-dm-scenario (thin delete create-delete-cycle) | ||||
|     "Create and delete a thin 1000 times" | ||||
|     (with-default-pool (pool) | ||||
|       (upto (n 1000) | ||||
|             (create-thin pool 0) | ||||
|             (delete-thin pool 0)))) | ||||
|  | ||||
|   (define-dm-scenario (thin delete create-delete-many) | ||||
|     "Create and delete 1000 thins" | ||||
|     (with-default-pool (pool) | ||||
|       (upto (n 1000) | ||||
|             (create-thin pool n)) | ||||
|       (upto (n 1000) | ||||
|             (delete-thin pool n)))) | ||||
|  | ||||
|   (define-dm-scenario (thin delete rolling-create-delete) | ||||
|     "Create and delete 1000 thins" | ||||
|     (with-default-pool (pool) | ||||
|       (upto (n 1000) | ||||
|             (create-thin pool n)) | ||||
|       (upto (n 1000) | ||||
|             (delete-thin pool n) | ||||
|             (create-thin pool n)))) | ||||
|  | ||||
|   (define-dm-scenario (thin delete unknown-id) | ||||
|     "Fails if the thin id is unknown" | ||||
|     (with-default-pool (pool) | ||||
|       (upto (n 100) | ||||
|             (create-thin pool (* n 100))) | ||||
|       (assert-raises | ||||
|         (delete-thin pool 57)))) | ||||
|  | ||||
|   (define-dm-scenario (thin delete active-device-fails) | ||||
|     "You can't delete an active device" | ||||
|     (with-default-pool (pool) | ||||
|       (with-new-thin (thin pool 0 (gig 1)) | ||||
|         (assert-raises | ||||
|           (delete-thin pool 0))))) | ||||
|  | ||||
|   #| | ||||
|   (define-dm-scenario (thin delete recover-space) | ||||
|     "Deleting a thin recovers data space" | ||||
|     (with-default-pool (pool) | ||||
|       (with-new-thin (thin pool 0 (gig 1)) | ||||
|         ;(zero-dev thin) | ||||
|         (fmt #t (get-pool-status pool))))) | ||||
|   |# | ||||
| ) | ||||
|  | ||||
|   | ||||
| @@ -9,6 +9,8 @@ | ||||
|           dm-device | ||||
|           dm-device-name | ||||
|           dm-device-path | ||||
|           dm-device-minor | ||||
|           dm-device-major | ||||
|  | ||||
|           dm-version | ||||
|           get-version | ||||
| @@ -37,11 +39,6 @@ | ||||
|           pause-device | ||||
|           pause-device-thunk | ||||
|  | ||||
|           device-details | ||||
|           device-details-name | ||||
|           device-details-major | ||||
|           device-details-minor | ||||
|  | ||||
|           get-status | ||||
|           get-table | ||||
|  | ||||
| @@ -64,10 +61,10 @@ | ||||
|     (struct | ||||
|       (fd int))) | ||||
|  | ||||
|   (define-record-type dm-device (fields (mutable name))) | ||||
|   (define-record-type dm-device (fields name major minor)) | ||||
|  | ||||
|   (define (dm-device-path d) | ||||
|     (fmt #f (dsp "/dev/mapper/") (dsp (dm-device-name d)))) | ||||
|     (fmt #f (dsp "/dev/dm-") (dsp (dm-device-minor d)))) | ||||
|  | ||||
|   (define open% (foreign-procedure "dm_open" () (* DMIoctlInterface))) | ||||
|  | ||||
| @@ -100,6 +97,17 @@ | ||||
|  | ||||
|   (define-record-type dm-version (fields major minor patch)) | ||||
|  | ||||
|   (define (alloc-u32) | ||||
|     (make-ftype-pointer unsigned-32 | ||||
|                         (foreign-alloc (ftype-sizeof unsigned-32)))) | ||||
|  | ||||
|   (define (deref-u32 p) | ||||
|     (ftype-ref unsigned-32 () p)) | ||||
|  | ||||
|   (define (free-u32 p) | ||||
|     (foreign-free (ftype-pointer-address p))) | ||||
|  | ||||
|   ;; FIXME: make a with-u32s macro | ||||
|   (define (get-version) | ||||
|     (define get | ||||
|       (foreign-procedure "dm_version" ((* DMIoctlInterface) | ||||
| @@ -107,25 +115,22 @@ | ||||
|                                        (* unsigned-32) | ||||
|                                        (* unsigned-32)) int)) | ||||
|  | ||||
|     (define (alloc-u32) | ||||
|       (make-ftype-pointer unsigned-32 | ||||
|         (foreign-alloc (ftype-sizeof unsigned-32)))) | ||||
|  | ||||
|     (define (deref-u32 p) | ||||
|       (ftype-ref unsigned-32 () p)) | ||||
|  | ||||
|     (let ((major (alloc-u32)) | ||||
|           (minor (alloc-u32)) | ||||
|           (patch (alloc-u32))) | ||||
|       (if (zero? (get (current-dm-interface) major minor patch)) | ||||
|           (let ((r (make-dm-version (deref-u32 major) | ||||
|                                     (deref-u32 minor) | ||||
|                                     (deref-u32 patch)))) | ||||
|             (foreign-free (ftype-pointer-address major)) | ||||
|             (foreign-free (ftype-pointer-address minor)) | ||||
|             (foreign-free (ftype-pointer-address patch)) | ||||
|             r) | ||||
|           (fail "couldn't get dm version")))) | ||||
|          (dynamic-wind | ||||
|            (lambda () #f) | ||||
|            (lambda () | ||||
|              (if (zero? (get (current-dm-interface) major minor patch)) | ||||
|                  (let ((r (make-dm-version (deref-u32 major) | ||||
|                                            (deref-u32 minor) | ||||
|                                            (deref-u32 patch)))) | ||||
|                       r) | ||||
|                  (fail "couldn't get dm version"))) | ||||
|            (lambda () | ||||
|              (free-u32 major) | ||||
|              (free-u32 minor) | ||||
|              (free-u32 patch))))) | ||||
|  | ||||
|   (define (remove-all) | ||||
|     (define do-it | ||||
| @@ -144,9 +149,6 @@ | ||||
|  | ||||
|   (define-ftype DevListPtr (* DevList)) | ||||
|  | ||||
|   (define-record-type device-details | ||||
|     (fields name major minor)) | ||||
|  | ||||
|   (define (cstring->string str) | ||||
|     (let loop ((i 0) | ||||
|                (acc '())) | ||||
| @@ -182,7 +184,7 @@ | ||||
|             (if (ftype-pointer-null? dl) | ||||
|                 acc | ||||
|                 (loop (ftype-ref DevList (next) dl) | ||||
|                       (cons (make-device-details | ||||
|                       (cons (make-dm-device | ||||
|                               (cstring->string (ftype-ref DevList (name) dl)) | ||||
|                               (ftype-ref DevList (major) dl) | ||||
|                               (ftype-ref DevList (minor) dl)) | ||||
| @@ -191,11 +193,19 @@ | ||||
|  | ||||
|   (define (create-device name uuid) | ||||
|     (define create | ||||
|       (foreign-procedure "dm_create_device" ((* DMIoctlInterface) string string) int)) | ||||
|       (foreign-procedure "dm_create_device" ((* DMIoctlInterface) string string (* unsigned-32) (* unsigned-32)) int)) | ||||
|  | ||||
|     (if (zero? (create (current-dm-interface) name uuid)) | ||||
|         (make-dm-device name) | ||||
|         (fail "create-device failed"))) | ||||
|     (let* ((major (alloc-u32)) | ||||
|            (minor (alloc-u32))) | ||||
|           (dynamic-wind | ||||
|             (lambda () #f) | ||||
|             (lambda () | ||||
|               (if (zero? (create (current-dm-interface) name uuid major minor)) | ||||
|                   (make-dm-device name (deref-u32 major) (deref-u32 minor)) | ||||
|                   (fail "create-device failed"))) | ||||
|             (lambda () | ||||
|               (free-u32 major) | ||||
|               (free-u32 minor))))) | ||||
|  | ||||
|   (define-syntax define-dev-cmd | ||||
|     (syntax-rules () | ||||
|   | ||||
		Reference in New Issue
	
	Block a user