ext4 - delay allocation数据结构

ext4的延迟分配 Ext4文件系统在应用程序调用write的时候并不为缓存页面分配对应的物理磁盘块,当文件的缓存页面真正要被刷新至磁盘中时,ext4会为所有未分配物理磁盘块的页面缓存分配尽量连续的磁盘块。         Linux文件系统Vfs层总是将应用程序的写入请求分割成页面(默认大小4KB)为单位,对于每个页面,VFS会检查其是否已经为其创建了buffer_head结构,如果没有创建,则为其创建buffe 阅读详情
概述

延迟分配delay allocation是ext4非常重要的特性,启用该特性write系统将用户空间buffer写入内存page cache中即返回,此时也不会真正进行磁盘block分配,而是延迟到磁盘回写时(比如dirty ratio达到一定值,定时刷新,主动sync等) 才开始映射磁盘block(map block)进行块分配,好处就是可以将连续的块进行合并merge,结合ext4的mballoc多块分配机制,可以一次性分配多个物理block,降低cpu使用率和碎片化问题。本文将根据内核源码分析ext4的delay allocation机制,脏页达到阈值后台writeback场景分析,其调用栈:

remote Thread 1 In: ext4_writepages                                                                                                                                              Line: 2634 PC: 0xffffffff8155cc91 
#0  ext4_writepages (mapping=0xffff8880062459d0, wbc=0xffff888000a27a60) at fs/ext4/inode.c:2634
#1  0xffffffff8134255a in do_writepages (mapping=0xffff8880062459d0, wbc=0xffff888000a27a60) at mm/page-writeback.c:2352
#2  0xffffffff814697c5 in __writeback_single_inode (inode=0xffff888006245858, wbc=0xffff888000a27a60) at fs/fs-writeback.c:1461
#3  0xffffffff8146a06c in writeback_sb_inodes (sb=<optimized out>, wb=0xffff88800442e060, work=0xffff888000a27d50) at fs/fs-writeback.c:1721
#4  0xffffffff8146a4ff in __writeback_inodes_wb (wb=0xffff88800442e060,	work=0xffff888000a27d50) at fs/fs-writeback.c:1790
#5  0xffffffff8146a9d9 in wb_writeback (wb=0xffff88800442e060, work=0xffff888000a27d50)	at fs/fs-writeback.c:1896
#6  0xffffffff8146c865 in wb_check_background_flush (wb=<optimized out>) at fs/fs-writeback.c:1964
#7  wb_do_writeback (wb=<optimized out>) at fs/fs-writeback.c:2052
#8  wb_workfn (work=0xffff88800442e1f0)	at fs/fs-writeback.c:2080
#9  0xffffffff81196a32 in process_one_work (worker=0xffff8880009f0400, work=0xffff88800442e1f0)	at kernel/workqueue.c:2269
#10 0xffffffff81196de9 in worker_thread (__worker=0xffff8880009f0400) at kernel/workqueue.c:2415
#11 0xffffffff811a0a89 in kthread (_create=<optimized out>) at kernel/kthread.c:292
数据结构
writeback_control
/*
 * A control structure which tells the writeback code what to do.  These are
 * always on the stack, and hence need no locking.  They are always initialised
 * in a manner such that unspecified fields are set to zero.
 */
struct writeback_control {
	long nr_to_write;		/* Write this many pages, and decrement
					   this for each page written */
	long pages_skipped;		/* Pages which were not written */

	/*
	 * For a_ops->writepages(): if start or end are non-zero then this is
	 * a hint that the filesystem need only write out the pages inside that
	 * byterange.  The byte at `end' is included in the writeout request.
	 */
	loff_t range_start;
	loff_t range_end;

	enum writeback_sync_modes sync_mode;

	unsigned for_kupdate:1;		/* A kupdate writeback */
	unsigned for_background:1;	/* A background writeback */
	unsigned tagged_writepages:1;	/* tag-and-write to avoid livelock */
	unsigned for_reclaim:1;		/* Invoked from the page allocator */
	unsigned range_cyclic:1;	/* range_start is cyclic */
	unsigned for_sync:1;		/* sync(2) WB_SYNC_ALL writeback */

	/*
	 * When writeback IOs are bounced through async layers, only the
	 * initial synchronous phase should be accounted towards inode
	 * cgroup ownership arbitration to avoid confusion.  Later stages
	 * can set the following flag to disable the accounting.
	 */
	unsigned no_cgroup_owner:1;

	unsigned punt_to_cgroup:1;	/* cgrp punting, see __REQ_CGROUP_PUNT */

    ...
};

1.sync_mode字段

/*
 * fs/fs-writeback.c
 */
enum writeback_sync_modes {
	WB_SYNC_NONE,	/* Don't wait on anything */
	WB_SYNC_ALL,	/* Wait on every mapping */
};

源码备注很清晰,WB_SYNC_NONE : 不需要等待数据真正落盘返回,WB_SYNC_ALL需要等待数据落盘完成返回,sync调用使用。

2. range_cyclic  字段

 值为 1 表示当前任务的回写范围为整个 inode,并且从上次完成的位置作为起始位置进行循环回写。值为 0 则根据 struct writeback_control wbc 的 range_start 以及 range_end 作为回写的范围。

static int ext4_writepages(struct address_space *mapping,
               struct writeback_control *wbc) {
    ...
    if (wbc->range_cyclic) {
        writeback_index = mapping->writeback_index;
        if (writeback_index)
            cycled = 0;
        mpd.first_page = writeback_index;
        mpd.last_page = -1;
    } else {
        mpd.first_page = wbc->range_start >> PAGE_SHIFT;
        mpd.last_page = wbc->range_end >> PAGE_SHIFT;
    }
    ...
}

3. for_update字段

值为 1 表示当前任务是定期回写任务,用于回写已经至脏超过指定时间的脏页。通过get_nr_dirty_pages获取回写的page数量。

static long wb_check_old_data_flush(struct bdi_writeback *wb)
{
    unsigned long expired;
    long nr_pages;

    /*
     * When set to zero, disable periodic writeback
     */
    if (!dirty_writeback_interval)
        return 0;

    expired = wb->last_old_flush +
            msecs_to_jiffies(dirty_writeback_interval * 10);
    if (time_before(jiffies, expired))
        return 0;

    wb->last_old_flush = jiffies;
    nr_pages = get_nr_dirty_pages();

    if (nr_pages) {
        struct wb_writeback_work work = {
            .nr_pages   = nr_pages,
            .sync_mode  = WB_SYNC_NONE,
            .for_kupdate    = 1,
            .range_cyclic   = 1,
            .reason     = WB_REASON_PERIODIC,
        };

        return wb_writeback(wb, &work);
    }

    return 0;
}

4. for_background 字段

值为 1 表示当前任务是阈值回写任务,当脏页比例超过阈值后才会触发。

static long wb_check_background_flush(struct bdi_writeback *wb)
{
    if (wb_over_bg_thresh(wb)) {

        struct wb_writeback_work work = {
            .nr_pages   = LONG_MAX,
            .sync_mode  = WB_SYNC_NONE,
            .for_background = 1,
            .range_cyclic   = 1,
            .reason     = WB_REASON_BACKGROUND,                                                                                                                          
        };

        return wb_writeback(wb, &work);
    }

    return 0;
}

5. for_sync字段

值为 1 表示当前任务是阈值回写任务 sync 系统调用手动触发的回写任务。

/**
 * sync_inodes_sb   -   sync sb inode pages
 * @sb: the superblock
 *
 * This function writes and waits on any dirty inode belonging to this
 * super_block.
 */
void sync_inodes_sb(struct super_block *sb)
{
    DEFINE_WB_COMPLETION_ONSTACK(done);
    struct wb_writeback_work work = {
        .sb     = sb,
        .sync_mode  = WB_SYNC_ALL,
        .nr_pages   = LONG_MAX,
        .range_cyclic   = 0,
        .done       = &done,
        .reason     = WB_REASON_SYNC,
        .for_sync   = 1,                                                                                                                                                 
    };
    ...

    wait_sb_inodes(sb);
}

6. for_reclaim 字段

主要来自mm模块,比如回收page将dirty page回写时设置:

static pageout_t pageout(struct page *page, struct address_space *mapping,
             struct scan_control *sc)
{
    ...
    
    if (clear_page_dirty_for_io(page)) {
        int res;
        struct writeback_control wbc = {
            .sync_mode = WB_SYNC_NONE,
            .nr_to_write = SWAP_CLUSTER_MAX,
            .range_start = 0,
            .range_end = LLONG_MAX,
            .for_reclaim = 1,
        };
    ...
}

7. nr_to_write 字段

回写的页面数量,注意单位是page。

问题:for_background阈值触发回写时候,wbc中的nr_to_write要回写多少page?

fs/fs-writeback.c中计算而得
static long writeback_chunk_size(struct bdi_writeback *wb,
				 struct wb_writeback_work *work)
{
	long pages;

	/*
	 * WB_SYNC_ALL mode does livelock avoidance by syncing dirty
	 * inodes/pages in one big loop. Setting wbc.nr_to_write=LONG_MAX
	 * here avoids calling into writeback_inodes_wb() more than once.
	 *
	 * The intended call sequence for WB_SYNC_ALL writeback is:
	 *
	 *      wb_writeback()
	 *          writeback_sb_inodes()       <== called only once
	 *              write_cache_pages()     <== called once for each inode
	 *                   (quickly) tag currently dirty pages
	 *                   (maybe slowly) sync all tagged pages
	 */
	if (work->sync_mode == WB_SYNC_ALL || work->tagged_writepages)
		pages = LONG_MAX;
	else {
		pages = min(wb->avg_write_bandwidth / 2,
			    global_wb_domain.dirty_limit / DIRTY_SCOPE);
		pages = min(pages, work->nr_pages);
		pages = round_down(pages + MIN_WRITEBACK_PAGES,
				   MIN_WRITEBACK_PAGES);
	}

	return pages;
}

8. tagged_writepages

回写标记为PAGECACHE_TAG_TOWRITE的页。

mpage_da_data
/*
 * Delayed allocation stuff
 */

struct mpage_da_data {
	struct inode *inode;
	struct writeback_control *wbc;

	pgoff_t first_page;	/* The first page to write */
	pgoff_t next_page;	/* Current page to examine */
	pgoff_t last_page;	/* Last page to examine */
	/*
	 * Extent to map - this can be after first_page because that can be
	 * fully mapped. We somewhat abuse m_flags to store whether the extent
	 * is delalloc or unwritten.
	 */
	struct ext4_map_blocks map;
	struct ext4_io_submit io_submit;	/* IO submission data */
	unsigned int do_map:1;
	unsigned int scanned_until_end:1;
};
  • inode : address_space->host对应的文件inode
  • wbc:即上文提到的writeback_control,记录writeback的信息
  • first_page : 回写的第一个页面
  • next_page : 正在操作回写(examine)的page。
  • last_page :最后一个操作回写的page
  • map : 存储文件逻辑块号和磁盘物理块号的映射
  • scanned_until_end:是否达到文件末尾

ext4_map_blocks数据结构

struct ext4_map_blocks {
	ext4_fsblk_t m_pblk; // 物理块号,相对于文件系统而言的
	ext4_lblk_t m_lblk; // 逻辑块号,相对于文件的
	unsigned int m_len; // 长度,单位为文件块
	unsigned int m_flags; // 映射关系的各种标记,参考EXT4_MAP_NEW附近的宏定义
};

物理块号:ext4文件系统默认将磁盘划分为4K的块,每一个4K的block有一个物理块号,物理块号从0开始,由于文件系统系统的磁盘空间可能是个分区,因此通用块层根据下发的物理块号计算真正的磁盘的sector(512B一般)时要加上分区的sector偏移。

逻辑块号:逻辑块号是相对于文件而言的,对于上层应用来说文件的内容是连续的,而实际的物理存储块号可能不连续,也可以把文件以4K为一个单位分割,比0-4K-1范围的文件的逻辑块号为0,依次类推增加。

extent status tree

ext4在内存中为每个文件维护一颗extent status tree,起初这树的名字是delay extent tree,是为了区分delay extent。ext4的delay allocation特性,真正分配physical block是推迟到page cache writeback时候进行,这里面临一个问题,根据ext4理论篇文章我们知道,extent tree是存储在磁盘上的,启用delay allocation特性的时候没有为写入的数据分配physical block,那么自然文件磁盘的extent tree没有更新。此时如果要区分文件的一个extent,到底是delay allocation的,还是hole,就只能去看文件的address space中有没有该extent对应的page cache,这种实现会有很多问题,所以在内存维护了extent status tree,dealloc的时候,write routine不会为写入数据分配physical block,但是会往extent status tree中插入一个delay extent status.

除了维护delay extent status之外,将磁盘的extent status缓存到内存中,也能加快extent status的查询速度,因而文件的extent status tree除了维护delay extent status之外,实际上还是磁盘中的extent tree的映像。

每个ext4 inode都维护一颗extent status tree,实际上是一个rbtree,其中所有extent status按照logical block number排序。

struct ext4_inode_info {
    /* extents status tree */
    struct ext4_es_tree i_es_tree;
    ...
}
struct ext4_es_tree {
    struct rb_root root;
    struct extent_status *cache_es; /* recently accessed extent */
};

extent status

extent status tree中的每个节点就是一个extent status,每个extent status实际上就是磁盘上一个extent的缓存。

struct extent_status {
    struct rb_node rb_node;
    ext4_lblk_t es_lblk;    /* first logical block extent covers */
    ext4_lblk_t es_len; /* length of extent in block */
    ext4_fsblk_t es_pblk;   /* first physical block */
};

 extent status分为几种类型,分别是written/unwritten/delay/hole/referenced,@es_pblk高位存储extent status 类型:

enum {
    ES_WRITTEN_B,
    ES_UNWRITTEN_B,
    ES_DELAYED_B,
    ES_HOLE_B,
    ES_REFERENCED_B,
    ES_FLAGS
};

delay

delay extent status描述delay allocation对应的extent,此时es_lblk/es_len有效,而es_pblk无效,如果上文提到delay allocation开启时,write routine写入page cache时不会分配physical block,而是往extent status tree中添加一个delay extent status中:

fs/ext4/inode.c : ext4_da_map_blocks

 hole

hole extent status描述文件的一个hole,此时es_lblk/es_len有效,而es_pblk字段无效。在extent lookup过程中,读取磁盘的extent tree后,如果发现传入的logical block number没有对应的extent,就会往extent status tree中插入一个hole extent status。

written

written extent status就是平常所说的磁盘中存储的extent tree在内存中缓存,此时es_lblk/es_len/es_pblk均有效。

unwritten

unwritten extent status也是磁盘中存储的extent tree的内存中的缓存,但是和written extent status的区别在于,unwritten extent status主要用户描述fallocate syscall分配的extent。

为了满足对于fallocate预分配的磁盘空间执行读操作英翻返回0的定义,一种实现时对预分配的physical block做填0处理,但是这种操作很低效,ext4中的实现是在extent tree中区分written/unwritten extent,written extent就是映射通过正常的写操作分配的physical tree,而unwritten extent则是映射通过fallocate预分配的physical block,这样read遇到unwritten extent可以返回0.

ext4中使用ee_len的最高bit来区分written/unwritten

struct ext4_extent {
    __le16  ee_len;     /* number of blocks covered by extent */
    ...
};

@ee_len 是一个 16 bit 的数据,其最高 bit 来用于区分 written/unwritten extent

  • @ee_len 的值小于等于 0x8000 表示 written extent,也就是说最高 bit 为 0、或者最高 bit 为 1 但是其余 bit 都为 0 的情况下,表示 written extent,也就是说 written extent 最大为 0x8000 个 block 大小,即 block size 为 4KB 时,written extent 最大为 128MB 大小
  • @ee_len 的值大于 0x8000 表示 unwritten extent

因而 unwritten extent status 实际上也是磁盘中存储的 unwritten extent 在内存中的缓存,此时 @es_lblk/es_len/es_pblk 都是有效的

ext4_ext_path 
/*
 * Array of ext4_ext_path contains path to some extent.
 * Creation/lookup routines use it for traversal/splitting/etc.
 * Truncate uses it to simulate recursive walking.
 */
struct ext4_ext_path {
	ext4_fsblk_t			p_block;
	__u16				p_depth;
	__u16				p_maxdepth;
	struct ext4_extent		*p_ext;
	struct ext4_extent_idx		*p_idx;
	struct ext4_extent_header	*p_hdr;
	struct buffer_head		*p_bh;
};

/*
 * This is the extent on-disk structure.
 * It's used at the bottom of the tree.
 */
struct ext4_extent {
	__le32	ee_block;	/* first logical block extent covers */
	__le16	ee_len;		/* number of blocks covered by extent */
	__le16	ee_start_hi;	/* high 16 bits of physical block */
	__le32	ee_start_lo;	/* low 32 bits of physical block */
};

/*
 * This is index on-disk structure.
 * It's used at all the levels except the bottom.
 */
struct ext4_extent_idx {
	__le32	ei_block;	/* index covers logical blocks from 'block' */
	__le32	ei_leaf_lo;	/* pointer to the physical block of the next *
				 * level. leaf or next index could be there */
	__le16	ei_leaf_hi;	/* high 16 bits of physical block */
	__u16	ei_unused;
};

/*
 * Each block (leaves and indexes), even inode-stored has header.
 */
struct ext4_extent_header {
	__le16	eh_magic;	/* probably will support different formats */
	__le16	eh_entries;	/* number of valid entries */
	__le16	eh_max;		/* capacity of store in entries */
	__le16	eh_depth;	/* has tree real underlying blocks? */
	__le32	eh_generation;	/* generation of the tree */
};

上述数据结构用来表示磁盘extent b+数据结构,比如:

图中数字范围是logical block number 

参考文章:

Ext4 - extent status tree - LostJeffle

Linux磁盘存储底层原理:块设备、分区表与文件系统全解析 在Linux系统中,‘磁盘’并非物理硬件的直接映射,而是一套分层抽象体系——从底层的块设备(如/dev/sda)开始,经由分区表(MBR/GPT)划分逻辑区域,再通过文件系统(ext4/xfs/btrfs)构建可读写的目录结构,最终挂载到统一命名空间。理解块设备的I/O接口特性、分区对齐对SSD性能的影响、日志机制与Extent设计如何提升ext4可靠性,以及挂载生命周期导致df与du差异等核心原理,是保障服务器存储稳定、规避rm -rf误操作、实现高效故障排查的技术根基。本文深入拆解这一完整技术栈。 阅读详情

相关推荐

Ubuntu 18.04 部署 Elastic Stack 的三大隐性冲突与实战调优

Elasticsearch 是一个基于 Lucene 构建的分布式搜索与分析引擎,其稳定运行高度依赖操作系统底层支持。在 Linux 环境中,尤其是 Ubuntu 18.04 这类默认启用 systemd-resolved 和 ext4 写屏障的发行版,常因 DNS 解析异常、JVM 内存锁定冲突及文件系统 I/O 性能瓶颈导致服务静默失败。技术价值在于通过内核参数调优、Java 版本锁定与服务配置协同,实现从‘能启动’到‘可生产’的跨越。典型应用场景包括日志分析平台 PoC 验证、本地开发环境快速搭建及面

devon2014的博客 372

ext4 delalloc相关

ext4文件系统delayed allocation功能的相关研究

江风的专栏 4030

Unity异步数据导入:UniTask实现外部模型的自动导入

在Unity开发中,异步编程是提升应用响应性和用户体验的关键技术。其核心原理在于将耗时的I/O或计算任务转移到后台线程执行,从而避免阻塞主线程,确保UI流畅和交互即时响应。这项技术的价值在于优化资源密集型操作,例如模型加载、文件读写或网络请求,是实现高性能应用的基础。在游戏开发、3D内容创作工具等场景中,异步处理能显著改善启动速度和运行时性能。本文聚焦于利用UniTask库,构建一个高效、健壮的外部模型自动导入系统,通过文件监控、任务队列和真正的后台处理,解决传统同步导入导致的主线程卡顿问题,并深入探讨了异

weixin_30247307的博客 465

磁盘数据读取监测返回值errno,是否能完全捕捉到磁盘故障引发的错误

今天有同事提了个问题,上层应用针对文件读操作做了错误处理,处理方法为如果read失败,且errno = EIO, 则认为磁盘上该文件出现坏道,并做后续的相关补救操作。 线上有台机器上的一个磁盘出现问题,持续几周大量打印: May 2 04:12:41 kernel: [30114401.884862] sd 0:1:0:5: [sdf] FAILED Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE May 2 04:12:41 kernel: [30

Vic的博客 3587

【信息科学与工程学】【运营科学】第二篇 C4信息与通信网络运营 (C4) ——数据中心网络运营01

这是运营的物理和逻辑对象。C4.11xx 传输资源:光纤、微波、卫星链路;频谱资源(Sub-6GHz, 毫米波)。C4.12xx 节点资源:核心路由器、交换机、基站(gNB)、数据中心服务器。C4.13xx 虚拟化资源:由NFV生成的虚拟网络功能(VNF)、容器、虚拟机和网络切片实例。这是实现智能、灵活运营的核心技术集。C4.21xx 软件定义与虚拟化:软件定义网络 (SDN):控制平面与数据平面分离,实现集中、可编程的网络控制。网络功能虚拟化 (NFV):将传统专用硬件设备的功能以软件形式运行在通用硬件上

weixin_49199313的博客 1450

【信息科学与工程学】【通信工程】第一百五十五篇 SRv6/SDN网络中的算法01

1 确定性路由算法 SRv6 控制平面 显式路径计算 SRv6段列表优化算法 1. 输入:源节点S,目标节点D,约束条件集合C={c₁,...,cₘ}<br>2. 构建有向图G(V,E),V为节点集

weixin_49199313的博客 255

调优之文件调优

08 Tunning Filesystem 文件系统调优 ================================================================================== 一、了解文件系统 VFS虚拟文件系统 虚拟文件系统向系统调用屏蔽了不同底层文件系统的差异 用户执行一个操作 系统调用 访问的是系统调用 EXT3 P

tangshiweibbs的专栏 417

【信息科学与工程学】计算机科学与自动化 第二百三十三篇 凤凰架构02

① Firecracker 为每个 microVM 提供极简设备模型:virtio-net, virtio-blk, serial console。:① BB84:Alice 随机选择基矢(+ 或 ×)发送单光子,Bob 随机测量基矢,比对后保留一致位的子集作为原始密钥。:密度 1 EB/mm³;:① Parquet 文件:行组(Row Group)→ 列块(Column Chunk)→ 页(Page)。

weixin_49199313的博客 136

ext4 delay allocation之ext4_writepages页回写源码剖析

ext4 write写入pagecache之后,再合适的时机会回写到磁盘,ext4文件系统中是通过ext4_writepages写入磁盘,本来将在源码角度分析该过程。建议先参照ext4 - delay allocation数据结构_nginux的博客-优快云博客看下涉及的重要数据结构。

GetnextWindow的专栏 1152

python123题目——个税计算器

类型:简单分支。

m0_62488776的博客 5802

遥感数据下载——FIRM:VIIRS火点数据、MODIS火点数据简介及下载

一、FIRMS(Fire Information for Resoutce Management System) 网站链接:https://firms.modaps.eosdis.nasa.gov/map/ 这个网站上对VIIRS及MODIS的火灾数据进行了显示,可以进行按日期、产品类别等动态的展示火点数据或火烧迹地,同时也提供了数据下载控件。高级选择中还可以进行数据统计结果展示。 二、VIIR...

knkn123的博客 3万+

Linux内核学习:EXT4 文件系统在 Linux 内核系统中的读写过程

目录 1 概述 2 虚拟文件系统 与 Ext4 文件系统 2.1 sys_write( ) 代码跟踪 2.2 sys_write( ) 过程分析 2.3 sys_write( ) 的核心部分 vfs_write( ) 2.4 ext4_file_write( ) 2.4.1 ext4文件系统的extent 2.4.2ext4_file_write( ) 2.5 generic...

Henry_Fordham——一个姓雪的程序员小哥哥 8186

《从0到1:CTFer成长之路》书籍配套题目-[第二章 web进阶]文件上传

[第二章 web进阶]文件上传开始行动绕过第1个限制绕过第2个限制 介绍:记录一下笔记,方便以后迅速回忆使用。 《从0到1:CTFer成长之路》书籍配套题目,来源网站:《从0到1:CTFer成长之路》 先看一下题目源码: <?php header("Content-Type:text/html; charset=utf-8"); // 每5分钟会清除一次目录下上传的文件 require_once('pclzip.lib.php'); if(!$_FILES){ echo '

weixin_46703850的博客 3410

【转】ext4+delalloc造成单次写延迟增加的分析

转自 http://blog.tao.ma/?p=58 这篇文章是淘宝内核组的刘峥同学在内部技术论坛上发表的一篇文章,但是由于刘峥同学目前没有blog,征得本人同意,贴在我的blog上,如果大家喜欢,请去新浪微博关注他。:) 日前线上在升级到Ext4文件系统后出现应用写操作延迟开销增大的问题。造成这一问题的根源目前已经查明,是由于Ext4文件系统的一个新特性——Delay Allocation

chongyang198999的专栏 606

Cadence Allegro实战:如何精准导入结构DXF文件避免安装偏差(附图层配置技巧)

本文详细讲解了在Cadence Allegro中精准导入结构DXF文件以避免安装偏差的实战技巧。核心在于导入前的单位校准、创建专用图层结构,以及基于坐标基准点的精确对齐方法。文章还分享了将DXF图形转化为正式板框和禁布区、高效管理图层以及向结构工程师导出DXF的完整流程,帮助PCB工程师确保设计与机械结构完美契合。

1a2s3d4f5g的博客 506

设计数据库 ER 图太麻烦?不妨试试这两款工具,自动生成数据库 ER 图!!!

告别手动画图,提高效率~

楼下小黑哥 2万+

[转载]ext4文件系统的delalloc选项造成单次写延迟增加的分析

转载http://www.cnblogs.com/cobbliu/p/5603472.html 最近我们的服务进程遇到kill -15后处于Z的状态,变为了僵尸进程,经过/proc/{thread_id}/stack查看其上线程的栈,发现是卡在了fwrite的过程中,而我们的系统中所有文件系统挂载参数都使用了delalloc参数,怀疑是这个原因:ext4挂载的时候打开了delalloc选项,然后系...

weixin_33912453的博客 87

国产化办公新选择:在银河麒麟V10上部署ToDesk远程桌面

本文详细介绍了在国产操作系统银河麒麟V10上部署ToDesk远程桌面的完整指南。作为国产远程控制工具,ToDesk在连接速度、系统适配性和用户体验方面表现优异,特别适合国产化办公场景。文章包含X86和ARM架构的安装步骤、常见问题排查及性能优化技巧,帮助用户高效实现远程办公。

weixin_33742618的博客 231

MPK架构解析:持久化内存与操作系统内核的创新设计

持久化内存技术正在重塑现代计算架构,其字节寻址和非易失性特性为系统设计带来新范式。传统操作系统通过page cache管理存储的架构面临挑战,需要新的内核设计实现内存与存储的统一管理。MPK(Mirage Persistent Kernel)采用创新的地址空间映射机制,消除传统存储栈开销,直接操作持久化内存区域。这种架构通过CLWB缓存行刷新技术保证原子写入,配合redo日志实现崩溃一致性,实测可提升4K随机写性能3.7倍。在NUMA架构中,MPK的首次接触分配策略能减少60%跨节点访问,其轻量级进程模型使

weixin_30301449的博客 452

VSCode终端打不开?3分钟搞定Windows下Terminal配置(附最新JSON设置方法)

本文针对Windows系统下VSCode终端无法启动的常见问题,提供了详细的诊断与解决方案。核心在于更新已弃用的旧配置,采用最新的JSON设置方法,通过定义`terminal.integrated.profiles.windows`和指定`terminal.integrated.defaultProfile.windows`,快速修复并优化终端配置,实现三分钟内恢复正常使用。

flower的专栏 740

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

Fiber 官方 FAQ 精讲:应用结构、404 处理、热重载、错误处理、子域路由、net/http 互操作与疑难排查

本篇以 Fiber(Go 生态中受 Express 启发的 Web 框架,当前仓库为 v3 主线)的官方 FAQ 为主体,逐一拆解开发者最高频的九个问题:项目如何分层、404 页面如何自定义、如何接入 Air 实现代码热重载、如何定制全局错误处理器、支持哪些模板引擎、如何用一台服务承载多个子域名、如何与标准库 `net/http` 互通,以及那个最令人头疼的 HPACK/gRPC 崩溃如何定位与修

gitblog_00322的博客 716

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Spark on YARN 部署模式与资源参数配置实战指南

在大数据处理领域,资源调度是分布式计算框架的核心机制之一。Apache Spark 作为主流计算引擎,通常需要与 YARN(Yet Another Resource Negotiator)等资源管理器协同工作,以实现集群资源的统一分配与管理。其原理在于,Spark 通过 `spark-submit` 提交作业时,会将计算任务分解为 Driver 和 Executor 角色,并由 YARN 将其映射为 Container 进行资源隔离与调度。这一机制的技术价值在于能够高效利用集群资源,支持多租户、多任务并发执

weixin_30279671的博客 452

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

ESP32 Arduino开发终极指南:从零到精通的完整实践路线

ESP32作为物联网开发领域的明星芯片,凭借其强大的双核处理器、丰富的无线连接能力和出色的功耗控制,已成为众多开发者的首选平台。Arduino ESP32项目将ESP32的强大功能与Arduino的易用性完美结合,为开发者提供了一个高效、便捷的开发环境。无论您是刚接触物联网的新手,还是希望将现有项目迁移到ESP32的资深开发者,本文都将为您提供从环境搭建到高级应用的完整解决方案。 ## 开发环境

gitblog_00206的博客 370

基于ESP32与MLX90614的智能红外测温枪DIY全攻略

红外测温技术通过检测物体表面发出的红外辐射能量来非接触测量温度,其核心原理基于斯特藩-玻尔兹曼定律。这项技术将物理信号转换为电信号,经处理芯片校准后输出温度值,具有快速、安全、不干扰被测对象的优势。在物联网和智能硬件领域,红外测温广泛应用于工业监测、医疗电子、智能家居及设备健康管理。通过结合ESP32主控的Wi-Fi/蓝牙连接能力和MLX90614高精度传感器,可以构建具备数据上传、远程报警及历史记录功能的智能测温终端。本项目详细介绍了从电路设计、低功耗固件开发到云端数据可视化的完整实现过程,为DIY爱好者

weixin_33739541的博客 348

从创客项目到实用产品:硬件方案选型与嵌入式开发实战解析

在嵌入式系统与物联网开发领域,硬件方案选型是项目成功的关键基础。其核心原理在于根据具体功能需求,将抽象问题映射为可执行的技术指标,并权衡性能、成本与开发复杂度。这一过程的技术价值在于,它能帮助开发者规避常见陷阱,构建稳定可靠的系统,从而将创意高效转化为实用产品。典型的应用场景包括智能家居控制、人机交互设备以及个性化数码产品等。本文以声控鼠标、自动灯控和复古怀表三个具体项目为例,深入剖析了从需求拆解到传感器选型、主控配置及电源设计的完整逻辑,并重点探讨了如何利用Arduino Leonardo的USB HID

weixin_34295316的博客 478
上一篇: Linux pagecache writeback的一个性能优化patch分析
下一篇: ext4 delay allocation之ext4_writepages页回写源码剖析
OS技术解密
博客等级 码龄16年 3760粉丝 189原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值