对于一直坚持到这一章的读者而言,应该对simp_blkdev_make_request()函数的功能烂熟于心了, 因此我们直接列出修改后的代码: static int simp_blkdev_trans_oneseg(struct page *start_page, unsigned long offset, void *buf, unsigned int len, int dir) { void *dsk_mem;
if (!dir) memcpy(buf, dsk_mem, len); else memcpy(dsk_mem, buf, len);
return 0; }
static int simp_blkdev_trans(unsigned long long dsk_offset, void *buf, unsigned int len, int dir) { unsigned int done_cnt; struct page *this_first_page; unsigned int this_off; unsigned int this_cnt;
done_cnt = 0; while (done_cnt < len) { /* iterate each data segment */ this_off = (dsk_offset + done_cnt) & ~SIMP_BLKDEV_DATASEGMASK; this_cnt = min(len - done_cnt, (unsigned int)SIMP_BLKDEV_DATASEGSIZE - this_off);
if (IS_ERR_VALUE(simp_blkdev_trans_oneseg(this_first_page, this_off, buf + done_cnt, this_cnt, dir))) return -EIO;
done_cnt += this_cnt; }
return 0; }
static int simp_blkdev_make_request(struct request_queue *q, struct bio *bio) { int dir; unsigned long long dsk_offset; struct bio_vec *bvec; int i; void *iovec_mem;
switch (bio_rw(bio)) { case READ: case READA: dir = 0; break; case WRITE: dir = 1; break; default: printk(KERN_ERR SIMP_BLKDEV_DISKNAME ": unknown value of bio_rw: %lu\n", bio_rw(bio)); goto bio_err; }
if ((bio->bi_sector << SIMP_BLKDEV_SECTORSHIFT) + bio->bi_size > simp_blkdev_bytes) { printk(KERN_ERR SIMP_BLKDEV_DISKNAME ": bad request: block=%llu, count=%u\n", (unsigned long long)bio->bi_sector, bio->bi_size); goto bio_err; }
首先改动alloc_diskmem()函数,给这个函数中申请内存的语句、也就是alloc_pages()的gfp_mask中加上__GFP_HIGHMEM标志, 这使得申请块设备的内存块时,会优先考虑使用高端内存。 修改过的函数如下: int alloc_diskmem(void) { int ret; int i; struct page *page;
INIT_RADIX_TREE(&simp_blkdev_data, GFP_KERNEL);
for (i = 0; i < (simp_blkdev_bytes + SIMP_BLKDEV_DATASEGSIZE - 1) >> SIMP_BLKDEV_DATASEGSHIFT; i++) { page = alloc_pages(GFP_KERNEL | __GFP_ZERO | __GFP_HIGHMEM, SIMP_BLKDEV_DATASEGORDER); if (!page) { ret = -ENOMEM; goto err_alloc; }
ret = radix_tree_insert(&simp_blkdev_data, i, page); if (IS_ERR_VALUE(ret)) goto err_radix_tree_insert; } return 0;
参照以上的思路,我们写出了新的simp_blkdev_trans_oneseg()函数: static int simp_blkdev_trans_oneseg(struct page *start_page, unsigned long offset, void *buf, unsigned int len, int dir) { unsigned int done_cnt; struct page *this_page; unsigned int this_off; unsigned int this_cnt; void *dsk_mem;