我正在尝试使用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找到合适的冲洗方法?
答案 0 :(得分:2)
I cannot duplicate ioctl(fd, BLKFLSBUF)
errors in Ubuntu 14.04.4 LTS on x86_64 using 4.2.0-42-generic kernel.
I tested both full block devices, and individual partitions on them. Could you try the following minimal test program?
Save the following as e.g. block-flush.c:
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
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;
}
Compile it using
gcc -Wall -O2 block-flush.c -o block-flush
and run it (as root), specifying the partition(s) or block device(s) at the command line:
sudo ./block-flush /dev/sda3
For me, this outputs /dev/sdxN: Flushed.
for unmounted partitions, as well as the disks (/dev/sdx
) themselves. (Also, adding fdatasync(descriptor)
before the ioctl() does not change anything, and it too succeeds without any errors.)
Also, I happened to test this using an external USB SATA docking station and a "loud" 3.5" drive (such docks needing external power; USB power not being sufficient for these larger drives with spinning platters). I could easily hear that the ioctl() does access the physical device, so it is not a no-op (and, again, the minimal test program never reported any failures in my tests). After closing the descriptor, the disk is also quiescent until the disk or partitions are opened for further accesses. Of course, these observations are only valid for USB-connected hard drives, and only on this particular kernel and hardware architecture, but in my opinion, it does indicate that the ioctl(descriptor, BLKFLSBUF);
should work for unmounted partitions and full block devices, in the expected manner.