У меня есть общий вопрос об обработке ядром Linux файлового ввода-вывода. Пока что я понимаю, что в идеальном случае после того, как процесс A читает файл, данные загружаются в кэш страницы, и если процесс B читает ту же страницу, прежде чем она будет восстановлена, ему не нужно снова обращаться к диску.
Мой вопрос связан с тем, как работает блок ввода-вывода. Запрос на чтение процесса A в конечном итоге будет поставлен в очередь до того, как фактически произойдет ввод-вывод. Теперь, если запрос устройства B (структура bio
) должен быть вставлен в request_queue
, до того, как запрос A будет выполнен, лифт рассмотрит, объединить ли bio
B в какой-либо из существующих request
,Теперь, если A и B пытаются прочитать одно и то же смещение файла, то есть один и тот же блок устройства, они в буквальном смысле являются одним и тем же вводом-выводом (или запросы A и B не совсем одинаковы, но перекрываются для некоторых блоков), но покаЯ не видел, чтобы этот случай рассматривался в коде ядра. (Единственное, что я видел, это проверка того, можно ли приклеить bio
к существующему request
непрерывно.)
ядро 2.6.11
inline int elv_try_merge(struct request *__rq, struct bio *bio)
{
int ret = ELEVATOR_NO_MERGE;
/*
* we can merge and sequence is ok, check if it's possible
*/
if (elv_rq_merge_ok(__rq, bio)) {
if (__rq->sector + __rq->nr_sectors == bio->bi_sector)
ret = ELEVATOR_BACK_MERGE;
else if (__rq->sector - bio_sectors(bio) == bio->bi_sector)
ret = ELEVATOR_FRONT_MERGE;
}
return ret;
}
ядро 5.3.5
enum elv_merge elv_merge(struct request_queue *q, struct request **req,
struct bio *bio)
{
struct elevator_queue *e = q->elevator;
struct request *__rq;
...
/*
* See if our hash lookup can find a potential backmerge.
*/
__rq = elv_rqhash_find(q, bio->bi_iter.bi_sector);
...
}
struct request *elv_rqhash_find(struct request_queue *q, sector_t offset)
{
struct elevator_queue *e = q->elevator;
struct hlist_node *next;
struct request *rq;
hash_for_each_possible_safe(e->hash, rq, next, hash, offset) {
...
if (rq_hash_key(rq) == offset)
return rq;
}
return NULL;
}
#define rq_hash_key(rq) (blk_rq_pos(rq) + blk_rq_sectors(rq))
Означает ли это, что ядро просто сделает два ввода-вывода? Или (очень вероятно) я что-то пропустил?
спасибо!