[Concept,25/26] fs: ext4l: Add inode and bmap functions

Message ID 20251222115639.700578-26-sjg@u-boot.org
State New
Headers
Series fs: ext4l: Add support for mounting ext4 filesystems (part G) |

Commit Message

Simon Glass Dec. 22, 2025, 11:56 a.m. UTC
  From: Simon Glass <simon.glass@canonical.com>

Add inode allocation and block mapping functions:
- iget_locked() - allocate inode by number
- new_inode() - allocate new empty inode
- ext4_uboot_bmap() - map logical to physical block
- bmap() - VFS interface for block mapping

Also add i_count reference counter to struct inode.

Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
---

 fs/ext4l/ext4_uboot.h |  9 ++--
 fs/ext4l/support.c    | 99 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 104 insertions(+), 4 deletions(-)
  

Patch

diff --git a/fs/ext4l/ext4_uboot.h b/fs/ext4l/ext4_uboot.h
index 5beedb4bb3d..4c4dd2ca559 100644
--- a/fs/ext4l/ext4_uboot.h
+++ b/fs/ext4l/ext4_uboot.h
@@ -377,8 +377,8 @@  struct buffer_head *sb_getblk(struct super_block *sb, sector_t block);
 #define ktime_get_real_seconds()		(0)
 #define time_before32(a, b)			(0)
 
-/* Inode operations - stubs */
-#define new_inode(sb)				((struct inode *)NULL)
+/* Inode operations - iget_locked and new_inode are in interface.c */
+extern struct inode *new_inode(struct super_block *sb);
 #define i_uid_write(inode, uid)			do { } while (0)
 #define i_gid_write(inode, gid)			do { } while (0)
 #define inode_fsuid_set(inode, idmap)		do { } while (0)
@@ -820,6 +820,7 @@  struct inode {
 	const struct inode_operations *i_op;
 	const struct file_operations *i_fop;
 	atomic_t i_writecount;		/* Count of writers */
+	atomic_t i_count;		/* Reference count */
 	struct rw_semaphore i_rwsem;	/* inode lock */
 	const char *i_link;		/* Symlink target for fast symlinks */
 	unsigned short i_write_hint;	/* Write life time hint */
@@ -1615,7 +1616,7 @@  static inline unsigned int i_gid_read(const struct inode *inode)
 #define fs_high2lowgid(gid)	((gid) & 0xFFFF)
 
 /* Inode allocation/state operations */
-#define iget_locked(sb, ino)		((struct inode *)NULL)
+extern struct inode *iget_locked(struct super_block *sb, unsigned long ino);
 #define set_nlink(i, n)			do { (i)->i_nlink = (n); } while (0)
 #define inc_nlink(i)			do { (i)->i_nlink++; } while (0)
 #define drop_nlink(i)			do { (i)->i_nlink--; } while (0)
@@ -2855,7 +2856,7 @@  struct disk_partition *ext4l_get_partition(void);
 /* JBD2 journal.c stubs */
 struct buffer_head *alloc_buffer_head(gfp_t gfp_mask);
 #define __getblk(bdev, block, size)	({ (void)(bdev); (void)(block); (void)(size); (struct buffer_head *)NULL; })
-#define bmap(inode, block)		({ (void)(inode); (void)(block); 0; })
+int bmap(struct inode *inode, sector_t *block);
 #define trace_jbd2_update_log_tail(j, t, b, f) \
 	do { (void)(j); (void)(t); (void)(b); (void)(f); } while (0)
 
diff --git a/fs/ext4l/support.c b/fs/ext4l/support.c
index 2040ad5f480..d1bc32ae8d6 100644
--- a/fs/ext4l/support.c
+++ b/fs/ext4l/support.c
@@ -39,6 +39,105 @@  u32 ext4l_crc32c(u32 crc, const void *address, unsigned int length)
 	return crc32c_cal(crc, address, length, ext4l_crc32c_table);
 }
 
+/*
+ * iget_locked - allocate a new inode
+ * @sb: super block of filesystem
+ * @ino: inode number to allocate
+ *
+ * U-Boot implementation: allocates ext4_inode_info and returns the embedded
+ * vfs_inode. In Linux, this would look up the inode in a hash table first.
+ * Since U-Boot is single-threaded and doesn't cache inodes, we always allocate.
+ */
+struct inode *iget_locked(struct super_block *sb, unsigned long ino)
+{
+	struct ext4_inode_info *ei;
+	struct inode *inode;
+
+	ei = kzalloc(sizeof(struct ext4_inode_info), GFP_KERNEL);
+	if (!ei)
+		return NULL;
+
+	/* Get pointer to the embedded vfs_inode using offsetof */
+	inode = (struct inode *)((char *)ei +
+				 offsetof(struct ext4_inode_info, vfs_inode));
+	inode->i_sb = sb;
+	inode->i_blkbits = sb->s_blocksize_bits;
+	inode->i_ino = ino;
+	inode->i_state = I_NEW;
+	inode->i_count.counter = 1;
+	inode->i_mapping = &inode->i_data;
+	inode->i_data.host = inode;
+	INIT_LIST_HEAD(&ei->i_es_list);
+
+	return inode;
+}
+
+/*
+ * new_inode - allocate a new empty inode
+ * @sb: super block of filesystem
+ *
+ * U-Boot implementation: allocates ext4_inode_info for a new inode that
+ * will be initialised by the caller (e.g., for creating new files).
+ */
+struct inode *new_inode(struct super_block *sb)
+{
+	struct ext4_inode_info *ei;
+	struct inode *inode;
+
+	ei = kzalloc(sizeof(struct ext4_inode_info), GFP_KERNEL);
+	if (!ei)
+		return NULL;
+
+	inode = &ei->vfs_inode;
+	inode->i_sb = sb;
+	inode->i_blkbits = sb->s_blocksize_bits;
+	inode->i_nlink = 1;
+	inode->i_count.counter = 1;
+	inode->i_mapping = &inode->i_data;
+	inode->i_data.host = inode;
+	INIT_LIST_HEAD(&ei->i_es_list);
+
+	return inode;
+}
+
+/*
+ * ext4_uboot_bmap - map a logical block to a physical block
+ * @inode: inode to map
+ * @block: on entry, logical block number; on exit, physical block number
+ *
+ * U-Boot implementation of bmap for ext4. Maps a logical block number
+ * to the corresponding physical block on disk.
+ */
+int ext4_uboot_bmap(struct inode *inode, sector_t *block)
+{
+	struct ext4_map_blocks map;
+	int ret;
+
+	map.m_lblk = *block;
+	map.m_len = 1;
+	map.m_flags = 0;
+
+	ret = ext4_map_blocks(NULL, inode, &map, 0);
+	if (ret > 0) {
+		*block = map.m_pblk;
+		return 0;
+	}
+
+	return ret < 0 ? ret : -EINVAL;
+}
+
+/*
+ * bmap - map a logical block to a physical block (VFS interface)
+ * @inode: inode to map
+ * @blockp: pointer to logical block number; updated to physical block number
+ *
+ * This is the VFS bmap interface used by jbd2.
+ */
+int bmap(struct inode *inode, sector_t *blockp)
+{
+	return ext4_uboot_bmap(inode, blockp);
+}
+
 /*
  * Buffer cache implementation
  *