[functional-tests] some thin/delete tests
This commit is contained in:
parent
93213135ad
commit
2db8ecf9e9
@ -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 ()
|
||||
|
Loading…
Reference in New Issue
Block a user