Block device driver from ldd3

Source: Internet
Author: User

The compilation failed on 2.6.36 and the appropriate changes were made.

 

/*
* Sample disk driver, from the beginning.
*/

// # Include <linux/config. h>
# Include <linux/module. h>
# Include <linux/moduleparam. h>
# Include <linux/init. h>

# Include <linux/sched. h>
# Include <linux/kernel. h>/* printk ()*/
# Include <linux/slab. h>/* kmalloc ()*/
# Include <linux/fs. h>/* everything ...*/
# Include <linux/errno. h>/* error codes */
# Include <linux/timer. h>
# Include <linux/types. h>/* size_t */
# Include <linux/fcntl. h>/* O_ACCMODE */
# Include <Linux/hdreg. h>/* hdio_getgeo */
# Include <Linux/kdev_t.h>
# Include <Linux/vmalloc. h>
# Include <Linux/genhd. h>
# Include <Linux/blkdev. h>
# Include <Linux/buffer_head.h>/* invalidate_bdev */
# Include <Linux/Bio. h>

Module_license ("dual BSD/GPL ");

Static int sbull_major = 0;
Module_param (sbull_major, Int, 0 );
Static int maid size = 512;
Module_param (hardsect_size, Int, 0 );
Static int nsectors = 1024;/* how big the drive is */
Module_param (nsectors, Int, 0 );
Static int ndevices = 4;
Module_param (ndevices, Int, 0 );

/*
* The different "request Modes" we can use.
*/
Enum {
RM_SIMPLE = 0,/* The extra-simple request function */
RM_FULL = 1,/* The full-blown version */
RM_NOQUEUE = 2,/* Use make_request */
};
Static int request_mode = RM_SIMPLE;
Module_param (request_mode, int, 0 );

/*
* Minor number and partition management.
*/
# Define SBULL_MINORS 16
# Define MINOR_SHIFT 4
# Define DEVNUM (kdevnum) (MINOR (kdev_t_to_nr (kdevnum)> MINOR_SHIFT

/*
* We can tweak our hardware sector size, but the kernel talks to us
* In terms of small sectors, always.
*/
# Define KERNEL_SECTOR_SIZE 512

/*
* After this much idle time, the driver will simulate a media change.
*/
# Define INVALIDATE_DELAY 30 * HZ

/*
* The internal representation of our device.
*/
Struct sbull_dev {
Int size;/* Device size in sectors */
U8 * data;/* The data array */
Short users;/* How many users */
Short media_change;/* Flag a media change? */
Spinlock_t lock;/* For mutual exclusion */
Struct request_queue * queue;/* The device request queue */
Struct gendisk * gd;/* The gendisk structure */
Struct timer_list timer;/* for simulated media changes */
};

Static struct sbull_dev * devices = NULL;

/*
* Handle an I/O Request.
*/
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)/n", offset, nbytes );
Return;
}
If (write)
Memcpy (dev-> data + offset, buffer, nbytes );
Else
Memcpy (buffer, dev-> data + offset, nbytes );
}

/*
* The simple form of the request function.
*/
Static void sbull_request (struct request_queue * q)
{
Struct request * req;

While (req = blk_fetch_request (q ))! = NULL ){
Struct sbull_dev * dev = req-> rq_disk-> private_data;
If (req-> performance_type! = REQ_TYPE_FS ){
Printk (KERN_NOTICE "Skip non-fs request/n ");
_ Blk_end_request_all (req, 0 );
Continue;
}
// Printk (KERN_NOTICE "Req dev % d dir % ld sec % ld, nr % d f % lx/n ",
// Dev-Devices, rq_data_dir (req ),
// Req-> sector, req-> current_nr_sectors,
// Req-> flags );
Sbull_transfer (dev, blk_rq_pos (req), blk_rq_cur_sectors (req ),
Req-> buffer, rq_data_dir (req ));
_ Blk_end_request_all (req, 1 );
}
}

/*
* Transfer a single BIO.
*/
Static int sbull_xfer_bio (struct sbull_dev * dev, struct bio * bio)
{
Int I;
Struct bio_vec * bvec;
Sector_t sector = bio-> bi_sector;

/* Do each segment independently .*/
Bio_for_each_segment (bvec, bio, I ){
Char * buffer = _ bio_kmap_atomic (bio, I, KM_USER0 );
Sbull_transfer (dev, sector, bio_cur_bytes (bio)> 9,
Buffer, bio_data_dir (bio) = WRITE );
Sector + = bio_cur_bytes (bio)> 9;
_ Bio_kunmap_atomic (bio, KM_USER0 );
}
Return 0;/* Always "succeed "*/
}

/*
* Transfer a full request.
*/
Static int sbull_xfer_request (struct sbull_dev * dev, struct request * req)
{
Struct bio_vec * biov;
Struct req_iterator riter;
Int nsect = 0;

Rq_for_each_segment (biov, req, riter ){
Sbull_xfer_bio (dev, req-> bio );
Nsect + = req-> bio-> bi_size/KERNEL_SECTOR_SIZE;
}
Return nsect;
}

/*
* Smarter request function that "handles clustering ".
*/
Static void sbull_full_request (struct request_queue * q)
{
Struct request * req;
Int sectors_xferred;
Struct sbull_dev * dev = q-> queuedata;

While (req = blk_fetch_request (q ))! = NULL ){
If (req-> performance_type! = REQ_TYPE_FS ){
Printk (KERN_NOTICE "Skip non-fs request/n ");
_ Blk_end_request_cur (req,-EIO );
Continue;
}
Sectors_xferred = sbull_xfer_request (dev, req );
_ Blk_end_request_all (req, 0 );
}
}

/*
* The direct make request version.
*/
Static int sbull_make_request (struct request_queue * q, struct bio * bio)
{
Struct sbull_dev * dev = q-> queuedata;
Int status;

Status = sbull_xfer_bio (Dev, bio );
Bio_endio (Bio, status );
Return 0;
}

/*
* Open and Close.
*/

Static int sbull_open (struct block_device * bdev, fmode_t Mode)
{
Struct sbull_dev * Dev = bdev-> bd_disk-> private_data;

Del_timer_sync (& Dev-> timer );
Spin_lock (& Dev-> lock );
If (! Dev-> Users)
Check_disk_change (bdev );
Dev-> Users ++;
Spin_unlock (& Dev-> lock );
Return 0;
}

Static int sbull_release (struct gendisk * gd, fmode_t mode)
{
Struct sbull_dev * dev = gd-> private_data;

Spin_lock (& dev-> lock );
Dev-> users --;

If (! Dev-> users ){
Dev-> timer. expires = jiffies + INVALIDATE_DELAY;
Add_timer (& dev-> timer );
}
Spin_unlock (& dev-> lock );

Return 0;
}

/*
* Look for a (simulated) media change.
*/
Int sbull_media_changed (struct gendisk * gd)
{
Struct sbull_dev * dev = gd-> private_data;

Return dev-> media_change;
}

/*
* Revalidate. we do not take the lock here, for fear of deadlocking
* With open. That needs to be reevaluated.
*/
Int sbull_revalidate (struct gendisk * gd)
{
Struct sbull_dev * dev = gd-> private_data;

If (dev-> media_change ){
Dev-> media_change = 0;
Memset (dev-> data, 0, dev-> size );
}
Return 0;
}

/*
* The "invalidate" function runs out of the device timer; it sets
* A flag to simulate the removal of the media.
*/
Void sbull_invalidate (unsigned long ldev)
{
Struct sbull_dev * dev = (struct sbull_dev *) ldev;

Spin_lock (& dev-> lock );
If (dev-> users |! Dev-> data)
Printk (KERN_WARNING "sbull: timer sanity check failed/n ");
Else
Dev-> media_change = 1;
Spin_unlock (& dev-> lock );
}

/*
* The ioctl () implementation
*/

Int sbull_ioctl (struct block_device * bdev, fmode_t mode,
Unsigned int cmd, unsigned long arg)
{
Long size;
Struct hd_geometry geo;
Struct sbull_dev * dev = bdev-> bd_disk-> private_data;

Switch (cmd ){
Case HDIO_GETGEO:
/*
* Get geometry: since we are a virtual device, we have to make
* Up something plausible. So we claim 16 sectors, four heads,
* And calculate the corresponding number of cylinders. We set
* Start of data at sector four.
*/
Size = dev-> size * (hardsect_size/KERNEL_SECTOR_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 */
}

/*
* The device operations structure.
*/
Static struct block_device_operations sbull_ops = {
. Owner = THIS_MODULE,
. Open = sbull_open,
. Release = sbull_release,
. Media_changed = sbull_media_changed,
. Revalidate_disk = sbull_revalidate,
. Ioctl = sbull_ioctl
};

/*
* Set up our internal device.
*/
Static void setup_device (struct sbull_dev * dev, int which)
{
/*
* Get some memory.
*/
Memset (Dev, 0, sizeof (struct sbull_dev ));
Dev-> size = nsectors * hardsect_size;
Dev-> DATA = vmalloc (Dev-> size );
If (Dev-> DATA = NULL ){
Printk (kern_notice "vmalloc failure./N ");
Return;
}
Spin_lock_init (& Dev-> lock );

/*
* The timer which "invalidates" the device.
*/
Init_timer (& Dev-> timer );
Dev-> timer. data = (unsigned long) dev;
Dev-> timer. function = sbull_invalidate;

/*
* The I/O queue, depending on whether we are using our own
* Make_request function or not.
*/
Switch (request_mode ){
Case RM_NOQUEUE:
Dev-> queue = blk_alloc_queue (GFP_KERNEL );
If (dev-> queue = NULL)
Goto out_vfree;
Blk_queue_make_request (dev-> queue, sbull_make_request );
Break;

Case RM_FULL:
Dev-> queue = blk_init_queue (sbull_full_request, & dev-> lock );
If (dev-> queue = NULL)
Goto out_vfree;
Break;

Default:
Printk (KERN_NOTICE "Bad request mode % d, using simple/n", request_mode );
/* Fall ..*/

Case RM_SIMPLE:
Dev-> queue = blk_init_queue (sbull_request, & dev-> lock );
If (dev-> queue = NULL)
Goto out_vfree;
Break;
}
Blk_queue_logical_block_size (dev-> queue, hardsect_size );
Dev-> queue-> queuedata = dev;
/*
* And the gendisk structure.
*/
Dev-> gd = alloc_disk (SBULL_MINORS );
If (! Dev-> gd ){
Printk (KERN_NOTICE "alloc_disk failure/n ");
Goto out_vfree;
}
Dev-> Gd-> major = sbull_major;
Dev-> Gd-> first_minor = which * sbull_minors;
Dev-> Gd-> fops = & sbull_ops;
Dev-> Gd-> queue = Dev-> queue;
Dev-> Gd-> private_data = dev;
Snprintf (Dev-> Gd-> disk_name, 32, "sbull % C", which + 'A ');
Set_capacity (Dev-> GD, nsectors * (hardsect_size/kernel_sector_size ));
Add_disk (Dev-> Gd );
Return;

Out_vfree:
If (Dev-> data)
Vfree (Dev-> data );
}

Static int _ init sbull_init (void)
{
Int I;
/*
* Get registered.
*/
Sbull_major = register_blkdev (sbull_major, "sbull ");
If (sbull_major <= 0 ){
Printk (KERN_WARNING "sbull: unable to get major number/n ");
Return-EBUSY;
}
/*
* Allocate the device array, and initialize each one.
*/
Devices = kmalloc (ndevices * sizeof (struct sbull_dev), GFP_KERNEL );
If (Devices = NULL)
Goto out_unregister;
For (I = 0; I <ndevices; I ++)
Setup_device (Devices + I, I );

Return 0;

Out_unregister:
Unregister_blkdev (sbull_major, "sbd ");
Return-ENOMEM;
}

Static void sbull_exit (void)
{
Int I;

For (I = 0; I <ndevices; I ++ ){
Struct sbull_dev * dev = Devices + I;

Del_timer_sync (& dev-> timer );
If (dev-> gd ){
Del_gendisk (dev-> gd );
Put_disk (dev-> gd );
}
If (dev-> queue ){
Blk_cleanup_queue (dev-> queue );
}
If (dev-> data)
Vfree (dev-> data );
}
Unregister_blkdev (sbull_major, "sbull ");
Kfree (Devices );
}

Module_init (sbull_init );
Module_exit (sbull_exit );

 

Finally, the loaded script

#! /Bin/bash

Function make_minors {
Minors = 16
Part = 0
# Echo "/$0 is $0"
# Echo "/$1 is $1"
# Echo "/$2 is $2"
While ["$ part"-le $ minors]
Do
Minor = $ ($ part + $2 ))
# Echo "minor is $ minor"
Name = 'echo "$1" $ part'
# Echo "name is $ name"
Mknod $ name B $ major $ minor
Part = $ ($ part + 1 ))
# Echo "part is $ part"
Done
}

# FIXME: This isn' t handling minors (partitions) at all.
Module = "sbull"
Device = "sbull"
Mode = "664"
Chardevice = "sbullr"

# Group: since distributions do it differently, look for wheel or use staff
If grep '^ staff:'/etc/group>/dev/null; then
Group = "staff"
Else
Group = "wheel"
Fi

# Invoke insmod with all arguments we got
# And use a pathname, as newer modutils don't look in. by default
/Sbin/insmod-f./$ module. ko $ * | exit 1

Major = 'cat/proc/devices | awk "// $2 =/" $ module/"{print // $1 }"'

# Remove stale nodes and replace them, then give GID and perms

Rm-F/dev/$ {Device} [a-d] */dev/$ {Device}

Mknod/dev/$ {Device} a B $ major 0
Make_minors/dev/$ {Device} A 0
Mknod/dev/$ {Device} B $ major 16
Make_minors/dev/$ {Device} B 16
Mknod/dev/$ {Device} c B $ major 32
Make_minors/dev/$ {Device} C 32
Mknod/dev/$ {Device} d B $ major 48
Make_minors/dev/$ {Device} d 48
Ln-SF $ {Device} A/dev/$ {Device}
Chgrp $ group/dev/$ {Device} [a-d] *
Chmod $ mode/dev/$ {Device} [a-d] *

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.