前面把ext2的acl.c和acl.h文件分析过了,今天来看一个比较重要的文件,就是balloc.c,这个文件是用来做块的分配方面工作的,在文件系统是属于较低层的,可能有点困难,我努力讲解的通俗一点,大家有什么问题欢迎提问啦。
/* 作者方面的信息
* linux/fs/ext2/balloc.c
*
* Copyright (C) 1992, 1993, 1994, 1995
* Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
*
* Enhanced block allocation by Stephen Tweedie (sct@redhat.com), 1993
* Big-endian to little-endian byte-swapping/bitmaps by
* David S. Miller (davem@caip.rutgers.edu), 1995
*/
#include "ext2.h"
#include <linux/quotaops.h>
#include <linux/sched.h>
#include <linux/buffer_head.h>
#include <linux/capability.h>
/*balloc.c 包含块的分配和销毁方面的程序*/
/*在ext2文件系统,块的管理是通过位图来实现的,一个文件系统包含若干个块组,每一个块组有一个针对数据块的位图,还有一个针对inode的位图,文件系统的组描述符在超级块的后边,每一个组描述符都有空闲块的数目记录,组描述符都会在挂载文件系统的时候读到内存里。(ext2_fill_super) */
/*很简单的宏,判断b是不是在一个以first为头指针,长度为len的内存里,相信有点c语言功底的都能看懂*/
#define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1)
/*获得组描述符,block_group代表是第几个组,bh参数如果不为空,就把buffer_head形式的组描述符放在bh里*/
struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb,
unsigned int block_group,
struct buffer_head ** bh)
{
unsigned long group_desc;
unsigned long offset;
struct ext2_group_desc * desc;
/*从super_block里获得ext2_sb_info结构体,super_block是vfs便于管理设置的统一的超级块结构体,ext2_sb_info是ext2文件系统的放在内存里的超级块结构体,super_block的s_fs_info字段就是ext2_sb_info结构体,转化还是挺方便的*/
struct ext2_sb_info *sbi = EXT2_SB(sb);
/*如果参数大于组的数目,说明参数有问题,报错,返回NULL*/
if (block_group >= sbi->s_groups_count) {
ext2_error (sb, "ext2_get_group_desc",
"block_group >= groups_count - "
"block_group = %d, groups_count = %lu",
block_group, sbi->s_groups_count);
return NULL;
}
/*EXT2_DESC_PER_BLOCK_BITS宏返回块拥有组描述符的数目转换成二进制位的位数,右移这些位就等于是除以一个块拥有组描述符的数目。我猜我这么说肯定大家不懂,还是举例子吧。比如ext2的ext2_group_desc是32字节,按照ext2的一个块有1K大小来算,一个块就有32个组描述符,所以就是5位,右移五位,除以32,块组描述符是聚集在一起的,有几个块是专门房块组描述符的,在超级块里有记录,我们知道了是第几个块组,但是接下来要知道是在块组描述符群组里的第几个块,比如我们要去第45个块组,45/32=1,所以就得到了是在第二个块里,偏移就是45%32=13,也可以与位,45&(32-1)=13*/
group_desc = block_group >> EXT2_DESC_PER_BLOCK_BITS(sb);
/*这里的offset就是在块内的第几个描述符*/
offset = block_group & (EXT2_DESC_PER_BLOCK(sb) - 1);
/*sbi->s_group_desc就存放着块组描述符好几个块哦,如果为空,就说明ext2出问题了,并且很严重,报错*/
if (!sbi->s_group_desc[group_desc]) {
ext2_error (sb, "ext2_get_group_desc",
"Group descriptor not loaded - "
"block_group = %d, group_desc = %lu, desc = %lu",
block_group, group_desc, offset);
return NULL;
}
/*描述符指针指向对应的buffer_head->b_data就是组描述符所在组的第一个组描述符*/
desc = (struct ext2_group_desc *) sbi->s_group_desc[group_desc]->b_data;
/*如果参数bh不为空,就赋值组描述符的buffer_head给bh*/
if (bh)
*bh = sbi->s_group_desc[group_desc];
/*返回想要的组描述符*/
return desc + offset;
}
/*阅读给定的块组的数据块位图,如果成功,返回位图的buffer_head,失败返回NULL*/
static struct buffer_head *
read_block_bitmap(struct super_block *sb, unsigned int block_group)
{
struct ext2_group_desc * desc;
struct buffer_head * bh = NULL;
/*上边的函数,刚讲过哦,根据block_group得到块组描述符*/
desc = ext2_get_group_desc (sb, block_group, NULL);
/*失败的话,返回NULL*/
if (!desc)
goto error_out;
/*调用底层驱动函数,读取数据块位图,desc->bg_block_bitmap代表着数据块位图的块号码,返回数据块位图的buffer_head格式,sb_bread是块设备驱动和文件系统的连接函数,很重要,以后我会好好研究下它*/
bh = sb_bread(sb, le32_to_cpu(desc->bg_block_bitmap));
/*没读出来,就报错*/
if (!bh)
ext2_error (sb, "read_block_bitmap",
"Cannot read block bitmap - "
"block_group = %d, block_bitmap = %u",
block_group, le32_to_cpu(desc->bg_block_bitmap));
error_out:
return bh;
}
/*把空闲的一部分放到保留块里边,保留块是为了防止ext2出现问题,预先保留一部分以备不测,一般是5%左右,count参数就是需要放到保留块里的块数目,需要知道,空闲块的数目也包括保留块的数目,保留块肯定也是空闲块,空闲块不一定是保留块
* Set sb->s_dirt here because the superblock was "logically" altered. We
* need to recalculate its free blocks count and flush it out.
*/
static int reserve_blocks(struct super_block *sb, int count)
{
struct ext2_sb_info *sbi = EXT2_SB(sb);
struct ext2_super_block *es = sbi->s_es;
unsigned free_blocks;
unsigned root_blocks;
/*percpu_counter_read_positive函数是为了防止多处理器并发导致的读取失败,从ext2_sb_info->s_freeblocks_counter得到的是当前ext2的空闲的数据块数目*/
free_blocks = percpu_counter_read_positive(&sbi->s_freebloc