You are on page 1of 34

Block Device Drivers

-Naga Manjunath Senior s\w Engg in Bosch

Linux Device Driver Architecture

Quick Functions Reference
#include <Linux/fs.h>
int register_blkdev(unsigned int major, const char *name); int unregister_blkdev(unsigned int major, const char *name); struct block_device_operations

#include <linux/genhd.h>
struct gendisk *alloc_disk(int minors); void add_disk(struct gendisk *gd); void set_capacity(struct gendisk *gd, setor_t sectors);

h> struct gendisk #include <linux/blkdev.Quick Functions Reference (cont’) #include <linux/fs.h> struct request .h> struct block_device_operations #include<linuix/genhd.

struct gendisk .

struct block_device_operations .

umount. < . mount. ls.c – Makefile Simple block device driver: sbull • Driver description: – it allocates 10 MB memory space to simulate a ramdisk which is like you insert a disk into the system – the ramdisk has only one partition – many file operations can be performed on it • mkfs.• Needed files: – sbull. cp.

Simple block device driver: sbull (cont’) • Needed functions: – – – – – – sbull_init() sbull_exit() sbull_open() sbull_release() sbull_request() sbull_transfer() .

c #include #include #include #include #include #include #include #include <linux/init.h> <linux/genhd. // system automatically allocate major number int SBULL_MINORS = 1.h> <linux/module.h> <linux/kernel. MODULE_AUTHOR(“MANJU").ie.h> include and define #define KERNEL_SECTOR_SIZE 512 // define sector size is 512 in kernel // HARDWARE define (ramdisksize = 20000*512 = 10M bytes) int nsectors = 20000. // MAX minor number is 1 .h> <linux/fs.only one partition char dev_name[8] = "sbull".h> <linux/blkdev.h> <linux/vmalloc. .h> <linux/hdreg.Source code of sbull. MODULE_LICENSE("DualBSD/GPL"). // sector size = 512 bytes int dev_major_nr = 0. // number of sectors int hardsector_size = 512.

spinlock_t lock. static int sbull_release(struct inode *inode. }Device. unsigned long sector.Source code of sbull. struct block_device *bdev. struct file *filp). int write). .c (cont’) struct sbull_dev { unsigned long size. struct gendisk *gd. struct file *filp). // function prototype static int sbull_open(struct inode *inode. struct and function prototype static struct sbull_dev *dev = &Device. char *buffer. static void sbull_transfer(struct sbull_dev *dev. static void sbull_request(request_queue_t *q).unsigned long nsect. unsigned char *data.

Source code of sbull. struct file *filp) { printk("sbull_open(): do nothing. return 0.\n").. struct Device and open... } . .\n"). return 0. ..owner = THIS_MODULE. } static int sbull_release(struct inode *inode. release methods static int sbull_open(struct inode *inode. struct file *filp) { printk("sbull_release(): do nothing.open = sbull_open.release = sbull_release }.c (cont’) static struct block_device_operations sbull_ops = { .

sbull_init method . dev->size = nsectors * hardsector_size..Source code of sbull. if (dev->data == NULL) { printk("sbull_init(): vmalloc failure.c (cont’) static int sbull_init(void) { printk("sbull_init(): initial sbull.. dev_name). return 0. dev->data = vmalloc(dev->size). return 0. } memset(dev. if (dev_major_nr <= 0) { printk("sbull_init(): unable to get major number\n"). } // initial spinlock spin_lock_init(&dev->lock). sizeof(struct sbull_dev)).\n").\n"). 0. // initial struct sbull_dev dev_major_nr = register_blkdev(dev_major_nr.

// initial queue dev->gd->queue = blk_init_queue(sbull_request. dev->gd->first_minor = 0. if (!dev->gd) { printk("sbull_init(): allocate disk failure.\n").c (cont’) // initial gendisk struct *gd dev->gd = alloc_disk(SBULL_MINORS). &dev->lock). return 0. "sbulla"). // device name is sbulla set_capacity(dev->gd. dev->gd->fops = &sbull_ops. // for private use strcpy(dev->gd->disk_name. nsectors). // file operations pointer dev->gd->private_data= dev. add_disk(dev->gd).Source code of sbull. } dev->gd->major = dev_major_nr. return 0. } sbull_init method: (cont’) .

end_request(req.c (cont’) sbull_request method static void sbull_request(request_queue_t *q) { struct request *req. of sectors to submit sbull_transfer(dev. if( !blk_fs_request(req)) { If non-fs request here. } } decide the transfer dir. } . req->current_nr_sectors. req->buffer. req->sector.0).1). end_request(req. while((req = elv_next_request(q)) != NULL) { struct sbull_dev *dev = req->rq_disk->private_data. do nothing } else { next sector to submit no.Source code of sbull. rq_data_dir(req)).

offset. unsigned long nbytes = nsect * KERNEL_SECTOR_SIZE. else memcpy(buffer. nbytes). unsigned long nsect. nbytes). return. buffer.Source code of sbull. unsigned long sector. char *buffer. int write) { unsigned long offset = sector * KERNEL_SECTOR_SIZE. } . if( (offset + nbytes) > dev->size ) { printk(KERN_NOTICE "beyond-end write (%ld %ld)\n". dev->data + offset.c (cont’) sbull_transfer method static void sbull_transfer(struct sbull_dev *dev. nbytes). } if(write) memcpy(dev->data + offset.

c (cont’) sbull_exit method and module-related macros static void sbull_exit(void) { printk("sbull_exit(): exit sbull. dev_name). unregister_blkdev(dev_major_nr.\n"). module_exit(sbull_exit). . put_disk(dev->gd).Source code of sbull. vfree(dev->data). } module_init(sbull_init).. del_gendisk(dev->gd)..

o # Otherwise we were called directly from the command # line.o *.6.ko *.c(kernel 2.The Makefile of sbull # Makefilefor sbull. invoke the kernel build system.mod. we've been invoked from the # kernel build system and can use its language.c endif . ifneq ($(KERNELRELEASE). else KDIR ?= /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) all: $(MAKE) -C $(KDIR) M=$(PWD) modules clean: rm –rf *.x) # If KERNELRELEASE is defined.) obj-m := sbull.

LAB 1 • Create the simple block device driver and insert into the kernel: – make – sudo insmod sbull.ko – cat /proc/devices | grep sbull .

LAB 1 (cont’) • Create the device node and mount it: – sudo mknod /dev/sbulla b XXX 0 • replaces XXX to the major number you get above • Ubuntu may create the /dev/sbulla for us – – – – sudo mkfs.ext2 /dev/sbulla mkdir temp sudo mount /dev/sbulla temp df .

LAB 1 (cont’) .

. sudo umount temp mkdir temp2 sudo mount /dev/sbulla temp2 ls temp2 .LAB 1 (cont’) • Test the read and write abilities: – – – – – – – cd temp sudo mkdir HANEL cd .

LAB 1 (cont’) .

LAB 1 (cont’) • Remove the sbull module from the kernel: – sudo umount temp2 – sudo rmmod sbull • Ubuntu will also clear the /dev/sbulla for us .

cp.LAB 2 • In this exercise. < . mount. a extended version sbull will be introduced – it allocates 10 MB memory space to simulate a ramdisk which is like you insert a disk into the system – the ramdisk has 2 partitions (partitionable) – many file operations can be performed on it • mkfs. ls. umount.

LAB 2 (cont’) • In order to let the sbull able to be partitioned. there are something needed be done: – sets SBULL_MINORS to 2 – adds new structure member “short users” in sbull_dev – adds one new function in sbull_ops structure – alters the sbull_open and sbull_release functions .

LAB 2 (cont’) The structure method sbull_ioctl int sbull_ioctl(struct inode *inode. geo. unsigned int cmd. sizeof(geo))) return -EFAULT. unsigned long arg) { long size.start= 4. geo. return 0. struct file *filp. geo. switch(cmd) { case HDIO_GETGEO: size = dev->size.sectors= 16. } return -ENOTTY. struct hd_geometry geo. &geo. struct sbull_dev *dev = filp->private_data.cylinders= (size & ~0x3f) >> 6. /* unknown command */ Provides the geometry information } . if (copy_to_user((void __user *) arg. geo.heads= 4.

spin_lock(&dev->lock). } static int sbull_release(struct inode *inode. spin_lock(&dev->lock). spin_unlock(&dev->lock). filp->private_data= dev. struct file *filp) { struct sbull_dev *dev = inode->i_bdev->bd_disk->private_data. return 0. spin_unlock(&dev->lock). } . dev->users--. return 0. dev->users++. struct file *filp) { struct sbull_dev *dev = inode->i_bdev->bd_disk->private_data.LAB 2 (cont’) The functions sbull_open and sbull_release static int sbull_open(struct inode *inode.

ko sudo fdisk –H 16 /dev/sbulla .LAB 2 (cont’) • Test the extended sbull modules: make clean make sudo insmod sbull.

LAB 2 (cont’) .

ext2 /dev/sbulla1 sudo mkfs.LAB 2 (cont’) • Now we have two partitions in the sbull ramdisk • Formats they by the following instructions: sudo mkfs.ext2 /dev/sbulla2 sudo mount /dev/sbulla1 temp sudo mount /dev/sbulla2 temp2 df .

vfat –F16 /dev/sbulla and observe what happened • Try the same instruction executed on the sbulla in LAB2 • Based on the LAB2.LAB 3 • Please format the sbull in LAB1 by instruction: sudo mkfs. give me one block device with: – 20MB and can be partitioned automatically: – you can consult the sbull of LDD here .

LAB 3 (cont’) .

” – if you want to try that one.ko ls –al /dev/sbull* .LAB 3 • There are two errors in the sbull of O’Reilly: – comment out the #include <linux/config.” • to “end_that_request_last(req.h> – change the line 181 • from “end_that_request_last(req). just type: make sudo insmod sbull. 1).

Reference • • • • Driver porting: a simple block driver “Linux Device Drivers” 3rd Edition Cross-Referencing Linux Linux Block Device Architecture .

!  .

4/0418-: .439 897:.0 .98-:*/0..9-4.0 897:.0 -/0.$4:7. 0.  :3830/4380 :3830/.3/1:3.903/8 / 897:.9.*/0.*94.98-:*/0.9.0. /0.7 /. .. 897:.9.94357494950 89. <0.897:... 8534.

.

38107 897:.4/8-:*97.910 15  89. :3830/43 80.98-:*/0.9 .934/0 34/0 897:..947 :3830/43380..7 -:1107 39790  89..9.9.1:3.80 897:. /0.910 15  89.934/0 34/0 897:.94357494950 89.4/8-:*706:089 706:089*6:0:0*9 6  .9.398-:*4503 897:.398-:*700.9.

9.0..398-:*700.910 15  5739 8-:*4503 /43493 3  709:73  < 89.80 /43493 3  709:73  < .94388-:*458  4307%$* & 45038-:*4503 700.9-4.897:.9.4/0418-: .802094/8 89.398-:*4503 897:.90.80 < 897:..910 15  5739 8-:*700.9.808-:*700.$4:7.*/0.80 897:.0*4507.3/4503  700. .934/0 34/0 897:.934/0 34/0 897:.0.439 89.

4/  5739 8-:*39 39. .8-: 3  .0.398-:*39 .439 89.9.4/0418-: .$4:7.

.

9.98-:*/0. /. /0.:70 3  709:73  < .4.4. /0. /0.98-:*/0.  8041 897:.47*37708907*-/0.39.47*37 /0.2. 80380. 80  1 /0.897:.*2.-094092.&  5739 8-:*39 .2.47*37  5739 8-:*39 :3.*2.7/80.9478 .9. /.20  1 /0.473:2-073  709:73  < 202809 /0..*3.1.  /0.*2.947*80 /0.

.

39.8534.*39 /0. 4. 853*4.  8-:*392094/ .

 .4/0418-: .0.439 .$4:7.

.

4.:70 3  709:73  < /0. / 1458 8-:*458 . /  5739 8-:*39 .47*37 /0. /.*/8 $&* #$  1 /0.4.39. / 2. / 1789*2347  /0.9 / /0.47/0.90/81..03/8897:.*2.

.

/ 57.9438543907 /0.104507. .9./0..90*/.

.

  .. / /8*3.20 8-:.90:80 897.5 /0.14757.

.

5.9 /0..03./0.2088-:. / 380.. 809*..9478  .

.

439 .//*/8 /0.39.6:0:0 /0.  . 4. /  709:73  < 8-:*392094/ . / 6:0:0-*39*6:0:0 8-:*706:089  /0.

38107 /0.9.9.4/0418-: .*309*706:089 6 &  897:.9478948:-29 8-:*97.9.439 8-:*706:0892094/ 89. 706 80.947 706 . .98-:*/0.38107/7 < .0..$4:7.4/8-:*706:089 706:089*6:0:0*9 6  897:. 1 -*18*706:089 706  1343 18706:089070  03/*706:089 706  /43493 < 080  30980../09097.9478 706 -:1107 76*/.706 76*/8 57.90*/.9706:089 706 0 7060. /0.:77039*37*80.*/7 706  03/*706:089 706   < < /0.947948:-29 34 4180.

5 -:1107 /0. /.. /.9.9.947 :3830/43380..9 .7 -:1107 39790  :3830/4341180980.5 /0.98-:*/0. :3830/4380.381072094/ 89. /0.$4:7.4/0418-: . 411809 -:1107 3-908  080 202. . 80  5739 #* %-043/ 03/790 // 3 411809 3-908  709:73 < 1 790 202.0.947 #*$% #*$ :3830/433-908380.38107 897:.4/8-:*97.9 #*$% #*$ 1  411809 3-908 /0.439 8-:*97. 411809 3-908  < .9.

/  5:9*/8 /0.3/24/:0 70.4/0418-: . .$4:7.9.90/2.439 8-:*092094/.47*37 /0.*2. /  :3708907*-/0...20  . /0.748 89.  < 24/:0*39 8-:*39  24/:0*09 8-:*09  .9.4/8-:*09 .*3. /.1700 /0.4/  5739 8-:*09 098-: 3  /0*03/8 /0.0.

0//70..0101478-: .3:8098.9174290.0-0033.010418-: .0 1306  ##$ 4- 28-: 4  907800070.422.40900730-:/88902 080 #.3/.40/174290 0730-:/88902.%0. 0730   1##$8/0130/ 0 .3:..3/ 303.

-.

24/:08.

20 7 . 80:3.

3 72 71 4 4 24/ .-:/ ! 805/ .0. 03/1 .     #  ! 24/:08 .

.0/7.0 8:/43824/8-: 4 ./0.90908250-4.3/38079394900730 2.9..07 . W 70.

574.

087058-: ./0..

. .9090/0.3/24:399 8:/4234/.439 W 70.034/0.

/0.

0 W &-:39:2.0894902.-4.473:2-074:09..- W 705.70.8-:.9090..

/0.

147:8 8:/4218 09.8-:.

/0.

2/79025 8:/424:39.8-:.

/0.

8-:.9025 /1 .

439 . .

439 W %0899070././ 8:/4:24:399025 2/79025 8:/424:39.3/790./9025 8:/42/7 . .-908 .

/0.

8-:.9025 89025 .

439 . .

0.84.0908-:24/:01742900730 8:/4:24:399025 8:/47224/8-: W &-:39:. .790.439 W #024.

/0.

147:8 .8-:.

.0/ 9.4.9438.79943.80 .799438 5..90. 7.85.-0 2.2/8.2/8.078438-: -03974/:.0903/0/.804:38079.3104507.5 8  ./839490 88902 907. W 398007..908 2024785.3-050714720/439 W 218 24:39 :24:39 .09482:.

9078908-:*4503 .//8430301:3.-094-0 5. .94338-:*458 897:.3/8-:*700. .9:70202-07 8479:8078 3 8-:*/0.799430/ 9070.9:70 .439 W 347/079409908-:.//830897:.80 1:3.70842093300/0/-0 /430 8098$&* #$94 .9438 .

2/ :3830/43.9/*04209704 897:.9.9 897:. /0./8 04 80.79 1 ..9478 04 89.439 %0897:.3/078 80 = 1  04 0.90*/. 80 04 .9:702094/8-:*4. .9 398-:*4.15 57. . 89.98-:*/0.2/  .910 15 :3830/39.45*94*:807 04 8041 04 709:73 &% 709:73  < 709:73  %%..80 *%  80/0.7  4380 897:.934/0 34/0 897:.

3/ .422. :3343.

4/**:807 . < ./0890042097 31472.943 .7  !74.

. 15 57. 4. 853*4.  709:73  < 89.934/0 34/0 897:.94388-:*4503.80 897:.398-:*700.  /0.3/8-:*700.9.90*/.90*/.34/0 *-/0.9.910 15  897:./0.9. -/*/8 57.  709:73  < .  /0. /0. /0. :8078  853*:34.934/0 34/0 897:. /0.90*/.439 %01:3. /0.9.98-:*/0.98-:*/0... -/*/8 57. :8078  853*:34. 4. /0.910 15  897:. 4.34/0 *-/0.80 89.9. 853*4. 4. .398-:*4503 897:. /0.

0 8:/43824/8-: 4 8:/41/8 .3 2.0.439 W %089900903/0/8-:24/:08 2.0. .

/0.

.8-:.

439 . .

439 W 40.7994383908-:7.0945.9438 8:/4218 09.9890-9014433897:..2/8 W 472. .

/0.

 8:/4218 09.8-:.

/0.

8-:. 8:/424:39.

/0.

8-:.9025 8:/424:39.

/0.

8-:.9025 /1 .

9908-:3-3897:.9 . W !0.943 8:/4218 .801472.1.

/0.

8-:.:942.09  .55030/ W %7908.438:9908-:41070 .0.203897:.3-05.80/4390 .3 W .94300.3/4-807.799430/...3.9..9.:90/43908-:./0. 4:.020430-4. .3/..

 .439 .

:/03:. W %070.4220394:9903.70940774783908-:41 #0 .

3994979.9430 :89950 2...89 706  W 94 03/*9.309030 W 1742 03/*9..431  .89 706   14:.9*706:089*.9*706:089*.0 8:/43824/8-: 4 8 .

/0.

8-: .

078 7//943 7488 #010703.0754793.07..07 3:0.#010703.33: 3:4.0 W W W W 7./7.90.07.9:70 ..8250-4.0.