主机:Gentoo Linux 11.2 with linux kernel 3.0.6
硬件渠道:FL2440(S3C2440)with linux kernel 2.6.35
本文剖析MTD设备的分区办理机制
分区办理实际上是将一个MTD设备分红几个分区,将其作为独自的MTD原始设备进行办理。
1、分区的结构体描绘结构体mtd_part
- /*Ourpartitionnodestructure*/
- //分区结构信息
- structmtd_part{
- structmtd_infomtd;//mtd_info数据结构,会被参加mtd_table中
- structmtd_info*master;//该分区的主分区
- uint64_toffset;//该分区的偏移地址
- structlist_headlist;
- };
2、分区链表mtd_partitions
- /*Ourpartitionlinkedlist*/
- //声明mtd_partitions链表
- staticLIST_HEAD(mtd_partitions);
3、add_mtd_partitions函数
- /*
- *Thisfunction,givenamasterMTDobjectandapartitiontable,creates
- *andregistersslaveMTDobjectswhichareboundtothemasteraccordingto
- *thepartitiondefinitions.
- *
- *Wedontregisterthemaster,orexpectthecallertohavedoneso,
- *forreasonsofdataintegrity.
- */
- //依据一个MTD主设备和分区表,创立新的主设备下的副设备并记录到分区表中
- //这儿咱们不将打针被注册到分区表中,只注册副设备到到分区表中
- intadd_mtd_partitions(structmtd_info*master,
- conststructmtd_partition*parts,
- intnbparts)
- {
- structmtd_part*slave;
- uint64_tcur_offset=0;
- inti;
- printk(KERN_NOTICE”Creating%dMTDpartitionson\”%s\”:\n”,nbparts,master->name);
- for(i=0;i
- slave=add_one_partition(master,parts+i,i,cur_offset);
- if(!slave)
- return-ENOMEM;
- cur_offset=slave->offset+slave->mtd.size;
- }
- return0;
- }
- EXPORT_SYMBOL(add_mtd_partitions);
而add_one_partition函数完成如下:
- //创立一个分区
- staticstructmtd_part*add_one_partition(structmtd_info*master,
- conststructmtd_partition*part,intpartno,
- uint64_tcur_offset)
- {
- structmtd_part*slave;
- /*allocatethepartitionstructure*/
- slave=kzalloc(sizeof(*slave),GFP_KERNEL);//分配内存
- if(!slave){
- printk(KERN_ERR”memoryallocationerrorwhilecreatingpartitionsfor\”%s\”\n”,
- master->name);
- del_mtd_partitions(master);
- returnNULL;
- }
- list_add(&slave->list,&mtd_partitions);//将原始设备表增加到分区表中
- /*setuptheMTDobjectforthispartition*/
- //大部分依据master相应的信息设置MTD分区slave的信息
- slave->mtd.type=master->type;
- slave->mtd.flags=master->flags&~part->mask_flags;
- slave->mtd.size=part->size;
- slave->mtd.writesize=master->writesize;
- slave->mtd.oobsize=master->oobsize;
- slave->mtd.oobavail=master->oobavail;
- slave->mtd.subpage_sft=master->subpage_sft;
- slave->mtd.name=part->name;
- slave->mtd.owner=master->owner;
- slave->mtd.backing_dev_info=master->backing_dev_info;
- /*NOTE:wedontarrangeMTDsasatree;itdbeerror-prone
- *tohavethesamedatabeintwodifferentpartitions.
- */
- slave->mtd.dev.parent=master->dev.parent;
- slave->mtd.read=part_read;
- slave->mtd.write=part_write;
- if(master->panic_write)
- slave->mtd.panic_write=part_panic_write;
- if(master->point&&master->unpoint){
- slave->mtd.point=part_point;
- slave->mtd.unpoint=part_unpoint;
- }
- if(master->get_unmapped_area)
- slave->mtd.get_unmapped_area=part_get_unmapped_area;
- if(master->read_oob)
- slave->mtd.read_oob=part_read_oob;
- if(master->write_oob)
- slave->mtd.write_oob=part_write_oob;
- if(master->read_user_prot_reg)
- slave->mtd.read_user_prot_reg=part_read_user_prot_reg;
- if(master->read_fact_prot_reg)
- slave->mtd.read_fact_prot_reg=part_read_fact_prot_reg;
- if(master->write_user_prot_reg)
- slave->mtd.write_user_prot_reg=part_write_user_prot_reg;
- if(master->lock_user_prot_reg)
- slave->mtd.lock_user_prot_reg=part_lock_user_prot_reg;
- if(master->get_user_prot_info)
- slave->mtd.get_user_prot_info=part_get_user_prot_info;
- if(master->get_fact_prot_info)
- slave->mtd.get_fact_prot_info=part_get_fact_prot_info;
- if(master->sync)
- slave->mtd.sync=part_sync;
- if(!partno&&!master->dev.class&&master->suspend&&master->resume){
- slave->mtd.suspend=part_suspend;
- slave->mtd.resume=part_resume;
- }
- if(master->writev)
- slave->mtd.writev=part_writev;
- if(master->lock)
- slave->mtd.lock=part_lock;
- if(master->unlock)
- slave->mtd.unlock=part_unlock;
- if(master->block_isbad)
- slave->mtd.block_isbad=part_block_isbad;
- if(master->block_markbad)
- slave->mtd.block_markbad=part_block_markbad;
- slave->mtd.erase=part_erase;
- slave->master=master;
- slave->offset=part->offset;
- if(slave->offset==MTDPART_OFS_APPEND)
- slave->offset=cur_offset;
- if(slave->offset==MTDPART_OFS_NXTBLK){
- slave->offset=cur_offset;
- if(mtd_mod_by_eb(cur_offset,master)!=0){
- /*Rounduptonexterasesize*/
- slave->offset=(mtd_div_by_eb(cur_offset,master)+1)*master->erasesize;
- printk(KERN_NOTICE”Movingpartition%d:”
- “0x%012llx->0x%012llx\n”,partno,
- (unsignedlonglong)cur_offset,(unsignedlonglong)slave->offset);
- }
- }
- if(slave->mtd.size==MTDPART_SIZ_FULL)
- slave->mtd.size=master->size-slave->offset;
- printk(KERN_NOTICE”0x%012llx-0x%012llx:\”%s\”\n”,(unsignedlonglong)slave->offset,
- (unsignedlonglong)(slave->offset+slave->mtd.size),slave->mtd.name);
- /*letsdosomesanitychecks*/
- if(slave->offset>=master->size){
- /*letsregisteritanywaytopreserveordering*/
- slave->offset=0;
- slave->mtd.size=0;
- printk(KERN_ERR”mtd:partition\”%s\”isoutofreach–disabled\n”,
- part->name);
- gotoout_register;
- }
- if(slave->offset+slave->mtd.size>master->size){
- slave->mtd.size=master->size-slave->offset;
- printk(KERN_WARNING”mtd:partition\”%s\”extendsbeyondtheendofdevice\”%s\”–sizetruncatedto%#llx\n”,
- part->name,master->name,(unsignedlonglong)slave->mtd.size);
- }
- if(master->numeraseregions>1){
- /*Dealwithvariableerasesizestuff*/
- inti,max=master->numeraseregions;
- u64end=slave->offset+slave->mtd.size;
- structmtd_erase_region_info*regions=master->eraseregions;
- /*Findthefirsteraseregionswhichispartofthis
- *partition.*/
- for(i=0;i
offset;i++) - ;
- /*Theloopsearchedfortheregion_behind_thefirstone*/
- if(i>0)
- i–;
- /*Pickbiggesterasesize*/
- for(;i
- if(slave->mtd.erasesize
- slave->mtd.erasesize=regions[i].erasesize;
- }
- }
- BUG_ON(slave->mtd.erasesize==0);
- }else{
- /*Singleerasesize*/
- slave->mtd.erasesize=master->erasesize;
- }
- if((slave->mtd.flags&MTD_WRITEABLE)&&
- mtd_mod_by_eb(slave->offset,&slave->mtd)){
- /*Doesntstartonaboundaryofmajorerasesize*/
- /*FIXME:Letitbewritableifitisonaboundaryof
- *_minor_erasesizethough*/
- slave->mtd.flags&=~MTD_WRITEABLE;
- printk(KERN_WARNING”mtd:partition\”%s\”doesntstartonaneraseblockboundary–forceread-only\n”,
- part->name);
- }
- if((slave->mtd.flags&MTD_WRITEABLE)&&
- mtd_mod_by_eb(slave->mtd.size,&slave->mtd)){
- slave->mtd.flags&=~MTD_WRITEABLE;
- printk(KERN_WARNING”mtd:partition\”%s\”doesntendonaneraseblock–forceread-only\n”,
- part->name);
- }
- slave->mtd.ecclayout=master->ecclayout;
- if(master->block_isbad){
- uint64_toffs=0;
- while(offs
mtd.size){ - if(master->block_isbad(master,
- offs+slave->offset))
- slave->mtd.ecc_stats.badblocks++;
- offs+=slave->mtd.erasesize;
- }
- }
- out_register:
- /*registerourpartition*/
- //最终调用add_mtd_device依据该设备的mtd_info信息增加设备链表,将其作为一个独立的MTD原始设备
- add_mtd_device(&slave->mtd);
- returnslave;
- }
- if(slave->mtd.erasesize
4、del_mtd_partition函数
- /*
- *ThisfunctionunregistersanddestroyallslaveMTDobjectswhichare
- *attachedtothegivenmasterMTDobject.
- */
- //将一个主设备下的一切副设备删去
- intdel_mtd_partitions(structmtd_info*master)
- {
- structmtd_part*slave,*next;
- list_for_each_entry_safe(slave,next,&mtd_partitions,list)//遍历mtd_partitions链表,查找到指定的主设备
- if(slave->master==master){
- list_del(&slave->list);//将主设备下的隶属设备删去
- del_mtd_device(&slave->mtd);//调用del_mtd_device函数将每个设备从MTD原始设备表中删去
- kfree(slave);//开释内存
- }
- return0;
- }
- EXPORT_SYMBOL(del_mtd_partitions);
5、其他的分区办理函数
- /*
- *MTDmethodswhichsimplytranslatetheeffectiveaddressandpassthrough
- *tothe_real_device.
- */
- //读取某个分区的指定数据
- staticintpart_read(structmtd_info*mtd,loff_tfrom,size_tlen,
- size_t*retlen,u_char*buf)
- {
- structmtd_part*part=PART(mtd);
- structmtd_ecc_statsstats;
- intres;
- stats=part->master->ecc_stats;
- if(from>=mtd->size)
- len=0;
- elseif(from+len>mtd->size)
- len=mtd->size-from;
- res=part->master->read(part->master,from+part->offset,
- len,retlen,buf);
- if(unlikely(res)){
- if(res==-EUCLEAN)
- mtd->ecc_stats.corrected+=part->master->ecc_stats.corrected-stats.corrected;
- if(res==-EBADMSG)
- mtd->ecc_stats.failed+=part->master->ecc_stats.failed-stats.failed;
- }
- returnres;
- }
- staticintpart_point(structmtd_info*mtd,loff_tfrom,size_tlen,
- size_t*retlen,void**virt,resource_size_t*phys)
- {
- structmtd_part*part=PART(mtd);
- if(from>=mtd->size)
- len=0;
- elseif(from+len>mtd->size)
- len=mtd->size-from;
- returnpart->master->point(part->master,from+part->offset,
- len,retlen,virt,phys);
- }
- staticvoidpart_unpoint(structmtd_info*mtd,loff_tfrom,size_tlen)
- {
- structmtd_part*part=PART(mtd);
- part->master->unpoint(part->master,from+part->offset,len);
- }
- //获取闲暇的内存驱动
- staticunsignedlongpart_get_unmapped_area(structmtd_info*mtd,
- unsignedlonglen,
- unsignedlongoffset,
- unsignedlongflags)
- {
- structmtd_part*part=PART(mtd);
- offset+=part->offset;
- returnpart->master->get_unmapped_area(part->master,len,offset,
- flags);
- }
- staticintpart_read_oob(structmtd_info*mtd,loff_tfrom,
- structmtd_oob_ops*ops)
- {
- structmtd_part*part=PART(mtd);
- intres;
- if(from>=mtd->size)
- return-EINVAL;
- if(ops->datbuf&&from+ops->len>mtd->size)
- return-EINVAL;
- res=part->master->read_oob(part->master,from+part->offset,ops);
- if(unlikely(res)){
- if(res==-EUCLEAN)
- mtd->ecc_stats.corrected++;
- if(res==-EBADMSG)
- mtd->ecc_stats.failed++;
- }
- returnres;
- }
- staticintpart_read_user_prot_reg(structmtd_info*mtd,loff_tfrom,
- size_tlen,size_t*retlen,u_char*buf)
- {
- structmtd_part*part=PART(mtd);
- returnpart->master->read_user_prot_reg(part->master,from,
- len,retlen,buf);
- }
- staticintpart_get_user_prot_info(structmtd_info*mtd,
- structotp_info*buf,size_tlen)
- {
- structmtd_part*part=PART(mtd);
- returnpart->master->get_user_prot_info(part->master,buf,len);
- }
- staticintpart_read_fact_prot_reg(structmtd_info*mtd,loff_tfrom,
- size_tlen,size_t*retlen,u_char*buf)
- {
- structmtd_part*part=PART(mtd);
- returnpart->master->read_fact_prot_reg(part->master,from,
- len,retlen,buf);
- }
- staticintpart_get_fact_prot_info(structmtd_info*mtd,structotp_info*buf,
- size_tlen)
- {
- structmtd_part*part=PART(mtd);
- returnpart->master->get_fact_prot_info(part->master,buf,len);
- }
- //分区写函数
- staticintpart_write(structmtd_info*mtd,loff_tto,size_tlen,
- size_t*retlen,constu_char*buf)
- {
- structmtd_part*part=PART(mtd);
- if(!(mtd->flags&MTD_WRITEABLE))
- return-EROFS;
- if(to>=mtd->size)
- len=0;
- elseif(to+len>mtd->size)
- len=mtd->size-to;
- returnpart->master->write(part->master,to+part->offset,
- len,retlen,buf);
- }
- staticintpart_panic_write(structmtd_info*mtd,loff_tto,size_tlen,
- size_t*retlen,constu_char*buf)
- {
- structmtd_part*part=PART(mtd);
- if(!(mtd->flags&MTD_WRITEABLE))
- return-EROFS;
- if(to>=mtd->size)
- len=0;
- elseif(to+len>mtd->size)
- len=mtd->size-to;
- returnpart->master->panic_write(part->master,to+part->offset,
- len,retlen,buf);
- }
- staticintpart_write_oob(structmtd_info*mtd,loff_tto,
- structmtd_oob_ops*ops)
- {
- structmtd_part*part=PART(mtd);
- if(!(mtd->flags&MTD_WRITEABLE))
- return-EROFS;
- if(to>=mtd->size)
- return-EINVAL;
- if(ops->datbuf&&to+ops->len>mtd->size)
- return-EINVAL;
- returnpart->master->write_oob(part->master,to+part->offset,ops);
- }
- staticintpart_write_user_prot_reg(structmtd_info*mtd,loff_tfrom,
- size_tlen,size_t*retlen,u_char*buf)
- {
- structmtd_part*part=PART(mtd);
- returnpart->master->write_user_prot_reg(part->master,from,
- len,retlen,buf);
- }
- staticintpart_lock_user_prot_reg(structmtd_info*mtd,loff_tfrom,
- size_tlen)
- {
- structmtd_part*part=PART(mtd);
- returnpart->master->lock_user_prot_reg(part->master,from,len);
- }
- staticintpart_writev(structmtd_info*mtd,conststructkvec*vecs,
- unsignedlongcount,loff_tto,size_t*retlen)
- {
- structmtd_part*part=PART(mtd);
- if(!(mtd->flags&MTD_WRITEABLE))
- return-EROFS;
- returnpart->master->writev(part->master,vecs,count,
- to+part->offset,retlen);
- }
- staticintpart_erase(structmtd_info*mtd,structerase_info*instr)
- {
- structmtd_part*part=PART(mtd);
- intret;
- if(!(mtd->flags&MTD_WRITEABLE))
- return-EROFS;
- if(instr->addr>=mtd->size)
- return-EINVAL;
- instr->addr+=part->offset;
- ret=part->master->erase(part->master,instr);
- if(ret){
- if(instr->fail_addr!=MTD_FAIL_ADDR_UNKNOWN)
- instr->fail_addr-=part->offset;
- instr->addr-=part->offset;
- }
- returnret;
- }
- voidmtd_erase_callback(structerase_info*instr)
- {
- if(instr->mtd->erase==part_erase){
- structmtd_part*part=PART(instr->mtd);
- if(instr->fail_addr!=MTD_FAIL_ADDR_UNKNOWN)
- instr->fail_addr-=part->offset;
- instr->addr-=part->offset;
- }
- if(instr->callback)
- instr->callback(instr);
- }
- EXPORT_SYMBOL_GPL(mtd_erase_callback);
- staticintpart_lock(structmtd_info*mtd,loff_tofs,uint64_tlen)
- {
- structmtd_part*part=PART(mtd);
- if((len+ofs)>mtd->size)
- return-EINVAL;
- returnpart->master->lock(part->master,ofs+part->offset,len);
- }
- staticintpart_unlock(structmtd_info*mtd,loff_tofs,uint64_tlen)
- {
- structmtd_part*part=PART(mtd);
- if((len+ofs)>mtd->size)
- return-EINVAL;
- returnpart->master->unlock(part->master,ofs+part->offset,len);
- }
- //分区同步函数
- staticvoidpart_sync(structmtd_info*mtd)
- {
- structmtd_part*part=PART(mtd);
- part->master->sync(part->master);
- }
- //支撑电源办理的功用函数
- staticintpart_suspend(structmtd_info*mtd)
- {
- structmtd_part*part=PART(mtd);
- returnpart->master->suspend(part->master);
- }
- staticvoidpart_resume(structmtd_info*mtd)
- {
- structmtd_part*part=PART(mtd);
- part->master->resume(part->master);
- }
- staticintpart_block_isbad(structmtd_info*mtd,loff_tofs)
- {
- structmtd_part*part=PART(mtd);
- if(ofs>=mtd->size)
- return-EINVAL;
- ofs+=part->offset;
- returnpart->master->block_isbad(part->master,ofs);
- }
- //符号设备地址坏块
- staticintpart_block_markbad(structmtd_info*mtd,loff_tofs)
- {
- structmtd_part*part=PART(mtd);
- intres;
- if(!(mtd->flags&MTD_WRITEABLE))
- return-EROFS;
- if(ofs>=mtd->size)
- return-EINVAL;
- ofs+=part->offset;
- res=part->master->block_markbad(part->master,ofs);
- if(!res)
- mtd->ecc_stats.badblocks++;
- returnres;
- }
下篇剖析详细的MTD设备,字符设备和块设备,待续……..