實際根檔案系統的掛載-sys_mount()
實際根檔案系統的掛載是在prepare_namespace()中實現的。
init/do_mounts.c
void __init prepare_namespace(void)
{
...
mount_root();
out:
...
sys_mount(".", "/", NULL, MS_MOVE, NULL);
sys_chroot(".");
...
}
首先呼叫mount_root()將實際的根檔案系統掛載在rootfs檔案系統的"/root"目錄下,並將當前目錄切換
到實際根檔案系統的根目錄下;接著呼叫sys_mount(".", "/", NULL, MS_MOVE, NULL)將實際檔案系統
的掛載點移到(MS_MOVE)rootfs的"/"根目錄下。最後將實際檔案系統的根目錄作為初始程序的根目錄。
下面分析下掛載的流程,裡面涉及到的MTD、jffs2知識,只簡單提下,以後再具體分析。
void __init mount_root(void) { ... /*建立裝置檔案*/ create_dev("/dev/root", ROOT_DEV); mount_block_root("/dev/root", root_mountflags); } void __init mount_block_root(char *name, int flags) { 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 /*從命令列獲取"rootfstype=根檔案系統的型別,本例是jffs2*/ get_fs_names(fs_names); retry: for (p = fs_names; *p; p += strlen(p)+1) { /*掛載*/ 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; } ... out: putname(fs_names); } static int __init do_mount_root(char *name, char *fs, int flags, void *data) { /*將"/dev/root"裝置掛載到"/root"目錄下*/ int err = sys_mount(name, "/root", fs, flags, data); if (err) return err; /*將當前目錄切換到"/root"目錄下,因為"/root"掛載有實際的根檔案系統, * 所以當前目錄被切換到實際的根檔案系統的根目錄下 */ 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; } SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, char __user *, type, unsigned long, flags, void __user *, data) { int ret; char *kernel_type; char *kernel_dir; char *kernel_dev; unsigned long data_page; /*獲取根檔案系統型別*/ ret = copy_mount_string(type, &kernel_type); if (ret < 0) goto out_type; /*獲取掛載點路徑名*/ kernel_dir = getname(dir_name); if (IS_ERR(kernel_dir)) { ret = PTR_ERR(kernel_dir); goto out_dir; } /*獲取要掛載的裝置名*/ ret = copy_mount_string(dev_name, &kernel_dev); if (ret < 0) goto out_dev; /*獲取附件資料*/ ret = copy_mount_options(data, &data_page); if (ret < 0) goto out_data; /*執行掛載*/ ret = do_mount(kernel_dev, kernel_dir, kernel_type, flags, (void *) data_page); free_page(data_page); out_data: kfree(kernel_dev); out_dev: putname(kernel_dir); out_dir: kfree(kernel_type); out_type: return ret; } long do_mount(char *dev_name, char *dir_name, char *type_page, unsigned long flags, void *data_page) { struct path path; int retval = 0; int mnt_flags = 0; /* Discard magic */ if ((flags & MS_MGC_MSK) == MS_MGC_VAL) flags &= ~MS_MGC_MSK; /* Basic sanity checks */ if (!dir_name || !*dir_name || !memchr(dir_name, 0, PAGE_SIZE)) return -EINVAL; if (data_page) ((char *)data_page)[PAGE_SIZE - 1] = 0; /* Default to relatime unless overriden */ if (!(flags & MS_NOATIME)) mnt_flags |= MNT_RELATIME; /* Separate the per-mountpoint flags */ if (flags & MS_NOSUID) mnt_flags |= MNT_NOSUID; if (flags & MS_NODEV) mnt_flags |= MNT_NODEV; if (flags & MS_NOEXEC) mnt_flags |= MNT_NOEXEC; if (flags & MS_NOATIME) mnt_flags |= MNT_NOATIME; if (flags & MS_NODIRATIME) mnt_flags |= MNT_NODIRATIME; if (flags & MS_STRICTATIME) mnt_flags &= ~(MNT_RELATIME | MNT_NOATIME); if (flags & MS_RDONLY) mnt_flags |= MNT_READONLY; flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT | MS_STRICTATIME); /* ... and get the mountpoint */ /*獲取掛載點的資訊即mnt結構和dentry結構*/ retval = kern_path(dir_name, LOOKUP_FOLLOW, &path); if (retval) return retval; retval = security_sb_mount(dev_name, &path, type_page, flags, data_page); if (retval) goto dput_out; if (flags & MS_REMOUNT) retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags, data_page); else if (flags & MS_BIND) retval = do_loopback(&path, dev_name, flags & MS_REC); else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE)) retval = do_change_type(&path, flags); else if (flags & MS_MOVE) retval = do_move_mount(&path, dev_name); else /*執行掛載*/ retval = do_new_mount(&path, type_page, flags, mnt_flags, dev_name, data_page); dput_out: path_put(&path); return retval; } static int do_new_mount(struct path *path, char *type, int flags, int mnt_flags, char *name, void *data) { struct vfsmount *mnt; if (!type) return -EINVAL; /* we need capabilities... */ if (!capable(CAP_SYS_ADMIN)) return -EPERM; lock_kernel(); /*建立新檔案系統的vfsmnt,superblock,dentry,inode等結構*/ mnt = do_kern_mount(type, flags, name, data); unlock_kernel(); if (IS_ERR(mnt)) return PTR_ERR(mnt); /*將上述建立的結構,新增到"/root"目錄結構中,從而實現掛載*/ return do_add_mount(mnt, path, mnt_flags, NULL); } struct vfsmount * do_kern_mount(const char *fstype, int flags, const char *name, void *data) { /*根據檔案系統型別jffs2,查詢對應的file_system_type結構 *jffs2檔案系統之前在fs/jffs2/super.c中的init_jffs2_fs()函式 *完成註冊,所以此時可以找到。 */ struct file_system_type *type = get_fs_type(fstype); struct vfsmount *mnt; if (!type) return ERR_PTR(-ENODEV); mnt = vfs_kern_mount(type, flags, name, data); if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) && !mnt->mnt_sb->s_subtype) mnt = fs_set_subtype(mnt, fstype); put_filesystem(type); return mnt; }
這個函式之前介紹過,首先分配一個vfsmount結構,然後呼叫具體檔案系統的get_sb()函式。
get_sb()函式會建立super block,根目錄dentry,根索引節點inode等結構。
此處需要注意的是,之前的get_sb()函式,是ram型別的,不會去操作flash等儲存IC,而jffs2
的get_sb()函式,會從flash中讀取實際檔案系統的內容,用來初始化super block,根目錄
dentry,根索引節點inode等結構。所以掛載完成後,flash裡的相關內容(不是全部)就會在記憶體
中,這也是掛載的實質用意。
struct vfsmount * vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data) { struct vfsmount *mnt; char *secdata = NULL; int error; if (!type) return ERR_PTR(-ENODEV); error = -ENOMEM; mnt = alloc_vfsmnt(name); if (!mnt) goto out; printk(KERN_WARNING "get_sb0\n"); if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) { secdata = alloc_secdata(); if (!secdata) goto out_mnt; error = security_sb_copy_data(data, secdata); if (error) goto out_free_secdata; } printk(KERN_WARNING "get_sb1\n"); error = type->get_sb(type, flags, name, data, mnt); printk(KERN_WARNING "get_sb2\n"); if (error < 0) goto out_free_secdata; BUG_ON(!mnt->mnt_sb); error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata); if (error) goto out_sb; /* * filesystems should never set s_maxbytes larger than MAX_LFS_FILESIZE * but s_maxbytes was an unsigned long long for many releases. Throw * this warning for a little while to try and catch filesystems that * violate this rule. This warning should be either removed or * converted to a BUG() in 2.6.34. */ WARN((mnt->mnt_sb->s_maxbytes < 0), "%s set sb->s_maxbytes to " "negative value (%lld)\n", type->name, mnt->mnt_sb->s_maxbytes); mnt->mnt_mountpoint = mnt->mnt_root; mnt->mnt_parent = mnt; up_write(&mnt->mnt_sb->s_umount); free_secdata(secdata); return mnt; out_sb: dput(mnt->mnt_root); deactivate_locked_super(mnt->mnt_sb); out_free_secdata: free_secdata(secdata); out_mnt: free_vfsmnt(mnt); out: return ERR_PTR(error); }
具體的get_sb()函式涉及jffs2的知識,先省略。
程式執行到此處,可以認為代表實際根檔案系統的vfsmount,super block,根目錄dentry,根索引節點inode
等結構都已初始化完畢。現在要做的就是將這些結構關聯到掛載點上。關聯過程是由do_add_mount()函式實現。
int do_add_mount(struct vfsmount *newmnt, struct path *path,
int mnt_flags, struct list_head *fslist)
{
int err;
down_write(&namespace_sem);
/* Something was mounted here while we slept */
/*判斷掛載點出是否已經掛載有其他的檔案系統,是則,覆蓋之。此處當然沒有*/
while (d_mountpoint(path->dentry) &&
follow_down(path))
;
err = -EINVAL;
if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt))
goto unlock;
/* Refuse the same filesystem on the same mount point */
err = -EBUSY;
if (path->mnt->mnt_sb == newmnt->mnt_sb &&
path->mnt->mnt_root == path->dentry)
goto unlock;
err = -EINVAL;
if (S_ISLNK(newmnt->mnt_root->d_inode->i_mode))
goto unlock;
newmnt->mnt_flags = mnt_flags;
if ((err = graft_tree(newmnt, path)))
goto unlock;
if (fslist) /* add to the specified expiration list */
list_add_tail(&newmnt->mnt_expire, fslist);
up_write(&namespace_sem);
return 0;
unlock:
up_write(&namespace_sem);
mntput(newmnt);
return err;
}
實際操作由graft_tree()中attach_recursive_mnt()的完成
static int graft_tree(struct vfsmount *mnt, struct path *path)
{
int err;
if (mnt->mnt_sb->s_flags & MS_NOUSER)
return -EINVAL;
if (S_ISDIR(path->dentry->d_inode->i_mode) !=
S_ISDIR(mnt->mnt_root->d_inode->i_mode))
return -ENOTDIR;
err = -ENOENT;
mutex_lock(&path->dentry->d_inode->i_mutex);
if (IS_DEADDIR(path->dentry->d_inode))
goto out_unlock;
err = security_sb_check_sb(mnt, path);
if (err)
goto out_unlock;
err = -ENOENT;
if (!d_unlinked(path->dentry))
err = attach_recursive_mnt(mnt, path, NULL);
out_unlock:
mutex_unlock(&path->dentry->d_inode->i_mutex);
if (!err)
security_sb_post_addmount(mnt, path);
return err;
}
static int attach_recursive_mnt(struct vfsmount *source_mnt,
struct path *path, struct path *parent_path)
{
LIST_HEAD(tree_list);
struct vfsmount *dest_mnt = path->mnt;
struct dentry *dest_dentry = path->dentry;
struct vfsmount *child, *p;
int err;
if (IS_MNT_SHARED(dest_mnt)) {
err = invent_group_ids(source_mnt, true);
if (err)
goto out;
}
/*此例中propagation_next為NULL,所以下面的函式時空函式。
*該函式不知道做什麼作用,先不管了
*/
err = propagate_mnt(dest_mnt, dest_dentry, source_mnt, &tree_list);
if (err)
goto out_cleanup_ids;
if (IS_MNT_SHARED(dest_mnt)) {
for (p = source_mnt; p; p = next_mnt(p, source_mnt))
set_mnt_shared(p);
}
spin_lock(&vfsmount_lock);
/*parent_path為NULL*/
if (parent_path) {
detach_mnt(source_mnt, parent_path);
attach_mnt(source_mnt, path);
touch_mnt_namespace(parent_path->mnt->mnt_ns);
} else {
mnt_set_mountpoint(dest_mnt, dest_dentry, source_mnt);
commit_tree(source_mnt);
}
/*tree_list為NULL*/
list_for_each_entry_safe(child, p, &tree_list, mnt_hash) {
list_del_init(&child->mnt_hash);
commit_tree(child);
}
spin_unlock(&vfsmount_lock);
return 0;
out_cleanup_ids:
if (IS_MNT_SHARED(dest_mnt))
cleanup_group_ids(source_mnt, NULL);
out:
return err;
}
就剩下mnt_set_mountpoint(dest_mnt, dest_dentry, source_mnt);和commit_tree(source_mnt);
void mnt_set_mountpoint(struct vfsmount *mnt, struct dentry *dentry,
struct vfsmount *child_mnt)
{
/*此處就是建立新檔案系統和掛載點之間關聯的地方
*主要設定mnt_parent、mnt_mountpoint以及dentry->d_mounted
*dentry->d_mounted就表示dentry目錄是否掛載有檔案系統
*/
child_mnt->mnt_parent = mntget(mnt);
/**/
child_mnt->mnt_mountpoint = dget(dentry);
dentry->d_mounted++;
}
static void commit_tree(struct vfsmount *mnt)
{
struct vfsmount *parent = mnt->mnt_parent;
struct vfsmount *m;
LIST_HEAD(head);
struct mnt_namespace *n = parent->mnt_ns;
BUG_ON(parent == mnt);
list_add_tail(&head, &mnt->mnt_list);
list_for_each_entry(m, &head, mnt_list)
{
/*設定新檔案系統的名稱空間*/
m->mnt_ns = n;
}
/*合併連結串列*/
list_splice(&head, n->list.prev);
/*將mnt->mnt_hash新增到mount_hashtable雜湊表中*/
list_add_tail(&mnt->mnt_hash, mount_hashtable +
hash(parent, mnt->mnt_mountpoint));
/*將mnt_child新增到mnt_mounts*/
list_add_tail(&mnt->mnt_child, &parent->mnt_mounts);
touch_mnt_namespace(n);
}
掛載後的主要資料結構圖如下:
另外,掛載後,會呼叫sys_mount(".", "/", NULL, MS_MOVE, NULL)函式,將掛載點移到(MS_MOVE)"/"目錄下.
因為設定了MS_MOVE,所以sys_mount()會呼叫do_move_mount()函式。do_move_mount()仍會呼叫attach_recursive_mnt();
只不過引數parent_path不再會NULL,所以會執行以下語句
if (parent_path) {
detach_mnt(source_mnt, parent_path);
attach_mnt(source_mnt, path);
touch_mnt_namespace(parent_path->mnt->mnt_ns);
}
static void detach_mnt(struct vfsmount *mnt, struct path *old_path)
{
/*儲存原始掛載點"/root"的資訊*/
old_path->dentry = mnt->mnt_mountpoint;
old_path->mnt = mnt->mnt_parent;
/*重新初始化新檔案系統的掛載資訊*/
mnt->mnt_parent = mnt;
mnt->mnt_mountpoint = mnt->mnt_root;
list_del_init(&mnt->mnt_child);
list_del_init(&mnt->mnt_hash);
/*原始掛載點的d_mounted減一,表示去掉了一個檔案系統*/
old_path->dentry->d_mounted--;
}
static void attach_mnt(struct vfsmount *mnt, struct path *path)
{
/*設定新的掛載點"/",上面分析過*/
mnt_set_mountpoint(path->mnt, path->dentry, mnt);
/*將mnt->mnt_hash新增到mount_hashtable雜湊表中*/
list_add_tail(&mnt->mnt_hash, mount_hashtable +
hash(path->mnt, path->dentry));
/*將mnt_child新增到mnt_mounts*/
list_add_tail(&mnt->mnt_child, &path->mnt->mnt_mounts);
}
還有一點,因為先後執行了sys_chdir("/root")和sys_chroot("."),所以當前目錄和根目錄都變成了實際檔案系統的根目錄。
相關推薦
實際根檔案系統的掛載-sys_mount()
實際根檔案系統的掛載是在prepare_namespace()中實現的。 init/do_mounts.c void __init prepare_namespace(void) { ... mount_root(); out: ... sys_mount(".",
根檔案系統掛載過程—基於linux3.10
本文基於linux3.10某一嵌入式系統,該檔案系統的配置選項設定如下: 圖1.1 根檔案系統配置選項設定 兩行配置如下: [*] Initial RAMfilesystem and RAM disk (initramfs/initrd) suppor
openwrt 將根檔案系統掛載在U盤上
u盤掛載完成(及 mount /dev/sda /mnt )後, #mkdir /tmp/cproot #mount --bind //tmp/cproot #tar -C /tmp/cproot-cvf - . | tar -C /mnt -xvf - #sync #sy
掛載根檔案系統的實操
宿主機的NFS配置,不詳細描述; 1. 檔案系統的許可權 ,進入根目錄 #chmod -R 777 * #chown -R nobody 2. 防火牆關閉 # service iptables stop 3.
Linux根檔案系統製作與各種掛載方式的實現
Linux根檔案系統的製作 什麼是檔案系統 計算機的檔案系統是一種儲存和組織計算機資料的方法,它使得對其訪問和查詢變得容易,檔案系統使用檔案和樹形目錄的抽象邏輯概念代替了硬碟和光碟等物理裝置使用資料塊的概念,使用者使用檔案系統來儲存資料不必關心資料實際儲存在硬碟(或者光碟)的地址為多少的資料
QEMU模擬Mini2440開發板執行環境(二):NFS掛載根檔案系統
前言 原創文章歡迎轉載,請保留出處。 若有任何疑問建議,歡迎回復。 郵箱:[email protected] 緊接著第一篇(http://blog.csdn.net/maxwell_nc/article/details/44279553),我們使用網路檔案系統NFS掛載根檔案
wlh- beagle bone 通過uboot tftp 載入zImage 裝置樹 及 nfs 掛載根檔案系統
首先重啟Ubuntu 伺服器的 tftp 和nfs sudo /etc/init.d/xinetd restart 命令 重啟 xinetd tftp服務 sudo&nbs
nfs掛載根檔案系統
1.安裝NFS nfs原理是通過網路,將遠端主機共享的檔案系統,掛載到本機。Ubuntu 12.04上預設是沒有安裝NFS伺服器的,首先要安裝NFS服務程式: 先執行 # apt-get update
NFS作為根檔案系統,掛載超時
NFS伺服器配置正確後,使用ramfs,通過mount能夠正常掛載NFS,但是作為ROOTFS無法正常掛載,顯示超時。 經檢視log,RPC報錯-120。 分析結果: 在Ubuntu1804上,nfsserver支援v3,v4,在UBuntu1304上,nfsserver
深度解析Linux根檔案系統的掛載過程
在前面的文章中介紹《Linux作業系統啟動過程》,而Linux系統的根檔案系統(root file system)的掛載過程則是其中一個重要環節,下面這部分內容來自於網路,經整理分享如下,希望能給這部份知識點比較迷茫的朋友一點幫助。 一、rootfs的種類 總的來說,rootfs分為兩種:虛擬roo
《Linux啟動過程分析》核心掛載根檔案系統
說明:本文基於Linux2.6.29核心分析;其他核心版本僅供參考。 前邊通過原始碼情景分析,看過了匯流排、裝置、驅動及其發現機制,Linux2.6核心udev裝置節點建立相關;對於檔案系統,一直望而生畏,但核心學習、這部分又不可能繞的過去。目前對VFS中使用的has
從NFS啟動Linux並掛載根檔案系統
要搞嵌入式NFS確實必不可少,否則每次都要重啟煩都煩死。這裡總結在NFS建立過程中遇到的幾個問題。 下面記錄幾個遇到的問題 VFS: Cannot open root device “
u-boot下配置掛載NFS根檔案系統
一、在linux系統主機下安裝NFS伺服器 在ubuntu10.04下安裝命令為: sudoapt-get install nfs-kernel-server 二、配置nfs伺服器 在ubuntu下安裝完ssh伺服器後預設開機啟動
Linux--根檔案系統的掛載過程分析
【轉自 http://blog.csdn.net/guopeixin/article/details/5962482】 前言: 本篇文章以S3C6410公版的Linux BSP和U-Boot來進行分析,文中所有提及的名詞和資料都是以該環境為例,所有的程式碼流程
利用NFS服務掛載NFS根檔案系統
嵌入式Linux根檔案系統,簡單地說,根檔案系統就是一種目錄結構 注意根檔案系統和普通的檔案系統的區別。 常見的Linux根檔案系統有: (1)NFS(網路根檔案系統),主要用於 產品除錯階段 。 (2)YAFFS,主要用於產品的釋出階段。大量生產直接寫入NandFl
mini6410基於linux2.6.36核心通過NFS啟動根檔案系統總結(四製作根檔案系統及通過NFS掛載檔案系統)
本系列文章有本人yinjiabin製作,轉載請註明出處: http://blog.csdn.net/yinjiabin/article/details/7489563根檔案系統一般包括: 1)基本的檔案系統結構,包含一些必須的目錄,比如:/dev,/proc,/bin,/
基於busybox製作mini2440根檔案系統及使用nfs掛載
常見的檔案系統有yaffs2, jffs2,他們是適用於根檔案系統映象存在於NAND Flash上的情況。而傳統的Linux EXT2/EXT3檔案系統格式適用於傳統的block裝置,比如SD卡或者硬碟。 cramfs同時適用於以上兩種情況。其不管採用哪種格式,核心都必
Beaglebone Black——理論篇beaglebone black啟動——從串列埠獲得SPL、U-BOOT,TFTP伺服器獲得核心,NFS伺服器掛載根檔案系統
一般來講啟動一個系統所需的bootloader(SPL/MLO、u-boot.img)和根檔案系統(/boot下包含核心zImage)要麼是放在NAND Flash,或者是SD卡,或者是eMMC,或者是USB中,那麼還有一種方式,就是所需要的這些檔案全部
u-boot通過nfs從伺服器下載核心,並且啟動核心,掛載根檔案系統的方法
http://www.linuxidc.com/Linux/2013-08/89154.htm http://blog.csdn.net/sinat_31500569/article/details/53120530 參考連結 首先要在電腦上安裝nfs伺服器 1.執行命令
linux開發環境搭建(3)-nfs掛載根檔案系統
前面講解了網絡卡配置和使用tftp下載核心,這次要講的是使用nfs掛載根檔案系統。 1、什麼是根檔案系統 所謂根檔案系統,也就是系統啟動後第一個掛載的目錄,根檔案系統包括Linux啟動時所必須的目錄和關鍵性的檔案,例如Linux啟動時都需要有init目錄下的