ubi文件系统分析
http://download.csdn.net/detail/songqqnew/4919666

drivers/mtd/ubi/build.c

mtd_devs是ubi卷和mtd分区绑定的数目。mtd_devs初始值=0,每执行一次ubi_mtd_param_parse,mtd_devs+1
ubi_mtd_param_parse在内核初期初始化执行parse_args时调用到(而build.c里的module_param_call(mtd, ubi_mtd_param_parse, NULL, NULL, 000)指定在解析到mtd=时,调用ubi_mtd_param_parse去处理)。

/*** ubi_mtd_param_parse - parse the 'mtd=' UBI parameter.* @val: the parameter value to parse* @kp: not used** This function returns zero in case of success and a negative error code in* case of error.*/
static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp)
{
//比如 Linux-CommandLine = root=ubi0:FriendlyARM-root ubi.mtd=2 rootfstype=ubifs init=/linuxrc console=ttySAC0,115200
// 则val = 2int i, len;struct mtd_dev_param *p;char buf[MTD_PARAM_LEN_MAX];char *pbuf = &buf[0];char *tokens[2] = {NULL, NULL};if (!val)return -EINVAL;if (mtd_devs == UBI_MAX_DEVICES) {printk(KERN_ERR "UBI error: too many parameters, max. is %d\n",UBI_MAX_DEVICES);return -EINVAL;}len = strnlen(val, MTD_PARAM_LEN_MAX);if (len == MTD_PARAM_LEN_MAX) {printk(KERN_ERR "UBI error: parameter \"%s\" is too long, ""max. is %d\n", val, MTD_PARAM_LEN_MAX);return -EINVAL;}if (len == 0) {printk(KERN_WARNING "UBI warning: empty 'mtd=' parameter - ""ignored\n");return 0;}strcpy(buf, val);/* Get rid of the final newline */if (buf[len - 1] == '\n')buf[len - 1] = '\0';for (i = 0; i < 2; i++)tokens[i] = strsep(&pbuf, ",");if (pbuf) {printk(KERN_ERR "UBI error: too many arguments at \"%s\"\n",val);return -EINVAL;}p = &mtd_dev_param[mtd_devs];strcpy(&p->name[0], tokens[0]);if (tokens[1])p->vid_hdr_offs = bytes_str_to_int(tokens[1]);if (p->vid_hdr_offs < 0)return p->vid_hdr_offs;mtd_devs += 1;return 0;
}

build.c中模块入口函数是ubi_init,此函数中使用ubi_attach_mtd_dev将ubi volume和mtd分区绑定,绑定mtd_devs次

在ubi_attach_mtd_dev函数中,使用io_init和attach_by_scanning函数对ubi结构体的成员初始化或赋值
其中io_init主要是初始化leb,peb的大小数量,最小读写字节数等全局一些的成员
而attach_by_scanning读取整个mtd分区的所有peb(物理擦除块)的ec和vid,对块进行检查和统计

attach_by_scanning中调用了ubi_scan函数对整个mtd分区扫描
drivers/mtd/ubi/build.c

/*** attach_by_scanning - attach an MTD device using scanning method.* @ubi: UBI device descriptor** This function returns zero in case of success and a negative error code in* case of failure.** Note, currently this is the only method to attach UBI devices. Hopefully in* the future we'll have more scalable attaching methods and avoid full media* scanning. But even in this case scanning will be needed as a fall-back* attaching method if there are some on-flash table corruptions.*/
static int attach_by_scanning(struct ubi_device *ubi)
{int err;struct ubi_scan_info *si;si = ubi_scan(ubi);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->corr_peb_count = si->corr_peb_count;ubi->max_ec = si->max_ec;ubi->mean_ec = si->mean_ec;ubi_msg("max. sequence number:       %llu", si->max_sqnum);err = ubi_read_volume_table(ubi, si);if (err)goto out_si;err = ubi_wl_init_scan(ubi, si);if (err)goto out_vtbl;err = ubi_eba_init_scan(ubi, si);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---------->process_eb(处理每个物理擦除块)-------->ubi_io_read_ec_hdr(读取ec头)--------->ubi_io_read-->ubi->mtd->read------------而read函数就是每个分区对应的mtd_info结构体的read成员函数,即mtdpart.c中的part_read(drivers/mtd/mtdpart.c)--------->part->master->read,这个read函数调用nand_do_read_ops(drivers/mtd/nand/nand_base.c),但此时还不是真正的从nand上读取数据,如下代码所示,此函数又会根据对其方式等,而调用其下3者之1
chip->ecc.read_page_raw-------->nand_read_page_raw------->chip->read_buf (在nand_base.c)
chip->ecc.read_subpage-------->nand_read_subpage--------->chip->read_buf (在nand_base.c)
chip->ecc.read_page--------->s3c_nand_read_page_1bit(如果是1GB SLC是调用的这个函数,在s3c_nand.c)


if (!chip->read_buf)//如果在s3c_nand.c中未定义,则使用nand_base.c中的下面的2个函数之1
chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;

/**
 * nand_read_buf - [DEFAULT] read chip data into buffer
 * @mtd: MTD device structure
 * @buf: buffer to store date
 * @len: number of bytes to read
 *
 * Default read function for 8bit buswith
 */
static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
{
int i;
struct nand_chip *chip = mtd->priv;
for (i = 0; i < len; i++)
buf[i] = readb(chip->IO_ADDR_R);
}

static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,struct mtd_oob_ops *ops)
{int chipnr, page, realpage, col, bytes, aligned;struct nand_chip *chip = mtd->priv;struct mtd_ecc_stats stats;int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;int sndcmd = 1;int ret = 0;uint32_t readlen = ops->len;uint32_t oobreadlen = ops->ooblen;uint32_t max_oobsize = ops->mode == MTD_OOB_AUTO ?mtd->oobavail : mtd->oobsize;uint8_t *bufpoi, *oob, *buf;stats = mtd->ecc_stats;chipnr = (int)(from >> chip->chip_shift);chip->select_chip(mtd, chipnr);realpage = (int)(from >> chip->page_shift);page = realpage & chip->pagemask;col = (int)(from & (mtd->writesize - 1));buf = ops->datbuf;oob = ops->oobbuf;while (1) {bytes = min(mtd->writesize - col, readlen);aligned = (bytes == mtd->writesize);/* Is the current page in the buffer ? */if (realpage != chip->pagebuf || oob) {bufpoi = aligned ? buf : chip->buffers->databuf;if (likely(sndcmd)) {chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);sndcmd = 0;}/* Now read the page into the buffer ******************************************************************/if (unlikely(ops->mode == MTD_OOB_RAW))ret = chip->ecc.read_page_raw(mtd, chip,bufpoi, page);else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob)ret = chip->ecc.read_subpage(mtd, chip,col, bytes, bufpoi);elseret = chip->ecc.read_page(mtd, chip, bufpoi,page);if (ret < 0)break;/* Transfer not aligned data ****************************************************************************/if (!aligned) {if (!NAND_SUBPAGE_READ(chip) && !oob &&!(mtd->ecc_stats.failed - stats.failed))chip->pagebuf = realpage;memcpy(buf, chip->buffers->databuf + col, bytes);}buf += bytes;if (unlikely(oob)) {int toread = min(oobreadlen, max_oobsize);if (toread) {oob = nand_transfer_oob(chip,oob, ops, toread);oobreadlen -= toread;}}if (!(chip->options & NAND_NO_READRDY)) {/** Apply delay or wait for ready/busy pin. Do* this before the AUTOINCR check, so no* problems arise if a chip which does auto* increment is marked as NOAUTOINCR by the* board driver.*/if (!chip->dev_ready)udelay(chip->chip_delay);elsenand_wait_ready(mtd);}} else {memcpy(buf, chip->buffers->databuf + col, bytes);buf += bytes;}readlen -= bytes;if (!readlen)break;/* For subsequent reads align to page boundary. */col = 0;/* Increment page address */realpage++;page = realpage & chip->pagemask;/* Check, if we cross a chip boundary */if (!page) {chipnr++;chip->select_chip(mtd, -1);chip->select_chip(mtd, chipnr);}/* Check, if the chip supports auto page increment* or if we have hit a block boundary.*/if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck))sndcmd = 1;}ops->retlen = ops->len - (size_t) readlen;if (oob)ops->oobretlen = ops->ooblen - oobreadlen;if (ret)return ret;if (mtd->ecc_stats.failed - stats.failed)return -EBADMSG;return  mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
}

ubi_scan-->process_eb(处理每个物理擦除块)-->ubi_io_read_vid_hdr(读取vid头)-->

/*** process_eb - read, check UBI headers, and add them to scanning information.* @ubi: UBI device description object* @si: scanning information* @pnum: the physical eraseblock number** This function returns a zero if the physical eraseblock was successfully* handled and a negative error code in case of failure.*/
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_err = 0;dbg_bld("scan PEB %d", pnum);/* Skip bad physical eraseblocks */err = ubi_io_is_bad(ubi, pnum);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);if (err < 0)return err;switch (err) {case 0:break;case UBI_IO_BITFLIPS:bitflips = 1;break;case UBI_IO_FF:si->empty_peb_count += 1;return add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, 0,&si->erase);case UBI_IO_FF_BITFLIPS:si->empty_peb_count += 1;return add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, 1,&si->erase);case UBI_IO_BAD_HDR_EBADMSG:case UBI_IO_BAD_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_err = err;ec = UBI_SCAN_UNKNOWN_EC;bitflips = 1;break;default:ubi_err("'ubi_io_read_ec_hdr()' returned unknown code %d", err);return -EINVAL;}if (!ec_err) {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_MAX_ERASECOUNTER);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);return -EINVAL;}}/* OK, we've done with the EC header, let's look at the VID header */err = ubi_io_read_vid_hdr(ubi, pnum, vidh, 0);if (err < 0)return err;switch (err) {case 0:break;case UBI_IO_BITFLIPS:bitflips = 1;break;case UBI_IO_BAD_HDR_EBADMSG:if (ec_err == UBI_IO_BAD_HDR_EBADMSG)/** Both EC and VID headers are corrupted and were read* with data integrity error, probably this is a bad* PEB, bit it is not marked as bad yet. This may also* be a result of power cut during erasure.*/si->maybe_bad_peb_count += 1;case UBI_IO_BAD_HDR:if (ec_err)/** Both headers are corrupted. There is a possibility* that this a valid UBI PEB which has corresponding* LEB, but the headers are corrupted. However, it is* impossible to distinguish it from a PEB which just* contains garbage because of a power cut during erase* operation. So we just schedule this PEB for erasure.** Besides, in case of NOR flash, we deliberatly* corrupt both headers because NOR flash erasure is* slow and can start from the end.*/err = 0;else/** The EC was OK, but the VID header is corrupted. We* have to check what is in the data area.*/err = check_corruption(ubi, vidh, pnum);if (err < 0)return err;else if (!err)/* This corruption is caused by a power cut */err = add_to_list(si, pnum, ec, 1, &si->erase);else/* This is an unexpected corruption */err = add_corrupted(si, pnum, ec);if (err)return err;goto adjust_mean_ec;case UBI_IO_FF_BITFLIPS:err = add_to_list(si, pnum, ec, 1, &si->erase);if (err)return err;goto adjust_mean_ec;case UBI_IO_FF:if (ec_err)err = add_to_list(si, pnum, ec, 1, &si->erase);elseerr = add_to_list(si, pnum, ec, 0, &si->free);if (err)return err;goto adjust_mean_ec;default:ubi_err("'ubi_io_read_vid_hdr()' returned unknown code %d",err);return -EINVAL;}vol_id = be32_to_cpu(vidh->vol_id);if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOLUME_ID) {int lnum = be32_to_cpu(vidh->lnum);/* Unsupported internal volume */switch (vidh->compat) {case UBI_COMPAT_DELETE:ubi_msg("\"delete\" compatible internal volume %d:%d"" found, will remove it", vol_id, lnum);err = add_to_list(si, pnum, ec, 1, &si->erase);if (err)return err;return 0;case UBI_COMPAT_RO:ubi_msg("read-only compatible internal volume %d:%d"" found, switch to read-only mode",vol_id, lnum);ubi->ro_mode = 1;break;case UBI_COMPAT_PRESERVE:ubi_msg("\"preserve\" compatible internal volume %d:%d"" found", vol_id, lnum);err = add_to_list(si, pnum, ec, 0, &si->alien);if (err)return err;return 0;case UBI_COMPAT_REJECT:ubi_err("incompatible internal volume %d:%d found",vol_id, lnum);return -EINVAL;}}if (ec_err)ubi_warn("valid VID header but corrupted EC header at PEB %d",pnum);err = ubi_scan_add_used(ubi, si, pnum, ec, vidh, bitflips);if (err)return err;adjust_mean_ec:if (!ec_err) {si->ec_sum += ec;si->ec_count += 1;if (ec > si->max_ec)si->max_ec = ec;if (ec < si->min_ec)si->min_ec = ec;}return 0;
}

转载于:https://www.cnblogs.com/-song/archive/2012/12/21/3331832.html

nand ubi - 5 kernel和ubi相关推荐

  1. linux ubi 分区,Linux最新UBI文件系统介绍

    嵌入式linux中文站关注嵌入式linux文件系统的发展.在linux-2.6.27以前,谈到Flash文件系统,大家很多时候多会想到cramfs.jffs2.yaffs2等文件系统.它们也都是基于文 ...

  2. 解压ubi文件_制作ubi文件系统

    制作 ubi 文件系统 目录 开发环境 ................................................................................ ...

  3. nand ubi -4 kernel和mtd

    tiny6410 linux2.6.38 1.nand驱动 nand是作为平台设备,在板子文件mach-mini6410.c调用,系统启动时自动加载进内核 static struct platform ...

  4. nand flash换nor flash ubi换squashfs

    分区 rootfs在分区6  1.uboot修改  及bootloader修改 bootargs:earlyprintk console=ttyS0,115200 rootwait nprofile_ ...

  5. nand ubi -3 uboot和ubi

    转载于:https://www.cnblogs.com/-song/archive/2012/12/07/3331836.html

  6. squashfs重打包和ubi重打包

    先查询文件系统相关信息 unsquashfs -s jike.squashfs Found a valid SQUASHFS 4:0 superblock on jike.squashfs. Crea ...

  7. u-boot中nand相关命令使用---- ubi, ubifsls, ubifsmount, ubifsumount

    [Version: 2013-01-rc2] [Author: Bo Shen <voice.shen@gmail.com>] 1.  帮助信息 1.1 ubi ------------- ...

  8. UBI 文件系统移植 sys 设备信息【转】

    转自:http://blog.chinaunix.net/uid-25304914-id-3058647.html cat /sys/class/misc/ubi_ctrl/dev --------- ...

  9. UBIFS - UBI File-System

    参考:http://www.linux-mtd.infradead.org/doc/ubifs.html#L_raw_vs_ftl UBIFS - UBI File-System Table of c ...

最新文章

  1. linux的阻塞waitqueue,Linux阻塞控制 wait_event与wait_event_interruptible函数详解
  2. 国内小程序生态服务平台即速应用完成5000万元A+轮融资
  3. Spring AOP进行日志记录,管理
  4. Autoencoder 详解
  5. 数据库-关系代数的分类
  6. Linux 阻塞和非阻塞IO 实验
  7. 创建型、结构型、行为型模式(1)
  8. java启动应用_java 学习:在java中启动其他应用,由jenkins想到的
  9. 利用c语言面向对象编程,用C语言程序实现面向对象编程
  10. 猎人能单拿修理机器人图纸_南京创新周麒麟行:他们为铁路配备“体检”机器人...
  11. 【C++ 与 STL】栈:stack
  12. https://blog.csdn.net/Darryl_Tang/article/details/80545688
  13. 阿里巴巴国际站全屏代码装修贸店铺装修平台国际站平台全屏代码装修方法教程视频教程
  14. 吴晓波罗振宇2019跨年演讲感想
  15. 基于区块链的二维码门禁系统成品演示视频
  16. 《大明王朝1566》台词摘录
  17. 推荐系统实践(八)UCG 利用ltf-idf方法
  18. vm打开虚拟机提示“未能启动虚拟机“解决方案
  19. 两个有序表的合并(三种方法)
  20. 单频信号的相位谱计算与误差修正-附Matlab代码

热门文章

  1. Python数据结构与算法--数据类型
  2. 金属的特性只是一种状态
  3. 联想天工 802.1x认证 主程序
  4. 为数据中心度身定制智能基础设施管理系统
  5. 我的20天项目经历--至今令我难忘的技术难题
  6. ORACLE PERFORMANCE TUNING 原厂培训.笔记1
  7. java动态添加view
  8. Python多线程下载网络URL图片的方法
  9. Eclipse没有server 配置Tomcat
  10. Spring Security构建Rest服务-1400-授权