[Vmdebootstrap-devel] Bug#741223: vmdebootstrap: please support root on btrfs
Petter Reinholdtsen
pere at hungry.com
Mon Nov 3 06:44:07 UTC 2014
Control: tags -1 + patch
I figured out the grub-probe problem. It was really just grub being
outdated because I was building a stable Debian system instead of the
unstable one I believed I was building.
Using testing or unstable, grub was able to find the correct device,
but thanks to the fact that --bootsize and --grub were incompatible,
grub did not have enough space at the start of the disk to install
itself there. I changed the partition code to reserve 1 MiB at the
start, similar to the amount reserved when --bootsize were not used.
With this change in place, vmdebootstrap could create images with a
btrfs subvolume as root.
The attached patch is working. Please include in a future version of
vmdebootstrap.
--
Happy hacking
Petter Reinholdtsen
-------------- next part --------------
--- vmdebootstrap.orig 2014-10-18 20:35:19.000000000 +0200
+++ vmdebootstrap 2014-11-03 05:34:47.319278095 +0100
@@ -39,6 +39,9 @@
self.settings.boolean(['verbose'], 'report what is going on')
self.settings.string(['image'], 'put created disk image in FILE',
metavar='FILE')
+ self.settings.string(['roottype'],
+ 'specify file system type for /',
+ default='ext4')
self.settings.bytesize(['size'],
'create a disk image of size SIZE (%default)',
metavar='SIZE',
@@ -129,7 +132,7 @@
try:
rootdev = None
- roottype = 'ext4'
+ roottype = self.settings['roottype']
bootdev = None
boottype = None
rootdir = None
@@ -141,6 +144,26 @@
(rootdev, bootdev) = self.setup_kpartx()
self.mkfs(rootdev, type=roottype)
rootdir = self.mount(rootdev)
+ rootfsdir = rootdir
+ if 'btrfs' == roottype:
+ self.settings['package'].append("btrfs-tools")
+ # Put root in a subvolume, to ease snapshots and volume management
+ self.message("Creating root file system as btrfs subvolume @")
+ self.runcmd(['btrfs', 'subvolume', 'create', "%s/@" % rootdir])
+
+ # Make sure the subvolume mount point show in in
+ # /proc/mounts for grub-update to figure out the
+ # device for the root file system.
+ newrootdir = "%s/build" % rootdir
+ os.mkdir(newrootdir)
+ self.mount(rootdev, newrootdir, ['-o','subvol=@'])
+# self.runcmd(['btrfs', 'subvolume', 'set-default', '@', rootdir])
+
+ # Make the btrfs root file system available in the chroot.
+ os.mkdir("%s/btrfs" % newrootdir)
+ self.mount(rootdev, "%s/btrfs" % newrootdir)
+
+ rootdir = newrootdir
if bootdev:
if self.settings['boottype']:
boottype = self.settings['boottype']
@@ -168,9 +191,9 @@
if self.settings['image']:
if self.settings['grub']:
- self.install_grub2(rootdev, rootdir)
+ self.install_grub2(rootdev, rootdir, rootfsdir)
elif self.settings['extlinux']:
- self.install_extlinux(rootdev, rootdir)
+ self.install_extlinux(rootdev, rootdir, rootfsdir)
self.append_serial_console(rootdir)
self.optimize_image(rootdir)
if self.settings['squash']:
@@ -221,13 +244,19 @@
logging.debug('mkdir %s' % dirname)
return dirname
- def mount(self, device, path=None):
+ def mount(self, device, path=None, opts=None):
if not path:
mount_point = self.mkdtemp()
else:
mount_point = path
self.message('Mounting %s on %s' % (device, mount_point))
- self.runcmd(['mount', device, mount_point])
+ cmd = ['mount']
+ if opts is not None:
+ for opt in opts:
+ cmd.append(opt)
+ cmd.append(device)
+ cmd.append(mount_point)
+ self.runcmd(cmd)
self.mount_points.append(mount_point)
logging.debug('mounted %s on %s' % (device, mount_point))
return mount_point
@@ -243,13 +272,14 @@
self.runcmd(['parted', '-s', self.settings['image'],
'mklabel', 'msdos'])
if self.settings['bootsize'] and self.settings['bootsize'] is not '0%':
- bootsize = str(self.settings['bootsize'] / (1024 * 1024))
+ reserved = 1 # MiB space for boot loader / grub
+ bootend = str(reserved + (self.settings['bootsize'] / (1024 * 1024)))
self.runcmd(['parted', '-s', self.settings['image'],
- 'mkpart', 'primary', 'fat16', '0', bootsize])
+ 'mkpart', 'primary', 'fat16', str(reserved), bootend])
else:
- bootsize = '0%'
+ bootend = '0%'
self.runcmd(['parted', '-s', self.settings['image'],
- 'mkpart', 'primary', bootsize, '100%'])
+ 'mkpart', 'primary', bootend, '100%'])
self.runcmd(['parted', '-s', self.settings['image'],
'set', '1', 'boot', 'on'])
@@ -289,7 +319,7 @@
self.runcmd(['mkfs', '-t', type, device])
def debootstrap(self, rootdir):
- self.message('Debootstrapping')
+ self.message('Debootstrapping %s' % self.settings['distribution'])
if self.settings['foreign']:
necessary_packages = []
@@ -379,7 +409,12 @@
fstab = os.path.join(rootdir, 'etc', 'fstab')
with open(fstab, 'w') as f:
f.write('proc /proc proc defaults 0 0\n')
- f.write('%s / %s errors=remount-ro 0 1\n' % (rootdevstr, roottype))
+ if 'btrfs' == roottype:
+# f.write('%s / %s defaults 0 1\n' % (rootdevstr, roottype))
+ f.write('%s / %s subvol=@ 0 1\n' % (rootdevstr, roottype))
+ f.write('%s /btrfs %s defaults 1\n' % (rootdevstr, roottype))
+ else:
+ f.write('%s / %s errors=remount-ro 0 1\n' % (rootdevstr, roottype))
if bootdevstr:
f.write('%s /boot %s errors=remount-ro 0 2\n' % (bootdevstr, boottype))
@@ -472,7 +507,8 @@
with open(inittab, 'a') as f:
f.write('\nS0:23:respawn:%s\n' % serial_command)
- def install_grub2(self, rootdev, rootdir):
+ def install_grub2(self, rootdev, rootdir, rootfsdir):
+ # FIXME use rootfsdir
self.message("Configuring grub2")
# rely on kpartx using consistent naming to map loop0p1 to loop0
install_dev = os.path.join('/dev', os.path.basename(rootdev)[:-2])
@@ -486,13 +522,14 @@
self.runcmd(['chroot', rootdir, 'update-grub'])
self.runcmd(['chroot', rootdir, 'grub-install', install_dev])
except cliapp.AppException as e:
+ self.message(str(e))
self.message("Failed. Is grub2-common installed? Using extlinux.")
self.runcmd(['umount', os.path.join(rootdir, 'sys')])
self.runcmd(['umount', os.path.join(rootdir, 'proc')])
self.runcmd(['umount', os.path.join(rootdir, 'dev')])
- self.install_extlinux(rootdev, rootdir)
+ self.install_extlinux(rootdev, rootdir, rootfsdir)
- def install_extlinux(self, rootdev, rootdir):
+ def install_extlinux(self, rootdev, rootdir, rootfsdir):
if not os.path.exists("/usr/bin/extlinux"):
self.message("extlinux not installed, skipping.")
return
@@ -519,7 +556,7 @@
'-s', 'UUID', rootdev])
uuid = out.splitlines()[0].strip()
- conf = os.path.join(rootdir, 'extlinux.conf')
+ conf = os.path.join(rootfsdir, 'extlinux.conf')
logging.debug('configure extlinux %s' % conf)
f = open(conf, 'w')
f.write('''
@@ -528,7 +565,7 @@
label linux
kernel %(kernel)s
-append initrd=%(initrd)s root=UUID=%(uuid)s ro %(kserial)s
+append initrd=%(initrd)s root=UUID=%(uuid)s ro %(kserial)s %(rootflags)s
%(extserial)s
''' % {
'kernel': kernel_image,
@@ -536,11 +573,12 @@
'uuid': uuid,
'kserial':
'console=ttyS0,115200' if self.settings['serial-console'] else '',
+ 'rootflags': 'rootfsflags=subvol=@' if 'btrfs' == self.settings['roottype'] else '',
'extserial': 'serial 0 115200' if self.settings['serial-console'] else '',
})
f.close()
- self.runcmd(['extlinux', '--install', rootdir])
+ self.runcmd(['extlinux', '--install', rootfsdir])
self.runcmd(['sync'])
time.sleep(2)
More information about the Vmdebootstrap-devel
mailing list