zram压缩机制看swapon系统调用
1.swapon开启zram交换分区
swapon /dev/block/zram0
mkswap /dev/block/zram0
上面命令调用了linux的swapon系统调用启动zram0交换分区;mkswap命令向块设备文件/dev/block/zram0写入了swap_header信息
问题:实际安卓平台是哪里触发swapon和mkswap调用的,我们已MTK8195平台为例:
init.xxx.rc:swapon_all /vendor/etc/fstab.enableswap其中fstab.enableswap内容如下:
/dev/block/zram0 none swap defaults zramsize=xx%
那么swapon_all命令执行了哪里的代码呢?又是哪里解析fstab.enableswap文件呢,答案是:
system/core/init/builtins.cpp:
/* swapon_all [ <fstab> ] */
static Result<void> do_swapon_all(const BuiltinArguments& args) {auto swapon_all = ParseSwaponAll(args.args);if (!swapon_all.ok()) return swapon_all.error();Fstab fstab;if (swapon_all->empty()) {if (!ReadDefaultFstab(&fstab)) {return Error() << "Could not read default fstab";}} else {if (!ReadFstabFromFile(*swapon_all, &fstab)) {return Error() << "Could not read fstab '" << *swapon_all << "'";}}if (!fs_mgr_swapon_all(fstab)) { return Error() << "fs_mgr_swapon_all() failed";}return {};
}
而fs_mgr_swapon_all实现:/system/core/fs_mgr/fs_mgr.cpp:
bool fs_mgr_swapon_all(const Fstab& fstab) {...const char* mkswap_argv[2] = {MKSWAP_BIN,entry.blk_device.c_str(),};int err = logwrap_fork_execvp(ARRAY_SIZE(mkswap_argv), mkswap_argv, nullptr, false,LOG_KLOG, false, nullptr);if (err) {LERROR << "mkswap failed for " << entry.blk_device;ret = false;continue;}/* If -1, then no priority was specified in fstab, so don't set* SWAP_FLAG_PREFER or encode the priority */int flags = 0;if (entry.swap_prio >= 0) {flags = (entry.swap_prio << SWAP_FLAG_PRIO_SHIFT) & SWAP_FLAG_PRIO_MASK;flags |= SWAP_FLAG_PREFER;} else {flags = 0;}err = swapon(entry.blk_device.c_str(), flags);if (err) {LERROR << "swapon failed for " << entry.blk_device;ret = false;}...
}
2.swapon系统调用
kernel-5.15/mm/swapfile.c
swapon(...) {swap_file = file_open_name(name, O_RDWR|O_LARGEFILE, 0);p->swap_file = swap_file;mapping = swap_file->f_mapping;dentry = swap_file->f_path.dentry;inode = mapping->host;/** Read the swap header.*/if (!mapping->a_ops->readpage) {error = -EINVAL;goto bad_swap_unlock_inode;}page = read_mapping_page(mapping, 0, swap_file);if (IS_ERR(page)) {error = PTR_ERR(page);goto bad_swap_unlock_inode;}swap_header = kmap(page);maxpages = read_swap_header(p, swap_header, inode);...nr_extents = setup_swap_map_and_extents(p, swap_header, swap_map, cluster_info, maxpages, &span);...error = init_swap_address_space(p->type, maxpages);...
}
上面代码read_mapping_page是能够读取内容的关键是mapping对象,因为mapping->aops有readpage函数,但是这里mapping和mapping->aops是什么时候设置的?先公布答案:mapping的aops指向的是def_blk_aops,定义在kernel-5.15/block/fops.c:
const struct address_space_operations def_blk_aops = { .set_page_dirty = __set_page_dirty_buffers,.readpage = blkdev_readpage,.readahead = blkdev_readahead,.writepage = blkdev_writepage,.write_begin = blkdev_write_begin,.write_end = blkdev_write_end,.writepages = blkdev_writepages,.direct_IO = blkdev_direct_IO,.migratepage = buffer_migrate_page_norefs,.is_dirty_writeback = buffer_check_dirty_writeback,
};
但是这是什么代码路径设置进去的呢?我们就以zram为例:一切要从blk_alloc_disk函数说起
zram_drv.c:
static int zram_add(void)
{struct zram *zram;int ret, device_id;zram = kzalloc(sizeof(struct zram), GFP_KERNEL);if (!zram)return -ENOMEM;ret = idr_alloc(&zram_index_idr, zram, 0, 0, GFP_KERNEL);if (ret < 0)goto out_free_dev;device_id = ret;init_rwsem(&zram->init_lock);
#ifdef CONFIG_ZRAM_WRITEBACKspin_lock_init(&zram->wb_limit_lock);
#endif/* gendisk structure */zram->disk = blk_alloc_disk(NUMA_NO_NODE);...
}__blk_alloc_disk(kernel-5.15/block/genhd.c)-->__alloc_disk_node(kernel-5.15/block/genhd.c)--->bdev_alloc(kernel-5.15/block/bdev.c)struct block_device *bdev_alloc(struct gendisk *disk, u8 partno)
{struct block_device *bdev;struct inode *inode;inode = new_inode(blockdev_superblock);if (!inode)return NULL;inode->i_mode = S_IFBLK;inode->i_rdev = 0;inode->i_data.a_ops = &def_blk_aops;mapping_set_gfp_mask(&inode->i_data, GFP_USER);bdev = I_BDEV(inode);mutex_init(&bdev->bd_fsfreeze_mutex);spin_lock_init(&bdev->bd_size_lock);bdev->bd_partno = partno;bdev->bd_inode = inode;bdev->bd_stats = alloc_percpu(struct disk_stats);if (!bdev->bd_stats) {iput(inode);return NULL;}bdev->bd_disk = disk;return bdev;
}
看到bdev_alloc可以看到inode->i_data.a_ops = &def_blk_aops就是设置的地方了。同时这里还生成了block_device,我们再看下block_device是怎么生成的!!!这里的关键是上面的new_inode调用到了哪里?答案:kernel-5.15/fs/inode.c:new_inode函数:
kernel-5.15/fs/inode.c:struct inode *new_inode(struct super_block *sb)
{struct inode *inode;spin_lock_prefetch(&sb->s_inode_list_lock);inode = new_inode_pseudo(sb);if (inode)inode_sb_list_add(inode);return inode;
}kernel-5.15/fs/inode.c:struct inode *new_inode_pseudo(struct super_block *sb)
{struct inode *inode = alloc_inode(sb);if (inode) {spin_lock(&inode->i_lock);inode->i_state = 0;spin_unlock(&inode->i_lock);INIT_LIST_HEAD(&inode->i_sb_list);}return inode;
}kernel-5.15/fs/inode.c:static struct inode *alloc_inode(struct super_block *sb)
{const struct super_operations *ops = sb->s_op;struct inode *inode;if (ops->alloc_inode)//调用对应的alloc_inode,我们分析的场景调用到了kernel-5.15/block/bdev.c:bdev_alloc_inodeinode = ops->alloc_inode(sb);elseinode = kmem_cache_alloc(inode_cachep, GFP_KERNEL);if (!inode)return NULL;//很重要的初始化函数:inode_init_alwaysif (unlikely(inode_init_always(sb, inode))) {if (ops->destroy_inode) {ops->destroy_inode(inode);if (!ops->free_inode)return NULL;}inode->free_inode = ops->free_inode;i_callback(&inode->i_rcu);return NULL;}return inode;
}
最终new_inode调用到了kernel-5.15/fs/inode.c:z的alloc_inode函数如下:
static struct inode *bdev_alloc_inode(struct super_block *sb)
{struct bdev_inode *ei = kmem_cache_alloc(bdev_cachep, GFP_KERNEL);if (!ei)return NULL;memset(&ei->bdev, 0, sizeof(ei->bdev));return &ei->vfs_inode;
}int inode_init_always(struct super_block *sb, struct inode *inode)
{static const struct inode_operations empty_iops;static const struct file_operations no_open_fops = {.open = no_open};struct address_space *const mapping = &inode->i_data;inode->i_sb = sb;inode->i_blkbits = sb->s_blocksize_bits;inode->i_flags = 0;atomic64_set(&inode->i_sequence, 0);atomic_set(&inode->i_count, 1);inode->i_op = &empty_iops;inode->i_fop = &no_open_fops;inode->i_ino = 0;inode->__i_nlink = 1;inode->i_opflags = 0;if (sb->s_xattr)inode->i_opflags |= IOP_XATTR;i_uid_write(inode, 0);i_gid_write(inode, 0);atomic_set(&inode->i_writecount, 0);inode->i_size = 0;inode->i_write_hint = WRITE_LIFE_NOT_SET;inode->i_blocks = 0;inode->i_bytes = 0;inode->i_generation = 0;inode->i_pipe = NULL;inode->i_cdev = NULL;inode->i_link = NULL;inode->i_dir_seq = 0;inode->i_rdev = 0;inode->dirtied_when = 0;...mapping->a_ops = &empty_aops;mapping->host = inode;
}
相关文章:
zram压缩机制看swapon系统调用
1.swapon开启zram交换分区 swapon /dev/block/zram0 mkswap /dev/block/zram0 上面命令调用了linux的swapon系统调用启动zram0交换分区;mkswap命令向块设备文件/dev/block/zram0写入了swap_header信息 问题:实际安卓平台是哪里触发swapon和mkswap调用的ÿ…...

SpringBoot2+Vue3开发博客管理系统
项目介绍 博客管理系统,可以帮助使用者管理自己的经验文章、学习心得、知识文章、技术文章,以及对文章进行分类,打标签等功能。便于日后的复习和回忆。 架构介绍 博客管理系统采用前后端分离模式进行开发。前端主要使用技术:Vu…...
JS【详解】Symbol (含Symbol 作为属性名,静态方法for 和 keyFor,11 个内置的 Symbol 值)
ES6 语法,表示唯一且不可变的值,常用作属性键值或者唯一标识符。 let a Symbol() let a Symbol(atomic symbol)console.log(Symbol() Symbol()) // false console.log(Symbol(atom) Symbol(atom)) // falseSymbol 作为属性名 let key Symbol(); le…...

Vue 项目运行时,报错Error: Cannot find module ‘node:path‘
Vue 项目运行时,报错Error: Cannot find module ‘node:path’ internal/modules/cjs/loader.js:883throw err;^Error: Cannot find module node:path Require stack: - D:\nodejs\node_modules\npm\node_modules\node_modules\npm\lib\cli.js - D:\nodejs\node_mo…...

综合评价 | 基于组合博弈赋权的物流系统综合评价(Matlab)
目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 综合评价 | 基于组合博弈赋权的物流系统综合评价(Matlab) 组合博弈赋权(Weighted Sum)是一种常见的多目标决策方法,用于将多个目标指标进行综合评估和权衡…...

国标GB28181视频汇聚平台EasyCVR安防监控系统常见播放问题分析及解决方法
国标GB28181安防综合管理系统EasyCVR视频汇聚平台能在复杂的网络环境中,将前端设备统一集中接入与汇聚管理。平台支持多协议接入,包括:国标GB/T 28181协议、GA/T 1400协议、RTMP、RTSP/Onvif协议、海康Ehome、海康SDK、大华SDK、华为SDK、宇视…...

30 哈希的应用
位图 概念 题目 给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何判断一个数是否在这40亿个整数中 1.遍历,时间复杂度O(N) 2.二分查找,需要先排序,排序(N*logN),二分查找,logN。…...

(笔记)Error: qemu-virgl: Failed to download resource “qemu-virgl--test-image“解决方法
错误: > Downloading https://www.ibiblio.org/pub/micro/pc-stuff/freedos/files/distributions/1.2/FD12FLOPPY.zip curl: (22) The requested URL returned error: 404Error: qemu-virgl: Failed to download resource "qemu-virgl--test-image" D…...
IntelliJ IDEA介绍
IntelliJ IDEA 是由 JetBrains 开发的一个集成开发环境 (IDE),专门为 Java 开发设计,同时也支持多种其他编程语言和框架。IntelliJ IDEA 以其智能代码分析、强大的重构功能以及丰富的插件生态系统而闻名,是许多开发者的首选 IDE。 IntelliJ IDEA介绍 IntelliJ IDEA 的主要…...
【office技巧】如何合并pdf并且添加目录页
所用工具:wps,acrobat reader 1.制作目录页 在wps里设置一级标题,二级标题,然后自动生成目录页,保存为pdf。 在acrobat reader里删除除了目录页之外的其他页面。 2.pdf合并 在acrobat reader里合并pdf。 注意有可能…...
Spring Boot中的安全性配置详解
Spring Boot中的安全性配置详解 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!今天我们将深入探讨如何在Spring Boot应用中实现全面的安全性配置,保…...
数据权限和字段权限设计指南
数据权限和字段权限的设计是信息系统安全的基础。随着数据量的增加和用户需求的多样化,合理的权限设计变得愈加重要。本文将介绍数据权限和字段权限的基本概念、设计思路和实际应用,帮助读者建立全面的权限管理体系。 2. 数据权限设计 2.1 数据权限的定…...
Linux 常用命令之 RZ和SZ 简介
一、引言 在Linux系统管理中,尤其是在远程操作时,文件的上传与下载是常见的需求。对于CentOS用户而言,rz和sz这两个命令提供了简单而高效的文件传输方式,尤其在SSH终端环境中更为便利。本文将详细介绍rz和sz命令的基本概念、如何…...
Docker Compose:简化多容器管理的利器
在现代的应用开发和部署过程中,Docker已经成为不可或缺的工具。它通过容器化技术,使得应用的部署变得更加轻松和高效。然而,当我们需要管理和运行多个容器时,单纯依赖Docker命令行工具可能会显得繁琐且复杂。这时,Dock…...

深度解析:机器学习如何助力GPT-5实现语言理解的飞跃
文章目录 文章前言机器学习在GPT-5中的具体应用模型训练与优化机器翻译与跨语言交流:情感分析与问答系统:集成机器学习功能:文本生成语言理解任务适应 机器学习对GPT-5性能的影响存在的挑战及解决方案技术细节与示例 文章前言 GPT-5是OpenAI公…...

Springcloud-消息总线-Bus
1.消息总线在微服务中的应用 BUS- 消息总线-将消息变更发送给所有的服务节点。 在微服务架构的系统中,通常我们会使用消息代理来构建一个Topic,让所有 服务节点监听这个主题,当生产者向topic中发送变更时,这个主题产生的消息会被…...
js 接收回调函数 转换为promise
下面是一个示例代码,展示如何编写一个接收回调函数并将其转换为 Promise 的 JavaScript 函数: // 定义一个接收回调函数并转换为 Promise 的函数 function convertCallbackToPromise(callbackFunction) {// 返回一个新的 Promise 对象return new Promis…...

Python 面试【★★★】
欢迎莅临我的博客 💝💝💝,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…...

计算机网络(物理层)
物理层 物理层最核心的工作内容就是解决比特流在线路上传输的问题 基本概念 何为物理层?笼统的讲,就是传输比特流的。 可以着重看一下物理层主要任务的特性 传输媒体 传输媒体举例: 引导型传输媒体 引导型传输媒体指的是信号通过某种…...

OpenGL-ES 学习(6)---- 立方体绘制
目录 立方体绘制基本原理立方体的顶点坐标和绘制顺序立方体颜色和着色器实现效果和参考代码 立方体绘制基本原理 一个立方体是由8个顶点组成,共6个面,所以绘制立方体本质上就是绘制这6个面共12个三角形 顶点的坐标体系如下图所示,三维坐标…...
三维GIS开发cesium智慧地铁教程(5)Cesium相机控制
一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点: 路径验证:确保相对路径.…...

CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...

STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...
GitHub 趋势日报 (2025年06月06日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...