深入了解 Linux 中的 MTD 设备:/dev/mtd* 与 /dev/mtdblock*
目录
- 前言
- 一、什么是MTD子系统?
- 二、 `/dev/mtd*` 设备文件
- 用途
- 注意事项
- 三、`/dev/mtdblock*` 设备文件
- 用途
- 注意事项
- 三、这两种设备文件的关系
- 四、关norflash的一些小知识
前言
在嵌入式Linux系统的世界里,非易失性存储技术扮演着至关重要的角色。MTD(Memory Technology Device)子系统是Linux内核的一个组成部分,它为各种类型的闪存和EEPROM设备提供了一个统一的接口。本文将深入探讨Linux系统中的两种MTD设备文件:/dev/mtd*和/dev/mtdblock*,它们的用途、区别以及如何在实际场景中应用这些知识。

一、什么是MTD子系统?
MTD(Memory Technology Device)子系统是 Linux 内核中的一个子系统,用于管理非易失性存储器设备,如闪存芯片(NAND、NOR 等)。MTD 子系统提供了一组通用的接口和驱动程序,使得 Linux 能够方便地访问和操作这些存储设备。
MTD 子系统的主要功能包括:
-
设备抽象和管理:MTD 子系统提供了一个设备抽象层,允许系统对不同类型的非易失性存储设备进行统一的管理。它提供了一种通用的方式来表示和操作这些设备,无论它们是基于 NAND、NOR 还是其他技术。
-
设备擦除和编程:MTD 子系统允许 Linux 内核对支持擦除和编程操作的存储设备执行这些操作。这对于闪存等设备是至关重要的,因为它们通常需要在写入新数据之前先擦除存储单元。
-
分区支持:MTD 子系统允许将存储设备划分为多个逻辑分区,每个分区可以独立管理。这使得在同一个物理设备上实现多个逻辑存储空间成为可能,可以用于实现文件系统、内核映像等。
-
驱动程序支持:MTD 子系统提供了一组通用的驱动程序接口,使得开发者可以编写适配不同类型存储设备的驱动程序,并将其与 MTD 子系统集成起来。
总的来说,MTD 子系统为 Linux 内核提供了与非易失性存储设备交互的标准接口,使得开发者可以更方便地实现对这些设备的管理、操作和访问。
二、 /dev/mtd* 设备文件
/dev/mtd*设备文件是MTD子系统的核心组成部分。这些文件代表了系统中的MTD设备,通常用于访问小块的、页对齐的内存区域。每个/dev/mtd*设备文件都有一个数字后缀,例如/dev/mtd0、/dev/mtd1等,这些数字代表了设备在系统中的索引。
用途
- 系统更新:
/dev/mtd*设备常用于更新系统的引导加载程序(bootloader)和内核。在嵌入式系统中,这些组件通常存储在闪存设备上,需要通过MTD子系统进行更新。 - 数据存储:某些系统可能会使用MTD设备来存储关键的数据,如U-Boot环境变量或其他系统配置信息。
- 设备测试:开发者可以使用
/dev/mtd*设备文件来测试闪存设备的读写性能和可靠性。
注意事项
- 访问
/dev/mtd*设备文件通常需要root权限。 - 由于MTD设备通常用于存储关键的系统数据,因此在对其进行操作时需要格外小心,以避免数据丢失或系统损坏。
三、/dev/mtdblock* 设备文件
与/dev/mtd*不同,/dev/mtdblock*设备文件提供了对MTD设备的块设备接口。这意味着它们可以被挂载为文件系统,并以块为单位进行读写操作。/dev/mtdblock*设备文件的命名方式与/dev/mtd*类似,也使用数字后缀来区分不同的设备。
用途
- 文件系统挂载:
/dev/mtdblock*设备文件可以挂载为文件系统,用于存储操作系统、应用程序或用户数据。这对于没有传统硬盘驱动器的嵌入式设备尤其有用。 - 数据分区:通过使用
/dev/mtdblock*设备,开发者可以在闪存设备上创建多个分区,每个分区可以独立地挂载和管理。 - 系统恢复:在系统崩溃或损坏的情况下,
/dev/mtdblock*设备可以用于恢复系统镜像或重要的配置文件。
注意事项
- 在对
/dev/mtdblock*设备进行写操作之前,应确保没有任何文件系统挂载在其上。 - 与
/dev/mtd*一样,访问/dev/mtdblock*设备文件也需要root权限。
三、这两种设备文件的关系
这些不同的设备文件通常对应同一块存储区域。比如在使用 NOR Flash 存储器时,不同的设备文件只是提供了不同的访问方式和操作权限,但是它们对应的确实是同一个物理空间或逻辑分区。
举例来说,当你在一个嵌入式系统中使用 NOR Flash 存储器时,可能会看到 /dev/mtd0 、/dev/mtdblock0 和 /dev/mtd0ro 这几个设备文件,它们对应的都是 NOR Flash 存储器中的同一个物理空间或逻辑分区。其中 /dev/mtd0 和 /dev/mtdblock0 提供了不同的读写方式,/dev/mtd0ro 则是只读的。这些设备文件允许用户以不同的方式与 NOR Flash 存储器进行交互和访问,例如可以进行烧写、读取和执行代码等操作。
因此,无论是块设备文件还是字符设备文件,以及只读设备文件,它们都可以对应同一块存储区域或相同的物理空间。区别在于它们提供了不同的权限和访问方式,以满足不同的使用需求。
四、关norflash的一些小知识
在 NOR Flash 存储器中,一个 block 的大小通常是 64KB(64 * 1024 字节)。这个 block 大小是 NOR Flash 存储器常见的值,但实际上在不同型号的 NOR Flash 存储器中,block 的大小可能会有所不同。因此,在具体使用时,需要查阅相关的数据手册或规格说明来确认所使用的 NOR Flash 存储器 block 的确切大小。
对于 NOR Flash 存储器来说,通常是在对其进行写操作之前需要先擦除。这是因为 NOR Flash 存储器中的存储单元(如字节或扇区)在执行写操作时,是将数据从逻辑值 1 写入逻辑值 0,因此需要先将要写入的存储单元擦除为逻辑值 1,然后再写入新的数据。
具体来说,擦除操作会将存储单元的数据全部置为逻辑值 1,而写操作则是将特定的存储单元从逻辑值 1 写入为逻辑值 0。如果在进行写操作时不进行擦除,那么由于 NOR Flash 存储器一般不支持原地写入(in-place write),可能会导致写入的数据无法正确覆盖之前的数据,从而产生错误数据或不稳定的状态。
因此,为了确保 NOR Flash 存储器中数据的正确性和稳定性,通常在进行写操作之前需要先执行擦除操作。在擦除操作和写操作过程中,还需要注意避免中断电等意外情况,以确保数据的完整性和一致性。
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/mtd/mtd.h>
#include <linux/mtddll.h>#define MTD_DEVICE_0 "/dev/mtd0"
#define MTD_DEVICE_1 "/dev/mtd1"int main() {int mtd0_fd, mtd1_fd;struct mtd_info_user mtd_info;struct erase_info_user erase_info;ssize_t bytes_read, bytes_written;char buffer[4096]; // 读取/写入的缓冲区大小// 打开第一个MTD设备进行读取if ((mtd0_fd = open(MTD_DEVICE_0, O_RDONLY)) < 0) {perror("Error opening MTD device 0");return EXIT_FAILURE;}// 获取MTD设备信息if (ioctl(mtd0_fd, MEMGETINFO, &mtd_info) < 0) {perror("Error getting MTD device information");close(mtd0_fd);return EXIT_FAILURE;}// 打开第二个MTD设备进行写入if ((mtd1_fd = open(MTD_DEVICE_1, O_WRONLY)) < 0) {perror("Error opening MTD device 1");close(mtd0_fd);return EXIT_FAILURE;}// 擦除第二个MTD设备的相关块for (int i = 0; i < mtd_info.eraseblocks; i++) {erase_info.start = i * mtd_info.erasesize;erase_info.length = mtd_info.erasesize;if (ioctl(mtd1_fd, MEMERASE, &erase_info) < 0) {perror("Error erasing MTD device 1");close(mtd0_fd);close(mtd1_fd);return EXIT_FAILURE;}}// 从第一个MTD设备读取数据while ((bytes_read = read(mtd0_fd, buffer, sizeof(buffer))) > 0) {// 将数据写入第二个MTD设备bytes_written = write(mtd1_fd, buffer, bytes_read);if (bytes_written != bytes_read) {perror("Error writing to MTD device 1");close(mtd0_fd);close(mtd1_fd);return EXIT_FAILURE;}}// 关闭MTD设备文件描述符close(mtd0_fd);close(mtd1_fd);printf("Data transfer from MTD device 0 to MTD device 1 completed successfully.\n");return EXIT_SUCCESS;
}
在这个示例中,我们使用MEMERASEioctl调用来擦除/dev/mtd1设备上的每个擦除块。erase_info_user结构体被用来指定要擦除的块的起始地址和长度。这个操作通常比读取和写入操作慢,因此在实际应用中,您可能希望优化这个过程,例如通过并行擦除或使用更高效的写入策略。
请记住,擦除操作是破坏性的,因此在执行之前应该确保数据已经备份。此外,确保您有足够的权限来执行这些操作,通常需要root权限。在实际部署之前,应该在受控环境中彻底测试代码,以避免数据丢失。
/*
BLKGETSIZE64 用于获取块设备的大小(以字节为单位),返回的值是一个 unsigned long long 类型
的整数,表示设备的总容量。这个命令通常用于获取大于 2 TB 的设备大小,因为 BLKGETSIZE 在 32
位系统上可能会出现溢出问题。BLKGETSIZE 用于获取块设备的大小(以扇区为单位),返回的值是一个 long 类型的整数,表示设备
的总扇区数。通常情况下,这个命令可以满足大多数小于 2 TB 的设备大小获取需求。
*/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>#define MTD_BLOCK_DEVICE "/dev/mtdblock0"int main() {int fd;unsigned long long erase_size, total_size;unsigned int erase_flags = 0; // 通常为0,表示默认擦除选项// 打开MTD块设备进行读写if ((fd = open(MTD_BLOCK_DEVICE, O_RDWR)) < 0) {perror("Error opening MTD block device");return EXIT_FAILURE;}// 获取MTD块设备的擦除大小和总大小if (ioctl(fd, BLKGETSIZE64, &total_size) != 0) {perror("Error getting device size");close(fd);return EXIT_FAILURE;}erase_size = total_size; // 假设整个设备需要擦除// 擦除MTD块设备if (ioctl(fd, BLKERASE, &erase_size) != 0) {perror("Error erasing MTD block device");close(fd);return EXIT_FAILURE;}// 准备要写入的数据const char *data_to_write = "This is a test.\n";size_t data_len = strlen(data_to_write) + 1; // 加1是为了包括字符串的终止符'\0'// 从设备开头开始写入数据if (write(fd, data_to_write, data_len) != data_len) {perror("Error writing to MTD block device");close(fd);return EXIT_FAILURE;}// 关闭MTD块设备close(fd);printf("Data successfully written to MTD block device.\n");return EXIT_SUCCESS;
}
在这个示例中,我们首先打开/dev/mtdblock0设备进行读写操作。然后,我们使用BLKGETSIZE64ioctl调用来获取设备的总大小。接着,我们使用BLKERASEioctl调用来擦除整个设备。最后,我们使用write函数将一个简单的字符串写入设备。
请注意,这个示例代码假设整个设备都需要擦除,这可能不是所有情况的最佳实践。在实际应用中,您可能需要根据设备的擦除块大小和您的写入需求来计算需要擦除的确切区域。
在编译和运行此代码之前,请确保您有足够的权限(通常需要root权限),并且/dev/mtdblock*设备文件确实存在于您的系统中。您可以使用以下命令来编译代码:
gcc -o mtdblock_write mtdblock_write.c
然后,使用以下命令以root用户身份运行编译后的程序:
sudo ./mtdblock_write
请记住,在对MTD设备进行操作时,您应该非常小心,因为不正确的操作可能会导致数据丢失。在实际部署之前,务必在受控环境中进行彻底的测试。
欢迎大家指导和交流!如果我有任何错误或遗漏,请立即指正,我愿意学习改进。期待与大家一起进步!
相关文章:
深入了解 Linux 中的 MTD 设备:/dev/mtd* 与 /dev/mtdblock*
目录 前言一、什么是MTD子系统?二、 /dev/mtd* 设备文件用途注意事项 三、/dev/mtdblock* 设备文件用途注意事项 三、这两种设备文件的关系四、关norflash的一些小知识 前言 在嵌入式Linux系统的世界里,非易失性存储技术扮演着至关重要的角色。MTD&#…...
2、Spring CLI安装
安装 Spring CLI 提供了多种格式,让您选择自己喜欢的安装方法。可下载的制品可从发布页面获取。 二进制发行版 WindowsLinuxMac手动安装(Windows,其他自己看) spring-cli-standalone-<version>-windows.x86_64.zip - 打包了 x86 JDKspring-cli-installer-<versi…...
数据库备份工具(实现数据定时覆盖)
数据库备份工具(实现数据定时覆盖) 永远热爱,永远执着! 工具介绍 自动化测试数据库更新调度程序 这段 Python 脚本自动化了每天定时从生产数据库更新测试数据库的过程。它利用了 schedule 库来安排并执行每天指定时间的更新任务…...
测试环境搭建整套大数据系统(十二:挂载磁盘到hadoop环境)
一:链接硬盘 将硬盘连接到计算机的 SATA 接口或 USB 接口,并确保硬盘通电并处于可用状态。 二:查看硬盘信息 sudo fdisk -l三:创建分区 gdisk /dev/vbd重新扫描磁盘 partprobe /dev/vdb格式化磁盘 mkfs.ext4 /dev/vdb2查看磁…...
Spring事务核心:声明式事务注解式事务
全解:声明式事务和注解事务 在Spring中,事务管理是一个非常重要的特性,它可以帮助开发者在应用程序中实现事务控制。Spring提供了两种事务管理方式:声明式事务和注解事务。 1. 声明式事务 声明式事务是指通过配置文件或注解的方…...
AcWing 1015. 摘花生
Problem: AcWing 1015. 摘花生 文章目录 思路解题方法复杂度Code 思路 这是一个典型的动态规划问题。我们需要在一个二维网格中,从左上角走到右下角,每次只能向右或向下移动,目标是使得经过的路径上的数字之和最大。 我们可以定义dp[i][j]为从…...
Dalle-3、Sora、Stable Diffusion 3 掀起AIGC新浪潮
随着科技的飞速发展,我们迎来了视觉AIGC高光时刻,一个充满无限可能与机遇的新时代。在这个时代里,三大里程碑Dalle-3、Sora和Stable Diffusion 3以其炸裂式的技术发展,引领着AIGC领域的新浪潮。文章首先做相应简要介绍,…...
Unity 视频组件 VideoPlayer
组件添加: 在自己定义的组件下(例如:Panel) 点击 Inspector 面板中的 AddComponent ,输入“VideoPlayer”。 资源 这里 视频资源有两种形式,第一种是 VideoClip ,需要将视频文件拖拽到该属性字段…...
RSTP环路避免实验(华为)
思科设备参考:RSTP环路避免实验(思科) 一,技术简介 RSTP (Rapid Spanning Tree Protocol) 是从STP发展而来 • RSTP标准版本为IEEE802.1w • RSTP具备STP的所有功能,可以兼容STP运行 • RSTP和STP有所不同 减少了…...
Arduino IDE工程代码多文件编程和中文设置
一、esp8266模块信息 二、中英文切换 点击文件( File )–选择首选项( Preference )—选择语言( Language )—选择中文–点击确定( OK ) 三、多文件编程 在Arduino编程中,将代码分割成多个文件是一种很好的做法,特别是项目变得越来越大和复杂时。这样…...
【微服务】Eureka(服务注册,服务发现)
文章目录 1.基本介绍1.学前说明2.当前架构分析1.示意图2.问题分析 3.引出Eureka1.项目架构分析2.上图解读 2.创建单机版的Eureka1.创建 e-commerce-eureka-server-9001 子模块2.检查父子pom.xml1.子 pom.xml2.父 pom.xml 3.pom.xml 引入依赖4.application.yml 配置eureka服务5.…...
windows上ssh设置代理,直接访问公司内网
ssh设置代理一般来说很简单,对于无密码或者可以支持密钥登录的,都比较无脑 难的地方在于使用用户名密码认证来使用一个http的代理或者socks5的代理,密码如何设置?特殊字符如何处理? 直接上答案,.ssh/conf…...
C++ union用法
在C中,union是一种特殊的数据类型,可以在同一个内存位置存储不同的数据类型。它的用法如下: 1. 声明union类型:使用关键字union加上union名称来声明一个union类型。 c union UnionName { dataType1 member1; dataType2 …...
JavaSE_运算符 案例分析
/*符号在字符串中的操作: 表示连接,会将其他内容和字符串连接在一起,形成一个字符串目标:理解符号在字符串中的作用会将其他内容和字符串连接在一起,形成一个字符串*/ public class Operator03 {public static void main(String[] args) {System.out.println("5 5 "…...
15、Spring Cloud Alibaba Sentinel实现熔断与限流
注:本篇文章主要参考周阳老师讲解的cloud进行整理的! 1、Sentinel 1.1、官网 https://sentinelguard.io/zh-cn/ 等价对标 Spring Cloud Circuit Breaker 1.2、是什么 https://github.com/alibaba/Sentinel/wiki 1.3、去哪下 https://github.com/alibab…...
Linux logout命令教程:如何安全地退出Linux会话(附实例详解和注意事项)
Linux logout命令介绍 logout命令用于退出当前的登录Shell。这个命令可以被普通用户用来结束他们自己的会话。 Linux logout命令适用的Linux版本 logout命令在所有主流的Linux发行版中都是可用的,包括但不限于Debian、Ubuntu、Alpine、Arch Linux、Kali Linux、R…...
数据结构——顺序表(C语言版)
顺序表是数据结构中最基本的一种线性表,它以一段连续的存储空间来存储数据元素,元素之间的顺序由它们在内存中的位置来决定。在C语言中,我们通常使用数组来实现顺序表。 目录 顺序表的结构定义 顺序表的基本操作 应用实例 顺序表的结构定义…...
Knative 助力 XTransfer 加速应用云原生 Serverless 化
作者:元毅 公司介绍 XTransfer 是一站式外贸企业跨境金融和风控服务公司,致力于帮助中小微企业大幅降低全球展业的门槛和成本,提升全球竞争力。公司连续7年专注 B2B 外贸金融服务,已成为中国 B2B 外贸金融第一平台,目…...
服务器离线配置vscode连接,conda虚拟环境
记录一下服务器离线配置问题,以备不时之需。 服务器离线配置 vscode连接参考:vscode-server离线安装-CSDN博客 服务器离线配置conda虚拟环境:Conda 环境离线迁移(服务器断网情况下搭建虚拟环境envs) - 知乎 上次两个…...
各种需要使用的方法-->vue/微信小程序/layui
各种需要使用的方法-->vue/微信小程序/layui 1、vue里样式不起作用的方法,可以通过deep穿透的方式2、 js获取本周、上周、本月、上月日期3、ArrayBuffer Blob 格式转换ArrayBuffer与Blob的区别ArrayBuffer转BlobBlob转ArrayBuffer需要借助fileReader对象 4、使用…...
避坑指南:WFDB读取ECG数据时,.hea文件真的‘几乎没用’吗?
避坑指南:WFDB读取ECG数据时,.hea文件真的‘几乎没用’吗? 在生物信号处理领域,WFDB(Waveform Database)格式是存储心电图(ECG)数据的黄金标准。许多开发者习惯性地认为.hea头文件只…...
【CentOS】sshd服务启动失败全攻略:从权限修复到目录缺失的完整解决方案
1. 当sshd服务罢工时,我们该从哪里入手? 每次遇到sshd服务启动失败,就像面对一台突然熄火的汽车——你明明记得昨天还好好的,今天却怎么都打不着火。作为运维人员,这种情况再熟悉不过了。最近我就遇到一个典型案例&…...
GKD规则冲突检测:自动化识别并提示重叠规则问题
GKD规则冲突检测:自动化识别并提示重叠规则问题 在GKD自动化工具的使用过程中,规则冲突检测是一个至关重要的功能。当多个订阅规则同时作用于同一个应用时,可能会出现规则重叠或相互干扰的情况。GKD的智能冲突检测机制能够自动识别这些问题&…...
DocHub二次开发指南:自定义功能扩展与API集成
DocHub二次开发指南:自定义功能扩展与API集成 【免费下载链接】DocHub 参考百度文库,使用Beego(Golang)开发的开源文库系统 项目地址: https://gitcode.com/gh_mirrors/do/DocHub DocHub是基于Beego框架(Golang…...
用STM32CubeMX配置PWM捕获:从定时器选型到串口输出全流程
STM32CubeMX实战:PWM捕获全流程解析与调试技巧 在嵌入式开发中,精确测量PWM信号的周期和占空比是常见需求。本文将带你从零开始,使用STM32CubeMX和HAL库完成PWM捕获功能的完整实现。不同于简单的教程复制,我们会深入探讨两种捕获…...
攻克模电难点(一):多级放大电路与差动放大电路实战解析
1. 多级放大电路的设计基础 第一次接触多级放大电路时,我被各种耦合方式绕得头晕。直到在实验室烧坏几个三极管后,才真正理解其中的门道。多级放大电路的核心思想很简单:把多个单级放大电路像搭积木一样连接起来,但实际设计时却要…...
告别重复造轮子,用快马平台一键生成OpenClaw高效工具模块
最近在做一个机器人控制项目,需要集成OpenClaw机械爪模块。传统开发方式需要从零开始写大量重复代码,效率很低。后来尝试用InsCode(快马)平台生成核心模块,效果出乎意料的好。这里分享下具体实现思路和优化点: 安全初始化模块设计…...
专治写作卡点!这几款 AI 续写软件,让论文写作像呼吸一样简单
写论文最怕卡壳?大纲想破头、续写没思路、降重改到哭,还怕 AI 痕迹露馅?2026 年这几款 AI 续写软件,直击本科生、研究生核心痛点,从选题到答辩一站式搞定,让写作效率翻倍!一、PaperRedÿ…...
WarcraftHelper技术适配方案:让经典RTS游戏重获现代硬件支持
WarcraftHelper技术适配方案:让经典RTS游戏重获现代硬件支持 【免费下载链接】WarcraftHelper Warcraft III Helper , support 1.20e, 1.24e, 1.26a, 1.27a, 1.27b 项目地址: https://gitcode.com/gh_mirrors/wa/WarcraftHelper 痛点解析:魔兽争霸…...
【微知】Mellanox网卡配置异常?mlxconfig reset全解与实战场景指南
1. Mellanox网卡配置异常?先别慌 遇到Mellanox网卡配置异常时,很多工程师第一反应是重装驱动或者更换硬件。其实在大多数情况下,用对mlxconfig reset这个神器就能快速解决问题。我处理过上百台配备Mellanox网卡的服务器,发现80%的…...
