dev 命令行参数调用_mount系统调用初探

86f3da4208853807ea41a4eef050457a.png

回顾

我们在上一篇文章里介绍了文件系统的file_system_type,以及如何注册一个文件系统。但是注册一个文件系统后不代表这个文件系统就被马上使用了,就像你注册了一个账号但是不代表你登录了一样,对于文件系统来说这个登录就相当于“挂载(mount)”。

回忆一下,一个文件系统的file_system_type里有两个主要成员,一个是文件系统的名字,一个是mount这个文件系统的方法(其它参数也很重要,但重点就是这两个)。名字就是一个id,唯一标记一个文件系统,并方便内核在需要时根据它找到这个文件系统的file_system_type。mount方法在挂载这个文件系统时使用的,在需要挂载一个文件系统时通过name找到这个文件系统的file_system_type实例,然后使用这个实例中挂载的方法(mount函数),进行挂载。

当一个文件系统被挂载之后,一个文件系统实例就诞生并可以使用了。


mount系统调用

一般我们类似这样挂载一个文件系统:

# mount -t xfs /dev/sdb1 /mnt -o ...

-t指定/dev/sdb1上的文件系统类型,如果不使用-t则mount命令也可以尝试探测device上的文件系统类型。

-o用来指定一些额外的(非默认的)挂载选项。

上面这个命令翻译成人话就是:请把/dev/sdb1上的XFS文件系统挂载到/mnt上,并在挂载时使能-o里的特性。

这是从一个命令的角度来看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,但是还剩下两个参数mountflags和data,可是我们只剩下一个-o选项了,这是怎么回事呢?

别急,我们先抛开mountflags和data看一下mount系统调用怎么用。

  • 首先,我们在一个存储设备上创建一个文件系统
# mkfs.xfs -f /dev/sdb1
  • 然后我们准备一个挂载点
# mkdir /mnt/scratch
  • 最后我们使用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

用mount系统调用的前三个参数,不带任何挂载选项就挂载了文件系统。好像蛮简单的,别着急,后面还两个可选参数呢。


mount的flags和data

实际上flags + data对应mount命令的所有-o选项。那怎么区分哪些属于flags哪些属于data呢?在深入内核代码一探究竟之前(本篇不深入了)我们可以通俗的认为flags就是所有文件系统通用的挂载选项,由VFS层解析。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来传递。我们选一个是flag的mount option,如nodev。再选一个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 

可见如我们所料,nodev传递给了第4个参数mountflags,noquota传递给了第5个参数data。

注意data参数是void *指针类型的参数,这表示它不一定接受的是字符串类型的变量,有些文件系统会将data定义为结构体格式,或其它什么格式。然后在挂载时解开这个格式分析出里面的选项。所以第5个参数传什么还要看你第3个参数是什么文件系统。

至此我们解释了mount系统调用的角度解释了mount需要哪些参数,以及这些参数的意义。后面该从mount系统调用陷入内核开始进入内核代码一探mount的过程了(希望我有时间写,孩子发高烧了,唉,这注定是一个不眠的夜晚)。


更多内容请参阅:

醉卧沙场:README - 专栏文章总索引

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值