cp & vfs & ubifs & ubi & mtd & nand driver 总结贴

来源:互联网 发布:海岛大亨mac汉化补丁 编辑:程序博客网 时间:2024/05/18 20:36
前段时间项目需要一直研究 ubifs ,作为流程的总结,学习了 cp 命令的实现【http://blog.csdn.net/chenqiang0721/article/details/8921613】, VFS 虚拟文件系统及其代码,ubifs 文件系统, ubi 设备层, mtd 设备层,以及最底层的nand flash driver.

马上就要开展新的项目了,作为总结,把之前看的东西在整理到CSDN 博客上,留做备忘。之前零散的东西动在之前的帖子上写过了,现在主要写一下从cp 到 nand flash driver 贯穿上下的流程。

首先,准备工作需要做好,包括使用 mtd-utils 的工具查看一个mtd partition (mtdinfo /dev/mtdx, eg: mtdinfo /dev/mtd10), 擦除一个 MTD device(flash_eraseall /dev/mtd10), 将UBI device 关联到MTD device(ubiattach /dev/ubi_ctrl -m 10), 这样就会在/dev/ 下面生成 UBI device的设备节点,如果以前没有的话,从0开始编号: /dev/ubi0,这是一个UBI device,然后可以在UBI device上面 创建 Volumn 卷(ubimkvol /dev/ubi0 -N test -s 8MiB),如果/dev 下面的设备节点没有自动创建的话,需要查看sys 文件系统下面的ubi 主从设备号,然后使用mknod 手动在/dev 下面创建就行了【http://blog.csdn.net/chenqiang0721/article/details/8825458】。

接下来就可以mount 文件系统了, 创建 mount 节点, $mkdir -p /mnt/ubifs, mount -t ubifs ubi0_0 /mnt/ubifs。 当然ubifs mount 的时候可以加上一些mount选项如 bulk_read 【http://blog.csdn.net/chenqiang0721/article/details/8906071#t6】。

这样就可以使用我们的ubifs 了,分析一个简单的例子,
$ cp ~/1.txt /mnt/ubifs (~/ 不是ubifs)
在之前的cp 命令分析中已经知道cp 使用到的文件操作相关的系统调用,包括 open, read, write。
在现在这个例子中我们先分析一下过程(不分析ubifs 以外的文件系统),cp 系统调用需要在 /mnt/ubifs 上面创建create 一个文件, VFS 的流程需要先检查这个文件是否存在(lookup),如果不存在的话,执行创建create 流程,其中VFS lookup, create 都要执行具体文件系统的方法,即 VFS 使用函数指针的形式执行lookup, create。在这个case 中使用ubifs 的lookup, create 方法,ubifs lookup 会在wandering tree (B+ tree) 中查找这样的node, 在读node 的过程中通过 I/O 接口调用的UBI 读LEB,UBI 层再通过mtd 接口调用nand flash driver 的PEB 读方法获取数据。

打开 ubifs 的debug config,看到上面描述的 lookup 过程:
5791 UBIFS DBG (pid 631): ubifs_lookup: '1.txt' in dir ino 1
5792 UBIFS DBG (pid 631): ubifs_lookup_level0: search key (1, direntry, 0x85c9644)
5793 UBIFS DBG (pid 631): ubifs_lookup_level0: found 0, lvl 0, n 0
5794 UBIFS DBG (pid 631): ubifs_lookup: not found
5795 UBIFS DBG (pid 631): ubifs_create: dent '1.txt', mode 0x81a4 in dir ino 1

下面看下代码流程:
1071 SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, int, mode)                                                                                                                               
1072 {
1073         long ret;
1074
1075         if (force_o_largefile())          
1076                 flags |= O_LARGEFILE;                                                                                                                                                                     
1077   
1078         ret = do_sys_open(AT_FDCWD, filename, flags, mode);


1048 long do_sys_open(int dfd, const char __user *filename, int flags, int mode)                                                                                                                               
1049 {
1050         char *tmp = getname(filename);
1051         int fd = PTR_ERR(tmp);                                                                                                                                                                            
1052
1053         if (!IS_ERR(tmp)) {               
1054                 fd = get_unused_fd_flags(flags);
1055                 if (fd >= 0) {                    
1056                         struct file *f = do_filp_open(dfd, tmp, flags, mode, 0);                                                                                                                          
1057                         if (IS_ERR(f)) {                  
1058                                 put_unused_fd(fd);        
1059                                 fd = PTR_ERR(f);  
1060                         } else {                          
1061                                 fsnotify_open(f->f_path.dentry);
1062                                 fd_install(fd, f);
1063                         }


1761 struct file *do_filp_open(int dfd, const char *pathname,
1762                 int open_flag, int mode, int acc_mode)
1763 {                       
1764         struct file *filp;
1765         struct nameidata nd;
1832         if (open_flag & O_DIRECTORY)
1833                 nd.flags |= LOOKUP_DIRECTORY;
1834         if (!(open_flag & O_NOFOLLOW))
1835                 nd.flags |= LOOKUP_FOLLOW;

1836         filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname);

lookup 和 create 的分支发生在这个函数中,先lookup 文件,如果不存在的话,执行create.

1612 static struct file *do_last(struct nameidata *nd, struct path *path,
1613                             int open_flag, int acc_mode,
1614                             int mode, const char *pathname)
1615 {
1616         struct dentry *dir = nd->path.dentry;
1617         struct file *filp;
1618         int error = -EISDIR;

1648         /* just plain open? */
1649         if (!(open_flag & O_CREAT)) {
1650                 error = do_lookup(nd, &nd->last, path);
1651                 if (error)
1652                         goto exit;
1653                 error = -ENOENT;
1654                 if (!path->dentry->d_inode)
1655                         goto exit_dput;
1656                 if (path->dentry->d_inode->i_op->follow_link)
1657                         return NULL;
1658                 error = -ENOTDIR;
1659                 if (nd->flags & LOOKUP_DIRECTORY) {
1660                         if (!path->dentry->d_inode->i_op->lookup)
1661                                 goto exit_dput;
1662                 }
1663                 path_to_nameidata(path, nd);
1664                 audit_inode(pathname, nd->path.dentry);
1665                 goto ok;
1666         }
1667
1668         /* OK, it's O_CREAT */
1669         mutex_lock(&dir->d_inode->i_mutex);
1670
1671         path->dentry = lookup_hash(nd);
1672         path->mnt = nd->path.mnt;
1673
1674         error = PTR_ERR(path->dentry);
1675         if (IS_ERR(path->dentry)) {
1676                 mutex_unlock(&dir->d_inode->i_mutex);
1677                 goto exit;
1678         }
1679
1680         if (IS_ERR(nd->intent.open.file)) {
1681                 error = PTR_ERR(nd->intent.open.file);
1682                 goto exit_mutex_unlock;
1683         }
1684
1685         /* Negative dentry, just create the file */
1686         if (!path->dentry->d_inode) {
1687                 /*
1688                  * This write is needed to ensure that a
1689                  * ro->rw transition does not occur between
1690                  * the time when the file is created and when
1691                  * a permanent write count is taken through
1692                  * the 'struct file' in nameidata_to_filp().
1693                  */
1694                 error = mnt_want_write(nd->path.mnt);
1695                 if (error)
1696                         goto exit_mutex_unlock;
1697                 error = __open_namei_create(nd, path, open_flag, mode);
1698                 if (error) {
1699                         mnt_drop_write(nd->path.mnt);
1700                         goto exit;
1701                 }
1702                 filp = nameidata_to_filp(nd);
1703                 mnt_drop_write(nd->path.mnt);
1704                 if (!IS_ERR(filp)) {
1705                         error = ima_file_check(filp, acc_mode);
1706                         if (error) {
1707                                 fput(filp);
1708                                 filp = ERR_PTR(error);
1709                         }
1710                 }
1711                 return filp;
1712         }

1181 static struct dentry *lookup_hash(struct nameidata *nd)
1182 {
1183         int err;
1184
1185         err = exec_permission(nd->path.dentry->d_inode);
1186         if (err)
1187                 return ERR_PTR(err);
1188         return __lookup_hash(&nd->last, nd->path.dentry, nd);
1189 }

1123 static struct dentry *__lookup_hash(struct qstr *name,
1124                 struct dentry *base, struct nameidata *nd)
1125 {
1126         struct dentry *dentry;
1127         struct inode *inode;
1128         int err;
1129
1130         inode = base->d_inode;
1131
1132         /*
1133          * See if the low-level filesystem might want
1134          * to use its own hash..
1135          */
1136         if (base->d_op && base->d_op->d_hash) {
1137                 err = base->d_op->d_hash(base, name);
1138                 dentry = ERR_PTR(err);
1139                 if (err < 0)
1140                         goto out;
1141         }
1142
1143         dentry = __d_lookup(base, name);
1144
1145         /* lockess __d_lookup may fail due to concurrent d_move()
1146          * in some unrelated directory, so try with d_lookup
1147          */
1148         if (!dentry)
1149                 dentry = d_lookup(base, name);
1150
1151         if (dentry && dentry->d_op && dentry->d_op->d_revalidate)
1152                 dentry = do_revalidate(dentry, nd);
1153
1154         if (!dentry) {
1155                 struct dentry *new;
1156
1157                 /* Don't create child dentry for a dead directory. */
1158                 dentry = ERR_PTR(-ENOENT);
1159                 if (IS_DEADDIR(inode))
1160                         goto out;
1161
1162                 new = d_alloc(base, name);
1163                 dentry = ERR_PTR(-ENOMEM);
1164                 if (!new)
1165                         goto out;
1166                 dentry = inode->i_op->lookup(inode, new, nd);
1167                 if (!dentry)
1168                         dentry = new;
1169                 else
1170                         dput(new);
1171         }
1172 out:
1173         return dentry;
1174 }


199 static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
 200                                    struct nameidata *nd)
 201 {       
 202         int err;
 203         union ubifs_key key;
 204         struct inode *inode = NULL;
 205         struct ubifs_dent_node *dent;
 206         struct ubifs_info *c = dir->i_sb->s_fs_info;
 207                 
 208         dbg_gen("'%.*s' in dir ino %lu",
 209                 dentry->d_name.len, dentry->d_name.name, dir->i_ino);
 210                         
 211         if (dentry->d_name.len > UBIFS_MAX_NLEN)
 212                 return ERR_PTR(-ENAMETOOLONG);
 213                 
 214         dent = kmalloc(UBIFS_MAX_DENT_NODE_SZ, GFP_NOFS);
 215         if (!dent)      
 216                 return ERR_PTR(-ENOMEM);
 217                 
 218         dent_key_init(c, &key, dir->i_ino, &dentry->d_name);
 219                 
 220         err = ubifs_tnc_lookup_nm(c, &key, dent, &dentry->d_name);


1852 int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
1853                         void *node, const struct qstr *nm)
1854 {       
1855         int err, len;
1856         const struct ubifs_dent_node *dent = node;
1857         
1858         /*
1859          * We assume that in most of the cases there are no name collisions and
1860          * 'ubifs_tnc_lookup()' returns us the right direntry.
1861          */
1862         err = ubifs_tnc_lookup(c, key, node);
1863         if (err)        
1864                 return err;


307 static inline int ubifs_tnc_lookup(struct ubifs_info *c,
308                                    const union ubifs_key *key, void *node)
309 {
310         return ubifs_tnc_locate(c, key, node, NULL, NULL);
311 }     

1442 int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key,
1443                      void *node, int *lnum, int *offs)
1444 {
1445         int found, n, err, safely = 0, gc_seq1;
1446         struct ubifs_znode *znode;
1447         struct ubifs_zbranch zbr, *zt;
1448
1449 again:
1450         mutex_lock(&c->tnc_mutex);
1451         found = ubifs_lookup_level0(c, key, &znode, &n);

1172 int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key,
1173                         struct ubifs_znode **zn, int *n)
1174 {
1175         int err, exact;
1176         struct ubifs_znode *znode;
1177         unsigned long time = get_seconds();
1178
1179         dbg_tnc("search key %s", DBGKEY(key));
1180
1181         znode = c->zroot.znode;
1182         if (unlikely(!znode)) {
1183                 znode = ubifs_load_znode(c, &c->zroot, NULL, 0);
1184                 if (IS_ERR(znode))
1185                         return PTR_ERR(znode);
1186         }

406 struct ubifs_znode *ubifs_load_znode(struct ubifs_info *c,
407                                      struct ubifs_zbranch *zbr,
408                                      struct ubifs_znode *parent, int iip)
409 {        
410         int err;
411         struct ubifs_znode *znode;
412
413         ubifs_assert(!zbr->znode);
414         /*       
415          * A slab cache is not presently used for znodes because the znode size
416          * depends on the fanout which is stored in the superblock.
417          */
418         znode = kzalloc(c->max_znode_sz, GFP_NOFS);
419         if (!znode)      
420                 return ERR_PTR(-ENOMEM);
421
422         err = read_znode(c, zbr->lnum, zbr->offs, zbr->len, znode);


273 static int read_znode(struct ubifs_info *c, int lnum, int offs, int len,
274                       struct ubifs_znode *znode)
275 {
276         int i, err, type, cmp;
277         struct ubifs_idx_node *idx;
278
279         idx = kmalloc(c->max_idx_node_sz, GFP_NOFS);
280         if (!idx)
281                 return -ENOMEM;
282
283         err = ubifs_read_node(c, idx, UBIFS_IDX_NODE, len, lnum, offs);


777 int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len,
778                     int lnum, int offs)
779 {
780         int err, l;
781         struct ubifs_ch *ch = buf;
782
783         dbg_io("LEB %d:%d, %s, length %d", lnum, offs, dbg_ntype(type), len);
784         ubifs_assert(lnum >= 0 && lnum < c->leb_cnt && offs >= 0);
785         ubifs_assert(len >= UBIFS_CH_SZ && offs + len <= c->leb_size);
786         ubifs_assert(!(offs & 7) && offs < c->leb_size);
787         ubifs_assert(type >= 0 && type < UBIFS_NODE_TYPES_CNT);
788
789         err = ubi_read(c->ubi, lnum, buf, offs, len);


200 static inline int ubi_read(struct ubi_volume_desc *desc, int lnum, char *buf,
201                            int offset, int len)
202 {               
203         return ubi_leb_read(desc, lnum, buf, offset, len, 0);
204 }               


382 int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
383                  int len, int check)
384 {
385         struct ubi_volume *vol = desc->vol;
386         struct ubi_device *ubi = vol->ubi;
387         int err, vol_id = vol->vol_id;
388         
389         dbg_gen("read %d bytes from LEB %d:%d:%d", len, vol_id, lnum, offset);
390         
391         if (vol_id < 0 || vol_id >= ubi->vtbl_slots || lnum < 0 ||
392             lnum >= vol->used_ebs || offset < 0 || len < 0 ||
393             offset + len > vol->usable_leb_size)
394                 return -EINVAL;
395
396         if (vol->vol_type == UBI_STATIC_VOLUME) {
397                 if (vol->used_ebs == 0)
398                         /* Empty static UBI volume */
399                         return 0;
400                 if (lnum == vol->used_ebs - 1 &&
401                     offset + len > vol->last_eb_bytes)
402                         return -EINVAL;
403         }
404
405         if (vol->upd_marker)
406                 return -EBADF;      
407         if (len == 0)
408                 return 0;
409
410         err = ubi_eba_read_leb(ubi, vol, lnum, buf, offset, len, check);


370 int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
371                      void *buf, int offset, int len, int check)
372 {
373         int err, pnum, scrub = 0, vol_id = vol->vol_id;
374         struct ubi_vid_hdr *vid_hdr;
375         uint32_t uninitialized_var(crc);

439
440         err = ubi_io_read_data(ubi, buf, pnum, offset, len);


632 static inline int ubi_io_read_data(const struct ubi_device *ubi, void *buf,
633                                    int pnum, int offset, int len)
634 {                                        
635         ubi_assert(offset >= 0);
636         return ubi_io_read(ubi, buf, pnum, offset + ubi->leb_start, len);
637 }            


132 int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
133                 int len)
134 {
135         int err, retries = 0;
136         size_t read;    
137         loff_t addr;

149         addr = (loff_t)pnum * ubi->peb_size + offset;
150 retry:
151         err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);

1365 static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
1366                      size_t *retlen, uint8_t *buf)
1367 {
1368         struct nand_chip *chip = mtd->priv;
1369         int ret;        
1370                         
1371         /* Do not allow reads past end of device */
1372         if ((from + len) > mtd->size)
1373                 return -EINVAL;
1374         if (!len)       
1375                 return 0;      
1376                                
1377         nand_get_device(chip, mtd, FL_READING);
1378                         
1379         chip->ops.len = len;
1380         chip->ops.datbuf = buf;
1381         chip->ops.oobbuf = NULL;
1382                         
1383         ret = nand_do_read_ops(mtd, from, &chip->ops);


1224 static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
1225                             struct mtd_oob_ops *ops)
1226 {
1227         int chipnr, page, realpage, col, bytes, aligned;
1228         struct nand_chip *chip = mtd->priv;
1229         struct mtd_ecc_stats stats;
1230         int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
1231         int sndcmd = 1;
1232         int ret = 0;
1233         uint32_t readlen = ops->len;
1234         uint32_t oobreadlen = ops->ooblen;
1235         uint8_t *bufpoi, *oob, *buf;
1236
1237         stats = mtd->ecc_stats;
1238
1239         chipnr = (int)(from >> chip->chip_shift);
1240         chip->select_chip(mtd, chipnr);
1241
1242         realpage = (int)(from >> chip->page_shift);
1243         page = realpage & chip->pagemask;
1244
1245         col = (int)(from & (mtd->writesize - 1));
1246
1247         buf = ops->datbuf;
1248         oob = ops->oobbuf;
1249
1250         while(1) {
1251                 bytes = min(mtd->writesize - col, readlen);
1252                 aligned = (bytes == mtd->writesize);
1253
1254                 /* Is the current page in the buffer ? */
1255                 if (realpage != chip->pagebuf || oob) {
1256                         bufpoi = aligned ? buf : chip->buffers->databuf;
1257
1258                         if (likely(sndcmd)) {
1259                                 chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
1260                                 sndcmd = 0;
1261                         }
1262
1263                         /* Now read the page into the buffer */
1264                         if (unlikely(ops->mode == MTD_OOB_RAW))
1265                                 ret = chip->ecc.read_page_raw(mtd, chip,
1266                                                               bufpoi, page);
1267                         else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob)
1268                                 ret = chip->ecc.read_subpage(mtd, chip, col, bytes, bufpoi);
1269                         else
1270                                 ret = chip->ecc.read_page(mtd, chip, bufpoi,
1271                                                           page);
1272                         if (ret < 0)

1273                                 break;


chip->ecc.read_page 方法一般都是在特定的nand flash driver 的init 初始化函数中(probe 流程中)进行注册,使用特定nand flash driver 私有的page read 方法。

很重要的一点就是要理解 抽象层的概念以及意义,这样看起代码来才会比较顺利!

原创粉丝点击