feat(disk_util): Switch to btrfs for root filesystem in /usr images

This is all that is required to swap out ext4 for btrfs.
No btrfs user space tools or auto-resize support yet.
This commit is contained in:
Michael Marineau 2014-03-05 17:23:12 -08:00
parent 2aa3571e45
commit 4dbdb391a4
3 changed files with 82 additions and 9 deletions

View File

@ -42,9 +42,10 @@ get_uuid() {
# Filesystem args differ between the old and new usr layouts.
if [[ "${FLAGS_disk_layout}" == *-usr ]]; then
gptprio_args="root=LABEL=ROOT usr=gptprio:"
slot_a_args="root=LABEL=ROOT usr=PARTUUID=$(get_uuid USR-A)"
slot_b_args="root=LABEL=ROOT usr=PARTUUID=$(get_uuid USR-B)"
root_args="root=LABEL=ROOT rootflags=subvol=root"
gptprio_args="${root_args} usr=gptprio:"
slot_a_args="${root_args} usr=PARTUUID=$(get_uuid USR-A)"
slot_b_args="${root_args} usr=PARTUUID=$(get_uuid USR-B)"
else
gptprio_args="root=gptprio:"
slot_a_args="root=PARTUUID=$(get_uuid ROOT-A)"

View File

@ -83,6 +83,8 @@
},
"9":{
"label":"ROOT",
"fs_type":"btrfs",
"fs_subvolume":"root",
"mount":"/",
"binds":{}
}
@ -103,6 +105,8 @@
},
"9":{
"label":"ROOT",
"fs_type":"btrfs",
"fs_subvolume":"root",
"mount":"/",
"binds":{},
"blocks":"6291456"
@ -124,6 +128,8 @@
},
"9":{
"label":"ROOT",
"fs_type":"btrfs",
"fs_subvolume":"root",
"mount":"/",
"binds":{},
"blocks":"33587200"

View File

@ -38,7 +38,7 @@ def LoadPartitionConfig(options):
valid_layout_keys = set((
'_comment', 'type', 'num', 'label', 'blocks', 'block_size', 'fs_blocks',
'fs_block_size', 'fs_type', 'features', 'uuid', 'alignment', 'mount',
'binds'))
'binds', 'fs_subvolume'))
integer_layout_keys = set((
'blocks', 'block_size', 'fs_blocks', 'fs_block_size', 'alignment'))
required_layout_keys = set(('type', 'num', 'label', 'blocks'))
@ -99,9 +99,12 @@ def LoadPartitionConfig(options):
raise InvalidLayout('Invalid uuid %r: %s' % (part['uuid'], e))
if 'fs_type' in part:
if part['fs_type'] not in ('ext2', 'ext4', 'vfat'):
if part['fs_type'] not in ('btrfs', 'ext2', 'ext4', 'vfat'):
raise InvalidLayout('Invalid fs_type: %r' % part['fs_type'])
if 'fs_subvolume' in part:
if part.get('fs_type', None) != 'btrfs':
raise InvalidLayout('Invalid fs: only btrfs supports subvolumes')
def Align(count, alignment):
offset = count % alignment
@ -300,6 +303,33 @@ def Sudo(cmd, stdout_null=False):
null.close()
def FormatBtrfs(part, device):
"""Format an ext2 or ext4 filesystem.
Args:
part: dict defining the partition
device: name of the block device to format
"""
Sudo(['mkfs.btrfs', '--byte-count', part['fs_bytes'],
'--label', part['label'],
# must use mixed chunks at this point because
# the filesystem size is too small.
'--data', 'single',
'--metadata', 'single',
'--mixed',
device])
if part.get('fs_subvolume', None):
btrfs_mount = tempfile.mkdtemp()
subvol_path = '%s/%s' % (btrfs_mount, part['fs_subvolume'])
Sudo(['mount', '-t', 'btrfs', device, btrfs_mount])
try:
Sudo(['btrfs', 'subvolume', 'create', subvol_path])
finally:
Sudo(['umount', btrfs_mount])
os.rmdir(btrfs_mount)
def FormatExt(part, device):
"""Format an ext2 or ext4 filesystem.
@ -394,12 +424,41 @@ def Format(options):
with PartitionLoop(options, part) as loop_dev:
if part['fs_type'] in ('ext2', 'ext4'):
FormatExt(part, loop_dev)
elif part['fs_type'] == 'btrfs':
FormatBtrfs(part, loop_dev)
elif part['fs_type'] == 'vfat':
FormatFat(part, loop_dev)
else:
raise Exception("Unhandled fs type %s" % part['fs_type'])
def ResizeExt(part, device):
"""Resize ext[234] filesystems.
Args:
part: dict defining the partition
device: name of the block device
"""
Sudo(['e2fsck', '-p', '-f', loop_dev], stdout_null=True)
Sudo(['resize2fs', loop_dev, str(part['fs_blocks'])])
def ResizeBtrfs(part, device):
"""Resize btrfs filesystems.
Args:
part: dict defining the partition
device: name of the block device
"""
btrfs_mount = tempfile.mkdtemp()
Sudo(['mount', '-t', 'btrfs', device, btrfs_mount])
try:
Sudo(['btrfs', 'filesystem', 'resize', part['fs_bytes'], btrfs_mount])
finally:
Sudo(['umount', btrfs_mount])
os.rmdir(btrfs_mount)
def Resize(options):
"""Writes the given partition table and resize ext[234] filesystems.
@ -411,19 +470,23 @@ def Resize(options):
WritePartitionTable(options, config, partitions)
for part in partitions.itervalues():
if part.get('fs_type', None) not in ('ext2', 'ext4'):
resize_func = None
if not part.get('fs_type', None):
continue
elif part['bytes'] == part['image_bytes']:
continue
elif not IsE2fsReadWrite(options, part):
elif part['fs_type'] in ('ext2', 'ext4') and IsE2fsReadWrite(options, part):
resize_func = ResizeExt
elif part.get('fs_type', None) == 'btrfs':
resize_func = ResizeBtrfs
else:
continue
print "Resizing partition %s (%s) to %s bytes" % (
part['num'], part['label'], part['fs_bytes'])
with PartitionLoop(options, part) as loop_dev:
Sudo(['e2fsck', '-p', '-f', loop_dev], stdout_null=True)
Sudo(['resize2fs', loop_dev, str(part['fs_blocks'])])
resize_func(part, loop_dev)
def Mount(options):
@ -463,6 +526,9 @@ def Mount(options):
not IsE2fsReadWrite(options, mount)):
mount_opts.append('ro')
if mount.get('fs_subvolume', None):
mount_opts.append('subvol=%s' % mount['fs_subvolume'])
Sudo(['mkdir', '-p', full_path])
Sudo(['mount', '-t', mount.get('fs_type', 'auto'),
'-o', ','.join(mount_opts),