平常/etc/fstab文件内容如下:


首先,读取/etc/fstab文件内容,将用户填写的信息挂载起来的命令是systemd-fstab-generator,这是systemd中的一个服务。所以在systemd(版本systemd-237)源码中,查看meson.build内容,查找到systemd-fstab-generator的源码文件是fstab-generator.c和mount-setup.c。

在fstab-generator.c 的main函数中调用parse_fstab函数,如下:
static int parse_fstab(bool initrd) {
_cleanup_endmntent_ FILE *f = NULL;
const char *fstab_path;
struct mntent *me;
int r = 0;
fstab_path = initrd ? "/sysroot/etc/fstab" : "/etc/fstab";
f = setmntent(fstab_path, "re");
if (!f) {
if (errno == ENOENT)
return 0;
return log_error_errno(errno, "Failed to open %s: %m", fstab_path);
}
while ((me = getmntent(f))) {
_cleanup_free_ char *where = NULL, *what = NULL, *canonical_where = NULL;
bool makefs, growfs, noauto, nofail;
int k;
if (initrd && !mount_in_initrd(me))
continue;
what = fstab_node_to_udev_node(me->mnt_fsname);
if (!what)
return log_oom();
if (is_device_path(what) && path_is_read_only_fs("sys") > 0) {
log_info("Running in a container, ignoring fstab device entry for %s.", what);
continue;
}
parse_fstab函数使用getmntent函数读取了/etc/fstab文件的每一行内容,其me->mnt_fsname就是要挂载的设备名。进入到fstab_node_to_udev_node函数:
static char *tag_to_udev_node(const char *tagvalue, const char *by) {
_cleanup_free_ char *t = NULL, *u = NULL;
size_t enc_len;
u = unquote(tagvalue, QUOTES);
if (!u)
return NULL;
enc_len = strlen(u) * 4 + 1;
t = new(char, enc_len);
if (!t)
return NULL;
if (encode_devnode_name(u, t, enc_len) < 0)
return NULL;
return strjoin("/dev/disk/by-", by, "/", t);
}
char *fstab_node_to_udev_node(const char *p) {
assert(p);
if (startswith(p, "LABEL="))
return tag_to_udev_node(p+6, "label");
if (startswith(p, "UUID="))
return tag_to_udev_node(p+5, "uuid");
if (startswith(p, "PARTUUID="))
return tag_to_udev_node(p+9, "partuuid");
if (startswith(p, "PARTLABEL="))
return tag_to_udev_node(p+10, "partlabel");
return strdup(p);
}
在代码中,清晰看到使用startswith判断设备名的开头是什么,然后调用tag_to_udev_node函数。如果是LABEL=,则会strjoin("/dev/disk/by-", by, "/", t),即获取/dev/disk/by-label/下对应的软连接。
至此,可以明白fatab文件如果书写UUID=xxx,其实systend会找到/dev/disk/by-uuid/xxx软连接;如果是label=xxx,其实systemd会找到/dev/disk/by-label/xxx软连接。所以,我们直接用/dev/disk/by-xx/xxx来表示设备也是可以的。根据代码,知道除了uuid和label外,还可以用partuuid和partlabel来表示设备。
查看/dev/disk/目录,还有一个by-id的目录,其中的文件名就是设备的wwid。因为代码没有解析WWID,所以我们也就在fstab中无法用WWID来表示设备了。
所以文件开头的问题,是不是这会儿就明白了呢?
另外,现在系统中,更喜欢使用uuid来表示设备,而不是使用设备名/dev/sdb。因为磁盘插槽替换,或者磁盘驱动问题,都可能会造成设备名变化。而挂载一个磁盘,必须要格式化,格式化则会给磁盘分配一个唯一的uuid。即使设备名变了,/dev/disk/by-uuid/xx始终会指向原来的设备。这是为什么呢?因为udev规则,/lib/udev/rules.d/60-persistent-storage.rules文件会维持这关系。