歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Linux I/O Block--塊設備的表示

塊設備的特點是其平均訪問時間較長,因此為了提高塊設備的訪問效率,Linux內核用了很多的筆墨來設計和塊設備相關的部分,這樣一來,從代碼的角度來看,訪問一個文件的過程變得尤其的漫長……整個路徑包含的過程基本可以概括為虛擬文件系統-->塊設備實際文件系統-->通用塊層-->I/O scheduler-->塊設備驅動程序。為了提高塊設備的訪問效率,內核主要是在兩個方面下功夫:

1.引入緩存,當用戶空間要訪問文件時,內核不可能每次都去訪問塊設備,內核會將塊設備的內容讀取到內存中,以便下次訪問時可以直接在內存中找到相應的內容,這其中又涉及到了預讀等相關的問題,當然這不是現在關注的重點……

2.對於I/O請求的重排列,I/O請求並不會立即被響應,而是會放在一個隊列裡進行一段延遲,以期能夠和後來的I/O請求進行合並或者進行排序。因為像磁盤這樣的塊設備,其耗時主要是因為磁頭的定位,因此內核會盡量保證磁頭只往一個方向移動,而不是來回移動(可以和電梯的運作進行對比),簡而言之,就是將存儲介質上相鄰的數據請求安排在一起,對於I/O請求的處理主要包括合並和排序,具體如何處理,由I/O scheduler決定。

首先,我們先來了解一個塊設備是如何表示的。描述塊設備的數據結構有兩個,一個是struct block_device,用來描述一個塊設備或者塊設備的一個分區;另一個是struct gendisk,用來描述整個塊設備的特性。對於一個包含多個分區的塊設備,struct block_device結構有多個,而struct gendisk結構永遠只有一個。

struct block_device { 
    dev_t          bd_dev;  /* not a kdev_t - it's a search key */ 
    struct inode *      bd_inode;  /* will die */ 
    struct super_block *    bd_super; 
    int        bd_openers; 
    struct mutex        bd_mutex;  /* open/close mutex */ 
    struct list_head    bd_inodes; 
    void *          bd_holder; 
    int        bd_holders; 
#ifdef CONFIG_SYSFS 
    struct list_head    bd_holder_list; 
#endif 
    struct block_device *  bd_contains; 
    unsigned        bd_block_size; 
    struct hd_struct *  bd_part; 
    /* number of times partitions within this device have been opened. */ 
    unsigned        bd_part_count; 
    int        bd_invalidated; 
    struct gendisk *    bd_disk; 
    struct list_head    bd_list; 
    /*
    * Private data.  You must have bd_claim'ed the block_device
    * to use this.  NOTE:  bd_claim allows an owner to claim
    * the same device multiple times, the owner must take special
    * care to not mess up bd_private for that case.
    */ 
    unsigned long      bd_private; 
 
    /* The counter of freeze processes */ 
    int        bd_fsfreeze_count; 
    /* Mutex for freeze */ 
    struct mutex        bd_fsfreeze_mutex; 
}; 

bd_dev:該設備(分區)的設備號

bd_inode:指向該設備文件的inode

bd_openers:一個引用計數,記錄了該塊設備打開的次數,或者說有多少個進程打開了該設備

bd_contains:如果該block_device描述的是一個分區,則該變量指向描述主塊設備的block_device,反之,其指向本身

bd_part:如果該block_device描述的是一個分區,則該變量指向分區的信息

bd_part_count:如果是分區,該變量記錄了分區被打開的次數,在進行分區的重新掃描前,要保證該計數值為0

bd_disk:指向描述整個設備的gendisk結構

struct gendisk { 
    /* major, first_minor and minors are input parameters only,
    * don't use directly.  Use disk_devt() and disk_max_parts().
    */ 
    int major;          /* major number of driver */ 
    int first_minor; 
    int minors;                    /* maximum number of minors, =1 for
                                        * disks that can't be partitioned. */ 
 
    char disk_name[DISK_NAME_LEN];  /* name of major driver */ 
    char *(*devnode)(struct gendisk *gd, mode_t *mode); 
    /* Array of pointers to partitions indexed by partno.
    * Protected with matching bdev lock but stat and other
    * non-critical accesses use RCU.  Always access through
    * helpers.
    */ 
    struct disk_part_tbl *part_tbl; 
    struct hd_struct part0; 
 
    const struct block_device_operations *fops; 
    struct request_queue *queue; 
    void *private_data; 
 
    int flags; 
    struct device *driverfs_dev;  // FIXME: remove 
    struct kobject *slave_dir; 
 
    struct timer_rand_state *random; 
 
    atomic_t sync_io;      /* RAID */ 
    struct work_struct async_notify; 
#ifdef  CONFIG_BLK_DEV_INTEGRITY 
    struct blk_integrity *integrity; 
#endif 
    int node_id; 
};

major:塊設備的主設備號

first_minor:起始次設備號

minors:描述了該塊設備有多少個次設備號,或者說有多少個分區,如果minors為1,則表示該塊設備沒有分區

part_tbl:整個塊設備的分區信息都包含在裡面,其核心結構是一個struct hd_struct的指針數組,每一項都指向一個描述分區的hd_struct結構

fops:指向特定於設備的底層操作函數集

queue:塊設備的請求隊列,所有針對該設備的請求都會放入該請求隊列中,經過I/O scheduler的處理再進行提交

Copyright © Linux教程網 All Rights Reserved