本文來源於:
1. http://www.cnblogs.com/dyllove98/archive/2013/07/01/3165567.html
塊設備相關的數據結構以及接口:
塊設備接口則相對復雜,讀寫API沒有直接到塊設備層,而是直接到文件系統層,然后再由文件系統層發起讀寫請求。
一: block_device: block_device結構代表了內核中的一個塊設備。它可以表示整個磁盤或一個特定的分區。當這個結構代表一個分區時,它的bd_contains成員指向包含這個分區的設備,bd_part成員指向設備的分區結構。當這個結構代表一個塊設備時,bd_disk成員指向設備的gendisk結構。
struct block_device { dev_t bd_dev; struct inode * bd_inode; /*分區結點*/ int bd_openers; struct semaphore bd_sem; /*打開/關閉鎖*/ struct semaphore bd_mount_sem; /* 加載互斥鎖*/ struct list_head bd_inodes; void * bd_holder; int bd_holders; struct block_device * bd_contains; unsigned bd_block_size;//分區塊大小 struct hd_struct * bd_part; unsigned bd_part_count;//打開次數 int bd_invalidated; struct gendisk * bd_disk; struct list_head bd_list; struct backing_dev_info *bd_inode_backing_dev_info; unsigned long bd_private; };
二:gendisk是一個單獨的磁盤驅動器的內核表示。內核還使用gendisk來表示分區。
struct gendisk { int major; //主設備號 int first_minor; int minors; //最大的次設備號數量,如果設備不能分區,該值為1 char disk_name[32]; //主設備名 struct hd_struct **part; //分區信息,有minors個 struct block_device_operations *fops;//設備操作 struct request_queue *queue; //設備管理I/O請求 void *private_data; sector_t capacity; int flags; char devfs_name[64]; int number; struct device *driverfs_dev; struct kobject kobj; struct timer_rand_state *random; int policy; atomic_t sync_io; unsigned long stamp, stamp_idle; int in_flight; #ifdef CONFIG_SMP struct disk_stats *dkstats; #else struct disk_stats dkstats; #endif };
gendisk結構的操作函數包括以下幾個: struct gendisk *alloc_disk(int minors); //分配磁盤 void add_disk(struct gendisk *disk); //增加磁盤信息 void unlink_gendisk(struct gendisk *disk) //刪除磁盤信息 void delete_partition(struct gendisk *disk, int part); //刪除分區 void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len, int flags);//添加分區
三: block_device_operations結構是塊設備對應的操作接口,是連接抽象的塊設備操作與具體塊設備操作之間的樞紐。
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); long (*unlocked_ioctl) (struct file *, unsigned, unsigned long); long (*compat_ioctl) (struct file *, unsigned, unsigned long); int (*direct_access) (struct block_device *, sector_t, unsigned long *); int (*media_changed) (struct gendisk *); int (*revalidate_disk) (struct gendisk *); int (*getgeo)(struct block_device *, struct hd_geometry *); struct module *owner; }; block_device_operations並不能完全提供文件操作全部的API,實際上只提供了open、release等函數,其他的文件操作依賴於def_blk_fops:
const struct file_operations def_blk_fops = { .open = blkdev_open, .release = blkdev_close, .llseek = block_llseek, .read = do_sync_read, .write = do_sync_write, .aio_read = generic_file_aio_read, .aio_write= generic_file_aio_write_nolock, .mmap = generic_file_mmap, .fsync = block_fsync, .unlocked_ioctl = block_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = compat_blkdev_ioctl, #endif .splice_read = generic_file_splice_read, .splice_write = generic_file_splice_write, };
四: 系統對塊設備進行讀寫操作時,通過塊設備通用的讀寫操作函數將一個請求保存在該設備的操作請求隊列(request queue)中,然后調用這個塊設備的底層處理函數,對請求隊列中的操作請求進行逐一執行。request_queue結構描述了塊設備的請求隊列,該結構定義如下:
struct request_queue { struct list_head queue_head; struct request *last_merge; elevator_t elevator; /*請求隊列列表*/ struct request_list rq; request_fn_proc *request_fn; merge_request_fn *back_merge_fn; merge_request_fn *front_merge_fn; merge_requests_fn *merge_requests_fn; make_request_fn *make_request_fn; prep_rq_fn *prep_rq_fn; unplug_fn *unplug_fn; merge_bvec_fn *merge_bvec_fn; activity_fn *activity_fn; /*自動卸載狀態*/ struct timer_list unplug_timer; int unplug_thresh; unsigned long unplug_delay; /*自動卸載延時*/ struct work_struct unplug_work; struct backing_dev_info backing_dev_info; void *queuedata; void *activity_data; unsigned long bounce_pfn; int bounce_gfp; unsigned long queue_flags;//各種隊列標志 /*保護隊列結構,避免重入*/ spinlock_t *queue_lock; /* 請求的核心結構*/ struct kobject kobj; /*請求的配置*/ unsigned long nr_requests; /* 請求的最大數*/ unsigned int nr_congestion_on; unsigned int nr_congestion_off; unsigned short max_sectors; unsigned short max_phys_segments; unsigned short max_hw_segments; unsigned short hardsect_size; unsigned int max_segment_size; unsigned long seg_boundary_mask; unsigned int dma_alignment; struct blk_queue_tag *queue_tags; atomic_t refcnt; unsigned int in_flight; /*sg 參數配置*/ unsigned int sg_timeout; unsigned int sg_reserved_size; };
請求隊列相關的處理函數包括: //創建隊列時提供了一個自旋鎖。 request_queue_t *blk_init_queue(request_fn_proc *rfn, spinlock_t *lock); //獲得隊列中第一個未完成的請求。 struct request *elv_next_request(request_queue_t *q); void end_request(struct request *req, int uptodate);//請求完成 void blk_stop_queue(request_queue_t *queue); //停止請求 void blk_start_queue(request_queue_t *queue); //開始請求 void blk_cleanup_queue(request_queue_t *);//清除請求隊列
五:向內核注冊和注銷一個塊設備可使用如下函數:
int register_blkdev(unsigned int major, const char *name); int unregister_blkdev(unsigned int major, const char *name);