自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+

原创 指针的引用传参

因为C语言不支持引用传参,有时候我们想在被调用函数中修改调用函数传进来的参数的地址,并让它在返回后仍然有效,这时候能用到的就是指针的指针。或者说是指针的引用。 #include <stdio.h> #include <stdlib.h> typedef struct A { int a; char c; }AS, *AP;//*AP相当于struct A, A...

2020-08-02 00:30:11 25

原创 C/C++ 函数参数传递:传值,传指针,传引用(C语言不支持传引用)

函数调用者如何将参数传递给被调用者是有讲究的。 总的来说,函数参数传递分为3种情况:传值,传指针和传引用。首先,理解一下实参与形参的概念。int func(int x)//x是形参{ return x*x;}int main(void){ int a = 10; func(a);//a是实参 return 0;}上面的代码中,x是形参,a是实参。形参x是实参a的一个拷贝。&a和&x完全不同。一,传值所谓传值,顾名思义,就是把实参的值直...

2020-08-01 06:54:01 592

转载 vs code 集成github

1. VSCode 默认已安装Git。输入git --version如果显示版本号,则安装成功。2. 在GitHub上新建一个仓库。例如:myrepo3. 在本地新建一个文件夹,作为VSCode代码的工作文件夹。例如:mycode4. mycode既是VSCode的代码工作文件夹又应该是Git的本地仓库。在命令行方式下进入mycode,输入git initgit init5. 添加用户名和邮箱。该用户名和邮箱是注册GitHub时使用的用户名和邮箱: git config --glob...

2020-07-29 07:45:00 32

原创 linux文件系统中文件阶段操作truncate

因为要给给文件系统增加数据索引功能,所以对文件系统进行了不少的修改(主要是仿照i_zone[]的方式进行索引数据的管理和存储),但是考虑到文件还有删除或者截断操作,我们就必须面对这个问题,看看文件系统是如何处理的。今天我们来看看ext2和minix是如何截断文件的:即,如何删除那些我们不需要的数据块了。 所谓的截断文件指的是:一个特定长度的文件,我们从某个位置开始丢弃后面的数据,之前的数据依然保留。对具体文件系统来说,截断数据主要意味着两件事情:1. 文件大小发生变化;2. 文件被截断...

2020-07-23 10:03:52 36

转载 Linux内核Page Cache和Buffer Cache关系及演化历史

在我们进行数据持久化,对文件内容进行落盘处理时,我们时常会使用fsync操作(file sync,即文件同步),该操作会将文件关联的脏页(dirty page)数据(实际文件内容及元数据信息)一同写回磁盘。这里提到的脏页(dirty page)即为页缓存(page cache,也叫页高速缓存)。块缓存(buffer cache),则是内核为了加速对底层存储介质的访问速度,而构建的一层缓存。它缓存部分磁盘数据,当有磁盘读取请求时,会首先查看块缓存中是否有对应的数据,如果有的话,则直接将对应数据返回,从而减

2020-07-21 14:12:37 66

原创 Page cache和buffer cache

这一段要在文件系统中对文件的记录增加索引。实现思路是借鉴了i_zone的三级间接寻址方案。i_zone实际上代表了3层意思,第一层是i_zone这个数组本身,它是放在episode_inode中的,只要拿到了episode_inode的指针或者对象,就可以直接访问;第二层,i_zone[0]--i_zone[9]的内容(就是一个blockid)所代表的那9个block、i_zone[7]-i_zone[9]指向的block里面存储的blocksize/4个blockid所代表的那blocksize/4个bl

2020-07-13 18:11:57 51

转载 使用PageCache读取文件元数据块

使用PageCache读取文件元数据块Linux 2.4的最大贡献是统一的PageCache与BufferCache,准确来说,它是讲所有数据都保存在了PageCache中,但是仍然保留了BufferCache的接口,以供如superblocks,bitmap,inode table,block table等文件元数据读写的使用。也即,与块设备交互时,我们依然使用bh抽象,但是,bh不会有自己的空间,其使用的是PageCache中对应页的空间。具体文件系统内部使用时,会在页上提供Buffer head抽

2020-07-10 13:33:42 41

转载 Linux系统中的高速缓存有哪几种

Linux系统使用了几种涉及到高速缓存的内存管理方法。1 缓冲区高速缓存缓冲区高速缓存中保存着块设备驱动程序所用到的数据缓冲区。这些缓冲区的大小固定,一般包括从块设备中读入的和将要写入到块设备中的信息块。块设备一次只能处理大小固定的数据块。硬盘就是块设备中的一种(这里指的是直接写硬盘这种块设备文件,我们平时用的是直接写普通文件,普通文件是一种文件类型,块设备文件也是一种文件类型,所以这里一定要区分清楚块设备和普通文件的区别)。缓冲区高速缓存使用设备标识符和块号作为索引来快速地查找数据块。块设备只通.

2020-07-10 11:30:11 78

转载 Linux内核空间中的高端内存HighMem

Linux内核地址映射模型x86 CPU采用了段页式地址映射模型。进程代码中的地址为逻辑地址,经过段页式地址映射后,才真正访问物理内存。段页式机制如下图。Linux内核地址空间的划分通常32位Linux内核地址空间划分0~3G为用户空间,3~4G为内核空间。注意这里是32位内核地址空间划分,64位内核地址空间划分是不同的。Linux内核高端内存的由来当内核模块代码或线程访问内存时,代码中的内存地址都为逻辑地址,而对应到真正的物理内存地址,需要地址一对一的映射,如逻辑地址0..

2020-07-10 11:10:31 74

转载 buffer_head的理解

在上一篇博客介绍address_space中,我们有提到,内存中一个page所包含的磁盘块在物理上不一定是相邻的。那么page中不同的磁盘块怎么管理呢?这里就涉及到了buffer_head结构。(实际上,我们的epsiode中设定了block大小和page 大小是一样的,都是4k,但buffer_head仍然大量存在,例如sb中的imap zmap,sbh,以及管理blockid的i_zone[10],我们下一步要做的i_index[]可能也得采用它)把块存放在页高速缓存page cache中就会涉及到

2020-07-10 10:07:08 49

转载 dentry与inode

dentry与inode首先看dentry数据结构。位于include/linux/dcache.h中 struct dentryps:dentry虽然是目录的意思,但是在vfs中,目录和文件都有自己的dentry。(dentry中存了文件名,同一文件存在别名就是这个结构实现的) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

2020-07-09 16:19:52 61

转载 linux文件系统的页高速缓存page cache中的核心数据结构address_space

address_space对象是文件系统中关于内存中页高速缓存的核心数据结构。这篇博客以address_space对象为切入点,分析文件系统的页高速缓存。1背景在文件系统中,内存中存在着dentry和inode结构,其中其分别的作用可以见我另一篇博客《dentry与inode》。由于这些结构要反复使用,所以内存里开辟了目录项高速缓存以及索引结点高速缓存,提高其访问速度。但这里要提到的是另一种高速缓存:页高速缓存,它是一种对完整的数据页进行操作的磁盘高速缓存,即把磁盘的数据块缓存在页高速缓存中。而ad

2020-07-09 10:51:21 91

转载 段式、页式内存管理以及linux采用的方案图解

这两年的工作主要是写一个适用于高速传感器的文件系统,近期要实现在内核中增加对数据记录的索引,已经实现了数据和索引混合存储的方案,但效率低下,所以要实现一个数据和索引分离的机制。索引的方案类似早期minix文件系统中存储文件的blockid的i_data[10]数组类似的ji本篇跟大家说说内存管理,内存管理还是比较重要的一个环节,理解了它,至少对整个操作系统的工作会有一个初步的轮廓,这也难怪面试的时候常问内存管理。干就完事,本文的提纲:正文虚拟内存如果你是电子相关专业的,肯定在大学里.

2020-07-03 09:47:32 86

转载 Linux内核内存管理算法Buddy和Slab

CPU所有的操作都是建立在虚拟地址上处理(这里的虚拟地址分为内核态虚拟地址和用户态虚拟地址),CPU看到的内存管理都是对page的管理,接下来我们看一下用来管理page的经典算法--Buddy。Buddy分配算法假设这是一段连续的页框,阴影部分表示已经被使用的页框,现在需要申请一个连续的5个页框。这个时候,在这段内存上不能找到连续的5个空闲的页框,就会去另一段内存上去寻找5个连续的页框,这样子,久而久之就形成了页框的浪费。为了避免出现这种情况,Linux内核中引入了伙伴系统算法(Buddy sy

2020-07-02 16:06:45 82

转载 基于内核模块实现linux内核中文件的读写

在为linux内核编写的模块中,用户空间的open,read,write,llseek等函数都是不可以使用的。而必须使用其在内核中对应的函数。可以使用filp->open配合struct file里的read/write来进行对文件的读写操作。直接上干货(内容自己悟!):例1 :filp->f_op->readfilp_openfilp->f_op->write#include <linux/kernel.h>#include <lin.

2020-07-02 14:46:55 150

转载 Linux为什么一定要copy_from_user ?

网上很多人提问为什么一定要copy_from_user,也有人解答。比如百度一下:但是这里面很多的解答没有回答到点子上,不能真正回答这个问题。我决定写篇文章正式回答一下这个问题,消除读者的各种疑虑。这个问题,我认为需要从2个层面回答 第一个层次是为什么要拷贝,可不可以不拷贝? 第二个层次是为什么要用copy_from_user而不是直接memcpy 为什么要拷贝拷贝这个事情是必须的,这个事情甚至都跟Linux都没有什么关系。比如Linux有个kobject结构体,kobj

2020-06-25 00:25:43 112

转载 linux page cache的同步机制

Page Cache 的同步广义上Cache的同步方式有两种,即Write Through(写穿)和Write back(写回). 从名字上就能看出这两种方式都是从写操作的不同处理方式引出的概念(纯读的话就不存在Cache一致性了,不是么)。对应到Linux的Page Cache上所谓Write Through就是指write(2)操作将数据拷贝到Page Cache后立即和下层进行同步的写操作,完成下层的更新后才返回,可以理解为写穿透page cache直抵磁盘。而Write back正好相反,指的是

2020-06-24 15:40:36 101

转载 linux IO 几种穿透模式解析

在Linux开发中,有几个关系到性能的东西,技术人员非常关注:进程,CPU,MEM,网络IO,磁盘IO。本篇文件打算详细全面,深入浅出。剖析文件IO的细节。从多个角度探索如何提高IO性能。本文尽量用通俗易懂的视角去阐述。不copy内核代码。 阐述之前,要先有个大视角,让我们站在万米高空,鸟瞰我们的文件IO,它们设计是分层的,分层有2个好处,一是架构清晰,二是解耦。让我们看一下下面这张图。1.穿越各层写文件方式程序的最终目的是要把数据写到磁盘上,但是系统从通用性和性能角...

2020-06-24 12:33:32 79

转载 mmap为什么比read/write快(兼论buffercache和pagecache)

首先说一下文件系统,Linux文件系统的三层结构想必大家多少都了解一些,每个进程中都有一个用户文件描述符表,表项指向一个全局的文件表中的某个表项,文件表表项有一个指向内存inode的指针,每个inode唯一标识一个文件。如果同时有多个进程打开同一文件,他们的用户文件描述符表项指向不同的文件表项,但是这些文件表项会指向同一个inode。 此时又会引出另外一个东东:page cache。内核会为每个文件单独维护一个page cache,用户进程对于文件的大多数读写操作会直接作用到page cach...

2020-06-24 11:47:13 99

原创 linux进程中的内存分布

进程空间分布概述对于一个进程,其空间分布如下图所示:程序段(Text):程序代码在内存中的映射,存放函数体的二进制代码。初始化过的数据(Data):在程序运行初已经对变量进行初始化的数据。未初始化过的数据(BSS):在程序运行初未对变量进行初始化的数据。栈 (Stack):存储局部、临时变量,函数调用时,存储函数的返回指针,用于控制函数的调用和返回。在程序块开始时自动分配内存,结束时自动释放内存,其操作方式类似于数据结构中的栈。堆 (Heap):存储动态内存分配,需要程序员手工.

2020-06-18 11:10:48 140

原创 mmap是什么,为什么?

这一段搞文件系统的索引的事情,因为使用的copy from user 和copy to user等方式,进行核内核外数据交换,效率较低。例如,对于使用O_DIRECT方式的写操作,因为要加索引,所以刚开始原始数据在iovec中,但是内核态并不能对它修改。需要先复制到内核空间,然后改完之后,复制回用户空间,来回复制太麻烦了。考虑到效率问题,开始研究mmap这种方式,最起码它不需要再核内核外进行交换了,最少是少了一次复制。mmap基础概念mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进

2020-06-14 16:57:49 100

原创 Linux内核中的likely()和unlikely()宏

在Linux内核代码中经常看到likely()和unlikely()这两个宏,它们都是对bool变量进行判定,其定义如下:# define likely(x)__builtin_expect(!!(x), 1)# define unlikely(x)__builtin_expect(!!(x), 0)其中__builtin_expect()函数是gcc提供的用于对分支语句进行优化,其原型如下:long __builtin_expect (long exp, long c)当exp ==..

2020-06-04 17:42:49 61

转载 linux文件读取中的Readahead预读机制

Readahead预读机制由于内存的速度比磁盘速度快很多,如果每一次访问文件数据都要从磁盘读取一次数据,就会导致非常严重的时延。因此Linux为了提高性能,通过page cache机制,将多个用户数据缓存在内存当中,从而避免多次再磁盘读取。Readahead预读机制正是将用户数据缓存到内存的方法之一。Readahead机制的介绍Readahead预读机制是Linux针对顺序读的性能优化机制。它的核心思想是当用户访问连续多个page的时候,一次性将多个连续的页从磁盘读取到内存中,从而避免多次与磁盘

2020-06-04 15:36:17 189

转载 宋宝华:关于Ftrace的一个完整案例

本文目录Ftrace简介 Ftrace案例 Ftrace结果怎么读? vim进行Ftrace折叠Ftrace简介Ftrace是Linux进行代码级实践分析最有效的工具之一,比如我们进行一个系统调用,出来的时间过长,我们想知道时间花哪里去了,利用Ftrace就可以追踪到一级级的时间分布。Ftrace案例写一个proc模块,包含一个proc的读和写的入口。test_proc_show()故意调用了一个kill_time()的函数,而kill_time()的函数,又调用了mde..

2020-06-04 14:41:32 89

转载 宋宝华: 文件读写(BIO)波澜壮阔的一生

前言网上关于BIO和块设备读写流程的文章何止千万,但是能够让你彻底读懂读明白的文章实在难找,可以说是越读越糊涂!我曾经跨过山和大海 也穿过人山人海我曾经问遍整个世界 从来没得到答案本文用一个最简单的read(fd, buf, 4096)的代码,分析它从开始读到读结束,在整个Linux系统里面波澜壮阔的一生。本文涉及到的代码如下:#include <fcntl.h>#include <stdio.h>#include <stdlib.h>#inc

2020-06-04 14:26:14 117

转载 [IO系统]01 IO子系统

从整个IO调用链层面俯视整个链路,其穿越“千山万水”,最终会到胜利的彼岸——“设备层”接下来,分别说明每个层次的主要功能,后续文章再详细分析和说明。1.1应用顾名思义,应用就是程序,是用户态的。用户在进行IO读写操作编程时,有两种方法:1. 直接通过系统调用(如sys_open,sys_read,sys_write等等)操作文件,但是这种方法不够方便。2. 通过glib库提供的函数进行文件操作,如open/fopen,read/fread, write/fwrite等,gl...

2020-06-04 11:35:43 107

转载 [IO系统]08 IO读流程分析

1. 整体流程本文从整体来分析缓存IO的控制流和数据流,并基于IO系统图来解析读IO:注:对上述层次图的理解参见文章《[IO系统]01 IO子系统》一步一步往前走。(内核代码版本4.5.4)1.1 用户态程序的最终目的是要把数据写到磁盘上,如前所述,用户态有两个“打开”函数——read和fread。其中fread是glibc对系统调用read的封装。参见《[IO系统]02 用户态的文件IO操作》fread的流程在用户态的操作比较复杂,涉及到更多的数据复制和处理流程,本文不做介绍,..

2020-06-04 11:30:05 93

转载 linux文件预读发展过程

Linux文件预读算法磁盘I/O性能的发展远远滞后于CPU和内存,因而成为现代计算机系统的一个主要瓶颈。预读可以有效的减少磁盘的寻道次数和应用程序的I/O等待时间,是改进磁盘读I/O性能的重要优化手段之一。本文作者是中国科学技术大学自动化系的博士生,他在1998年开始学习Linux,为了优化服务器的性能,他开始尝试改进Linux kernel,并最终重写了内核的文件预读部分,这些改进被收录到Linux Kernel 2.6.23及其后续版本中。从寄存器、L1/L2高速缓存、内存、闪存,到磁盘/光盘/磁带

2020-06-04 10:50:23 72

转载 linux文件读写过程--各种层级结构

在《linux内核虚拟文件系统浅析》这篇文章中,我们看到文件是如何被打开、文件的读写是如何被触发的。对一个已打开的文件fd进行read/write系统调用时,内核中该文件所对应的file结构的f_op->read/f_op->write被调用。本文将顺着这条路走下去,大致看看普通磁盘文件的读写是怎样实现的。linux内核响应一个块设备文件读写的层次结构如图(摘自ULK3):1、VFS,虚拟文件系统。之前我们已经看到f_op->read/f_op->write如何被调用,这就

2020-06-02 16:17:48 92

原创 linux内核中的address_space 结构解析

在阅读Linux2.6的内核内存管理这一部分时,我看到page结构中的一个mapping成员,我感到很迷惑,这个成员的属性太复杂了,我们来看看:struct address_space *mapping;表示该页所在地址空间描述结构指针,用于内容为文件的页帧(1)如果page->mapping等于0,说明该页属于交换告诉缓存swap cache(2)如果page->mapping不等于0,但第0位为0,说明该页为匿名也,此时mapping指向一个struc...

2020-06-02 15:13:01 221

转载 iov_iter结构体

《存储技术原理分析》上讲到了结构体iovec的由来,概括起来就是我们通常用的系统调用read/write用于读取或写入文件,比如read用于读取数据到一个用户态缓冲区,readv读取数据到多个用户态缓冲区,那么为了兼容这两种syscall,引入了数据结构iovec,而iov_iter又是对iovec的迭代。故使用iov_iter结构体的本质是用于协助处理用户态缓冲区数据和页缓存之间的映射关系。以下内容是翻译过来的,原文内容链接:https://lwn.net/Articles/625077/1.

2020-06-01 16:23:58 124

原创 为啥C语言中的void *被称作万能指针

在进行c语言开发过程中,有时候会遇到void *这种数据类型。比如:void * memcpy(void * dest, const void * src, size_t n);void * memmove(void * dest, const void * src, size_t n);对于指针类型来说,不管是int *,char * 还是void*,亦或是struct stru*,这种类型都是值一个地址,在32位环境下,都是一个32位的无符号整形数值,表示一个地址。既然都是一个地址,为啥还

2020-05-29 16:41:48 99

原创 numpy中sum函数求和时参数axis=0和axis=1的含义

简单来说,对于一个m*n的矩阵,如果sum()的参数中没有指定axis,就是将所有的数值加到一起,得到1*1的标量。如果是axis=0,就是按照列进行加,得到一个1*n的行向量;如果axis=1,表示矩阵每一个行相加,得到一个m*1的列向量。例如:import numpy as npnp.sum([[0,1,2],[2,1,3],axis=1)结果就是:array([3,6])a = np.array([[0, 2, 1]])print a.sum()print a.sum(axi

2020-05-27 11:29:54 176

原创 linux 内核时间打印

struct timespec ts;ts = current_kernel_time();printk(KERN_ALERT "i=%d, channel=%d, %ld %ld\n", i, channel, ts.tv_sec, ts.tv_nsec); struct timeval tv;/*获取时间*/do_gettimeofday(&tv);printk(KERN_ALERT "now: %ld %ld\n", tv.tv_sec, tv.tv_usec); /*设置.

2020-05-22 14:35:11 77

原创 linux内核模块call trace格式解析

今天测试编写的内核模块进行文件读写,结果失败。通过dmesg查看内核输出,结果如下:[37725.645804] I am here! and the user buf size is 1024[37725.645812] The last data record position: 4096 current postion:0[37725.645818] buff size 8[37725.647660] BUG: unable to handle kernel

2020-05-20 14:06:36 563

原创 linux下写C程序编译出现 function declaration isnot a prototype问题和for loop initial declarations 的解决方案

今天在编译自己写的linux 内核模块的时候,报错如标题所示,指向我在episode.h文件中声明的函数extern int getCurrentTime();查过资料后发现,对于没有参数的函数,需要在函数的声明的时候,在参数列表里加上一个void,而在函数实现的地方却不需要。于是,改成extern int getCurrentTime(void);就可以编译通过啦。另一个错误是关于for语句的,也就是我们经常在for循环后面的控制条件里写的临时变量的定义的问题'for' loop initia

2020-05-19 14:52:42 81

转载 vs code中项目的基本配置--include路径、运行参数、debug配置

1.安装C/C++ for Visual Studio Code点击左边扩展栏图标—>搜索C/C++ -> 安装->Reload:安装完成之后,打开你的包含c++的文件夹,将会生成一个.vscode文件夹,所有的配置将在这个文件夹中进行配置。2.配置IntelliSense扩展程序会根据当前系统环境配置基本信息,因此有可能配置不完整,这时需要通过生成c_cpp_properties.json文件来配置缺少的信息:ctrl+shift+P打开Command Palette

2020-05-18 09:44:03 455

转载 红黑树的插入操作过程详细图解

说在前面对于文章中提到的左旋右旋等旋转详细过程请参考我的上一篇博客平衡二叉树插入操作的详细过程中的解决失衡的口诀方法,其中有旋转的详细图解过程红黑树 定义与性质 红黑树是一种含有红黑结点并能自平衡的二叉查找树 任意结点都有颜色,红色或者黑色 红黑树中根节点一定是黑色的 红黑树中的 null 位置看作是黑色 红黑树中红色不能与红色相邻 从根到所有 null 的路径上黑色结点的个数相同 红黑树中,最长的路径的长度,不会超过最短的路径的长度的2倍 时间复杂度:Olog

2020-05-09 15:30:04 88

转载 HashMap中 get 和 put 操作的具体过程

说在前面本文包含手写泛型HashMap<K,V>为简化版,仅为理解 HashMap 的 get() 和put() 方法的工作过程,非Java源码。get(K key) 原理先计算出key对应的hash值 int hash = key.hashCode();//此处的 hashCode() 方法为 Object对象 所属方法,默认都有//自定义的类需要覆写该方法 对超出数组范围的hash值进行处理 hash = (hash >>> 16)^hash;

2020-05-09 15:16:42 140

转载 平衡二叉树插入操作的详细过程图解

二叉搜索树/二叉排序树/二叉查找树是二叉树、任意结点的左子树的值均小于根节点的值,右子树均大于根节点的值 没有键值相等 平衡二叉树(AVL树) 定义 左右字数的高度差的绝对值不超过1,并且两子树都是平衡二叉树 没有键值相等 高度差,又名平衡因子,范围为[-1,0,1],在此规定==平衡因子 bf = 右子树的高度-左子树的高度== 插入操作 当有新的结点...

2020-05-08 08:22:53 163

提示
确定要删除当前文章?
取消 删除