Linux 网络文件系统的数据备份及恢复机制实现
用为例,进行扩充、修改而实现记录操作日志的功能。
int nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname,
int flen,struct svc_fh *tfhp, char *tname, int tlen)
{
struct dentry *fdentry, *tdentry, *odentry, *ndentry;
struct inode *fdir, *tdir;
int err;
char *name;
mem_segment_t oldfs;
int fd;
err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_REMOVE);
if (err)
goto out;
rqstp->rq_path1 = rqstp->rq_path2;
err = fh_verify(rqstp, tfhp, S_IFDIR, MAY_CREATE);
if (err)
goto out;
fdentry = ffhp->fh_dentry;
fdir = fdentry->d_inode;
tdentry = tfhp->fh_dentry;
tdir = tdentry->d_inode;
……
//加入的代码进行处理工作
if((!rqstp->rq_recover)(!S_ISDIR(odentry->d_inode->i_mode))
(odentry->d_inode->i_nlink>1)){
rqstp->rq_copy->wait = 1;
rqstp->rq_copy->done = 0;
name = get_total_name(dentry,NULL);
oldfs = get_fs();
set_fs(KERNEL_DS); //进入内核模式
fd = sys_open(/backupserv/changfilename.c,0,31681);
sys_write(fd,name,strlen(name));
sys_close(fd);
set_fs(oldfs); //从内核模式返回
while(!rqstp->rq_copy->done){
schedule_timeout((HZ+99)/100);
……
}
}
该文件是在 nfs 服务器端执行 nfs 客户机发送过来的修改文件或者是目录的原函数。在这里,我们可以通过添加自己的代码,来将创建的目录和文件名存入一个磁盘文件当中,以备后面的备份和恢复操作。
图 6 NFS 文件细粒度恢复日志产生示意图

获得了操作日志信息,然后就可以进行精确恢复和选择性恢复时。首先由用户利用数据查询、浏览工具确定需要恢复的文件操作集,然后利用相应的日志数据按记录产生顺序逐条生成恢复请求,发送给文件服务器端的代理程序,由它通过 proc 文件请求 NFS 文件系统恢复模块进行恢复,恢复模块收到请求后,取出相关数据,然后通过调用底层 ext3 文件系统基本操作完成该次文件操作的”重放”,最后返回执行结果,通过 proc 文件通知代理程序,代理程序再通知管理端,管理端再发送下一条恢复请求,及到所有选中的操作全完成为止。具体实现模式请参看图 7:
图 7 恢复流程示意图

数据快速同步技术
在系统中,各文件服务器之间的数据需要及时同步更新,这样才能保证服务迁移后到新的环境后相关数据环境的一致性,从而保证服务迁移在语义上的正确性。在本方案中,每个文件服务器均采用 NFSv3 协议向外提供文件服务,当系统开始工作时,管理员会指定一台主服务器,由该服务器负责向外提供服务,其他文件服务器为备份服务器,接收同步数据,进行数据的同步更新,并不对外提供服务,只有当系统决定迁移后,选定的迁移目标对应的文件服务器才成为主文件服务器。
由于主文件服务器负责对外的文件服务,因此,数据同步的发起者应该是主文件服务器,而所有的备份服务器均为被动的同步数据接收者。因此,数据的快速同步包含两方面的工作:主文件服务器产生同步数据和备份文件服务器接收同步数据完成同步。具体的数据流向如图 8 所示:
图 8 同步数据的产生与流动示意图

为了达到数据快速同步的目的,我们采用了记录文件写操作(包括创建、修改、删除、改名、属性修改等所有的改变文件或目录属性、内容的操作)的具体参数的方法来生成同步数据,这样每次生成的数据量比较少,而且可以满足及时更新的目的。同步数据的格式及相关代码段如下:
struct Log {
int length; //整个数据包的长度
int ops; //操作的类型
char* data; //与操作相关数据
};
//下面代码段从内核将同步数据包发往其他文件服务器
long send(struct socket* sock, void * buff,size_t len)
{
int err;
mm_segment_t oldfs;
struct msghdr msg;
struct iovec iov;
static int total = 0;
down(log_sem);
iov.iov_base=buff;
iov.iov_len=len;
msg.msg_name=NULL;
msg.msg_iov=iov;
msg.msg_iovlen=1;
msg.msg_control=NULL;
msg.msg_controllen=0;
msg.msg_namelen=0;
total += len;
msg.msg_flags = MSG_SYN;//DONTWAIT;
oldfs=get_fs();
set_fs(KERNEL_DS);
err = sock_sendmsg(sock, msg, len);
set_fs(oldfs);
if(err0){
dprintk(send err(errNo=%d len = %d)\n,err,len);
netbroken = 1;
}
……
up(log_sem);
return(err);
}
同步数据产生后,先放入一个缓冲区中,而不是立即发送到备份文件服务器,这样可以较大程度改善系统的总体性
- REDIce-Linux--灵活的实时Linux内核(11-12)
- linux文件系统基础(02-09)
- Linux标准趋向统一(11-12)
- linux基础技术(02-09)
- LINUX的目录树(02-09)
- 在Windows下启动Linux(02-09)
