Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1863102
  • 博文数量: 211
  • 博客积分: 464
  • 博客等级: 下士
  • 技术积分: 3794
  • 用 户 组: 普通用户
  • 注册时间: 2011-01-24 18:25
个人简介

阿弥陀佛

文章分类

全部博文(211)

文章存档

2020年(2)

2019年(3)

2018年(5)

2017年(6)

2016年(10)

2015年(9)

2014年(73)

2013年(90)

2012年(13)

分类: 服务器与存储

2012-12-15 16:07:39

很少有和zfs相关的代码分析,中文的材料基本没有,我来剖析一下zfs的写磁盘的底层的实现吧。
在zio 的流水线当中,有一个流水线的名称为vdev_disk_io_start。
在vdev_disk_io_start(zio *zio)函数中,做了如下的事情:
1.判断zio的请求类型(zio->io_type)
2.根据类型,将zio 传递给__vdev_disk_physio(vd->vd_bdev, zio, zio->io_data,
                   zio->io_size, zio->io_offset, flags);
在函数 __vdev_disk_physio函数当中,涉及到dio_request 结构体,为了submit_bio的时候使用的对单个请求的包装。
dio_request 请求如下

 点击(此处)折叠或打开

  1. /*
  2.  * Virtual device vector for disks.
  3.  */
  4. typedef struct dio_request {
  5.     struct completion    dr_comp;    /* Completion for sync IO */
  6.     atomic_t        dr_ref;        /* References */
  7.     zio_t            *dr_zio;    /* Parent ZIO */
  8.     int            dr_rw;        /* Read/Write */
  9.     int            dr_error;    /* Bio error */
  10.     int            dr_bio_count;    /* Count of bio's */
  11.         struct bio        *dr_bio[0];    /* Attached bio's */
  12. } dio_request_t;
可以看到dr_bio[]变量为可变的。并且在这个函数当中,给bio进行赋值
对于zio传下来的参数,可以告诉vdev层,请求的io偏移量,请求的buf指针。以及请求的类型

点击(此处)折叠或打开

  1. error = __vdev_disk_physio(vd->vd_bdev, zio, zio->io_data,
  2. zio->io_size, zio->io_offset, flags);


点击(此处)折叠或打开

  1. static int
  2. __vdev_disk_physio(struct block_device *bdev, zio_t *zio, caddr_t kbuf_ptr,
  3.                    size_t kbuf_size, uint64_t kbuf_offset, int flags)
  4. {
  5.         dio_request_t *dr;
  6.     caddr_t bio_ptr;
  7.     uint64_t bio_offset;
  8.     int bio_size, bio_count = 16;
  9.     int i = 0, error = 0;

  10.     ASSERT3U(kbuf_offset + kbuf_size, <=, bdev->bd_inode->i_size);

  11. retry:
  12.     dr = vdev_disk_dio_alloc(bio_count);
  13.     if (dr == NULL)
  14.         return ENOMEM;
  15. ...
  16.     dr->dr_zio = zio;
  17.     dr->dr_rw = flags;
  18. /*bio_ptr为真正的存放数据的内存指针*/
  19.     bio_ptr = kbuf_ptr;
  20.     bio_offset = kbuf_offset;
  21.     bio_size = kbuf_size;
  22.     for (i = 0; i <= dr->dr_bio_count; i++) {
  23. ...
  24. if (bio_size <= 0)
  25. break;
  26.         dr->dr_bio[i] = bio_alloc(GFP_NOIO,
  27.          bio_nr_pages(bio_ptr, bio_size));
  28.         if (dr->dr_bio[i] == NULL) {
  29.             vdev_disk_dio_free(dr);
  30.             return ENOMEM;
  31.         }

  32.         /* Matching put called by vdev_disk_physio_completion */
  33.         vdev_disk_dio_get(dr);

  34.         dr->dr_bio[i]->bi_bdev = bdev;
  35.         dr->dr_bio[i]->bi_sector = bio_offset >> 9;  //根据提供的偏移量,缩小为以扇区为单位。
  36.         dr->dr_bio[i]->bi_rw = dr->dr_rw;
  37.         dr->dr_bio[i]->bi_end_io = vdev_disk_physio_completion;
  38.         dr->dr_bio[i]->bi_private = dr;

  39.         /* Remaining size is returned to become the new size */
  40.         bio_size = bio_map(dr->dr_bio[i], bio_ptr, bio_size); 在这里给每个bio的bi_vect变量赋值。bio_size 如果小于0,那么将跳出循环。传进bio_ptr,将数据以页的形式加入到bio当中。
  41.         /* Advance in buffer and construct another bio if needed */
  42.         bio_ptr += dr->dr_bio[i]->bi_size;
  43.         bio_offset += dr->dr_bio[i]->bi_size;
  44.     }

  45.     /* Extra reference to protect dio_request during submit_bio */
  46.     vdev_disk_dio_get(dr);
  47.     if (zio)
  48.         zio->io_delay = jiffies_64;

  49.     /* Submit all bio's associated with this dio */
  50.     for (i = 0; i < dr->dr_bio_count; i++)
  51.         if (dr->dr_bio[i])
  52.             submit_bio(dr->dr_rw, dr->dr_bio[i]);//同一个request,bio的请求类型都是相同的,并将生成的bio提交给内核来处理。

  53.     /*
  54.      * On synchronous blocking requests we wait for all bio the completion
  55.      * callbacks to run. We will be woken when the last callback runs
  56.      * for this dio. We are responsible for putting the last dio_request
  57.      * reference will in turn put back the last bio references. The
  58.      * only synchronous consumer is vdev_disk_read_rootlabel() all other
  59.      * IO originating from vdev_disk_io_start() is asynchronous.
  60.      */
  61.     if (vdev_disk_dio_is_sync(dr)) {
  62.         wait_for_completion(&dr->dr_comp);
  63.         error = dr->dr_error;
  64.         ASSERT3S(atomic_read(&dr->dr_ref), ==, 1);
  65.     }

  66.     (void)vdev_disk_dio_put(dr);

  67.     return error;
  68. }
到这里,所有的处理工作都已经结束了。然后该执行zio的其他的流水线的函数了。

阅读(1996) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:zfs异步写分析(一)

给主人留下些什么吧!~~