LINUX.ORG.RU

Ошибка обработки запроса в блочном устройстве


0

0

Есть свой собственнй модуль для блочного устройств по ядро 2.4.27.

В нем есть функция block_request которая инициализируется как обработчик очереди.

После обработки запроса (чтения или записи), если все хорошо end_request(1)

Но если возникает ошибка обработки запроса, то вызываю функцию end_request( 0 )

При этом в основной программе я открываю данное блочное устройсво и начинаю писать в него данные (например линейно). Я вижу как перебираются сектора и данные. Если все хорошо write возращает количество записаннх данных - все Ок.

Но если все плохо, (я говорю end_request(0)), то на экране я вижу сообщение ядра о том что возникла ошибка ввода вывода по такомоту сектору, но приетом в главной программе write по прежнему не знает о ней - возвращает количество якобы успешно записанных байт и наступает следующий запрос на обработку блока.

Что надо сказать в блочном устройстве (в обрабочике очереди запросов), что бы write вернул ошибку записи в блочное устройство?

С уважением, Подколзин Игорь.

Ответ на: комментарий от tailgunner

Да мне нужно именно блочное устройство - это диск.

Так в данной редакции предлагают следующий код:

/* Process all of the buffers in this (possibly clustered) request. */ do { status = sbull_transfer(device, req); } while (end_that_request_first(req, status, DEVICE_NAME)); spin_unlock(&device->lock); spin_lock_irq (&io_request_lock); end_that_request_last(req);

А в моих исходных кодах данного примера было по другому:

spin_lock(&device->lock); status = sbull_transfer(device, CURRENT); spin_unlock(&device->lock); end_request(status);

Жаль... Пойду пробовать. спасибо.

p_igorek
() автор топика
Ответ на: комментарий от p_igorek

После размышлений на свежую голову, вот моя версия: у тебя в драйвере всё правильно (раз система жалуется - значит, она видит возвращенный тобой код ошибки). Но вот _тест_ у тебя принципиально неправильный: вызов write в Linux (и любом UNIX) не пишет данные на устройство, а оставляет их в кэше, и ошибка при записи происходит потом, когда о ней уже некому сообщить. Решения - смонтировать ФС с опциями синхронной записи, делать fsync или fdatasync, или использовать direct io (если на твоем устройстве нет ФС).

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Переделал под новую концепцию (как написано в LDD) - все тоже самое.

Да, судя по всему дело во write (кеше).

Как сделать direct io? Просто там еще нет ФС. Она накладывается чуть позже.

Спасибо.

p_igorek
() автор топика
Ответ на: комментарий от p_igorek

Совсем забыл, при открытии устройства на запись флаг O_SYNC установлен.

p_igorek
() автор топика
Ответ на: комментарий от p_igorek

> Как сделать direct io? Просто там еще нет ФС. Она накладывается чуть позже.

Если верить man 2 open. надо открыть файл с флагом O_DIRECT. Почитай там о требованиях по выравниванию.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Хотя я припоминаю еще один способ direct io (времен еще 2.2) - создание специальных символьных устройств, и работа с ними.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Сивольное устройство это конечно хорошо. Можно и реализовать.

Но как при этом файловая система поверх блочного устройства узнает, что призошла ошибка на диске?

p_igorek
() автор топика
Ответ на: комментарий от p_igorek

>Сивольное устройство это конечно хорошо. Можно и реализовать.

:-D

Всё учтено могучим ураганом. Ты не реализовываешь его _сам_б ты просто конфигурируешь character raw device для своего существующего block device, и читаешь пишешь через raw device - и система прозрачно для тебя делает синхронные запись/чтение.

> Но как при этом файловая система поверх блочного устройства узнает, что призошла ошибка на диске?

raw device - это, AFAIK, устаревший интерфейс, и применим только к дискам без ФС (но для твоего теста такие и нужны).

Если же тебе нужен direct io на из файла на ФС - только O_DIRECT.

tailgunner ★★★★★
()
Ответ на: комментарий от p_igorek


RHEL4:

--- man open ---
O_DIRECT
Try to minimize cache effects of the I/O to and from this file. In general this
will degrade performance, but it is useful in special situations, such as when
applications do their own caching. File I/O is done directly to/from user space
buffers. The I/O is synchronous, i.e., at the completion of the read(2) or
write(2) system call, data is guaranteed to have been transferred. Under Linux 2.4
transfer sizes, and the alignment of user buffer and file offset must all be multi-
ples of the logical block size of the file system. Under Linux 2.6 alignment to
512-byte boundaries suffices.
A semantically similar interface for block devices is described in raw(8).
--- man open ---

// wbr

klalafuda ★☆☆
()
Ответ на: комментарий от tailgunner

Целевая машина

ARM AT91RM9200 Kernel 2.4.27-vrs1-ATMEL GCC 2.95.3 ARM LINUX uClibC 0.9.27

Свойя плата, свой жесткий диск, свой модуль блочного устройства для него, поверх файловая система Ext2

Диск может быть извлечен на ходу (нежелательно но возможно).

Но нужно и писать в него напрямую минуя ФС.

Как определить в программе (write) что блочное устройство завершилось с ошибкой? Как драйвер ФС определяет что операция чтения записи завершилась с ошибкой?

Ядро явно "видит", что операция завершилась с ошибкой.

Разработка на ASP Linux 7.0

Флага O_DIRECT нет и не компилирует соответсвенно.

p_igorek
() автор топика
Ответ на: комментарий от p_igorek

> Разработка на ASP Linux 7.0

Я в местных дистрибутивах не разбираюсь, но это явно что-то древнее.

> Флага O_DIRECT нет и не компилирует соответсвенно.

Ну, по=быструхе, #define O_DIRECT 040000

Или попробуй man 8 raw

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

При #define O_DIRECT 0x40000 ничего не меняется

ASP тут вовсе не причем, ну может быть man старый.

Все ведь работает на ARM и.....

А может мне uClibC такую свинью подложила????

p_igorek
() автор топика
Ответ на: комментарий от p_igorek

> При #define O_DIRECT 0x40000 ничего не меняется

<грубая матерная ругань/> Не 0x40000, а 040000 :-P

> А может мне uClibC такую свинью подложила????

Всё может быть...

tailgunner ★★★★★
()
Ответ на: комментарий от p_igorek

Ошибочка вышла в дефайнах

fcntl.h

#ifdef __USE_GNU # define O_DIRECTORY 040000 /* Must be a directory. */ # define O_NOFOLLOW 0100000 /* Do not follow links. */ # define O_DIRECT 0200000 /* Direct disk access. */ # define O_STREAMING 04000000/* streaming access */ #endif

Хотя и с данными определениями все не так.

Я немогу определить, что запись не состоялась.

mke2fs как нормальное приложение не может этого определить. Продолжает форматировать хотя диска и в помине нет.

Запись в файл (тоесть фаловая система) тоже не может определить что все плохо, хотя ядро и говорит, что завершает ввод вывод с ошибкой

end_request: I/O error, dev f5:01 (at91_hdd), sector 268336

Значит всеже в драйвере что то не так. А как надо?

p_igorek
() автор топика
Ответ на: комментарий от tailgunner

<грубая матерная ругань/> Не 0x40000, а 040000 :-P

При 040000 неможет сделать open...

p_igorek
() автор топика
Ответ на: комментарий от p_igorek

> Ошибочка вышла в дефайнах

> fcntl.h

> #ifdef __USE_GNU # define O_DIRECTORY 040000 /* Must be a directory. */ # define O_NOFOLLOW 0100000 /* Do not follow links. */ # define O_DIRECT 0200000 /* Direct disk access. */ # define O_STREAMING 04000000/* streaming access */ #endif

Я не подумал, что они на ARM могут быть другие. У меня:

bits/fcntl.h:# define O_DIRECT 040000 /* Direct disk access. */

bits/fcntl.h:# define O_DIRECTORY 0200000 /* Must be a directory. */

Насчет end_request(0) - судя по исходникам, этого недостаточно, надо делать buffer_IO_error на ошибочном буфере. Хотя я не специалист по блочным драйверам :/

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Если добавить при ошибке записи следующий код:

buffer_IO_error( CURRENT->bh );

То все остается как было, за исключением нового сообщения ядра

теперь это выглядит так: end_request: I/O error, dev f5:00 (at91_hdd), sector 50944 VFS: brelse: Trying to free free buffer

Но приложение все равно ни чего не знает об ошибке ввода/вывода.

p_igorek
() автор топика
Ответ на: комментарий от p_igorek

> теперь это выглядит так: end_request: I/O error, dev f5:00 (at91_hdd), sector 50944 VFS: brelse: Trying to free free buffer

Прикольно. Должен же быть какой-то способ... А ты делаешь buffer_IO_error до или после end_request(0) ?

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Да, и еще - я бы на твоем месте пока работал только с _чтением_ (сразу после перезагрузки драйвера) - думаю, там эффекты кэша не проявляются. А когда научишься передавать ошибку в read, можно будет попробовать делать то же write.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

До.

Сейчас сделую после, хотя, наверное после неимеет смысла , так как там уже должен быть другой запрос.

Да, еще добавил такой код: CURRENT->errors++; buffer_IO_error(CURRENT->bh);

p_igorek
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.