Chinaunix首页 | 论坛 | 博客
  • 博客访问: 47957
  • 博文数量: 18
  • 博客积分: 1415
  • 博客等级: 上尉
  • 技术积分: 209
  • 用 户 组: 普通用户
  • 注册时间: 2009-09-11 19:33
文章分类

全部博文(18)

文章存档

2011年(1)

2009年(17)

我的朋友

分类: LINUX

2009-09-19 10:26:01


从现在开始我们来看一下,在实现一个块设备驱动时你经常会遇到的一些数据结构和函数方法。

下面是一些主要的块设备驱动的数据结构

1、        内核使用gendisk(generic disk 的简写)结构体来代表一个磁盘设备,该结构体定义在include/linux/genhd.h

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;        /*starting minor number*/

  int minors;       /* maximum number of minors, =1 for

                  * disks that can't be partitioned. 每一个分区都有一个minor*/

 

  char disk_name[DISK_NAME_LEN];  /* name of major driver */

 

  /* 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;

 

  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;

};

2、        和每一个块设备驱动联系的I/O请求队列,使用request_queue结构体来描述,该结构体定义在include/linux/blkdev.h之中。可以看到这个结构体也是比较大,但是你可能用到的只有request 结构体。

3、        每一个在request_queue中的请求都是使用request 结构体来表示的,request结构体也定义在include/linux/blkdev.h

/*

 * try to put the fields that are referenced together in the same cacheline.

 * if you modify this structure, be sure to check block/blk-core.c:rq_init()

 * as well!

 */

struct request {

      struct list_head queuelist;

      struct call_single_data csd;

      int cpu;

 

      struct request_queue *q;/*The container request queue*/

 

   …………

      /* Maintain bio traversal state for part by part I/O submission.

       * hard_* are block layer internals, no driver should touch them!

       */

 

      sector_t sector;       /* next sector to submit (要访问的数据扇区)*/

      sector_t hard_sector;         /* next sector to complete */

      unsigned long nr_sectors; /* no. of sectors left to submit */

      unsigned long hard_nr_sectors;   /* no. of sectors left to complete */

      /* no. of sectors left to submit in the current segment */

      unsigned int current_nr_sectors;

 

      /* no. of sectors left to complete in the current segment */

      unsigned int hard_cur_sectors;

 

      struct bio *bio;

      struct bio *biotail;

 

      struct hlist_node hash; /* merge hash */

      /*

       * The rb_node is only used inside the io scheduler, requests

       * are pruned when moved to the dispatch queue. So let the

       * completion_data share space with the rb_node.

       */

      union {

           struct rb_node rb_node;   /* sort/lookup */

           void *completion_data;

      };

 

      /*

       * two pointers are available for the IO schedulers, if they need

       * more they have to dynamically allocate it.

       */

      void *elevator_private;

      void *elevator_private2;

 

      struct gendisk *rq_disk;

      unsigned long start_time;

 

      /* Number of scatter-gather DMA addr+len pairs after

       * physical address coalescing is performed.

       */

      unsigned short nr_phys_segments;

 

      unsigned short ioprio;

 

      void *special;

      char *buffer;

 

      int tag;

      int errors;

 

      int ref_count;

 

      /*

       * when request is used as a packet command carrier

       */

      unsigned short cmd_len;

      unsigned char __cmd[BLK_MAX_CDB];

      unsigned char *cmd;

 

      unsigned int data_len;

      unsigned int extra_len;      /* length of alignment and padding */

      unsigned int sense_len;

      void *data;

      void *sense;

 

      unsigned long deadline;

      struct list_head timeout_list;

      unsigned int timeout;

      int retries;

 

      /*

       * completion callback.

       */

      rq_end_io_fn *end_io;

      void *end_io_data;

 

      /* for bidi */

      struct request *next_rq; /*队列中的下一个请求*/

};

4、        块设备的block_device_operations 结构体对应字符设备的file_operations结构体。 该结构体包含着块设备驱动程序的函数入口点。

标准的方法有open()release()ioctl()等等

另外对块设备还有一些特殊的方法,例如:media_changed()revalidate_disk(),这些函数支持可移动(可插拔)的块设备。

结构体block_device_operations 定义在include/linux/fs.h之中

  struct block_device_operations {

  int (*open) (struct block_device *, fmode_t);/*打开*/

  int (*release) (struct gendisk *, fmode_t); /*关闭*/

  int (*locked_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);

  int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long); /*I/O控制*/

  int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);

  int (*direct_access) (struct block_device *, sector_t,

                              void **, unsigned long *);

  int (*media_changed) (struct gendisk *);/*检查介质是否可用或拔出*/

  int (*revalidate_disk) (struct gendisk *);

  int (*getgeo)(struct block_device *, struct hd_geometry *);

  struct module *owner;

};

5、        我们在request结构体中曾看到一个结构体bio,我们现在就来看看这个结构体。一个bio结构体是在通用块层或更底层对块设备i/o操作的的表示单位。该结构体定义在include/linux/bio.h中。

/*

 * main unit of I/O for the block layer and lower layers (ie drivers and

 * stacking drivers)

 */

struct bio {

      sector_t         bi_sector;      /* device address in 512 byte

                                     sectors */

      struct bio      *bi_next; /* request queue link */

      struct block_device *bi_bdev;

      unsigned long          bi_flags;   /* status, command, etc */

      unsigned long          bi_rw;      /* bottom bits READ/WRITE,

                                   * top bits priority

                                   */

 

      unsigned short        bi_vcnt;   /* how many bio_vec's */

      unsigned short        bi_idx;           /* current index into bvl_vec */

 

      /* Number of segments in this BIO after

       * physical address coalescing is performed.

       */

      unsigned int       bi_phys_segments;

 

      unsigned int       bi_size;    /* residual I/O count */

 

      /*

       * To keep track of the max segment size, we account for the

       * sizes of the first and last mergeable segments in this bio.

       */

      unsigned int       bi_seg_front_size;

      unsigned int       bi_seg_back_size;

 

      unsigned int       bi_max_vecs;     /* max bvl_vecs we can hold */

 

      unsigned int       bi_comp_cpu;    /* completion CPU */

 

      atomic_t       bi_cnt;           /* pin count */

 

      struct bio_vec          *bi_io_vec;   /* the actual vec list */

 

      bio_end_io_t           *bi_end_io;

 

      void               *bi_private;

#if defined(CONFIG_BLK_DEV_INTEGRITY)

      struct bio_integrity_payload *bi_integrity;  /* data integrity */

#endif

 

      bio_destructor_t     *bi_destructor;  /* destructor */

 

      /*

       * We can inline a number of vecs at the end of the bio, to avoid

       * double allocations for a small number of bio_vecs. This member

       * MUST obviously be kept at the very end of the bio.

       */

      struct bio_vec          bi_inline_vecs[0];

};

块数据内在使用bio_vec结构体来表示的。bio_vec数组的每一个元素都是由(pagepage_offsetlength)元素组成的。



这次我们简要的介绍了一些块设备常见的数据结构和函数等,下次我们就来使用这些结构和函数来做一个简单 的例子,来感受一下块设备驱动程序的编写方式。

感谢你对小孟的支持!

如果你有什么问题可以和我联系:xiangpengmeng@gmail.com或mxp556@163.com

阅读(676) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2009-09-22 14:03:17

孟大哥写得真好!!!顶顶顶!!!!!!!!!!!!!!!!!!

chinaunix网友2009-09-19 20:19:19

好多啊