1 / 39

Block Device Driver

Block Device Driver. Dr A Sahu Dept of Comp Sc & Engg . IIT Guwahati. Outline. File System, Block Devices Block Device Registration Initialization of Sbull Block Device Operation Request processing. File System & Block Devices. Block Devices (Disk) Sector, inode

cynara
Télécharger la présentation

Block Device Driver

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Block Device Driver Dr A Sahu Dept of Comp Sc & Engg. IIT Guwahati

  2. Outline • File System, Block Devices • Block Device Registration • Initialization of Sbull • Block Device Operation • Request processing

  3. File System & Block Devices • Block Devices (Disk) • Sector, inode • File systems (Operations) • Read/write, open,close, lseek, type

  4. Block Devices Registration • Block Devices (Disk) • Sector, inode • File systems (Operations) • Read/write, open,close, lseek, type

  5. File System & Block Devices • Block Devices (Disk) • Sector, inode • File systems (Operations) • Read/write, open,close, lseek, type

  6. What is the VFS ? Component in the kernel that handles file-systems, directory and file access. Abstracts common tasks of many file-systems. Presents the user with a unified interface, via the file-related system calls (open, stat, chmod etc.). Filesystem-specific operations:- vector them to the filesystem in charge of the file.

  7. Mounting a device $ mount -t iso9660 -o ro /dev/cdrom /mnt/cdrom Steps involved: Find the file system.(file_systems list) Find the VFS inode of the directory that is to be the new file system's mount point. Allocate a VFS superblock and call the file system specific read_super function.

  8. What will we learn ? • The details of how a block device works • ll_rw_block() : trigger I/O transfer • __make_request (): make request -> request queue • task queue : plug/unplug use the mechanism • request service routine : • How to write a block device driver • writing a module • Init / exit • implement the necessary operations • block_device_operations • request_fn_proc

  9. Common Block Device Operations • In fs/block_dev.c struct file_operations def_blk_fops = { open: blkdev_open, release: blkdev_close, llseek: block_llseek, read: generic_file_read, write: generic_file_write, mmap: generic_file_mmap, fsync: block_fsync, ioctl: blkdev_ioctl, };

  10. Block Device Specific Operations • Additional operations for block device only • In include/linux/fs.h : struct block_device_operations { int (*open) (struct inode *, struct file *); int (*release) (struct inode *, struct file *); int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long); int (*check_media_change) (kdev_t); int (*revalidate) (kdev_t); }; • In include/linux/blkdev.h : typedef void (request_fn_proc) (request_queue_t *q);

  11. Bh= block header

  12. Generic Block Device Layer • Provides common functionality for all block devices in Linux • Uniform interface (to file system) e.g. bread( ) block_prepare_write( ) block_read_full_page( ) ll_rw_block( ) • buffer management and disk caching • Block I/O requests scheduling • Generates and queues actual I/O requests in a request queue (per device) • Individual device driver services this queue (likely interrupt driven)

  13. Request Queue • Data structure: in include/linux/blkdev.h • Queue header: type request_queue_ttypedef structure request_queuerequest_queue_t • queue_head: double linked list of pending requests • request_fn: pointer to request service routine • Queue element: struct request • cmd: read or write • Number of request sectors, segments • bh, bhtail: a list of buffer header • Memory area (for I/O transfer)

  14. Request Queue

  15. Invoking the Lower Layer • Generic block device layer • Generates and queues I/O request • If the request queue is initially empty, schedule a plug_tq tasklet into tq_disk task queue • Asynchronous run of task queue tq_disk • Run in a few places (e.g., in kswapd) • Take a request from the queue and call the request_fn function: • q->request_fn(q);

  16. Request Service Routine • To service all I/O requests in the queue • Typical interrupt-driven procedure • Service the first request in the queue • Set up hardware so it raises interrupt when it is done • Return • Interrupt handler tasklet • Remove the just-finished request from the queue • Re-enter the request service routine (to service the next)

  17. Request submission • ll_rw_block() • submit_bh() • generic_make_request() • __make_request() • generic_plug_device() • elevator algorithm • __get_request_wait()

  18. ll_rw_block() • void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]) • rw: read/write • nr: number of buffer_head structures in the array • bhs: array of buffer_head structures • Top-level function to submit the I/O request • Checks whether the requested operation is permitted by the device • Performing a write operation on a read-only device • Checks the buffer size is a multiple of the sector size of the device • Locks the buffer and verifies whether the operation is required • If the dirty bit is not set on the buffer, write operation is not necessary • Read operation on a buffer with uptodate buffer is redundant

  19. submit_bh() • void submit_bh(int rw, struct buffer_head *bh) • submit a buffer_head to the block device later for I/O • Sets the BH_Req and the BH_Launder flags on the buffer • Sets the real device and sector values • count = bh->b_size >> 9; • bh->b_rdev = bh->b_dev; • bh->b_rsector = bh->b_blocknr * count;

  20. generic_make_request() • void generic_make_request(int rw, struct buffer_head *bh) • Hand a buffer head to it’s device driver for I/O • Checks the requested sector is within the range (blk_size[major][minor] • Get the request queue of the device, calls make_request_fn to put the buffer in the request queue (in most case,this handler is __make_request)

  21. __make_request() • static int __make_request(request_queue_t * q, int rw, struct buffer_head * bh) • Inserts the buffer in the request queue • Plug device by calling plug_device_fn handler of the request queue • In most case, this is generic_plug_device() • Submits the plug_tq to the disk task queue tq_disk • Enlarger an existing request – elevator algorithm

  22. __make_request() (cont.) • __get_request_wait() • If a new request has to be created and there are no free request objects, it waits on the request queue till it gets a free request object • static struct request *__get_request_wait(request_queue_t *q, intrw) { register struct request *rq; DECLARE_WAITQUEUE(wait, current); generic_unplug_device(q); add_wait_queue(&q->wait_for_request, &wait); do { set_current_state(TASK_UNINTERRUPTIBLE); if (q->rq[rw].count < batch_requests) schedule(); spin_lock_irq(&io_request_lock); rq =get_request(q,rw); spin_unlock_irq(&io_request_lock); } while (rq == NULL); remove_wait_queue(&q->wait_for_request, &wait); current->state = TASK_RUNNING; return rq; }

  23. Request processing • __generic_unplug_device() • Called by __get_request_wait() or generic_unplug_device() • Marks the queue as unplugged • Calls the request_fn handler of the request queue

  24. Block Device in 2.4 Kernel • Not completely rid of major/minor number yet • Still keep queues and device driver related parameters in arrays indexed by major numbers • In include/linux/blkdev.h • structblk_dev_struct { request_queue_trequest_q; queue_proc *queue; void *data; } structblk_dev_structblk_dev[MAX_BLKDEV]; #define BLK_DEFAULT_QUEUE(_MAJOR) &blk_dev[_MAJOR].request_q

  25. Block Device in 2.4 Kernel (2) • Matrices for device paramaters • Type: int * xxx[MAX_BLKDEV]; • Indexed by major then minor number • blk_size, blksize_size, hardsec_size, max_readahead, max_sectors, max_segments • Read ahead parameters • intread_ahead[] (include/linux/fs.h) • Indexed by major number • You will need to set these parameters for any device in your init and open functions

  26. include/linux/blk.h • Assign major number for each device driver • Define macros for each device (by major number) • MAJOR_NR: major number • DEVICE_NAME: name of your device • DEVICE_INTR: device interrupt handler • DEVICE_REQUEST: request service routine • DEVICE_NR(): how to calculate the minor number • You may have to add a set for each new device driver (major number) you introduce

  27. Skeleton Block Device • Device operation structure: • static struct block_device_operations xxx_fops = { open: xxx_open, release: xxx_release, ioctl: xxx_ioctl, check_media_change, xxx_check_change, revalidate, xxx_revalidate, owner: THIS_MODULE, };

  28. Skeleton Block Device • Xxx_open() • MOD_INC_USE_COUNT; • Xxx_release() • MOD_DEC_USE_COUNT; • Xxx_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) • switch(cmd) • BLKGETSIZE • HDIO_GETGEO • … • default: return blk_ioctl(inode->i_rdev, cmd, arg);

  29. Skeleton “ Init” Function #define MAJOR_NR XXX_MAJOR static int __init xxx_init(void){ /* probe the hardware, request irq, … */ devfs_dir = devfs_mk_dir(NULL, “xxx_dir”, NULL); /* old way: register_blkdev(MAJOR_NR, “xxx”, &xxx_bdops); */ devfs_handle = devfs_register_blk(devfs_dir, “xxx", ......); blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), xxx_request); read_ahead[MAJOR_NR] = 8; /* 8 sector (4K) read ahead */ /* you may also setup those: blk_size[MAJOR_NR] blksize_size[MAJOR_NR] hardsect_size[MAJOR_NR] */ /* rest of the initial setup */ printk( … ); return 0; }

  30. Skeleton “ Exit” Function static void __exit xxx_exit (void) { /* clean up */ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); /* old way: unregister_blkdev(MAJOR_NR, “xxx”); */ devfs_unregister(devfs_handle); devfs_unregister(devfs_dir); /* clean up */ } module_init(xxx_init); module_exit(xxx_exit);

  31. Skeleton “ Request” Operation static void xxx_request(request_queue_t *q) { while (1) { INIT_REQUEST;//a macro,quit while loop when request queue is empty switch (CURRENT->cmd) { case READ: /* do read request, i.e: memcpy(q->buffer, mem_block, size); */ case WRITE: /* do write request, i.e: memcpy(mem_block, q->buffer, size); */ default: /* impossible */ return 0; } end_request(status);//when finishing a request, remove it } }

  32. To Write a Block Device Driver (summarize) • Write all the device operation functions • xxx_open(), xxx_release(), xxx_ioctl()... • Write a request service routine • xxx_request() • Write interrupt handler and related tasklets • Write module “ init” and “ exit” functions to • Register and unregister the device driver • Set up and clear up the request queue and parameters • Set up and clear up the interrupt line and handler

  33. ThanksRef: Chap 16, LDD 3e Rubini- CorbetWishing u happy diwali

More Related