本帖最后由 forlinx2013 于 2014-1-24 09:19 编辑
欢迎大家来到飞凌爱板网专区,对嵌入式技术感兴趣的朋友不妨多多关注一下,我们提供了公司所有开发板的所有资料,也会更新大量技术文章,欢迎大家一块学习提高!!!
主机:Gentoo Linux 11.2 with linux kernel 3.0.6 硬件平台:FL2440(S3C2440)with linux kernel 2.6.35
本文分析MTD设备的分区管理机制 分区管理实际上是将一个MTD设备分成几个分区,将其作为单独的MTD原始设备进行管理。 1、分区的结构体描述结构体mtd_part 1 /* Our partition node structure */ 2 //分区结构信息 3 struct mtd_part { 4 struct mtd_info mtd;//mtd_info数据结构,会被加入mtd_table中 5 struct mtd_info *master;//该分区的主分区 6 uint64_t offset;//该分区的偏移地址 7 struct list_head list; 8 }; /* Our partition node structure */ //分区结构信息 struct mtd_part { struct mtd_info mtd;//mtd_info数据结构,会被加入mtd_table中 struct mtd_info *master;//该分区的主分区 uint64_t offset;//该分区的偏移地址 struct list_head list; };
2、分区链表mtd_partitions
9 /* Our partition linked list */ 10 //声明mtd_partitions链表 11 static LIST_HEAD(mtd_partitions); /* Our partition linked list */ //声明mtd_partitions链表 static LIST_HEAD(mtd_partitions);
3、add_mtd_partitions函数
12 /* 13 * This function, given a master MTD object and a partition table, creates 14 * and registers slave MTD objects which are bound to the master according to 15 * the partition definitions. 16 * 17 * We don't register the master, or expect the caller to have done so, 18 * for reasons of data integrity. 19 */ 20 //根据一个MTD主设备和分区表,创建新的主设备下的副设备并记录到分区表中 21 //这里我们不将注射被注册到分区表中,只注册副设备到到分区表中 22 int add_mtd_partitions(struct mtd_info *master, 23 const struct mtd_partition *parts, 24 int nbparts) 25 { 26 struct mtd_part *slave; 27 uint64_t cur_offset = 0; 28 int i; 29 30 printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name); 31 32 for (i = 0; i < nbparts; i++) {//对每一个分区调用add_one_partition函数更新分区表 33 slave = add_one_partition(master, parts + i, i, cur_offset); 34 if (!slave) 35 return -ENOMEM; 36 cur_offset = slave->offset + slave->mtd.size; 37 } 38 39 return 0; 40 } 41 EXPORT_SYMBOL(add_mtd_partitions); /* * This function, given a master MTD object and a partition table, creates * and registers slave MTD objects which are bound to the master according to * the partition definitions. * * We don't register the master, or expect the caller to have done so, * for reasons of data integrity. */ //根据一个MTD主设备和分区表,创建新的主设备下的副设备并记录到分区表中 //这里我们不将注射被注册到分区表中,只注册副设备到到分区表中 int add_mtd_partitions(struct mtd_info *master, const struct mtd_partition *parts, int nbparts) { struct mtd_part *slave; uint64_t cur_offset = 0; int i;
printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name);
for (i = 0; i < nbparts; i++) {//对每一个分区调用add_one_partition函数更新分区表 slave = add_one_partition(master, parts + i, i, cur_offset); if (!slave) return -ENOMEM; cur_offset = slave->offset + slave->mtd.size; }
return 0; } EXPORT_SYMBOL(add_mtd_partitions);
而add_one_partition函数实现如下:
42 //创建一个分区 43 static struct mtd_part *add_one_partition(struct mtd_info *master, 44 const struct mtd_partition *part, int partno, 45 uint64_t cur_offset) 46 { 47 struct mtd_part *slave; 48 49 /* allocate the partition structure */ 50 slave = kzalloc(sizeof(*slave), GFP_KERNEL);//分配内存 51 if (!slave) { 52 printk(KERN_ERR"memory allocation error while creating partitions for \"%s\"\n", 53 master->name); 54 del_mtd_partitions(master); 55 return NULL; 56 } 57 list_add(&slave->list, &mtd_partitions);//将原始设备表添加到分区表中 58 59 /* set up the MTD object for this partition */ 60 //大部分根据master相应的信息设置MTD分区slave的信息 61 slave->mtd.type = master->type; 62 slave->mtd.flags = master->flags & ~part->mask_flags; 63 slave->mtd.size = part->size; 64 slave->mtd.writesize = master->writesize; 65 slave->mtd.oobsize = master->oobsize; 66 slave->mtd.oobavail = master->oobavail; 67 slave->mtd.subpage_sft = master->subpage_sft; 68 69 slave->mtd.name = part->name; 70 slave->mtd.owner = master->owner; 71 slave->mtd.backing_dev_info = master->backing_dev_info; 72 73 /* NOTE: we don't arrange MTDs as a tree; it'd be error-prone 74 * to have the same data be in two different partitions. 75 */ 76 slave->mtd.dev.parent = master->dev.parent; 77 78 slave->mtd.read = part_read; 79 slave->mtd.write = part_write; 80 81 if (master->panic_write) 82 slave->mtd.panic_write = part_panic_write; 83 84 if (master->point && master->unpoint) { 85 slave->mtd.point = part_point; 86 slave->mtd.unpoint = part_unpoint; 87 } 88 89 if (master->get_unmapped_area) 90 slave->mtd.get_unmapped_area = part_get_unmapped_area; 91 if (master->read_oob) 92 slave->mtd.read_oob = part_read_oob; 93 if (master->write_oob) 94 slave->mtd.write_oob = part_write_oob; 95 if (master->read_user_prot_reg) 96 slave->mtd.read_user_prot_reg = part_read_user_prot_reg; 97 if (master->read_fact_prot_reg) 98 slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg; 99 if (master->write_user_prot_reg) 100 slave->mtd.write_user_prot_reg = part_write_user_prot_reg; 101 if (master->lock_user_prot_reg) 102 slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg; 103 if (master->get_user_prot_info) 104 slave->mtd.get_user_prot_info = part_get_user_prot_info; 105 if (master->get_fact_prot_info) 106 slave->mtd.get_fact_prot_info = part_get_fact_prot_info; 107 if (master->sync) 108 slave->mtd.sync = part_sync; 109 if (!partno && !master->dev.class && master->suspend && master->resume) { 110 slave->mtd.suspend = part_suspend; 111 slave->mtd.resume = part_resume; 112 } 113 if (master->writev) 114 slave->mtd.writev = part_writev; 115 if (master->lock) 116 slave->mtd.lock = part_lock; 117 if (master->unlock) 118 slave->mtd.unlock = part_unlock; 119 if (master->block_isbad) 120 slave->mtd.block_isbad = part_block_isbad; 121 if (master->block_markbad) 122 slave->mtd.block_markbad = part_block_markbad; 123 slave->mtd.erase = part_erase; 124 slave->master = master; 125 slave->offset = part->offset; 126 127 if (slave->offset == MTDPART_OFS_APPEND) 128 slave->offset = cur_offset; 129 if (slave->offset == MTDPART_OFS_NXTBLK) { 130 slave->offset = cur_offset; 131 if (mtd_mod_by_eb(cur_offset, master) != 0) { 132 /* Round up to next erasesize */ 133 slave->offset = (mtd_div_by_eb(cur_offset, master) + 1) * master->erasesize; 134 printk(KERN_NOTICE "Moving partition %d: " 135 "0x%012llx -> 0x%012llx\n", partno, 136 (unsigned long long)cur_offset, (unsigned long long)slave->offset); 137 } 138 } 139 if (slave->mtd.size == MTDPART_SIZ_FULL) 140 slave->mtd.size = master->size - slave->offset; 141 142 printk(KERN_NOTICE "0x%012llx-0x%012llx : \"%s\"\n", (unsigned long long)slave->offset, 143 (unsigned long long)(slave->offset + slave->mtd.size), slave->mtd.name); 144 145 /* let's do some sanity checks */ 146 if (slave->offset >= master->size) { 147 /* let's register it anyway to preserve ordering */ 148 slave->offset = 0; 149 slave->mtd.size = 0; 150 printk(KERN_ERR"mtd: partition \"%s\" is out of reach -- disabled\n", 151 part->name); 152 goto out_register; 153 } 154 if (slave->offset + slave->mtd.size > master->size) { 155 slave->mtd.size = master->size - slave->offset; 156 printk(KERN_WARNING"mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#llx\n", 157 part->name, master->name, (unsigned long long)slave->mtd.size); 158 } 159 if (master->numeraseregions > 1) { 160 /* Deal with variable erase size stuff */ 161 int i, max = master->numeraseregions; 162 u64 end = slave->offset + slave->mtd.size; 163 struct mtd_erase_region_info *regions = master->eraseregions; 164 165 /* Find the first erase regions which is part of this 166 * partition. */ 167 for (i = 0; i < max && regions.offset <= slave->offset; i++) 168 ; 169 /* The loop searched for the region _behind_ the first one */ 170 if (i > 0) 171 i--; 172 173 /* Pick biggest erasesize */ 174 for (; i < max && regions.offset < end; i++) { 175 if (slave->mtd.erasesize < regions.erasesize) { 176 slave->mtd.erasesize = regions.erasesize; 177 } 178 } 179 BUG_ON(slave->mtd.erasesize == 0); 180 } else { 181 /* Single erase size */ 182 slave->mtd.erasesize = master->erasesize; 183 } 184 185 if ((slave->mtd.flags & MTD_WRITEABLE) && 186 mtd_mod_by_eb(slave->offset, &slave->mtd)) { 187 /* Doesn't start on a boundary of major erase size */ 188 /* FIXME: Let it be writable if it is on a boundary of 189 * _minor_ erase size though */ 190 slave->mtd.flags &= ~MTD_WRITEABLE; 191 printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n", 192 part->name); 193 } 194 if ((slave->mtd.flags & MTD_WRITEABLE) && 195 mtd_mod_by_eb(slave->mtd.size, &slave->mtd)) { 196 slave->mtd.flags &= ~MTD_WRITEABLE; 197 printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n", 198 part->name); 199 } 200 201 slave->mtd.ecclayout = master->ecclayout; 202 if (master->block_isbad) { 203 uint64_t offs = 0; 204 205 while (offs < slave->mtd.size) { 206 if (master->block_isbad(master, 207 offs + slave->offset)) 208 slave->mtd.ecc_stats.badblocks++; 209 offs += slave->mtd.erasesize; 210 } 211 } 212 213 out_register: 214 /* register our partition */ 215 //最后调用add_mtd_device根据该设备的mtd_info信息添加设备链表,将其作为一个独立的MTD原始设备 216 add_mtd_device(&slave->mtd); 217 218 return slave; 219 } //创建一个分区 static struct mtd_part *add_one_partition(struct mtd_info *master, const struct mtd_partition *part, int partno, uint64_t cur_offset) { struct mtd_part *slave;
/* allocate the partition structure */ slave = kzalloc(sizeof(*slave), GFP_KERNEL);//分配内存 if (!slave) { printk(KERN_ERR"memory allocation error while creating partitions for \"%s\"\n", master->name); del_mtd_partitions(master); return NULL; } list_add(&slave->list, &mtd_partitions);//将原始设备表添加到分区表中
/* set up the MTD object for this partition */ //大部分根据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: we don't arrange MTDs as a tree; it'd be error-prone * to have the same data be in two different partitions. */ 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) { /* Round up to next erasesize */ slave->offset = (mtd_div_by_eb(cur_offset, master) + 1) * master->erasesize; printk(KERN_NOTICE "Moving partition %d: " "0x%012llx -> 0x%012llx\n", partno, (unsigned long long)cur_offset, (unsigned long long)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", (unsigned long long)slave->offset, (unsigned long long)(slave->offset + slave->mtd.size), slave->mtd.name);
/* let's do some sanity checks */ if (slave->offset >= master->size) { /* let's register it anyway to preserve ordering */ slave->offset = 0; slave->mtd.size = 0; printk(KERN_ERR"mtd: partition \"%s\" is out of reach -- disabled\n", part->name); goto out_register; } if (slave->offset + slave->mtd.size > master->size) { slave->mtd.size = master->size - slave->offset; printk(KERN_WARNING"mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#llx\n", part->name, master->name, (unsigned long long)slave->mtd.size); } if (master->numeraseregions > 1) { /* Deal with variable erase size stuff */ int i, max = master->numeraseregions; u64 end = slave->offset + slave->mtd.size; struct mtd_erase_region_info *regions = master->eraseregions;
/* Find the first erase regions which is part of this * partition. */ for (i = 0; i < max && regions.offset <= slave->offset; i++) ; /* The loop searched for the region _behind_ the first one */ if (i > 0) i--;
/* Pick biggest erasesize */ for (; i < max && regions.offset < end; i++) { if (slave->mtd.erasesize < regions.erasesize) { slave->mtd.erasesize = regions.erasesize; } } BUG_ON(slave->mtd.erasesize == 0); } else { /* Single erase size */ slave->mtd.erasesize = master->erasesize; }
if ((slave->mtd.flags & MTD_WRITEABLE) && mtd_mod_by_eb(slave->offset, &slave->mtd)) { /* Doesn't start on a boundary of major erase size */ /* FIXME: Let it be writable if it is on a boundary of * _minor_ erase size though */ slave->mtd.flags &= ~MTD_WRITEABLE; printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-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\" doesn't end on an erase block -- force read-only\n", part->name); }
slave->mtd.ecclayout = master->ecclayout; if (master->block_isbad) { uint64_t offs = 0;
while (offs < slave->mtd.size) { if (master->block_isbad(master, offs + slave->offset)) slave->mtd.ecc_stats.badblocks++; offs += slave->mtd.erasesize; } }
out_register: /* register our partition */ //最后调用add_mtd_device根据该设备的mtd_info信息添加设备链表,将其作为一个独立的MTD原始设备 add_mtd_device(&slave->mtd);
return slave; }
4、del_mtd_partition函数
220 /* 221 * This function unregisters and destroy all slave MTD objects which are 222 * attached to the given master MTD object. 223 */ 224 //将一个主设备下的所有副设备删除 225 int del_mtd_partitions(struct mtd_info *master) 226 { 227 struct mtd_part *slave, *next; 228 229 list_for_each_entry_safe(slave, next, &mtd_partitions, list)//遍历mtd_partitions链表,查找到指定的主设备 230 if (slave->master == master) { 231 list_del(&slave->list);//将主设备下的附属设备删除 232 del_mtd_device(&slave->mtd);//调用del_mtd_device函数将每个设备从MTD原始设备表中删除 233 kfree(slave);//释放内存 234 } 235 236 return 0; 237 } 238 EXPORT_SYMBOL(del_mtd_partitions); /* * This function unregisters and destroy all slave MTD objects which are * attached to the given master MTD object. */ //将一个主设备下的所有副设备删除 int del_mtd_partitions(struct mtd_info *master) { struct mtd_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);//释放内存 }
return 0; } EXPORT_SYMBOL(del_mtd_partitions);
|