mount系統調用初探

1.mount系統調用

  • 但是註冊一個文件系統後不代表這個文件系統就被馬上使用了,就像你註冊了一個賬號但是不代表你登錄了一樣,對於文件系統來說這個登錄就相當於“掛載(mount)”。

  • 一個文件系統的file_system_type裏有兩個主要成員,一個是文件系統的名字,一個是mount這個文件系統的方法(其它參數也很重要,但重點就是這兩個)。
    (1)名字就是一個id,唯一標記一個文件系統,並方便內核在需要時根據它找到這個文件系統的file_system_type。
    (2)mount方法在掛載這個文件系統時使用的,在需要掛載一個文件系統時通過name找到這個文件系統的file_system_type實例,然後使用這個實例中掛載的方法(mount函數),進行掛載。

  • (1)mount系統調用:從一個命令的角度來看mount操作
    一般我們類似這樣掛載一個文件系統:

# mount -t xfs /dev/sdb1 /mnt -o ...
-t指定/dev/sdb1上的文件系統類型,如果不使用-t則mount命令也可以嘗試探測device上的文件系統類型。

-o用來指定一些額外的(非默認的)掛載選項。

上面這個命令翻譯成人話就是:請把/dev/sdb1上的XFS文件系統掛載到/mnt上,並在掛載時使能-o裏的特性。
  • (2)mount系統調用:mount系統調用
    mount命令的最終執行還得是陷入內核後執行的系統調用,來看一下mount系統調用的定義(man 2 mount):
NAME
       mount - mount filesystem

SYNOPSIS
       #include <sys/mount.h>

       int mount(const char *source, const char *target,
                 const char *filesystemtype, unsigned long mountflags,
                 const void *data);


和上面的命令行對應一下,source對應/dev/sdb1,target對應/mnt,filesystemtype對應-t xfs
  • mount系統調用具體過程
    用mount系統調用的前三個參數,不帶任何掛載選項就掛載了文件系統
1)首先,我們在一個存儲設備上創建一個文件系統
# mkfs.xfs -f /dev/sdb12)然後我們準備一個掛載點
# mkdir /mnt/scratch3)最後我們使用mount系統調用來掛載上面的文件系統和掛載點
# cat mymount.c
#include <sys/mount.h>  
#include <stdio.h>  
  
int main(int argc, char *argv[]) {  
        if (mount("/dev/sdb1", "/mnt/scratch", "xfs", 0, NULL)) {  
                perror("mount failed");  
        }
        return 0;  
}

# gcc -Wall -o mymount mymount.c
# ./mymount 
# cat /proc/mounts |grep sdb1
/dev/sdb1 /mnt/scratch xfs rw,seclabel,relatime,attr2,inode64,noquota 0 0

2.mount的flags和data

  • 實際上flags + data對應mount命令的所有-o選項。那怎麼區分哪些屬於flags哪些屬於data呢?
  • 由於每個文件系統特有的選項都各有不同,具體有哪些可以參考(man 8 mount),以及每個文件系統各自的man page
  • 在此我們先說一下通用的flags,在內核中有對flags的宏定義,如下(來自Linux 4.17-rc2 include/uapi/linux/fs.h,我用註釋大致解釋了一下每一個flag對應哪個mount命令裏的參數):
/* 
 * These are the fs-independent mount-flags: up to 32 flags are supported 
 */  
#define MS_RDONLY        1         /* 對應-o ro/rw */  
#define MS_NOSUID        2         /* 對應-o suid/nosuid */  
#define MS_NODEV         4         /* 對應-o dev/nodev */  
#define MS_NOEXEC        8         /* 對應-o exec/noexec */  
#define MS_SYNCHRONOUS  16         /* 對應-o sync/async */  
#define MS_REMOUNT      32         /* 對應-o remount,告訴mount這是一次remount操作 */  
#define MS_MANDLOCK     64         /* 對應-o mand/nomand */  
#define MS_DIRSYNC      128        /* 對應-o dirsync */  
#define MS_NOATIME      1024       /* 對應-o atime/noatime */  
#define MS_NODIRATIME   2048       /* 對應-o diratime/nodiratime */  
#define MS_BIND         4096       /* 對應-B/--bind選項,告訴mount這是一次bind操作 */  
#define MS_MOVE         8192       /* 對應-M/--move,告訴mount這是一次move操作 */  
#define MS_REC          16384      /* rec是recursive的意思,這個flag一般不單獨出現,都是伴隨這其它flag,表示遞歸的進行操作 */  
#define MS_VERBOSE      32768      /* 對應-v/--verbose */  
#define MS_SILENT       32768      /* 對應-o silent/loud */  
#define MS_POSIXACL     (1<<16)    /* 讓VFS不應用umask,如NFS */  
#define MS_UNBINDABLE   (1<<17)    /* 對應--make-unbindable */  
#define MS_PRIVATE      (1<<18)    /* 對應--make-private */  
#define MS_SLAVE        (1<<19)    /* 對應--make-slave */  
#define MS_SHARED       (1<<20)    /* 對應--make-shared */  
#define MS_RELATIME     (1<<21)    /* 對應-o relatime/norelatime */  
#define MS_KERNMOUNT    (1<<22)    /* 這個一般不在應用層使用,一般內核掛載的文件系統如sysfs使用,表示使用kern_mount()進行掛載 */  
#define MS_I_VERSION    (1<<23)    /* 對應-o iversion/noiversion */  
#define MS_STRICTATIME  (1<<24)    /* 對應-o strictatime/nostrictatime */  
#define MS_LAZYTIME     (1<<25)    /* 對應 -o lazytime/nolazytime*/

/* 下面這幾個flags都是內核內部使用的,不由mount系統調用傳遞 */
#define MS_SUBMOUNT     (1<<26)
#define MS_NOREMOTELOCK (1<<27)
#define MS_NOSEC        (1<<28)
#define MS_BORN         (1<<29)
#define MS_ACTIVE       (1<<30)
#define MS_NOUSER       (1<<31)
/* 
 * Superblock flags that can be altered by MS_REMOUNT 
 */  
#define MS_RMT_MASK     (MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK|MS_I_VERSION|\                   
                         MS_LAZYTIME)  // 可以在remount時改變的flags  
  
/* 
 * Old magic mount flag and mask 
 */  
#define MS_MGC_VAL 0xC0ED0000      /* magic number */  
#define MS_MGC_MSK 0xffff0000      /* flags mask */
  • 除了上面這些flags對應的mount選項,剩下的基本就是data來傳遞。
    (1)我們選一個是flag的mount option,如nodev。
    (2)再選一個XFS支持的非通用mount option,如noquota。通過strace來看一下nodev和noquota對應mount系統調用的哪個參數:
strace mount /dev/sdb1 /mnt/scratch -o nodev,noquota
可以看到下面這一行:
mount("/dev/sdb1", "/mnt/scratch", "xfs", MS_MGC_VAL|MS_NODEV, "noquota") = 0 

結論:
(1)可見如我們所料,nodev傳遞給了第4個參數mountflags,noquota傳遞給了第5個參數data

(2)注意data參數是void *指針類型的參數,這表示它不一定接受的是字符串類型的變量,有些文件系統會將data定義爲結構體格式,
或其它什麼格式。
然後在掛載時解開這個格式分析出裏面的選項。所以第5個參數傳什麼還要看你第3個參數是什麼文件系統。

3.Linux系統調用-- mount/umount函數詳解

  • mount/umount系統調用】
功能描述:
mount掛上文件系統,umount執行相反的操作。
  
用法:  
#include <sys/mount.h>

int mount(const char *source, const char *target,
   const char *filesystemtype, unsigned long mountflags, const void *data);

int umount(const char *target);

int umount2(const char *target, int flags);
  • 參數mountflags:
source:將要掛上的文件系統,通常是一個設備名。
target:文件系統所要掛在的目標目錄。
filesystemtype:文件系統的類型,可以是"ext2""msdos""proc""nfs""iso9660" 。。。
mountflags:指定文件系統的讀寫訪問標誌,可能值有以下

MS_BIND:執行bind掛載,使文件或者子目錄樹在文件系統內的另一個點上可視。
MS_DIRSYNC:同步目錄的更新。
MS_MANDLOCK:允許在文件上執行強制鎖。
MS_MOVE:移動子目錄樹。
MS_NOATIME:不要更新文件上的訪問時間。
MS_NODEV:不允許訪問設備文件。
MS_NODIRATIME:不允許更新目錄上的訪問時間。
MS_NOEXEC:不允許在掛上的文件系統上執行程序。
MS_NOSUID:執行程序時,不遵照set-user-ID 和 set-group-ID位。
MS_RDONLY:指定文件系統爲只讀。
MS_REMOUNT:重新加載文件系統。這允許你改變現存文件系統的mountflag和數據,而無需使用先卸載,再掛上文件系統的方式。
MS_SYNCHRONOUS:同步文件的更新。
MNT_FORCE:強制卸載,即使文件系統處於忙狀態。
MNT_EXPIRE:將掛載點標誌爲過時。
  • data:文件系統特有的參數。
  • 返回說明:
成功執行時,返回0。失敗返回-1,errno被設爲以下的某個值   
EACCES:權能不足,可能原因是,路徑的一部分不可搜索,或者掛載只讀的文件系統時,沒有指定 MS_RDONLY 標誌。
EAGAIN:成功地將不處於忙狀態的文件系統標誌爲過時。
EBUSY:一. 源文件系統已被掛上。或者不可以以只讀的方式重新掛載,因爲它還擁有以寫方式打開的文件。二. 目標處於忙狀態。
EFAULT: 內存空間訪問出錯。
EINVAL:操作無效,可能是源文件系統超級塊無效。
ELOOP :路徑解析的過程中存在太多的符號連接。
EMFILE:無需塊設備要求的情況下,無用設備表已滿。
ENAMETOOLONG:路徑名超出可允許的長度。
ENODEV:內核不支持某中文件系統。
ENOENT:路徑名部分內容表示的目錄不存在。
ENOMEM: 核心內存不足。
ENOTBLK:source不是塊設備。
ENOTDIR:路徑名的部分內容不是目錄。
EPERM : 調用者權能不足。
ENXIO:塊主設備號超出所允許的範圍。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章