Linux block device driver (iv)--Simple Sbull instance

Source: Internet
Author: User

#include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> #include <linux /sched.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/fs.h> #include < linux/errno.h> #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>Static intsbull_major = 0;/ * block device number, 0 is automatically assigned * /Module_param (Sbull_major,int, 0);//modulus parameter, this main device number can specify a value when the module is loaded Static intHardsect_size = 512;/ * Hardware Sector size * /Module_param (Hardsect_size,int, 0);/ * ditto * / Static intNsectors = 1024;/ * Number of hardware sectors * /Module_param (Nsectors,int, 0);/ * ditto * / Static intNdevices = 4; Module_param (Ndevices,int, 0);/ * The different "request modes" we can use. */ enum{rm_simple = 0, Rm_full = 1, Rm_noqueue = 2,};Static intRequest_mode = Rm_simple; Module_param (Request_mode,int, 0);#defineSbull_minors 16#defineKernel_sector_size 512#defineInvalidate_delay 30*hz/*SBULL Device Structure * / structsbull_dev{intSize/ * In sector units, device size * /U8 *data;/ * Data array * / ShortUsers/ * Number of users * / ShortMedia_change;/ * Media Change flag * /spinlock_tLock;/ * for Mutex * / structRequest_queue *queue;/ * Device Request queue * / structGendisk *GD;/ * GENDISK structure * / structTimer_list timer;/ * Used to simulate media changes * /};Static structSbull_dev *devices = NULL;/* * Handle an I/O request. Functions for processing I/O copy data */ Static voidSbull_transfer (structSbull_dev *dev, unsignedLongsector, unsignedLongNsect,Char*buffer,intWrite) {unsignedLongoffset = sector * KERNEL_SECTOR_SIZE; UnsignedLongnbytes = 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);Elsememcpy (buffer, Dev->data + offset, nbytes); }/* * The simple form of the request function. */ Static voidSbull_request (structRequest_queue *q) {structRequest *req;//define Request structurereq = Blk_fetch_request (q); while(req! = NULL) {structSbull_dev *dev = req->rq_disk->private_data;//Get the first outstanding request in a queue if(Req->cmd_type! = req_type_fs) {//Determine if the file system requestPRINTK (Kern_notice"Skip non-fs request\n"); Blk_end_request_all (req,-eio);//Notification request processing failed, Eio for I/O error. Continue; } sbull_transfer (Dev, Blk_rq_pos (req),//Sector cursor whereBlk_rq_cur_sectors (req),//number of sectors that need to be transferredReq->buffer,//data buffers to be transmitted or acceptedRq_data_dir (req));//Get transmission direction, 0 means read, 1 means write if(!__blk_end_request_cur (req, 0)) {//Next requestreq = NULL; } } }/* * Transfer a single bio. Bio Processing function */ Static intSbull_xfer_bio (structSbull_dev *dev,structBio *bio) {intIstructBio_vec *bvec;//define the actual VEC listsector_t sector = bio->bi_sector;//Define the first sector to be transferredBio_for_each_segment (bvec,bio,i) {//The following macro traverses each of the bio's segments, obtaining a kernel virtual address to access the buffer Char*buffer = __bio_kmap_atomic (BIO,I,KM_USER0);//Through the kmap_atomic () function to get the virtual address of the I-buffer returning bioSbull_transfer (Dev, Sector,index number of the//start sectorBio_cur_bytes (bio)/kernel_sector_size,//number of sectors that need to be transferredBuffer//buffer pointer for data transferBio_data_dir (bio) = = WRITE);//transmission direction, 0 representations from device read, not 0 write from deviceSector + = Bio_cur_bytes (bio)/kernel_sector_size;//return sector number__bio_kunmap_atomic (BIO,KM_USER0);//Returns the kernel virtual address obtained by __bio_kmap_atomic ()}return0; }/* * Transfer a full request. Requests handler function */ Static intSbull_xfer_request (structSbull_dev *dev,structRequest *req) {structBio *bio;intNsect = 0; __rq_for_each_bio (bio, req) {//This macro traverses each bio in the request, passing a pointer for the Sbull_xfer_bio () transferSbull_xfer_bio (dev, bio);//Call bio processing functionNsect + = bio->bi_size/kernel_sector_size;//Number of bytes passed/sector size equals sector number}returnNsect; }/* * Smarter request function that "handles clustering". */ Static voidSbull_full_request (structRequest_queue *q) {structRequest *req;structSbull_dev *dev = q->queuedata; req = Blk_fetch_request (q);/ * Iterate through each request * / while(req! = NULL) {if(Req->cmd_type! = req_type_fs) {//Determine if the request is a file system requestPRINTK (Kern_notice"Skip non-fs request\n"); Blk_end_request_all (req,-eio);//The request is an I/O error Continue; } sbull_xfer_request (Dev, req);//Call Request handler function if(!blk_end_request_cur (req, 0)) {//req point to Next requestreq = NULL; } } }/* * The direct make request version. */ Static intSbull_make_request (structRequest_queue *q,structBio *bio) {structSbull_dev *dev = q->queuedata;intStatus Status = Sbull_xfer_bio (Dev,bio); Bio_endio (bio, status);//Bio_endio () function notification processing end return0; }/* * Open () function */ Static intSbull_open (structBlock_device *BD, fmode_t mode) {structSbull_dev *dev = bd->bd_disk->private_data; Del_timer_sync (&dev->timer);/* Media removal Timer: Destroy Timer */Spin_lock (&dev->Lock);/ * Lock * / if(!dev->users) Check_disk_change (BD); dev->users++; Spin_unlock (&dev->Lock);/ * unlock * / return0; }Static intSbull_release (structGendisk *GD, fmode_t mode) {structSbull_dev *dev = gd->private_data; Spin_lock (&dev->Lock); dev->users--;if(!dev->users) {dev->timer.expires = jiffies + invalidate_delay; Add_timer (&dev->timer);/* Media removal timer: Load timer, 30s */} spin_unlock (&dev->Lock);return0; }/* * Look for a (simulated) media change. */ intSbull_media_change (structGendisk *gd) {structSbull_dev *dev = gd->private_data;returndev->media_change; }/* * Revalidate.we do not take the lock here,for fear of deadlocking with open. * That's needs to be reevaluated. * Call this function kernel will try to re-read the partition table, here This function is simply reset the MEDIA_CHANGE flag bit, and * Clear memory space to simulate inserting a disk */ intSbull_revalidate (structGendisk *gd) {structSbull_dev *dev = gd->private_data;if(Dev->media_change) {dev->media_change = 0; memset (dev->data, 0, dev->size);}return0; }/* * the "Invalidte" function runs out of the device Timer;it sets a flag to * Simulate the removal of the media. */ voidSbull_invalidate (unsignedLongLdev) {structSbull_dev *dev = (structSbull_dev *) Ldev; Spin_lock (&dev->Lock);if(Dev->users | |!dev->data) PRINTK (kern_warning"Sbull:timer sanity check failed\n");ElseDev->media_change = 1; Spin_unlock (&dev->Lock); }/* *ioctl: * Temporary processing of a command: Query request for physical information about the device */ intSbull_ioctl (structBlock_device *BD, fmode_t mode, unsigned cmd, unsignedLongARG) {LongSizestructHd_geometry Geo;structSbull_dev *dev = bd->bd_disk->private_data;Switch(CMD) { CaseHdio_getgeo:size = dev->size* (hardsect_size/kernel_sector_size); Geo.cylinders = (Size & ~0x3f) >> 6; Geo.sectors = 16; Geo.heads = 4; Geo.start = 4;if(Copy_to_user (void__user*) arg, &geo,sizeof(GEO)))return-efault;return0; }return-enotty; }/ * Get geometry information * / Static intSbull_getgeo (structBlock_device *BD,structHd_geometry *geo) {LongSizestructSbull_dev *dev = bd->bd_disk->private_data; Size = Dev->size * (hardsect_size/kernel_sector_size); Geo->cylinders = (Size & ~0x3f) >> 6; Geo->heads = 4; Geo->sectors = 16; Geo->start = 4;return0; }/* * the device operations structure. */ Static structBlock_device_operations sbull_ops = {. Owner = This_module,. Open = Sbull_open,. Release = Sbull_release,. media_changed = Sbull_media_change,/* User checks whether the media has been changed (removed) */. Revalidate_disk = Sbull_revalidate,. IOCTL = Sbull_ioctl,. Getgeo = Sbull_getgeo};/ * Initialize the specific implementation of the SBULL_DEV data structure * / Static voidSbull_setup_device (structSbull_dev *dev) {PRINTK (kern_info"sbull:step into into setup_device\n"); memset (Dev, 0,sizeof(structSbull_dev)); Dev->size = nsectors * hardsect_size;//Whole block device size 1024 (sector number) * 512 (sector size)Dev->data = Vmalloc (dev->size);/ * Open up virtual storage space * / if(Dev->data = = NULL) {PRINTK (Kern_notice"Vmalloc failure\n");return; } spin_lock_init (&dev->Lock);/ * Initialize spin lock * /Init_timer (&dev->timer);/ * Initialize timer * /Dev->timer.data = (unsignedLong) Dev; Dev->timer.function = sbull_invalidate;/ * Timeout processing function * / /* * The I/O queue, depending on whether we is using our own * Make_request function or not. */ Switch(Request_mode) { CaseRm_noqueue:dev->queue = Blk_alloc_queue (Gfp_kernel);/ * Assign "request Queue" * / if(Dev->queue = = NULL)GotoOut_vfree; Blk_queue_make_request (Dev->queue, sbull_make_request);/ * Bind the "Manufacturing request" function * / Break; CaseRm_full:dev->queue = Blk_init_queue (Sbull_full_request, &dev->Lock);/ * Request Queue initialization * / if(Dev->queue = = NULL)GotoOut_vfree; Break; CaseRm_simple:dev->queue = Blk_init_queue (Sbull_request, &dev->Lock);/ * Request Queue initialization * / if(Dev->queue = = NULL)GotoOut_vfree; Break;default: PRINTK (Kern_notice"Bad Request mode%d, using simple\n", Request_mode); } blk_queue_logical_block_size (Dev->queue, hardsect_size);/ * Hardware sector size settings * /Dev->queue->queuedata = Dev; DEV-&GT;GD = Alloc_disk (sbull_minors);if(!DEV-&GT;GD) {/ * Dynamically Assign GENDISK structure * /PRINTK (Kern_notice"Alloc_disk failure\n");GotoOut_vfree; } dev->gd->major = Sbull_major;/ * main device number * /Dev->gd->first_minor = sbull_minors;/ * Secondary Device number * /Dev->gd->fops = &sbull_ops;/ * block device operation structure Body * /Dev->gd->queue = dev->queue;/ * Request queue * /Dev->gd->private_data = Dev;/ * Private Data * /snprintf (Dev->gd->disk_name, 32,"Sbull");/ * The name of the secondary device * / / * The size of each request is an integer multiple of the sector size, and the kernel always considers the sector size to be 512 bytes, so it must be converted/*Set_capacity (DEV-&GT;GD, Nsectors * (hardsect_size/kernel_sector_size)); Add_disk (DEV-&GT;GD);/ * After completing the above initialization, call the Add_disk function to register the disk device * / return; Out_vfree:if(dev->data) Vfree (dev->data); }Static int__init Sbull_init (void) {intI PRINTK (kern_warning"Sbull:start init\n");//Register a block device, the first parameter is the device number, 0 is the dynamic allocation, the second parameter is the device nameSbull_major = Register_blkdev (Sbull_major,"Sbull");if(sbull_major <= 0) {PRINTK (kern_warning"sbull:unable to get major number\n");return-ebusy; } PRINTK (Kern_info"Sbull:start kmalloc\n"); Devices = Kmalloc (ndevices *sizeof(structSbull_dev), Gfp_kernel);/ * Allocate space for block core data structure Sbull_dev * / if(Devices = = NULL)GotoOut_unregister; PRINTK (kern_warning"Sbull:start setup_device\n"); Sbull_setup_device (Devices);/ * Initialize the SBULL_DEV core data structure and add_disk*/ return0; Out_unregister:unregister_blkdev (Sbull_major,"Sbull");return-enomem; }Static voidSbull_exit (void) {structSbull_dev *dev = Devices; Del_timer_sync (&dev->timer);if(DEV-&GT;GD) {Del_gendisk (DEV-&GT;GD); Put_disk (DEV-&GT;GD);}if(Dev->queue) {if(Request_mode = = Rm_noqueue) kobject_put (& (Dev->queue)->kobj);ElseBlk_cleanup_queue (Dev->queue); }if(dev->data) Vfree (dev->data); Unregister_blkdev (Sbull_major,"Sbull"); Kfree (Devices); } module_license ("Dual BSD/GPL"); Module_init (Sbull_init); Module_exit (Sbull_exit);

Linux block device driver (iv)--Simple Sbull instance

Related Article

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.