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