① 在linux下如何创建设备文件!!!
两种 方法:
一种是mknod手动创建,另一种是调用内核函数自动创建。
② 列举linux系统的4种文件类型及其属性符号
一. 文件类型
Linux文件类型常见的有:普通文件、目录文件、字符设备文件和块设备文件、符号链接文件等,现在我们进行一个简要的说明。
1. 普通文件
我们用 ls -lh 来查看某个文件的属性,可以看到有类似-rwxrwxrwx,值得注意的是第一个符号是 - ,这样的文件在Linux中就是普通文件。这些文件一般是用一些相关的应用程序创建,比如图像工具、文档工具、归档工具... .... 或 cp工具等。这类文件的删除方式是用rm 命令。 另外,依照文件的内容,又大略可以分为:
1>. 纯文本档(ASCII):
这是Linux系统中最多的一种文件类型,称为纯文本档是因为内容为我们人类可以直接读到的数据,例如数字、字母等等。 几乎只要我们可以用来做为设定的文件都属于这一种文件类型。 举例来说,你可以用命令: cat ~/.bashrc 来看到该文件的内容。 (cat 是将一个文件内容读出来的指令).
2>. 二进制文件(binary):
Linux系统其实仅认识且可以执行二进制文件(binary file)。Linux当中的可执行文件(scripts, 文字型批处理文件不算)就是这种格式的文件。 刚刚使用的命令cat就是一个binary file。
3>. 数据格式文件(data):
有些程序在运作的过程当中会读取某些特定格式的文件,那些特定格式的文件可以被称为数据文件 (data file)。举例来说,我们的Linux在使用者登录时,都会将登录的数据记录在 /var/log/wtmp那个文件内,该文件是一个data file,他能够透过last这个指令读出来! 但是使用cat时,会读出乱码~因为他是属于一种特殊格式的文件?
2. 目录文件
当我们在某个目录下执行,看到有类似 drwxr-xr-x ,这样的文件就是目录,目录在Linux是一个比较特殊的文件。注意它的第一个字符是d。创建目录的命令可以用 mkdir 命令,或cp命令,cp可以把一个目录复制为另一个目录。删除用rm 或rmdir命令。
3. 字符设备或块设备文件
如时您进入/dev目录,列一下文件,会看到类似如下的:
复制代码
代码如下:
[root@localhost ~]# ls -al /dev/tty</p> <p>crw-rw-rw- 1 root tty 5, 0 11-03 15:11 /dev/tty</p> <p>[root@localhost ~]# ls -la /dev/sda1</p> <p>brw-r----- 1 root disk 8, 1 11-03 07:11 /dev/sda1
我们看到/dev/tty的属性是 crw-rw-rw- ,注意前面第一个字符是 c ,这表示字符设备文件。比如猫等串口设备。我们看到 /dev/sda1 的属性是 brw-r----- ,注意前面的第一个字符是b,这表示块设备,比如硬盘,光驱等设备。
这个种类的文件,是用mknode来创建,用rm来删除。目前在最新的Linux发行版本中,我们一般不用自己来创建设备文件。因为这些文件是和内核相关联的。
与系统周边及储存等相关的一些文件, 通常都集中在/dev这个目录之下!通常又分为两种:
区块(block)设备档 :
就是一些储存数据, 以提供系统随机存取的接口设备,举例来说,硬盘与软盘等就是啦! 你可以随机的在硬盘的不同区块读写,这种装置就是成组设备!你可以自行查一下/dev/sda看看, 会发现第一个属性为[ b ]!
字符(character)设备文件:
亦即是一些串行端口的接口设备, 例如键盘、鼠标等等!这些设备的特色就是一次性读取的,不能够截断输出。 举例来说,你不可能让鼠标跳到另一个画面,而是滑动到另一个地方!第一个属性为 [ c ]。
4. 数据接口文件(sockets):
数据接口文件(或者:套接口文件),这种类型的文件通常被用在网络上的数据承接了。我们可以启动一个程序来监听客户端的要求, 而客户端就可以透过这个socket来进行数据的沟通了。第一个属性为 [ s ], 最常在/var/run这个目录中看到这种文件类型了。
例如:当我们启动MySQL服务器时,会产生一个mysql.sock的文件。
复制代码
代码如下:
[root@localhost ~]# ls -lh /var/lib/mysql/mysql.sock </p> <p>srwxrwxrwx 1 mysql mysql 0 04-19 11:12 /var/lib/mysql/mysql.sock
注意这个文件的属性的第一个字符是 s。
5. 符号链接文件:
当我们查看文件属性时,会看到有类似 lrwxrwxrwx,注意第一个字符是l,这类文件是链接文件。是通过ln -s 源文件名 新文件名 。上面是一个例子,表示setup.log是install.log的软链接文件。怎么理解呢?这和Windows操作系统中的快捷方式有点相似。
符号链接文件的创建方法举例:
复制代码
代码如下:
[root@localhost test]# ls -lh log2012.log</p> <p>-rw-r--r-- 1 root root 296K 11-13 06:03 log2012.log</p> <p>[root@localhost test]# ln -s log2012.log linklog.log</p> <p>[root@localhost test]# ls -lh *.log</p> <p>lrwxrwxrwx 1 root root 11 11-22 06:58 linklog.log -> log2012.log</p> <p>-rw-r--r-- 1 root root 296K 11-13 06:03 log2012.log
6. 数据输送文件(FIFO,pipe):
FIFO也是一种特殊的文件类型,他主要的目的在解决多个程序同时存取一个文件所造成的错误问题。 FIFO是first-in-first-out的缩写。第一个属性为[p] 。
③ linux自动创建设备文件时:
我想应该是从设备的名字来区分是字符还是块设备,因为设备驱动本身是个子系统,然后,在建立设备文件与设备驱动关联的时候,也就是自动创建设备文件的时候,class_create和devicec_create会根据你建立的设备名索引到你的设备驱动,因此,它们就知道该为你创建的是字符设备文件还是块设备文件了。
这仅仅是个人猜测而已,因为字符设备文件和块设备文件的创建都是使用这两个函数,而从表面的调用来看是分不出是字符还是块的。那唯一能关联起来的就是设备名了,而这两个函数能跟设备名关联起来的也就是类名了。
④ 1)Linux2.6内核下,在编写字符设备驱动程序时,设备文件节点的创建有几种方法,分别是什么
1手动mknod
2 自动调用函数
⑤ Linux上如何创建裸设备
1.创建
pv
pvcreate -M2 --metadatasize 100M /dev/sda
pvcreate -M2 --metadatasize 100M /dev/sdb1
pvcreate -M2 --metadatasize 100M /dev/sdb2
pvcreate -M2 --metadatasize 100M /dev/sdc
物理卷可以是整个硬盘(
lun
),也可以是硬盘上的一个分区
2.创建
vg
vgcreate vg_db /dev/sda /dev/sdb1 /dev/sdb2 /dev/sdc -s128m
3.创建
lv
lvcreate -L2048m -i4 -I64k vg_db -n lv_2g_001
lvcreate -L2048m -i4 -I64k vg_db -n lv_2g_002
4.绑定
raw /dev/raw/raw1 /dev/mapper/vg_db-lv_2g_001
raw /dev/raw/raw2 /dev/mapper/vg_db-lv_2g_002
使用
raw
命令绑定的裸设备在重启后会失效。所以需要修改
/etc/sysconfig/rawdevices
配置文件,在文件中加入如下内容(每个裸设备一
行):
/dev/raw/raw1 /dev/mapper/vg_db-lv_2g_001
/dev/raw/raw2 /dev/mapper/vg_db-lv_2g_002
执行
/etc/init.d/rawdevices restart
使配置文件中的裸设备生效
执行
/sbin/chkconfig rawdevices on
保证机器启动的时候裸设备能够加载
5.授权
chown -R oracle.dba /dev/mapper
修改配置文件
/etc/udev/permissions.d/50-udev.permissions
注释掉
raw/*:root:disk:0660
添加新行
raw/*:oracle:dba:0660
6.链
(可选)
ln -s /dev/raw/raw1 /oradata/ningoo/system01.dbf
ln -s /dev/raw/raw2 /oradata/ningoo/undo01.dbf
⑥ 如何编写Linux 驱动程序
如何编写Linux设备驱动程序
回想学习Linux操作系统已经有近一年的时间了,前前后后,零零碎碎的一路学习过来,也该试着写的东西了。也算是给自己能留下一点记忆和回忆吧!由于完全是自学的,以下内容若有不当之处,还请大家多指教。
Linux是Unix操作系统的一种变种,在Linux下编写驱动程序的原理和思想完全类似于其他的Unix系统,但它dos或window环境下的驱动程序有很大的区别。在Linux环境下设计驱动程序,思想简洁,操作方便,功能也很强大,但是支持函数少,只能依赖kernel中的函数,有些常用的操作要自己来编写,而且调试也不方便。
以下的一些文字主要来源于khg,johnsonm的Write linux device driver,Brennan's Guide to Inline Assembly,The Linux A-Z,还有清华BBS上的有关device driver的一些资料。
一、Linux device driver 的概念
系统调用是操作系统内核和应用程序之间的接口,设备驱动程序是操作系统内核和机器硬件之间的接口。设备驱动程序为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件,应用程序可以象操作普通文件一样对硬件设备进行操作。设备驱动程序是内核的一部分,它完成以下的功能:
1、对设备初始化和释放。
2、把数据从内核传送到硬件和从硬件读取数据。
3、读取应用程序传送给设备文件的数据和回送应用程序请求的数据。
4、检测和处理设备出现的错误。
在Linux操作系统下有三类主要的设备文件类型,一是字符设备,二是块设备,三是网络设备。字符设备和块设备的主要区别是:在对字符设备发出读/写请求时,实际的硬件I/O一般就紧接着发生了,块设备则不然,它利用一块系统内存作缓冲区,当用户进程对设备请求能满足用户的要求,就返回请求的数据,如果不能,就调用请求函数来进行实际的I/O操作。块设备是主要针对磁盘等慢速设备设计的,以免耗费过多的CPU时间来等待。
已经提到,用户进程是通过设备文件来与实际的硬件打交道。每个设备文件都都有其文件属性(c/b),表示是字符设备还是块设备?另外每个文件都有两个设备号,第一个是主设备号,标识驱动程序,第二个是从设备号,标识使用同一个设备驱动程序的不同的硬件设备,比如有两个软盘,就可以用从设备号来区分他们。设备文件的的主设备号必须与设备驱动程序在登记时申请的主设备号一致,否则用户进程将无法访问到驱动程序。
最后必须提到的是,在用户进程调用驱动程序时,系统进入核心态,这时不再是抢先式调度。也就是说,系统必须在你的驱动程序的子函数返回后才能进行其他的工作。如果你的驱动程序陷入死循环,不幸的是你只有重新启动机器了,然后就是漫长的fsck。
读/写时,它首先察看缓冲区的内容,如果缓冲区的数据未被处理,则先处理其中的内容。
如何编写Linux操作系统下的设备驱动程序
二、实例剖析
我们来写一个最简单的字符设备驱动程序。虽然它什么也不做,但是通过它可以了解Linux的设备驱动程序的工作原理。把下面的C代码输入机器,你就会获得一个真正的设备驱动程序。
#define __NO_VERSION__
#include <linux/moles.h>
#include <linux/version.h>
char kernel_version [] = UTS_RELEASE;
这一段定义了一些版本信息,虽然用处不是很大,但也必不可少。Johnsonm说所有的驱动程序的开头都要包含<linux/config.h>,一般来讲最好使用。
由于用户进程是通过设备文件同硬件打交道,对设备文件的操作方式不外乎就是一些系统调用,如 open,read,write,close…, 注意,不是fopen, fread,但是如何把系统调用和驱动程序关联起来呢?这需要了解一个非常关键的数据结构:
struct file_operations
{
int (*seek) (struct inode * ,struct file *, off_t ,int);
int (*read) (struct inode * ,struct file *, char ,int);
int (*write) (struct inode * ,struct file *, off_t ,int);
int (*readdir) (struct inode * ,struct file *, struct dirent * ,int);
int (*select) (struct inode * ,struct file *, int ,select_table *);
int (*ioctl) (struct inode * ,struct file *, unsined int ,unsigned long);
int (*mmap) (struct inode * ,struct file *, struct vm_area_struct *);
int (*open) (struct inode * ,struct file *);
int (*release) (struct inode * ,struct file *);
int (*fsync) (struct inode * ,struct file *);
int (*fasync) (struct inode * ,struct file *,int);
int (*check_media_change) (struct inode * ,struct file *);
int (*revalidate) (dev_t dev);
}
这个结构的每一个成员的名字都对应着一个系统调用。用户进程利用系统调用在对设备文件进行诸如read/write操作时,系统调用通过设备文件的主设备号找到相应的设备驱动程序,然后读取这个数据结构相应的函数指针,接着把控制权交给该函数。这是linux的设备驱动程序工作的基本原理。既然是这样,则编写设备驱动程序的主要工作就是编写子函数,并填充file_operations的各个域。
下面就开始写子程序。
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include<linux/config.h>
#include <linux/errno.h>
#include <asm/segment.h>
unsigned int test_major = 0;
static int read_test(struct inode *node,struct file *file,char *buf,int count)
{
int left;
if (verify_area(VERIFY_WRITE,buf,count) == -EFAULT )
return -EFAULT;
for(left = count ; left > 0 ; left--)
{
__put_user(1,buf,1);
buf++;
}
return count;
}
这个函数是为read调用准备的。当调用read时,read_test()被调用,它把用户的缓冲区全部写1。buf 是read调用的一个参数。它是用户进程空间的一个地址。但是在read_test被调用时,系统进入核心态。所以不能使用buf这个地址,必须用__put_user(),这是kernel提供的一个函数,用于向用户传送数据。另外还有很多类似功能的函数。请参考Robert着的《Linux内核设计与实现》(第二版)。然而,在向用户空间拷贝数据之前,必须验证buf是否可用。这就用到函数verify_area。
static int write_tibet(struct inode *inode,struct file *file,const char *buf,int count)
{
return count;
}
static int open_tibet(struct inode *inode,struct file *file )
{
MOD_INC_USE_COUNT;
return 0;
}
static void release_tibet(struct inode *inode,struct file *file )
{
MOD_DEC_USE_COUNT;
}
这几个函数都是空操作。实际调用发生时什么也不做,他们仅仅为下面的结构提供函数指针。
struct file_operations test_fops = {
NULL,
read_test,
write_test,
NULL, /* test_readdir */
NULL,
NULL, /* test_ioctl */
NULL, /* test_mmap */
open_test,
release_test,
NULL, /* test_fsync */
NULL, /* test_fasync */
/* nothing more, fill with NULLs */
};
这样,设备驱动程序的主体可以说是写好了。现在要把驱动程序嵌入内核。驱动程序可以按照两种方式编译。一种是编译进kernel,另一种是编译成模块(moles),如果编译进内核的话,会增加内核的大小,还要改动内核的源文件,而且不能动态的卸载,不利于调试,所以推荐使用模块方式。
int init_mole(void)
{
int result;
result = register_chrdev(0, "test", &test_fops);
if (result < 0) {
printk(KERN_INFO "test: can't get major number\n");
return result;
}
if (test_major == 0) test_major = result; /* dynamic */
return 0;
}
在用insmod命令将编译好的模块调入内存时,init_mole 函数被调用。在这里,init_mole只做了一件事,就是向系统的字符设备表登记了一个字符设备。register_chrdev需要三个参数,参数一是希望获得的设备号,如果是零的话,系统将选择一个没有被占用的设备号返回。参数二是设备文件名,参数三用来登记驱动程序实际执行操作的函数的指针。
如果登记成功,返回设备的主设备号,不成功,返回一个负值。
void cleanup_mole(void)
{
unregister_chrdev(test_major,"test");
}
在用rmmod卸载模块时,cleanup_mole函数被调用,它释放字符设备test在系统字符设备表中占有的表项。
一个极其简单的字符设备可以说写好了,文件名就叫test.c吧。
下面编译 :
$ gcc -O2 -DMODULE -D__KERNEL__ -c test.c
得到文件test.o就是一个设备驱动程序。
如果设备驱动程序有多个文件,把每个文件按上面的命令行编译,然后
ld -r file1.o file2.o -o molename。
驱动程序已经编译好了,现在把它安装到系统中去。
$ insmod –f test.o
如果安装成功,在/proc/devices文件中就可以看到设备test,并可以看到它的主设备号。要卸载的话,运行 :
$ rmmod test
下一步要创建设备文件。
mknod /dev/test c major minor
c 是指字符设备,major是主设备号,就是在/proc/devices里看到的。
用shell命令
$ cat /proc/devices
就可以获得主设备号,可以把上面的命令行加入你的shell script中去。
minor是从设备号,设置成0就可以了。
我们现在可以通过设备文件来访问我们的驱动程序。写一个小小的测试程序。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
main()
{
int testdev;
int i;
char buf[10];
testdev = open("/dev/test",O_RDWR);
if ( testdev == -1 )
{
printf("Cann't open file \n");
exit(0);
}
read(testdev,buf,10);
for (i = 0; i < 10;i++)
printf("%d\n",buf[i]);
close(testdev);
}
编译运行,看看是不是打印出全1 ?
以上只是一个简单的演示。真正实用的驱动程序要复杂的多,要处理如中断,DMA,I/O port等问题。这些才是真正的难点。请看下节,实际情况的处理。
如何编写Linux操作系统下的设备驱动程序
三、设备驱动程序中的一些具体问题
1。 I/O Port。
和硬件打交道离不开I/O Port,老的ISA设备经常是占用实际的I/O端口,在linux下,操作系统没有对I/O口屏蔽,也就是说,任何驱动程序都可对任意的I/O口操作,这样就很容易引起混乱。每个驱动程序应该自己避免误用端口。
有两个重要的kernel函数可以保证驱动程序做到这一点。
1)check_region(int io_port, int off_set)
这个函数察看系统的I/O表,看是否有别的驱动程序占用某一段I/O口。
参数1:I/O端口的基地址,
参数2:I/O端口占用的范围。
返回值:0 没有占用, 非0,已经被占用。
2)request_region(int io_port, int off_set,char *devname)
如果这段I/O端口没有被占用,在我们的驱动程序中就可以使用它。在使用之前,必须向系统登记,以防止被其他程序占用。登记后,在/proc/ioports文件中可以看到你登记的I/O口。
参数1:io端口的基地址。
参数2:io端口占用的范围。
参数3:使用这段io地址的设备名。
在对I/O口登记后,就可以放心地用inb(), outb()之类的函来访问了。
在一些pci设备中,I/O端口被映射到一段内存中去,要访问这些端口就相当于访问一段内存。经常性的,我们要获得一块内存的物理地址。
2。内存操作
在设备驱动程序中动态开辟内存,不是用malloc,而是kmalloc,或者用get_free_pages直接申请页。释放内存用的是kfree,或free_pages。 请注意,kmalloc等函数返回的是物理地址!
注意,kmalloc最大只能开辟128k-16,16个字节是被页描述符结构占用了。
内存映射的I/O口,寄存器或者是硬件设备的RAM(如显存)一般占用F0000000以上的地址空间。在驱动程序中不能直接访问,要通过kernel函数vremap获得重新映射以后的地址。
另外,很多硬件需要一块比较大的连续内存用作DMA传送。这块程序需要一直驻留在内存,不能被交换到文件中去。但是kmalloc最多只能开辟128k的内存。
这可以通过牺牲一些系统内存的方法来解决。
3。中断处理
同处理I/O端口一样,要使用一个中断,必须先向系统登记。
int request_irq(unsigned int irq ,void(*handle)(int,void *,struct pt_regs *),
unsigned int long flags, const char *device);
irq: 是要申请的中断。
handle:中断处理函数指针。
flags:SA_INTERRUPT 请求一个快速中断,0 正常中断。
device:设备名。
如果登记成功,返回0,这时在/proc/interrupts文件中可以看你请求的中断。
4。一些常见的问题。
对硬件操作,有时时序很重要(关于时序的具体问题就要参考具体的设备芯片手册啦!比如网卡芯片RTL8139)。但是如果用C语言写一些低级的硬件操作的话,gcc往往会对你的程序进行优化,这样时序会发生错误。如果用汇编写呢,gcc同样会对汇编代码进行优化,除非用volatile关键字修饰。最保险的办法是禁止优化。这当然只能对一部分你自己编写的代码。如果对所有的代码都不优化,你会发现驱动程序根本无法装载。这是因为在编译驱动程序时要用到gcc的一些扩展特性,而这些扩展特性必须在加了优化选项之后才能体现出来。
写在后面:学习Linux确实不是一件容易的事情,因为要付出很多精力,也必须具备很好的C语言基础;但是,学习Linux也是一件非常有趣的事情,它里面包含了许多高手的智慧和“幽默”,这些都需要自己亲自动手才能体会到,O(∩_∩)O~哈哈!
⑦ Linux下如何创建loop device
因为这种设备的存在,就为我们提供了一种创建一个存在于其他文件中的虚拟文件系统的机制.如果我们在使用一种集群需要使用其他盘符而没有新设备的时候可以采取这种方式,在虚拟机下需要设备的时候也可以采取这种方式: 第一步:用dd命令创建一个文件,文件大小即为你的新设备的大小 dd if=/dev/zero of=sd1 bs=4M count=1000 这样就创建了一个大小为4G的文件sd1 第二步:使用losetup命令创建一个loop 设备 losetup /dev/loop0 sd1 第三步:创建一个文件系统 mkfs.ext3 /dev/loop0 最后:如果要删除刚才创建的这些对象 losetup -d /dev/loop0rm sd1默认情况下linux支持的loop设备是8个 如果需要超过8个loop device,那么使用losetup命令的时候可能会遇到类似的错误 'no such device',这是因为超过了可用loop device设备的最大限制,依据你的Linux系统,可以通过修改 /etc/modprobe.conf 配置文件,增加如下参数的方式进行扩展 options loop max_loop=20 --比如我增加到20个 保存退出,如果要了马上生效的话,可以通过 modprobe -v loop 命令立即加载该模块。
⑧ linux驱动中怎么创建led0,led1,led2设备文件
直接调用linux读写寄存器的API就可以拉,led就是控制GPIO阿,很简单的,内核里面有led的驱动实例程序
⑨ 写linux驱动的请帮我看看,我这个程序怎么创建不了设备文件
参考答案 智者不惑,仁者不忧,勇者不惧。--孔子
⑩ Linux一切皆文件
Linux 中所有内容都是以文件的形式保存和管理的,即一切皆文件,普通文件是文件,目录(Windows称为文件夹)是文件,硬件设备(键盘、监视器、硬盘、打印机)是文件,就连套接字(socket)、网络通讯等资源也都是文件。
Linux系统中的文件类型
类似于 mp4、pdf、HTML、这样可以直接拿来使用的文件属于普通文件,Linux用户根据访问权限的不同可以对这些文件进行查看、删除以及更改操作。
对于用惯Windows系统的用户来说,目录是文件可能不太好理解
Linux系统中,目录文件包含了此目录中各个文件的文件名以及指向这些文件的指针,打开目录等同于目录文件,只要你有权限,可以随意访问目录中的任何文件。
注意:目录文件的访问权限,同普通文件的执行权限是一个意思。
这些文件隐藏在/dev/目录下,当进行设备读取或外设交互时才会被使用。
例如,磁盘光驱属于块设备文件,串口设备则属于字符设备文件
Linux系统中的所有设备,要么是块设备文件,要么是字符设备文件
套接字文件一般隐藏在/var/run/目录下,用于进程间的网络通信。
类似于Windows中的快捷方式,是指向另一文件的简介指针(也就是软链接)。
主要用于进程间的通讯。例如,使用mkfifo命令创建一个FIFO文件,与此同时,启用进程A从FIFO文件读取数据,启用B从FIFO文件中写数据,随写随读。
一切皆是文件的利弊
和Windows不同的是,Linux没有C盘、D盘E盘那么多的盘符,只有一个根目录(/),所有文件资源所有的文件资源都存储在以根目录(/)为树根的树形目录结构中。
这样最明显的好处就是开发者仅需要使用一套API和开发工具即可调取Linux系统中绝大部分资源。举个简单的例子,Linux中几乎所有读(读文件、读系统状态、读socket,读PIPE)的操作都可以用read函数来进行;几乎所有更改,(更改文件、更改系统参数,写socket,写PIPE)的操作都可以用write函数来进行。
不利之处在于,使用任何硬件设备都必须与根目录下某一目录执行挂载操作,否则无法使用。我们知道,本身Linux具有一个以根目录为树根的文件目录结构,每个设备也同样如此,他们是相互独立的。如果我们想通过Linux上的根目录找到设备文件的目录结构,就必须将这两个文件系统目录合二为一,这就是挂载的真正含义。