制作最小根文件系统使用NFS挂载、烧写至EMMC两种方式

  • Post author:
  • Post category:其他




iTOP4412制作最小根文件系统使用NFS挂载、烧写至EMMC两种方式


目录介绍


根文件系统是存放运行、维护系统所必须的各种工具、软件、库文件、脚本,配置文件和其他特殊文件的地方,也可以是安装各种软件的地方


/bin

可执行程序


/dev

块 , 字符设备节点文件


/lib

基本的库文件 如C库和内核模块 (modules)


/etc

主要配置文件和初始化文件


/linuxrc

init=/linuxrc 根文件系统挂载后运行的第一个程序


/proc

虚拟文件系统,用于内核和进程通讯


/sys

虚拟文件系统SYSFS挂载点


/usr

更多的用户程序


/mnt

挂载点,临时挂载文件系统


/sbin

基本的系统管理程序


/tmp

临时目录文件


/var

可变信息存储,如log等


制作根文件系统 使用busybox工具



一、前期准备


下载并解压busybox

https://busybox.net/


在这里插入图片描述

我使用的是busybox-1.22.1版本的


二、指定交叉编译器


修改Makefile 指定交叉编译器

在这里插入图片描述


三、配置busybox


busybox采用了和内核相同的菜单式选配方式,相当友好

make menuconfig

修改生成的根文件安装路径 也可以不修改

Busybox Settings –>

Installation Options (“make install” behavior) —>

在这里插入图片描述


四 、编译 安装

make

在这里插入图片描述

编译完成 安装

make install

在这里插入图片描述

在这里插入图片描述


五、创建相关目录

mkdir mnt dev sys proc etc var boot

在这里插入图片描述


六、创建配置文件


在这里插入图片描述

​ 由于init=/linuxrc,因此,在文件系统挂载后,运行的第一个程序就是根目录下的linuxrc,而这是一个指向/bin/busybox 的链接,也就是说,系统起来后运行的第一个程序就是busybox本身。

busybox首先将试图解析/etc/inittab来获取进一步的初始化配置信息(参考busybox源代码init/init.c中的parse_inittab()函数)。而事实上,root_qtopia中并没有/etc/inittab这个配置文件,根据busybox的裸机,它将生成默认的配置。其中最重要的一个,就是new_init_action(SYSINIT,INIT_SCRIPT,””),也就决定了接下来初始化的脚本是INIT_SCRIPT所定义的值,这个宏的默认值是”etc/init.d/rcS”。

所以首先创建/etc/init.d/rcS文件,这里重点分析一下rcS文件

1、/etc/init.d/rcS

#! /bin/sh:
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:

runlevel=S 
#运行级别 
prevlevel=N

umask 022
#权限掩码 创建文件默认为 777-022 =755
export PATH runlevel pervlevel

trap ":" INT QUIT TSTP 
#捕捉信号 SIGINT SIGQUIT SIGTSTP 然后执行":" 相当于忽视这几个信号
#只在init 进程捕捉这几个信号 这样就可以终止子进程
/bin/hostname yuan

#none:取消使用mount命令回显"xxx on /proc type proc (rw,noexec,nosuid,nodev)
#挂载文件系统
mount -t sysfs none /sys
#挂载proc 文件系统 为内核和内核模块将信息发送给进程
mount -t proc none /proc
#挂载 ramfs, 相当于把原本nandflash上的只读的/dev目录"覆盖上"一块可写的空的SDRAM
mount -t ramfs none /dev
#/sys 和挂载了ramfs的/dev是正确创建设备节点的关键 对于如今的内核已经没有devfs的支持,创建设备节点只有通过两种办法由文件系统完成:
1)制作文件系统镜像前用mknod手动创建好系统所有的(包括可能有的)设备节点,
并把这些节点文件一起做进文件系统镜像中;
2)在文件系统初始化过程中,通过/sys目录所输出的信息,
在/dev目录下动态的创建系统中当前实际有的设备节点。
显然,方法1)有很大的局限性,仅限于没有设备动态增加或减少的情况,
不适用于很多设备热插拔的情况,比如U盘,SD卡等等。
方法2)是目前大多数PC上的linux的做法(基于udev实现)。
这种方法有2个前提:/sys目录挂载和一个可写的/dev目录。这也就是为什么我们这里需要挂载/sys和ramfs在/dev目录上,事实上,这种方法最早就是为热插拔设计的,你可以理解为当系统启动时,所有设备一下子全部"插入"了进来。
这里有一点要说明的是,在文件系统初始化跑到这里之前,原来的/dev目录下必须有一个设备节点:/dev/console。
其实,要搞清楚"程序"这种东西,没有什么好的办法,无非2个东西,源码和脚本
echo /sbin/mdev > /proc/sys/kernel/hotplug 
#热插拔 把/sbin/mdev写到/proc/sys/kernel/hotplug,内核会读取里面的内容,当有热插拔时间时,会调用这个函数
/sbin/mdev -s 
/bin/hotplug 
##这几个就是用来完成上面所说的两个东西:1)通过mdev -s在/dev目录下创建必要的设备节点;2)设置内核的hotplug handler 为mdev,即当设备热插拔时,由mdev接受来自内核的消息并作出相应的回应,比如挂载U盘。
mkdir -p /dev/pts 
mkdir -p /dev/shm
/bin/mount -n -t devpts none /dev/pts -o mode=0622
/bin/mount -n -t tmpfs tmpfs /dev/shm 
#作用可以了解目前虚拟终端(telent,ssh等)的基本情况

mkdir -p /var/empty
mkdir -p /var/log 
mkdir -p /var/log/boa 
mkdir -p /var/lock 
mkdir -p /var/run 
mkdir -p /var/tmp 

/etc/rc.d/init.d/netd start  
#启动网卡

/sbin/ifconfig lo 127.0.0.1

/etc/init.d/ifconfig-eth0
#对网卡进行配置

2、profile

USER="`id -un`"
LOGNAME=$USER 

PS1='[$USER@$HOSTNAME]# '
#终端前面的提示符
HOSTNAME=`/bin/hostname`

PATH=$PATH 


export USER LOGNAME PS1 PATH 


3、password(可以直接copy虚拟机上的root用户)

root::0:0:root:/:/bin/sh   
bin:*:1:1:bin:/bin:
daemon:*:2:2:daemon:/sbin:
nobody:*:99:99:Nobody:/:
~                            

4、eth0-setting

IP=192.168.12.166
Mask=255.255.255.0
Geteway=192.168.1.1
DNS=192.168.1.1
MAC=08:90:90:90:90:90

5、/etc/rc.d/init.d/netd

#! /bin/sh 
base=inetd

case "$1" in 
	start)
		/usr/sbin/$base 
		;;
	stop)
		pid='/bin/pidof %base'
		if [ -n "$pid" ]; then 
			kill -9 $pid 
		fi 
		;;
esac

6、/etc/init.d/ifconfig-eth0

#!/bin/sh

source /etc/eth0-setting

ifconfig eth0 down
ifconfig eth0 hw ether $MAC
ifconfig eth0 $IP netmask $Mask up
route add default gw $Geteway

echo eth0 interface done > /dev/ttySAC2


七、生成ext4文件格式镜像 并烧写至EMMC


执行以下命令

make_ext4fs -s -l 314572800 -a root -L Linux system.img system

在这里插入图片描述

使用fastboot烧写至emmc

结果出错了!!

Kernel panic – not syncing: Requested init /linuxrc failed (error -13)

错误在这里定义:在Linux源码目录/include/uapi/asm-generic的errno-base.h中

#define EPERM 1 /* Operation not permitted */
#define ENOENT 2 /* No such file or directory */
#define ESRCH 3 /* No such process */
#define EINTR 4 /* Interrupted system call */
#define EIO 5 /* I/O error */
#define ENXIO 6 /* No such device or address */
#define E2BIG 7 /* Argument list too long */
#define ENOEXEC 8 /* Exec format error */
#define EBADF 9 /* Bad file number */
#define ECHILD 10 /* No child processes */
#define EAGAIN 11 /* Try again */
#define ENOMEM 12 /* Out of memory */
#define EACCES 13 /* Permission denied */
#define EFAULT 14 /* Bad address */
#define ENOTBLK 15 /* Block device required */
#define EBUSY 16 /* Device or resource busy */
#define EEXIST 17 /* File exists */
#define EXDEV 18 /* Cross-device link */
#define ENODEV 19 /* No such device */
#define ENOTDIR 20 /* Not a directory */
#define EISDIR 21 /* Is a directory */
#define EINVAL 22 /* Invalid argument */
#define ENFILE 23 /* File table overflow */
#define EMFILE 24 /* Too many open files */
#define ENOTTY 25 /* Not a typewriter */
#define ETXTBSY 26 /* Text file busy */
#define EFBIG 27 /* File too large */
#define ENOSPC 28 /* No space left on device */
#define ESPIPE 29 /* Illegal seek */
#define EROFS 30 /* Read-only file system */
#define EMLINK 31 /* Too many links */
#define EPIPE 32 /* Broken pipe */
#define EDOM 33 /* Math argument out of domain of func */
#define ERANGE 34 /* Math result not representable */

原因是显示没有权限

有一个问题是,使用这样制作的镜像,system分区文件的权限都是预定的,即使先修改system目录文件权限后在制作镜像,烧入设备后,其权限仍未改变。关键问题在make_ext4fs工具,在制作ext4fs时更改了权限,其依据为system/core/private/android_ilesystem_config.h所定义的权限。

“-a system”,是指这个img用于android系统,挂载点是/system,使用这个参数,make_ext4fs会根据private/android_filesystem_config.h里定义好的权限来给文件夹里的所有文件重新设置权限,如果你刷机以后发现有文件权限不对,可以手工修改android_filesystem_config.h来添加权限,重新编译make_ext4fs,也可以不使用 “-a system”参数,这样就会使用文件的默认权限。

去掉-a选项即可

重新制作system.img

make_ext4fs -s -l 314572800 -L Linux system.img system

烧写、启动 ——-成功!

为了这个根文件系统来回烧写了好多次,实在是麻烦,因而使用一种更加方便高效的方式使用nfs挂载根文件系统


八、使用NFS服务挂载根文件系统


1、准备工作

在主机上安装并配置NFS服务

apt-get install nfs-kernel-server

配置nfs服务 进入/etc/exports

在这里插入图片描述


其中/home/nfs/system放的是最小文件系统不是img镜像,我当时挂载时挂载成了system.img,然后死活挂载不上

[    7.413837] VFS: Mounted root (nfs filesystem) on device 0:16.
[    7.421726] devtmpfs: error mounting -2
[    7.426034] Freeing unused kernel memory: 1024K
[    7.460197] Run /linuxrc as init process
[    7.467259] Kernel panic - not syncing: Requested init /linuxrc failed (error -2).
[    7.883171] ---[ end Kernel panic - not syncing: Requested init /linuxrc failed (error -2). ]---

#define ENOENT 2 /* No such file or directory */


启动nfs服务

/etc/init.d/nfs-kernel-server start

2、修改uboot的bootargs参数

Setenv bootargs ‘root=/dev/nfs rw nfsroot=192.168.12.144:/home/nfs/system,proto=tcp ip=192.168.12.166:192.168.12.144::255.255.255.0:itop:eth0:off init=/linuxrc console=ttySAC2,115200’

设置为以nfs方式启动

参数详解

root=/dev/nfs nfsroot=server-ip:root-dir,nfs-options ip=client-ip:server-ip:gwip:netmask:hostname:device:autoconf:dns0-ip:dns1-ip
server-ip:服务器 IP 地址,也就是存放根文件系统主机的 IP 地址,那就是 Ubuntu 的 IP
地址,比如我的 Ubuntu 主机 IP 地址为 192.168.12.144
root-dir: 根文件系统的存放路径,比如我的就是/home/nfs/system。
nfs-options: NFS 的其他可选选项 例如proto=tcp,使用tcp传输
client-ip: 客户端 IP 地址,也就是我们开发板的 IP 地址, Linux 内核启动以后就会使用
此 IP 地址来配置开发板。此地址一定要和 Ubuntu 主机在同一个网段内,并且没有被其他的设
备使用,在 Ubuntu 中使用 ping 命令 ping 一下就知道要设置的 IP 地址有没有被使用,如果不能
ping 通就说明没有被使用,那么就可以设置为开发板的 IP 地址,比如我就可以设置为
192.168.12.166。
server-ip: 服务器 IP 地址,即ubuntu的IP地址。
gw-ip: 网关地址,我的就是 192.168.1.1。
netmask:子网掩码,我的就是 255.255.255.0。
hostname:客户机的名字,一般不设置,此值可以空着,但是“:”不能少。
device: 设备名,也就是网卡名,一般是 eth0, eth1….
autoconf: 自动配置,一般不使用,所以设置为 off。
dns0-ip: DNS0 服务器 IP 地址,不使用。
dns1-ip: DNS1 服务器 IP 地址,不使用。

3、修改最小根文件系统/home/nfs/system/etc/init.d/rcS

在这里插入图片描述

因为我们已经在bootargs中设置了IP 这几个脚本是用来设置网卡信息的,会重启网卡那样nfs便会断开无法进入根文件系统


如果出现挂载不上的话,首先看看客户机有没有启动nfs服务,然后检查参数是否正确

极大可能是参数问题


在这里插入图片描述



版权声明:本文为weixin_43937576原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。