分类: LINUX
2009-09-02 17:29:22
Reshape对应磁盘个数的变化,只支持增加,不支持减少。
Reshape的基本操作是,以一个条带为例,这个条带之前的内容已经完成reshape,这个条带之后的内容尚未开始reshape。首先按照旧的磁阵尺寸读出这个条带的内容,按照新的磁阵尺寸计算这个条带的写入位置,并在这个位置写入读出的数据,也就是将数据从旧的磁阵搬到新的磁阵上去。由于reshape只允许增加磁盘,不允许减少磁盘,所以这样的操作是可行的,并且只要访问和reshape正在操作的位置不重复,就不用中断应用的访问。对于超过原磁阵大小的空间,数据部分全部填充0。
Reshape由用户命令触发(sysfs的sync_action如果等于reshape),触发后调用raid5_start_reshape进行处理。
在raid5_start_reshape中MD_RECOVERY_RESHAPE标志被设置,注册并唤醒同步线程,在同步线程中会调用sync_request,该函数又调用reshape_request对当前条带进行处理。
expand_progress之前的区域是设备reshape已经完成的部分,而expand_lo是已写盘的磁阵超级块中记录的reshape已经完成的位置。在expand_lo和expand_progress之间是正在或者已完成的reshape,但还没有可靠写盘。
1. reshape_request一次处理一个chunk(磁阵条带,和stripe不同):对chunk中的每一段(段的大小是strip的深度,即一个页),先以新的磁阵大小申请stripe-A,设置其STRIPE_EXPANDING标志;然后对应这些strip,以旧的磁阵大小申请strip-B,设置其STRIPE_EXPAND_SOURCE标志和STRIPE_HANDLE标志。即准备将strip-B的数据读出,写入strip-A。
2. 在handle_stripe5中,如果是STRIPE_EXPAND_SOURCE,说明是strip-B类型的,则会:
a) 判断是否需要提交读请求;
b) 如果条带所有读请求都完成(if (expanding && locked == 0)),则:
i. 清除STRIPE_EXPAND_SOURCE标志。
ii. 找到对应的(在reshape_request中申请的)以新磁阵大小的条带stripe-A,将对应数据拷贝到strip-A中,如果strip-A中的所有数据已经收集完成(所有缓存都R5_Expanded),则设置stripe-A的STRIPE_EXPAND_READY标志,将其挂入handle队列。
3. 在handle_stripe5中,如果是STRIPE_EXPAND_READY(expanded),说明是strip-A类型的,则:
a) 如果条带STRIPE_EXPANDING标志设置,说明此时源数据全部读出,但未写盘,计算出该strip-A的条带效验和,向磁盘提交写请求。清除STRIPE_EXPANDING标志。
b) 如果条带STRIPE_EXPANDING标志未设置,说明此时写也已经完成了,则清除STRIPE_EXPAND_READY标志,结束本stripe的reshape操作。
在make_request中,会检查当前请求的数据位置,如果在expand_progress之后,说明该区域此时尚未进行reshape,磁阵磁盘取值为previous_raid_disks。如果请求位置在expand_progress和expand_Io之间,此时由于访问的是一个不稳定区域,所以放弃调度权,等待。
在申请到stripe后,还要继续检查此刻的reshape位置,如果已经发生变化,使得访问位置在expand_progress之前,则返回重新开始。如果申请到的条带处在expanding(STRIPE_EXPANDING)状态,则放弃调度权,等待。
在sync_request中,如果发现当前处理位置已经到磁阵的尾部了,则调用end_reshape结束reshape操作,很奇怪这里还是没有对MD_RECOVERY_RESHAPE标志进行清除,应该是一个bug。