Когда два процесса одновременно прочитают один и тот же файл, сохранит ли ядро ​​Linux один ввод / вывод устройства? - PullRequest
4 голосов
/ 09 октября 2019

У меня есть общий вопрос об обработке ядром 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))

Означает ли это, что ядро ​​просто сделает два ввода-вывода? Или (очень вероятно) я что-то пропустил?

спасибо!

...