/*
 * The free blocks are managed by bitmaps.  A file system contains several
 * blocks groups.  Each group contains 1 bitmap block for blocks, 1 bitmap
 * block for inodes, N blocks for the inode table and data blocks.
 *
 * The file system contains group descriptors which are located after the
 * super block.  Each descriptor contains the number of the bitmap block and
 * the free blocks count in the block.  The descriptors are loaded in memory
 * when a file system is mounted (see ext4_fill_super).
 */

/**
 * ext4_get_group_desc() -- load group descriptor from disk
 * @sb:            super block
 * @block_group:    given block group
 * @bh:            pointer to the buffer head to store the block
 *            group descriptor
 */
struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb,
                         ext4_group_t block_group,
                         struct buffer_head **bh)
{
    unsigned int group_desc;
    unsigned int offset;
    ext4_group_t ngroups = ext4_get_groups_count(sb);
    struct ext4_group_desc *desc;
    struct ext4_sb_info *sbi = EXT4_SB(sb);

    if (block_group >= ngroups) {
        ext4_error(sb, "block_group >= groups_count - block_group = %u,"
               " groups_count = %u", block_group, ngroups);

        return NULL;
    }

    group_desc = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb);
    offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1);
    if (!sbi->s_group_desc[group_desc]) {
        ext4_error(sb, "Group descriptor not loaded - "
               "block_group = %u, group_desc = %u, desc = %u",
               block_group, group_desc, offset);
        return NULL;
    }

    desc = (struct ext4_group_desc *)(
        (__u8 *)sbi->s_group_desc[group_desc]->b_data +
        offset * EXT4_DESC_SIZE(sb));
    if (bh)
        *bh = sbi->s_group_desc[group_desc];
    return desc;
}