UBIFS⽂件系统源码分析
课程教育研究
⼀):挂载UBIFS的代码分析
陆陆续续的看UBIFS很长时间了,⼀直没有写出⼀点东西。因为我在=到能够系统的理解UBIFS的时候再写出⼀点东西。但是因为⼯作⽐较忙,UBIFS源码读的断断续续,⽼是需要复习拾起,⽐较浪费时间,所以决定写出⼀点东西,做个备份吧。
白菜炒豆芽我决定在读UBIFS源码之前需要读两份关于UBIF设计的⽂档:
⼀份是《UBI-Unsorted Block Images》
另外⼀份是《A Brief Introduction to the design of UBIFS》
这两份简洁的介绍了UBIFS设计的⼀些结构和考虑。
我们按照挂载ubifs的⼯序来分析代码:
(2)ubimkvol /dev/ubi0 -N ubifs -s 15MiB
(3)mount -t ubifs ubi0:ubifs /mnt
⾸先先分析(1),相应的代码是ubi_attach_mtd_dev()函数,下⾯我们紧跟代码来看看究竟⼲了些什么。
.ubi_attach_mtd_dev
int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offt)
{
//ubi_num, vid_hdr_offt是命令传进来的参数
struct ubi_device *ubi;
int i, err, do_free = 1;
/*
* Check if we already have the same MTD device attached.
*
* Note, this function assumes that UBI devices creations and deletions
* are rialized, so it does not take the &ubi_devices_lock.
*/
for (i = 0; i < UBI_MAX_DEVICES; i++) {
ubi = ubi_devices[i];
政务公开的意义if (ubi && mtd->index == ubi->mtd->index) {
dbg_err("mtd%d is already attached to ubi%d",
mtd->index, i);
return -EEXIST;
}
}
//上⾯的这段代码可以看英⽂注释,⼀个mtd设备(⼀个分区)不能被attach两次,除⾮你已经deatch了。所以在这段代码的开始就检查被attach的mtd设备是否已经被attach了。八下语文古诗词
if (mtd->type == MTD_UBIVOLUME) {
ubi_err("refu attaching mtd%d - it is already emulated on "
"top of UBI", mtd->index);
return -EINVAL;
}
上⾯的代码接着检查被attach的mtd设备时候是⼀个mtd volume(卷区),如果已经是⼀个mtd卷了,那么就不能再被attach了。
if (ubi_num == UBI_DEV_NUM_AUTO) {
for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++)
if (!ubi_devices[ubi_num])
break;
如果在终端输⼊命令的时候没有带ubinum,那么就是⾃动分配ubinum,系统就会从ubi_device[]数组中找出⼀个没被使⽤的ubinum号 if (ubi_num == UBI_MAX_DEVICES) {
dbg_err("only %d UBI devices may be created",
return -ENFILE;
}
} el {
if (ubi_num >= UBI_MAX_DEVICES)
return -EINVAL;
如果ubi_num > UBI_MAX_DEVICES,就代表没有空余ubinum号可供分配,返回出错
/* Make sure ubi_num is not busy */
if (ubi_devices[ubi_num]) {
dbg_err("ubi%d already exists", ubi_num);
return -EEXIST;
}莆田九鲤湖
}
ubi = kzalloc(sizeof(struct ubi_device), GFP_KERNEL);
if (!ubi)
return -ENOMEM;
ubi->mtd = mtd;
ubi->ubi_num = ubi_num;
ubi->vid_hdr_offt = vid_hdr_offt;
ubi->autoresize_vol_id = -1;
mutex_init(&ubi->buf_mutex);
mutex_init(&ubi->ckvol_mutex);
mutex_init(&ubi->mult_mutex);
mutex_init(&ubi->volumes_mutex);
spin_lock_init(&ubi->volumes_lock);
托福拼分初始化信号
ubi_msg("attaching mtd%d to ubi%d", mtd->index, ubi_num);
err =io_init(ubi);
if (err)
goto out_free;
下⾯跟着io_init()往下分析:
static int io_init(struct ubi_device *ubi)
{
if (ubi->mtd->numeraregions != 0) {
ubi_err("multiple regions, not implemented");
return -EINVAL;
}
Numeraregions是扫描nandflash得到的信息,如果numeraregions等于0,代表我们需要attach的设备已经擦除过了
if (ubi->vid_hdr_offt < 0)
return -EINVAL;
ubi->vid_hdr_offt显然应该是⼀个正数,⼀般是nandflash的⼀页,我们的4020上的nandflash页⼤⼩为512字节,所以ubi-
>vid_hdr_offt为512.这⼉再稍微说⼀下,EC header和VID header,是记录我们ubi管理信息。⼀般
EC在⼀个擦除块的第⼀页,所以偏移量为0,VID在擦除块的第⼆页上,所以偏移量为512.,在我们4020的nandflash上,⼀个擦除块的⼤⼩为16K,也就是32页。
下⾯接着讲我们的扫描信息写进mtd结构体
ubi->peb_size = ubi->mtd->erasize;
ubi->peb_count = ubi->mtd->size / ubi->mtd->erasize;
是指逻辑块的数⽬,也就是总的⼤⼩除以每⼀页的⼤⼩
ubi->flash_size = ubi->mtd->size;
if (ubi->mtd->block_isbad && ubi->mtd->block_markbad)
ubi->bad_allowed = 1;
ubi->min_io_size = ubi->mtd->writesize;
ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft; if (!is_power_of_2(ubi->min_io_size)) {
ubi_err("min. I/O unit (%d) is not power of 2",
ubi->min_io_size);
return -EINVAL;
}
ubi_asrt(ubi->hdrs_min_io_size > 0);
ubi_asrt(ubi->hdrs_min_io_size <= ubi->min_io_size);
苏烈最强出装ubi_asrt(ubi->min_io_size % ubi->hdrs_min_io_size == 0);
/* Calculate default aligned sizes of EC and VID headers */
ubi->ec_hdr_alsize = ALIGN(UBI_EC_HDR_SIZE, ubi->hdrs_min_io_size); ubi->vid_hdr_alsize = ALIGN(UBI_VID_HDR_SIZE, ubi->hdrs_min_io_size);
dbg_msg("min_io_size %d", ubi->min_io_size);
dbg_msg("hdrs_min_io_size %d", ubi->hdrs_min_io_size);
dbg_msg("ec_hdr_alsize %d", ubi->ec_hdr_alsize);
dbg_msg("vid_hdr_alsize %d", ubi->vid_hdr_alsize);
if (ubi->vid_hdr_offt == 0)
/* Default offt */
ubi->vid_hdr_offt = ubi->vid_hdr_alofft =
ubi->ec_hdr_alsize;
el {
ubi->vid_hdr_alofft = ubi->vid_hdr_offt &
~(ubi->hdrs_min_io_size - 1);
ubi->vid_hdr_shift = ubi->vid_hdr_offt -
ubi->vid_hdr_alofft;
}
剩余的部分就不分析了,⽐较容易
接着上⾯ubi_attach_mtd_dev()往下说:
ubi->peb_buf1 = vmalloc(ubi->peb_size);
if (!ubi->peb_buf1)
goto out_free;
ubi->peb_buf2 = vmalloc(ubi->peb_size);
if (!ubi->peb_buf2)
goto out_free;
分配两个物理擦除块⼤⼩的buf,具体的⽤途下⾯再说
err = attach_by_scanning(ubi);
if (err) {
dbg_err("failed to attach by scanning, error %d", err);
goto out_free;
}
我们再跟着attach_by_scanning(ubi)细说
static int attach_by_scanning(struct ubi_device *ubi)
{
int err;
struct ubi_scan_info *si;
si = ubi_scan(ubi);
**********************************************************************************
这⼉通过ubi_scan函数来扫描MTD分区的每⼀块。具体是调⽤static int process_eb(struct ubi_device *ubi, struct ubi_scan_info
*si,int pnum)函数来读取EC和VID头(即没⼀块的前两页),在读每⼀页的时候,会调⽤check_pattern函数来判断这⼀页是否为空,如果每⼀页都是空的,那么就会发现这个MTD分区是空的。
**********************************************************************************
if (IS_ERR(si))
return PTR_ERR(si);
ubi->bad_peb_count = si->bad_peb_count;
ubi->good_peb_count = ubi->peb_count - ubi->bad_peb_count;
ubi->max_ec = si->max_ec;
ubi->mean_ec = si->mean_ec;
err = ubi_read_volume_table(ubi, si);
if (err)
1971年属什么生肖