Chinaunix首页 | 论坛 | 博客
  • 博客访问: 91393
  • 博文数量: 25
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 221
  • 用 户 组: 普通用户
  • 注册时间: 2014-01-08 16:03
个人简介

一万年太久,只争朝夕

文章分类
文章存档

2016年(4)

2015年(19)

2014年(2)

我的朋友

分类: Android平台

2015-02-10 17:09:38

按照nand方案,ubi卷创建过程分析如下:

 

1、载入分区配置表

用下载工具下载编译镜像时,完成下载功能代码之后,首先会载入分区配置表,作为一个打包的packet发送到手机端。按照packet的封装方式:

    unsigned short size = pakcet->packet_body.size;

    unsigned short *data = (unsigned short *)

 (pakcet->packet_body.content);

获取包内容:data

获取分区数:total_partition_num =

size/(MAX_PARTITION_NAME_SIZE + PARTITION_SIZE_LENGTH);

可以看出封装包内容由一个纯粹的列表构成:分区名+分区大小

所以总的分区数就可以确定下来。

 

2、重分区

接下来调用重分区函数:

repartition(void* vol_cfg, unsigned short total_vol_num);

其中,

vol_cfg = data;

total_vol_num = total_partition_num;

根据data和分区数total_partition_num,检测原有的卷配置,首先分配了total_partition_num个卷:

fdl_ubi_vtbl_t *vtbl=NULL;

vtbl = malloc(total_vol_num * sizeof(fdl_ubi_vtbl_t));

 

2.1、解析卷配置

调用_parse_volume_cfg(vol_cfg, total_vol_num, vtbl);

此函数实际上是根据vol_cfg来填充vtbl,卷表主要包含三个元素:

typedef struct{

   char name[UBI_VOL_NAME_MAX+1];

   long long size;//size in byte

   int autoresize;

}fdl_ubi_vtbl_t;

因此,此函数就是根据分区表来填充相应的位域;

size = *(unsigned long *)(vol_cfg+38*(i+1)-2);

vtbl[i].name[j] = *(vol_cfg+38*i+j) & 0xFF;//j=1~36,最大卷名长度

autoresize 由AUTO_RESIZE_FLAG确定。

 

2.2、卷表检测

 _vtbl_check(vtbl, total_vol_num, &remove, &create);

卷表检测需要决定出:

全部重分区:卷表记录与NAND存储卷表完全不一致

局部重分区:卷表记录与NAND存储卷表部分一致

不进行重分区:卷表记录与NAND存储卷表完全一致

struct ubi_device {

    struct cdev cdev;

    struct device dev;

    int ubi_num;

    char ubi_name[sizeof(UBI_NAME_STR)+5];

    int vol_count;

    struct ubi_volume *volumes[UBI_MAX_VOLUMES+UBI_INT_VOL_COUNT];

    ……

    int rsvd_pebs;

    int avail_pebs;

……

    struct ubi_vtbl_record *vtbl;

    struct mutex volumes_mutex;

 

    int max_ec;

    /* TODO: mean_ec is not updated run-time, fix */

    int mean_ec;

 

    /* EBA unit's stuff */

    unsigned long long global_sqnum;

    spinlock_t ltree_lock;

    struct rb_root ltree;

    struct mutex alc_mutex;

 

    /* Wear-leveling unit's stuff */

    struct rb_root used;

    struct rb_root free;

    struct rb_root scrub;

    ……

   struct ubi_wl_entry **lookuptbl;

   unsigned long long abs_ec;

   struct ubi_wl_entry *move_from;

   struct ubi_wl_entry *move_to;

    ……

 

    /* I/O unit's stuff */

    long long flash_size;

    int peb_count;

    int peb_size;

    int bad_peb_count;

    int good_peb_count;

    int min_io_size;

    int hdrs_min_io_size;

    int ro_mode;

    int leb_size;

   int leb_start;

……

    struct mtd_info *mtd;

……

};

 

struct ubi_volume {

    struct device dev;

    struct cdev cdev;

    struct ubi_device *ubi;

    int vol_id;

    ……

 

    int reserved_pebs;

    int vol_type;

    ……

    char name[UBI_VOL_NAME_MAX+1];

    ……

    int *eba_tbl;

    ……

};

 

初始化两条双向链表removecreate

INIT_LIST_HEAD(&remove);

INIT_LIST_HEAD(&create);

获取ubi设备:struct ubi_device *ubi = cur_ubi.dev;

定义卷,struct ubi_volume *vol;

vol= ubi->volumes[j];//j=1~ubi->vtbl_slots

获取ubi设备上的每一个ubi卷,strcmp(vol->name, vtbl[i].name),比较ubi设备上与下载工具下载的卷配置获取的卷表记录,卷名进行比较:

若卷名相同,再比较if(new_rsvd_pebs == vol->reserved_pebs),若新的分区表配置的保留块数目与旧的配置相同,那么就认为当前处理的分区相同。如果不相同,将当前分区记录(vtbl[i].name,0,0)添加到remove链表;若不相同,也将当前分区记录(vtbl[i].name,vtbl[i].size,vtbl[i].autoresize)添加到create链表。

 

2.3、全部重分区

根据上述check的结果,进入到三个不同的分支。

2.3.1 _mtd_part_erase(UBIPAC_PART)

对于全部重分区的情况,首先会调用_mtd_part_erase(UBIPAC_PART),将建ubi卷的UBIPAC_PART分区全部擦除。

 

2.3.2 _ubi_dev_init

然后调用_ubi_dev_init函数初始化,此函数执行了mtdparts_initubi_init函数,然后执行_ubi_dev_attach(UBIPAC_PART),将ubi设备attach到给定的mtd分区UBIPAC_PART,并且返回新的ubi设备号。

typedef struct disk_partition {

   ulong  start;     /* # of first block in partition   */

   ulong  size;      /* number of blocks in partition   */

   ulong  blksz;     /* block size in bytes          */

   uchar  name[72];  /* partition name        */

   uchar  type[32];  /* string type description      */

} disk_partition_t;

 

_ubi_dev_attach(const char *mtdpart)解析:

1)、此函数首先调用find_dev_and_part (const char *id, struct mtd_device **dev,u8 *part_num, struct part_info **part),根据分区名“ubipac”(即此处的参数id),调用mtd_id_parse函数解析得到mtd设备类型(nand/nor/onenand)和设备号

2)根据设备类型和设备号在设备链表(需确认是所有的设备构成的设备链表,还是仅mtd设备)上遍历,仅当设备类型和设备号都一致时,返回所找到的mtd设备:*dev = device_find(type, dnum)

3)*part = mtd_part_info(*dev, pnum),从设备dev上按照给定的分区号pnum,寻找对应这个分区号的分区,并返回一个指向此分区的指针。此分区partdisk_partition类型的分区。

4)sprintf(mtd_dev, "%s%d", MTD_DEV_TYPE(dev->id->type), dev->id->num);

   mtd = get_mtd_device_nm(mtd_dev);

通过设备名mtd_dev(由设备类型和设备号,nand+x),获取一个mtd设备的handle

5)填充mtd分区信息mtd_partitionstruct mtd_partition mtd_part;

   mtd_part.name = mtdpart;// mtdpart=“ubipac

   mtd_part.size = part->size;

   mtd_part.offset = part->offset;//part即为步骤3)获取的磁盘类型分区

   add_mtd_partitions(mtd, &mtd_part, 1);//此函数在mtd原始设备mtd上创建1mtd分区mtd_part.

6)调用ubi_attach_mtd_dev函数,将上述mtd设备attachubi_numUBI_DEV_NUM_AUTOubi设备。

 

总结一下,这个函数主要是将mtdubi进行初始化,然后将分区名为“ubipac”的mtd分区attachubi卷。

 

Tips:通常mtd分区包含splubootubipac这几个分区,ubipac分区在这一步挂接到ubi设备上,然后在ubi设备上创建ubi卷,也即ubi分区,包括bootsystemuserdatacache等分区。

 

2.3.3 _ubi_create_vol

创建卷,对卷表每一个卷轮询:

调用函数:

fdl_ubi_create_vol(cur_ubi.dev, vtbl[i].name, &vol_id, vtbl[i].size, 1);

通过卷名、卷id、卷大小,在当前ubi设备cur_ubi.dev上一一创建动态卷,最后一个参数1表示所创建的卷是动态卷。

1)创建一个卷请求reqstruct ubi_mkvol_req req;并填充卷请求结构:

req.vol_type = UBI_DYNAMIC_VOLUME;//动态卷

req.vol_id = UBI_VOL_NUM_AUTO;//自动分配卷id

req.alignment = 1;

req.bytes = size;//卷大小

strcpy(req.name, volume);//卷名

req.name_len = strlen(volume);//卷名长度

req.name[req.name_len] = '\0';

req.padding1 = 0;

2)调用ubi_create_volume(ubi, &req)函数,创建一个描述为req的卷。依据ubi->slots(最大卷数目),进行轮询,找到未占用的卷idvol_id,分配给新创建的卷。然后将该id填充到卷创建请求:req->vol_id = vol_id;

3)进行一系列校验:根据卷id确认ubi设备中的卷索引指针ubi->volumes[vol_id]为空,证明当前卷不是已存在的卷;

确认当前的卷名唯一,将req->name逐一轮询ubi->volume[i]对比卷名,确认新请求创建的卷卷名唯一。

4)计算需要的擦除块数目

vol->usable_leb_size = ubi->leb_size - ubi->leb_size % req->alignment;

bytes = req->bytes;

if (do_div(bytes, vol->usable_leb_size))

vol->reserved_pebs = 1;

vol->reserved_pebs += bytes;

5)保留物理擦除块:

ubi->avail_pebs -= vol->reserved_pebs;//ubi可用的擦除块要减去新卷占用的擦除块数目

ubi->rsvd_pebs += vol->reserved_pebs;//ubi保留的擦除块数目加上新增卷占用的保留块数目。

6)将卷请求req的信息填充到新建卷vol

    vol->vol_id    = vol_id;

    vol->alignment = req->alignment;

    vol->data_pad  = ubi->leb_size % vol->alignment;

    vol->vol_type  = req->vol_type;

    vol->name_len  = req->name_len;

    memcpy(vol->name, req->name, vol->name_len + 1);

    vol->ubi = ubi;//记录当前卷所属ubi设备

7)完成所有待定擦除,源于可能有一些LEB块属于相同的卷ID,此工作调用ubi_wl_flush(ubi)函数实现。

8)初始化eba表:

vol->eba_tbl = kmalloc(vol->reserved_pebs * sizeof(int), GFP_KERNEL);

for (i = 0; i < vol->reserved_pebs; i++)

    vol->eba_tbl[i] = UBI_LEB_UNMAPPED;//一一映射,初始化为未映射

9)将卷注册为字符设备:

cdev_init(&vol->cdev, &ubi_vol_cdev_operations);

// ubi_vol_cdev_operations为file_operations操作函数集

vol->cdev.owner = THIS_MODULE;

dev = MKDEV(MAJOR(ubi->cdev.dev), vol_id + 1);

err = cdev_add(&vol->cdev, dev, 1);//添加字符设备

 

ubi_create_gluebi(ubi, vol);

 

vol->dev.release = vol_release;

vol->dev.parent = &ubi->dev;

vol->dev.devt = dev;

vol->dev.class = ubi_class;

 

sprintf(&vol->dev.bus_id[0], "%s_%d", ubi->ubi_name, vol->vol_id);

err = device_register(&vol->dev);

 

volume_sysfs_init(ubi, vol);

 

10)填充卷表记录struct ubi_vtbl_record vtbl_rec;

vtbl_rec.reserved_pebs = cpu_to_be32(vol->reserved_pebs);

vtbl_rec.alignment     = cpu_to_be32(vol->alignment);

vtbl_rec.data_pad      = cpu_to_be32(vol->data_pad);

vtbl_rec.name_len      = cpu_to_be16(vol->name_len);

vtbl_rec.vol_type = UBI_VID_DYNAMIC;

memcpy(vtbl_rec.name, vol->name, vol->name_len + 1);

 

ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);

计算卷记录的CRC,存储于vtbl_rec->CRC;

擦除旧的布局卷(layout volume),两个块

将卷表记录写入布局卷。

 

struct ubi_vtbl_record {

   __be32  reserved_pebs;

   __be32  alignment;

   __be32  data_pad;

   __u8    vol_type;

   __u8    upd_marker;

   __be16  name_len;

   __u8    name[UBI_VOL_NAME_MAX+1];

   __u8    flags;

   __u8    padding[23];

   __be32  crc;

} __attribute__ ((packed));

 

需要进行autoresize的卷调用fdl_ubi_volume_autoresize(cur_ubi.dev, auto_resize_id)函数进行resize

 

至此,当前卷创建完毕,其他的卷也按照这个流程进行创建。

 

阅读(4106) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~