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

struct gendisk .

struct block_device_operations .

< . ls. cp. umount.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. mount.

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

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

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

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

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

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

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

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

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

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

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 .

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

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.

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

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

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’) .

h> – change the line 181 • from “end_that_request_last(req).” • to “end_that_request_last(req. just type: make sudo insmod sbull.ko ls –al /dev/sbull* .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. 1).

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

!  .

.*94.. <0.9.  :3830/4380 :3830/.0 .$4:7.9-4.3/1:3.. . 0.0 897:..9.439 897:.897:.94357494950 89.*/0.9.4/0418-: . 897:. 8534.0 -/0.0. /0.7 /.98-:*/0.98-:*/0.903/8 / 897:.

.

94357494950 89.398-:*4503 897:.9. :3830/43 80..98-:*/0.9.9..934/0 34/0 897:.4/8-:*706:089 706:089*6:0:0*9 6  .9 .9.947 :3830/43380.398-:*700.4/8-:*97.80 897:. /0.934/0 34/0 897:.910 15  89.38107 897:..1:3.910 15  89.7 -:1107 39790  89.

.439 89.0*4507.$4:7..910 15  5739 8-:*700.802094/8 89.90.910 15  5739 8-:*4503 /43493 3  709:73  < 89.934/0 34/0 897:.398-:*4503 897:.0.934/0 34/0 897:.80 < 897:.9-4.3/4503  700.80 897:.80 /43493 3  709:73  < . .*/0.9.94388-:*458  4307%$* & 45038-:*4503 700.9.4/0418-: .808-:*700.0.9.897:.398-:*700.

4/0418-: .398-:*39 . .0.$4:7.4/  5739 8-:*39 39.9.439 89.8-: 3  .

.

*3..20  1 /0.897:. /.947*80 /0.9. /0.7/80.2.9478 .47*37  5739 8-:*39 :3.98-:*/0. /0.:70 3  709:73  < .&  5739 8-:*39 .*2.1.98-:*/0.47*37 /0.  8041 897:. /. 80380.47*37708907*-/0.2.473:2-073  709:73  < 202809 /0.  /0.-094092.4.39.*2. /0. 80  1 /0.4.9.*2.

.

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

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

.

/. /  5739 8-:*39 .47/0..03/8897:.47*37 /0.4. / 1789*2347  /0.39. / 2.*2.9 / /0.4. / 1458 8-:*458 .90/81.*/8 $&* #$  1 /0.:70 3  709:73  < /0.

.

9438543907 /0.90*/. / 57. .9.104507../0.

.

.90:80 897. / /8*3.5 /0.  .20 8-:.14757.

.

5.. / 380./0.03. 809*.2088-:..9478  .9 /0..

.

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

439 8-:*706:0892094/ 89.9478948:-29 8-:*97.*309*706:089 6 &  897:.$4:7.947948:-29 34 4180.4/0418-: .9.947 706 . 1 -*18*706:089 706  1343 18706:089070  03/*706:089 706  /43493 < 080  30980.9478 706 -:1107 76*/. /0..38107/7 < . 706 80.*/7 706  03/*706:089 706   < < /0..9. .4/8-:*706:089 706:089*6:0:0*9 6  897:.98-:*/0.:77039*37*80.90*/.38107 /0.706 76*/8 57./09097.9.0.9706:089 706 0 7060.

4/8-:*97. .4/0418-: ..7 -:1107 39790  :3830/4341180980.5 -:1107 /0.9.9 .947 #*$% #*$ :3830/433-908380.5 /0.9 #*$% #*$ 1  411809 3-908 /0.38107 897:.439 8-:*97.98-:*/0. /. 411809 3-908  < . /0.0.947 :3830/43380. 80  5739 #* %-043/ 03/790 // 3 411809 3-908  709:73 < 1 790 202. :3830/4380.$4:7.381072094/ 89.9. /.9.. 411809 -:1107 3-908  080 202.

.*3.47*37 /0.4/8-:*09 .3/24/:0 70. .9. /  :3708907*-/0. /0. /.20  .9.439 8-:*092094/.4/0418-: .90/2.  < 24/:0*39 8-:*39  24/:0*09 8-:*09  .4/  5739 8-:*09 098-: 3  /0*03/8 /0. /  5:9*/8 /0.$4:7.1700 /0..*2.748 89.0.

0730   1##$8/0130/ 0 .3:.3/.422.3/ 303..40900730-:/88902 080 #.9174290..0 1306  ##$ 4- 28-: 4  907800070.40/174290 0730-:/88902.3:8098.0101478-: .0//70.%0.0-0033.010418-: .

-.

24/:08.

20 7 . 80:3.

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

./0.0 8:/43824/8-: 4 .0/7.9.07 .3/38079394900730 2. W 70..90908250-4.

574.

/0.087058-: ..

 .3/24:399 8:/4234/.439 W 70.9090/0.034/0..

/0.

473:2-074:09.- W 705.9090.0 W &-:39:2.-4..8-:.70..0894902.

/0.

147:8 8:/4218 09.8-:.

/0.

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

/0.

8-:.9025 /1 .

439 . .

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

/0.

9025 89025 .8-:.

439 . .

439 W #024.790.84.0.0908-:24/:01742900730 8:/4:24:399025 8:/47224/8-: W &-:39:. .

/0.

8-:.147:8 .

3104507.79943...804:38079.078438-: -03974/:. 7.. W 398007.3-050714720/439 W 218 24:39 :24:39 .0/ 9.5 8  .9438.0903/0/.799438 5.80 .908 2024785.90.-0 2.4./839490 88902 907.09482:.85.2/8.2/8.

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

98-:*/0.910 15 :3830/39.3/078 80 = 1  04 0.45*94*:807 04 8041 04 709:73 &% 709:73  < 709:73  %%.9:702094/8-:*4. .79 1 .90*/..80 *%  80/0.9478 04 89.2/ :3830/43.9/*04209704 897:.15 57. 89.9.934/0 34/0 897:./8 04 80.7  4380 897:. 80 04 . /0..439 %0897:.9 398-:*4.9 897:.2/  . .

3/ .422. :3343.

943 .4/**:807 ./0890042097 31472.7  !74. < .

90*/.910 15  897:. /0.98-:*/0.398-:*700.3/8-:*700.910 15  897:. . /0. :8078  853*:34. /0.9.80 897:.34/0 *-/0. /0.  709:73  < 89.9.90*/.  709:73  < .9.90*/. :8078  853*:34.398-:*4503 897:.439 %01:3.  /0. 853*4. 853*4.  /0.34/0 *-/0. -/*/8 57./0. -/*/8 57. 4.98-:*/0..934/0 34/0 897:. 15 57.80 89..9..9. 4. /0. 4.94388-:*4503. /0. 4.934/0 34/0 897:.

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

/0.

8-:. .

 .439 .

9890-9014433897:..0945.7994383908-:7. .2/8 W 472.439 W 40.9438 8:/4218 09.

/0.

8-:. 8:/4218 09.

/0.

8-:. 8:/424:39.

/0.

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

/0.

8-:.9025 /1 .

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

/0.

 4:.80/4390 ..3/4-807.:90/43908-:.3/..799430/..09  .3.9.3-05.3 W ..:942.55030/ W %7908.0./0. .438:9908-:41070 .94300.8-:.9.020430-4.203897:.

439 . .

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

.309030 W 1742 03/*9.431  ...9*706:089*.9430 :89950 2.89 706  W 94 03/*9.9*706:089*.0 8:/43824/8-: 4 8 .3994979.89 706   14:.

/0.

8-: .

90.0754793..07.#010703.8250-4.07 3:0.9:70 .078 7//943 7488 #010703.07.33: 3:4.0.0 W W W W 7../7.