久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

MTD系列

 蝸牛an 2015-05-21
分類: linux驅(qū)動 2010-11-13 22:51 4631人閱讀 評論(0) 收藏 舉報

/*
題記:
 上一篇文章《android平臺上linux啟動時init進(jìn)程解析init.rc文件分析.txt》中跟蹤了nand分區(qū)上的yaffs2文件系統(tǒng)在系統(tǒng)初始化時最上層的表現(xiàn),,調(diào)用到libc庫函數(shù)mount()為止。對于我關(guān)心的幾個分區(qū)可以將其羅列一下:
 mount(“/dev/block/mtdblock4”,  “/system”,   “yaffs2”, 0          , NULL);
 mount(“/dev/block/mtdblock7”,  “/opl”,      “yaffs2”, 0          , NULL);
 mount(“/dev/block/mtdblock13”, “/userdata”, “yaffs2”, MS_NOSUID | MS_NODEV, NULL);
 mount(“/dev/block/mtdblock5”,  “/local”,    “yaffs2”, MS_NOSUID | MS_NODEV, NULL);
 mount(“/dev/block/mtdblock9”,  “/cache”,    “yaffs2”, MS_NOSUID | MS_NODEV, NULL);
 這片文章主要描述主線,,關(guān)于yaffs2的技術(shù)細(xì)節(jié)不會分析太多,,主要跟蹤它是如何建立在mtd原始設(shè)備層之上的。
 
 * linux2.6.29
 * 主要以yaffs2為例
 * 李枝果/lizgo  2010-11-5  [email protected]
 * 文中不妥之處,,煩請指正,,謝謝!
*/
一,、系統(tǒng)如何支持yaffs2類型的文件系統(tǒng)
/*
 在分析mount掛載過程之前呢,我們先來分析一下,,在系統(tǒng)初始化階段,,也就是do_initcalls()的時候,怎么將yaffs類型
 的文件系統(tǒng)注冊進(jìn)系統(tǒng)的,,只有在這之后,,我們才可以使用mount命令來掛載yaffs類型的文件系統(tǒng)。
 
 話說在fs/yaffs2目錄中存在這樣的一個文件:yaffs_fs.c,,該文件中存在如下兩聲明語句:
 module_init(init_yaffs_fs)
 module_exit(exit_yaffs_fs)
 是不是已經(jīng)很熟悉了,,對,init_yaffs_fs()就是yaffs文件系統(tǒng)注冊的入口處,!
*/
static struct file_system_type yaffs_fs_type = {
 .owner = THIS_MODULE,
 .name = "yaffs",
 .get_sb = yaffs_read_super,
 .kill_sb = kill_block_super,
 .fs_flags = FS_REQUIRES_DEV,
};
static struct file_system_type yaffs2_fs_type = {
 .owner = THIS_MODULE,
 .name = "yaffs2",
 .get_sb = yaffs2_read_super,
 .kill_sb = kill_block_super,
 .fs_flags = FS_REQUIRES_DEV,
};
/* Stuff to handle installation of file systems */
struct file_system_to_install {
 struct file_system_type *fst;
 int installed;
};
static struct file_system_to_install fs_to_install[] = {
 {&yaffs_fs_type, 0},
 {&yaffs2_fs_type, 0},
 {NULL, 0}
};
static int __init init_yaffs_fs(void)
{
 int error = 0;
 struct file_system_to_install *fsinst;
 T(YAFFS_TRACE_ALWAYS,
   ("yaffs " __DATE__ " " __TIME__ " Installing. /n"));
 /* Install the proc_fs entry */
 my_proc_entry = create_proc_entry("yaffs",
            S_IRUGO | S_IFREG,
            YPROC_ROOT);
 // 在proc頂層目錄中創(chuàng)建yaffs文件,,用來存放后期掛載的yaffs文件系統(tǒng)的信息
 if (my_proc_entry) {
  my_proc_entry->write_proc = yaffs_proc_write;
  my_proc_entry->read_proc = yaffs_proc_read;
  my_proc_entry->data = NULL; // 操作該文件的方法注冊
 } else
  return -ENOMEM;
 /* Now add the file system entries */
 fsinst = fs_to_install;   // 將要注冊進(jìn)系統(tǒng)的yaffs類型列表
 while (fsinst->fst && !error) {
  error = register_filesystem(fsinst->fst); // note1
  if (!error)
   fsinst->installed = 1; // 注冊成功標(biāo)志
  fsinst++;
 }
 /* Any errors? uninstall  */
 if (error) {
  fsinst = fs_to_install;
  while (fsinst->fst) {
   if (fsinst->installed) {
    unregister_filesystem(fsinst->fst);
    fsinst->installed = 0;
   }
   fsinst++;
  }
 }
 return error;
}
/** note1   register_filesystem() **/
// fs/filesystems.c
static struct file_system_type *file_systems;
static DEFINE_RWLOCK(file_systems_lock);
int register_filesystem(struct file_system_type * fs)
{
 int res = 0;
 struct file_system_type ** p;  // 二級指針
 BUG_ON(strchr(fs->name, '.'));
 if (fs->next)
  return -EBUSY;
 INIT_LIST_HEAD(&fs->fs_supers);  // 初始化該類型文件系統(tǒng)的超級塊列表指針
 // 每個類型的文件系統(tǒng)都可能有多個文件系統(tǒng)實例存在于整個系統(tǒng)中,那么fs_supers
 // 鏈表頭就是用來掛接這些實例文件系統(tǒng)的超級塊,,以方便管理
 write_lock(&file_systems_lock);
 p = find_filesystem(fs->name, strlen(fs->name)); // note1-1
 if (*p)    // !NULL
  res = -EBUSY;
 else    // NULL
  *p = fs;
 write_unlock(&file_systems_lock);
 return res;
}
/**** note1-1   find_filesystem() ****/
static struct file_system_type **find_filesystem(const char *name, unsigned len)
{
 struct file_system_type **p;
 for (p=&file_systems; *p; p=&(*p)->next)
 // file_systems用來鏈接注冊進(jìn)系統(tǒng)的所有文件系統(tǒng)類型
 // 實際上file_systems不是鏈表頭,,而是指向了第一個注冊進(jìn)來的file_system_type的對象
  if (strlen((*p)->name) == len &&
      strncmp((*p)->name, name, len) == 0)
   break;
 return p;
 // *p == NULl , 那么就是沒有找到該類型的文件系統(tǒng)注冊過
 // *p != NULL , 那么就說明該類型的文件系統(tǒng)時注冊過的
}
/**** note1-1   find_filesystem() ****/
/** note1   register_filesystem() **/
/*
 至此,,系統(tǒng)在將來mount yaffs和yaffs2類型的文件系統(tǒng)的時候就會正常進(jìn)行。
 接下來就分析mount的過程吧?。,。?br> */
二,、yaffs2文件系統(tǒng)mount過程
/*
 libc庫中的mount函數(shù)最終是通過軟中斷陷入內(nèi)核來完成其工作的,,在內(nèi)核中向上提供的接口函數(shù)就是sys_mount()。
 linux內(nèi)核文件include/linux/syscalls.h中有如下的函數(shù)聲明:
 asmlinkage long sys_mount(char __user *dev_name, char __user *dir_name,
              char __user *type, unsigned long flags, void __user *data);
 該函數(shù)就是系統(tǒng)調(diào)用mount在內(nèi)核中的實現(xiàn)函數(shù)了,,但是我整個工程搜索都沒有找到sys_mount()函數(shù)的實現(xiàn)代碼,,無奈上網(wǎng)
一搜,有高人指出do_mount()函數(shù),,呵呵,,這下找到了,來一起看看吧,!
 搜了半天,,只有這里比較像那么回事兒,先看看再說,。namespace.c中有如下函數(shù)的實現(xiàn):
 SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,
  char __user *, type, unsigned long, flags, void __user *, data)
 {
 ... // 暫時先忽略不看
 }
 SYSCALL_DEFINE5定義于syscalls.h文件中:
 #define SYSCALL_DEFINE5(name, ...) SYSCALL_DEFINEx(5, _##name, __VA_ARGS__)
 
 #define SYSCALL_DEFINEx(x, name, ...)     /
     asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__))
 
 #define __SC_DECL1(t1, a1) t1 a1
 #define __SC_DECL2(t2, a2, ...) t2 a2, __SC_DECL1(__VA_ARGS__)
 #define __SC_DECL3(t3, a3, ...) t3 a3, __SC_DECL2(__VA_ARGS__)
 #define __SC_DECL4(t4, a4, ...) t4 a4, __SC_DECL3(__VA_ARGS__)
 #define __SC_DECL5(t5, a5, ...) t5 a5, __SC_DECL4(__VA_ARGS__)
 #define __SC_DECL6(t6, a6, ...) t6 a6, __SC_DECL5(__VA_ARGS__)
 
 ---> asmlinkage long sys_mount(__SC_DECL5x(__VA_ARGS__))  // __SC_DECL5x(__VA_ARGS__)帶有5個參數(shù)
 ---> asmlinkage long sys_mount(char __user *dev_name, char __user *dir_name,
              char __user *type, unsigned long flags, void __user *data)
 其余的系統(tǒng)調(diào)用函數(shù)的實現(xiàn)也是這么定義的,。
 
 namespace.c文件中實現(xiàn)了sys_mount()函數(shù)的實現(xiàn):
*/
SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,
  char __user *, type, unsigned long, flags, void __user *, data)
{
 int retval;
 unsigned long data_page;
 unsigned long type_page;
 unsigned long dev_page;
 char *dir_page;
 // 將用戶空間中的參數(shù)拷貝到內(nèi)核空間中來,這里會分配一個物理頁來存放數(shù)據(jù)
 retval = copy_mount_options(type, &type_page);
 if (retval < 0)
  return retval;
 dir_page = getname(dir_name);// 獲取掛載目錄路徑字符串
 retval = PTR_ERR(dir_page);
 if (IS_ERR(dir_page))
  goto out1;
 retval = copy_mount_options(dev_name, &dev_page); // 同上
 if (retval < 0)
  goto out2;
 retval = copy_mount_options(data, &data_page);  // 同上
 if (retval < 0)
  goto out3;
 lock_kernel();
 retval = do_mount((char *)dev_page, dir_page, (char *)type_page,
     flags, (void *)data_page);  // 主體函數(shù)  note2
 unlock_kernel();
 free_page(data_page);
out3:
 free_page(dev_page);
out2:
 putname(dir_page);
out1:
 free_page(type_page);
 return retval;
}
/** note2   do_mount() **/
long do_mount(char *dev_name, char *dir_name, char *type_page,
    unsigned long flags, void *data_page)
{
 struct path path;
 int retval = 0;
 int mnt_flags = 0;
 /* Discard magic */
 if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
  flags &= ~MS_MGC_MSK;
 /* Basic sanity checks */
 if (!dir_name || !*dir_name || !memchr(dir_name, 0, PAGE_SIZE))
  return -EINVAL;
 if (dev_name && !memchr(dev_name, 0, PAGE_SIZE))
  return -EINVAL;
 if (data_page)
  ((char *)data_page)[PAGE_SIZE - 1] = 0;
 /* Separate the per-mountpoint flags */
 if (flags & MS_NOSUID)
  mnt_flags |= MNT_NOSUID;
 if (flags & MS_NODEV)
  mnt_flags |= MNT_NODEV;
 if (flags & MS_NOEXEC)
  mnt_flags |= MNT_NOEXEC;
 if (flags & MS_NOATIME)
  mnt_flags |= MNT_NOATIME;
 if (flags & MS_NODIRATIME)
  mnt_flags |= MNT_NODIRATIME;
 if (flags & MS_RELATIME)
  mnt_flags |= MNT_RELATIME;
 if (flags & MS_RDONLY)
  mnt_flags |= MNT_READONLY;
 flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE |
     MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT);
 /* ... and get the mountpoint */
 retval = kern_path(dir_name, LOOKUP_FOLLOW, &path);    // note2-1
 // 取得當(dāng)前任務(wù)的fs_struct結(jié)構(gòu)體中的root域,,直接復(fù)制給path結(jié)構(gòu)體
 // 驗證dir_name給出的路徑是否有效,,ok返回0
 if (retval)
  return retval;
 retval = security_sb_mount(dev_name, &path,
       type_page, flags, data_page);          // 實際上是一個空函數(shù)security.h
 if (retval)
  goto dput_out;
 if (flags & MS_REMOUNT)
  retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags,
        data_page);
 else if (flags & MS_BIND)
  retval = do_loopback(&path, dev_name, flags & MS_REC);
 else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
  retval = do_change_type(&path, flags);
 else if (flags & MS_MOVE)
  retval = do_move_mount(&path, dev_name);
 else
  retval = do_new_mount(&path, type_page, flags, mnt_flags,
          dev_name, data_page);// 完成mount工作的主要函數(shù)  note 2-2
dput_out:
 path_put(&path);
 return retval;
}
/**** note2-1 kern_path() ****/
/** // mount.h
struct vfsmount {
 struct list_head mnt_hash;   /* 哈希表 */
 struct vfsmount *mnt_parent;  /* fs we are mounted on 父文件系統(tǒng) */
 struct dentry *mnt_mountpoint; /* dentry of mountpoint 安裝點的目錄項對象*/
 struct dentry *mnt_root;    /* root of the mounted tree
                    該文件系統(tǒng)的根目錄項對象*/
 struct super_block *mnt_sb;   /* pointer to superblock 該文件系統(tǒng)的超級塊*/
 struct list_head mnt_mounts;  /* list of children, anchored here
                    子文件系統(tǒng)列表*/
 struct list_head mnt_child;   /* and going through their mnt_child
                    子文件系統(tǒng)列表*/
 int mnt_flags;         /* 安裝標(biāo)記 */
 // MNT_NOSUID - 禁止該文件系統(tǒng)的可執(zhí)行文件設(shè)置setuid和setgid標(biāo)志
 // MNT_NODEV  - 禁止訪問該文件系統(tǒng)上的設(shè)備文件
 // MNT_NOEXEC - 禁止執(zhí)行該文件系統(tǒng)上的可執(zhí)行文件
                 /* 4 bytes hole on 64bits arches */
 const char *mnt_devname;    /* Name of device e.g. /dev/dsk/hda1 設(shè)備文件名*/
 struct list_head mnt_list;   /* 描述符鏈表 */
 struct list_head mnt_expire;  /* link in fs-specific expiry list */
 struct list_head mnt_share;   /* circular list of shared mounts */
 struct list_head mnt_slave_list;/* list of slave mounts */
 struct list_head mnt_slave;   /* slave list entry */
 struct vfsmount *mnt_master;  /* slave is on master->mnt_slave_list */
 struct mnt_namespace *mnt_ns;  /* containing namespace */
 int mnt_id;           /* mount identifier */
 int mnt_group_id;        /* peer group identifier */
 /*
  * We put mnt_count & mnt_expiry_mark at the end of struct vfsmount
  * to let these frequently modified fields in a separate cache line
  * (so that reads of mnt_flags wont ping-pong on SMP machines)
  */
 atomic_t mnt_count;       /* vfsmount結(jié)構(gòu)體引用計數(shù) */
 int mnt_expiry_mark;      /* true if marked for expiry */
 int mnt_pinned;
 int mnt_ghosts;
 /*
  * This value is not stable unless all of the mnt_writers[] spinlocks
  * are held, and all mnt_writer[]s on this mount have 0 as their ->count
  */
 atomic_t __mnt_writers;  
};
**/
/** // dcache.h
struct dentry {
 atomic_t d_count;   // dentry結(jié)構(gòu)體引用計數(shù)
 unsigned int d_flags;  /* protected by d_lock 目錄項緩存標(biāo)志*/
 spinlock_t d_lock;   /* per dentry lock 單目錄項鎖*/
 int d_mounted;    /* 是登陸點的目錄項嗎? */
 struct inode *d_inode;  /* Where the name belongs to - NULL is
            negative  相關(guān)索引節(jié)點*/
 /*
  * The next three fields are touched by __d_lookup.  Place them here
  * so they all fit in a cache line.
  */
 struct hlist_node d_hash; /* lookup hash list */
 struct dentry *d_parent; /* parent directory */
 struct qstr d_name;
 struct list_head d_lru;  /* LRU list */
 /*
  * d_child and d_rcu can share memory
  */
 union {
  struct list_head d_child; /* child of parent list */
   struct rcu_head d_rcu;
 } d_u;
 struct list_head d_subdirs; /* our children */
 struct list_head d_alias; /* inode alias list */
 unsigned long d_time;  /* used by d_revalidate */
 struct dentry_operations *d_op;
 struct super_block *d_sb; /* The root of the dentry tree */
 void *d_fsdata;   /* fs-specific data */
 unsigned char d_iname[DNAME_INLINE_LEN_MIN]; /* small names */
};
**/
/** // path.h
struct dentry;
struct vfsmount;
struct path {
 struct vfsmount *mnt;   // 描述一個已安裝文件系統(tǒng)的結(jié)構(gòu)體指針, 代表某類型文件系統(tǒng)的安裝點
 struct dentry *dentry;  // 目錄項對象指針
};
extern void path_get(struct path *);
extern void path_put(struct path *);
**/
/**
 目錄可以層層嵌套,形成文件路徑,,路徑中的每一部分稱作目錄條目,,也叫目錄項。如:/dev/block/mtdblock4
 其中根目錄是/, 目錄dev,,block和設(shè)備文件mtdblock4都是目錄條目,,即目錄項,使用結(jié)構(gòu)體struct dentry來描述
**/
// 根據(jù)給出的name路徑名,,返回該路徑所描述的文件或目錄的struct path對象給上級函數(shù),。path中既有該文件或目錄所屬
// 的文件系統(tǒng),也有該文件和目錄對應(yīng)的目錄項對象,。
int kern_path(const char *name, unsigned int flags, struct path *path)
{
 struct nameidata nd;
 int res = do_path_lookup(AT_FDCWD, name, flags, &nd);  // note 2-1-1
 if (!res)
  *path = nd.path;// 將函數(shù)do_path_lookup函數(shù)最終得到的path結(jié)構(gòu)體返回給上級函數(shù)
 return res;
}
/****** note2-1-1 do_path_lookup() ******/
// 路徑分解函數(shù)
static int do_path_lookup(int dfd, const char *name,
    unsigned int flags, struct nameidata *nd)
{
 int retval = 0;
 int fput_needed;
 struct file *file;
 struct fs_struct *fs = current->fs;
 nd->last_type = LAST_ROOT; /* if there are only slashes... */
 nd->flags = flags;
 nd->depth = 0;
 if (*name=='/') {    // 檢查掛載的路徑是否處于根目錄下
  read_lock(&fs->lock);
  nd->path = fs->root;
  path_get(&fs->root); // 增加當(dāng)前任務(wù)fs_struct結(jié)構(gòu)體中root域引用計數(shù)
  read_unlock(&fs->lock);
 } else if (dfd == AT_FDCWD) {
  read_lock(&fs->lock);
  nd->path = fs->pwd;
  path_get(&fs->pwd);
  read_unlock(&fs->lock);
 } else {
  struct dentry *dentry;
  file = fget_light(dfd, &fput_needed);
  retval = -EBADF;
  if (!file)
   goto out_fail;
  dentry = file->f_path.dentry;
  retval = -ENOTDIR;
  if (!S_ISDIR(dentry->d_inode->i_mode))
   goto fput_fail;
  retval = file_permission(file, MAY_EXEC);
  if (retval)
   goto fput_fail;
  nd->path = file->f_path;
  path_get(&file->f_path);
  fput_light(file, fput_needed);
 }
 retval = path_walk(name, nd);  // 真正的路徑分解函數(shù),,返回最終的nd.path,這里就不往下分析了,。
 // path_walk()-->link_path_walk()-->__link_path_walk()-->do_lookup()
 if (unlikely(!retval && !audit_dummy_context() && nd->path.dentry &&
    nd->path.dentry->d_inode))
  audit_inode(name, nd->path.dentry);
out_fail:
 return retval;
fput_fail:
 fput_light(file, fput_needed);
 goto out_fail;
}
/****** note2-1-1 do_path_lookup() ******/
/**** note2-1 kern_path() ****/
/**** note2-2 do_new_mount() ****/
static int do_new_mount(struct path *path, char *type, int flags,
   int mnt_flags, char *name, void *data)
{
 struct vfsmount *mnt; // 用來指向描述一個已安裝文件系統(tǒng)的vfsmount結(jié)構(gòu)體實例
 if (!type || !memchr(type, 0, PAGE_SIZE))
  return -EINVAL;
 /* we need capabilities... */
 if (!capable(CAP_SYS_ADMIN))
  return -EPERM;
 mnt = do_kern_mount(type, flags, name, data);  // 呵呵,,很眼熟的一個函數(shù)  note2-2-1
                         // 曾經(jīng)分析rootfs初始化的時候詳細(xì)分析過,這里再來走一次
 // eg: do_kern_mount("yaffs2", 0, "/dev/block/mtdblock4", NULL);
 // eg: do_kern_mount("yaffs2", MS_NOSUID | MS_NODEV, "/dev/block/mtdblock13", NULL);
 if (IS_ERR(mnt))
  return PTR_ERR(mnt);
 return do_add_mount(mnt, path, mnt_flags, NULL);
}
/****** note2-2-1 do_kern_mount() ******/
struct vfsmount *
do_kern_mount(const char *fstype, int flags, const char *name, void *data)
{
 struct file_system_type *type = get_fs_type(fstype);
 // 獲取全局鏈表file_system中名為fstype(yaffs2)的文件系統(tǒng)結(jié)構(gòu)體指針(&yaffs2_fs_type)
 struct vfsmount *mnt;
 if (!type)
  return ERR_PTR(-ENODEV);
 mnt = vfs_kern_mount(type, flags, name, data);    // note2-2-1-1
 if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) &&
     !mnt->mnt_sb->s_subtype)
  mnt = fs_set_subtype(mnt, fstype);
 put_filesystem(type);
 return mnt;
}
/******** note2-2-1-1 vfs_kern_mount() ********/
struct vfsmount *
vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
{
 struct vfsmount *mnt;
 char *secdata = NULL;
 int error;
 if (!type)
  return ERR_PTR(-ENODEV);  // 參數(shù)驗證
 error = -ENOMEM;
 mnt = alloc_vfsmnt(name);   // note2-2-1-1-1
 /*在slab高速緩存組mnt_cache中分配一個vfsmount對象,并對其進(jìn)行初始化*/
 if (!mnt)
  goto out;
 if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) { // 我們這里沒有data傳入,,所以暫不研究
  secdata = alloc_secdata();
  if (!secdata)
   goto out_mnt;
  error = security_sb_copy_data(data, secdata);
  if (error)
   goto out_free_secdata;
 }
 error = type->get_sb(type, flags, name, data, mnt); // note2-2-1-1-2  文件系統(tǒng)超級塊回調(diào)函數(shù)
 // 對yaffs2類型的文件系統(tǒng),,該函數(shù)是: yaffs2_read_super()
 if (error < 0)
  goto out_free_secdata;
 BUG_ON(!mnt->mnt_sb);
  error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata);
  if (error)
   goto out_sb;
 mnt->mnt_mountpoint = mnt->mnt_root; // vfsmount結(jié)構(gòu)體相關(guān)域設(shè)置
 mnt->mnt_parent = mnt;
 up_write(&mnt->mnt_sb->s_umount);
 free_secdata(secdata);
 return mnt;              // 執(zhí)行到這里,,整個mount過程基本就完成了,看的出來,,
                    // 主要是block_device結(jié)構(gòu)體查找和超級塊的填充,。
out_sb:
 dput(mnt->mnt_root);
 up_write(&mnt->mnt_sb->s_umount);
 deactivate_super(mnt->mnt_sb);
out_free_secdata:
 free_secdata(secdata);
out_mnt:
 free_vfsmnt(mnt);
out:
 return ERR_PTR(error);
}
/********** note2-2-1-1-1 alloc_vfsmnt() **********/
/* 該函數(shù)初始化內(nèi)容
1. 分配一個vfsmount的結(jié)構(gòu)體
2. mnt->mnt_id分配一個隨機(jī)值
3. mnt->mnt_devname設(shè)置,eg: mnt->mnt_devname = “/dev/block/mtdblock13”
4. mnt->mnt_count和mnt->__mnt_writers 設(shè)置為1
5. mnt->mnt_hash,、mnt->mnt_child,、mnt->mnt_mounts、mnt->mnt_list,、mnt->mnt_expire,、mnt->mnt_share、
   mnt->mnt_slave_list,、mnt->mnt_slave初始化
*/
struct vfsmount *alloc_vfsmnt(const char *name) // name是欲掛載的設(shè)備
{
 struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);
 // mnt_cache高速緩存已經(jīng)在mnt_init()中創(chuàng)建,,可以直接去獲取空間
 if (mnt) {
  int err;
  err = mnt_alloc_id(mnt);
  // Allocate new ID, id returns a value in the range 0 ... 0x7fffffff.
  if (err)
   goto out_free_cache;
  if (name) {
   mnt->mnt_devname = kstrdup(name, GFP_KERNEL); // copy name
   if (!mnt->mnt_devname)
    goto out_free_id;
  }
  atomic_set(&mnt->mnt_count, 1);
  INIT_LIST_HEAD(&mnt->mnt_hash);
  INIT_LIST_HEAD(&mnt->mnt_child);
  INIT_LIST_HEAD(&mnt->mnt_mounts);
  INIT_LIST_HEAD(&mnt->mnt_list);
  INIT_LIST_HEAD(&mnt->mnt_expire);
  INIT_LIST_HEAD(&mnt->mnt_share);
  INIT_LIST_HEAD(&mnt->mnt_slave_list);
  INIT_LIST_HEAD(&mnt->mnt_slave);
  atomic_set(&mnt->__mnt_writers, 0);
 }
 return mnt;
out_free_id:
 mnt_free_id(mnt);
out_free_cache:
 kmem_cache_free(mnt_cache, mnt);
 return NULL;
}
/********** note2-2-1-1-1 alloc_vfsmnt() **********/
/********** note2-2-1-1-2 type->get_sb() // yaffs2_read_super() **********/
static int yaffs2_read_super(struct file_system_type *fs,
             int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
 return get_sb_bdev(fs, flags, dev_name, data,
           yaffs2_internal_read_super_mtd, mnt);  // note2-2-1-1-2-1
 // eg: get_sb_bdev(&yaffs2_fs_type, MS_NOSUID | MS_NODEV, "/dev/block/mtdblock13", NULL,
 //                 yaffs2_internal_read_super_mtd, mnt);
}
/************ note2-2-1-1-2-1 get_sb_bdev() ************/
int get_sb_bdev(struct file_system_type *fs_type,
 int flags, const char *dev_name, void *data,
 int (*fill_super)(struct super_block *, void *, int),
 struct vfsmount *mnt)
{
 struct block_device *bdev;   // block device pointer
 struct super_block *s;    // 超級塊指針
 fmode_t mode = FMODE_READ;
 int error = 0;
 if (!(flags & MS_RDONLY))
  mode |= FMODE_WRITE;   // 可寫
 bdev = open_bdev_exclusive(dev_name, mode, fs_type);// note2-2-1-1-2-1-1
 // 打開dev_name對應(yīng)的塊設(shè)備節(jié)點, 獲得對應(yīng)的block_device結(jié)構(gòu)體
 if (IS_ERR(bdev))
  return PTR_ERR(bdev);
 /*
  * once the super is inserted into the list by sget, s_umount
  * will protect the lockfs code from trying to start a snapshot
  * while we are mounting
  */
 down(&bdev->bd_mount_sem);
 s = sget(fs_type, test_bdev_super, set_bdev_super, bdev); // note2-2-1-1-2-1-2
 up(&bdev->bd_mount_sem);
 if (IS_ERR(s))
  goto error_s;
 if (s->s_root) {
  if ((flags ^ s->s_flags) & MS_RDONLY) {
   up_write(&s->s_umount);
   deactivate_super(s);
   error = -EBUSY;
   goto error_bdev;
  }
  close_bdev_exclusive(bdev, mode);
 } else {
  char b[BDEVNAME_SIZE];
  s->s_flags = flags;  // 超級塊的標(biāo)志
  s->s_mode = mode;   // 訪問權(quán)限
  strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
  sb_set_blocksize(s, block_size(bdev));
  error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);
  // yaffs_internal_read_super_mtd()  note2-2-1-1-2-1-3 
  if (error) {
   up_write(&s->s_umount);
   deactivate_super(s);
   goto error;
  }
  s->s_flags |= MS_ACTIVE;
  bdev->bd_super = s;
 }
 return simple_set_mnt(mnt, s);
error_s:
 error = PTR_ERR(s);
error_bdev:
 close_bdev_exclusive(bdev, mode);
error:
 return error;
}
/************** note2-2-1-1-2-1-1 open_bdev_exclusive() **************/
struct block_device *open_bdev_exclusive(const char *path, fmode_t mode, void *holder)
{
 struct block_device *bdev;
 int error = 0;
 bdev = lookup_bdev(path);  // note2-2-1-1-2-1-1-1
 // 根據(jù)路徑先找到對應(yīng)的path結(jié)構(gòu)體,然后通過 path->dentry->d_inode->i_bdev 取得該塊設(shè)備
 // 節(jié)點對應(yīng)的block_device結(jié)構(gòu)體,。
 if (IS_ERR(bdev))
  return bdev;
 error = blkdev_get(bdev, mode);// 找到對應(yīng)的gendisk,,放在bdev->bd_disk中
 if (error)
  return ERR_PTR(error);
 error = -EACCES;
 if ((mode & FMODE_WRITE) && bdev_read_only(bdev))
  goto blkdev_put;
 error = bd_claim(bdev, holder);// 檢查該塊設(shè)備屬于哪一類文件系統(tǒng)
 if (error)
  goto blkdev_put;
 return bdev;
 
blkdev_put:
 blkdev_put(bdev, mode);
 return ERR_PTR(error);
}
/**************** note2-2-1-1-2-1-1-1 lookup_bdev() ****************/
struct block_device *lookup_bdev(const char *pathname)
{
 struct block_device *bdev;
 struct inode *inode;
 struct path path;
 int error;
 if (!pathname || !*pathname)
  return ERR_PTR(-EINVAL);
 error = kern_path(pathname, LOOKUP_FOLLOW, &path); // 參考前文note2-1
 // 路徑分解,得到最后塊設(shè)備文件的path結(jié)構(gòu)體
 if (error)
  return ERR_PTR(error);
 inode = path.dentry->d_inode;  // 取出對應(yīng)目錄項的inode
 error = -ENOTBLK;
 if (!S_ISBLK(inode->i_mode))  // 檢查其訪問權(quán)限,,是否是塊設(shè)備
  goto fail;
 error = -EACCES;
 if (path.mnt->mnt_flags & MNT_NODEV)
  goto fail;
 error = -ENOMEM;
 bdev = bd_acquire(inode);    // note2-2-1-1-2-1-1-1-1
 // 取得inode->i_bdev,這是一個描述塊設(shè)備結(jié)構(gòu)體指針
 if (!bdev)
  goto fail;
out:
 path_put(&path);
 return bdev;
fail:
 bdev = ERR_PTR(error);
 goto out;
}
/****************** note2-2-1-1-2-1-1-1-1 bd_acquire() ******************/
static struct block_device *bd_acquire(struct inode *inode)
{
 struct block_device *bdev;
 spin_lock(&bdev_lock);
 bdev = inode->i_bdev; // 如果是塊設(shè)備文件,,那么這個指向其塊設(shè)備結(jié)構(gòu)體
 if (bdev) {
  atomic_inc(&bdev->bd_inode->i_count);
  spin_unlock(&bdev_lock);
  return bdev;  // 返回塊設(shè)備結(jié)構(gòu)體指針
 }
 spin_unlock(&bdev_lock);
 bdev = bdget(inode->i_rdev); // 根據(jù)主次設(shè)備號獲得block_device結(jié)構(gòu)體
 if (bdev) {
  spin_lock(&bdev_lock);
  if (!inode->i_bdev) {
   /*
    * We take an additional bd_inode->i_count for inode,
    * and it's released in clear_inode() of inode.
    * So, we can access it via ->i_mapping always
    * without igrab().
    */
   atomic_inc(&bdev->bd_inode->i_count);
   inode->i_bdev = bdev;
   inode->i_mapping = bdev->bd_inode->i_mapping;
   list_add(&inode->i_devices, &bdev->bd_inodes);
  }
  spin_unlock(&bdev_lock);
 }
 return bdev;
}
/****************** note2-2-1-1-2-1-1-1-1 bd_acquire() ******************/
/**************** note2-2-1-1-2-1-1-1 lookup_bdev() ****************/
/************** note2-2-1-1-2-1-1 open_bdev_exclusive() **************/
/************** note2-2-1-1-2-1-2 sget() **************/
static int set_bdev_super(struct super_block *s, void *data)
{
 s->s_bdev = data;        // block_device
 s->s_dev = s->s_bdev->bd_dev;  // 主次設(shè)備號 
 return 0;
}
static int test_bdev_super(struct super_block *s, void *data)
{
 return (void *)s->s_bdev == data;
}
struct super_block *sget(struct file_system_type *type,
   int (*test)(struct super_block *,void *),
   int (*set)(struct super_block *,void *),
   void *data)
{
 struct super_block *s = NULL;
 struct super_block *old;
 int err;
retry:
 spin_lock(&sb_lock);
 if (test) {
  list_for_each_entry(old, &type->fs_supers, s_instances) {
   if (!test(old, data))
    // 檢查上層傳遞下來的block_device是否已經(jīng)和存在的超級塊聯(lián)系上了,是則返回1
    continue;
   if (!grab_super(old))
    goto retry;
   if (s) {
    up_write(&s->s_umount);
    destroy_super(s);
   }
   return old;
  }
 }
 if (!s) {
  spin_unlock(&sb_lock);
  s = alloc_super(type);  // 分配超級塊空間
  if (!s)
   return ERR_PTR(-ENOMEM);
  goto retry;
 }
 
 err = set(s, data);
 // 用上層傳下來的block_device指針來初始化超級塊相關(guān)域
 if (err) {
  spin_unlock(&sb_lock);
  up_write(&s->s_umount);
  destroy_super(s);
  return ERR_PTR(err);
 }
 s->s_type = type;   // 該超級塊對應(yīng)的文件系統(tǒng)的類型
 strlcpy(s->s_id, type->name, sizeof(s->s_id)); // 文件系統(tǒng)類型名字
 list_add_tail(&s->s_list, &super_blocks);
 // 將該超級塊加入到全局的超級塊列表中
 list_add(&s->s_instances, &type->fs_supers);
 // 將該超級塊加入到對應(yīng)文件系統(tǒng)的超級塊列表中
 spin_unlock(&sb_lock);
 get_filesystem(type);
 return s;
}
/************** note2-2-1-1-2-1-2 sget() **************/
/************** note2-2-1-1-2-1-3 fill_super() // yaffs_internal_read_super_mtd() **************/
static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
      int silent)
{
 return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
}
/**************** note2-2-1-1-2-1-3-1 yaffs_internal_read_super() ****************/
static struct super_block *yaffs_internal_read_super(int yaffsVersion,
      struct super_block *sb,
      void *data, int silent)
{
 int nBlocks;
 struct inode *inode = NULL;
 struct dentry *root;
 yaffs_Device *dev = 0;
 char devname_buf[BDEVNAME_SIZE + 1];
 struct mtd_info *mtd;
 int err;
 char *data_str = (char *)data;
 yaffs_options options;
 sb->s_magic = YAFFS_MAGIC;
 sb->s_op = &yaffs_super_ops;
 sb->s_flags |= MS_NOATIME;
 ...
 
 sb->s_blocksize = PAGE_CACHE_SIZE;
 sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
 ...
 
 /* Check it's an mtd device..... */
 if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR)
  return NULL; /* This isn't an mtd device */
 
 ...
 
 /* Get the device */
 mtd = get_mtd_device(NULL, MINOR(sb->s_dev)); // 取得對應(yīng)的mtd_info結(jié)構(gòu)體
 ...
 
 /* Check it's NAND */
 if (mtd->type != MTD_NANDFLASH) {
  T(YAFFS_TRACE_ALWAYS,
    ("yaffs: MTD device is not NAND it's type %d/n", mtd->type));
  return NULL;
 }
 ...
 
 if (yaffsVersion == 1 && WRITE_SIZE(mtd) >= 2048) {
  T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs2/n"));
  yaffsVersion = 2;
 }
 ...
 
 memset(dev, 0, sizeof(yaffs_Device));
 dev->genericDevice = mtd;
 dev->name = mtd->name;
 ...
 
 /* ... and the functions. */
 if (yaffsVersion == 2) {
  dev->writeChunkWithTagsToNAND =
      nandmtd2_WriteChunkWithTagsToNAND;
  dev->readChunkWithTagsFromNAND =
      nandmtd2_ReadChunkWithTagsFromNAND;
  dev->markNANDBlockBad = nandmtd2_MarkNANDBlockBad;
  dev->queryNANDBlock = nandmtd2_QueryNANDBlock;
  dev->spareBuffer = YMALLOC(mtd->oobsize);
  dev->isYaffs2 = 1;
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
  dev->totalBytesPerChunk = mtd->writesize;
  dev->nChunksPerBlock = mtd->erasesize / mtd->writesize;
#else
  dev->totalBytesPerChunk = mtd->oobblock;
  dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
#endif
  nBlocks = YCALCBLOCKS(mtd->size, mtd->erasesize);
  dev->startBlock = 0;
  dev->endBlock = nBlocks - 1;
 }
 ...
 
 inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0,
     yaffs_Root(dev));
 inode->i_op = &yaffs_dir_inode_operations;
 inode->i_fop = &yaffs_dir_operations;
 
 ...
 root = d_alloc_root(inode);
 ...
 sb->s_root = root;
 sb->s_dirt = !dev->isCheckpointed;
 
 ...
 return sb;
}
/**************** note2-2-1-1-2-1-3-1 yaffs_internal_read_super() ****************/
/************** note2-2-1-1-2-1-3 fill_super() // yaffs_internal_read_super_mtd() **************/
/************ note2-2-1-1-2-1 get_sb_bdev() ************/
/********** note2-2-1-1-2 type->get_sb() // yaffs2_read_super() **********/
/******** note2-2-1-1 vfs_kern_mount() ********/
/****** note2-2-1 do_kern_mount() ******/
/**** note2-2 do_new_mount() ****/
/** note2   do_mount() **/
/// mount的過程主要繁雜在函數(shù)vfs_kern_mount()中,,其中完成的工作主要是block_device結(jié)構(gòu)體的查找和超級塊的填充,。
/// 接下來在yaffs2的操作函數(shù)中,比如:nandmtd2_ReadChunkWithTagsFromNAND中,,實際上是調(diào)用了對應(yīng)的
/// mtd->read函數(shù),。但是在什么時候調(diào)用這些函數(shù)和怎么調(diào)用,那就是IO調(diào)度層的工作了,。
/// 總的來說,,通過設(shè)備節(jié)點的inode結(jié)構(gòu)體找到了對應(yīng)得struct block_device結(jié)構(gòu)體,即inode->i_bdev.

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點,。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多