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] *