您的位置:首页 > 大数据 > 人工智能

Raid5.h注释翻译

2011-09-16 15:39 176 查看
Linux内核2.6.32中的Raid5.h一上来就是150多行的注释!看起来好辛苦,简单翻译一份留在这里,翻译不对的地方希望大家指出~

每个条纹都包含一个buffer,每个buffer和每个磁盘对应。每个buffer都包括一些列的状态,存储在flags字段中。这些状态之间的切换“几乎”都是异步的,并且在一个“每条纹”的自旋锁中进行。一些非常特殊的标志位改变可以在bi_end_io中进行,这些改变不会由自旋锁保护。

两个标志位R5_UPTODATE和R5_LOCKED指出四种不同的状态:

State Empty == !UPTODATE, !LOCK

内存(buffer)中没有数据,而且也没有活跃的请求

State Want == !UPTODATE, LOCK

这个块上提交有读请求

State Dirty == UPTODATE, LOCK

内存中有数据,正在被写入磁盘

State Clean == UPTODATE, !LOCK

内存中有数据,并且和磁盘上的数据是同步的

状态转换可能:

* Empty -> Want - 读或者写(写操作需要读旧数据用于更新校验)

* Empty -> Dirty - 计算校验数据(sync或者重构写)

* Empty -> Clean - 一个失效的设备上恢复出来的数据

* Want -> Empty - 读失败

* Want -> Clean - 读请求成功完成

* Dirty -> Clean - 写请求成功完成

* Dirty -> Clean - 写失败

* Clean -> Dirty - 计算校验数据(sync或者重构、读改写)

Want->Empty, Want->Clean, Dirty->Clean的过程都发生在b_end_io的中断中。每次都要在释放锁标记位之前设置Uptodate位。

只剩下一种多状态转换可能:Want->Dirty->Clean。这种转换是安全的,因为,试想一个标记为Clean的buffer如果实际上是dirty的,最坏情况便是推迟了一些动作,条纹会在转换完成的时候注意到并且被重新调度。

上述状态并未包括一种可能性,即如果一个设备失效,同时有一个spare的设备正在重构。我们无法区分一个由计算校验而产生的clean的块还是一个成功写入spare设备的块(或者是resync进行中的校验)。为了区分这两种情况,条纹中的STRIPE_INSYNC为用以指明。当一个写操作是面向spare设备,或者没有spare设备的时候面向校验盘,该位将被置位。一个sync请求将复位该位,当我们发现(置位并且)没有任何buffer锁住的时候,就知道sync完成了。

md设备的buffer通过make_request是依附在合适的条纹中,这些条纹在两个b_reqnext链表之一。bh_read是读请求链表,bh_write是写请求链表。一个buffer应该是不可能同时存在于两个链表中,但是我们无法保证这一点,因此需要做更多的许可。

如果一个buffer对应的cache buffer标记为Uptodate的并且在读链表中,数据将拷贝到读缓冲区,并且调用自己的b_end_io例程。这种情况仅仅发生在buffer刚刚成功读取时候的end_request例程中。end_request需要将buffer从列表中移除,然后设置buffer的Uptodate位。其他线程仅仅在他们第一次检测Uptodate被设置的时候这么做,一旦检测完成,就将buffer从读队列中移除。

当一个写链表中的buffer进行写提交时候,将被拷贝到cache buffer中,这时将标记为dirty,并且移至第三个列表,written列表(bh_written)。一旦校验快和cache buffer都被成功写入磁盘,written列表中的buffer们将随b_end_io返回。

写列表和读列表都以fifo的方式工作。读列表由device_lock保护。write和written列表由条纹锁保护。device_lock将在条纹块持有的时候声明,仅仅用于人工修改列表,并且持有很短的时间。可以从中断中声明。

stripe cache中的条纹可以在两个列表中的一个里(也可以一个都不在)。“非活动列表”包括了当前没有被任何请求使用的列表,可以自由的由其他条纹使用。“处理列表”包括了需要按某种方法处理的条纹。这些列表都是fifo的队列。每个条纹也都(可能的)连接到一个哈希桶中,因此可以由扇区号索引到。条纹没有被哈希的,一定是在非活动列表中,并且一般都是在前头。所有的条纹都是以这种方式开始自己的生存期。

非活动列表、处理列表和哈希桶列表都由device_lock保护

---非活动列表中的条纹永远不会获得其条纹锁

---条纹都有引用计数,如果count==0,则必定在某个列表中

---如果一个条纹必须需要处理,STRIPE_HANDLE置位

---当引用计数到达0,如果STRIPE_HANDLE没有置位,该条纹放在非活动列表中,否则放在处理列表中

结合STRIPE_HANDLE仅仅当条纹具有一个非0的引用计数的情况下才能被复位,这意味着如果引用计数到达0并且STRIPE_HANDLE被置位,该条纹一定在处理列表中,如果STRIPE_HANDLE复位,该条纹一定在非活动列表中。

可能的转换包括:

---没有哈希/非活跃条纹---->激活(get_active_stripe())

++设备上锁--检验哈希--unlink条纹--cnt++--clean条纹--哈希条纹--设备解锁

---哈希(很可能是活跃)的条纹--->激活(get_active_stripe())

++设备上锁--检验哈希--if(!cnt++)unlink条纹--设备解锁

---将一个请求加到一个活跃条纹头上(add_stripe_bh())

++设备上锁--附加buffer--设备解锁

---处理一个条纹(handle_stripe())

++条文上锁--清STRIPE_HANDLE位--(设备上锁--检测buffers--设备解锁--)--改变状态--记录需要的io/ops--条纹解锁--调度io/ops

---释放一个活跃的条纹(release_stripe())

++设备上锁--if(!--cnt){根据STRIPE_HANDLE将条纹放回处理列表或者非活跃列表}--设备解锁

引用计数记录了激活了这个条纹的线程数+正在处理这个条纹的raid5d+cache buffer上的活跃请求数目,如果条纹正在进行条纹操作,那么再加1.

对条纹的操作在条纹锁的外面进行,主要包括:

---在stripe cache和用户应用缓冲之间拷贝数据

---为了减少一次磁盘访问进行的块(重构)计算,或者恢复一个丢失的块

---写操作中的更新校验

---检测校验是否正确

---运行到磁盘的I/O操作

这些操作都由raid5_run_ops进行,这个函数使用了async_tx相关api,使用专用的硬件以(可选的)减少操作负载。当请求一个操作时候,handle_stripe设置操作的pending位并且计数加一。每当计数为非0的时候,raid5_run_ops运行。

为了避免一些操作被请求而另一些操作正在进行的情况,操作之间要服从一些严格的依赖:

(1)因为校验检查操作破坏了校验块的缓存中版本,所以必须防止检查进程进行中的依赖校验的操作,比如写操作和计算块(即恢复块)操作。一些dma机器可以在不破坏校验块的前提下进行检查操作,这时校验块将被重新标记为实时(假设检查操作成功)并且不从磁盘中重新读取。

(2)当一个写请求到来时,要立即锁住相关的块,标记这些块为过期。这造成了新的读请求被拦截,并且带来了校验检查和块的计算操作。

(3)一旦有块计算请求,handle_stripe将这些块视作已经实时有效。raid5_run_ops保证任何独立于块计算结果的操作都在块计算完成之后被初始化。

操作状态 - sh->lock之外能看到的内部状态

一般的,_idle表示什么都没有进行中,_run表示一个数据操作正在进行,_result表示数据操作的结果是稳定的(即运算完了),并且可以受到(别的操作影响)。对于像biofill这样的简单操作和只有一个_idle和_run状态的计算,都用sh->state标志位表示(STRIPE_BIOFILL_RUN和STRIPE_COMPUTE_RUN)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息