linux 刷新磁盘分区,如何在linux中使用ioctl(原始分区)正确刷新磁盘缓存

我正在尝试使用ioctl来确保直接写入卷的更改正在访问磁盘.

fsync()显然在原始分区中不可用. sync()也是一个可怕的解决方案(为了冲洗64MB,我需要整个生命时间等待同步)

所以..这就是我想要做的事情 – 得到错误25.

/ dev / sda3是ssd驱动器上的原始卸载分区open(_fd, "/dev/sda3", ...)

pwritev(_fd, ...)

ioctl(_fd, BLKFLSBUF, 0) <== errno = 25.

Ubuntu 14.04,c

注意:hdparm -W 0 /dev/sda3

失败:对设备不适当的ioctl.

如何为我的ssd找到合适的冲洗方法?

最佳答案 我不能使用4.2.0-42泛型内核在x86_64上的Ubuntu 14.04.4 LTS中复制ioctl(fd,BLKFLSBUF)错误.

我测试了两个完整的块设备,以及它们上的各个分区.你能试试下面的最小测试程序吗?

保存以下内容,例如块flush.c:#include

#include

#include

#include

#include

#include

#include

#include

int main(int argc, char *argv[])

{

int arg, descriptor, result;

if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {

fprintf(stderr, "\n");

fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);

fprintf(stderr, " %s BLOCK-DEVICE-OR-PARTITION ...\n", argv[0]);

fprintf(stderr, "\n");

return EXIT_FAILURE;

}

for (arg = 1; arg < argc; arg++) {

do {

descriptor = open(argv[arg], O_RDWR);

} while (descriptor == -1 && errno == EINTR);

if (descriptor == -1) {

const int cause = errno;

fprintf(stderr, "%s: Cannot open device: %s [%d].\n", argv[arg], strerror(cause), cause);

return EXIT_FAILURE;

}

errno = 0;

result = ioctl(descriptor, BLKFLSBUF);

if (result && errno) {

const int cause = errno;

fprintf(stderr, "%s: Cannot flush device: %s [%d].\n", argv[arg], strerror(cause), cause);

return EXIT_FAILURE;

} else

if (result)

fprintf(stderr, "%s: Flush returned %d.\n", argv[arg], result);

else

if (errno) {

const int cause = errno;

fprintf(stderr, "%s: Flush returned zero, but with error: %s [%d]. Ignored.\n", argv[arg], strerror(cause), cause);

}

result = close(descriptor);

if (result == -1) {

const int cause = errno;

fprintf(stderr, "%s: Error closing device: %s [%d].\n", argv[arg], strerror(cause), cause);

return EXIT_FAILURE;

}

fprintf(stderr, "%s: Flushed.\n", argv[arg]);

}

return EXIT_SUCCESS;

}

使用编译它gcc -Wall -O2 block-flush.c -o block-flush

并运行它(以root身份),在命令行指定分区或块设备:sudo ./block-flush /dev/sda3

对我来说,这输出/ dev / sdxN:刷新.对于未安装的分区,以及磁盘(/ dev / sdx)本身. (另外,在ioctl()之前添加fdatasync(描述符)不会改变任何东西,并且它也会成功而没有任何错误.)

此外,我碰巧使用外部USB SATA扩展坞和“响亮的”3.5“驱动器(这种扩展需要外部电源; USB电源不足以满足这些带有旋转盘片的大型驱动器)进行测试.我很容易听到ioctl ()确实访问物理设备,所以它不是无操作(并且,最小的测试程序再次没有报告我的测试中的任何失败).关闭描述符后,磁盘也是静止的,直到磁盘或分区是当然,这些观察仅适用于USB连接的硬盘驱动器,并且只适用于这种特定的内核和硬件架构,但在我看来,它确实表明ioctl(描述符,BLKFLSBUF);应该适用于未预装的分区和完整的块设备,以预期的方式.

### Linux 内核中读取和写入操作的实现原理 #### 文件系统的抽象层 Linux 内核通过虚拟文件系统 (VFS) 层来提供统一接口,用于访问不同类型的文件系统。这允许应用程序无需关心底层具体存储介质或文件系统类型即可执行 I/O 操作[^1]。 #### 系统调用机制 当用户空间进程发起 `read` 或 `write` 请求时,会触发相应的系统调用进入内核模式。此时 VFS 将请求转发给特定文件系统的实现模块去完成实际的数据传输工作[^2]。 对于字符设备而言,在驱动程序内部通常定义了一组针对该类设备的操作方法表(file_operations),其中包含了诸如 open、close、ioctl 及 read/write 函数指针等成员变量;而对于块设备,则由专门负责管理磁盘分区及其上文件系统的逻辑处理单元来进行数据交换过程控制[^3]。 #### 缓存与同步策略 为了提高效率并减少频繁访问物理媒介带来的延迟开销,Linux 还引入了页缓存(Page Cache),它能够暂存最近使用的页面副本以便快速响应后续相同位置处发生的连续性 IO 请求。此外,为了避免多个并发线程间可能引发的竞争条件问题,操作系统采用锁机制确保每次只有一个实体可以修改共享资源状态直至事务结束为止[^4]。 ```c ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { ssize_t ret; if (!(file->f_mode & FMODE_READ)) return -EBADF; // ... 更多代码 ... } ``` 上述代码片段展示了vfs_read函数的部分实现细节,此函数位于fs/read_write.c源码文件之中,属于VFS层面的一部分,用来处理来自高层API传下来的读取指令,并最终映射到具体的文件系统或者设备驱动上去执行真正的I/O动作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值