diff options
-rwxr-xr-x | old-school/grok-block | 4 | ||||
-rw-r--r-- | old-school/mdadm-dup.sh | 165 |
2 files changed, 168 insertions, 1 deletions
diff --git a/old-school/grok-block b/old-school/grok-block index 62b063f..3f61c4a 100755 --- a/old-school/grok-block +++ b/old-school/grok-block | |||
@@ -172,7 +172,9 @@ then | |||
172 | # Recognize and mount the Samizdat | 172 | # Recognize and mount the Samizdat |
173 | if ! mountpoint -q /cdrom; then | 173 | if ! mountpoint -q /cdrom; then |
174 | mkdir -p /cdrom | 174 | mkdir -p /cdrom |
175 | (retry_mount -t iso9660 -r "$DEVNAME" /cdrom && bootdone samizdat-cdrom) & | 175 | . mdadm-dup.sh |
176 | mount_cdrom "$DEVNAME" && bootdone samizdat-cdrom | ||
177 | # (retry_mount -t iso9660 -r "$DEVNAME" /cdrom && bootdone samizdat-cdrom) & | ||
176 | fi | 178 | fi |
177 | else | 179 | else |
178 | grok_block & | 180 | grok_block & |
diff --git a/old-school/mdadm-dup.sh b/old-school/mdadm-dup.sh new file mode 100644 index 0000000..27a39ca --- /dev/null +++ b/old-school/mdadm-dup.sh | |||
@@ -0,0 +1,165 @@ | |||
1 | dm_snapshot() | ||
2 | { | ||
3 | # TODO: eliminate duplication; this function exists elsewhere in a less generalized form | ||
4 | local ro_file rw_file cutoff_size | ||
5 | ro_file=$1 | ||
6 | rw_file=$2 | ||
7 | cutoff_size=$3 | ||
8 | |||
9 | local ro_dev rw_dev size new_dev_name persist chunksize | ||
10 | |||
11 | if [ -b "$ro_file" ]; | ||
12 | then ro_dev=$ro_file | ||
13 | else ro_dev=$(LoSetup -r -f --show "$ro_file") || return | ||
14 | fi | ||
15 | |||
16 | if [ -b "$rw_file" ]; | ||
17 | then rw_dev=$rw_file | ||
18 | else rw_dev=$(LoSetup -f --show "$rw_file") || return | ||
19 | fi | ||
20 | |||
21 | if [ "$cutoff_size" -a "$cutoff_size" -gt 0 ]; then | ||
22 | size=$cutoff_size | ||
23 | else | ||
24 | size=$(blockdev --getsz "$ro_dev") || return | ||
25 | fi | ||
26 | |||
27 | new_dev_name=${ro_dev##*/} | ||
28 | persist=p | ||
29 | chunksize=16 | ||
30 | dmsetup create "$new_dev_name" --table "0 $size snapshot $ro_dev $rw_dev $persist $chunksize" || return | ||
31 | wait_for_dm_device /dev/mapper/"$new_dev_name"; | ||
32 | echo /dev/mapper/"$new_dev_name" | ||
33 | } | ||
34 | |||
35 | dm_snapshot_teardown() | ||
36 | { | ||
37 | local dev="$1" | ||
38 | case "$dev" in | ||
39 | /dev/dm-*) | ||
40 | dmsetup table "$dev" | ( | ||
41 | read _ _ snapshot ro_dev rw_dev _ _ | ||
42 | [ "$snapshot" = snapshot ] || exit 1 | ||
43 | dmsetup remove "$dev" || exit 1 | ||
44 | # errors ignored because the loop dev can be automatically removed upon disuse already | ||
45 | losetup -d /dev/block/"$rw_dev" || true | ||
46 | eject /dev/block/"$ro_dev" || exit 1 | ||
47 | ) || return | ||
48 | ;; | ||
49 | *) return 1 ;; | ||
50 | esac | ||
51 | } | ||
52 | |||
53 | wait_for_dm_device() | ||
54 | { | ||
55 | # TODO: improve | ||
56 | while ! [ -e "$1" ]; do | ||
57 | sleep 1 | ||
58 | done | ||
59 | } | ||
60 | |||
61 | mount_cdrom() | ||
62 | { | ||
63 | local cdrom_dev="$1" | ||
64 | |||
65 | local sectors md_dev=/dev/md0 cdrom_rw_file=/"${cdrom_dev##*/}".rw | ||
66 | |||
67 | sectors=$(get_cdrom_sizelimit "$cdrom_dev") || return | ||
68 | |||
69 | # TODO: do we even need this backing file? We do need to trick mdadm into | ||
70 | # thinking that this is a RW device, but previously we got away with just | ||
71 | # creating a loopback device. | ||
72 | dd if=/dev/zero of="$cdrom_rw_file" bs=1K count=32 || return | ||
73 | cdrom_rw_dev=$(dm_snapshot "$cdrom_dev" "$cdrom_rw_file" "$sectors") || return | ||
74 | mdadm_dup "$cdrom_rw_dev" "$md_dev" "$sectors" || return | ||
75 | mount -t iso9660 -r $md_dev /cdrom | ||
76 | } | ||
77 | |||
78 | get_cdrom_sizelimit() | ||
79 | { | ||
80 | # returns 512-byte sectors | ||
81 | local dev="$1" sectors | ||
82 | sectors=$(blockdev --getsz "$dev") || return | ||
83 | |||
84 | # Check if we can read the last 8 sectors. With a TAO CDROM, we can't -- | ||
85 | # these sectors are faux, and not part of the ISO fs. If mdadm is allowed to | ||
86 | # read them, it will mark the device failed. | ||
87 | if dd count=2 if="$dev" bs=2048 skip=$((sectors/4 - 2)) of=/dev/null 2>/dev/null; then | ||
88 | echo $sectors | ||
89 | else | ||
90 | echo $((sectors - 8)) | ||
91 | fi | ||
92 | } | ||
93 | |||
94 | mdadm_dup() | ||
95 | { | ||
96 | local input_dev="$1" md_name="$2" sectors="$3" | ||
97 | |||
98 | mdadm --build $md_name ${sectors:+--size=$((sectors / 2))} \ | ||
99 | --level=1 --raid-devices=1 --force --write-mostly "$input_dev" || return | ||
100 | } | ||
101 | |||
102 | |||
103 | mdadm_subdevices() | ||
104 | { | ||
105 | local md_dev="$1" | ||
106 | mdadm -D "$md_dev" -Y | sed -ne 's/MD_DEVICE_.*_DEV=//p' | ||
107 | } | ||
108 | |||
109 | Mdadm() | ||
110 | { | ||
111 | mdadm "$@" | ||
112 | # r=$? | ||
113 | # mdadm -D "$1" | ||
114 | # sleep 2 | ||
115 | # return $r | ||
116 | } | ||
117 | |||
118 | mdadm_copy_eject() # NOT INITRD; uses non-busybox "losetup" | ||
119 | { | ||
120 | local md_dev="$1" output_file="$2" | ||
121 | |||
122 | [ -b "$md_dev" ] || return | ||
123 | [ ! -e "$output_file" ] || return | ||
124 | |||
125 | local output_dev sectors | ||
126 | |||
127 | old_subdev=$(mdadm_subdevices "$md_dev"|head -n1) || return | ||
128 | [ -b "$old_subdev" ] || return | ||
129 | sectors=$(blockdev --getsz "$md_dev") || return | ||
130 | |||
131 | truncate -s $((sectors * 512)) "$output_file" || return | ||
132 | output_dev=$(losetup -f --show "$output_file") || return | ||
133 | |||
134 | Mdadm "$md_dev" --add "$output_dev" || return | ||
135 | Mdadm "$md_dev" --grow -n2 || return | ||
136 | |||
137 | mdadm_wait_remove "$md_dev" "$old_subdev" || return | ||
138 | |||
139 | Mdadm "$md_dev" --grow -n1 --force || return | ||
140 | dm_snapshot_teardown "$old_subdev" | ||
141 | } | ||
142 | |||
143 | mdadm_wait_remove() | ||
144 | { | ||
145 | # We should perhaps use mdadm --monitor's RebuildFinished event. | ||
146 | |||
147 | local dev="$1" disk="$2" tries | ||
148 | if ! mdadm --wait "$dev"; then | ||
149 | tries=1000 | ||
150 | while ! mdadm --detail --test "$dev"; do | ||
151 | [ $tries -gt 0 ] || return 1 | ||
152 | sleep 1 | ||
153 | tries=$((tries-1)) | ||
154 | done | ||
155 | fi | ||
156 | |||
157 | mdadm "$dev" --fail "$disk" || return 1 | ||
158 | tries=100 | ||
159 | while ! mdadm "$dev" --remove "$disk"; do | ||
160 | [ $tries -gt 0 ] || return 1 | ||
161 | sleep 1 | ||
162 | tries=$((tries-1)) | ||
163 | done | ||
164 | return 0 | ||
165 | } | ||