三副本的PNFS重构流程

重构流程概述:

重构步骤如下,后面会有相关主要代码分析,具体代码实现可参考http://git.erc.ict.ac.cn/?p=bwfs_pnfs.sles11u1.git;a=shortlog;h=refs/heads/replication

1.       客户端在下刷或者读取磁盘时候,发现错误,记录到nfs_inode中的链表中。

2.       读写完成时,把错误链表发送到服务器。

3.       服务器收到错误链表后,将其插入到exfs_inode_info中的链表。启动异步重构线程

4.       重构线程,先召回需要重构文件的layout。设置重构标志位,构建file_handle和stateid等结构。然后选择一个client,发送重构命令和必要的信息。

5.       客户端接到重构要求后,异步启动一个重构线程。

6.       客户端的重构线程根据fh和i_ino等信息,调用getattr,构建出nfs_inode dentry(此结构只有重构线程可见)nfs_open_contex等必要信息,完成重构。

7.       客户端完成重构后,向服务器发送rebuild_done,服务器更新exfs_inode_info中的错误链表。

三副本读写情景分析:

1.在bl_read_pagelist()函数中,选择可用的副本完成磁盘内容的读取,代码如下:

for (i = pg_index; i < nr_pages; i++) {

。。。

be =find_get_extent(BLK_LSEG2EXT(rdata->pdata.lseg),

                                                         isect, &cow_read);

          。。。

 

 

截图部分为新添加代码,功能为选取合适的副本编号,存储在变量 index中。

其中,check_seg_available()函数为在nfs_inode的错误区段链表中查找可用的副本编号,同时检查extent中对应的副本的状态是否可用,若可用则跳转到FIND_INDEX.

若If(j ! = 0)成立,说明之前添加到bio中的页所用的副本,在添加当前页时候已经不可用,即index的值已经改变。则调用bl_submit_bio(),促使产生新的bio,并用改变后的index来给bio添加卷信息。

之所以不把错误信息记录到extent而是记录到nfs_inode的链表中的原因是:

A.      Extent通常很大(最小1M),若错误区段长度很小比如4k,若记录到对应的extent,则整个extent都会被标记为不可用。

B.      读写完成后,想MS报告错误信息时候,extent可能已经return或者callback,而且读写的extent链表是分开的;而记录到nfs_inode,具有读写都可见并且持久有效。

C.      在正常情况下,nfs_inode中的错误区段为空,并不会影响代码执行效率。

D.      当存在错误区段链表时候,由于每次都检查上次所用的副本编号,查到可用副本的命中率较高,也不会显著影响效率。

 

 

 

 

2.bl_end_io_read()是读完成后的回调函数,在这个函数中,检测读磁盘的结果,若失败,把错误信息记录到nfs_inode中,并选择另一个可用的副本再次读。

代码如下:

re_index 和bio_index 为所用副本编号和bio编号。下刷时存储在nfs_read_data中,根据编号找出此bio对应的offset 和len;

当此bio失败时候,uptodate的值为0。则调用add_err_seg_to_inode()将错误区段添加到nfs_inode中。

并再次查找可用的副本,设置新的bio,再次读取磁盘,直到成功或者没有副本可用为止。

 

 

3三副本的下刷逻辑比较简单,不在赘述。

 

 

重构代码情景分析:

1.发现并记录错误

客户端在下刷或者读取磁盘时候,发现错误,记录到nfs_inode中的链表中。具体函数为

Bl_end_bio_read()和bl_end_bio_write(),这两个函数均调用

add_err_seg_to_inode(NFS_I(data->inode),re_index,(loff_t)(offset<< 9),(u64)( len << 9));

添加到链表中。

 

 

2读写完成时候,报告错误。

读写完成后分别会调用static void nfs_writeback_release_full(void *calldata 和

static void nfs_readpage_release_full(void*calldata)

在这两个函数添加代码

 

若存在读写错误则调用 nfs_rw_back_call_err_report()函数,函数代码如下:

 

 

1362 – 1368行,是将nfs_inode链表清空,将节点挂接到err_seg_list[]中。这么做的原因是由于争用自旋锁,要尽量缩短代码执行时间。

然后统计参数,调用rebuild_proc_err_report()发送rpc,若成功,则删除链表。

rebuild_proc_err_report()代码如下:

 

 

这是rpc调用代码,包括编解码,已经服务器端的编解码都略去不讲。

 

 

 

 

 

 

 

 

 

 

 

 

 

3.服务器收到错误链表后,将其插入到exfs_inode_info中的链表。启动异步重构线程

服务器处理客户端发来的错误报告函数如下:

 

1366-1381行,将所需参数记录到re_task结构中,并将其添加到全局链表rebuild_task_list中。

1388行,将错误区段添加到exfs_inode_info结构中,

1394行,将重构任务添加到任务队列中,在5hz后执行。

4.重构线程,先召回需要重构文件的layout。设置重构标志位,构建file_handle和stateid等结构。然后选择一个client,发送重构命令和必要的信息。

 

1322行,若发现错误区段链表已经为空(其他线程已经完成重构),则返回。

1331行,主要完成重构所需参数的准备,如fh 以及 stated。

1335行,召回布局,目的有1.触发其他客户端发现错误;2通过layoutget互斥其他客户端对文件的访问。

1340行,启动call back要求发送rpc要求客户端重构。此函数和编解码函数都略去不讲。


 

5.客户端完成重构

客户端RPC守护进程接收到重构要求后,调用nfs4_rebuild函数

 

5661 -5666行,把在解码过程中,kmalloc创建的结构转移到re_task的指针域中,并启动nfs4_do_rebuild函数。

Nfs_do_rebuild函数定义如下:

5636行,nfs4_rebuild_prepare()函数根据服务器发送来的fh和i_ino等信息,调用getattr,构建出nfs_inode   dentry(此结构只有重构线程可见)以及nfs_open_contex等必要信息。

Nfs4_rebuild_read_and_write()函数完成重构。

5647行,客户端完成重构后,向服务器发送rebuild_done,服务器收到此RPC后更新exfs_inode_info中的错误链表。

5651行,调用nfs4_do_rebuild_release(),删除动态创建的数据结构。

 

 

 

 


你可能感兴趣的:(三副本的PNFS重构流程)