眼瞅着2020年马上就要到头了,承诺给大家的Linux移植三部曲还差最后一篇,这个拖延癌晚期恐怕今年是治不好了,不到最后的DL绝不妥协……
(这句话是年前写的,写了个开头就疫情了,封城,电脑丢在了公司,于是过上了老婆媳妇热炕头的性福生活,已无力码字……)
前面我们已经把U-Boot和Linux内核移植完成了,中间还加了个SDL2的移植过程,但其实看完我前面两篇的移植,Linux是不能跑起来的——没有根文件系统。
啥是根文件系统?根文件系统可以简单的理解为一个文件夹,或者目录,就是我们经常用到的“/”,这个目录中有包含了很多的子目录,我们系统运行所需要的库文件、命令、软件、配置、设备文件等等,都分类保存在不同的子目录中,这些文件统一叫做“根文件系统”。度娘说,根文件系统是Linux内核启动后挂载的第一个文件系统,Linux的内核镜像被保存在根文件系统中,呃……我不知道是我理解的有问题,还是度娘错了,我发现嵌入式Linux中镜像文件并没有保存在根文件系统中,而是保存在了另外一个分区,就是之前我们在SD卡中烧录的的0:1这个分区中,一般都会被存放在eMMC、SD卡、Flash、网络中某个地址,还记得U-Boot启动的时候加载的那些文件吗,一个是zImage,还有一个是设备树文件,就是从这些分区来的,但是我理解的他们并不属于根文件系统的一部分。
这些都瓦特艾沃了,直接拖鞋上炕吧!
本次我们构建系统用的是BusyBox,她是一个集成了三百多种常用Linux命令和工具的软件包,包含了一些简单的工具,例如ls、cat、echo等常用命令,还包含了例如grep、find、mount、telnet等更复杂更强大的的工具。类似BusyBox一类用于创建根文件系统的还有Yocto、Debian一类的,那些功能更强大,移植更简单,但耗时比较长,而且过于傻瓜,应用方便,不利于底层的学习。
在构建根文件系统之前,我们先卡一下根文件系统里都有啥,以Ubuntu为例,进入根目录,用ls看一下里面的文件夹:
目录 |
介绍 |
bin |
用于存放系统可执行文件,如ls、mv一类的命令,此目录下的命令所有用户都可以使用 |
dev |
device的缩写,里面的所有文件都与设备有关,Linux下一切接文件,硬件设备也是以文件方式体现的 |
etc |
跟高速收费没啥关系,这个目录是用来存放各种配置文件的 |
lib |
顾名思义,library的缩写,用来存放Linux所需要的库文件 |
mnt |
临时挂载目录,用于临时设备的挂载,例如优盘插入后,会在这个目录下生成sd、usb一类的子目录,就是优盘的根目录 |
proc |
此目录一般是空的,当 Linux系统启动以后会将此目录作为 proc文件系统的挂载点, proc是个虚拟文件系统,没有实际的存储设备。 proc里面的文件都是临时存在的,一般用来存储系 统运行信息文件。 |
usr |
刚开始接触linux的时候,我一直以为这是用户目录,但后来发现丫不是user的缩写,是Unix Software Resource的缩写,这个目录用来存放软件,目录下也存放着很多软件,一般系统安装完成以 后此目录占用的空间最多。 |
var |
存放数据的,比如日志、数据库文件、webroot一类的东西,都放在下面 |
sbin |
不要从两个字母的看,容易不敢进去。此目录页用户存放一些可执行文件,但是此目录下的文件或者说命令只有管理员才能使用, 主要用户系统管理。 |
sys |
系统启动以后此目录作为 sysfs文件系统的挂载点, sysfs是一个类似于 proc文件系统的特 殊文件系统, sysfs也是基于 ram的文件系统,也就是说它也没有实际的存储设备。此目录是系 统设备管理的重要目录,此目录通过一定的组织结构向用户提供详细的内核数据结构信息。 |
opt |
可选的文件、软件存放区,由用户选择将哪些文件或软件放到此目录中。之前一直SDL的时候我就放在这里了。 |
home |
用户目录,存放这除root用户之外的其他用户工作目录,每创建一个用户就多一个子文件夹。咱们这次一直的是单用户的系统,这个目录用不到 |
root |
root用户目录。 |
其他目录都不用搭理了,有兴趣的找度娘问问吧。
BusyBox可以去官网下载一份,https://busybox.net,找到最新版下载就行了,据说之前的版本中(V1.29)出现过DNS不可用的问题,不知道后面的版本解决了没有,我用的是1.32,最新版肯定没错,如果实在不行,就去NXP官网找一份。
首先修改Makefile文件,加入交叉编译的一些参数,否则每次make都得写,太麻烦。
修改以下参数:
CROSS_COMPILE ?= /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-
ARCH ?= arm
Linux默认采用UTF8的编码格式,但是丫不支持中文,稍作修改即可。
找到libbb/printable_string.c 中的printtable_string函数,这里面当c>=0x7F的时候就跳出了,把这里改改,修改后的代码如下:
const char* FAST_FUNC printable_string2(uni_stat_t *stats, const char *str)
{
char *dst;
const char *s;
s = str;
while (1) {
unsigned char c = *s;
if (c == '\0') {
/* 99+% of inputs do not need conversion */
if (stats) {
stats->byte_count = (s - str);
stats->unicode_count = (s - str);
stats->unicode_width = (s - str);
}
return str;
}
if (c < ' ')
break;
/*if (c >= 0x7f)
break; */
s++;
}
#if ENABLE_UNICODE_SUPPORT
dst = unicode_conv_to_printable(stats, str);
#else
{
char *d = dst = xstrdup(str);
while (1) {
unsigned char c = *d;
if (c == '\0')
break;
/*if (c < ' ' || c >= 0x7f)*/
if(c < ' ')
*d = '?';
d++;
}
if (stats) {
stats->byte_count = (d - dst);
stats->unicode_count = (d - dst);
stats->unicode_width = (d - dst);
}
}
#endif
return auto_string(dst);
}
在libbb/unicode.c找到unicode_conv_to_printable2函数,做同样修改:
if (unicode_status != UNICODE_ON) {
char *d;
if (flags & UNI_FLAG_PAD) {
d = dst = xmalloc(width + 1);
while ((int)--width >= 0) {
unsigned char c = *src;
if (c == '\0') {
do
*d++ = ' ';
while ((int)--width >= 0);
break;
}
/* *d++ = (c >= ' ' && c < 0x7f) ? c : '?';*/
*d++ = (c >= ' ') ? c : '?';
src++;
}
*d = '\0';
} else {
d = dst = xstrndup(src, width);
while (*d) {
unsigned char c = *d;
/*if (c < ' ' || c >= 0x7f)*/
if (c < ' ')
*d = '?';
d++;
}
}
if (stats) {
stats->byte_count = (d - dst);
stats->unicode_count = (d - dst);
stats->unicode_width = (d - dst);
}
return dst;
}
以上两部分是支持中文目录的,如果纯英文环境,不改也罢。
接下来开始配置busybox,和linux内核、uboot的移植一样,也可以通过menuconfig进行调整,官方带了三种支持,分别是:
1. defconfig:缺省配置,也就是默认的配置项
2. allyesconfig:全选配置,也就是选中busybox中所有功能
3. allnoconfig:最小配置
我们使用默认的配置。
make defconfig
然后对默认配置进行微调:
make menuconfig
1. Settings -> Build static binary(no shared libs) 不选中
不使用静态编译,胴体爱编译的话要根据文件系统中所有库文件,编译出来的busybox比较小,静态编译出来的文件较大,但是DNS可能会出问题(1.29出这个问题,不知道1.32解决了没有,待验证)
2. Settings -> vi-style line editing commands 选中
3. Linux Module Utilities -> Simplified modutils 取消勾选
4. Linux System Utilities -> mdev 确保下面全部选中
5. Settings -> Support Unicode -> Check $LC_All,$LC_CTYPE and $LANG environment variables 选中
以上配置基本就完成了。
最后编译和安装
make
make install CONFIG_PREFIX=/home/mars/Linux/nfs/rootfs
CONFIG_PREFIX指向的目录就是启动根文件系统要用到的目录,busybox会把编译好的根文件系统整体复制到这个目录中。
以上,基本完成了根文件系统的第一步,但此时还无法启动,需要再复制一些文件进去才行。
Linux中的应用程序一般都是需要动态库的,当然你也可以编译成静态的,但是静态的可执行文件会很大。如果编译为动态的话就需要动态库,所以我们需要先根文件系统中添加动态库。
创建好了,库文件从哪里来呢? lib库文件从交叉编译器中获取, 前面我们搭建交叉编译环境的时候将交叉编译器存放到了“/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf”中,arm/”目录中。交叉编译器里面有很多的库文件,这些库文件具体是做什么的我们作为初学者肯定不知道,既然我不知道那就简单粗暴的把所有的库文件都放到我们的根文件系统中。这样做出来的根文件系统肯定很大,但是我们现在是学习阶段,还做不了裁剪。
进入根目录(不是Ubuntu的根目录,/home/mars/Linux/nfs/rootfs,千万别搞错了,要不然一会搞完你Ubuntu也打不开了,我就干了次这种傻事),在根目录中创建lib子目录,把交叉编译器下的类库复制到这里,命令如下:
cd /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/lib/
cp *so* *.a /home/mars/Linux/nfs/rootfs/lib/ -d
cd /home/mars/Linux/nfs/rootfs/lib/
rm ld-linux-armhf.so.3
cd /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/lib/
cp ld-linux-armhf.so.3 /home/mars/Linux/nfs/rootfs/lib/
cd /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/lib
cp *so* *.a /home/mars/Linux/nfs/rootfs/lib/ -d
其中/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf这里就是Ubuntu下gcc交叉编译环境的位置。
在根目录下创建usr/lib子目录,把其中一些类库再拷进去
cd /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/usr/lib
cp *so* *.a /home/mars/Linux/nfs/rootfs/usr/lib/ -d
搞完之后,用du命令看一下两个目录的大小
du lib usr/lib -sh
57M lib
67M usr/lib
如果大小差不多,基本上一步是没问题了,到此为止,我们的根文件系统基本就完备了,此时可以正常启动。
但是启动前,还是需要配置一下你的NFS服务器和BootLoader环境,NFS配置我记得前面讲过,如果没有就去问度娘吧,实在找不到留言,我再补充。
重启开发板,进入uboot,设置bootargs参数:
setenv bootargs 'console=tty1 console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.31.128:/home/mars/Linux/nfs/rootfs,proto=tcp rw ip=192.168.31.100:192.168.31.128:192.168.31.1:255.255.255.0::eth0:off'
saveenv
最后一步记得保存,上次发了Linux内核移植后,有很多人给我留言,说设置的参数重启后就丢了,可能是两种原因造成的,一个是没有调用saveenv,另外一种是烧在SD卡的时候保存不上,这时候还需要用U盘量产工具重新格式化一下SD卡就行了,没有洗分析原因,可能是存储格式导致的。其他导致无法保存的,各位大佬可以补充。
关于bootargs参数的格式顺带说一下:
root=/dev/nfs nfsroot=[
root: 启动根文件系统的设备,/dev/nfs表示从nfs启动,如果充SD卡或者emmc启动,这里设置/dev/mmcblk1p2一类的参数即可。
有些值可以空着,但是冒号要保留,冒号一定用英文的,中文的不认。
弄完后重启你的开发板,发现顺利加载根目录,但有可能提示“can't run '/etc/init.d/rcS': No such file or directory ”,下面就解决这个问题。
如果启动过程中出现乱码,看看bootargs是否配置正确。
如果启动过程中一直无法进入根文件系统,看看你的NFS配置是否正确,还有就网卡选择是否正确,网线接在左边口(野火的板子),网卡选择的是eth0,另外一个口是eth1。
另外一种可能就是NFS版本造成的,后面附加内容中我把NFS配置简单写一下。
到这里,几本你就成功了。
但是根文件系统中还少rcS这个文件,这个文件就是个shell脚本,是Linux内核启动后需要启动的一些服务,这个脚本中我们需要设置PATH和LD_LIBRARY_PATH两个环境变量(前者是执行命令时查找命令的目录,后者是通用库文件的保存目录),挂载所有文件系统,管理热插拔设备等。
文件内容如下:
#!/bin/sh
PATH=/sbin:/bin:/usr/sbin:usr/bin:$PATH
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/lib:/usr/lib
export PATH LD_LIBRARY_PATH
mount -a
mkdir /dev/pts
mount -t devpts devpts /dev/pts
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
编写完成后,给这个文件777的权限。
如果启动后一些环境变量不起作用,尝试把两个环境变量的申明写在/etc/profile中,我移植SDL的时候发现的这个问题,但一直没有跟踪是哪出的问题。
其中在第七行中,我们使用 mount命令来挂载所有的文件系统,这些文件系统由文件 /etc/fstab来指定,所以我们一会还要创建 /etc/fstab这个文件。
fstab在Linux开机以后自动配置哪些需要自动挂载的分区,格式如下:
文件内容:
#
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0
注意分隔符别多打了,否则你会很Happy!
做好文件后重启,发现原来那个找不到rcS的提示木有了,但是这事还没完,还差一个文件没创建。
Linux在完成核内引导(已经被载入内存,开始运行,并已初始化所有的设备驱动程序和数据结构等)之后,就通过启动一个用户级程序init的方式来启动其他用户级的进程或服务。所以,init始终是第一个进程,其PID始终为1(ps -aux | less),它是系统所有进程的父进程。
init程序需要读取配置文件/etc/inittab.inittab是一个不可执行的文本文件,它有若干行指令所组成,由若干条指令组成。每条指令的结构都是一样的,由以“ “:”分隔的 4个段组成,格式如下:
Busybox支持的动作如下表所示:
动作 |
描述 |
sysinit |
在系统初始化的时候process才会执行一次。 |
respawn |
当process终止以后马上启动一个新的。 |
askfirst |
和respawn类似,在运行 process之前在控制台上显示“ Please press Enter to activate this console.”。只要用户按下 Enter”键以后才会执行 process。 |
wait |
告诉init,要等待相应的进程执行完以后才能继续执行。 |
once |
仅执行一次,而且不会等待process执行完成。 |
restart |
当init重启的时候才会执行 procee。 |
ctrlaltdel |
当按下ctrl+alt+del组合键才会执行 process。 |
shutdown |
关机的时候执行process。 |
创建/etc/inittab文件,内容如下:
#etc/inittab
::sysinit:/etc/init.d/rcS
console::askfirst:-/bin/sh
tty1::askfirst:-/bin/sh
::restart:/sbin/init
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
::shutdown:/sbin/swapoff -a
重启开发板,顺利进入系统,并不断收到“random: nonblocking pool is initialized”的提示,表示一切都OK了!
如果想关闭这个提示,用cat /proc/sys/kernel/printk命令,输入7 4 1 7的密码即可,这是个数字分别表示了不同级别的Linux日志输出,不再业务范围,就不解释了,想了解的问度娘吧。
进入系统后ping一下百度,看是否能通,如果提示“ping: bad address 'www.baidu.com'”说明DNS有问题,要么是busybox版本问题,要么就是你DNS设置有问题,如果是版本的事,去官网下载一个最新的,我用的是1.32,没这个问题。
如果是DNS设置问题那就好办了,创建/etc/resolv.conf,里面写入:
nameserver 114.114.114.114
nameserver 192.168.31.1
第二个地址是我网关的地址,换成你的就行。
最后要说一句,根文件系统一些目录中的内容需要在开发板的命令行中才能看到,Ubuntu中看不到这些虚拟文件,不用诧异。
之前我们做的内核镜像和根文件系统都是在SD卡上,或者NFS、SFTP方式启动的,这个章节中,我要把U-Boot、Linux内核、根文件系统一并烧写到emmc上,实现独立运行。
烧写EMMC、NAND或者QSPIFlash到设备上,用的是NXP官方提供的MfgTool工具,这里只演示EMMC的烧写方式,其他的大同小异。这个工具可以去官网下载,或者去野火提供的工具包中找找看有没有,我直接用的隔壁家的。还有一点需要说明的是,这工具只有Windows版的,目前没找到Linux版本的。
工具下载后有两个版本,without-rootfs是不烧写根文件系统的,with-rootfs是烧写根文件系统的,第一次用的会后看似已用后面的,后面改动内核后再烧写可以用前面的,如果为了省事,推荐后一个。
解压文件包后,里面有一堆的.vbs文件,那就是启动文件,直接起exe是不好使的。
只需要关心mfgtool2-yocto-mx-evk-*.vbs即可,其他碍眼的都可以删除,后缀说明了是烧写哪类外设的,这里以mfgtool2-yocto-mx-evk-emmc.vbs为基础进行试用和修改。
首先把开发板拨码开关拨到USB启动,然后连接OTA线,在右边那个USB口,左边的是串口,连接好后启动xshell(或其他的串口工具)监听开发板输出,重启开发板。
然后双击运行mfgtool2-yocto-mx-evk-emmc.vbs,看到“提示”后表示连接成功。
单击Start开始烧录,烧录过程中PC上会出现一个U盘,不用理丫,也别乱动。等待烧录结束,软件上会提示Dane,并且进度条全变成绿色,表示烧录成功,如果过程中出现错误,可能是文件不全或者使用的vbs文件不对导致的,重新解压一份,官方提供的工具百分百可用。
烧录结束后别着急拔线,一定要点Stop和Exit,再拔线,否则就烧废了(烧废了重烧就行了,除非硬件被你搞坏了,一般情况不会变砖)。
关闭开发板电源,拔OTA线,把拨码开关调到eMMC启动,重新上电。此时你运行的系统就是在开发板中的了。
这里面有两个地方需要注意:
上面是烧NXP官方提供的内核文件,一般第二个问题不会出现,启动后用户名是root,没有密码,进入命令行后表示启动成功。
前面说的只是个引子,体验一下MfgTool这个工具,下面开始移植自己的烧录工具。
首先是烧录的文件,在工具目录的Profiles/Linux/OS Firmware用来存放要烧录系统的固件,files、firmware两个子目录和ucl2.xml文件。
在具体看这三个文件和文件夹之前,我们先来简单了解一下 MfgTool烧写的原理, MfgTool其实是先通过 USB OTG先将 uboot、 kernel和 .dtb(设备树 )这是三个文件下载到开发板的 DDR中,注意不需要下载 rootfs。就相当于直接在开发板的 DDR上启动 Linux系统,等 Linux系统启动以后再向 EMMC中烧写完整的系统,包括 uboot、 linux kernel、 .dtb(设备树 )和 rootfs,因此 MfgTool工作过程主要分两个阶段:
firmware目录中有很多个.imx的uboot文件,一个zImage内核镜像文件和好多个.dtb格式的设备树文件,这些文件是NXP官方对不同板子做的支持,其实我们只需要关组imx6ull-14x14-evk的文件即可。
u-boot-imx6ull14x14evk_emmc.imx:NXP官方针对EVK板子做的U-Boot文件。
zImage-imx6ull-14x14-evk-emmc.dtb:EVK板子的设备树文件。
zImage:Linux镜像文件。
我们做自己的移植需要修改的就是这三个文件,其他的都可以不搭理。
files文件夹真正最后要烧入emmc的文件系统,也就是第二阶段要干的事。这里面除了上面说的那三个文件之外,还有一个rootfs_nogpu.tar.bz2的归档文件,这是就是根文件系统。
ucl2.xml文件知名了我们在烧录的时候如何从众多的文件中选择指定的型号,这个xml以标签包裹的是针对不同存储芯片烧写的命令,如果想要了解的话,我后面会附上一个做完注释的文件,有兴趣可以看看,没啥难的。
首先制作u-boot-imx6ull14x14evk_emmc.imx、zImage-imx6ull-14x14-evk-emmc.dtb、zImage和rootfs_nogpu.tar.bz2四个文件,覆盖原来的文件,根文件系统打包用的命令是tar jcvf rootfs_nogpu.tar.bz2 rootfs,打包一定要在移植的根目录进行,如果根文件系统加载不成功,看看是不是把rootfs也打包进行了,多一层目录启动不成功。保证这几个文件的名称和原来的名字一样,第一步就成功了。剩下的烧录过程和上面操作烧录官方镜像的一样即可。
各位,这事还没完,我们最终要的是一个完全属于野火i.MX6ULL Pro开发板的烧录工具,仪式感还是要有的!
回到烧录工具根目录,复制mfgtool2-yocto-mx-evk-emmc.vbs,重命名为mfgtool2-embedfire-emmc.vbs,其他的碍眼就删了吧。
复制ucl2.xml修改(我负载后面了),里面的内容不多解释了,看注释。
ucl2.xml中我把上面烧录的四个文件名都改了,都打上了embedfire的标签,根官方evk彻底闹掰,具体文件名在配置文件中找吧,都备注了。
用mfgtool2-embedfire-emmc.vbs烧录即可。
但我们自己烧录完之后还需要修改U-Boot的启动参数:
setenv bootcmd 'mmc dev 1;fatload mmc 1:1 80800000 zImage;fatload mmc 1:1 83000000 imx6ull-embedfire-emmc.dtb;bootz 80800000 - 83000000'
setenv bootargs 'console=tty1 console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw ip=192.168.31.100:192.168.31.128:192.168.31.1:255.255.255.0::eth0:off'
setenv
第一行让U-Boot去emmc中找Linux内核。
第二句让内核到emmc中找根文件系统。
如果不想每次设置,就该U-Boot源码,找到u-boot的include/configs/mx6ull_embedfire_emmc.h的CONFIG_EXTRA_ENV_SETTINGS标签,里面的findfdt修改为一下内容:
"findfdt="\
"if test $fdt_file = undefined; then " \
"setenv fdt_file imx6ull-embedfire-emmc.dtb; " \
"fi;\0" \
完了,终于完了!
到此为止,Linux移植三部曲全整理完毕,谁也不欠谁了。
这个坑有必要填一下,因为我再折腾NFS的时候,一开始总是加载不上,找了很多资料,都说是NFS配置问题,后来到国外的一个论坛中才发现这个坑(初中毕业的时候就把英语原封不动的还给老师了,所以遇到英文资料直接关了不看)。
如果你NFS加载根文件系统不成功,试试在U-Boot中手动输入nfs 80800000 192.168.31.128:/home/mars/Linux/nfs/zImage,看看能否加载,然后排除网线接错问题、IP设置问题、服务器IP设置问题后,依然提示“ERROR: File lookup fail”的错误,那多半是NFS版本问题没走。
这是因为uboot中使用的NFS版本是V2,而ubuntu的NFS版本为V3或V4及以上版本,导致uboot不能在NFS服务器中找到文件, 所以需要修改ubuntu中NFS的兼容。
在Ubuntu下,找到/etc/default/nfs-kernel-server文件,修改成下面的内容:
# Number of servers to start up
#RPCNFSDCOUNT=8
RPCNFSDCOUNT="-V 2 8"
# Runtime priority of server (see nice(1))
RPCNFSDPRIORITY=0
# Options for rpc.mountd.
# If you have a port-based firewall, you might want to set up
# a fixed port here using the --port option. For more information,
# see rpc.mountd(8) or http://wiki.debian.org/SecuringNFS
# To disable NFSv4 on the server, specify '--no-nfs-version 4' here
#RPCMOUNTDOPTS="--manage-gids"
RPCMOUNTDOPTS="-V 2 --manage-gids"
# Do you want to start the svcgssd daemon? It is only required for Kerberos
# exports. Valid alternatives are "yes" and "no"; the default is "no".
NEED_SVCGSSD=""
# Options for rpc.svcgssd.
RPCSVCGSSDOPTS="--nfs-version 2,3,4 --debug --syslog"
然后重启NFS服务
sudo /etc/init.d/nfs-kernel-server restart
这问题基本就解决了。
好吧,这次真的写完了。
别人疫情封城后都会胖个十斤八斤的,我这咋还瘦了十几斤呢……
配置文件下载地址:
https://download.csdn.net/download/suolong123/15382715