Saturday, October 20, 2012

Linux kernel file I/O from a block driver

This code shows how a hypothetical block driver might handle submitted BIOs, servicing them with a file.
/* Handle I/O for a BIO component. */
int file_do_bvec(struct file *file, struct bio_vec *bvec, loff_t pos, int rw)
{
        u8 *buf;
        ssize_t bw;
        mm_segment_t old_fs = get_fs();

        buf = kmap_atomic(bvec->bv_page, KM_USER0) + bvec->bv_offset;

        set_fs(get_ds());

        if (rw == WRITE)
                bw = vfs_write(file, buf, bvec->bv_len, &pos);
        else
                bw = vfs_read(file, buf, bvec->bv_len, &pos);
        set_fs(old_fs);

        kunmap_atomic(buf, KM_USER0);
        cond_resched();

        if (likely(bw == len))
                return 0;
        printk(KERN_ERR "Error at byte offset %llu, length %i.\n",
                        (unsigned long long)pos, len);
        if (bw >= 0)
                bw = -EIO;
        return bw;
}

/* Handle I/O for a BIO. */
int file_do_bio(struct file *file, struct bio *bio, loff_t pos)
{
        struct bio_vec *bvec;
        struct page *page = NULL;
        int i, ret = 0;

        /* Should have read-only check here, BIOs other than READ/WRITE. */

        bio_for_each_segment(bvec, bio, i) {
                ret = file_do_bvec(file, bvec, pos, bio_rw(bio));
                if (ret < 0)
                        break;
                pos += bvec->bv_len;
        }

        /*
         * At some point we need to fsync. In this simple example - I'll do it here.
         * TBD: should check error.
         */
        vfs_fsync(file, 0);
        return ret;
}

No comments:

Post a Comment