Chinaunix首页 | 论坛 | 博客
  • 博客访问: 294603
  • 博文数量: 60
  • 博客积分: 2697
  • 博客等级: 少校
  • 技术积分: 653
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-13 15:52
文章分类

全部博文(60)

文章存档

2012年(6)

2011年(31)

2010年(23)

分类: LINUX

2011-01-24 14:51:59

  1. /*
  2. *from和to分别指定页面内将要操作的段的起点和终点
  3. *get_block针对具体的文件系统把文件逻辑块号转换成相对于设备分区起始的逻辑块号
  4. */
  5. int block_prepare_write(struct page *page, unsigned from, unsigned to,
  6. get_block_t *get_block)
  7. {
  8. struct inode *inode = page->mapping->host;
  9. int err = __block_prepare_write(inode, page, from, to, get_block);
  10. if (err)
  11. ClearPageUptodate(page);
  12. return err;
  13. }

 

  1. static int __block_prepare_write(struct inode *inode, struct page *page,
  2. unsigned from, unsigned to, get_block_t *get_block)
  3. {
  4. unsigned block_start, block_end;
  5. sector_t block;
  6. int err = 0;
  7. unsigned blocksize, bbits;
  8. struct buffer_head *bh, *head, *wait[2], **wait_bh=wait;
  9. BUG_ON(!PageLocked(page));
  10. BUG_ON(from > PAGE_CACHE_SIZE);
  11. BUG_ON(to > PAGE_CACHE_SIZE);
  12. BUG_ON(from > to);
  13. blocksize = 1 << inode->i_blkbits; //块大小,也即页内缓冲区大小
  14. /*
  15. *调用create_empty_buffers为该页建立缓冲区队列,然后对队列进行初始化。
  16. *没有涉及bh的state标志
  17. *调用的create_buffers中设置bh->state = 0
  18. *且把新分配的buffer放入BUF_CLEAN链表(BH_dirty标志为0)
  19. * 缓冲队列头赋给page->buffer
  20. */
  21. if (!page_has_buffers(page))
  22. create_empty_buffers(page, blocksize, 0);
  23. head = page_buffers(page);
  24. /*当前页所在的块号*/
  25. /*
  26. *假设块大小为1k,则bbits = inode->i_blkbits, bbits为10
  27. *则一页占2^(PAGE_CACHE_SHIFT-bbits)=2^(12-10)=2^2=4个块
  28. *因此该页的逻辑起始块号为: page->index*每页块数
  29. *即page->index*2^(PAGE_CACHE_SHIFT-bbits)=
  30. * page->index<<(PAGE_CACHE_SHIFT-bbits)
  31. */
  32. bbits = inode->i_blkbits;
  33. block = (sector_t)page->index << (PAGE_CACHE_SHIFT - bbits);
  34. /*
  35. *对页中每个buffer对应的bh和受写影响的每个bh
  36. *block_start记录循环写入的总块大小
  37. */
  38. for(bh = head, block_start = 0; bh != head || !block_start;
  39. block++, block_start=block_end, bh = bh->b_this_page) {
  40. block_end = block_start + blocksize; /*累计写入块大小*/
  41. if (block_end <= from || block_start >= to) {   //对页内from到to的区域进行下列转换、检查或设置
  42. if (PageUptodate(page)) {
  43. if (!buffer_uptodate(bh))
  44. set_buffer_uptodate(bh);
  45. }
  46. continue;
  47. }
  48. if (buffer_new(bh))
  49. clear_buffer_new(bh); /*清BH_New标志(如果相应的文件块正好被分配但从未被访问)*/
  50. /*
  51. *检查如果BH_Mapped标志未设置
  52. *调用get_block将文件逻辑块号-〉设备上记录块(相对磁盘分区的起始位置)
  53. *块号存放与b_blocknr字段且设置BH_Mapped标志(完成映射)
  54. */
  55. if (!buffer_mapped(bh)) {
  56. WARN_ON(bh->b_size != blocksize);
  57. err = get_block(inode, block, bh, 1);
  58. if (err)
  59. break;
  60. /*
  61. *检查BH_New标志,如果被设置
  62. *调用unmap_underlying_metadata来检查页高速缓存内的某个块设备缓冲区页是否包含指向磁盘同一块的缓冲区
  63. *如果找到一块,BH_Dirty清0并等待知道该缓冲区的I/O数据传输完毕
  64. */
  65. if (buffer_new(bh)) {
  66. unmap_underlying_metadata(bh->b_bdev,
  67. bh->b_blocknr);
  68. if (PageUptodate(page)) {
  69. set_buffer_uptodate(bh);
  70. continue;
  71. }
  72. if (block_end > to || block_start < from) {
  73. void *kaddr;
  74. kaddr = kmap_atomic(page, KM_USER0);
  75. if (block_end > to)
  76. memset(kaddr+to, 0,
  77. block_end-to);
  78. if (block_start < from)
  79. memset(kaddr+block_start,
  80. 0, from-block_start);
  81. flush_dcache_page(page);
  82. kunmap_atomic(kaddr, KM_USER0);
  83. }
  84. continue;
  85. }
  86. }
  87. if (PageUptodate(page)) { /*如果page的读操作完成的PG_uptodate标志设置了,则将其缓冲区的BH_Uptodate也设置*/
  88. if (!buffer_uptodate(bh))
  89. set_buffer_uptodate(bh);
  90. continue;
  91. }
  92. /*如果不对整个缓冲区进行重写且它的BH_Delay和BH_Uptodate标志未置位(即缓冲区没有有效的数据影响),
  93. *调用ll_rw_block来从磁盘读入块的内容
  94. *ll_rw_block函数中自定义了I/O完后调用了end_buffer_io_sync
  95. */
  96. if (!buffer_uptodate(bh) && !buffer_delay(bh) &&
  97. (block_start < from || block_end > to)) {
  98. ll_rw_block(READ, 1, &bh);
  99. *wait_bh++=bh;
  100. }
  101. }
  102. /*
  103. * If we issued read requests - let them complete.
  104. */
  105. /*
  106. * 阻塞当前进程,直到for循环中的ll_rw_block读操作全部完成
  107. */
  108. while(wait_bh > wait) {
  109. wait_on_buffer(*--wait_bh);
  110. if (!buffer_uptodate(*wait_bh))
  111. err = -EIO;
  112. }
  113. if (!err) {
  114. bh = head;
  115. do {
  116. if (buffer_new(bh))
  117. clear_buffer_new(bh);
  118. } while ((bh = bh->b_this_page) != head);
  119. return 0;
  120. }
  121. /* Error case: */
  122. /*
  123. * Zero out any newly allocated blocks to avoid exposing stale
  124. * data. If BH_New is set, we know that the block was newly
  125. * allocated in the above loop.
  126. */
  127. bh = head;
  128. block_start = 0;
  129. do {
  130. block_end = block_start+blocksize;
  131. if (block_end <= from)
  132. goto next_bh;
  133. if (block_start >= to)
  134. break;
  135. if (buffer_new(bh)) {
  136. void *kaddr;
  137. clear_buffer_new(bh);
  138. kaddr = kmap_atomic(page, KM_USER0);
  139. memset(kaddr+block_start, 0, bh->b_size);
  140. kunmap_atomic(kaddr, KM_USER0);
  141. set_buffer_uptodate(bh);
  142. mark_buffer_dirty(bh);
  143. }
  144. next_bh:
  145. block_start = block_end;
  146. bh = bh->b_this_page;
  147. } while (bh != head);
  148. return err;
  149. }
阅读(1690) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~