在文件系统中读写文件时,一般需要先得到操作对象的索引inode信息,在客户端未缓存的情况下,除了调用open外,客户端也会下发lookup或者getattr命令到服务端去获取操作对象的inode。Lookup和getattr IO的mds端流程几乎一致,所以以lookup流程为例进行介绍。
客户端以linux 4.18内核源码(cephfs的内核客户端在linux内核中实现)进行分析,服务端使用单活冷备的3节点集群。
1. 内核客户端处理发送
假设lookup的路径是/mnt/cephfs/testdir/1 (/mnt/cephfs是内核挂载根目录)
函数入口:
static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) { ... 入参分析:dir包含了父目录的inode索引号; dentry里面包含了d_name表示文件名’1’,可以获得 len;flag变量cephfs没有用到 ... /* 判断lookup的是否是快照来决定opcode,这里为opcode当然为CEPH_MDS_OP_LOOKUP*/ op = ceph_snap(dir) == CEPH_SNAPDIR ?CEPH_MDS_OP_LOOKUPSNAP : CEPH_MDS_OP_LOOKUP; /* 新建一个req请求。*/ req = ceph_mdsc_create_request(mdsc, op, USE_ANY_MDS); if (IS_ERR(req)) return ERR_CAST(req); /* 赋予dentry到请求r_dentry */ req->r_dentry = dget(dentry); req->r_num_caps = 2; /* 需要去mds端获取的inode cap和auth shard cap */ mask = CEPH_STAT_CAP_INODE | CEPH_CAP_AUTH_SHARED; ... /* 赋父目录的inode号给请求的r_parent */ req->r_parent = dir; ... /* 发送请求处理,等待请求完成 */ err = ceph_mdsc_do_request(mdsc, NULL, req); ... /* 获取dentry (这时dentry已经拼接好了对应inode了)*/ dentry = ceph_finish_lookup(req, dentry, err); /* 减请求计数,释放请求 */ ceph_mdsc_put_request(req); /* will dput(dentry) */ dout("lookup result=%p\n", dentry); return dentry; }
大体流程为创建输入父目录testdir的inode和文件1的名字,创建请求发送到mds处理,等待mds处理完成后回请求返回文件1的inode和dentry结构,返回带有inode链接的dentry给vfs。
ceph_mdsc_do_request处理了较为复杂的逻辑,涉及到消息发送的框架,下面重点分析下入参相关的转换。
调用关系如下:
|__ ceph_mdsc_do_request
|__ __do_request
|__ ____prepare_send_request
|__ ______create_request_message
由于mds端处理的函数是直接使用了filepath结构体承接客户端传来的参数,所以在创建请求消息create_request_message这里客户端转换之前填充req的入参为filepath结构体。
Mds端的filepath结构体:
Class filepath { inodeno_t ino; string path; }
create_request_message函数里使用了set_request_path_attr,如下图所示,由于本次是使用了lookup,所以只用了第一次的set_request_path_attr,rename的情况才需要记录old的dentry和新的dentry所在。
set_request_path_attr中由于lookup只填了目标的dentry,所以走图中标记的红框流程,build_dentry_path主要是将之前填入req中的父目录testdir的inode和文件1的dentry的名字和长度转填到filepath结构体中。
2. MDS服务端
服务端通过消息通信框架机制Messager来处理请求,由于消息的收发都是异步的,所以需要单独的模块来处理,这块本文就简单略说,调用堆栈如下:
|___ Server::handle_client_request
|__ __Server::dispatch
|__ ____MDSRank::handle_deferrable_message
|__ ______MDSRank::_dispatch
|__ ________MDSRank::retry_dispatch
|__ ____