我们按照挂载ubifs的工序来分析代码:
)ubiattach /dev/ubi_ctrl -m 3
(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_offset)
{
//ubi_num, vid_hdr_offset是命令传进来的参数
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 serialized, 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("refuse
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;
}
} else {
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_offset = vid_hdr_offset;
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->numeraseregions != 0) {
ubi_err("multiple regions, not implemented");
return -EINVAL;
}
Numeraseregions是扫描nandflash得到的信息,如果numeraseregions等于0,代表我们需要attach的设备已经擦除过了
if (ubi->vid_hdr_offset < 0)
return -EINVAL;
ubi->vid_hdr_offset显然应该是一个正数,一般是nandflash的一页,我们的4020上的nandflash页大小为512字节,所以ubi->vid_hdr_offset为512.这儿再稍微说一下,EC header和VID header,是记录我们ubi管理信息。一般EC在一个擦除块的第一页,所以偏移量为0,VID在擦除块的第二页上,所以偏移量为512.,在我们4020的nandflash上,一个擦除块的大小为16K,也就是32页。
下面接着讲我们的扫描信息写进mtd结构体
ubi->peb_size=
ubi->mtd->erasesize;
ubi->peb_count=
ubi->mtd->size / ubi->mtd->erasesize;
是指逻辑块的数目,也就是总的大小除以每一页的大小
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_assert(ubi->hdrs_min_io_size > 0);
ubi_assert(ubi->hdrs_min_io_size <=
ubi->min_io_size);
ubi_assert(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_offset == 0)
/* Default offset */
ubi->vid_hdr_offset = ubi->vid_hdr_aloffset =
ubi->ec_hdr_alsize;
else {
ubi->vid_hdr_aloffset = ubi->vid_hdr_offset &
~(ubi->hdrs_min_io_size
- 1);
ubi->vid_hdr_shift = ubi->vid_hdr_offset -
ubi->vid_hdr_aloffset;
}
剩余的部分就不分析了,比较容易
接着上面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)
goto out_si;
err = ubi_wl_init_scan(ubi, si);
**********************************************************************************
取之ubi_wl_init_scan(ubi, si);函数片段
list_for_each_entry_safe(seb,
tmp, &si->erase, u.list) {
cond_resched();
e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
if (!e)
goto out_free;
e->pnum = seb->pnum;
e->ec = seb->ec;
ubi->lookuptbl[e->pnum] = e;
if (schedule_erase(ubi, e, 0)) {
kmem_cache_free(ubi_wl_entry_slab, e);
goto out_free;
}
}
在初始化wl的时候会将为每一个空页建立一个struct ubi_work *wl_wrk;结构体(该结构体的具体处理函数为erase_worker,擦除一块,并写入EC头),并添加到ubi->works队列中(list_add_tail(&wrk->list,
&));这儿我们渐渐的认识到ubi->works这个队列的作用,后台进程ubi_thread就是循环的处理该队列中的工作的。
在第一次attach的时候,在这儿ubi_thread进程还没有被唤醒,所以这些工作要等到进程被唤醒的时候才能被处理
**********************************************************************************
if (err)
goto out_vtbl;
err =
ubi_eba_init_scan(ubi, si);
**********************************************************************************
前面我们看到了ubi_scan,其实这个这个过程是建立ubifs的基础,因为所有关于ubi和ubifs的基本信息都是在scan的过程中建立在内存中的,现在调用ubi_eba_init_scan来建立起EBA子系统就是利用前面的扫描信息,建立起没一个volumn的vtl。
if (err)
goto out_wl;
ubi_scan_destroy_si(si);
return 0;
out_wl:
ubi_wl_close(ubi);
out_vtbl:
free_internal_volumes(ubi);
vfree(ubi->vtbl);
out_si:
ubi_scan_destroy_si(si);
return err;
}
.Ubi_scan
struct ubi_scan_info
*ubi_scan(struct ubi_device *ubi)
{
int err, pnum;
struct rb_node *rb1, *rb2;
struct ubi_scan_volume *sv;
struct ubi_scan_leb *seb;
struct ubi_scan_info *si;
si = kzalloc(sizeof(struct ubi_scan_info), GFP_KERNEL);
if (!si)
return ERR_PTR(-ENOMEM);
初始化si的corrupt队列
INIT_LIST_HEAD(&si->free);// //初始化si的corrupt队列
初始化si的corrupt队列
INIT_LIST_HEAD(&si->alien); //初始化si的corrupt队列
si->volumes = RB_ROOT;
只是空的,哈哈
si->is_empty = 1;
err = -ENOMEM;
ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);//为ec头部分配空间,用于暂存后面读出的每一个peb的ec头部信息
if (!ech)
goto out_si;
vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);//为vid头部分配空间,用于暂存后面读出的每一个peb的vid头部信息,注意扫描的目的就是收集EC和VID中信息,在内存中建立相关的信息
if (!vidh)
goto out_ech;
for (pnum = 0; pnum < ubi->peb_count; pnum++) {
cond_resched();
dbg_gen("process PEB %d", pnum);
err = process_eb(ubi, si, pnum);//具体的扫描每一个物理块
if (err < 0)
goto out_vidh;
}
dbg_msg("scanning is finished");
/* Calculate mean erase counter */
if (si->ec_count)//算平均擦除次数
si->mean_ec = div_u64(si->ec_sum,
si->ec_count);
if (si->is_empty)//判断这是否是一个空的MTD,如果是空的话,那么后面的mount的时候调用create_default_filesystem在建立初始的ubifs数据
ubi_msg("empty MTD device detected");
/*
* Few corrupted PEBs
are not a problem and may be just a result of
* unclean reboots.
However, many of them may indicate some problems
* with the flash HW or
driver. Print a warning in this case.
*/
if (si->corr_count >= 8 || si->corr_count >=
ubi->peb_count / 4) {
ubi_warn("%d PEBs are corrupted",
si->corr_count);
printk(KERN_WARNING "corrupted PEBs are:");
list_for_each_entry(seb, &si->corr, u.list)
printk(KERN_CONT " %d", seb->pnum);
printk(KERN_CONT "\n");
}
/*
* In case of unknown
erase counter we use the mean erase counter
* value.
*/
ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) {
ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb)
if (seb->ec == UBI_SCAN_UNKNOWN_EC)
seb->ec = si->mean_ec;
}
list_for_each_entry(seb, &si->free, u.list) {
if (seb->ec == UBI_SCAN_UNKNOWN_EC)
seb->ec = si->mean_ec;
}
list_for_each_entry(seb, &si->corr, u.list)
if (seb->ec == UBI_SCAN_UNKNOWN_EC)
seb->ec = si->mean_ec;
list_for_each_entry(seb, &si->erase, u.list)
if (seb->ec == UBI_SCAN_UNKNOWN_EC)
seb->ec = si->mean_ec;
err = paranoid_check_si(ubi, si);
if (err) {
if (err > 0)
err = -EINVAL;
goto out_vidh;
}
ubi_free_vid_hdr(ubi, vidh);
kfree(ech);
return si;
out_vidh:
ubi_free_vid_hdr(ubi, vidh);
out_ech:
kfree(ech);
out_si:
ubi_scan_destroy_si(si);
return ERR_PTR(err);
}
.process_eb
static int
process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,int pnum)
{
long long uninitialized_var(ec);
int err, bitflips = 0, vol_id, ec_corr = 0;
dbg_bld("scan PEB %d", pnum);
/* Skip bad physical eraseblocks */
err = ubi_io_is_bad(ubi, pnum);
判断一个块是否为坏块,直接调用mtd层的mtd->block_isbad
if (err < 0)
return err;
else if (err) {
/*
* FIXME: this is
actually duty of the I/O sub-system to
* initialize
this, but MTD does not provide enough
* information.
*/
si->bad_peb_count += 1;
return 0;
}
err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0);//读ec header,一般为一块的第一页
if (err < 0)
return err;
else if (err == UBI_IO_BITFLIPS)
bitflips = 1;
else if (err == UBI_IO_PEB_EMPTY)
return add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC,
&si->erase);
//注意这儿,为什么这个块是empty(也就是全是0xff),还要丢到si->erase队列中呢?这是因为MTD所谓的空与UBI所谓的空不是一回事。在UBI中,空块是指只包含EC头部的块。所以这些需要将全0xff的块进行擦除,写入EC头部
else if (err == UBI_IO_BAD_EC_HDR) {
/*
* We have to
also look at the VID header, possibly it is not
* corrupted. Set
%bitflips flag in order to make this PEB be
* moved and EC
be re-created.
*/
ec_corr = 1;
ec = UBI_SCAN_UNKNOWN_EC;
bitflips = 1;
}
si->is_empty = 0;
if (!ec_corr) {
int image_seq;
/* Make sure UBI version is OK */
if (ech->version != UBI_VERSION) {
ubi_err("this UBI version is %d, image
version is %d",
UBI_VERSION, (int)ech->version);
return -EINVAL;
}
ec = be64_to_cpu(ech->ec);
if (ec > UBI_MAX_ERASECOUNTER) {
/*
* Erase
counter overflow. The EC headers have 64 bits
*
reserved, but we anyway make use of only 31 bit
* values,
as this seems to be enough for any existing
* flash.
Upgrade UBI and use 64-bit erase counters
*
internally.
*/
ubi_err("erase counter overflow, max is
%d",
ubi_dbg_dump_ec_hdr(ech);
return -EINVAL;
}
/*
* Make sure that
all PEBs have the same image sequence number.
* This allows us
to detect situations when users flash UBI
* images
incorrectly, so that the flash has the new UBI image
* and leftovers
from the old one. This feature was added
* relatively
recently, and the sequence number was always
* zero, because
old UBI implementations always set it to zero.
* For this
reasons, we do not panic if some PEBs have zero
* sequence
number, while other PEBs have non-zero sequence
* number.
*/
image_seq = be32_to_cpu(ech->image_seq);
if (!ubi->image_seq && image_seq)
ubi->image_seq = image_seq;
if (ubi->image_seq && image_seq &&
ubi->image_seq
!= image_seq) {
ubi_err("bad image sequence number %d in
PEB %d, "
"expected %d", image_seq, pnum,
ubi->image_seq);
ubi_dbg_dump_ec_hdr(ech);