说明:本文基于Linux2.6.29内核分析;其他内核版本仅供参考。

Android2.3及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;   //指向父文件系统对应的vfsmountstruct dentry *mnt_mountpoint; //指向该文件系统挂载点对应的目录项对象dentrystruct dentry *mnt_root; //该文件系统对应的设备根目录dentrystruct 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_SECURITYvoid                    *s_security;
#endifstruct 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_ORDEREDseqcount_t      i_size_seqcount;
#endifstruct 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_QUOTAstruct dquot     *i_dquot[MAXQUOTAS];
#endifstruct 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_DNOTIFYunsigned long     i_dnotify_mask; /* Directory notify events */struct dnotify_struct  *i_dnotify; /* for directory notifications */
#endif#ifdef CONFIG_INOTIFYstruct list_head inotify_watches; /* watches on this inode */struct mutex        inotify_mutex;  /* protects the watches list */
#endifunsigned long     i_state;unsigned long       dirtied_when;   /* jiffies of first dirtying */unsigned int     i_flags;atomic_t        i_writecount;
#ifdef CONFIG_SECURITYvoid          *i_security;
#endifvoid          *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.mntconst 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_SECURITYvoid          *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_WRITECOUNTunsigned 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(); //向内核注册rootfsinit_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); //建立并填充vfsmounterror = 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.cstatic 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_inodekernel/fs/ramfs/inode.cstruct 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_inodevoid 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;elseprintk(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 endbreak;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_operationsstatic const struct inode_operations ramfs_dir_inode_operations;kernel/include/linux/fs.hstruct 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 endinode->i_fop = &simple_dir_operations;  //目录文件的操作方法inc_nlink(inode);break;}}//ramfs_get_inode end//建立根目录目录对象,目录项对象的存在主要是为了我们进行路径的查找。root = d_alloc_root(inode);   //d_alloc_rootkernel/fs/dcache.cstruct 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 endsb->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 tankaimnt->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.crootfs_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从这里启动initrun_init_process(ramdisk_execute_command);printk(KERN_WARNING "Failed to execute %s\n", ramdisk_execute_command);}//initrd、nfs和磁盘都是从如下启动的initif (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挂载到/rootsys_chdir("/root"); //系统current->fs->pwd为当前目录/rootROOT_DEV = current->fs->pwd.mnt->mnt_sb->s_dev;return 0;
}

2.将当前目录/root设置为系统current根目录,磁盘文件系统设置为系统current根文件系统

分析sys_chroot("."):见Linux内核编程之C语言预处理功能与宏

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:4M@0x400000(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 80Try to bring eth0 interface up......eth0: link down
DonePlease press Enter to activate this console.
[root@FriendlyARM /]# 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)
[root@FriendlyARM /]# 

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/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 vfat
TK---->>>>init/main.c>>>kernel_init>>>>current->fs->pwd.mnt->mnt_sb->s_type->name is vfat
Goodbye, cruel world

由此证明;current->fs->root就是系统承认的根文件系统。

《Linux启动过程分析》内核挂载根文件系统相关推荐

  1. linux uboot nfs启动,嵌入式uboot,内核启动通过nfs挂载根文件系统

    概述 嵌入式移植学习第二个内容,通过nfs挂载根文件系统.也是自己第一次做,也遇到了一些问题,但最后还是都解决了.在此记录一下整个流程,也希望能够给别的初学者一个参考. 系统环境 PC端 linux ...

  2. linux启动过程文件系统崩溃,Linux启动过程简介(根文件系统加载过程)

    许多人对Linux的启动过程感到很神秘,因为所有的启动信息都在屏幕上一闪而过.其实, Linux的启动过程并不象启动信息所显示的那样复杂,它主要分成两个阶段: 1.启动内核.在这个阶段,内核装入内存并 ...

  3. 一文讲解Linux内核中根文件系统挂载流程

    根文件系统的概念 根文件系统是控制权从linux内核转移到用户空间的一个桥梁.linux内核就类似于一个黑匣子,只向用户提供各种功能的接口,但是功能的具体实现不可见,用户程序通过对这些功能接口的不同整 ...

  4. initramfs下启动linux_《Linux启动过程分析》之区别Initramfs与initrd

    https://blog.csdn.net/tankai19880619/article/details/16885615 之前<Linux启动过程分析>内核挂载根文件系统一文,分析的ro ...

  5. linux内核开文件系统,新手,Linux内核无法挂载根文件系统

    新手求助,Linux内核无法挂载根文件系统 一块开发板,厂商已经提供好了uboot,kernel,ramdisk文件系统跟安卓镜像 有:uboot.bin, zImage, ramdisk-uboot ...

  6. 【linux kernel】linux内核如何挂载根文件系统

    文章目录 一.前世今生 二.kernel_init线程入口 三.重磅角色-prepare_namespace 一.前世今生 在kernel_init线程函数中会调用kernel_init_freeab ...

  7. linux 0.11根文件系统,linux内核与根文件系统之间的关联的理解

    学者 于 2011-10-19 12:46:08发表: 哦,原来还有一个initrd镜像,后缀名为".img",我一直以为只有一个内核镜像呢: 还有引导程序的路径表示与系统不同啊! ...

  8. linux内核 删除文件_Linux内核与根文件系统的关系详解

    Linux内核与根文件系统的关系 开篇题外话:对于Linux初学者来说,这是一个很纠结的问题,但这也是一个很关键的问题! 一语破天机: "尽管内核是 Linux 的核心,但文件却是用户与操作 ...

  9. 嵌入式linux加载引导内核和根文件系统的方法

    总体来说,嵌入式Linux内核和根文件的引导与PC机差不多. 嵌入式linux内核和根文件系统可以存放在各种可能的存储设备中,一般情况下我 们将内核和根文件系统直接烧入到Flash中(包括NOR和NA ...

  10. 嵌入式烧写Linux内核,嵌入式linux 内核和根文件系统烧写方式简介

    总体来说,嵌入式Linux内核和根文件的引导与PC机差不多. 嵌入式linux内核和根文件系统可以存放在各种可能的存储设备中,一般情况下我们将内核和根文件系统直接烧入到Flash中(包括NOR和NAN ...

最新文章

  1. 机器学习5种特征选择的方法!
  2. Linux 下 zip unzip压缩与解压
  3. win8以上windows系统eclipse环境下图片显示乱码问题解决
  4. python3中的type与object
  5. 网络摄象机常用传输协议
  6. 有哪些你踏入社会才明白的道理
  7. Maven常用的构建命令
  8. vm15 安装 mac虚拟机的过程 转载的
  9. oracle 创建新库时报错:enterprise manager 配置失败
  10. 利用循环神经网络生成唐诗_PyTorch实现用于文本生成的循环神经网络
  11. java如何无感知部署_干货!如何平稳用户无感知的完成系统重构升级
  12. 值类型、引用类型 再次理解
  13. php十六进制转为ascii,16进制转换成ascii_16进制转ascii码转换工具_16进制转ascii
  14. 【Java】月份枚举
  15. 与Simon,Warren,Neo,Paul同学聊天体会
  16. android和asp交互,Android客户端用Json与Asp.Net服务器交互信息
  17. CSDN 上如何设置「关注博主」即可阅读全文
  18. 计算机键盘锁不了怎么办,电脑键盘被锁,打字打不出来怎么处理,
  19. 阿里妈妈站长全国群英会SEO演讲PPT下载
  20. XStar房屋最短路径

热门文章

  1. 2022蓝桥杯冲刺(历年真题剖析,含省赛、国赛)
  2. 蓝桥杯题目常用API (JAVA)
  3. COOLFluiD安装教程
  4. 手把手教你架构3D引擎高级篇系列四
  5. 概率机器人-贝叶斯滤波
  6. fortran调用MKL函数库中的gemm的fortran95接口计算矩阵相乘
  7. 电子设计竞赛经验介绍
  8. python 爬虫 糗百成人
  9. delphi 的GetTickCount计时用法缺陷及管制
  10. C/C++网络编程详解(Windows版)