首先定义一个锁,因为是用来锁simp_blkdev_data的, 就放在static struct radix_tree_root simp_blkdev_data;后面吧: DEFINE_MUTEX(simp_blkdev_datalock); /* protects the disk data op */
完成了吗?细心看看就知道还没完。 simp_blkdev_trans()函数中有一些判断异常的代码,这些代码大多是扔出一条printk就直接return的。 这样可不行,可千万别让它们临走时把锁也顺回去了。 这意味着我们要在simp_blkdev_trans()函数中的3个故障时return的代码前完成锁的释放。 因此simp_blkdev_trans()函数最后就成了这样: 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);
/* * A simple block device driver based on memory * * Copyright 2008 - * Zhaolei * * Sample for using: * Create device file (first time only): * Note: If your system have udev, it can create device file for you in time * of lsmod and fdisk automatically. * Otherwise you need to create them yourself by following steps. * mknod /dev/simp_blkdev b 72 0 * mknod /dev/simp_blkdev1 b 72 1 * mknod /dev/simp_blkdev2 b 72 2 * * Create dirs for test (first time only): * mkdir /mnt/temp1/ # first time only * mkdir /mnt/temp2/ # first time only * * Run it: * make * insmod simp_blkdev.ko * # or insmod simp_blkdev.ko size=numK/M/G/T * fdisk /dev/simp_blkdev # create 2 patitions * mkfs.ext3 /dev/simp_blkdev1 * mkfs.ext3 /dev/simp_blkdev2 * mount /dev/simp_blkdev1 /mnt/temp1/ * mount /dev/simp_blkdev2 /mnt/temp2/ * # play in /mnt/temp1/ and /mnt/temp2/ * umount /mnt/temp1/ * umount /mnt/temp2/ * rmmod simp_blkdev.ko * */
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;
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);
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; }
switch (unit) { case ‘g‘: case ‘G‘: simp_blkdev_bytes <<= 30; break; case ‘m‘: case ‘M‘: simp_blkdev_bytes <<= 20; break; case ‘k‘: case ‘K‘: simp_blkdev_bytes <<= 10; break; case ‘b‘: case ‘B‘: break; default: return -EINVAL; }