Block Device Drivers: - Naga Manjunath Senior S/W Engg in Bosch

Download as ppt, pdf, or txt
Download as ppt, pdf, or txt
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);

Quick Functions Reference


(cont)

#include <linux/fs.h>
struct block_device_operations

#include<linuix/genhd.h>
struct gendisk

#include <linux/blkdev.h>
struct request

struct gendisk

struct block_device_operations

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

Simple block device driver: sbull (cont)


Needed functions:
sbull_init() sbull_exit() sbull_open() sbull_release() sbull_request() sbull_transfer()

Source code of sbull.c


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

Source code of sbull.c (cont)


struct sbull_dev { unsigned long size; unsigned char *data; spinlock_t lock; struct gendisk *gd; struct block_device *bdev; }Device;

struct and function prototype

static struct sbull_dev *dev = &Device; // function prototype static int sbull_open(struct inode *inode, struct file *filp); static int sbull_release(struct inode *inode, struct file *filp); static void sbull_transfer(struct sbull_dev *dev, unsigned long sector,unsigned long nsect, char *buffer, int write); static void sbull_request(request_queue_t *q);

Source code of sbull.c (cont)


static struct block_device_operations sbull_ops = { .owner = THIS_MODULE, .open = sbull_open, .release = sbull_release };

struct Device and open, release methods

static int sbull_open(struct inode *inode, struct file *filp) { printk("sbull_open(): do nothing...\n"); return 0; } static int sbull_release(struct inode *inode, struct file *filp) { printk("sbull_release(): do nothing...\n"); return 0; }

Source code of sbull.c (cont)


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

sbull_init method

Source code of sbull.c (cont)


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

sbull_init method: (cont)

Source code of sbull.c (cont)

sbull_request method

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

Source code of sbull.c (cont)


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

Source code of sbull.c (cont)


sbull_exit method and module-related macros

static void sbull_exit(void) { printk("sbull_exit(): exit sbull...\n"); del_gendisk(dev->gd); put_disk(dev->gd); unregister_blkdev(dev_major_nr, dev_name); vfree(dev->data); } module_init(sbull_init); module_exit(sbull_exit);

The Makefile of sbull


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

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)

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

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

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, struct file *filp, unsigned int cmd, unsigned long arg) { long size; struct hd_geometry geo; struct sbull_dev *dev = filp->private_data; switch(cmd) { case HDIO_GETGEO: size = dev->size; geo.cylinders= (size & ~0x3f) >> 6; geo.heads= 4; geo.sectors= 16; geo.start= 4; if (copy_to_user((void __user *) arg, &geo, sizeof(geo))) return -EFAULT; return 0; } return -ENOTTY; /* unknown command */

Provides the geometry information

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

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

LAB 2 (cont)

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.ext2 /dev/sbulla2 sudo mount /dev/sbulla1 temp sudo mount /dev/sbulla2 temp2 df

LAB 3
Please format the sbull in LAB1 by instruction: sudo mkfs.vfat F16 /dev/sbulla and observe what happened Try the same instruction executed on the sbulla in LAB2 Based on the LAB2, 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 OReilly:
comment out the #include <linux/config.h> change the line 181
from end_that_request_last(req); to end_that_request_last(req, 1);

if you want to try that one, just type:


make sudo insmod sbull.ko ls al /dev/sbull*

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

You might also like