I had another look at setting up a root file system on a btrfs subvolume now that vmdebootstrap support grub, and freshed up the patch to give it another go.
Unfortunately, grub is not able to find / when it is a btrfs subvolume: # vmdebootstrap --roottype btrfs --image=test.img --verbose --grub --bootsize=256M Creating disk image Creating partitions Creating filesystem btrfs Mounting /dev/mapper/loop0p2 on /tmp/tmpAtr8MZ Creating filesystem ext2 Mounting /dev/mapper/loop0p1 on /tmp/tmpAtr8MZ/@/boot/ Debootstrapping Give root an empty password Removing udev persistent cd and net rules Setting up networking Updating the initramfs Configuring grub2 command failed: ['chroot', '/tmp/tmpAtr8MZ/@', 'update-grub'] /usr/sbin/grub-probe: error: cannot find a device for / (is /dev mounted?). Failed. Is grub2-common installed? Using extlinux. Installing extlinux Cleaning up # The resulting image were not able to boot. This is the patch I used: --- vmdebootstrap.orig 2014-10-18 20:35:19.000000000 +0200 +++ vmdebootstrap 2014-11-01 21:40:56.046766661 +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,15 @@ (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 + newrootdir = "%s/@" % rootdir + self.runcmd(['btrfs', 'subvolume', 'create', newrootdir]) + self.runcmd(['btrfs', 'subvolume', 'set-default', '@', rootdir]) + os.mkdir("%s/btrfs" % newrootdir) + rootdir = newrootdir if bootdev: if self.settings['boottype']: boottype = self.settings['boottype'] @@ -168,9 +180,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']: @@ -379,7 +391,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 +489,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 +504,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 +538,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 +547,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 +555,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) -- Happy hacking Petter Reinholdtsen -- To UNSUBSCRIBE, email to debian-bugs-dist-requ...@lists.debian.org with a subject of "unsubscribe". Trouble? Contact listmas...@lists.debian.org