Re: [PATCH v6 03/24] erofs: add super block operations

Christoph Hellwig
2019-08-29T10:16:03Z

On Fri, Aug 02, 2019 at 08:53:26PM +0800, Gao Xiang wrote:
> +static int __init erofs_init_inode_cache(void)
> +{
> + erofs_inode_cachep = kmem_cache_create("erofs_inode",
> + sizeof(struct erofs_vnode), 0,
> + SLAB_RECLAIM_ACCOUNT,
> + init_once);
> +
> + return erofs_inode_cachep ? 0 : -ENOMEM;

Please just use normal if/else. Also having this function seems
entirely pointless.

> +static void erofs_exit_inode_cache(void)
> +{
> + kmem_cache_destroy(erofs_inode_cachep);
> +}

Same for this one.

> +static void free_inode(struct inode *inode)

Please use an erofs_ prefix for all your functions.

> +{
> + struct erofs_vnode *vi = EROFS_V(inode);

Why is this called vnode instead of inode? That seems like a rather
odd naming for a Linux file system.

> +
> + /* be careful RCU symlink path (see ext4_inode_info->i_data)! */
> + if (is_inode_fast_symlink(inode))
> + kfree(inode->i_link);

is_inode_fast_symlink only shows up in a later patch. And really
obsfucates the check here in the only caller as you can just do an
unconditional kfree here - i_link will be NULL except for the case
where you explicitly set it.

Also this code is nothing like ext4, so the code seems a little confusing.

> +static bool check_layout_compatibility(struct super_block *sb,
> + struct erofs_super_block *layout)
> +{
> + const unsigned int requirements = le32_to_cpu(layout->requirements);

Why is the variable name for the on-disk subperblock layout? We usually
still calls this something with sb in the name, e.g. dsb. for disk
super block.

> + EROFS_SB(sb)->requirements = requirements;
> +
> + /* check if current kernel meets all mandatory requirements */
> + if (requirements & (~EROFS_ALL_REQUIREMENTS)) {
> + errln("unidentified requirements %x, please upgrade kernel version",
> + requirements & ~EROFS_ALL_REQUIREMENTS);
> + return false;
> + }
> + return true;

Note that normally we call this features, but that doesn't really
matter too much.

> +static int superblock_read(struct super_block *sb)
> +{
> + struct erofs_sb_info *sbi;
> + struct buffer_head *bh;
> + struct erofs_super_block *layout;
> + unsigned int blkszbits;
> + int ret;
> +
> + bh = sb_bread(sb, 0);

Is there any good reasons to use buffer heads like this in new code
vs directly using bios?

> +
> + sbi->blocks = le32_to_cpu(layout->blocks);
> + sbi->meta_blkaddr = le32_to_cpu(layout->meta_blkaddr);
> + sbi->islotbits = ffs(sizeof(struct erofs_inode_v1)) - 1;
> + sbi->root_nid = le16_to_cpu(layout->root_nid);
> + sbi->inos = le64_to_cpu(layout->inos);
> +
> + sbi->build_time = le64_to_cpu(layout->build_time);
> + sbi->build_time_nsec = le32_to_cpu(layout->build_time_nsec);
> +
> + memcpy(&sb->s_uuid, layout->uuid, sizeof(layout->uuid));
> + memcpy(sbi->volume_name, layout->volume_name,
> + sizeof(layout->volume_name));

s_uuid should preferably be a uuid_t (assuming it is a real BE uuid,
if it is le it should be a guid_t).

> +/* set up default EROFS parameters */
> +static void default_options(struct erofs_sb_info *sbi)
> +{
> +}

No need to add an empty function.

> +static int erofs_fill_super(struct super_block *sb, void *data, int silent)
> +{
> + struct inode *inode;
> + struct erofs_sb_info *sbi;
> + int err;
> +
> + infoln("fill_super, device -> %s", sb->s_id);
> + infoln("options -> %s", (char *)data);

That is some very verbose debug info. We usually don't add that and
let people trace the function instead. Also you should probably
implement the new mount API.
new mount API.

> +static void erofs_kill_sb(struct super_block *sb)
> +{
> + struct erofs_sb_info *sbi;
> +
> + WARN_ON(sb->s_magic != EROFS_SUPER_MAGIC);
> + infoln("unmounting for %s", sb->s_id);
> +
> + kill_block_super(sb);
> +
> + sbi = EROFS_SB(sb);
> + if (!sbi)
> + return;
> + kfree(sbi);
> + sb->s_fs_info = NULL;
> +}

Why is this needed? You can just free your sb privatte information in
->put_super and wire up kill_block_super as the ->kill_sb method
directly.