1. 程式人生 > >《Linux啟動過程分析》核心掛載根檔案系統

《Linux啟動過程分析》核心掛載根檔案系統

說明:本文基於Linux2.6.29核心分析;其他核心版本僅供參考。

  前邊通過原始碼情景分析,看過了匯流排、裝置、驅動及其發現機制,Linux2.6核心udev裝置節點建立相關;對於檔案系統,一直望而生畏,但核心學習、這部分又不可能繞的過去。目前對VFS中使用的hash表還未做研究,它在dentry和vfsmount下查詢節點起關鍵作用;後邊在做分析。下邊將根檔案系統掛載過程做簡單分析:

一、rootfs的誕生

引子:

Linux一切皆檔案的提出:在Linux中,普通檔案、目錄、字元裝置、塊裝置、套接字等都以檔案被對待;他們具體的型別及其操作不同,但需要向上層提供統一的操作介面。

虛擬檔案系統VFS就是Linux核心中的一個軟體層,向上給使用者空間程式提供檔案系統操作介面;向下允許不同的檔案系統共存。所以,所有實際檔案系統都必須實現VFS的結構封裝。

矛盾的提出:

Linux系統中任何檔案系統的掛載必須滿足兩個條件:掛載點和檔案系統。

直接掛載nfs或flash檔案系統有如下兩個問題必須解決:

1.誰來提供掛載點?我們可以想象自己建立一個超級塊(包含目錄項和i節點),這時掛載點不是就有了嗎;很可惜,linux引入VFS(一切皆檔案,所有型別檔案系統必須提供一個VFS的軟體層、以向上層提供統一介面)後該問題不能這麼解決,因為掛載點必須關聯到檔案系統、也就是說掛載點必須屬於某個檔案系統。

2.怎樣訪問到nfs或flash上的檔案系統?我們可以說直接訪問裝置驅動讀取其上邊的檔案系統(裝置上的檔案系統是掛載在自己的根目錄),不就可以了嗎;別忘了還是Linux的VFS,裝置訪問也不例外。因為訪問裝置還是需要通過檔案系統來訪問它的掛載點,不能直接訪問(要滿足Linux的VFS架構,一切皆檔案)。

所以,一句話:rootfs之所以存在,是因為需要在VFS機制下給系統提供最原始的掛載點。

如此矛盾,需要我們引入一種特殊檔案系統:

1.它是系統自己建立並載入的第一個檔案系統;該檔案系統的掛載點就是它自己的根目錄項。

2.該檔案系統不能存在於nfs或flash上,因為如此將會陷入之前的矛盾。

rootfs的誕生:

上述問題需要我們建立具有如下三個特點的特殊檔案系統:

1.它是系統自己建立並載入的第一個檔案系統;

2.該檔案系統的掛載點就是它自己的根目錄項物件;

3.該檔案系統僅僅存在於記憶體中。

  由以上分析可以看出,rootfs是Linux的VFS(一切皆檔案,所有型別檔案系統必須提供一個VFS的軟體層、以向上層提供統一介面)存在的基石;二者關係密切。如果沒有VFS機制,rootfs也就沒有存在的必要;同樣,如果沒有rootfs、VFS機制也就不能實現。

  這就是兩者之間的真正關係,之前看網上什麼說法都有:有的只說關係密切,沒有指明具體關係;有的乾脆誤人子弟,說VFS就是rootfs。

  其實,VFS是一種機制、是Linux下每一種檔案系統(包括剛才說的rootfs,還有常見的ext3、yaffs等)都必須按照這個機制去實現的一種規範;而rootfs僅僅是符合VFS規範的而且又具有如上3個特點的一個檔案系統。

  VFS是Linux檔案系統實現必須遵循的一種機制,rootfs是一種具體實現的檔案系統、Linux下所有檔案系統的實現都必須符合VFS的機制(符合VFS的介面);這就是二者的真正關係。

以下分析基於Android模擬器Linux2.6.29核心:

二、相關資料結構

Linux核心中current指標作為全域性變數,使用非常廣泛;例如:程序上下文中獲取當前程序ID、任務排程,以及open等檔案系統呼叫中路徑搜尋等;首先介紹下current結構體:

各個平臺、各個核心版本中current的實現可能不同;但原理是一樣的。該指標一般定義在具體平臺的current.h標頭檔案中,型別為struct task_struct:

#define current (get_current())
static inline struct task_struct *get_current(void)

include/linux/sched.h

struct task_struct {
  ......
  struct thread_info *thread_info;
  struct list_head tasks;
  pid_t pid;
  pid_t tgid;
  uid_t uid,euid,suid,fsuid;
  gid_t gid,egid,sgid,fsgid;
  struct fs_struct *fs;  //本節將大量使用這個
  struct files_struct *files;
  ......
}

1.檔案系統註冊

kernel/include/include/fs.h

struct file_system_type {
  const char *name; //檔案系統名字;如:rootfs及ext3等
  int fs_flags;
  int (*get_sb) (struct file_system_type *, int, const char *, void *, struct vfsmount *);
  //安裝/掛載檔案系統時,會呼叫;獲取超級塊。
  void (*kill_sb) (struct super_block *);
  //解除安裝檔案系統時會呼叫。
  struct module *owner;
  struct file_system_type * next;
  //指向下一個檔案系統型別。
  struct list_head fs_supers;
  //同一個檔案系統型別中所有超級塊組成雙向連結串列。
  struct lock_class_key s_lock_key;
  struct lock_class_key s_umount_key;

  struct lock_class_key i_lock_key;
  struct lock_class_key i_mutex_key;
  struct lock_class_key i_mutex_dir_key;
  struct lock_class_key i_alloc_sem_key;
};

2.檔案系統掛載vfsmount(struct vfsmount):

  本質上,mount操作的過程就是新建一個vfsmount結構,然後將此結構和掛載點(目錄項物件)關聯。關聯之後,目錄查詢時就能沿著vfsmount掛載點一級級向下查詢檔案了。
對於每一個mount的檔案系統,都由一個vfsmount例項來表示。

kernel/include/linux/mount.h

struct vfsmount {
  struct list_head mnt_hash; //核心通過雜湊表對vfsmount進行管理
  struct vfsmount *mnt_parent;	//指向父檔案系統對應的vfsmount
  struct dentry *mnt_mountpoint; //指向該檔案系統掛載點對應的目錄項物件dentry
  struct dentry *mnt_root; //該檔案系統對應的裝置根目錄dentry
  struct super_block *mnt_sb; //指向該檔案系統對應的超級塊
  struct list_head mnt_mounts; 
  struct list_head mnt_child;  //同一個父檔案系統中的所有子檔案系統通過該欄位連結成雙聯表
  int mnt_flags;
  /* 4 bytes hole on 64bits arches */
  const char *mnt_devname;	/* Name of device e.g. /dev/dsk/hda1 */
  struct list_head mnt_list;  //所有已掛載檔案系統的vfsmount結構通過該欄位連結在一起
  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;
  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;
};

3.超級塊(struct super_bloc):

kernel/include/linux/fs.h

struct super_block {
  struct list_head	s_list;		/* Keep this first */
  dev_t			s_dev;		/* search index; _not_ kdev_t */
  unsigned long		s_blocksize;
  unsigned char		s_blocksize_bits;
  unsigned char		s_dirt;
  unsigned long long	s_maxbytes;	/* Max file size */
  struct file_system_type	*s_type; //檔案系統型別
  //(kernel/include/linux/fs.h,struct file_system_type)
  const struct super_operations	*s_op;
  struct dquot_operations	*dq_op;
  struct quotactl_ops	*s_qcop;
  const struct export_operations *s_export_op;
  unsigned long		s_flags;
  unsigned long		s_magic;
  struct dentry		*s_root;  //超級塊要指向目錄項物件
  struct rw_semaphore	s_umount;
  struct mutex		s_lock;
  int			s_count;
  int			s_need_sync_fs;
  atomic_t		s_active;
#ifdef CONFIG_SECURITY
  void                    *s_security;
#endif
  struct xattr_handler	**s_xattr;

  struct list_head	s_inodes;	/* all inodes */
  struct list_head	s_dirty;	/* dirty inodes */
  struct list_head	s_io;		/* parked for writeback */
  struct list_head	s_more_io;	/* parked for more writeback */
  struct hlist_head	s_anon;//雜湊表頭		/* anonymous dentries for (nfs) exporting */
  struct list_head	s_files;
  /* s_dentry_lru and s_nr_dentry_unused are protected by dcache_lock */
  struct list_head	s_dentry_lru;	/* unused dentry lru */
  int			s_nr_dentry_unused;	/* # of dentry on lru */

  struct block_device	*s_bdev;
  struct mtd_info		*s_mtd;
  struct list_head	s_instances;
  struct quota_info	s_dquot;	/* Diskquota specific options */

  int			s_frozen;
  wait_queue_head_t	s_wait_unfrozen;

  char s_id[32];				/* Informational name */

  void 			*s_fs_info;	/* Filesystem private info */
  fmode_t			s_mode;

  /*
  * The next field is for VFS *only*. No filesystems have any business
  * even looking at it. You had been warned.
  */
  struct mutex s_vfs_rename_mutex;	/* Kludge */

  /* Granularity of c/m/atime in ns.Cannot be worse than a second */
  u32		   s_time_gran;

  /*
  * Filesystem subtype.  If non-empty the filesystem type field
  * in /proc/mounts will be "type.subtype"
  */
  char *s_subtype;

  /*
  * Saved mount options for lazy filesystems using
  * generic_show_options()
  */
  char *s_options;

  /*
  * storage for asynchronous operations
  */
  struct list_head s_async_list;
};

4.目錄索引節點(struct inode):

kernel/include/linux/fs.h

struct inode {
  struct hlist_node	i_hash; //雜湊表節點
  struct list_head	i_list;
  struct list_head	i_sb_list;
  struct list_head	i_dentry;
  unsigned long		i_ino;
  atomic_t		i_count;
  unsigned int		i_nlink;
  uid_t			i_uid;
  gid_t			i_gid;
  dev_t			i_rdev;
  u64			i_version;
  loff_t			i_size;
#ifdef __NEED_I_SIZE_ORDERED
  seqcount_t		i_size_seqcount;
#endif
  struct timespec		i_atime;
  struct timespec		i_mtime;
  struct timespec		i_ctime;
  unsigned int		i_blkbits;
  blkcnt_t		i_blocks;
  unsigned short          i_bytes;
  umode_t			i_mode;
  spinlock_t		i_lock;	/* i_blocks, i_bytes, maybe i_size */
  struct mutex		i_mutex;
  struct rw_semaphore	i_alloc_sem;
  const struct inode_operations	*i_op;
  const struct file_operations	*i_fop;	/* former ->i_op->default_file_ops */
  struct super_block	*i_sb;
  struct file_lock	*i_flock;
  struct address_space	*i_mapping;
  struct address_space	i_data;
#ifdef CONFIG_QUOTA
  struct dquot		*i_dquot[MAXQUOTAS];
#endif
  struct list_head	i_devices;
  union {
    struct pipe_inode_info	*i_pipe;
    struct block_device	*i_bdev;
    struct cdev		*i_cdev;
  };
  int			i_cindex;

  __u32			i_generation;

#ifdef CONFIG_DNOTIFY
  unsigned long		i_dnotify_mask; /* Directory notify events */
  struct dnotify_struct	*i_dnotify; /* for directory notifications */
#endif

#ifdef CONFIG_INOTIFY
  struct list_head	inotify_watches; /* watches on this inode */
  struct mutex		inotify_mutex;	/* protects the watches list */
#endif

  unsigned long		i_state;
  unsigned long		dirtied_when;	/* jiffies of first dirtying */

  unsigned int		i_flags;

  atomic_t		i_writecount;
#ifdef CONFIG_SECURITY
  void			*i_security;
#endif
  void			*i_private; /* fs or device private pointer */
};

5.目錄項物件(struct dentry):

kernel/include/linux/dcache.h

struct dentry {
  atomic_t d_count;
  unsigned int d_flags;		/* protected by d_lock */
  spinlock_t d_lock;		/* per dentry lock */
  int d_mounted;
  struct inode *d_inode; //目錄項物件與目錄索引的關聯		
  /* Where the name belongs to - NULL is
  * negative */
  /*
  * 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; //d_name.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 */
};

其他:

include/linux/fs.h

struct file {
  /*
  * fu_list becomes invalid after file_free is called and queued via
  * fu_rcuhead for RCU freeing
  */
  union {
    struct list_head	fu_list;
    struct rcu_head 	fu_rcuhead;
  } f_u;
  struct path		f_path;  //重要!!!記錄掛載資訊和目錄項資訊
#define f_dentry	f_path.dentry
#define f_vfsmnt	f_path.mnt
  const struct file_operations	*f_op;
  atomic_long_t		f_count;
  unsigned int 		f_flags;
  fmode_t			f_mode;
  loff_t			f_pos;
  struct fown_struct	f_owner;
  const struct cred	*f_cred;
  struct file_ra_state	f_ra;

  u64			f_version;
#ifdef CONFIG_SECURITY
  void			*f_security;
#endif
  /* needed for tty driver, and maybe others */
  void			*private_data;

#ifdef CONFIG_EPOLL
  /* Used by fs/eventpoll.c to link all the hooks to this file */
  struct list_head	f_ep_links;
  spinlock_t		f_ep_lock;
#endif /* #ifdef CONFIG_EPOLL */
  struct address_space	*f_mapping;
#ifdef CONFIG_DEBUG_WRITECOUNT
  unsigned long f_mnt_write_state;
#endif
};

include/linux/fs_struct.h

struct fs_struct {
  atomic_t count;
  rwlock_t lock;
  int umask;
  struct path root, pwd; //重要!!!記錄掛載資訊和目錄項資訊
};

include/linux/namei.h

struct nameidata {
  struct path	path;  //重要!!!記錄掛載資訊和目錄項資訊
  struct qstr	last;  //重要!!!記錄目錄名
  unsigned int	flags;
  int		last_type;
  unsigned	depth;
  char *saved_names[MAX_NESTED_LINKS + 1];

  /* Intent data */
  union {
    struct open_intent open;
  } intent;
};

include/linux/path.h

struct path {
  struct vfsmount *mnt; //重要!!!記錄檔案系統掛載資訊
  struct dentry *dentry;  //重要!!!記錄目錄項資訊
};

include/linux/dcache.h

struct qstr {
  unsigned int hash;
  unsigned int len;
  const unsigned char *name;//重要!!!目錄/檔名字,如"/","tank1"等具體的檔名
};

三、註冊/建立、安裝/掛載rootfs,並呼叫set_fs_root設定系統current的根檔案系統為rootfs

過程:

第一步:建立rootfs檔案系統;

第二步:呼叫其get_sb函式(對於rootfs這種記憶體/偽檔案系統是get_sb_nodev,實際檔案系統比如ext2等是get_sb_bdev)、建立超級塊(包含目錄項和i節點);

第三步:掛載該檔案系統(該檔案系統的掛載點指向該檔案系統超級塊的根目錄項);

第四步:將系統current的根檔案系統和根目錄設定為rootfs和其根目錄。

kernel/init/main.c

asmlinkage void __init start_kernel(void)
{
  setup_arch(&command_line);//解析uboot命令列,實際檔案系統掛載需要
  parse_args("Booting kernel", static_command_line, __start___param,
		   __stop___param - __start___param,
		   &unknown_bootoption);
  vfs_caches_init(num_physpages);
}

kernel/fs/dcache.c

void __init vfs_caches_init(unsigned long mempages)
{
  mnt_init();
  bdev_cache_init(); //塊裝置檔案建立
  chrdev_init();//字元裝置檔案建立
}

kernel/fs/namespace.c

void __init mnt_init(void)
{
  init_rootfs(); //向核心註冊rootfs
  init_mount_tree();//重要!!!rootfs根目錄的建立以及rootfs檔案系統的掛載;設定系統current根目錄和根檔案系統為rootfs
}

下邊分兩步:

1.向核心註冊rootfs虛擬檔案系統init_rootfs

kernel/fs/ramfs/inode.c
int __init init_rootfs(void)
{
  err = register_filesystem(&rootfs_fs_type);
}
static struct file_system_type rootfs_fs_type = {
  .name		= "rootfs",
  .get_sb		= rootfs_get_sb,
  .kill_sb	= kill_litter_super,
};

2.建立rootfs的根目錄,並將rootfs掛載到自己的根目錄;設定系統current根目錄和根檔案系統

kernel/fs/namespace.c
static void __init init_mount_tree(void)
{
  struct vfsmount *mnt;
  struct mnt_namespace *ns;
  struct path root;
  //建立rootfs的vfsmount結構,建立rootfs的超級塊、並將rootfs掛載到自己的根目錄。
  /*
  mnt->mnt_mountpoint = mnt->mnt_root = dget(sb->s_root),而該mnt和自己的sb是關聯的;
  所以,是把rootfs檔案系統掛載到了自己對應的超級塊的根目錄上。
  這裡也是實現的關鍵:一般檔案系統的掛載是呼叫do_mount->do_new_mount而該函式中首先呼叫do_kern_mount,這時mnt->mnt_mountpoint = mnt->mnt_root;但後邊
  它還會呼叫do_add_mount->graft_tree->attach_recursive_mnt如下程式碼mnt_set_mountpoint(dest_mnt, dest_dentry, source_mnt)改變了其掛載點!!!
  */
  mnt = do_kern_mount("rootfs", 0, "rootfs", NULL);
  list_add(&mnt->mnt_list, &ns->list);
  ns->root = mnt; //將建立好的mnt加入系統當前
  mnt->mnt_ns = ns;

  init_task.nsproxy->mnt_ns = ns; //設定程序的名稱空間
  get_mnt_ns(ns);

  root.mnt = ns->root; //檔案系統為rootfs,相當與root.mnt = mnt;
  root.dentry = ns->root->mnt_root;//目錄項為根目錄項,相當與root.dentry = mnt->mnt_root;

  //設定系統current的pwd目錄和檔案系統
  set_fs_pwd(current->fs, &root);
  //設定系統current根目錄,根檔案系統。這個是關鍵!!!整個核心程式碼最多隻有兩處呼叫
  set_fs_root(current->fs, &root);  
}

以下著重分析do_kern_mount函式,它實現了rootfs在自己根目錄上的掛載:

kernel/fs/super.c
struct vfsmount *
do_kern_mount(const char *fstype, int flags, const char *name, void *data)
{
  mnt = vfs_kern_mount(type, flags, name, data);
  return mnt;
}

kernel/fs/super.c

struct vfsmount *
vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
{
  mnt = alloc_vfsmnt(name); //建立並填充vfsmount
  error = type->get_sb(type, flags, name, data, mnt);//為檔案系統建立並填充超級塊(主要是其dentry和inode),建立rootfs根目錄
  mnt->mnt_mountpoint = mnt->mnt_root; //檔案系統掛載點目錄,其實就是剛才建立的”/”目錄。掛載點就是自己!!!!
  mnt->mnt_parent = mnt; //父物件是自己!!!!
  return mnt;
}
kernel/fs/ramfs/inode.c
static int rootfs_get_sb(struct file_system_type *fs_type,
	int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
  return get_sb_nodev(fs_type, flags|MS_NOUSER, data, ramfs_fill_super,
			    mnt);
}

kernel/fs/super.c

int get_sb_nodev(struct file_system_type *fs_type,
	int flags, void *data,
	int (*fill_super)(struct super_block *, void *, int),
	struct vfsmount *mnt)
{
  struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL);
  //在記憶體中分配一個超級塊
  error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);
  //執行回撥,填充超級塊,並建立根目錄項及對應i節點
  /*
  kernel/fs/ramfs/inode.c
  static int ramfs_fill_super(struct super_block * sb, void * data, int silent)
  {
    struct inode * inode;
    struct dentry * root;
    sb->s_maxbytes = MAX_LFS_FILESIZE;
    sb->s_blocksize = PAGE_CACHE_SIZE;
    sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
    sb->s_magic = RAMFS_MAGIC;
    sb->s_op = &ramfs_ops;
    //static const struct super_operations ramfs_ops;
    sb->s_time_gran = 1;
    //建立根目錄索引節點,我們最終的目標是要找到目錄項物件關聯的索引節點。
    //根目錄索引節點會有自己的ops。
    inode = ramfs_get_inode(sb, S_IFDIR | 0755, 0); 
    //ramfs_get_inode
    kernel/fs/ramfs/inode.c
    struct inode *ramfs_get_inode(struct super_block *sb, int mode, dev_t dev)
    {
      struct inode * inode = new_inode(sb);
      switch (mode & S_IFMT) {  //判斷檔案型別
        default:
	  init_special_inode(inode, mode, dev);
	  //init_special_inode
          void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)
          {
	    inode->i_mode = mode;
	    if (S_ISCHR(mode)) {//字元裝置檔案
	      inode->i_fop = &def_chr_fops;
	      inode->i_rdev = rdev;
	    } else if (S_ISBLK(mode)) {//塊裝置檔案
	      inode->i_fop = &def_blk_fops;
	      inode->i_rdev = rdev;
	    } else if (S_ISFIFO(mode))
	      inode->i_fop = &def_fifo_fops;
	    else if (S_ISSOCK(mode)) //網路裝置檔案
	      inode->i_fop = &bad_sock_fops;
	    else
	      printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o) for"
				  " inode %s:%lu\n", mode, inode->i_sb->s_id,
				  inode->i_ino);
           }
          //init_special_inode end
          break;
        case S_IFREG: //普通檔案
          inode->i_op = &ramfs_file_inode_operations;  //索引節點的操作方法
          inode->i_fop = &ramfs_file_operations;  //預設普通檔案的操作方法
          break;
        case S_IFDIR:  //目錄檔案
          inode->i_op = &ramfs_dir_inode_operations;
          //ramfs_dir_inode_operations
          static const struct inode_operations ramfs_dir_inode_operations;
          kernel/include/linux/fs.h
          struct inode_operations {
            int (*create) (struct inode *,struct dentry *,int, struct nameidata *);
            int (*mkdir) (struct inode *,struct dentry *,int);
	    int (*rmdir) (struct inode *,struct dentry *);
	    int (*mknod) (struct inode *,struct dentry *,int,dev_t);
          }
          //ramfs_dir_inode_operations end
          inode->i_fop = &simple_dir_operations;  //目錄檔案的操作方法
          inc_nlink(inode);
          break;
      }
    }
    //ramfs_get_inode end
    //建立根目錄目錄物件,目錄項物件的存在主要是為了我們進行路徑的查詢。
    root = d_alloc_root(inode);   
    //d_alloc_root
    kernel/fs/dcache.c
    struct dentry * d_alloc_root(struct inode * root_inode)
    {
      struct dentry *res = NULL;
      static const struct qstr name = { .name = "/", .len = 1 };
      res = d_alloc(NULL, &name);
      res->d_sb = root_inode->i_sb; //指向該檔案系統的超級塊
      res->d_parent = res;  //根目錄的父親是它自己
      d_instantiate(res, root_inode); //關聯 dentry 和 inode
    }
    //d_alloc_root end
    sb->s_root = root;  //超級塊的s_root指向剛建立的根目錄物件。
  }
  */
  return simple_set_mnt(mnt, s); //關聯超級塊(包含目錄項dentry和i節點inode)和vfsmount
}
kernel/fs/namespace.c
int simple_set_mnt(struct vfsmount *mnt, struct super_block *sb)
{
  printk("TK-------_>>>>>>>namespace.c>>>>simple_set_mnt\n");//add by tankai
  mnt->mnt_sb = sb;  //對 mnt_sb超級塊指標附值
  mnt->mnt_root = dget(sb->s_root); //對mnt_root指向的根目錄賦值
  return 0;
}

至此,rootfs檔案系統建立、並且掛載於自己超級塊(包括目錄項dentry和i節點inod)對應的目錄項,設定了系統current根目錄和根檔案系統、pwd的目錄和檔案系統。

========================================

釋放Initramfs到rootfs;如果Initramfs中有init,這種情況比較特殊、rootfs就是最後系統使用的根檔案系統。

而且此時,不需要在單獨燒錄根檔案系統的img;此時,根檔案系統就是核心uImage的一部分。當然,缺陷就是該檔案系統執行時的介質是ramdisk即記憶體盤、它不再與磁碟對應;因此,此時修改根目錄下的檔案將不被得到儲存。它的核心配置項為:CONFIG_INITRAMFS_SOURCE。實際專案中會經常碰到。

make menuconfig->General setup->Initial RAM filesystem and RAM disk(initramfs/initrd) support
底下的Initramfs source file(s)填寫根檔案系統的路徑,如:../out/target/product/tclm6/root;不填的話,將導致initrd或磁碟檔案系統的掛載(因為下邊將會看到,核心將找不到“/init”)。

對應核心原始碼:

kernel/init/main.c
static int __init kernel_init(void * unused){
  ......
  do_basic_setup();  //初始化裝置驅動,載入靜態核心模組;釋放Initramfs到rootfs
  /*
  kernel/init/initramfs.c
  rootfs_initcall(populate_rootfs);
  static int __init populate_rootfs(void)
  {
    printk(KERN_INFO "checking if image is initramfs...");
    err = unpack_to_rootfs((char *)initrd_start,
                        initrd_end - initrd_start, 1); //釋放ramdisk到rootfs
  }
  */
  ......
  if (!ramdisk_execute_command)  ramdisk_execute_command = "/init";
  if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {
    ramdisk_execute_command = NULL;
    //如果此時rootfs中沒有init,則載入initfd、nfs或磁碟檔案系統
    //也即磁碟的檔案系統掛載至rootfs的/root目錄,並設定系統current對應的根目錄項為磁碟根目錄項、系統current根檔案系統為磁碟檔案系統
    //至此,rootfs對於以後所有程序而言、已被隱藏。
    prepare_namespace(); 
  }
  init_post(); //啟動init程序
  ......
}

看看init_post實現:

static noinline int init_post(void)
{
  if (ramdisk_execute_command) {  //Initramfs從這裡啟動init
    run_init_process(ramdisk_execute_command);
    printk(KERN_WARNING "Failed to execute %s\n", ramdisk_execute_command);
  }
  //initrd、nfs和磁碟都是從如下啟動的init
  if (execute_command) {
    run_init_process(execute_command);
    printk(KERN_WARNING "Failed to execute %s.  Attempting "
					"defaults...\n", execute_command);
  }
  //一般執行如下
  run_init_process("/sbin/init");
  run_init_process("/etc/init");
  run_init_process("/bin/init");
  run_init_process("/bin/sh");
}

四、掛載實際檔案系統至rootfs,並呼叫set_fs_root設定為系統current的根檔案系統

下邊從uboot啟動核心引數的角度來簡單說明:

以下三種情況都是將檔案系統掛載到rootfs的/root目錄,並將系統current的根目錄切換為/root、系統current的根檔案系統切換為磁碟檔案系統。

kernel/init/do_mounts.c

void __init prepare_namespace(void)
{
  if (initrd_load()) //如果掛載initrd並執行成功,則不再掛載磁碟檔案系統
    goto out;
  if (saved_root_name[0]) {
    root_device_name = saved_root_name;
    if (!strncmp(root_device_name, "mtd", 3) ||
        !strncmp(root_device_name, "ubi", 3)) {
      mount_block_root(root_device_name, root_mountflags); //啟動時root=引數,如《四.2》中“root=/dev/mtdblock0”
      goto out;
    }
    ROOT_DEV = name_to_dev_t(root_device_name);
    if (strncmp(root_device_name, "/dev/", 5) == 0)
      root_device_name += 5;
  }
  mount_root(); //將實際檔案系統掛載到rootfs的/root目錄
out:
  //sys_mount(".", "/", NULL, MS_MOVE, NULL); 這句話無關緊要,影響理解;遮蔽不影響功能
  sys_chroot(".");  //將當前目錄(/root)設定為系統current根目錄,磁碟檔案系統設定為系統current根檔案系統。
}

下邊分兩步解釋mount_root()和sys_chroot(".")呼叫:

1.將nfs或磁碟檔案系統掛載至rootfs的/root目錄(以磁碟為例)

void __init mount_root(void)
{
  if (mount_nfs_root())  //如果網路檔案系統掛載成功,則nfs作為根檔案系統
    return;
  //掛載磁碟檔案系統為根檔案系統
  //在rootfs中建立/dev/root裝置檔案
  create_dev("/dev/root", ROOT_DEV);  //在rootfs中建立/dev/root裝置檔案,也就是/dev/mtdblock0裝置。
  //掛載/dev/root到rootfs的/root目錄
  mount_block_root("/dev/root", root_mountflags);
}
void __init mount_block_root(char *name, int flags)
{
  int err = do_mount_root(name, p, flags, root_mount_data);  
}
static int __init do_mount_root(char *name, char *fs, int flags, void *data)
{
  int err = sys_mount(name, "/root", fs, flags, data);//將/dev/root掛載到/root
  sys_chdir("/root"); //系統current->fs->pwd為當前目錄/root
  ROOT_DEV = current->fs->pwd.mnt->mnt_sb->s_dev;
  return 0;
}

2.將當前目錄/root設定為系統current根目錄,磁碟檔案系統設定為系統current根檔案系統

fs/open.c

SYSCALL_DEFINE1(chroot, const char __user *, filename)
{
  struct path path;
  error = user_path_dir(filename, &path);
  //這才是完成切換的關鍵!!!!整個核心程式碼只有兩處呼叫
  set_fs_root(current->fs, &path); 
}

注意,如下情況:rootfs特殊檔案系統沒有被解除安裝,他只是隱藏在基於磁碟的根檔案系統下了。

initrd作為根檔案系統

setenv bootargs root=/dev/ram0 initrd=0x2800000,24M rootfstype=ext2 mem=64M console=ttyAMA0

引數說明:

root:用來指定rootfs的位置。

rootfstype:用來指定檔案系統的型別。

nfs作為根檔案系統

setenv bootargs root=/dev/nfs nfsroot=192.168.1.7:/opt/yz/nfs,rw ip=192.168.1.160 mem=64M console=ttyAMA0

引數說明:

nfsroot:檔案系統在哪臺主機的哪個目錄下。

ip:指定系統啟動之後網絡卡的ip地址。

flash作為根檔案系統

setenv bootargs root=/dev/mtdblock0 mem=16M mtdparts=armflash.1:[email protected](jffs2) macaddr=9854 rootfstype=jffs2 console=ttyAMA0

引數說明:

mtdparts:根檔案系統在flash中的位置。

總結:rootfs永遠不會被解除安裝,它只是被隱藏了。在使用者空間下,更多地情況是隻能見到rootfs這棵大樹的一葉,而且還是被安裝過檔案系統了的。

五、其他說明

至於在mirco2440下mount出的結果:

rootfs on / type rootfs (rw)
/dev/root on / type yaffs (rw,relatime)
none on /proc type proc (rw,relatime)
none on /sys type sysfs (rw,relatime)
none on /proc/bus/usb type usbfs (rw,relatime)
none on /dev type ramfs (rw,relatime)
none on /dev/pts type devpts (rw,relatime,mode=622)
tmpfs on /dev/shm type tmpfs (rw,relatime)
none on /tmp type ramfs (rw,relatime)
none on /var type ramfs (rw,relatime)

從log中體會一下這個過程:

s3c2410-rtc s3c2410-rtc: setting system clock to 2006-04-16 22:15:34 UTC (1145225734)
TK------->>>>>init/main.c>>>>>>kernel_init>>before>prepare_namespace
##################################################################################################################
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.dentry->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.dentry->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_mountpoint->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_mountpoint->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_root->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_root->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_sb->s_type->name is rootfs
##################################################################################################################
##################################################################################################################
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.dentry->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.dentry->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_mountpoint->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_mountpoint->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_root->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_root->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_sb->s_type->name is rootfs
##################################################################################################################
TK------->>>>>init/do_mounts.c>>>>>>prepare_namespace>>before>mount_root
##################################################################################################################
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.dentry->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.dentry->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_mountpoint->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_mountpoint->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_root->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_root->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_sb->s_type->name is rootfs
##################################################################################################################
##################################################################################################################
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.dentry->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.dentry->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_mountpoint->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_mountpoint->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_root->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_root->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_sb->s_type->name is rootfs
##################################################################################################################
yaffs: dev is 32505859 name is "mtdblock3"
yaffs: passed flags ""
yaffs: Attempting MTD mount on 31.3, "mtdblock3"
yaffs_read_super: isCheckpointed 0
VFS: Mounted root (yaffs filesystem) on device 31:3.
TK------->>>>>init/do_mounts.c>>>>>>prepare_namespace>>before>sys_mount
##################################################################################################################
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.dentry->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.dentry->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_mountpoint->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_mountpoint->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_root->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_root->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_sb->s_type->name is rootfs
##################################################################################################################
##################################################################################################################
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.dentry->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.dentry->d_sb->s_type->name is yaffs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_mountpoint->d_name.name is root
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_mountpoint->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_root->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_root->d_sb->s_type->name is yaffs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_sb->s_type->name is yaffs
##################################################################################################################
TK------->>>>>init/do_mounts.c>>>>>>prepare_namespace>>before>sys_chroot
##################################################################################################################
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.dentry->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.dentry->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_mountpoint->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_mountpoint->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_root->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_root->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_sb->s_type->name is rootfs
##################################################################################################################
##################################################################################################################
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.dentry->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.dentry->d_sb->s_type->name is yaffs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_mountpoint->d_name.name is root
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_mountpoint->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_root->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_root->d_sb->s_type->name is yaffs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_sb->s_type->name is yaffs
##################################################################################################################
TK------->>>>>fs/open.c>>>>>>SYSCALL_DEFINE1(chroot>>before>set_fs_root
##################################################################################################################
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.dentry->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.dentry->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_mountpoint->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_mountpoint->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_root->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_root->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_sb->s_type->name is rootfs
##################################################################################################################
##################################################################################################################
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.dentry->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.dentry->d_sb->s_type->name is yaffs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_mountpoint->d_name.name is root
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_mountpoint->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_root->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_root->d_sb->s_type->name is yaffs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_sb->s_type->name is yaffs
##################################################################################################################
TK------->>>>>init/do_mounts.c>>>>>>SYSCALL_DEFINE1(chroot>>after>set_fs_root
##################################################################################################################
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.dentry->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.dentry->d_sb->s_type->name is yaffs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_mountpoint->d_name.name is root
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_mountpoint->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_root->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_root->d_sb->s_type->name is yaffs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_sb->s_type->name is yaffs
##################################################################################################################
##################################################################################################################
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.dentry->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.dentry->d_sb->s_type->name is yaffs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_mountpoint->d_name.name is root
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_mountpoint->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_root->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_root->d_sb->s_type->name is yaffs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_sb->s_type->name is yaffs
##################################################################################################################
TK------->>>>>init/do_mounts.c>>>>>>prepare_namespace>>after>sys_chroot
##################################################################################################################
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.dentry->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.dentry->d_sb->s_type->name is yaffs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_mountpoint->d_name.name is root
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_mountpoint->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_root->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_root->d_sb->s_type->name is yaffs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_sb->s_type->name is yaffs
##################################################################################################################
##################################################################################################################
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.dentry->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.dentry->d_sb->s_type->name is yaffs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_mountpoint->d_name.name is root
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_mountpoint->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_root->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_root->d_sb->s_type->name is yaffs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_sb->s_type->name is yaffs
##################################################################################################################
TK------->>>>>init/main.c>>>>>>kernel_init>>after>prepare_namespace
##################################################################################################################
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.dentry->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.dentry->d_sb->s_type->name is yaffs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_mountpoint->d_name.name is root
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_mountpoint->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_root->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_root->d_sb->s_type->name is yaffs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_sb->s_type->name is yaffs
##################################################################################################################
##################################################################################################################
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.dentry->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.dentry->d_sb->s_type->name is yaffs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_mountpoint->d_name.name is root
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_mountpoint->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_root->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_root->d_sb->s_type->name is yaffs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_sb->s_type->name is yaffs
##################################################################################################################
Freeing init memory: 156K
[16/Apr/2006:14:15:35 +0000] boa: server version Boa/0.94.13
[16/Apr/2006:14:15:35 +0000] boa: server built Mar 26 2009 at 15:28:42.
[16/Apr/2006:14:15:35 +0000] boa: starting server pid=681, port 80
                        
Try to bring eth0 interface up......eth0: link down
Done

Please press Enter to activate this console. 
[[email protected] /]# mount
rootfs on / type rootfs (rw)
/dev/root on / type yaffs (rw,relatime)
none on /proc type proc (rw,relatime)
none on /sys type sysfs (rw,relatime)
none on /proc/bus/usb type usbfs (rw,relatime)
none on /dev type ramfs (rw,relatime)
none on /dev/pts type devpts (rw,relatime,mode=622)
tmpfs on /dev/shm type tmpfs (rw,relatime)
none on /tmp type ramfs (rw,relatime)
none on /var type ramfs (rw,relatime)
[[email protected] /]# 

ubuntu下mount出的結果:

/dev/sda5 on / type ext3 (rw,errors=remount-ro,commit=0)
proc on /proc type proc (rw,noexec,nosuid,nodev)
sysfs on /sys type sysfs (rw,noexec,nosuid,nodev)
fusectl on /sys/fs/fuse/connections type fusectl (rw)
none on /sys/kernel/debug type debugfs (rw)
none on /sys/kernel/security type securityfs (rw)
udev on /dev type devtmpfs (rw,mode=0755)
devpts on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=0620)
tmpfs on /run type tmpfs (rw,noexec,nosuid,size=10%,mode=0755)
none on /run/lock type tmpfs (rw,noexec,nosuid,nodev,size=5242880)
none on /run/shm type tmpfs (rw,nosuid,nodev)
/dev/sda7 on /home type ext3 (rw,commit=0)
binfmt_misc on /proc/sys/fs/binfmt_misc type binfmt_misc (rw,noexec,nosuid,nodev)
rpc_pipefs on /var/lib/nfs/rpc_pipefs type rpc_pipefs (rw)
nfsd on /proc/fs/nfsd type nfsd (rw)
gvfs-fuse-daemon on /home/tankai/.gvfs type fuse.gvfs-fuse-daemon (rw,nosuid,nodev,user=tankai)

    一個還顯示rootfs,一個乾脆不顯示。這個無關緊要。可能micro2440中執行mount命令還會將系統current根目錄的父節點也顯示出來;而ubuntu下不會再去關心繫統current根目錄的父節點。但所有的檔案搜尋,核心都是從系統current根目錄開始向下查詢的,因此、可以說我們不能在訪問rootfs中除了作為系統current根檔案系統之外的其他任何節點。

六、測試用例,說明系統current的檔案系統佈局,不管在那個目錄、其根都不會改變:

hello.c

#include <linux/syscalls.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/acct.h>
#include <linux/capability.h>
#include <linux/cpumask.h>
#include <linux/module.h>
#include <linux/sysfs.h>
#include <linux/seq_file.h>
#include <linux/mnt_namespace.h>
#include <linux/namei.h>
#include <linux/security.h>
#include <linux/mount.h>
#include <linux/ramfs.h>
#include <linux/log2.h>
#include <linux/idr.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
//#include "pnode.h"
//#include "internal.h"


#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");

static int hello_init(void)
{
    printk(KERN_ALERT "Hello, world\n");
    printk("TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.dentry->d_name.name is %s\n",current->fs->root.dentry->d_name.name);
    printk("TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.dentry->d_sb->s_type->name is %s\n",current->fs->root.dentry->d_sb->s_type->name);
    printk("TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_mountpoint->d_name.name is %s\n",current->fs->root.mnt->mnt_mountpoint->d_name.name);
    printk("TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_mountpoint->d_sb->s_type->name is %s\n",current->fs->root.mnt->mnt_mountpoint->d_sb->s_type->name);
    printk("TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_root->d_name.name is %s\n",current->fs->root.mnt->mnt_root->d_name.name);
    printk("TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_root->d_sb->s_type->name is %s\n",current->fs->root.mnt->mnt_root->d_sb->s_type->name);
    printk("TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_sb->s_type->name is %s\n",current->fs->root.mnt->mnt_sb->s_type->name);
    printk("########################################################################################\n");
    printk("TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.dentry->d_name.name is %s\n",current->fs->pwd.dentry->d_name.name);
    printk("TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.dentry->d_sb->s_type->name is %s\n",current->fs->pwd.dentry->d_sb->s_type->name);
    printk("TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_mountpoint->d_name.name is %s\n",current->fs->pwd.mnt->mnt_mountpoint->d_name.name);
    printk("TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_mountpoint->d_sb->s_type->name is %s\n",current->fs->pwd.mnt->mnt_mountpoint->d_sb->s_type->name);
    printk("TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_root->d_name.name is %s\n",current->fs->pwd.mnt->mnt_root->d_name.name);
    printk("TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_root->d_sb->s_type->name is %s\n",current->fs->pwd.mnt->mnt_root->d_sb->s_type->name);
    printk("TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_sb->s_type->name is %s\n",current->fs->pwd.mnt->mnt_sb->s_type->name);
    return 0;
}

static void hello_exit(void)
{
    printk(KERN_ALERT"Goodbye, cruel world\n");
}

module_init(hello_init);
module_exit(hello_exit);
Makefile
ifneq ($(KERNELRELEASE),)
obj-m:=hello.o
else
KERNELDIR:=/home/android2.3/android2.3_kernel/
PWD:=$(shell pwd)
default:
	$(MAKE) -C $(KERNELDIR)  M=$(PWD) modules
clean:
	rm -rf *.o *.mod.c *.mod.o *.ko
endif

make生成hello.ko

先看下檔案系統佈局:

mount

rootfs / rootfs ro 0 0
tmpfs /dev tmpfs rw,mode=755 0 0
devpts /dev/pts devpts rw,mode=600 0 0
proc /proc proc rw 0 0
sysfs /sys sysfs rw 0 0
none /acct cgroup rw,cpuacct 0 0
tmpfs /mnt/asec tmpfs rw,mode=755,gid=1000 0 0
tmpfs /mnt/obb tmpfs rw,mode=755,gid=1000 0 0
none /dev/cpuctl cgroup rw,cpu 0 0
/dev/block/mtdblock0 /system yaffs2 rw 0 0
/dev/block/mtdblock1 /data yaffs2 rw,nosuid,nodev 0 0
/dev/block/mtdblock2 /cache yaffs2 rw,nosuid,nodev 0 0
/dev/block/vold/179:0 /mnt/sdcard vfat rw,dirsync,nosuid,nodev,noexec,uid=1000,gid=1015,fmask=0702,dmask=0702,allow_utime=0020,codepage=cp437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro 0 0
/dev/block/vold/179:0 /mnt/secure/asec vfat rw,dirsync,nosuid,nodev,noexec,uid=1000,gid=1015,fmask=0702,dmask=0702,allow_utime=0020,codepage=cp437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro 0 0
tmpfs /mnt/sdcard/.android_secure tmpfs ro,size=0k,mode=000 0 0

1.放入/data/下執行insmod hello.ko rmmod hello.ko

Hello, world
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.dentry->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.dentry->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_mountpoint->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_mountpoint->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_root->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_root->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_sb->s_type->name is rootfs
########################################################################################
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.dentry->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.dentry->d_sb->s_type->name is yaffs2
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_mountpoint->d_name.name is data
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_mountpoint->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_root->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_root->d_sb->s_type->name is yaffs2
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_sb->s_type->name is yaffs2
Goodbye, cruel world
2.放在/sdcard/tank/下執行insmod hello.ko rmmod hello.ko
Hello, world
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.dentry->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.dentry->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_mountpoint->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_mountpoint->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_root->d_name.name is /
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_root->d_sb->s_type->name is rootfs
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->root.mnt->mnt_sb->s_type->name is rootfs
########################################################################################
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.dentry->d_name.name is tank
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.dentry->d_sb->s_type->name is vfat
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_mountpoint->d_name.name is sdcard
TK---->>>>init/ma