当前位置: 首页 > news >正文

Linux-0.11 文件系统super.c详解

Linux-0.11 文件系统super.c详解

模块简介

该模块主要包含了对超级块的一些读写操作。

函数详解

lock_super

static void lock_super(struct super_block * sb)

该函数的作用是锁定bh块。

    cli();//关中断while (sb->s_lock)//如果已经被锁定sleep_on(&(sb->s_wait));//将当前任务置为不可中断的等待状态,并添加到该超级快等待队列。sb->s_lock = 1;//锁定该超级快sti();//关中断

free_super

static void free_super(struct super_block * sb)

对指定超级块进行解锁。

	cli();//关中断sb->s_lock = 0;//对超级块进行解锁wake_up(&(sb->s_wait));//唤醒等待该超级块的进程sti();//开中断

wait_on_super

static void wait_on_super(struct super_block * sb)

该函数的作用是等待超级块解锁。

	cli();//关中断while (sb->s_lock)//如果已经被锁定sleep_on(&(sb->s_wait));//将当前任务置为不可中断的等待状态,并添加到该超级快等待队列。sti();//开中断

get_super

struct super_block * get_super(int dev)

获取指定设备的超级块。

	struct super_block * s;if (!dev)return NULL;s = 0+super_block;while (s < NR_SUPER+super_block)if (s->s_dev == dev) {wait_on_super(s);if (s->s_dev == dev)return s;s = 0+super_block;} elses++;return NULL;

put_super

void put_super(int dev)

该函数用于放回指定设备的超级块。

	struct super_block * sb;/* struct m_inode * inode;*/int i;

首先判断该设备是否是根文件系统设备,如果是,则直接返回。

	if (dev == ROOT_DEV) {printk("root diskette changed: prepare for armageddon\n\r");return;}

接着开始读取该设备的超级块。如果该超级块的挂载位置i节点s_imount还没有处理,则打印告警并返回。

	if (!(sb = get_super(dev)))return;if (sb->s_imount) {printk("Mounted disk changed - tssk, tssk\n\r");return;}

找到该设备的超级块这时候,首先需要锁定该超级块。接着释放i节点位图和逻辑块位图。结束之后,对该超级块进行解锁,并返回。

	lock_super(sb);sb->s_dev = 0;for(i=0;i<I_MAP_SLOTS;i++)brelse(sb->s_imap[i]);for(i=0;i<Z_MAP_SLOTS;i++)brelse(sb->s_zmap[i]);free_super(sb);return;

read_super

static struct super_block * read_super(int dev)

该函数的作用是用于读取指定设备的超级块。

程序的开始定义了一些变量,对进行一些校验。

	struct super_block * s;struct buffer_head * bh;int i,block;if (!dev)return NULL;check_disk_change(dev);

接着从超级块数组中获取一个超级块。如果已经存在,则直接返回该超级块的指针。如果不存在,则找出一个空闲的位置(s_dev=0)。找到之后边进行初始化。

	if ((s = get_super(dev)))return s;for (s = 0+super_block ;; s++) {if (s >= NR_SUPER+super_block)return NULL;if (!s->s_dev)break;}s->s_dev = dev;s->s_isup = NULL;s->s_imount = NULL;s->s_time = 0;s->s_rd_only = 0;s->s_dirt = 0;

接下来就是读取该设备的第一个磁盘块到内存中。(第0个磁盘块是引导,第一个磁盘块是超级块。)

	if (!(bh = bread(dev,1))) {s->s_dev=0;free_super(s);return NULL;}*((struct d_super_block *) s) =*((struct d_super_block *) bh->b_data);brelse(bh);

接下俩检查其魔数,如果不是0x137F,则不能处理。

	if (s->s_magic != SUPER_MAGIC) {s->s_dev = 0;free_super(s);return NULL;}

接下来开始读取i节点位图和逻辑块位图数据。i节点位图在设备的第2号块开始,共占用s_imap_blocks块。逻辑块位图在i节点位图之后,共占用s_zmap_blocks块。

	for (i=0;i<I_MAP_SLOTS;i++)s->s_imap[i] = NULL;for (i=0;i<Z_MAP_SLOTS;i++)s->s_zmap[i] = NULL;block=2;for (i=0 ; i < s->s_imap_blocks ; i++)if ((s->s_imap[i]=bread(dev,block)))block++;elsebreak;for (i=0 ; i < s->s_zmap_blocks ; i++)if ((s->s_zmap[i]=bread(dev,block)))block++;elsebreak;

接下来如果文件系统信息有问题,则意味着初始化失败,则进行失败的处理。

	if (block != 2+s->s_imap_blocks+s->s_zmap_blocks) {for(i=0;i<I_MAP_SLOTS;i++)brelse(s->s_imap[i]);for(i=0;i<Z_MAP_SLOTS;i++)brelse(s->s_zmap[i]);s->s_dev=0;free_super(s);return NULL;}

程序运行到这里,说明一切正常。因为0号i节点和0号数据块是不能使用的,因此将i节点位图和逻辑块位图的0号位置设置为1。

	s->s_imap[0]->b_data[0] |= 1;s->s_zmap[0]->b_data[0] |= 1;free_super(s);return s;

sys_umount

int sys_umount(char * dev_name)

该函数用于卸载一个文件系统。

程序的开始定义了一些变量,接着通过设备名称获取其i节点。

	struct m_inode * inode;struct super_block * sb;int dev;if (!(inode=namei(dev_name)))return -ENOENT;

对于设备节点而言,其设备号存放在i节点的i_zone[0]中。如果该i节点不是一个块设备文件,则不能进行卸载,于是返回错误。

	dev = inode->i_zone[0];if (!S_ISBLK(inode->i_mode)) {iput(inode);return -ENOTBLK;}iput(inode);

如果该设备号存放的是根文件系统,则不能进行卸载。

	if (dev==ROOT_DEV)return -EBUSY;

接下来根据设备号取出其超级块,如果该超级块中的s_imount为NULL,也就是该设备没有被挂载,则不能进行卸载。

	if (!(sb=get_super(dev)) || !(sb->s_imount))return -ENOENT;

如果挂载的目录节点的i_mount字段为0,则需要打印日志提示。

	if (!sb->s_imount->i_mount)printk("Mounted inode has i_mount=0\n");

接下来遍历inode表,查看该设备节点是否被占用,如果被占用则返回错误。

	for (inode=inode_table+0 ; inode<inode_table+NR_INODE ; inode++)if (inode->i_dev==dev && inode->i_count)return -EBUSY;

程序运行到这里,就开始正式的卸载。首先将挂载的目录节点的i_mount标记为0,随后放回该挂载目录节点。随后将超级块的s_imount字段标记为NULL,并将该文件系统的根i节点进行放回。

	sb->s_imount->i_mount=0;iput(sb->s_imount);sb->s_imount = NULL;iput(sb->s_isup);sb->s_isup = NULL;

最后释放该设备上的超级块以及位图中占用的高速缓冲块,并对该设备进行数据同步。

	put_super(dev);sync_dev(dev);

sys_mount

int sys_mount(char * dev_name, char * dir_name, int rw_flag)

该函数的作用是用于安装文件系统。该函数是sys_开头的,是一个系统调用。

函数的开始定义了一些变量,接着通过设备名称获取其i节点。

	struct m_inode * dev_i, * dir_i;struct super_block * sb;int dev;if (!(dev_i=namei(dev_name)))return -ENOENT;

对于设备类型的i节点,其i_zone[0]存放的是设备号dev。接着判断该设备是否是一个块设备文件,如果不是块设备文件,是不能挂在文件系统的,就会返回权限错误。如果权限校验没有问题,就把dev_i节点放回。

	dev = dev_i->i_zone[0];   //获取其设备号devif (!S_ISBLK(dev_i->i_mode)) { //判断该i节点是否是一个设备节点,如果不是则返回权限错误iput(dev_i);return -EPERM;}iput(dev_i);  //获取到dev_i

接下来获取dir_name对应的i节点dir_i。

	if (!(dir_i=namei(dir_name))) //获取dir_name的i节点return -ENOENT;

如果dir_i这个i节点的引用计数不为1,也就是说这个i节点还被其他进程使用,或者dir_i节点是根文件系统的1号i节点,则不能进行挂载。

	if (dir_i->i_count != 1 || dir_i->i_num == ROOT_INO) {iput(dir_i);return -EBUSY;}

此外,如果该i节点不是一个目录节点,则也不能进行挂载。

	if (!S_ISDIR(dir_i->i_mode)) { //判断dir_i的类型,如果不是目录节点则不能进行挂载iput(dir_i);return -EPERM;}

当运行到这里时,就意味着对挂载设备和挂载目录的校验就通过了。接下来,读取设备dev的超级块。

	if (!(sb=read_super(dev))) {//读取dev设备的超级块iput(dir_i);return -EBUSY;}

如果该超级块已经挂载到某个目录下,那么将返回错误。如果该目录已经挂载了其他的块设备,也返回错误。

	if (sb->s_imount) {//超级块的s_imount不为空,代表该超级块已经挂载到某个目录下,则返回EBUSYiput(dir_i);return -EBUSY;}if (dir_i->i_mount) {//目标的目录节点已经挂载了其他的设备,则返回EPERMiput(dir_i);return -EPERM;}

最后便开始进行真正的挂载步骤,其实就是将超级块sb的s_imount指向挂载的目录i节点dir_i。接着将目录i节点dir_i的i_mount字段标记为1,也将i_dirt标记为1。这些执行完毕之后,将返回0。

	sb->s_imount=dir_i;dir_i->i_mount=1;dir_i->i_dirt=1;return 0;

mount_root

void mount_root(void)

该函数的作用是安装根文件系统。

该函数的最初定义了一些变量,对d_inode的结构的长度进行校验。

	int i,free;struct super_block * p;struct m_inode * mi;if (32 != sizeof (struct d_inode))panic("bad i-node size");

如果根文件系统在软盘中,就提示插入跟文件系统盘。

	for(i=0;i<NR_FILE;i++)file_table[i].f_count=0;if (MAJOR(ROOT_DEV) == 2) {printk("Insert root floppy and press ENTER");wait_for_keypress();}

初始化超级块数组。

	for(p = &super_block[0] ; p < &super_block[NR_SUPER] ; p++) {p->s_dev = 0;p->s_lock = 0;p->s_wait = NULL;}

读取根文件系统的超级块。

	if (!(p=read_super(ROOT_DEV)))panic("Unable to mount root");

读取根目录的i节点。

	if (!(mi=iget(ROOT_DEV,ROOT_INO)))panic("Unable to read root i-node");

该函数在init进程中调用,下面设置init进程PCB的pwd和root。

	mi->i_count += 3 ;	/* NOTE! it is logically used 4 times, not 1 */p->s_isup = p->s_imount = mi;current->pwd = mi;current->root = mi;

统计空闲的i节点数量。

	free=0;i=p->s_nzones;while (-- i >= 0)if (!set_bit(i&8191,p->s_zmap[i>>13]->b_data))free++;printk("%d/%d free blocks\n\r",free,p->s_nzones);

统计空闲的逻辑块节点。

	free=0;i=p->s_ninodes+1;while (-- i >= 0)if (!set_bit(i&8191,p->s_imap[i>>13]->b_data))free++;printk("%d/%d free inodes\n\r",free,p->s_ninodes);

Q & A

相关文章:

Linux-0.11 文件系统super.c详解

Linux-0.11 文件系统super.c详解 模块简介 该模块主要包含了对超级块的一些读写操作。 函数详解 lock_super static void lock_super(struct super_block * sb)该函数的作用是锁定bh块。 cli();//关中断while (sb->s_lock)//如果已经被锁定sleep_on(&(sb->s_wai…...

什么是ChatGPT、历史发展及应用领域

什么是ChatGPT ChatGPT是一种基于深度学习的自然语言处理技术&#xff0c;它可以生成高质量的自然语言文本&#xff0c;该技术是由OpenAI团队开发&#xff0c;旨在使计算机能够像人类一样理解和产生自然语言。ChatGPT使用了深度神经网络和自然语言处理技术&#xff0c;通过对大…...

Spring的创建与使用

目录 1.创建 Spring 项⽬ 1.1 创建一个 maven 项目 1.2 添加 spring 框架支持(spring-context/spring-beans) 2.将 Bean (对象) 存储到 Spring (容器) 中 2.1 在resources中创建一个spring配置文件 2.2 将 Bean 对象存储到 Spring 当中 2.2.1 创建 Bean 对象 2.2.2 将B…...

抖音Flutter插件的使用

Flutter是一个开源的移动应用程序开发框架&#xff0c;由谷歌开发&#xff0c;支持Android和iOS。随着Flutter的发展和成熟&#xff0c;许多人开始使用它来开发跨平台应用程序。本文将介绍如何使用抖音的Flutter插件&#xff0c;以增强Flutter应用程序的功能。 1. 安装Flutter…...

Debezium报错处理系列之六十八:No resolvable bootstrap urls given in bootstrap.servers

Debezium报错处理系列之六十八:No resolvable bootstrap urls given in bootstrap.servers 一、完整报错二、错误原因三、解决方法Debezium报错处理系列一:The db history topic is missing. Debezium报错处理系列二:Make sure that the same history topic isn‘t shared b…...

Python二级编程:分词去重

一、原题 参考编程模板&#xff0c;完善代码&#xff0c;实现以下功能。‪‪‪‪‪‫‫‪‪‪‪‪‪‪‪‪‪‪‪‪‪‪‪‪‫‪‪‪‪‪‪‪‪‪‪‪‪‪‫ 利用 jieba 库实现中文分词。对分词后的列表进行去重处理&#xff0c;然后将分词结果中字符数大于等于 3 的词语&…...

Android Wifi开发——Wifi锁(十九)

有的时候我们需要 APP 在手机后台运行,但是会遇到手机一旦息屏或者断网,APP 无法正常运行的情况,这是因为手机屏幕关闭之后,并且其他的应用程序没有在使用 Wifi 的时候,系统大概在两分钟之后,会关闭 Wifi,使得 Wifi 处于睡眠状态。而 Wifi 锁 就是 Android 锁屏后 Wifi …...

Nginx的优化与防盗链

目录 一. 隐藏版本号方法一&#xff1a;配置文件隐藏版本号方法二&#xff1a;源代码隐藏版本号 修改用户与组缓存时间日志切割连接超时更改进程数配置网页压缩配置防盗链fpm参数优化 一. 隐藏版本号 可以使用 Fiddler 工具抓取数据包&#xff0c;查看 Nginx版本&#xff0c;也…...

STP协议

目录 STP的基本概念&#xff1a; 桥ID&#xff08;Bridge ID&#xff09;&#xff1a; 根桥&#xff1a; 开销&#xff08;Cost&#xff09;&#xff1a; RPC&#xff08;根路径开销&#xff09;&#xff1a; Port ID&#xff1a; BPDU&#xff1a;&#xff08;网桥协议…...

方法——检查参数的有效性

检查参数的有效性 绝大多数方法和构造方法对于传递给它们的参数都会有某些限制,比如对象引用不能为null,比如必须是正数等.你应该在文档中(或者注释中)清楚地指出所有这些限制,并且在方法体的开头检查参数,并且强制施加这些限制.如果做不到这一点,检测出错误的可能性就很小,即…...

七、Docker仓库之nexus搭建(四)

Nexus简介 使用 Docker 官方的 Registry 创建的仓库面临一些维护问题。比如某些镜像删除以后空间默认是不会回收的&#xff0c;需要一些命令去回收空间然后重启 Registry。在企业中把内部的一些工具包放入 Nexus 中是比较常见的做法&#xff0c;最新版本 Nexus3.x 全面支持 Doc…...

MySQL 锁机制

1.概述 锁是计算机协调多个进程或线程并发访问某一种资源的机制。 在数据库中&#xff0c;除去计算机硬件资源&#xff08;CPU、RAM、I/O等&#xff09;的争用外&#xff0c;数据也是一种供许多用户共享的资源。如何保证并发访问数据的一致性、有效性是所有数据库必须解决的一…...

HACKER KID: 1.0.1实战演练

文章目录 HACKER KID: 1.0.1实战演练一、前期准备1、相关信息 二、信息收集1、端口扫描2、访问网站3、扫描目录4、查看源码5、请求参数6、burpsuite批量请求7、编辑hosts文件8、DNS区域传输9、编辑hosts10、访问网站11、注册账号12、burpsuite抓包13、XML注入14、解密15、登录网…...

Android车载学习笔记1——车载整体系统简介

一、汽车操作系统 汽车操作系统包括安全车载操作系统、智能驾驶操作系统和智能座舱操作系统。 1. 安全车载操作系统 安全车载操作系统主要面向经典车辆控制领域&#xff0c;如动力系统、底盘系统和车身系统等&#xff0c;该类操作系统对实时性和安全性要求极高&#xff0c;生态…...

Apache Doris

Apache Doris教程 1.Doris 简介 1.1 Doris 概述 Apache Doris 由百度大数据部研发&#xff08;之前叫百度 Palo&#xff0c;2018 年贡献到 Apache 社区后&#xff0c; 更名为 Doris &#xff09;&#xff0c;在百度内部&#xff0c;有超过 200 个产品线在使用&#xff0c;…...

GB28181 对接海康平台,解决音视频卡顿问题

GB28181 对接海康平台,解决音视频卡顿问题 一、概述二、问题分析1、设备对比分析2、抓包对比分析3、验证分析结果三、总结四、讨论一、概述 设备使用GB28181协议对接海康平台时,发现音频和视频存在卡顿现象,不是一直卡顿,有时候卡有时候不卡,但是卡顿的时候音视频一起卡顿…...

Linux系统编程面试题

1. 什么是系统调用&#xff1f;它与普通函数调用有什么不同&#xff1f; 系统调用和普通函数调用的区别在于它们执行的上下文和权限不同。系统调用是操作系统内核提供的一组接口&#xff0c;允许用户程序请求操作系统执行特权操作&#xff0c;例如打开或关闭文件、创建新进程等…...

计算机网络 - 网络层的数据平面

Overview 首先Network Layer负责的是host to host的传输, 然后可以分为两个平面, 控制平面以及数据平面. 数据平面: 负责forward datagrams from input to output links 决定路由器从input到output 转发功能: 基于目标地址 转发表 SDN方式基于多个字段流表 控制平面: 调…...

《Spring Guides系列学习》guide41 - guide45

要想全面快速学习Spring的内容&#xff0c;最好的方法肯定是先去Spring官网去查阅文档&#xff0c;在Spring官网中找到了适合新手了解的官网Guides&#xff0c;一共68篇&#xff0c;打算全部过一遍&#xff0c;能尽量全面的了解Spring框架的每个特性和功能。 接着上篇看过的gu…...

数据库基础——1.数据库概述

从这篇文章我们开始学习数据库的相关知识 目录 1.为什么要使用数据库 2.数据库与数据库管理系统 2.1相关概念 2.2数据库与数据库管理系统的关系 ​编辑2.3常见的数据库管理系统 2.4常见的数据库介绍 3.MySQL介绍 3.1概述 3.2关于MySQL8.0 3.3 Oracle vs MySQL 4.RD…...

2023 光亚展|乐鑫将携 AI、Wi-Fi 6、私有云和 Matter 方案精彩亮相

2023 广州国际照明展览会&#xff08;光亚展&#xff09;将于 6 月 9 至 12 日在广州琶洲展馆启幕。本届展会以“光未来”为主题&#xff0c;畅想未来生活方式的无限可能。乐鑫科技 (688018.SH) 将在 B 区 9.2 号厅 D55 展位&#xff0c;带来具有前瞻性的智能照明解决方案和实体…...

用反射设计通用的实例化对象方案

需求 对象的相关信息存储在javabean.properties文件中&#xff0c;通过读取properties文件中的信息&#xff0c;实例化对象&#xff0c;要求程序不能硬编码&#xff0c;即程序可以通用&#xff0c;针对不同的对象&#xff0c;都可以实例化。仅需修改配置文件&#xff0c;不需要…...

破坏单例模式--存在的问题---问题的解决

目录 破坏单例模式--存在的问题---问题的解决 问题演示 破坏单例模式&#xff1a; 序列化 反射 序列化反序列化&#xff1a; 代码&#xff1a; 运行结果&#xff1a; 反射 代码&#xff1a; 运行结果&#xff1a; 问题的解决 序列化、反序列方式破坏单例模式的解…...

SpringCloud微服务踩坑系列-java.lang.IllegalStateException

异常如下&#xff1a; 2023-05-24 08:47:10.764 ERROR 118400 --- [nio-8084-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exceptio…...

Linux-地址空间

文章目录 问题引入操作系统宏观认识操作系统与进程程序地址空间进程地址空间问题解释 问题引入 在Linux操作系统中、vim编译器下&#xff0c;出现了变量同地址但不同值的现象。 下面以解释该现象产生的原因为主线&#xff0c;在过程中学习Linux操作系统的知识。 运行代码展示…...

【EKS】基于Amazon EKS搭建kubernetes集群

文章目录 前言 | 亚马逊云科技 re:Invent前沿资讯一、介绍篇&#x1f3a8;什么是AWS 云计算什么是Amazon EKS 二、部署篇&#x1f528;1、创建集群VPC2、创建集群子网3、创建IGW网关4、创建路由表与子网绑定5、EKS集群创建6、创建kubeconfig配置文件7、添加计算节点组8、查看EK…...

Tomcat安装与启动和配置

目录 Tomcat 简介 Tomcat 安装 Tomcat 启动和配置 文件夹作用 启动&#xff0c;关闭Tomcat&#xff1b; 常见问题 配置 环境变量 IDEA中配置Tomcat Tomcat 简介 Tomcat 服务器是一个免费的开放源代码的Web 应用服务器&#xff0c;属于轻量级应用服务器&#xff0c;在…...

ruoyi-vue版本(十八)创建自己的项目,使用若依里面的技术,多数据源的实现

目录 1 创建自己的项目2 连接MySQL数据库(多数据源)2.1 若依实现多数据源2.1.1 主要思想2.2 第三方的依赖的实现1 创建自己的项目 1 创建一个空文件夹 2 idea 里面创建项目...

C++-stack题型->最小栈,栈的压入与弹出,逆波兰表达式

目录 最小栈 栈的压入与弹出 逆波兰表达式 最小栈 155. 最小栈 - 力扣&#xff08;Leetcode&#xff09; 设计一个支持 push &#xff0c;pop &#xff0c;top 操作&#xff0c;并能在常数时间内检索到最小元素的栈。 实现 MinStack 类: MinStack() 初始化堆栈对象。void …...

【计算机网络实验】BGP和OSPF协议仿真实验

实验内容  BGP和OSPF协议仿真实验 实验目的 &#xff08;1&#xff09;学习BGP协议的配置方法&#xff1b; &#xff08;2&#xff09;验证BGP协议的工作原理&#xff1b; &#xff08;3&#xff09;掌握网络自治系统的划分方法&#xff1b; &#xff08;4&#xff09;验证…...