ubifs文件系统代码解析

注:源码取的是v5.10.135版本,仅供个人学习使用
在线阅读地址:https://elixir.bootlin.com/linux/v5.10.135/source/fs/ubifs
ubiattach
ubimkvol
mount

ubiattach
作用:将指定的mtd分区关联到ubi上
举例:ubiattach /dev/ubi_ctrl -m 3**

int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,int vid_hdr_offset, int max_beb_per1024)
{struct ubi_device *ubi;int i, err;/* * max_beb_per1024:maximum expected number of bad PEBs per 1024 PEBs* 翻译过来就是,每1024个PEB中,允许的最大坏块数--块就是PEB,记住这个* ubiattach 使用-b 参数可以指定max_beb_per1024* -b, --max-beb-per1024 maximum expected bad block number per 1024 eraseblock.* The default value is correct for most NAND devices.* Allowed range is 0-768, 0 means the default kernel value.* #define MAX_MTD_UBI_BEB_LIMIT 768* 不用-b指定的预期值,则默认为max_beb_per1024 默认为 MAX_MTD_UBI_BEB_LIMIT * MAX_MTD_UBI_BEB_LIMIT 由 CONFIG_MTD_UBI_BEB_LIMIT 指定,默认未20* 参考链接:https://zhuanlan.zhihu.com/p/504692426*/if (max_beb_per1024 < 0 || max_beb_per1024 > MAX_MTD_UBI_BEB_LIMIT)return -EINVAL;if (!max_beb_per1024)max_beb_per1024 = CONFIG_MTD_UBI_BEB_LIMIT;/** 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.*//** 检查这个MTD设备是否已经被attach过了* UBI_MAX_DEVICES:UBI设备最大的支持数,32* ubi_devices[i]:ubi设备的结构体,全局数组,每当有新mtd设备attach的时候,会加入到到全局数组中,i+1* 遍历一下现有ubi设备中,绑定的mtd信息是否与新attach的mtd相同* 如果是则说明该mtd已经被attach过了* struct mtd_info *mtd 结构体中,index 是唯一的*/for (i = 0; i < UBI_MAX_DEVICES; i++) {ubi = ubi_devices[i];if (ubi && mtd->index == ubi->mtd->index) {pr_err("ubi: mtd%d is already attached to ubi%d\n",mtd->index, i);return -EEXIST;}}/** Make sure this MTD device is not emulated on top of an UBI volume* already. Well, generally this recursion works fine, but there are* different problems like the UBI module takes a reference to itself* by attaching (and thus, opening) the emulated MTD device. This* results in inability to unload the module. And in general it makes* no sense to attach emulated MTD devices, so we prohibit this.*//** 保证MTD设备没有被模拟卷轴,这部分知识不懂,是不是要保证没有被ubimkvol执行过,还是用其他模拟的手段?* 重点遗留,如遇到其他地方有类似的,后续再补充*/if (mtd->type == MTD_UBIVOLUME) {pr_err("ubi: refuse attaching mtd%d - it is already emulated on top of UBI\n",mtd->index);return -EINVAL;}/** Both UBI and UBIFS have been designed for SLC NAND and NOR flashes.* MLC NAND is different and needs special care, otherwise UBI or UBIFS* will die soon and you will lose all your data.* Relax this rule if the partition we're attaching to operates in SLC* mode.*//** 所有的UBI和UBIFS文件系统 都是用用来设置给SLC NAND(Single-LevelCell,单层单元闪存) 和 NOR flashes* MLC NAND(Multi-Level Cell,多层单元闪存)比较特殊,需要重点关注,否则很快设备就坏掉了* 可以网上去搜一下,SLC NAND 和 MLC NAND的区别,重点关注擦除次数* 转译一下,就是不支持UBIFS不支持 MLC NAND 设备*/if (mtd->type == MTD_MLCNANDFLASH &&!(mtd->flags & MTD_SLC_ON_MLC_EMULATION)) {pr_err("ubi: refuse attaching mtd%d - MLC NAND is not supported\n",mtd->index);return -EINVAL;}/** ubi_num:第二入参,可以通过ubiattach -d参数指定* ubiattach 命令参考链接:https://zhuanlan.zhihu.com/p/504692426* 如果未指定,则自动分配* 基本步骤为遍历一下,在不超过32个ubi设备数的前提下,找到空位给它*/if (ubi_num == UBI_DEV_NUM_AUTO) {/* Search for an empty slot in the @ubi_devices array */for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++)if (!ubi_devices[ubi_num])break;if (ubi_num == UBI_MAX_DEVICES) {pr_err("ubi: only %d UBI devices may be created\n",UBI_MAX_DEVICES);return -ENFILE;}} else {if (ubi_num >= UBI_MAX_DEVICES)return -EINVAL;/* Make sure ubi_num is not busy */if (ubi_devices[ubi_num]) {pr_err("ubi: ubi%i already exists\n", ubi_num);return -EEXIST;}}/* 在内核空间,申请一个ubi设备结构体空间,填充数据 */ubi = kzalloc(sizeof(struct ubi_device), GFP_KERNEL);if (!ubi)return -ENOMEM;device_initialize(&ubi->dev);  /* 初始化新建的逻辑设备 */ubi->dev.release = dev_release; /* 设备的release方法 */ubi->dev.class = &ubi_class;  /* 设备的class类 */ubi->dev.groups = ubi_dev_groups;    /*  */ubi->mtd = mtd;   /* MTD绑定在UBI上 */ubi->ubi_num = ubi_num; /* UBI设备号,就是之前-d指定的那个 */ubi->vid_hdr_offset = vid_hdr_offset;    /* 表示vid 头的偏移,一般跟在ec header 后面*/ubi->autoresize_vol_id = -1;    /* 卷轴ID,ubimkvol步骤应该会赋值*//* * FASTMAP特性,还在实验室阶段,落地还需要时间* 遗留,研究透了ubifs后,再来研究这部分*/
#ifdef CONFIG_MTD_UBI_FASTMAPubi->fm_pool.used = ubi->fm_pool.size = 0;ubi->fm_wl_pool.used = ubi->fm_wl_pool.size = 0;/** fm_pool.max_size is 5% of the total number of PEBs but it's also* between UBI_FM_MAX_POOL_SIZE and UBI_FM_MIN_POOL_SIZE.*/ubi->fm_pool.max_size = min(((int)mtd_div_by_eb(ubi->mtd->size,ubi->mtd) / 100) * 5, UBI_FM_MAX_POOL_SIZE);ubi->fm_pool.max_size = max(ubi->fm_pool.max_size,UBI_FM_MIN_POOL_SIZE);ubi->fm_wl_pool.max_size = ubi->fm_pool.max_size / 2;ubi->fm_disabled = !fm_autoconvert;if (fm_debug)ubi_enable_dbg_chk_fastmap(ubi);if (!ubi->fm_disabled && (int)mtd_div_by_eb(ubi->mtd->size, ubi->mtd)<= UBI_FM_MAX_START) {ubi_err(ubi, "More than %i PEBs are needed for fastmap, sorry.",UBI_FM_MAX_START);ubi->fm_disabled = 1;}ubi_msg(ubi, "default fastmap pool size: %d", ubi->fm_pool.max_size);ubi_msg(ubi, "default fastmap WL pool size: %d",ubi->fm_wl_pool.max_size);
#else/* fastmap特性未开启的标志位 */ubi->fm_disabled = 1;
#endif/* * 初始化几个重要的锁,原文是这样的* @peb_buf: a buffer of PEB size used for different purposes* @buf_mutex: protects @peb_buf* @ckvol_mutex: serializes static volume checking when opening* @volumes_lock: protects @volumes, @rsvd_pebs, @avail_pebs, beb_rsvd_pebs,*                 @beb_rsvd_level, @bad_peb_count, @good_peb_count, @vol_count,*              @vol->readers, @vol->writers, @vol->exclusive,*                 @vol->metaonly, @vol->ref_count, @vol->mapping and @vol->eba_tbl.* @volumes_lock: protects @volumes, @rsvd_pebs, @avail_pebs, beb_rsvd_pebs,*            @beb_rsvd_level, @bad_peb_count, @good_peb_count, @vol_count,*            @vol->readers, @vol->writers, @vol->exclusive,*            @vol->metaonly, @vol->ref_count, @vol->mapping and*            @vol->eba_tbl.*/mutex_init(&ubi->buf_mutex);mutex_init(&ubi->ckvol_mutex);mutex_init(&ubi->device_mutex);spin_lock_init(&ubi->volumes_lock);/* fastmap特性相关的,这里只是做了个初始化,这里暂时先遗留 */init_rwsem(&ubi->fm_protect);init_rwsem(&ubi->fm_eba_sem);/* 正常情况下,我们能看到最早的打印就在这里了 */ubi_msg(ubi, "attaching mtd%d", mtd->index);/* * io_init - initialize I/O sub-system for a given UBI device.* IO初始化,重点解析的函数,放到下面讲拆解 * */err = io_init(ubi, max_beb_per1024);if (err)goto out_free;/* 申请一段PEB大小的空间 */err = -ENOMEM;ubi->peb_buf = vmalloc(ubi->peb_size);if (!ubi->peb_buf)goto out_free;/* FASTMAP特性*/
#ifdef CONFIG_MTD_UBI_FASTMAPubi->fm_size = ubi_calc_fm_size(ubi);ubi->fm_buf = vzalloc(ubi->fm_size);if (!ubi->fm_buf)goto out_free;
#endif/* attach动作,重点讲解函数,放到下面讲拆解*/err = ubi_attach(ubi, 0);if (err) {ubi_err(ubi, "failed to attach mtd%d, error %d",mtd->index, err);goto out_free;}if (ubi->autoresize_vol_id != -1) {err = autoresize(ubi, ubi->autoresize_vol_id);if (err)goto out_detach;}err = uif_init(ubi);if (err)goto out_detach;err = ubi_debugfs_init_dev(ubi);if (err)goto out_uif;ubi->bgt_thread = kthread_create(ubi_thread, ubi, "%s", ubi->bgt_name);if (IS_ERR(ubi->bgt_thread)) {err = PTR_ERR(ubi->bgt_thread);ubi_err(ubi, "cannot spawn \"%s\", error %d",ubi->bgt_name, err);goto out_debugfs;}ubi_msg(ubi, "attached mtd%d (name \"%s\", size %llu MiB)",mtd->index, mtd->name, ubi->flash_size >> 20);ubi_msg(ubi, "PEB size: %d bytes (%d KiB), LEB size: %d bytes",ubi->peb_size, ubi->peb_size >> 10, ubi->leb_size);ubi_msg(ubi, "min./max. I/O unit sizes: %d/%d, sub-page size %d",ubi->min_io_size, ubi->max_write_size, ubi->hdrs_min_io_size);ubi_msg(ubi, "VID header offset: %d (aligned %d), data offset: %d",ubi->vid_hdr_offset, ubi->vid_hdr_aloffset, ubi->leb_start);ubi_msg(ubi, "good PEBs: %d, bad PEBs: %d, corrupted PEBs: %d",ubi->good_peb_count, ubi->bad_peb_count, ubi->corr_peb_count);ubi_msg(ubi, "user volume: %d, internal volumes: %d, max. volumes count: %d",ubi->vol_count - UBI_INT_VOL_COUNT, UBI_INT_VOL_COUNT,ubi->vtbl_slots);ubi_msg(ubi, "max/mean erase counter: %d/%d, WL threshold: %d, image sequence number: %u",ubi->max_ec, ubi->mean_ec, CONFIG_MTD_UBI_WL_THRESHOLD,ubi->image_seq);ubi_msg(ubi, "available PEBs: %d, total reserved PEBs: %d, PEBs reserved for bad PEB handling: %d",ubi->avail_pebs, ubi->rsvd_pebs, ubi->beb_rsvd_pebs);/** The below lock makes sure we do not race with 'ubi_thread()' which* checks @ubi->thread_enabled. Otherwise we may fail to wake it up.*/spin_lock(&ubi->wl_lock);ubi->thread_enabled = 1;wake_up_process(ubi->bgt_thread);spin_unlock(&ubi->wl_lock);ubi_devices[ubi_num] = ubi;ubi_notify_all(ubi, UBI_VOLUME_ADDED, NULL);return ubi_num;out_debugfs:ubi_debugfs_exit_dev(ubi);
out_uif:uif_close(ubi);
out_detach:ubi_wl_close(ubi);ubi_free_all_volumes(ubi);vfree(ubi->vtbl);
out_free:vfree(ubi->peb_buf);vfree(ubi->fm_buf);put_device(&ubi->dev);return err;
}static int io_init(struct ubi_device *ubi, int max_beb_per1024)
{dbg_gen("sizeof(struct ubi_ainf_peb) %zu", sizeof(struct ubi_ainf_peb));dbg_gen("sizeof(struct ubi_wl_entry) %zu", sizeof(struct ubi_wl_entry));/* 预留特性,还未实现 */if (ubi->mtd->numeraseregions != 0) {/** Some flashes have several erase regions. Different regions* may have different eraseblock size and other* characteristics. It looks like mostly multi-region flashes* have one "main" region and one or more small regions to* store boot loader code or boot parameters or whatever. I* guess we should just pick the largest region. But this is* not implemented.*/ubi_err(ubi, "multiple regions, not implemented");return -EINVAL;}if (ubi->vid_hdr_offset < 0)return -EINVAL;/** Note, in this implementation we support MTD devices with 0x7FFFFFFF* physical eraseblocks maximum.*//* * 支持最大0x7FFF FFFF个擦除块数量的MTD设备 * peb_size:PEB大小* peb_count:PEB数量* flash_size:flash大小* peb_count = flash_size / peb_size  这个是简易换算,实际单位不同,需要查看 mtd_div_by_eb 函数的具体实现*/ubi->peb_size   = ubi->mtd->erasesize;ubi->peb_count  = mtd_div_by_eb(ubi->mtd->size, ubi->mtd);ubi->flash_size = ubi->mtd->size;/* 重点函数:设置最大允许坏块数量,这里说的是总值,并非每1024个允许的数量 */if (mtd_can_have_bb(ubi->mtd)) {ubi->bad_allowed = 1;ubi->bad_peb_limit = get_bad_peb_limit(ubi, max_beb_per1024);}/* 如果是nor_flash设备,则设置设置成nor_flash类型 */if (ubi->mtd->type == MTD_NORFLASH) {ubi_assert(ubi->mtd->writesize == 1);ubi->nor_flash = 1;}/* * min_io_size:底层设备最小输入/输出单元大小* hdrs_min_io_size:最小输入/输出单元(用于VID和EC头)*/ubi->min_io_size = ubi->mtd->writesize;ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft;/** Make sure minimal I/O unit is power of 2. Note, there is no* fundamental reason for this assumption. It is just an optimization* which allows us to avoid costly division operations.*//** 确保min_io_size是2的倍数,保证数据操作正常*/if (!is_power_of_2(ubi->min_io_size)) {ubi_err(ubi, "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);/* 底层flash单次可写入的最大字节数 */ubi->max_write_size = ubi->mtd->writebufsize;/** Maximum write size has to be greater or equivalent to min. I/O* size, and be multiple of min. I/O size.*//** 要求 max_write_size >= min_io_size* 即 单次最大写入量 大于或等于 最小输入/输出单元大小*/ if (ubi->max_write_size < ubi->min_io_size ||ubi->max_write_size % ubi->min_io_size ||!is_power_of_2(ubi->max_write_size)) {ubi_err(ubi, "bad write buffer size %d for %d min. I/O unit",ubi->max_write_size, ubi->min_io_size);return -EINVAL;}/* 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_gen("min_io_size      %d", ubi->min_io_size);dbg_gen("max_write_size   %d", ubi->max_write_size);dbg_gen("hdrs_min_io_size %d", ubi->hdrs_min_io_size);dbg_gen("ec_hdr_alsize    %d", ubi->ec_hdr_alsize);dbg_gen("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;}/* Similar for the data offset */ubi->leb_start = ubi->vid_hdr_offset + UBI_VID_HDR_SIZE;ubi->leb_start = ALIGN(ubi->leb_start, ubi->min_io_size);dbg_gen("vid_hdr_offset   %d", ubi->vid_hdr_offset);dbg_gen("vid_hdr_aloffset %d", ubi->vid_hdr_aloffset);dbg_gen("vid_hdr_shift    %d", ubi->vid_hdr_shift);dbg_gen("leb_start        %d", ubi->leb_start);/* The shift must be aligned to 32-bit boundary */if (ubi->vid_hdr_shift % 4) {ubi_err(ubi, "unaligned VID header shift %d",ubi->vid_hdr_shift);return -EINVAL;}/* Check sanity */if (ubi->vid_hdr_offset < UBI_EC_HDR_SIZE ||ubi->leb_start < ubi->vid_hdr_offset + UBI_VID_HDR_SIZE ||ubi->leb_start > ubi->peb_size - UBI_VID_HDR_SIZE ||ubi->leb_start & (ubi->min_io_size - 1)) {ubi_err(ubi, "bad VID header (%d) or data offsets (%d)",ubi->vid_hdr_offset, ubi->leb_start);return -EINVAL;}/** Set maximum amount of physical erroneous eraseblocks to be 10%.* Erroneous PEB are those which have read errors.*/ubi->max_erroneous = ubi->peb_count / 10;if (ubi->max_erroneous < 16)ubi->max_erroneous = 16;dbg_gen("max_erroneous    %d", ubi->max_erroneous);/** It may happen that EC and VID headers are situated in one minimal* I/O unit. In this case we can only accept this UBI image in* read-only mode.*/if (ubi->vid_hdr_offset + UBI_VID_HDR_SIZE <= ubi->hdrs_min_io_size) {ubi_warn(ubi, "EC and VID headers are in the same minimal I/O unit, switch to read-only mode");ubi->ro_mode = 1;}ubi->leb_size = ubi->peb_size - ubi->leb_start;if (!(ubi->mtd->flags & MTD_WRITEABLE)) {ubi_msg(ubi, "MTD device %d is write-protected, attach in read-only mode",ubi->mtd->index);ubi->ro_mode = 1;}/** Note, ideally, we have to initialize @ubi->bad_peb_count here. But* unfortunately, MTD does not provide this information. We should loop* over all physical eraseblocks and invoke mtd->block_is_bad() for* each physical eraseblock. So, we leave @ubi->bad_peb_count* uninitialized so far.*/return 0;
}

ubifs代码解析之ubi_attach_mtd_dev--个人学习相关推荐

  1. 对抗思想与强化学习的碰撞-SeqGAN模型原理和代码解析

    GAN作为生成模型的一种新型训练方法,通过discriminative model来指导generative model的训练,并在真实数据中取得了很好的效果.尽管如此,当目标是一个待生成的非连续性序 ...

  2. Selenium学习 - 库代码解析

    Selenium学习 - 库代码解析 一.selenium/common exceptions.py 定义了一个继承自Exception类的WebDriverException基础异常类,然后通过它扩 ...

  3. YOLO-V5 算法和代码解析系列 —— 学习路线规划综述

    目录标题 为什么学习 YOLO-V5 ? 博客文章列表 面向对象 开源项目学习方法 预备知识 项目目录结构 为什么学习 YOLO-V5 ? 算法性能:与YOLO系列(V1,V2,V3,V4)相比,YO ...

  4. 【对比学习】CUT模型论文解读与NCE loss代码解析

    标题:Contrastive Learning for Unpaired Image-to-Image Translation(基于对比学习的非配对图像转换) 作者:Taesung Park, Ale ...

  5. LOAM学习-代码解析(三)特征点运动估计 laserOdometry

    LOAM学习-代码解析(三)特征点运动估计 laserOdometry 前言 一.初始化 二.去除位移畸变 TransformToStart TransformToEnd 三.去除角度畸变 Plugi ...

  6. [BEV] 学习笔记之BEVDet(原理+代码解析)

    前言 基于LSS的成功,鉴智机器人提出了BEVDet,目前来到了2.0版本,在nuscences排行榜中以mAP=0.586暂列第一名.本文将对BEVDet的原理进行简要说明,然后结合代码对BEVDe ...

  7. 视觉SLAM开源算法ORB-SLAM3 原理与代码解析

    来源:深蓝学院,文稿整理者:何常鑫,审核&修改:刘国庆 本文总结于上交感知与导航研究所科研助理--刘国庆关于[视觉SLAM开源算法ORB-SLAM3 原理与代码解析]的公开课. ORB-SLA ...

  8. python中的doc_基于Python获取docx/doc文件内容代码解析

    这篇文章主要介绍了基于Python获取docx/doc文件内容代码解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 整体思路: 下载文件并修改后缀 ...

  9. ViBe算法原理和代码解析

    ViBe - a powerful technique for background detection and subtraction in video sequences 算法官网:http:// ...

  10. java的时间变化_通过java记录数据持续变化时间代码解析

    这篇文章主要介绍了通过java记录数据持续变化时间代码解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.需求:获取count为null和不为n ...

最新文章

  1. Jquery DIV滚动至浏览器顶部后固定不动代码
  2. HEOI2018游记
  3. msvcr100.dll丢失原因及解决方法
  4. 几句话说明 .NET MVC中ViewData, ViewBag和TempData的区别
  5. Ipython 和 python 的区别
  6. PHPCMS 模板的设置
  7. android okhttpclient设置编码,Android之okhttp实现socket通讯(非原创)
  8. cocos2d-x lua 学习笔记(1) -- 环境搭建
  9. php http_user_agent 微信浏览器改变为其他浏览器,微信内置浏览器HTTP_USER_AGENT
  10. google浏览器打开关闭标签
  11. 小马哥----山寨高仿小米5 图片1:1机型 机型曝光 与真假鉴别方法
  12. 【网络与信息安全】 2019年-中国计算机学会推荐国际学术会议和期刊目录(三)
  13. JavaMail实现注册邮箱验证案例
  14. 看完它你就造了!为什么AR直播是淘宝造物节最火的黑科技
  15. java开发视频教程精品整理 全部是牛B教程
  16. 爬虫——豆瓣电影top250
  17. 数据中台 画像标签_中台产品经理必懂(4):数据中台标签系统
  18. linux查看sata端口速率,[linux] 查看SATA速度和具体设备
  19. imu 数据 如何处理颠簸_预测危险的地震颠簸第二部分训练监督分类器模型和
  20. 教程:使用PySpark和MapR沙盒

热门文章

  1. java金蝶云单据查询_金蝶云星空使用WebAPI来新增单据
  2. 软件测试学习之悟空CRM项目测试用例编写
  3. 英语语法基础入门怎么学好
  4. C++软件调试与异常排查从入门到精通系列汇总
  5. 极路由3(HC5861)刷Padavan固件教程
  6. Typec接口颜色代表什么?
  7. 六大iT公司的组织结构
  8. Word 页眉 页脚 出现一条横线删不掉
  9. 自适应PC端网页制作使用rem
  10. 计算机软件后缀名,如何显示文件后缀名