LINUX.ORG.RU

[kernel] Блочные устройства в ядре 2.6.32

 


0

2

С Новым годом.

Учусь писать драйвер блочного устройства, в качестве руководства использую LLD3. Заметил, что в моем ядре Linux debian 2.6.32-5-486 кое-что отличается от написанного в книге. Например, изменились передаваемые параметры функциями block_device_operations, blk_put_queue больше недоступно и.т.д.

Среди прочего заметил, что теперь запросы делаются в байтах, а не в секторах. Означает ли это, что я могу теперь использовать размер блока меньший, чем 512 байт (для меня оптимальным размером был бы 64 байта)? С другой стороны

dd if=/dev/urandom of=/dev/lptprom count=1 bs=512 
Делает запросы по 4 кб. Как мне тогда определить, что надо записать именно 512 байт?

Эта же команда, перед тем как записать что-то, сначала читает этот блок, а уж потом пишет. Зачем?

> Заметил, что в моем ядре Linux debian 2.6.32-5-486 кое-что отличается от написанного в книге. Например, изменились передаваемые параметры функциями block_device_operations, blk_put_queue больше недоступно и.т.д.

На LWN.net есть список изменений ядерного API - посмотри там.

Делает запросы по 4 кб. Как мне тогда определить, что надо записать именно 512 байт?

Блочное устройство обычно работает по запросам страничного кэша, который оперирует страницами по 4 Кб; еще у тебя может быть размер блока ФС == 4К.

Напиши свою тестовую программу, которая будет использовать O_DIRECT - сможешь читать по секторам.

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

dd умеет использовать O_DIRECT. dd oflags=direct откроет выходной файл с флагом O_DIRECT.

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

Когда открываю файл с O_DIRECT, вызовы read и write завершаеются с ошибкой Invalid argument.

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

В тестовой программе читаю разными порциями из файла устройства. Не пойму по какому принципу определяется количество чтений так как оно никак не связано с количеством получаемой информациии. Я не использую очередей и планировшик для жесткого диска не прогнозирующий.

 cat /sys/block/sda/queue/scheduler
noop anticipatory deadline [cfq]

Правильно ли я понимаю, что запросы я должен обрабатывать не по секторам, а по объему запрашиваемой информации. И если у меня размер блока 64 байта, то мне просто надо 4096/64=64 вызвать процедуру обработки блока?

Если да, то где же в этой схеме используются blk_queue_logical_block_size, set_capacity?

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

> Когда открываю файл с O_DIRECT, вызовы read и write завершаеются с ошибкой Invalid argument.

Читал man 2 open насчет O_DIRECT?

Я не использую очередей и планировшик для жесткого диска не прогнозирующий.

IIRC ты всегда используешь очередь, но планировщик не влияет на ввод/вывод с O_DIRECT.

Правильно ли я понимаю, что запросы я должен обрабатывать не по секторам, а по объему запрашиваемой информации.

Деталей, к сожалению, не помню.

И если у меня размер блока 64 байта

Если да, то где же в этой схеме используются blk_queue_logical_block_size, set_capacity?

Ты точно читал LDD3? «As we have mentioned before, the kernel treats every disk as a linear array of 512-byte sectors. Not all hardware uses that sector size, however. Getting a device with a different sector size to work is not particularly hard; it is just a matter of taking care of a few details».

Если ты выбрал экзотический размер сектора - разбирайся с деталями. Я бы на твоем месте сначала попробовал реализовать хоть что-то работоспособное.

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

Я сам не против работоспособного. Я просто не могу понять зачем указывать размер сектора 512 байт, если запросы мне идут по 4 кб.

С O_DIRECT я еще раз посмотрел. Оказалось, что fstat возвращает структуру с полем st_size = 0. Хотя количество блоков (set_capacity) и размер блока (blk_queue_logical_block) я указал. Размер должен быть logical_block_size*capacity, верно?

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

> Я сам не против работоспособного.Я просто не могу понять зачем указывать размер сектора 512 байт, если запросы мне идут по 4 кб.

Написание драйверов - это изнурительное согласование деталей. Внимательно читай учебник - не думаю, что кто-то обещал тебе, что запросы будут именно по одному сектору.

Кроме того, ответь наконец, какие именно параметры ты задаешь в read.

fstat возвращает структуру с полем st_size = 0. Хотя количество блоков (set_capacity) и размер блока (blk_queue_logical_block) я указал.

А остальные поля?

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner
int fd = open ("/dev/lptprom", O_RDWR | O_NOCTTY | O_DIRECT);
char buf[4096];
int len = 4096;
int res = read (fd, buf, len);

Чесно говоря не знаю как я вчера получил st_size = 4096.

	struct stat sbuf;
	if (fstat(fd, &sbuf) < 0) {
	 perror("fstat");
	 goto shutdown;
	}
	
	printf( "st_dev = %ld\n"
		"st_ino = %ld\n"
		"st_mode = %x\n"
		"st_nlink = %ld\n"
		"st_rdev = %ld\n"
		"st_size = %ld\n"
		"st_blksize = %ld\n"
		"st_blocks = %ld\n"
		,sbuf.st_dev,sbuf.st_ino,sbuf.st_mode,
		sbuf.st_nlink,sbuf.st_rdev,
		sbuf.st_size,sbuf.st_blksize,sbuf.st_blocks);
И вот результат:
st_dev = 14
st_ino = 0
st_mode = 518e
st_nlink = 25008
st_rdev = 1
st_size = 65024
st_blksize = 0
st_blocks = 0

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

> char buf[4096];

int len = 4096;

int res = read (fd, buf, len);

То есть ты читаешь по 4К и удивляешься, почему тебе приходят запросы по 4К? Прелестно.

И вот результат:

Хлам. st_blksize и st_nlink особенно умиляют.

Короче, возьми пример из LDD3 (sbull или как он там называется) и модифицируй его.

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

Я пробовал разные значения для len. Все равно запросы приходили по 4 кб. И более того, несмотря на то что я читаю всего 512 (или 64) байта приходит не один запрос, а 4. Когда я читаю 16кб и больше приходит уже 8 запросов. И еще когда я делаю insmod происходит чтение сразу всего устройства.

Вот код из LDD

int i;
struct bio_vec *bvec;
sector_t sector = bio->bi_sector;
/* Do each segment independently. */
bio_for_each_segment(bvec, bio, i) {
    char *buffer = __bio_kmap_atomic(bio, i, KM_USER0);
    sbull_transfer(dev, sector, bio_cur_sectors(bio),
            buffer, bio_data_dir(bio) == WRITE);
    sector += bio_cur_sectors(bio);
    __bio_kunmap_atomic(bio, KM_USER0);
}
return 0; /* Always "succeed" */

Функции bio_cur_sectors больше нет и я ее заменил на bio_cur_bytes, которая неизменно возвращает 4096. Может здесь я ошибся?

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

> несмотря на то что я читаю всего 512 (или 64) байта приходит не один запрос, а 4. Когда я читаю 16кб и больше приходит уже 8 запросов.

/0

Функции bio_cur_sectors больше нет и я ее заменил на bio_cur_bytes, которая неизменно возвращает 4096.

Тебе не кажется, что bio_cur_sectors возвращает количество секторов, а не байтов?

Может здесь я ошибся?

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

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

Тебе не кажется, что bio_cur_sectors возвращает количество секторов, а не байтов?

И что ты хотел этим сказать? Функции bio_cur_sectors уже нет. Это означает, что я не могу ее использовать.

DesertFox
() автор топика

эта... я забыл все то немногое, что знал про block devices,
так что могу и соврать...

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

а не в секторах.



где?

Означает ли это, что я могу теперь использовать размер блока

меньший, чем 512 байт



насколько я понимаю, нет.

те, девайс-то может быть устроен как угодно, но в bio/req
все будет по 512 байт.

Эта же команда, перед тем как записать что-то, сначала читает

этот блок, а уж потом пишет. Зачем?



потому, что как уже tailgunner сказал, пишет оно в page-cache,
а там 4K. забудь про block device, представь, что ты пишешь
один байт в начало файла. прежде чем записать сектор/page/whatever,
его нужно считать, затем изменить первый байт.

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

Я смирился с тем что в bio буферы по 4 кб, а не по 512 байт и все-таки дописал модуль. Но я так и не могу понять для чего нам нужны функции blk_queue_logical_block_size, set_capacity, я нигде результаты их выполнения так и не использовал. И может подскажите что можно почитать на эту тему, кроме LDD и Лава?

Спасибо всем за помощь.

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