単純linuxブロックデバイスドライバ

28733 ワード

本文のコードは《LINUX設備ドライバ》の第16章のブロックの設備ドライバを参考にします
本明細書の「ブロックデバイス」は、PAGE_のサイズのセグメントである.SIZEのメモリ領域(2セクタ、各セクタ512バイト)
機能:ブロックデバイスにコンテンツを入力し、ブロックデバイスからコンテンツを読み出す
注意:ldd付属ブロックデバイスドライバソースコードは2.6.32カーネルのリリース版でコンパイルすると、kernel 2.6でblock layer APIが変更されているため、多くのAPIが定義されていないことが示されます.本稿のプログラムはhttp://hi.baidu.com/casualfish/item/7931bbb58925fb951846977dを参照しています.ありがとうございます.
 
コード:
1. sbull.c
 1 #include <linux/module.h>

 2 #include <linux/moduleparam.h>

 3 #include <linux/init.h>

 4 

 5 #include <linux/sched.h>

 6 #include <linux/kernel.h>

 7 #include <linux/slab.h>

 8 #include <linux/fs.h>

 9 #include <linux/errno.h>

 10 #include <linux/timer.h>

 11 #include <linux/types.h>

 12 #include <linux/fcntl.h>

 13 #include <linux/hdreg.h>

 14 #include <linux/kdev_t.h>

 15 #include <linux/vmalloc.h>

 16 #include <linux/genhd.h>

 17 #include <linux/blkdev.h>

 18 #include <linux/buffer_head.h>

 19 #include <linux/bio.h>

 20 

 21 #include "sbull.h"

 22 

 23 static int sbull_major = SBULL_MAJOR;  24 static int hardsect_size = SBULL_HARDSECT;  25 static int nsectors = 2;  26 module_param(sbull_major, int, 0);  27 module_param(hardsect_size, int, 0);  28 module_param(nsectors, int, 0);  29 

 30 struct sbull_dev {  31     int size;  32     u8 *data;  33     short users;  34     spinlock_t lock;  35     struct request_queue *queue;  36     struct gendisk *gd;  37 };  38 

 39 static struct sbull_dev *device = NULL;  40 

 41 static void sbull_transfer(struct sbull_dev *dev, unsigned long sector, unsigned long nsect, char *buffer, int write)  42 {  43     unsigned long offset = sector*KERNEL_SECTOR_SIZE;  44     unsigned long nbytes = nsect*KERNEL_SECTOR_SIZE;  45 

 46     if ((offset+nbytes) > dev->size)  47  {  48         return;  49  }  50 

 51     if (write)  52  {  53         memcpy(dev->data+offset, buffer, nbytes);  54  }  55     else

 56  {  57         memcpy(buffer, dev->data+offset, nbytes);  58  }  59 }  60 

 61 static int sbull_xfer_bio(struct sbull_dev *dev, struct bio *bio)  62 {  63     int i;  64     struct bio_vec *bvec;  65     sector_t sector = bio->bi_sector;  66 

 67  bio_for_each_segment(bvec, bio, i)  68  {  69         char *buffer = __bio_kmap_atomic(bio, i, KM_USER0);  70         sbull_transfer(dev, sector, bio_cur_bytes(bio)>>9, buffer, bio_data_dir(bio) == WRITE);  71         sector += bio_cur_bytes(bio)>>9;  72  __bio_kunmap_atomic(bio, KM_USER0);  73  }  74     return 0;  75 }  76 

 77 static int sbull_xfer_request(struct sbull_dev *dev, struct request *req)  78 {  79     struct bio *bio;  80     int nsect = 0;  81 

 82  __rq_for_each_bio(bio, req) {  83  sbull_xfer_bio(dev, bio);  84         nsect += bio->bi_size/KERNEL_SECTOR_SIZE;  85  }  86     return nsect;  87 }  88 

 89 static void sbull_full_request(struct request_queue *q)  90 {  91     struct request *req;  92     int sectors_xferred;  93     struct sbull_dev *dev = q->queuedata;  94 

 95     while((req = blk_fetch_request(q)) != NULL)  96  {  97         if (req->cmd_type != REQ_TYPE_FS)  98  {  99             __blk_end_request_all(req, -EIO); 100             continue; 101  } 102 

103         sectors_xferred = sbull_xfer_request(dev, req); 104 

105         __blk_end_request_cur(req, 0); 106  } 107 } 108 

109 static int sbull_open(struct block_device *device, fmode_t mode) 110 { 111     struct sbull_dev *dev = device->bd_disk->private_data; 112 

113     spin_lock(&dev->lock); 114     dev->users++; 115     spin_unlock(&dev->lock); 116     return 0; 117 } 118 

119 static int sbull_release(struct gendisk *disk, fmode_t mode) 120 { 121     struct sbull_dev *dev = disk->private_data; 122 

123     spin_lock(&dev->lock); 124     dev->users--; 125     spin_unlock(&dev->lock); 126 

127     return 0; 128 } 129 

130 static struct block_device_operations sbull_ops = { 131     .owner = THIS_MODULE, 132     .open = sbull_open, 133     .release = sbull_release, 134 }; 135 

136 static void setup_device(struct sbull_dev *dev) 137 { 138     memset(dev, 0, sizeof(struct sbull_dev)); 139     dev->size = nsectors*hardsect_size; 140     dev->data = vmalloc(dev->size); 141     if (dev->data == NULL) 142  { 143         return; 144  } 145 

146     spin_lock_init(&dev->lock); 147 

148     dev->queue = blk_init_queue(sbull_full_request, &dev->lock); 149     if (dev->queue == NULL) 150  { 151         goto out_vfree; 152  } 153 

154     blk_queue_logical_block_size(dev->queue, hardsect_size); 155     dev->queue->queuedata = dev; 156 

157     dev->gd = alloc_disk(1); 158     if (!dev->gd) 159  { 160         goto out_vfree; 161  } 162 

163     dev->gd->major = sbull_major; 164     dev->gd->first_minor = 0; 165     dev->gd->fops = &sbull_ops; 166     dev->gd->queue = dev->queue; 167     dev->gd->private_data = dev; 168     snprintf(dev->gd->disk_name, 6, "sbull"); 169     set_capacity(dev->gd, nsectors*(hardsect_size/KERNEL_SECTOR_SIZE)); 170     add_disk(dev->gd); 171 

172     return; 173 

174  out_vfree: 175         if (dev->data) 176  { 177             vfree(dev->data); 178  } 179 } 180 

181 static int __init sbull_init(void) 182 { 183     sbull_major = register_blkdev(sbull_major, "sbull"); 184     if (sbull_major <= 0) 185  { 186         return -EBUSY; 187  } 188 

189     device = kmalloc(sizeof(struct sbull_dev), GFP_KERNEL); 190     if (device == NULL) 191  { 192         goto out_unregister; 193  } 194 

195  setup_device(device); 196 

197     return 0; 198 

199  out_unregister: 200         unregister_blkdev(sbull_major, "sbull"); 201         return -ENOMEM; 202 } 203 

204 static void sbull_exit(void) 205 { 206     struct sbull_dev *dev = device; 207 

208     if (dev->gd) 209  { 210         del_gendisk(dev->gd); 211         put_disk(dev->gd); 212  } 213 

214     if (dev->queue) 215  { 216         blk_cleanup_queue(dev->queue); 217  } 218 

219     if (dev->data) 220  { 221         vfree(dev->data); 222  } 223 

224     unregister_blkdev(sbull_major, "sbull"); 225  kfree(device); 226 } 227 

228 module_init(sbull_init); 229 module_exit(sbull_exit); 230 MODULE_LICENSE("GPL");

2. sbull.h
1 #ifndef _SBULL_H 2 #define _SBULL_H

3 

4 #define SBULL_MAJOR    0

5 #define SBULL_HARDSECT    512

6 

7 #define KERNEL_SECTOR_SIZE    512

8 

9 #endif

3. Makefile
 1 obj-m += sbull.o  2 

 3 CURRENT_PATH:=$(shell pwd)  4 LINUX_KERNEL:=$(shell uname -r)  5 LINUX_KERNEL_PATH:=/usr/src/kernels/$(LINUX_KERNEL)  6 

 7 all:  8     make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules  9 clean: 10     make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean

4.効果の検証
1)#make
2)#insmod sbull.ko
3)#ls/dev/   //sbullが表示されます
4)#ls -lh/tmp/test1   
-rw-r--r--. 1 root root 4.3k Dec 2 20:47 test1
5)#dd if=/tmp/test1 of=/dev/sbull bs=512 count=2   //test 1の2つのセクタの内容をブロックデバイスsbullに入力
6)#dd if=/dev/sbull of=/tmp/test2 bs=512 count=2   //ブロックデバイスsbullの2つのセクタの内容を一時ファイルtest 2に入力
7)#ls -lh/tmp/test2
-rw-r--r--. 1 root root 1.0k Dec 2 21:19 test2
8)#vim test2   //test 2の内容はtest 1の上位1024バイトの内容と同じです