操作系统课程设计.docx
《操作系统课程设计.docx》由会员分享,可在线阅读,更多相关《操作系统课程设计.docx(21页珍藏版)》请在冰豆网上搜索。
操作系统课程设计
东北大学秦皇岛分校
计算机与通信工程学院
操作系统课程设计
设计题目Linux中的虚拟文件系统的分析
专业名称
计算机科学与技术
班级学号
学生姓名
黎楠
指导教师
王翠荣
设计时间
2018年01月01日—2018年01月12日
课程设计任务书
专业:
计算机科学与技术学号:
学生姓名(签名):
设计题目:
Linux中的虚拟文件系统的分析与进程管理器
一、设计实验条件
综合楼1208、1210实验室
二、设计任务及要求
1.Linux中的虚拟文件系统的分析;
2.进程管理器;
三、设计报告的内容
1.设计题目与设计任务(设计任务书)
题目一:
Linux中的虚拟文件系统的分析
要求:
虚拟文件系统(VFS)是物理文件系统与服务之间的一个接口层。
试说明它与物理文件系统有何关系,以及VFS超级块地实现方法;
题目二:
进程管理器
要求:
在Linux或Windows系统环境下,实现一个系统进程管理器,能够显示当前系统的活动进程信息(进程名、用户、优先级、内存使用等),并能结束或创建特定进程。
可参考Windows下“任务管理器”功能。
2.前言(绪论)(设计的目的、意义等)
任何一个操作系统都是基于文件系统之上的,在Linux操作系统中下的文件系统主要可分为三大块:
一是上层的文件系统的系统调用,二是虚拟文件系统VFS(VirtualFilesystemSwitch),三是挂载到VFS中的各实际文件系统,例如ext2,jffs等。
VFS处于文件系统的使用者与具体的文件系统之间,将两者隔离开来。
这种引入一个抽象层次的设计思想,即“上层不依赖于具体实现,而依赖于接口;下层不依赖于具体实现,而依赖于接口”,就是著名的“依赖反转”,它在Linux内核中随处可见。
所以对VFS与物理文件系统之间关系的分析以及VFS超级块的实现方法显得格外重要。
而正是因为虚拟文件系统的存在,跨文件系统的文件操作才能得以实现。
对虚拟文件系统的分析将有助于我们对Linux文件系统的学习,同时对深入理解Linux操作系统有很大帮助。
3.设计主体(各部分设计内容、分析、结论等)
3.1.Linux中的虚拟文件系统的分析
【题目分析】
虚拟文件系统(VirtualFileSystem,简称VFS),是Linux内核中的一个软件层,用于给用户空间的程序提供文件系统接口;同时,它也提供了内核中的一个抽象功能,允许不同的文件系统共存。
系统中所有的文件系统不但依赖VFS共存,而且也依靠VFS协同工作。
VFS支持的文件系统可以分为3种类型:
基于磁盘的文件系统、网络文件系统、特殊文件系统(虚拟文件系统)。
为了能够支持各种实际文件系统,VFS定义了所有文件系统都支持的基本的、概念上的接口和数据结构;同时实际文件系统也提供VFS所期望的抽象接口和数据结构,将自身的诸如文件、目录等概念在形式上与VFS的定义保持一致。
换句话说,一个实际的文件系统想要被Linux支持,就必须提供一个符合VFS标准的接口,才能与VFS协同工作。
实际文件系统在统一的接口和数据结构下隐藏了具体的实现细节,所以在VFS层和内核的其他部分看来,所有文件系统都是相同的。
图1VFS在内核中与其他的内核模块的协同关系
【VFS与物理文件系统的关系】
Linux的VFS位于Linux整个文件系统的最上层,是一种软件机制,提供文件系统对用户命令、系统调用及内核其他模块的统一接口,负责管理并控制下层的逻辑文件系统,使它们按照各自特定的模式正常运转,同时能够对用户提供尽可能相同的表现形式。
VFS是物理文件系统与服务之间的一个接口层,它对Linux的每个文件系统的所有细节进行抽象,使得不同的文件系统在Linux核心以及系统中运行的进程看来都是相同的。
严格的说,VFS并不是一种实际的文件系统。
它只存在于内存中,并没有真正存在于磁盘分区中,磁盘分区存放的是逻辑文件系统的内容,所有VFS的数据结构都是在系统启动之后才建立完成,并在系统关闭时撤销。
同时,它必须和其他实际存在于磁盘的文件系统,比如Linux默认的ext2或者WindowsNT的NTFS等逻辑文件系统一起,才能构成一个完整的文件系统。
VFS对逻辑文件系统进行抽象,采用统一的数据结构在内存中描述所有这些文件系统,接受用户层的系统调用和核心层其他模块的访问,通过VFS操作函数,按照一定的映射关系,把这些访问重新定向到逻辑文件系统中相应的函数调用,然后由逻辑文件系统来完成真正的具体操作。
这样,VFS只负责处理设备无关的操作,主要是进行具体操作的映射关系。
正是VFS的这种抽象的功能层次,保证了Linux系统可以支持多种不同的逻辑文件系统,所有文件系统都具有基本相同的外部表现,而且可以方便地进行相互访问。
针对下层的逻辑文件系统,Linux系统中的VFS为它们提供一致的接口,统一管理各种逻辑文件系统,包括进行文件系统的注册和注销、安装和卸载等,提供限额机制,对用户存储空间进行有效的控制。
对文件操作进行适当的转换,转交由具体的逻辑文件系统进行处理,然后把具体的操作结果提供给上层的调用者。
针对上层,VFS为用户层函数调用和内核其他模块的访问提供接口,接受访问并返回由具体逻辑文件系统完成的结果。
此外,VFS还负责管理文件系统的各种缓冲区,保证文件系统的整体效率。
从本质上讲,文件系统是特殊的数据分层存储结构,它包含文件、目录和相关的控制信息。
为了描述这个结构,Linux引入了一些基本概念:
文件一组在逻辑上具有完整意义的信息项的系列。
在Linux中,除了普通文件,其他诸如目录、设备、套接字等也以文件被对待。
总之,“一切皆文件”。
目录目录好比一个文件夹,用来容纳相关文件。
因为目录可以包含子目录,所以目录是可以层层嵌套,形成文件路径。
在Linux中,目录也是以一种特殊文件被对待的,所以用于文件的操作同样也可以用在目录上。
目录项在一个文件路径中,路径中的每一部分都被称为目录项;如路径/home/source/helloworld.c中,目录/,home,source和文件helloworld.c都是一个目录项。
索引节点用于存储文件的元数据的一个数据结构。
文件的元数据,也就是文件的相关信息,和文件本身是两个不同的概念。
它包含的是诸如文件的大小、拥有者、创建时间、磁盘位置等和文件相关的信息。
超级块用于存储文件系统的控制信息的数据结构。
描述文件系统的状态、文件系统类型、大小、区块数、索引节点数等,存放于磁盘的特定扇区中。
如上的几个概念在磁盘中的位置关系如图4所示。
图2磁盘与文件系统
VFS依靠四个主要的数据结构和一些辅助的数据结构来描述其结构信息,这些数据结构表现得就像是对象;每个主要对象中都包含由操作函数表构成的操作对象,这些操作对象描述了内核针对这几个主要的对象可以进行的操作。
下图就是逻辑上对VFS及其下层实际文件系统的组织图,可以看到用户层只能于VFS打交道,而不能直接访问实际的文件系统,比如EXT2、EXT3、PROC,换句话说,就是用户层不用也不能区别对待这些真正的文件系统,不过,SOCKET虽然也属于VFS的管辖范围,但是有其特殊性,就是不能像打开大部分文件系统下的“文件”一样打开socket,它只能被创建,而且内核中对其有特殊性处理。
图3逻辑上对VFS及其下层实际文件系统的组织图
【超级块的实现方法】
VFS描述文件系统使用超级块和inode的方式,所谓超级块就是对所有文件系统的管理机构,每种文件系统都要把自己的信息挂到super_blocks这么一个全局链表上。
内核中是分成2个步骤完成:
首先每个文件系统必须通过register_filesystem函数将自己的file_system_type挂接到file_systems这个全局变量上,然后调用kern_mount函数把自己的文件相关操作函数集合表挂到super_blocks上。
每种文件系统类型的读超级块的例程(get_sb)必须由自己实现。
图4超级块的实现
存储一个已安装的文件系统的控制信息,代表一个已安装的文件系统;每次一个实际的文件系统被安装时,内核会从磁盘的特定位置读取一些控制信息来填充内存中的超级块对象。
一个安装实例和一个超级块对象一一对应。
超级块通过其结构中的一个域s_type记录它所属的文件系统类型。
VFS超级块是各种逻辑文件系统在安装时建立的,并在这些文件系统卸载时自动删除,它只存在于内存中。
VFS中保存了系统中挂接的文件系统的链表以及这些文件系统对应的VFS超级块。
系统启动后所有被初始化的文件系统都要向VFS登记。
每个已安装的文件系统由一个VFS超块表示,它包含如下信息:
⑴Device:
表示文件系统所在块设备的设备标志符。
例如系统中第一个IDE硬盘的设备标志符为0x301。
⑵Inodepointers:
这个mountedinode指针指向文件系统中第一个inode。
而coveredinode指针指向此文件系统安装目录的inode。
根文件系统的VFS超块不包含covered指针。
⑶Blocksize:
以字节记数的文件系统块大小,如1024字节。
⑷Superblockoperations:
指向此文件系统一组超块操纵例程的指针。
这些例程被VFS用来读写inode和超块。
⑸FileSystemtype:
这是一个指向已安装文件系统的file_system_type结构的指针。
⑹FileSystemspecific:
指向文件系统所需信息的指针。
一个超级块对应一个文件系统(已经安装的文件系统类型如ext2,此处是实际的文件系统)。
之前我们已经说了文件系统用于管理这些文件的数据格式和操作之类的,系统文件有系统文件自己的文件系统,同时对于不同的磁盘分区也有可以是不同的文件系统。
那么一个超级块对应一个独立的文件系统,保存文件系统的类型、大小、状态等等。
(“文件系统”和“文件系统类型”是不同的概念,一个文件系统类型下可以包括很多文件系统即很多的super_block)
对于不同的文件系统有不同的super_block,对于不同的super_block的操作也是不同的,所以我们在下面的super_block结构中可以看到上面说的抽象的struct结构(例如下面的:
structsuper_operations):
(linux内核2.4.37)
图5Structsuper_operations
解释字段:
s_list:
指向超级块链表的指针,这个structlist_head是很熟悉的结构了,里面其实就是用于连接关系的prev和next字段。
内核中的结构处理都是有讲究的(内核协议栈中也说过),内核单独使用一个简单的结构体将所有的super_block都链接起来,但是这个结构不是super_block本身,因为本身数据结构太大,效率不高,所有仅仅使用
struct
{
list_headprev;
list_headnext;
}
这样的结构来将super_block中的s_list链接起来,那么遍历到s_list之后,直接读取super_block这么长的一个内存块,就可以将这个
super_block直接读进来!
这样就很快捷方便!
这也是为什么s_list必须放在第一个字段的原因。
s_dev:
包含该具体文件系统的块设备标识符。
例如,对于 /dev/hda1,其设备标识符为 0x301
s_blocksize:
文件系统中数据块大小,以字节单位
s_blocksize_bits:
上面的size大小占用位数,例如512字节就是9bits
s_dirt:
脏位,标识是否超级块被修改
s_maxbytes:
允许的最大的文件大小(字节数)
structfile_system_type*s_type:
文件系统类型(也就是当前这个文件系统属于哪个类型?
ext2还是fat32)
要区分“文件系统”和“文件系统类型”不一样!
一个文件系统类型下可以包括很多文件系统即很多的super_block,后面会说!
structsuper_operations*s_op:
指向某个特定的具体文件系统的用于超级块操作的函数集合
structdquot_operations*dq_op:
指向某个特定的具体文件系统用于限额操作的函数集合
structquotactl_ops *s_qcop:
用于配置磁盘限额的的方法,处理来自用户空间的请求
s_flags:
安装标识
s_magic:
区别于其他文件系统的标识
s_root:
指向该具体文件系统安装目录的目录项
s_umount:
对超级块读写时进行同步
s_lock:
锁标志位,若置该位,则其它进程不能对该超级块操作
s_count:
对超级块的使用计数
s_active:
引用计数
s_dirty:
已修改的索引节点inode形成的链表,一个文件系统中有很多的inode,有些inode节点的内容会被修改,那么会先被记录,然后写回磁盘。
s_locked_inodes:
要进行同步的索引节点形成的链表
s_files:
所有的已经打开文件的链表,这个file和实实在在的进程相关的
s_bdev:
指向文件系统被安装的块设备
u:
u 联合体域包括属于具体文件系统的超级块信息
s_instances:
具体的意义后来会说的!
(同一类型的文件系统通过这个子墩将所有的super_block连接起来)
s_dquot:
磁盘限额相关选项
super_block存在于两个链表中,一个是系统所有super_block的链表,一个是对于特定的文件系统的super_block链表。
所有的super_block都存在于super_blocks(VFS管理层)链表中:
图6超级块与VFS管理层链表
对于特定的文件系统(文件系统层的具体文件系统),该文件系统的所有的super_block都存在于file_sytem_type中的fs_supers链表中;而所有的文件系统,都存在于file_systems链表中.这是通过调用register_filesystem接口来注册文件系统的。
intregister_filesystem(structfile_system_type*fs)
图7文件系统层的具体文件系统的超级块
3.2.进程管理器
【任务描述】
在Windows系统环境下,实现一个系统进程管理器,能够显示当前系统的活动进程信息(进程名、进程ID、优先级、线程数、内存使用等),并能结束或创建特定的进程。
【源代码】
Form1:
usingSystem;
usingSystem.Collections.Generic;
usingSystem.ComponentModel;
usingSystem.Data;
usingSystem.Drawing;
usingSystem.Text;
usingSystem.Windows.Forms;
usingSystem.Threading;
usingSystem.Diagnostics;
usingSystem.Management;
namespace进程管理器
{
publicpartialclassForm1:
Form
{
publicForm1()
{
InitializeComponent();
this.listView1.Columns.Add("进程名",65,HorizontalAlignment.Center);
this.listView1.Columns.Add("进程ID",65,HorizontalAlignment.Center);
this.listView1.Columns.Add("线程数",65,HorizontalAlignment.Center);
this.listView1.Columns.Add("优先级",65,HorizontalAlignment.Center);
this.listView1.Columns.Add("占用内存",65,HorizontalAlignment.Center);
this.listView1.View=System.Windows.Forms.View.Details;
}
privatevoidgetProcessInfo()
{
try
{
listView1.Items.Clear();
Process[]MyProcesses=Process.GetProcesses();
listView1.Items.Clear();
Process[]AllProcesses=Process.GetProcesses();
foreach(ProcessMyProcessinAllProcesses)
{
ListViewItem
item1=newListViewItem(MyProcess.ProcessName+".exe",0);//映像名称
//item1.Checked=true;
item1.SubItems.Add(MyProcess.Id.ToString());//进程PID
item1.SubItems.Add(MyProcess.BasePriority.ToString());//优先级
item1.SubItems.Add(MyProcess.Threads.Count.ToString());//线程数
item1.SubItems.Add((MyProcess.WorkingSet64/1024).ToString()+"K");//内存大小
listView1.Items.AddRange(newListViewItem[]{item1});
}
}
catch{}
}
privatevoidForm1_Load(objectsender,EventArgse)
{
getProcessInfo();
}
privatevoidbutton1_Click(objectsender,EventArgse)
{
listView1.Refresh();
getProcessInfo();
}
privatevoidbutton3_Click(objectsender,EventArgse)
{
if(listView1.SelectedItems.Count<=0)
return;
ListViewItemitems=listView1.SelectedItems[0];
stringStrPro=items.Text;//获取选中的进程名
intpid=int.Parse(items.SubItems[1].Text);//获取选中的进程的PID
ProcessSelPro=newProcess();
intflag=0;//异常标志。
如果Process.GetProcessById(pid)出现异常,不执行结束....
try
{
SelPro=Process.GetProcessById(pid);
}
catch(ArgumentExceptionae)
{
flag++;
MessageBox.Show(ae.Message);
}
if(0==flag)
{
if(DialogResult.OK==MessageBox.Show(string.Format("确定要结束进程{0}吗?
",StrPro),"提示",MessageBoxButtons.OKCancel,MessageBoxIcon.Information))
{
try
{
SelPro.Kill();//结束进程
getProcessInfo();//结束进程后刷新listview
}
catch(Win32Exceptionioe)//获取异常信息
{
MessageBox.Show(ioe.Message);
}
catch(InvalidOperationExceptionioe)
{
MessageBox.Show(ioe.Message);
}
}
button1_Click(sender,e);
}
}
privatevoidlistView1_SelectedIndexChanged(objectsender,EventArgse)
{
}
privatevoidbutton2_Click(objectsender,EventArgse)
{
Form2dlg=newForm2();
if(dlg.ShowDialog()==DialogResult.OK)
{
try
{
Process.Start(dlg.FileName);
}
catch(System.ComponentModel.Win32Exception)
{
MessageBox.Show(String.Format("can'tfindthefiles'{0}',pleasemakesureofthenameoffilesthentryagain。
\npress[start]tosearchfiles",dlg.FileName));
}
}
button1_Click(sender,e);
}
}
}
Form2:
usingSystem;
usingSystem.Collections.Generic;
usingSystem.ComponentModel;
usingSystem.Data;
usingSystem.Drawing;
usingSystem.Linq;
usingSystem.Text;
usingSystem.Windows.Forms;
usingSystem.Management;
namespace进程管理器
{
publicpartialclassForm2:
Form
{
publicForm2()
{
InitializeComponent();
StartPosition=FormStartPosition.CenterParent;
}
privatevoidbutton1_Click(objectsender,EventArgse)
{
DialogResult=DialogResult.OK;
}
privatevoidbutton2_Click(objectsender,EventArgse)
{
DialogResult=DialogResult.Cancel;
}
privatevoidbutton3_Click(objectse