mirror of
https://github.com/flatcar/scripts.git
synced 2026-05-05 20:26:44 +02:00
feat(disk_util): Add tune command, controlling fs read-only hack.
Now disk_util is aware of the weird ext2 read-only hack, both by providing a command to manipulate it and support in the mount command to automatically set the 'ro' mount option for filesystems with it. Making mount aware of the hack makes it much easier to mount prod images with a mix read-only and read-write filesystems.
This commit is contained in:
parent
89b61ac7b0
commit
e066f91ca3
@ -414,6 +414,8 @@ def Resize(options):
|
||||
continue
|
||||
elif part['bytes'] == part['image_bytes']:
|
||||
continue
|
||||
elif not IsE2fsReadWrite(options, part):
|
||||
continue
|
||||
|
||||
print "Resizing partition %s (%s) to %s bytes" % (
|
||||
part['num'], part['label'], part['fs_bytes'])
|
||||
@ -458,6 +460,9 @@ def Mount(options):
|
||||
'sizelimit=%d' % mount['image_bytes']]
|
||||
if options.read_only:
|
||||
mount_opts.append('ro')
|
||||
elif (mount.get('fs_type', None) in ('ext2', 'ext4') and
|
||||
not IsE2fsReadWrite(options, mount)):
|
||||
mount_opts.append('ro')
|
||||
|
||||
Sudo(['mkdir', '-p', full_path])
|
||||
Sudo(['mount', '-t', mount.get('fs_type', 'auto'),
|
||||
@ -485,6 +490,93 @@ def Umount(options):
|
||||
Sudo(['umount', '--recursive', '--detach-loop', options.mount_dir])
|
||||
|
||||
|
||||
def Tune2fsReadWrite(options, partition):
|
||||
"""Enable/Disable read-only hack.
|
||||
|
||||
From common.sh:
|
||||
This helper clobbers the ro compat value in our root filesystem.
|
||||
|
||||
When the system is built with --enable_rootfs_verification, bit-precise
|
||||
integrity checking is performed. That precision poses a usability issue on
|
||||
systems that automount partitions with recognizable filesystems, such as
|
||||
ext2/3/4. When the filesystem is mounted 'rw', ext2 metadata will be
|
||||
automatically updated even if no other writes are performed to the
|
||||
filesystem. In addition, ext2+ does not support a "read-only" flag for a
|
||||
given filesystem. That said, forward and backward compatibility of
|
||||
filesystem features are supported by tracking if a new feature breaks r/w or
|
||||
just write compatibility. We abuse the read-only compatibility flag[1] in
|
||||
the filesystem header by setting the high order byte (le) to FF. This tells
|
||||
the kernel that features R24-R31 are all enabled. Since those features are
|
||||
undefined on all ext-based filesystem, all standard kernels will refuse to
|
||||
mount the filesystem as read-write -- only read-only[2].
|
||||
|
||||
[1] 32-bit flag we are modifying:
|
||||
http://git.chromium.org/cgi-bin/gitweb.cgi?p=kernel.git;a=blob;f=include/linux/ext2_fs.h#l417
|
||||
[2] Mount behavior is enforced here:
|
||||
http://git.chromium.org/cgi-bin/gitweb.cgi?p=kernel.git;a=blob;f=fs/ext2/super.c#l857
|
||||
|
||||
N.B., if the high order feature bits are used in the future, we will need to
|
||||
revisit this technique.
|
||||
|
||||
Args:
|
||||
options: Flags passed to the script
|
||||
partition: Config for partition to manipulate
|
||||
"""
|
||||
|
||||
if options.disable2fs_rw:
|
||||
print "Disabling read-write mounting of partition %s (%s)" % (
|
||||
partition['num'], partition['label'])
|
||||
else:
|
||||
print "Enabling read-write mounting of partition %s (%s)" % (
|
||||
partition['num'], partition['label'])
|
||||
|
||||
# offset of ro_compat, highest order byte (le 32 bit field)
|
||||
flag_offset = 0x464 + 3
|
||||
flag_value = 0xff if options.disable2fs_rw else 0x00
|
||||
with open(options.disk_image, 'r+') as image:
|
||||
image.seek(partition['first_byte'] + flag_offset)
|
||||
image.write(chr(flag_value))
|
||||
|
||||
|
||||
def IsE2fsReadWrite(options, partition):
|
||||
"""Returns True if FS is read-write, False if hack is active.
|
||||
|
||||
Args:
|
||||
options: Flags passed to the script
|
||||
partition: Config for partition to query
|
||||
"""
|
||||
|
||||
# offset of ro_compat, highest order byte (le 32 bit field)
|
||||
flag_offset = 0x464 + 3
|
||||
with open(options.disk_image, 'r') as image:
|
||||
image.seek(partition['first_byte'] + flag_offset)
|
||||
flag_value = image.read(1)
|
||||
|
||||
return ord(flag_value) == 0
|
||||
|
||||
|
||||
def Tune(options):
|
||||
"""Tweak some filesystem options.
|
||||
|
||||
Args:
|
||||
options: Flags passed to the script
|
||||
"""
|
||||
|
||||
config, partitions = LoadPartitionConfig(options)
|
||||
GetPartitionTableFromImage(options, config, partitions)
|
||||
part = GetPartition(partitions, options.partition)
|
||||
|
||||
if not part['image_compat']:
|
||||
raise InvalidLayout("Disk layout is incompatible existing image")
|
||||
|
||||
if options.disable2fs_rw is not None:
|
||||
if part.get('fs_type', None) not in ('ext2', 'ext4'):
|
||||
raise Exception("Partition %s is not a ext2 or ext4" % options.partition)
|
||||
Tune2fsReadWrite(options, part)
|
||||
else:
|
||||
raise Exception("No options specified!")
|
||||
|
||||
|
||||
def GetPartitionByNumber(partitions, num):
|
||||
"""Given a partition table and number returns the partition object.
|
||||
|
||||
@ -520,6 +612,21 @@ def GetPartitionByLabel(partitions, label):
|
||||
raise PartitionNotFound('Partition not found')
|
||||
|
||||
|
||||
def GetPartition(partitions, part_id):
|
||||
"""Given a partition table and label or num returns the partition object.
|
||||
|
||||
Args:
|
||||
partitions: List of partitions to search in
|
||||
part_id: Label or number of partition to find
|
||||
Returns:
|
||||
An object for the selected partition
|
||||
"""
|
||||
if str(part_id).isdigit():
|
||||
return GetPartitionByNumber(partitions, part_id)
|
||||
else:
|
||||
return GetPartitionByLabel(partitions, part_id)
|
||||
|
||||
|
||||
def GetBlockSize(options):
|
||||
"""Returns the partition table block size.
|
||||
|
||||
@ -704,6 +811,15 @@ def main(argv):
|
||||
a.add_argument('mount_dir', help='path to root filesystem mount point')
|
||||
a.set_defaults(func=Umount)
|
||||
|
||||
a = actions.add_parser('tune', help='tweak filesystem options')
|
||||
a.add_argument('--disable2fs_rw', action='store_true', default=None,
|
||||
help='disable mounting ext2 filesystems read-write')
|
||||
a.add_argument('--enable2fs_rw', action='store_false', dest='disable2fs_rw',
|
||||
help='re-enable mounting ext2 filesystems read-write')
|
||||
a.add_argument('disk_image', help='path to disk image file')
|
||||
a.add_argument('partition', help='number or label of partition to edit')
|
||||
a.set_defaults(func=Tune)
|
||||
|
||||
a = actions.add_parser('readblocksize', help='get device block size')
|
||||
a.set_defaults(func=GetBlockSize)
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user