linux安裝文件系統(tǒng)
linux安裝文件系統(tǒng)
Linux文件系統(tǒng)中的文件是數(shù)據(jù)的集合,文件系統(tǒng)不僅包含著文件中的數(shù)據(jù)而且還有文件系統(tǒng)的結(jié)構(gòu),所有Linux 用戶和程序看到的文件、目錄、軟連接及文件保護(hù)信息等都存儲(chǔ)在其中。下面大家與學(xué)習(xí)啦小編一起來學(xué)習(xí)一下吧。
安裝linux文件系統(tǒng)
安裝根文件系統(tǒng)式系統(tǒng)初始化的關(guān)鍵部分。Linux內(nèi)核允許根文件系統(tǒng)放在很多不同的地方,比如硬盤分區(qū)、軟盤、通過NFS共享的遠(yuǎn)程文件系統(tǒng)以及保存在ramdisk中。內(nèi)核要在變量ROOT_DEV中尋找包含根文件系統(tǒng)的磁盤主設(shè)備號(hào)。當(dāng)編譯內(nèi)核時(shí),或者像最初的啟動(dòng)裝入程序傳遞一個(gè)合適的“root”選項(xiàng)時(shí),根文件系統(tǒng)可以被指定為/dev目錄下的一個(gè)設(shè)備文件。
安裝根文件系統(tǒng)分為兩個(gè)階段:
1,內(nèi)核安裝特殊rootfs文件系統(tǒng),該文件系統(tǒng)僅提供一個(gè)作為初始安裝點(diǎn)的空目錄
start_kernel()->vfs_caches_init()->mnt_init()->init_rootfs()
[cpp] view plain copy print?
/*初始化根文件系統(tǒng)*/
int __init init_rootfs(void)
{
int err;
/*初始化ramfs_backing_dev_info*/
err = bdi_init(&ramfs_backing_dev_info);
if (err)
return err;
/*注冊(cè)rootfs_fs_type文件類型*/
err = register_filesystem(&rootfs_fs_type);
if (err)/*如果出錯(cuò),銷毀上面初始化的*/
bdi_destroy(&ramfs_backing_dev_info);
return err;
}
[cpp] view plain copy print?
static struct backing_dev_info ramfs_backing_dev_info = {
.name = "ramfs",
.ra_pages = 0, /* No readahead */
.capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK |
BDI_CAP_MAP_DIRECT | BDI_CAP_MAP_COPY |
BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP,
};
[cpp] view plain copy print?
/**
* register_filesystem - register a new filesystem
* @fs: the file system structure
*
* Adds the file system passed to the list of file systems the kernel
* is aware of for mount and other syscalls. Returns 0 on success,
* or a negative errno code on an error.
*
* The &struct file_system_type that is passed is linked into the kernel
* structures and must not be freed until the file system has been
* unregistered.
*/
/*注冊(cè)一個(gè)新的文件系統(tǒng)*/
int register_filesystem(struct file_system_type * fs)
{
int res = 0;
struct file_system_type ** p;
BUG_ON(strchr(fs->name, '.'));
if (fs->next)
return -EBUSY;
INIT_LIST_HEAD(&fs->fs_supers);
write_lock(&file_systems_lock);
/*從system_type鏈表中查找指定名稱的file_system_type*/
p = find_filesystem(fs->name, strlen(fs->name));
if (*p)
res = -EBUSY;
else
*p = fs;
write_unlock(&file_systems_lock);
return res;
}
根文件系統(tǒng)定義如下
[cpp] view plain copy print?
static struct file_system_type rootfs_fs_type = {
.name = "rootfs",
.get_sb = rootfs_get_sb,
.kill_sb = kill_litter_super,
};
下面看看他的兩個(gè)函數(shù)
[cpp] view plain copy print?
/*獲得根目錄的sb*/
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);
}
[cpp] view plain copy print?
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)
{
int error;
/*獲得sb結(jié)構(gòu)*/
struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL);
if (IS_ERR(s))
return PTR_ERR(s);
s->s_flags = flags;
/*這里實(shí)際調(diào)用ramfs_fill_super,對(duì)sb結(jié)構(gòu)的屬性進(jìn)行設(shè)置*/
error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);
if (error) {
deactivate_locked_super(s);
return error;
}
s->s_flags |= MS_ACTIVE;
simple_set_mnt(mnt, s);/*設(shè)置mnt和sb關(guān)聯(lián)*/
return 0;
}
[cpp] view plain copy print?
/**
* sget - find or create a superblock
* @type: filesystem type superblock should belong to
* @test: comparison callback
* @set: setup callback
* @data: argument to each of them
*/
/*查找或創(chuàng)建一個(gè)sb結(jié)構(gòu)*/
struct super_block *sget(struct file_system_type *type,
int (*test)(struct super_block *,void *),
int (*set)(struct super_block *,void *),
void *data)
{
struct super_block *s = NULL;
struct super_block *old;
int err;
retry:
spin_lock(&sb_lock);
if (test) {
list_for_each_entry(old, &type->fs_supers, s_instances) {
if (!test(old, data))
continue;
if (!grab_super(old))
goto retry;
if (s) {
up_write(&s->s_umount);
destroy_super(s);
}
return old;
}
}
if (!s) {/*如果找不到sb,從內(nèi)存中申請(qǐng)一個(gè)*/
spin_unlock(&sb_lock);
s = alloc_super(type);
if (!s)
return ERR_PTR(-ENOMEM);
goto retry;
}
err = set(s, data);
if (err) {
spin_unlock(&sb_lock);
up_write(&s->s_umount);
destroy_super(s);
return ERR_PTR(err);
}
/*初始化得到的sb結(jié)構(gòu)*/
s->s_type = type;
strlcpy(s->s_id, type->name, sizeof(s->s_id));
/*加入鏈表尾*/
list_add_tail(&s->s_list, &super_blocks);
list_add(&s->s_instances, &type->fs_supers);
spin_unlock(&sb_lock);
get_filesystem(type);
return s;
}
[cpp] view plain copy print?
/*所有超級(jí)塊對(duì)象都以雙向循環(huán)鏈表的形式鏈接在一起,量表中第一個(gè)
元素用super_blocks變量表示,而超級(jí)塊對(duì)象的s_list字段存放指向鏈表
相鄰元素的指針*/
LIST_HEAD(super_blocks);
[cpp] view plain copy print?
/**
* alloc_super - create new superblock
* @type: filesystem type superblock should belong to
*
* Allocates and initializes a new &struct super_block. alloc_super()
* returns a pointer new superblock or %NULL if allocation had failed.
*/
static struct super_block *alloc_super(struct file_system_type *type)
{
/*從內(nèi)存中申請(qǐng)sb*/
struct super_block *s = kzalloc(sizeof(struct super_block), GFP_USER);
static const struct super_operations default_op;
if (s) {
if (security_sb_alloc(s)) {
kfree(s);
s = NULL;
goto out;
}
/*初始化*/
INIT_LIST_HEAD(&s->s_files);
INIT_LIST_HEAD(&s->s_instances);
INIT_HLIST_HEAD(&s->s_anon);
INIT_LIST_HEAD(&s->s_inodes);
INIT_LIST_HEAD(&s->s_dentry_lru);
init_rwsem(&s->s_umount);
mutex_init(&s->s_lock);
lockdep_set_class(&s->s_umount, &type->s_umount_key);
/*
* The locking rules for s_lock are up to the
* filesystem. For example ext3fs has different
* lock ordering than usbfs:
*/
lockdep_set_class(&s->s_lock, &type->s_lock_key);
/*
* sget() can have s_umount recursion.
*
* When it cannot find a suitable sb, it allocates a new
* one (this one), and tries again to find a suitable old
* one.
*
* In case that succeeds, it will acquire the s_umount
* lock of the old one. Since these are clearly distrinct
* locks, and this object isn't exposed yet, there's no
* risk of deadlocks.
*
* Annotate this by putting this lock in a different
* subclass.
*/
down_write_nested(&s->s_umount, SINGLE_DEPTH_NESTING);
s->s_count = S_BIAS;
atomic_set(&s->s_active, 1);
mutex_init(&s->s_vfs_rename_mutex);
mutex_init(&s->s_dquot.dqio_mutex);
mutex_init(&s->s_dquot.dqonoff_mutex);
init_rwsem(&s->s_dquot.dqptr_sem);
init_waitqueue_head(&s->s_wait_unfrozen);
s->s_maxbytes = MAX_NON_LFS;
s->dq_op = sb_dquot_ops;
s->s_qcop = sb_quotactl_ops;
s->s_op = &default_op;
s->s_time_gran = 1000000000;
}
out:
return s;
}
kill_litter_super的過程相反,這里不再寫了。
構(gòu)造根目錄是由init_mount_tree()函數(shù)實(shí)現(xiàn)的,該函數(shù)在前面已經(jīng)介紹過了。
2,安裝實(shí)際根文件系統(tǒng)
關(guān)于__setup宏
__setup宏來注冊(cè)關(guān)鍵字及相關(guān)聯(lián)的處理函數(shù),__setup宏在include/linux/init.h中定義,其原型如下:
__setup(string, _handler);
其中:string是關(guān)鍵字,_handler是關(guān)聯(lián)處理函數(shù)。__setup只是告訴內(nèi)核在啟動(dòng)時(shí)輸入串中含有string時(shí),內(nèi)核要去
執(zhí)行_handler。String必須以“=”符結(jié)束以使parse_args更方便解析。緊隨“=”后的任何文本都會(huì)作為輸入傳給
_handler。下面的例子來自于init/do_mounts.c,其中root_dev_setup作為處理程序被注冊(cè)給“root=”關(guān)鍵字:
__setup("root=", root_dev_setup);
比如我們?cè)趩?dòng)向參數(shù)終有
noinitrd root=/dev/mtdblock2 console=/linuxrc
setup_arch解釋時(shí)會(huì)發(fā)現(xiàn)root=/dev/mtdblock2,然后它就會(huì)調(diào)用root_dev_setup
[cpp] view plain copy print?
static int __init root_dev_setup(char *line)
{
strlcpy(saved_root_name, line, sizeof(saved_root_name));
return 1;
}
__setup("root=", root_dev_setup);
Start_kernel->rest_init->init-> prepare_namespace->
[cpp] view plain copy print?
/*
* Prepare the namespace - decide what/where to mount, load ramdisks, etc.
*/
void __init prepare_namespace(void)
{
int is_floppy;
if (root_delay) {
printk(KERN_INFO "Waiting %dsec before mounting root device...\n",
root_delay);
ssleep(root_delay);
}
/*
* wait for the known devices to complete their probing
*
* Note: this is a potential source of long boot delays.
* For example, it is not atypical to wait 5 seconds here
* for the touchpad of a laptop to initialize.
*/
wait_for_device_probe();
/*創(chuàng)建/dev/ram0,必須得,因?yàn)閕nitrd要放到/dev/ram0里*/
md_run_setup();
if (saved_root_name[0]) {/*saved_root_name為從啟動(dòng)參數(shù)"root"中獲取的設(shè)備文件名*/
root_device_name = saved_root_name;
if (!strncmp(root_device_name, "mtd", 3) ||
!strncmp(root_device_name, "ubi", 3)) {/*如果設(shè)備名開頭為這兩個(gè)*/
mount_block_root(root_device_name, root_mountflags);
goto out;
}
/*主設(shè)備號(hào)和次設(shè)備號(hào)*/
ROOT_DEV = name_to_dev_t(root_device_name);
if (strncmp(root_device_name, "/dev/", 5) == 0)
root_device_name += 5;/*濾掉'/dev/'字符*/
}
if (initrd_load())
goto out;
/* wait for any asynchronous scanning to complete */
if ((ROOT_DEV == 0) && root_wait) {
printk(KERN_INFO "Waiting for root device %s...\n",
saved_root_name);
while (driver_probe_done() != 0 ||
(ROOT_DEV = name_to_dev_t(saved_root_name)) == 0)
msleep(100);
async_synchronize_full();
}
is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;
if (is_floppy && rd_doload && rd_load_disk(0))
ROOT_DEV = Root_RAM0;
/*實(shí)際操作*/
mount_root();
out:
devtmpfs_mount("dev");/*devfs從虛擬的根文件系統(tǒng)的/dev umount*/
sys_mount(".", "/", NULL, MS_MOVE, NULL);/*將掛載點(diǎn)從當(dāng)前目錄【/root】(在mount_root函數(shù)中設(shè)置的)移到根目錄*/
/*當(dāng)前目錄即【/root】(真正文件系統(tǒng)掛載的目錄)做為系統(tǒng)根目錄*/
sys_chroot(".");
}
mount_root操作
[cpp] view plain copy print?
void __init mount_root(void)
{
#ifdef CONFIG_ROOT_NFS
if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) {
if (mount_nfs_root())
return;
printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n");
ROOT_DEV = Root_FD0;
}
#endif
#ifdef CONFIG_BLK_DEV_FD
if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {
/* rd_doload is 2 for a dual initrd/ramload setup */
if (rd_doload==2) {
if (rd_load_disk(1)) {
ROOT_DEV = Root_RAM1;
root_device_name = NULL;
}
} else
change_floppy("root floppy");
}
#endif
#ifdef CONFIG_BLOCK/*這里是一般流程*/
create_dev("/dev/root", ROOT_DEV);/*用系統(tǒng)調(diào)用創(chuàng)建"/dev/root"*/
mount_block_root("/dev/root", root_mountflags);
#endif
}
[cpp] view plain copy print?
void __init mount_block_root(char *name, int flags)
{
/*從cache中分配空間*/
char *fs_names = __getname_gfp(GFP_KERNEL
| __GFP_NOTRACK_FALSE_POSITIVE);
char *p;
#ifdef CONFIG_BLOCK
char b[BDEVNAME_SIZE];
#else
const char *b = name;
#endif
/*獲得文件系統(tǒng)類型,如果在bootoption里有,
則就為這個(gè)文件系統(tǒng)類型,如果沒有指定,
則返回ilesytem鏈上所有類型,下面再對(duì)每個(gè)進(jìn)行嘗試.*/
get_fs_names(fs_names);
retry:
for (p = fs_names; *p; p += strlen(p)+1) {
/*實(shí)際的安裝工作,這里調(diào)用了mount系統(tǒng)調(diào)用
將文件系統(tǒng)掛到/root目錄,p為文件系統(tǒng)類型,由get_fs_names得到
*/
int err = do_mount_root(name, p, flags, root_mount_data);
switch (err) {
case 0:
goto out;
case -EACCES:
flags |= MS_RDONLY;
goto retry;
case -EINVAL:
continue;
}
/*
* Allow the user to distinguish between failed sys_open
* and bad superblock on root device.
* and give them a list of the available devices
*/
#ifdef CONFIG_BLOCK
__bdevname(ROOT_DEV, b);
#endif
printk("VFS: Cannot open root device \"%s\" or %s\n",
root_device_name, b);
printk("Please append a correct \"root=\" boot option; here are the available partitions:\n");
printk_all_partitions();
#ifdef CONFIG_DEBUG_BLOCK_EXT_DEVT
printk("DEBUG_BLOCK_EXT_DEVT is enabled, you need to specify "
"explicit textual name for \"root=\" boot option.\n");
#endif
panic("VFS: Unable to mount root fs on %s", b);
}
printk("List of all partitions:\n");
printk_all_partitions();
printk("No filesystem could mount root, tried: ");
for (p = fs_names; *p; p += strlen(p)+1)
printk(" %s", p);
printk("\n");
#ifdef CONFIG_BLOCK
__bdevname(ROOT_DEV, b);
#endif
panic("VFS: Unable to mount root fs on %s", b);
out:
putname(fs_names);
}
[cpp] view plain copy print?
static int __init do_mount_root(char *name, char *fs, int flags, void *data)
{
/*mount系統(tǒng)調(diào)用來做實(shí)際的安裝文件系統(tǒng)工作*/
int err = sys_mount(name, "/root", fs, flags, data);
if (err)
return err;
/*改變當(dāng)前路徑到根目錄*/
sys_chdir("/root");
ROOT_DEV = current->fs->pwd.mnt->mnt_sb->s_dev;
printk("VFS: Mounted root (%s filesystem)%s on device %u:%u.\n",
current->fs->pwd.mnt->mnt_sb->s_type->name,
current->fs->pwd.mnt->mnt_sb->s_flags & MS_RDONLY ?
" readonly" : "", MAJOR(ROOT_DEV), MINOR(ROOT_DEV));
return 0;
}
到此,根文件系統(tǒng)的安裝過程算是完成了,中間關(guān)于mount等系統(tǒng)調(diào)用將在后面分析。可以看出總的步驟主要有:
1,創(chuàng)建一個(gè)rootfs,這個(gè)是虛擬的rootfs,是內(nèi)存文件系統(tǒng)(和ramfs),后面還會(huì)指向具體的根文件系統(tǒng);
2,從系統(tǒng)啟動(dòng)參數(shù)中獲取設(shè)備文件名以及設(shè)備號(hào);
3,調(diào)用系統(tǒng)調(diào)用創(chuàng)建符號(hào)鏈接,并調(diào)用mount系統(tǒng)調(diào)用進(jìn)程實(shí)際的安裝操作;
4,改變進(jìn)程當(dāng)前目錄;
5,移動(dòng)rootfs文件系統(tǒng)根目錄上得已經(jīng)安裝文件系統(tǒng)的安裝點(diǎn);
rootfs特殊文件系統(tǒng)沒有被卸載,他只是隱藏在基于磁盤的根文件系統(tǒng)下了。