赞
踩
mount2
介绍了mount调用的定义
NAME top
mount - mount filesystem
SYNOPSIS top
#include <sys/mount.h>
int mount(const char *source, const char *target,
const char *filesystemtype, unsigned long mountflags,
const void *data);
关键参数有source
,target
,filesystemtype
,mountflags
,data
假设有个分区 /dev/sdb1
, 如果我们要把它挂载到/mnt/test
,并且传参nodev
,noquota
和nosuid
,则可执行如下命令:
mount /dev/sdb1 /mnt/test -o nodev,noquota,nosuid
看下mount结果,可以看到nodev
,noquota
和nosuid
都生效了:
#mount | grep test
/dev/sdb1 on /mnt/test type xfs (rw,nosuid,nodev,relatime,attr2,inode64,logbufs=8,logbsize=32k,noquota)
重新mount,通过starce来跟踪看下
# umount /mnt/test
# strace mount /dev/sdb1 /mnt/test -o nodev,noquota,nosuid 2>&1 | grep '/mnt/test'
execve("/usr/bin/mount", ["mount", "/dev/sdb1", "/mnt/test", "-o", "nodev,noquota,nosuid"], 0x7ffc9b571e00 /* 19 vars */) = 0
lstat("/mnt/test", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
mount("/dev/sdb1", "/mnt/test", "xfs", MS_NOSUID|MS_NODEV, "noquota") = 0
可以看到在调用mount方法时,传参为:
mount("/dev/sdb1", "/mnt/test", "xfs", MS_NOSUID|MS_NODEV, "noquota") = 0
这里的MS_NOSUID|MS_NODEV
就是mount参数里的mountflags
,使用了位运算的方式来传参,挺有意思,我们就来看看mountflags
的传参吧。
在开始之前复习下位运算
运算符 | 描述 | 例子 |
---|---|---|
& | 与运算,两值同为1,结果为1,否则为0 | A=0,B=1, A&B=0 |
| | 或运算,只要有一个值为1,结果为1 | A=0,B=1, A|B=1 |
^ | 异或运算,如果a、b两个值相同,结果为0。如果a、b两个值不同,结果为1 | A=0,B=1, A^B=1 |
~ | 取反 | A=1, ~A=-1 |
<< | 左移, 向左移动 | A=1, A<<2=4 |
>> | 右移, 向右移动 | A=3, A>>1=1 |
举个例子,假设有两个数p=23和q=15,对应的二进制为:
p = 10111
q = 1111
p | q 为:
10111 | 01111
每一位一一对应,做|运算,得到
11111
结果为31
我们用代码验证下
>>> p = 23
>>> q = 15
>>> p | q
31
可以看到结果相等。
有了位运算的基础,我们就可以来看下mountflags的传参了,并体会到这样传参的好处。
在/usr/include/linux/mount.h
里可以看到mountflags的定义
/* * These are the fs-independent mount-flags: up to 32 flags are supported * * Usage of these is restricted within the kernel to core mount(2) code and * callers of sys_mount() only. Filesystems should be using the SB_* * equivalent instead. */ #define MS_RDONLY 1 /* Mount read-only */ #define MS_NOSUID 2 /* Ignore suid and sgid bits */ #define MS_NODEV 4 /* Disallow access to device special files */ #define MS_NOEXEC 8 /* Disallow program execution */ #define MS_SYNCHRONOUS 16 /* Writes are synced at once */ #define MS_REMOUNT 32 /* Alter flags of a mounted FS */ #define MS_MANDLOCK 64 /* Allow mandatory locks on an FS */ #define MS_DIRSYNC 128 /* Directory modifications are synchronous */ #define MS_NOATIME 1024 /* Do not update access times. */ #define MS_NODIRATIME 2048 /* Do not update directory access times */ #define MS_BIND 4096 #define MS_MOVE 8192 #define MS_REC 16384 #define MS_VERBOSE 32768 /* War is peace. Verbosity is silence. MS_VERBOSE is deprecated. */ #define MS_SILENT 32768 #define MS_POSIXACL (1<<16) /* VFS does not apply the umask */ #define MS_UNBINDABLE (1<<17) /* change to unbindable */ #define MS_PRIVATE (1<<18) /* change to private */ #define MS_SLAVE (1<<19) /* change to slave */ #define MS_SHARED (1<<20) /* change to shared */ #define MS_RELATIME (1<<21) /* Update atime relative to mtime/ctime. */ #define MS_KERNMOUNT (1<<22) /* this is a kern_mount call */ #define MS_I_VERSION (1<<23) /* Update inode I_version field */ #define MS_STRICTATIME (1<<24) /* Always perform atime updates */ #define MS_LAZYTIME (1<<25) /* Update the on-disk [acm]times lazily */ /* These sb flags are internal to the kernel */ #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)
可以看到里面的参数比较多,如果按照普通的传参方式,我们可能这样做:
// 定义个函数,并定义几个参数 function mount(MS_RDONLY,MS_NOSUID,MS_NODEV,MS_NOEXEC){ // 逻辑代码里一个个去判断,做计算 if(MS_RDONLY){ // ... } if(MS_NOSUID){ // ... } if(MS_NODEV){ // ... } if(MS_NOEXEC){ // ... } }
初看好像没啥问题,但如果参数变多了,调用函数的地方多了之后,这样的方式就会变得难以维护。
通过看Linux内核代码,我们会发现使用标志位操作就是解决这个问题的一个很好的方式。
看下Linux内核(5.17)里path_mount
/* * Flags is a 32-bit value that allows up to 31 non-fs dependent flags to * be given to the mount() call (ie: read-only, no-dev, no-suid etc). * * data is a (void *) that can point to any structure up to * PAGE_SIZE-1 bytes, which can contain arbitrary fs-dependent * information (or be NULL). * * Pre-0.97 versions of mount() didn't have a flags word. * When the flags word was introduced its top half was required * to have the magic value 0xC0ED, and this remained so until 2.4.0-test9. * Therefore, if this magic number is present, it carries no information * and must be discarded. */ int path_mount(const char *dev_name, struct path *path, const char *type_page, unsigned long flags, void *data_page) { unsigned int mnt_flags = 0, sb_flags; int ret; /* Discard magic */ if ((flags & MS_MGC_MSK) == MS_MGC_VAL) flags &= ~MS_MGC_MSK; /* Basic sanity checks */ if (data_page) ((char *)data_page)[PAGE_SIZE - 1] = 0; if (flags & MS_NOUSER) return -EINVAL; ret = security_sb_mount(dev_name, path, type_page, flags, data_page); if (ret) return ret; if (!may_mount()) return -EPERM; if (flags & SB_MANDLOCK) warn_mandlock(); /* 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; if (flags & MS_NOSYMFOLLOW) mnt_flags |= MNT_NOSYMFOLLOW; /* The default atime for remount is preservation */ if ((flags & MS_REMOUNT) && ((flags & (MS_NOATIME | MS_NODIRATIME | MS_RELATIME | MS_STRICTATIME)) == 0)) { mnt_flags &= ~MNT_ATIME_MASK; mnt_flags |= path->mnt->mnt_flags & MNT_ATIME_MASK; } sb_flags = flags & (SB_RDONLY | SB_SYNCHRONOUS | SB_MANDLOCK | SB_DIRSYNC | SB_SILENT | SB_POSIXACL | SB_LAZYTIME | SB_I_VERSION); if ((flags & (MS_REMOUNT | MS_BIND)) == (MS_REMOUNT | MS_BIND)) return do_reconfigure_mnt(path, mnt_flags); if (flags & MS_REMOUNT) return do_remount(path, flags, sb_flags, mnt_flags, data_page); if (flags & MS_BIND) return do_loopback(path, dev_name, flags & MS_REC); if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE)) return do_change_type(path, flags); if (flags & MS_MOVE) return do_move_mount_old(path, dev_name); return do_new_mount(path, type_page, sb_flags, mnt_flags, dev_name, data_page); }
可以看到里面有大量的位运算来判断传参,比如判断MS_NOSUID
参数:
if (flags & MS_NOSUID)
mnt_flags |= MNT_NOSUID;
传参时我们传的是MS_NOSUID|MS_NODEV,所以这里判断MS_NOSUID时实际上是:
(MS_NOSUID|MS_NODEV) & MS_NOSUID
可以说是非常的优雅了。
今天的介绍就到这里了,感谢阅读。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。