Я не могу дублировать ioctl(fd, BLKFLSBUF)
ошибки в Ubuntu 14.04.4 LTS на x86_64 с использованием ядра 4.2.0-42.
Я тестировал как полноразмерные устройства, так и отдельные разделы на них. Не могли бы вы попробовать следующую минимальную тестовую программу?
Сохраните следующее, например. блок-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;
}
Скомпилируйте его с помощью
gcc -Wall -O2 block-flush.c -o block-flush
и запустить его (как корень), указывающий раздел (ы) или блочное устройство (ы) в командной строке:
sudo ./block-flush /dev/sda3
для меня это выводит /dev/sdxN: Flushed.
для немонтированных перегородок, а также дисков (/dev/sdx
) сами. (Кроме того, добавление fdatasync(descriptor)
до того, как ioctl() ничего не изменит, и он тоже успешно прошел без каких-либо ошибок.)
Кроме того, мне довелось проверить это с помощью внешней док-станции USB SATA и «громкого» 3,5-дюймового диска (такие доки, которые требуют внешнего питания, USB-мощность недостаточна для этих больших дисков с вращающимися планшетами). Я легко мог слышать, что ioctl() действительно имеет доступ к физическому устройству, поэтому он не является no-op (и, опять же, минимальная тестовая программа никогда не сообщала о каких-либо сбоях в моих тестах). После закрытия дескриптора диск также находится в состоянии покоя, пока диск или разделы не будут открыты для дальнейшего доступа. Конечно, эти наблюдения действительны только для жестких дисков, подключенных к USB, и только на эту конкретную ядерную и аппаратную архитектуру, но, на мой взгляд, это указывает на то, что ioctl(descriptor, BLKFLSBUF);
должен работать для размонтированных partiti так и полноблочных устройств.
Использует прямой ввод-вывод или/dev/raw вариант? –
Что вы имеете в виду, * «fsync(), очевидно, недоступен в сыром разделе» *? 'fsync (_fd)' и 'fdatasync (_fd)' должны очищать содержимое до базового устройства, даже если '_fd' относится к блочному устройству. Фактическая промывка выполняется с помощью [fs/block_dev.c: blkdev_fsync()] (https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/fs/block_dev.c# n368) (через [fs/sync.c: fdatasync()] (https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/fs/sync.C# n230) → do_fsync() → vfs_fsync() → vfs_fsync_range(), затем blkdev_fsync() через структуру file_operations). –
@MarkPlotnick - я открываю/dev/sda3. not/dev/raw. Я взял другую машину, где работал hdparam -W 0. Тем не менее ioctl не работает с errno = 25. Поэтому мой вопрос: могу ли я использовать ioctl BLKFLSHBUF на/dev/sdxN? – Adi