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);

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

struct gendisk .

struct block_device_operations .

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

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

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

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

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

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

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

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

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

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

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

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

ext2 /dev/sbulla mkdir temp sudo mount /dev/sbulla temp df .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.

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

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.

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

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

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

LAB 2 (cont’) .

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

give me one block device with: – 20MB and can be partitioned automatically: – you can consult the sbull of LDD here .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.

LAB 3 (cont’) .

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

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

!  .

439 897:.9. 897:.4/0418-: .0.*94.9.7 /.0 897:.$4:7.3/1:3.9. <0..0 -/0. /0..897:.98-:*/0. .  :3830/4380 :3830/..94357494950 89..9-4.*/0.0 . 0. 8534.98-:*/0.903/8 / 897:.

.

398-:*700.80 897:.910 15  89.947 :3830/43380.9.98-:*/0.398-:*4503 897:.. :3830/43 80.934/0 34/0 897:..38107 897:.94357494950 89.9..9.7 -:1107 39790  89.4/8-:*706:089 706:089*6:0:0*9 6  .934/0 34/0 897:. /0.9 .4/8-:*97.1:3.9.910 15  89.

$4:7.802094/8 89.94388-:*458  4307%$* & 45038-:*4503 700. .4/0418-: .9.80 897:.398-:*700.0.0.9..3/4503  700.439 89.80 /43493 3  709:73  < .398-:*4503 897:.*/0.808-:*700.0*4507.910 15  5739 8-:*700.9..934/0 34/0 897:.897:.910 15  5739 8-:*4503 /43493 3  709:73  < 89.934/0 34/0 897:.9-4.80 < 897:.90.

8-: 3  .439 89.4/0418-: .4/  5739 8-:*39 39. .$4:7.0.398-:*39 .9.

.

98-:*/0.9.2. /.  8041 897:.9478 .47*37  5739 8-:*39 :3.897:.-094092.4.473:2-073  709:73  < 202809 /0.39.*2.:70 3  709:73  < .47*37 /0.*2.2.20  1 /0. /0.947*80 /0. 80  1 /0.7/80. /0..  /0.*3.9.4.47*37708907*-/0.1.&  5739 8-:*39 .98-:*/0. /.*2. /0. 80380.

.

 853*4.*39 /0.39.8534.  8-:*392094/ . 4.

4/0418-: . .439 .0.$4:7.

.

47*37 /0.:70 3  709:73  < /0. / 1789*2347  /0.9 / /0. / 1458 8-:*458 . /.*/8 $&* #$  1 /0.4.*2.90/81..47/0.4.39. /  5739 8-:*39 . / 2.03/8897:.

.

9..104507./0. . / 57.9438543907 /0.90*/.

.

14757.90:80 897..  . / /8*3.5 /0.20 8-:.

.

5. 809*. / 380..03.9478  ...2088-:./0.9 /0.

.

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

90*/.4/0418-: . .4/8-:*706:089 706:089*6:0:0*9 6  897:.98-:*/0.947948:-29 34 4180. 1 -*18*706:089 706  1343 18706:089070  03/*706:089 706  /43493 < 080  30980.38107/7 < . 706 80./09097..$4:7.947 706 .9478948:-29 8-:*97.*/7 706  03/*706:089 706   < < /0.:77039*37*80.*309*706:089 6 &  897:..9478 706 -:1107 76*/.9.38107 /0.9.0.9706:089 706 0 7060.9.439 8-:*706:0892094/ 89. /0.706 76*/8 57.

9 .9. . 411809 -:1107 3-908  080 202.$4:7.0.9.5 -:1107 /0. :3830/4380.381072094/ 89.4/8-:*97.38107 897:.439 8-:*97. /.947 #*$% #*$ :3830/433-908380. 80  5739 #* %-043/ 03/790 // 3 411809 3-908  709:73 < 1 790 202.947 :3830/43380..9 #*$% #*$ 1  411809 3-908 /0.5 /0. /.7 -:1107 39790  :3830/4341180980.9..4/0418-: .98-:*/0. /0. 411809 3-908  < .

0.*3. /  :3708907*-/0. /0.20  .*2..9.  < 24/:0*39 8-:*39  24/:0*09 8-:*09  ..439 8-:*092094/.9.$4:7.1700 /0.3/24/:0 70.90/2. /.4/8-:*09 .748 89. .4/  5739 8-:*09 098-: 3  /0*03/8 /0.47*37 /0.4/0418-: . /  5:9*/8 /0.

0//70.3:8098..422.3:.0 1306  ##$ 4- 28-: 4  907800070.9174290..40900730-:/88902 080 #.010418-: .0-0033.40/174290 0730-:/88902. 0730   1##$8/0130/ 0 .3/.%0.3/ 303.0101478-: .

-.

24/:08.

 80:3.20 7 .

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

0/7../0.0 8:/43824/8-: 4 .07 ..90908250-4. W 70.9.3/38079394900730 2.

574.

087058-: ../0.

439 W 70. .3/24:399 8:/4234/.034/0.9090/0..

/0.

- W 705..0894902.-4.70.0 W &-:39:2.9090.8-:..473:2-074:09.

/0.

147:8 8:/4218 09.8-:.

/0.

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

/0.

9025 /1 .8-:.

 .439 .

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

/0.

9025 89025 .8-:.

439 . .

439 W #024. .84.0908-:24/:01742900730 8:/4:24:399025 8:/47224/8-: W &-:39:.0.790.

/0.

8-:.147:8 .

3-050714720/439 W 218 24:39 :24:39 .-0 2.3104507.80 . 7.4.2/8.90.09482:.078438-: -03974/:.9438./839490 88902 907....2/8.0903/0/.799438 5.5 8  .908 2024785.804:38079.85. W 398007.79943.0/ 9.

//8430301:3. .439 W 347/079409908-:.3/8-:*700.799430/ 9070.//830897:.9:70202-07 8479:8078 3 8-:*/0.94338-:*458 897:.-094-0 5.9438 .9078908-:*4503 .80 1:3.9:70 . .70842093300/0/-0 /430 8098$&* #$94 .

2/ :3830/43. 89.439 %0897:.9/*04209704 897:.90*/.15 57.3/078 80 = 1  04 0. 80 04 .45*94*:807 04 8041 04 709:73 &% 709:73  < 709:73  %%. ./8 04 80.9:702094/8-:*4.2/  ...9 398-:*4. /0.80 *%  80/0.7  4380 897:.934/0 34/0 897:. .98-:*/0.79 1 .9.910 15 :3830/39.9478 04 89.9 897:.

3/ .422. :3343.

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

 853*4./0.80 897:.  709:73  < 89. /0.90*/. /0.  709:73  < . :8078  853*:34.398-:*4503 897:.934/0 34/0 897:. 4.90*/. 4. /0.439 %01:3.910 15  897:. 853*4.94388-:*4503.9. /0. . 4.9. -/*/8 57.80 89.98-:*/0.34/0 *-/0.9.910 15  897:. /0..98-:*/0. :8078  853*:34.3/8-:*700. 15 57.  /0.34/0 *-/0..90*/. 4. /0.9..934/0 34/0 897:.  /0.9. -/*/8 57.398-:*700.

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

/0.

.8-:.

 .439 .

. .7994383908-:7.9438 8:/4218 09.2/8 W 472.9890-9014433897:.0945.439 W 40.

/0.

 8:/4218 09.8-:.

/0.

 8:/424:39.8-:.

/0.

9025 8:/424:39.8-:.

/0.

8-:.9025 /1 .

801472. W !0.1.9908-:3-3897:.9 .943 8:/4218 .

/0.

.:90/43908-:.09  .80/4390 .9.8-:.3-05.3/.203897:.3.55030/ W %7908.0.3/4-807.438:9908-:41070 ..:942.799430/. 4:.3 W .020430-4.9.. ./0..94300.

 .439 .

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

.309030 W 1742 03/*9.3994979..89 706   14:.9*706:089*.0 8:/43824/8-: 4 8 .9430 :89950 2.9*706:089*.89 706  W 94 03/*9.431  ..

/0.

8-: .

9:70 ..0 W W W W 7.07 3:0.8250-4..078 7//943 7488 #010703./7.07.90.0.07.#010703.33: 3:4.0754793.