在QNX开启NFS服务,由QNX上的guest OS–Android作为客户端,将QNX的目录作为网络设备以NFS的方式挂载。过程中主要遇到三个问题,下面分别描述配置方法,配置过程遇到的问题、分析思路以及解决方案。
配置方法
QNX侧 1.1 将netconfig配置文件保存至/etc目录下,netconfig内容如下:
udp6 tpi_clts v inet6 udp - -
tcp6 tpi_cots_ord v inet6 tcp - -
udp tpi_clts v inet udp - -
tcp tpi_cots_ord v inet tcp - -
rawip tpi_raw - inet - - -
local tpi_cots_ord - loopback - - -
1.2 将exprots配置文件推送至/etc路径下,exprots内容如下:
/persist/nfs_server -mask=255.255.255.0 -match=192.168.1.0
exports文件定义了NFS服务端提供给客户端的挂载点,以及相关的挂载权限,以上述配置内容为例,设置的挂载点为/persist/nfs_server,允许的挂载的客户端IP为必须属于192.168.1这个网段,即IP必须满足IP & 255.255.255.0=192.168.1.0。其他可配置的选项还有-norsvd,-ro,-root等,每个选项的详细介绍可以查询QNX官方开发者网站。
1.3 执行rpcbind和nfsd
rpcbind
nfsd -c /etc/exports -t
Android侧 1.1 kernel内核配置NFS client
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_SWAP=y
+CONFIG_NFS_V4_1=y
+CONFIG_NFS_V4_2=y
+CONFIG_NFS_V4_1_MIGRATION=y
+CONFIG_NFS_USE_LEGACY_DNS=y
+
1.2 挂载在/data/nfs_client目录
busybox mount -t nfs -o nolock 192.168.1.1:/persist/nfs_server /mnt/nfs_client
挂载时提示“Permission denied”
完成上述配置后,在Android端进行挂载时,遇到了“Permission denied”的错误
busybox mount -t nfs -o nolock 192.168.1.1:/persist/nfs_server /mnt/nfs_client
mount: mounting 192.168.1.1:/persist/nfs_server on /data/nfs_client failed: Permission denied
对QNX侧的/persist/nfs_server和Android侧的/data/nfs_client进行检查,发现权限都已经正确配置
drwxrwxrwx 2 root root 4096 Jan 01 00:01 /persist/nfs_server/
drwxrwxrwx 2 root root 4096 1970-01-01 00:02 nfs_client/
为了排查是QNX侧还是Android侧的问题,先在Android侧尝试将其他分区挂载到/data/nfs_client,发现可以成功
mount /dev/block/log /data/nfs_client/
EXT4-fs (vdm): mounted filesystem with ordered data mode. Opts: (null)
因此更倾向于QNX侧的问题,既然nfs_server的权限没有问题,难道是/persist目录的权限有问题,无法访问/persist目录才导致无法获取/persist/目录下nfs_server的信息? 于是检查/persist的权限,发现是660
drw-rw----+ 5 root root 4096 Jan 01 00:01 /persist/
于是将/persist的权限改至最大
chmod 777 /persist/
但是chmod后,发现权限仍然没改变:
drw-rw----+ 5 root root 4096 Jan 01 00:01 /persist/
于是使用mount命令检查,发现/persist上挂载了一个qnx6文件系统
/dev/disk/persist on /persist type qnx6
将这个文件系统umount,再次检查/persist目录的权限,发现和挂载了文件系统时的权限是不一样的,这是因为将文件系统挂载到某个挂载点时,会将挂载点的权限、属性都设置成默认值,而挂载了文件系统后,使用chmod对挂载点的权限进行修改,是不会起作用的
umount /persist/
ls -ald /persist/
drwxrwxrwx 2 root root 4096 Jan 01 00:04 /persist/
想要设定挂载后挂载目录的权限,就需要用到mount命令的mntperms选项,就可以将挂载后的/persist目录设置成自己需要的权限
mount mntperms=0777 /dev/disk/persist /persist/
ls -ald /persist/
drwxrwxrwx+ 5 root root 4096 Jan 01 00:01 /persist/
此时再次回到安卓进行挂载,发现可以挂载成功
busybox mount -t nfs -o nolock 192.168.1.1:/persist/nfs_server /mnt/nfs_client
mount |grep nfs
192.168.1.1:/persist/nfs_server on /data/nfs_client type nfs (rw,relatime,vers=3,rsize=32768,wsize=32768,namlen=255,hard,nolock,proto=tcp,timeo=600,retrans=2,sec=sys,mountaddr=192.168.1.1,mountvers=3,mountproto=tcp,local_lock=all,addr=192.168.1.1)
再进一步进行验证,确定时其他组用户对QNX的/persist/nfs_server缺少x权限时就会出现permission denied的问题,因为对目录的执行权限其实就是cd,即打开目录。 只是这里还是想不通的一点是,NFS挂载时,在QNX这一边,看起来并不是一个root用户的进程去访问/persist/nfs_server并传输数据,否则就不会需要给其他组用户设置上x权限了。
挂载后对挂载目录只有读权限,无法写入数据
上一个问题解决后,在Android侧可以正常挂载QNX的NFS目录,但是又遇到了另一个问题,在往挂载目录写入数据时,又提示了“Permission denied”。
touch file11
touch: 'file11': Permission denied
mkdir ttt
mkdir: 'ttt': I/O error
重新查阅QNX官方开发网站,按照里面的描述,默认情况下,NFS端的目录就是可读写权限,如果想设置只读权限,可以在/etc/exports文件加上-ro选项将目录权限设置为只读。 使用mkdir命令创建目录提示I/O error后,再次ls检查目录的情况,发现其实ttt目录其实有创建成功,但是这个目录的uid和gid非常奇怪,是数值非常大的数字。
ls -al ttt/
drwx------ 2 4294967294 4294967294 4096 1970-01-01 01:48 ttt/
用计算器转换,发现其二进制是111…1110,总共32位,这个其实就是-2的补码,重新看会QNX官方开发者文档中关于/etc/exports的描述,在-root选项的描述里看到,默认情况下,QNX的root uid在NFS客户端是映射为-2的,可以通过-root指定为其他数字。
-root=uid Map root’s uid (real user ID). By default, root is mapped to -2.
-2这个uid在Android系统应该是无效的,猜测是因为这个问题导致创建文件和目录异常。于是在QNX侧的/etc/exports文件加上-root=0的选项
/persist/nfs_server -root=0 -mask=255.255.255.0 -match=192.168.1.0
在Android侧再次挂载,并尝试创建文件,现象如下:
touch new_test
touch: 'new_test': I/O error
ls -al new_test
-rw------- 1 root root 0 1970-01-01 02:22 new_test
可以看到,文件可以成功创建了,且uid和gid都是root,但是还是和创建目录一样,有IO error的问题。
写入数据时提示“I/O error”
继续分析I/O error的问题。 尝试往文件写入数据,发现可以成功写入:
echo test_content > new_test
cat new_test
test_content
经过多次测试后,发现两个现象: 1.发现在创建文件时,第一次执行都会提示IO error,用ls可以看到目录下的文件,用echo方法往一个不存在的文件写入数据时,文件虽然被创建,但是内容并没有被写入
echo "write test" > newfile
/system/bin/sh: can't create newfile: I/O error
ls -al newfile
-rw------- 1 root root 0 1970-01-01 02:36 newfile
cat newfile
此时再次执行echo “write test” > newfile,则没有IO error的提示,且内容被成功写入
echo "write test" > newfile
cat newfile
write test
2.第一次touch文件时,会有IO error提示(ls可以看到文件已经生成),当再次创建同名文件时,就不会出现IO error。
touch newfile2
touch: 'newfile2': I/O error
touch newfile2
为了跟踪创建过程中到底哪里出错,在Android端使用strace命令跟踪touch的执行过程,省略中间过程,发现在执行openat的调用出错,返回了EIO,即I/O error。
strace touch newfile
...
openat(AT_FDCWD, "newfile", O_RDONLY|O_CREAT, 0666) = -1 EIO (I/O error)
write(2, "touch: ", 7touch: ) = 7
write(2, "'newfile'", 9'newfile') = 9
write(2, ": I/O error", 11: I/O error) = 11
write(2, "\n", 1
) = 1
exit_group(1) = ?
+++ exited with 1 +++
查阅网上的资料,对比open函数,openat多了传入文件的路径可以为相对路径的功能,其他地方和open函数一样。 正当无从下手分析时,同事经过不断测试和网上查阅资料,发现了只要在Android端挂载NFS时,加上nfsvers=2的选项,即可解决创建文件和目录时提示的I/O error问题。
busybox mount -t nfs -o nolock 192.168.1.1:/persist/nfs_server /data/nfs_client
不知道不同版本之间关于openat这个系统调用的支持是否有差异才导致I/O error的问题,还是QNX和Android之间需要使用一样的NFS版本,最后根本的原因还是不清楚~。
|