From: Simon Glass <simon.glass@canonical.com>
Some block devices, such as LUKS-encrypted volumes mounted via
blkmap_crypt, only support read access. When ext4l attempts to write
the superblock during mount, the write fails and causes mount to fail.
Add a way to detect this read-only device detection:
- Test writes during mount by writing back the superblock data; if the
write fails, mark the device as read-only
- Update bdev_read_only() to return the actual read_only status
- Update sb_rdonly() to check the SB_RDONLY flag
This allows ext4l to successfully mount read-only devices like LUKS
volumes for read access.
We could perhaps have a read-only flag in the block device, but that is
left for another day.
Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
---
(no changes since v1)
fs/ext4l/ext4_uboot.h | 8 ++++----
fs/ext4l/interface.c | 14 ++++++++++++--
include/linux/fs.h | 1 +
3 files changed, 17 insertions(+), 6 deletions(-)
@@ -315,8 +315,8 @@ extern struct user_namespace init_user_ns;
/* might_sleep - stub */
#define might_sleep() do { } while (0)
-/* sb_rdonly - U-Boot mounts filesystems read-write */
-#define sb_rdonly(sb) 0
+/* sb_rdonly - check if filesystem is mounted read-only */
+#define sb_rdonly(sb) ((sb)->s_flags & SB_RDONLY)
/* Trace stubs */
#define trace_ext4_journal_start_inode(...) do { } while (0)
@@ -696,10 +696,10 @@ struct super_block {
struct list_head s_inodes;
};
-/* Block device read-only check - stub */
+/* Block device read-only check */
static inline int bdev_read_only(struct block_device *bdev)
{
- return 0;
+ return bdev ? bdev->read_only : 0;
}
/* kuid_t and kgid_t - from linux/cred.h */
@@ -401,8 +401,6 @@ int ext4l_probe(struct blk_desc *fs_dev_desc,
goto err_free_buf;
}
- free(buf);
-
/* Save device info for later operations */
ext4l_dev_desc = fs_dev_desc;
if (fs_partition)
@@ -411,6 +409,18 @@ int ext4l_probe(struct blk_desc *fs_dev_desc,
/* Set block device for buffer I/O */
ext4l_set_blk_dev(fs_dev_desc, fs_partition);
+ /*
+ * Test if device supports writes by writing back the same data.
+ * If write returns 0, the device is read-only (e.g. LUKS/blkmap_crypt)
+ */
+ if (blk_dwrite(fs_dev_desc,
+ (part_offset + BLOCK_SIZE) / fs_dev_desc->blksz,
+ 2, buf) != 2) {
+ sb->s_bdev->read_only = true;
+ sb->s_flags |= SB_RDONLY;
+ }
+ free(buf);
+
/* Mount the filesystem */
ret = ext4_fill_super(sb, fc);
if (ret) {
@@ -76,6 +76,7 @@ struct block_device {
void *bd_disk;
struct super_block *bd_super;
dev_t bd_dev;
+ bool read_only;
};
/* errseq functions - stubs */