[Vmdebootstrap-devel] [PATCH 4/4] btrfs root support
Jan Gerber
j at mailb.org
Thu Apr 9 10:00:15 UTC 2015
If roottype is set to btrfs, create a root subvolume to allow
snapshots and other btrfs features that depend on subvolumes.
btrfs root with grub:
vmdebootstrap --image btrfs.img --distribution=jessie \
--rootyype btrfs --grub
btrfs root with ext2 boot partition and grub:
vmdebootstrap --image btrfs.img --distribution=jessie \
--roottype btrfs --bootsize 256M --grub
btrfs root with ext2 boot partition and extlinux:
vmdebootstrap --image btrfs.img --distribution=jessie \
--roottype btrfs --bootsize 256M --extlinux
---
vmdebootstrap | 49 +++++++++++++++++++++++++++++++++++--------------
1 file changed, 35 insertions(+), 14 deletions(-)
diff --git a/vmdebootstrap b/vmdebootstrap
index 3bb9c9f..b4e9569 100755
--- a/vmdebootstrap
+++ b/vmdebootstrap
@@ -201,7 +201,16 @@ class VmDebootstrap(cliapp.Application): # pylint: disable=too-many-public-meth
self.message("Creating swap space")
self.runcmd(['mkswap', swapdev])
self.mkfs(rootdev, fstype=roottype)
- rootdir = self.mount(rootdev)
+ bootdir = rootdir = self.mount(rootdev)
+ if roottype == 'btrfs':
+ # Btrfs root requires a separate boot partition with extlinux,
+ # default to grub if bootdev is not defined.
+ if not bootdev and not self.settings['grub']:
+ self.settings['grub'] = True
+ subvol = '@'
+ self.message("Creating subvolume for root file system: %s" % subvol)
+ self.runcmd(['btrfs', 'subvolume', 'create', '%s/%s' % (rootdir, subvol)])
+ rootdir = self.mount(rootdev, options=['-o', 'subvol=%s' % subvol])
if bootdev:
if self.settings['boottype']:
boottype = self.settings['boottype']
@@ -229,9 +238,9 @@ class VmDebootstrap(cliapp.Application): # pylint: disable=too-many-public-meth
if self.settings['image']:
if self.settings['grub']:
- self.install_grub2(rootdev, rootdir)
+ self.install_grub2(rootdev, rootdir, bootdir)
elif self.settings['extlinux']:
- self.install_extlinux(rootdev, rootdir)
+ self.install_extlinux(rootdev, rootdir, bootdir)
self.append_serial_console(rootdir)
self.optimize_image(rootdir)
if self.settings['squash']:
@@ -284,13 +293,13 @@ class VmDebootstrap(cliapp.Application): # pylint: disable=too-many-public-meth
logging.debug('mkdir %s', dirname)
return dirname
- def mount(self, device, path=None):
+ def mount(self, device, path=None, options=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])
+ self.runcmd(['mount'] + (options or []) + [device, mount_point])
self.mount_points.append(mount_point)
logging.debug('mounted %s on %s', device, mount_point)
return mount_point
@@ -422,6 +431,9 @@ class VmDebootstrap(cliapp.Application): # pylint: disable=too-many-public-meth
if self.settings['grub']:
include.append('grub2')
+ if self.settings['roottype'] == 'btrfs':
+ include.append('btrfs-tools')
+
if not self.settings['no-kernel']:
if self.settings['arch'] == 'i386':
kernel_arch = '486'
@@ -501,7 +513,12 @@ class VmDebootstrap(cliapp.Application): # pylint: disable=too-many-public-meth
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 roottype == 'btrfs':
+ f.write('%s / %s subvol=@ 0 1\n' % (rootdevstr, roottype))
+ f.write('%s /media/btrfs %s noauto,subvolid=0 0 0\n' % (rootdevstr, roottype))
+ os.mkdir(os.path.join(rootdir, 'media', 'btrfs'))
+ 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))
if self.settings['swap'] > 0:
@@ -599,7 +616,7 @@ class VmDebootstrap(cliapp.Application): # pylint: disable=too-many-public-meth
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, bootdir):
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])
@@ -625,24 +642,26 @@ class VmDebootstrap(cliapp.Application): # pylint: disable=too-many-public-meth
self.runcmd(['chroot', rootdir, 'grub-install', install_dev])
except cliapp.AppException:
self.message("Failed. Is grub2-common installed? Using extlinux.")
- self.install_extlinux(rootdev, rootdir)
+ self.install_extlinux(rootdev, rootdir, bootdir)
self.runcmd(['umount', os.path.join(rootdir, 'sys')])
self.runcmd(['umount', os.path.join(rootdir, 'proc')])
self.runcmd(['umount', os.path.join(rootdir, 'dev')])
- def install_extlinux(self, rootdev, rootdir):
+ def install_extlinux(self, rootdev, rootdir, bootdir):
if not os.path.exists("/usr/bin/extlinux"):
self.message("extlinux not installed, skipping.")
return
self.message('Installing extlinux')
def find(pattern):
- dirname = os.path.join(rootdir, 'boot')
+ dirname = os.path.join(bootdir, 'boot')
+ if not os.path.exists(dirname):
+ dirname = bootdir
basenames = os.listdir(dirname)
logging.debug('find: %s', basenames)
for basename in basenames:
if re.search(pattern, basename):
- return os.path.join('boot', basename)
+ return basename if dirname == bootdir else os.path.join('boot', basename)
raise cliapp.AppException('Cannot find match: %s' % pattern)
try:
@@ -657,23 +676,25 @@ class VmDebootstrap(cliapp.Application): # pylint: disable=too-many-public-meth
'-s', 'UUID', rootdev])
uuid = out.splitlines()[0].strip()
- conf = os.path.join(rootdir, 'extlinux.conf')
+ conf = os.path.join(bootdir, 'extlinux.conf')
logging.debug('configure extlinux %s', conf)
kserial = 'console=ttyS0,115200' if self.settings['serial-console'] else ''
extserial = 'serial 0 115200' if self.settings['serial-console'] else ''
+ rootflags = 'rootflags=subvol=@' if self.settings['roottype'] == 'btrfs' else ''
msg = '''
default linux
timeout 1
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, # pylint: disable=bad-continuation
'initrd': initrd_image, # pylint: disable=bad-continuation
'uuid': uuid, # pylint: disable=bad-continuation
'kserial': kserial, # pylint: disable=bad-continuation
+ 'rootflags': rootflags, # pylint: disable=bad-continuation
'extserial': extserial, # pylint: disable=bad-continuation
} # pylint: disable=bad-continuation
logging.debug("extlinux config:\n%s", msg)
@@ -684,7 +705,7 @@ append initrd=%(initrd)s root=UUID=%(uuid)s ro %(kserial)s
f = open(conf, 'w')
f.write(msg)
- self.runcmd(['extlinux', '--install', rootdir])
+ self.runcmd(['extlinux', '--install', bootdir])
self.runcmd(['sync'])
time.sleep(2)
--
2.1.4
More information about the Vmdebootstrap-devel
mailing list