| 1 | #!/usr/bin/env bash |
| 2 | # |
| 3 | # Copyright (C) 2009 Red Hat, Inc. |
| 4 | # |
| 5 | # This program is free software; you can redistribute it and/or modify |
| 6 | # it under the terms of the GNU General Public License as published by |
| 7 | # the Free Software Foundation; either version 2 of the License, or |
| 8 | # (at your option) any later version. |
| 9 | # |
| 10 | # This program is distributed in the hope that it will be useful, |
| 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | # GNU General Public License for more details. |
| 14 | # |
| 15 | # You should have received a copy of the GNU General Public License |
| 16 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 17 | # |
| 18 | |
| 19 | do_is_allocated() { |
| 20 | local start=$1 |
| 21 | local size=$2 |
| 22 | local step=$3 |
| 23 | local count=$4 |
| 24 | |
| 25 | for ((i=1;i<=$count;i++)); do |
| 26 | echo "alloc $(( start + (i - 1) * step )) $size" |
| 27 | done |
| 28 | } |
| 29 | |
| 30 | is_allocated() { |
| 31 | do_is_allocated "$@" | $QEMU_IO "$TEST_IMG" | _filter_qemu_io |
| 32 | } |
| 33 | |
| 34 | do_io() { |
| 35 | local op=$1 |
| 36 | local start=$2 |
| 37 | local size=$3 |
| 38 | local step=$4 |
| 39 | local count=$5 |
| 40 | local pattern=$6 |
| 41 | |
| 42 | echo "=== IO: pattern $pattern" >&2 |
| 43 | for ((i=1;i<=$count;i++)); do |
| 44 | echo "$op -P $pattern $(( start + (i - 1) * step )) $size" |
| 45 | done |
| 46 | } |
| 47 | |
| 48 | io_pattern() { |
| 49 | do_io "$@" | $QEMU_IO "$TEST_IMG" | _filter_qemu_io |
| 50 | } |
| 51 | |
| 52 | io() { |
| 53 | local start=$2 |
| 54 | local pattern=$(( (start >> 9) % 256 )) |
| 55 | |
| 56 | do_io "$@" $pattern | $QEMU_IO "$TEST_IMG" | _filter_qemu_io |
| 57 | } |
| 58 | |
| 59 | io_zero() { |
| 60 | do_io "$@" 0 | $QEMU_IO "$TEST_IMG" | _filter_qemu_io |
| 61 | } |
| 62 | |
| 63 | io_test() { |
| 64 | local op=$1 |
| 65 | local offset=$2 |
| 66 | local cluster_size=$3 |
| 67 | |
| 68 | local num_large=$4 |
| 69 | local num_medium=$((num_large * num_large)) |
| 70 | local num_small=$((4 * num_medium)) |
| 71 | |
| 72 | local half_cluster=$((cluster_size / 2)) |
| 73 | local quarter_cluster=$((cluster_size / 4)) |
| 74 | local l2_size=$((cluster_size * cluster_size / 8)) |
| 75 | |
| 76 | # Complete clusters |
| 77 | io "$op" $offset $cluster_size $cluster_size $num_small |
| 78 | offset=$((offset + num_small * $cluster_size)) |
| 79 | |
| 80 | # From somewhere in the middle to the end of a cluster |
| 81 | io "$op" $((offset + $half_cluster)) $half_cluster $cluster_size $num_small |
| 82 | offset=$((offset + num_small * $cluster_size)) |
| 83 | |
| 84 | # From the start to somewhere in the middle of a cluster |
| 85 | io "$op" $offset $half_cluster $cluster_size $num_small |
| 86 | offset=$((offset + num_small * $cluster_size)) |
| 87 | |
| 88 | # Completely misaligned (and small) |
| 89 | io "$op" $((offset + $quarter_cluster)) $half_cluster $cluster_size $num_small |
| 90 | offset=$((offset + num_small * $cluster_size)) |
| 91 | |
| 92 | # Spanning multiple clusters |
| 93 | io "$op" $((offset + $half_cluster)) $((cluster_size * 2)) $((cluster_size * 3)) $num_medium |
| 94 | offset=$((offset + num_medium * 3 * $cluster_size)) |
| 95 | |
| 96 | # Spanning multiple L2 tables |
| 97 | # L2 table size: 512 clusters of 4k = 2M |
| 98 | offset=$(( ((offset + l2_size - 1) & ~(l2_size - 1)) - (3 * half_cluster) )) |
| 99 | io "$op" $offset $((6 * half_cluster)) $(( l2_size + half_cluster )) $num_large |
| 100 | offset=$((offset + num_large * ( l2_size + half_cluster ))) |
| 101 | } |
| 102 | |
| 103 | io_test2() { |
| 104 | local orig_offset=$1 |
| 105 | local cluster_size=$2 |
| 106 | local num=$3 |
| 107 | |
| 108 | # Pattern (repeat after 9 clusters): |
| 109 | # used - used - free - used - compressed - compressed - |
| 110 | # free - free - compressed |
| 111 | |
| 112 | # Write the clusters to be compressed |
| 113 | echo '=== Clusters to be compressed [1]' |
| 114 | io_pattern writev $((offset + 4 * $cluster_size)) $cluster_size $((9 * $cluster_size)) $num 165 |
| 115 | echo '=== Clusters to be compressed [2]' |
| 116 | io_pattern writev $((offset + 5 * $cluster_size)) $cluster_size $((9 * $cluster_size)) $num 165 |
| 117 | echo '=== Clusters to be compressed [3]' |
| 118 | io_pattern writev $((offset + 8 * $cluster_size)) $cluster_size $((9 * $cluster_size)) $num 165 |
| 119 | |
| 120 | mv "$TEST_IMG" "$TEST_IMG.orig" |
| 121 | $QEMU_IMG convert -f $IMGFMT -O $IMGFMT -c "$TEST_IMG.orig" "$TEST_IMG" |
| 122 | |
| 123 | # Write the used clusters |
| 124 | echo '=== Used clusters [1]' |
| 125 | io_pattern writev $((offset + 0 * $cluster_size)) $cluster_size $((9 * $cluster_size)) $num 165 |
| 126 | echo '=== Used clusters [2]' |
| 127 | io_pattern writev $((offset + 1 * $cluster_size)) $cluster_size $((9 * $cluster_size)) $num 165 |
| 128 | echo '=== Used clusters [3]' |
| 129 | io_pattern writev $((offset + 3 * $cluster_size)) $cluster_size $((9 * $cluster_size)) $num 165 |
| 130 | |
| 131 | # Read them |
| 132 | echo '=== Read used/compressed clusters' |
| 133 | io_pattern readv $((offset + 0 * $cluster_size)) $((2 * $cluster_size)) $((9 * $cluster_size)) $num 165 |
| 134 | io_pattern readv $((offset + 3 * $cluster_size)) $((3 * $cluster_size)) $((9 * $cluster_size)) $num 165 |
| 135 | io_pattern readv $((offset + 8 * $cluster_size)) $((1 * $cluster_size)) $((9 * $cluster_size)) $num 165 |
| 136 | |
| 137 | echo '=== Read zeros' |
| 138 | io_zero readv $((offset + 2 * $cluster_size)) $((1 * $cluster_size)) $((9 * $cluster_size)) $num |
| 139 | io_zero readv $((offset + 6 * $cluster_size)) $((2 * $cluster_size)) $((9 * $cluster_size)) $num |
| 140 | } |