単純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
2. sbull.h
3. Makefile
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バイトの内容と同じです
本明細書の「ブロックデバイス」は、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バイトの内容と同じです