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 block_device_operations #include<linuix/genhd.h> struct request .h> struct gendisk #include <linux/blkdev.Quick Functions Reference (cont’) #include <linux/fs.

struct gendisk .

struct block_device_operations .

mount. < .• Needed files: – sbull. cp.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. ls. umount.

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

.h> <linux/vmalloc. // sector size = 512 bytes int dev_major_nr = 0.h> <linux/genhd.c #include #include #include #include #include #include #include #include <linux/init.h> <linux/kernel.only one partition char dev_name[8] = "sbull".ie.Source code of sbull.h> <linux/fs. // MAX minor number is 1 .h> <linux/hdreg. MODULE_AUTHOR(“MANJU"). MODULE_LICENSE("DualBSD/GPL").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.h> <linux/module. // number of sectors int hardsector_size = 512. // system automatically allocate major number int SBULL_MINORS = 1.h> <linux/blkdev.

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

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

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

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

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

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

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

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

ko – cat /proc/devices | grep sbull .LAB 1 • Create the simple block device driver and insert into the kernel: – make – sudo insmod 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’) .

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

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 .

mount. ls. cp. 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. < . umount.LAB 2 • In this exercise.

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’) • In order to let the sbull able to be partitioned.

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

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

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

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

!  .

7 /. . 0.94357494950 89.*/0..0 -/0. 8534.903/8 / 897:..0 897:.$4:7.3/1:3.98-:*/0.  :3830/4380 :3830/. /0. 897:..9.4/0418-: .9. <0.98-:*/0..897:.439 897:.9.0.0 .*94.9-4.

.

98-:*/0.398-:*700.80 897:.934/0 34/0 897:.1:3.9 .9. /0.. :3830/43 80..9.9.934/0 34/0 897:.38107 897:.947 :3830/43380.4/8-:*706:089 706:089*6:0:0*9 6  .398-:*4503 897:.4/8-:*97.9.910 15  89.910 15  89.94357494950 89..7 -:1107 39790  89.

808-:*700.*/0.0.910 15  5739 8-:*4503 /43493 3  709:73  < 89.90..0*4507.4/0418-: .802094/8 89.80 897:.439 89. .$4:7.934/0 34/0 897:.398-:*4503 897:.9.0.80 /43493 3  709:73  < .3/4503  700.94388-:*458  4307%$* & 45038-:*4503 700.897:.9-4.80 < 897:.934/0 34/0 897:.9.398-:*700.9.910 15  5739 8-:*700..

8-: 3  .9.439 89.4/  5739 8-:*39 39.$4:7. .398-:*39 .0.4/0418-: .

.

80380.7/80.4. 80  1 /0.897:..98-:*/0.4.  /0.20  1 /0.47*37708907*-/0.2.:70 3  709:73  < .9.*2.473:2-073  709:73  < 202809 /0.47*37 /0.2. /.47*37  5739 8-:*39 :3.9.  8041 897:.*2.1.39. /0. /0. /.*3.947*80 /0.&  5739 8-:*39 .*2.-094092. /0.98-:*/0.9478 .

.

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

0. .4/0418-: .$4:7.439 .

.

*/8 $&* #$  1 /0.4.9 / /0. / 2.03/8897:. / 1789*2347  /0.47/0.90/81. / 1458 8-:*458 . /  5739 8-:*39 .:70 3  709:73  < /0.*2. /.39.4.47*37 /0..

.

9. .104507./0. / 57.90*/.9438543907 /0..

.

  .90:80 897.5 /0. / /8*3.14757..20 8-:.

.

.03. / 380.9478  ./0.5.. 809*.2088-:..9 /0.

.

4.439 . / 6:0:0-*39*6:0:0 8-:*706:089  /0.  .6:0:0 /0.39.//*/8 /0. /  709:73  < 8-:*392094/ .

/09097.9478 706 -:1107 76*/.90*/. .4/8-:*706:089 706:089*6:0:0*9 6  897:.439 8-:*706:0892094/ 89.947 706 .0.706 76*/8 57.$4:7.*/7 706  03/*706:089 706   < < /0.9706:089 706 0 7060. /0.9. 706 80.98-:*/0.9.4/0418-: .38107 /0.947948:-29 34 4180.9478948:-29 8-:*97.. 1 -*18*706:089 706  1343 18706:089070  03/*706:089 706  /43493 < 080  30980.*309*706:089 6 &  897:.9.38107/7 < ..:77039*37*80.

80  5739 #* %-043/ 03/790 // 3 411809 3-908  709:73 < 1 790 202.5 /0.98-:*/0. /..5 -:1107 /0. /.381072094/ 89. 411809 3-908  < .947 #*$% #*$ :3830/433-908380.. /0.9.7 -:1107 39790  :3830/4341180980.$4:7.9 #*$% #*$ 1  411809 3-908 /0. 411809 -:1107 3-908  080 202. :3830/4380.4/8-:*97.0.947 :3830/43380.9.9.38107 897:. .439 8-:*97.4/0418-: .9 .

.0.90/2. /  5:9*/8 /0. /  :3708907*-/0.4/0418-: .*2. /. /0.20  .4/8-:*09 .4/  5739 8-:*09 098-: 3  /0*03/8 /0..*3.  < 24/:0*39 8-:*39  24/:0*09 8-:*09  .47*37 /0.748 89.$4:7. .9.9.3/24/:0 70.439 8-:*092094/.1700 /0.

3:.%0.3/.3/ 303.0 1306  ##$ 4- 28-: 4  907800070.422.0//70.0-0033.9174290. 0730   1##$8/0130/ 0 .40/174290 0730-:/88902...3:8098.40900730-:/88902 080 #.0101478-: .010418-: .

-.

24/:08.

20 7 . 80:3.

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

0 8:/43824/8-: 4 .3/38079394900730 2.9..07 . W 70.90908250-4./0..0/7.

574.

/0.087058-: ..

034/0. .439 W 70.3/24:399 8:/4234/.9090/0..

/0.

0 W &-:39:2.- W 705.473:2-074:09.8-:.70..9090.-4.0894902..

/0.

147:8 8:/4218 09.8-:.

/0.

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

/0.

9025 /1 .8-:.

439 . .

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

/0.

8-:.9025 89025 .

439 . .

790.439 W #024.0908-:24/:01742900730 8:/4:24:399025 8:/47224/8-: W &-:39:.0.84. .

/0.

8-:.147:8 .

/839490 88902 907.078438-: -03974/:.2/8.80 .799438 5.0/ 9.4.. W 398007.79943.5 8  .85..804:38079.3104507.3-050714720/439 W 218 24:39 :24:39 .-0 2.2/8.908 2024785.09482:. 7.0903/0/.90.9438..

.80 1:3.//8430301:3.9:70 .94338-:*458 897:.9438 .9:70202-07 8479:8078 3 8-:*/0.439 W 347/079409908-:.//830897:. .9078908-:*4503 .-094-0 5.799430/ 9070.3/8-:*700.70842093300/0/-0 /430 8098$&* #$94 .

80 04 .2/ :3830/43.98-:*/0.439 %0897:.9 398-:*4./8 04 80.9478 04 89.9 897:. .80 *%  80/0.90*/.9.2/  . /0.910 15 :3830/39.45*94*:807 04 8041 04 709:73 &% 709:73  < 709:73  %%.9:702094/8-:*4.7  4380 897:.79 1 .. 89.9/*04209704 897:.934/0 34/0 897:. .3/078 80 = 1  04 0..15 57.

:3343.3/ .422.

943 ./0890042097 31472. < .4/**:807 .7  !74.

4..934/0 34/0 897:. /0.439 %01:3.34/0 *-/0. /0. 15 57.80 89. /0.  709:73  < 89.80 897:. 4. 853*4.  709:73  < . :8078  853*:34.90*/.9. . /0. -/*/8 57.90*/.3/8-:*700.90*/. :8078  853*:34. /0.34/0 *-/0.934/0 34/0 897:.98-:*/0.9.9./0.94388-:*4503.98-:*/0.910 15  897:..9.398-:*4503 897:.  /0. /0.910 15  897:. -/*/8 57.398-:*700.. 4.9. 853*4.  /0. 4.

0.3 2.0 8:/43824/8-: 4 8:/41/8 . .0.439 W %089900903/0/8-:24/:08 2.

/0.

8-:. .

439 . .

439 W 40.. .9890-9014433897:.0945.2/8 W 472.9438 8:/4218 09.7994383908-:7.

/0.

 8:/4218 09.8-:.

/0.

 8:/424:39.8-:.

/0.

9025 8:/424:39.8-:.

/0.

9025 /1 .8-:.

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

/0.

3.203897:.:90/43908-:..3/.9.020430-4.3/4-807..3-05. .80/4390 . 4:.94300.799430/.09  .3 W .438:9908-:41070 .0../0..55030/ W %7908.:942.8-:.9.

439 . .

 W %070.4220394:9903.:/03:.70940774783908-:41 #0 .

.309030 W 1742 03/*9.9430 :89950 2.0 8:/43824/8-: 4 8 .89 706  W 94 03/*9.3994979..9*706:089*.431  .89 706   14:..9*706:089*.

/0.

8-: .

90.9:70 .33: 3:4.0754793.#010703..078 7//943 7488 #010703.0 W W W W 7.07./7.8250-4.07.07 3:0.0..