Merge ~jibel/ubiquity:zfs_fixes into ubiquity:master

Proposed by Jean-Baptiste Lallement
Status: Merged
Merged at revision: 3d62cb23e755f1afbb5f8027edf441b23799eb8c
Proposed branch: ~jibel/ubiquity:zfs_fixes
Merge into: ubiquity:master
Diff against target: 461 lines (+240/-90)
4 files modified
debian/changelog (+13/-3)
debian/ubiquity.templates (+5/-0)
scripts/zsys-setup (+181/-86)
ubiquity/plugins/ubi-partman.py (+41/-1)
Reviewer Review Type Date Requested Status
Didier Roche-Tolomelli (community) Approve
Review via email: mp+375238@code.launchpad.net

Commit message

Various fixes from experiment:
  - Use version 5000 for bpool with some features disabled to stay compatible with grub and prevent users from upgrading and breaking their systems.
  - The partman confirmation dialog now displays the final layout of the partition that will be created instead of the true but confusing message from partman telling that an ext4 partition will be created (LP: #1847719)
  - Calculate the size of bpool to be 500M < 5% partition size < 2G
  - Always create an ESP and moved grub to the ESP.

To post a comment you must log in.
Revision history for this message
Didier Roche-Tolomelli (didrocks) wrote :

I didn't test yet as we are going to have some iterations. Here are mostly nitpick, good work :)

Revision history for this message
Jean-Baptiste Lallement (jibel) wrote :

Thanks fir the review. Comments addressed.

Revision history for this message
Didier Roche-Tolomelli (didrocks) wrote :

- one more comment on the new changes
- still 2 pending on previous diff

Revision history for this message
Jean-Baptiste Lallement (jibel) :
Revision history for this message
Didier Roche-Tolomelli (didrocks) wrote :

LGTM! I didn't give it a try yet, but I didn't spot anything more. Just 2 notes:
- Is having predictable names in /tmp is a security issue? I remember we removed from flag filenames in the past due to this.
- Did you have a look at our latest exchanges with Richard (the ones before the 19.10 release) to ensure we address all of his remarks?

Ack (pending testing)

Revision history for this message
Didier Roche-Tolomelli (didrocks) wrote :

Did a test-run without UEFI enabled, and working well for me.

Revision history for this message
Jean-Baptiste Lallement (jibel) wrote :

I reviewed the comments from Richard in the spec and latest email exchanges and apparently they've all been addressed.

About the temporary directory in /tmp we could pass an additional argument to the script, but it's called from completely different scopes: from ubiquity itself (ubi-partman and gtk_ui) and from a subprocess, it would add lot of complexity for share the name of the temporary directory between these scopes. Passing it in the environment wouldn't improve the security either. At best we could umask the directory so it can only be accessed by root.

Revision history for this message
Didier Roche-Tolomelli (didrocks) wrote :

+1 for me then :)

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/debian/changelog b/debian/changelog
2index 8a152ab..9ba61ce 100644
3--- a/debian/changelog
4+++ b/debian/changelog
5@@ -1,8 +1,18 @@
6 ubiquity (20.04.1) UNRELEASED; urgency=medium
7
8- * script/zsys-setup: fix tag name from org.zsys to com.ubuntu.zsys.
9- * Added an advanced features dialog to the partitioning page. LVM, LVM with
10- encryption and experimental ZFS support have been moved to this dialog.
11+ * zfs:
12+ - Added an advanced features dialog to the partitioning page. LVM, LVM
13+ with encryption and experimental ZFS support have been moved to this
14+ dialog.
15+ - Fix tag name from org.zsys to com.ubuntu.zsys.
16+ - Use version 5000 for bpool with some features disabled to stay
17+ compatible with grub and prevent users from upgrading and breaking their
18+ systems.
19+ - The partman confirmation dialog now displays the final layout of the
20+ partition that will be created instead of the true but confusing message
21+ from partman telling that an ext4 partition will be created (LP: #1847719)
22+ - Calculate the size of bpool to be 500M < 5% partition size < 2G
23+ - Always create an ESP and moved grub to the ESP.
24
25 -- Jean-Baptiste Lallement <jean-baptiste.lallement@ubuntu.com> Mon, 28 Oct 2019 09:07:57 +0100
26
27diff --git a/debian/ubiquity.templates b/debian/ubiquity.templates
28index f56ac69..4342a2a 100644
29--- a/debian/ubiquity.templates
30+++ b/debian/ubiquity.templates
31@@ -1597,3 +1597,8 @@ _Description:
32 Template: ubiquity/secureboot_key
33 Type: password
34 _Description: SecureBoot key for MokPW
35+
36+Template: ubiquity/text/partman_confirm_zfs
37+Type: text
38+_Description:
39+ partition #%(partid)s as %(parttype)s used for %(partusage)s
40\ No newline at end of file
41diff --git a/scripts/zsys-setup b/scripts/zsys-setup
42index 439a9d7..554adb2 100755
43--- a/scripts/zsys-setup
44+++ b/scripts/zsys-setup
45@@ -43,7 +43,12 @@ set -eu
46 REQUIREDPKGS="zfsutils-linux"
47 TARGET="/target"
48 ESP="${TARGET}/boot/efi"
49-INIT_FLAG="/tmp/.zsys-init.done"
50+ZSYSTMP="/tmp/$(basename $0)"
51+INIT_FLAG="${ZSYSTMP}/init.done"
52+FSTAB_PARTMAN="${ZSYSTMP}/fstab.partman"
53+PARTITION_LAYOUT="${ZSYSTMP}/layout"
54+
55+mkdir -p "${ZSYSTMP}"
56
57 usage() {
58 # Display script usage
59@@ -122,7 +127,7 @@ prepare_target() {
60 # Save fstab generated by partman
61 if [ -f "${target}/etc/fstab" ]; then
62 echo "I: Saving existing fstab"
63- cp "${target}/etc/fstab" /tmp/fstab.partman
64+ cp "${target}/etc/fstab" "${FSTAB_PARTMAN}"
65 else
66 echo "W: ${target}/etc/fstab doesn't exist"
67 fi
68@@ -156,46 +161,116 @@ prepare_target() {
69 done
70 }
71
72+get_layout() {
73+ # Returns disk, base name of the partition and partition numbers to create
74+ target="$1"
75+
76+ # The entire disk has been formatted with use_device
77+ # There is either one ext4 partition or one ext4 and one ESP
78+ part="$(grep -E "\s${target}\s" /proc/mounts | awk '{print $1}')"
79+ disk=""
80+ partbase=""
81+
82+ if [ -n "${part}" ]; then
83+ disk="$(lsblk -lns -o TYPE,PATH ${part}| grep disk| awk '{print $2}')"
84+ if [ -z "${disk}" ]; then
85+ echo "E: Couldn't identify disk for partition ${part}. Exiting!"
86+ exit 1
87+ fi
88+ # Some disks have letters in the partition number like /dev/nvme0n1p1
89+ # In this case we want to retrieve 'p' so we deal only with partition number
90+ # in the rest of the script and prepend the base.
91+ partbase="$(echo ${part} | sed -e 's/[0-9]*$//' | sed -e "s#${disk}##")"
92+ fi
93+
94+ partesp=1
95+ if in_efi_mode; then
96+ # No extended partition on EFI + GPT
97+ # The layout is
98+ # 1: ESP
99+ # 2: swap
100+ # 3: bpool
101+ # 4: rpool
102+ partswap=2
103+ partbpool=3
104+ partrpool=4
105+ else
106+ # MBR pools are on extended partition
107+ # The layout is:
108+ # 1: ESP
109+ # 2: Extended
110+ # 5: swap
111+ # 6: bpool
112+ # 7: rpool
113+ partswap=5
114+ partbpool=6
115+ partrpool=7
116+ fi
117+
118+ echo "OK|${disk}|${partbase}|${partesp}|${partswap}|${partbpool}|${partrpool}"
119+}
120+
121 format_disk() {
122 disk="$1"
123- partgrub="$2"
124- partbpool="$3"
125- partrpool="$4"
126- ss="$5"
127+ partbase="$2"
128+ partesp="$3"
129+ partbpool="$4"
130+ partrpool="$5"
131+ ss="$6"
132 partswap=$(( partbpool - 1 ))
133- partext=$(( partgrub + 1 ))
134+ partext=$(( partesp + 1 ))
135 sfdiskopts=""
136- partprefix="${disk}${PARTBASE}"
137+ partprefix="${disk}${partbase}"
138
139- echo "I: Formatting disk $disk with partitions grub:${partgrub} ext:${partext} bpool:${partbpool} rpool:${partrpool}"
140+ sfdisktmp="${ZSYSTMP}/sfdisk.cfg"
141+ rm -f "${sfdisktmp}"
142
143- if [ "${IS_EFI}" = "true" ]; then
144+ echo "I: Formatting disk $disk with partitions ESP:${partesp} ext:${partext} swap:${partswap} bpool:${partbpool} rpool:${partrpool}"
145
146+ # bpool size: 500M < 5% of ZFS allocated space < 2G
147+ # partext4 is the ext4 partition created by partman.
148+ # Its id is 2 or 1 depending on being on and EFI system of not.
149+ partext4=1
150+ if in_efi_mode; then
151+ partext4=$(( partesp + 1 ))
152+ fi
153+
154+ size_percent=$(expr \( $(blockdev --getsize64 ${disk}${partext4}) / 1024 / 1024 \) \* 5 / 100)
155+ bpool_size=500
156+ [ ${size_percent} -gt ${bpool_size} ] && bpool_size=${size_percent}
157+ [ ${bpool_size} -gt 2048 ] && bpool_size=2048
158+
159+ if in_efi_mode; then
160 # Improvement: Delete all the partitions but the ESP
161- # We should be only 1 or 2 partittion but well it can be made generic
162- sfdisk --delete "${disk}" ${partgrub}
163-
164- cat > /tmp/sfdisk.cfg <<EOF
165-${partprefix}${partgrub} : size= 50M, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4
166-${partprefix}${partswap} : size= ${ss}M, type=0657FD6D-A4AB-43C4-84E5-0933C84B4F4F
167-${partprefix}${partbpool} : size= 2G, type=6A82CB45-1DD2-11B2-99A6-080020736631
168-${partprefix}${partrpool} : type=6A85CF4D-1DD2-11B2-99A6-080020736631
169+ # There should be only 1 or 2 partitions but it can be made generic
170+ sfdisk --delete "${disk}" ${partswap}
171+
172+ cat > "${sfdisktmp}" <<EOF
173+${partprefix}${partswap} : size= ${ss}M, type=0657FD6D-A4AB-43C4-84E5-0933C84B4F4F
174+${partprefix}${partbpool} : size= ${bpool_size}M, type=6A82CB45-1DD2-11B2-99A6-080020736631
175+${partprefix}${partrpool} : type=6A85CF4D-1DD2-11B2-99A6-080020736631
176 EOF
177 sfdiskopts="--append"
178 else
179- start=$(sfdisk -l "${disk}"|grep "^${partprefix}${partgrub}"|awk '{print $2}')
180-
181- cat > /tmp/sfdisk.cfg <<EOF
182-${partprefix}${partgrub} : start= $start, size= 50M, type=83, bootable
183-${partprefix}${partext} : type=5
184-${partprefix}${partswap} : size= ${ss}M, type=82
185-${partprefix}${partbpool} : size= 2G, type=a5
186-${partprefix}${partrpool} : type=a5
187+ if ! esp_exists; then
188+ start=$(sfdisk -l "${disk}"|grep "^${partprefix}${partesp}"|awk '{print $2}')
189+ cat > "${sfdisktmp}" <<EOF
190+${partprefix}${partesp} : start= $start, size= 512M, type=ef, bootable
191+EOF
192+ else
193+ sfdisk --delete "${disk}" ${partswap}
194+ fi
195+
196+ cat >> "${sfdisktmp}" <<EOF
197+${partprefix}${partext} : type=5
198+${partprefix}${partswap} : size= ${ss}M, type=82
199+${partprefix}${partbpool} : size= ${bpool_size}M, type=a5
200+${partprefix}${partrpool} : type=a5
201 EOF
202
203 fi
204
205- cat /tmp/sfdisk.cfg | sfdisk ${sfdiskopts} "${disk}"
206+ cat "${sfdisktmp}" | sfdisk ${sfdiskopts} "${disk}"
207
208 # Force a re-read of the partition table
209 echo "I: Re-reading partition table"
210@@ -228,12 +303,26 @@ init_zfs() {
211 -O mountpoint=/ -R "${target}" rpool "${partrpool}"
212
213 # bpool
214+ # The version of bpool is set to the default version to prevent users from upgrading
215+ # Then only features supported by grub are enabled.
216 zpool create -f \
217- -o version=28 \
218 -o ashift=12 \
219 -d \
220- -O xattr=sa \
221+ -o feature@async_destroy=enabled \
222+ -o feature@bookmarks=enabled \
223+ -o feature@embedded_data=enabled \
224+ -o feature@empty_bpobj=enabled \
225+ -o feature@enabled_txg=enabled \
226+ -o feature@extensible_dataset=enabled \
227+ -o feature@filesystem_limits=enabled \
228+ -o feature@hole_birth=enabled \
229+ -o feature@large_blocks=enabled \
230+ -o feature@lz4_compress=enabled \
231+ -o feature@spacemap_histogram=enabled \
232+ -o feature@userobj_accounting=enabled \
233+ -O compression=lz4 \
234 -O acltype=posixacl \
235+ -O xattr=sa \
236 -O relatime=on \
237 -O normalization=formD \
238 -O canmount=off \
239@@ -297,18 +386,27 @@ init_system_partitions() {
240 partefi="$2"
241 partgrub="$3"
242
243- echo "I: Creating grub partition $partgrub"
244+ # ESP
245+ mkdir -p "${target}/boot/efi"
246+ if ! in_efi_mode; then
247+ echo "I: Creating ESP"
248+ mkfs.vfat "${partefi}"
249+ fi
250+ mount -t vfat "${partefi}" "${target}/boot/efi"
251+ mkdir -p "${target}/boot/efi/grub"
252+
253+ echo "I: Mount grub directory"
254 # Finalize grub directory
255 mkdir -p "${target}/boot/grub"
256- mke2fs -F -t ext4 "${partgrub}"
257- mount -t ext4 "${partgrub}" "${target}/boot/grub"
258-
259- if [ "${IS_EFI}" = "true" ]; then
260- # ESP
261- mkdir -p "${target}/boot/efi"
262- # No need to reformat the partition has been prepared by partman-efi
263- mount -t vfat "${partefi}" "${target}/boot/efi"
264- fi
265+ mount -o bind "${target}/boot/efi/grub" "${target}/boot/grub"
266+}
267+
268+in_efi_mode() {
269+ [ -d /proc/efi ] || [ -d /sys/firmware/efi ]
270+}
271+
272+esp_exists() {
273+ grep -q "\s${ESP}\s" /proc/mounts
274 }
275
276 check_prerequisites ${REQUIREDPKGS}
277@@ -318,57 +416,48 @@ echo "I: Running $(basename "$0") ${COMMAND}"
278 if [ -z "${COMMAND}" ]; then
279 echo "E: ${COMMAND} is mandatory. Exiting!"
280 exit 1
281-elif [ "${COMMAND}" = "init" ]; then
282- # The entire disk has been formatted with use_device
283- # There is either one ext4 partition or one ext4 and one ESP
284- PART=$(grep -E "\s${TARGET}\s" /proc/mounts | awk '{print $1}')
285+elif [ "${COMMAND}" = "layout" ]; then
286+ # Just displays de layout that will be created without any change to the disk.
287+ # At this stage we don't now yet the size of the partition that will be created.
288+ IFS="|" read ERR DISK PARTBASE PARTESP PARTSWAP PARTBPOOL PARTRPOOL<<EOF
289+$(get_layout ${TARGET})
290+EOF
291
292- if [ -z "${PART}" ]; then
293- echo "E: Couldn't identify partition matching ${TARGET}. Exiting!"
294+ if [ "${ERR}" != "OK" ]; then
295+ echo "${ERR}"
296 exit 1
297 fi
298
299- DISK="$(lsblk -lns -o TYPE,PATH ${PART}| grep disk| awk '{print $2}')"
300+ cat > "${PARTITION_LAYOUT}" <<EOF
301+disk:${DISK}
302+EOF
303+ if ! in_efi_mode || ! esp_exists; then
304+ cat >> "${PARTITION_LAYOUT}" <<EOF
305+part:vfat:ESP:${DISK}${PARTBASE}${PARTESP}
306+EOF
307+ fi
308
309- echo "I: Partition table before init of ZFS"
310- partx --show "${DISK}"
311+ cat >> "${PARTITION_LAYOUT}" <<EOF
312+part:swap:swap:${DISK}${PARTBASE}${PARTSWAP}
313+part:zfs:bpool:${DISK}${PARTBASE}${PARTBPOOL}
314+part:zfs:rpool:${DISK}${PARTBASE}${PARTRPOOL}
315+EOF
316
317- # Some disks have letters in the partion number like /dev/nvme0n1p1
318- # In this case we want to retrieve 'p' so we deal only with partition number
319- # in the rest of the script and prepend the base.
320- PARTBASE="$(echo ${PART} | sed -e 's/[0-9]*$//' | sed -e "s#${DISK}##")"
321+elif [ "${COMMAND}" = "init" ]; then
322+ rm -f "${INIT_FLAG}"
323
324- # Better check if the ESP has been created than if it's a EFI system
325- IS_EFI="false"
326- if grep -q "\s${ESP}\s" /proc/mounts; then
327- IS_EFI="true"
328- fi
329+ IFS="|" read ERR DISK PARTBASE PARTESP PARTSWAP PARTBPOOL PARTRPOOL<<EOF
330+$(get_layout ${TARGET})
331+EOF
332
333- PARTGRUB=$(lsblk -n -o TYPE ${DISK}|grep ^part| wc -l)
334- if [ "$IS_EFI" = "true" ]; then
335- # No extended partition on EFI + GPT
336- # The layout is
337- # 1: ESP
338- # 2: grub
339- # 3: swap
340- # 4: bpool
341- # 5: rpool
342- PARTSWAP=3
343- PARTBPOOL=4
344- PARTRPOOL=5
345- else
346- # MBR pools are on extended partition
347- # The layout is:
348- # 1: grub
349- # 2: Extended
350- # 5: swap
351- # 6: bpool
352- # 7: rpool
353- PARTSWAP=5
354- PARTBPOOL=6
355- PARTRPOOL=7
356+ if [ "${ERR}" != "OK" ]; then
357+ echo "${ERR}"
358+ exit 1
359 fi
360
361+ echo "I: Partition table before init of ZFS"
362+ partx --show "${DISK}"
363+
364 # Swap files are not supported on ZFS, we use a swap partition instead:
365 SWAPFILE="$(grep "^${TARGET}" /proc/swaps |awk '{print $1}')"
366 # Give us a minimum swap partition size of 4MB in case we decide on
367@@ -385,20 +474,26 @@ elif [ "${COMMAND}" = "init" ]; then
368 SWAPVOLSIZE=$(( SWAPSIZE / 1024 / 1024 ))
369
370 prepare_target "${TARGET}"
371- format_disk "${DISK}" "${PARTGRUB}" "${PARTBPOOL}" "${PARTRPOOL}" "${SWAPVOLSIZE}"
372+ format_disk "${DISK}" "${PARTBASE}" "${PARTESP}" "${PARTBPOOL}" "${PARTRPOOL}" "${SWAPVOLSIZE}"
373 init_zfs "${TARGET}" "${DISK}${PARTBASE}${PARTBPOOL}" "${DISK}${PARTBASE}${PARTRPOOL}"
374- init_system_partitions "${TARGET}" "${DISK}${PARTBASE}1" "${DISK}${PARTBASE}${PARTGRUB}"
375+ init_system_partitions "${TARGET}" "${DISK}${PARTBASE}1" "${DISK}${PARTBASE}${PARTESP}"
376
377 # Generate fstab
378 # $TARGET/etc has been destroyed by the creation of the zfs partitition
379 # Recreate it
380 mkdir -p "${TARGET}/etc"
381- if [ -f /tmp/fstab.partman ]; then
382+ if [ -f "${FSTAB_PARTMAN}" ]; then
383 echo "I: Creating fstab"
384- grep -Ev '\s/\s|/swapfile' /tmp/fstab.partman > "${TARGET}/etc/fstab"
385+ grep -Ev '\s/\s|/swapfile' "${FSTAB_PARTMAN}" > "${TARGET}/etc/fstab"
386+ fi
387+
388+ if ! grep -q "boot/efi" "${TARGET}/etc/fstab"; then
389+ espuuid=$(blkid -s UUID -o value "${DISK}${PARTBASE}${PARTESP}")
390+ echo "UUID=${espuuid}\t/boot/efi\tvfat\tumask=0077\t0\t1" >> "${TARGET}/etc/fstab"
391 fi
392- grubuuid=$(blkid -s UUID -o value "${DISK}${PARTBASE}${PARTGRUB}")
393- echo "UUID=${grubuuid}\t/boot/grub\text4\terrors=remount-ro\t0\t1" >> "${TARGET}/etc/fstab"
394+
395+ # Bind mount grub from ESP to the expected location
396+ echo "/boot/efi/grub\t/boot/grub\tnone\tdefaults,bind\t0\t0" >> "${TARGET}/etc/fstab"
397
398 if [ -n "${SWAPFILE}" ]; then
399 SWAPDEVICE="${DISK}${PARTBASE}${PARTSWAP}"
400diff --git a/ubiquity/plugins/ubi-partman.py b/ubiquity/plugins/ubi-partman.py
401index 5601d7d..086ac2b 100644
402--- a/ubiquity/plugins/ubi-partman.py
403+++ b/ubiquity/plugins/ubi-partman.py
404@@ -3215,9 +3215,15 @@ class Page(plugin.Plugin):
405 raise AssertionError("Arrived at %s unexpectedly" % question)
406
407 elif question.startswith('partman/confirm'):
408+ description = self.extended_description(question)
409+
410+ if hasattr(self.ui, "use_zfs"):
411+ if (self.ui.use_zfs.get_active() and self.ui.use_device.get_active()):
412+ description = self.update_zfs_description(self.extended_description(question))
413+
414 response = self.frontend.question_dialog(
415 self.description(question),
416- self.extended_description(question),
417+ description,
418 ('ubiquity/text/go_back', 'ubiquity/text/continue'))
419 if response == 'ubiquity/text/continue':
420 self.db.set('ubiquity/partman-confirm', question[8:])
421@@ -3293,6 +3299,40 @@ class Page(plugin.Plugin):
422
423 return plugin.Plugin.run(self, priority, question)
424
425+ def update_zfs_description(self, description):
426+ """Update the description in the partman dialog to display custom
427+ messages"""
428+
429+ misc.execute_root('/usr/share/ubiquity/zsys-setup', 'layout')
430+
431+ zsys_layout = '/tmp/zsys-setup/layout'
432+ lines = description.splitlines()
433+ # Remove the last line of the output from partman which corresponds to
434+ # the ext4 partition
435+ del(lines[-1])
436+
437+ if not os.path.exists(zsys_layout):
438+ return description
439+
440+ with open(zsys_layout, 'r') as f:
441+ layout = f.readlines()
442+
443+ partlabel = misc.utf8(self.db.metaget('ubiquity/text/partman_confirm_zfs', 'extended_description'),
444+ errors='replace')
445+ for line in layout:
446+ if not line.startswith("part:"):
447+ continue
448+
449+ line = line.strip()
450+ (t, f, u, p) = line.split(':')
451+
452+ lines.append(" " + partlabel % {
453+ 'partid': os.path.basename(p),
454+ 'parttype': f,
455+ 'partusage': u})
456+
457+ return "\n".join(lines)
458+
459 def ok_handler(self):
460 if self.install_bootloader and not self.is_bootdev_preseeded():
461 self.preseed('grub-installer/bootdev', self.ui.get_grub_choice())

Subscribers

People subscribed via source and target branches