首页 > 解决方案 > 在 Linux 中,我想根据 i/o 请求的大小有选择地使用中断和轮询

问题描述

我是学习Linux内核的本科生。

我对 Linux 内核中的 I/O 路径有一些疑问。

在 Linux 中,我想根据 i/o 请求的大小有选择地使用中断和轮询。

比如我想修改内核代码,在fio benchmark的block size小于64kb的时候进行poll,大的时候进行interrupt。

由于通过“Perf”跟踪函数,它似乎与“__blkdev_direct_IO_simple”函数的工作方式不同。

如何修复代码?

__blkdev_direct_IO_simple(struct kiocb *iocb, struct iov_iter *iter, int nr_pages)

    {
        struct file *file = iocb->ki_filp;
        struct block_device *bdev = I_BDEV(bdev_file_inode(file));
        struct bio_vec inline_vecs[DIO_INLINE_BIO_VECS], *vecs, *bvec;
        loff_t pos = iocb->ki_pos;
        bool should_dirty = false;
        struct bio bio;
        ssize_t ret;
        blk_qc_t qc;
        int i;

        if ((pos | iov_iter_alignment(iter)) &
            (bdev_logical_block_size(bdev) - 1))
            return -EINVAL;

        if (nr_pages <= DIO_INLINE_BIO_VECS)
            vecs = inline_vecs;
        else {
            vecs = kmalloc(nr_pages * sizeof(struct bio_vec), GFP_KERNEL);
            if (!vecs)
                return -ENOMEM;
        }

        bio_init(&bio, vecs, nr_pages);
        bio.bi_bdev = bdev;
        bio.bi_iter.bi_sector = pos >> 9;
        bio.bi_write_hint = iocb->ki_hint;
        bio.bi_private = current;
        bio.bi_end_io = blkdev_bio_end_io_simple;

        ret = bio_iov_iter_get_pages(&bio, iter);
        if (unlikely(ret))
            return ret;
        ret = bio.bi_iter.bi_size;

        if (iov_iter_rw(iter) == READ) {
            bio.bi_opf = REQ_OP_READ;
            if (iter_is_iovec(iter))
                should_dirty = true;
        } else {
            bio.bi_opf = dio_bio_write_op(iocb);
            task_io_account_write(ret);
        }

        qc = submit_bio(&bio);
        for (;;) {
            set_current_state(TASK_UNINTERRUPTIBLE);
            if (!READ_ONCE(bio.bi_private))
                break;
            if (!(iocb->ki_flags & IOCB_HIPRI) ||
                !blk_mq_poll(bdev_get_queue(bdev), qc))
                io_schedule();
        }
        __set_current_state(TASK_RUNNING);

        bio_for_each_segment_all(bvec, &bio, i) {
            if (should_dirty && !PageCompound(bvec->bv_page))
                set_page_dirty_lock(bvec->bv_page);
            put_page(bvec->bv_page);
        }

        if (vecs != inline_vecs)
            kfree(vecs);

        if (unlikely(bio.bi_status))
            ret = blk_status_to_errno(bio.bi_status);

        bio_uninit(&bio);

        return ret;
    }

标签: linuxkernel

解决方案


推荐阅读